From b6e01c8a3c836032823e13a404ceca2e968b6411 Mon Sep 17 00:00:00 2001 From: Diogo Soares Rodrigues Date: Mon, 27 Jul 2026 07:45:02 -0300 Subject: [PATCH] feat(ai): handle Cursor's modern exec wire protocol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current Cursor CLI builds emit exec frames this client did not model. A frame whose oneof number is absent from `agent.proto` decodes with `message.case` unset, so the dispatcher found no handler, ran no tool and sent no result — the server was left waiting on an execution that never happened. Every recognised frame now gets a typed answer: - The seven Pi tools (45-51) run their local equivalents. They are a separate wire family from the legacy args, not aliases: `pi_grep`'s `ignore_case` is the inverse of the local `case` flag, `pi_find` searches filenames (so it routes to `glob`, not `grep`), and `pi_edit`'s replacements are renamed to snake_case pairs. - Hooks, subagents, prechecks, MCP state, smart-mode, canvas, conversation search and agent-store answer with the error, not-found or empty-but-valid variant that is true of this client. - Unnameable frames raise `ExecClientControlMessage.throw` (`unknown_exec_variant`); recognised frames with no truthful answer — `git_diff_request`, whose `GetDiffResponse` has no error variant — raise `exec_variant_unsupported`. Four frames previously answered `create(XSchema, {})`. In proto3 that is not an empty result: the oneof is unset and the server reads it as "the tool ran and produced nothing", indistinguishable from success. They now send real variants. `connect_scm` lost its repository (the target rides in a oneof, so the flat property was always undefined) and settled on a fixed failure at the announcement, before the server's `success`/`error`/`rejected` verdict arrived on the completion frame. The stream decoder tracked a single "current" tool-call block and settled it on any `toolCallCompleted`, ignoring the envelope `call_id`: an unrelated completion paired the wrong block, and `start A, start B` orphaned A so nothing ever paired it — which strips the whole interaction from every rebuilt transcript. Blocks are now retained per envelope id. `lsp` is advertised as MCP again; the native `diagnostics` frame covers one of ~10 actions. (cherry picked from commit 4d269724a3a448886d13b4323ac02aadbfe38de3) --- packages/ai/CHANGELOG.md | 12 + packages/ai/src/providers/cursor.ts | 841 ++++++++++++- .../ai/src/providers/cursor/exec-modern.ts | 393 ++++++ .../ai/src/providers/cursor/proto/agent.proto | 105 ++ packages/ai/src/types.ts | 41 + packages/ai/src/utils/block-symbols.ts | 12 + packages/ai/test/cursor-exec-handlers.test.ts | 1 + packages/ai/test/cursor-exec-modern.test.ts | 1062 +++++++++++++++++ .../ai/test/cursor-streaming-args.test.ts | 1 + packages/ai/test/cursor-todo-bridge.test.ts | 1 + packages/catalog/CHANGELOG.md | 3 + .../src/discovery/cursor-gen/agent_pb.ts | 418 ++++++- packages/coding-agent/CHANGELOG.md | 3 + packages/coding-agent/src/cursor.ts | 69 ++ .../coding-agent/test/cursor-exec.test.ts | 94 ++ 15 files changed, 2997 insertions(+), 59 deletions(-) create mode 100644 packages/ai/src/providers/cursor/exec-modern.ts create mode 100644 packages/ai/test/cursor-exec-modern.test.ts diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 599b4f30d..823950063 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -63,6 +63,18 @@ - Kimi Code now sends its session-stable prompt cache key on both supported transports: `prompt_cache_key` for OpenAI-compatible requests and `metadata.user_id` for Anthropic-compatible requests. Explicit keys survive side-channel session IDs, while `cacheRetention: "none"` still disables automatic affinity ([#6049](https://github.com/can1357/oh-my-pi/issues/6049)). - Fresh encrypted auth-broker snapshot caches are revalidated within a short startup budget, so one-shot clients see newly imported or revoked credentials immediately when the broker is reachable while retaining cache fallback for transport and server failures. - Fixed custom `anthropic-messages` endpoints dropping native web-search call/result blocks in the leaked-thinking wrapper, preserving signed continuation history in source order without carrying a preceding text signature onto later unsigned blocks ([#6703](https://github.com/can1357/oh-my-pi/issues/6703)). +### Added + +- Cursor's modern exec wire protocol is now handled end to end. `agent.proto` models the frames current Cursor CLI builds emit — the seven Pi tools (`ExecServerMessage` 45-51), hooks, subagents, allowlist prechecks, MCP state, smart-mode classification, canvas diagnostics, conversation search, agent-store conflicts and git diff — and every one of them gets a typed answer. The Pi frames run their local equivalents (`read`/`bash`/`edit`/`write`/`grep`/`glob`); the rest answer with the error, not-found or empty-but-valid variant that is actually true of this client. Frames this build cannot name at all now raise `ExecClientControlMessage.throw` with `unknown_exec_variant`, and recognised frames with no truthful answer (`git_diff_request`, whose `GetDiffResponse` has no error variant) raise `exec_variant_unsupported`, instead of a silent ack that leaves the server waiting. +- `lsp` is advertised in the MCP tool catalog again. It was filtered out as a Cursor-native tool, but the native `diagnostics` frame covers one of roughly ten LSP actions, so the other nine were unreachable. + +### Fixed + +- Fixed four Cursor exec frames answering with a result whose oneof was never set. In proto3 that is not an empty result — the server reads it as "the tool ran and produced nothing", indistinguishable from real success. `listMcpResourcesExecResult`, `readMcpResourceExecResult`, `recordScreenResult` and `computerUseResult` now send `ListMcpResourcesSuccess{resources: []}`, `ReadMcpResourceNotFound{uri}`, `RecordScreenFailure` and `ComputerUseError` respectively. +- Fixed Cursor `connect_scm` calls losing their repository and settling on a fabricated verdict. The target rides in the `ConnectScmArgs.target` oneof, so reading a flat `github` property always saw `undefined`; and the authoritative `success`/`error`/`rejected` result only arrives on the completion frame, so answering at the announcement persisted a fixed failure for every call — including the ones the server went on to accept. The block now opens on the start frame and settles from the completion's decoded result. +- Fixed interleaved Cursor tool calls corrupting each other. The stream decoder tracked a single "current" block and settled it on any `toolCallCompleted`, ignoring the envelope's `call_id`: a completion for one call closed whichever block happened to be open and paired it with the wrong result, and `start A, start B` orphaned A entirely so its own completion settled B while A was never paired — which strips the whole interaction from every rebuilt transcript. Open blocks are now retained per envelope `call_id`, and end-of-stream closes all of them rather than only the last. +- Fixed a Cursor `search_conversations` call leaving no transcript block. The frame is answered from a fixed verdict, so nothing downstream pairs a result for it, and an unpaired call takes its whole interaction out of every rebuilt transcript. +- Fixed the streamed `pi_*_tool_call` announcements that modern builds send alongside each exec frame being unrecognized. The exec channel already synthesizes those blocks when it runs the tool; the duplicate was avoided only because the decoder recognized none of the variants, which would have started double-rendering as soon as any one was added. ## [17.1.4] - 2026-07-26 diff --git a/packages/ai/src/providers/cursor.ts b/packages/ai/src/providers/cursor.ts index 35232ce74..f613c3ff2 100644 --- a/packages/ai/src/providers/cursor.ts +++ b/packages/ai/src/providers/cursor.ts @@ -10,11 +10,18 @@ import { AgentRunRequestSchema, type AgentServerMessage, AgentServerMessageSchema, + AgentStoreConflictErrorSchema, + AgentStoreConflictResultSchema, AssistantMessageSchema, BackgroundShellSpawnResultSchema, + CanvasDiagnosticsErrorSchema, + CanvasDiagnosticsResultSchema, ClientHeartbeatSchema, + ComputerUseErrorSchema, ComputerUseResultSchema, ConversationActionSchema, + ConversationSearchErrorSchema, + ConversationSearchResultSchema, type ConversationStateStructure, ConversationStateStructureSchema, ConversationStepSchema, @@ -31,9 +38,14 @@ import { type ExecClientMessage, ExecClientMessageSchema, ExecClientStreamCloseSchema, + ExecClientThrowSchema, type ExecServerMessage, FetchErrorSchema, FetchResultSchema, + ForceBackgroundShellResultSchema, + ForceBackgroundShellStatus, + ForceBackgroundSubagentResultSchema, + ForceBackgroundSubagentStatus, GetBlobResultSchema, GrepContentMatchSchema, GrepContentResultSchema, @@ -50,6 +62,7 @@ import { KvClientMessageSchema, type KvServerMessage, ListMcpResourcesExecResultSchema, + ListMcpResourcesSuccessSchema, type LsDirectoryTreeNode, type LsDirectoryTreeNode_File, LsDirectoryTreeNode_FileSchema, @@ -58,6 +71,7 @@ import { LsRejectedSchema, LsResultSchema, LsSuccessSchema, + McpAllowlistPrecheckResultSchema, McpErrorSchema, McpImageContentSchema, McpResultSchema, @@ -69,9 +83,11 @@ import { ModelDetailsSchema, ReadErrorSchema, ReadMcpResourceExecResultSchema, + ReadMcpResourceNotFoundSchema, ReadRejectedSchema, ReadResultSchema, ReadSuccessSchema, + RecordScreenFailureSchema, RecordScreenResultSchema, RequestContextResultSchema, RequestContextSchema, @@ -81,6 +97,7 @@ import { SelectedContextSchema, SelectedImageSchema, SetBlobResultSchema, + ShellAllowlistPrecheckResultSchema, type ShellArgs, ShellFailureSchema, ShellRejectedSchema, @@ -93,8 +110,15 @@ import { ShellStreamStderrSchema, ShellStreamStdoutSchema, ShellSuccessSchema, + SmartModeClassifierErrorSchema, + SmartModeClassifierResultSchema, + SubagentAwaitNotFoundSchema, + SubagentAwaitResultSchema, + SubagentErrorSchema, + SubagentResultSchema, UserMessageActionSchema, UserMessageSchema, + WebFetchAllowlistPrecheckResultSchema, WriteErrorSchema, WriteRejectedSchema, WriteResultSchema, @@ -142,6 +166,7 @@ import { kCursorExecResolved, kStreamingBlockIndex, kStreamingBlockKind, + kStreamingEnvelopeId, kStreamingLastParseLen, kStreamingPartialJson, } from "../utils/block-symbols"; @@ -150,12 +175,38 @@ import { AssistantMessageEventStream } from "../utils/event-stream"; import { connectProxiedSocket, getProxyForProvider, shouldBypassProxy } from "../utils/proxy"; import { createRequestDebugSession, isRequestDebugEnabled, type RequestDebugResponseLog } from "../utils/request-debug"; import { toolWireSchema } from "../utils/schema/wire"; +import { + buildMcpStateResult, + buildNeutralHookResult, + buildPiBashError, + buildPiBashResult, + buildPiEditError, + buildPiEditResult, + buildPiFindError, + buildPiFindResult, + buildPiGrepError, + buildPiGrepResult, + buildPiLsError, + buildPiLsResult, + buildPiReadError, + buildPiReadResult, + buildPiWriteError, + buildPiWriteResult, +} from "./cursor/exec-modern"; export const CURSOR_API_URL = "https://api2.cursor.sh"; export const CURSOR_CLIENT_VERSION = "cli-2026.01.09-231024f"; const CURSOR_PROXY_TUNNEL_TIMEOUT_MS = 30_000; +/** + * Text for a recognised frame this client answers with its own typed error + * variant. Phrased as a client capability statement, not a tool failure: the + * model reads it and should route around the capability, not retry the call. + */ +const NOT_IMPLEMENTED_SUFFIX = "not implemented by this client"; +const NOT_IMPLEMENTED = `Not implemented by this client`; + const conversationStateCache = new Map(); const conversationBlobStores = new Map>(); @@ -520,6 +571,7 @@ export const streamCursor: StreamFunction<"cursor-agent"> = ( get currentToolCall() { return currentToolCall; }, + openToolCalls: new Map(), resolvedMcpToolCallIds, get firstTokenTime() { return firstTokenTime; @@ -677,17 +729,20 @@ export const streamCursor: StreamFunction<"cursor-agent"> = ( endCurrentTextBlock(output, stream, state); endCurrentThinkingBlock(output, stream, state); - if (state.currentToolCall) { - const idx = output.content.indexOf(state.currentToolCall); - state.currentToolCall.arguments = parseStreamingJson(state.currentToolCall[kStreamingPartialJson]); - clearStreamingPartialJson(state.currentToolCall); - stream.push({ - type: "toolcall_end", - contentIndex: idx, - toolCall: state.currentToolCall, - partial: output, - }); + // Every block still open when the transport ends must be closed, not + // just the last one started: with interleaved calls several can be + // open at once, and an unclosed block leaves its live card animating + // and its call unpaired. + const openBlocks = new Set(state.openToolCalls.values()); + if (state.currentToolCall) openBlocks.add(state.currentToolCall); + for (const block of openBlocks) { + const idx = output.content.indexOf(block); + block.arguments = parseStreamingJson(block[kStreamingPartialJson]); + clearStreamingPartialJson(block); + stream.push({ type: "toolcall_end", contentIndex: idx, toolCall: block, partial: output }); } + state.openToolCalls.clear(); + state.setToolCall(null); calculateCost(model, output.usage); @@ -736,7 +791,8 @@ export type ToolCallState = ToolCall & { [kStreamingBlockIndex]: number; [kStreamingPartialJson]?: string; [kStreamingLastParseLen]?: number; - [kStreamingBlockKind]: "mcp" | "todo" | "cursor-exec"; + [kStreamingBlockKind]: "mcp" | "todo" | "cursor-exec" | "connect-scm"; + [kStreamingEnvelopeId]?: string; [kCursorExecResolved]?: true; }; @@ -744,6 +800,17 @@ export interface BlockState { currentTextBlock: (TextContent & { [kStreamingBlockIndex]: number }) | null; currentThinkingBlock: (ThinkingContent & { [kStreamingBlockIndex]: number }) | null; currentToolCall: ToolCallState | null; + /** + * Open streamed tool-call blocks, keyed by the interaction envelope's + * `call_id`. + * + * Cursor interleaves calls: two `toolCallStarted` frames can arrive before + * either completes. A single "current" slot would let the second overwrite + * the first, orphaning a block that nothing then settles. Every keyed block + * stays reachable until its own completion, and `currentToolCall` remains + * only as the fallback for frames that carry no `call_id`. + */ + openToolCalls: Map; /** MCP call IDs synthesized from exec frames before their redundant streamed block arrives. */ resolvedMcpToolCallIds: Set; firstTokenTime: number | undefined; @@ -1195,6 +1262,14 @@ async function handleExecServerMessage( } if (!execCase) { + // A frame carrying a oneof number this build's `agent.proto` does not + // model at all: protobuf decodes it into unknown fields and leaves + // `message.case` unset, so the client cannot even name what was asked. + // Returning silently strands the exec id — the server waits on a reply + // that never comes. Distinct from the `default:` branch below, which + // names a frame it recognises but cannot serve. + log("warn", "unknownExecVariant", { id: execMsg.id, execId: execMsg.execId }); + sendExecClientThrow(h2Request, execMsg, "Unknown exec message variant", "unknown_exec_variant"); return; } @@ -1449,54 +1524,412 @@ async function handleExecServerMessage( return; } case "listMcpResourcesExecArgs": { - const execResult = create(ListMcpResourcesExecResultSchema, {}); + // This client hosts no MCP servers, so it exposes no resources. An + // unset-oneof `ListMcpResourcesExecResult` would read as "the call + // produced nothing"; an explicit empty success says "asked, none exist". + const execResult = create(ListMcpResourcesExecResultSchema, { + result: { case: "success", value: create(ListMcpResourcesSuccessSchema, { resources: [] }) }, + }); sendExecClientMessage(h2Request, execMsg, "listMcpResourcesExecResult", execResult); return; } case "readMcpResourceExecArgs": { - const execResult = create(ReadMcpResourceExecResultSchema, {}); + const args = execMsg.message.value; + // No resources are advertised, so every uri is genuinely not found. + const execResult = create(ReadMcpResourceExecResultSchema, { + result: { case: "notFound", value: create(ReadMcpResourceNotFoundSchema, { uri: args.uri }) }, + }); sendExecClientMessage(h2Request, execMsg, "readMcpResourceExecResult", execResult); return; } case "recordScreenArgs": { - const execResult = create(RecordScreenResultSchema, {}); + const execResult = create(RecordScreenResultSchema, { + result: { case: "failure", value: create(RecordScreenFailureSchema, { error: NOT_IMPLEMENTED }) }, + }); sendExecClientMessage(h2Request, execMsg, "recordScreenResult", execResult); return; } case "computerUseArgs": { - const execResult = create(ComputerUseResultSchema, {}); + const execResult = create(ComputerUseResultSchema, { + result: { case: "error", value: create(ComputerUseErrorSchema, { error: NOT_IMPLEMENTED }) }, + }); sendExecClientMessage(h2Request, execMsg, "computerUseResult", execResult); return; } + case "piReadArgs": { + const args = execMsg.message.value; + const toolCallId = crypto.randomUUID(); + synthesizeCursorExecToolCall(output, stream, state, toolCallId, "read", { path: args.path }); + const { execResult } = await resolveExecHandler( + { args, toolCallId }, + execHandlers?.piRead?.bind(execHandlers), + onToolResult, + buildPiReadResult, + buildPiReadError, + buildPiReadError, + { toolCallId, toolName: "read" }, + ); + sendExecClientMessage(h2Request, execMsg, "piReadResult", execResult); + return; + } + case "piBashArgs": { + const args = execMsg.message.value; + const toolCallId = crypto.randomUUID(); + synthesizeCursorExecToolCall(output, stream, state, toolCallId, "bash", { + command: args.command, + timeout: args.timeout && args.timeout > 0 ? args.timeout : undefined, + }); + const { execResult } = await resolveExecHandler( + { args, toolCallId }, + execHandlers?.piBash?.bind(execHandlers), + onToolResult, + buildPiBashResult, + buildPiBashError, + buildPiBashError, + { toolCallId, toolName: "bash" }, + ); + sendExecClientMessage(h2Request, execMsg, "piBashResult", execResult); + return; + } + case "piEditArgs": { + const args = execMsg.message.value; + const toolCallId = crypto.randomUUID(); + // `PiEditReplacement` is the local `edit` tool's replace mode verbatim: + // snake_case `old_text`/`new_text` entries against one path. + synthesizeCursorExecToolCall(output, stream, state, toolCallId, "edit", { + path: args.path, + edits: args.edits.map(edit => ({ old_text: edit.oldText, new_text: edit.newText })), + }); + const { execResult } = await resolveExecHandler( + { args, toolCallId }, + execHandlers?.piEdit?.bind(execHandlers), + onToolResult, + buildPiEditResult, + buildPiEditError, + buildPiEditError, + { toolCallId, toolName: "edit" }, + ); + sendExecClientMessage(h2Request, execMsg, "piEditResult", execResult); + return; + } + case "piWriteArgs": { + const args = execMsg.message.value; + const toolCallId = crypto.randomUUID(); + synthesizeCursorExecToolCall(output, stream, state, toolCallId, "write", { + path: args.path, + content: args.content, + }); + const { execResult } = await resolveExecHandler( + { args, toolCallId }, + execHandlers?.piWrite?.bind(execHandlers), + onToolResult, + buildPiWriteResult, + buildPiWriteError, + buildPiWriteError, + { toolCallId, toolName: "write" }, + ); + sendExecClientMessage(h2Request, execMsg, "piWriteResult", execResult); + return; + } + case "piGrepArgs": { + const args = execMsg.message.value; + const toolCallId = crypto.randomUUID(); + synthesizeCursorExecToolCall(output, stream, state, toolCallId, "grep", { + pattern: args.pattern, + path: args.glob ? `${args.path || "."}/${args.glob}` : args.path || ".", + case: args.ignoreCase === true ? false : undefined, + }); + const { execResult } = await resolveExecHandler( + { args, toolCallId }, + execHandlers?.piGrep?.bind(execHandlers), + onToolResult, + buildPiGrepResult, + buildPiGrepError, + buildPiGrepError, + { toolCallId, toolName: "grep" }, + ); + sendExecClientMessage(h2Request, execMsg, "piGrepResult", execResult); + return; + } + case "piFindArgs": { + const args = execMsg.message.value; + const toolCallId = crypto.randomUUID(); + synthesizeCursorExecToolCall(output, stream, state, toolCallId, "glob", { + path: args.path ? `${args.path}/${args.pattern}` : args.pattern, + limit: args.limit, + }); + const { execResult } = await resolveExecHandler( + { args, toolCallId }, + execHandlers?.piFind?.bind(execHandlers), + onToolResult, + buildPiFindResult, + buildPiFindError, + buildPiFindError, + { toolCallId, toolName: "glob" }, + ); + sendExecClientMessage(h2Request, execMsg, "piFindResult", execResult); + return; + } + case "piLsArgs": { + const args = execMsg.message.value; + const toolCallId = crypto.randomUUID(); + // Same mapping as the legacy `lsArgs` frame: the local `read` tool lists + // directories, so the synthesized block must name `read` to match the + // bridge's own `toolResult`. + synthesizeCursorExecToolCall(output, stream, state, toolCallId, "read", { path: args.path || "." }); + const { execResult } = await resolveExecHandler( + { args, toolCallId }, + execHandlers?.piLs?.bind(execHandlers), + onToolResult, + buildPiLsResult, + buildPiLsError, + buildPiLsError, + { toolCallId, toolName: "read" }, + ); + sendExecClientMessage(h2Request, execMsg, "piLsResult", execResult); + return; + } + case "miniSweAgentBashArgs": { + // Same `ShellArgs`/`ShellResult` pair as `shellArgs`, under its own frame + // number, so the existing shell handler answers it unchanged. + const args = execMsg.message.value; + if (!args.toolCallId) args.toolCallId = crypto.randomUUID(); + const normalizedArgs: ShellArgs = { ...args, workingDirectory: args.workingDirectory || process.cwd() }; + synthesizeCursorExecToolCall(output, stream, state, args.toolCallId, "bash", { + command: args.command, + cwd: args.workingDirectory || undefined, + timeout: args.timeout && args.timeout > 0 ? args.timeout : undefined, + }); + const { execResult } = await resolveExecHandler( + normalizedArgs, + execHandlers?.shell?.bind(execHandlers), + onToolResult, + toolResult => buildShellResultFromToolResult(normalizedArgs, toolResult), + reason => buildShellRejectedResult(normalizedArgs.command, normalizedArgs.workingDirectory, reason), + error => buildShellFailureResult(normalizedArgs.command, normalizedArgs.workingDirectory, error), + { toolCallId: args.toolCallId, toolName: "bash" }, + ); + sendExecClientMessage(h2Request, execMsg, "miniSweAgentBashResult", sanitizeShellExecResult(execResult)); + return; + } + case "redactedReadArgs": { + // Same `ReadArgs`/`ReadResult` pair as `readArgs`, but the server expects + // the client to strip secrets from the content first. No redaction is + // implemented here, and serving a plain read would hand back exactly the + // unredacted bytes the frame exists to withhold. + const args = execMsg.message.value; + sendExecClientMessage( + h2Request, + execMsg, + "redactedReadResult", + buildReadErrorResult(args.path, "Secret redaction is not implemented by this client"), + ); + return; + } + case "mcpStateExecArgs": { + const args = execMsg.message.value; + sendExecClientMessage( + h2Request, + execMsg, + "mcpStateExecResult", + buildMcpStateResult(requestContextTools, args.serverIdentifiers), + ); + return; + } + case "executeHookArgs": { + const args = execMsg.message.value; + const execResult = buildNeutralHookResult(args.request); + if (!execResult) { + sendExecClientThrow( + h2Request, + execMsg, + `Unsupported hook request: ${args.request?.request.case ?? "unset"}`, + "unknown_hook_request", + ); + return; + } + sendExecClientMessage(h2Request, execMsg, "executeHookResult", execResult); + return; + } + case "subagentArgs": { + const args = execMsg.message.value; + const execResult = create(SubagentResultSchema, { + result: { + case: "error", + value: create(SubagentErrorSchema, { error: `Subagents are ${NOT_IMPLEMENTED_SUFFIX}` }), + }, + }); + log("exec", "subagentRejected", { subagentType: args.subagentType }); + sendExecClientMessage(h2Request, execMsg, "subagentResult", execResult); + return; + } + case "subagentAwaitArgs": { + // No subagent was ever spawned, so every awaited id is genuinely unknown. + const args = execMsg.message.value; + const execResult = create(SubagentAwaitResultSchema, { + result: { + case: "notFound", + value: create(SubagentAwaitNotFoundSchema, { agentId: args.agentId }), + }, + }); + sendExecClientMessage(h2Request, execMsg, "subagentAwaitResult", execResult); + return; + } + case "forceBackgroundShellArgs": { + // Backgrounding targets a running tool call by id. This client runs every + // shell to completion in band, so there is never one to move. + const execResult = create(ForceBackgroundShellResultSchema, { + status: ForceBackgroundShellStatus.NOT_FOUND, + }); + sendExecClientMessage(h2Request, execMsg, "forceBackgroundShellResult", execResult); + return; + } + case "forceBackgroundSubagentArgs": { + const execResult = create(ForceBackgroundSubagentResultSchema, { + status: ForceBackgroundSubagentStatus.NOT_FOUND, + }); + sendExecClientMessage(h2Request, execMsg, "forceBackgroundSubagentResult", execResult); + return; + } + case "smartModeClassifierArgs": { + // The classifier decides whether a risky action needs approval. Answering + // `ALLOW` would silently wave through actions the server asked us to + // judge, so the honest answer is that no classifier exists here. + const execResult = create(SmartModeClassifierResultSchema, { + result: { + case: "error", + value: create(SmartModeClassifierErrorSchema, { + error: `Smart-mode classification is ${NOT_IMPLEMENTED_SUFFIX}`, + }), + }, + }); + sendExecClientMessage(h2Request, execMsg, "smartModeClassifierResult", execResult); + return; + } + case "canvasDiagnosticsArgs": { + const args = execMsg.message.value; + const execResult = create(CanvasDiagnosticsResultSchema, { + result: { + case: "error", + value: create(CanvasDiagnosticsErrorSchema, { + path: args.path, + error: `Canvas diagnostics are ${NOT_IMPLEMENTED_SUFFIX}`, + }), + }, + }); + sendExecClientMessage(h2Request, execMsg, "canvasDiagnosticsResult", execResult); + return; + } + case "shellAllowlistPrecheckArgs": { + // The prechecks ask "is this pre-approved, so may it skip the approval + // prompt?". This client keeps no allowlist, so the answer is always no: + // `false` costs an approval round-trip, `true` would grant one that was + // never configured. + sendExecClientMessage( + h2Request, + execMsg, + "shellAllowlistPrecheckResult", + create(ShellAllowlistPrecheckResultSchema, { allowlisted: false }), + ); + return; + } + case "mcpAllowlistPrecheckArgs": { + sendExecClientMessage( + h2Request, + execMsg, + "mcpAllowlistPrecheckResult", + create(McpAllowlistPrecheckResultSchema, { allowlisted: false }), + ); + return; + } + case "webFetchAllowlistPrecheckArgs": { + sendExecClientMessage( + h2Request, + execMsg, + "webFetchAllowlistPrecheckResult", + create(WebFetchAllowlistPrecheckResultSchema, { allowlisted: false }), + ); + return; + } + case "conversationSearchArgs": { + // Cursor conversation history lives server-side; this client keeps no + // local index of it to search. + // + // The streamed `search_conversations_tool_call` envelope announces this + // call but the interaction decoder builds no block for it, so the block + // and its paired result are synthesized here — exactly like every other + // exec frame. Without the pair, `buildSessionContext` strips the whole + // interaction on replay. The frame carries its own `tool_call_id`, so + // the streamed announcement and this block agree on the key. + const args = execMsg.message.value; + const toolCallId = args.toolCallId || crypto.randomUUID(); + const error = `Conversation search is ${NOT_IMPLEMENTED_SUFFIX}`; + synthesizeCursorExecToolCall(output, stream, state, toolCallId, "search_conversations", { + query: args.query, + limit: args.limit, + }); + await pairSynthesizedExecResult(state, onToolResult, toolCallId, "search_conversations", error); + const execResult = create(ConversationSearchResultSchema, { + result: { case: "error", value: create(ConversationSearchErrorSchema, { error }) }, + }); + sendExecClientMessage(h2Request, execMsg, "conversationSearchResult", execResult); + return; + } + case "agentStoreConflictArgs": { + // The agent store is Cursor's own on-disk journal; this client never + // writes one, so it has no conflict events to replay. + const execResult = create(AgentStoreConflictResultSchema, { + result: { + case: "error", + value: create(AgentStoreConflictErrorSchema, { + error: `Agent store conflicts are ${NOT_IMPLEMENTED_SUFFIX}`, + }), + }, + }); + sendExecClientMessage(h2Request, execMsg, "agentStoreConflictResult", execResult); + return; + } + case "gitDiffRequest": { + // `GetDiffResponse` has no error variant: it models five output formats + // plus before/after file contents and nothing else. Any in-band answer is + // therefore a claim that a diff was computed, so a `throw` is the only + // truthful reply. + sendExecClientThrow(h2Request, execMsg, `Git diff is ${NOT_IMPLEMENTED_SUFFIX}`, "exec_variant_unsupported"); + return; + } default: { + // A frame number this build recognises structurally but has no answer + // for. Distinct from the unset-case path above: there the client cannot + // even name the frame. log("warn", "unhandledExecMessage", { execCase }); - // Send a bare ExecClientMessage (id + execId only, no typed result) so the - // server gets an acknowledgement and doesn't hang waiting forever. - const ack = create(ExecClientMessageSchema, { - id: execMsg.id, - execId: execMsg.execId, - }); - const clientMessage = create(AgentClientMessageSchema, { - message: { case: "execClientMessage", value: ack }, - }); - h2Request.write(frameConnectMessage(toBinary(AgentClientMessageSchema, clientMessage))); + sendExecClientThrow( + h2Request, + execMsg, + `No handler for exec message of type ${execCase}`, + "exec_variant_unsupported", + ); } } } -function sendExecClientMessage( +/** + * Send one typed answer on the exec channel. + * + * `ExecClientMessage["message"]` is a discriminated union pairing each case + * with its own result type, so the generic is keyed on the case: passing a + * `ReadResult` under `"shellResult"` is a compile error rather than a wire + * message the server rejects at runtime. + */ +function sendExecClientMessage>( h2Request: http2.ClientHttp2Stream, execMsg: ExecServerMessage, - messageCase: ExecClientMessage["message"]["case"], - value: T, + messageCase: TCase, + value: Extract["value"], ): void { const execClientMessage = create(ExecClientMessageSchema, { id: execMsg.id, execId: execMsg.execId, - message: { - case: messageCase, - value: value as any, - }, + message: { case: messageCase, value } as ExecClientMessage["message"], }); const clientMessage = create(AgentClientMessageSchema, { @@ -1509,6 +1942,42 @@ function sendExecClientMessage( log("execClientMessage", messageCase, value); } +/** + * Fail one exec frame in band. + * + * `ExecClientThrow` is the protocol's failure channel for a frame that cannot + * be answered at all — as opposed to a frame answered with its own typed error + * variant, which means "the tool ran and failed". Cursor's own executor sends + * exactly this for a frame no handler claims + * (`agent-exec/dist/index.js`: `No handler found for server message of type …` + * → `case: 'throw'` then `streamClose`), so the server already knows how to + * recover from it: it surfaces the error to the model instead of blocking on a + * reply that never comes. + * + * The alternative this replaces — writing an `ExecClientMessage` whose `message` + * oneof is unset — is not a valid answer: the server sees a reply carrying no + * result and cannot tell it apart from a malformed frame. + */ +function sendExecClientThrow( + h2Request: http2.ClientHttp2Stream, + execMsg: ExecServerMessage, + error: string, + errorCode?: string, +): void { + const controlMessage = create(ExecClientControlMessageSchema, { + message: { + case: "throw", + value: create(ExecClientThrowSchema, { id: execMsg.id, error, errorCode }), + }, + }); + const clientMessage = create(AgentClientMessageSchema, { + message: { case: "execClientControlMessage", value: controlMessage }, + }); + h2Request.write(frameConnectMessage(toBinary(AgentClientMessageSchema, clientMessage))); + log("execClientControl", "throw", { id: execMsg.id, execId: execMsg.execId, error, errorCode }); + sendExecClientStreamClose(h2Request, execMsg); +} + function sendExecClientStreamClose(h2Request: http2.ClientHttp2Stream, execMsg: ExecServerMessage): void { const closeMessage = create(ExecClientControlMessageSchema, { message: { @@ -2304,6 +2773,146 @@ function selectMcpCall(toolCall: CursorMcpToolCallCarrier | undefined): CursorMc return toolCall?.mcpToolCall; } +/** + * The streamed `ToolCall` variants whose block the exec channel owns. + * + * Each of these is announced on the interaction stream AND dispatched as its + * own `ExecServerMessage` frame (45-51), so the block is synthesized once — by + * the exec handler, which is the side that has the result. + * + * `connect_scm` is deliberately NOT here: `ExecServerMessage` has no + * connect-SCM case at all (field 44 is `git_diff_request`), so nothing on the + * exec channel ever answers it and the streamed announcement is the only + * signal. `search_conversations` is not here either: frame 53 answers it, but + * it carries its own `tool_call_id` on the streamed envelope and pairs there, + * so the exec branch does not synthesize a block for it. + */ +const EXEC_OWNED_TOOL_CALL_CASES: ReadonlySet = new Set([ + "piReadToolCall", + "piBashToolCall", + "piEditToolCall", + "piWriteToolCall", + "piGrepToolCall", + "piFindToolCall", + "piLsToolCall", +]); + +function isExecOwnedToolCall(toolCall: { tool?: { case?: string } } | undefined): boolean { + const variant = toolCall?.tool?.case; + return variant !== undefined && EXEC_OWNED_TOOL_CALL_CASES.has(variant); +} + +/** + * Retain a freshly opened streamed tool-call block. + * + * Keyed by the interaction envelope's `call_id`, which is the only key every + * `ToolCall*Update` for that call shares. The block's own `id` is deliberately + * not the key: MCP, Pi and connect-SCM blocks are filed under the id carried + * inside the call's `args`, because that is what the exec channel pairs its + * result under and what the transcript files the visible block under. + * + * `currentToolCall` is still set, as the fallback for frames that carry no + * `call_id` (proto3-optional, and unset on what older builds send). + */ +function retainStreamedCall(state: BlockState, block: ToolCallState, envelopeId: string | undefined): void { + if (envelopeId) state.openToolCalls.set(envelopeId, block); + state.setToolCall(block); +} + +/** + * The open block a streamed update addresses, or `null` to ignore the update. + * + * Cursor interleaves calls: `start A, start B, complete A` is legal, so the + * update must reach block A even though B opened last. An id naming no open + * block is ignored rather than misapplied — settling the wrong block would pair + * it with another call's result. + * + * A missing id falls back to the current block: the correlation key is + * optional, and dropping those updates would strand a block stamped + * {@link kCursorExecResolved}, which nothing else settles and whose whole + * interaction is then stripped from every rebuilt transcript. + */ +function resolveStreamedCall(state: BlockState, envelopeId: string | undefined): ToolCallState | null { + if (!envelopeId) return state.currentToolCall; + const keyed = state.openToolCalls.get(envelopeId); + if (keyed) return keyed; + // Blocks opened before this build tracked envelope ids, and blocks opened + // from a frame that carried none, are only reachable as `currentToolCall`. + const current = state.currentToolCall; + return current && current[kStreamingEnvelopeId] === undefined ? current : null; +} + +/** Release a settled block from both the keyed map and the current slot. */ +function releaseStreamedCall(state: BlockState, block: ToolCallState): void { + const envelopeId = block[kStreamingEnvelopeId]; + if (envelopeId) state.openToolCalls.delete(envelopeId); + if (state.currentToolCall === block) state.setToolCall(null); +} + +interface CursorConnectScmRepository { + owner?: string; + repo?: string; +} + +interface CursorConnectScmCall { + args?: { + toolCallId?: string; + /** `ConnectScmArgs.target` oneof; `github` is its only member today. */ + target?: { case?: string; value?: { repository?: CursorConnectScmRepository } }; + github?: { repository?: CursorConnectScmRepository }; + }; + /** `ConnectScmResult.result` oneof: `success` | `error` | `rejected`. */ + result?: { result?: { case?: string; value?: { error?: string; reason?: string } } }; +} + +interface CursorConnectScmCarrier { + tool?: { case?: string; value?: unknown }; + connectScmToolCall?: CursorConnectScmCall; +} + +/** + * The streamed `connect_scm_tool_call` variant, if this update carries one. + * + * Same oneof-vs-flattened handling as {@link selectMcpCall}: a wire-decoded + * `ToolCall` exposes its variant as `{ case, value }`, while hand-shaped test + * fixtures use the flat property. + */ +function selectConnectScmCall(toolCall: CursorConnectScmCarrier | undefined): CursorConnectScmCall | undefined { + const oneof = toolCall?.tool; + if (oneof?.case === "connectScmToolCall") return oneof.value as CursorConnectScmCall; + return toolCall?.connectScmToolCall; +} + +/** The repository a connect-SCM call targets, across the `target` oneof. */ +function selectConnectScmRepository(call: CursorConnectScmCall | undefined): CursorConnectScmRepository | undefined { + const target = call?.args?.target; + if (target?.case === "github") return target.value?.repository; + return call?.args?.github?.repository; +} + +/** + * Render a settled `ConnectScmResult` as the text of its paired tool result. + * + * Returns `isError` because the three outcomes are not interchangeable: only + * `success` means the repository was connected, and reporting a rejection as + * success would tell the model to proceed against a repo it cannot reach. + */ +function describeConnectScmResult(call: CursorConnectScmCall | undefined): { text: string; isError: boolean } { + const result = call?.result?.result; + switch (result?.case) { + case "success": + return { text: "SCM connected", isError: false }; + case "error": + return { text: result.value?.error || "SCM connection failed", isError: true }; + case "rejected": + return { text: result.value?.reason || "SCM connection rejected", isError: true }; + default: + // A completion carrying no result settles the block anyway: it is + // stamped resolved, so nothing downstream would ever pair it. + return { text: "SCM connection reported no result", isError: true }; + } +} + /** * Extract the authoritative full todo list from a completed native todo call. * @@ -2637,6 +3246,37 @@ export function synthesizeCursorExecToolCall( stream.push({ type: "toolcall_end", contentIndex: idx, toolCall: block, partial: output }); } +/** + * Pair a `toolResult` for a synthesized block the client answered itself, + * without ever consulting a handler. + * + * {@link resolveExecHandler} does this for every frame backed by a local tool. + * Frames answered from a fixed verdict — no handler, no local execution — still + * need the pair for the same reason: the block was stamped + * {@link kCursorExecResolved}, so `agent-loop.ts` emits no placeholder for it + * and `buildSessionContext` strips an unpaired call, taking the whole + * interaction out of every rebuilt transcript. + */ +async function pairSynthesizedExecResult( + state: BlockState, + onToolResult: CursorToolResultHandler | undefined, + toolCallId: string, + toolName: string, + text: string, +): Promise { + const synthesized: ToolResultMessage = { + role: "toolResult", + toolCallId, + toolName, + content: [{ type: "text", text }], + isError: true, + timestamp: Date.now(), + }; + const sink = onToolResult ?? state.onToolResult; + if (!sink) return; + await sink(synthesized); +} + /** Exported for tests: drives one Cursor interaction update through the streaming state machine. */ export function processInteractionUpdate( update: any, @@ -2683,6 +3323,43 @@ export function processInteractionUpdate( stream.push({ type: "thinking_delta", contentIndex: idx, delta, partial: output }); } else if (updateCase === "thinkingCompleted") { endCurrentThinkingBlock(output, stream, state); + } else if (updateCase === "toolCallStarted" && selectConnectScmCall(update.message.value.toolCall)) { + // `connect_scm` is resolved entirely server-side and has NO exec frame: + // `ExecServerMessage` carries no connect-SCM case (field 44 is + // `git_diff_request`), so the streamed pair is the only signal this client + // sees. The authoritative outcome rides on the COMPLETION's `result` + // oneof, so the block is opened here and settled there — answering now + // would persist a verdict before the server has given one. + // + // Stamped resolved so `agent-loop.ts` runs no local tool for it: there is + // no local `connect_scm`, and the completion pairs the result itself. + endCurrentTextBlock(output, stream, state); + endCurrentThinkingBlock(output, stream, state); + const scmCall = selectConnectScmCall(update.message.value.toolCall); + const repository = selectConnectScmRepository(scmCall); + const block: ToolCallState = { + type: "toolCall", + id: scmCall?.args?.toolCallId || update.message.value.callId || crypto.randomUUID(), + name: "connect_scm", + arguments: repository ? { owner: repository.owner, repo: repository.repo } : {}, + [kStreamingBlockIndex]: output.content.length, + [kStreamingBlockKind]: "connect-scm", + [kStreamingEnvelopeId]: update.message.value.callId || undefined, + [kCursorExecResolved]: true, + }; + output.content.push(block); + retainStreamedCall(state, block, update.message.value.callId); + stream.push({ type: "toolcall_start", contentIndex: output.content.length - 1, partial: output }); + } else if (updateCase === "toolCallStarted" && isExecOwnedToolCall(update.message.value.toolCall)) { + // The exec channel already synthesized this block (and marked it resolved) + // when it ran the tool locally, so the streamed announcement must not + // create a second one. Modern builds stream a `pi_*_tool_call` envelope + // alongside every `ExecServerMessage` 45-51 frame; before this branch the + // duplicate was avoided only because the decoder recognised neither, which + // would silently start double-rendering the moment a variant was added. + endCurrentTextBlock(output, stream, state); + endCurrentThinkingBlock(output, stream, state); + log("exec", "streamedToolCallOwnedByExec", { case: update.message.value.toolCall?.tool?.case }); } else if (updateCase === "toolCallStarted") { endCurrentTextBlock(output, stream, state); endCurrentThinkingBlock(output, stream, state); @@ -2707,12 +3384,13 @@ export function processInteractionUpdate( [kStreamingBlockIndex]: output.content.length, [kStreamingPartialJson]: "", [kStreamingBlockKind]: "mcp", + [kStreamingEnvelopeId]: update.message.value.callId || undefined, }; if (resolvedByExec) { markCursorExecResolved(block); } output.content.push(block); - state.setToolCall(block); + retainStreamedCall(state, block, update.message.value.callId); stream.push({ type: "toolcall_start", contentIndex: output.content.length - 1, partial: output }); return; } @@ -2733,54 +3411,92 @@ export function processInteractionUpdate( arguments: buildTodoDisplayArgs(toolCall), [kStreamingBlockIndex]: output.content.length, [kStreamingBlockKind]: "todo", + // Only the real envelope id is a correlation key; the minted + // fallback below names no frame the server will ever send back. + [kStreamingEnvelopeId]: update.message.value.callId || undefined, [kCursorExecResolved]: true, }; output.content.push(block); - state.setToolCall(block); + retainStreamedCall(state, block, update.message.value.callId); stream.push({ type: "toolcall_start", contentIndex: output.content.length - 1, partial: output }); } } } else if (updateCase === "toolCallDelta" || updateCase === "partialToolCall") { - if (state.currentToolCall?.[kStreamingBlockKind] === "mcp") { + // Same correlation rule as the completion path below: an argument delta + // belonging to a different call must not be appended to this block's + // buffer, which would corrupt the JSON both of them parse. + const target = resolveStreamedCall(state, update.message.value.callId); + if (target?.[kStreamingBlockKind] === "mcp") { // Cursor's `args_text_delta` is "aggregated args text so far" per agent.proto: each // delta is a cumulative snapshot of the JSON-text args. Strip the prefix we already // have to recover the new suffix; fall back to treating the value as an incremental // fragment when it doesn't extend the buffer. const snapshot: string = update.message.value.argsTextDelta || ""; - const current = state.currentToolCall[kStreamingPartialJson] ?? ""; + const current = target[kStreamingPartialJson] ?? ""; const chunk = snapshot.startsWith(current) ? snapshot.slice(current.length) : snapshot; if (chunk.length === 0) { return; } const nextBuffer = current + chunk; - state.currentToolCall[kStreamingPartialJson] = nextBuffer; + target[kStreamingPartialJson] = nextBuffer; // Throttle mid-stream parses to keep total parse work O(N) instead of O(N²) // in the argument-buffer length; the authoritative full parse runs in // `toolCallCompleted` (mcp branch) and the fallback end-of-stream path. - const throttled = parseStreamingJsonThrottled(nextBuffer, state.currentToolCall[kStreamingLastParseLen] ?? 0); + const throttled = parseStreamingJsonThrottled(nextBuffer, target[kStreamingLastParseLen] ?? 0); if (throttled) { - state.currentToolCall.arguments = throttled.value; - state.currentToolCall[kStreamingLastParseLen] = throttled.parsedLen; + target.arguments = throttled.value; + target[kStreamingLastParseLen] = throttled.parsedLen; } - const idx = output.content.indexOf(state.currentToolCall); + const idx = output.content.indexOf(target); stream.push({ type: "toolcall_delta", contentIndex: idx, delta: chunk, partial: output }); } } else if (updateCase === "toolCallCompleted") { - if (state.currentToolCall) { + // Correlate on the envelope's `call_id`, NOT the block id: MCP, Pi and SCM + // blocks are filed under the id inside the call's `args` (which is what + // the exec channel pairs its result under), and that need not equal the + // envelope id. Cursor also interleaves calls, so the block this settles + // is looked up by id rather than assumed to be the last one opened — + // otherwise an unrelated completion closes whichever block is current and + // pairs it with the wrong result. + const settled = resolveStreamedCall(state, update.message.value.callId); + if (settled) { const toolCall = update.message.value.toolCall; - if (state.currentToolCall[kStreamingBlockKind] === "mcp") { + if (settled[kStreamingBlockKind] === "mcp") { // Authoritative full parse of the accumulated argument buffer; the delta // path throttles mid-stream parses, so `arguments` may lag the buffer. - const partial = state.currentToolCall[kStreamingPartialJson]; + const partial = settled[kStreamingPartialJson]; if (partial !== undefined) { - state.currentToolCall.arguments = parseStreamingJson(partial); + settled.arguments = parseStreamingJson(partial); } const decodedArgs = decodeMcpArgsMap(selectMcpCall(toolCall)?.args?.args); - state.currentToolCall.arguments = mergeCursorMcpToolCallArgs( - state.currentToolCall.arguments as Record | undefined, + settled.arguments = mergeCursorMcpToolCallArgs( + settled.arguments as Record | undefined, decodedArgs, ); - } else if (state.currentToolCall[kStreamingBlockKind] === "todo") { + } else if (settled[kStreamingBlockKind] === "connect-scm") { + // The authoritative outcome arrives only here, on the completion's + // `ConnectScmResult` oneof. The block was stamped resolved at start, + // so nothing downstream pairs it: settling is this branch's job, and + // a completion with no `toolCall` still settles rather than leaking a + // dangling call into every rebuilt transcript. + // + // Late args are merged too — a start frame may announce the call + // before the target repository is known. + const scmCall = selectConnectScmCall(toolCall); + const repository = selectConnectScmRepository(scmCall); + if (repository) { + settled.arguments = { owner: repository.owner, repo: repository.repo }; + } + const { text, isError } = describeConnectScmResult(scmCall); + state.onToolResult?.({ + role: "toolResult", + toolCallId: settled.id, + toolName: "connect_scm", + content: [{ type: "text", text }], + isError, + timestamp: Date.now(), + }); + } else if (settled[kStreamingBlockKind] === "todo") { // Only the server's success snapshot is authoritative: the request args // may differ from what was actually stored after a merge, and on // `UpdateTodosError` nothing was stored at all. No snapshot => leave @@ -2794,7 +3510,7 @@ export function processInteractionUpdate( const snapshot = toolCall ? extractTodoSnapshot(toolCall) : null; const error = toolCall ? extractTodoError(toolCall) : null; if (snapshot) { - state.currentToolCall.arguments = { todos: snapshot.todos, merged: snapshot.merged }; + settled.arguments = { todos: snapshot.todos, merged: snapshot.merged }; } // The host settles EVERY completed native todo call, successful or // not: the interactive card only resolves on a matching @@ -2810,7 +3526,7 @@ export function processInteractionUpdate( let persisted: ToolResultMessage | undefined; let hostError: string | null = null; try { - persisted = state.onTodoSnapshot?.(snapshot, state.currentToolCall.id, error) ?? undefined; + persisted = state.onTodoSnapshot?.(snapshot, settled.id, error) ?? undefined; } catch (callbackError) { // A throwing host callback (e.g. session persistence failing on // disk error) must not leave the resolved block unpaired: the @@ -2820,14 +3536,12 @@ export function processInteractionUpdate( hostError = callbackError instanceof Error ? callbackError.message : String(callbackError); log("error", "onTodoSnapshot", { error: hostError }); } - state.onToolResult?.( - persisted ?? buildTodoToolResult(state.currentToolCall.id, snapshot, hostError ?? error), - ); + state.onToolResult?.(persisted ?? buildTodoToolResult(settled.id, snapshot, hostError ?? error)); } - const idx = output.content.indexOf(state.currentToolCall); - clearStreamingPartialJson(state.currentToolCall); - stream.push({ type: "toolcall_end", contentIndex: idx, toolCall: state.currentToolCall, partial: output }); - state.setToolCall(null); + const idx = output.content.indexOf(settled); + clearStreamingPartialJson(settled); + stream.push({ type: "toolcall_end", contentIndex: idx, toolCall: settled, partial: output }); + releaseStreamedCall(state, settled); } } else if (updateCase === "turnEnded") { output.stopReason = "stop"; @@ -2877,7 +3591,18 @@ function readCursorBlob(blobStore: Map, blobId: Uint8Array): return data; } -const CURSOR_NATIVE_TOOL_NAMES = new Set(["bash", "read", "write", "delete", "ls", "grep", "lsp", "todo"]); +/** + * Local tools Cursor already drives natively over the exec channel, so + * advertising them again as MCP tools would give the model two ways to call the + * same thing. + * + * `lsp` is deliberately NOT here. The native `diagnosticsArgs` frame covers + * exactly one of the tool's actions (`action: "diagnostics"`); the rest — + * `definition`, `references`, `rename`, `code_actions`, `hover`, + * `implementation`, `type_definition`, `symbols`, ... — have no native frame at + * all, so filtering the whole tool out hid every one of them from the model. + */ +const CURSOR_NATIVE_TOOL_NAMES = new Set(["bash", "read", "write", "delete", "ls", "grep", "todo"]); export function buildMcpToolDefinitions(tools: Tool[] | undefined): McpToolDefinition[] { if (!tools || tools.length === 0) { diff --git a/packages/ai/src/providers/cursor/exec-modern.ts b/packages/ai/src/providers/cursor/exec-modern.ts new file mode 100644 index 000000000..bd8d96254 --- /dev/null +++ b/packages/ai/src/providers/cursor/exec-modern.ts @@ -0,0 +1,393 @@ +/** + * Proto builders for the modern Cursor CLI exec frames (`ExecServerMessage` + * 27-31, 36-38, 40-55). + * + * Split out of `cursor.ts` because these are pure `create(...)` shapes with no + * transport, stream, or block-state coupling: the dispatcher decides *which* + * answer a frame gets, this module knows *what* that answer looks like on the + * wire. Every builder returns a result whose oneof case is set — an + * `ExecClientMessage` carrying a result with an unset oneof is a fake success + * the server reads as "the tool ran and produced nothing". + */ + +import { create } from "@bufbuild/protobuf"; +import { + AfterAgentResponseRequestResponseSchema, + AfterAgentThoughtRequestResponseSchema, + BeforeSubmitPromptRequestResponseSchema, + type ExecuteHookRequest, + type ExecuteHookResponse, + ExecuteHookResponseSchema, + type ExecuteHookResult, + ExecuteHookResultSchema, + type McpStateExecResult, + McpStateExecResultSchema, + McpStateServerSchema, + McpStateSuccessSchema, + type McpToolDefinition, + PiBashExecErrorSchema, + type PiBashExecResult, + PiBashExecResultSchema, + PiBashExecSuccessSchema, + PiEditExecErrorSchema, + type PiEditExecResult, + PiEditExecResultSchema, + PiEditExecSuccessSchema, + PiFindExecErrorSchema, + type PiFindExecResult, + PiFindExecResultSchema, + PiFindExecSuccessSchema, + PiGrepExecErrorSchema, + type PiGrepExecResult, + PiGrepExecResultSchema, + PiGrepExecSuccessSchema, + PiLsExecErrorSchema, + type PiLsExecResult, + PiLsExecResultSchema, + PiLsExecSuccessSchema, + PiReadExecErrorSchema, + type PiReadExecResult, + PiReadExecResultSchema, + PiReadExecSuccessSchema, + type PiTruncation, + PiTruncationSchema, + PiWriteExecErrorSchema, + type PiWriteExecResult, + PiWriteExecResultSchema, + PiWriteExecSuccessSchema, + PostToolUseFailureRequestResponseSchema, + PostToolUseRequestResponseSchema, + PreCompactRequestResponseSchema, + PreToolUseRequestResponseSchema, + StopRequestResponseSchema, + SubagentStartRequestResponseSchema, + SubagentStopRequestResponseSchema, +} from "@oh-my-pi/pi-catalog/discovery/cursor-gen/agent_pb"; +import type { ToolResultMessage } from "../../types"; + +/** Flatten a tool result's content into the single `output` string the Pi frames carry. */ +export function piOutputText(toolResult: ToolResultMessage): string { + return toolResult.content.map(item => (item.type === "text" ? item.text : `[${item.mimeType} image]`)).join("\n"); +} + +/** + * Read one field off a tool result's `details` bag, or off a nested object + * inside it. + * + * `details` is `unknown` by design — every tool ships its own shape — so each + * read is narrowed rather than asserted, and the caller decides what a value of + * the wrong type means. + */ +function bagValue(bag: unknown, key: string): unknown { + if (!bag || typeof bag !== "object" || !(key in bag)) return undefined; + return Reflect.get(bag, key); +} + +/** + * A positive integer count from `details`, or `undefined`. + * + * The Pi frames model their limit counters as `optional uint32`: zero means + * "the limit was reached at zero results", so a missing, non-numeric, or + * non-positive value must stay unset rather than be sent as 0. + */ +function detailCount(toolResult: ToolResultMessage, key: string): number | undefined { + const value = bagValue(toolResult.details, key); + return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : undefined; +} + +/** + * Translate a local tool's truncation summary + * (`coding-agent/src/session/streaming-output.ts:TruncationResult`) into + * `PiTruncation`. + * + * Returns `undefined` when nothing was truncated: the field is `optional` on + * every Pi success message, and emitting a zeroed `PiTruncation` would tell the + * server the output was trimmed to nothing. + */ +export function piTruncation(toolResult: ToolResultMessage): PiTruncation | undefined { + const truncation = bagValue(toolResult.details, "truncation"); + if (bagValue(truncation, "truncated") !== true) return undefined; + const truncatedBy = bagValue(truncation, "truncatedBy"); + const totalLines = bagValue(truncation, "totalLines"); + const outputLines = bagValue(truncation, "outputLines"); + const outputBytes = bagValue(truncation, "outputBytes"); + return create(PiTruncationSchema, { + truncated: true, + truncatedBy: typeof truncatedBy === "string" ? truncatedBy : "", + totalLines: typeof totalLines === "number" ? totalLines : 0, + outputLines: typeof outputLines === "number" ? outputLines : 0, + outputBytes: typeof outputBytes === "number" ? outputBytes : 0, + firstLineExceedsLimit: bagValue(truncation, "firstLineExceedsLimit") === true, + lastLinePartial: bagValue(truncation, "lastLinePartial") === true, + }); +} + +export function buildPiReadResult(toolResult: ToolResultMessage): PiReadExecResult { + const text = piOutputText(toolResult); + if (toolResult.isError) return buildPiReadError(text || "Read failed"); + return create(PiReadExecResultSchema, { + result: { + case: "success", + value: create(PiReadExecSuccessSchema, { output: text, truncation: piTruncation(toolResult) }), + }, + }); +} + +export function buildPiReadError(error: string): PiReadExecResult { + return create(PiReadExecResultSchema, { + result: { case: "error", value: create(PiReadExecErrorSchema, { error }) }, + }); +} + +export function buildPiBashResult(toolResult: ToolResultMessage): PiBashExecResult { + const text = piOutputText(toolResult); + const truncation = piTruncation(toolResult); + if (toolResult.isError) { + return create(PiBashExecResultSchema, { + result: { + case: "error", + value: create(PiBashExecErrorSchema, { error: text || "Command failed", truncation }), + }, + }); + } + return create(PiBashExecResultSchema, { + result: { + case: "success", + value: create(PiBashExecSuccessSchema, { output: text, truncation }), + }, + }); +} + +export function buildPiBashError(error: string): PiBashExecResult { + return create(PiBashExecResultSchema, { + result: { case: "error", value: create(PiBashExecErrorSchema, { error }) }, + }); +} + +/** + * `PiEditExecSuccess` requires `diff` and `patch` alongside `output`. The local + * `edit` tool reports them under `details`; when it does not, the strings stay + * empty rather than being faked from the output text. + */ +export function buildPiEditResult(toolResult: ToolResultMessage): PiEditExecResult { + const text = piOutputText(toolResult); + if (toolResult.isError) return buildPiEditError(text || "Edit failed"); + const diff = bagValue(toolResult.details, "diff"); + const patch = bagValue(toolResult.details, "patch"); + return create(PiEditExecResultSchema, { + result: { + case: "success", + value: create(PiEditExecSuccessSchema, { + output: text, + diff: typeof diff === "string" ? diff : "", + patch: typeof patch === "string" ? patch : "", + firstChangedLine: detailCount(toolResult, "firstChangedLine"), + }), + }, + }); +} + +export function buildPiEditError(error: string): PiEditExecResult { + return create(PiEditExecResultSchema, { + result: { case: "error", value: create(PiEditExecErrorSchema, { error }) }, + }); +} + +export function buildPiWriteResult(toolResult: ToolResultMessage): PiWriteExecResult { + const text = piOutputText(toolResult); + if (toolResult.isError) return buildPiWriteError(text || "Write failed"); + return create(PiWriteExecResultSchema, { + result: { case: "success", value: create(PiWriteExecSuccessSchema, { output: text }) }, + }); +} + +export function buildPiWriteError(error: string): PiWriteExecResult { + return create(PiWriteExecResultSchema, { + result: { case: "error", value: create(PiWriteExecErrorSchema, { error }) }, + }); +} + +export function buildPiGrepResult(toolResult: ToolResultMessage): PiGrepExecResult { + const text = piOutputText(toolResult); + if (toolResult.isError) return buildPiGrepError(text || "Grep failed"); + return create(PiGrepExecResultSchema, { + result: { + case: "success", + value: create(PiGrepExecSuccessSchema, { + output: text, + truncation: piTruncation(toolResult), + matchLimitReached: detailCount(toolResult, "perFileLimitReached"), + linesTruncated: bagValue(toolResult.details, "linesTruncated") === true, + }), + }, + }); +} + +export function buildPiGrepError(error: string): PiGrepExecResult { + return create(PiGrepExecResultSchema, { + result: { case: "error", value: create(PiGrepExecErrorSchema, { error }) }, + }); +} + +export function buildPiFindResult(toolResult: ToolResultMessage): PiFindExecResult { + const text = piOutputText(toolResult); + if (toolResult.isError) return buildPiFindError(text || "Find failed"); + return create(PiFindExecResultSchema, { + result: { + case: "success", + value: create(PiFindExecSuccessSchema, { + output: text, + truncation: piTruncation(toolResult), + resultLimitReached: detailCount(toolResult, "resultLimitReached"), + }), + }, + }); +} + +export function buildPiFindError(error: string): PiFindExecResult { + return create(PiFindExecResultSchema, { + result: { case: "error", value: create(PiFindExecErrorSchema, { error }) }, + }); +} + +export function buildPiLsResult(toolResult: ToolResultMessage): PiLsExecResult { + const text = piOutputText(toolResult); + if (toolResult.isError) return buildPiLsError(text || "Ls failed"); + return create(PiLsExecResultSchema, { + result: { + case: "success", + value: create(PiLsExecSuccessSchema, { + output: text, + truncation: piTruncation(toolResult), + entryLimitReached: detailCount(toolResult, "resultLimitReached"), + }), + }, + }); +} + +export function buildPiLsError(error: string): PiLsExecResult { + return create(PiLsExecResultSchema, { + result: { case: "error", value: create(PiLsExecErrorSchema, { error }) }, + }); +} + +/** + * Answer `mcpStateExecArgs` (frame 36) from the catalog already advertised in + * `RequestContext.tools`. + * + * This client hosts no MCP servers of its own: every forwarded tool is a local + * pi-agent tool published under a synthetic `providerIdentifier`. Regrouping + * the same list keeps the server's view of "which servers exist and what do + * they expose" consistent with what it was told at context time, instead of + * claiming zero servers while tool calls for them keep arriving. + * + * `serverIdentifiers` filters the answer when the server asks about specific + * servers. `kickOnly` is a restart request — there is nothing to restart, so it + * is answered with the same state rather than an error. + */ +export function buildMcpStateResult( + tools: McpToolDefinition[], + serverIdentifiers: readonly string[], +): McpStateExecResult { + const byProvider = new Map(); + for (const tool of tools) { + const identifier = tool.providerIdentifier; + const existing = byProvider.get(identifier); + if (existing) existing.push(tool); + else byProvider.set(identifier, [tool]); + } + + const wanted = serverIdentifiers.length > 0 ? new Set(serverIdentifiers) : undefined; + const servers = []; + for (const [identifier, serverTools] of byProvider) { + if (wanted && !wanted.has(identifier)) continue; + servers.push( + create(McpStateServerSchema, { + serverName: identifier, + serverIdentifier: identifier, + tools: serverTools, + status: "connected", + }), + ); + } + + return create(McpStateExecResultSchema, { + result: { case: "success", value: create(McpStateSuccessSchema, { servers }) }, + }); +} + +/** + * Build the neutral response for a hook query: the matching response case with + * every field unset. + * + * This client runs no Cursor hooks, and every field of every response variant + * is `optional` — so an empty response of the right case means "no hook had + * anything to say", which is exactly true. It is NOT the unset-oneof fake + * success: the case itself is set, only the payload is empty. + * + * `ExecuteHookRequest` and `ExecuteHookResponse` are parallel oneofs whose case + * names line up, but the two unions are unrelated to the compiler: a `switch` + * is what makes each pairing individually type-checked, and it forces a + * deliberate branch when a future regen adds a request case. + * + * Returns `null` for a request case this build does not model, which the + * dispatcher answers with `ExecClientThrow` rather than guessing a case. + */ +export function buildNeutralHookResult(request: ExecuteHookRequest | undefined): ExecuteHookResult | null { + let response: ExecuteHookResponse; + switch (request?.request.case) { + case "preCompact": + response = create(ExecuteHookResponseSchema, { + response: { case: "preCompact", value: create(PreCompactRequestResponseSchema, {}) }, + }); + break; + case "subagentStart": + response = create(ExecuteHookResponseSchema, { + response: { case: "subagentStart", value: create(SubagentStartRequestResponseSchema, {}) }, + }); + break; + case "subagentStop": + response = create(ExecuteHookResponseSchema, { + response: { case: "subagentStop", value: create(SubagentStopRequestResponseSchema, {}) }, + }); + break; + case "preToolUse": + response = create(ExecuteHookResponseSchema, { + response: { case: "preToolUse", value: create(PreToolUseRequestResponseSchema, {}) }, + }); + break; + case "postToolUse": + response = create(ExecuteHookResponseSchema, { + response: { case: "postToolUse", value: create(PostToolUseRequestResponseSchema, {}) }, + }); + break; + case "postToolUseFailure": + response = create(ExecuteHookResponseSchema, { + response: { case: "postToolUseFailure", value: create(PostToolUseFailureRequestResponseSchema, {}) }, + }); + break; + case "beforeSubmitPrompt": + response = create(ExecuteHookResponseSchema, { + response: { case: "beforeSubmitPrompt", value: create(BeforeSubmitPromptRequestResponseSchema, {}) }, + }); + break; + case "afterAgentResponse": + response = create(ExecuteHookResponseSchema, { + response: { case: "afterAgentResponse", value: create(AfterAgentResponseRequestResponseSchema, {}) }, + }); + break; + case "afterAgentThought": + response = create(ExecuteHookResponseSchema, { + response: { case: "afterAgentThought", value: create(AfterAgentThoughtRequestResponseSchema, {}) }, + }); + break; + case "stop": + response = create(ExecuteHookResponseSchema, { + response: { case: "stop", value: create(StopRequestResponseSchema, {}) }, + }); + break; + default: + return null; + } + return create(ExecuteHookResultSchema, { response }); +} diff --git a/packages/ai/src/providers/cursor/proto/agent.proto b/packages/ai/src/providers/cursor/proto/agent.proto index 49cbb4775..47c37aeac 100644 --- a/packages/ai/src/providers/cursor/proto/agent.proto +++ b/packages/ai/src/providers/cursor/proto/agent.proto @@ -417,7 +417,21 @@ message ToolCall { TruncatedToolCall truncated_tool_call = 34; StartGrindExecutionToolCall start_grind_execution_tool_call = 35; StartGrindPlanningToolCall start_grind_planning_tool_call = 36; + PiReadToolCall pi_read_tool_call = 61; + PiBashToolCall pi_bash_tool_call = 62; + PiEditToolCall pi_edit_tool_call = 63; + PiWriteToolCall pi_write_tool_call = 64; + PiGrepToolCall pi_grep_tool_call = 65; + PiFindToolCall pi_find_tool_call = 66; + PiLsToolCall pi_ls_tool_call = 67; + ConnectScmToolCall connect_scm_tool_call = 68; + SearchConversationsToolCall search_conversations_tool_call = 69; } + // Modern builds carry the call id on the envelope instead of inside each + // variant's args. Fields 37-53, 55, 56, 58 (further tool variants) and 54 + // (hook_additional_contexts), 59/60 (started_at_ms/completed_at_ms) are not + // modelled and decode into unknown fields; do not reuse those numbers. + optional string tool_call_id = 57; } message TruncatedToolCallArgs { @@ -4426,3 +4440,94 @@ message GetDiffResponse { optional string head_sha = 4; optional bool has_uncommitted_changes = 5; } + +// ===== Pi tool calls (ToolCall 61-67) ===== +// +// The streamed `ToolCall` wrappers for the Pi exec frames. Their `args`/`result` +// payloads are field-identical to the `Pi*Exec*` messages above (verified against +// the modern CLI's `pi_*_tool_pb.js`), and the exec channel is binary protobuf, +// so field numbers — not type names — define wire compatibility. Reusing the +// exec messages keeps one shape per Pi tool instead of two that must stay in sync. + +message PiReadToolCall { + PiReadExecArgs args = 1; + PiReadExecResult result = 2; +} + +message PiBashToolCall { + PiBashExecArgs args = 1; + PiBashExecResult result = 2; +} + +message PiEditToolCall { + PiEditExecArgs args = 1; + PiEditExecResult result = 2; +} + +message PiWriteToolCall { + PiWriteExecArgs args = 1; + PiWriteExecResult result = 2; +} + +message PiGrepToolCall { + PiGrepExecArgs args = 1; + PiGrepExecResult result = 2; +} + +message PiFindToolCall { + PiFindExecArgs args = 1; + PiFindExecResult result = 2; +} + +message PiLsToolCall { + PiLsExecArgs args = 1; + PiLsExecResult result = 2; +} + +// ===== Conversation search / SCM tool calls (ToolCall 68-69) ===== + +message SearchConversationsToolCall { + ConversationSearchArgs args = 1; + ConversationSearchResult result = 2; +} + +message ConnectScmGithubRepository { + string owner = 1; + string repo = 2; +} + +message ConnectScmGithub { + ConnectScmGithubRepository repository = 1; + optional string ghe_application = 2; +} + +message ConnectScmArgs { + string tool_call_id = 1; + oneof target { + ConnectScmGithub github = 2; + } +} + +message ConnectScmSuccess { +} + +message ConnectScmError { + string error = 1; +} + +message ConnectScmRejected { + string reason = 1; +} + +message ConnectScmResult { + oneof result { + ConnectScmSuccess success = 1; + ConnectScmError error = 2; + ConnectScmRejected rejected = 3; + } +} + +message ConnectScmToolCall { + ConnectScmArgs args = 1; + ConnectScmResult result = 2; +} diff --git a/packages/ai/src/types.ts b/packages/ai/src/types.ts index 539ad2e5b..cf27c65bf 100644 --- a/packages/ai/src/types.ts +++ b/packages/ai/src/types.ts @@ -11,6 +11,20 @@ import type { LsArgs, LsResult, McpResult, + PiBashExecArgs, + PiBashExecResult, + PiEditExecArgs, + PiEditExecResult, + PiFindExecArgs, + PiFindExecResult, + PiGrepExecArgs, + PiGrepExecResult, + PiLsExecArgs, + PiLsExecResult, + PiReadExecArgs, + PiReadExecResult, + PiWriteExecArgs, + PiWriteExecResult, ReadArgs, ReadResult, ShellArgs, @@ -989,6 +1003,21 @@ export interface CursorShellStreamCallbacks { onStderr(data: string): void; } +/** + * A modern Pi exec frame plus the call id the dispatcher minted for it. + * + * Unlike the legacy exec args (`ReadArgs`, `ShellArgs`, ...), the Pi frames + * carry no `tool_call_id` field: on modern builds the id rides the streamed + * `ToolCall` envelope (`ToolCall.tool_call_id = 57`) instead of each variant's + * args. The exec channel has no access to that envelope, so the dispatcher + * mints an id and hands it to the handler, keeping the synthesized transcript + * block and its paired `toolResult` on the same key. + */ +export interface CursorPiCall { + args: TArgs; + toolCallId: string; +} + export interface CursorExecHandlers { read?: (args: ReadArgs) => Promise>; ls?: (args: LsArgs) => Promise>; @@ -1002,6 +1031,18 @@ export interface CursorExecHandlers { ) => Promise>; diagnostics?: (args: DiagnosticsArgs) => Promise>; mcp?: (call: CursorMcpCall) => Promise>; + /** + * Modern Cursor CLI Pi tool frames (`ExecServerMessage` 45-51). They are a + * distinct frame family from the legacy `readArgs`/`shellArgs`/... set, not + * an alias: different args, different result oneofs, and no `tool_call_id`. + */ + piRead?: (call: CursorPiCall) => Promise>; + piBash?: (call: CursorPiCall) => Promise>; + piEdit?: (call: CursorPiCall) => Promise>; + piWrite?: (call: CursorPiCall) => Promise>; + piGrep?: (call: CursorPiCall) => Promise>; + piFind?: (call: CursorPiCall) => Promise>; + piLs?: (call: CursorPiCall) => Promise>; /** Mirror Cursor's server-owned todo list into local session state. */ todoSync?: CursorTodoSyncHandler; onToolResult?: CursorToolResultHandler; diff --git a/packages/ai/src/utils/block-symbols.ts b/packages/ai/src/utils/block-symbols.ts index d09f8fe13..1792cdb71 100644 --- a/packages/ai/src/utils/block-symbols.ts +++ b/packages/ai/src/utils/block-symbols.ts @@ -25,6 +25,18 @@ export const kStreamingBlockIndex = Symbol("provider.block.index"); /** Stores the last parsed argument prefix length for throttled streaming JSON parsing. */ export const kStreamingLastParseLen = Symbol("provider.block.lastParseLen"); +/** + * The Cursor interaction envelope's `call_id` for a streamed tool-call block. + * + * Tracked separately from the block's own `id` because they are NOT the same + * key: MCP and Pi blocks are filed under the id inside the call's `args`, which + * is what the exec channel pairs its result under, while every streamed + * `ToolCall*Update` correlates on the envelope's `call_id`. Matching + * completions against the block id would mis-route every call whose args carry + * their own id. + */ +export const kStreamingEnvelopeId = Symbol("provider.block.envelopeId"); + /** Marks streamed tool-call arguments that already received an authoritative done payload. */ export const kStreamingArgumentsDone = Symbol("provider.block.argumentsDone"); diff --git a/packages/ai/test/cursor-exec-handlers.test.ts b/packages/ai/test/cursor-exec-handlers.test.ts index 26d4856ab..bfdc4fad3 100644 --- a/packages/ai/test/cursor-exec-handlers.test.ts +++ b/packages/ai/test/cursor-exec-handlers.test.ts @@ -689,6 +689,7 @@ function newBlockState(): BlockState { get currentToolCall() { return toolCall; }, + openToolCalls: new Map(), resolvedMcpToolCallIds: new Set(), firstTokenTime: undefined, setTextBlock: b => { diff --git a/packages/ai/test/cursor-exec-modern.test.ts b/packages/ai/test/cursor-exec-modern.test.ts new file mode 100644 index 000000000..64f3754a5 --- /dev/null +++ b/packages/ai/test/cursor-exec-modern.test.ts @@ -0,0 +1,1062 @@ +import { describe, expect, it } from "bun:test"; +import { create, fromBinary, toBinary } from "@bufbuild/protobuf"; +import { + type BlockState, + handleServerMessage, + processInteractionUpdate, + type ToolCallState, +} from "@oh-my-pi/pi-ai/providers/cursor"; +import type { AssistantMessage, CursorExecHandlers, ToolResultMessage } from "@oh-my-pi/pi-ai/types"; +import { kCursorExecResolved } from "@oh-my-pi/pi-ai/utils/block-symbols"; +import { AssistantMessageEventStream } from "@oh-my-pi/pi-ai/utils/event-stream"; +import { + type AgentClientMessage, + AgentClientMessageSchema, + AgentServerMessageSchema, + AgentStoreConflictArgsSchema, + CanvasDiagnosticsArgsSchema, + ComputerUseArgsSchema, + ConnectScmArgsSchema, + ConnectScmErrorSchema, + ConnectScmGithubRepositorySchema, + ConnectScmGithubSchema, + ConnectScmRejectedSchema, + ConnectScmResultSchema, + ConnectScmSuccessSchema, + ConnectScmToolCallSchema, + ConversationSearchArgsSchema, + type ExecServerMessage, + ExecServerMessageSchema, + ExecuteHookArgsSchema, + ExecuteHookRequestSchema, + ForceBackgroundShellArgsSchema, + ForceBackgroundShellStatus, + ForceBackgroundSubagentArgsSchema, + ForceBackgroundSubagentStatus, + GetDiffRequestSchema, + ListMcpResourcesExecArgsSchema, + McpAllowlistPrecheckArgsSchema, + McpStateExecArgsSchema, + type McpToolDefinition, + McpToolDefinitionSchema, + PiBashExecArgsSchema, + PiEditExecArgsSchema, + PiEditReplacementSchema, + PiFindExecArgsSchema, + PiGrepExecArgsSchema, + PiLsExecArgsSchema, + PiReadExecArgsSchema, + PiWriteExecArgsSchema, + PostToolUseRequestQuerySchema, + ReadArgsSchema, + ReadMcpResourceExecArgsSchema, + RecordScreenArgsSchema, + ShellAllowlistPrecheckArgsSchema, + ShellArgsSchema, + SmartModeClassifierArgsSchema, + SubagentArgsSchema, + SubagentAwaitArgsSchema, + ToolCallSchema, + WebFetchAllowlistPrecheckArgsSchema, +} from "@oh-my-pi/pi-catalog/discovery/cursor-gen/agent_pb"; + +/** + * Drive one `ExecServerMessage` through the real dispatcher and decode every + * frame it wrote back. + * + * The frames are decoded from the actual wire bytes rather than intercepted as + * objects: the whole point of these cases is what the SERVER receives, and an + * `ExecClientMessage` whose oneof never got set still looks like a populated + * object in memory. + */ +async function dispatchExec( + message: ExecServerMessage, + options: { execHandlers?: CursorExecHandlers; requestContextTools?: McpToolDefinition[] } = {}, +): Promise<{ frames: AgentClientMessage[]; output: AssistantMessage; results: ToolResultMessage[] }> { + const output = cursorAssistantMessage(); + const stream = new AssistantMessageEventStream(); + const state = newBlockState(); + const written: Buffer[] = []; + const h2Request = { + write: (chunk: Buffer) => { + written.push(chunk); + return true; + }, + } as unknown as Parameters[5]; + const results: ToolResultMessage[] = []; + + await handleServerMessage( + create(AgentServerMessageSchema, { message: { case: "execServerMessage", value: message } }), + output, + stream, + state, + new Map(), + h2Request, + options.execHandlers, + result => { + results.push(result); + return result; + }, + { sawTokenDelta: false }, + options.requestContextTools ?? [], + ); + + return { frames: written.map(decodeClientFrame), output, results }; +} + +/** Strip the 5-byte Connect envelope (flags + big-endian length) and decode. */ +function decodeClientFrame(frame: Buffer): AgentClientMessage { + const length = frame.readUInt32BE(1); + return fromBinary(AgentClientMessageSchema, frame.subarray(5, 5 + length)); +} + +function buildExecMessage(message: ExecServerMessage["message"]): ExecServerMessage { + return create(ExecServerMessageSchema, { id: 7, execId: "exec-modern", message }); +} + +function mcpTool(name: string, providerIdentifier: string) { + return create(McpToolDefinitionSchema, { name, toolName: name, providerIdentifier, description: `${name} tool` }); +} + +function cursorAssistantMessage(): AssistantMessage { + return { + role: "assistant", + content: [], + api: "cursor-agent", + provider: "cursor", + model: "cursor-composer-2.5", + usage: { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0, + totalTokens: 0, + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }, + }, + stopReason: "stop", + timestamp: 0, + }; +} + +function newBlockState(): BlockState { + let textBlock: BlockState["currentTextBlock"] = null; + let thinkingBlock: BlockState["currentThinkingBlock"] = null; + let toolCall: ToolCallState | null = null; + return { + get currentTextBlock() { + return textBlock; + }, + get currentThinkingBlock() { + return thinkingBlock; + }, + get currentToolCall() { + return toolCall; + }, + openToolCalls: new Map(), + resolvedMcpToolCallIds: new Set(), + firstTokenTime: undefined, + setTextBlock: b => { + textBlock = b; + }, + setThinkingBlock: b => { + thinkingBlock = b; + }, + setToolCall: t => { + toolCall = t; + }, + setFirstTokenTime: () => {}, + }; +} + +function toolResult(text: string, extra?: Partial): ToolResultMessage { + return { + role: "toolResult", + toolCallId: "unused", + toolName: "unused", + content: [{ type: "text", text }], + isError: false, + timestamp: 1, + ...extra, + }; +} + +/** The single `execClientMessage` a dispatch produced, or a failure if it produced anything else. */ +function soleResult(frames: AgentClientMessage[]) { + expect(frames).toHaveLength(1); + const frame = frames[0].message; + if (frame.case !== "execClientMessage") throw new Error(`expected execClientMessage, got ${frame.case}`); + return frame.value.message; +} + +describe("Cursor modern exec frames: failure channel", () => { + it("throws on a frame whose oneof this build does not model, instead of stranding the exec id", async () => { + // A oneof number absent from agent.proto decodes into unknown fields and + // leaves `message.case` unset. The old code returned silently, so the + // server waited on a reply that never arrived. + const message = create(ExecServerMessageSchema, { id: 11, execId: "exec-unknown" }); + + const { frames } = await dispatchExec(message); + + const control = frames[0].message; + expect(control.case).toBe("execClientControlMessage"); + if (control.case !== "execClientControlMessage") throw new Error("unreachable"); + expect(control.value.message.case).toBe("throw"); + if (control.value.message.case !== "throw") throw new Error("unreachable"); + expect(control.value.message.value.id).toBe(11); + expect(control.value.message.value.errorCode).toBe("unknown_exec_variant"); + + // A throw must be followed by a stream close, or the exec stays open. + const close = frames[1].message; + expect(close.case).toBe("execClientControlMessage"); + if (close.case !== "execClientControlMessage") throw new Error("unreachable"); + expect(close.value.message.case).toBe("streamClose"); + }); + + it("throws for gitDiffRequest, whose response type has no error variant", async () => { + // `GetDiffResponse` models five output formats and no failure, so any + // in-band answer claims a diff was computed. + const { frames } = await dispatchExec( + buildExecMessage({ + case: "gitDiffRequest", + value: create(GetDiffRequestSchema, { cwd: "/repo", ref: "HEAD" }), + }), + ); + + const control = frames[0].message; + if (control.case !== "execClientControlMessage") throw new Error(`got ${control.case}`); + expect(control.value.message.case).toBe("throw"); + if (control.value.message.case !== "throw") throw new Error("unreachable"); + expect(control.value.message.value.errorCode).toBe("exec_variant_unsupported"); + }); +}); + +describe("Cursor modern exec frames: no answer carries an unset oneof", () => { + // A result whose `result` oneof is unset is indistinguishable from "the tool + // ran and produced nothing". Every one of these frames was previously + // answered that way, or is newly handled and must not regress into it. + const cases: [name: string, message: ExecServerMessage, resultCase: string][] = [ + [ + "listMcpResourcesExecArgs", + buildExecMessage({ + case: "listMcpResourcesExecArgs", + value: create(ListMcpResourcesExecArgsSchema, {}), + }), + "success", + ], + [ + "readMcpResourceExecArgs", + buildExecMessage({ + case: "readMcpResourceExecArgs", + value: create(ReadMcpResourceExecArgsSchema, { uri: "file:///nope" }), + }), + "notFound", + ], + [ + "recordScreenArgs", + buildExecMessage({ case: "recordScreenArgs", value: create(RecordScreenArgsSchema, {}) }), + "failure", + ], + [ + "computerUseArgs", + buildExecMessage({ case: "computerUseArgs", value: create(ComputerUseArgsSchema, {}) }), + "error", + ], + [ + "subagentArgs", + buildExecMessage({ + case: "subagentArgs", + value: create(SubagentArgsSchema, { toolCallId: "c1", subagentType: "explore", prompt: "go" }), + }), + "error", + ], + [ + "subagentAwaitArgs", + buildExecMessage({ + case: "subagentAwaitArgs", + value: create(SubagentAwaitArgsSchema, { agentId: "agent-1", timeoutMs: 10 }), + }), + "notFound", + ], + [ + "smartModeClassifierArgs", + buildExecMessage({ + case: "smartModeClassifierArgs", + value: create(SmartModeClassifierArgsSchema, { toolCallId: "c1" }), + }), + "error", + ], + [ + "canvasDiagnosticsArgs", + buildExecMessage({ + case: "canvasDiagnosticsArgs", + value: create(CanvasDiagnosticsArgsSchema, { path: "/a.ts", toolCallId: "c1" }), + }), + "error", + ], + [ + "conversationSearchArgs", + buildExecMessage({ + case: "conversationSearchArgs", + value: create(ConversationSearchArgsSchema, { query: "chess", toolCallId: "c1" }), + }), + "error", + ], + [ + "agentStoreConflictArgs", + buildExecMessage({ + case: "agentStoreConflictArgs", + value: create(AgentStoreConflictArgsSchema, {}), + }), + "error", + ], + ]; + + for (const [name, message, resultCase] of cases) { + it(`answers ${name} with a set '${resultCase}' variant`, async () => { + const { frames } = await dispatchExec(message); + const answer = soleResult(frames); + expect(answer.case).toBeDefined(); + const value = answer.value; + expect(value).toHaveProperty("result"); + const result = (value as { result: { case?: string } }).result; + expect(result.case).toBe(resultCase); + }); + } + + it("reports the requested uri back on a not-found MCP resource read", async () => { + const { frames } = await dispatchExec( + buildExecMessage({ + case: "readMcpResourceExecArgs", + value: create(ReadMcpResourceExecArgsSchema, { uri: "mcp://server/thing" }), + }), + ); + const answer = soleResult(frames); + if (answer.case !== "readMcpResourceExecResult") throw new Error(`got ${answer.case}`); + if (answer.value.result.case !== "notFound") throw new Error("expected notFound"); + expect(answer.value.result.value.uri).toBe("mcp://server/thing"); + }); + + it("echoes the requested path on a canvas diagnostics error", async () => { + const { frames } = await dispatchExec( + buildExecMessage({ + case: "canvasDiagnosticsArgs", + value: create(CanvasDiagnosticsArgsSchema, { path: "/canvas/a.ts", toolCallId: "c1" }), + }), + ); + const answer = soleResult(frames); + if (answer.case !== "canvasDiagnosticsResult") throw new Error(`got ${answer.case}`); + if (answer.value.result.case !== "error") throw new Error("expected error"); + expect(answer.value.result.value.path).toBe("/canvas/a.ts"); + }); + + it("reports the awaited agent id back as not found", async () => { + const { frames } = await dispatchExec( + buildExecMessage({ + case: "subagentAwaitArgs", + value: create(SubagentAwaitArgsSchema, { agentId: "agent-42", timeoutMs: 5 }), + }), + ); + const answer = soleResult(frames); + if (answer.case !== "subagentAwaitResult") throw new Error(`got ${answer.case}`); + if (answer.value.result.case !== "notFound") throw new Error("expected notFound"); + expect(answer.value.result.value.agentId).toBe("agent-42"); + }); +}); + +describe("Cursor modern exec frames: status and precheck answers", () => { + it("reports NOT_FOUND for force-background requests, since nothing runs in the background", async () => { + const shell = await dispatchExec( + buildExecMessage({ + case: "forceBackgroundShellArgs", + value: create(ForceBackgroundShellArgsSchema, { toolCallId: "c1" }), + }), + ); + const shellAnswer = soleResult(shell.frames); + if (shellAnswer.case !== "forceBackgroundShellResult") throw new Error(`got ${shellAnswer.case}`); + expect(shellAnswer.value.status).toBe(ForceBackgroundShellStatus.NOT_FOUND); + + const subagent = await dispatchExec( + buildExecMessage({ + case: "forceBackgroundSubagentArgs", + value: create(ForceBackgroundSubagentArgsSchema, { toolCallId: "c1" }), + }), + ); + const subagentAnswer = soleResult(subagent.frames); + if (subagentAnswer.case !== "forceBackgroundSubagentResult") throw new Error(`got ${subagentAnswer.case}`); + expect(subagentAnswer.value.status).toBe(ForceBackgroundSubagentStatus.NOT_FOUND); + }); + + it("declines every allowlist precheck, since no allowlist is configured", async () => { + // `true` here would grant an approval bypass that was never configured. + const shell = await dispatchExec( + buildExecMessage({ + case: "shellAllowlistPrecheckArgs", + value: create(ShellAllowlistPrecheckArgsSchema, { command: "rm -rf /", workingDirectory: "/" }), + }), + ); + const shellAnswer = soleResult(shell.frames); + if (shellAnswer.case !== "shellAllowlistPrecheckResult") throw new Error(`got ${shellAnswer.case}`); + expect(shellAnswer.value.allowlisted).toBe(false); + + const mcp = await dispatchExec( + buildExecMessage({ + case: "mcpAllowlistPrecheckArgs", + value: create(McpAllowlistPrecheckArgsSchema, { providerIdentifier: "pi-agent", toolName: "task" }), + }), + ); + const mcpAnswer = soleResult(mcp.frames); + if (mcpAnswer.case !== "mcpAllowlistPrecheckResult") throw new Error(`got ${mcpAnswer.case}`); + expect(mcpAnswer.value.allowlisted).toBe(false); + + const web = await dispatchExec( + buildExecMessage({ + case: "webFetchAllowlistPrecheckArgs", + value: create(WebFetchAllowlistPrecheckArgsSchema, { url: "https://example.com" }), + }), + ); + const webAnswer = soleResult(web.frames); + if (webAnswer.case !== "webFetchAllowlistPrecheckResult") throw new Error(`got ${webAnswer.case}`); + expect(webAnswer.value.allowlisted).toBe(false); + }); +}); + +describe("Cursor modern exec frames: hooks", () => { + it("answers a hook query with the matching response case and an empty payload", async () => { + // The request and response oneofs are parallel; a response of the wrong + // case is read as a different hook entirely. + const { frames } = await dispatchExec( + buildExecMessage({ + case: "executeHookArgs", + value: create(ExecuteHookArgsSchema, { + request: create(ExecuteHookRequestSchema, { + request: { case: "postToolUse", value: create(PostToolUseRequestQuerySchema, {}) }, + }), + }), + }), + ); + + const answer = soleResult(frames); + if (answer.case !== "executeHookResult") throw new Error(`got ${answer.case}`); + expect(answer.value.response?.response.case).toBe("postToolUse"); + if (answer.value.response?.response.case !== "postToolUse") throw new Error("unreachable"); + // Every field is optional; this client runs no hooks, so it contributes none. + expect(answer.value.response.response.value.additionalContext).toBeUndefined(); + }); + + it("throws for a hook request whose case this build does not model", async () => { + const { frames } = await dispatchExec( + buildExecMessage({ + case: "executeHookArgs", + value: create(ExecuteHookArgsSchema, { request: create(ExecuteHookRequestSchema, {}) }), + }), + ); + + const control = frames[0].message; + if (control.case !== "execClientControlMessage") throw new Error(`got ${control.case}`); + expect(control.value.message.case).toBe("throw"); + if (control.value.message.case !== "throw") throw new Error("unreachable"); + expect(control.value.message.value.errorCode).toBe("unknown_hook_request"); + }); +}); + +describe("Cursor modern exec frames: MCP state", () => { + it("regroups the advertised tool catalog by provider identifier", async () => { + const { frames } = await dispatchExec( + buildExecMessage({ case: "mcpStateExecArgs", value: create(McpStateExecArgsSchema, {}) }), + { + requestContextTools: [ + mcpTool("task", "pi-agent"), + mcpTool("hub", "pi-agent"), + mcpTool("mcp__fixture_report", "fixture"), + ], + }, + ); + + const answer = soleResult(frames); + if (answer.case !== "mcpStateExecResult") throw new Error(`got ${answer.case}`); + if (answer.value.result.case !== "success") throw new Error("expected success"); + const servers = answer.value.result.value.servers; + expect(servers.map(server => server.serverIdentifier).sort()).toEqual(["fixture", "pi-agent"]); + const piAgent = servers.find(server => server.serverIdentifier === "pi-agent"); + expect(piAgent?.tools.map(t => t.name)).toEqual(["task", "hub"]); + }); + + it("restricts the answer to the requested server identifiers", async () => { + const { frames } = await dispatchExec( + buildExecMessage({ + case: "mcpStateExecArgs", + value: create(McpStateExecArgsSchema, { serverIdentifiers: ["fixture"] }), + }), + { requestContextTools: [mcpTool("task", "pi-agent"), mcpTool("mcp__fixture_report", "fixture")] }, + ); + + const answer = soleResult(frames); + if (answer.case !== "mcpStateExecResult") throw new Error(`got ${answer.case}`); + if (answer.value.result.case !== "success") throw new Error("expected success"); + expect(answer.value.result.value.servers.map(s => s.serverIdentifier)).toEqual(["fixture"]); + }); +}); + +describe("Cursor modern exec frames: redacted read", () => { + it("refuses redactedRead rather than serving the unredacted file", async () => { + // The frame exists so the client can strip secrets first. No redaction is + // implemented, so answering with a plain read would leak exactly what the + // frame withholds. + const readHandler: CursorExecHandlers = { + async read() { + return toolResult("SECRET=hunter2"); + }, + }; + const { frames } = await dispatchExec( + buildExecMessage({ + case: "redactedReadArgs", + value: create(ReadArgsSchema, { path: "/repo/.env", toolCallId: "c1" }), + }), + { execHandlers: readHandler }, + ); + + const answer = soleResult(frames); + if (answer.case !== "redactedReadResult") throw new Error(`got ${answer.case}`); + expect(answer.value.result.case).toBe("error"); + if (answer.value.result.case !== "error") throw new Error("unreachable"); + expect(answer.value.result.value.error).toContain("redaction"); + expect(JSON.stringify(answer.value)).not.toContain("hunter2"); + }); +}); + +describe("Cursor modern exec frames: Pi tools", () => { + it("round-trips piRead through its handler into a typed success", async () => { + const { frames, output, results } = await dispatchExec( + buildExecMessage({ + case: "piReadArgs", + value: create(PiReadExecArgsSchema, { path: "/repo/a.ts", offset: 5, limit: 20 }), + }), + { + execHandlers: { + async piRead(call) { + expect(call.args.path).toBe("/repo/a.ts"); + expect(call.args.offset).toBe(5); + // The Pi frames carry no tool_call_id; the dispatcher mints one. + expect(call.toolCallId).toBeTruthy(); + // Like the real bridge, the handler files its result under the id + // it was handed. + return toolResult("line one\nline two", { toolCallId: call.toolCallId, toolName: "read" }); + }, + }, + }, + ); + + const answer = soleResult(frames); + if (answer.case !== "piReadResult") throw new Error(`got ${answer.case}`); + if (answer.value.result.case !== "success") throw new Error("expected success"); + expect(answer.value.result.value.output).toBe("line one\nline two"); + + // The synthesized block and its paired result must share the minted id, or + // the call is stripped as dangling on replay. + const blocks = output.content.filter((block): block is ToolCallState => block.type === "toolCall"); + expect(blocks).toHaveLength(1); + expect(blocks[0].name).toBe("read"); + expect(results.map(r => r.toolCallId)).toEqual([blocks[0].id]); + }); + + it("maps a failing Pi handler onto the frame's own error variant", async () => { + const { frames } = await dispatchExec( + buildExecMessage({ case: "piReadArgs", value: create(PiReadExecArgsSchema, { path: "/nope" }) }), + { + execHandlers: { + async piRead(call) { + return toolResult("ENOENT: /nope", { isError: true, toolCallId: call.toolCallId }); + }, + }, + }, + ); + + const answer = soleResult(frames); + if (answer.case !== "piReadResult") throw new Error(`got ${answer.case}`); + if (answer.value.result.case !== "error") throw new Error("expected error"); + expect(answer.value.result.value.error).toBe("ENOENT: /nope"); + }); + + it("rejects a Pi frame with no handler installed instead of faking a success", async () => { + const { frames } = await dispatchExec( + buildExecMessage({ case: "piGrepArgs", value: create(PiGrepExecArgsSchema, { pattern: "foo" }) }), + ); + + const answer = soleResult(frames); + if (answer.case !== "piGrepResult") throw new Error(`got ${answer.case}`); + expect(answer.value.result.case).toBe("error"); + }); + + it("carries a truncation summary onto the Pi success payload", async () => { + const { frames } = await dispatchExec( + buildExecMessage({ case: "piBashArgs", value: create(PiBashExecArgsSchema, { command: "yes" }) }), + { + execHandlers: { + async piBash() { + return toolResult("out", { + details: { + truncation: { + truncated: true, + truncatedBy: "lines", + totalLines: 5000, + outputLines: 300, + outputBytes: 4096, + }, + }, + }); + }, + }, + }, + ); + + const answer = soleResult(frames); + if (answer.case !== "piBashResult") throw new Error(`got ${answer.case}`); + if (answer.value.result.case !== "success") throw new Error("expected success"); + expect(answer.value.result.value.truncation?.truncated).toBe(true); + expect(answer.value.result.value.truncation?.truncatedBy).toBe("lines"); + expect(answer.value.result.value.truncation?.totalLines).toBe(5000); + }); + + it("omits truncation entirely when nothing was truncated", async () => { + // `optional PiTruncation` — a zeroed message would claim the output was + // trimmed to nothing. + const { frames } = await dispatchExec( + buildExecMessage({ case: "piBashArgs", value: create(PiBashExecArgsSchema, { command: "echo hi" }) }), + { + execHandlers: { + async piBash() { + return toolResult("hi", { details: { truncation: { truncated: false, totalLines: 1 } } }); + }, + }, + }, + ); + + const answer = soleResult(frames); + if (answer.case !== "piBashResult") throw new Error(`got ${answer.case}`); + if (answer.value.result.case !== "success") throw new Error("expected success"); + expect(answer.value.result.value.truncation).toBeUndefined(); + }); + + it("passes edit replacements through to the handler and surfaces diff/patch", async () => { + const { frames, output } = await dispatchExec( + buildExecMessage({ + case: "piEditArgs", + value: create(PiEditExecArgsSchema, { + path: "/repo/a.ts", + edits: [create(PiEditReplacementSchema, { oldText: "before", newText: "after" })], + }), + }), + { + execHandlers: { + async piEdit(call) { + expect(call.args.edits[0].oldText).toBe("before"); + return toolResult("edited", { details: { diff: "-before\n+after", patch: "@@" } }); + }, + }, + }, + ); + + const answer = soleResult(frames); + if (answer.case !== "piEditResult") throw new Error(`got ${answer.case}`); + if (answer.value.result.case !== "success") throw new Error("expected success"); + expect(answer.value.result.value.diff).toBe("-before\n+after"); + expect(answer.value.result.value.patch).toBe("@@"); + + // The synthesized display block must use the local edit tool's snake_case + // replace schema, or the rebuilt transcript renders empty edits. + const block = output.content.find((b): b is ToolCallState => b.type === "toolCall"); + expect(block?.name).toBe("edit"); + expect(block?.arguments).toEqual({ path: "/repo/a.ts", edits: [{ old_text: "before", new_text: "after" }] }); + }); + + it("answers each remaining Pi frame with its own matching result case", async () => { + const handlers: CursorExecHandlers = { + async piWrite() { + return toolResult("wrote"); + }, + async piGrep() { + return toolResult("a.ts:1:hit"); + }, + async piFind() { + return toolResult("a.ts"); + }, + async piLs() { + return toolResult("a.ts\nb.ts"); + }, + }; + + const write = soleResult( + ( + await dispatchExec( + buildExecMessage({ + case: "piWriteArgs", + value: create(PiWriteExecArgsSchema, { path: "/a.ts", content: "x" }), + }), + { execHandlers: handlers }, + ) + ).frames, + ); + expect(write.case).toBe("piWriteResult"); + + const grep = soleResult( + ( + await dispatchExec( + buildExecMessage({ case: "piGrepArgs", value: create(PiGrepExecArgsSchema, { pattern: "hit" }) }), + { execHandlers: handlers }, + ) + ).frames, + ); + expect(grep.case).toBe("piGrepResult"); + + const find = soleResult( + ( + await dispatchExec( + buildExecMessage({ case: "piFindArgs", value: create(PiFindExecArgsSchema, { pattern: "*.ts" }) }), + { execHandlers: handlers }, + ) + ).frames, + ); + expect(find.case).toBe("piFindResult"); + + const ls = soleResult( + ( + await dispatchExec(buildExecMessage({ case: "piLsArgs", value: create(PiLsExecArgsSchema, {}) }), { + execHandlers: handlers, + }) + ).frames, + ); + expect(ls.case).toBe("piLsResult"); + }); + + it("serves miniSweAgentBash from the existing shell handler under its own frame", async () => { + // Frame 52 carries the same ShellArgs/ShellResult pair as `shellArgs`, so + // the shell handler answers it unchanged — under result field 55. + const { frames } = await dispatchExec( + buildExecMessage({ + case: "miniSweAgentBashArgs", + value: create(ShellArgsSchema, { command: "echo hi", workingDirectory: "/repo", toolCallId: "c1" }), + }), + { + execHandlers: { + async shell(args) { + expect(args.command).toBe("echo hi"); + return toolResult("hi", { toolCallId: "c1", toolName: "bash" }); + }, + }, + }, + ); + + const answer = soleResult(frames); + expect(answer.case).toBe("miniSweAgentBashResult"); + if (answer.case !== "miniSweAgentBashResult") throw new Error("unreachable"); + expect(answer.value.result.case).toBe("success"); + }); +}); + +describe("Cursor modern exec frames: server-resolved tool calls leave a paired block", () => { + // `buildSessionContext` strips a `toolCall` with no matching `toolResult`, + // taking the whole interaction out of every rebuilt transcript. Both of these + // variants are refused, but a refusal still has to settle its block. + + it("pairs the conversationSearch block the exec frame synthesizes", async () => { + const { output, results } = await dispatchExec( + buildExecMessage({ + case: "conversationSearchArgs", + value: create(ConversationSearchArgsSchema, { query: "chess", toolCallId: "call-search-1", limit: 5 }), + }), + ); + + const blocks = output.content.filter((block): block is ToolCallState => block.type === "toolCall"); + expect(blocks).toHaveLength(1); + expect(blocks[0]).toMatchObject({ id: "call-search-1", name: "search_conversations" }); + // Resolved => agent-loop emits no placeholder, so the pair must come from here. + expect(blocks[0][kCursorExecResolved]).toBe(true); + expect(results.map(result => result.toolCallId)).toEqual(["call-search-1"]); + expect(results[0].isError).toBe(true); + }); + + /** + * Drive a streamed `connect_scm` pair through the interaction decoder. + * + * The `ToolCall` is built with the generated schema and re-decoded from its + * own wire bytes, so the `target` / `result` oneofs carry the real + * `{ case, value }` shape the server sends — a hand-shaped literal would + * silently pass against a selector reading the wrong field. + */ + function runConnectScm( + args: { toolCallId?: string; repository?: { owner: string; repo: string } }, + result: { case: "success" | "error" | "rejected"; value: Record } | undefined, + options: { envelopeId?: string; completionCarriesCall?: boolean } = {}, + ): { output: AssistantMessage; results: ToolResultMessage[]; resultsAfterStart: number } { + const wire = create(ToolCallSchema, { + tool: { + case: "connectScmToolCall", + value: create(ConnectScmToolCallSchema, { + args: create(ConnectScmArgsSchema, { + toolCallId: args.toolCallId ?? "", + target: args.repository + ? { + case: "github", + value: create(ConnectScmGithubSchema, { + repository: create(ConnectScmGithubRepositorySchema, args.repository), + }), + } + : { case: undefined }, + }), + result: result + ? create(ConnectScmResultSchema, { + result: + result.case === "success" + ? { case: "success", value: create(ConnectScmSuccessSchema, {}) } + : result.case === "error" + ? { case: "error", value: create(ConnectScmErrorSchema, result.value) } + : { case: "rejected", value: create(ConnectScmRejectedSchema, result.value) }, + }) + : undefined, + }), + }, + }); + const toolCall = fromBinary(ToolCallSchema, toBinary(ToolCallSchema, wire)); + + const output = cursorAssistantMessage(); + const stream = new AssistantMessageEventStream(); + const state = newBlockState(); + const results: ToolResultMessage[] = []; + state.onToolResult = toolResultMessage => { + results.push(toolResultMessage); + return toolResultMessage; + }; + + const usage = { sawTokenDelta: false }; + processInteractionUpdate( + { message: { case: "toolCallStarted", value: { callId: options.envelopeId ?? "", toolCall } } }, + output, + stream, + state, + usage, + ); + const resultsAfterStart = results.length; + processInteractionUpdate( + { + message: { + case: "toolCallCompleted", + value: options.completionCarriesCall === false ? {} : { toolCall }, + }, + }, + output, + stream, + state, + usage, + ); + return { output, results, resultsAfterStart }; + } + + function soleBlock(output: AssistantMessage): ToolCallState { + const blocks = output.content.filter((block): block is ToolCallState => block.type === "toolCall"); + expect(blocks).toHaveLength(1); + return blocks[0]; + } + + it("reads the connectScm repository out of the target oneof, not a flat field", async () => { + const { output, results } = runConnectScm( + { toolCallId: "call-scm-1", repository: { owner: "can1357", repo: "oh-my-pi" } }, + { case: "success", value: {} }, + ); + + const block = soleBlock(output); + expect(block).toMatchObject({ + id: "call-scm-1", + name: "connect_scm", + arguments: { owner: "can1357", repo: "oh-my-pi" }, + }); + // Resolved => agent-loop runs no local tool, so the decoder owes the pair. + expect(block[kCursorExecResolved]).toBe(true); + expect(results.map(result => result.toolCallId)).toEqual(["call-scm-1"]); + }); + + it("settles connectScm from the completion's result, never from the announcement", async () => { + // The start frame carries no verdict. Answering there would persist a + // fabricated outcome before the server reported one. + const success = runConnectScm({ toolCallId: "c1" }, { case: "success", value: {} }); + const failed = runConnectScm({ toolCallId: "c2" }, { case: "error", value: { error: "token expired" } }); + const rejected = runConnectScm({ toolCallId: "c3" }, { case: "rejected", value: { reason: "user declined" } }); + + // The bug this guards: settling at start persisted a hard-coded failure + // for every call, including the ones the server went on to accept. + expect([success, failed, rejected].map(run => run.resultsAfterStart)).toEqual([0, 0, 0]); + expect(success.results.map(r => r.isError)).toEqual([false]); + expect(failed.results[0].isError).toBe(true); + expect(failed.results[0].content).toEqual([{ type: "text", text: "token expired" }]); + expect(rejected.results[0].isError).toBe(true); + expect(rejected.results[0].content).toEqual([{ type: "text", text: "user declined" }]); + }); + + it("still pairs connectScm when the completion carries no tool call at all", async () => { + // An unpaired resolved block is stripped along with its whole interaction, + // so a resultless completion must settle as a failure rather than stay open. + const { output, results } = runConnectScm({ toolCallId: "c4" }, undefined, { + completionCarriesCall: false, + }); + + expect(soleBlock(output).id).toBe("c4"); + expect(results.map(result => result.toolCallId)).toEqual(["c4"]); + expect(results[0].isError).toBe(true); + }); + + it("falls back to the envelope call id when connectScm args carry none", async () => { + const { output, results } = runConnectScm( + { repository: { owner: "o", repo: "r" } }, + { case: "success", value: {} }, + { + envelopeId: "envelope-id", + }, + ); + + expect(soleBlock(output).id).toBe("envelope-id"); + expect(results.map(result => result.toolCallId)).toEqual(["envelope-id"]); + }); + + it("ignores a completion whose envelope id belongs to a different call", async () => { + // Server-resolved and parallel calls interleave: a completion for an + // unrelated call would otherwise close whichever block is current and pair + // it with the wrong verdict — here, marking a pending connect as rejected. + // + // Correlation is on the envelope id, which is deliberately NOT the block + // id: the block persists under the inner `tool_call_id` the transcript + // files it under. + const wire = create(ToolCallSchema, { + tool: { + case: "connectScmToolCall", + value: create(ConnectScmToolCallSchema, { + args: create(ConnectScmArgsSchema, { toolCallId: "inner-id" }), + result: create(ConnectScmResultSchema, { + result: { case: "rejected", value: create(ConnectScmRejectedSchema, { reason: "other call" }) }, + }), + }), + }, + }); + const toolCall = fromBinary(ToolCallSchema, toBinary(ToolCallSchema, wire)); + + const output = cursorAssistantMessage(); + const stream = new AssistantMessageEventStream(); + const state = newBlockState(); + const results: ToolResultMessage[] = []; + state.onToolResult = result => { + results.push(result); + return result; + }; + const usage = { sawTokenDelta: false }; + + processInteractionUpdate( + { message: { case: "toolCallStarted", value: { callId: "envelope-a", toolCall } } }, + output, + stream, + state, + usage, + ); + processInteractionUpdate( + { message: { case: "toolCallCompleted", value: { callId: "envelope-b", toolCall } } }, + output, + stream, + state, + usage, + ); + + // The block stays open and unpaired; only its own completion settles it. + expect(results).toEqual([]); + + processInteractionUpdate( + { message: { case: "toolCallCompleted", value: { callId: "envelope-a", toolCall } } }, + output, + stream, + state, + usage, + ); + + expect(results.map(result => result.toolCallId)).toEqual(["inner-id"]); + expect(results[0].content).toEqual([{ type: "text", text: "other call" }]); + }); + + it("settles two interleaved calls independently, each with its own result", async () => { + // `start A, start B, complete A, complete B` is legal wire order. With a + // single "current block" slot, B's start orphaned A: A's completion then + // settled B, and A was never paired — so the transcript rebuild dropped + // the whole interaction. + function scmCall(toolCallId: string, reason: string) { + const wire = create(ToolCallSchema, { + tool: { + case: "connectScmToolCall", + value: create(ConnectScmToolCallSchema, { + args: create(ConnectScmArgsSchema, { toolCallId }), + result: create(ConnectScmResultSchema, { + result: { case: "rejected", value: create(ConnectScmRejectedSchema, { reason }) }, + }), + }), + }, + }); + return fromBinary(ToolCallSchema, toBinary(ToolCallSchema, wire)); + } + + const callA = scmCall("inner-a", "reason A"); + const callB = scmCall("inner-b", "reason B"); + + const output = cursorAssistantMessage(); + const stream = new AssistantMessageEventStream(); + const state = newBlockState(); + const results: ToolResultMessage[] = []; + state.onToolResult = result => { + results.push(result); + return result; + }; + const usage = { sawTokenDelta: false }; + const send = (updateCase: string, callId: string, toolCall: unknown) => + processInteractionUpdate( + { message: { case: updateCase, value: { callId, toolCall } } }, + output, + stream, + state, + usage, + ); + + send("toolCallStarted", "envelope-a", callA); + send("toolCallStarted", "envelope-b", callB); + send("toolCallCompleted", "envelope-a", callA); + send("toolCallCompleted", "envelope-b", callB); + + // Both blocks exist, and each is paired with its OWN verdict. + const blocks = output.content.filter((block): block is ToolCallState => block.type === "toolCall"); + expect(blocks.map(block => block.id)).toEqual(["inner-a", "inner-b"]); + expect(results.map(result => result.toolCallId)).toEqual(["inner-a", "inner-b"]); + expect(results.map(result => result.content)).toEqual([ + [{ type: "text", text: "reason A" }], + [{ type: "text", text: "reason B" }], + ]); + }); + + it("does not double-create a block for a Pi call the exec channel already synthesized", async () => { + // Modern builds stream a `pi_*_tool_call` envelope alongside the exec + // frame. The exec side owns that block; a second one here would render the + // same call twice and leave the duplicate unpaired. + const output = cursorAssistantMessage(); + const stream = new AssistantMessageEventStream(); + const state = newBlockState(); + + processInteractionUpdate( + { + message: { + case: "toolCallStarted", + value: { + callId: "call-pi-read", + toolCall: { tool: { case: "piReadToolCall", value: { args: { path: "/a.ts" } } } }, + }, + }, + }, + output, + stream, + state, + { sawTokenDelta: false }, + ); + + expect(output.content.filter(block => block.type === "toolCall")).toHaveLength(0); + }); +}); diff --git a/packages/ai/test/cursor-streaming-args.test.ts b/packages/ai/test/cursor-streaming-args.test.ts index 9f74c743a..4101a7457 100644 --- a/packages/ai/test/cursor-streaming-args.test.ts +++ b/packages/ai/test/cursor-streaming-args.test.ts @@ -58,6 +58,7 @@ function newHarness(): Harness { get currentToolCall() { return toolCall; }, + openToolCalls: new Map(), resolvedMcpToolCallIds: new Set(), firstTokenTime: undefined, setTextBlock: b => { diff --git a/packages/ai/test/cursor-todo-bridge.test.ts b/packages/ai/test/cursor-todo-bridge.test.ts index 1f184e9d0..bff4d27cf 100644 --- a/packages/ai/test/cursor-todo-bridge.test.ts +++ b/packages/ai/test/cursor-todo-bridge.test.ts @@ -89,6 +89,7 @@ function newHarness(): Harness { get currentToolCall() { return toolCall; }, + openToolCalls: new Map(), resolvedMcpToolCallIds: new Set(), firstTokenTime: undefined, setTextBlock: b => { diff --git a/packages/catalog/CHANGELOG.md b/packages/catalog/CHANGELOG.md index 59e7a4f7f..df136f5b9 100644 --- a/packages/catalog/CHANGELOG.md +++ b/packages/catalog/CHANGELOG.md @@ -39,6 +39,9 @@ - Fixed Kimi Code (`kimi-code`) reporting `maxTokens: 32000` for every model — its `/coding/v1/models` discovery mapper and the bundled catalog applied a blanket constant, truncating `k3`/`k3-256k` output at ~4x below their real 131072 ceiling and `kimi-for-coding`/`kimi-for-coding-highspeed` below their 32768 ceiling. Output caps are now derived per family, and the model cache is invalidated so upgrades drop the stale `maxTokens: 32000` rows (including the discovery-only `k3-256k`) instead of serving them until the next network refresh ([#6711](https://github.com/can1357/oh-my-pi/issues/6711)). - Fixed Anthropic model discovery 404ing when the registry derived the provider base URL from a bundled model without the `/v1` suffix (`https://api.anthropic.com/models` instead of `/v1/models`), which let a stale text-only cache row shadow fresh models.dev vision metadata — surfacing as snapcompact refusing to run on `claude-opus-5`. Discovery now always targets `/v1/models` while model rows keep the provider base URL ([#6563](https://github.com/can1357/oh-my-pi/issues/6563)). +### Added + +- Regenerated the Cursor agent protobufs (`discovery/cursor-gen/agent_pb.ts`) against the modern `agent.proto`, adding the message and enum families current Cursor CLI builds emit: Pi tool exec frames, hook queries and responses, subagents, allowlist prechecks, MCP state, smart-mode classification, canvas diagnostics, conversation search, agent-store conflicts and git diff. Purely additive — no existing exported symbol changed shape. ## [17.1.4] - 2026-07-26 diff --git a/packages/catalog/src/discovery/cursor-gen/agent_pb.ts b/packages/catalog/src/discovery/cursor-gen/agent_pb.ts index d88893d14..21e4d8244 100644 --- a/packages/catalog/src/discovery/cursor-gen/agent_pb.ts +++ b/packages/catalog/src/discovery/cursor-gen/agent_pb.ts @@ -10,7 +10,7 @@ import type { Message } from "@bufbuild/protobuf"; * Describes the file agent.proto. */ export const file_agent: GenFile = /*@__PURE__*/ - fileDesc("CgthZ2VudC5wcm90bxIIYWdlbnQudjEicgoOR2xvYlRvb2xSZXN1bHQSLAoHc3VjY2VzcxgBIAEoCzIZLmFnZW50LnYxLkdsb2JUb29sU3VjY2Vzc0gAEigKBWVycm9yGAIgASgLMhcuYWdlbnQudjEuR2xvYlRvb2xFcnJvckgAQggKBnJlc3VsdCIeCg1HbG9iVG9vbEVycm9yEg0KBWVycm9yGAEgASgJIokBCg9HbG9iVG9vbFN1Y2Nlc3MSDwoHcGF0dGVybhgBIAEoCRIMCgRwYXRoGAIgASgJEg0KBWZpbGVzGAMgAygJEhMKC3RvdGFsX2ZpbGVzGAQgASgFEhgKEGNsaWVudF90cnVuY2F0ZWQYBSABKAgSGQoRcmlwZ3JlcF90cnVuY2F0ZWQYBiABKAgiRgoMR2xvYlRvb2xDYWxsEgwKBGFyZ3MYASABKAwSKAoGcmVzdWx0GAIgASgLMhguYWdlbnQudjEuR2xvYlRvb2xSZXN1bHQibQoRUmVhZExpbnRzVG9vbENhbGwSKQoEYXJncxgBIAEoCzIbLmFnZW50LnYxLlJlYWRMaW50c1Rvb2xBcmdzEi0KBnJlc3VsdBgCIAEoCzIdLmFnZW50LnYxLlJlYWRMaW50c1Rvb2xSZXN1bHQiIgoRUmVhZExpbnRzVG9vbEFyZ3MSDQoFcGF0aHMYASADKAkigQEKE1JlYWRMaW50c1Rvb2xSZXN1bHQSMQoHc3VjY2VzcxgBIAEoCzIeLmFnZW50LnYxLlJlYWRMaW50c1Rvb2xTdWNjZXNzSAASLQoFZXJyb3IYAiABKAsyHC5hZ2VudC52MS5SZWFkTGludHNUb29sRXJyb3JIAEIICgZyZXN1bHQiewoUUmVhZExpbnRzVG9vbFN1Y2Nlc3MSMwoQZmlsZV9kaWFnbm9zdGljcxgBIAMoCzIZLmFnZW50LnYxLkZpbGVEaWFnbm9zdGljcxITCgt0b3RhbF9maWxlcxgCIAEoBRIZChF0b3RhbF9kaWFnbm9zdGljcxgDIAEoBSJpCg9GaWxlRGlhZ25vc3RpY3MSDAoEcGF0aBgBIAEoCRItCgtkaWFnbm9zdGljcxgCIAMoCzIYLmFnZW50LnYxLkRpYWdub3N0aWNJdGVtEhkKEWRpYWdub3N0aWNzX2NvdW50GAMgASgFIqsBCg5EaWFnbm9zdGljSXRlbRIuCghzZXZlcml0eRgBIAEoDjIcLmFnZW50LnYxLkRpYWdub3N0aWNTZXZlcml0eRIoCgVyYW5nZRgCIAEoCzIZLmFnZW50LnYxLkRpYWdub3N0aWNSYW5nZRIPCgdtZXNzYWdlGAMgASgJEg4KBnNvdXJjZRgEIAEoCRIMCgRjb2RlGAUgASgJEhAKCGlzX3N0YWxlGAYgASgIIlUKD0RpYWdub3N0aWNSYW5nZRIhCgVzdGFydBgBIAEoCzISLmFnZW50LnYxLlBvc2l0aW9uEh8KA2VuZBgCIAEoCzISLmFnZW50LnYxLlBvc2l0aW9uIisKElJlYWRMaW50c1Rvb2xFcnJvchIVCg1lcnJvcl9tZXNzYWdlGAEgASgJIj0KDE1jcFRvb2xFcnJvchINCgVlcnJvchgBIAEoCRIeChZyZWFkX3Rvb2xfZGVmX3JlbWluZGVyGAIgASgJItIBCg1NY3BUb29sUmVzdWx0EicKB3N1Y2Nlc3MYASABKAsyFC5hZ2VudC52MS5NY3BTdWNjZXNzSAASJwoFZXJyb3IYAiABKAsyFi5hZ2VudC52MS5NY3BUb29sRXJyb3JIABIpCghyZWplY3RlZBgDIAEoCzIVLmFnZW50LnYxLk1jcFJlamVjdGVkSAASOgoRcGVybWlzc2lvbl9kZW5pZWQYBCABKAsyHS5hZ2VudC52MS5NY3BQZXJtaXNzaW9uRGVuaWVkSABCCAoGcmVzdWx0IoEBCgtNY3BUb29sQ2FsbBIfCgRhcmdzGAEgASgLMhEuYWdlbnQudjEuTWNwQXJncxInCgZyZXN1bHQYAiABKAsyFy5hZ2VudC52MS5NY3BUb29sUmVzdWx0EhgKC2Rlc2NyaXB0aW9uGAMgASgJSACIAQFCDgoMX2Rlc2NyaXB0aW9uIm0KEVNlbVNlYXJjaFRvb2xDYWxsEikKBGFyZ3MYASABKAsyGy5hZ2VudC52MS5TZW1TZWFyY2hUb29sQXJncxItCgZyZXN1bHQYAiABKAsyHS5hZ2VudC52MS5TZW1TZWFyY2hUb29sUmVzdWx0IlMKEVNlbVNlYXJjaFRvb2xBcmdzEg0KBXF1ZXJ5GAEgASgJEhoKEnRhcmdldF9kaXJlY3RvcmllcxgCIAMoCRITCgtleHBsYW5hdGlvbhgDIAEoCSKBAQoTU2VtU2VhcmNoVG9vbFJlc3VsdBIxCgdzdWNjZXNzGAEgASgLMh4uYWdlbnQudjEuU2VtU2VhcmNoVG9vbFN1Y2Nlc3NIABItCgVlcnJvchgCIAEoCzIcLmFnZW50LnYxLlNlbVNlYXJjaFRvb2xFcnJvckgAQggKBnJlc3VsdCI9ChRTZW1TZWFyY2hUb29sU3VjY2VzcxIPCgdyZXN1bHRzGAEgASgJEhQKDGNvZGVfcmVzdWx0cxgCIAMoDCIrChJTZW1TZWFyY2hUb29sRXJyb3ISFQoNZXJyb3JfbWVzc2FnZRgBIAEoCSKCAQoYTGlzdE1jcFJlc291cmNlc1Rvb2xDYWxsEjAKBGFyZ3MYASABKAsyIi5hZ2VudC52MS5MaXN0TWNwUmVzb3VyY2VzRXhlY0FyZ3MSNAoGcmVzdWx0GAIgASgLMiQuYWdlbnQudjEuTGlzdE1jcFJlc291cmNlc0V4ZWNSZXN1bHQifwoXUmVhZE1jcFJlc291cmNlVG9vbENhbGwSLwoEYXJncxgBIAEoCzIhLmFnZW50LnYxLlJlYWRNY3BSZXNvdXJjZUV4ZWNBcmdzEjMKBnJlc3VsdBgCIAEoCzIjLmFnZW50LnYxLlJlYWRNY3BSZXNvdXJjZUV4ZWNSZXN1bHQiWQoNRmV0Y2hUb29sQ2FsbBIhCgRhcmdzGAEgASgLMhMuYWdlbnQudjEuRmV0Y2hBcmdzEiUKBnJlc3VsdBgCIAEoCzIVLmFnZW50LnYxLkZldGNoUmVzdWx0Im4KFFJlY29yZFNjcmVlblRvb2xDYWxsEigKBGFyZ3MYASABKAsyGi5hZ2VudC52MS5SZWNvcmRTY3JlZW5BcmdzEiwKBnJlc3VsdBgCIAEoCzIcLmFnZW50LnYxLlJlY29yZFNjcmVlblJlc3VsdCJ3ChdXcml0ZVNoZWxsU3RkaW5Ub29sQ2FsbBIrCgRhcmdzGAEgASgLMh0uYWdlbnQudjEuV3JpdGVTaGVsbFN0ZGluQXJncxIvCgZyZXN1bHQYAiABKAsyHy5hZ2VudC52MS5Xcml0ZVNoZWxsU3RkaW5SZXN1bHQisQEKC1JlZmxlY3RBcmdzEiIKGnVuZXhwZWN0ZWRfYWN0aW9uX291dGNvbWVzGAEgASgJEh0KFXJlbGV2YW50X2luc3RydWN0aW9ucxgCIAEoCRIZChFzY2VuYXJpb19hbmFseXNpcxgDIAEoCRIaChJjcml0aWNhbF9zeW50aGVzaXMYBCABKAkSEgoKbmV4dF9zdGVwcxgFIAEoCRIUCgx0b29sX2NhbGxfaWQYBiABKAkibwoNUmVmbGVjdFJlc3VsdBIrCgdzdWNjZXNzGAEgASgLMhguYWdlbnQudjEuUmVmbGVjdFN1Y2Nlc3NIABInCgVlcnJvchgCIAEoCzIWLmFnZW50LnYxLlJlZmxlY3RFcnJvckgAQggKBnJlc3VsdCIQCg5SZWZsZWN0U3VjY2VzcyIdCgxSZWZsZWN0RXJyb3ISDQoFZXJyb3IYASABKAkiXwoPUmVmbGVjdFRvb2xDYWxsEiMKBGFyZ3MYASABKAsyFS5hZ2VudC52MS5SZWZsZWN0QXJncxInCgZyZXN1bHQYAiABKAsyFy5hZ2VudC52MS5SZWZsZWN0UmVzdWx0IlkKF1N0YXJ0R3JpbmRFeGVjdXRpb25BcmdzEhgKC2V4cGxhbmF0aW9uGAEgASgJSACIAQESFAoMdG9vbF9jYWxsX2lkGAIgASgJQg4KDF9leHBsYW5hdGlvbiKTAQoZU3RhcnRHcmluZEV4ZWN1dGlvblJlc3VsdBI3CgdzdWNjZXNzGAEgASgLMiQuYWdlbnQudjEuU3RhcnRHcmluZEV4ZWN1dGlvblN1Y2Nlc3NIABIzCgVlcnJvchgCIAEoCzIiLmFnZW50LnYxLlN0YXJ0R3JpbmRFeGVjdXRpb25FcnJvckgAQggKBnJlc3VsdCIcChpTdGFydEdyaW5kRXhlY3V0aW9uU3VjY2VzcyIpChhTdGFydEdyaW5kRXhlY3V0aW9uRXJyb3ISDQoFZXJyb3IYASABKAkigwEKG1N0YXJ0R3JpbmRFeGVjdXRpb25Ub29sQ2FsbBIvCgRhcmdzGAEgASgLMiEuYWdlbnQudjEuU3RhcnRHcmluZEV4ZWN1dGlvbkFyZ3MSMwoGcmVzdWx0GAIgASgLMiMuYWdlbnQudjEuU3RhcnRHcmluZEV4ZWN1dGlvblJlc3VsdCJYChZTdGFydEdyaW5kUGxhbm5pbmdBcmdzEhgKC2V4cGxhbmF0aW9uGAEgASgJSACIAQESFAoMdG9vbF9jYWxsX2lkGAIgASgJQg4KDF9leHBsYW5hdGlvbiKQAQoYU3RhcnRHcmluZFBsYW5uaW5nUmVzdWx0EjYKB3N1Y2Nlc3MYASABKAsyIy5hZ2VudC52MS5TdGFydEdyaW5kUGxhbm5pbmdTdWNjZXNzSAASMgoFZXJyb3IYAiABKAsyIS5hZ2VudC52MS5TdGFydEdyaW5kUGxhbm5pbmdFcnJvckgAQggKBnJlc3VsdCIbChlTdGFydEdyaW5kUGxhbm5pbmdTdWNjZXNzIigKF1N0YXJ0R3JpbmRQbGFubmluZ0Vycm9yEg0KBWVycm9yGAEgASgJIoABChpTdGFydEdyaW5kUGxhbm5pbmdUb29sQ2FsbBIuCgRhcmdzGAEgASgLMiAuYWdlbnQudjEuU3RhcnRHcmluZFBsYW5uaW5nQXJncxIyCgZyZXN1bHQYAiABKAsyIi5hZ2VudC52MS5TdGFydEdyaW5kUGxhbm5pbmdSZXN1bHQinAEKCFRhc2tBcmdzEhMKC2Rlc2NyaXB0aW9uGAEgASgJEg4KBnByb21wdBgCIAEoCRItCg1zdWJhZ2VudF90eXBlGAMgASgLMhYuYWdlbnQudjEuU3ViYWdlbnRUeXBlEhIKBW1vZGVsGAQgASgJSACIAQESEwoGcmVzdW1lGAUgASgJSAGIAQFCCAoGX21vZGVsQgkKB19yZXN1bWUiqgEKC1Rhc2tTdWNjZXNzEjYKEmNvbnZlcnNhdGlvbl9zdGVwcxgBIAMoCzIaLmFnZW50LnYxLkNvbnZlcnNhdGlvblN0ZXASFQoIYWdlbnRfaWQYAiABKAlIAIgBARIVCg1pc19iYWNrZ3JvdW5kGAMgASgIEhgKC2R1cmF0aW9uX21zGAQgASgESAGIAQFCCwoJX2FnZW50X2lkQg4KDF9kdXJhdGlvbl9tcyIaCglUYXNrRXJyb3ISDQoFZXJyb3IYASABKAkiZgoKVGFza1Jlc3VsdBIoCgdzdWNjZXNzGAEgASgLMhUuYWdlbnQudjEuVGFza1N1Y2Nlc3NIABIkCgVlcnJvchgCIAEoCzITLmFnZW50LnYxLlRhc2tFcnJvckgAQggKBnJlc3VsdCJWCgxUYXNrVG9vbENhbGwSIAoEYXJncxgBIAEoCzISLmFnZW50LnYxLlRhc2tBcmdzEiQKBnJlc3VsdBgCIAEoCzIULmFnZW50LnYxLlRhc2tSZXN1bHQiTAoRVGFza1Rvb2xDYWxsRGVsdGESNwoSaW50ZXJhY3Rpb25fdXBkYXRlGAEgASgLMhsuYWdlbnQudjEuSW50ZXJhY3Rpb25VcGRhdGUiyw8KCFRvb2xDYWxsEjIKD3NoZWxsX3Rvb2xfY2FsbBgBIAEoCzIXLmFnZW50LnYxLlNoZWxsVG9vbENhbGxIABI0ChBkZWxldGVfdG9vbF9jYWxsGAMgASgLMhguYWdlbnQudjEuRGVsZXRlVG9vbENhbGxIABIwCg5nbG9iX3Rvb2xfY2FsbBgEIAEoCzIWLmFnZW50LnYxLkdsb2JUb29sQ2FsbEgAEjAKDmdyZXBfdG9vbF9jYWxsGAUgASgLMhYuYWdlbnQudjEuR3JlcFRvb2xDYWxsSAASMAoOcmVhZF90b29sX2NhbGwYCCABKAsyFi5hZ2VudC52MS5SZWFkVG9vbENhbGxIABI/ChZ1cGRhdGVfdG9kb3NfdG9vbF9jYWxsGAkgASgLMh0uYWdlbnQudjEuVXBkYXRlVG9kb3NUb29sQ2FsbEgAEjsKFHJlYWRfdG9kb3NfdG9vbF9jYWxsGAogASgLMhsuYWdlbnQudjEuUmVhZFRvZG9zVG9vbENhbGxIABIwCg5lZGl0X3Rvb2xfY2FsbBgMIAEoCzIWLmFnZW50LnYxLkVkaXRUb29sQ2FsbEgAEiwKDGxzX3Rvb2xfY2FsbBgNIAEoCzIULmFnZW50LnYxLkxzVG9vbENhbGxIABI7ChRyZWFkX2xpbnRzX3Rvb2xfY2FsbBgOIAEoCzIbLmFnZW50LnYxLlJlYWRMaW50c1Rvb2xDYWxsSAASLgoNbWNwX3Rvb2xfY2FsbBgPIAEoCzIVLmFnZW50LnYxLk1jcFRvb2xDYWxsSAASOwoUc2VtX3NlYXJjaF90b29sX2NhbGwYECABKAsyGy5hZ2VudC52MS5TZW1TZWFyY2hUb29sQ2FsbEgAEj0KFWNyZWF0ZV9wbGFuX3Rvb2xfY2FsbBgRIAEoCzIcLmFnZW50LnYxLkNyZWF0ZVBsYW5Ub29sQ2FsbEgAEjsKFHdlYl9zZWFyY2hfdG9vbF9jYWxsGBIgASgLMhsuYWdlbnQudjEuV2ViU2VhcmNoVG9vbENhbGxIABIwCg50YXNrX3Rvb2xfY2FsbBgTIAEoCzIWLmFnZW50LnYxLlRhc2tUb29sQ2FsbEgAEkoKHGxpc3RfbWNwX3Jlc291cmNlc190b29sX2NhbGwYFCABKAsyIi5hZ2VudC52MS5MaXN0TWNwUmVzb3VyY2VzVG9vbENhbGxIABJIChtyZWFkX21jcF9yZXNvdXJjZV90b29sX2NhbGwYFSABKAsyIS5hZ2VudC52MS5SZWFkTWNwUmVzb3VyY2VUb29sQ2FsbEgAEkYKGmFwcGx5X2FnZW50X2RpZmZfdG9vbF9jYWxsGBYgASgLMiAuYWdlbnQudjEuQXBwbHlBZ2VudERpZmZUb29sQ2FsbEgAEj8KFmFza19xdWVzdGlvbl90b29sX2NhbGwYFyABKAsyHS5hZ2VudC52MS5Bc2tRdWVzdGlvblRvb2xDYWxsSAASMgoPZmV0Y2hfdG9vbF9jYWxsGBggASgLMhcuYWdlbnQudjEuRmV0Y2hUb29sQ2FsbEgAEj0KFXN3aXRjaF9tb2RlX3Rvb2xfY2FsbBgZIAEoCzIcLmFnZW50LnYxLlN3aXRjaE1vZGVUb29sQ2FsbEgAEjsKFGV4YV9zZWFyY2hfdG9vbF9jYWxsGBogASgLMhsuYWdlbnQudjEuRXhhU2VhcmNoVG9vbENhbGxIABI5ChNleGFfZmV0Y2hfdG9vbF9jYWxsGBsgASgLMhouYWdlbnQudjEuRXhhRmV0Y2hUb29sQ2FsbEgAEkMKGGdlbmVyYXRlX2ltYWdlX3Rvb2xfY2FsbBgcIAEoCzIfLmFnZW50LnYxLkdlbmVyYXRlSW1hZ2VUb29sQ2FsbEgAEkEKF3JlY29yZF9zY3JlZW5fdG9vbF9jYWxsGB0gASgLMh4uYWdlbnQudjEuUmVjb3JkU2NyZWVuVG9vbENhbGxIABI/ChZjb21wdXRlcl91c2VfdG9vbF9jYWxsGB4gASgLMh0uYWdlbnQudjEuQ29tcHV0ZXJVc2VUb29sQ2FsbEgAEkgKG3dyaXRlX3NoZWxsX3N0ZGluX3Rvb2xfY2FsbBgfIAEoCzIhLmFnZW50LnYxLldyaXRlU2hlbGxTdGRpblRvb2xDYWxsSAASNgoRcmVmbGVjdF90b29sX2NhbGwYICABKAsyGS5hZ2VudC52MS5SZWZsZWN0VG9vbENhbGxIABJOCh5zZXR1cF92bV9lbnZpcm9ubWVudF90b29sX2NhbGwYISABKAsyJC5hZ2VudC52MS5TZXR1cFZtRW52aXJvbm1lbnRUb29sQ2FsbEgAEjoKE3RydW5jYXRlZF90b29sX2NhbGwYIiABKAsyGy5hZ2VudC52MS5UcnVuY2F0ZWRUb29sQ2FsbEgAElAKH3N0YXJ0X2dyaW5kX2V4ZWN1dGlvbl90b29sX2NhbGwYIyABKAsyJS5hZ2VudC52MS5TdGFydEdyaW5kRXhlY3V0aW9uVG9vbENhbGxIABJOCh5zdGFydF9ncmluZF9wbGFubmluZ190b29sX2NhbGwYJCABKAsyJC5hZ2VudC52MS5TdGFydEdyaW5kUGxhbm5pbmdUb29sQ2FsbEgAQgYKBHRvb2wiFwoVVHJ1bmNhdGVkVG9vbENhbGxBcmdzIhoKGFRydW5jYXRlZFRvb2xDYWxsU3VjY2VzcyInChZUcnVuY2F0ZWRUb29sQ2FsbEVycm9yEg0KBWVycm9yGAEgASgJIo0BChdUcnVuY2F0ZWRUb29sQ2FsbFJlc3VsdBI1CgdzdWNjZXNzGAEgASgLMiIuYWdlbnQudjEuVHJ1bmNhdGVkVG9vbENhbGxTdWNjZXNzSAASMQoFZXJyb3IYAiABKAsyIC5hZ2VudC52MS5UcnVuY2F0ZWRUb29sQ2FsbEVycm9ySABCCAoGcmVzdWx0IpQBChFUcnVuY2F0ZWRUb29sQ2FsbBIdChVvcmlnaW5hbF9zdGVwX2Jsb2JfaWQYASABKAwSLQoEYXJncxgCIAEoCzIfLmFnZW50LnYxLlRydW5jYXRlZFRvb2xDYWxsQXJncxIxCgZyZXN1bHQYAyABKAsyIS5hZ2VudC52MS5UcnVuY2F0ZWRUb29sQ2FsbFJlc3VsdCLRAQoNVG9vbENhbGxEZWx0YRI9ChVzaGVsbF90b29sX2NhbGxfZGVsdGEYASABKAsyHC5hZ2VudC52MS5TaGVsbFRvb2xDYWxsRGVsdGFIABI7ChR0YXNrX3Rvb2xfY2FsbF9kZWx0YRgCIAEoCzIbLmFnZW50LnYxLlRhc2tUb29sQ2FsbERlbHRhSAASOwoUZWRpdF90b29sX2NhbGxfZGVsdGEYAyABKAsyGy5hZ2VudC52MS5FZGl0VG9vbENhbGxEZWx0YUgAQgcKBWRlbHRhIrYBChBDb252ZXJzYXRpb25TdGVwEjcKEWFzc2lzdGFudF9tZXNzYWdlGAEgASgLMhouYWdlbnQudjEuQXNzaXN0YW50TWVzc2FnZUgAEicKCXRvb2xfY2FsbBgCIAEoCzISLmFnZW50LnYxLlRvb2xDYWxsSAASNQoQdGhpbmtpbmdfbWVzc2FnZRgDIAEoCzIZLmFnZW50LnYxLlRoaW5raW5nTWVzc2FnZUgAQgkKB21lc3NhZ2UigQQKEkNvbnZlcnNhdGlvbkFjdGlvbhI6ChN1c2VyX21lc3NhZ2VfYWN0aW9uGAEgASgLMhsuYWdlbnQudjEuVXNlck1lc3NhZ2VBY3Rpb25IABIvCg1yZXN1bWVfYWN0aW9uGAIgASgLMhYuYWdlbnQudjEuUmVzdW1lQWN0aW9uSAASLwoNY2FuY2VsX2FjdGlvbhgDIAEoCzIWLmFnZW50LnYxLkNhbmNlbEFjdGlvbkgAEjUKEHN1bW1hcml6ZV9hY3Rpb24YBCABKAsyGS5hZ2VudC52MS5TdW1tYXJpemVBY3Rpb25IABI8ChRzaGVsbF9jb21tYW5kX2FjdGlvbhgFIAEoCzIcLmFnZW50LnYxLlNoZWxsQ29tbWFuZEFjdGlvbkgAEjYKEXN0YXJ0X3BsYW5fYWN0aW9uGAYgASgLMhkuYWdlbnQudjEuU3RhcnRQbGFuQWN0aW9uSAASOgoTZXhlY3V0ZV9wbGFuX2FjdGlvbhgHIAEoCzIbLmFnZW50LnYxLkV4ZWN1dGVQbGFuQWN0aW9uSAASWgokYXN5bmNfYXNrX3F1ZXN0aW9uX2NvbXBsZXRpb25fYWN0aW9uGAggASgLMiouYWdlbnQudjEuQXN5bmNBc2tRdWVzdGlvbkNvbXBsZXRpb25BY3Rpb25IAEIICgZhY3Rpb24ivwEKEVVzZXJNZXNzYWdlQWN0aW9uEisKDHVzZXJfbWVzc2FnZRgBIAEoCzIVLmFnZW50LnYxLlVzZXJNZXNzYWdlEjEKD3JlcXVlc3RfY29udGV4dBgCIAEoCzIYLmFnZW50LnYxLlJlcXVlc3RDb250ZXh0EikKHHNlbmRfdG9faW50ZXJhY3Rpb25fbGlzdGVuZXIYAyABKAhIAIgBAUIfCh1fc2VuZF90b19pbnRlcmFjdGlvbl9saXN0ZW5lciIOCgxDYW5jZWxBY3Rpb24iQQoMUmVzdW1lQWN0aW9uEjEKD3JlcXVlc3RfY29udGV4dBgCIAEoCzIYLmFnZW50LnYxLlJlcXVlc3RDb250ZXh0IqABCiBBc3luY0Fza1F1ZXN0aW9uQ29tcGxldGlvbkFjdGlvbhIdChVvcmlnaW5hbF90b29sX2NhbGxfaWQYASABKAkSMAoNb3JpZ2luYWxfYXJncxgCIAEoCzIZLmFnZW50LnYxLkFza1F1ZXN0aW9uQXJncxIrCgZyZXN1bHQYAyABKAsyGy5hZ2VudC52MS5Bc2tRdWVzdGlvblJlc3VsdCIRCg9TdW1tYXJpemVBY3Rpb24iVAoSU2hlbGxDb21tYW5kQWN0aW9uEi0KDXNoZWxsX2NvbW1hbmQYASABKAsyFi5hZ2VudC52MS5TaGVsbENvbW1hbmQSDwoHZXhlY19pZBgCIAEoCSKCAQoPU3RhcnRQbGFuQWN0aW9uEisKDHVzZXJfbWVzc2FnZRgBIAEoCzIVLmFnZW50LnYxLlVzZXJNZXNzYWdlEjEKD3JlcXVlc3RfY29udGV4dBgCIAEoCzIYLmFnZW50LnYxLlJlcXVlc3RDb250ZXh0Eg8KB2lzX3NwZWMYAyABKAgi4gEKEUV4ZWN1dGVQbGFuQWN0aW9uEjEKD3JlcXVlc3RfY29udGV4dBgBIAEoCzIYLmFnZW50LnYxLlJlcXVlc3RDb250ZXh0Ei0KBHBsYW4YAiABKAsyGi5hZ2VudC52MS5Db252ZXJzYXRpb25QbGFuSACIAQESGgoNcGxhbl9maWxlX3VyaRgDIAEoCUgBiAEBEh4KEXBsYW5fZmlsZV9jb250ZW50GAQgASgJSAKIAQFCBwoFX3BsYW5CEAoOX3BsYW5fZmlsZV91cmlCFAoSX3BsYW5fZmlsZV9jb250ZW50IugCCgtVc2VyTWVzc2FnZRIMCgR0ZXh0GAEgASgJEhIKCm1lc3NhZ2VfaWQYAiABKAkSOAoQc2VsZWN0ZWRfY29udGV4dBgDIAEoCzIZLmFnZW50LnYxLlNlbGVjdGVkQ29udGV4dEgAiAEBEgwKBG1vZGUYBCABKAUSHQoQaXNfc2ltdWxhdGVkX21zZxgFIAEoCEgBiAEBEh8KEmJlc3Rfb2Zfbl9ncm91cF9pZBgGIAEoCUgCiAEBEigKG3RyeV91c2VfYmVzdF9vZl9uX3Byb21vdGlvbhgHIAEoCEgDiAEBEhYKCXJpY2hfdGV4dBgIIAEoCUgEiAEBQhMKEV9zZWxlY3RlZF9jb250ZXh0QhMKEV9pc19zaW11bGF0ZWRfbXNnQhUKE19iZXN0X29mX25fZ3JvdXBfaWRCHgocX3RyeV91c2VfYmVzdF9vZl9uX3Byb21vdGlvbkIMCgpfcmljaF90ZXh0IiAKEEFzc2lzdGFudE1lc3NhZ2USDAoEdGV4dBgBIAEoCSI0Cg9UaGlua2luZ01lc3NhZ2USDAoEdGV4dBgBIAEoCRITCgtkdXJhdGlvbl9tcxgCIAEoDSIfCgxTaGVsbENvbW1hbmQSDwoHY29tbWFuZBgBIAEoCSJACgtTaGVsbE91dHB1dBIOCgZzdGRvdXQYASABKAkSDgoGc3RkZXJyGAIgASgJEhEKCWV4aXRfY29kZRgDIAEoBSKiAQoQQ29udmVyc2F0aW9uVHVybhJCChdhZ2VudF9jb252ZXJzYXRpb25fdHVybhgBIAEoCzIfLmFnZW50LnYxLkFnZW50Q29udmVyc2F0aW9uVHVybkgAEkIKF3NoZWxsX2NvbnZlcnNhdGlvbl90dXJuGAIgASgLMh8uYWdlbnQudjEuU2hlbGxDb252ZXJzYXRpb25UdXJuSABCBgoEdHVybiIgChBDb252ZXJzYXRpb25QbGFuEgwKBHBsYW4YASABKAkivQEKGUNvbnZlcnNhdGlvblR1cm5TdHJ1Y3R1cmUSSwoXYWdlbnRfY29udmVyc2F0aW9uX3R1cm4YASABKAsyKC5hZ2VudC52MS5BZ2VudENvbnZlcnNhdGlvblR1cm5TdHJ1Y3R1cmVIABJLChdzaGVsbF9jb252ZXJzYXRpb25fdHVybhgCIAEoCzIoLmFnZW50LnYxLlNoZWxsQ29udmVyc2F0aW9uVHVyblN0cnVjdHVyZUgAQgYKBHR1cm4ilwEKFUFnZW50Q29udmVyc2F0aW9uVHVybhIrCgx1c2VyX21lc3NhZ2UYASABKAsyFS5hZ2VudC52MS5Vc2VyTWVzc2FnZRIpCgVzdGVwcxgCIAMoCzIaLmFnZW50LnYxLkNvbnZlcnNhdGlvblN0ZXASFwoKcmVxdWVzdF9pZBgDIAEoCUgAiAEBQg0KC19yZXF1ZXN0X2lkIm0KHkFnZW50Q29udmVyc2F0aW9uVHVyblN0cnVjdHVyZRIUCgx1c2VyX21lc3NhZ2UYASABKAwSDQoFc3RlcHMYAiADKAwSFwoKcmVxdWVzdF9pZBgDIAEoCUgAiAEBQg0KC19yZXF1ZXN0X2lkInMKFVNoZWxsQ29udmVyc2F0aW9uVHVybhItCg1zaGVsbF9jb21tYW5kGAEgASgLMhYuYWdlbnQudjEuU2hlbGxDb21tYW5kEisKDHNoZWxsX291dHB1dBgCIAEoCzIVLmFnZW50LnYxLlNoZWxsT3V0cHV0Ik0KHlNoZWxsQ29udmVyc2F0aW9uVHVyblN0cnVjdHVyZRIVCg1zaGVsbF9jb21tYW5kGAEgASgMEhQKDHNoZWxsX291dHB1dBgCIAEoDCImChNDb252ZXJzYXRpb25TdW1tYXJ5Eg8KB3N1bW1hcnkYASABKAkieAoaQ29udmVyc2F0aW9uU3VtbWFyeUFyY2hpdmUSGwoTc3VtbWFyaXplZF9tZXNzYWdlcxgBIAMoDBIPCgdzdW1tYXJ5GAIgASgJEhMKC3dpbmRvd190YWlsGAMgASgNEhcKD3N1bW1hcnlfbWVzc2FnZRgEIAEoDCJDChhDb252ZXJzYXRpb25Ub2tlbkRldGFpbHMSEwoLdXNlZF90b2tlbnMYASABKA0SEgoKbWF4X3Rva2VucxgCIAEoDSJfCglGaWxlU3RhdGUSFAoHY29udGVudBgBIAEoCUgAiAEBEhwKD2luaXRpYWxfY29udGVudBgCIAEoCUgBiAEBQgoKCF9jb250ZW50QhIKEF9pbml0aWFsX2NvbnRlbnQiaAoSRmlsZVN0YXRlU3RydWN0dXJlEhQKB2NvbnRlbnQYASABKAxIAIgBARIcCg9pbml0aWFsX2NvbnRlbnQYAiABKAxIAYgBAUIKCghfY29udGVudEISChBfaW5pdGlhbF9jb250ZW50IjcKClN0ZXBUaW1pbmcSEwoLZHVyYXRpb25fbXMYASABKAQSFAoMdGltZXN0YW1wX21zGAIgASgEIvYEChFDb252ZXJzYXRpb25TdGF0ZRIhChlyb290X3Byb21wdF9tZXNzYWdlc19qc29uGAEgAygJEikKBXR1cm5zGAggAygLMhouYWdlbnQudjEuQ29udmVyc2F0aW9uVHVybhIhCgV0b2RvcxgDIAMoCzISLmFnZW50LnYxLlRvZG9JdGVtEhoKEnBlbmRpbmdfdG9vbF9jYWxscxgEIAMoCRI5Cg10b2tlbl9kZXRhaWxzGAUgASgLMiIuYWdlbnQudjEuQ29udmVyc2F0aW9uVG9rZW5EZXRhaWxzEjMKB3N1bW1hcnkYBiABKAsyHS5hZ2VudC52MS5Db252ZXJzYXRpb25TdW1tYXJ5SACIAQESLQoEcGxhbhgHIAEoCzIaLmFnZW50LnYxLkNvbnZlcnNhdGlvblBsYW5IAYgBARJCCg9zdW1tYXJ5X2FyY2hpdmUYCSABKAsyJC5hZ2VudC52MS5Db252ZXJzYXRpb25TdW1tYXJ5QXJjaGl2ZUgCiAEBEkAKC2ZpbGVfc3RhdGVzGAogAygLMisuYWdlbnQudjEuQ29udmVyc2F0aW9uU3RhdGUuRmlsZVN0YXRlc0VudHJ5Ej4KEHN1bW1hcnlfYXJjaGl2ZXMYCyADKAsyJC5hZ2VudC52MS5Db252ZXJzYXRpb25TdW1tYXJ5QXJjaGl2ZRpGCg9GaWxlU3RhdGVzRW50cnkSCwoDa2V5GAEgASgJEiIKBXZhbHVlGAIgASgLMhMuYWdlbnQudjEuRmlsZVN0YXRlOgI4AUIKCghfc3VtbWFyeUIHCgVfcGxhbkISChBfc3VtbWFyeV9hcmNoaXZlIscBChZTdWJhZ2VudFBlcnNpc3RlZFN0YXRlEkAKEmNvbnZlcnNhdGlvbl9zdGF0ZRgBIAEoCzIkLmFnZW50LnYxLkNvbnZlcnNhdGlvblN0YXRlU3RydWN0dXJlEhwKFGNyZWF0ZWRfdGltZXN0YW1wX21zGAIgASgEEh4KFmxhc3RfdXNlZF90aW1lc3RhbXBfbXMYAyABKAQSLQoNc3ViYWdlbnRfdHlwZRgEIAEoCzIWLmFnZW50LnYxLlN1YmFnZW50VHlwZSK3BwoaQ29udmVyc2F0aW9uU3RhdGVTdHJ1Y3R1cmUSEQoJdHVybnNfb2xkGAIgAygMEiEKGXJvb3RfcHJvbXB0X21lc3NhZ2VzX2pzb24YASADKAwSDQoFdHVybnMYCCADKAwSDQoFdG9kb3MYAyADKAwSGgoScGVuZGluZ190b29sX2NhbGxzGAQgAygJEjkKDXRva2VuX2RldGFpbHMYBSABKAsyIi5hZ2VudC52MS5Db252ZXJzYXRpb25Ub2tlbkRldGFpbHMSFAoHc3VtbWFyeRgGIAEoDEgAiAEBEhEKBHBsYW4YByABKAxIAYgBARIfChdwcmV2aW91c193b3Jrc3BhY2VfdXJpcxgJIAMoCRIRCgRtb2RlGAogASgFSAKIAQESHAoPc3VtbWFyeV9hcmNoaXZlGAsgASgMSAOIAQESSQoLZmlsZV9zdGF0ZXMYDCADKAsyNC5hZ2VudC52MS5Db252ZXJzYXRpb25TdGF0ZVN0cnVjdHVyZS5GaWxlU3RhdGVzRW50cnkSTgoOZmlsZV9zdGF0ZXNfdjIYDyADKAsyNi5hZ2VudC52MS5Db252ZXJzYXRpb25TdGF0ZVN0cnVjdHVyZS5GaWxlU3RhdGVzVjJFbnRyeRIYChBzdW1tYXJ5X2FyY2hpdmVzGA0gAygMEioKDHR1cm5fdGltaW5ncxgOIAMoCzIULmFnZW50LnYxLlN0ZXBUaW1pbmcSUQoPc3ViYWdlbnRfc3RhdGVzGBAgAygLMjguYWdlbnQudjEuQ29udmVyc2F0aW9uU3RhdGVTdHJ1Y3R1cmUuU3ViYWdlbnRTdGF0ZXNFbnRyeRIaChJzZWxmX3N1bW1hcnlfY291bnQYESABKA0SEgoKcmVhZF9wYXRocxgSIAMoCRoxCg9GaWxlU3RhdGVzRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgMOgI4ARpRChFGaWxlU3RhdGVzVjJFbnRyeRILCgNrZXkYASABKAkSKwoFdmFsdWUYAiABKAsyHC5hZ2VudC52MS5GaWxlU3RhdGVTdHJ1Y3R1cmU6AjgBGlcKE1N1YmFnZW50U3RhdGVzRW50cnkSCwoDa2V5GAEgASgJEi8KBXZhbHVlGAIgASgLMiAuYWdlbnQudjEuU3ViYWdlbnRQZXJzaXN0ZWRTdGF0ZToCOAFCCgoIX3N1bW1hcnlCBwoFX3BsYW5CBwoFX21vZGVCEgoQX3N1bW1hcnlfYXJjaGl2ZSIRCg9UaGlua2luZ0RldGFpbHMiSAoRQXBpS2V5Q3JlZGVudGlhbHMSDwoHYXBpX2tleRgBIAEoCRIVCghiYXNlX3VybBgCIAEoCUgAiAEBQgsKCV9iYXNlX3VybCJJChBBenVyZUNyZWRlbnRpYWxzEg8KB2FwaV9rZXkYASABKAkSEAoIYmFzZV91cmwYAiABKAkSEgoKZGVwbG95bWVudBgDIAEoCSJ6ChJCZWRyb2NrQ3JlZGVudGlhbHMSEgoKYWNjZXNzX2tleRgBIAEoCRISCgpzZWNyZXRfa2V5GAIgASgJEg4KBnJlZ2lvbhgDIAEoCRIaCg1zZXNzaW9uX3Rva2VuGAQgASgJSACIAQFCEAoOX3Nlc3Npb25fdG9rZW4isQMKDE1vZGVsRGV0YWlscxIQCghtb2RlbF9pZBgBIAEoCRIYChBkaXNwbGF5X21vZGVsX2lkGAMgASgJEhQKDGRpc3BsYXlfbmFtZRgEIAEoCRIaChJkaXNwbGF5X25hbWVfc2hvcnQYBSABKAkSDwoHYWxpYXNlcxgGIAMoCRI4ChB0aGlua2luZ19kZXRhaWxzGAIgASgLMhkuYWdlbnQudjEuVGhpbmtpbmdEZXRhaWxzSAGIAQESFQoIbWF4X21vZGUYByABKAhIAogBARI6ChNhcGlfa2V5X2NyZWRlbnRpYWxzGAggASgLMhsuYWdlbnQudjEuQXBpS2V5Q3JlZGVudGlhbHNIABI3ChFhenVyZV9jcmVkZW50aWFscxgJIAEoCzIaLmFnZW50LnYxLkF6dXJlQ3JlZGVudGlhbHNIABI7ChNiZWRyb2NrX2NyZWRlbnRpYWxzGAogASgLMhwuYWdlbnQudjEuQmVkcm9ja0NyZWRlbnRpYWxzSABCDQoLY3JlZGVudGlhbHNCEwoRX3RoaW5raW5nX2RldGFpbHNCCwoJX21heF9tb2RlIrcCCg5SZXF1ZXN0ZWRNb2RlbBIQCghtb2RlbF9pZBgBIAEoCRIQCghtYXhfbW9kZRgCIAEoCBJACgpwYXJhbWV0ZXJzGAMgAygLMiwuYWdlbnQudjEuUmVxdWVzdGVkTW9kZWxfTW9kZWxQYXJhbWV0ZXJieXRlcxI6ChNhcGlfa2V5X2NyZWRlbnRpYWxzGAQgASgLMhsuYWdlbnQudjEuQXBpS2V5Q3JlZGVudGlhbHNIABI3ChFhenVyZV9jcmVkZW50aWFscxgFIAEoCzIaLmFnZW50LnYxLkF6dXJlQ3JlZGVudGlhbHNIABI7ChNiZWRyb2NrX2NyZWRlbnRpYWxzGAYgASgLMhwuYWdlbnQudjEuQmVkcm9ja0NyZWRlbnRpYWxzSABCDQoLY3JlZGVudGlhbHMiPwoiUmVxdWVzdGVkTW9kZWxfTW9kZWxQYXJhbWV0ZXJieXRlcxIKCgJpZBgBIAEoCRINCgV2YWx1ZRgCIAEoCSK5BAoPQWdlbnRSdW5SZXF1ZXN0EkAKEmNvbnZlcnNhdGlvbl9zdGF0ZRgBIAEoCzIkLmFnZW50LnYxLkNvbnZlcnNhdGlvblN0YXRlU3RydWN0dXJlEiwKBmFjdGlvbhgCIAEoCzIcLmFnZW50LnYxLkNvbnZlcnNhdGlvbkFjdGlvbhItCg1tb2RlbF9kZXRhaWxzGAMgASgLMhYuYWdlbnQudjEuTW9kZWxEZXRhaWxzEjYKD3JlcXVlc3RlZF9tb2RlbBgJIAEoCzIYLmFnZW50LnYxLlJlcXVlc3RlZE1vZGVsSACIAQESJQoJbWNwX3Rvb2xzGAQgASgLMhIuYWdlbnQudjEuTWNwVG9vbHMSHAoPY29udmVyc2F0aW9uX2lkGAUgASgJSAGIAQESRAoXbWNwX2ZpbGVfc3lzdGVtX29wdGlvbnMYBiABKAsyHi5hZ2VudC52MS5NY3BGaWxlU3lzdGVtT3B0aW9uc0gCiAEBEjIKDXNraWxsX29wdGlvbnMYByABKAsyFi5hZ2VudC52MS5Ta2lsbE9wdGlvbnNIA4gBARIhChRjdXN0b21fc3lzdGVtX3Byb21wdBgIIAEoCUgEiAEBQhIKEF9yZXF1ZXN0ZWRfbW9kZWxCEgoQX2NvbnZlcnNhdGlvbl9pZEIaChhfbWNwX2ZpbGVfc3lzdGVtX29wdGlvbnNCEAoOX3NraWxsX29wdGlvbnNCFwoVX2N1c3RvbV9zeXN0ZW1fcHJvbXB0Ih8KD1RleHREZWx0YVVwZGF0ZRIMCgR0ZXh0GAEgASgJImYKFVRvb2xDYWxsU3RhcnRlZFVwZGF0ZRIPCgdjYWxsX2lkGAEgASgJEiUKCXRvb2xfY2FsbBgCIAEoCzISLmFnZW50LnYxLlRvb2xDYWxsEhUKDW1vZGVsX2NhbGxfaWQYAyABKAkiaAoXVG9vbENhbGxDb21wbGV0ZWRVcGRhdGUSDwoHY2FsbF9pZBgBIAEoCRIlCgl0b29sX2NhbGwYAiABKAsyEi5hZ2VudC52MS5Ub29sQ2FsbBIVCg1tb2RlbF9jYWxsX2lkGAMgASgJIm8KE1Rvb2xDYWxsRGVsdGFVcGRhdGUSDwoHY2FsbF9pZBgBIAEoCRIwCg90b29sX2NhbGxfZGVsdGEYAiABKAsyFy5hZ2VudC52MS5Ub29sQ2FsbERlbHRhEhUKDW1vZGVsX2NhbGxfaWQYAyABKAkifwoVUGFydGlhbFRvb2xDYWxsVXBkYXRlEg8KB2NhbGxfaWQYASABKAkSJQoJdG9vbF9jYWxsGAIgASgLMhIuYWdlbnQudjEuVG9vbENhbGwSFwoPYXJnc190ZXh0X2RlbHRhGAMgASgJEhUKDW1vZGVsX2NhbGxfaWQYBCABKAkiIwoTVGhpbmtpbmdEZWx0YVVwZGF0ZRIMCgR0ZXh0GAEgASgJIjcKF1RoaW5raW5nQ29tcGxldGVkVXBkYXRlEhwKFHRoaW5raW5nX2R1cmF0aW9uX21zGAEgASgFIiIKEFRva2VuRGVsdGFVcGRhdGUSDgoGdG9rZW5zGAEgASgFIiAKDVN1bW1hcnlVcGRhdGUSDwoHc3VtbWFyeRgBIAEoCSIWChRTdW1tYXJ5U3RhcnRlZFVwZGF0ZSIRCg9IZWFydGJlYXRVcGRhdGUiGAoWU3VtbWFyeUNvbXBsZXRlZFVwZGF0ZSLXAQoWU2hlbGxPdXRwdXREZWx0YVVwZGF0ZRItCgZzdGRvdXQYASABKAsyGy5hZ2VudC52MS5TaGVsbFN0cmVhbVN0ZG91dEgAEi0KBnN0ZGVychgCIAEoCzIbLmFnZW50LnYxLlNoZWxsU3RyZWFtU3RkZXJySAASKQoEZXhpdBgDIAEoCzIZLmFnZW50LnYxLlNoZWxsU3RyZWFtRXhpdEgAEisKBXN0YXJ0GAQgASgLMhouYWdlbnQudjEuU2hlbGxTdHJlYW1TdGFydEgAQgcKBWV2ZW50IhEKD1R1cm5FbmRlZFVwZGF0ZSJIChlVc2VyTWVzc2FnZUFwcGVuZGVkVXBkYXRlEisKDHVzZXJfbWVzc2FnZRgBIAEoCzIVLmFnZW50LnYxLlVzZXJNZXNzYWdlIiQKEVN0ZXBTdGFydGVkVXBkYXRlEg8KB3N0ZXBfaWQYASABKAQiQAoTU3RlcENvbXBsZXRlZFVwZGF0ZRIPCgdzdGVwX2lkGAEgASgEEhgKEHN0ZXBfZHVyYXRpb25fbXMYAiABKAMi7wcKEUludGVyYWN0aW9uVXBkYXRlEi8KCnRleHRfZGVsdGEYASABKAsyGS5hZ2VudC52MS5UZXh0RGVsdGFVcGRhdGVIABI8ChFwYXJ0aWFsX3Rvb2xfY2FsbBgHIAEoCzIfLmFnZW50LnYxLlBhcnRpYWxUb29sQ2FsbFVwZGF0ZUgAEjgKD3Rvb2xfY2FsbF9kZWx0YRgPIAEoCzIdLmFnZW50LnYxLlRvb2xDYWxsRGVsdGFVcGRhdGVIABI8ChF0b29sX2NhbGxfc3RhcnRlZBgCIAEoCzIfLmFnZW50LnYxLlRvb2xDYWxsU3RhcnRlZFVwZGF0ZUgAEkAKE3Rvb2xfY2FsbF9jb21wbGV0ZWQYAyABKAsyIS5hZ2VudC52MS5Ub29sQ2FsbENvbXBsZXRlZFVwZGF0ZUgAEjcKDnRoaW5raW5nX2RlbHRhGAQgASgLMh0uYWdlbnQudjEuVGhpbmtpbmdEZWx0YVVwZGF0ZUgAEj8KEnRoaW5raW5nX2NvbXBsZXRlZBgFIAEoCzIhLmFnZW50LnYxLlRoaW5raW5nQ29tcGxldGVkVXBkYXRlSAASRAoVdXNlcl9tZXNzYWdlX2FwcGVuZGVkGAYgASgLMiMuYWdlbnQudjEuVXNlck1lc3NhZ2VBcHBlbmRlZFVwZGF0ZUgAEjEKC3Rva2VuX2RlbHRhGAggASgLMhouYWdlbnQudjEuVG9rZW5EZWx0YVVwZGF0ZUgAEioKB3N1bW1hcnkYCSABKAsyFy5hZ2VudC52MS5TdW1tYXJ5VXBkYXRlSAASOQoPc3VtbWFyeV9zdGFydGVkGAogASgLMh4uYWdlbnQudjEuU3VtbWFyeVN0YXJ0ZWRVcGRhdGVIABI9ChFzdW1tYXJ5X2NvbXBsZXRlZBgLIAEoCzIgLmFnZW50LnYxLlN1bW1hcnlDb21wbGV0ZWRVcGRhdGVIABI+ChJzaGVsbF9vdXRwdXRfZGVsdGEYDCABKAsyIC5hZ2VudC52MS5TaGVsbE91dHB1dERlbHRhVXBkYXRlSAASLgoJaGVhcnRiZWF0GA0gASgLMhkuYWdlbnQudjEuSGVhcnRiZWF0VXBkYXRlSAASLwoKdHVybl9lbmRlZBgOIAEoCzIZLmFnZW50LnYxLlR1cm5FbmRlZFVwZGF0ZUgAEjMKDHN0ZXBfc3RhcnRlZBgQIAEoCzIbLmFnZW50LnYxLlN0ZXBTdGFydGVkVXBkYXRlSAASNwoOc3RlcF9jb21wbGV0ZWQYESABKAsyHS5hZ2VudC52MS5TdGVwQ29tcGxldGVkVXBkYXRlSABCCQoHbWVzc2FnZSKaBAoQSW50ZXJhY3Rpb25RdWVyeRIKCgJpZBgBIAEoDRJDChh3ZWJfc2VhcmNoX3JlcXVlc3RfcXVlcnkYAiABKAsyHy5hZ2VudC52MS5XZWJTZWFyY2hSZXF1ZXN0UXVlcnlIABJPCh5hc2tfcXVlc3Rpb25faW50ZXJhY3Rpb25fcXVlcnkYAyABKAsyJS5hZ2VudC52MS5Bc2tRdWVzdGlvbkludGVyYWN0aW9uUXVlcnlIABJFChlzd2l0Y2hfbW9kZV9yZXF1ZXN0X3F1ZXJ5GAQgASgLMiAuYWdlbnQudjEuU3dpdGNoTW9kZVJlcXVlc3RRdWVyeUgAEkMKGGV4YV9zZWFyY2hfcmVxdWVzdF9xdWVyeRgFIAEoCzIfLmFnZW50LnYxLkV4YVNlYXJjaFJlcXVlc3RRdWVyeUgAEkEKF2V4YV9mZXRjaF9yZXF1ZXN0X3F1ZXJ5GAYgASgLMh4uYWdlbnQudjEuRXhhRmV0Y2hSZXF1ZXN0UXVlcnlIABJFChljcmVhdGVfcGxhbl9yZXF1ZXN0X3F1ZXJ5GAcgASgLMiAuYWdlbnQudjEuQ3JlYXRlUGxhblJlcXVlc3RRdWVyeUgAEkUKGXNldHVwX3ZtX2Vudmlyb25tZW50X2FyZ3MYCCABKAsyIC5hZ2VudC52MS5TZXR1cFZtRW52aXJvbm1lbnRBcmdzSABCBwoFcXVlcnkixgQKE0ludGVyYWN0aW9uUmVzcG9uc2USCgoCaWQYASABKA0SSQobd2ViX3NlYXJjaF9yZXF1ZXN0X3Jlc3BvbnNlGAIgASgLMiIuYWdlbnQudjEuV2ViU2VhcmNoUmVxdWVzdFJlc3BvbnNlSAASVQohYXNrX3F1ZXN0aW9uX2ludGVyYWN0aW9uX3Jlc3BvbnNlGAMgASgLMiguYWdlbnQudjEuQXNrUXVlc3Rpb25JbnRlcmFjdGlvblJlc3BvbnNlSAASSwocc3dpdGNoX21vZGVfcmVxdWVzdF9yZXNwb25zZRgEIAEoCzIjLmFnZW50LnYxLlN3aXRjaE1vZGVSZXF1ZXN0UmVzcG9uc2VIABJJChtleGFfc2VhcmNoX3JlcXVlc3RfcmVzcG9uc2UYBSABKAsyIi5hZ2VudC52MS5FeGFTZWFyY2hSZXF1ZXN0UmVzcG9uc2VIABJHChpleGFfZmV0Y2hfcmVxdWVzdF9yZXNwb25zZRgGIAEoCzIhLmFnZW50LnYxLkV4YUZldGNoUmVxdWVzdFJlc3BvbnNlSAASSwocY3JlYXRlX3BsYW5fcmVxdWVzdF9yZXNwb25zZRgHIAEoCzIjLmFnZW50LnYxLkNyZWF0ZVBsYW5SZXF1ZXN0UmVzcG9uc2VIABJJChtzZXR1cF92bV9lbnZpcm9ubWVudF9yZXN1bHQYCCABKAsyIi5hZ2VudC52MS5TZXR1cFZtRW52aXJvbm1lbnRSZXN1bHRIAEIICgZyZXN1bHQiXAobQXNrUXVlc3Rpb25JbnRlcmFjdGlvblF1ZXJ5EicKBGFyZ3MYASABKAsyGS5hZ2VudC52MS5Bc2tRdWVzdGlvbkFyZ3MSFAoMdG9vbF9jYWxsX2lkGAIgASgJIk0KHkFza1F1ZXN0aW9uSW50ZXJhY3Rpb25SZXNwb25zZRIrCgZyZXN1bHQYASABKAsyGy5hZ2VudC52MS5Bc2tRdWVzdGlvblJlc3VsdCIRCg9DbGllbnRIZWFydGJlYXQixgQKDlByZXdhcm1SZXF1ZXN0Ei0KDW1vZGVsX2RldGFpbHMYASABKAsyFi5hZ2VudC52MS5Nb2RlbERldGFpbHMSNgoPcmVxdWVzdGVkX21vZGVsGAkgASgLMhguYWdlbnQudjEuUmVxdWVzdGVkTW9kZWxIAIgBARIcCg9jb252ZXJzYXRpb25faWQYAiABKAlIAYgBARJAChJjb252ZXJzYXRpb25fc3RhdGUYAyABKAsyJC5hZ2VudC52MS5Db252ZXJzYXRpb25TdGF0ZVN0cnVjdHVyZRIlCgltY3BfdG9vbHMYBCABKAsyEi5hZ2VudC52MS5NY3BUb29scxJEChdtY3BfZmlsZV9zeXN0ZW1fb3B0aW9ucxgFIAEoCzIeLmFnZW50LnYxLk1jcEZpbGVTeXN0ZW1PcHRpb25zSAKIAQESHwoSYmVzdF9vZl9uX2dyb3VwX2lkGAYgASgJSAOIAQESKAobdHJ5X3VzZV9iZXN0X29mX25fcHJvbW90aW9uGAcgASgISASIAQESIQoUY3VzdG9tX3N5c3RlbV9wcm9tcHQYCCABKAlIBYgBAUISChBfcmVxdWVzdGVkX21vZGVsQhIKEF9jb252ZXJzYXRpb25faWRCGgoYX21jcF9maWxlX3N5c3RlbV9vcHRpb25zQhUKE19iZXN0X29mX25fZ3JvdXBfaWRCHgocX3RyeV91c2VfYmVzdF9vZl9uX3Byb21vdGlvbkIXChVfY3VzdG9tX3N5c3RlbV9wcm9tcHQiHQoPRXhlY1NlcnZlckFib3J0EgoKAmlkGAEgASgNIlEKGEV4ZWNTZXJ2ZXJDb250cm9sTWVzc2FnZRIqCgVhYm9ydBgBIAEoCzIZLmFnZW50LnYxLkV4ZWNTZXJ2ZXJBYm9ydEgAQgkKB21lc3NhZ2Ui+AMKEkFnZW50Q2xpZW50TWVzc2FnZRIwCgtydW5fcmVxdWVzdBgBIAEoCzIZLmFnZW50LnYxLkFnZW50UnVuUmVxdWVzdEgAEjoKE2V4ZWNfY2xpZW50X21lc3NhZ2UYAiABKAsyGy5hZ2VudC52MS5FeGVjQ2xpZW50TWVzc2FnZUgAEkkKG2V4ZWNfY2xpZW50X2NvbnRyb2xfbWVzc2FnZRgFIAEoCzIiLmFnZW50LnYxLkV4ZWNDbGllbnRDb250cm9sTWVzc2FnZUgAEjYKEWt2X2NsaWVudF9tZXNzYWdlGAMgASgLMhkuYWdlbnQudjEuS3ZDbGllbnRNZXNzYWdlSAASOwoTY29udmVyc2F0aW9uX2FjdGlvbhgEIAEoCzIcLmFnZW50LnYxLkNvbnZlcnNhdGlvbkFjdGlvbkgAEj0KFGludGVyYWN0aW9uX3Jlc3BvbnNlGAYgASgLMh0uYWdlbnQudjEuSW50ZXJhY3Rpb25SZXNwb25zZUgAEjUKEGNsaWVudF9oZWFydGJlYXQYByABKAsyGS5hZ2VudC52MS5DbGllbnRIZWFydGJlYXRIABIzCg9wcmV3YXJtX3JlcXVlc3QYCCABKAsyGC5hZ2VudC52MS5QcmV3YXJtUmVxdWVzdEgAQgkKB21lc3NhZ2UiogMKEkFnZW50U2VydmVyTWVzc2FnZRI5ChJpbnRlcmFjdGlvbl91cGRhdGUYASABKAsyGy5hZ2VudC52MS5JbnRlcmFjdGlvblVwZGF0ZUgAEjoKE2V4ZWNfc2VydmVyX21lc3NhZ2UYAiABKAsyGy5hZ2VudC52MS5FeGVjU2VydmVyTWVzc2FnZUgAEkkKG2V4ZWNfc2VydmVyX2NvbnRyb2xfbWVzc2FnZRgFIAEoCzIiLmFnZW50LnYxLkV4ZWNTZXJ2ZXJDb250cm9sTWVzc2FnZUgAEk4KHmNvbnZlcnNhdGlvbl9jaGVja3BvaW50X3VwZGF0ZRgDIAEoCzIkLmFnZW50LnYxLkNvbnZlcnNhdGlvblN0YXRlU3RydWN0dXJlSAASNgoRa3Zfc2VydmVyX21lc3NhZ2UYBCABKAsyGS5hZ2VudC52MS5LdlNlcnZlck1lc3NhZ2VIABI3ChFpbnRlcmFjdGlvbl9xdWVyeRgHIAEoCzIaLmFnZW50LnYxLkludGVyYWN0aW9uUXVlcnlIAEIJCgdtZXNzYWdlIigKEE5hbWVBZ2VudFJlcXVlc3QSFAoMdXNlcl9tZXNzYWdlGAEgASgJIiEKEU5hbWVBZ2VudFJlc3BvbnNlEgwKBG5hbWUYASABKAkiMgoWR2V0VXNhYmxlTW9kZWxzUmVxdWVzdBIYChBjdXN0b21fbW9kZWxfaWRzGAEgAygJIkEKF0dldFVzYWJsZU1vZGVsc1Jlc3BvbnNlEiYKBm1vZGVscxgBIAMoCzIWLmFnZW50LnYxLk1vZGVsRGV0YWlscyIeChxHZXREZWZhdWx0TW9kZWxGb3JDbGlSZXF1ZXN0IkYKHUdldERlZmF1bHRNb2RlbEZvckNsaVJlc3BvbnNlEiUKBW1vZGVsGAEgASgLMhYuYWdlbnQudjEuTW9kZWxEZXRhaWxzIh8KHUdldEFsbG93ZWRNb2RlbEludGVudHNSZXF1ZXN0IjcKHkdldEFsbG93ZWRNb2RlbEludGVudHNSZXNwb25zZRIVCg1tb2RlbF9pbnRlbnRzGAEgAygJIpcCChNJZGVFZGl0b3JzU3RhdGVGaWxlEhUKDXJlbGF0aXZlX3BhdGgYASABKAkSFQoNYWJzb2x1dGVfcGF0aBgCIAEoCRIhChRpc19jdXJyZW50bHlfZm9jdXNlZBgDIAEoCEgAiAEBEiAKE2N1cnJlbnRfbGluZV9udW1iZXIYBCABKAVIAYgBARIeChFjdXJyZW50X2xpbmVfdGV4dBgFIAEoCUgCiAEBEhcKCmxpbmVfY291bnQYBiABKAVIA4gBAUIXChVfaXNfY3VycmVudGx5X2ZvY3VzZWRCFgoUX2N1cnJlbnRfbGluZV9udW1iZXJCFAoSX2N1cnJlbnRfbGluZV90ZXh0Qg0KC19saW5lX2NvdW50IlMKE0lkZUVkaXRvcnNTdGF0ZUxpdGUSPAoVcmVjZW50bHlfdmlld2VkX2ZpbGVzGAEgAygLMh0uYWdlbnQudjEuSWRlRWRpdG9yc1N0YXRlRmlsZSJ0ChZBcHBseUFnZW50RGlmZlRvb2xDYWxsEioKBGFyZ3MYASABKAsyHC5hZ2VudC52MS5BcHBseUFnZW50RGlmZkFyZ3MSLgoGcmVzdWx0GAIgASgLMh4uYWdlbnQudjEuQXBwbHlBZ2VudERpZmZSZXN1bHQiJgoSQXBwbHlBZ2VudERpZmZBcmdzEhAKCGFnZW50X2lkGAEgASgJIoQBChRBcHBseUFnZW50RGlmZlJlc3VsdBIyCgdzdWNjZXNzGAEgASgLMh8uYWdlbnQudjEuQXBwbHlBZ2VudERpZmZTdWNjZXNzSAASLgoFZXJyb3IYAiABKAsyHS5hZ2VudC52MS5BcHBseUFnZW50RGlmZkVycm9ySABCCAoGcmVzdWx0Ik4KFUFwcGx5QWdlbnREaWZmU3VjY2VzcxI1Cg9hcHBsaWVkX2NoYW5nZXMYASADKAsyHC5hZ2VudC52MS5BcHBsaWVkQWdlbnRDaGFuZ2Ui6QEKEkFwcGxpZWRBZ2VudENoYW5nZRIMCgRwYXRoGAEgASgJEhMKC2NoYW5nZV90eXBlGAIgASgFEhsKDmJlZm9yZV9jb250ZW50GAMgASgJSACIAQESGgoNYWZ0ZXJfY29udGVudBgEIAEoCUgBiAEBEhIKBWVycm9yGAUgASgJSAKIAQESHgoRbWVzc2FnZV9mb3JfbW9kZWwYBiABKAlIA4gBAUIRCg9fYmVmb3JlX2NvbnRlbnRCEAoOX2FmdGVyX2NvbnRlbnRCCAoGX2Vycm9yQhQKEl9tZXNzYWdlX2Zvcl9tb2RlbCJbChNBcHBseUFnZW50RGlmZkVycm9yEg0KBWVycm9yGAEgASgJEjUKD2FwcGxpZWRfY2hhbmdlcxgCIAMoCzIcLmFnZW50LnYxLkFwcGxpZWRBZ2VudENoYW5nZSJrChNBc2tRdWVzdGlvblRvb2xDYWxsEicKBGFyZ3MYASABKAsyGS5hZ2VudC52MS5Bc2tRdWVzdGlvbkFyZ3MSKwoGcmVzdWx0GAIgASgLMhsuYWdlbnQudjEuQXNrUXVlc3Rpb25SZXN1bHQijwEKD0Fza1F1ZXN0aW9uQXJncxINCgV0aXRsZRgBIAEoCRI1CglxdWVzdGlvbnMYAiADKAsyIi5hZ2VudC52MS5Bc2tRdWVzdGlvbkFyZ3NfUXVlc3Rpb24SEQoJcnVuX2FzeW5jGAUgASgIEiMKG2FzeW5jX29yaWdpbmFsX3Rvb2xfY2FsbF9pZBgGIAEoCSKBAQoYQXNrUXVlc3Rpb25BcmdzX1F1ZXN0aW9uEgoKAmlkGAEgASgJEg4KBnByb21wdBgCIAEoCRIxCgdvcHRpb25zGAMgAygLMiAuYWdlbnQudjEuQXNrUXVlc3Rpb25BcmdzX09wdGlvbhIWCg5hbGxvd19tdWx0aXBsZRgEIAEoCCIzChZBc2tRdWVzdGlvbkFyZ3NfT3B0aW9uEgoKAmlkGAEgASgJEg0KBWxhYmVsGAIgASgJIhIKEEFza1F1ZXN0aW9uQXN5bmMi2wEKEUFza1F1ZXN0aW9uUmVzdWx0Ei8KB3N1Y2Nlc3MYASABKAsyHC5hZ2VudC52MS5Bc2tRdWVzdGlvblN1Y2Nlc3NIABIrCgVlcnJvchgCIAEoCzIaLmFnZW50LnYxLkFza1F1ZXN0aW9uRXJyb3JIABIxCghyZWplY3RlZBgDIAEoCzIdLmFnZW50LnYxLkFza1F1ZXN0aW9uUmVqZWN0ZWRIABIrCgVhc3luYxgEIAEoCzIaLmFnZW50LnYxLkFza1F1ZXN0aW9uQXN5bmNIAEIICgZyZXN1bHQiSgoSQXNrUXVlc3Rpb25TdWNjZXNzEjQKB2Fuc3dlcnMYASADKAsyIy5hZ2VudC52MS5Bc2tRdWVzdGlvblN1Y2Nlc3NfQW5zd2VyIk0KGUFza1F1ZXN0aW9uU3VjY2Vzc19BbnN3ZXISEwoLcXVlc3Rpb25faWQYASABKAkSGwoTc2VsZWN0ZWRfb3B0aW9uX2lkcxgCIAMoCSIpChBBc2tRdWVzdGlvbkVycm9yEhUKDWVycm9yX21lc3NhZ2UYASABKAkiJQoTQXNrUXVlc3Rpb25SZWplY3RlZBIOCgZyZWFzb24YASABKAki/QUKGEJhY2tncm91bmRTaGVsbFNwYXduQXJncxIPCgdjb21tYW5kGAEgASgJEhkKEXdvcmtpbmdfZGlyZWN0b3J5GAIgASgJEhQKDHRvb2xfY2FsbF9pZBgDIAEoCRI7Cg5wYXJzaW5nX3Jlc3VsdBgEIAEoCzIjLmFnZW50LnYxLlNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQSNAoOc2FuZGJveF9wb2xpY3kYBSABKAsyFy5hZ2VudC52MS5TYW5kYm94UG9saWN5SACIAQESJQodZW5hYmxlX3dyaXRlX3NoZWxsX3N0ZGluX3Rvb2wYBiABKAgSGAoLZGVzY3JpcHRpb24YByABKAlIAYgBARJBChFjbGFzc2lmaWVyX3Jlc3VsdBgIIAEoCzIhLmFnZW50LnYxLkNvbW1hbmRDbGFzc2lmaWVyUmVzdWx0SAKIAQESSQoTb3V0cHV0X25vdGlmaWNhdGlvbhgJIAEoCzInLmFnZW50LnYxLlNoZWxsT3V0cHV0Tm90aWZpY2F0aW9uQ29uZmlnSAOIAQESPQoTc21hcnRfbW9kZV9hcHByb3ZhbBgKIAEoCzIbLmFnZW50LnYxLlNtYXJ0TW9kZUFwcHJvdmFsSASIAQESTgoZaG9va19hcHByb3ZhbF9yZXF1aXJlbWVudBgLIAEoCzImLmFnZW50LnYxLlNoZWxsSG9va0FwcHJvdmFsUmVxdWlyZW1lbnRIBYgBARIVCg1za2lwX2FwcHJvdmFsGAwgASgIEhwKD2NvbnZlcnNhdGlvbl9pZBgNIAEoCUgGiAEBQhEKD19zYW5kYm94X3BvbGljeUIOCgxfZGVzY3JpcHRpb25CFAoSX2NsYXNzaWZpZXJfcmVzdWx0QhYKFF9vdXRwdXRfbm90aWZpY2F0aW9uQhYKFF9zbWFydF9tb2RlX2FwcHJvdmFsQhwKGl9ob29rX2FwcHJvdmFsX3JlcXVpcmVtZW50QhIKEF9jb252ZXJzYXRpb25faWQigQIKGkJhY2tncm91bmRTaGVsbFNwYXduUmVzdWx0EjgKB3N1Y2Nlc3MYASABKAsyJS5hZ2VudC52MS5CYWNrZ3JvdW5kU2hlbGxTcGF3blN1Y2Nlc3NIABI0CgVlcnJvchgCIAEoCzIjLmFnZW50LnYxLkJhY2tncm91bmRTaGVsbFNwYXduRXJyb3JIABIrCghyZWplY3RlZBgDIAEoCzIXLmFnZW50LnYxLlNoZWxsUmVqZWN0ZWRIABI8ChFwZXJtaXNzaW9uX2RlbmllZBgEIAEoCzIfLmFnZW50LnYxLlNoZWxsUGVybWlzc2lvbkRlbmllZEgAQggKBnJlc3VsdCJ1ChtCYWNrZ3JvdW5kU2hlbGxTcGF3blN1Y2Nlc3MSEAoIc2hlbGxfaWQYASABKA0SDwoHY29tbWFuZBgCIAEoCRIZChF3b3JraW5nX2RpcmVjdG9yeRgDIAEoCRIQCgNwaWQYBCABKA1IAIgBAUIGCgRfcGlkIlYKGUJhY2tncm91bmRTaGVsbFNwYXduRXJyb3ISDwoHY29tbWFuZBgBIAEoCRIZChF3b3JraW5nX2RpcmVjdG9yeRgCIAEoCRINCgVlcnJvchgDIAEoCSI2ChNXcml0ZVNoZWxsU3RkaW5BcmdzEhAKCHNoZWxsX2lkGAEgASgNEg0KBWNoYXJzGAIgASgJIocBChVXcml0ZVNoZWxsU3RkaW5SZXN1bHQSMwoHc3VjY2VzcxgBIAEoCzIgLmFnZW50LnYxLldyaXRlU2hlbGxTdGRpblN1Y2Nlc3NIABIvCgVlcnJvchgCIAEoCzIeLmFnZW50LnYxLldyaXRlU2hlbGxTdGRpbkVycm9ySABCCAoGcmVzdWx0Il0KFldyaXRlU2hlbGxTdGRpblN1Y2Nlc3MSEAoIc2hlbGxfaWQYASABKA0SMQopdGVybWluYWxfZmlsZV9sZW5ndGhfYmVmb3JlX2lucHV0X3dyaXR0ZW4YAiABKA0iJQoUV3JpdGVTaGVsbFN0ZGluRXJyb3ISDQoFZXJyb3IYASABKAkiIgoKQ29vcmRpbmF0ZRIJCgF4GAEgASgFEgkKAXkYAiABKAUiVQoPQ29tcHV0ZXJVc2VBcmdzEhQKDHRvb2xfY2FsbF9pZBgBIAEoCRIsCgdhY3Rpb25zGAIgAygLMhsuYWdlbnQudjEuQ29tcHV0ZXJVc2VBY3Rpb24igQQKEUNvbXB1dGVyVXNlQWN0aW9uEi8KCm1vdXNlX21vdmUYASABKAsyGS5hZ2VudC52MS5Nb3VzZU1vdmVBY3Rpb25IABImCgVjbGljaxgCIAEoCzIVLmFnZW50LnYxLkNsaWNrQWN0aW9uSAASLwoKbW91c2VfZG93bhgDIAEoCzIZLmFnZW50LnYxLk1vdXNlRG93bkFjdGlvbkgAEisKCG1vdXNlX3VwGAQgASgLMhcuYWdlbnQudjEuTW91c2VVcEFjdGlvbkgAEiQKBGRyYWcYBSABKAsyFC5hZ2VudC52MS5EcmFnQWN0aW9uSAASKAoGc2Nyb2xsGAYgASgLMhYuYWdlbnQudjEuU2Nyb2xsQWN0aW9uSAASJAoEdHlwZRgHIAEoCzIULmFnZW50LnYxLlR5cGVBY3Rpb25IABIiCgNrZXkYCCABKAsyEy5hZ2VudC52MS5LZXlBY3Rpb25IABIkCgR3YWl0GAkgASgLMhQuYWdlbnQudjEuV2FpdEFjdGlvbkgAEjAKCnNjcmVlbnNob3QYCiABKAsyGi5hZ2VudC52MS5TY3JlZW5zaG90QWN0aW9uSAASOQoPY3Vyc29yX3Bvc2l0aW9uGAsgASgLMh4uYWdlbnQudjEuQ3Vyc29yUG9zaXRpb25BY3Rpb25IAEIICgZhY3Rpb24iOwoPTW91c2VNb3ZlQWN0aW9uEigKCmNvb3JkaW5hdGUYASABKAsyFC5hZ2VudC52MS5Db29yZGluYXRlIpgBCgtDbGlja0FjdGlvbhItCgpjb29yZGluYXRlGAEgASgLMhQuYWdlbnQudjEuQ29vcmRpbmF0ZUgAiAEBEg4KBmJ1dHRvbhgCIAEoBRINCgVjb3VudBgDIAEoBRIaCg1tb2RpZmllcl9rZXlzGAQgASgJSAGIAQFCDQoLX2Nvb3JkaW5hdGVCEAoOX21vZGlmaWVyX2tleXMiIQoPTW91c2VEb3duQWN0aW9uEg4KBmJ1dHRvbhgBIAEoBSIfCg1Nb3VzZVVwQWN0aW9uEg4KBmJ1dHRvbhgBIAEoBSJACgpEcmFnQWN0aW9uEiIKBHBhdGgYASADKAsyFC5hZ2VudC52MS5Db29yZGluYXRlEg4KBmJ1dHRvbhgCIAEoBSKdAQoMU2Nyb2xsQWN0aW9uEi0KCmNvb3JkaW5hdGUYASABKAsyFC5hZ2VudC52MS5Db29yZGluYXRlSACIAQESEQoJZGlyZWN0aW9uGAIgASgFEg4KBmFtb3VudBgDIAEoBRIaCg1tb2RpZmllcl9rZXlzGAQgASgJSAGIAQFCDQoLX2Nvb3JkaW5hdGVCEAoOX21vZGlmaWVyX2tleXMiGgoKVHlwZUFjdGlvbhIMCgR0ZXh0GAEgASgJIkwKCUtleUFjdGlvbhILCgNrZXkYASABKAkSHQoQaG9sZF9kdXJhdGlvbl9tcxgCIAEoBUgAiAEBQhMKEV9ob2xkX2R1cmF0aW9uX21zIiEKCldhaXRBY3Rpb24SEwoLZHVyYXRpb25fbXMYASABKAUiEgoQU2NyZWVuc2hvdEFjdGlvbiIWChRDdXJzb3JQb3NpdGlvbkFjdGlvbiJ7ChFDb21wdXRlclVzZVJlc3VsdBIvCgdzdWNjZXNzGAEgASgLMhwuYWdlbnQudjEuQ29tcHV0ZXJVc2VTdWNjZXNzSAASKwoFZXJyb3IYAiABKAsyGi5hZ2VudC52MS5Db21wdXRlclVzZUVycm9ySABCCAoGcmVzdWx0IvsBChJDb21wdXRlclVzZVN1Y2Nlc3MSFAoMYWN0aW9uX2NvdW50GAEgASgFEhMKC2R1cmF0aW9uX21zGAIgASgFEhcKCnNjcmVlbnNob3QYAyABKAlIAIgBARIQCgNsb2cYBCABKAlIAYgBARIcCg9zY3JlZW5zaG90X3BhdGgYBSABKAlIAogBARIyCg9jdXJzb3JfcG9zaXRpb24YBiABKAsyFC5hZ2VudC52MS5Db29yZGluYXRlSAOIAQFCDQoLX3NjcmVlbnNob3RCBgoEX2xvZ0ISChBfc2NyZWVuc2hvdF9wYXRoQhIKEF9jdXJzb3JfcG9zaXRpb24iwAEKEENvbXB1dGVyVXNlRXJyb3ISDQoFZXJyb3IYASABKAkSFAoMYWN0aW9uX2NvdW50GAIgASgFEhMKC2R1cmF0aW9uX21zGAMgASgFEhAKA2xvZxgEIAEoCUgAiAEBEhcKCnNjcmVlbnNob3QYBSABKAlIAYgBARIcCg9zY3JlZW5zaG90X3BhdGgYBiABKAlIAogBAUIGCgRfbG9nQg0KC19zY3JlZW5zaG90QhIKEF9zY3JlZW5zaG90X3BhdGgiawoTQ29tcHV0ZXJVc2VUb29sQ2FsbBInCgRhcmdzGAEgASgLMhkuYWdlbnQudjEuQ29tcHV0ZXJVc2VBcmdzEisKBnJlc3VsdBgCIAEoCzIbLmFnZW50LnYxLkNvbXB1dGVyVXNlUmVzdWx0ImgKEkNyZWF0ZVBsYW5Ub29sQ2FsbBImCgRhcmdzGAEgASgLMhguYWdlbnQudjEuQ3JlYXRlUGxhbkFyZ3MSKgoGcmVzdWx0GAIgASgLMhouYWdlbnQudjEuQ3JlYXRlUGxhblJlc3VsdCI4CgVQaGFzZRIMCgRuYW1lGAEgASgJEiEKBXRvZG9zGAIgAygLMhIuYWdlbnQudjEuVG9kb0l0ZW0ilgEKDkNyZWF0ZVBsYW5BcmdzEgwKBHBsYW4YASABKAkSIQoFdG9kb3MYAiADKAsyEi5hZ2VudC52MS5Ub2RvSXRlbRIQCghvdmVydmlldxgDIAEoCRIMCgRuYW1lGAQgASgJEhIKCmlzX3Byb2plY3QYBSABKAgSHwoGcGhhc2VzGAYgAygLMg8uYWdlbnQudjEuUGhhc2UiigEKEENyZWF0ZVBsYW5SZXN1bHQSEAoIcGxhbl91cmkYAyABKAkSLgoHc3VjY2VzcxgBIAEoCzIbLmFnZW50LnYxLkNyZWF0ZVBsYW5TdWNjZXNzSAASKgoFZXJyb3IYAiABKAsyGS5hZ2VudC52MS5DcmVhdGVQbGFuRXJyb3JIAEIICgZyZXN1bHQiEwoRQ3JlYXRlUGxhblN1Y2Nlc3MiIAoPQ3JlYXRlUGxhbkVycm9yEg0KBWVycm9yGAEgASgJIlYKFkNyZWF0ZVBsYW5SZXF1ZXN0UXVlcnkSJgoEYXJncxgBIAEoCzIYLmFnZW50LnYxLkNyZWF0ZVBsYW5BcmdzEhQKDHRvb2xfY2FsbF9pZBgCIAEoCSJHChlDcmVhdGVQbGFuUmVxdWVzdFJlc3BvbnNlEioKBnJlc3VsdBgBIAEoCzIaLmFnZW50LnYxLkNyZWF0ZVBsYW5SZXN1bHQiFgoUQ3Vyc29yUnVsZVR5cGVHbG9iYWwiKAoXQ3Vyc29yUnVsZVR5cGVGaWxlR2xvYnMSDQoFZ2xvYnMYASADKAkiMQoaQ3Vyc29yUnVsZVR5cGVBZ2VudEZldGNoZWQSEwoLZGVzY3JpcHRpb24YASABKAkiIAoeQ3Vyc29yUnVsZVR5cGVNYW51YWxseUF0dGFjaGVkIosCCg5DdXJzb3JSdWxlVHlwZRIwCgZnbG9iYWwYASABKAsyHi5hZ2VudC52MS5DdXJzb3JSdWxlVHlwZUdsb2JhbEgAEjkKDGZpbGVfZ2xvYmJlZBgCIAEoCzIhLmFnZW50LnYxLkN1cnNvclJ1bGVUeXBlRmlsZUdsb2JzSAASPQoNYWdlbnRfZmV0Y2hlZBgDIAEoCzIkLmFnZW50LnYxLkN1cnNvclJ1bGVUeXBlQWdlbnRGZXRjaGVkSAASRQoRbWFudWFsbHlfYXR0YWNoZWQYBCABKAsyKC5hZ2VudC52MS5DdXJzb3JSdWxlVHlwZU1hbnVhbGx5QXR0YWNoZWRIAEIGCgR0eXBlIsgBCgpDdXJzb3JSdWxlEhEKCWZ1bGxfcGF0aBgBIAEoCRIPCgdjb250ZW50GAIgASgJEiYKBHR5cGUYAyABKAsyGC5hZ2VudC52MS5DdXJzb3JSdWxlVHlwZRIOCgZzb3VyY2UYBCABKAUSHgoRZ2l0X3JlbW90ZV9vcmlnaW4YBSABKAlIAIgBARIYCgtwYXJzZV9lcnJvchgGIAEoCUgBiAEBQhQKEl9naXRfcmVtb3RlX29yaWdpbkIOCgxfcGFyc2VfZXJyb3IiMAoKRGVsZXRlQXJncxIMCgRwYXRoGAEgASgJEhQKDHRvb2xfY2FsbF9pZBgCIAEoCSLtAgoMRGVsZXRlUmVzdWx0EioKB3N1Y2Nlc3MYASABKAsyFy5hZ2VudC52MS5EZWxldGVTdWNjZXNzSAASNgoOZmlsZV9ub3RfZm91bmQYAiABKAsyHC5hZ2VudC52MS5EZWxldGVGaWxlTm90Rm91bmRIABIrCghub3RfZmlsZRgDIAEoCzIXLmFnZW50LnYxLkRlbGV0ZU5vdEZpbGVIABI9ChFwZXJtaXNzaW9uX2RlbmllZBgEIAEoCzIgLmFnZW50LnYxLkRlbGV0ZVBlcm1pc3Npb25EZW5pZWRIABItCglmaWxlX2J1c3kYBSABKAsyGC5hZ2VudC52MS5EZWxldGVGaWxlQnVzeUgAEiwKCHJlamVjdGVkGAYgASgLMhguYWdlbnQudjEuRGVsZXRlUmVqZWN0ZWRIABImCgVlcnJvchgHIAEoCzIVLmFnZW50LnYxLkRlbGV0ZUVycm9ySABCCAoGcmVzdWx0IlwKDURlbGV0ZVN1Y2Nlc3MSDAoEcGF0aBgBIAEoCRIUCgxkZWxldGVkX2ZpbGUYAiABKAkSEQoJZmlsZV9zaXplGAMgASgDEhQKDHByZXZfY29udGVudBgEIAEoCSIiChJEZWxldGVGaWxlTm90Rm91bmQSDAoEcGF0aBgBIAEoCSIyCg1EZWxldGVOb3RGaWxlEgwKBHBhdGgYASABKAkSEwoLYWN0dWFsX3R5cGUYAiABKAkiWQoWRGVsZXRlUGVybWlzc2lvbkRlbmllZBIMCgRwYXRoGAEgASgJEhwKFGNsaWVudF92aXNpYmxlX2Vycm9yGAIgASgJEhMKC2lzX3JlYWRvbmx5GAMgASgIIh4KDkRlbGV0ZUZpbGVCdXN5EgwKBHBhdGgYASABKAkiLgoORGVsZXRlUmVqZWN0ZWQSDAoEcGF0aBgBIAEoCRIOCgZyZWFzb24YAiABKAkiKgoLRGVsZXRlRXJyb3ISDAoEcGF0aBgBIAEoCRINCgVlcnJvchgCIAEoCSJcCg5EZWxldGVUb29sQ2FsbBIiCgRhcmdzGAEgASgLMhQuYWdlbnQudjEuRGVsZXRlQXJncxImCgZyZXN1bHQYAiABKAsyFi5hZ2VudC52MS5EZWxldGVSZXN1bHQiNQoPRGlhZ25vc3RpY3NBcmdzEgwKBHBhdGgYASABKAkSFAoMdG9vbF9jYWxsX2lkGAIgASgJIq8CChFEaWFnbm9zdGljc1Jlc3VsdBIvCgdzdWNjZXNzGAEgASgLMhwuYWdlbnQudjEuRGlhZ25vc3RpY3NTdWNjZXNzSAASKwoFZXJyb3IYAiABKAsyGi5hZ2VudC52MS5EaWFnbm9zdGljc0Vycm9ySAASMQoIcmVqZWN0ZWQYAyABKAsyHS5hZ2VudC52MS5EaWFnbm9zdGljc1JlamVjdGVkSAASOwoOZmlsZV9ub3RfZm91bmQYBCABKAsyIS5hZ2VudC52MS5EaWFnbm9zdGljc0ZpbGVOb3RGb3VuZEgAEkIKEXBlcm1pc3Npb25fZGVuaWVkGAUgASgLMiUuYWdlbnQudjEuRGlhZ25vc3RpY3NQZXJtaXNzaW9uRGVuaWVkSABCCAoGcmVzdWx0ImgKEkRpYWdub3N0aWNzU3VjY2VzcxIMCgRwYXRoGAEgASgJEikKC2RpYWdub3N0aWNzGAIgAygLMhQuYWdlbnQudjEuRGlhZ25vc3RpYxIZChF0b3RhbF9kaWFnbm9zdGljcxgDIAEoBSJ/CgpEaWFnbm9zdGljEhAKCHNldmVyaXR5GAEgASgFEh4KBXJhbmdlGAIgASgLMg8uYWdlbnQudjEuUmFuZ2USDwoHbWVzc2FnZRgDIAEoCRIOCgZzb3VyY2UYBCABKAkSDAoEY29kZRgFIAEoCRIQCghpc19zdGFsZRgGIAEoCCIvChBEaWFnbm9zdGljc0Vycm9yEgwKBHBhdGgYASABKAkSDQoFZXJyb3IYAiABKAkiMwoTRGlhZ25vc3RpY3NSZWplY3RlZBIMCgRwYXRoGAEgASgJEg4KBnJlYXNvbhgCIAEoCSInChdEaWFnbm9zdGljc0ZpbGVOb3RGb3VuZBIMCgRwYXRoGAEgASgJIisKG0RpYWdub3N0aWNzUGVybWlzc2lvbkRlbmllZBIMCgRwYXRoGAEgASgJIkgKCEVkaXRBcmdzEgwKBHBhdGgYASABKAkSGwoOc3RyZWFtX2NvbnRlbnQYBiABKAlIAIgBAUIRCg9fc3RyZWFtX2NvbnRlbnQi1gIKCkVkaXRSZXN1bHQSKAoHc3VjY2VzcxgBIAEoCzIVLmFnZW50LnYxLkVkaXRTdWNjZXNzSAASNAoOZmlsZV9ub3RfZm91bmQYAiABKAsyGi5hZ2VudC52MS5FZGl0RmlsZU5vdEZvdW5kSAASRAoWcmVhZF9wZXJtaXNzaW9uX2RlbmllZBgDIAEoCzIiLmFnZW50LnYxLkVkaXRSZWFkUGVybWlzc2lvbkRlbmllZEgAEkYKF3dyaXRlX3Blcm1pc3Npb25fZGVuaWVkGAQgASgLMiMuYWdlbnQudjEuRWRpdFdyaXRlUGVybWlzc2lvbkRlbmllZEgAEioKCHJlamVjdGVkGAYgASgLMhYuYWdlbnQudjEuRWRpdFJlamVjdGVkSAASJAoFZXJyb3IYByABKAsyEy5hZ2VudC52MS5FZGl0RXJyb3JIAEIICgZyZXN1bHQipAIKC0VkaXRTdWNjZXNzEgwKBHBhdGgYASABKAkSGAoLbGluZXNfYWRkZWQYAyABKAVIAIgBARIaCg1saW5lc19yZW1vdmVkGAQgASgFSAGIAQESGAoLZGlmZl9zdHJpbmcYBSABKAlIAogBARIlChhiZWZvcmVfZnVsbF9maWxlX2NvbnRlbnQYBiABKAlIA4gBARIfChdhZnRlcl9mdWxsX2ZpbGVfY29udGVudBgHIAEoCRIUCgdtZXNzYWdlGAggASgJSASIAQFCDgoMX2xpbmVzX2FkZGVkQhAKDl9saW5lc19yZW1vdmVkQg4KDF9kaWZmX3N0cmluZ0IbChlfYmVmb3JlX2Z1bGxfZmlsZV9jb250ZW50QgoKCF9tZXNzYWdlIiAKEEVkaXRGaWxlTm90Rm91bmQSDAoEcGF0aBgBIAEoCSIoChhFZGl0UmVhZFBlcm1pc3Npb25EZW5pZWQSDAoEcGF0aBgBIAEoCSJNChlFZGl0V3JpdGVQZXJtaXNzaW9uRGVuaWVkEgwKBHBhdGgYASABKAkSDQoFZXJyb3IYAiABKAkSEwoLaXNfcmVhZG9ubHkYAyABKAgiLAoMRWRpdFJlamVjdGVkEgwKBHBhdGgYASABKAkSDgoGcmVhc29uGAIgASgJImIKCUVkaXRFcnJvchIMCgRwYXRoGAEgASgJEg0KBWVycm9yGAIgASgJEiAKE21vZGVsX3Zpc2libGVfZXJyb3IYBSABKAlIAIgBAUIWChRfbW9kZWxfdmlzaWJsZV9lcnJvciJWCgxFZGl0VG9vbENhbGwSIAoEYXJncxgBIAEoCzISLmFnZW50LnYxLkVkaXRBcmdzEiQKBnJlc3VsdBgCIAEoCzIULmFnZW50LnYxLkVkaXRSZXN1bHQiMQoRRWRpdFRvb2xDYWxsRGVsdGESHAoUc3RyZWFtX2NvbnRlbnRfZGVsdGEYASABKAkiMQoMRXhhRmV0Y2hBcmdzEgsKA2lkcxgBIAMoCRIUCgx0b29sX2NhbGxfaWQYAiABKAkiogEKDkV4YUZldGNoUmVzdWx0EiwKB3N1Y2Nlc3MYASABKAsyGS5hZ2VudC52MS5FeGFGZXRjaFN1Y2Nlc3NIABIoCgVlcnJvchgCIAEoCzIXLmFnZW50LnYxLkV4YUZldGNoRXJyb3JIABIuCghyZWplY3RlZBgDIAEoCzIaLmFnZW50LnYxLkV4YUZldGNoUmVqZWN0ZWRIAEIICgZyZXN1bHQiPgoPRXhhRmV0Y2hTdWNjZXNzEisKCGNvbnRlbnRzGAEgAygLMhkuYWdlbnQudjEuRXhhRmV0Y2hDb250ZW50Ih4KDUV4YUZldGNoRXJyb3ISDQoFZXJyb3IYASABKAkiIgoQRXhhRmV0Y2hSZWplY3RlZBIOCgZyZWFzb24YASABKAkiUwoPRXhhRmV0Y2hDb250ZW50Eg0KBXRpdGxlGAEgASgJEgsKA3VybBgCIAEoCRIMCgR0ZXh0GAMgASgJEhYKDnB1Ymxpc2hlZF9kYXRlGAQgASgJImIKEEV4YUZldGNoVG9vbENhbGwSJAoEYXJncxgBIAEoCzIWLmFnZW50LnYxLkV4YUZldGNoQXJncxIoCgZyZXN1bHQYAiABKAsyGC5hZ2VudC52MS5FeGFGZXRjaFJlc3VsdCI8ChRFeGFGZXRjaFJlcXVlc3RRdWVyeRIkCgRhcmdzGAEgASgLMhYuYWdlbnQudjEuRXhhRmV0Y2hBcmdzIqMBChdFeGFGZXRjaFJlcXVlc3RSZXNwb25zZRI+CghhcHByb3ZlZBgBIAEoCzIqLmFnZW50LnYxLkV4YUZldGNoUmVxdWVzdFJlc3BvbnNlX0FwcHJvdmVkSAASPgoIcmVqZWN0ZWQYAiABKAsyKi5hZ2VudC52MS5FeGFGZXRjaFJlcXVlc3RSZXNwb25zZV9SZWplY3RlZEgAQggKBnJlc3VsdCIiCiBFeGFGZXRjaFJlcXVlc3RSZXNwb25zZV9BcHByb3ZlZCIyCiBFeGFGZXRjaFJlcXVlc3RSZXNwb25zZV9SZWplY3RlZBIOCgZyZWFzb24YASABKAkiVwoNRXhhU2VhcmNoQXJncxINCgVxdWVyeRgBIAEoCRIMCgR0eXBlGAIgASgJEhMKC251bV9yZXN1bHRzGAMgASgFEhQKDHRvb2xfY2FsbF9pZBgEIAEoCSKmAQoPRXhhU2VhcmNoUmVzdWx0Ei0KB3N1Y2Nlc3MYASABKAsyGi5hZ2VudC52MS5FeGFTZWFyY2hTdWNjZXNzSAASKQoFZXJyb3IYAiABKAsyGC5hZ2VudC52MS5FeGFTZWFyY2hFcnJvckgAEi8KCHJlamVjdGVkGAMgASgLMhsuYWdlbnQudjEuRXhhU2VhcmNoUmVqZWN0ZWRIAEIICgZyZXN1bHQiRAoQRXhhU2VhcmNoU3VjY2VzcxIwCgpyZWZlcmVuY2VzGAEgAygLMhwuYWdlbnQudjEuRXhhU2VhcmNoUmVmZXJlbmNlIh8KDkV4YVNlYXJjaEVycm9yEg0KBWVycm9yGAEgASgJIiMKEUV4YVNlYXJjaFJlamVjdGVkEg4KBnJlYXNvbhgBIAEoCSJWChJFeGFTZWFyY2hSZWZlcmVuY2USDQoFdGl0bGUYASABKAkSCwoDdXJsGAIgASgJEgwKBHRleHQYAyABKAkSFgoOcHVibGlzaGVkX2RhdGUYBCABKAkiZQoRRXhhU2VhcmNoVG9vbENhbGwSJQoEYXJncxgBIAEoCzIXLmFnZW50LnYxLkV4YVNlYXJjaEFyZ3MSKQoGcmVzdWx0GAIgASgLMhkuYWdlbnQudjEuRXhhU2VhcmNoUmVzdWx0Ij4KFUV4YVNlYXJjaFJlcXVlc3RRdWVyeRIlCgRhcmdzGAEgASgLMhcuYWdlbnQudjEuRXhhU2VhcmNoQXJncyKmAQoYRXhhU2VhcmNoUmVxdWVzdFJlc3BvbnNlEj8KCGFwcHJvdmVkGAEgASgLMisuYWdlbnQudjEuRXhhU2VhcmNoUmVxdWVzdFJlc3BvbnNlX0FwcHJvdmVkSAASPwoIcmVqZWN0ZWQYAiABKAsyKy5hZ2VudC52MS5FeGFTZWFyY2hSZXF1ZXN0UmVzcG9uc2VfUmVqZWN0ZWRIAEIICgZyZXN1bHQiIwohRXhhU2VhcmNoUmVxdWVzdFJlc3BvbnNlX0FwcHJvdmVkIjMKIUV4YVNlYXJjaFJlcXVlc3RSZXNwb25zZV9SZWplY3RlZBIOCgZyZWFzb24YASABKAkiIwoVRXhlY0NsaWVudFN0cmVhbUNsb3NlEgoKAmlkGAEgASgNIn4KD0V4ZWNDbGllbnRUaHJvdxIKCgJpZBgBIAEoDRINCgVlcnJvchgCIAEoCRIYCgtzdGFja190cmFjZRgDIAEoCUgAiAEBEhcKCmVycm9yX2NvZGUYBCABKAlIAYgBAUIOCgxfc3RhY2tfdHJhY2VCDQoLX2Vycm9yX2NvZGUiIQoTRXhlY0NsaWVudEhlYXJ0YmVhdBIKCgJpZBgBIAEoDSK+AQoYRXhlY0NsaWVudENvbnRyb2xNZXNzYWdlEjcKDHN0cmVhbV9jbG9zZRgBIAEoCzIfLmFnZW50LnYxLkV4ZWNDbGllbnRTdHJlYW1DbG9zZUgAEioKBXRocm93GAIgASgLMhkuYWdlbnQudjEuRXhlY0NsaWVudFRocm93SAASMgoJaGVhcnRiZWF0GAMgASgLMh0uYWdlbnQudjEuRXhlY0NsaWVudEhlYXJ0YmVhdEgAQgkKB21lc3NhZ2UihAEKC1NwYW5Db250ZXh0EhAKCHRyYWNlX2lkGAEgASgJEg8KB3NwYW5faWQYAiABKAkSGAoLdHJhY2VfZmxhZ3MYAyABKA1IAIgBARIYCgt0cmFjZV9zdGF0ZRgEIAEoCUgBiAEBQg4KDF90cmFjZV9mbGFnc0IOCgxfdHJhY2Vfc3RhdGUiCwoJQWJvcnRBcmdzIg0KC0Fib3J0UmVzdWx0ItoTChFFeGVjU2VydmVyTWVzc2FnZRIKCgJpZBgBIAEoDRIPCgdleGVjX2lkGA8gASgJEjAKDHNwYW5fY29udGV4dBgTIAEoCzIVLmFnZW50LnYxLlNwYW5Db250ZXh0SAGIAQESKQoKc2hlbGxfYXJncxgCIAEoCzITLmFnZW50LnYxLlNoZWxsQXJnc0gAEikKCndyaXRlX2FyZ3MYAyABKAsyEy5hZ2VudC52MS5Xcml0ZUFyZ3NIABIrCgtkZWxldGVfYXJncxgEIAEoCzIULmFnZW50LnYxLkRlbGV0ZUFyZ3NIABInCglncmVwX2FyZ3MYBSABKAsyEi5hZ2VudC52MS5HcmVwQXJnc0gAEicKCXJlYWRfYXJncxgHIAEoCzISLmFnZW50LnYxLlJlYWRBcmdzSAASIwoHbHNfYXJncxgIIAEoCzIQLmFnZW50LnYxLkxzQXJnc0gAEjUKEGRpYWdub3N0aWNzX2FyZ3MYCSABKAsyGS5hZ2VudC52MS5EaWFnbm9zdGljc0FyZ3NIABI8ChRyZXF1ZXN0X2NvbnRleHRfYXJncxgKIAEoCzIcLmFnZW50LnYxLlJlcXVlc3RDb250ZXh0QXJnc0gAEiUKCG1jcF9hcmdzGAsgASgLMhEuYWdlbnQudjEuTWNwQXJnc0gAEjAKEXNoZWxsX3N0cmVhbV9hcmdzGA4gASgLMhMuYWdlbnQudjEuU2hlbGxBcmdzSAASSQobYmFja2dyb3VuZF9zaGVsbF9zcGF3bl9hcmdzGBAgASgLMiIuYWdlbnQudjEuQmFja2dyb3VuZFNoZWxsU3Bhd25BcmdzSAASSgocbGlzdF9tY3BfcmVzb3VyY2VzX2V4ZWNfYXJncxgRIAEoCzIiLmFnZW50LnYxLkxpc3RNY3BSZXNvdXJjZXNFeGVjQXJnc0gAEkgKG3JlYWRfbWNwX3Jlc291cmNlX2V4ZWNfYXJncxgSIAEoCzIhLmFnZW50LnYxLlJlYWRNY3BSZXNvdXJjZUV4ZWNBcmdzSAASKQoKZmV0Y2hfYXJncxgUIAEoCzITLmFnZW50LnYxLkZldGNoQXJnc0gAEjgKEnJlY29yZF9zY3JlZW5fYXJncxgVIAEoCzIaLmFnZW50LnYxLlJlY29yZFNjcmVlbkFyZ3NIABI2ChFjb21wdXRlcl91c2VfYXJncxgWIAEoCzIZLmFnZW50LnYxLkNvbXB1dGVyVXNlQXJnc0gAEj8KFndyaXRlX3NoZWxsX3N0ZGluX2FyZ3MYFyABKAsyHS5hZ2VudC52MS5Xcml0ZVNoZWxsU3RkaW5BcmdzSAASMAoScmVkYWN0ZWRfcmVhZF9hcmdzGB0gASgLMhIuYWdlbnQudjEuUmVhZEFyZ3NIABI5ChNtY3Bfc3RhdGVfZXhlY19hcmdzGCQgASgLMhouYWdlbnQudjEuTWNwU3RhdGVFeGVjQXJnc0gAEjYKEWV4ZWN1dGVfaG9va19hcmdzGBsgASgLMhkuYWdlbnQudjEuRXhlY3V0ZUhvb2tBcmdzSAASLwoNc3ViYWdlbnRfYXJncxgcIAEoCzIWLmFnZW50LnYxLlN1YmFnZW50QXJnc0gAEkkKG2ZvcmNlX2JhY2tncm91bmRfc2hlbGxfYXJncxgeIAEoCzIiLmFnZW50LnYxLkZvcmNlQmFja2dyb3VuZFNoZWxsQXJnc0gAEk8KHmZvcmNlX2JhY2tncm91bmRfc3ViYWdlbnRfYXJncxgfIAEoCzIlLmFnZW50LnYxLkZvcmNlQmFja2dyb3VuZFN1YmFnZW50QXJnc0gAEjoKE3N1YmFnZW50X2F3YWl0X2FyZ3MYJSABKAsyGy5hZ2VudC52MS5TdWJhZ2VudEF3YWl0QXJnc0gAEkcKGnNtYXJ0X21vZGVfY2xhc3NpZmllcl9hcmdzGCYgASgLMiEuYWdlbnQudjEuU21hcnRNb2RlQ2xhc3NpZmllckFyZ3NIABJCChdjYW52YXNfZGlhZ25vc3RpY3NfYXJncxgoIAEoCzIfLmFnZW50LnYxLkNhbnZhc0RpYWdub3N0aWNzQXJnc0gAEk0KHXNoZWxsX2FsbG93bGlzdF9wcmVjaGVja19hcmdzGCkgASgLMiQuYWdlbnQudjEuU2hlbGxBbGxvd2xpc3RQcmVjaGVja0FyZ3NIABJJChttY3BfYWxsb3dsaXN0X3ByZWNoZWNrX2FyZ3MYKiABKAsyIi5hZ2VudC52MS5NY3BBbGxvd2xpc3RQcmVjaGVja0FyZ3NIABJUCiF3ZWJfZmV0Y2hfYWxsb3dsaXN0X3ByZWNoZWNrX2FyZ3MYKyABKAsyJy5hZ2VudC52MS5XZWJGZXRjaEFsbG93bGlzdFByZWNoZWNrQXJnc0gAEjQKEGdpdF9kaWZmX3JlcXVlc3QYLCABKAsyGC5hZ2VudC52MS5HZXREaWZmUmVxdWVzdEgAEjAKDHBpX3JlYWRfYXJncxgtIAEoCzIYLmFnZW50LnYxLlBpUmVhZEV4ZWNBcmdzSAASMAoMcGlfYmFzaF9hcmdzGC4gASgLMhguYWdlbnQudjEuUGlCYXNoRXhlY0FyZ3NIABIwCgxwaV9lZGl0X2FyZ3MYLyABKAsyGC5hZ2VudC52MS5QaUVkaXRFeGVjQXJnc0gAEjIKDXBpX3dyaXRlX2FyZ3MYMCABKAsyGS5hZ2VudC52MS5QaVdyaXRlRXhlY0FyZ3NIABIwCgxwaV9ncmVwX2FyZ3MYMSABKAsyGC5hZ2VudC52MS5QaUdyZXBFeGVjQXJnc0gAEjAKDHBpX2ZpbmRfYXJncxgyIAEoCzIYLmFnZW50LnYxLlBpRmluZEV4ZWNBcmdzSAASLAoKcGlfbHNfYXJncxgzIAEoCzIWLmFnZW50LnYxLlBpTHNFeGVjQXJnc0gAEjcKGG1pbmlfc3dlX2FnZW50X2Jhc2hfYXJncxg0IAEoCzITLmFnZW50LnYxLlNoZWxsQXJnc0gAEkQKGGNvbnZlcnNhdGlvbl9zZWFyY2hfYXJncxg1IAEoCzIgLmFnZW50LnYxLkNvbnZlcnNhdGlvblNlYXJjaEFyZ3NIABJFChlhZ2VudF9zdG9yZV9jb25mbGljdF9hcmdzGDYgASgLMiAuYWdlbnQudjEuQWdlbnRTdG9yZUNvbmZsaWN0QXJnc0gAEiwKH2FjY2VwdF9ob29rX2FkZGl0aW9uYWxfY29udGV4dHMYNyABKAhIAogBAUIJCgdtZXNzYWdlQg8KDV9zcGFuX2NvbnRleHRCIgogX2FjY2VwdF9ob29rX2FkZGl0aW9uYWxfY29udGV4dHMi4RQKEUV4ZWNDbGllbnRNZXNzYWdlEgoKAmlkGAEgASgNEg8KB2V4ZWNfaWQYDyABKAkSLQoMc2hlbGxfcmVzdWx0GAIgASgLMhUuYWdlbnQudjEuU2hlbGxSZXN1bHRIABItCgx3cml0ZV9yZXN1bHQYAyABKAsyFS5hZ2VudC52MS5Xcml0ZVJlc3VsdEgAEi8KDWRlbGV0ZV9yZXN1bHQYBCABKAsyFi5hZ2VudC52MS5EZWxldGVSZXN1bHRIABIrCgtncmVwX3Jlc3VsdBgFIAEoCzIULmFnZW50LnYxLkdyZXBSZXN1bHRIABIrCgtyZWFkX3Jlc3VsdBgHIAEoCzIULmFnZW50LnYxLlJlYWRSZXN1bHRIABInCglsc19yZXN1bHQYCCABKAsyEi5hZ2VudC52MS5Mc1Jlc3VsdEgAEjkKEmRpYWdub3N0aWNzX3Jlc3VsdBgJIAEoCzIbLmFnZW50LnYxLkRpYWdub3N0aWNzUmVzdWx0SAASQAoWcmVxdWVzdF9jb250ZXh0X3Jlc3VsdBgKIAEoCzIeLmFnZW50LnYxLlJlcXVlc3RDb250ZXh0UmVzdWx0SAASKQoKbWNwX3Jlc3VsdBgLIAEoCzITLmFnZW50LnYxLk1jcFJlc3VsdEgAEi0KDHNoZWxsX3N0cmVhbRgOIAEoCzIVLmFnZW50LnYxLlNoZWxsU3RyZWFtSAASTQodYmFja2dyb3VuZF9zaGVsbF9zcGF3bl9yZXN1bHQYECABKAsyJC5hZ2VudC52MS5CYWNrZ3JvdW5kU2hlbGxTcGF3blJlc3VsdEgAEk4KHmxpc3RfbWNwX3Jlc291cmNlc19leGVjX3Jlc3VsdBgRIAEoCzIkLmFnZW50LnYxLkxpc3RNY3BSZXNvdXJjZXNFeGVjUmVzdWx0SAASTAodcmVhZF9tY3BfcmVzb3VyY2VfZXhlY19yZXN1bHQYEiABKAsyIy5hZ2VudC52MS5SZWFkTWNwUmVzb3VyY2VFeGVjUmVzdWx0SAASLQoMZmV0Y2hfcmVzdWx0GBQgASgLMhUuYWdlbnQudjEuRmV0Y2hSZXN1bHRIABI8ChRyZWNvcmRfc2NyZWVuX3Jlc3VsdBgVIAEoCzIcLmFnZW50LnYxLlJlY29yZFNjcmVlblJlc3VsdEgAEjoKE2NvbXB1dGVyX3VzZV9yZXN1bHQYFiABKAsyGy5hZ2VudC52MS5Db21wdXRlclVzZVJlc3VsdEgAEkMKGHdyaXRlX3NoZWxsX3N0ZGluX3Jlc3VsdBgXIAEoCzIfLmFnZW50LnYxLldyaXRlU2hlbGxTdGRpblJlc3VsdEgAEjQKFHJlZGFjdGVkX3JlYWRfcmVzdWx0GB0gASgLMhQuYWdlbnQudjEuUmVhZFJlc3VsdEgAEj0KFW1jcF9zdGF0ZV9leGVjX3Jlc3VsdBgkIAEoCzIcLmFnZW50LnYxLk1jcFN0YXRlRXhlY1Jlc3VsdEgAEjoKE2V4ZWN1dGVfaG9va19yZXN1bHQYGyABKAsyGy5hZ2VudC52MS5FeGVjdXRlSG9va1Jlc3VsdEgAEjMKD3N1YmFnZW50X3Jlc3VsdBgcIAEoCzIYLmFnZW50LnYxLlN1YmFnZW50UmVzdWx0SAASTQodZm9yY2VfYmFja2dyb3VuZF9zaGVsbF9yZXN1bHQYHiABKAsyJC5hZ2VudC52MS5Gb3JjZUJhY2tncm91bmRTaGVsbFJlc3VsdEgAElMKIGZvcmNlX2JhY2tncm91bmRfc3ViYWdlbnRfcmVzdWx0GB8gASgLMicuYWdlbnQudjEuRm9yY2VCYWNrZ3JvdW5kU3ViYWdlbnRSZXN1bHRIABI+ChVzdWJhZ2VudF9hd2FpdF9yZXN1bHQYJSABKAsyHS5hZ2VudC52MS5TdWJhZ2VudEF3YWl0UmVzdWx0SAASSwocc21hcnRfbW9kZV9jbGFzc2lmaWVyX3Jlc3VsdBgmIAEoCzIjLmFnZW50LnYxLlNtYXJ0TW9kZUNsYXNzaWZpZXJSZXN1bHRIABJGChljYW52YXNfZGlhZ25vc3RpY3NfcmVzdWx0GCggASgLMiEuYWdlbnQudjEuQ2FudmFzRGlhZ25vc3RpY3NSZXN1bHRIABJRCh9zaGVsbF9hbGxvd2xpc3RfcHJlY2hlY2tfcmVzdWx0GCkgASgLMiYuYWdlbnQudjEuU2hlbGxBbGxvd2xpc3RQcmVjaGVja1Jlc3VsdEgAEk0KHW1jcF9hbGxvd2xpc3RfcHJlY2hlY2tfcmVzdWx0GCogASgLMiQuYWdlbnQudjEuTWNwQWxsb3dsaXN0UHJlY2hlY2tSZXN1bHRIABJYCiN3ZWJfZmV0Y2hfYWxsb3dsaXN0X3ByZWNoZWNrX3Jlc3VsdBgrIAEoCzIpLmFnZW50LnYxLldlYkZldGNoQWxsb3dsaXN0UHJlY2hlY2tSZXN1bHRIABI2ChFnaXRfZGlmZl9yZXNwb25zZRgsIAEoCzIZLmFnZW50LnYxLkdldERpZmZSZXNwb25zZUgAEjQKDnBpX3JlYWRfcmVzdWx0GC4gASgLMhouYWdlbnQudjEuUGlSZWFkRXhlY1Jlc3VsdEgAEjQKDnBpX2Jhc2hfcmVzdWx0GC8gASgLMhouYWdlbnQudjEuUGlCYXNoRXhlY1Jlc3VsdEgAEjQKDnBpX2VkaXRfcmVzdWx0GDAgASgLMhouYWdlbnQudjEuUGlFZGl0RXhlY1Jlc3VsdEgAEjYKD3BpX3dyaXRlX3Jlc3VsdBgxIAEoCzIbLmFnZW50LnYxLlBpV3JpdGVFeGVjUmVzdWx0SAASNAoOcGlfZ3JlcF9yZXN1bHQYMiABKAsyGi5hZ2VudC52MS5QaUdyZXBFeGVjUmVzdWx0SAASNAoOcGlfZmluZF9yZXN1bHQYMyABKAsyGi5hZ2VudC52MS5QaUZpbmRFeGVjUmVzdWx0SAASMAoMcGlfbHNfcmVzdWx0GDQgASgLMhguYWdlbnQudjEuUGlMc0V4ZWNSZXN1bHRIABJIChpjb252ZXJzYXRpb25fc2VhcmNoX3Jlc3VsdBg1IAEoCzIiLmFnZW50LnYxLkNvbnZlcnNhdGlvblNlYXJjaFJlc3VsdEgAEkkKG2FnZW50X3N0b3JlX2NvbmZsaWN0X3Jlc3VsdBg2IAEoCzIiLmFnZW50LnYxLkFnZW50U3RvcmVDb25mbGljdFJlc3VsdEgAEjsKGm1pbmlfc3dlX2FnZW50X2Jhc2hfcmVzdWx0GDcgASgLMhUuYWdlbnQudjEuU2hlbGxSZXN1bHRIABIkChdsb2NhbF9leGVjdXRpb25fdGltZV9tcxgnIAEoBUgBiAEBEkEKGGhvb2tfYWRkaXRpb25hbF9jb250ZXh0cxgtIAMoCzIfLmFnZW50LnYxLkhvb2tBZGRpdGlvbmFsQ29udGV4dEIJCgdtZXNzYWdlQhoKGF9sb2NhbF9leGVjdXRpb25fdGltZV9tcyIuCglGZXRjaEFyZ3MSCwoDdXJsGAEgASgJEhQKDHRvb2xfY2FsbF9pZBgCIAEoCSJpCgtGZXRjaFJlc3VsdBIpCgdzdWNjZXNzGAEgASgLMhYuYWdlbnQudjEuRmV0Y2hTdWNjZXNzSAASJQoFZXJyb3IYAiABKAsyFC5hZ2VudC52MS5GZXRjaEVycm9ySABCCAoGcmVzdWx0IlcKDEZldGNoU3VjY2VzcxILCgN1cmwYASABKAkSDwoHY29udGVudBgCIAEoCRITCgtzdGF0dXNfY29kZRgDIAEoBRIUCgxjb250ZW50X3R5cGUYBCABKAkiKAoKRmV0Y2hFcnJvchILCgN1cmwYASABKAkSDQoFZXJyb3IYAiABKAkibQoRR2VuZXJhdGVJbWFnZUFyZ3MSEwoLZGVzY3JpcHRpb24YASABKAkSFgoJZmlsZV9wYXRoGAIgASgJSACIAQESHQoVcmVmZXJlbmNlX2ltYWdlX3BhdGhzGAUgAygJQgwKCl9maWxlX3BhdGgigQEKE0dlbmVyYXRlSW1hZ2VSZXN1bHQSMQoHc3VjY2VzcxgBIAEoCzIeLmFnZW50LnYxLkdlbmVyYXRlSW1hZ2VTdWNjZXNzSAASLQoFZXJyb3IYAiABKAsyHC5hZ2VudC52MS5HZW5lcmF0ZUltYWdlRXJyb3JIAEIICgZyZXN1bHQiPQoUR2VuZXJhdGVJbWFnZVN1Y2Nlc3MSEQoJZmlsZV9wYXRoGAEgASgJEhIKCmltYWdlX2RhdGEYAiABKAkiIwoSR2VuZXJhdGVJbWFnZUVycm9yEg0KBWVycm9yGAEgASgJInEKFUdlbmVyYXRlSW1hZ2VUb29sQ2FsbBIpCgRhcmdzGAEgASgLMhsuYWdlbnQudjEuR2VuZXJhdGVJbWFnZUFyZ3MSLQoGcmVzdWx0GAIgASgLMh0uYWdlbnQudjEuR2VuZXJhdGVJbWFnZVJlc3VsdCLmBAoIR3JlcEFyZ3MSDwoHcGF0dGVybhgBIAEoCRIRCgRwYXRoGAIgASgJSACIAQESEQoEZ2xvYhgDIAEoCUgBiAEBEhgKC291dHB1dF9tb2RlGAQgASgJSAKIAQESGwoOY29udGV4dF9iZWZvcmUYBSABKAVIA4gBARIaCg1jb250ZXh0X2FmdGVyGAYgASgFSASIAQESFAoHY29udGV4dBgHIAEoBUgFiAEBEh0KEGNhc2VfaW5zZW5zaXRpdmUYCCABKAhIBogBARIRCgR0eXBlGAkgASgJSAeIAQESFwoKaGVhZF9saW1pdBgKIAEoBUgIiAEBEhYKCW11bHRpbGluZRgLIAEoCEgJiAEBEhEKBHNvcnQYDCABKAlICogBARIbCg5zb3J0X2FzY2VuZGluZxgNIAEoCEgLiAEBEhQKDHRvb2xfY2FsbF9pZBgOIAEoCRI0Cg5zYW5kYm94X3BvbGljeRgPIAEoCzIXLmFnZW50LnYxLlNhbmRib3hQb2xpY3lIDIgBARITCgZvZmZzZXQYECABKAVIDYgBAUIHCgVfcGF0aEIHCgVfZ2xvYkIOCgxfb3V0cHV0X21vZGVCEQoPX2NvbnRleHRfYmVmb3JlQhAKDl9jb250ZXh0X2FmdGVyQgoKCF9jb250ZXh0QhMKEV9jYXNlX2luc2Vuc2l0aXZlQgcKBV90eXBlQg0KC19oZWFkX2xpbWl0QgwKCl9tdWx0aWxpbmVCBwoFX3NvcnRCEQoPX3NvcnRfYXNjZW5kaW5nQhEKD19zYW5kYm94X3BvbGljeUIJCgdfb2Zmc2V0ImYKCkdyZXBSZXN1bHQSKAoHc3VjY2VzcxgBIAEoCzIVLmFnZW50LnYxLkdyZXBTdWNjZXNzSAASJAoFZXJyb3IYAiABKAsyEy5hZ2VudC52MS5HcmVwRXJyb3JIAEIICgZyZXN1bHQiGgoJR3JlcEVycm9yEg0KBWVycm9yGAEgASgJIrQCCgtHcmVwU3VjY2VzcxIPCgdwYXR0ZXJuGAEgASgJEgwKBHBhdGgYAiABKAkSEwoLb3V0cHV0X21vZGUYAyABKAkSRgoRd29ya3NwYWNlX3Jlc3VsdHMYBCADKAsyKy5hZ2VudC52MS5HcmVwU3VjY2Vzcy5Xb3Jrc3BhY2VSZXN1bHRzRW50cnkSPAoUYWN0aXZlX2VkaXRvcl9yZXN1bHQYBSABKAsyGS5hZ2VudC52MS5HcmVwVW5pb25SZXN1bHRIAIgBARpSChVXb3Jrc3BhY2VSZXN1bHRzRW50cnkSCwoDa2V5GAEgASgJEigKBXZhbHVlGAIgASgLMhkuYWdlbnQudjEuR3JlcFVuaW9uUmVzdWx0OgI4AUIXChVfYWN0aXZlX2VkaXRvcl9yZXN1bHQiowEKD0dyZXBVbmlvblJlc3VsdBIqCgVjb3VudBgBIAEoCzIZLmFnZW50LnYxLkdyZXBDb3VudFJlc3VsdEgAEioKBWZpbGVzGAIgASgLMhkuYWdlbnQudjEuR3JlcEZpbGVzUmVzdWx0SAASLgoHY29udGVudBgDIAEoCzIbLmFnZW50LnYxLkdyZXBDb250ZW50UmVzdWx0SABCCAoGcmVzdWx0IoMCCg9HcmVwQ291bnRSZXN1bHQSJwoGY291bnRzGAEgAygLMhcuYWdlbnQudjEuR3JlcEZpbGVDb3VudBITCgt0b3RhbF9maWxlcxgCIAEoBRIVCg10b3RhbF9tYXRjaGVzGAMgASgFEhgKEGNsaWVudF90cnVuY2F0ZWQYBCABKAgSGQoRcmlwZ3JlcF90cnVuY2F0ZWQYBSABKAgSHwoSaGVhZF9saW1pdF9hcHBsaWVkGAYgASgFSACIAQESGwoOb2Zmc2V0X2FwcGxpZWQYByABKAVIAYgBAUIVChNfaGVhZF9saW1pdF9hcHBsaWVkQhEKD19vZmZzZXRfYXBwbGllZCIsCg1HcmVwRmlsZUNvdW50EgwKBGZpbGUYASABKAkSDQoFY291bnQYAiABKAUi0gEKD0dyZXBGaWxlc1Jlc3VsdBINCgVmaWxlcxgBIAMoCRITCgt0b3RhbF9maWxlcxgCIAEoBRIYChBjbGllbnRfdHJ1bmNhdGVkGAMgASgIEhkKEXJpcGdyZXBfdHJ1bmNhdGVkGAQgASgIEh8KEmhlYWRfbGltaXRfYXBwbGllZBgFIAEoBUgAiAEBEhsKDm9mZnNldF9hcHBsaWVkGAYgASgFSAGIAQFCFQoTX2hlYWRfbGltaXRfYXBwbGllZEIRCg9fb2Zmc2V0X2FwcGxpZWQijAIKEUdyZXBDb250ZW50UmVzdWx0EigKB21hdGNoZXMYASADKAsyFy5hZ2VudC52MS5HcmVwRmlsZU1hdGNoEhMKC3RvdGFsX2xpbmVzGAIgASgFEhsKE3RvdGFsX21hdGNoZWRfbGluZXMYAyABKAUSGAoQY2xpZW50X3RydW5jYXRlZBgEIAEoCBIZChFyaXBncmVwX3RydW5jYXRlZBgFIAEoCBIfChJoZWFkX2xpbWl0X2FwcGxpZWQYBiABKAVIAIgBARIbCg5vZmZzZXRfYXBwbGllZBgHIAEoBUgBiAEBQhUKE19oZWFkX2xpbWl0X2FwcGxpZWRCEQoPX29mZnNldF9hcHBsaWVkIkoKDUdyZXBGaWxlTWF0Y2gSDAoEZmlsZRgBIAEoCRIrCgdtYXRjaGVzGAIgAygLMhouYWdlbnQudjEuR3JlcENvbnRlbnRNYXRjaCJsChBHcmVwQ29udGVudE1hdGNoEhMKC2xpbmVfbnVtYmVyGAEgASgFEg8KB2NvbnRlbnQYAiABKAkSGQoRY29udGVudF90cnVuY2F0ZWQYAyABKAgSFwoPaXNfY29udGV4dF9saW5lGAQgASgIIh0KCkdyZXBTdHJlYW0SDwoHcGF0dGVybhgBIAEoCSJWCgxHcmVwVG9vbENhbGwSIAoEYXJncxgBIAEoCzISLmFnZW50LnYxLkdyZXBBcmdzEiQKBnJlc3VsdBgCIAEoCzIULmFnZW50LnYxLkdyZXBSZXN1bHQiHgoLR2V0QmxvYkFyZ3MSDwoHYmxvYl9pZBgBIAEoDCI1Cg1HZXRCbG9iUmVzdWx0EhYKCWJsb2JfZGF0YRgBIAEoDEgAiAEBQgwKCl9ibG9iX2RhdGEiMQoLU2V0QmxvYkFyZ3MSDwoHYmxvYl9pZBgBIAEoDBIRCglibG9iX2RhdGEYAiABKAwiPgoNU2V0QmxvYlJlc3VsdBIjCgVlcnJvchgBIAEoCzIPLmFnZW50LnYxLkVycm9ySACIAQFCCAoGX2Vycm9yIssBCg9LdlNlcnZlck1lc3NhZ2USCgoCaWQYASABKA0SMAoMc3Bhbl9jb250ZXh0GAQgASgLMhUuYWdlbnQudjEuU3BhbkNvbnRleHRIAYgBARIuCg1nZXRfYmxvYl9hcmdzGAIgASgLMhUuYWdlbnQudjEuR2V0QmxvYkFyZ3NIABIuCg1zZXRfYmxvYl9hcmdzGAMgASgLMhUuYWdlbnQudjEuU2V0QmxvYkFyZ3NIAEIJCgdtZXNzYWdlQg8KDV9zcGFuX2NvbnRleHQikAEKD0t2Q2xpZW50TWVzc2FnZRIKCgJpZBgBIAEoDRIyCg9nZXRfYmxvYl9yZXN1bHQYAiABKAsyFy5hZ2VudC52MS5HZXRCbG9iUmVzdWx0SAASMgoPc2V0X2Jsb2JfcmVzdWx0GAMgASgLMhcuYWdlbnQudjEuU2V0QmxvYlJlc3VsdEgAQgkKB21lc3NhZ2UirQEKBkxzQXJncxIMCgRwYXRoGAEgASgJEg4KBmlnbm9yZRgCIAMoCRIUCgx0b29sX2NhbGxfaWQYAyABKAkSNAoOc2FuZGJveF9wb2xpY3kYBCABKAsyFy5hZ2VudC52MS5TYW5kYm94UG9saWN5SACIAQESFwoKdGltZW91dF9tcxgFIAEoDUgBiAEBQhEKD19zYW5kYm94X3BvbGljeUINCgtfdGltZW91dF9tcyKyAQoITHNSZXN1bHQSJgoHc3VjY2VzcxgBIAEoCzITLmFnZW50LnYxLkxzU3VjY2Vzc0gAEiIKBWVycm9yGAIgASgLMhEuYWdlbnQudjEuTHNFcnJvckgAEigKCHJlamVjdGVkGAMgASgLMhQuYWdlbnQudjEuTHNSZWplY3RlZEgAEiYKB3RpbWVvdXQYBCABKAsyEy5hZ2VudC52MS5Mc1RpbWVvdXRIAEIICgZyZXN1bHQiRwoJTHNTdWNjZXNzEjoKE2RpcmVjdG9yeV90cmVlX3Jvb3QYASABKAsyHS5hZ2VudC52MS5Mc0RpcmVjdG9yeVRyZWVOb2RlIvYCChNMc0RpcmVjdG9yeVRyZWVOb2RlEhAKCGFic19wYXRoGAEgASgJEjQKDWNoaWxkcmVuX2RpcnMYAiADKAsyHS5hZ2VudC52MS5Mc0RpcmVjdG9yeVRyZWVOb2RlEjoKDmNoaWxkcmVuX2ZpbGVzGAMgAygLMiIuYWdlbnQudjEuTHNEaXJlY3RvcnlUcmVlTm9kZV9GaWxlEh8KF2NoaWxkcmVuX3dlcmVfcHJvY2Vzc2VkGAQgASgIEmQKHWZ1bGxfc3VidHJlZV9leHRlbnNpb25fY291bnRzGAUgAygLMj0uYWdlbnQudjEuTHNEaXJlY3RvcnlUcmVlTm9kZS5GdWxsU3VidHJlZUV4dGVuc2lvbkNvdW50c0VudHJ5EhEKCW51bV9maWxlcxgGIAEoBRpBCh9GdWxsU3VidHJlZUV4dGVuc2lvbkNvdW50c0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoBToCOAEiegoYTHNEaXJlY3RvcnlUcmVlTm9kZV9GaWxlEgwKBG5hbWUYASABKAkSOgoRdGVybWluYWxfbWV0YWRhdGEYAiABKAsyGi5hZ2VudC52MS5UZXJtaW5hbE1ldGFkYXRhSACIAQFCFAoSX3Rlcm1pbmFsX21ldGFkYXRhIiYKB0xzRXJyb3ISDAoEcGF0aBgBIAEoCRINCgVlcnJvchgCIAEoCSIqCgpMc1JlamVjdGVkEgwKBHBhdGgYASABKAkSDgoGcmVhc29uGAIgASgJIkcKCUxzVGltZW91dBI6ChNkaXJlY3RvcnlfdHJlZV9yb290GAEgASgLMh0uYWdlbnQudjEuTHNEaXJlY3RvcnlUcmVlTm9kZSLxAQoQVGVybWluYWxNZXRhZGF0YRIQCgNjd2QYASABKAlIAIgBARI5Cg1sYXN0X2NvbW1hbmRzGAIgAygLMiIuYWdlbnQudjEuVGVybWluYWxNZXRhZGF0YV9Db21tYW5kEh0KEGxhc3RfbW9kaWZpZWRfbXMYAyABKANIAYgBARJACg9jdXJyZW50X2NvbW1hbmQYBCABKAsyIi5hZ2VudC52MS5UZXJtaW5hbE1ldGFkYXRhX0NvbW1hbmRIAogBAUIGCgRfY3dkQhMKEV9sYXN0X21vZGlmaWVkX21zQhIKEF9jdXJyZW50X2NvbW1hbmQipwEKGFRlcm1pbmFsTWV0YWRhdGFfQ29tbWFuZBIPCgdjb21tYW5kGAEgASgJEhYKCWV4aXRfY29kZRgCIAEoBUgAiAEBEhkKDHRpbWVzdGFtcF9tcxgDIAEoA0gBiAEBEhgKC2R1cmF0aW9uX21zGAQgASgDSAKIAQFCDAoKX2V4aXRfY29kZUIPCg1fdGltZXN0YW1wX21zQg4KDF9kdXJhdGlvbl9tcyJQCgpMc1Rvb2xDYWxsEh4KBGFyZ3MYASABKAsyEC5hZ2VudC52MS5Mc0FyZ3MSIgoGcmVzdWx0GAIgASgLMhIuYWdlbnQudjEuTHNSZXN1bHQi4AIKB01jcEFyZ3MSDAoEbmFtZRgBIAEoCRIpCgRhcmdzGAIgAygLMhsuYWdlbnQudjEuTWNwQXJncy5BcmdzRW50cnkSFAoMdG9vbF9jYWxsX2lkGAMgASgJEhsKE3Byb3ZpZGVyX2lkZW50aWZpZXIYBCABKAkSEQoJdG9vbF9uYW1lGAUgASgJEj0KE3NtYXJ0X21vZGVfYXBwcm92YWwYBiABKAsyGy5hZ2VudC52MS5TbWFydE1vZGVBcHByb3ZhbEgAiAEBEiAKGHNtYXJ0X21vZGVfYXBwcm92YWxfb25seRgHIAEoCBIVCg1za2lwX2FwcHJvdmFsGAggASgIEhkKEXNlcnZlcl9pZGVudGlmaWVyGAkgASgJGisKCUFyZ3NFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAw6AjgBQhYKFF9zbWFydF9tb2RlX2FwcHJvdmFsIuMCCglNY3BSZXN1bHQSJwoHc3VjY2VzcxgBIAEoCzIULmFnZW50LnYxLk1jcFN1Y2Nlc3NIABIjCgVlcnJvchgCIAEoCzISLmFnZW50LnYxLk1jcEVycm9ySAASKQoIcmVqZWN0ZWQYAyABKAsyFS5hZ2VudC52MS5NY3BSZWplY3RlZEgAEjoKEXBlcm1pc3Npb25fZGVuaWVkGAQgASgLMh0uYWdlbnQudjEuTWNwUGVybWlzc2lvbkRlbmllZEgAEjMKDnRvb2xfbm90X2ZvdW5kGAUgASgLMhkuYWdlbnQudjEuTWNwVG9vbE5vdEZvdW5kSAASNwoQc2VydmVyX25vdF9mb3VuZBgGIAEoCzIbLmFnZW50LnYxLk1jcFNlcnZlck5vdEZvdW5kSAASKQoIYXBwcm92ZWQYByABKAsyFS5hZ2VudC52MS5NY3BBcHByb3ZlZEgAQggKBnJlc3VsdCI4Cg9NY3BUb29sTm90Rm91bmQSDAoEbmFtZRgBIAEoCRIXCg9hdmFpbGFibGVfdG9vbHMYAiADKAkiagoOTWNwVGV4dENvbnRlbnQSDAoEdGV4dBgBIAEoCRI2Cg9vdXRwdXRfbG9jYXRpb24YAiABKAsyGC5hZ2VudC52MS5PdXRwdXRMb2NhdGlvbkgAiAEBQhIKEF9vdXRwdXRfbG9jYXRpb24iMgoPTWNwSW1hZ2VDb250ZW50EgwKBGRhdGEYASABKAwSEQoJbWltZV90eXBlGAIgASgJInsKGE1jcFRvb2xSZXN1bHRDb250ZW50SXRlbRIoCgR0ZXh0GAEgASgLMhguYWdlbnQudjEuTWNwVGV4dENvbnRlbnRIABIqCgVpbWFnZRgCIAEoCzIZLmFnZW50LnYxLk1jcEltYWdlQ29udGVudEgAQgkKB2NvbnRlbnQiUwoKTWNwU3VjY2VzcxIzCgdjb250ZW50GAEgAygLMiIuYWdlbnQudjEuTWNwVG9vbFJlc3VsdENvbnRlbnRJdGVtEhAKCGlzX2Vycm9yGAIgASgIIhkKCE1jcEVycm9yEg0KBWVycm9yGAEgASgJIjIKC01jcFJlamVjdGVkEg4KBnJlYXNvbhgBIAEoCRITCgtpc19yZWFkb25seRgCIAEoCCI5ChNNY3BQZXJtaXNzaW9uRGVuaWVkEg0KBWVycm9yGAEgASgJEhMKC2lzX3JlYWRvbmx5GAIgASgIIjoKGExpc3RNY3BSZXNvdXJjZXNFeGVjQXJncxITCgZzZXJ2ZXIYASABKAlIAIgBAUIJCgdfc2VydmVyIsYBChpMaXN0TWNwUmVzb3VyY2VzRXhlY1Jlc3VsdBI0CgdzdWNjZXNzGAEgASgLMiEuYWdlbnQudjEuTGlzdE1jcFJlc291cmNlc1N1Y2Nlc3NIABIwCgVlcnJvchgCIAEoCzIfLmFnZW50LnYxLkxpc3RNY3BSZXNvdXJjZXNFcnJvckgAEjYKCHJlamVjdGVkGAMgASgLMiIuYWdlbnQudjEuTGlzdE1jcFJlc291cmNlc1JlamVjdGVkSABCCAoGcmVzdWx0Ir0CCiZMaXN0TWNwUmVzb3VyY2VzRXhlY1Jlc3VsdF9NY3BSZXNvdXJjZRILCgN1cmkYASABKAkSEQoEbmFtZRgCIAEoCUgAiAEBEhgKC2Rlc2NyaXB0aW9uGAMgASgJSAGIAQESFgoJbWltZV90eXBlGAQgASgJSAKIAQESDgoGc2VydmVyGAUgASgJElYKC2Fubm90YXRpb25zGAYgAygLMkEuYWdlbnQudjEuTGlzdE1jcFJlc291cmNlc0V4ZWNSZXN1bHRfTWNwUmVzb3VyY2UuQW5ub3RhdGlvbnNFbnRyeRoyChBBbm5vdGF0aW9uc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAFCBwoFX25hbWVCDgoMX2Rlc2NyaXB0aW9uQgwKCl9taW1lX3R5cGUiXgoXTGlzdE1jcFJlc291cmNlc1N1Y2Nlc3MSQwoJcmVzb3VyY2VzGAEgAygLMjAuYWdlbnQudjEuTGlzdE1jcFJlc291cmNlc0V4ZWNSZXN1bHRfTWNwUmVzb3VyY2UiJgoVTGlzdE1jcFJlc291cmNlc0Vycm9yEg0KBWVycm9yGAEgASgJIioKGExpc3RNY3BSZXNvdXJjZXNSZWplY3RlZBIOCgZyZWFzb24YASABKAki0QEKF1JlYWRNY3BSZXNvdXJjZUV4ZWNBcmdzEg4KBnNlcnZlchgBIAEoCRILCgN1cmkYAiABKAkSGgoNZG93bmxvYWRfcGF0aBgDIAEoCUgAiAEBEhQKDHRvb2xfY2FsbF9pZBgEIAEoCRI9ChNzbWFydF9tb2RlX2FwcHJvdmFsGAUgASgLMhsuYWdlbnQudjEuU21hcnRNb2RlQXBwcm92YWxIAYgBAUIQCg5fZG93bmxvYWRfcGF0aEIWChRfc21hcnRfbW9kZV9hcHByb3ZhbCL6AQoZUmVhZE1jcFJlc291cmNlRXhlY1Jlc3VsdBIzCgdzdWNjZXNzGAEgASgLMiAuYWdlbnQudjEuUmVhZE1jcFJlc291cmNlU3VjY2Vzc0gAEi8KBWVycm9yGAIgASgLMh4uYWdlbnQudjEuUmVhZE1jcFJlc291cmNlRXJyb3JIABI1CghyZWplY3RlZBgDIAEoCzIhLmFnZW50LnYxLlJlYWRNY3BSZXNvdXJjZVJlamVjdGVkSAASNgoJbm90X2ZvdW5kGAQgASgLMiEuYWdlbnQudjEuUmVhZE1jcFJlc291cmNlTm90Rm91bmRIAEIICgZyZXN1bHQisgMKFlJlYWRNY3BSZXNvdXJjZVN1Y2Nlc3MSCwoDdXJpGAEgASgJEhEKBG5hbWUYAiABKAlIAYgBARIYCgtkZXNjcmlwdGlvbhgDIAEoCUgCiAEBEhYKCW1pbWVfdHlwZRgEIAEoCUgDiAEBEkYKC2Fubm90YXRpb25zGAcgAygLMjEuYWdlbnQudjEuUmVhZE1jcFJlc291cmNlU3VjY2Vzcy5Bbm5vdGF0aW9uc0VudHJ5EhoKDWRvd25sb2FkX3BhdGgYCCABKAlIBIgBARIOCgR0ZXh0GAUgASgJSAASDgoEYmxvYhgGIAEoDEgAEjYKD291dHB1dF9sb2NhdGlvbhgJIAEoCzIYLmFnZW50LnYxLk91dHB1dExvY2F0aW9uSAWIAQEaMgoQQW5ub3RhdGlvbnNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBQgkKB2NvbnRlbnRCBwoFX25hbWVCDgoMX2Rlc2NyaXB0aW9uQgwKCl9taW1lX3R5cGVCEAoOX2Rvd25sb2FkX3BhdGhCEgoQX291dHB1dF9sb2NhdGlvbiIyChRSZWFkTWNwUmVzb3VyY2VFcnJvchILCgN1cmkYASABKAkSDQoFZXJyb3IYAiABKAkiNgoXUmVhZE1jcFJlc291cmNlUmVqZWN0ZWQSCwoDdXJpGAEgASgJEg4KBnJlYXNvbhgCIAEoCSImChdSZWFkTWNwUmVzb3VyY2VOb3RGb3VuZBILCgN1cmkYASABKAkisgEKEU1jcFRvb2xEZWZpbml0aW9uEgwKBG5hbWUYASABKAkSGwoTcHJvdmlkZXJfaWRlbnRpZmllchgEIAEoCRIRCgl0b29sX25hbWUYBSABKAkSEwoLZGVzY3JpcHRpb24YAiABKAkSFAoMaW5wdXRfc2NoZW1hGAMgASgMEh4KEWlucHV0X3NjaGVtYV9qc29uGAYgASgJSACIAQFCFAoSX2lucHV0X3NjaGVtYV9qc29uIjoKCE1jcFRvb2xzEi4KCW1jcF90b29scxgBIAMoCzIbLmFnZW50LnYxLk1jcFRvb2xEZWZpbml0aW9uIlcKD01jcEluc3RydWN0aW9ucxITCgtzZXJ2ZXJfbmFtZRgBIAEoCRIUCgxpbnN0cnVjdGlvbnMYAiABKAkSGQoRc2VydmVyX2lkZW50aWZpZXIYAyABKAki/QIKDU1jcERlc2NyaXB0b3ISEwoLc2VydmVyX25hbWUYASABKAkSGQoRc2VydmVyX2lkZW50aWZpZXIYAiABKAkSGAoLZm9sZGVyX3BhdGgYAyABKAlIAIgBARIkChdzZXJ2ZXJfdXNlX2luc3RydWN0aW9ucxgEIAEoCUgBiAEBEioKBXRvb2xzGAUgAygLMhsuYWdlbnQudjEuTWNwVG9vbERlc2NyaXB0b3ISEwoGcGx1Z2luGAcgASgJSAKIAQESGAoLbWFya2V0cGxhY2UYCCABKAlIA4gBARIZCgxwbHVnaW5fZGJfaWQYCSABKAlIBIgBARIbCg5tYXJrZXRwbGFjZV9pZBgKIAEoCUgFiAEBQg4KDF9mb2xkZXJfcGF0aEIaChhfc2VydmVyX3VzZV9pbnN0cnVjdGlvbnNCCQoHX3BsdWdpbkIOCgxfbWFya2V0cGxhY2VCDwoNX3BsdWdpbl9kYl9pZEIRCg9fbWFya2V0cGxhY2VfaWQiuAEKEU1jcFRvb2xEZXNjcmlwdG9yEhEKCXRvb2xfbmFtZRgBIAEoCRIcCg9kZWZpbml0aW9uX3BhdGgYAiABKAlIAIgBARIYCgtkZXNjcmlwdGlvbhgDIAEoCUgBiAEBEh4KEWlucHV0X3NjaGVtYV9qc29uGAUgASgJSAKIAQFCEgoQX2RlZmluaXRpb25fcGF0aEIOCgxfZGVzY3JpcHRpb25CFAoSX2lucHV0X3NjaGVtYV9qc29uIngKFE1jcEZpbGVTeXN0ZW1PcHRpb25zEg8KB2VuYWJsZWQYASABKAgSHQoVd29ya3NwYWNlX3Byb2plY3RfZGlyGAIgASgJEjAKD21jcF9kZXNjcmlwdG9ycxgDIAMoCzIXLmFnZW50LnYxLk1jcERlc2NyaXB0b3IimgEKCFJlYWRBcmdzEgwKBHBhdGgYASABKAkSFAoMdG9vbF9jYWxsX2lkGAIgASgJEhMKBm9mZnNldBgEIAEoBUgAiAEBEhIKBWxpbWl0GAUgASgNSAGIAQESGgoNZW5jb2RpbmdfaGludBgGIAEoCUgCiAEBQgkKB19vZmZzZXRCCAoGX2xpbWl0QhAKDl9lbmNvZGluZ19oaW50IrgCCgpSZWFkUmVzdWx0EigKB3N1Y2Nlc3MYASABKAsyFS5hZ2VudC52MS5SZWFkU3VjY2Vzc0gAEiQKBWVycm9yGAIgASgLMhMuYWdlbnQudjEuUmVhZEVycm9ySAASKgoIcmVqZWN0ZWQYAyABKAsyFi5hZ2VudC52MS5SZWFkUmVqZWN0ZWRIABI0Cg5maWxlX25vdF9mb3VuZBgEIAEoCzIaLmFnZW50LnYxLlJlYWRGaWxlTm90Rm91bmRIABI7ChFwZXJtaXNzaW9uX2RlbmllZBgFIAEoCzIeLmFnZW50LnYxLlJlYWRQZXJtaXNzaW9uRGVuaWVkSAASMQoMaW52YWxpZF9maWxlGAYgASgLMhkuYWdlbnQudjEuUmVhZEludmFsaWRGaWxlSABCCAoGcmVzdWx0IsoBCgtSZWFkU3VjY2VzcxIMCgRwYXRoGAEgASgJEhMKC3RvdGFsX2xpbmVzGAMgASgFEhEKCWZpbGVfc2l6ZRgEIAEoAxIRCgl0cnVuY2F0ZWQYBiABKAgSGwoOb3V0cHV0X2Jsb2JfaWQYByABKAxIAYgBARIRCgdjb250ZW50GAIgASgJSAASDgoEZGF0YRgFIAEoDEgAEhUKDXJhbmdlX2FwcGxpZWQYCCABKAhCCAoGb3V0cHV0QhEKD19vdXRwdXRfYmxvYl9pZCIoCglSZWFkRXJyb3ISDAoEcGF0aBgBIAEoCRINCgVlcnJvchgCIAEoCSIsCgxSZWFkUmVqZWN0ZWQSDAoEcGF0aBgBIAEoCRIOCgZyZWFzb24YAiABKAkiIAoQUmVhZEZpbGVOb3RGb3VuZBIMCgRwYXRoGAEgASgJIiQKFFJlYWRQZXJtaXNzaW9uRGVuaWVkEgwKBHBhdGgYASABKAkiLwoPUmVhZEludmFsaWRGaWxlEgwKBHBhdGgYASABKAkSDgoGcmVhc29uGAIgASgJIl4KDFJlYWRUb29sQ2FsbBIkCgRhcmdzGAEgASgLMhYuYWdlbnQudjEuUmVhZFRvb2xBcmdzEigKBnJlc3VsdBgCIAEoCzIYLmFnZW50LnYxLlJlYWRUb29sUmVzdWx0IloKDFJlYWRUb29sQXJncxIMCgRwYXRoGAEgASgJEhMKBm9mZnNldBgCIAEoBUgAiAEBEhIKBWxpbWl0GAMgASgFSAGIAQFCCQoHX29mZnNldEIICgZfbGltaXQicgoOUmVhZFRvb2xSZXN1bHQSLAoHc3VjY2VzcxgBIAEoCzIZLmFnZW50LnYxLlJlYWRUb29sU3VjY2Vzc0gAEigKBWVycm9yGAIgASgLMhcuYWdlbnQudjEuUmVhZFRvb2xFcnJvckgAQggKBnJlc3VsdCIxCglSZWFkUmFuZ2USEgoKc3RhcnRfbGluZRgBIAEoDRIQCghlbmRfbGluZRgCIAEoDSKOAgoPUmVhZFRvb2xTdWNjZXNzEhAKCGlzX2VtcHR5GAIgASgIEhYKDmV4Y2VlZGVkX2xpbWl0GAMgASgIEhMKC3RvdGFsX2xpbmVzGAQgASgNEhEKCWZpbGVfc2l6ZRgFIAEoDRIMCgRwYXRoGAcgASgJEiwKCnJlYWRfcmFuZ2UYCCABKAsyEy5hZ2VudC52MS5SZWFkUmFuZ2VIAYgBARIRCgdjb250ZW50GAEgASgJSAASDgoEZGF0YRgGIAEoDEgAEhYKDGRhdGFfYmxvYl9pZBgJIAEoDEgAEhkKD2NvbnRlbnRfYmxvYl9pZBgKIAEoDEgAQggKBm91dHB1dEINCgtfcmVhZF9yYW5nZSImCg1SZWFkVG9vbEVycm9yEhUKDWVycm9yX21lc3NhZ2UYASABKAkiagoQUmVjb3JkU2NyZWVuQXJncxIMCgRtb2RlGAEgASgFEhQKDHRvb2xfY2FsbF9pZBgCIAEoCRIdChBzYXZlX2FzX2ZpbGVuYW1lGAMgASgJSACIAQFCEwoRX3NhdmVfYXNfZmlsZW5hbWUiiQIKElJlY29yZFNjcmVlblJlc3VsdBI7Cg1zdGFydF9zdWNjZXNzGAEgASgLMiIuYWdlbnQudjEuUmVjb3JkU2NyZWVuU3RhcnRTdWNjZXNzSAASOQoMc2F2ZV9zdWNjZXNzGAIgASgLMiEuYWdlbnQudjEuUmVjb3JkU2NyZWVuU2F2ZVN1Y2Nlc3NIABI/Cg9kaXNjYXJkX3N1Y2Nlc3MYAyABKAsyJC5hZ2VudC52MS5SZWNvcmRTY3JlZW5EaXNjYXJkU3VjY2Vzc0gAEjAKB2ZhaWx1cmUYBCABKAsyHS5hZ2VudC52MS5SZWNvcmRTY3JlZW5GYWlsdXJlSABCCAoGcmVzdWx0ImcKGFJlY29yZFNjcmVlblN0YXJ0U3VjY2VzcxIlCh13YXNfcHJpb3JfcmVjb3JkaW5nX2NhbmNlbGxlZBgBIAEoCBIkChx3YXNfc2F2ZV9hc19maWxlbmFtZV9pZ25vcmVkGAIgASgIIqABChdSZWNvcmRTY3JlZW5TYXZlU3VjY2VzcxIMCgRwYXRoGAEgASgJEh0KFXJlY29yZGluZ19kdXJhdGlvbl9tcxgCIAEoAxIwCiNyZXF1ZXN0ZWRfZmlsZV9wYXRoX3JlamVjdGVkX3JlYXNvbhgDIAEoBUgAiAEBQiYKJF9yZXF1ZXN0ZWRfZmlsZV9wYXRoX3JlamVjdGVkX3JlYXNvbiIcChpSZWNvcmRTY3JlZW5EaXNjYXJkU3VjY2VzcyIkChNSZWNvcmRTY3JlZW5GYWlsdXJlEg0KBWVycm9yGAEgASgJIjYKE0N1cnNvclBhY2thZ2VQcm9tcHQSDAoEbmFtZRgBIAEoCRIRCglmaWxlX3BhdGgYAiABKAki4gEKDUN1cnNvclBhY2thZ2USDAoEbmFtZRgBIAEoCRITCgtkZXNjcmlwdGlvbhgCIAEoCRITCgtmb2xkZXJfcGF0aBgDIAEoCRIPCgdlbmFibGVkGAQgASgIEhgKC3BhcnNlX2Vycm9yGAUgASgJSACIAQESLgoHcHJvbXB0cxgGIAMoCzIdLmFnZW50LnYxLkN1cnNvclBhY2thZ2VQcm9tcHQSGAoQcmVhZG1lX2ZpbGVfcGF0aBgHIAEoCRIUCgxwYWNrYWdlX3R5cGUYCCABKAVCDgoMX3BhcnNlX2Vycm9yIqsCChZSZXBvc2l0b3J5SW5kZXhpbmdJbmZvEh8KF3JlbGF0aXZlX3dvcmtzcGFjZV9wYXRoGAEgASgJEhMKC3JlbW90ZV91cmxzGAIgAygJEhQKDHJlbW90ZV9uYW1lcxgDIAMoCRIRCglyZXBvX25hbWUYBCABKAkSEgoKcmVwb19vd25lchgFIAEoCRISCgppc190cmFja2VkGAYgASgIEhAKCGlzX2xvY2FsGAcgASgIEiYKGW9ydGhvZ29uYWxfdHJhbnNmb3JtX3NlZWQYCCABKAFIAIgBARIVCg13b3Jrc3BhY2VfdXJpGAkgASgJEhsKE3BhdGhfZW5jcnlwdGlvbl9rZXkYCiABKAlCHAoaX29ydGhvZ29uYWxfdHJhbnNmb3JtX3NlZWQirAIKElJlcXVlc3RDb250ZXh0QXJncxIdChBub3Rlc19zZXNzaW9uX2lkGAIgASgJSACIAQESGQoMd29ya3NwYWNlX2lkGAMgASgJSAGIAQESJgoZcmVhZF9vbmx5X3Bpbm5lZF90cmVlX3NoYRgEIAEoCUgCiAEBEigKG3JlYWRfb25seV9wbHVnaW5fY2FjaGVfcm9vdBgFIAEoCUgDiAEBEhcKCnVzZV9jYWNoZWQYByABKAhIBIgBAUITChFfbm90ZXNfc2Vzc2lvbl9pZEIPCg1fd29ya3NwYWNlX2lkQhwKGl9yZWFkX29ubHlfcGlubmVkX3RyZWVfc2hhQh4KHF9yZWFkX29ubHlfcGx1Z2luX2NhY2hlX3Jvb3RCDQoLX3VzZV9jYWNoZWQiugEKFFJlcXVlc3RDb250ZXh0UmVzdWx0EjIKB3N1Y2Nlc3MYASABKAsyHy5hZ2VudC52MS5SZXF1ZXN0Q29udGV4dFN1Y2Nlc3NIABIuCgVlcnJvchgCIAEoCzIdLmFnZW50LnYxLlJlcXVlc3RDb250ZXh0RXJyb3JIABI0CghyZWplY3RlZBgDIAEoCzIgLmFnZW50LnYxLlJlcXVlc3RDb250ZXh0UmVqZWN0ZWRIAEIICgZyZXN1bHQiigEKFVJlcXVlc3RDb250ZXh0U3VjY2VzcxIxCg9yZXF1ZXN0X2NvbnRleHQYASABKAsyGC5hZ2VudC52MS5SZXF1ZXN0Q29udGV4dBIjChZzZXJ2ZWRfZnJvbV9kaXNrX2NhY2hlGAIgASgISACIAQFCGQoXX3NlcnZlZF9mcm9tX2Rpc2tfY2FjaGUiJAoTUmVxdWVzdENvbnRleHRFcnJvchINCgVlcnJvchgBIAEoCSIoChZSZXF1ZXN0Q29udGV4dFJlamVjdGVkEg4KBnJlYXNvbhgBIAEoCSLCAQoKSW1hZ2VQcm90bxIMCgRkYXRhGAEgASgMEgwKBHV1aWQYAiABKAkSDAoEcGF0aBgDIAEoCRIxCglkaW1lbnNpb24YBCABKAsyHi5hZ2VudC52MS5JbWFnZVByb3RvX0RpbWVuc2lvbhImChl0YXNrX3NwZWNpZmljX2Rlc2NyaXB0aW9uGAYgASgJSACIAQESEQoJbWltZV90eXBlGAcgASgJQhwKGl90YXNrX3NwZWNpZmljX2Rlc2NyaXB0aW9uIjUKFEltYWdlUHJvdG9fRGltZW5zaW9uEg0KBXdpZHRoGAEgASgFEg4KBmhlaWdodBgCIAEoBSJoCgtHaXRSZXBvSW5mbxIMCgRwYXRoGAEgASgJEg4KBnN0YXR1cxgCIAEoCRITCgticmFuY2hfbmFtZRgDIAEoCRIXCgpyZW1vdGVfdXJsGAQgASgJSACIAQFCDQoLX3JlbW90ZV91cmwimwIKEVJlcXVlc3RDb250ZXh0RW52EhIKCm9zX3ZlcnNpb24YASABKAkSFwoPd29ya3NwYWNlX3BhdGhzGAIgAygJEg0KBXNoZWxsGAMgASgJEhcKD3NhbmRib3hfZW5hYmxlZBgFIAEoCBIYChB0ZXJtaW5hbHNfZm9sZGVyGAcgASgJEiEKGWFnZW50X3NoYXJlZF9ub3Rlc19mb2xkZXIYCCABKAkSJwofYWdlbnRfY29udmVyc2F0aW9uX25vdGVzX2ZvbGRlchgJIAEoCRIRCgl0aW1lX3pvbmUYCiABKAkSFgoOcHJvamVjdF9mb2xkZXIYCyABKAkSIAoYYWdlbnRfdHJhbnNjcmlwdHNfZm9sZGVyGAwgASgJIjwKD0RlYnVnTW9kZUNvbmZpZxIQCghsb2dfcGF0aBgBIAEoCRIXCg9zZXJ2ZXJfZW5kcG9pbnQYAiABKAkitAEKD1NraWxsRGVzY3JpcHRvchIMCgRuYW1lGAEgASgJEhMKC2Rlc2NyaXB0aW9uGAIgASgJEhMKC2ZvbGRlcl9wYXRoGAMgASgJEg8KB2VuYWJsZWQYBCABKAgSGAoLcGFyc2VfZXJyb3IYBSABKAlIAIgBARIYChByZWFkbWVfZmlsZV9wYXRoGAYgASgJEhQKDHBhY2thZ2VfdHlwZRgHIAEoBUIOCgxfcGFyc2VfZXJyb3IiRAoMU2tpbGxPcHRpb25zEjQKEXNraWxsX2Rlc2NyaXB0b3JzGAEgAygLMhkuYWdlbnQudjEuU2tpbGxEZXNjcmlwdG9yIvYICg5SZXF1ZXN0Q29udGV4dBIjCgVydWxlcxgCIAMoCzIULmFnZW50LnYxLkN1cnNvclJ1bGUSKAoDZW52GAQgASgLMhsuYWdlbnQudjEuUmVxdWVzdENvbnRleHRFbnYSOQoPcmVwb3NpdG9yeV9pbmZvGAYgAygLMiAuYWdlbnQudjEuUmVwb3NpdG9yeUluZGV4aW5nSW5mbxIqCgV0b29scxgHIAMoCzIbLmFnZW50LnYxLk1jcFRvb2xEZWZpbml0aW9uEicKGmNvbnZlcnNhdGlvbl9ub3Rlc19saXN0aW5nGAggASgJSACIAQESIQoUc2hhcmVkX25vdGVzX2xpc3RpbmcYCSABKAlIAYgBARIoCglnaXRfcmVwb3MYCyADKAsyFS5hZ2VudC52MS5HaXRSZXBvSW5mbxI2Cg9wcm9qZWN0X2xheW91dHMYDSADKAsyHS5hZ2VudC52MS5Mc0RpcmVjdG9yeVRyZWVOb2RlEjMKEG1jcF9pbnN0cnVjdGlvbnMYDiADKAsyGS5hZ2VudC52MS5NY3BJbnN0cnVjdGlvbnMSOQoRZGVidWdfbW9kZV9jb25maWcYDyABKAsyGS5hZ2VudC52MS5EZWJ1Z01vZGVDb25maWdIAogBARIXCgpjbG91ZF9ydWxlGBAgASgJSAOIAQESHwoSd2ViX3NlYXJjaF9lbmFibGVkGBEgASgISASIAQESMgoNc2tpbGxfb3B0aW9ucxgSIAEoCzIWLmFnZW50LnYxLlNraWxsT3B0aW9uc0gFiAEBEi4KIXJlcG9zaXRvcnlfaW5mb19zaG91bGRfcXVlcnlfcHJvZBgTIAEoCEgGiAEBEkEKDWZpbGVfY29udGVudHMYFCADKAsyKi5hZ2VudC52MS5SZXF1ZXN0Q29udGV4dC5GaWxlQ29udGVudHNFbnRyeRIgChN1c2VyX2ludGVudF9zdW1tYXJ5GBUgASgJSAeIAQESMgoQY3VzdG9tX3N1YmFnZW50cxgWIAMoCzIYLmFnZW50LnYxLkN1c3RvbVN1YmFnZW50EkQKF21jcF9maWxlX3N5c3RlbV9vcHRpb25zGBcgASgLMh4uYWdlbnQudjEuTWNwRmlsZVN5c3RlbU9wdGlvbnNICIgBARozChFGaWxlQ29udGVudHNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBQh0KG19jb252ZXJzYXRpb25fbm90ZXNfbGlzdGluZ0IXChVfc2hhcmVkX25vdGVzX2xpc3RpbmdCFAoSX2RlYnVnX21vZGVfY29uZmlnQg0KC19jbG91ZF9ydWxlQhUKE193ZWJfc2VhcmNoX2VuYWJsZWRCEAoOX3NraWxsX29wdGlvbnNCJAoiX3JlcG9zaXRvcnlfaW5mb19zaG91bGRfcXVlcnlfcHJvZEIWChRfdXNlcl9pbnRlbnRfc3VtbWFyeUIaChhfbWNwX2ZpbGVfc3lzdGVtX29wdGlvbnMisgIKDVNhbmRib3hQb2xpY3kSDAoEdHlwZRgBIAEoBRIbCg5uZXR3b3JrX2FjY2VzcxgCIAEoCEgAiAEBEiIKGmFkZGl0aW9uYWxfcmVhZHdyaXRlX3BhdGhzGAMgAygJEiEKGWFkZGl0aW9uYWxfcmVhZG9ubHlfcGF0aHMYBCADKAkSHQoQZGVidWdfb3V0cHV0X2RpchgFIAEoCUgBiAEBEh0KEGJsb2NrX2dpdF93cml0ZXMYBiABKAhIAogBARIeChFkaXNhYmxlX3RtcF93cml0ZRgHIAEoCEgDiAEBQhEKD19uZXR3b3JrX2FjY2Vzc0ITChFfZGVidWdfb3V0cHV0X2RpckITChFfYmxvY2tfZ2l0X3dyaXRlc0IUChJfZGlzYWJsZV90bXBfd3JpdGUi7wEKDVNlbGVjdGVkSW1hZ2USDAoEdXVpZBgCIAEoCRIMCgRwYXRoGAMgASgJEjQKCWRpbWVuc2lvbhgEIAEoCzIhLmFnZW50LnYxLlNlbGVjdGVkSW1hZ2VfRGltZW5zaW9uEhEKCW1pbWVfdHlwZRgHIAEoCRIRCgdibG9iX2lkGAEgASgMSAASDgoEZGF0YRgIIAEoDEgAEkMKEWJsb2JfaWRfd2l0aF9kYXRhGAkgASgLMiYuYWdlbnQudjEuU2VsZWN0ZWRJbWFnZV9CbG9iSWRXaXRoRGF0YUgAQhEKD2RhdGFfb3JfYmxvYl9pZCI9ChxTZWxlY3RlZEltYWdlX0Jsb2JJZFdpdGhEYXRhEg8KB2Jsb2JfaWQYASABKAwSDAoEZGF0YRgCIAEoDCI4ChdTZWxlY3RlZEltYWdlX0RpbWVuc2lvbhINCgV3aWR0aBgBIAEoBRIOCgZoZWlnaHQYAiABKAUiSQoRRXh0cmFDb250ZXh0RW50cnkSDgoEZGF0YRgBIAEoCUgAEhEKB2Jsb2JfaWQYAiABKAxIAEIRCg9kYXRhX29yX2Jsb2JfaWQiWwoMU2VsZWN0ZWRGaWxlEg8KB2NvbnRlbnQYASABKAkSDAoEcGF0aBgCIAEoCRIaCg1yZWxhdGl2ZV9wYXRoGAMgASgJSACIAQFCEAoOX3JlbGF0aXZlX3BhdGgihAEKFVNlbGVjdGVkQ29kZVNlbGVjdGlvbhIPCgdjb250ZW50GAEgASgJEgwKBHBhdGgYAiABKAkSGgoNcmVsYXRpdmVfcGF0aBgDIAEoCUgAiAEBEh4KBXJhbmdlGAQgASgLMg8uYWdlbnQudjEuUmFuZ2VCEAoOX3JlbGF0aXZlX3BhdGgiXQoQU2VsZWN0ZWRUZXJtaW5hbBIPCgdjb250ZW50GAEgASgJEhIKBXRpdGxlGAIgASgJSACIAQESEQoEcGF0aBgDIAEoCUgBiAEBQggKBl90aXRsZUIHCgVfcGF0aCKGAQoZU2VsZWN0ZWRUZXJtaW5hbFNlbGVjdGlvbhIPCgdjb250ZW50GAEgASgJEhIKBXRpdGxlGAIgASgJSACIAQESEQoEcGF0aBgDIAEoCUgBiAEBEh4KBXJhbmdlGAQgASgLMg8uYWdlbnQudjEuUmFuZ2VCCAoGX3RpdGxlQgcKBV9wYXRoIoMBCg5TZWxlY3RlZEZvbGRlchIMCgRwYXRoGAEgASgJEhoKDXJlbGF0aXZlX3BhdGgYAiABKAlIAIgBARI1Cg5kaXJlY3RvcnlfdHJlZRgDIAEoCzIdLmFnZW50LnYxLkxzRGlyZWN0b3J5VHJlZU5vZGVCEAoOX3JlbGF0aXZlX3BhdGginwEKFFNlbGVjdGVkRXh0ZXJuYWxMaW5rEgsKA3VybBgBIAEoCRIMCgR1dWlkGAIgASgJEhgKC3BkZl9jb250ZW50GAMgASgJSACIAQESEwoGaXNfcGRmGAQgASgISAGIAQESFQoIZmlsZW5hbWUYBSABKAlIAogBAUIOCgxfcGRmX2NvbnRlbnRCCQoHX2lzX3BkZkILCglfZmlsZW5hbWUiOAoSU2VsZWN0ZWRDdXJzb3JSdWxlEiIKBHJ1bGUYASABKAsyFC5hZ2VudC52MS5DdXJzb3JSdWxlIiIKD1NlbGVjdGVkR2l0RGlmZhIPCgdjb250ZW50GAEgASgJIjIKH1NlbGVjdGVkR2l0RGlmZkZyb21CcmFuY2hUb01haW4SDwoHY29udGVudBgBIAEoCSJpChFTZWxlY3RlZEdpdENvbW1pdBILCgNzaGEYASABKAkSDwoHbWVzc2FnZRgCIAEoCRIYCgtkZXNjcmlwdGlvbhgDIAEoCUgAiAEBEgwKBGRpZmYYBCABKAlCDgoMX2Rlc2NyaXB0aW9uIt0BChNTZWxlY3RlZFB1bGxSZXF1ZXN0Eg4KBm51bWJlchgBIAEoBRILCgN1cmwYAiABKAkSEgoFdGl0bGUYAyABKAlIAIgBARITCgtmb2xkZXJfcGF0aBgEIAEoCRIZCgxzdW1tYXJ5X2pzb24YBSABKAlIAYgBARIYCgtkZXNjcmlwdGlvbhgGIAEoCUgCiAEBEhQKB2Jsb2JfaWQYByABKAxIA4gBAUIICgZfdGl0bGVCDwoNX3N1bW1hcnlfanNvbkIOCgxfZGVzY3JpcHRpb25CCgoIX2Jsb2JfaWQiswEKGlNlbGVjdGVkR2l0UFJEaWZmU2VsZWN0aW9uEg4KBnByX3VybBgBIAEoCRIRCglmaWxlX3BhdGgYAiABKAkSEgoKc3RhcnRfbGluZRgDIAEoBRIQCghlbmRfbGluZRgEIAEoBRIZCgxkaWZmX2NvbnRlbnQYBSABKAlIAIgBARIUCgdibG9iX2lkGAYgASgMSAGIAQFCDwoNX2RpZmZfY29udGVudEIKCghfYmxvYl9pZCI2ChVTZWxlY3RlZEN1cnNvckNvbW1hbmQSDAoEbmFtZRgBIAEoCRIPCgdjb250ZW50GAIgASgJIjUKFVNlbGVjdGVkRG9jdW1lbnRhdGlvbhIOCgZkb2NfaWQYASABKAkSDAoEbmFtZRgCIAEoCSIyChBTZWxlY3RlZFBhc3RDaGF0EhAKCGFnZW50X2lkGAEgASgJEgwKBG5hbWUYAiABKAkiqwEKCUNhbGxGcmFtZRIaCg1mdW5jdGlvbl9uYW1lGAEgASgJSACIAQESEAoDdXJsGAIgASgJSAGIAQESGAoLbGluZV9udW1iZXIYAyABKAVIAogBARIaCg1jb2x1bW5fbnVtYmVyGAQgASgFSAOIAQFCEAoOX2Z1bmN0aW9uX25hbWVCBgoEX3VybEIOCgxfbGluZV9udW1iZXJCEAoOX2NvbHVtbl9udW1iZXIiaAoKU3RhY2tUcmFjZRIoCgtjYWxsX2ZyYW1lcxgBIAMoCzITLmFnZW50LnYxLkNhbGxGcmFtZRIcCg9yYXdfc3RhY2tfdHJhY2UYAiABKAlIAIgBAUISChBfcmF3X3N0YWNrX3RyYWNlIuQBChJTZWxlY3RlZENvbnNvbGVMb2cSDwoHbWVzc2FnZRgBIAEoCRIRCgl0aW1lc3RhbXAYAiABKAESDQoFbGV2ZWwYAyABKAkSEwoLY2xpZW50X25hbWUYBCABKAkSEgoKc2Vzc2lvbl9pZBgFIAEoCRIuCgtzdGFja190cmFjZRgGIAEoCzIULmFnZW50LnYxLlN0YWNrVHJhY2VIAIgBARIdChBvYmplY3RfZGF0YV9qc29uGAcgASgJSAGIAQFCDgoMX3N0YWNrX3RyYWNlQhMKEV9vYmplY3RfZGF0YV9qc29uIroBChFTZWxlY3RlZFVJRWxlbWVudBIPCgdlbGVtZW50GAEgASgJEg0KBXhwYXRoGAIgASgJEhQKDHRleHRfY29udGVudBgDIAEoCRINCgVleHRyYRgEIAEoCRIWCgljb21wb25lbnQYBSABKAlIAIgBARIhChRjb21wb25lbnRfcHJvcHNfanNvbhgGIAEoCUgBiAEBQgwKCl9jb21wb25lbnRCFwoVX2NvbXBvbmVudF9wcm9wc19qc29uIiAKEFNlbGVjdGVkU3ViYWdlbnQSDAoEbmFtZRgBIAEoCSKCCgoPU2VsZWN0ZWRDb250ZXh0EjAKD3NlbGVjdGVkX2ltYWdlcxgBIAMoCzIXLmFnZW50LnYxLlNlbGVjdGVkSW1hZ2USPAoSaW52b2NhdGlvbl9jb250ZXh0GAIgASgLMhsuYWdlbnQudjEuSW52b2NhdGlvbkNvbnRleHRIAIgBARIVCg1leHRyYV9jb250ZXh0GAMgAygJEjoKFWV4dHJhX2NvbnRleHRfZW50cmllcxgQIAMoCzIbLmFnZW50LnYxLkV4dHJhQ29udGV4dEVudHJ5EiUKBWZpbGVzGAQgAygLMhYuYWdlbnQudjEuU2VsZWN0ZWRGaWxlEjgKD2NvZGVfc2VsZWN0aW9ucxgFIAMoCzIfLmFnZW50LnYxLlNlbGVjdGVkQ29kZVNlbGVjdGlvbhItCgl0ZXJtaW5hbHMYBiADKAsyGi5hZ2VudC52MS5TZWxlY3RlZFRlcm1pbmFsEkAKE3Rlcm1pbmFsX3NlbGVjdGlvbnMYByADKAsyIy5hZ2VudC52MS5TZWxlY3RlZFRlcm1pbmFsU2VsZWN0aW9uEikKB2ZvbGRlcnMYCCADKAsyGC5hZ2VudC52MS5TZWxlY3RlZEZvbGRlchI2Cg5leHRlcm5hbF9saW5rcxgJIAMoCzIeLmFnZW50LnYxLlNlbGVjdGVkRXh0ZXJuYWxMaW5rEjIKDGN1cnNvcl9ydWxlcxgKIAMoCzIcLmFnZW50LnYxLlNlbGVjdGVkQ3Vyc29yUnVsZRIwCghnaXRfZGlmZhgSIAEoCzIZLmFnZW50LnYxLlNlbGVjdGVkR2l0RGlmZkgBiAEBElQKHGdpdF9kaWZmX2Zyb21fYnJhbmNoX3RvX21haW4YCyABKAsyKS5hZ2VudC52MS5TZWxlY3RlZEdpdERpZmZGcm9tQnJhbmNoVG9NYWluSAKIAQESOAoPY3Vyc29yX2NvbW1hbmRzGAwgAygLMh8uYWdlbnQudjEuU2VsZWN0ZWRDdXJzb3JDb21tYW5kEjcKDmRvY3VtZW50YXRpb25zGA0gAygLMh8uYWdlbnQudjEuU2VsZWN0ZWREb2N1bWVudGF0aW9uEjAKC3VpX2VsZW1lbnRzGA4gAygLMhsuYWdlbnQudjEuU2VsZWN0ZWRVSUVsZW1lbnQSMgoMY29uc29sZV9sb2dzGA8gAygLMhwuYWdlbnQudjEuU2VsZWN0ZWRDb25zb2xlTG9nEjAKC2dpdF9jb21taXRzGBEgAygLMhsuYWdlbnQudjEuU2VsZWN0ZWRHaXRDb21taXQSLgoKcGFzdF9jaGF0cxgTIAMoCzIaLmFnZW50LnYxLlNlbGVjdGVkUGFzdENoYXQSRAoWZ2l0X3ByX2RpZmZfc2VsZWN0aW9ucxgUIAMoCzIkLmFnZW50LnYxLlNlbGVjdGVkR2l0UFJEaWZmU2VsZWN0aW9uEj0KFnNlbGVjdGVkX3B1bGxfcmVxdWVzdHMYFSADKAsyHS5hZ2VudC52MS5TZWxlY3RlZFB1bGxSZXF1ZXN0EjYKEnNlbGVjdGVkX3N1YmFnZW50cxgWIAMoCzIaLmFnZW50LnYxLlNlbGVjdGVkU3ViYWdlbnRCFQoTX2ludm9jYXRpb25fY29udGV4dEILCglfZ2l0X2RpZmZCHwodX2dpdF9kaWZmX2Zyb21fYnJhbmNoX3RvX21haW4i5QEKEUludm9jYXRpb25Db250ZXh0Ej8KDHNsYWNrX3RocmVhZBgBIAEoCzInLmFnZW50LnYxLkludm9jYXRpb25Db250ZXh0X1NsYWNrVGhyZWFkSAASOQoJZ2l0aHViX3ByGAIgASgLMiQuYWdlbnQudjEuSW52b2NhdGlvbkNvbnRleHRfR2l0aHViUFJIABI5CglpZGVfc3RhdGUYAyABKAsyJC5hZ2VudC52MS5JbnZvY2F0aW9uQ29udGV4dF9JZGVTdGF0ZUgAEhEKB2Jsb2JfaWQYCiABKAxIAEIGCgRkYXRhIrsBCh1JbnZvY2F0aW9uQ29udGV4dF9TbGFja1RocmVhZBIOCgZ0aHJlYWQYASABKAkSGQoMY2hhbm5lbF9uYW1lGAIgASgJSACIAQESHAoPY2hhbm5lbF9wdXJwb3NlGAMgASgJSAGIAQESGgoNY2hhbm5lbF90b3BpYxgEIAEoCUgCiAEBQg8KDV9jaGFubmVsX25hbWVCEgoQX2NoYW5uZWxfcHVycG9zZUIQCg5fY2hhbm5lbF90b3BpYyJ8ChpJbnZvY2F0aW9uQ29udGV4dF9HaXRodWJQUhINCgV0aXRsZRgBIAEoCRITCgtkZXNjcmlwdGlvbhgCIAEoCRIQCghjb21tZW50cxgDIAEoCRIYCgtjaV9mYWlsdXJlcxgEIAEoCUgAiAEBQg4KDF9jaV9mYWlsdXJlcyL+AQoaSW52b2NhdGlvbkNvbnRleHRfSWRlU3RhdGUSQAoNdmlzaWJsZV9maWxlcxgBIAMoCzIpLmFnZW50LnYxLkludm9jYXRpb25Db250ZXh0X0lkZVN0YXRlX0ZpbGUSSAoVcmVjZW50bHlfdmlld2VkX2ZpbGVzGAIgAygLMikuYWdlbnQudjEuSW52b2NhdGlvbkNvbnRleHRfSWRlU3RhdGVfRmlsZRJUChRjdXJyZW50bHlfdmlld2VkX3BycxgDIAMoCzI2LmFnZW50LnYxLkludm9jYXRpb25Db250ZXh0X0lkZVN0YXRlX1ZpZXdlZFB1bGxSZXF1ZXN0Io4CCh9JbnZvY2F0aW9uQ29udGV4dF9JZGVTdGF0ZV9GaWxlEgwKBHBhdGgYASABKAkSGgoNcmVsYXRpdmVfcGF0aBgCIAEoCUgAiAEBElYKD2N1cnNvcl9wb3NpdGlvbhgDIAEoCzI4LmFnZW50LnYxLkludm9jYXRpb25Db250ZXh0X0lkZVN0YXRlX0ZpbGVfQ3Vyc29yUG9zaXRpb25IAYgBARITCgt0b3RhbF9saW5lcxgEIAEoBRIbCg5hY3RpdmVfY29tbWFuZBgFIAEoCUgCiAEBQhAKDl9yZWxhdGl2ZV9wYXRoQhIKEF9jdXJzb3JfcG9zaXRpb25CEQoPX2FjdGl2ZV9jb21tYW5kIkwKLkludm9jYXRpb25Db250ZXh0X0lkZVN0YXRlX0ZpbGVfQ3Vyc29yUG9zaXRpb24SDAoEbGluZRgBIAEoBRIMCgR0ZXh0GAIgASgJIukBCixJbnZvY2F0aW9uQ29udGV4dF9JZGVTdGF0ZV9WaWV3ZWRQdWxsUmVxdWVzdBIOCgZudW1iZXIYASABKAUSCwoDdXJsGAIgASgJEhIKBXRpdGxlGAMgASgJSACIAQESGAoLZm9sZGVyX3BhdGgYBCABKAlIAYgBARIZCgxzdW1tYXJ5X2pzb24YBSABKAlIAogBARIYCgtkZXNjcmlwdGlvbhgGIAEoCUgDiAEBQggKBl90aXRsZUIOCgxfZm9sZGVyX3BhdGhCDwoNX3N1bW1hcnlfanNvbkIOCgxfZGVzY3JpcHRpb24iSAoWU2V0dXBWbUVudmlyb25tZW50QXJncxIXCg9pbnN0YWxsX2NvbW1hbmQYAiABKAkSFQoNc3RhcnRfY29tbWFuZBgDIAEoCSJcChhTZXR1cFZtRW52aXJvbm1lbnRSZXN1bHQSNgoHc3VjY2VzcxgBIAEoCzIjLmFnZW50LnYxLlNldHVwVm1FbnZpcm9ubWVudFN1Y2Nlc3NIAEIICgZyZXN1bHQiGwoZU2V0dXBWbUVudmlyb25tZW50U3VjY2VzcyKAAQoaU2V0dXBWbUVudmlyb25tZW50VG9vbENhbGwSLgoEYXJncxgBIAEoCzIgLmFnZW50LnYxLlNldHVwVm1FbnZpcm9ubWVudEFyZ3MSMgoGcmVzdWx0GAIgASgLMiIuYWdlbnQudjEuU2V0dXBWbUVudmlyb25tZW50UmVzdWx0IskCChlTaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0EhYKDnBhcnNpbmdfZmFpbGVkGAEgASgIElIKE2V4ZWN1dGFibGVfY29tbWFuZHMYAiADKAsyNS5hZ2VudC52MS5TaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0X0V4ZWN1dGFibGVDb21tYW5kEhUKDWhhc19yZWRpcmVjdHMYAyABKAgSIAoYaGFzX2NvbW1hbmRfc3Vic3RpdHV0aW9uGAQgASgIEicKGmFsbF9yZWRpcmVjdHNfYXJlX2Rldl9udWxsGAUgASgISACIAQESPwoJcmVkaXJlY3RzGAYgAygLMiwuYWdlbnQudjEuU2hlbGxDb21tYW5kUGFyc2luZ1Jlc3VsdF9SZWRpcmVjdEIdChtfYWxsX3JlZGlyZWN0c19hcmVfZGV2X251bGwiTQouU2hlbGxDb21tYW5kUGFyc2luZ1Jlc3VsdF9FeGVjdXRhYmxlQ29tbWFuZEFyZxIMCgR0eXBlGAEgASgJEg0KBXZhbHVlGAIgASgJIpYBCitTaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0X0V4ZWN1dGFibGVDb21tYW5kEgwKBG5hbWUYASABKAkSRgoEYXJncxgCIAMoCzI4LmFnZW50LnYxLlNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHRfRXhlY3V0YWJsZUNvbW1hbmRBcmcSEQoJZnVsbF90ZXh0GAMgASgJIvoHCglTaGVsbEFyZ3MSDwoHY29tbWFuZBgBIAEoCRIZChF3b3JraW5nX2RpcmVjdG9yeRgCIAEoCRIPCgd0aW1lb3V0GAMgASgFEhQKDHRvb2xfY2FsbF9pZBgEIAEoCRIXCg9zaW1wbGVfY29tbWFuZHMYBSADKAkSGgoSaGFzX2lucHV0X3JlZGlyZWN0GAYgASgIEhsKE2hhc19vdXRwdXRfcmVkaXJlY3QYByABKAgSOwoOcGFyc2luZ19yZXN1bHQYCCABKAsyIy5hZ2VudC52MS5TaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0Ej4KGHJlcXVlc3RlZF9zYW5kYm94X3BvbGljeRgJIAEoCzIXLmFnZW50LnYxLlNhbmRib3hQb2xpY3lIAIgBARIoChtmaWxlX291dHB1dF90aHJlc2hvbGRfYnl0ZXMYCiABKARIAYgBARIVCg1pc19iYWNrZ3JvdW5kGAsgASgIEhUKDXNraXBfYXBwcm92YWwYDCABKAgSGAoQdGltZW91dF9iZWhhdmlvchgNIAEoBRIZCgxoYXJkX3RpbWVvdXQYDiABKAVIAogBARIYCgtkZXNjcmlwdGlvbhgPIAEoCUgDiAEBEkEKEWNsYXNzaWZpZXJfcmVzdWx0GBAgASgLMiEuYWdlbnQudjEuQ29tbWFuZENsYXNzaWZpZXJSZXN1bHRIBIgBARITCgtjbG9zZV9zdGRpbhgRIAEoCBJJChNvdXRwdXRfbm90aWZpY2F0aW9uGBIgASgLMicuYWdlbnQudjEuU2hlbGxPdXRwdXROb3RpZmljYXRpb25Db25maWdIBYgBARI9ChNzbWFydF9tb2RlX2FwcHJvdmFsGBMgASgLMhsuYWdlbnQudjEuU21hcnRNb2RlQXBwcm92YWxIBogBARJOChlob29rX2FwcHJvdmFsX3JlcXVpcmVtZW50GBQgASgLMiYuYWdlbnQudjEuU2hlbGxIb29rQXBwcm92YWxSZXF1aXJlbWVudEgHiAEBEhwKD2NvbnZlcnNhdGlvbl9pZBgVIAEoCUgIiAEBQhsKGV9yZXF1ZXN0ZWRfc2FuZGJveF9wb2xpY3lCHgocX2ZpbGVfb3V0cHV0X3RocmVzaG9sZF9ieXRlc0IPCg1faGFyZF90aW1lb3V0Qg4KDF9kZXNjcmlwdGlvbkIUChJfY2xhc3NpZmllcl9yZXN1bHRCFgoUX291dHB1dF9ub3RpZmljYXRpb25CFgoUX3NtYXJ0X21vZGVfYXBwcm92YWxCHAoaX2hvb2tfYXBwcm92YWxfcmVxdWlyZW1lbnRCEgoQX2NvbnZlcnNhdGlvbl9pZCL6AwoLU2hlbGxSZXN1bHQSNAoOc2FuZGJveF9wb2xpY3kYZSABKAsyFy5hZ2VudC52MS5TYW5kYm94UG9saWN5SAGIAQESGgoNaXNfYmFja2dyb3VuZBhmIAEoCEgCiAEBEh0KEHRlcm1pbmFsc19mb2xkZXIYZyABKAlIA4gBARIQCgNwaWQYaCABKA1IBIgBARIpCgdzdWNjZXNzGAEgASgLMhYuYWdlbnQudjEuU2hlbGxTdWNjZXNzSAASKQoHZmFpbHVyZRgCIAEoCzIWLmFnZW50LnYxLlNoZWxsRmFpbHVyZUgAEikKB3RpbWVvdXQYAyABKAsyFi5hZ2VudC52MS5TaGVsbFRpbWVvdXRIABIrCghyZWplY3RlZBgEIAEoCzIXLmFnZW50LnYxLlNoZWxsUmVqZWN0ZWRIABIwCgtzcGF3bl9lcnJvchgFIAEoCzIZLmFnZW50LnYxLlNoZWxsU3Bhd25FcnJvckgAEjwKEXBlcm1pc3Npb25fZGVuaWVkGAcgASgLMh8uYWdlbnQudjEuU2hlbGxQZXJtaXNzaW9uRGVuaWVkSABCCAoGcmVzdWx0QhEKD19zYW5kYm94X3BvbGljeUIQCg5faXNfYmFja2dyb3VuZEITChFfdGVybWluYWxzX2ZvbGRlckIGCgRfcGlkIiEKEVNoZWxsU3RyZWFtU3Rkb3V0EgwKBGRhdGEYASABKAkiIQoRU2hlbGxTdHJlYW1TdGRlcnISDAoEZGF0YRgBIAEoCSL3AQoPU2hlbGxTdHJlYW1FeGl0EgwKBGNvZGUYASABKA0SCwoDY3dkGAIgASgJEjYKD291dHB1dF9sb2NhdGlvbhgDIAEoCzIYLmFnZW50LnYxLk91dHB1dExvY2F0aW9uSACIAQESDwoHYWJvcnRlZBgEIAEoCBIZCgxhYm9ydF9yZWFzb24YBSABKAVIAYgBARIkChdsb2NhbF9leGVjdXRpb25fdGltZV9tcxgGIAEoBUgCiAEBQhIKEF9vdXRwdXRfbG9jYXRpb25CDwoNX2Fib3J0X3JlYXNvbkIaChhfbG9jYWxfZXhlY3V0aW9uX3RpbWVfbXMiWwoQU2hlbGxTdHJlYW1TdGFydBI0Cg5zYW5kYm94X3BvbGljeRgBIAEoCzIXLmFnZW50LnYxLlNhbmRib3hQb2xpY3lIAIgBAUIRCg9fc2FuZGJveF9wb2xpY3ki2gEKF1NoZWxsU3RyZWFtQmFja2dyb3VuZGVkEhAKCHNoZWxsX2lkGAEgASgNEg8KB2NvbW1hbmQYAiABKAkSGQoRd29ya2luZ19kaXJlY3RvcnkYAyABKAkSEAoDcGlkGAQgASgNSACIAQESFwoKbXNfdG9fd2FpdBgFIAEoBUgBiAEBEjQKBnJlYXNvbhgGIAEoDjIfLmFnZW50LnYxLlNoZWxsQmFja2dyb3VuZFJlYXNvbkgCiAEBQgYKBF9waWRCDQoLX21zX3RvX3dhaXRCCQoHX3JlYXNvbiKsAwoLU2hlbGxTdHJlYW0SLQoGc3Rkb3V0GAEgASgLMhsuYWdlbnQudjEuU2hlbGxTdHJlYW1TdGRvdXRIABItCgZzdGRlcnIYAiABKAsyGy5hZ2VudC52MS5TaGVsbFN0cmVhbVN0ZGVyckgAEikKBGV4aXQYAyABKAsyGS5hZ2VudC52MS5TaGVsbFN0cmVhbUV4aXRIABIrCgVzdGFydBgEIAEoCzIaLmFnZW50LnYxLlNoZWxsU3RyZWFtU3RhcnRIABIrCghyZWplY3RlZBgFIAEoCzIXLmFnZW50LnYxLlNoZWxsUmVqZWN0ZWRIABI8ChFwZXJtaXNzaW9uX2RlbmllZBgGIAEoCzIfLmFnZW50LnYxLlNoZWxsUGVybWlzc2lvbkRlbmllZEgAEjkKDGJhY2tncm91bmRlZBgHIAEoCzIhLmFnZW50LnYxLlNoZWxsU3RyZWFtQmFja2dyb3VuZGVkSAASOAoMaG9va19jb250ZXh0GAggASgLMiAuYWdlbnQudjEuU2hlbGxTdHJlYW1Ib29rQ29udGV4dEgAQgcKBWV2ZW50IksKDk91dHB1dExvY2F0aW9uEhEKCWZpbGVfcGF0aBgBIAEoCRISCgpzaXplX2J5dGVzGAIgASgDEhIKCmxpbmVfY291bnQYAyABKAMimAUKDFNoZWxsU3VjY2VzcxIPCgdjb21tYW5kGAEgASgJEhkKEXdvcmtpbmdfZGlyZWN0b3J5GAIgASgJEhEKCWV4aXRfY29kZRgDIAEoBRIOCgZzaWduYWwYBCABKAkSDgoGc3Rkb3V0GAUgASgJEg4KBnN0ZGVychgGIAEoCRIWCg5leGVjdXRpb25fdGltZRgHIAEoBRI2Cg9vdXRwdXRfbG9jYXRpb24YCCABKAsyGC5hZ2VudC52MS5PdXRwdXRMb2NhdGlvbkgAiAEBEhUKCHNoZWxsX2lkGAkgASgNSAGIAQESHwoSaW50ZXJsZWF2ZWRfb3V0cHV0GAogASgJSAKIAQESEAoDcGlkGAsgASgNSAOIAQESFwoKbXNfdG9fd2FpdBgMIAEoBUgEiAEBEiQKF2xvY2FsX2V4ZWN1dGlvbl90aW1lX21zGA0gASgFSAWIAQESPwoRYmFja2dyb3VuZF9yZWFzb24YDiABKA4yHy5hZ2VudC52MS5TaGVsbEJhY2tncm91bmRSZWFzb25IBogBARIYCgtvdXRwdXRfaGVhZBgPIAEoCUgHiAEBEhgKC291dHB1dF90YWlsGBAgASgJSAiIAQESGQoMZWxpZGVkX2NoYXJzGBEgASgNSAmIAQFCEgoQX291dHB1dF9sb2NhdGlvbkILCglfc2hlbGxfaWRCFQoTX2ludGVybGVhdmVkX291dHB1dEIGCgRfcGlkQg0KC19tc190b193YWl0QhoKGF9sb2NhbF9leGVjdXRpb25fdGltZV9tc0IUChJfYmFja2dyb3VuZF9yZWFzb25CDgoMX291dHB1dF9oZWFkQg4KDF9vdXRwdXRfdGFpbEIPCg1fZWxpZGVkX2NoYXJzIpgECgxTaGVsbEZhaWx1cmUSDwoHY29tbWFuZBgBIAEoCRIZChF3b3JraW5nX2RpcmVjdG9yeRgCIAEoCRIRCglleGl0X2NvZGUYAyABKAUSDgoGc2lnbmFsGAQgASgJEg4KBnN0ZG91dBgFIAEoCRIOCgZzdGRlcnIYBiABKAkSFgoOZXhlY3V0aW9uX3RpbWUYByABKAUSNgoPb3V0cHV0X2xvY2F0aW9uGAggASgLMhguYWdlbnQudjEuT3V0cHV0TG9jYXRpb25IAIgBARIfChJpbnRlcmxlYXZlZF9vdXRwdXQYCSABKAlIAYgBARIZCgxhYm9ydF9yZWFzb24YCiABKAVIAogBARIPCgdhYm9ydGVkGAsgASgIEiQKF2xvY2FsX2V4ZWN1dGlvbl90aW1lX21zGAwgASgFSAOIAQESGAoLb3V0cHV0X2hlYWQYDSABKAlIBIgBARIYCgtvdXRwdXRfdGFpbBgOIAEoCUgFiAEBEhkKDGVsaWRlZF9jaGFycxgPIAEoDUgGiAEBQhIKEF9vdXRwdXRfbG9jYXRpb25CFQoTX2ludGVybGVhdmVkX291dHB1dEIPCg1fYWJvcnRfcmVhc29uQhoKGF9sb2NhbF9leGVjdXRpb25fdGltZV9tc0IOCgxfb3V0cHV0X2hlYWRCDgoMX291dHB1dF90YWlsQg8KDV9lbGlkZWRfY2hhcnMiTgoMU2hlbGxUaW1lb3V0Eg8KB2NvbW1hbmQYASABKAkSGQoRd29ya2luZ19kaXJlY3RvcnkYAiABKAkSEgoKdGltZW91dF9tcxgDIAEoBSJgCg1TaGVsbFJlamVjdGVkEg8KB2NvbW1hbmQYASABKAkSGQoRd29ya2luZ19kaXJlY3RvcnkYAiABKAkSDgoGcmVhc29uGAMgASgJEhMKC2lzX3JlYWRvbmx5GAQgASgIImcKFVNoZWxsUGVybWlzc2lvbkRlbmllZBIPCgdjb21tYW5kGAEgASgJEhkKEXdvcmtpbmdfZGlyZWN0b3J5GAIgASgJEg0KBWVycm9yGAMgASgJEhMKC2lzX3JlYWRvbmx5GAQgASgIIkwKD1NoZWxsU3Bhd25FcnJvchIPCgdjb21tYW5kGAEgASgJEhkKEXdvcmtpbmdfZGlyZWN0b3J5GAIgASgJEg0KBWVycm9yGAMgASgJIkAKElNoZWxsUGFydGlhbFJlc3VsdBIUCgxzdGRvdXRfZGVsdGEYASABKAkSFAoMc3RkZXJyX2RlbHRhGAIgASgJIlkKDVNoZWxsVG9vbENhbGwSIQoEYXJncxgBIAEoCzITLmFnZW50LnYxLlNoZWxsQXJncxIlCgZyZXN1bHQYAiABKAsyFS5hZ2VudC52MS5TaGVsbFJlc3VsdCIrChhTaGVsbFRvb2xDYWxsU3Rkb3V0RGVsdGESDwoHY29udGVudBgBIAEoCSIrChhTaGVsbFRvb2xDYWxsU3RkZXJyRGVsdGESDwoHY29udGVudBgBIAEoCSKJAQoSU2hlbGxUb29sQ2FsbERlbHRhEjQKBnN0ZG91dBgBIAEoCzIiLmFnZW50LnYxLlNoZWxsVG9vbENhbGxTdGRvdXREZWx0YUgAEjQKBnN0ZGVychgCIAEoCzIiLmFnZW50LnYxLlNoZWxsVG9vbENhbGxTdGRlcnJEZWx0YUgAQgcKBWRlbHRhIu0BCgxTdWJhZ2VudFR5cGUSOAoLdW5zcGVjaWZpZWQYASABKAsyIS5hZ2VudC52MS5TdWJhZ2VudFR5cGVVbnNwZWNpZmllZEgAEjkKDGNvbXB1dGVyX3VzZRgCIAEoCzIhLmFnZW50LnYxLlN1YmFnZW50VHlwZUNvbXB1dGVyVXNlSAASLgoGY3VzdG9tGAMgASgLMhwuYWdlbnQudjEuU3ViYWdlbnRUeXBlQ3VzdG9tSAASMAoHZXhwbG9yZRgEIAEoCzIdLmFnZW50LnYxLlN1YmFnZW50VHlwZUV4cGxvcmVIAEIGCgR0eXBlIhkKF1N1YmFnZW50VHlwZVVuc3BlY2lmaWVkIhkKF1N1YmFnZW50VHlwZUNvbXB1dGVyVXNlIhUKE1N1YmFnZW50VHlwZUV4cGxvcmUiIgoSU3ViYWdlbnRUeXBlQ3VzdG9tEgwKBG5hbWUYASABKAkijQEKDkN1c3RvbVN1YmFnZW50EhEKCWZ1bGxfcGF0aBgBIAEoCRIMCgRuYW1lGAIgASgJEhMKC2Rlc2NyaXB0aW9uGAMgASgJEg0KBXRvb2xzGAQgAygJEg0KBW1vZGVsGAUgASgJEg4KBnByb21wdBgGIAEoCRIXCg9wZXJtaXNzaW9uX21vZGUYByABKAUiaAoOU3dpdGNoTW9kZUFyZ3MSFgoOdGFyZ2V0X21vZGVfaWQYASABKAkSGAoLZXhwbGFuYXRpb24YAiABKAlIAIgBARIUCgx0b29sX2NhbGxfaWQYAyABKAlCDgoMX2V4cGxhbmF0aW9uIqoBChBTd2l0Y2hNb2RlUmVzdWx0Ei4KB3N1Y2Nlc3MYASABKAsyGy5hZ2VudC52MS5Td2l0Y2hNb2RlU3VjY2Vzc0gAEioKBWVycm9yGAIgASgLMhkuYWdlbnQudjEuU3dpdGNoTW9kZUVycm9ySAASMAoIcmVqZWN0ZWQYAyABKAsyHC5hZ2VudC52MS5Td2l0Y2hNb2RlUmVqZWN0ZWRIAEIICgZyZXN1bHQiPQoRU3dpdGNoTW9kZVN1Y2Nlc3MSFAoMZnJvbV9tb2RlX2lkGAEgASgJEhIKCnRvX21vZGVfaWQYAiABKAkiIAoPU3dpdGNoTW9kZUVycm9yEg0KBWVycm9yGAEgASgJIiQKElN3aXRjaE1vZGVSZWplY3RlZBIOCgZyZWFzb24YASABKAkiaAoSU3dpdGNoTW9kZVRvb2xDYWxsEiYKBGFyZ3MYASABKAsyGC5hZ2VudC52MS5Td2l0Y2hNb2RlQXJncxIqCgZyZXN1bHQYAiABKAsyGi5hZ2VudC52MS5Td2l0Y2hNb2RlUmVzdWx0IkAKFlN3aXRjaE1vZGVSZXF1ZXN0UXVlcnkSJgoEYXJncxgBIAEoCzIYLmFnZW50LnYxLlN3aXRjaE1vZGVBcmdzIqkBChlTd2l0Y2hNb2RlUmVxdWVzdFJlc3BvbnNlEkAKCGFwcHJvdmVkGAEgASgLMiwuYWdlbnQudjEuU3dpdGNoTW9kZVJlcXVlc3RSZXNwb25zZV9BcHByb3ZlZEgAEkAKCHJlamVjdGVkGAIgASgLMiwuYWdlbnQudjEuU3dpdGNoTW9kZVJlcXVlc3RSZXNwb25zZV9SZWplY3RlZEgAQggKBnJlc3VsdCIkCiJTd2l0Y2hNb2RlUmVxdWVzdFJlc3BvbnNlX0FwcHJvdmVkIjQKIlN3aXRjaE1vZGVSZXF1ZXN0UmVzcG9uc2VfUmVqZWN0ZWQSDgoGcmVhc29uGAEgASgJInUKCFRvZG9JdGVtEgoKAmlkGAEgASgJEg8KB2NvbnRlbnQYAiABKAkSDgoGc3RhdHVzGAMgASgFEhIKCmNyZWF0ZWRfYXQYBCABKAMSEgoKdXBkYXRlZF9hdBgFIAEoAxIUCgxkZXBlbmRlbmNpZXMYBiADKAkiawoTVXBkYXRlVG9kb3NUb29sQ2FsbBInCgRhcmdzGAEgASgLMhkuYWdlbnQudjEuVXBkYXRlVG9kb3NBcmdzEisKBnJlc3VsdBgCIAEoCzIbLmFnZW50LnYxLlVwZGF0ZVRvZG9zUmVzdWx0IkMKD1VwZGF0ZVRvZG9zQXJncxIhCgV0b2RvcxgBIAMoCzISLmFnZW50LnYxLlRvZG9JdGVtEg0KBW1lcmdlGAIgASgIInsKEVVwZGF0ZVRvZG9zUmVzdWx0Ei8KB3N1Y2Nlc3MYASABKAsyHC5hZ2VudC52MS5VcGRhdGVUb2Rvc1N1Y2Nlc3NIABIrCgVlcnJvchgCIAEoCzIaLmFnZW50LnYxLlVwZGF0ZVRvZG9zRXJyb3JIAEIICgZyZXN1bHQiXwoSVXBkYXRlVG9kb3NTdWNjZXNzEiEKBXRvZG9zGAEgAygLMhIuYWdlbnQudjEuVG9kb0l0ZW0SEwoLdG90YWxfY291bnQYAiABKAUSEQoJd2FzX21lcmdlGAMgASgIIiEKEFVwZGF0ZVRvZG9zRXJyb3ISDQoFZXJyb3IYASABKAkiZQoRUmVhZFRvZG9zVG9vbENhbGwSJQoEYXJncxgBIAEoCzIXLmFnZW50LnYxLlJlYWRUb2Rvc0FyZ3MSKQoGcmVzdWx0GAIgASgLMhkuYWdlbnQudjEuUmVhZFRvZG9zUmVzdWx0IjkKDVJlYWRUb2Rvc0FyZ3MSFQoNc3RhdHVzX2ZpbHRlchgBIAMoBRIRCglpZF9maWx0ZXIYAiADKAkidQoPUmVhZFRvZG9zUmVzdWx0Ei0KB3N1Y2Nlc3MYASABKAsyGi5hZ2VudC52MS5SZWFkVG9kb3NTdWNjZXNzSAASKQoFZXJyb3IYAiABKAsyGC5hZ2VudC52MS5SZWFkVG9kb3NFcnJvckgAQggKBnJlc3VsdCJKChBSZWFkVG9kb3NTdWNjZXNzEiEKBXRvZG9zGAEgAygLMhIuYWdlbnQudjEuVG9kb0l0ZW0SEwoLdG90YWxfY291bnQYAiABKAUiHwoOUmVhZFRvZG9zRXJyb3ISDQoFZXJyb3IYASABKAkiSwoFUmFuZ2USIQoFc3RhcnQYASABKAsyEi5hZ2VudC52MS5Qb3NpdGlvbhIfCgNlbmQYAiABKAsyEi5hZ2VudC52MS5Qb3NpdGlvbiIoCghQb3NpdGlvbhIMCgRsaW5lGAEgASgNEg4KBmNvbHVtbhgCIAEoDSIYCgVFcnJvchIPCgdtZXNzYWdlGAEgASgJIjoKDVdlYlNlYXJjaEFyZ3MSEwoLc2VhcmNoX3Rlcm0YASABKAkSFAoMdG9vbF9jYWxsX2lkGAIgASgJIqYBCg9XZWJTZWFyY2hSZXN1bHQSLQoHc3VjY2VzcxgBIAEoCzIaLmFnZW50LnYxLldlYlNlYXJjaFN1Y2Nlc3NIABIpCgVlcnJvchgCIAEoCzIYLmFnZW50LnYxLldlYlNlYXJjaEVycm9ySAASLwoIcmVqZWN0ZWQYAyABKAsyGy5hZ2VudC52MS5XZWJTZWFyY2hSZWplY3RlZEgAQggKBnJlc3VsdCJEChBXZWJTZWFyY2hTdWNjZXNzEjAKCnJlZmVyZW5jZXMYASADKAsyHC5hZ2VudC52MS5XZWJTZWFyY2hSZWZlcmVuY2UiHwoOV2ViU2VhcmNoRXJyb3ISDQoFZXJyb3IYASABKAkiIwoRV2ViU2VhcmNoUmVqZWN0ZWQSDgoGcmVhc29uGAEgASgJIj8KEldlYlNlYXJjaFJlZmVyZW5jZRINCgV0aXRsZRgBIAEoCRILCgN1cmwYAiABKAkSDQoFY2h1bmsYAyABKAkiZQoRV2ViU2VhcmNoVG9vbENhbGwSJQoEYXJncxgBIAEoCzIXLmFnZW50LnYxLldlYlNlYXJjaEFyZ3MSKQoGcmVzdWx0GAIgASgLMhkuYWdlbnQudjEuV2ViU2VhcmNoUmVzdWx0Ij4KFVdlYlNlYXJjaFJlcXVlc3RRdWVyeRIlCgRhcmdzGAEgASgLMhcuYWdlbnQudjEuV2ViU2VhcmNoQXJncyKmAQoYV2ViU2VhcmNoUmVxdWVzdFJlc3BvbnNlEj8KCGFwcHJvdmVkGAEgASgLMisuYWdlbnQudjEuV2ViU2VhcmNoUmVxdWVzdFJlc3BvbnNlX0FwcHJvdmVkSAASPwoIcmVqZWN0ZWQYAiABKAsyKy5hZ2VudC52MS5XZWJTZWFyY2hSZXF1ZXN0UmVzcG9uc2VfUmVqZWN0ZWRIAEIICgZyZXN1bHQiIwohV2ViU2VhcmNoUmVxdWVzdFJlc3BvbnNlX0FwcHJvdmVkIjMKIVdlYlNlYXJjaFJlcXVlc3RSZXNwb25zZV9SZWplY3RlZBIOCgZyZWFzb24YASABKAkirQEKCVdyaXRlQXJncxIMCgRwYXRoGAEgASgJEhEKCWZpbGVfdGV4dBgCIAEoCRIUCgx0b29sX2NhbGxfaWQYAyABKAkSJwofcmV0dXJuX2ZpbGVfY29udGVudF9hZnRlcl93cml0ZRgEIAEoCBISCgpmaWxlX2J5dGVzGAUgASgMEhoKDWVuY29kaW5nX2hpbnQYBiABKAlIAIgBAUIQCg5fZW5jb2RpbmdfaGludCKAAgoLV3JpdGVSZXN1bHQSKQoHc3VjY2VzcxgBIAEoCzIWLmFnZW50LnYxLldyaXRlU3VjY2Vzc0gAEjwKEXBlcm1pc3Npb25fZGVuaWVkGAMgASgLMh8uYWdlbnQudjEuV3JpdGVQZXJtaXNzaW9uRGVuaWVkSAASKgoIbm9fc3BhY2UYBCABKAsyFi5hZ2VudC52MS5Xcml0ZU5vU3BhY2VIABIlCgVlcnJvchgFIAEoCzIULmFnZW50LnYxLldyaXRlRXJyb3JIABIrCghyZWplY3RlZBgGIAEoCzIXLmFnZW50LnYxLldyaXRlUmVqZWN0ZWRIAEIICgZyZXN1bHQiigEKDFdyaXRlU3VjY2VzcxIMCgRwYXRoGAEgASgJEhUKDWxpbmVzX2NyZWF0ZWQYAiABKAUSEQoJZmlsZV9zaXplGAMgASgFEiUKGGZpbGVfY29udGVudF9hZnRlcl93cml0ZRgEIAEoCUgAiAEBQhsKGV9maWxlX2NvbnRlbnRfYWZ0ZXJfd3JpdGUibwoVV3JpdGVQZXJtaXNzaW9uRGVuaWVkEgwKBHBhdGgYASABKAkSEQoJZGlyZWN0b3J5GAIgASgJEhEKCW9wZXJhdGlvbhgDIAEoCRINCgVlcnJvchgEIAEoCRITCgtpc19yZWFkb25seRgFIAEoCCIcCgxXcml0ZU5vU3BhY2USDAoEcGF0aBgBIAEoCSIpCgpXcml0ZUVycm9yEgwKBHBhdGgYASABKAkSDQoFZXJyb3IYAiABKAkiLQoNV3JpdGVSZWplY3RlZBIMCgRwYXRoGAEgASgJEg4KBnJlYXNvbhgCIAEoCSKDAQoXQm9vdHN0cmFwU3RhdHNpZ1JlcXVlc3QSHgoRaWdub3JlX2Rldl9zdGF0dXMYASABKAhIAIgBARIdChBvcGVyYXRpbmdfc3lzdGVtGAIgASgFSAGIAQFCFAoSX2lnbm9yZV9kZXZfc3RhdHVzQhMKEV9vcGVyYXRpbmdfc3lzdGVtIg4KDFBpbmdSZXNwb25zZSK3AQoLRXhlY1JlcXVlc3QSDwoHY29tbWFuZBgBIAEoCRIQCgNjd2QYAiABKAlIAIgBARIMCgRhcmdzGAMgAygJEjsKC2Vudmlyb25tZW50GAQgAygLMiYuYWdlbnQudjEuRXhlY1JlcXVlc3QuRW52aXJvbm1lbnRFbnRyeRoyChBFbnZpcm9ubWVudEVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAFCBgoEX2N3ZCKgAQoMRXhlY1Jlc3BvbnNlEi0KDHN0ZG91dF9ldmVudBgBIAEoCzIVLmFnZW50LnYxLlN0ZG91dEV2ZW50SAASLQoMc3RkZXJyX2V2ZW50GAIgASgLMhUuYWdlbnQudjEuU3RkZXJyRXZlbnRIABIpCgpleGl0X2V2ZW50GAMgASgLMhMuYWdlbnQudjEuRXhpdEV2ZW50SABCBwoFZXZlbnQiGwoLU3Rkb3V0RXZlbnQSDAoEZGF0YRgBIAEoCSIbCgtTdGRlcnJFdmVudBIMCgRkYXRhGAEgASgJIh4KCUV4aXRFdmVudBIRCglleGl0X2NvZGUYASABKAUiIwoTUmVhZFRleHRGaWxlUmVxdWVzdBIMCgRwYXRoGAEgASgJIicKFFJlYWRUZXh0RmlsZVJlc3BvbnNlEg8KB2NvbnRlbnQYASABKAkiNQoUV3JpdGVUZXh0RmlsZVJlcXVlc3QSDAoEcGF0aBgBIAEoCRIPCgdjb250ZW50GAIgASgJIhcKFVdyaXRlVGV4dEZpbGVSZXNwb25zZSIlChVSZWFkQmluYXJ5RmlsZVJlcXVlc3QSDAoEcGF0aBgBIAEoCSIpChZSZWFkQmluYXJ5RmlsZVJlc3BvbnNlEg8KB2NvbnRlbnQYASABKAwiNwoWV3JpdGVCaW5hcnlGaWxlUmVxdWVzdBIMCgRwYXRoGAEgASgJEg8KB2NvbnRlbnQYAiABKAwiGQoXV3JpdGVCaW5hcnlGaWxlUmVzcG9uc2UiRQoeR2V0V29ya3NwYWNlQ2hhbmdlc0hhc2hSZXF1ZXN0EhEKCXJvb3RfcGF0aBgBIAEoCRIQCghiYXNlX3JlZhgCIAEoCSIvCh9HZXRXb3Jrc3BhY2VDaGFuZ2VzSGFzaFJlc3BvbnNlEgwKBGhhc2gYASABKAkiUAofUmVmcmVzaEdpdGh1YkFjY2Vzc1Rva2VuUmVxdWVzdBIbChNnaXRodWJfYWNjZXNzX3Rva2VuGAEgASgJEhAKCGhvc3RuYW1lGAIgASgJIiIKIFJlZnJlc2hHaXRodWJBY2Nlc3NUb2tlblJlc3BvbnNlIlcKHVdhcm1SZW1vdGVBY2Nlc3NTZXJ2ZXJSZXF1ZXN0Eg4KBmNvbW1pdBgBIAEoCRIMCgRwb3J0GAIgASgFEhgKEGNvbm5lY3Rpb25fdG9rZW4YAyABKAkiIAoeV2FybVJlbW90ZUFjY2Vzc1NlcnZlclJlc3BvbnNlIhYKFExpc3RBcnRpZmFjdHNSZXF1ZXN0IooCChZBcnRpZmFjdFVwbG9hZE1ldGFkYXRhEhUKDWFic29sdXRlX3BhdGgYASABKAkSEgoKc2l6ZV9ieXRlcxgCIAEoBBIaChJ1cGRhdGVkX2F0X3VuaXhfbXMYAyABKAMSDgoGc3RhdHVzGAQgASgFEhYKDmJ5dGVzX3VwbG9hZGVkGAUgASgEEhIKCmxhc3RfZXJyb3IYBiABKAkSFwoPdXBsb2FkX2F0dGVtcHRzGAcgASgNEh8KF2xhc3Rfc3RhcnRlZF9hdF91bml4X21zGAggASgDEiAKGGxhc3RfZmluaXNoZWRfYXRfdW5peF9tcxgJIAEoAxIRCgl1cGxvYWRfaWQYCiABKAkiTAoVTGlzdEFydGlmYWN0c1Jlc3BvbnNlEjMKCWFydGlmYWN0cxgBIAMoCzIgLmFnZW50LnYxLkFydGlmYWN0VXBsb2FkTWV0YWRhdGEiTgoWVXBsb2FkQXJ0aWZhY3RzUmVxdWVzdBI0Cgd1cGxvYWRzGAEgAygLMiMuYWdlbnQudjEuQXJ0aWZhY3RVcGxvYWRJbnN0cnVjdGlvbiLXAgoZQXJ0aWZhY3RVcGxvYWRJbnN0cnVjdGlvbhIVCg1hYnNvbHV0ZV9wYXRoGAEgASgJEhIKCnVwbG9hZF91cmwYAiABKAkSDgoGbWV0aG9kGAMgASgJEkEKB2hlYWRlcnMYBCADKAsyMC5hZ2VudC52MS5BcnRpZmFjdFVwbG9hZEluc3RydWN0aW9uLkhlYWRlcnNFbnRyeRIZCgxjb250ZW50X3R5cGUYBSABKAlIAIgBARIdChBzbGFja191cGxvYWRfdXJsGAYgASgJSAGIAQESGgoNc2xhY2tfZmlsZV9pZBgHIAEoCUgCiAEBGi4KDEhlYWRlcnNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBQg8KDV9jb250ZW50X3R5cGVCEwoRX3NsYWNrX3VwbG9hZF91cmxCEAoOX3NsYWNrX2ZpbGVfaWQihAEKHEFydGlmYWN0VXBsb2FkRGlzcGF0Y2hSZXN1bHQSFQoNYWJzb2x1dGVfcGF0aBgBIAEoCRIOCgZzdGF0dXMYAiABKAUSDwoHbWVzc2FnZRgDIAEoCRIaCg1zbGFja19maWxlX2lkGAQgASgJSACIAQFCEAoOX3NsYWNrX2ZpbGVfaWQiUgoXVXBsb2FkQXJ0aWZhY3RzUmVzcG9uc2USNwoHcmVzdWx0cxgBIAMoCzImLmFnZW50LnYxLkFydGlmYWN0VXBsb2FkRGlzcGF0Y2hSZXN1bHQiHAoaR2V0TWNwUmVmcmVzaFRva2Vuc1JlcXVlc3QipQEKG0dldE1jcFJlZnJlc2hUb2tlbnNSZXNwb25zZRJQCg5yZWZyZXNoX3Rva2VucxgBIAMoCzI4LmFnZW50LnYxLkdldE1jcFJlZnJlc2hUb2tlbnNSZXNwb25zZS5SZWZyZXNoVG9rZW5zRW50cnkaNAoSUmVmcmVzaFRva2Vuc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEiowEKIVVwZGF0ZUVudmlyb25tZW50VmFyaWFibGVzUmVxdWVzdBJBCgNlbnYYASADKAsyNC5hZ2VudC52MS5VcGRhdGVFbnZpcm9ubWVudFZhcmlhYmxlc1JlcXVlc3QuRW52RW50cnkSDwoHcmVwbGFjZRgCIAEoCBoqCghFbnZFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIkYKIlVwZGF0ZUVudmlyb25tZW50VmFyaWFibGVzUmVzcG9uc2USDwoHYXBwbGllZBgBIAEoDRIPCgdyZW1vdmVkGAIgASgNIoMBChJNY3BPQXV0aFN0b3JlZERhdGESFQoNcmVmcmVzaF90b2tlbhgBIAEoCRIRCgljbGllbnRfaWQYAiABKAkSGgoNY2xpZW50X3NlY3JldBgDIAEoCUgAiAEBEhUKDXJlZGlyZWN0X3VyaXMYBCADKAlCEAoOX2NsaWVudF9zZWNyZXQiTgoFRnJhbWUSCgoCaWQYASABKAkSDgoGbWV0aG9kGAIgASgJEgwKBGRhdGEYAyABKAwSDAoEa2luZBgEIAEoBRINCgVlcnJvchgFIAEoCSIHCgVFbXB0eSIjCg1CaWRpUmVxdWVzdElkEhIKCnJlcXVlc3RfaWQYASABKAkigQIKDFBpVHJ1bmNhdGlvbhIRCgl0cnVuY2F0ZWQYASABKAgSFAoMdHJ1bmNhdGVkX2J5GAIgASgJEhMKC3RvdGFsX2xpbmVzGAMgASgNEhQKDG91dHB1dF9saW5lcxgEIAEoDRIUCgxvdXRwdXRfYnl0ZXMYBSABKA0SFgoJbWF4X2xpbmVzGAYgASgNSACIAQESFgoJbWF4X2J5dGVzGAcgASgNSAGIAQESIAoYZmlyc3RfbGluZV9leGNlZWRzX2xpbWl0GAggASgIEhkKEWxhc3RfbGluZV9wYXJ0aWFsGAkgASgIQgwKCl9tYXhfbGluZXNCDAoKX21heF9ieXRlcyI3ChFQaUVkaXRSZXBsYWNlbWVudBIQCghvbGRfdGV4dBgBIAEoCRIQCghuZXdfdGV4dBgCIAEoCSJcCg5QaVJlYWRFeGVjQXJncxIMCgRwYXRoGAEgASgJEhMKBm9mZnNldBgCIAEoBUgAiAEBEhIKBWxpbWl0GAMgASgFSAGIAQFCCQoHX29mZnNldEIICgZfbGltaXQiYwoRUGlSZWFkRXhlY1N1Y2Nlc3MSDgoGb3V0cHV0GAEgASgJEi8KCnRydW5jYXRpb24YAiABKAsyFi5hZ2VudC52MS5QaVRydW5jYXRpb25IAIgBAUINCgtfdHJ1bmNhdGlvbiIgCg9QaVJlYWRFeGVjRXJyb3ISDQoFZXJyb3IYASABKAkieAoQUGlSZWFkRXhlY1Jlc3VsdBIuCgdzdWNjZXNzGAEgASgLMhsuYWdlbnQudjEuUGlSZWFkRXhlY1N1Y2Nlc3NIABIqCgVlcnJvchgCIAEoCzIZLmFnZW50LnYxLlBpUmVhZEV4ZWNFcnJvckgAQggKBnJlc3VsdCJDCg5QaUJhc2hFeGVjQXJncxIPCgdjb21tYW5kGAEgASgJEhQKB3RpbWVvdXQYAiABKAFIAIgBAUIKCghfdGltZW91dCKXAQoRUGlCYXNoRXhlY1N1Y2Nlc3MSDgoGb3V0cHV0GAEgASgJEi8KCnRydW5jYXRpb24YAiABKAsyFi5hZ2VudC52MS5QaVRydW5jYXRpb25IAIgBARIdChBmdWxsX291dHB1dF9wYXRoGAMgASgJSAGIAQFCDQoLX3RydW5jYXRpb25CEwoRX2Z1bGxfb3V0cHV0X3BhdGgilAEKD1BpQmFzaEV4ZWNFcnJvchINCgVlcnJvchgBIAEoCRIvCgp0cnVuY2F0aW9uGAIgASgLMhYuYWdlbnQudjEuUGlUcnVuY2F0aW9uSACIAQESHQoQZnVsbF9vdXRwdXRfcGF0aBgDIAEoCUgBiAEBQg0KC190cnVuY2F0aW9uQhMKEV9mdWxsX291dHB1dF9wYXRoIngKEFBpQmFzaEV4ZWNSZXN1bHQSLgoHc3VjY2VzcxgBIAEoCzIbLmFnZW50LnYxLlBpQmFzaEV4ZWNTdWNjZXNzSAASKgoFZXJyb3IYAiABKAsyGS5hZ2VudC52MS5QaUJhc2hFeGVjRXJyb3JIAEIICgZyZXN1bHQiSgoOUGlFZGl0RXhlY0FyZ3MSDAoEcGF0aBgBIAEoCRIqCgVlZGl0cxgCIAMoCzIbLmFnZW50LnYxLlBpRWRpdFJlcGxhY2VtZW50IngKEVBpRWRpdEV4ZWNTdWNjZXNzEg4KBm91dHB1dBgBIAEoCRIMCgRkaWZmGAIgASgJEg0KBXBhdGNoGAMgASgJEh8KEmZpcnN0X2NoYW5nZWRfbGluZRgEIAEoDUgAiAEBQhUKE19maXJzdF9jaGFuZ2VkX2xpbmUiIAoPUGlFZGl0RXhlY0Vycm9yEg0KBWVycm9yGAEgASgJIiQKElBpRWRpdEV4ZWNSZWplY3RlZBIOCgZyZWFzb24YASABKAkiqgEKEFBpRWRpdEV4ZWNSZXN1bHQSLgoHc3VjY2VzcxgBIAEoCzIbLmFnZW50LnYxLlBpRWRpdEV4ZWNTdWNjZXNzSAASKgoFZXJyb3IYAiABKAsyGS5hZ2VudC52MS5QaUVkaXRFeGVjRXJyb3JIABIwCghyZWplY3RlZBgDIAEoCzIcLmFnZW50LnYxLlBpRWRpdEV4ZWNSZWplY3RlZEgAQggKBnJlc3VsdCIwCg9QaVdyaXRlRXhlY0FyZ3MSDAoEcGF0aBgBIAEoCRIPCgdjb250ZW50GAIgASgJIiQKElBpV3JpdGVFeGVjU3VjY2VzcxIOCgZvdXRwdXQYASABKAkiIQoQUGlXcml0ZUV4ZWNFcnJvchINCgVlcnJvchgBIAEoCSIlChNQaVdyaXRlRXhlY1JlamVjdGVkEg4KBnJlYXNvbhgBIAEoCSKuAQoRUGlXcml0ZUV4ZWNSZXN1bHQSLwoHc3VjY2VzcxgBIAEoCzIcLmFnZW50LnYxLlBpV3JpdGVFeGVjU3VjY2Vzc0gAEisKBWVycm9yGAIgASgLMhouYWdlbnQudjEuUGlXcml0ZUV4ZWNFcnJvckgAEjEKCHJlamVjdGVkGAMgASgLMh0uYWdlbnQudjEuUGlXcml0ZUV4ZWNSZWplY3RlZEgAQggKBnJlc3VsdCLlAQoOUGlHcmVwRXhlY0FyZ3MSDwoHcGF0dGVybhgBIAEoCRIRCgRwYXRoGAIgASgJSACIAQESEQoEZ2xvYhgDIAEoCUgBiAEBEhgKC2lnbm9yZV9jYXNlGAQgASgISAKIAQESFAoHbGl0ZXJhbBgFIAEoCEgDiAEBEhQKB2NvbnRleHQYBiABKAVIBIgBARISCgVsaW1pdBgHIAEoBUgFiAEBQgcKBV9wYXRoQgcKBV9nbG9iQg4KDF9pZ25vcmVfY2FzZUIKCghfbGl0ZXJhbEIKCghfY29udGV4dEIICgZfbGltaXQitgEKEVBpR3JlcEV4ZWNTdWNjZXNzEg4KBm91dHB1dBgBIAEoCRIvCgp0cnVuY2F0aW9uGAIgASgLMhYuYWdlbnQudjEuUGlUcnVuY2F0aW9uSACIAQESIAoTbWF0Y2hfbGltaXRfcmVhY2hlZBgDIAEoDUgBiAEBEhcKD2xpbmVzX3RydW5jYXRlZBgEIAEoCEINCgtfdHJ1bmNhdGlvbkIWChRfbWF0Y2hfbGltaXRfcmVhY2hlZCIgCg9QaUdyZXBFeGVjRXJyb3ISDQoFZXJyb3IYASABKAkieAoQUGlHcmVwRXhlY1Jlc3VsdBIuCgdzdWNjZXNzGAEgASgLMhsuYWdlbnQudjEuUGlHcmVwRXhlY1N1Y2Nlc3NIABIqCgVlcnJvchgCIAEoCzIZLmFnZW50LnYxLlBpR3JlcEV4ZWNFcnJvckgAQggKBnJlc3VsdCJbCg5QaUZpbmRFeGVjQXJncxIPCgdwYXR0ZXJuGAEgASgJEhEKBHBhdGgYAiABKAlIAIgBARISCgVsaW1pdBgDIAEoBUgBiAEBQgcKBV9wYXRoQggKBl9saW1pdCKfAQoRUGlGaW5kRXhlY1N1Y2Nlc3MSDgoGb3V0cHV0GAEgASgJEi8KCnRydW5jYXRpb24YAiABKAsyFi5hZ2VudC52MS5QaVRydW5jYXRpb25IAIgBARIhChRyZXN1bHRfbGltaXRfcmVhY2hlZBgDIAEoDUgBiAEBQg0KC190cnVuY2F0aW9uQhcKFV9yZXN1bHRfbGltaXRfcmVhY2hlZCIgCg9QaUZpbmRFeGVjRXJyb3ISDQoFZXJyb3IYASABKAkieAoQUGlGaW5kRXhlY1Jlc3VsdBIuCgdzdWNjZXNzGAEgASgLMhsuYWdlbnQudjEuUGlGaW5kRXhlY1N1Y2Nlc3NIABIqCgVlcnJvchgCIAEoCzIZLmFnZW50LnYxLlBpRmluZEV4ZWNFcnJvckgAQggKBnJlc3VsdCJICgxQaUxzRXhlY0FyZ3MSEQoEcGF0aBgBIAEoCUgAiAEBEhIKBWxpbWl0GAIgASgFSAGIAQFCBwoFX3BhdGhCCAoGX2xpbWl0IpsBCg9QaUxzRXhlY1N1Y2Nlc3MSDgoGb3V0cHV0GAEgASgJEi8KCnRydW5jYXRpb24YAiABKAsyFi5hZ2VudC52MS5QaVRydW5jYXRpb25IAIgBARIgChNlbnRyeV9saW1pdF9yZWFjaGVkGAMgASgNSAGIAQFCDQoLX3RydW5jYXRpb25CFgoUX2VudHJ5X2xpbWl0X3JlYWNoZWQiHgoNUGlMc0V4ZWNFcnJvchINCgVlcnJvchgBIAEoCSJyCg5QaUxzRXhlY1Jlc3VsdBIsCgdzdWNjZXNzGAEgASgLMhkuYWdlbnQudjEuUGlMc0V4ZWNTdWNjZXNzSAASKAoFZXJyb3IYAiABKAsyFy5hZ2VudC52MS5QaUxzRXhlY0Vycm9ySABCCAoGcmVzdWx0IjwKEU1jcFNlcnZlck5vdEZvdW5kEgwKBG5hbWUYASABKAkSGQoRYXZhaWxhYmxlX3NlcnZlcnMYAiADKAkiDQoLTWNwQXBwcm92ZWQiQQoQTWNwU3RhdGVFeGVjQXJncxIaChJzZXJ2ZXJfaWRlbnRpZmllcnMYASADKAkSEQoJa2lja19vbmx5GAIgASgIIocCCg5NY3BTdGF0ZVNlcnZlchITCgtzZXJ2ZXJfbmFtZRgBIAEoCRIZChFzZXJ2ZXJfaWRlbnRpZmllchgCIAEoCRITCgZwbHVnaW4YAyABKAlIAIgBARIYCgttYXJrZXRwbGFjZRgEIAEoCUgBiAEBEioKBXRvb2xzGAUgAygLMhsuYWdlbnQudjEuTWNwVG9vbERlZmluaXRpb24SLwoMaW5zdHJ1Y3Rpb25zGAYgAygLMhkuYWdlbnQudjEuTWNwSW5zdHJ1Y3Rpb25zEhMKBnN0YXR1cxgHIAEoCUgCiAEBQgkKB19wbHVnaW5CDgoMX21hcmtldHBsYWNlQgkKB19zdGF0dXMiPAoPTWNwU3RhdGVTdWNjZXNzEikKB3NlcnZlcnMYASADKAsyGC5hZ2VudC52MS5NY3BTdGF0ZVNlcnZlciIeCg1NY3BTdGF0ZUVycm9yEg0KBWVycm9yGAEgASgJIiIKEE1jcFN0YXRlUmVqZWN0ZWQSDgoGcmVhc29uGAEgASgJIqYBChJNY3BTdGF0ZUV4ZWNSZXN1bHQSLAoHc3VjY2VzcxgBIAEoCzIZLmFnZW50LnYxLk1jcFN0YXRlU3VjY2Vzc0gAEigKBWVycm9yGAIgASgLMhcuYWdlbnQudjEuTWNwU3RhdGVFcnJvckgAEi4KCHJlamVjdGVkGAMgASgLMhouYWdlbnQudjEuTWNwU3RhdGVSZWplY3RlZEgAQggKBnJlc3VsdCKtAQopQ29tbWFuZENsYXNzaWZpZXJSZXN1bHRfQ2xhc3NpZmllZENvbW1hbmQSDAoEbmFtZRgBIAEoCRIRCglhcmd1bWVudHMYAiADKAkSJgoZc3VnZ2VzdGVkX2FsbG93bGlzdF9lbnRyeRgDIAEoCUgAiAEBEhkKEXN1YmNvbW1hbmRfdG9rZW5zGAQgAygJQhwKGl9zdWdnZXN0ZWRfYWxsb3dsaXN0X2VudHJ5ItcBChdDb21tYW5kQ2xhc3NpZmllclJlc3VsdBJFCghjb21tYW5kcxgBIAMoCzIzLmFnZW50LnYxLkNvbW1hbmRDbGFzc2lmaWVyUmVzdWx0X0NsYXNzaWZpZWRDb21tYW5kElYKFnN1Z2dlc3RlZF9zYW5kYm94X21vZGUYAiABKA4yNi5hZ2VudC52MS5Db21tYW5kQ2xhc3NpZmllclJlc3VsdF9TdWdnZXN0ZWRTYW5kYm94TW9kZRIdChVjbGFzc2lmaWNhdGlvbl9mYWlsZWQYAyABKAgikwEKIlNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHRfUmVkaXJlY3QSEAoIb3BlcmF0b3IYASABKAkSFwoPZGVzdGluYXRpb25fZmRzGAIgAygNEhgKEHRhcmdldF9ub2RlX3R5cGUYAyABKAkSGAoLdGFyZ2V0X3RleHQYBCABKAlIAIgBAUIOCgxfdGFyZ2V0X3RleHQiigIKGlNoZWxsQWxsb3dsaXN0UHJlY2hlY2tBcmdzEg8KB2NvbW1hbmQYASABKAkSGQoRd29ya2luZ19kaXJlY3RvcnkYAiABKAkSOwoOcGFyc2luZ19yZXN1bHQYAyABKAsyIy5hZ2VudC52MS5TaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0EkEKEWNsYXNzaWZpZXJfcmVzdWx0GAQgASgLMiEuYWdlbnQudjEuQ29tbWFuZENsYXNzaWZpZXJSZXN1bHRIAIgBARIZCgx0b29sX2NhbGxfaWQYBSABKAlIAYgBAUIUChJfY2xhc3NpZmllcl9yZXN1bHRCDwoNX3Rvb2xfY2FsbF9pZCIzChxTaGVsbEFsbG93bGlzdFByZWNoZWNrUmVzdWx0EhMKC2FsbG93bGlzdGVkGAEgASgIInYKGE1jcEFsbG93bGlzdFByZWNoZWNrQXJncxIbChNwcm92aWRlcl9pZGVudGlmaWVyGAEgASgJEhEKCXRvb2xfbmFtZRgCIAEoCRIZCgx0b29sX2NhbGxfaWQYAyABKAlIAIgBAUIPCg1fdG9vbF9jYWxsX2lkIjEKGk1jcEFsbG93bGlzdFByZWNoZWNrUmVzdWx0EhMKC2FsbG93bGlzdGVkGAEgASgIIlgKHVdlYkZldGNoQWxsb3dsaXN0UHJlY2hlY2tBcmdzEgsKA3VybBgBIAEoCRIZCgx0b29sX2NhbGxfaWQYAiABKAlIAIgBAUIPCg1fdG9vbF9jYWxsX2lkIjYKH1dlYkZldGNoQWxsb3dsaXN0UHJlY2hlY2tSZXN1bHQSEwoLYWxsb3dsaXN0ZWQYASABKAgiNwoRU21hcnRNb2RlQXBwcm92YWwSEgoKcmVxdWVzdF9pZBgBIAEoCRIOCgZyZWFzb24YAiABKAkinAEKHVNoZWxsT3V0cHV0Tm90aWZpY2F0aW9uQ29uZmlnEg8KB3BhdHRlcm4YASABKAkSDgoGcmVhc29uGAIgASgJEhUKCGRlYm91bmNlGAMgASgBSACIAQESHwoSbm90aWZpY2F0aW9uX2xpbWl0GAQgASgFSAGIAQFCCwoJX2RlYm91bmNlQhUKE19ub3RpZmljYXRpb25fbGltaXQieQocU2hlbGxIb29rQXBwcm92YWxSZXF1aXJlbWVudBI5CgRraW5kGAEgASgOMisuYWdlbnQudjEuU2hlbGxIb29rQXBwcm92YWxSZXF1aXJlbWVudF9LaW5kEhMKBnJlYXNvbhgCIAEoCUgAiAEBQgkKB19yZWFzb24iMAoYRm9yY2VCYWNrZ3JvdW5kU2hlbGxBcmdzEhQKDHRvb2xfY2FsbF9pZBgBIAEoCSKVAQoaRm9yY2VCYWNrZ3JvdW5kU2hlbGxSZXN1bHQSNAoGc3RhdHVzGAEgASgOMiQuYWdlbnQudjEuRm9yY2VCYWNrZ3JvdW5kU2hlbGxTdGF0dXMSMAoMc2hlbGxfcmVzdWx0GAIgASgLMhUuYWdlbnQudjEuU2hlbGxSZXN1bHRIAIgBAUIPCg1fc2hlbGxfcmVzdWx0IkEKFUhvb2tBZGRpdGlvbmFsQ29udGV4dBIXCg9ob29rX2V2ZW50X25hbWUYASABKAkSDwoHY29udGVudBgCIAEoCSJbChZTaGVsbFN0cmVhbUhvb2tDb250ZXh0EkEKGGhvb2tfYWRkaXRpb25hbF9jb250ZXh0cxgBIAMoCzIfLmFnZW50LnYxLkhvb2tBZGRpdGlvbmFsQ29udGV4dCJLCgxTdWJhZ2VudEFyZ3MSFAoMdG9vbF9jYWxsX2lkGAEgASgJEhUKDXN1YmFnZW50X3R5cGUYAiABKAkSDgoGcHJvbXB0GAQgASgJItsBCg9TdWJhZ2VudFN1Y2Nlc3MSEAoIYWdlbnRfaWQYASABKAkSGgoNZmluYWxfbWVzc2FnZRgCIAEoCUgAiAEBEhcKD3Rvb2xfY2FsbF9jb3VudBgDIAEoBRI9ChFiYWNrZ3JvdW5kX3JlYXNvbhgEIAEoDjIiLmFnZW50LnYxLlN1YmFnZW50QmFja2dyb3VuZFJlYXNvbhIcCg90cmFuc2NyaXB0X3BhdGgYBSABKAlIAYgBAUIQCg5fZmluYWxfbWVzc2FnZUISChBfdHJhbnNjcmlwdF9wYXRoIkIKDVN1YmFnZW50RXJyb3ISFQoIYWdlbnRfaWQYASABKAlIAIgBARINCgVlcnJvchgCIAEoCUILCglfYWdlbnRfaWQicgoOU3ViYWdlbnRSZXN1bHQSLAoHc3VjY2VzcxgBIAEoCzIZLmFnZW50LnYxLlN1YmFnZW50U3VjY2Vzc0gAEigKBWVycm9yGAIgASgLMhcuYWdlbnQudjEuU3ViYWdlbnRFcnJvckgAQggKBnJlc3VsdCI5ChFTdWJhZ2VudEF3YWl0QXJncxIQCghhZ2VudF9pZBgBIAEoCRISCgp0aW1lb3V0X21zGAIgASgNIqIBChVTdWJhZ2VudEF3YWl0Q29tcGxldGUSEAoIYWdlbnRfaWQYASABKAkSHAoPdHJhbnNjcmlwdF9wYXRoGAIgASgJSACIAQESFwoPdG9vbF9jYWxsX2NvdW50GAMgASgFEhoKDWZpbmFsX21lc3NhZ2UYBCABKAlIAYgBAUISChBfdHJhbnNjcmlwdF9wYXRoQhAKDl9maW5hbF9tZXNzYWdlIl8KGVN1YmFnZW50QXdhaXRTdGlsbFJ1bm5pbmcSEAoIYWdlbnRfaWQYASABKAkSHAoPdHJhbnNjcmlwdF9wYXRoGAIgASgJSACIAQFCEgoQX3RyYW5zY3JpcHRfcGF0aCIpChVTdWJhZ2VudEF3YWl0Tm90Rm91bmQSEAoIYWdlbnRfaWQYASABKAkiRwoSU3ViYWdlbnRBd2FpdEVycm9yEhUKCGFnZW50X2lkGAEgASgJSACIAQESDQoFZXJyb3IYAiABKAlCCwoJX2FnZW50X2lkIvcBChNTdWJhZ2VudEF3YWl0UmVzdWx0EjMKCGNvbXBsZXRlGAEgASgLMh8uYWdlbnQudjEuU3ViYWdlbnRBd2FpdENvbXBsZXRlSAASPAoNc3RpbGxfcnVubmluZxgCIAEoCzIjLmFnZW50LnYxLlN1YmFnZW50QXdhaXRTdGlsbFJ1bm5pbmdIABI0Cglub3RfZm91bmQYAyABKAsyHy5hZ2VudC52MS5TdWJhZ2VudEF3YWl0Tm90Rm91bmRIABItCgVlcnJvchgEIAEoCzIcLmFnZW50LnYxLlN1YmFnZW50QXdhaXRFcnJvckgAQggKBnJlc3VsdCIzChtGb3JjZUJhY2tncm91bmRTdWJhZ2VudEFyZ3MSFAoMdG9vbF9jYWxsX2lkGAEgASgJIlgKHUZvcmNlQmFja2dyb3VuZFN1YmFnZW50UmVzdWx0EjcKBnN0YXR1cxgBIAEoDjInLmFnZW50LnYxLkZvcmNlQmFja2dyb3VuZFN1YmFnZW50U3RhdHVzIhgKFlByZUNvbXBhY3RSZXF1ZXN0UXVlcnkiGwoZU3ViYWdlbnRTdGFydFJlcXVlc3RRdWVyeSIaChhTdWJhZ2VudFN0b3BSZXF1ZXN0UXVlcnkiGAoWUHJlVG9vbFVzZVJlcXVlc3RRdWVyeSIZChdQb3N0VG9vbFVzZVJlcXVlc3RRdWVyeSIgCh5Qb3N0VG9vbFVzZUZhaWx1cmVSZXF1ZXN0UXVlcnkiIAoeQmVmb3JlU3VibWl0UHJvbXB0UmVxdWVzdFF1ZXJ5IiAKHkFmdGVyQWdlbnRSZXNwb25zZVJlcXVlc3RRdWVyeSIfCh1BZnRlckFnZW50VGhvdWdodFJlcXVlc3RRdWVyeSISChBTdG9wUmVxdWVzdFF1ZXJ5IkcKGVByZUNvbXBhY3RSZXF1ZXN0UmVzcG9uc2USGQoMdXNlcl9tZXNzYWdlGAEgASgJSACIAQFCDwoNX3VzZXJfbWVzc2FnZSKqAQocU3ViYWdlbnRTdGFydFJlcXVlc3RSZXNwb25zZRIXCgpwZXJtaXNzaW9uGAEgASgJSACIAQESGQoMdXNlcl9tZXNzYWdlGAIgASgJSAGIAQESHwoSYWRkaXRpb25hbF9jb250ZXh0GAMgASgJSAKIAQFCDQoLX3Blcm1pc3Npb25CDwoNX3VzZXJfbWVzc2FnZUIVChNfYWRkaXRpb25hbF9jb250ZXh0IokBChtTdWJhZ2VudFN0b3BSZXF1ZXN0UmVzcG9uc2USHQoQZm9sbG93dXBfbWVzc2FnZRgBIAEoCUgAiAEBEh8KEmFkZGl0aW9uYWxfY29udGV4dBgCIAEoCUgBiAEBQhMKEV9mb2xsb3d1cF9tZXNzYWdlQhUKE19hZGRpdGlvbmFsX2NvbnRleHQigwIKGVByZVRvb2xVc2VSZXF1ZXN0UmVzcG9uc2USFwoKcGVybWlzc2lvbhgBIAEoCUgAiAEBEhkKDHVzZXJfbWVzc2FnZRgCIAEoCUgBiAEBEhoKDWFnZW50X21lc3NhZ2UYAyABKAlIAogBARIaCg11cGRhdGVkX2lucHV0GAQgASgJSAOIAQESHwoSYWRkaXRpb25hbF9jb250ZXh0GAUgASgJSASIAQFCDQoLX3Blcm1pc3Npb25CDwoNX3VzZXJfbWVzc2FnZUIQCg5fYWdlbnRfbWVzc2FnZUIQCg5fdXBkYXRlZF9pbnB1dEIVChNfYWRkaXRpb25hbF9jb250ZXh0IlQKGlBvc3RUb29sVXNlUmVxdWVzdFJlc3BvbnNlEh8KEmFkZGl0aW9uYWxfY29udGV4dBgBIAEoCUgAiAEBQhUKE19hZGRpdGlvbmFsX2NvbnRleHQiWwohUG9zdFRvb2xVc2VGYWlsdXJlUmVxdWVzdFJlc3BvbnNlEh8KEmFkZGl0aW9uYWxfY29udGV4dBgBIAEoCUgAiAEBQhUKE19hZGRpdGlvbmFsX2NvbnRleHQiqwEKIUJlZm9yZVN1Ym1pdFByb21wdFJlcXVlc3RSZXNwb25zZRIVCghjb250aW51ZRgBIAEoCEgAiAEBEhkKDHVzZXJfbWVzc2FnZRgCIAEoCUgBiAEBEh8KEmFkZGl0aW9uYWxfY29udGV4dBgDIAEoCUgCiAEBQgsKCV9jb250aW51ZUIPCg1fdXNlcl9tZXNzYWdlQhUKE19hZGRpdGlvbmFsX2NvbnRleHQiIwohQWZ0ZXJBZ2VudFJlc3BvbnNlUmVxdWVzdFJlc3BvbnNlIiIKIEFmdGVyQWdlbnRUaG91Z2h0UmVxdWVzdFJlc3BvbnNlIkkKE1N0b3BSZXF1ZXN0UmVzcG9uc2USHQoQZm9sbG93dXBfbWVzc2FnZRgBIAEoCUgAiAEBQhMKEV9mb2xsb3d1cF9tZXNzYWdlIp0FChJFeGVjdXRlSG9va1JlcXVlc3QSNwoLcHJlX2NvbXBhY3QYASABKAsyIC5hZ2VudC52MS5QcmVDb21wYWN0UmVxdWVzdFF1ZXJ5SAASPQoOc3ViYWdlbnRfc3RhcnQYAiABKAsyIy5hZ2VudC52MS5TdWJhZ2VudFN0YXJ0UmVxdWVzdFF1ZXJ5SAASOwoNc3ViYWdlbnRfc3RvcBgDIAEoCzIiLmFnZW50LnYxLlN1YmFnZW50U3RvcFJlcXVlc3RRdWVyeUgAEjgKDHByZV90b29sX3VzZRgEIAEoCzIgLmFnZW50LnYxLlByZVRvb2xVc2VSZXF1ZXN0UXVlcnlIABI6Cg1wb3N0X3Rvb2xfdXNlGAUgASgLMiEuYWdlbnQudjEuUG9zdFRvb2xVc2VSZXF1ZXN0UXVlcnlIABJJChVwb3N0X3Rvb2xfdXNlX2ZhaWx1cmUYBiABKAsyKC5hZ2VudC52MS5Qb3N0VG9vbFVzZUZhaWx1cmVSZXF1ZXN0UXVlcnlIABJIChRiZWZvcmVfc3VibWl0X3Byb21wdBgHIAEoCzIoLmFnZW50LnYxLkJlZm9yZVN1Ym1pdFByb21wdFJlcXVlc3RRdWVyeUgAEkgKFGFmdGVyX2FnZW50X3Jlc3BvbnNlGAggASgLMiguYWdlbnQudjEuQWZ0ZXJBZ2VudFJlc3BvbnNlUmVxdWVzdFF1ZXJ5SAASRgoTYWZ0ZXJfYWdlbnRfdGhvdWdodBgJIAEoCzInLmFnZW50LnYxLkFmdGVyQWdlbnRUaG91Z2h0UmVxdWVzdFF1ZXJ5SAASKgoEc3RvcBgLIAEoCzIaLmFnZW50LnYxLlN0b3BSZXF1ZXN0UXVlcnlIAEIJCgdyZXF1ZXN0Ir0FChNFeGVjdXRlSG9va1Jlc3BvbnNlEjoKC3ByZV9jb21wYWN0GAEgASgLMiMuYWdlbnQudjEuUHJlQ29tcGFjdFJlcXVlc3RSZXNwb25zZUgAEkAKDnN1YmFnZW50X3N0YXJ0GAIgASgLMiYuYWdlbnQudjEuU3ViYWdlbnRTdGFydFJlcXVlc3RSZXNwb25zZUgAEj4KDXN1YmFnZW50X3N0b3AYAyABKAsyJS5hZ2VudC52MS5TdWJhZ2VudFN0b3BSZXF1ZXN0UmVzcG9uc2VIABI7CgxwcmVfdG9vbF91c2UYBCABKAsyIy5hZ2VudC52MS5QcmVUb29sVXNlUmVxdWVzdFJlc3BvbnNlSAASPQoNcG9zdF90b29sX3VzZRgFIAEoCzIkLmFnZW50LnYxLlBvc3RUb29sVXNlUmVxdWVzdFJlc3BvbnNlSAASTAoVcG9zdF90b29sX3VzZV9mYWlsdXJlGAYgASgLMisuYWdlbnQudjEuUG9zdFRvb2xVc2VGYWlsdXJlUmVxdWVzdFJlc3BvbnNlSAASSwoUYmVmb3JlX3N1Ym1pdF9wcm9tcHQYByABKAsyKy5hZ2VudC52MS5CZWZvcmVTdWJtaXRQcm9tcHRSZXF1ZXN0UmVzcG9uc2VIABJLChRhZnRlcl9hZ2VudF9yZXNwb25zZRgIIAEoCzIrLmFnZW50LnYxLkFmdGVyQWdlbnRSZXNwb25zZVJlcXVlc3RSZXNwb25zZUgAEkkKE2FmdGVyX2FnZW50X3Rob3VnaHQYCSABKAsyKi5hZ2VudC52MS5BZnRlckFnZW50VGhvdWdodFJlcXVlc3RSZXNwb25zZUgAEi0KBHN0b3AYCyABKAsyHS5hZ2VudC52MS5TdG9wUmVxdWVzdFJlc3BvbnNlSABCCgoIcmVzcG9uc2UiQAoPRXhlY3V0ZUhvb2tBcmdzEi0KB3JlcXVlc3QYASABKAsyHC5hZ2VudC52MS5FeGVjdXRlSG9va1JlcXVlc3QiRAoRRXhlY3V0ZUhvb2tSZXN1bHQSLwoIcmVzcG9uc2UYASABKAsyHS5hZ2VudC52MS5FeGVjdXRlSG9va1Jlc3BvbnNlIiUKE1NtYXJ0TW9kZVJpc2tUYXJnZXQSDgoGYWN0aW9uGAEgASgJIkcKJlNtYXJ0TW9kZUNsYXNzaWZpZXJDb252ZXJzYXRpb25NZXNzYWdlEgwKBHJvbGUYASABKAkSDwoHY29udGVudBgCIAEoCSLuAQoXU21hcnRNb2RlQ2xhc3NpZmllckFyZ3MSFAoMdG9vbF9jYWxsX2lkGAEgASgJEiMKFnBhcmVudF9jb252ZXJzYXRpb25faWQYAiABKAlIAIgBARItCgZ0YXJnZXQYAyABKAsyHS5hZ2VudC52MS5TbWFydE1vZGVSaXNrVGFyZ2V0Ek4KFGNvbnZlcnNhdGlvbl9jb250ZXh0GAQgAygLMjAuYWdlbnQudjEuU21hcnRNb2RlQ2xhc3NpZmllckNvbnZlcnNhdGlvbk1lc3NhZ2VCGQoXX3BhcmVudF9jb252ZXJzYXRpb25faWQigQEKGlNtYXJ0TW9kZUNsYXNzaWZpZXJTdWNjZXNzEjcKCGRlY2lzaW9uGAEgASgOMiUuYWdlbnQudjEuU21hcnRNb2RlQ2xhc3NpZmllckRlY2lzaW9uEhkKDGJsb2NrX3JlYXNvbhgCIAEoCUgAiAEBQg8KDV9ibG9ja19yZWFzb24iKQoYU21hcnRNb2RlQ2xhc3NpZmllckVycm9yEg0KBWVycm9yGAEgASgJIpMBChlTbWFydE1vZGVDbGFzc2lmaWVyUmVzdWx0EjcKB3N1Y2Nlc3MYASABKAsyJC5hZ2VudC52MS5TbWFydE1vZGVDbGFzc2lmaWVyU3VjY2Vzc0gAEjMKBWVycm9yGAIgASgLMiIuYWdlbnQudjEuU21hcnRNb2RlQ2xhc3NpZmllckVycm9ySABCCAoGcmVzdWx0IjsKFUNhbnZhc0RpYWdub3N0aWNzQXJncxIMCgRwYXRoGAEgASgJEhQKDHRvb2xfY2FsbF9pZBgCIAEoCSJTChhDYW52YXNEaWFnbm9zdGljc1N1Y2Nlc3MSDAoEcGF0aBgBIAEoCRIpCgtkaWFnbm9zdGljcxgCIAMoCzIULmFnZW50LnYxLkRpYWdub3N0aWMiNQoWQ2FudmFzRGlhZ25vc3RpY3NFcnJvchIMCgRwYXRoGAEgASgJEg0KBWVycm9yGAIgASgJIo0BChdDYW52YXNEaWFnbm9zdGljc1Jlc3VsdBI1CgdzdWNjZXNzGAEgASgLMiIuYWdlbnQudjEuQ2FudmFzRGlhZ25vc3RpY3NTdWNjZXNzSAASMQoFZXJyb3IYAiABKAsyIC5hZ2VudC52MS5DYW52YXNEaWFnbm9zdGljc0Vycm9ySABCCAoGcmVzdWx0IqwBChVDb252ZXJzYXRpb25TZWFyY2hIaXQSFwoPY29udmVyc2F0aW9uX2lkGAEgASgJEg0KBXRpdGxlGAIgASgJEjIKBnNvdXJjZRgDIAEoDjIiLmFnZW50LnYxLkNvbnZlcnNhdGlvblNlYXJjaFNvdXJjZRIVCg11cGRhdGVkX2F0X21zGAQgASgDEhQKB3NuaXBwZXQYBSABKAlIAIgBAUIKCghfc25pcHBldCKCAQoZQ29udmVyc2F0aW9uU2VhcmNoU3VjY2VzcxItCgRoaXRzGAEgAygLMh8uYWdlbnQudjEuQ29udmVyc2F0aW9uU2VhcmNoSGl0EhEKCXRydW5jYXRlZBgCIAEoCBIPCgdwYXJ0aWFsGAMgASgIEhIKCnJlYnVpbGRpbmcYBCABKAgiKAoXQ29udmVyc2F0aW9uU2VhcmNoRXJyb3ISDQoFZXJyb3IYASABKAkiWwoWQ29udmVyc2F0aW9uU2VhcmNoQXJncxINCgVxdWVyeRgBIAEoCRIUCgx0b29sX2NhbGxfaWQYAiABKAkSEgoFbGltaXQYAyABKAVIAIgBAUIICgZfbGltaXQikAEKGENvbnZlcnNhdGlvblNlYXJjaFJlc3VsdBI2CgdzdWNjZXNzGAEgASgLMiMuYWdlbnQudjEuQ29udmVyc2F0aW9uU2VhcmNoU3VjY2Vzc0gAEjIKBWVycm9yGAIgASgLMiEuYWdlbnQudjEuQ29udmVyc2F0aW9uU2VhcmNoRXJyb3JIAEIICgZyZXN1bHQiVQoYQWdlbnRTdG9yZUNvbmZsaWN0Q3Vyc29yEhUKDWpvdXJuYWxfZXBvY2gYASABKAkSCwoDc2VxGAIgASgEEhUKDWxhc3RfZXZlbnRfaWQYAyABKAkipQMKF0FnZW50U3RvcmVDb25mbGljdEV2ZW50EgkKAXYYASABKA0SEAoIZXZlbnRfaWQYAiABKAkSFQoNam91cm5hbF9lcG9jaBgDIAEoCRILCgNzZXEYBCABKAQSDQoFdHNfbXMYBSABKAQSDAoEa2luZBgGIAEoCRIVCghzdG9yZV9pZBgHIAEoCUgAiAEBEh4KEW9yaWdpbmFsX3JlbF9wYXRoGAggASgJSAGIAQESHgoRY29uZmxpY3RfcmVsX3BhdGgYCSABKAlIAogBARIeChFvcmlnaW5hbF9hYnNfcGF0aBgKIAEoCUgDiAEBEh4KEWNvbmZsaWN0X2Fic19wYXRoGAsgASgJSASIAQESHAoPcHJlc2VydmVkX2J5dGVzGAwgASgESAWIAQFCCwoJX3N0b3JlX2lkQhQKEl9vcmlnaW5hbF9yZWxfcGF0aEIUChJfY29uZmxpY3RfcmVsX3BhdGhCFAoSX29yaWdpbmFsX2Fic19wYXRoQhQKEl9jb25mbGljdF9hYnNfcGF0aEISChBfcHJlc2VydmVkX2J5dGVzIpQBChlBZ2VudFN0b3JlQ29uZmxpY3RTdWNjZXNzEjEKBmV2ZW50cxgBIAMoCzIhLmFnZW50LnYxLkFnZW50U3RvcmVDb25mbGljdEV2ZW50EjcKC25leHRfY3Vyc29yGAIgASgLMiIuYWdlbnQudjEuQWdlbnRTdG9yZUNvbmZsaWN0Q3Vyc29yEgsKA2dhcBgDIAEoCCIoChdBZ2VudFN0b3JlQ29uZmxpY3RFcnJvchINCgVlcnJvchgBIAEoCSJ+ChZBZ2VudFN0b3JlQ29uZmxpY3RBcmdzEjcKBmN1cnNvchgBIAEoCzIiLmFnZW50LnYxLkFnZW50U3RvcmVDb25mbGljdEN1cnNvckgAiAEBEhQKB2FkdmFuY2UYAiABKAhIAYgBAUIJCgdfY3Vyc29yQgoKCF9hZHZhbmNlIpABChhBZ2VudFN0b3JlQ29uZmxpY3RSZXN1bHQSNgoHc3VjY2VzcxgBIAEoCzIjLmFnZW50LnYxLkFnZW50U3RvcmVDb25mbGljdFN1Y2Nlc3NIABIyCgVlcnJvchgCIAEoCzIhLmFnZW50LnYxLkFnZW50U3RvcmVDb25mbGljdEVycm9ySABCCAoGcmVzdWx0InwKDkZpbGVEaWZmX0NodW5rEg8KB2NvbnRlbnQYASABKAkSDQoFbGluZXMYAiADKAkSEQoJb2xkX3N0YXJ0GAMgASgFEhEKCW9sZF9saW5lcxgEIAEoBRIRCgluZXdfc3RhcnQYBSABKAUSEQoJbmV3X2xpbmVzGAYgASgFIpACCghGaWxlRGlmZhINCgVhZGRlZBgEIAEoBRIPCgdyZW1vdmVkGAUgASgFEgwKBGZyb20YASABKAkSCgoCdG8YAiABKAkSKAoGY2h1bmtzGAMgAygLMhguYWdlbnQudjEuRmlsZURpZmZfQ2h1bmsSIQoUYmVmb3JlX2ZpbGVfY29udGVudHMYBiABKAlIAIgBARIgChNhZnRlcl9maWxlX2NvbnRlbnRzGAcgASgJSAGIAQESGQoMaXNfZ2VuZXJhdGVkGAggASgISAKIAQFCFwoVX2JlZm9yZV9maWxlX2NvbnRlbnRzQhYKFF9hZnRlcl9maWxlX2NvbnRlbnRzQg8KDV9pc19nZW5lcmF0ZWQiWwoHR2l0RGlmZhIhCgVkaWZmcxgBIAMoCzISLmFnZW50LnYxLkZpbGVEaWZmEi0KCWRpZmZfdHlwZRgCIAEoDjIaLmFnZW50LnYxLkdpdERpZmZfRGlmZlR5cGUiaAodR2V0RGlmZlJlc3BvbnNlX1N1Ym1vZHVsZURpZmYSFQoNcmVsYXRpdmVfcGF0aBgBIAEoCRIfCgRkaWZmGAIgASgLMhEuYWdlbnQudjEuR2l0RGlmZhIPCgdlcnJvcmVkGAMgASgIIvIDCg5HZXREaWZmUmVxdWVzdBILCgNjd2QYASABKAkSCwoDcmVmGAIgASgJEhAKCGJhc2VfcmVmGAMgASgJEhIKCm1lcmdlX2Jhc2UYBCABKAgSFAoMdGFyZ2V0X3BhdGhzGAUgAygJEiIKFXVuaWZpZWRfY29udGV4dF9saW5lcxgGIAEoBUgAiAEBEhsKE21heF91bnRyYWNrZWRfZmlsZXMYByABKAUSHwoXc3VibW9kdWxlX3JlY3Vyc2VfZGVwdGgYCSABKAUSHQoVaW5jbHVkZV9zcGFjZV9jaGFuZ2VzGAogASgIEhYKDmNvbW1pdHRlZF9vbmx5GAsgASgIEhgKEGNvbXB1dGVfcGF0Y2hfaWQYDCABKAgSHAoPcmV0dXJuX2hlYWRfc2hhGA0gASgISAGIAQESHwoSbWF4X3Jlc3BvbnNlX2J5dGVzGA4gASgFSAKIAQESQQoNb3V0cHV0X2Zvcm1hdBgIIAEoDjIlLmFnZW50LnYxLkdldERpZmZSZXF1ZXN0X091dHB1dEZvcm1hdEgDiAEBQhgKFl91bmlmaWVkX2NvbnRleHRfbGluZXNCEgoQX3JldHVybl9oZWFkX3NoYUIVChNfbWF4X3Jlc3BvbnNlX2J5dGVzQhAKDl9vdXRwdXRfZm9ybWF0Iv4BCg9HZXREaWZmUmVzcG9uc2USHwoEZGlmZhgBIAEoCzIRLmFnZW50LnYxLkdpdERpZmYSQAoPc3VibW9kdWxlX2RpZmZzGAIgAygLMicuYWdlbnQudjEuR2V0RGlmZlJlc3BvbnNlX1N1Ym1vZHVsZURpZmYSFQoIcGF0Y2hfaWQYAyABKAlIAIgBARIVCghoZWFkX3NoYRgEIAEoCUgBiAEBEiQKF2hhc191bmNvbW1pdHRlZF9jaGFuZ2VzGAUgASgISAKIAQFCCwoJX3BhdGNoX2lkQgsKCV9oZWFkX3NoYUIaChhfaGFzX3VuY29tbWl0dGVkX2NoYW5nZXMqiAEKHUFwcGxpZWRBZ2VudENoYW5nZV9DaGFuZ2VUeXBlEhsKF0NIQU5HRV9UWVBFX1VOU1BFQ0lGSUVEEAASFwoTQ0hBTkdFX1RZUEVfQ1JFQVRFRBABEhgKFENIQU5HRV9UWVBFX01PRElGSUVEEAISFwoTQ0hBTkdFX1RZUEVfREVMRVRFRBADKqQBCgtNb3VzZUJ1dHRvbhIcChhNT1VTRV9CVVRUT05fVU5TUEVDSUZJRUQQABIVChFNT1VTRV9CVVRUT05fTEVGVBABEhYKEk1PVVNFX0JVVFRPTl9SSUdIVBACEhcKE01PVVNFX0JVVFRPTl9NSURETEUQAxIVChFNT1VTRV9CVVRUT05fQkFDSxAEEhgKFE1PVVNFX0JVVFRPTl9GT1JXQVJEEAUqngEKD1Njcm9sbERpcmVjdGlvbhIgChxTQ1JPTExfRElSRUNUSU9OX1VOU1BFQ0lGSUVEEAASFwoTU0NST0xMX0RJUkVDVElPTl9VUBABEhkKFVNDUk9MTF9ESVJFQ1RJT05fRE9XThACEhkKFVNDUk9MTF9ESVJFQ1RJT05fTEVGVBADEhoKFlNDUk9MTF9ESVJFQ1RJT05fUklHSFQQBCpwChBDdXJzb3JSdWxlU291cmNlEiIKHkNVUlNPUl9SVUxFX1NPVVJDRV9VTlNQRUNJRklFRBAAEhsKF0NVUlNPUl9SVUxFX1NPVVJDRV9URUFNEAESGwoXQ1VSU09SX1JVTEVfU09VUkNFX1VTRVIQAiq8AQoSRGlhZ25vc3RpY1NldmVyaXR5EiMKH0RJQUdOT1NUSUNfU0VWRVJJVFlfVU5TUEVDSUZJRUQQABIdChlESUFHTk9TVElDX1NFVkVSSVRZX0VSUk9SEAESHwobRElBR05PU1RJQ19TRVZFUklUWV9XQVJOSU5HEAISIwofRElBR05PU1RJQ19TRVZFUklUWV9JTkZPUk1BVElPThADEhwKGERJQUdOT1NUSUNfU0VWRVJJVFlfSElOVBAEKpwBCg1SZWNvcmRpbmdNb2RlEh4KGlJFQ09SRElOR19NT0RFX1VOU1BFQ0lGSUVEEAASIgoeUkVDT1JESU5HX01PREVfU1RBUlRfUkVDT1JESU5HEAESIQodUkVDT1JESU5HX01PREVfU0FWRV9SRUNPUkRJTkcQAhIkCiBSRUNPUkRJTkdfTU9ERV9ESVNDQVJEX1JFQ09SRElORxADKpMBCh9SZXF1ZXN0ZWRGaWxlUGF0aFJlamVjdGVkUmVhc29uEjMKL1JFUVVFU1RFRF9GSUxFX1BBVEhfUkVKRUNURURfUkVBU09OX1VOU1BFQ0lGSUVEEAASOwo3UkVRVUVTVEVEX0ZJTEVfUEFUSF9SRUpFQ1RFRF9SRUFTT05fU0xBU0hFU19OT1RfQUxMT1dFRBABKq0BCgtQYWNrYWdlVHlwZRIcChhQQUNLQUdFX1RZUEVfVU5TUEVDSUZJRUQQABIfChtQQUNLQUdFX1RZUEVfQ1VSU09SX1BST0pFQ1QQARIgChxQQUNLQUdFX1RZUEVfQ1VSU09SX1BFUlNPTkFMEAISHQoZUEFDS0FHRV9UWVBFX0NMQVVERV9TS0lMTBADEh4KGlBBQ0tBR0VfVFlQRV9DTEFVREVfUExVR0lOEAQqfQoSU2FuZGJveFBvbGljeV9UeXBlEhQKEFRZUEVfVU5TUEVDSUZJRUQQABIWChJUWVBFX0lOU0VDVVJFX05PTkUQARIcChhUWVBFX1dPUktTUEFDRV9SRUFEV1JJVEUQAhIbChdUWVBFX1dPUktTUEFDRV9SRUFET05MWRADKnEKD1RpbWVvdXRCZWhhdmlvchIgChxUSU1FT1VUX0JFSEFWSU9SX1VOU1BFQ0lGSUVEEAASGwoXVElNRU9VVF9CRUhBVklPUl9DQU5DRUwQARIfChtUSU1FT1VUX0JFSEFWSU9SX0JBQ0tHUk9VTkQQAip5ChBTaGVsbEFib3J0UmVhc29uEiIKHlNIRUxMX0FCT1JUX1JFQVNPTl9VTlNQRUNJRklFRBAAEiEKHVNIRUxMX0FCT1JUX1JFQVNPTl9VU0VSX0FCT1JUEAESHgoaU0hFTExfQUJPUlRfUkVBU09OX1RJTUVPVVQQAiqqAQocQ3VzdG9tU3ViYWdlbnRQZXJtaXNzaW9uTW9kZRIvCitDVVNUT01fU1VCQUdFTlRfUEVSTUlTU0lPTl9NT0RFX1VOU1BFQ0lGSUVEEAASKwonQ1VTVE9NX1NVQkFHRU5UX1BFUk1JU1NJT05fTU9ERV9ERUZBVUxUEAESLAooQ1VTVE9NX1NVQkFHRU5UX1BFUk1JU1NJT05fTU9ERV9SRUFET05MWRACKpUBCgpUb2RvU3RhdHVzEhsKF1RPRE9fU1RBVFVTX1VOU1BFQ0lGSUVEEAASFwoTVE9ET19TVEFUVVNfUEVORElORxABEhsKF1RPRE9fU1RBVFVTX0lOX1BST0dSRVNTEAISGQoVVE9ET19TVEFUVVNfQ09NUExFVEVEEAMSGQoVVE9ET19TVEFUVVNfQ0FOQ0VMTEVEEAQqZgoIQ2xpZW50T1MSGQoVQ0xJRU5UX09TX1VOU1BFQ0lGSUVEEAASFQoRQ0xJRU5UX09TX1dJTkRPV1MQARITCg9DTElFTlRfT1NfTUFDT1MQAhITCg9DTElFTlRfT1NfTElOVVgQAyrsAQocQXJ0aWZhY3RVcGxvYWREaXNwYXRjaFN0YXR1cxIvCitBUlRJRkFDVF9VUExPQURfRElTUEFUQ0hfU1RBVFVTX1VOU1BFQ0lGSUVEEAASLAooQVJUSUZBQ1RfVVBMT0FEX0RJU1BBVENIX1NUQVRVU19BQ0NFUFRFRBABEiwKKEFSVElGQUNUX1VQTE9BRF9ESVNQQVRDSF9TVEFUVVNfUkVKRUNURUQQAhI/CjtBUlRJRkFDVF9VUExPQURfRElTUEFUQ0hfU1RBVFVTX1NLSVBQRURfQUxSRUFEWV9JTl9QUk9HUkVTUxADKlcKCkZyYW1lX0tpbmQSFAoQS0lORF9VTlNQRUNJRklFRBAAEhAKDEtJTkRfUkVRVUVTVBABEhEKDUtJTkRfUkVTUE9OU0UQAhIOCgpLSU5EX0VSUk9SEAMqsAIKF0J1Z2JvdERlZXBsaW5rRXZlbnRLaW5kEioKJkJVR0JPVF9ERUVQTElOS19FVkVOVF9LSU5EX1VOU1BFQ0lGSUVEEAASJgoiQlVHQk9UX0RFRVBMSU5LX0VWRU5UX0tJTkRfQ0xJQ0tFRBABEjMKL0JVR0JPVF9ERUVQTElOS19FVkVOVF9LSU5EX0hBTkRMRURfRElBTE9HX1NIT1dOEAISMwovQlVHQk9UX0RFRVBMSU5LX0VWRU5UX0tJTkRfSEFORExFRF9DSEFUX0NSRUFURUQQAxIkCiBCVUdCT1RfREVFUExJTktfRVZFTlRfS0lORF9FUlJPUhAEEjEKLUJVR0JPVF9ERUVQTElOS19FVkVOVF9LSU5EX0hBTkRMRURfRklYX0lOX1dFQhAFKsoBCixDb21tYW5kQ2xhc3NpZmllclJlc3VsdF9TdWdnZXN0ZWRTYW5kYm94TW9kZRImCiJTVUdHRVNURURfU0FOREJPWF9NT0RFX1VOU1BFQ0lGSUVEEAASIgoeU1VHR0VTVEVEX1NBTkRCT1hfTU9ERV9TQU5EQk9YEAESJQohU1VHR0VTVEVEX1NBTkRCT1hfTU9ERV9OT19TQU5EQk9YEAISJwojU1VHR0VTVEVEX1NBTkRCT1hfTU9ERV9VTkRFVEVSTUlORUQQAyqQAQohU2hlbGxIb29rQXBwcm92YWxSZXF1aXJlbWVudF9LaW5kEjQKMFNIRUxMX0hPT0tfQVBQUk9WQUxfUkVRVUlSRU1FTlRfS0lORF9VTlNQRUNJRklFRBAAEjUKMVNIRUxMX0hPT0tfQVBQUk9WQUxfUkVRVUlSRU1FTlRfS0lORF9GT1JDRV9QUk9NUFQQASqPAQoVU2hlbGxCYWNrZ3JvdW5kUmVhc29uEicKI1NIRUxMX0JBQ0tHUk9VTkRfUkVBU09OX1VOU1BFQ0lGSUVEEAASIwofU0hFTExfQkFDS0dST1VORF9SRUFTT05fVElNRU9VVBABEigKJFNIRUxMX0JBQ0tHUk9VTkRfUkVBU09OX1VTRVJfUkVRVUVTVBACKqQBChpGb3JjZUJhY2tncm91bmRTaGVsbFN0YXR1cxItCilGT1JDRV9CQUNLR1JPVU5EX1NIRUxMX1NUQVRVU19VTlNQRUNJRklFRBAAEioKJkZPUkNFX0JBQ0tHUk9VTkRfU0hFTExfU1RBVFVTX0FDQ0VQVEVEEAESKwonRk9SQ0VfQkFDS0dST1VORF9TSEVMTF9TVEFUVVNfTk9UX0ZPVU5EEAIq0gEKGFN1YmFnZW50QmFja2dyb3VuZFJlYXNvbhIqCiZTVUJBR0VOVF9CQUNLR1JPVU5EX1JFQVNPTl9VTlNQRUNJRklFRBAAEiwKKFNVQkFHRU5UX0JBQ0tHUk9VTkRfUkVBU09OX0FHRU5UX1JFUVVFU1QQARIrCidTVUJBR0VOVF9CQUNLR1JPVU5EX1JFQVNPTl9VU0VSX1JFUVVFU1QQAhIvCitTVUJBR0VOVF9CQUNLR1JPVU5EX1JFQVNPTl9RVUVVRURfRk9MTE9XX1VQEAMqsAEKHUZvcmNlQmFja2dyb3VuZFN1YmFnZW50U3RhdHVzEjAKLEZPUkNFX0JBQ0tHUk9VTkRfU1VCQUdFTlRfU1RBVFVTX1VOU1BFQ0lGSUVEEAASLQopRk9SQ0VfQkFDS0dST1VORF9TVUJBR0VOVF9TVEFUVVNfQUNDRVBURUQQARIuCipGT1JDRV9CQUNLR1JPVU5EX1NVQkFHRU5UX1NUQVRVU19OT1RfRk9VTkQQAiqhAQobU21hcnRNb2RlQ2xhc3NpZmllckRlY2lzaW9uEi4KKlNNQVJUX01PREVfQ0xBU1NJRklFUl9ERUNJU0lPTl9VTlNQRUNJRklFRBAAEigKJFNNQVJUX01PREVfQ0xBU1NJRklFUl9ERUNJU0lPTl9BTExPVxABEigKJFNNQVJUX01PREVfQ0xBU1NJRklFUl9ERUNJU0lPTl9CTE9DSxACKpgBChhDb252ZXJzYXRpb25TZWFyY2hTb3VyY2USKgomQ09OVkVSU0FUSU9OX1NFQVJDSF9TT1VSQ0VfVU5TUEVDSUZJRUQQABIkCiBDT05WRVJTQVRJT05fU0VBUkNIX1NPVVJDRV9MT0NBTBABEioKJkNPTlZFUlNBVElPTl9TRUFSQ0hfU09VUkNFX0NMT1VEX0NBQ0hFEAIq0wEKG0dldERpZmZSZXF1ZXN0X091dHB1dEZvcm1hdBIdChlPVVRQVVRfRk9STUFUX1VOU1BFQ0lGSUVEEAASHQoZT1VUUFVUX0ZPUk1BVF9OQU1FX1NUQVRVUxABEikKJU9VVFBVVF9GT1JNQVRfTkFNRV9TVEFUVVNfQU5EX05VTVNUQVQQAhIcChhPVVRQVVRfRk9STUFUX0ZJTEVfRElGRlMQAxItCilPVVRQVVRfRk9STUFUX0RJRkZTX1dJVEhfQkVGT1JFX0FORF9BRlRFUhAEKnEKEEdpdERpZmZfRGlmZlR5cGUSGQoVRElGRl9UWVBFX1VOU1BFQ0lGSUVEEAASGgoWRElGRl9UWVBFX0RJRkZfVE9fSEVBRBABEiYKIkRJRkZfVFlQRV9ESUZGX0ZST01fQlJBTkNIX1RPX01BSU4QAjKHBAoMQWdlbnRTZXJ2aWNlEkEKA1J1bhIcLmFnZW50LnYxLkFnZW50Q2xpZW50TWVzc2FnZRocLmFnZW50LnYxLkFnZW50U2VydmVyTWVzc2FnZRI/CgZSdW5TU0USFy5hZ2VudC52MS5CaWRpUmVxdWVzdElkGhwuYWdlbnQudjEuQWdlbnRTZXJ2ZXJNZXNzYWdlEkQKCU5hbWVBZ2VudBIaLmFnZW50LnYxLk5hbWVBZ2VudFJlcXVlc3QaGy5hZ2VudC52MS5OYW1lQWdlbnRSZXNwb25zZRJWCg9HZXRVc2FibGVNb2RlbHMSIC5hZ2VudC52MS5HZXRVc2FibGVNb2RlbHNSZXF1ZXN0GiEuYWdlbnQudjEuR2V0VXNhYmxlTW9kZWxzUmVzcG9uc2USaAoVR2V0RGVmYXVsdE1vZGVsRm9yQ2xpEiYuYWdlbnQudjEuR2V0RGVmYXVsdE1vZGVsRm9yQ2xpUmVxdWVzdBonLmFnZW50LnYxLkdldERlZmF1bHRNb2RlbEZvckNsaVJlc3BvbnNlEmsKFkdldEFsbG93ZWRNb2RlbEludGVudHMSJy5hZ2VudC52MS5HZXRBbGxvd2VkTW9kZWxJbnRlbnRzUmVxdWVzdBooLmFnZW50LnYxLkdldEFsbG93ZWRNb2RlbEludGVudHNSZXNwb25zZTK1CAoOQ29udHJvbFNlcnZpY2USTQoMUmVhZFRleHRGaWxlEh0uYWdlbnQudjEuUmVhZFRleHRGaWxlUmVxdWVzdBoeLmFnZW50LnYxLlJlYWRUZXh0RmlsZVJlc3BvbnNlElAKDVdyaXRlVGV4dEZpbGUSHi5hZ2VudC52MS5Xcml0ZVRleHRGaWxlUmVxdWVzdBofLmFnZW50LnYxLldyaXRlVGV4dEZpbGVSZXNwb25zZRJTCg5SZWFkQmluYXJ5RmlsZRIfLmFnZW50LnYxLlJlYWRCaW5hcnlGaWxlUmVxdWVzdBogLmFnZW50LnYxLlJlYWRCaW5hcnlGaWxlUmVzcG9uc2USVgoPV3JpdGVCaW5hcnlGaWxlEiAuYWdlbnQudjEuV3JpdGVCaW5hcnlGaWxlUmVxdWVzdBohLmFnZW50LnYxLldyaXRlQmluYXJ5RmlsZVJlc3BvbnNlEm4KF0dldFdvcmtzcGFjZUNoYW5nZXNIYXNoEiguYWdlbnQudjEuR2V0V29ya3NwYWNlQ2hhbmdlc0hhc2hSZXF1ZXN0GikuYWdlbnQudjEuR2V0V29ya3NwYWNlQ2hhbmdlc0hhc2hSZXNwb25zZRJxChhSZWZyZXNoR2l0aHViQWNjZXNzVG9rZW4SKS5hZ2VudC52MS5SZWZyZXNoR2l0aHViQWNjZXNzVG9rZW5SZXF1ZXN0GiouYWdlbnQudjEuUmVmcmVzaEdpdGh1YkFjY2Vzc1Rva2VuUmVzcG9uc2USawoWV2FybVJlbW90ZUFjY2Vzc1NlcnZlchInLmFnZW50LnYxLldhcm1SZW1vdGVBY2Nlc3NTZXJ2ZXJSZXF1ZXN0GiguYWdlbnQudjEuV2FybVJlbW90ZUFjY2Vzc1NlcnZlclJlc3BvbnNlElAKDUxpc3RBcnRpZmFjdHMSHi5hZ2VudC52MS5MaXN0QXJ0aWZhY3RzUmVxdWVzdBofLmFnZW50LnYxLkxpc3RBcnRpZmFjdHNSZXNwb25zZRJWCg9VcGxvYWRBcnRpZmFjdHMSIC5hZ2VudC52MS5VcGxvYWRBcnRpZmFjdHNSZXF1ZXN0GiEuYWdlbnQudjEuVXBsb2FkQXJ0aWZhY3RzUmVzcG9uc2USYgoTR2V0TWNwUmVmcmVzaFRva2VucxIkLmFnZW50LnYxLkdldE1jcFJlZnJlc2hUb2tlbnNSZXF1ZXN0GiUuYWdlbnQudjEuR2V0TWNwUmVmcmVzaFRva2Vuc1Jlc3BvbnNlEncKGlVwZGF0ZUVudmlyb25tZW50VmFyaWFibGVzEisuYWdlbnQudjEuVXBkYXRlRW52aXJvbm1lbnRWYXJpYWJsZXNSZXF1ZXN0GiwuYWdlbnQudjEuVXBkYXRlRW52aXJvbm1lbnRWYXJpYWJsZXNSZXNwb25zZTINCgtFeGVjU2VydmljZTJRCiJQcml2YXRlV29ya2VyQnJpZGdlRXh0ZXJuYWxTZXJ2aWNlEisKB0Nvbm5lY3QSDy5hZ2VudC52MS5GcmFtZRoPLmFnZW50LnYxLkZyYW1lMngKEExpZmVjeWNsZVNlcnZpY2USMQoNUmVzZXRJbnN0YW5jZRIPLmFnZW50LnYxLkVtcHR5Gg8uYWdlbnQudjEuRW1wdHkSMQoNUmVuZXdJbnN0YW5jZRIPLmFnZW50LnYxLkVtcHR5Gg8uYWdlbnQudjEuRW1wdHliBnByb3RvMw"); + fileDesc("CgthZ2VudC5wcm90bxIIYWdlbnQudjEicgoOR2xvYlRvb2xSZXN1bHQSLAoHc3VjY2VzcxgBIAEoCzIZLmFnZW50LnYxLkdsb2JUb29sU3VjY2Vzc0gAEigKBWVycm9yGAIgASgLMhcuYWdlbnQudjEuR2xvYlRvb2xFcnJvckgAQggKBnJlc3VsdCIeCg1HbG9iVG9vbEVycm9yEg0KBWVycm9yGAEgASgJIokBCg9HbG9iVG9vbFN1Y2Nlc3MSDwoHcGF0dGVybhgBIAEoCRIMCgRwYXRoGAIgASgJEg0KBWZpbGVzGAMgAygJEhMKC3RvdGFsX2ZpbGVzGAQgASgFEhgKEGNsaWVudF90cnVuY2F0ZWQYBSABKAgSGQoRcmlwZ3JlcF90cnVuY2F0ZWQYBiABKAgiRgoMR2xvYlRvb2xDYWxsEgwKBGFyZ3MYASABKAwSKAoGcmVzdWx0GAIgASgLMhguYWdlbnQudjEuR2xvYlRvb2xSZXN1bHQibQoRUmVhZExpbnRzVG9vbENhbGwSKQoEYXJncxgBIAEoCzIbLmFnZW50LnYxLlJlYWRMaW50c1Rvb2xBcmdzEi0KBnJlc3VsdBgCIAEoCzIdLmFnZW50LnYxLlJlYWRMaW50c1Rvb2xSZXN1bHQiIgoRUmVhZExpbnRzVG9vbEFyZ3MSDQoFcGF0aHMYASADKAkigQEKE1JlYWRMaW50c1Rvb2xSZXN1bHQSMQoHc3VjY2VzcxgBIAEoCzIeLmFnZW50LnYxLlJlYWRMaW50c1Rvb2xTdWNjZXNzSAASLQoFZXJyb3IYAiABKAsyHC5hZ2VudC52MS5SZWFkTGludHNUb29sRXJyb3JIAEIICgZyZXN1bHQiewoUUmVhZExpbnRzVG9vbFN1Y2Nlc3MSMwoQZmlsZV9kaWFnbm9zdGljcxgBIAMoCzIZLmFnZW50LnYxLkZpbGVEaWFnbm9zdGljcxITCgt0b3RhbF9maWxlcxgCIAEoBRIZChF0b3RhbF9kaWFnbm9zdGljcxgDIAEoBSJpCg9GaWxlRGlhZ25vc3RpY3MSDAoEcGF0aBgBIAEoCRItCgtkaWFnbm9zdGljcxgCIAMoCzIYLmFnZW50LnYxLkRpYWdub3N0aWNJdGVtEhkKEWRpYWdub3N0aWNzX2NvdW50GAMgASgFIqsBCg5EaWFnbm9zdGljSXRlbRIuCghzZXZlcml0eRgBIAEoDjIcLmFnZW50LnYxLkRpYWdub3N0aWNTZXZlcml0eRIoCgVyYW5nZRgCIAEoCzIZLmFnZW50LnYxLkRpYWdub3N0aWNSYW5nZRIPCgdtZXNzYWdlGAMgASgJEg4KBnNvdXJjZRgEIAEoCRIMCgRjb2RlGAUgASgJEhAKCGlzX3N0YWxlGAYgASgIIlUKD0RpYWdub3N0aWNSYW5nZRIhCgVzdGFydBgBIAEoCzISLmFnZW50LnYxLlBvc2l0aW9uEh8KA2VuZBgCIAEoCzISLmFnZW50LnYxLlBvc2l0aW9uIisKElJlYWRMaW50c1Rvb2xFcnJvchIVCg1lcnJvcl9tZXNzYWdlGAEgASgJIj0KDE1jcFRvb2xFcnJvchINCgVlcnJvchgBIAEoCRIeChZyZWFkX3Rvb2xfZGVmX3JlbWluZGVyGAIgASgJItIBCg1NY3BUb29sUmVzdWx0EicKB3N1Y2Nlc3MYASABKAsyFC5hZ2VudC52MS5NY3BTdWNjZXNzSAASJwoFZXJyb3IYAiABKAsyFi5hZ2VudC52MS5NY3BUb29sRXJyb3JIABIpCghyZWplY3RlZBgDIAEoCzIVLmFnZW50LnYxLk1jcFJlamVjdGVkSAASOgoRcGVybWlzc2lvbl9kZW5pZWQYBCABKAsyHS5hZ2VudC52MS5NY3BQZXJtaXNzaW9uRGVuaWVkSABCCAoGcmVzdWx0IoEBCgtNY3BUb29sQ2FsbBIfCgRhcmdzGAEgASgLMhEuYWdlbnQudjEuTWNwQXJncxInCgZyZXN1bHQYAiABKAsyFy5hZ2VudC52MS5NY3BUb29sUmVzdWx0EhgKC2Rlc2NyaXB0aW9uGAMgASgJSACIAQFCDgoMX2Rlc2NyaXB0aW9uIm0KEVNlbVNlYXJjaFRvb2xDYWxsEikKBGFyZ3MYASABKAsyGy5hZ2VudC52MS5TZW1TZWFyY2hUb29sQXJncxItCgZyZXN1bHQYAiABKAsyHS5hZ2VudC52MS5TZW1TZWFyY2hUb29sUmVzdWx0IlMKEVNlbVNlYXJjaFRvb2xBcmdzEg0KBXF1ZXJ5GAEgASgJEhoKEnRhcmdldF9kaXJlY3RvcmllcxgCIAMoCRITCgtleHBsYW5hdGlvbhgDIAEoCSKBAQoTU2VtU2VhcmNoVG9vbFJlc3VsdBIxCgdzdWNjZXNzGAEgASgLMh4uYWdlbnQudjEuU2VtU2VhcmNoVG9vbFN1Y2Nlc3NIABItCgVlcnJvchgCIAEoCzIcLmFnZW50LnYxLlNlbVNlYXJjaFRvb2xFcnJvckgAQggKBnJlc3VsdCI9ChRTZW1TZWFyY2hUb29sU3VjY2VzcxIPCgdyZXN1bHRzGAEgASgJEhQKDGNvZGVfcmVzdWx0cxgCIAMoDCIrChJTZW1TZWFyY2hUb29sRXJyb3ISFQoNZXJyb3JfbWVzc2FnZRgBIAEoCSKCAQoYTGlzdE1jcFJlc291cmNlc1Rvb2xDYWxsEjAKBGFyZ3MYASABKAsyIi5hZ2VudC52MS5MaXN0TWNwUmVzb3VyY2VzRXhlY0FyZ3MSNAoGcmVzdWx0GAIgASgLMiQuYWdlbnQudjEuTGlzdE1jcFJlc291cmNlc0V4ZWNSZXN1bHQifwoXUmVhZE1jcFJlc291cmNlVG9vbENhbGwSLwoEYXJncxgBIAEoCzIhLmFnZW50LnYxLlJlYWRNY3BSZXNvdXJjZUV4ZWNBcmdzEjMKBnJlc3VsdBgCIAEoCzIjLmFnZW50LnYxLlJlYWRNY3BSZXNvdXJjZUV4ZWNSZXN1bHQiWQoNRmV0Y2hUb29sQ2FsbBIhCgRhcmdzGAEgASgLMhMuYWdlbnQudjEuRmV0Y2hBcmdzEiUKBnJlc3VsdBgCIAEoCzIVLmFnZW50LnYxLkZldGNoUmVzdWx0Im4KFFJlY29yZFNjcmVlblRvb2xDYWxsEigKBGFyZ3MYASABKAsyGi5hZ2VudC52MS5SZWNvcmRTY3JlZW5BcmdzEiwKBnJlc3VsdBgCIAEoCzIcLmFnZW50LnYxLlJlY29yZFNjcmVlblJlc3VsdCJ3ChdXcml0ZVNoZWxsU3RkaW5Ub29sQ2FsbBIrCgRhcmdzGAEgASgLMh0uYWdlbnQudjEuV3JpdGVTaGVsbFN0ZGluQXJncxIvCgZyZXN1bHQYAiABKAsyHy5hZ2VudC52MS5Xcml0ZVNoZWxsU3RkaW5SZXN1bHQisQEKC1JlZmxlY3RBcmdzEiIKGnVuZXhwZWN0ZWRfYWN0aW9uX291dGNvbWVzGAEgASgJEh0KFXJlbGV2YW50X2luc3RydWN0aW9ucxgCIAEoCRIZChFzY2VuYXJpb19hbmFseXNpcxgDIAEoCRIaChJjcml0aWNhbF9zeW50aGVzaXMYBCABKAkSEgoKbmV4dF9zdGVwcxgFIAEoCRIUCgx0b29sX2NhbGxfaWQYBiABKAkibwoNUmVmbGVjdFJlc3VsdBIrCgdzdWNjZXNzGAEgASgLMhguYWdlbnQudjEuUmVmbGVjdFN1Y2Nlc3NIABInCgVlcnJvchgCIAEoCzIWLmFnZW50LnYxLlJlZmxlY3RFcnJvckgAQggKBnJlc3VsdCIQCg5SZWZsZWN0U3VjY2VzcyIdCgxSZWZsZWN0RXJyb3ISDQoFZXJyb3IYASABKAkiXwoPUmVmbGVjdFRvb2xDYWxsEiMKBGFyZ3MYASABKAsyFS5hZ2VudC52MS5SZWZsZWN0QXJncxInCgZyZXN1bHQYAiABKAsyFy5hZ2VudC52MS5SZWZsZWN0UmVzdWx0IlkKF1N0YXJ0R3JpbmRFeGVjdXRpb25BcmdzEhgKC2V4cGxhbmF0aW9uGAEgASgJSACIAQESFAoMdG9vbF9jYWxsX2lkGAIgASgJQg4KDF9leHBsYW5hdGlvbiKTAQoZU3RhcnRHcmluZEV4ZWN1dGlvblJlc3VsdBI3CgdzdWNjZXNzGAEgASgLMiQuYWdlbnQudjEuU3RhcnRHcmluZEV4ZWN1dGlvblN1Y2Nlc3NIABIzCgVlcnJvchgCIAEoCzIiLmFnZW50LnYxLlN0YXJ0R3JpbmRFeGVjdXRpb25FcnJvckgAQggKBnJlc3VsdCIcChpTdGFydEdyaW5kRXhlY3V0aW9uU3VjY2VzcyIpChhTdGFydEdyaW5kRXhlY3V0aW9uRXJyb3ISDQoFZXJyb3IYASABKAkigwEKG1N0YXJ0R3JpbmRFeGVjdXRpb25Ub29sQ2FsbBIvCgRhcmdzGAEgASgLMiEuYWdlbnQudjEuU3RhcnRHcmluZEV4ZWN1dGlvbkFyZ3MSMwoGcmVzdWx0GAIgASgLMiMuYWdlbnQudjEuU3RhcnRHcmluZEV4ZWN1dGlvblJlc3VsdCJYChZTdGFydEdyaW5kUGxhbm5pbmdBcmdzEhgKC2V4cGxhbmF0aW9uGAEgASgJSACIAQESFAoMdG9vbF9jYWxsX2lkGAIgASgJQg4KDF9leHBsYW5hdGlvbiKQAQoYU3RhcnRHcmluZFBsYW5uaW5nUmVzdWx0EjYKB3N1Y2Nlc3MYASABKAsyIy5hZ2VudC52MS5TdGFydEdyaW5kUGxhbm5pbmdTdWNjZXNzSAASMgoFZXJyb3IYAiABKAsyIS5hZ2VudC52MS5TdGFydEdyaW5kUGxhbm5pbmdFcnJvckgAQggKBnJlc3VsdCIbChlTdGFydEdyaW5kUGxhbm5pbmdTdWNjZXNzIigKF1N0YXJ0R3JpbmRQbGFubmluZ0Vycm9yEg0KBWVycm9yGAEgASgJIoABChpTdGFydEdyaW5kUGxhbm5pbmdUb29sQ2FsbBIuCgRhcmdzGAEgASgLMiAuYWdlbnQudjEuU3RhcnRHcmluZFBsYW5uaW5nQXJncxIyCgZyZXN1bHQYAiABKAsyIi5hZ2VudC52MS5TdGFydEdyaW5kUGxhbm5pbmdSZXN1bHQinAEKCFRhc2tBcmdzEhMKC2Rlc2NyaXB0aW9uGAEgASgJEg4KBnByb21wdBgCIAEoCRItCg1zdWJhZ2VudF90eXBlGAMgASgLMhYuYWdlbnQudjEuU3ViYWdlbnRUeXBlEhIKBW1vZGVsGAQgASgJSACIAQESEwoGcmVzdW1lGAUgASgJSAGIAQFCCAoGX21vZGVsQgkKB19yZXN1bWUiqgEKC1Rhc2tTdWNjZXNzEjYKEmNvbnZlcnNhdGlvbl9zdGVwcxgBIAMoCzIaLmFnZW50LnYxLkNvbnZlcnNhdGlvblN0ZXASFQoIYWdlbnRfaWQYAiABKAlIAIgBARIVCg1pc19iYWNrZ3JvdW5kGAMgASgIEhgKC2R1cmF0aW9uX21zGAQgASgESAGIAQFCCwoJX2FnZW50X2lkQg4KDF9kdXJhdGlvbl9tcyIaCglUYXNrRXJyb3ISDQoFZXJyb3IYASABKAkiZgoKVGFza1Jlc3VsdBIoCgdzdWNjZXNzGAEgASgLMhUuYWdlbnQudjEuVGFza1N1Y2Nlc3NIABIkCgVlcnJvchgCIAEoCzITLmFnZW50LnYxLlRhc2tFcnJvckgAQggKBnJlc3VsdCJWCgxUYXNrVG9vbENhbGwSIAoEYXJncxgBIAEoCzISLmFnZW50LnYxLlRhc2tBcmdzEiQKBnJlc3VsdBgCIAEoCzIULmFnZW50LnYxLlRhc2tSZXN1bHQiTAoRVGFza1Rvb2xDYWxsRGVsdGESNwoSaW50ZXJhY3Rpb25fdXBkYXRlGAEgASgLMhsuYWdlbnQudjEuSW50ZXJhY3Rpb25VcGRhdGUihhQKCFRvb2xDYWxsEjIKD3NoZWxsX3Rvb2xfY2FsbBgBIAEoCzIXLmFnZW50LnYxLlNoZWxsVG9vbENhbGxIABI0ChBkZWxldGVfdG9vbF9jYWxsGAMgASgLMhguYWdlbnQudjEuRGVsZXRlVG9vbENhbGxIABIwCg5nbG9iX3Rvb2xfY2FsbBgEIAEoCzIWLmFnZW50LnYxLkdsb2JUb29sQ2FsbEgAEjAKDmdyZXBfdG9vbF9jYWxsGAUgASgLMhYuYWdlbnQudjEuR3JlcFRvb2xDYWxsSAASMAoOcmVhZF90b29sX2NhbGwYCCABKAsyFi5hZ2VudC52MS5SZWFkVG9vbENhbGxIABI/ChZ1cGRhdGVfdG9kb3NfdG9vbF9jYWxsGAkgASgLMh0uYWdlbnQudjEuVXBkYXRlVG9kb3NUb29sQ2FsbEgAEjsKFHJlYWRfdG9kb3NfdG9vbF9jYWxsGAogASgLMhsuYWdlbnQudjEuUmVhZFRvZG9zVG9vbENhbGxIABIwCg5lZGl0X3Rvb2xfY2FsbBgMIAEoCzIWLmFnZW50LnYxLkVkaXRUb29sQ2FsbEgAEiwKDGxzX3Rvb2xfY2FsbBgNIAEoCzIULmFnZW50LnYxLkxzVG9vbENhbGxIABI7ChRyZWFkX2xpbnRzX3Rvb2xfY2FsbBgOIAEoCzIbLmFnZW50LnYxLlJlYWRMaW50c1Rvb2xDYWxsSAASLgoNbWNwX3Rvb2xfY2FsbBgPIAEoCzIVLmFnZW50LnYxLk1jcFRvb2xDYWxsSAASOwoUc2VtX3NlYXJjaF90b29sX2NhbGwYECABKAsyGy5hZ2VudC52MS5TZW1TZWFyY2hUb29sQ2FsbEgAEj0KFWNyZWF0ZV9wbGFuX3Rvb2xfY2FsbBgRIAEoCzIcLmFnZW50LnYxLkNyZWF0ZVBsYW5Ub29sQ2FsbEgAEjsKFHdlYl9zZWFyY2hfdG9vbF9jYWxsGBIgASgLMhsuYWdlbnQudjEuV2ViU2VhcmNoVG9vbENhbGxIABIwCg50YXNrX3Rvb2xfY2FsbBgTIAEoCzIWLmFnZW50LnYxLlRhc2tUb29sQ2FsbEgAEkoKHGxpc3RfbWNwX3Jlc291cmNlc190b29sX2NhbGwYFCABKAsyIi5hZ2VudC52MS5MaXN0TWNwUmVzb3VyY2VzVG9vbENhbGxIABJIChtyZWFkX21jcF9yZXNvdXJjZV90b29sX2NhbGwYFSABKAsyIS5hZ2VudC52MS5SZWFkTWNwUmVzb3VyY2VUb29sQ2FsbEgAEkYKGmFwcGx5X2FnZW50X2RpZmZfdG9vbF9jYWxsGBYgASgLMiAuYWdlbnQudjEuQXBwbHlBZ2VudERpZmZUb29sQ2FsbEgAEj8KFmFza19xdWVzdGlvbl90b29sX2NhbGwYFyABKAsyHS5hZ2VudC52MS5Bc2tRdWVzdGlvblRvb2xDYWxsSAASMgoPZmV0Y2hfdG9vbF9jYWxsGBggASgLMhcuYWdlbnQudjEuRmV0Y2hUb29sQ2FsbEgAEj0KFXN3aXRjaF9tb2RlX3Rvb2xfY2FsbBgZIAEoCzIcLmFnZW50LnYxLlN3aXRjaE1vZGVUb29sQ2FsbEgAEjsKFGV4YV9zZWFyY2hfdG9vbF9jYWxsGBogASgLMhsuYWdlbnQudjEuRXhhU2VhcmNoVG9vbENhbGxIABI5ChNleGFfZmV0Y2hfdG9vbF9jYWxsGBsgASgLMhouYWdlbnQudjEuRXhhRmV0Y2hUb29sQ2FsbEgAEkMKGGdlbmVyYXRlX2ltYWdlX3Rvb2xfY2FsbBgcIAEoCzIfLmFnZW50LnYxLkdlbmVyYXRlSW1hZ2VUb29sQ2FsbEgAEkEKF3JlY29yZF9zY3JlZW5fdG9vbF9jYWxsGB0gASgLMh4uYWdlbnQudjEuUmVjb3JkU2NyZWVuVG9vbENhbGxIABI/ChZjb21wdXRlcl91c2VfdG9vbF9jYWxsGB4gASgLMh0uYWdlbnQudjEuQ29tcHV0ZXJVc2VUb29sQ2FsbEgAEkgKG3dyaXRlX3NoZWxsX3N0ZGluX3Rvb2xfY2FsbBgfIAEoCzIhLmFnZW50LnYxLldyaXRlU2hlbGxTdGRpblRvb2xDYWxsSAASNgoRcmVmbGVjdF90b29sX2NhbGwYICABKAsyGS5hZ2VudC52MS5SZWZsZWN0VG9vbENhbGxIABJOCh5zZXR1cF92bV9lbnZpcm9ubWVudF90b29sX2NhbGwYISABKAsyJC5hZ2VudC52MS5TZXR1cFZtRW52aXJvbm1lbnRUb29sQ2FsbEgAEjoKE3RydW5jYXRlZF90b29sX2NhbGwYIiABKAsyGy5hZ2VudC52MS5UcnVuY2F0ZWRUb29sQ2FsbEgAElAKH3N0YXJ0X2dyaW5kX2V4ZWN1dGlvbl90b29sX2NhbGwYIyABKAsyJS5hZ2VudC52MS5TdGFydEdyaW5kRXhlY3V0aW9uVG9vbENhbGxIABJOCh5zdGFydF9ncmluZF9wbGFubmluZ190b29sX2NhbGwYJCABKAsyJC5hZ2VudC52MS5TdGFydEdyaW5kUGxhbm5pbmdUb29sQ2FsbEgAEjUKEXBpX3JlYWRfdG9vbF9jYWxsGD0gASgLMhguYWdlbnQudjEuUGlSZWFkVG9vbENhbGxIABI1ChFwaV9iYXNoX3Rvb2xfY2FsbBg+IAEoCzIYLmFnZW50LnYxLlBpQmFzaFRvb2xDYWxsSAASNQoRcGlfZWRpdF90b29sX2NhbGwYPyABKAsyGC5hZ2VudC52MS5QaUVkaXRUb29sQ2FsbEgAEjcKEnBpX3dyaXRlX3Rvb2xfY2FsbBhAIAEoCzIZLmFnZW50LnYxLlBpV3JpdGVUb29sQ2FsbEgAEjUKEXBpX2dyZXBfdG9vbF9jYWxsGEEgASgLMhguYWdlbnQudjEuUGlHcmVwVG9vbENhbGxIABI1ChFwaV9maW5kX3Rvb2xfY2FsbBhCIAEoCzIYLmFnZW50LnYxLlBpRmluZFRvb2xDYWxsSAASMQoPcGlfbHNfdG9vbF9jYWxsGEMgASgLMhYuYWdlbnQudjEuUGlMc1Rvb2xDYWxsSAASPQoVY29ubmVjdF9zY21fdG9vbF9jYWxsGEQgASgLMhwuYWdlbnQudjEuQ29ubmVjdFNjbVRvb2xDYWxsSAASTwoec2VhcmNoX2NvbnZlcnNhdGlvbnNfdG9vbF9jYWxsGEUgASgLMiUuYWdlbnQudjEuU2VhcmNoQ29udmVyc2F0aW9uc1Rvb2xDYWxsSAASGQoMdG9vbF9jYWxsX2lkGDkgASgJSAGIAQFCBgoEdG9vbEIPCg1fdG9vbF9jYWxsX2lkIhcKFVRydW5jYXRlZFRvb2xDYWxsQXJncyIaChhUcnVuY2F0ZWRUb29sQ2FsbFN1Y2Nlc3MiJwoWVHJ1bmNhdGVkVG9vbENhbGxFcnJvchINCgVlcnJvchgBIAEoCSKNAQoXVHJ1bmNhdGVkVG9vbENhbGxSZXN1bHQSNQoHc3VjY2VzcxgBIAEoCzIiLmFnZW50LnYxLlRydW5jYXRlZFRvb2xDYWxsU3VjY2Vzc0gAEjEKBWVycm9yGAIgASgLMiAuYWdlbnQudjEuVHJ1bmNhdGVkVG9vbENhbGxFcnJvckgAQggKBnJlc3VsdCKUAQoRVHJ1bmNhdGVkVG9vbENhbGwSHQoVb3JpZ2luYWxfc3RlcF9ibG9iX2lkGAEgASgMEi0KBGFyZ3MYAiABKAsyHy5hZ2VudC52MS5UcnVuY2F0ZWRUb29sQ2FsbEFyZ3MSMQoGcmVzdWx0GAMgASgLMiEuYWdlbnQudjEuVHJ1bmNhdGVkVG9vbENhbGxSZXN1bHQi0QEKDVRvb2xDYWxsRGVsdGESPQoVc2hlbGxfdG9vbF9jYWxsX2RlbHRhGAEgASgLMhwuYWdlbnQudjEuU2hlbGxUb29sQ2FsbERlbHRhSAASOwoUdGFza190b29sX2NhbGxfZGVsdGEYAiABKAsyGy5hZ2VudC52MS5UYXNrVG9vbENhbGxEZWx0YUgAEjsKFGVkaXRfdG9vbF9jYWxsX2RlbHRhGAMgASgLMhsuYWdlbnQudjEuRWRpdFRvb2xDYWxsRGVsdGFIAEIHCgVkZWx0YSK2AQoQQ29udmVyc2F0aW9uU3RlcBI3ChFhc3Npc3RhbnRfbWVzc2FnZRgBIAEoCzIaLmFnZW50LnYxLkFzc2lzdGFudE1lc3NhZ2VIABInCgl0b29sX2NhbGwYAiABKAsyEi5hZ2VudC52MS5Ub29sQ2FsbEgAEjUKEHRoaW5raW5nX21lc3NhZ2UYAyABKAsyGS5hZ2VudC52MS5UaGlua2luZ01lc3NhZ2VIAEIJCgdtZXNzYWdlIoEEChJDb252ZXJzYXRpb25BY3Rpb24SOgoTdXNlcl9tZXNzYWdlX2FjdGlvbhgBIAEoCzIbLmFnZW50LnYxLlVzZXJNZXNzYWdlQWN0aW9uSAASLwoNcmVzdW1lX2FjdGlvbhgCIAEoCzIWLmFnZW50LnYxLlJlc3VtZUFjdGlvbkgAEi8KDWNhbmNlbF9hY3Rpb24YAyABKAsyFi5hZ2VudC52MS5DYW5jZWxBY3Rpb25IABI1ChBzdW1tYXJpemVfYWN0aW9uGAQgASgLMhkuYWdlbnQudjEuU3VtbWFyaXplQWN0aW9uSAASPAoUc2hlbGxfY29tbWFuZF9hY3Rpb24YBSABKAsyHC5hZ2VudC52MS5TaGVsbENvbW1hbmRBY3Rpb25IABI2ChFzdGFydF9wbGFuX2FjdGlvbhgGIAEoCzIZLmFnZW50LnYxLlN0YXJ0UGxhbkFjdGlvbkgAEjoKE2V4ZWN1dGVfcGxhbl9hY3Rpb24YByABKAsyGy5hZ2VudC52MS5FeGVjdXRlUGxhbkFjdGlvbkgAEloKJGFzeW5jX2Fza19xdWVzdGlvbl9jb21wbGV0aW9uX2FjdGlvbhgIIAEoCzIqLmFnZW50LnYxLkFzeW5jQXNrUXVlc3Rpb25Db21wbGV0aW9uQWN0aW9uSABCCAoGYWN0aW9uIr8BChFVc2VyTWVzc2FnZUFjdGlvbhIrCgx1c2VyX21lc3NhZ2UYASABKAsyFS5hZ2VudC52MS5Vc2VyTWVzc2FnZRIxCg9yZXF1ZXN0X2NvbnRleHQYAiABKAsyGC5hZ2VudC52MS5SZXF1ZXN0Q29udGV4dBIpChxzZW5kX3RvX2ludGVyYWN0aW9uX2xpc3RlbmVyGAMgASgISACIAQFCHwodX3NlbmRfdG9faW50ZXJhY3Rpb25fbGlzdGVuZXIiDgoMQ2FuY2VsQWN0aW9uIkEKDFJlc3VtZUFjdGlvbhIxCg9yZXF1ZXN0X2NvbnRleHQYAiABKAsyGC5hZ2VudC52MS5SZXF1ZXN0Q29udGV4dCKgAQogQXN5bmNBc2tRdWVzdGlvbkNvbXBsZXRpb25BY3Rpb24SHQoVb3JpZ2luYWxfdG9vbF9jYWxsX2lkGAEgASgJEjAKDW9yaWdpbmFsX2FyZ3MYAiABKAsyGS5hZ2VudC52MS5Bc2tRdWVzdGlvbkFyZ3MSKwoGcmVzdWx0GAMgASgLMhsuYWdlbnQudjEuQXNrUXVlc3Rpb25SZXN1bHQiEQoPU3VtbWFyaXplQWN0aW9uIlQKElNoZWxsQ29tbWFuZEFjdGlvbhItCg1zaGVsbF9jb21tYW5kGAEgASgLMhYuYWdlbnQudjEuU2hlbGxDb21tYW5kEg8KB2V4ZWNfaWQYAiABKAkiggEKD1N0YXJ0UGxhbkFjdGlvbhIrCgx1c2VyX21lc3NhZ2UYASABKAsyFS5hZ2VudC52MS5Vc2VyTWVzc2FnZRIxCg9yZXF1ZXN0X2NvbnRleHQYAiABKAsyGC5hZ2VudC52MS5SZXF1ZXN0Q29udGV4dBIPCgdpc19zcGVjGAMgASgIIuIBChFFeGVjdXRlUGxhbkFjdGlvbhIxCg9yZXF1ZXN0X2NvbnRleHQYASABKAsyGC5hZ2VudC52MS5SZXF1ZXN0Q29udGV4dBItCgRwbGFuGAIgASgLMhouYWdlbnQudjEuQ29udmVyc2F0aW9uUGxhbkgAiAEBEhoKDXBsYW5fZmlsZV91cmkYAyABKAlIAYgBARIeChFwbGFuX2ZpbGVfY29udGVudBgEIAEoCUgCiAEBQgcKBV9wbGFuQhAKDl9wbGFuX2ZpbGVfdXJpQhQKEl9wbGFuX2ZpbGVfY29udGVudCLoAgoLVXNlck1lc3NhZ2USDAoEdGV4dBgBIAEoCRISCgptZXNzYWdlX2lkGAIgASgJEjgKEHNlbGVjdGVkX2NvbnRleHQYAyABKAsyGS5hZ2VudC52MS5TZWxlY3RlZENvbnRleHRIAIgBARIMCgRtb2RlGAQgASgFEh0KEGlzX3NpbXVsYXRlZF9tc2cYBSABKAhIAYgBARIfChJiZXN0X29mX25fZ3JvdXBfaWQYBiABKAlIAogBARIoCht0cnlfdXNlX2Jlc3Rfb2Zfbl9wcm9tb3Rpb24YByABKAhIA4gBARIWCglyaWNoX3RleHQYCCABKAlIBIgBAUITChFfc2VsZWN0ZWRfY29udGV4dEITChFfaXNfc2ltdWxhdGVkX21zZ0IVChNfYmVzdF9vZl9uX2dyb3VwX2lkQh4KHF90cnlfdXNlX2Jlc3Rfb2Zfbl9wcm9tb3Rpb25CDAoKX3JpY2hfdGV4dCIgChBBc3Npc3RhbnRNZXNzYWdlEgwKBHRleHQYASABKAkiNAoPVGhpbmtpbmdNZXNzYWdlEgwKBHRleHQYASABKAkSEwoLZHVyYXRpb25fbXMYAiABKA0iHwoMU2hlbGxDb21tYW5kEg8KB2NvbW1hbmQYASABKAkiQAoLU2hlbGxPdXRwdXQSDgoGc3Rkb3V0GAEgASgJEg4KBnN0ZGVychgCIAEoCRIRCglleGl0X2NvZGUYAyABKAUiogEKEENvbnZlcnNhdGlvblR1cm4SQgoXYWdlbnRfY29udmVyc2F0aW9uX3R1cm4YASABKAsyHy5hZ2VudC52MS5BZ2VudENvbnZlcnNhdGlvblR1cm5IABJCChdzaGVsbF9jb252ZXJzYXRpb25fdHVybhgCIAEoCzIfLmFnZW50LnYxLlNoZWxsQ29udmVyc2F0aW9uVHVybkgAQgYKBHR1cm4iIAoQQ29udmVyc2F0aW9uUGxhbhIMCgRwbGFuGAEgASgJIr0BChlDb252ZXJzYXRpb25UdXJuU3RydWN0dXJlEksKF2FnZW50X2NvbnZlcnNhdGlvbl90dXJuGAEgASgLMiguYWdlbnQudjEuQWdlbnRDb252ZXJzYXRpb25UdXJuU3RydWN0dXJlSAASSwoXc2hlbGxfY29udmVyc2F0aW9uX3R1cm4YAiABKAsyKC5hZ2VudC52MS5TaGVsbENvbnZlcnNhdGlvblR1cm5TdHJ1Y3R1cmVIAEIGCgR0dXJuIpcBChVBZ2VudENvbnZlcnNhdGlvblR1cm4SKwoMdXNlcl9tZXNzYWdlGAEgASgLMhUuYWdlbnQudjEuVXNlck1lc3NhZ2USKQoFc3RlcHMYAiADKAsyGi5hZ2VudC52MS5Db252ZXJzYXRpb25TdGVwEhcKCnJlcXVlc3RfaWQYAyABKAlIAIgBAUINCgtfcmVxdWVzdF9pZCJtCh5BZ2VudENvbnZlcnNhdGlvblR1cm5TdHJ1Y3R1cmUSFAoMdXNlcl9tZXNzYWdlGAEgASgMEg0KBXN0ZXBzGAIgAygMEhcKCnJlcXVlc3RfaWQYAyABKAlIAIgBAUINCgtfcmVxdWVzdF9pZCJzChVTaGVsbENvbnZlcnNhdGlvblR1cm4SLQoNc2hlbGxfY29tbWFuZBgBIAEoCzIWLmFnZW50LnYxLlNoZWxsQ29tbWFuZBIrCgxzaGVsbF9vdXRwdXQYAiABKAsyFS5hZ2VudC52MS5TaGVsbE91dHB1dCJNCh5TaGVsbENvbnZlcnNhdGlvblR1cm5TdHJ1Y3R1cmUSFQoNc2hlbGxfY29tbWFuZBgBIAEoDBIUCgxzaGVsbF9vdXRwdXQYAiABKAwiJgoTQ29udmVyc2F0aW9uU3VtbWFyeRIPCgdzdW1tYXJ5GAEgASgJIngKGkNvbnZlcnNhdGlvblN1bW1hcnlBcmNoaXZlEhsKE3N1bW1hcml6ZWRfbWVzc2FnZXMYASADKAwSDwoHc3VtbWFyeRgCIAEoCRITCgt3aW5kb3dfdGFpbBgDIAEoDRIXCg9zdW1tYXJ5X21lc3NhZ2UYBCABKAwiQwoYQ29udmVyc2F0aW9uVG9rZW5EZXRhaWxzEhMKC3VzZWRfdG9rZW5zGAEgASgNEhIKCm1heF90b2tlbnMYAiABKA0iXwoJRmlsZVN0YXRlEhQKB2NvbnRlbnQYASABKAlIAIgBARIcCg9pbml0aWFsX2NvbnRlbnQYAiABKAlIAYgBAUIKCghfY29udGVudEISChBfaW5pdGlhbF9jb250ZW50ImgKEkZpbGVTdGF0ZVN0cnVjdHVyZRIUCgdjb250ZW50GAEgASgMSACIAQESHAoPaW5pdGlhbF9jb250ZW50GAIgASgMSAGIAQFCCgoIX2NvbnRlbnRCEgoQX2luaXRpYWxfY29udGVudCI3CgpTdGVwVGltaW5nEhMKC2R1cmF0aW9uX21zGAEgASgEEhQKDHRpbWVzdGFtcF9tcxgCIAEoBCL2BAoRQ29udmVyc2F0aW9uU3RhdGUSIQoZcm9vdF9wcm9tcHRfbWVzc2FnZXNfanNvbhgBIAMoCRIpCgV0dXJucxgIIAMoCzIaLmFnZW50LnYxLkNvbnZlcnNhdGlvblR1cm4SIQoFdG9kb3MYAyADKAsyEi5hZ2VudC52MS5Ub2RvSXRlbRIaChJwZW5kaW5nX3Rvb2xfY2FsbHMYBCADKAkSOQoNdG9rZW5fZGV0YWlscxgFIAEoCzIiLmFnZW50LnYxLkNvbnZlcnNhdGlvblRva2VuRGV0YWlscxIzCgdzdW1tYXJ5GAYgASgLMh0uYWdlbnQudjEuQ29udmVyc2F0aW9uU3VtbWFyeUgAiAEBEi0KBHBsYW4YByABKAsyGi5hZ2VudC52MS5Db252ZXJzYXRpb25QbGFuSAGIAQESQgoPc3VtbWFyeV9hcmNoaXZlGAkgASgLMiQuYWdlbnQudjEuQ29udmVyc2F0aW9uU3VtbWFyeUFyY2hpdmVIAogBARJACgtmaWxlX3N0YXRlcxgKIAMoCzIrLmFnZW50LnYxLkNvbnZlcnNhdGlvblN0YXRlLkZpbGVTdGF0ZXNFbnRyeRI+ChBzdW1tYXJ5X2FyY2hpdmVzGAsgAygLMiQuYWdlbnQudjEuQ29udmVyc2F0aW9uU3VtbWFyeUFyY2hpdmUaRgoPRmlsZVN0YXRlc0VudHJ5EgsKA2tleRgBIAEoCRIiCgV2YWx1ZRgCIAEoCzITLmFnZW50LnYxLkZpbGVTdGF0ZToCOAFCCgoIX3N1bW1hcnlCBwoFX3BsYW5CEgoQX3N1bW1hcnlfYXJjaGl2ZSLHAQoWU3ViYWdlbnRQZXJzaXN0ZWRTdGF0ZRJAChJjb252ZXJzYXRpb25fc3RhdGUYASABKAsyJC5hZ2VudC52MS5Db252ZXJzYXRpb25TdGF0ZVN0cnVjdHVyZRIcChRjcmVhdGVkX3RpbWVzdGFtcF9tcxgCIAEoBBIeChZsYXN0X3VzZWRfdGltZXN0YW1wX21zGAMgASgEEi0KDXN1YmFnZW50X3R5cGUYBCABKAsyFi5hZ2VudC52MS5TdWJhZ2VudFR5cGUitwcKGkNvbnZlcnNhdGlvblN0YXRlU3RydWN0dXJlEhEKCXR1cm5zX29sZBgCIAMoDBIhChlyb290X3Byb21wdF9tZXNzYWdlc19qc29uGAEgAygMEg0KBXR1cm5zGAggAygMEg0KBXRvZG9zGAMgAygMEhoKEnBlbmRpbmdfdG9vbF9jYWxscxgEIAMoCRI5Cg10b2tlbl9kZXRhaWxzGAUgASgLMiIuYWdlbnQudjEuQ29udmVyc2F0aW9uVG9rZW5EZXRhaWxzEhQKB3N1bW1hcnkYBiABKAxIAIgBARIRCgRwbGFuGAcgASgMSAGIAQESHwoXcHJldmlvdXNfd29ya3NwYWNlX3VyaXMYCSADKAkSEQoEbW9kZRgKIAEoBUgCiAEBEhwKD3N1bW1hcnlfYXJjaGl2ZRgLIAEoDEgDiAEBEkkKC2ZpbGVfc3RhdGVzGAwgAygLMjQuYWdlbnQudjEuQ29udmVyc2F0aW9uU3RhdGVTdHJ1Y3R1cmUuRmlsZVN0YXRlc0VudHJ5Ek4KDmZpbGVfc3RhdGVzX3YyGA8gAygLMjYuYWdlbnQudjEuQ29udmVyc2F0aW9uU3RhdGVTdHJ1Y3R1cmUuRmlsZVN0YXRlc1YyRW50cnkSGAoQc3VtbWFyeV9hcmNoaXZlcxgNIAMoDBIqCgx0dXJuX3RpbWluZ3MYDiADKAsyFC5hZ2VudC52MS5TdGVwVGltaW5nElEKD3N1YmFnZW50X3N0YXRlcxgQIAMoCzI4LmFnZW50LnYxLkNvbnZlcnNhdGlvblN0YXRlU3RydWN0dXJlLlN1YmFnZW50U3RhdGVzRW50cnkSGgoSc2VsZl9zdW1tYXJ5X2NvdW50GBEgASgNEhIKCnJlYWRfcGF0aHMYEiADKAkaMQoPRmlsZVN0YXRlc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoDDoCOAEaUQoRRmlsZVN0YXRlc1YyRW50cnkSCwoDa2V5GAEgASgJEisKBXZhbHVlGAIgASgLMhwuYWdlbnQudjEuRmlsZVN0YXRlU3RydWN0dXJlOgI4ARpXChNTdWJhZ2VudFN0YXRlc0VudHJ5EgsKA2tleRgBIAEoCRIvCgV2YWx1ZRgCIAEoCzIgLmFnZW50LnYxLlN1YmFnZW50UGVyc2lzdGVkU3RhdGU6AjgBQgoKCF9zdW1tYXJ5QgcKBV9wbGFuQgcKBV9tb2RlQhIKEF9zdW1tYXJ5X2FyY2hpdmUiEQoPVGhpbmtpbmdEZXRhaWxzIkgKEUFwaUtleUNyZWRlbnRpYWxzEg8KB2FwaV9rZXkYASABKAkSFQoIYmFzZV91cmwYAiABKAlIAIgBAUILCglfYmFzZV91cmwiSQoQQXp1cmVDcmVkZW50aWFscxIPCgdhcGlfa2V5GAEgASgJEhAKCGJhc2VfdXJsGAIgASgJEhIKCmRlcGxveW1lbnQYAyABKAkiegoSQmVkcm9ja0NyZWRlbnRpYWxzEhIKCmFjY2Vzc19rZXkYASABKAkSEgoKc2VjcmV0X2tleRgCIAEoCRIOCgZyZWdpb24YAyABKAkSGgoNc2Vzc2lvbl90b2tlbhgEIAEoCUgAiAEBQhAKDl9zZXNzaW9uX3Rva2VuIrEDCgxNb2RlbERldGFpbHMSEAoIbW9kZWxfaWQYASABKAkSGAoQZGlzcGxheV9tb2RlbF9pZBgDIAEoCRIUCgxkaXNwbGF5X25hbWUYBCABKAkSGgoSZGlzcGxheV9uYW1lX3Nob3J0GAUgASgJEg8KB2FsaWFzZXMYBiADKAkSOAoQdGhpbmtpbmdfZGV0YWlscxgCIAEoCzIZLmFnZW50LnYxLlRoaW5raW5nRGV0YWlsc0gBiAEBEhUKCG1heF9tb2RlGAcgASgISAKIAQESOgoTYXBpX2tleV9jcmVkZW50aWFscxgIIAEoCzIbLmFnZW50LnYxLkFwaUtleUNyZWRlbnRpYWxzSAASNwoRYXp1cmVfY3JlZGVudGlhbHMYCSABKAsyGi5hZ2VudC52MS5BenVyZUNyZWRlbnRpYWxzSAASOwoTYmVkcm9ja19jcmVkZW50aWFscxgKIAEoCzIcLmFnZW50LnYxLkJlZHJvY2tDcmVkZW50aWFsc0gAQg0KC2NyZWRlbnRpYWxzQhMKEV90aGlua2luZ19kZXRhaWxzQgsKCV9tYXhfbW9kZSK3AgoOUmVxdWVzdGVkTW9kZWwSEAoIbW9kZWxfaWQYASABKAkSEAoIbWF4X21vZGUYAiABKAgSQAoKcGFyYW1ldGVycxgDIAMoCzIsLmFnZW50LnYxLlJlcXVlc3RlZE1vZGVsX01vZGVsUGFyYW1ldGVyYnl0ZXMSOgoTYXBpX2tleV9jcmVkZW50aWFscxgEIAEoCzIbLmFnZW50LnYxLkFwaUtleUNyZWRlbnRpYWxzSAASNwoRYXp1cmVfY3JlZGVudGlhbHMYBSABKAsyGi5hZ2VudC52MS5BenVyZUNyZWRlbnRpYWxzSAASOwoTYmVkcm9ja19jcmVkZW50aWFscxgGIAEoCzIcLmFnZW50LnYxLkJlZHJvY2tDcmVkZW50aWFsc0gAQg0KC2NyZWRlbnRpYWxzIj8KIlJlcXVlc3RlZE1vZGVsX01vZGVsUGFyYW1ldGVyYnl0ZXMSCgoCaWQYASABKAkSDQoFdmFsdWUYAiABKAkiuQQKD0FnZW50UnVuUmVxdWVzdBJAChJjb252ZXJzYXRpb25fc3RhdGUYASABKAsyJC5hZ2VudC52MS5Db252ZXJzYXRpb25TdGF0ZVN0cnVjdHVyZRIsCgZhY3Rpb24YAiABKAsyHC5hZ2VudC52MS5Db252ZXJzYXRpb25BY3Rpb24SLQoNbW9kZWxfZGV0YWlscxgDIAEoCzIWLmFnZW50LnYxLk1vZGVsRGV0YWlscxI2Cg9yZXF1ZXN0ZWRfbW9kZWwYCSABKAsyGC5hZ2VudC52MS5SZXF1ZXN0ZWRNb2RlbEgAiAEBEiUKCW1jcF90b29scxgEIAEoCzISLmFnZW50LnYxLk1jcFRvb2xzEhwKD2NvbnZlcnNhdGlvbl9pZBgFIAEoCUgBiAEBEkQKF21jcF9maWxlX3N5c3RlbV9vcHRpb25zGAYgASgLMh4uYWdlbnQudjEuTWNwRmlsZVN5c3RlbU9wdGlvbnNIAogBARIyCg1za2lsbF9vcHRpb25zGAcgASgLMhYuYWdlbnQudjEuU2tpbGxPcHRpb25zSAOIAQESIQoUY3VzdG9tX3N5c3RlbV9wcm9tcHQYCCABKAlIBIgBAUISChBfcmVxdWVzdGVkX21vZGVsQhIKEF9jb252ZXJzYXRpb25faWRCGgoYX21jcF9maWxlX3N5c3RlbV9vcHRpb25zQhAKDl9za2lsbF9vcHRpb25zQhcKFV9jdXN0b21fc3lzdGVtX3Byb21wdCIfCg9UZXh0RGVsdGFVcGRhdGUSDAoEdGV4dBgBIAEoCSJmChVUb29sQ2FsbFN0YXJ0ZWRVcGRhdGUSDwoHY2FsbF9pZBgBIAEoCRIlCgl0b29sX2NhbGwYAiABKAsyEi5hZ2VudC52MS5Ub29sQ2FsbBIVCg1tb2RlbF9jYWxsX2lkGAMgASgJImgKF1Rvb2xDYWxsQ29tcGxldGVkVXBkYXRlEg8KB2NhbGxfaWQYASABKAkSJQoJdG9vbF9jYWxsGAIgASgLMhIuYWdlbnQudjEuVG9vbENhbGwSFQoNbW9kZWxfY2FsbF9pZBgDIAEoCSJvChNUb29sQ2FsbERlbHRhVXBkYXRlEg8KB2NhbGxfaWQYASABKAkSMAoPdG9vbF9jYWxsX2RlbHRhGAIgASgLMhcuYWdlbnQudjEuVG9vbENhbGxEZWx0YRIVCg1tb2RlbF9jYWxsX2lkGAMgASgJIn8KFVBhcnRpYWxUb29sQ2FsbFVwZGF0ZRIPCgdjYWxsX2lkGAEgASgJEiUKCXRvb2xfY2FsbBgCIAEoCzISLmFnZW50LnYxLlRvb2xDYWxsEhcKD2FyZ3NfdGV4dF9kZWx0YRgDIAEoCRIVCg1tb2RlbF9jYWxsX2lkGAQgASgJIiMKE1RoaW5raW5nRGVsdGFVcGRhdGUSDAoEdGV4dBgBIAEoCSI3ChdUaGlua2luZ0NvbXBsZXRlZFVwZGF0ZRIcChR0aGlua2luZ19kdXJhdGlvbl9tcxgBIAEoBSIiChBUb2tlbkRlbHRhVXBkYXRlEg4KBnRva2VucxgBIAEoBSIgCg1TdW1tYXJ5VXBkYXRlEg8KB3N1bW1hcnkYASABKAkiFgoUU3VtbWFyeVN0YXJ0ZWRVcGRhdGUiEQoPSGVhcnRiZWF0VXBkYXRlIhgKFlN1bW1hcnlDb21wbGV0ZWRVcGRhdGUi1wEKFlNoZWxsT3V0cHV0RGVsdGFVcGRhdGUSLQoGc3Rkb3V0GAEgASgLMhsuYWdlbnQudjEuU2hlbGxTdHJlYW1TdGRvdXRIABItCgZzdGRlcnIYAiABKAsyGy5hZ2VudC52MS5TaGVsbFN0cmVhbVN0ZGVyckgAEikKBGV4aXQYAyABKAsyGS5hZ2VudC52MS5TaGVsbFN0cmVhbUV4aXRIABIrCgVzdGFydBgEIAEoCzIaLmFnZW50LnYxLlNoZWxsU3RyZWFtU3RhcnRIAEIHCgVldmVudCIRCg9UdXJuRW5kZWRVcGRhdGUiSAoZVXNlck1lc3NhZ2VBcHBlbmRlZFVwZGF0ZRIrCgx1c2VyX21lc3NhZ2UYASABKAsyFS5hZ2VudC52MS5Vc2VyTWVzc2FnZSIkChFTdGVwU3RhcnRlZFVwZGF0ZRIPCgdzdGVwX2lkGAEgASgEIkAKE1N0ZXBDb21wbGV0ZWRVcGRhdGUSDwoHc3RlcF9pZBgBIAEoBBIYChBzdGVwX2R1cmF0aW9uX21zGAIgASgDIu8HChFJbnRlcmFjdGlvblVwZGF0ZRIvCgp0ZXh0X2RlbHRhGAEgASgLMhkuYWdlbnQudjEuVGV4dERlbHRhVXBkYXRlSAASPAoRcGFydGlhbF90b29sX2NhbGwYByABKAsyHy5hZ2VudC52MS5QYXJ0aWFsVG9vbENhbGxVcGRhdGVIABI4Cg90b29sX2NhbGxfZGVsdGEYDyABKAsyHS5hZ2VudC52MS5Ub29sQ2FsbERlbHRhVXBkYXRlSAASPAoRdG9vbF9jYWxsX3N0YXJ0ZWQYAiABKAsyHy5hZ2VudC52MS5Ub29sQ2FsbFN0YXJ0ZWRVcGRhdGVIABJAChN0b29sX2NhbGxfY29tcGxldGVkGAMgASgLMiEuYWdlbnQudjEuVG9vbENhbGxDb21wbGV0ZWRVcGRhdGVIABI3Cg50aGlua2luZ19kZWx0YRgEIAEoCzIdLmFnZW50LnYxLlRoaW5raW5nRGVsdGFVcGRhdGVIABI/ChJ0aGlua2luZ19jb21wbGV0ZWQYBSABKAsyIS5hZ2VudC52MS5UaGlua2luZ0NvbXBsZXRlZFVwZGF0ZUgAEkQKFXVzZXJfbWVzc2FnZV9hcHBlbmRlZBgGIAEoCzIjLmFnZW50LnYxLlVzZXJNZXNzYWdlQXBwZW5kZWRVcGRhdGVIABIxCgt0b2tlbl9kZWx0YRgIIAEoCzIaLmFnZW50LnYxLlRva2VuRGVsdGFVcGRhdGVIABIqCgdzdW1tYXJ5GAkgASgLMhcuYWdlbnQudjEuU3VtbWFyeVVwZGF0ZUgAEjkKD3N1bW1hcnlfc3RhcnRlZBgKIAEoCzIeLmFnZW50LnYxLlN1bW1hcnlTdGFydGVkVXBkYXRlSAASPQoRc3VtbWFyeV9jb21wbGV0ZWQYCyABKAsyIC5hZ2VudC52MS5TdW1tYXJ5Q29tcGxldGVkVXBkYXRlSAASPgoSc2hlbGxfb3V0cHV0X2RlbHRhGAwgASgLMiAuYWdlbnQudjEuU2hlbGxPdXRwdXREZWx0YVVwZGF0ZUgAEi4KCWhlYXJ0YmVhdBgNIAEoCzIZLmFnZW50LnYxLkhlYXJ0YmVhdFVwZGF0ZUgAEi8KCnR1cm5fZW5kZWQYDiABKAsyGS5hZ2VudC52MS5UdXJuRW5kZWRVcGRhdGVIABIzCgxzdGVwX3N0YXJ0ZWQYECABKAsyGy5hZ2VudC52MS5TdGVwU3RhcnRlZFVwZGF0ZUgAEjcKDnN0ZXBfY29tcGxldGVkGBEgASgLMh0uYWdlbnQudjEuU3RlcENvbXBsZXRlZFVwZGF0ZUgAQgkKB21lc3NhZ2UimgQKEEludGVyYWN0aW9uUXVlcnkSCgoCaWQYASABKA0SQwoYd2ViX3NlYXJjaF9yZXF1ZXN0X3F1ZXJ5GAIgASgLMh8uYWdlbnQudjEuV2ViU2VhcmNoUmVxdWVzdFF1ZXJ5SAASTwoeYXNrX3F1ZXN0aW9uX2ludGVyYWN0aW9uX3F1ZXJ5GAMgASgLMiUuYWdlbnQudjEuQXNrUXVlc3Rpb25JbnRlcmFjdGlvblF1ZXJ5SAASRQoZc3dpdGNoX21vZGVfcmVxdWVzdF9xdWVyeRgEIAEoCzIgLmFnZW50LnYxLlN3aXRjaE1vZGVSZXF1ZXN0UXVlcnlIABJDChhleGFfc2VhcmNoX3JlcXVlc3RfcXVlcnkYBSABKAsyHy5hZ2VudC52MS5FeGFTZWFyY2hSZXF1ZXN0UXVlcnlIABJBChdleGFfZmV0Y2hfcmVxdWVzdF9xdWVyeRgGIAEoCzIeLmFnZW50LnYxLkV4YUZldGNoUmVxdWVzdFF1ZXJ5SAASRQoZY3JlYXRlX3BsYW5fcmVxdWVzdF9xdWVyeRgHIAEoCzIgLmFnZW50LnYxLkNyZWF0ZVBsYW5SZXF1ZXN0UXVlcnlIABJFChlzZXR1cF92bV9lbnZpcm9ubWVudF9hcmdzGAggASgLMiAuYWdlbnQudjEuU2V0dXBWbUVudmlyb25tZW50QXJnc0gAQgcKBXF1ZXJ5IsYEChNJbnRlcmFjdGlvblJlc3BvbnNlEgoKAmlkGAEgASgNEkkKG3dlYl9zZWFyY2hfcmVxdWVzdF9yZXNwb25zZRgCIAEoCzIiLmFnZW50LnYxLldlYlNlYXJjaFJlcXVlc3RSZXNwb25zZUgAElUKIWFza19xdWVzdGlvbl9pbnRlcmFjdGlvbl9yZXNwb25zZRgDIAEoCzIoLmFnZW50LnYxLkFza1F1ZXN0aW9uSW50ZXJhY3Rpb25SZXNwb25zZUgAEksKHHN3aXRjaF9tb2RlX3JlcXVlc3RfcmVzcG9uc2UYBCABKAsyIy5hZ2VudC52MS5Td2l0Y2hNb2RlUmVxdWVzdFJlc3BvbnNlSAASSQobZXhhX3NlYXJjaF9yZXF1ZXN0X3Jlc3BvbnNlGAUgASgLMiIuYWdlbnQudjEuRXhhU2VhcmNoUmVxdWVzdFJlc3BvbnNlSAASRwoaZXhhX2ZldGNoX3JlcXVlc3RfcmVzcG9uc2UYBiABKAsyIS5hZ2VudC52MS5FeGFGZXRjaFJlcXVlc3RSZXNwb25zZUgAEksKHGNyZWF0ZV9wbGFuX3JlcXVlc3RfcmVzcG9uc2UYByABKAsyIy5hZ2VudC52MS5DcmVhdGVQbGFuUmVxdWVzdFJlc3BvbnNlSAASSQobc2V0dXBfdm1fZW52aXJvbm1lbnRfcmVzdWx0GAggASgLMiIuYWdlbnQudjEuU2V0dXBWbUVudmlyb25tZW50UmVzdWx0SABCCAoGcmVzdWx0IlwKG0Fza1F1ZXN0aW9uSW50ZXJhY3Rpb25RdWVyeRInCgRhcmdzGAEgASgLMhkuYWdlbnQudjEuQXNrUXVlc3Rpb25BcmdzEhQKDHRvb2xfY2FsbF9pZBgCIAEoCSJNCh5Bc2tRdWVzdGlvbkludGVyYWN0aW9uUmVzcG9uc2USKwoGcmVzdWx0GAEgASgLMhsuYWdlbnQudjEuQXNrUXVlc3Rpb25SZXN1bHQiEQoPQ2xpZW50SGVhcnRiZWF0IsYECg5QcmV3YXJtUmVxdWVzdBItCg1tb2RlbF9kZXRhaWxzGAEgASgLMhYuYWdlbnQudjEuTW9kZWxEZXRhaWxzEjYKD3JlcXVlc3RlZF9tb2RlbBgJIAEoCzIYLmFnZW50LnYxLlJlcXVlc3RlZE1vZGVsSACIAQESHAoPY29udmVyc2F0aW9uX2lkGAIgASgJSAGIAQESQAoSY29udmVyc2F0aW9uX3N0YXRlGAMgASgLMiQuYWdlbnQudjEuQ29udmVyc2F0aW9uU3RhdGVTdHJ1Y3R1cmUSJQoJbWNwX3Rvb2xzGAQgASgLMhIuYWdlbnQudjEuTWNwVG9vbHMSRAoXbWNwX2ZpbGVfc3lzdGVtX29wdGlvbnMYBSABKAsyHi5hZ2VudC52MS5NY3BGaWxlU3lzdGVtT3B0aW9uc0gCiAEBEh8KEmJlc3Rfb2Zfbl9ncm91cF9pZBgGIAEoCUgDiAEBEigKG3RyeV91c2VfYmVzdF9vZl9uX3Byb21vdGlvbhgHIAEoCEgEiAEBEiEKFGN1c3RvbV9zeXN0ZW1fcHJvbXB0GAggASgJSAWIAQFCEgoQX3JlcXVlc3RlZF9tb2RlbEISChBfY29udmVyc2F0aW9uX2lkQhoKGF9tY3BfZmlsZV9zeXN0ZW1fb3B0aW9uc0IVChNfYmVzdF9vZl9uX2dyb3VwX2lkQh4KHF90cnlfdXNlX2Jlc3Rfb2Zfbl9wcm9tb3Rpb25CFwoVX2N1c3RvbV9zeXN0ZW1fcHJvbXB0Ih0KD0V4ZWNTZXJ2ZXJBYm9ydBIKCgJpZBgBIAEoDSJRChhFeGVjU2VydmVyQ29udHJvbE1lc3NhZ2USKgoFYWJvcnQYASABKAsyGS5hZ2VudC52MS5FeGVjU2VydmVyQWJvcnRIAEIJCgdtZXNzYWdlIvgDChJBZ2VudENsaWVudE1lc3NhZ2USMAoLcnVuX3JlcXVlc3QYASABKAsyGS5hZ2VudC52MS5BZ2VudFJ1blJlcXVlc3RIABI6ChNleGVjX2NsaWVudF9tZXNzYWdlGAIgASgLMhsuYWdlbnQudjEuRXhlY0NsaWVudE1lc3NhZ2VIABJJChtleGVjX2NsaWVudF9jb250cm9sX21lc3NhZ2UYBSABKAsyIi5hZ2VudC52MS5FeGVjQ2xpZW50Q29udHJvbE1lc3NhZ2VIABI2ChFrdl9jbGllbnRfbWVzc2FnZRgDIAEoCzIZLmFnZW50LnYxLkt2Q2xpZW50TWVzc2FnZUgAEjsKE2NvbnZlcnNhdGlvbl9hY3Rpb24YBCABKAsyHC5hZ2VudC52MS5Db252ZXJzYXRpb25BY3Rpb25IABI9ChRpbnRlcmFjdGlvbl9yZXNwb25zZRgGIAEoCzIdLmFnZW50LnYxLkludGVyYWN0aW9uUmVzcG9uc2VIABI1ChBjbGllbnRfaGVhcnRiZWF0GAcgASgLMhkuYWdlbnQudjEuQ2xpZW50SGVhcnRiZWF0SAASMwoPcHJld2FybV9yZXF1ZXN0GAggASgLMhguYWdlbnQudjEuUHJld2FybVJlcXVlc3RIAEIJCgdtZXNzYWdlIqIDChJBZ2VudFNlcnZlck1lc3NhZ2USOQoSaW50ZXJhY3Rpb25fdXBkYXRlGAEgASgLMhsuYWdlbnQudjEuSW50ZXJhY3Rpb25VcGRhdGVIABI6ChNleGVjX3NlcnZlcl9tZXNzYWdlGAIgASgLMhsuYWdlbnQudjEuRXhlY1NlcnZlck1lc3NhZ2VIABJJChtleGVjX3NlcnZlcl9jb250cm9sX21lc3NhZ2UYBSABKAsyIi5hZ2VudC52MS5FeGVjU2VydmVyQ29udHJvbE1lc3NhZ2VIABJOCh5jb252ZXJzYXRpb25fY2hlY2twb2ludF91cGRhdGUYAyABKAsyJC5hZ2VudC52MS5Db252ZXJzYXRpb25TdGF0ZVN0cnVjdHVyZUgAEjYKEWt2X3NlcnZlcl9tZXNzYWdlGAQgASgLMhkuYWdlbnQudjEuS3ZTZXJ2ZXJNZXNzYWdlSAASNwoRaW50ZXJhY3Rpb25fcXVlcnkYByABKAsyGi5hZ2VudC52MS5JbnRlcmFjdGlvblF1ZXJ5SABCCQoHbWVzc2FnZSIoChBOYW1lQWdlbnRSZXF1ZXN0EhQKDHVzZXJfbWVzc2FnZRgBIAEoCSIhChFOYW1lQWdlbnRSZXNwb25zZRIMCgRuYW1lGAEgASgJIjIKFkdldFVzYWJsZU1vZGVsc1JlcXVlc3QSGAoQY3VzdG9tX21vZGVsX2lkcxgBIAMoCSJBChdHZXRVc2FibGVNb2RlbHNSZXNwb25zZRImCgZtb2RlbHMYASADKAsyFi5hZ2VudC52MS5Nb2RlbERldGFpbHMiHgocR2V0RGVmYXVsdE1vZGVsRm9yQ2xpUmVxdWVzdCJGCh1HZXREZWZhdWx0TW9kZWxGb3JDbGlSZXNwb25zZRIlCgVtb2RlbBgBIAEoCzIWLmFnZW50LnYxLk1vZGVsRGV0YWlscyIfCh1HZXRBbGxvd2VkTW9kZWxJbnRlbnRzUmVxdWVzdCI3Ch5HZXRBbGxvd2VkTW9kZWxJbnRlbnRzUmVzcG9uc2USFQoNbW9kZWxfaW50ZW50cxgBIAMoCSKXAgoTSWRlRWRpdG9yc1N0YXRlRmlsZRIVCg1yZWxhdGl2ZV9wYXRoGAEgASgJEhUKDWFic29sdXRlX3BhdGgYAiABKAkSIQoUaXNfY3VycmVudGx5X2ZvY3VzZWQYAyABKAhIAIgBARIgChNjdXJyZW50X2xpbmVfbnVtYmVyGAQgASgFSAGIAQESHgoRY3VycmVudF9saW5lX3RleHQYBSABKAlIAogBARIXCgpsaW5lX2NvdW50GAYgASgFSAOIAQFCFwoVX2lzX2N1cnJlbnRseV9mb2N1c2VkQhYKFF9jdXJyZW50X2xpbmVfbnVtYmVyQhQKEl9jdXJyZW50X2xpbmVfdGV4dEINCgtfbGluZV9jb3VudCJTChNJZGVFZGl0b3JzU3RhdGVMaXRlEjwKFXJlY2VudGx5X3ZpZXdlZF9maWxlcxgBIAMoCzIdLmFnZW50LnYxLklkZUVkaXRvcnNTdGF0ZUZpbGUidAoWQXBwbHlBZ2VudERpZmZUb29sQ2FsbBIqCgRhcmdzGAEgASgLMhwuYWdlbnQudjEuQXBwbHlBZ2VudERpZmZBcmdzEi4KBnJlc3VsdBgCIAEoCzIeLmFnZW50LnYxLkFwcGx5QWdlbnREaWZmUmVzdWx0IiYKEkFwcGx5QWdlbnREaWZmQXJncxIQCghhZ2VudF9pZBgBIAEoCSKEAQoUQXBwbHlBZ2VudERpZmZSZXN1bHQSMgoHc3VjY2VzcxgBIAEoCzIfLmFnZW50LnYxLkFwcGx5QWdlbnREaWZmU3VjY2Vzc0gAEi4KBWVycm9yGAIgASgLMh0uYWdlbnQudjEuQXBwbHlBZ2VudERpZmZFcnJvckgAQggKBnJlc3VsdCJOChVBcHBseUFnZW50RGlmZlN1Y2Nlc3MSNQoPYXBwbGllZF9jaGFuZ2VzGAEgAygLMhwuYWdlbnQudjEuQXBwbGllZEFnZW50Q2hhbmdlIukBChJBcHBsaWVkQWdlbnRDaGFuZ2USDAoEcGF0aBgBIAEoCRITCgtjaGFuZ2VfdHlwZRgCIAEoBRIbCg5iZWZvcmVfY29udGVudBgDIAEoCUgAiAEBEhoKDWFmdGVyX2NvbnRlbnQYBCABKAlIAYgBARISCgVlcnJvchgFIAEoCUgCiAEBEh4KEW1lc3NhZ2VfZm9yX21vZGVsGAYgASgJSAOIAQFCEQoPX2JlZm9yZV9jb250ZW50QhAKDl9hZnRlcl9jb250ZW50QggKBl9lcnJvckIUChJfbWVzc2FnZV9mb3JfbW9kZWwiWwoTQXBwbHlBZ2VudERpZmZFcnJvchINCgVlcnJvchgBIAEoCRI1Cg9hcHBsaWVkX2NoYW5nZXMYAiADKAsyHC5hZ2VudC52MS5BcHBsaWVkQWdlbnRDaGFuZ2UiawoTQXNrUXVlc3Rpb25Ub29sQ2FsbBInCgRhcmdzGAEgASgLMhkuYWdlbnQudjEuQXNrUXVlc3Rpb25BcmdzEisKBnJlc3VsdBgCIAEoCzIbLmFnZW50LnYxLkFza1F1ZXN0aW9uUmVzdWx0Io8BCg9Bc2tRdWVzdGlvbkFyZ3MSDQoFdGl0bGUYASABKAkSNQoJcXVlc3Rpb25zGAIgAygLMiIuYWdlbnQudjEuQXNrUXVlc3Rpb25BcmdzX1F1ZXN0aW9uEhEKCXJ1bl9hc3luYxgFIAEoCBIjChthc3luY19vcmlnaW5hbF90b29sX2NhbGxfaWQYBiABKAkigQEKGEFza1F1ZXN0aW9uQXJnc19RdWVzdGlvbhIKCgJpZBgBIAEoCRIOCgZwcm9tcHQYAiABKAkSMQoHb3B0aW9ucxgDIAMoCzIgLmFnZW50LnYxLkFza1F1ZXN0aW9uQXJnc19PcHRpb24SFgoOYWxsb3dfbXVsdGlwbGUYBCABKAgiMwoWQXNrUXVlc3Rpb25BcmdzX09wdGlvbhIKCgJpZBgBIAEoCRINCgVsYWJlbBgCIAEoCSISChBBc2tRdWVzdGlvbkFzeW5jItsBChFBc2tRdWVzdGlvblJlc3VsdBIvCgdzdWNjZXNzGAEgASgLMhwuYWdlbnQudjEuQXNrUXVlc3Rpb25TdWNjZXNzSAASKwoFZXJyb3IYAiABKAsyGi5hZ2VudC52MS5Bc2tRdWVzdGlvbkVycm9ySAASMQoIcmVqZWN0ZWQYAyABKAsyHS5hZ2VudC52MS5Bc2tRdWVzdGlvblJlamVjdGVkSAASKwoFYXN5bmMYBCABKAsyGi5hZ2VudC52MS5Bc2tRdWVzdGlvbkFzeW5jSABCCAoGcmVzdWx0IkoKEkFza1F1ZXN0aW9uU3VjY2VzcxI0CgdhbnN3ZXJzGAEgAygLMiMuYWdlbnQudjEuQXNrUXVlc3Rpb25TdWNjZXNzX0Fuc3dlciJNChlBc2tRdWVzdGlvblN1Y2Nlc3NfQW5zd2VyEhMKC3F1ZXN0aW9uX2lkGAEgASgJEhsKE3NlbGVjdGVkX29wdGlvbl9pZHMYAiADKAkiKQoQQXNrUXVlc3Rpb25FcnJvchIVCg1lcnJvcl9tZXNzYWdlGAEgASgJIiUKE0Fza1F1ZXN0aW9uUmVqZWN0ZWQSDgoGcmVhc29uGAEgASgJIv0FChhCYWNrZ3JvdW5kU2hlbGxTcGF3bkFyZ3MSDwoHY29tbWFuZBgBIAEoCRIZChF3b3JraW5nX2RpcmVjdG9yeRgCIAEoCRIUCgx0b29sX2NhbGxfaWQYAyABKAkSOwoOcGFyc2luZ19yZXN1bHQYBCABKAsyIy5hZ2VudC52MS5TaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0EjQKDnNhbmRib3hfcG9saWN5GAUgASgLMhcuYWdlbnQudjEuU2FuZGJveFBvbGljeUgAiAEBEiUKHWVuYWJsZV93cml0ZV9zaGVsbF9zdGRpbl90b29sGAYgASgIEhgKC2Rlc2NyaXB0aW9uGAcgASgJSAGIAQESQQoRY2xhc3NpZmllcl9yZXN1bHQYCCABKAsyIS5hZ2VudC52MS5Db21tYW5kQ2xhc3NpZmllclJlc3VsdEgCiAEBEkkKE291dHB1dF9ub3RpZmljYXRpb24YCSABKAsyJy5hZ2VudC52MS5TaGVsbE91dHB1dE5vdGlmaWNhdGlvbkNvbmZpZ0gDiAEBEj0KE3NtYXJ0X21vZGVfYXBwcm92YWwYCiABKAsyGy5hZ2VudC52MS5TbWFydE1vZGVBcHByb3ZhbEgEiAEBEk4KGWhvb2tfYXBwcm92YWxfcmVxdWlyZW1lbnQYCyABKAsyJi5hZ2VudC52MS5TaGVsbEhvb2tBcHByb3ZhbFJlcXVpcmVtZW50SAWIAQESFQoNc2tpcF9hcHByb3ZhbBgMIAEoCBIcCg9jb252ZXJzYXRpb25faWQYDSABKAlIBogBAUIRCg9fc2FuZGJveF9wb2xpY3lCDgoMX2Rlc2NyaXB0aW9uQhQKEl9jbGFzc2lmaWVyX3Jlc3VsdEIWChRfb3V0cHV0X25vdGlmaWNhdGlvbkIWChRfc21hcnRfbW9kZV9hcHByb3ZhbEIcChpfaG9va19hcHByb3ZhbF9yZXF1aXJlbWVudEISChBfY29udmVyc2F0aW9uX2lkIoECChpCYWNrZ3JvdW5kU2hlbGxTcGF3blJlc3VsdBI4CgdzdWNjZXNzGAEgASgLMiUuYWdlbnQudjEuQmFja2dyb3VuZFNoZWxsU3Bhd25TdWNjZXNzSAASNAoFZXJyb3IYAiABKAsyIy5hZ2VudC52MS5CYWNrZ3JvdW5kU2hlbGxTcGF3bkVycm9ySAASKwoIcmVqZWN0ZWQYAyABKAsyFy5hZ2VudC52MS5TaGVsbFJlamVjdGVkSAASPAoRcGVybWlzc2lvbl9kZW5pZWQYBCABKAsyHy5hZ2VudC52MS5TaGVsbFBlcm1pc3Npb25EZW5pZWRIAEIICgZyZXN1bHQidQobQmFja2dyb3VuZFNoZWxsU3Bhd25TdWNjZXNzEhAKCHNoZWxsX2lkGAEgASgNEg8KB2NvbW1hbmQYAiABKAkSGQoRd29ya2luZ19kaXJlY3RvcnkYAyABKAkSEAoDcGlkGAQgASgNSACIAQFCBgoEX3BpZCJWChlCYWNrZ3JvdW5kU2hlbGxTcGF3bkVycm9yEg8KB2NvbW1hbmQYASABKAkSGQoRd29ya2luZ19kaXJlY3RvcnkYAiABKAkSDQoFZXJyb3IYAyABKAkiNgoTV3JpdGVTaGVsbFN0ZGluQXJncxIQCghzaGVsbF9pZBgBIAEoDRINCgVjaGFycxgCIAEoCSKHAQoVV3JpdGVTaGVsbFN0ZGluUmVzdWx0EjMKB3N1Y2Nlc3MYASABKAsyIC5hZ2VudC52MS5Xcml0ZVNoZWxsU3RkaW5TdWNjZXNzSAASLwoFZXJyb3IYAiABKAsyHi5hZ2VudC52MS5Xcml0ZVNoZWxsU3RkaW5FcnJvckgAQggKBnJlc3VsdCJdChZXcml0ZVNoZWxsU3RkaW5TdWNjZXNzEhAKCHNoZWxsX2lkGAEgASgNEjEKKXRlcm1pbmFsX2ZpbGVfbGVuZ3RoX2JlZm9yZV9pbnB1dF93cml0dGVuGAIgASgNIiUKFFdyaXRlU2hlbGxTdGRpbkVycm9yEg0KBWVycm9yGAEgASgJIiIKCkNvb3JkaW5hdGUSCQoBeBgBIAEoBRIJCgF5GAIgASgFIlUKD0NvbXB1dGVyVXNlQXJncxIUCgx0b29sX2NhbGxfaWQYASABKAkSLAoHYWN0aW9ucxgCIAMoCzIbLmFnZW50LnYxLkNvbXB1dGVyVXNlQWN0aW9uIoEEChFDb21wdXRlclVzZUFjdGlvbhIvCgptb3VzZV9tb3ZlGAEgASgLMhkuYWdlbnQudjEuTW91c2VNb3ZlQWN0aW9uSAASJgoFY2xpY2sYAiABKAsyFS5hZ2VudC52MS5DbGlja0FjdGlvbkgAEi8KCm1vdXNlX2Rvd24YAyABKAsyGS5hZ2VudC52MS5Nb3VzZURvd25BY3Rpb25IABIrCghtb3VzZV91cBgEIAEoCzIXLmFnZW50LnYxLk1vdXNlVXBBY3Rpb25IABIkCgRkcmFnGAUgASgLMhQuYWdlbnQudjEuRHJhZ0FjdGlvbkgAEigKBnNjcm9sbBgGIAEoCzIWLmFnZW50LnYxLlNjcm9sbEFjdGlvbkgAEiQKBHR5cGUYByABKAsyFC5hZ2VudC52MS5UeXBlQWN0aW9uSAASIgoDa2V5GAggASgLMhMuYWdlbnQudjEuS2V5QWN0aW9uSAASJAoEd2FpdBgJIAEoCzIULmFnZW50LnYxLldhaXRBY3Rpb25IABIwCgpzY3JlZW5zaG90GAogASgLMhouYWdlbnQudjEuU2NyZWVuc2hvdEFjdGlvbkgAEjkKD2N1cnNvcl9wb3NpdGlvbhgLIAEoCzIeLmFnZW50LnYxLkN1cnNvclBvc2l0aW9uQWN0aW9uSABCCAoGYWN0aW9uIjsKD01vdXNlTW92ZUFjdGlvbhIoCgpjb29yZGluYXRlGAEgASgLMhQuYWdlbnQudjEuQ29vcmRpbmF0ZSKYAQoLQ2xpY2tBY3Rpb24SLQoKY29vcmRpbmF0ZRgBIAEoCzIULmFnZW50LnYxLkNvb3JkaW5hdGVIAIgBARIOCgZidXR0b24YAiABKAUSDQoFY291bnQYAyABKAUSGgoNbW9kaWZpZXJfa2V5cxgEIAEoCUgBiAEBQg0KC19jb29yZGluYXRlQhAKDl9tb2RpZmllcl9rZXlzIiEKD01vdXNlRG93bkFjdGlvbhIOCgZidXR0b24YASABKAUiHwoNTW91c2VVcEFjdGlvbhIOCgZidXR0b24YASABKAUiQAoKRHJhZ0FjdGlvbhIiCgRwYXRoGAEgAygLMhQuYWdlbnQudjEuQ29vcmRpbmF0ZRIOCgZidXR0b24YAiABKAUinQEKDFNjcm9sbEFjdGlvbhItCgpjb29yZGluYXRlGAEgASgLMhQuYWdlbnQudjEuQ29vcmRpbmF0ZUgAiAEBEhEKCWRpcmVjdGlvbhgCIAEoBRIOCgZhbW91bnQYAyABKAUSGgoNbW9kaWZpZXJfa2V5cxgEIAEoCUgBiAEBQg0KC19jb29yZGluYXRlQhAKDl9tb2RpZmllcl9rZXlzIhoKClR5cGVBY3Rpb24SDAoEdGV4dBgBIAEoCSJMCglLZXlBY3Rpb24SCwoDa2V5GAEgASgJEh0KEGhvbGRfZHVyYXRpb25fbXMYAiABKAVIAIgBAUITChFfaG9sZF9kdXJhdGlvbl9tcyIhCgpXYWl0QWN0aW9uEhMKC2R1cmF0aW9uX21zGAEgASgFIhIKEFNjcmVlbnNob3RBY3Rpb24iFgoUQ3Vyc29yUG9zaXRpb25BY3Rpb24iewoRQ29tcHV0ZXJVc2VSZXN1bHQSLwoHc3VjY2VzcxgBIAEoCzIcLmFnZW50LnYxLkNvbXB1dGVyVXNlU3VjY2Vzc0gAEisKBWVycm9yGAIgASgLMhouYWdlbnQudjEuQ29tcHV0ZXJVc2VFcnJvckgAQggKBnJlc3VsdCL7AQoSQ29tcHV0ZXJVc2VTdWNjZXNzEhQKDGFjdGlvbl9jb3VudBgBIAEoBRITCgtkdXJhdGlvbl9tcxgCIAEoBRIXCgpzY3JlZW5zaG90GAMgASgJSACIAQESEAoDbG9nGAQgASgJSAGIAQESHAoPc2NyZWVuc2hvdF9wYXRoGAUgASgJSAKIAQESMgoPY3Vyc29yX3Bvc2l0aW9uGAYgASgLMhQuYWdlbnQudjEuQ29vcmRpbmF0ZUgDiAEBQg0KC19zY3JlZW5zaG90QgYKBF9sb2dCEgoQX3NjcmVlbnNob3RfcGF0aEISChBfY3Vyc29yX3Bvc2l0aW9uIsABChBDb21wdXRlclVzZUVycm9yEg0KBWVycm9yGAEgASgJEhQKDGFjdGlvbl9jb3VudBgCIAEoBRITCgtkdXJhdGlvbl9tcxgDIAEoBRIQCgNsb2cYBCABKAlIAIgBARIXCgpzY3JlZW5zaG90GAUgASgJSAGIAQESHAoPc2NyZWVuc2hvdF9wYXRoGAYgASgJSAKIAQFCBgoEX2xvZ0INCgtfc2NyZWVuc2hvdEISChBfc2NyZWVuc2hvdF9wYXRoImsKE0NvbXB1dGVyVXNlVG9vbENhbGwSJwoEYXJncxgBIAEoCzIZLmFnZW50LnYxLkNvbXB1dGVyVXNlQXJncxIrCgZyZXN1bHQYAiABKAsyGy5hZ2VudC52MS5Db21wdXRlclVzZVJlc3VsdCJoChJDcmVhdGVQbGFuVG9vbENhbGwSJgoEYXJncxgBIAEoCzIYLmFnZW50LnYxLkNyZWF0ZVBsYW5BcmdzEioKBnJlc3VsdBgCIAEoCzIaLmFnZW50LnYxLkNyZWF0ZVBsYW5SZXN1bHQiOAoFUGhhc2USDAoEbmFtZRgBIAEoCRIhCgV0b2RvcxgCIAMoCzISLmFnZW50LnYxLlRvZG9JdGVtIpYBCg5DcmVhdGVQbGFuQXJncxIMCgRwbGFuGAEgASgJEiEKBXRvZG9zGAIgAygLMhIuYWdlbnQudjEuVG9kb0l0ZW0SEAoIb3ZlcnZpZXcYAyABKAkSDAoEbmFtZRgEIAEoCRISCgppc19wcm9qZWN0GAUgASgIEh8KBnBoYXNlcxgGIAMoCzIPLmFnZW50LnYxLlBoYXNlIooBChBDcmVhdGVQbGFuUmVzdWx0EhAKCHBsYW5fdXJpGAMgASgJEi4KB3N1Y2Nlc3MYASABKAsyGy5hZ2VudC52MS5DcmVhdGVQbGFuU3VjY2Vzc0gAEioKBWVycm9yGAIgASgLMhkuYWdlbnQudjEuQ3JlYXRlUGxhbkVycm9ySABCCAoGcmVzdWx0IhMKEUNyZWF0ZVBsYW5TdWNjZXNzIiAKD0NyZWF0ZVBsYW5FcnJvchINCgVlcnJvchgBIAEoCSJWChZDcmVhdGVQbGFuUmVxdWVzdFF1ZXJ5EiYKBGFyZ3MYASABKAsyGC5hZ2VudC52MS5DcmVhdGVQbGFuQXJncxIUCgx0b29sX2NhbGxfaWQYAiABKAkiRwoZQ3JlYXRlUGxhblJlcXVlc3RSZXNwb25zZRIqCgZyZXN1bHQYASABKAsyGi5hZ2VudC52MS5DcmVhdGVQbGFuUmVzdWx0IhYKFEN1cnNvclJ1bGVUeXBlR2xvYmFsIigKF0N1cnNvclJ1bGVUeXBlRmlsZUdsb2JzEg0KBWdsb2JzGAEgAygJIjEKGkN1cnNvclJ1bGVUeXBlQWdlbnRGZXRjaGVkEhMKC2Rlc2NyaXB0aW9uGAEgASgJIiAKHkN1cnNvclJ1bGVUeXBlTWFudWFsbHlBdHRhY2hlZCKLAgoOQ3Vyc29yUnVsZVR5cGUSMAoGZ2xvYmFsGAEgASgLMh4uYWdlbnQudjEuQ3Vyc29yUnVsZVR5cGVHbG9iYWxIABI5CgxmaWxlX2dsb2JiZWQYAiABKAsyIS5hZ2VudC52MS5DdXJzb3JSdWxlVHlwZUZpbGVHbG9ic0gAEj0KDWFnZW50X2ZldGNoZWQYAyABKAsyJC5hZ2VudC52MS5DdXJzb3JSdWxlVHlwZUFnZW50RmV0Y2hlZEgAEkUKEW1hbnVhbGx5X2F0dGFjaGVkGAQgASgLMiguYWdlbnQudjEuQ3Vyc29yUnVsZVR5cGVNYW51YWxseUF0dGFjaGVkSABCBgoEdHlwZSLIAQoKQ3Vyc29yUnVsZRIRCglmdWxsX3BhdGgYASABKAkSDwoHY29udGVudBgCIAEoCRImCgR0eXBlGAMgASgLMhguYWdlbnQudjEuQ3Vyc29yUnVsZVR5cGUSDgoGc291cmNlGAQgASgFEh4KEWdpdF9yZW1vdGVfb3JpZ2luGAUgASgJSACIAQESGAoLcGFyc2VfZXJyb3IYBiABKAlIAYgBAUIUChJfZ2l0X3JlbW90ZV9vcmlnaW5CDgoMX3BhcnNlX2Vycm9yIjAKCkRlbGV0ZUFyZ3MSDAoEcGF0aBgBIAEoCRIUCgx0b29sX2NhbGxfaWQYAiABKAki7QIKDERlbGV0ZVJlc3VsdBIqCgdzdWNjZXNzGAEgASgLMhcuYWdlbnQudjEuRGVsZXRlU3VjY2Vzc0gAEjYKDmZpbGVfbm90X2ZvdW5kGAIgASgLMhwuYWdlbnQudjEuRGVsZXRlRmlsZU5vdEZvdW5kSAASKwoIbm90X2ZpbGUYAyABKAsyFy5hZ2VudC52MS5EZWxldGVOb3RGaWxlSAASPQoRcGVybWlzc2lvbl9kZW5pZWQYBCABKAsyIC5hZ2VudC52MS5EZWxldGVQZXJtaXNzaW9uRGVuaWVkSAASLQoJZmlsZV9idXN5GAUgASgLMhguYWdlbnQudjEuRGVsZXRlRmlsZUJ1c3lIABIsCghyZWplY3RlZBgGIAEoCzIYLmFnZW50LnYxLkRlbGV0ZVJlamVjdGVkSAASJgoFZXJyb3IYByABKAsyFS5hZ2VudC52MS5EZWxldGVFcnJvckgAQggKBnJlc3VsdCJcCg1EZWxldGVTdWNjZXNzEgwKBHBhdGgYASABKAkSFAoMZGVsZXRlZF9maWxlGAIgASgJEhEKCWZpbGVfc2l6ZRgDIAEoAxIUCgxwcmV2X2NvbnRlbnQYBCABKAkiIgoSRGVsZXRlRmlsZU5vdEZvdW5kEgwKBHBhdGgYASABKAkiMgoNRGVsZXRlTm90RmlsZRIMCgRwYXRoGAEgASgJEhMKC2FjdHVhbF90eXBlGAIgASgJIlkKFkRlbGV0ZVBlcm1pc3Npb25EZW5pZWQSDAoEcGF0aBgBIAEoCRIcChRjbGllbnRfdmlzaWJsZV9lcnJvchgCIAEoCRITCgtpc19yZWFkb25seRgDIAEoCCIeCg5EZWxldGVGaWxlQnVzeRIMCgRwYXRoGAEgASgJIi4KDkRlbGV0ZVJlamVjdGVkEgwKBHBhdGgYASABKAkSDgoGcmVhc29uGAIgASgJIioKC0RlbGV0ZUVycm9yEgwKBHBhdGgYASABKAkSDQoFZXJyb3IYAiABKAkiXAoORGVsZXRlVG9vbENhbGwSIgoEYXJncxgBIAEoCzIULmFnZW50LnYxLkRlbGV0ZUFyZ3MSJgoGcmVzdWx0GAIgASgLMhYuYWdlbnQudjEuRGVsZXRlUmVzdWx0IjUKD0RpYWdub3N0aWNzQXJncxIMCgRwYXRoGAEgASgJEhQKDHRvb2xfY2FsbF9pZBgCIAEoCSKvAgoRRGlhZ25vc3RpY3NSZXN1bHQSLwoHc3VjY2VzcxgBIAEoCzIcLmFnZW50LnYxLkRpYWdub3N0aWNzU3VjY2Vzc0gAEisKBWVycm9yGAIgASgLMhouYWdlbnQudjEuRGlhZ25vc3RpY3NFcnJvckgAEjEKCHJlamVjdGVkGAMgASgLMh0uYWdlbnQudjEuRGlhZ25vc3RpY3NSZWplY3RlZEgAEjsKDmZpbGVfbm90X2ZvdW5kGAQgASgLMiEuYWdlbnQudjEuRGlhZ25vc3RpY3NGaWxlTm90Rm91bmRIABJCChFwZXJtaXNzaW9uX2RlbmllZBgFIAEoCzIlLmFnZW50LnYxLkRpYWdub3N0aWNzUGVybWlzc2lvbkRlbmllZEgAQggKBnJlc3VsdCJoChJEaWFnbm9zdGljc1N1Y2Nlc3MSDAoEcGF0aBgBIAEoCRIpCgtkaWFnbm9zdGljcxgCIAMoCzIULmFnZW50LnYxLkRpYWdub3N0aWMSGQoRdG90YWxfZGlhZ25vc3RpY3MYAyABKAUifwoKRGlhZ25vc3RpYxIQCghzZXZlcml0eRgBIAEoBRIeCgVyYW5nZRgCIAEoCzIPLmFnZW50LnYxLlJhbmdlEg8KB21lc3NhZ2UYAyABKAkSDgoGc291cmNlGAQgASgJEgwKBGNvZGUYBSABKAkSEAoIaXNfc3RhbGUYBiABKAgiLwoQRGlhZ25vc3RpY3NFcnJvchIMCgRwYXRoGAEgASgJEg0KBWVycm9yGAIgASgJIjMKE0RpYWdub3N0aWNzUmVqZWN0ZWQSDAoEcGF0aBgBIAEoCRIOCgZyZWFzb24YAiABKAkiJwoXRGlhZ25vc3RpY3NGaWxlTm90Rm91bmQSDAoEcGF0aBgBIAEoCSIrChtEaWFnbm9zdGljc1Blcm1pc3Npb25EZW5pZWQSDAoEcGF0aBgBIAEoCSJICghFZGl0QXJncxIMCgRwYXRoGAEgASgJEhsKDnN0cmVhbV9jb250ZW50GAYgASgJSACIAQFCEQoPX3N0cmVhbV9jb250ZW50ItYCCgpFZGl0UmVzdWx0EigKB3N1Y2Nlc3MYASABKAsyFS5hZ2VudC52MS5FZGl0U3VjY2Vzc0gAEjQKDmZpbGVfbm90X2ZvdW5kGAIgASgLMhouYWdlbnQudjEuRWRpdEZpbGVOb3RGb3VuZEgAEkQKFnJlYWRfcGVybWlzc2lvbl9kZW5pZWQYAyABKAsyIi5hZ2VudC52MS5FZGl0UmVhZFBlcm1pc3Npb25EZW5pZWRIABJGChd3cml0ZV9wZXJtaXNzaW9uX2RlbmllZBgEIAEoCzIjLmFnZW50LnYxLkVkaXRXcml0ZVBlcm1pc3Npb25EZW5pZWRIABIqCghyZWplY3RlZBgGIAEoCzIWLmFnZW50LnYxLkVkaXRSZWplY3RlZEgAEiQKBWVycm9yGAcgASgLMhMuYWdlbnQudjEuRWRpdEVycm9ySABCCAoGcmVzdWx0IqQCCgtFZGl0U3VjY2VzcxIMCgRwYXRoGAEgASgJEhgKC2xpbmVzX2FkZGVkGAMgASgFSACIAQESGgoNbGluZXNfcmVtb3ZlZBgEIAEoBUgBiAEBEhgKC2RpZmZfc3RyaW5nGAUgASgJSAKIAQESJQoYYmVmb3JlX2Z1bGxfZmlsZV9jb250ZW50GAYgASgJSAOIAQESHwoXYWZ0ZXJfZnVsbF9maWxlX2NvbnRlbnQYByABKAkSFAoHbWVzc2FnZRgIIAEoCUgEiAEBQg4KDF9saW5lc19hZGRlZEIQCg5fbGluZXNfcmVtb3ZlZEIOCgxfZGlmZl9zdHJpbmdCGwoZX2JlZm9yZV9mdWxsX2ZpbGVfY29udGVudEIKCghfbWVzc2FnZSIgChBFZGl0RmlsZU5vdEZvdW5kEgwKBHBhdGgYASABKAkiKAoYRWRpdFJlYWRQZXJtaXNzaW9uRGVuaWVkEgwKBHBhdGgYASABKAkiTQoZRWRpdFdyaXRlUGVybWlzc2lvbkRlbmllZBIMCgRwYXRoGAEgASgJEg0KBWVycm9yGAIgASgJEhMKC2lzX3JlYWRvbmx5GAMgASgIIiwKDEVkaXRSZWplY3RlZBIMCgRwYXRoGAEgASgJEg4KBnJlYXNvbhgCIAEoCSJiCglFZGl0RXJyb3ISDAoEcGF0aBgBIAEoCRINCgVlcnJvchgCIAEoCRIgChNtb2RlbF92aXNpYmxlX2Vycm9yGAUgASgJSACIAQFCFgoUX21vZGVsX3Zpc2libGVfZXJyb3IiVgoMRWRpdFRvb2xDYWxsEiAKBGFyZ3MYASABKAsyEi5hZ2VudC52MS5FZGl0QXJncxIkCgZyZXN1bHQYAiABKAsyFC5hZ2VudC52MS5FZGl0UmVzdWx0IjEKEUVkaXRUb29sQ2FsbERlbHRhEhwKFHN0cmVhbV9jb250ZW50X2RlbHRhGAEgASgJIjEKDEV4YUZldGNoQXJncxILCgNpZHMYASADKAkSFAoMdG9vbF9jYWxsX2lkGAIgASgJIqIBCg5FeGFGZXRjaFJlc3VsdBIsCgdzdWNjZXNzGAEgASgLMhkuYWdlbnQudjEuRXhhRmV0Y2hTdWNjZXNzSAASKAoFZXJyb3IYAiABKAsyFy5hZ2VudC52MS5FeGFGZXRjaEVycm9ySAASLgoIcmVqZWN0ZWQYAyABKAsyGi5hZ2VudC52MS5FeGFGZXRjaFJlamVjdGVkSABCCAoGcmVzdWx0Ij4KD0V4YUZldGNoU3VjY2VzcxIrCghjb250ZW50cxgBIAMoCzIZLmFnZW50LnYxLkV4YUZldGNoQ29udGVudCIeCg1FeGFGZXRjaEVycm9yEg0KBWVycm9yGAEgASgJIiIKEEV4YUZldGNoUmVqZWN0ZWQSDgoGcmVhc29uGAEgASgJIlMKD0V4YUZldGNoQ29udGVudBINCgV0aXRsZRgBIAEoCRILCgN1cmwYAiABKAkSDAoEdGV4dBgDIAEoCRIWCg5wdWJsaXNoZWRfZGF0ZRgEIAEoCSJiChBFeGFGZXRjaFRvb2xDYWxsEiQKBGFyZ3MYASABKAsyFi5hZ2VudC52MS5FeGFGZXRjaEFyZ3MSKAoGcmVzdWx0GAIgASgLMhguYWdlbnQudjEuRXhhRmV0Y2hSZXN1bHQiPAoURXhhRmV0Y2hSZXF1ZXN0UXVlcnkSJAoEYXJncxgBIAEoCzIWLmFnZW50LnYxLkV4YUZldGNoQXJncyKjAQoXRXhhRmV0Y2hSZXF1ZXN0UmVzcG9uc2USPgoIYXBwcm92ZWQYASABKAsyKi5hZ2VudC52MS5FeGFGZXRjaFJlcXVlc3RSZXNwb25zZV9BcHByb3ZlZEgAEj4KCHJlamVjdGVkGAIgASgLMiouYWdlbnQudjEuRXhhRmV0Y2hSZXF1ZXN0UmVzcG9uc2VfUmVqZWN0ZWRIAEIICgZyZXN1bHQiIgogRXhhRmV0Y2hSZXF1ZXN0UmVzcG9uc2VfQXBwcm92ZWQiMgogRXhhRmV0Y2hSZXF1ZXN0UmVzcG9uc2VfUmVqZWN0ZWQSDgoGcmVhc29uGAEgASgJIlcKDUV4YVNlYXJjaEFyZ3MSDQoFcXVlcnkYASABKAkSDAoEdHlwZRgCIAEoCRITCgtudW1fcmVzdWx0cxgDIAEoBRIUCgx0b29sX2NhbGxfaWQYBCABKAkipgEKD0V4YVNlYXJjaFJlc3VsdBItCgdzdWNjZXNzGAEgASgLMhouYWdlbnQudjEuRXhhU2VhcmNoU3VjY2Vzc0gAEikKBWVycm9yGAIgASgLMhguYWdlbnQudjEuRXhhU2VhcmNoRXJyb3JIABIvCghyZWplY3RlZBgDIAEoCzIbLmFnZW50LnYxLkV4YVNlYXJjaFJlamVjdGVkSABCCAoGcmVzdWx0IkQKEEV4YVNlYXJjaFN1Y2Nlc3MSMAoKcmVmZXJlbmNlcxgBIAMoCzIcLmFnZW50LnYxLkV4YVNlYXJjaFJlZmVyZW5jZSIfCg5FeGFTZWFyY2hFcnJvchINCgVlcnJvchgBIAEoCSIjChFFeGFTZWFyY2hSZWplY3RlZBIOCgZyZWFzb24YASABKAkiVgoSRXhhU2VhcmNoUmVmZXJlbmNlEg0KBXRpdGxlGAEgASgJEgsKA3VybBgCIAEoCRIMCgR0ZXh0GAMgASgJEhYKDnB1Ymxpc2hlZF9kYXRlGAQgASgJImUKEUV4YVNlYXJjaFRvb2xDYWxsEiUKBGFyZ3MYASABKAsyFy5hZ2VudC52MS5FeGFTZWFyY2hBcmdzEikKBnJlc3VsdBgCIAEoCzIZLmFnZW50LnYxLkV4YVNlYXJjaFJlc3VsdCI+ChVFeGFTZWFyY2hSZXF1ZXN0UXVlcnkSJQoEYXJncxgBIAEoCzIXLmFnZW50LnYxLkV4YVNlYXJjaEFyZ3MipgEKGEV4YVNlYXJjaFJlcXVlc3RSZXNwb25zZRI/CghhcHByb3ZlZBgBIAEoCzIrLmFnZW50LnYxLkV4YVNlYXJjaFJlcXVlc3RSZXNwb25zZV9BcHByb3ZlZEgAEj8KCHJlamVjdGVkGAIgASgLMisuYWdlbnQudjEuRXhhU2VhcmNoUmVxdWVzdFJlc3BvbnNlX1JlamVjdGVkSABCCAoGcmVzdWx0IiMKIUV4YVNlYXJjaFJlcXVlc3RSZXNwb25zZV9BcHByb3ZlZCIzCiFFeGFTZWFyY2hSZXF1ZXN0UmVzcG9uc2VfUmVqZWN0ZWQSDgoGcmVhc29uGAEgASgJIiMKFUV4ZWNDbGllbnRTdHJlYW1DbG9zZRIKCgJpZBgBIAEoDSJ+Cg9FeGVjQ2xpZW50VGhyb3cSCgoCaWQYASABKA0SDQoFZXJyb3IYAiABKAkSGAoLc3RhY2tfdHJhY2UYAyABKAlIAIgBARIXCgplcnJvcl9jb2RlGAQgASgJSAGIAQFCDgoMX3N0YWNrX3RyYWNlQg0KC19lcnJvcl9jb2RlIiEKE0V4ZWNDbGllbnRIZWFydGJlYXQSCgoCaWQYASABKA0ivgEKGEV4ZWNDbGllbnRDb250cm9sTWVzc2FnZRI3CgxzdHJlYW1fY2xvc2UYASABKAsyHy5hZ2VudC52MS5FeGVjQ2xpZW50U3RyZWFtQ2xvc2VIABIqCgV0aHJvdxgCIAEoCzIZLmFnZW50LnYxLkV4ZWNDbGllbnRUaHJvd0gAEjIKCWhlYXJ0YmVhdBgDIAEoCzIdLmFnZW50LnYxLkV4ZWNDbGllbnRIZWFydGJlYXRIAEIJCgdtZXNzYWdlIoQBCgtTcGFuQ29udGV4dBIQCgh0cmFjZV9pZBgBIAEoCRIPCgdzcGFuX2lkGAIgASgJEhgKC3RyYWNlX2ZsYWdzGAMgASgNSACIAQESGAoLdHJhY2Vfc3RhdGUYBCABKAlIAYgBAUIOCgxfdHJhY2VfZmxhZ3NCDgoMX3RyYWNlX3N0YXRlIgsKCUFib3J0QXJncyINCgtBYm9ydFJlc3VsdCLaEwoRRXhlY1NlcnZlck1lc3NhZ2USCgoCaWQYASABKA0SDwoHZXhlY19pZBgPIAEoCRIwCgxzcGFuX2NvbnRleHQYEyABKAsyFS5hZ2VudC52MS5TcGFuQ29udGV4dEgBiAEBEikKCnNoZWxsX2FyZ3MYAiABKAsyEy5hZ2VudC52MS5TaGVsbEFyZ3NIABIpCgp3cml0ZV9hcmdzGAMgASgLMhMuYWdlbnQudjEuV3JpdGVBcmdzSAASKwoLZGVsZXRlX2FyZ3MYBCABKAsyFC5hZ2VudC52MS5EZWxldGVBcmdzSAASJwoJZ3JlcF9hcmdzGAUgASgLMhIuYWdlbnQudjEuR3JlcEFyZ3NIABInCglyZWFkX2FyZ3MYByABKAsyEi5hZ2VudC52MS5SZWFkQXJnc0gAEiMKB2xzX2FyZ3MYCCABKAsyEC5hZ2VudC52MS5Mc0FyZ3NIABI1ChBkaWFnbm9zdGljc19hcmdzGAkgASgLMhkuYWdlbnQudjEuRGlhZ25vc3RpY3NBcmdzSAASPAoUcmVxdWVzdF9jb250ZXh0X2FyZ3MYCiABKAsyHC5hZ2VudC52MS5SZXF1ZXN0Q29udGV4dEFyZ3NIABIlCghtY3BfYXJncxgLIAEoCzIRLmFnZW50LnYxLk1jcEFyZ3NIABIwChFzaGVsbF9zdHJlYW1fYXJncxgOIAEoCzITLmFnZW50LnYxLlNoZWxsQXJnc0gAEkkKG2JhY2tncm91bmRfc2hlbGxfc3Bhd25fYXJncxgQIAEoCzIiLmFnZW50LnYxLkJhY2tncm91bmRTaGVsbFNwYXduQXJnc0gAEkoKHGxpc3RfbWNwX3Jlc291cmNlc19leGVjX2FyZ3MYESABKAsyIi5hZ2VudC52MS5MaXN0TWNwUmVzb3VyY2VzRXhlY0FyZ3NIABJIChtyZWFkX21jcF9yZXNvdXJjZV9leGVjX2FyZ3MYEiABKAsyIS5hZ2VudC52MS5SZWFkTWNwUmVzb3VyY2VFeGVjQXJnc0gAEikKCmZldGNoX2FyZ3MYFCABKAsyEy5hZ2VudC52MS5GZXRjaEFyZ3NIABI4ChJyZWNvcmRfc2NyZWVuX2FyZ3MYFSABKAsyGi5hZ2VudC52MS5SZWNvcmRTY3JlZW5BcmdzSAASNgoRY29tcHV0ZXJfdXNlX2FyZ3MYFiABKAsyGS5hZ2VudC52MS5Db21wdXRlclVzZUFyZ3NIABI/ChZ3cml0ZV9zaGVsbF9zdGRpbl9hcmdzGBcgASgLMh0uYWdlbnQudjEuV3JpdGVTaGVsbFN0ZGluQXJnc0gAEjAKEnJlZGFjdGVkX3JlYWRfYXJncxgdIAEoCzISLmFnZW50LnYxLlJlYWRBcmdzSAASOQoTbWNwX3N0YXRlX2V4ZWNfYXJncxgkIAEoCzIaLmFnZW50LnYxLk1jcFN0YXRlRXhlY0FyZ3NIABI2ChFleGVjdXRlX2hvb2tfYXJncxgbIAEoCzIZLmFnZW50LnYxLkV4ZWN1dGVIb29rQXJnc0gAEi8KDXN1YmFnZW50X2FyZ3MYHCABKAsyFi5hZ2VudC52MS5TdWJhZ2VudEFyZ3NIABJJChtmb3JjZV9iYWNrZ3JvdW5kX3NoZWxsX2FyZ3MYHiABKAsyIi5hZ2VudC52MS5Gb3JjZUJhY2tncm91bmRTaGVsbEFyZ3NIABJPCh5mb3JjZV9iYWNrZ3JvdW5kX3N1YmFnZW50X2FyZ3MYHyABKAsyJS5hZ2VudC52MS5Gb3JjZUJhY2tncm91bmRTdWJhZ2VudEFyZ3NIABI6ChNzdWJhZ2VudF9hd2FpdF9hcmdzGCUgASgLMhsuYWdlbnQudjEuU3ViYWdlbnRBd2FpdEFyZ3NIABJHChpzbWFydF9tb2RlX2NsYXNzaWZpZXJfYXJncxgmIAEoCzIhLmFnZW50LnYxLlNtYXJ0TW9kZUNsYXNzaWZpZXJBcmdzSAASQgoXY2FudmFzX2RpYWdub3N0aWNzX2FyZ3MYKCABKAsyHy5hZ2VudC52MS5DYW52YXNEaWFnbm9zdGljc0FyZ3NIABJNCh1zaGVsbF9hbGxvd2xpc3RfcHJlY2hlY2tfYXJncxgpIAEoCzIkLmFnZW50LnYxLlNoZWxsQWxsb3dsaXN0UHJlY2hlY2tBcmdzSAASSQobbWNwX2FsbG93bGlzdF9wcmVjaGVja19hcmdzGCogASgLMiIuYWdlbnQudjEuTWNwQWxsb3dsaXN0UHJlY2hlY2tBcmdzSAASVAohd2ViX2ZldGNoX2FsbG93bGlzdF9wcmVjaGVja19hcmdzGCsgASgLMicuYWdlbnQudjEuV2ViRmV0Y2hBbGxvd2xpc3RQcmVjaGVja0FyZ3NIABI0ChBnaXRfZGlmZl9yZXF1ZXN0GCwgASgLMhguYWdlbnQudjEuR2V0RGlmZlJlcXVlc3RIABIwCgxwaV9yZWFkX2FyZ3MYLSABKAsyGC5hZ2VudC52MS5QaVJlYWRFeGVjQXJnc0gAEjAKDHBpX2Jhc2hfYXJncxguIAEoCzIYLmFnZW50LnYxLlBpQmFzaEV4ZWNBcmdzSAASMAoMcGlfZWRpdF9hcmdzGC8gASgLMhguYWdlbnQudjEuUGlFZGl0RXhlY0FyZ3NIABIyCg1waV93cml0ZV9hcmdzGDAgASgLMhkuYWdlbnQudjEuUGlXcml0ZUV4ZWNBcmdzSAASMAoMcGlfZ3JlcF9hcmdzGDEgASgLMhguYWdlbnQudjEuUGlHcmVwRXhlY0FyZ3NIABIwCgxwaV9maW5kX2FyZ3MYMiABKAsyGC5hZ2VudC52MS5QaUZpbmRFeGVjQXJnc0gAEiwKCnBpX2xzX2FyZ3MYMyABKAsyFi5hZ2VudC52MS5QaUxzRXhlY0FyZ3NIABI3ChhtaW5pX3N3ZV9hZ2VudF9iYXNoX2FyZ3MYNCABKAsyEy5hZ2VudC52MS5TaGVsbEFyZ3NIABJEChhjb252ZXJzYXRpb25fc2VhcmNoX2FyZ3MYNSABKAsyIC5hZ2VudC52MS5Db252ZXJzYXRpb25TZWFyY2hBcmdzSAASRQoZYWdlbnRfc3RvcmVfY29uZmxpY3RfYXJncxg2IAEoCzIgLmFnZW50LnYxLkFnZW50U3RvcmVDb25mbGljdEFyZ3NIABIsCh9hY2NlcHRfaG9va19hZGRpdGlvbmFsX2NvbnRleHRzGDcgASgISAKIAQFCCQoHbWVzc2FnZUIPCg1fc3Bhbl9jb250ZXh0QiIKIF9hY2NlcHRfaG9va19hZGRpdGlvbmFsX2NvbnRleHRzIuEUChFFeGVjQ2xpZW50TWVzc2FnZRIKCgJpZBgBIAEoDRIPCgdleGVjX2lkGA8gASgJEi0KDHNoZWxsX3Jlc3VsdBgCIAEoCzIVLmFnZW50LnYxLlNoZWxsUmVzdWx0SAASLQoMd3JpdGVfcmVzdWx0GAMgASgLMhUuYWdlbnQudjEuV3JpdGVSZXN1bHRIABIvCg1kZWxldGVfcmVzdWx0GAQgASgLMhYuYWdlbnQudjEuRGVsZXRlUmVzdWx0SAASKwoLZ3JlcF9yZXN1bHQYBSABKAsyFC5hZ2VudC52MS5HcmVwUmVzdWx0SAASKwoLcmVhZF9yZXN1bHQYByABKAsyFC5hZ2VudC52MS5SZWFkUmVzdWx0SAASJwoJbHNfcmVzdWx0GAggASgLMhIuYWdlbnQudjEuTHNSZXN1bHRIABI5ChJkaWFnbm9zdGljc19yZXN1bHQYCSABKAsyGy5hZ2VudC52MS5EaWFnbm9zdGljc1Jlc3VsdEgAEkAKFnJlcXVlc3RfY29udGV4dF9yZXN1bHQYCiABKAsyHi5hZ2VudC52MS5SZXF1ZXN0Q29udGV4dFJlc3VsdEgAEikKCm1jcF9yZXN1bHQYCyABKAsyEy5hZ2VudC52MS5NY3BSZXN1bHRIABItCgxzaGVsbF9zdHJlYW0YDiABKAsyFS5hZ2VudC52MS5TaGVsbFN0cmVhbUgAEk0KHWJhY2tncm91bmRfc2hlbGxfc3Bhd25fcmVzdWx0GBAgASgLMiQuYWdlbnQudjEuQmFja2dyb3VuZFNoZWxsU3Bhd25SZXN1bHRIABJOCh5saXN0X21jcF9yZXNvdXJjZXNfZXhlY19yZXN1bHQYESABKAsyJC5hZ2VudC52MS5MaXN0TWNwUmVzb3VyY2VzRXhlY1Jlc3VsdEgAEkwKHXJlYWRfbWNwX3Jlc291cmNlX2V4ZWNfcmVzdWx0GBIgASgLMiMuYWdlbnQudjEuUmVhZE1jcFJlc291cmNlRXhlY1Jlc3VsdEgAEi0KDGZldGNoX3Jlc3VsdBgUIAEoCzIVLmFnZW50LnYxLkZldGNoUmVzdWx0SAASPAoUcmVjb3JkX3NjcmVlbl9yZXN1bHQYFSABKAsyHC5hZ2VudC52MS5SZWNvcmRTY3JlZW5SZXN1bHRIABI6ChNjb21wdXRlcl91c2VfcmVzdWx0GBYgASgLMhsuYWdlbnQudjEuQ29tcHV0ZXJVc2VSZXN1bHRIABJDChh3cml0ZV9zaGVsbF9zdGRpbl9yZXN1bHQYFyABKAsyHy5hZ2VudC52MS5Xcml0ZVNoZWxsU3RkaW5SZXN1bHRIABI0ChRyZWRhY3RlZF9yZWFkX3Jlc3VsdBgdIAEoCzIULmFnZW50LnYxLlJlYWRSZXN1bHRIABI9ChVtY3Bfc3RhdGVfZXhlY19yZXN1bHQYJCABKAsyHC5hZ2VudC52MS5NY3BTdGF0ZUV4ZWNSZXN1bHRIABI6ChNleGVjdXRlX2hvb2tfcmVzdWx0GBsgASgLMhsuYWdlbnQudjEuRXhlY3V0ZUhvb2tSZXN1bHRIABIzCg9zdWJhZ2VudF9yZXN1bHQYHCABKAsyGC5hZ2VudC52MS5TdWJhZ2VudFJlc3VsdEgAEk0KHWZvcmNlX2JhY2tncm91bmRfc2hlbGxfcmVzdWx0GB4gASgLMiQuYWdlbnQudjEuRm9yY2VCYWNrZ3JvdW5kU2hlbGxSZXN1bHRIABJTCiBmb3JjZV9iYWNrZ3JvdW5kX3N1YmFnZW50X3Jlc3VsdBgfIAEoCzInLmFnZW50LnYxLkZvcmNlQmFja2dyb3VuZFN1YmFnZW50UmVzdWx0SAASPgoVc3ViYWdlbnRfYXdhaXRfcmVzdWx0GCUgASgLMh0uYWdlbnQudjEuU3ViYWdlbnRBd2FpdFJlc3VsdEgAEksKHHNtYXJ0X21vZGVfY2xhc3NpZmllcl9yZXN1bHQYJiABKAsyIy5hZ2VudC52MS5TbWFydE1vZGVDbGFzc2lmaWVyUmVzdWx0SAASRgoZY2FudmFzX2RpYWdub3N0aWNzX3Jlc3VsdBgoIAEoCzIhLmFnZW50LnYxLkNhbnZhc0RpYWdub3N0aWNzUmVzdWx0SAASUQofc2hlbGxfYWxsb3dsaXN0X3ByZWNoZWNrX3Jlc3VsdBgpIAEoCzImLmFnZW50LnYxLlNoZWxsQWxsb3dsaXN0UHJlY2hlY2tSZXN1bHRIABJNCh1tY3BfYWxsb3dsaXN0X3ByZWNoZWNrX3Jlc3VsdBgqIAEoCzIkLmFnZW50LnYxLk1jcEFsbG93bGlzdFByZWNoZWNrUmVzdWx0SAASWAojd2ViX2ZldGNoX2FsbG93bGlzdF9wcmVjaGVja19yZXN1bHQYKyABKAsyKS5hZ2VudC52MS5XZWJGZXRjaEFsbG93bGlzdFByZWNoZWNrUmVzdWx0SAASNgoRZ2l0X2RpZmZfcmVzcG9uc2UYLCABKAsyGS5hZ2VudC52MS5HZXREaWZmUmVzcG9uc2VIABI0Cg5waV9yZWFkX3Jlc3VsdBguIAEoCzIaLmFnZW50LnYxLlBpUmVhZEV4ZWNSZXN1bHRIABI0Cg5waV9iYXNoX3Jlc3VsdBgvIAEoCzIaLmFnZW50LnYxLlBpQmFzaEV4ZWNSZXN1bHRIABI0Cg5waV9lZGl0X3Jlc3VsdBgwIAEoCzIaLmFnZW50LnYxLlBpRWRpdEV4ZWNSZXN1bHRIABI2Cg9waV93cml0ZV9yZXN1bHQYMSABKAsyGy5hZ2VudC52MS5QaVdyaXRlRXhlY1Jlc3VsdEgAEjQKDnBpX2dyZXBfcmVzdWx0GDIgASgLMhouYWdlbnQudjEuUGlHcmVwRXhlY1Jlc3VsdEgAEjQKDnBpX2ZpbmRfcmVzdWx0GDMgASgLMhouYWdlbnQudjEuUGlGaW5kRXhlY1Jlc3VsdEgAEjAKDHBpX2xzX3Jlc3VsdBg0IAEoCzIYLmFnZW50LnYxLlBpTHNFeGVjUmVzdWx0SAASSAoaY29udmVyc2F0aW9uX3NlYXJjaF9yZXN1bHQYNSABKAsyIi5hZ2VudC52MS5Db252ZXJzYXRpb25TZWFyY2hSZXN1bHRIABJJChthZ2VudF9zdG9yZV9jb25mbGljdF9yZXN1bHQYNiABKAsyIi5hZ2VudC52MS5BZ2VudFN0b3JlQ29uZmxpY3RSZXN1bHRIABI7ChptaW5pX3N3ZV9hZ2VudF9iYXNoX3Jlc3VsdBg3IAEoCzIVLmFnZW50LnYxLlNoZWxsUmVzdWx0SAASJAoXbG9jYWxfZXhlY3V0aW9uX3RpbWVfbXMYJyABKAVIAYgBARJBChhob29rX2FkZGl0aW9uYWxfY29udGV4dHMYLSADKAsyHy5hZ2VudC52MS5Ib29rQWRkaXRpb25hbENvbnRleHRCCQoHbWVzc2FnZUIaChhfbG9jYWxfZXhlY3V0aW9uX3RpbWVfbXMiLgoJRmV0Y2hBcmdzEgsKA3VybBgBIAEoCRIUCgx0b29sX2NhbGxfaWQYAiABKAkiaQoLRmV0Y2hSZXN1bHQSKQoHc3VjY2VzcxgBIAEoCzIWLmFnZW50LnYxLkZldGNoU3VjY2Vzc0gAEiUKBWVycm9yGAIgASgLMhQuYWdlbnQudjEuRmV0Y2hFcnJvckgAQggKBnJlc3VsdCJXCgxGZXRjaFN1Y2Nlc3MSCwoDdXJsGAEgASgJEg8KB2NvbnRlbnQYAiABKAkSEwoLc3RhdHVzX2NvZGUYAyABKAUSFAoMY29udGVudF90eXBlGAQgASgJIigKCkZldGNoRXJyb3ISCwoDdXJsGAEgASgJEg0KBWVycm9yGAIgASgJIm0KEUdlbmVyYXRlSW1hZ2VBcmdzEhMKC2Rlc2NyaXB0aW9uGAEgASgJEhYKCWZpbGVfcGF0aBgCIAEoCUgAiAEBEh0KFXJlZmVyZW5jZV9pbWFnZV9wYXRocxgFIAMoCUIMCgpfZmlsZV9wYXRoIoEBChNHZW5lcmF0ZUltYWdlUmVzdWx0EjEKB3N1Y2Nlc3MYASABKAsyHi5hZ2VudC52MS5HZW5lcmF0ZUltYWdlU3VjY2Vzc0gAEi0KBWVycm9yGAIgASgLMhwuYWdlbnQudjEuR2VuZXJhdGVJbWFnZUVycm9ySABCCAoGcmVzdWx0Ij0KFEdlbmVyYXRlSW1hZ2VTdWNjZXNzEhEKCWZpbGVfcGF0aBgBIAEoCRISCgppbWFnZV9kYXRhGAIgASgJIiMKEkdlbmVyYXRlSW1hZ2VFcnJvchINCgVlcnJvchgBIAEoCSJxChVHZW5lcmF0ZUltYWdlVG9vbENhbGwSKQoEYXJncxgBIAEoCzIbLmFnZW50LnYxLkdlbmVyYXRlSW1hZ2VBcmdzEi0KBnJlc3VsdBgCIAEoCzIdLmFnZW50LnYxLkdlbmVyYXRlSW1hZ2VSZXN1bHQi5gQKCEdyZXBBcmdzEg8KB3BhdHRlcm4YASABKAkSEQoEcGF0aBgCIAEoCUgAiAEBEhEKBGdsb2IYAyABKAlIAYgBARIYCgtvdXRwdXRfbW9kZRgEIAEoCUgCiAEBEhsKDmNvbnRleHRfYmVmb3JlGAUgASgFSAOIAQESGgoNY29udGV4dF9hZnRlchgGIAEoBUgEiAEBEhQKB2NvbnRleHQYByABKAVIBYgBARIdChBjYXNlX2luc2Vuc2l0aXZlGAggASgISAaIAQESEQoEdHlwZRgJIAEoCUgHiAEBEhcKCmhlYWRfbGltaXQYCiABKAVICIgBARIWCgltdWx0aWxpbmUYCyABKAhICYgBARIRCgRzb3J0GAwgASgJSAqIAQESGwoOc29ydF9hc2NlbmRpbmcYDSABKAhIC4gBARIUCgx0b29sX2NhbGxfaWQYDiABKAkSNAoOc2FuZGJveF9wb2xpY3kYDyABKAsyFy5hZ2VudC52MS5TYW5kYm94UG9saWN5SAyIAQESEwoGb2Zmc2V0GBAgASgFSA2IAQFCBwoFX3BhdGhCBwoFX2dsb2JCDgoMX291dHB1dF9tb2RlQhEKD19jb250ZXh0X2JlZm9yZUIQCg5fY29udGV4dF9hZnRlckIKCghfY29udGV4dEITChFfY2FzZV9pbnNlbnNpdGl2ZUIHCgVfdHlwZUINCgtfaGVhZF9saW1pdEIMCgpfbXVsdGlsaW5lQgcKBV9zb3J0QhEKD19zb3J0X2FzY2VuZGluZ0IRCg9fc2FuZGJveF9wb2xpY3lCCQoHX29mZnNldCJmCgpHcmVwUmVzdWx0EigKB3N1Y2Nlc3MYASABKAsyFS5hZ2VudC52MS5HcmVwU3VjY2Vzc0gAEiQKBWVycm9yGAIgASgLMhMuYWdlbnQudjEuR3JlcEVycm9ySABCCAoGcmVzdWx0IhoKCUdyZXBFcnJvchINCgVlcnJvchgBIAEoCSK0AgoLR3JlcFN1Y2Nlc3MSDwoHcGF0dGVybhgBIAEoCRIMCgRwYXRoGAIgASgJEhMKC291dHB1dF9tb2RlGAMgASgJEkYKEXdvcmtzcGFjZV9yZXN1bHRzGAQgAygLMisuYWdlbnQudjEuR3JlcFN1Y2Nlc3MuV29ya3NwYWNlUmVzdWx0c0VudHJ5EjwKFGFjdGl2ZV9lZGl0b3JfcmVzdWx0GAUgASgLMhkuYWdlbnQudjEuR3JlcFVuaW9uUmVzdWx0SACIAQEaUgoVV29ya3NwYWNlUmVzdWx0c0VudHJ5EgsKA2tleRgBIAEoCRIoCgV2YWx1ZRgCIAEoCzIZLmFnZW50LnYxLkdyZXBVbmlvblJlc3VsdDoCOAFCFwoVX2FjdGl2ZV9lZGl0b3JfcmVzdWx0IqMBCg9HcmVwVW5pb25SZXN1bHQSKgoFY291bnQYASABKAsyGS5hZ2VudC52MS5HcmVwQ291bnRSZXN1bHRIABIqCgVmaWxlcxgCIAEoCzIZLmFnZW50LnYxLkdyZXBGaWxlc1Jlc3VsdEgAEi4KB2NvbnRlbnQYAyABKAsyGy5hZ2VudC52MS5HcmVwQ29udGVudFJlc3VsdEgAQggKBnJlc3VsdCKDAgoPR3JlcENvdW50UmVzdWx0EicKBmNvdW50cxgBIAMoCzIXLmFnZW50LnYxLkdyZXBGaWxlQ291bnQSEwoLdG90YWxfZmlsZXMYAiABKAUSFQoNdG90YWxfbWF0Y2hlcxgDIAEoBRIYChBjbGllbnRfdHJ1bmNhdGVkGAQgASgIEhkKEXJpcGdyZXBfdHJ1bmNhdGVkGAUgASgIEh8KEmhlYWRfbGltaXRfYXBwbGllZBgGIAEoBUgAiAEBEhsKDm9mZnNldF9hcHBsaWVkGAcgASgFSAGIAQFCFQoTX2hlYWRfbGltaXRfYXBwbGllZEIRCg9fb2Zmc2V0X2FwcGxpZWQiLAoNR3JlcEZpbGVDb3VudBIMCgRmaWxlGAEgASgJEg0KBWNvdW50GAIgASgFItIBCg9HcmVwRmlsZXNSZXN1bHQSDQoFZmlsZXMYASADKAkSEwoLdG90YWxfZmlsZXMYAiABKAUSGAoQY2xpZW50X3RydW5jYXRlZBgDIAEoCBIZChFyaXBncmVwX3RydW5jYXRlZBgEIAEoCBIfChJoZWFkX2xpbWl0X2FwcGxpZWQYBSABKAVIAIgBARIbCg5vZmZzZXRfYXBwbGllZBgGIAEoBUgBiAEBQhUKE19oZWFkX2xpbWl0X2FwcGxpZWRCEQoPX29mZnNldF9hcHBsaWVkIowCChFHcmVwQ29udGVudFJlc3VsdBIoCgdtYXRjaGVzGAEgAygLMhcuYWdlbnQudjEuR3JlcEZpbGVNYXRjaBITCgt0b3RhbF9saW5lcxgCIAEoBRIbChN0b3RhbF9tYXRjaGVkX2xpbmVzGAMgASgFEhgKEGNsaWVudF90cnVuY2F0ZWQYBCABKAgSGQoRcmlwZ3JlcF90cnVuY2F0ZWQYBSABKAgSHwoSaGVhZF9saW1pdF9hcHBsaWVkGAYgASgFSACIAQESGwoOb2Zmc2V0X2FwcGxpZWQYByABKAVIAYgBAUIVChNfaGVhZF9saW1pdF9hcHBsaWVkQhEKD19vZmZzZXRfYXBwbGllZCJKCg1HcmVwRmlsZU1hdGNoEgwKBGZpbGUYASABKAkSKwoHbWF0Y2hlcxgCIAMoCzIaLmFnZW50LnYxLkdyZXBDb250ZW50TWF0Y2gibAoQR3JlcENvbnRlbnRNYXRjaBITCgtsaW5lX251bWJlchgBIAEoBRIPCgdjb250ZW50GAIgASgJEhkKEWNvbnRlbnRfdHJ1bmNhdGVkGAMgASgIEhcKD2lzX2NvbnRleHRfbGluZRgEIAEoCCIdCgpHcmVwU3RyZWFtEg8KB3BhdHRlcm4YASABKAkiVgoMR3JlcFRvb2xDYWxsEiAKBGFyZ3MYASABKAsyEi5hZ2VudC52MS5HcmVwQXJncxIkCgZyZXN1bHQYAiABKAsyFC5hZ2VudC52MS5HcmVwUmVzdWx0Ih4KC0dldEJsb2JBcmdzEg8KB2Jsb2JfaWQYASABKAwiNQoNR2V0QmxvYlJlc3VsdBIWCglibG9iX2RhdGEYASABKAxIAIgBAUIMCgpfYmxvYl9kYXRhIjEKC1NldEJsb2JBcmdzEg8KB2Jsb2JfaWQYASABKAwSEQoJYmxvYl9kYXRhGAIgASgMIj4KDVNldEJsb2JSZXN1bHQSIwoFZXJyb3IYASABKAsyDy5hZ2VudC52MS5FcnJvckgAiAEBQggKBl9lcnJvciLLAQoPS3ZTZXJ2ZXJNZXNzYWdlEgoKAmlkGAEgASgNEjAKDHNwYW5fY29udGV4dBgEIAEoCzIVLmFnZW50LnYxLlNwYW5Db250ZXh0SAGIAQESLgoNZ2V0X2Jsb2JfYXJncxgCIAEoCzIVLmFnZW50LnYxLkdldEJsb2JBcmdzSAASLgoNc2V0X2Jsb2JfYXJncxgDIAEoCzIVLmFnZW50LnYxLlNldEJsb2JBcmdzSABCCQoHbWVzc2FnZUIPCg1fc3Bhbl9jb250ZXh0IpABCg9LdkNsaWVudE1lc3NhZ2USCgoCaWQYASABKA0SMgoPZ2V0X2Jsb2JfcmVzdWx0GAIgASgLMhcuYWdlbnQudjEuR2V0QmxvYlJlc3VsdEgAEjIKD3NldF9ibG9iX3Jlc3VsdBgDIAEoCzIXLmFnZW50LnYxLlNldEJsb2JSZXN1bHRIAEIJCgdtZXNzYWdlIq0BCgZMc0FyZ3MSDAoEcGF0aBgBIAEoCRIOCgZpZ25vcmUYAiADKAkSFAoMdG9vbF9jYWxsX2lkGAMgASgJEjQKDnNhbmRib3hfcG9saWN5GAQgASgLMhcuYWdlbnQudjEuU2FuZGJveFBvbGljeUgAiAEBEhcKCnRpbWVvdXRfbXMYBSABKA1IAYgBAUIRCg9fc2FuZGJveF9wb2xpY3lCDQoLX3RpbWVvdXRfbXMisgEKCExzUmVzdWx0EiYKB3N1Y2Nlc3MYASABKAsyEy5hZ2VudC52MS5Mc1N1Y2Nlc3NIABIiCgVlcnJvchgCIAEoCzIRLmFnZW50LnYxLkxzRXJyb3JIABIoCghyZWplY3RlZBgDIAEoCzIULmFnZW50LnYxLkxzUmVqZWN0ZWRIABImCgd0aW1lb3V0GAQgASgLMhMuYWdlbnQudjEuTHNUaW1lb3V0SABCCAoGcmVzdWx0IkcKCUxzU3VjY2VzcxI6ChNkaXJlY3RvcnlfdHJlZV9yb290GAEgASgLMh0uYWdlbnQudjEuTHNEaXJlY3RvcnlUcmVlTm9kZSL2AgoTTHNEaXJlY3RvcnlUcmVlTm9kZRIQCghhYnNfcGF0aBgBIAEoCRI0Cg1jaGlsZHJlbl9kaXJzGAIgAygLMh0uYWdlbnQudjEuTHNEaXJlY3RvcnlUcmVlTm9kZRI6Cg5jaGlsZHJlbl9maWxlcxgDIAMoCzIiLmFnZW50LnYxLkxzRGlyZWN0b3J5VHJlZU5vZGVfRmlsZRIfChdjaGlsZHJlbl93ZXJlX3Byb2Nlc3NlZBgEIAEoCBJkCh1mdWxsX3N1YnRyZWVfZXh0ZW5zaW9uX2NvdW50cxgFIAMoCzI9LmFnZW50LnYxLkxzRGlyZWN0b3J5VHJlZU5vZGUuRnVsbFN1YnRyZWVFeHRlbnNpb25Db3VudHNFbnRyeRIRCgludW1fZmlsZXMYBiABKAUaQQofRnVsbFN1YnRyZWVFeHRlbnNpb25Db3VudHNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAU6AjgBInoKGExzRGlyZWN0b3J5VHJlZU5vZGVfRmlsZRIMCgRuYW1lGAEgASgJEjoKEXRlcm1pbmFsX21ldGFkYXRhGAIgASgLMhouYWdlbnQudjEuVGVybWluYWxNZXRhZGF0YUgAiAEBQhQKEl90ZXJtaW5hbF9tZXRhZGF0YSImCgdMc0Vycm9yEgwKBHBhdGgYASABKAkSDQoFZXJyb3IYAiABKAkiKgoKTHNSZWplY3RlZBIMCgRwYXRoGAEgASgJEg4KBnJlYXNvbhgCIAEoCSJHCglMc1RpbWVvdXQSOgoTZGlyZWN0b3J5X3RyZWVfcm9vdBgBIAEoCzIdLmFnZW50LnYxLkxzRGlyZWN0b3J5VHJlZU5vZGUi8QEKEFRlcm1pbmFsTWV0YWRhdGESEAoDY3dkGAEgASgJSACIAQESOQoNbGFzdF9jb21tYW5kcxgCIAMoCzIiLmFnZW50LnYxLlRlcm1pbmFsTWV0YWRhdGFfQ29tbWFuZBIdChBsYXN0X21vZGlmaWVkX21zGAMgASgDSAGIAQESQAoPY3VycmVudF9jb21tYW5kGAQgASgLMiIuYWdlbnQudjEuVGVybWluYWxNZXRhZGF0YV9Db21tYW5kSAKIAQFCBgoEX2N3ZEITChFfbGFzdF9tb2RpZmllZF9tc0ISChBfY3VycmVudF9jb21tYW5kIqcBChhUZXJtaW5hbE1ldGFkYXRhX0NvbW1hbmQSDwoHY29tbWFuZBgBIAEoCRIWCglleGl0X2NvZGUYAiABKAVIAIgBARIZCgx0aW1lc3RhbXBfbXMYAyABKANIAYgBARIYCgtkdXJhdGlvbl9tcxgEIAEoA0gCiAEBQgwKCl9leGl0X2NvZGVCDwoNX3RpbWVzdGFtcF9tc0IOCgxfZHVyYXRpb25fbXMiUAoKTHNUb29sQ2FsbBIeCgRhcmdzGAEgASgLMhAuYWdlbnQudjEuTHNBcmdzEiIKBnJlc3VsdBgCIAEoCzISLmFnZW50LnYxLkxzUmVzdWx0IuACCgdNY3BBcmdzEgwKBG5hbWUYASABKAkSKQoEYXJncxgCIAMoCzIbLmFnZW50LnYxLk1jcEFyZ3MuQXJnc0VudHJ5EhQKDHRvb2xfY2FsbF9pZBgDIAEoCRIbChNwcm92aWRlcl9pZGVudGlmaWVyGAQgASgJEhEKCXRvb2xfbmFtZRgFIAEoCRI9ChNzbWFydF9tb2RlX2FwcHJvdmFsGAYgASgLMhsuYWdlbnQudjEuU21hcnRNb2RlQXBwcm92YWxIAIgBARIgChhzbWFydF9tb2RlX2FwcHJvdmFsX29ubHkYByABKAgSFQoNc2tpcF9hcHByb3ZhbBgIIAEoCBIZChFzZXJ2ZXJfaWRlbnRpZmllchgJIAEoCRorCglBcmdzRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgMOgI4AUIWChRfc21hcnRfbW9kZV9hcHByb3ZhbCLjAgoJTWNwUmVzdWx0EicKB3N1Y2Nlc3MYASABKAsyFC5hZ2VudC52MS5NY3BTdWNjZXNzSAASIwoFZXJyb3IYAiABKAsyEi5hZ2VudC52MS5NY3BFcnJvckgAEikKCHJlamVjdGVkGAMgASgLMhUuYWdlbnQudjEuTWNwUmVqZWN0ZWRIABI6ChFwZXJtaXNzaW9uX2RlbmllZBgEIAEoCzIdLmFnZW50LnYxLk1jcFBlcm1pc3Npb25EZW5pZWRIABIzCg50b29sX25vdF9mb3VuZBgFIAEoCzIZLmFnZW50LnYxLk1jcFRvb2xOb3RGb3VuZEgAEjcKEHNlcnZlcl9ub3RfZm91bmQYBiABKAsyGy5hZ2VudC52MS5NY3BTZXJ2ZXJOb3RGb3VuZEgAEikKCGFwcHJvdmVkGAcgASgLMhUuYWdlbnQudjEuTWNwQXBwcm92ZWRIAEIICgZyZXN1bHQiOAoPTWNwVG9vbE5vdEZvdW5kEgwKBG5hbWUYASABKAkSFwoPYXZhaWxhYmxlX3Rvb2xzGAIgAygJImoKDk1jcFRleHRDb250ZW50EgwKBHRleHQYASABKAkSNgoPb3V0cHV0X2xvY2F0aW9uGAIgASgLMhguYWdlbnQudjEuT3V0cHV0TG9jYXRpb25IAIgBAUISChBfb3V0cHV0X2xvY2F0aW9uIjIKD01jcEltYWdlQ29udGVudBIMCgRkYXRhGAEgASgMEhEKCW1pbWVfdHlwZRgCIAEoCSJ7ChhNY3BUb29sUmVzdWx0Q29udGVudEl0ZW0SKAoEdGV4dBgBIAEoCzIYLmFnZW50LnYxLk1jcFRleHRDb250ZW50SAASKgoFaW1hZ2UYAiABKAsyGS5hZ2VudC52MS5NY3BJbWFnZUNvbnRlbnRIAEIJCgdjb250ZW50IlMKCk1jcFN1Y2Nlc3MSMwoHY29udGVudBgBIAMoCzIiLmFnZW50LnYxLk1jcFRvb2xSZXN1bHRDb250ZW50SXRlbRIQCghpc19lcnJvchgCIAEoCCIZCghNY3BFcnJvchINCgVlcnJvchgBIAEoCSIyCgtNY3BSZWplY3RlZBIOCgZyZWFzb24YASABKAkSEwoLaXNfcmVhZG9ubHkYAiABKAgiOQoTTWNwUGVybWlzc2lvbkRlbmllZBINCgVlcnJvchgBIAEoCRITCgtpc19yZWFkb25seRgCIAEoCCI6ChhMaXN0TWNwUmVzb3VyY2VzRXhlY0FyZ3MSEwoGc2VydmVyGAEgASgJSACIAQFCCQoHX3NlcnZlciLGAQoaTGlzdE1jcFJlc291cmNlc0V4ZWNSZXN1bHQSNAoHc3VjY2VzcxgBIAEoCzIhLmFnZW50LnYxLkxpc3RNY3BSZXNvdXJjZXNTdWNjZXNzSAASMAoFZXJyb3IYAiABKAsyHy5hZ2VudC52MS5MaXN0TWNwUmVzb3VyY2VzRXJyb3JIABI2CghyZWplY3RlZBgDIAEoCzIiLmFnZW50LnYxLkxpc3RNY3BSZXNvdXJjZXNSZWplY3RlZEgAQggKBnJlc3VsdCK9AgomTGlzdE1jcFJlc291cmNlc0V4ZWNSZXN1bHRfTWNwUmVzb3VyY2USCwoDdXJpGAEgASgJEhEKBG5hbWUYAiABKAlIAIgBARIYCgtkZXNjcmlwdGlvbhgDIAEoCUgBiAEBEhYKCW1pbWVfdHlwZRgEIAEoCUgCiAEBEg4KBnNlcnZlchgFIAEoCRJWCgthbm5vdGF0aW9ucxgGIAMoCzJBLmFnZW50LnYxLkxpc3RNY3BSZXNvdXJjZXNFeGVjUmVzdWx0X01jcFJlc291cmNlLkFubm90YXRpb25zRW50cnkaMgoQQW5ub3RhdGlvbnNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBQgcKBV9uYW1lQg4KDF9kZXNjcmlwdGlvbkIMCgpfbWltZV90eXBlIl4KF0xpc3RNY3BSZXNvdXJjZXNTdWNjZXNzEkMKCXJlc291cmNlcxgBIAMoCzIwLmFnZW50LnYxLkxpc3RNY3BSZXNvdXJjZXNFeGVjUmVzdWx0X01jcFJlc291cmNlIiYKFUxpc3RNY3BSZXNvdXJjZXNFcnJvchINCgVlcnJvchgBIAEoCSIqChhMaXN0TWNwUmVzb3VyY2VzUmVqZWN0ZWQSDgoGcmVhc29uGAEgASgJItEBChdSZWFkTWNwUmVzb3VyY2VFeGVjQXJncxIOCgZzZXJ2ZXIYASABKAkSCwoDdXJpGAIgASgJEhoKDWRvd25sb2FkX3BhdGgYAyABKAlIAIgBARIUCgx0b29sX2NhbGxfaWQYBCABKAkSPQoTc21hcnRfbW9kZV9hcHByb3ZhbBgFIAEoCzIbLmFnZW50LnYxLlNtYXJ0TW9kZUFwcHJvdmFsSAGIAQFCEAoOX2Rvd25sb2FkX3BhdGhCFgoUX3NtYXJ0X21vZGVfYXBwcm92YWwi+gEKGVJlYWRNY3BSZXNvdXJjZUV4ZWNSZXN1bHQSMwoHc3VjY2VzcxgBIAEoCzIgLmFnZW50LnYxLlJlYWRNY3BSZXNvdXJjZVN1Y2Nlc3NIABIvCgVlcnJvchgCIAEoCzIeLmFnZW50LnYxLlJlYWRNY3BSZXNvdXJjZUVycm9ySAASNQoIcmVqZWN0ZWQYAyABKAsyIS5hZ2VudC52MS5SZWFkTWNwUmVzb3VyY2VSZWplY3RlZEgAEjYKCW5vdF9mb3VuZBgEIAEoCzIhLmFnZW50LnYxLlJlYWRNY3BSZXNvdXJjZU5vdEZvdW5kSABCCAoGcmVzdWx0IrIDChZSZWFkTWNwUmVzb3VyY2VTdWNjZXNzEgsKA3VyaRgBIAEoCRIRCgRuYW1lGAIgASgJSAGIAQESGAoLZGVzY3JpcHRpb24YAyABKAlIAogBARIWCgltaW1lX3R5cGUYBCABKAlIA4gBARJGCgthbm5vdGF0aW9ucxgHIAMoCzIxLmFnZW50LnYxLlJlYWRNY3BSZXNvdXJjZVN1Y2Nlc3MuQW5ub3RhdGlvbnNFbnRyeRIaCg1kb3dubG9hZF9wYXRoGAggASgJSASIAQESDgoEdGV4dBgFIAEoCUgAEg4KBGJsb2IYBiABKAxIABI2Cg9vdXRwdXRfbG9jYXRpb24YCSABKAsyGC5hZ2VudC52MS5PdXRwdXRMb2NhdGlvbkgFiAEBGjIKEEFubm90YXRpb25zRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4AUIJCgdjb250ZW50QgcKBV9uYW1lQg4KDF9kZXNjcmlwdGlvbkIMCgpfbWltZV90eXBlQhAKDl9kb3dubG9hZF9wYXRoQhIKEF9vdXRwdXRfbG9jYXRpb24iMgoUUmVhZE1jcFJlc291cmNlRXJyb3ISCwoDdXJpGAEgASgJEg0KBWVycm9yGAIgASgJIjYKF1JlYWRNY3BSZXNvdXJjZVJlamVjdGVkEgsKA3VyaRgBIAEoCRIOCgZyZWFzb24YAiABKAkiJgoXUmVhZE1jcFJlc291cmNlTm90Rm91bmQSCwoDdXJpGAEgASgJIrIBChFNY3BUb29sRGVmaW5pdGlvbhIMCgRuYW1lGAEgASgJEhsKE3Byb3ZpZGVyX2lkZW50aWZpZXIYBCABKAkSEQoJdG9vbF9uYW1lGAUgASgJEhMKC2Rlc2NyaXB0aW9uGAIgASgJEhQKDGlucHV0X3NjaGVtYRgDIAEoDBIeChFpbnB1dF9zY2hlbWFfanNvbhgGIAEoCUgAiAEBQhQKEl9pbnB1dF9zY2hlbWFfanNvbiI6CghNY3BUb29scxIuCgltY3BfdG9vbHMYASADKAsyGy5hZ2VudC52MS5NY3BUb29sRGVmaW5pdGlvbiJXCg9NY3BJbnN0cnVjdGlvbnMSEwoLc2VydmVyX25hbWUYASABKAkSFAoMaW5zdHJ1Y3Rpb25zGAIgASgJEhkKEXNlcnZlcl9pZGVudGlmaWVyGAMgASgJIv0CCg1NY3BEZXNjcmlwdG9yEhMKC3NlcnZlcl9uYW1lGAEgASgJEhkKEXNlcnZlcl9pZGVudGlmaWVyGAIgASgJEhgKC2ZvbGRlcl9wYXRoGAMgASgJSACIAQESJAoXc2VydmVyX3VzZV9pbnN0cnVjdGlvbnMYBCABKAlIAYgBARIqCgV0b29scxgFIAMoCzIbLmFnZW50LnYxLk1jcFRvb2xEZXNjcmlwdG9yEhMKBnBsdWdpbhgHIAEoCUgCiAEBEhgKC21hcmtldHBsYWNlGAggASgJSAOIAQESGQoMcGx1Z2luX2RiX2lkGAkgASgJSASIAQESGwoObWFya2V0cGxhY2VfaWQYCiABKAlIBYgBAUIOCgxfZm9sZGVyX3BhdGhCGgoYX3NlcnZlcl91c2VfaW5zdHJ1Y3Rpb25zQgkKB19wbHVnaW5CDgoMX21hcmtldHBsYWNlQg8KDV9wbHVnaW5fZGJfaWRCEQoPX21hcmtldHBsYWNlX2lkIrgBChFNY3BUb29sRGVzY3JpcHRvchIRCgl0b29sX25hbWUYASABKAkSHAoPZGVmaW5pdGlvbl9wYXRoGAIgASgJSACIAQESGAoLZGVzY3JpcHRpb24YAyABKAlIAYgBARIeChFpbnB1dF9zY2hlbWFfanNvbhgFIAEoCUgCiAEBQhIKEF9kZWZpbml0aW9uX3BhdGhCDgoMX2Rlc2NyaXB0aW9uQhQKEl9pbnB1dF9zY2hlbWFfanNvbiJ4ChRNY3BGaWxlU3lzdGVtT3B0aW9ucxIPCgdlbmFibGVkGAEgASgIEh0KFXdvcmtzcGFjZV9wcm9qZWN0X2RpchgCIAEoCRIwCg9tY3BfZGVzY3JpcHRvcnMYAyADKAsyFy5hZ2VudC52MS5NY3BEZXNjcmlwdG9yIpoBCghSZWFkQXJncxIMCgRwYXRoGAEgASgJEhQKDHRvb2xfY2FsbF9pZBgCIAEoCRITCgZvZmZzZXQYBCABKAVIAIgBARISCgVsaW1pdBgFIAEoDUgBiAEBEhoKDWVuY29kaW5nX2hpbnQYBiABKAlIAogBAUIJCgdfb2Zmc2V0QggKBl9saW1pdEIQCg5fZW5jb2RpbmdfaGludCK4AgoKUmVhZFJlc3VsdBIoCgdzdWNjZXNzGAEgASgLMhUuYWdlbnQudjEuUmVhZFN1Y2Nlc3NIABIkCgVlcnJvchgCIAEoCzITLmFnZW50LnYxLlJlYWRFcnJvckgAEioKCHJlamVjdGVkGAMgASgLMhYuYWdlbnQudjEuUmVhZFJlamVjdGVkSAASNAoOZmlsZV9ub3RfZm91bmQYBCABKAsyGi5hZ2VudC52MS5SZWFkRmlsZU5vdEZvdW5kSAASOwoRcGVybWlzc2lvbl9kZW5pZWQYBSABKAsyHi5hZ2VudC52MS5SZWFkUGVybWlzc2lvbkRlbmllZEgAEjEKDGludmFsaWRfZmlsZRgGIAEoCzIZLmFnZW50LnYxLlJlYWRJbnZhbGlkRmlsZUgAQggKBnJlc3VsdCLKAQoLUmVhZFN1Y2Nlc3MSDAoEcGF0aBgBIAEoCRITCgt0b3RhbF9saW5lcxgDIAEoBRIRCglmaWxlX3NpemUYBCABKAMSEQoJdHJ1bmNhdGVkGAYgASgIEhsKDm91dHB1dF9ibG9iX2lkGAcgASgMSAGIAQESEQoHY29udGVudBgCIAEoCUgAEg4KBGRhdGEYBSABKAxIABIVCg1yYW5nZV9hcHBsaWVkGAggASgIQggKBm91dHB1dEIRCg9fb3V0cHV0X2Jsb2JfaWQiKAoJUmVhZEVycm9yEgwKBHBhdGgYASABKAkSDQoFZXJyb3IYAiABKAkiLAoMUmVhZFJlamVjdGVkEgwKBHBhdGgYASABKAkSDgoGcmVhc29uGAIgASgJIiAKEFJlYWRGaWxlTm90Rm91bmQSDAoEcGF0aBgBIAEoCSIkChRSZWFkUGVybWlzc2lvbkRlbmllZBIMCgRwYXRoGAEgASgJIi8KD1JlYWRJbnZhbGlkRmlsZRIMCgRwYXRoGAEgASgJEg4KBnJlYXNvbhgCIAEoCSJeCgxSZWFkVG9vbENhbGwSJAoEYXJncxgBIAEoCzIWLmFnZW50LnYxLlJlYWRUb29sQXJncxIoCgZyZXN1bHQYAiABKAsyGC5hZ2VudC52MS5SZWFkVG9vbFJlc3VsdCJaCgxSZWFkVG9vbEFyZ3MSDAoEcGF0aBgBIAEoCRITCgZvZmZzZXQYAiABKAVIAIgBARISCgVsaW1pdBgDIAEoBUgBiAEBQgkKB19vZmZzZXRCCAoGX2xpbWl0InIKDlJlYWRUb29sUmVzdWx0EiwKB3N1Y2Nlc3MYASABKAsyGS5hZ2VudC52MS5SZWFkVG9vbFN1Y2Nlc3NIABIoCgVlcnJvchgCIAEoCzIXLmFnZW50LnYxLlJlYWRUb29sRXJyb3JIAEIICgZyZXN1bHQiMQoJUmVhZFJhbmdlEhIKCnN0YXJ0X2xpbmUYASABKA0SEAoIZW5kX2xpbmUYAiABKA0ijgIKD1JlYWRUb29sU3VjY2VzcxIQCghpc19lbXB0eRgCIAEoCBIWCg5leGNlZWRlZF9saW1pdBgDIAEoCBITCgt0b3RhbF9saW5lcxgEIAEoDRIRCglmaWxlX3NpemUYBSABKA0SDAoEcGF0aBgHIAEoCRIsCgpyZWFkX3JhbmdlGAggASgLMhMuYWdlbnQudjEuUmVhZFJhbmdlSAGIAQESEQoHY29udGVudBgBIAEoCUgAEg4KBGRhdGEYBiABKAxIABIWCgxkYXRhX2Jsb2JfaWQYCSABKAxIABIZCg9jb250ZW50X2Jsb2JfaWQYCiABKAxIAEIICgZvdXRwdXRCDQoLX3JlYWRfcmFuZ2UiJgoNUmVhZFRvb2xFcnJvchIVCg1lcnJvcl9tZXNzYWdlGAEgASgJImoKEFJlY29yZFNjcmVlbkFyZ3MSDAoEbW9kZRgBIAEoBRIUCgx0b29sX2NhbGxfaWQYAiABKAkSHQoQc2F2ZV9hc19maWxlbmFtZRgDIAEoCUgAiAEBQhMKEV9zYXZlX2FzX2ZpbGVuYW1lIokCChJSZWNvcmRTY3JlZW5SZXN1bHQSOwoNc3RhcnRfc3VjY2VzcxgBIAEoCzIiLmFnZW50LnYxLlJlY29yZFNjcmVlblN0YXJ0U3VjY2Vzc0gAEjkKDHNhdmVfc3VjY2VzcxgCIAEoCzIhLmFnZW50LnYxLlJlY29yZFNjcmVlblNhdmVTdWNjZXNzSAASPwoPZGlzY2FyZF9zdWNjZXNzGAMgASgLMiQuYWdlbnQudjEuUmVjb3JkU2NyZWVuRGlzY2FyZFN1Y2Nlc3NIABIwCgdmYWlsdXJlGAQgASgLMh0uYWdlbnQudjEuUmVjb3JkU2NyZWVuRmFpbHVyZUgAQggKBnJlc3VsdCJnChhSZWNvcmRTY3JlZW5TdGFydFN1Y2Nlc3MSJQodd2FzX3ByaW9yX3JlY29yZGluZ19jYW5jZWxsZWQYASABKAgSJAocd2FzX3NhdmVfYXNfZmlsZW5hbWVfaWdub3JlZBgCIAEoCCKgAQoXUmVjb3JkU2NyZWVuU2F2ZVN1Y2Nlc3MSDAoEcGF0aBgBIAEoCRIdChVyZWNvcmRpbmdfZHVyYXRpb25fbXMYAiABKAMSMAojcmVxdWVzdGVkX2ZpbGVfcGF0aF9yZWplY3RlZF9yZWFzb24YAyABKAVIAIgBAUImCiRfcmVxdWVzdGVkX2ZpbGVfcGF0aF9yZWplY3RlZF9yZWFzb24iHAoaUmVjb3JkU2NyZWVuRGlzY2FyZFN1Y2Nlc3MiJAoTUmVjb3JkU2NyZWVuRmFpbHVyZRINCgVlcnJvchgBIAEoCSI2ChNDdXJzb3JQYWNrYWdlUHJvbXB0EgwKBG5hbWUYASABKAkSEQoJZmlsZV9wYXRoGAIgASgJIuIBCg1DdXJzb3JQYWNrYWdlEgwKBG5hbWUYASABKAkSEwoLZGVzY3JpcHRpb24YAiABKAkSEwoLZm9sZGVyX3BhdGgYAyABKAkSDwoHZW5hYmxlZBgEIAEoCBIYCgtwYXJzZV9lcnJvchgFIAEoCUgAiAEBEi4KB3Byb21wdHMYBiADKAsyHS5hZ2VudC52MS5DdXJzb3JQYWNrYWdlUHJvbXB0EhgKEHJlYWRtZV9maWxlX3BhdGgYByABKAkSFAoMcGFja2FnZV90eXBlGAggASgFQg4KDF9wYXJzZV9lcnJvciKrAgoWUmVwb3NpdG9yeUluZGV4aW5nSW5mbxIfChdyZWxhdGl2ZV93b3Jrc3BhY2VfcGF0aBgBIAEoCRITCgtyZW1vdGVfdXJscxgCIAMoCRIUCgxyZW1vdGVfbmFtZXMYAyADKAkSEQoJcmVwb19uYW1lGAQgASgJEhIKCnJlcG9fb3duZXIYBSABKAkSEgoKaXNfdHJhY2tlZBgGIAEoCBIQCghpc19sb2NhbBgHIAEoCBImChlvcnRob2dvbmFsX3RyYW5zZm9ybV9zZWVkGAggASgBSACIAQESFQoNd29ya3NwYWNlX3VyaRgJIAEoCRIbChNwYXRoX2VuY3J5cHRpb25fa2V5GAogASgJQhwKGl9vcnRob2dvbmFsX3RyYW5zZm9ybV9zZWVkIqwCChJSZXF1ZXN0Q29udGV4dEFyZ3MSHQoQbm90ZXNfc2Vzc2lvbl9pZBgCIAEoCUgAiAEBEhkKDHdvcmtzcGFjZV9pZBgDIAEoCUgBiAEBEiYKGXJlYWRfb25seV9waW5uZWRfdHJlZV9zaGEYBCABKAlIAogBARIoChtyZWFkX29ubHlfcGx1Z2luX2NhY2hlX3Jvb3QYBSABKAlIA4gBARIXCgp1c2VfY2FjaGVkGAcgASgISASIAQFCEwoRX25vdGVzX3Nlc3Npb25faWRCDwoNX3dvcmtzcGFjZV9pZEIcChpfcmVhZF9vbmx5X3Bpbm5lZF90cmVlX3NoYUIeChxfcmVhZF9vbmx5X3BsdWdpbl9jYWNoZV9yb290Qg0KC191c2VfY2FjaGVkIroBChRSZXF1ZXN0Q29udGV4dFJlc3VsdBIyCgdzdWNjZXNzGAEgASgLMh8uYWdlbnQudjEuUmVxdWVzdENvbnRleHRTdWNjZXNzSAASLgoFZXJyb3IYAiABKAsyHS5hZ2VudC52MS5SZXF1ZXN0Q29udGV4dEVycm9ySAASNAoIcmVqZWN0ZWQYAyABKAsyIC5hZ2VudC52MS5SZXF1ZXN0Q29udGV4dFJlamVjdGVkSABCCAoGcmVzdWx0IooBChVSZXF1ZXN0Q29udGV4dFN1Y2Nlc3MSMQoPcmVxdWVzdF9jb250ZXh0GAEgASgLMhguYWdlbnQudjEuUmVxdWVzdENvbnRleHQSIwoWc2VydmVkX2Zyb21fZGlza19jYWNoZRgCIAEoCEgAiAEBQhkKF19zZXJ2ZWRfZnJvbV9kaXNrX2NhY2hlIiQKE1JlcXVlc3RDb250ZXh0RXJyb3ISDQoFZXJyb3IYASABKAkiKAoWUmVxdWVzdENvbnRleHRSZWplY3RlZBIOCgZyZWFzb24YASABKAkiwgEKCkltYWdlUHJvdG8SDAoEZGF0YRgBIAEoDBIMCgR1dWlkGAIgASgJEgwKBHBhdGgYAyABKAkSMQoJZGltZW5zaW9uGAQgASgLMh4uYWdlbnQudjEuSW1hZ2VQcm90b19EaW1lbnNpb24SJgoZdGFza19zcGVjaWZpY19kZXNjcmlwdGlvbhgGIAEoCUgAiAEBEhEKCW1pbWVfdHlwZRgHIAEoCUIcChpfdGFza19zcGVjaWZpY19kZXNjcmlwdGlvbiI1ChRJbWFnZVByb3RvX0RpbWVuc2lvbhINCgV3aWR0aBgBIAEoBRIOCgZoZWlnaHQYAiABKAUiaAoLR2l0UmVwb0luZm8SDAoEcGF0aBgBIAEoCRIOCgZzdGF0dXMYAiABKAkSEwoLYnJhbmNoX25hbWUYAyABKAkSFwoKcmVtb3RlX3VybBgEIAEoCUgAiAEBQg0KC19yZW1vdGVfdXJsIpsCChFSZXF1ZXN0Q29udGV4dEVudhISCgpvc192ZXJzaW9uGAEgASgJEhcKD3dvcmtzcGFjZV9wYXRocxgCIAMoCRINCgVzaGVsbBgDIAEoCRIXCg9zYW5kYm94X2VuYWJsZWQYBSABKAgSGAoQdGVybWluYWxzX2ZvbGRlchgHIAEoCRIhChlhZ2VudF9zaGFyZWRfbm90ZXNfZm9sZGVyGAggASgJEicKH2FnZW50X2NvbnZlcnNhdGlvbl9ub3Rlc19mb2xkZXIYCSABKAkSEQoJdGltZV96b25lGAogASgJEhYKDnByb2plY3RfZm9sZGVyGAsgASgJEiAKGGFnZW50X3RyYW5zY3JpcHRzX2ZvbGRlchgMIAEoCSI8Cg9EZWJ1Z01vZGVDb25maWcSEAoIbG9nX3BhdGgYASABKAkSFwoPc2VydmVyX2VuZHBvaW50GAIgASgJIrQBCg9Ta2lsbERlc2NyaXB0b3ISDAoEbmFtZRgBIAEoCRITCgtkZXNjcmlwdGlvbhgCIAEoCRITCgtmb2xkZXJfcGF0aBgDIAEoCRIPCgdlbmFibGVkGAQgASgIEhgKC3BhcnNlX2Vycm9yGAUgASgJSACIAQESGAoQcmVhZG1lX2ZpbGVfcGF0aBgGIAEoCRIUCgxwYWNrYWdlX3R5cGUYByABKAVCDgoMX3BhcnNlX2Vycm9yIkQKDFNraWxsT3B0aW9ucxI0ChFza2lsbF9kZXNjcmlwdG9ycxgBIAMoCzIZLmFnZW50LnYxLlNraWxsRGVzY3JpcHRvciL2CAoOUmVxdWVzdENvbnRleHQSIwoFcnVsZXMYAiADKAsyFC5hZ2VudC52MS5DdXJzb3JSdWxlEigKA2VudhgEIAEoCzIbLmFnZW50LnYxLlJlcXVlc3RDb250ZXh0RW52EjkKD3JlcG9zaXRvcnlfaW5mbxgGIAMoCzIgLmFnZW50LnYxLlJlcG9zaXRvcnlJbmRleGluZ0luZm8SKgoFdG9vbHMYByADKAsyGy5hZ2VudC52MS5NY3BUb29sRGVmaW5pdGlvbhInChpjb252ZXJzYXRpb25fbm90ZXNfbGlzdGluZxgIIAEoCUgAiAEBEiEKFHNoYXJlZF9ub3Rlc19saXN0aW5nGAkgASgJSAGIAQESKAoJZ2l0X3JlcG9zGAsgAygLMhUuYWdlbnQudjEuR2l0UmVwb0luZm8SNgoPcHJvamVjdF9sYXlvdXRzGA0gAygLMh0uYWdlbnQudjEuTHNEaXJlY3RvcnlUcmVlTm9kZRIzChBtY3BfaW5zdHJ1Y3Rpb25zGA4gAygLMhkuYWdlbnQudjEuTWNwSW5zdHJ1Y3Rpb25zEjkKEWRlYnVnX21vZGVfY29uZmlnGA8gASgLMhkuYWdlbnQudjEuRGVidWdNb2RlQ29uZmlnSAKIAQESFwoKY2xvdWRfcnVsZRgQIAEoCUgDiAEBEh8KEndlYl9zZWFyY2hfZW5hYmxlZBgRIAEoCEgEiAEBEjIKDXNraWxsX29wdGlvbnMYEiABKAsyFi5hZ2VudC52MS5Ta2lsbE9wdGlvbnNIBYgBARIuCiFyZXBvc2l0b3J5X2luZm9fc2hvdWxkX3F1ZXJ5X3Byb2QYEyABKAhIBogBARJBCg1maWxlX2NvbnRlbnRzGBQgAygLMiouYWdlbnQudjEuUmVxdWVzdENvbnRleHQuRmlsZUNvbnRlbnRzRW50cnkSIAoTdXNlcl9pbnRlbnRfc3VtbWFyeRgVIAEoCUgHiAEBEjIKEGN1c3RvbV9zdWJhZ2VudHMYFiADKAsyGC5hZ2VudC52MS5DdXN0b21TdWJhZ2VudBJEChdtY3BfZmlsZV9zeXN0ZW1fb3B0aW9ucxgXIAEoCzIeLmFnZW50LnYxLk1jcEZpbGVTeXN0ZW1PcHRpb25zSAiIAQEaMwoRRmlsZUNvbnRlbnRzRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4AUIdChtfY29udmVyc2F0aW9uX25vdGVzX2xpc3RpbmdCFwoVX3NoYXJlZF9ub3Rlc19saXN0aW5nQhQKEl9kZWJ1Z19tb2RlX2NvbmZpZ0INCgtfY2xvdWRfcnVsZUIVChNfd2ViX3NlYXJjaF9lbmFibGVkQhAKDl9za2lsbF9vcHRpb25zQiQKIl9yZXBvc2l0b3J5X2luZm9fc2hvdWxkX3F1ZXJ5X3Byb2RCFgoUX3VzZXJfaW50ZW50X3N1bW1hcnlCGgoYX21jcF9maWxlX3N5c3RlbV9vcHRpb25zIrICCg1TYW5kYm94UG9saWN5EgwKBHR5cGUYASABKAUSGwoObmV0d29ya19hY2Nlc3MYAiABKAhIAIgBARIiChphZGRpdGlvbmFsX3JlYWR3cml0ZV9wYXRocxgDIAMoCRIhChlhZGRpdGlvbmFsX3JlYWRvbmx5X3BhdGhzGAQgAygJEh0KEGRlYnVnX291dHB1dF9kaXIYBSABKAlIAYgBARIdChBibG9ja19naXRfd3JpdGVzGAYgASgISAKIAQESHgoRZGlzYWJsZV90bXBfd3JpdGUYByABKAhIA4gBAUIRCg9fbmV0d29ya19hY2Nlc3NCEwoRX2RlYnVnX291dHB1dF9kaXJCEwoRX2Jsb2NrX2dpdF93cml0ZXNCFAoSX2Rpc2FibGVfdG1wX3dyaXRlIu8BCg1TZWxlY3RlZEltYWdlEgwKBHV1aWQYAiABKAkSDAoEcGF0aBgDIAEoCRI0CglkaW1lbnNpb24YBCABKAsyIS5hZ2VudC52MS5TZWxlY3RlZEltYWdlX0RpbWVuc2lvbhIRCgltaW1lX3R5cGUYByABKAkSEQoHYmxvYl9pZBgBIAEoDEgAEg4KBGRhdGEYCCABKAxIABJDChFibG9iX2lkX3dpdGhfZGF0YRgJIAEoCzImLmFnZW50LnYxLlNlbGVjdGVkSW1hZ2VfQmxvYklkV2l0aERhdGFIAEIRCg9kYXRhX29yX2Jsb2JfaWQiPQocU2VsZWN0ZWRJbWFnZV9CbG9iSWRXaXRoRGF0YRIPCgdibG9iX2lkGAEgASgMEgwKBGRhdGEYAiABKAwiOAoXU2VsZWN0ZWRJbWFnZV9EaW1lbnNpb24SDQoFd2lkdGgYASABKAUSDgoGaGVpZ2h0GAIgASgFIkkKEUV4dHJhQ29udGV4dEVudHJ5Eg4KBGRhdGEYASABKAlIABIRCgdibG9iX2lkGAIgASgMSABCEQoPZGF0YV9vcl9ibG9iX2lkIlsKDFNlbGVjdGVkRmlsZRIPCgdjb250ZW50GAEgASgJEgwKBHBhdGgYAiABKAkSGgoNcmVsYXRpdmVfcGF0aBgDIAEoCUgAiAEBQhAKDl9yZWxhdGl2ZV9wYXRoIoQBChVTZWxlY3RlZENvZGVTZWxlY3Rpb24SDwoHY29udGVudBgBIAEoCRIMCgRwYXRoGAIgASgJEhoKDXJlbGF0aXZlX3BhdGgYAyABKAlIAIgBARIeCgVyYW5nZRgEIAEoCzIPLmFnZW50LnYxLlJhbmdlQhAKDl9yZWxhdGl2ZV9wYXRoIl0KEFNlbGVjdGVkVGVybWluYWwSDwoHY29udGVudBgBIAEoCRISCgV0aXRsZRgCIAEoCUgAiAEBEhEKBHBhdGgYAyABKAlIAYgBAUIICgZfdGl0bGVCBwoFX3BhdGgihgEKGVNlbGVjdGVkVGVybWluYWxTZWxlY3Rpb24SDwoHY29udGVudBgBIAEoCRISCgV0aXRsZRgCIAEoCUgAiAEBEhEKBHBhdGgYAyABKAlIAYgBARIeCgVyYW5nZRgEIAEoCzIPLmFnZW50LnYxLlJhbmdlQggKBl90aXRsZUIHCgVfcGF0aCKDAQoOU2VsZWN0ZWRGb2xkZXISDAoEcGF0aBgBIAEoCRIaCg1yZWxhdGl2ZV9wYXRoGAIgASgJSACIAQESNQoOZGlyZWN0b3J5X3RyZWUYAyABKAsyHS5hZ2VudC52MS5Mc0RpcmVjdG9yeVRyZWVOb2RlQhAKDl9yZWxhdGl2ZV9wYXRoIp8BChRTZWxlY3RlZEV4dGVybmFsTGluaxILCgN1cmwYASABKAkSDAoEdXVpZBgCIAEoCRIYCgtwZGZfY29udGVudBgDIAEoCUgAiAEBEhMKBmlzX3BkZhgEIAEoCEgBiAEBEhUKCGZpbGVuYW1lGAUgASgJSAKIAQFCDgoMX3BkZl9jb250ZW50QgkKB19pc19wZGZCCwoJX2ZpbGVuYW1lIjgKElNlbGVjdGVkQ3Vyc29yUnVsZRIiCgRydWxlGAEgASgLMhQuYWdlbnQudjEuQ3Vyc29yUnVsZSIiCg9TZWxlY3RlZEdpdERpZmYSDwoHY29udGVudBgBIAEoCSIyCh9TZWxlY3RlZEdpdERpZmZGcm9tQnJhbmNoVG9NYWluEg8KB2NvbnRlbnQYASABKAkiaQoRU2VsZWN0ZWRHaXRDb21taXQSCwoDc2hhGAEgASgJEg8KB21lc3NhZ2UYAiABKAkSGAoLZGVzY3JpcHRpb24YAyABKAlIAIgBARIMCgRkaWZmGAQgASgJQg4KDF9kZXNjcmlwdGlvbiLdAQoTU2VsZWN0ZWRQdWxsUmVxdWVzdBIOCgZudW1iZXIYASABKAUSCwoDdXJsGAIgASgJEhIKBXRpdGxlGAMgASgJSACIAQESEwoLZm9sZGVyX3BhdGgYBCABKAkSGQoMc3VtbWFyeV9qc29uGAUgASgJSAGIAQESGAoLZGVzY3JpcHRpb24YBiABKAlIAogBARIUCgdibG9iX2lkGAcgASgMSAOIAQFCCAoGX3RpdGxlQg8KDV9zdW1tYXJ5X2pzb25CDgoMX2Rlc2NyaXB0aW9uQgoKCF9ibG9iX2lkIrMBChpTZWxlY3RlZEdpdFBSRGlmZlNlbGVjdGlvbhIOCgZwcl91cmwYASABKAkSEQoJZmlsZV9wYXRoGAIgASgJEhIKCnN0YXJ0X2xpbmUYAyABKAUSEAoIZW5kX2xpbmUYBCABKAUSGQoMZGlmZl9jb250ZW50GAUgASgJSACIAQESFAoHYmxvYl9pZBgGIAEoDEgBiAEBQg8KDV9kaWZmX2NvbnRlbnRCCgoIX2Jsb2JfaWQiNgoVU2VsZWN0ZWRDdXJzb3JDb21tYW5kEgwKBG5hbWUYASABKAkSDwoHY29udGVudBgCIAEoCSI1ChVTZWxlY3RlZERvY3VtZW50YXRpb24SDgoGZG9jX2lkGAEgASgJEgwKBG5hbWUYAiABKAkiMgoQU2VsZWN0ZWRQYXN0Q2hhdBIQCghhZ2VudF9pZBgBIAEoCRIMCgRuYW1lGAIgASgJIqsBCglDYWxsRnJhbWUSGgoNZnVuY3Rpb25fbmFtZRgBIAEoCUgAiAEBEhAKA3VybBgCIAEoCUgBiAEBEhgKC2xpbmVfbnVtYmVyGAMgASgFSAKIAQESGgoNY29sdW1uX251bWJlchgEIAEoBUgDiAEBQhAKDl9mdW5jdGlvbl9uYW1lQgYKBF91cmxCDgoMX2xpbmVfbnVtYmVyQhAKDl9jb2x1bW5fbnVtYmVyImgKClN0YWNrVHJhY2USKAoLY2FsbF9mcmFtZXMYASADKAsyEy5hZ2VudC52MS5DYWxsRnJhbWUSHAoPcmF3X3N0YWNrX3RyYWNlGAIgASgJSACIAQFCEgoQX3Jhd19zdGFja190cmFjZSLkAQoSU2VsZWN0ZWRDb25zb2xlTG9nEg8KB21lc3NhZ2UYASABKAkSEQoJdGltZXN0YW1wGAIgASgBEg0KBWxldmVsGAMgASgJEhMKC2NsaWVudF9uYW1lGAQgASgJEhIKCnNlc3Npb25faWQYBSABKAkSLgoLc3RhY2tfdHJhY2UYBiABKAsyFC5hZ2VudC52MS5TdGFja1RyYWNlSACIAQESHQoQb2JqZWN0X2RhdGFfanNvbhgHIAEoCUgBiAEBQg4KDF9zdGFja190cmFjZUITChFfb2JqZWN0X2RhdGFfanNvbiK6AQoRU2VsZWN0ZWRVSUVsZW1lbnQSDwoHZWxlbWVudBgBIAEoCRINCgV4cGF0aBgCIAEoCRIUCgx0ZXh0X2NvbnRlbnQYAyABKAkSDQoFZXh0cmEYBCABKAkSFgoJY29tcG9uZW50GAUgASgJSACIAQESIQoUY29tcG9uZW50X3Byb3BzX2pzb24YBiABKAlIAYgBAUIMCgpfY29tcG9uZW50QhcKFV9jb21wb25lbnRfcHJvcHNfanNvbiIgChBTZWxlY3RlZFN1YmFnZW50EgwKBG5hbWUYASABKAkiggoKD1NlbGVjdGVkQ29udGV4dBIwCg9zZWxlY3RlZF9pbWFnZXMYASADKAsyFy5hZ2VudC52MS5TZWxlY3RlZEltYWdlEjwKEmludm9jYXRpb25fY29udGV4dBgCIAEoCzIbLmFnZW50LnYxLkludm9jYXRpb25Db250ZXh0SACIAQESFQoNZXh0cmFfY29udGV4dBgDIAMoCRI6ChVleHRyYV9jb250ZXh0X2VudHJpZXMYECADKAsyGy5hZ2VudC52MS5FeHRyYUNvbnRleHRFbnRyeRIlCgVmaWxlcxgEIAMoCzIWLmFnZW50LnYxLlNlbGVjdGVkRmlsZRI4Cg9jb2RlX3NlbGVjdGlvbnMYBSADKAsyHy5hZ2VudC52MS5TZWxlY3RlZENvZGVTZWxlY3Rpb24SLQoJdGVybWluYWxzGAYgAygLMhouYWdlbnQudjEuU2VsZWN0ZWRUZXJtaW5hbBJAChN0ZXJtaW5hbF9zZWxlY3Rpb25zGAcgAygLMiMuYWdlbnQudjEuU2VsZWN0ZWRUZXJtaW5hbFNlbGVjdGlvbhIpCgdmb2xkZXJzGAggAygLMhguYWdlbnQudjEuU2VsZWN0ZWRGb2xkZXISNgoOZXh0ZXJuYWxfbGlua3MYCSADKAsyHi5hZ2VudC52MS5TZWxlY3RlZEV4dGVybmFsTGluaxIyCgxjdXJzb3JfcnVsZXMYCiADKAsyHC5hZ2VudC52MS5TZWxlY3RlZEN1cnNvclJ1bGUSMAoIZ2l0X2RpZmYYEiABKAsyGS5hZ2VudC52MS5TZWxlY3RlZEdpdERpZmZIAYgBARJUChxnaXRfZGlmZl9mcm9tX2JyYW5jaF90b19tYWluGAsgASgLMikuYWdlbnQudjEuU2VsZWN0ZWRHaXREaWZmRnJvbUJyYW5jaFRvTWFpbkgCiAEBEjgKD2N1cnNvcl9jb21tYW5kcxgMIAMoCzIfLmFnZW50LnYxLlNlbGVjdGVkQ3Vyc29yQ29tbWFuZBI3Cg5kb2N1bWVudGF0aW9ucxgNIAMoCzIfLmFnZW50LnYxLlNlbGVjdGVkRG9jdW1lbnRhdGlvbhIwCgt1aV9lbGVtZW50cxgOIAMoCzIbLmFnZW50LnYxLlNlbGVjdGVkVUlFbGVtZW50EjIKDGNvbnNvbGVfbG9ncxgPIAMoCzIcLmFnZW50LnYxLlNlbGVjdGVkQ29uc29sZUxvZxIwCgtnaXRfY29tbWl0cxgRIAMoCzIbLmFnZW50LnYxLlNlbGVjdGVkR2l0Q29tbWl0Ei4KCnBhc3RfY2hhdHMYEyADKAsyGi5hZ2VudC52MS5TZWxlY3RlZFBhc3RDaGF0EkQKFmdpdF9wcl9kaWZmX3NlbGVjdGlvbnMYFCADKAsyJC5hZ2VudC52MS5TZWxlY3RlZEdpdFBSRGlmZlNlbGVjdGlvbhI9ChZzZWxlY3RlZF9wdWxsX3JlcXVlc3RzGBUgAygLMh0uYWdlbnQudjEuU2VsZWN0ZWRQdWxsUmVxdWVzdBI2ChJzZWxlY3RlZF9zdWJhZ2VudHMYFiADKAsyGi5hZ2VudC52MS5TZWxlY3RlZFN1YmFnZW50QhUKE19pbnZvY2F0aW9uX2NvbnRleHRCCwoJX2dpdF9kaWZmQh8KHV9naXRfZGlmZl9mcm9tX2JyYW5jaF90b19tYWluIuUBChFJbnZvY2F0aW9uQ29udGV4dBI/CgxzbGFja190aHJlYWQYASABKAsyJy5hZ2VudC52MS5JbnZvY2F0aW9uQ29udGV4dF9TbGFja1RocmVhZEgAEjkKCWdpdGh1Yl9wchgCIAEoCzIkLmFnZW50LnYxLkludm9jYXRpb25Db250ZXh0X0dpdGh1YlBSSAASOQoJaWRlX3N0YXRlGAMgASgLMiQuYWdlbnQudjEuSW52b2NhdGlvbkNvbnRleHRfSWRlU3RhdGVIABIRCgdibG9iX2lkGAogASgMSABCBgoEZGF0YSK7AQodSW52b2NhdGlvbkNvbnRleHRfU2xhY2tUaHJlYWQSDgoGdGhyZWFkGAEgASgJEhkKDGNoYW5uZWxfbmFtZRgCIAEoCUgAiAEBEhwKD2NoYW5uZWxfcHVycG9zZRgDIAEoCUgBiAEBEhoKDWNoYW5uZWxfdG9waWMYBCABKAlIAogBAUIPCg1fY2hhbm5lbF9uYW1lQhIKEF9jaGFubmVsX3B1cnBvc2VCEAoOX2NoYW5uZWxfdG9waWMifAoaSW52b2NhdGlvbkNvbnRleHRfR2l0aHViUFISDQoFdGl0bGUYASABKAkSEwoLZGVzY3JpcHRpb24YAiABKAkSEAoIY29tbWVudHMYAyABKAkSGAoLY2lfZmFpbHVyZXMYBCABKAlIAIgBAUIOCgxfY2lfZmFpbHVyZXMi/gEKGkludm9jYXRpb25Db250ZXh0X0lkZVN0YXRlEkAKDXZpc2libGVfZmlsZXMYASADKAsyKS5hZ2VudC52MS5JbnZvY2F0aW9uQ29udGV4dF9JZGVTdGF0ZV9GaWxlEkgKFXJlY2VudGx5X3ZpZXdlZF9maWxlcxgCIAMoCzIpLmFnZW50LnYxLkludm9jYXRpb25Db250ZXh0X0lkZVN0YXRlX0ZpbGUSVAoUY3VycmVudGx5X3ZpZXdlZF9wcnMYAyADKAsyNi5hZ2VudC52MS5JbnZvY2F0aW9uQ29udGV4dF9JZGVTdGF0ZV9WaWV3ZWRQdWxsUmVxdWVzdCKOAgofSW52b2NhdGlvbkNvbnRleHRfSWRlU3RhdGVfRmlsZRIMCgRwYXRoGAEgASgJEhoKDXJlbGF0aXZlX3BhdGgYAiABKAlIAIgBARJWCg9jdXJzb3JfcG9zaXRpb24YAyABKAsyOC5hZ2VudC52MS5JbnZvY2F0aW9uQ29udGV4dF9JZGVTdGF0ZV9GaWxlX0N1cnNvclBvc2l0aW9uSAGIAQESEwoLdG90YWxfbGluZXMYBCABKAUSGwoOYWN0aXZlX2NvbW1hbmQYBSABKAlIAogBAUIQCg5fcmVsYXRpdmVfcGF0aEISChBfY3Vyc29yX3Bvc2l0aW9uQhEKD19hY3RpdmVfY29tbWFuZCJMCi5JbnZvY2F0aW9uQ29udGV4dF9JZGVTdGF0ZV9GaWxlX0N1cnNvclBvc2l0aW9uEgwKBGxpbmUYASABKAUSDAoEdGV4dBgCIAEoCSLpAQosSW52b2NhdGlvbkNvbnRleHRfSWRlU3RhdGVfVmlld2VkUHVsbFJlcXVlc3QSDgoGbnVtYmVyGAEgASgFEgsKA3VybBgCIAEoCRISCgV0aXRsZRgDIAEoCUgAiAEBEhgKC2ZvbGRlcl9wYXRoGAQgASgJSAGIAQESGQoMc3VtbWFyeV9qc29uGAUgASgJSAKIAQESGAoLZGVzY3JpcHRpb24YBiABKAlIA4gBAUIICgZfdGl0bGVCDgoMX2ZvbGRlcl9wYXRoQg8KDV9zdW1tYXJ5X2pzb25CDgoMX2Rlc2NyaXB0aW9uIkgKFlNldHVwVm1FbnZpcm9ubWVudEFyZ3MSFwoPaW5zdGFsbF9jb21tYW5kGAIgASgJEhUKDXN0YXJ0X2NvbW1hbmQYAyABKAkiXAoYU2V0dXBWbUVudmlyb25tZW50UmVzdWx0EjYKB3N1Y2Nlc3MYASABKAsyIy5hZ2VudC52MS5TZXR1cFZtRW52aXJvbm1lbnRTdWNjZXNzSABCCAoGcmVzdWx0IhsKGVNldHVwVm1FbnZpcm9ubWVudFN1Y2Nlc3MigAEKGlNldHVwVm1FbnZpcm9ubWVudFRvb2xDYWxsEi4KBGFyZ3MYASABKAsyIC5hZ2VudC52MS5TZXR1cFZtRW52aXJvbm1lbnRBcmdzEjIKBnJlc3VsdBgCIAEoCzIiLmFnZW50LnYxLlNldHVwVm1FbnZpcm9ubWVudFJlc3VsdCLJAgoZU2hlbGxDb21tYW5kUGFyc2luZ1Jlc3VsdBIWCg5wYXJzaW5nX2ZhaWxlZBgBIAEoCBJSChNleGVjdXRhYmxlX2NvbW1hbmRzGAIgAygLMjUuYWdlbnQudjEuU2hlbGxDb21tYW5kUGFyc2luZ1Jlc3VsdF9FeGVjdXRhYmxlQ29tbWFuZBIVCg1oYXNfcmVkaXJlY3RzGAMgASgIEiAKGGhhc19jb21tYW5kX3N1YnN0aXR1dGlvbhgEIAEoCBInChphbGxfcmVkaXJlY3RzX2FyZV9kZXZfbnVsbBgFIAEoCEgAiAEBEj8KCXJlZGlyZWN0cxgGIAMoCzIsLmFnZW50LnYxLlNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHRfUmVkaXJlY3RCHQobX2FsbF9yZWRpcmVjdHNfYXJlX2Rldl9udWxsIk0KLlNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHRfRXhlY3V0YWJsZUNvbW1hbmRBcmcSDAoEdHlwZRgBIAEoCRINCgV2YWx1ZRgCIAEoCSKWAQorU2hlbGxDb21tYW5kUGFyc2luZ1Jlc3VsdF9FeGVjdXRhYmxlQ29tbWFuZBIMCgRuYW1lGAEgASgJEkYKBGFyZ3MYAiADKAsyOC5hZ2VudC52MS5TaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0X0V4ZWN1dGFibGVDb21tYW5kQXJnEhEKCWZ1bGxfdGV4dBgDIAEoCSL6BwoJU2hlbGxBcmdzEg8KB2NvbW1hbmQYASABKAkSGQoRd29ya2luZ19kaXJlY3RvcnkYAiABKAkSDwoHdGltZW91dBgDIAEoBRIUCgx0b29sX2NhbGxfaWQYBCABKAkSFwoPc2ltcGxlX2NvbW1hbmRzGAUgAygJEhoKEmhhc19pbnB1dF9yZWRpcmVjdBgGIAEoCBIbChNoYXNfb3V0cHV0X3JlZGlyZWN0GAcgASgIEjsKDnBhcnNpbmdfcmVzdWx0GAggASgLMiMuYWdlbnQudjEuU2hlbGxDb21tYW5kUGFyc2luZ1Jlc3VsdBI+ChhyZXF1ZXN0ZWRfc2FuZGJveF9wb2xpY3kYCSABKAsyFy5hZ2VudC52MS5TYW5kYm94UG9saWN5SACIAQESKAobZmlsZV9vdXRwdXRfdGhyZXNob2xkX2J5dGVzGAogASgESAGIAQESFQoNaXNfYmFja2dyb3VuZBgLIAEoCBIVCg1za2lwX2FwcHJvdmFsGAwgASgIEhgKEHRpbWVvdXRfYmVoYXZpb3IYDSABKAUSGQoMaGFyZF90aW1lb3V0GA4gASgFSAKIAQESGAoLZGVzY3JpcHRpb24YDyABKAlIA4gBARJBChFjbGFzc2lmaWVyX3Jlc3VsdBgQIAEoCzIhLmFnZW50LnYxLkNvbW1hbmRDbGFzc2lmaWVyUmVzdWx0SASIAQESEwoLY2xvc2Vfc3RkaW4YESABKAgSSQoTb3V0cHV0X25vdGlmaWNhdGlvbhgSIAEoCzInLmFnZW50LnYxLlNoZWxsT3V0cHV0Tm90aWZpY2F0aW9uQ29uZmlnSAWIAQESPQoTc21hcnRfbW9kZV9hcHByb3ZhbBgTIAEoCzIbLmFnZW50LnYxLlNtYXJ0TW9kZUFwcHJvdmFsSAaIAQESTgoZaG9va19hcHByb3ZhbF9yZXF1aXJlbWVudBgUIAEoCzImLmFnZW50LnYxLlNoZWxsSG9va0FwcHJvdmFsUmVxdWlyZW1lbnRIB4gBARIcCg9jb252ZXJzYXRpb25faWQYFSABKAlICIgBAUIbChlfcmVxdWVzdGVkX3NhbmRib3hfcG9saWN5Qh4KHF9maWxlX291dHB1dF90aHJlc2hvbGRfYnl0ZXNCDwoNX2hhcmRfdGltZW91dEIOCgxfZGVzY3JpcHRpb25CFAoSX2NsYXNzaWZpZXJfcmVzdWx0QhYKFF9vdXRwdXRfbm90aWZpY2F0aW9uQhYKFF9zbWFydF9tb2RlX2FwcHJvdmFsQhwKGl9ob29rX2FwcHJvdmFsX3JlcXVpcmVtZW50QhIKEF9jb252ZXJzYXRpb25faWQi+gMKC1NoZWxsUmVzdWx0EjQKDnNhbmRib3hfcG9saWN5GGUgASgLMhcuYWdlbnQudjEuU2FuZGJveFBvbGljeUgBiAEBEhoKDWlzX2JhY2tncm91bmQYZiABKAhIAogBARIdChB0ZXJtaW5hbHNfZm9sZGVyGGcgASgJSAOIAQESEAoDcGlkGGggASgNSASIAQESKQoHc3VjY2VzcxgBIAEoCzIWLmFnZW50LnYxLlNoZWxsU3VjY2Vzc0gAEikKB2ZhaWx1cmUYAiABKAsyFi5hZ2VudC52MS5TaGVsbEZhaWx1cmVIABIpCgd0aW1lb3V0GAMgASgLMhYuYWdlbnQudjEuU2hlbGxUaW1lb3V0SAASKwoIcmVqZWN0ZWQYBCABKAsyFy5hZ2VudC52MS5TaGVsbFJlamVjdGVkSAASMAoLc3Bhd25fZXJyb3IYBSABKAsyGS5hZ2VudC52MS5TaGVsbFNwYXduRXJyb3JIABI8ChFwZXJtaXNzaW9uX2RlbmllZBgHIAEoCzIfLmFnZW50LnYxLlNoZWxsUGVybWlzc2lvbkRlbmllZEgAQggKBnJlc3VsdEIRCg9fc2FuZGJveF9wb2xpY3lCEAoOX2lzX2JhY2tncm91bmRCEwoRX3Rlcm1pbmFsc19mb2xkZXJCBgoEX3BpZCIhChFTaGVsbFN0cmVhbVN0ZG91dBIMCgRkYXRhGAEgASgJIiEKEVNoZWxsU3RyZWFtU3RkZXJyEgwKBGRhdGEYASABKAki9wEKD1NoZWxsU3RyZWFtRXhpdBIMCgRjb2RlGAEgASgNEgsKA2N3ZBgCIAEoCRI2Cg9vdXRwdXRfbG9jYXRpb24YAyABKAsyGC5hZ2VudC52MS5PdXRwdXRMb2NhdGlvbkgAiAEBEg8KB2Fib3J0ZWQYBCABKAgSGQoMYWJvcnRfcmVhc29uGAUgASgFSAGIAQESJAoXbG9jYWxfZXhlY3V0aW9uX3RpbWVfbXMYBiABKAVIAogBAUISChBfb3V0cHV0X2xvY2F0aW9uQg8KDV9hYm9ydF9yZWFzb25CGgoYX2xvY2FsX2V4ZWN1dGlvbl90aW1lX21zIlsKEFNoZWxsU3RyZWFtU3RhcnQSNAoOc2FuZGJveF9wb2xpY3kYASABKAsyFy5hZ2VudC52MS5TYW5kYm94UG9saWN5SACIAQFCEQoPX3NhbmRib3hfcG9saWN5ItoBChdTaGVsbFN0cmVhbUJhY2tncm91bmRlZBIQCghzaGVsbF9pZBgBIAEoDRIPCgdjb21tYW5kGAIgASgJEhkKEXdvcmtpbmdfZGlyZWN0b3J5GAMgASgJEhAKA3BpZBgEIAEoDUgAiAEBEhcKCm1zX3RvX3dhaXQYBSABKAVIAYgBARI0CgZyZWFzb24YBiABKA4yHy5hZ2VudC52MS5TaGVsbEJhY2tncm91bmRSZWFzb25IAogBAUIGCgRfcGlkQg0KC19tc190b193YWl0QgkKB19yZWFzb24irAMKC1NoZWxsU3RyZWFtEi0KBnN0ZG91dBgBIAEoCzIbLmFnZW50LnYxLlNoZWxsU3RyZWFtU3Rkb3V0SAASLQoGc3RkZXJyGAIgASgLMhsuYWdlbnQudjEuU2hlbGxTdHJlYW1TdGRlcnJIABIpCgRleGl0GAMgASgLMhkuYWdlbnQudjEuU2hlbGxTdHJlYW1FeGl0SAASKwoFc3RhcnQYBCABKAsyGi5hZ2VudC52MS5TaGVsbFN0cmVhbVN0YXJ0SAASKwoIcmVqZWN0ZWQYBSABKAsyFy5hZ2VudC52MS5TaGVsbFJlamVjdGVkSAASPAoRcGVybWlzc2lvbl9kZW5pZWQYBiABKAsyHy5hZ2VudC52MS5TaGVsbFBlcm1pc3Npb25EZW5pZWRIABI5CgxiYWNrZ3JvdW5kZWQYByABKAsyIS5hZ2VudC52MS5TaGVsbFN0cmVhbUJhY2tncm91bmRlZEgAEjgKDGhvb2tfY29udGV4dBgIIAEoCzIgLmFnZW50LnYxLlNoZWxsU3RyZWFtSG9va0NvbnRleHRIAEIHCgVldmVudCJLCg5PdXRwdXRMb2NhdGlvbhIRCglmaWxlX3BhdGgYASABKAkSEgoKc2l6ZV9ieXRlcxgCIAEoAxISCgpsaW5lX2NvdW50GAMgASgDIpgFCgxTaGVsbFN1Y2Nlc3MSDwoHY29tbWFuZBgBIAEoCRIZChF3b3JraW5nX2RpcmVjdG9yeRgCIAEoCRIRCglleGl0X2NvZGUYAyABKAUSDgoGc2lnbmFsGAQgASgJEg4KBnN0ZG91dBgFIAEoCRIOCgZzdGRlcnIYBiABKAkSFgoOZXhlY3V0aW9uX3RpbWUYByABKAUSNgoPb3V0cHV0X2xvY2F0aW9uGAggASgLMhguYWdlbnQudjEuT3V0cHV0TG9jYXRpb25IAIgBARIVCghzaGVsbF9pZBgJIAEoDUgBiAEBEh8KEmludGVybGVhdmVkX291dHB1dBgKIAEoCUgCiAEBEhAKA3BpZBgLIAEoDUgDiAEBEhcKCm1zX3RvX3dhaXQYDCABKAVIBIgBARIkChdsb2NhbF9leGVjdXRpb25fdGltZV9tcxgNIAEoBUgFiAEBEj8KEWJhY2tncm91bmRfcmVhc29uGA4gASgOMh8uYWdlbnQudjEuU2hlbGxCYWNrZ3JvdW5kUmVhc29uSAaIAQESGAoLb3V0cHV0X2hlYWQYDyABKAlIB4gBARIYCgtvdXRwdXRfdGFpbBgQIAEoCUgIiAEBEhkKDGVsaWRlZF9jaGFycxgRIAEoDUgJiAEBQhIKEF9vdXRwdXRfbG9jYXRpb25CCwoJX3NoZWxsX2lkQhUKE19pbnRlcmxlYXZlZF9vdXRwdXRCBgoEX3BpZEINCgtfbXNfdG9fd2FpdEIaChhfbG9jYWxfZXhlY3V0aW9uX3RpbWVfbXNCFAoSX2JhY2tncm91bmRfcmVhc29uQg4KDF9vdXRwdXRfaGVhZEIOCgxfb3V0cHV0X3RhaWxCDwoNX2VsaWRlZF9jaGFycyKYBAoMU2hlbGxGYWlsdXJlEg8KB2NvbW1hbmQYASABKAkSGQoRd29ya2luZ19kaXJlY3RvcnkYAiABKAkSEQoJZXhpdF9jb2RlGAMgASgFEg4KBnNpZ25hbBgEIAEoCRIOCgZzdGRvdXQYBSABKAkSDgoGc3RkZXJyGAYgASgJEhYKDmV4ZWN1dGlvbl90aW1lGAcgASgFEjYKD291dHB1dF9sb2NhdGlvbhgIIAEoCzIYLmFnZW50LnYxLk91dHB1dExvY2F0aW9uSACIAQESHwoSaW50ZXJsZWF2ZWRfb3V0cHV0GAkgASgJSAGIAQESGQoMYWJvcnRfcmVhc29uGAogASgFSAKIAQESDwoHYWJvcnRlZBgLIAEoCBIkChdsb2NhbF9leGVjdXRpb25fdGltZV9tcxgMIAEoBUgDiAEBEhgKC291dHB1dF9oZWFkGA0gASgJSASIAQESGAoLb3V0cHV0X3RhaWwYDiABKAlIBYgBARIZCgxlbGlkZWRfY2hhcnMYDyABKA1IBogBAUISChBfb3V0cHV0X2xvY2F0aW9uQhUKE19pbnRlcmxlYXZlZF9vdXRwdXRCDwoNX2Fib3J0X3JlYXNvbkIaChhfbG9jYWxfZXhlY3V0aW9uX3RpbWVfbXNCDgoMX291dHB1dF9oZWFkQg4KDF9vdXRwdXRfdGFpbEIPCg1fZWxpZGVkX2NoYXJzIk4KDFNoZWxsVGltZW91dBIPCgdjb21tYW5kGAEgASgJEhkKEXdvcmtpbmdfZGlyZWN0b3J5GAIgASgJEhIKCnRpbWVvdXRfbXMYAyABKAUiYAoNU2hlbGxSZWplY3RlZBIPCgdjb21tYW5kGAEgASgJEhkKEXdvcmtpbmdfZGlyZWN0b3J5GAIgASgJEg4KBnJlYXNvbhgDIAEoCRITCgtpc19yZWFkb25seRgEIAEoCCJnChVTaGVsbFBlcm1pc3Npb25EZW5pZWQSDwoHY29tbWFuZBgBIAEoCRIZChF3b3JraW5nX2RpcmVjdG9yeRgCIAEoCRINCgVlcnJvchgDIAEoCRITCgtpc19yZWFkb25seRgEIAEoCCJMCg9TaGVsbFNwYXduRXJyb3ISDwoHY29tbWFuZBgBIAEoCRIZChF3b3JraW5nX2RpcmVjdG9yeRgCIAEoCRINCgVlcnJvchgDIAEoCSJAChJTaGVsbFBhcnRpYWxSZXN1bHQSFAoMc3Rkb3V0X2RlbHRhGAEgASgJEhQKDHN0ZGVycl9kZWx0YRgCIAEoCSJZCg1TaGVsbFRvb2xDYWxsEiEKBGFyZ3MYASABKAsyEy5hZ2VudC52MS5TaGVsbEFyZ3MSJQoGcmVzdWx0GAIgASgLMhUuYWdlbnQudjEuU2hlbGxSZXN1bHQiKwoYU2hlbGxUb29sQ2FsbFN0ZG91dERlbHRhEg8KB2NvbnRlbnQYASABKAkiKwoYU2hlbGxUb29sQ2FsbFN0ZGVyckRlbHRhEg8KB2NvbnRlbnQYASABKAkiiQEKElNoZWxsVG9vbENhbGxEZWx0YRI0CgZzdGRvdXQYASABKAsyIi5hZ2VudC52MS5TaGVsbFRvb2xDYWxsU3Rkb3V0RGVsdGFIABI0CgZzdGRlcnIYAiABKAsyIi5hZ2VudC52MS5TaGVsbFRvb2xDYWxsU3RkZXJyRGVsdGFIAEIHCgVkZWx0YSLtAQoMU3ViYWdlbnRUeXBlEjgKC3Vuc3BlY2lmaWVkGAEgASgLMiEuYWdlbnQudjEuU3ViYWdlbnRUeXBlVW5zcGVjaWZpZWRIABI5Cgxjb21wdXRlcl91c2UYAiABKAsyIS5hZ2VudC52MS5TdWJhZ2VudFR5cGVDb21wdXRlclVzZUgAEi4KBmN1c3RvbRgDIAEoCzIcLmFnZW50LnYxLlN1YmFnZW50VHlwZUN1c3RvbUgAEjAKB2V4cGxvcmUYBCABKAsyHS5hZ2VudC52MS5TdWJhZ2VudFR5cGVFeHBsb3JlSABCBgoEdHlwZSIZChdTdWJhZ2VudFR5cGVVbnNwZWNpZmllZCIZChdTdWJhZ2VudFR5cGVDb21wdXRlclVzZSIVChNTdWJhZ2VudFR5cGVFeHBsb3JlIiIKElN1YmFnZW50VHlwZUN1c3RvbRIMCgRuYW1lGAEgASgJIo0BCg5DdXN0b21TdWJhZ2VudBIRCglmdWxsX3BhdGgYASABKAkSDAoEbmFtZRgCIAEoCRITCgtkZXNjcmlwdGlvbhgDIAEoCRINCgV0b29scxgEIAMoCRINCgVtb2RlbBgFIAEoCRIOCgZwcm9tcHQYBiABKAkSFwoPcGVybWlzc2lvbl9tb2RlGAcgASgFImgKDlN3aXRjaE1vZGVBcmdzEhYKDnRhcmdldF9tb2RlX2lkGAEgASgJEhgKC2V4cGxhbmF0aW9uGAIgASgJSACIAQESFAoMdG9vbF9jYWxsX2lkGAMgASgJQg4KDF9leHBsYW5hdGlvbiKqAQoQU3dpdGNoTW9kZVJlc3VsdBIuCgdzdWNjZXNzGAEgASgLMhsuYWdlbnQudjEuU3dpdGNoTW9kZVN1Y2Nlc3NIABIqCgVlcnJvchgCIAEoCzIZLmFnZW50LnYxLlN3aXRjaE1vZGVFcnJvckgAEjAKCHJlamVjdGVkGAMgASgLMhwuYWdlbnQudjEuU3dpdGNoTW9kZVJlamVjdGVkSABCCAoGcmVzdWx0Ij0KEVN3aXRjaE1vZGVTdWNjZXNzEhQKDGZyb21fbW9kZV9pZBgBIAEoCRISCgp0b19tb2RlX2lkGAIgASgJIiAKD1N3aXRjaE1vZGVFcnJvchINCgVlcnJvchgBIAEoCSIkChJTd2l0Y2hNb2RlUmVqZWN0ZWQSDgoGcmVhc29uGAEgASgJImgKElN3aXRjaE1vZGVUb29sQ2FsbBImCgRhcmdzGAEgASgLMhguYWdlbnQudjEuU3dpdGNoTW9kZUFyZ3MSKgoGcmVzdWx0GAIgASgLMhouYWdlbnQudjEuU3dpdGNoTW9kZVJlc3VsdCJAChZTd2l0Y2hNb2RlUmVxdWVzdFF1ZXJ5EiYKBGFyZ3MYASABKAsyGC5hZ2VudC52MS5Td2l0Y2hNb2RlQXJncyKpAQoZU3dpdGNoTW9kZVJlcXVlc3RSZXNwb25zZRJACghhcHByb3ZlZBgBIAEoCzIsLmFnZW50LnYxLlN3aXRjaE1vZGVSZXF1ZXN0UmVzcG9uc2VfQXBwcm92ZWRIABJACghyZWplY3RlZBgCIAEoCzIsLmFnZW50LnYxLlN3aXRjaE1vZGVSZXF1ZXN0UmVzcG9uc2VfUmVqZWN0ZWRIAEIICgZyZXN1bHQiJAoiU3dpdGNoTW9kZVJlcXVlc3RSZXNwb25zZV9BcHByb3ZlZCI0CiJTd2l0Y2hNb2RlUmVxdWVzdFJlc3BvbnNlX1JlamVjdGVkEg4KBnJlYXNvbhgBIAEoCSJ1CghUb2RvSXRlbRIKCgJpZBgBIAEoCRIPCgdjb250ZW50GAIgASgJEg4KBnN0YXR1cxgDIAEoBRISCgpjcmVhdGVkX2F0GAQgASgDEhIKCnVwZGF0ZWRfYXQYBSABKAMSFAoMZGVwZW5kZW5jaWVzGAYgAygJImsKE1VwZGF0ZVRvZG9zVG9vbENhbGwSJwoEYXJncxgBIAEoCzIZLmFnZW50LnYxLlVwZGF0ZVRvZG9zQXJncxIrCgZyZXN1bHQYAiABKAsyGy5hZ2VudC52MS5VcGRhdGVUb2Rvc1Jlc3VsdCJDCg9VcGRhdGVUb2Rvc0FyZ3MSIQoFdG9kb3MYASADKAsyEi5hZ2VudC52MS5Ub2RvSXRlbRINCgVtZXJnZRgCIAEoCCJ7ChFVcGRhdGVUb2Rvc1Jlc3VsdBIvCgdzdWNjZXNzGAEgASgLMhwuYWdlbnQudjEuVXBkYXRlVG9kb3NTdWNjZXNzSAASKwoFZXJyb3IYAiABKAsyGi5hZ2VudC52MS5VcGRhdGVUb2Rvc0Vycm9ySABCCAoGcmVzdWx0Il8KElVwZGF0ZVRvZG9zU3VjY2VzcxIhCgV0b2RvcxgBIAMoCzISLmFnZW50LnYxLlRvZG9JdGVtEhMKC3RvdGFsX2NvdW50GAIgASgFEhEKCXdhc19tZXJnZRgDIAEoCCIhChBVcGRhdGVUb2Rvc0Vycm9yEg0KBWVycm9yGAEgASgJImUKEVJlYWRUb2Rvc1Rvb2xDYWxsEiUKBGFyZ3MYASABKAsyFy5hZ2VudC52MS5SZWFkVG9kb3NBcmdzEikKBnJlc3VsdBgCIAEoCzIZLmFnZW50LnYxLlJlYWRUb2Rvc1Jlc3VsdCI5Cg1SZWFkVG9kb3NBcmdzEhUKDXN0YXR1c19maWx0ZXIYASADKAUSEQoJaWRfZmlsdGVyGAIgAygJInUKD1JlYWRUb2Rvc1Jlc3VsdBItCgdzdWNjZXNzGAEgASgLMhouYWdlbnQudjEuUmVhZFRvZG9zU3VjY2Vzc0gAEikKBWVycm9yGAIgASgLMhguYWdlbnQudjEuUmVhZFRvZG9zRXJyb3JIAEIICgZyZXN1bHQiSgoQUmVhZFRvZG9zU3VjY2VzcxIhCgV0b2RvcxgBIAMoCzISLmFnZW50LnYxLlRvZG9JdGVtEhMKC3RvdGFsX2NvdW50GAIgASgFIh8KDlJlYWRUb2Rvc0Vycm9yEg0KBWVycm9yGAEgASgJIksKBVJhbmdlEiEKBXN0YXJ0GAEgASgLMhIuYWdlbnQudjEuUG9zaXRpb24SHwoDZW5kGAIgASgLMhIuYWdlbnQudjEuUG9zaXRpb24iKAoIUG9zaXRpb24SDAoEbGluZRgBIAEoDRIOCgZjb2x1bW4YAiABKA0iGAoFRXJyb3ISDwoHbWVzc2FnZRgBIAEoCSI6Cg1XZWJTZWFyY2hBcmdzEhMKC3NlYXJjaF90ZXJtGAEgASgJEhQKDHRvb2xfY2FsbF9pZBgCIAEoCSKmAQoPV2ViU2VhcmNoUmVzdWx0Ei0KB3N1Y2Nlc3MYASABKAsyGi5hZ2VudC52MS5XZWJTZWFyY2hTdWNjZXNzSAASKQoFZXJyb3IYAiABKAsyGC5hZ2VudC52MS5XZWJTZWFyY2hFcnJvckgAEi8KCHJlamVjdGVkGAMgASgLMhsuYWdlbnQudjEuV2ViU2VhcmNoUmVqZWN0ZWRIAEIICgZyZXN1bHQiRAoQV2ViU2VhcmNoU3VjY2VzcxIwCgpyZWZlcmVuY2VzGAEgAygLMhwuYWdlbnQudjEuV2ViU2VhcmNoUmVmZXJlbmNlIh8KDldlYlNlYXJjaEVycm9yEg0KBWVycm9yGAEgASgJIiMKEVdlYlNlYXJjaFJlamVjdGVkEg4KBnJlYXNvbhgBIAEoCSI/ChJXZWJTZWFyY2hSZWZlcmVuY2USDQoFdGl0bGUYASABKAkSCwoDdXJsGAIgASgJEg0KBWNodW5rGAMgASgJImUKEVdlYlNlYXJjaFRvb2xDYWxsEiUKBGFyZ3MYASABKAsyFy5hZ2VudC52MS5XZWJTZWFyY2hBcmdzEikKBnJlc3VsdBgCIAEoCzIZLmFnZW50LnYxLldlYlNlYXJjaFJlc3VsdCI+ChVXZWJTZWFyY2hSZXF1ZXN0UXVlcnkSJQoEYXJncxgBIAEoCzIXLmFnZW50LnYxLldlYlNlYXJjaEFyZ3MipgEKGFdlYlNlYXJjaFJlcXVlc3RSZXNwb25zZRI/CghhcHByb3ZlZBgBIAEoCzIrLmFnZW50LnYxLldlYlNlYXJjaFJlcXVlc3RSZXNwb25zZV9BcHByb3ZlZEgAEj8KCHJlamVjdGVkGAIgASgLMisuYWdlbnQudjEuV2ViU2VhcmNoUmVxdWVzdFJlc3BvbnNlX1JlamVjdGVkSABCCAoGcmVzdWx0IiMKIVdlYlNlYXJjaFJlcXVlc3RSZXNwb25zZV9BcHByb3ZlZCIzCiFXZWJTZWFyY2hSZXF1ZXN0UmVzcG9uc2VfUmVqZWN0ZWQSDgoGcmVhc29uGAEgASgJIq0BCglXcml0ZUFyZ3MSDAoEcGF0aBgBIAEoCRIRCglmaWxlX3RleHQYAiABKAkSFAoMdG9vbF9jYWxsX2lkGAMgASgJEicKH3JldHVybl9maWxlX2NvbnRlbnRfYWZ0ZXJfd3JpdGUYBCABKAgSEgoKZmlsZV9ieXRlcxgFIAEoDBIaCg1lbmNvZGluZ19oaW50GAYgASgJSACIAQFCEAoOX2VuY29kaW5nX2hpbnQigAIKC1dyaXRlUmVzdWx0EikKB3N1Y2Nlc3MYASABKAsyFi5hZ2VudC52MS5Xcml0ZVN1Y2Nlc3NIABI8ChFwZXJtaXNzaW9uX2RlbmllZBgDIAEoCzIfLmFnZW50LnYxLldyaXRlUGVybWlzc2lvbkRlbmllZEgAEioKCG5vX3NwYWNlGAQgASgLMhYuYWdlbnQudjEuV3JpdGVOb1NwYWNlSAASJQoFZXJyb3IYBSABKAsyFC5hZ2VudC52MS5Xcml0ZUVycm9ySAASKwoIcmVqZWN0ZWQYBiABKAsyFy5hZ2VudC52MS5Xcml0ZVJlamVjdGVkSABCCAoGcmVzdWx0IooBCgxXcml0ZVN1Y2Nlc3MSDAoEcGF0aBgBIAEoCRIVCg1saW5lc19jcmVhdGVkGAIgASgFEhEKCWZpbGVfc2l6ZRgDIAEoBRIlChhmaWxlX2NvbnRlbnRfYWZ0ZXJfd3JpdGUYBCABKAlIAIgBAUIbChlfZmlsZV9jb250ZW50X2FmdGVyX3dyaXRlIm8KFVdyaXRlUGVybWlzc2lvbkRlbmllZBIMCgRwYXRoGAEgASgJEhEKCWRpcmVjdG9yeRgCIAEoCRIRCglvcGVyYXRpb24YAyABKAkSDQoFZXJyb3IYBCABKAkSEwoLaXNfcmVhZG9ubHkYBSABKAgiHAoMV3JpdGVOb1NwYWNlEgwKBHBhdGgYASABKAkiKQoKV3JpdGVFcnJvchIMCgRwYXRoGAEgASgJEg0KBWVycm9yGAIgASgJIi0KDVdyaXRlUmVqZWN0ZWQSDAoEcGF0aBgBIAEoCRIOCgZyZWFzb24YAiABKAkigwEKF0Jvb3RzdHJhcFN0YXRzaWdSZXF1ZXN0Eh4KEWlnbm9yZV9kZXZfc3RhdHVzGAEgASgISACIAQESHQoQb3BlcmF0aW5nX3N5c3RlbRgCIAEoBUgBiAEBQhQKEl9pZ25vcmVfZGV2X3N0YXR1c0ITChFfb3BlcmF0aW5nX3N5c3RlbSIOCgxQaW5nUmVzcG9uc2UitwEKC0V4ZWNSZXF1ZXN0Eg8KB2NvbW1hbmQYASABKAkSEAoDY3dkGAIgASgJSACIAQESDAoEYXJncxgDIAMoCRI7CgtlbnZpcm9ubWVudBgEIAMoCzImLmFnZW50LnYxLkV4ZWNSZXF1ZXN0LkVudmlyb25tZW50RW50cnkaMgoQRW52aXJvbm1lbnRFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBQgYKBF9jd2QioAEKDEV4ZWNSZXNwb25zZRItCgxzdGRvdXRfZXZlbnQYASABKAsyFS5hZ2VudC52MS5TdGRvdXRFdmVudEgAEi0KDHN0ZGVycl9ldmVudBgCIAEoCzIVLmFnZW50LnYxLlN0ZGVyckV2ZW50SAASKQoKZXhpdF9ldmVudBgDIAEoCzITLmFnZW50LnYxLkV4aXRFdmVudEgAQgcKBWV2ZW50IhsKC1N0ZG91dEV2ZW50EgwKBGRhdGEYASABKAkiGwoLU3RkZXJyRXZlbnQSDAoEZGF0YRgBIAEoCSIeCglFeGl0RXZlbnQSEQoJZXhpdF9jb2RlGAEgASgFIiMKE1JlYWRUZXh0RmlsZVJlcXVlc3QSDAoEcGF0aBgBIAEoCSInChRSZWFkVGV4dEZpbGVSZXNwb25zZRIPCgdjb250ZW50GAEgASgJIjUKFFdyaXRlVGV4dEZpbGVSZXF1ZXN0EgwKBHBhdGgYASABKAkSDwoHY29udGVudBgCIAEoCSIXChVXcml0ZVRleHRGaWxlUmVzcG9uc2UiJQoVUmVhZEJpbmFyeUZpbGVSZXF1ZXN0EgwKBHBhdGgYASABKAkiKQoWUmVhZEJpbmFyeUZpbGVSZXNwb25zZRIPCgdjb250ZW50GAEgASgMIjcKFldyaXRlQmluYXJ5RmlsZVJlcXVlc3QSDAoEcGF0aBgBIAEoCRIPCgdjb250ZW50GAIgASgMIhkKF1dyaXRlQmluYXJ5RmlsZVJlc3BvbnNlIkUKHkdldFdvcmtzcGFjZUNoYW5nZXNIYXNoUmVxdWVzdBIRCglyb290X3BhdGgYASABKAkSEAoIYmFzZV9yZWYYAiABKAkiLwofR2V0V29ya3NwYWNlQ2hhbmdlc0hhc2hSZXNwb25zZRIMCgRoYXNoGAEgASgJIlAKH1JlZnJlc2hHaXRodWJBY2Nlc3NUb2tlblJlcXVlc3QSGwoTZ2l0aHViX2FjY2Vzc190b2tlbhgBIAEoCRIQCghob3N0bmFtZRgCIAEoCSIiCiBSZWZyZXNoR2l0aHViQWNjZXNzVG9rZW5SZXNwb25zZSJXCh1XYXJtUmVtb3RlQWNjZXNzU2VydmVyUmVxdWVzdBIOCgZjb21taXQYASABKAkSDAoEcG9ydBgCIAEoBRIYChBjb25uZWN0aW9uX3Rva2VuGAMgASgJIiAKHldhcm1SZW1vdGVBY2Nlc3NTZXJ2ZXJSZXNwb25zZSIWChRMaXN0QXJ0aWZhY3RzUmVxdWVzdCKKAgoWQXJ0aWZhY3RVcGxvYWRNZXRhZGF0YRIVCg1hYnNvbHV0ZV9wYXRoGAEgASgJEhIKCnNpemVfYnl0ZXMYAiABKAQSGgoSdXBkYXRlZF9hdF91bml4X21zGAMgASgDEg4KBnN0YXR1cxgEIAEoBRIWCg5ieXRlc191cGxvYWRlZBgFIAEoBBISCgpsYXN0X2Vycm9yGAYgASgJEhcKD3VwbG9hZF9hdHRlbXB0cxgHIAEoDRIfChdsYXN0X3N0YXJ0ZWRfYXRfdW5peF9tcxgIIAEoAxIgChhsYXN0X2ZpbmlzaGVkX2F0X3VuaXhfbXMYCSABKAMSEQoJdXBsb2FkX2lkGAogASgJIkwKFUxpc3RBcnRpZmFjdHNSZXNwb25zZRIzCglhcnRpZmFjdHMYASADKAsyIC5hZ2VudC52MS5BcnRpZmFjdFVwbG9hZE1ldGFkYXRhIk4KFlVwbG9hZEFydGlmYWN0c1JlcXVlc3QSNAoHdXBsb2FkcxgBIAMoCzIjLmFnZW50LnYxLkFydGlmYWN0VXBsb2FkSW5zdHJ1Y3Rpb24i1wIKGUFydGlmYWN0VXBsb2FkSW5zdHJ1Y3Rpb24SFQoNYWJzb2x1dGVfcGF0aBgBIAEoCRISCgp1cGxvYWRfdXJsGAIgASgJEg4KBm1ldGhvZBgDIAEoCRJBCgdoZWFkZXJzGAQgAygLMjAuYWdlbnQudjEuQXJ0aWZhY3RVcGxvYWRJbnN0cnVjdGlvbi5IZWFkZXJzRW50cnkSGQoMY29udGVudF90eXBlGAUgASgJSACIAQESHQoQc2xhY2tfdXBsb2FkX3VybBgGIAEoCUgBiAEBEhoKDXNsYWNrX2ZpbGVfaWQYByABKAlIAogBARouCgxIZWFkZXJzRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4AUIPCg1fY29udGVudF90eXBlQhMKEV9zbGFja191cGxvYWRfdXJsQhAKDl9zbGFja19maWxlX2lkIoQBChxBcnRpZmFjdFVwbG9hZERpc3BhdGNoUmVzdWx0EhUKDWFic29sdXRlX3BhdGgYASABKAkSDgoGc3RhdHVzGAIgASgFEg8KB21lc3NhZ2UYAyABKAkSGgoNc2xhY2tfZmlsZV9pZBgEIAEoCUgAiAEBQhAKDl9zbGFja19maWxlX2lkIlIKF1VwbG9hZEFydGlmYWN0c1Jlc3BvbnNlEjcKB3Jlc3VsdHMYASADKAsyJi5hZ2VudC52MS5BcnRpZmFjdFVwbG9hZERpc3BhdGNoUmVzdWx0IhwKGkdldE1jcFJlZnJlc2hUb2tlbnNSZXF1ZXN0IqUBChtHZXRNY3BSZWZyZXNoVG9rZW5zUmVzcG9uc2USUAoOcmVmcmVzaF90b2tlbnMYASADKAsyOC5hZ2VudC52MS5HZXRNY3BSZWZyZXNoVG9rZW5zUmVzcG9uc2UuUmVmcmVzaFRva2Vuc0VudHJ5GjQKElJlZnJlc2hUb2tlbnNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIqMBCiFVcGRhdGVFbnZpcm9ubWVudFZhcmlhYmxlc1JlcXVlc3QSQQoDZW52GAEgAygLMjQuYWdlbnQudjEuVXBkYXRlRW52aXJvbm1lbnRWYXJpYWJsZXNSZXF1ZXN0LkVudkVudHJ5Eg8KB3JlcGxhY2UYAiABKAgaKgoIRW52RW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASJGCiJVcGRhdGVFbnZpcm9ubWVudFZhcmlhYmxlc1Jlc3BvbnNlEg8KB2FwcGxpZWQYASABKA0SDwoHcmVtb3ZlZBgCIAEoDSKDAQoSTWNwT0F1dGhTdG9yZWREYXRhEhUKDXJlZnJlc2hfdG9rZW4YASABKAkSEQoJY2xpZW50X2lkGAIgASgJEhoKDWNsaWVudF9zZWNyZXQYAyABKAlIAIgBARIVCg1yZWRpcmVjdF91cmlzGAQgAygJQhAKDl9jbGllbnRfc2VjcmV0Ik4KBUZyYW1lEgoKAmlkGAEgASgJEg4KBm1ldGhvZBgCIAEoCRIMCgRkYXRhGAMgASgMEgwKBGtpbmQYBCABKAUSDQoFZXJyb3IYBSABKAkiBwoFRW1wdHkiIwoNQmlkaVJlcXVlc3RJZBISCgpyZXF1ZXN0X2lkGAEgASgJIoECCgxQaVRydW5jYXRpb24SEQoJdHJ1bmNhdGVkGAEgASgIEhQKDHRydW5jYXRlZF9ieRgCIAEoCRITCgt0b3RhbF9saW5lcxgDIAEoDRIUCgxvdXRwdXRfbGluZXMYBCABKA0SFAoMb3V0cHV0X2J5dGVzGAUgASgNEhYKCW1heF9saW5lcxgGIAEoDUgAiAEBEhYKCW1heF9ieXRlcxgHIAEoDUgBiAEBEiAKGGZpcnN0X2xpbmVfZXhjZWVkc19saW1pdBgIIAEoCBIZChFsYXN0X2xpbmVfcGFydGlhbBgJIAEoCEIMCgpfbWF4X2xpbmVzQgwKCl9tYXhfYnl0ZXMiNwoRUGlFZGl0UmVwbGFjZW1lbnQSEAoIb2xkX3RleHQYASABKAkSEAoIbmV3X3RleHQYAiABKAkiXAoOUGlSZWFkRXhlY0FyZ3MSDAoEcGF0aBgBIAEoCRITCgZvZmZzZXQYAiABKAVIAIgBARISCgVsaW1pdBgDIAEoBUgBiAEBQgkKB19vZmZzZXRCCAoGX2xpbWl0ImMKEVBpUmVhZEV4ZWNTdWNjZXNzEg4KBm91dHB1dBgBIAEoCRIvCgp0cnVuY2F0aW9uGAIgASgLMhYuYWdlbnQudjEuUGlUcnVuY2F0aW9uSACIAQFCDQoLX3RydW5jYXRpb24iIAoPUGlSZWFkRXhlY0Vycm9yEg0KBWVycm9yGAEgASgJIngKEFBpUmVhZEV4ZWNSZXN1bHQSLgoHc3VjY2VzcxgBIAEoCzIbLmFnZW50LnYxLlBpUmVhZEV4ZWNTdWNjZXNzSAASKgoFZXJyb3IYAiABKAsyGS5hZ2VudC52MS5QaVJlYWRFeGVjRXJyb3JIAEIICgZyZXN1bHQiQwoOUGlCYXNoRXhlY0FyZ3MSDwoHY29tbWFuZBgBIAEoCRIUCgd0aW1lb3V0GAIgASgBSACIAQFCCgoIX3RpbWVvdXQilwEKEVBpQmFzaEV4ZWNTdWNjZXNzEg4KBm91dHB1dBgBIAEoCRIvCgp0cnVuY2F0aW9uGAIgASgLMhYuYWdlbnQudjEuUGlUcnVuY2F0aW9uSACIAQESHQoQZnVsbF9vdXRwdXRfcGF0aBgDIAEoCUgBiAEBQg0KC190cnVuY2F0aW9uQhMKEV9mdWxsX291dHB1dF9wYXRoIpQBCg9QaUJhc2hFeGVjRXJyb3ISDQoFZXJyb3IYASABKAkSLwoKdHJ1bmNhdGlvbhgCIAEoCzIWLmFnZW50LnYxLlBpVHJ1bmNhdGlvbkgAiAEBEh0KEGZ1bGxfb3V0cHV0X3BhdGgYAyABKAlIAYgBAUINCgtfdHJ1bmNhdGlvbkITChFfZnVsbF9vdXRwdXRfcGF0aCJ4ChBQaUJhc2hFeGVjUmVzdWx0Ei4KB3N1Y2Nlc3MYASABKAsyGy5hZ2VudC52MS5QaUJhc2hFeGVjU3VjY2Vzc0gAEioKBWVycm9yGAIgASgLMhkuYWdlbnQudjEuUGlCYXNoRXhlY0Vycm9ySABCCAoGcmVzdWx0IkoKDlBpRWRpdEV4ZWNBcmdzEgwKBHBhdGgYASABKAkSKgoFZWRpdHMYAiADKAsyGy5hZ2VudC52MS5QaUVkaXRSZXBsYWNlbWVudCJ4ChFQaUVkaXRFeGVjU3VjY2VzcxIOCgZvdXRwdXQYASABKAkSDAoEZGlmZhgCIAEoCRINCgVwYXRjaBgDIAEoCRIfChJmaXJzdF9jaGFuZ2VkX2xpbmUYBCABKA1IAIgBAUIVChNfZmlyc3RfY2hhbmdlZF9saW5lIiAKD1BpRWRpdEV4ZWNFcnJvchINCgVlcnJvchgBIAEoCSIkChJQaUVkaXRFeGVjUmVqZWN0ZWQSDgoGcmVhc29uGAEgASgJIqoBChBQaUVkaXRFeGVjUmVzdWx0Ei4KB3N1Y2Nlc3MYASABKAsyGy5hZ2VudC52MS5QaUVkaXRFeGVjU3VjY2Vzc0gAEioKBWVycm9yGAIgASgLMhkuYWdlbnQudjEuUGlFZGl0RXhlY0Vycm9ySAASMAoIcmVqZWN0ZWQYAyABKAsyHC5hZ2VudC52MS5QaUVkaXRFeGVjUmVqZWN0ZWRIAEIICgZyZXN1bHQiMAoPUGlXcml0ZUV4ZWNBcmdzEgwKBHBhdGgYASABKAkSDwoHY29udGVudBgCIAEoCSIkChJQaVdyaXRlRXhlY1N1Y2Nlc3MSDgoGb3V0cHV0GAEgASgJIiEKEFBpV3JpdGVFeGVjRXJyb3ISDQoFZXJyb3IYASABKAkiJQoTUGlXcml0ZUV4ZWNSZWplY3RlZBIOCgZyZWFzb24YASABKAkirgEKEVBpV3JpdGVFeGVjUmVzdWx0Ei8KB3N1Y2Nlc3MYASABKAsyHC5hZ2VudC52MS5QaVdyaXRlRXhlY1N1Y2Nlc3NIABIrCgVlcnJvchgCIAEoCzIaLmFnZW50LnYxLlBpV3JpdGVFeGVjRXJyb3JIABIxCghyZWplY3RlZBgDIAEoCzIdLmFnZW50LnYxLlBpV3JpdGVFeGVjUmVqZWN0ZWRIAEIICgZyZXN1bHQi5QEKDlBpR3JlcEV4ZWNBcmdzEg8KB3BhdHRlcm4YASABKAkSEQoEcGF0aBgCIAEoCUgAiAEBEhEKBGdsb2IYAyABKAlIAYgBARIYCgtpZ25vcmVfY2FzZRgEIAEoCEgCiAEBEhQKB2xpdGVyYWwYBSABKAhIA4gBARIUCgdjb250ZXh0GAYgASgFSASIAQESEgoFbGltaXQYByABKAVIBYgBAUIHCgVfcGF0aEIHCgVfZ2xvYkIOCgxfaWdub3JlX2Nhc2VCCgoIX2xpdGVyYWxCCgoIX2NvbnRleHRCCAoGX2xpbWl0IrYBChFQaUdyZXBFeGVjU3VjY2VzcxIOCgZvdXRwdXQYASABKAkSLwoKdHJ1bmNhdGlvbhgCIAEoCzIWLmFnZW50LnYxLlBpVHJ1bmNhdGlvbkgAiAEBEiAKE21hdGNoX2xpbWl0X3JlYWNoZWQYAyABKA1IAYgBARIXCg9saW5lc190cnVuY2F0ZWQYBCABKAhCDQoLX3RydW5jYXRpb25CFgoUX21hdGNoX2xpbWl0X3JlYWNoZWQiIAoPUGlHcmVwRXhlY0Vycm9yEg0KBWVycm9yGAEgASgJIngKEFBpR3JlcEV4ZWNSZXN1bHQSLgoHc3VjY2VzcxgBIAEoCzIbLmFnZW50LnYxLlBpR3JlcEV4ZWNTdWNjZXNzSAASKgoFZXJyb3IYAiABKAsyGS5hZ2VudC52MS5QaUdyZXBFeGVjRXJyb3JIAEIICgZyZXN1bHQiWwoOUGlGaW5kRXhlY0FyZ3MSDwoHcGF0dGVybhgBIAEoCRIRCgRwYXRoGAIgASgJSACIAQESEgoFbGltaXQYAyABKAVIAYgBAUIHCgVfcGF0aEIICgZfbGltaXQinwEKEVBpRmluZEV4ZWNTdWNjZXNzEg4KBm91dHB1dBgBIAEoCRIvCgp0cnVuY2F0aW9uGAIgASgLMhYuYWdlbnQudjEuUGlUcnVuY2F0aW9uSACIAQESIQoUcmVzdWx0X2xpbWl0X3JlYWNoZWQYAyABKA1IAYgBAUINCgtfdHJ1bmNhdGlvbkIXChVfcmVzdWx0X2xpbWl0X3JlYWNoZWQiIAoPUGlGaW5kRXhlY0Vycm9yEg0KBWVycm9yGAEgASgJIngKEFBpRmluZEV4ZWNSZXN1bHQSLgoHc3VjY2VzcxgBIAEoCzIbLmFnZW50LnYxLlBpRmluZEV4ZWNTdWNjZXNzSAASKgoFZXJyb3IYAiABKAsyGS5hZ2VudC52MS5QaUZpbmRFeGVjRXJyb3JIAEIICgZyZXN1bHQiSAoMUGlMc0V4ZWNBcmdzEhEKBHBhdGgYASABKAlIAIgBARISCgVsaW1pdBgCIAEoBUgBiAEBQgcKBV9wYXRoQggKBl9saW1pdCKbAQoPUGlMc0V4ZWNTdWNjZXNzEg4KBm91dHB1dBgBIAEoCRIvCgp0cnVuY2F0aW9uGAIgASgLMhYuYWdlbnQudjEuUGlUcnVuY2F0aW9uSACIAQESIAoTZW50cnlfbGltaXRfcmVhY2hlZBgDIAEoDUgBiAEBQg0KC190cnVuY2F0aW9uQhYKFF9lbnRyeV9saW1pdF9yZWFjaGVkIh4KDVBpTHNFeGVjRXJyb3ISDQoFZXJyb3IYASABKAkicgoOUGlMc0V4ZWNSZXN1bHQSLAoHc3VjY2VzcxgBIAEoCzIZLmFnZW50LnYxLlBpTHNFeGVjU3VjY2Vzc0gAEigKBWVycm9yGAIgASgLMhcuYWdlbnQudjEuUGlMc0V4ZWNFcnJvckgAQggKBnJlc3VsdCI8ChFNY3BTZXJ2ZXJOb3RGb3VuZBIMCgRuYW1lGAEgASgJEhkKEWF2YWlsYWJsZV9zZXJ2ZXJzGAIgAygJIg0KC01jcEFwcHJvdmVkIkEKEE1jcFN0YXRlRXhlY0FyZ3MSGgoSc2VydmVyX2lkZW50aWZpZXJzGAEgAygJEhEKCWtpY2tfb25seRgCIAEoCCKHAgoOTWNwU3RhdGVTZXJ2ZXISEwoLc2VydmVyX25hbWUYASABKAkSGQoRc2VydmVyX2lkZW50aWZpZXIYAiABKAkSEwoGcGx1Z2luGAMgASgJSACIAQESGAoLbWFya2V0cGxhY2UYBCABKAlIAYgBARIqCgV0b29scxgFIAMoCzIbLmFnZW50LnYxLk1jcFRvb2xEZWZpbml0aW9uEi8KDGluc3RydWN0aW9ucxgGIAMoCzIZLmFnZW50LnYxLk1jcEluc3RydWN0aW9ucxITCgZzdGF0dXMYByABKAlIAogBAUIJCgdfcGx1Z2luQg4KDF9tYXJrZXRwbGFjZUIJCgdfc3RhdHVzIjwKD01jcFN0YXRlU3VjY2VzcxIpCgdzZXJ2ZXJzGAEgAygLMhguYWdlbnQudjEuTWNwU3RhdGVTZXJ2ZXIiHgoNTWNwU3RhdGVFcnJvchINCgVlcnJvchgBIAEoCSIiChBNY3BTdGF0ZVJlamVjdGVkEg4KBnJlYXNvbhgBIAEoCSKmAQoSTWNwU3RhdGVFeGVjUmVzdWx0EiwKB3N1Y2Nlc3MYASABKAsyGS5hZ2VudC52MS5NY3BTdGF0ZVN1Y2Nlc3NIABIoCgVlcnJvchgCIAEoCzIXLmFnZW50LnYxLk1jcFN0YXRlRXJyb3JIABIuCghyZWplY3RlZBgDIAEoCzIaLmFnZW50LnYxLk1jcFN0YXRlUmVqZWN0ZWRIAEIICgZyZXN1bHQirQEKKUNvbW1hbmRDbGFzc2lmaWVyUmVzdWx0X0NsYXNzaWZpZWRDb21tYW5kEgwKBG5hbWUYASABKAkSEQoJYXJndW1lbnRzGAIgAygJEiYKGXN1Z2dlc3RlZF9hbGxvd2xpc3RfZW50cnkYAyABKAlIAIgBARIZChFzdWJjb21tYW5kX3Rva2VucxgEIAMoCUIcChpfc3VnZ2VzdGVkX2FsbG93bGlzdF9lbnRyeSLXAQoXQ29tbWFuZENsYXNzaWZpZXJSZXN1bHQSRQoIY29tbWFuZHMYASADKAsyMy5hZ2VudC52MS5Db21tYW5kQ2xhc3NpZmllclJlc3VsdF9DbGFzc2lmaWVkQ29tbWFuZBJWChZzdWdnZXN0ZWRfc2FuZGJveF9tb2RlGAIgASgOMjYuYWdlbnQudjEuQ29tbWFuZENsYXNzaWZpZXJSZXN1bHRfU3VnZ2VzdGVkU2FuZGJveE1vZGUSHQoVY2xhc3NpZmljYXRpb25fZmFpbGVkGAMgASgIIpMBCiJTaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0X1JlZGlyZWN0EhAKCG9wZXJhdG9yGAEgASgJEhcKD2Rlc3RpbmF0aW9uX2ZkcxgCIAMoDRIYChB0YXJnZXRfbm9kZV90eXBlGAMgASgJEhgKC3RhcmdldF90ZXh0GAQgASgJSACIAQFCDgoMX3RhcmdldF90ZXh0IooCChpTaGVsbEFsbG93bGlzdFByZWNoZWNrQXJncxIPCgdjb21tYW5kGAEgASgJEhkKEXdvcmtpbmdfZGlyZWN0b3J5GAIgASgJEjsKDnBhcnNpbmdfcmVzdWx0GAMgASgLMiMuYWdlbnQudjEuU2hlbGxDb21tYW5kUGFyc2luZ1Jlc3VsdBJBChFjbGFzc2lmaWVyX3Jlc3VsdBgEIAEoCzIhLmFnZW50LnYxLkNvbW1hbmRDbGFzc2lmaWVyUmVzdWx0SACIAQESGQoMdG9vbF9jYWxsX2lkGAUgASgJSAGIAQFCFAoSX2NsYXNzaWZpZXJfcmVzdWx0Qg8KDV90b29sX2NhbGxfaWQiMwocU2hlbGxBbGxvd2xpc3RQcmVjaGVja1Jlc3VsdBITCgthbGxvd2xpc3RlZBgBIAEoCCJ2ChhNY3BBbGxvd2xpc3RQcmVjaGVja0FyZ3MSGwoTcHJvdmlkZXJfaWRlbnRpZmllchgBIAEoCRIRCgl0b29sX25hbWUYAiABKAkSGQoMdG9vbF9jYWxsX2lkGAMgASgJSACIAQFCDwoNX3Rvb2xfY2FsbF9pZCIxChpNY3BBbGxvd2xpc3RQcmVjaGVja1Jlc3VsdBITCgthbGxvd2xpc3RlZBgBIAEoCCJYCh1XZWJGZXRjaEFsbG93bGlzdFByZWNoZWNrQXJncxILCgN1cmwYASABKAkSGQoMdG9vbF9jYWxsX2lkGAIgASgJSACIAQFCDwoNX3Rvb2xfY2FsbF9pZCI2Ch9XZWJGZXRjaEFsbG93bGlzdFByZWNoZWNrUmVzdWx0EhMKC2FsbG93bGlzdGVkGAEgASgIIjcKEVNtYXJ0TW9kZUFwcHJvdmFsEhIKCnJlcXVlc3RfaWQYASABKAkSDgoGcmVhc29uGAIgASgJIpwBCh1TaGVsbE91dHB1dE5vdGlmaWNhdGlvbkNvbmZpZxIPCgdwYXR0ZXJuGAEgASgJEg4KBnJlYXNvbhgCIAEoCRIVCghkZWJvdW5jZRgDIAEoAUgAiAEBEh8KEm5vdGlmaWNhdGlvbl9saW1pdBgEIAEoBUgBiAEBQgsKCV9kZWJvdW5jZUIVChNfbm90aWZpY2F0aW9uX2xpbWl0InkKHFNoZWxsSG9va0FwcHJvdmFsUmVxdWlyZW1lbnQSOQoEa2luZBgBIAEoDjIrLmFnZW50LnYxLlNoZWxsSG9va0FwcHJvdmFsUmVxdWlyZW1lbnRfS2luZBITCgZyZWFzb24YAiABKAlIAIgBAUIJCgdfcmVhc29uIjAKGEZvcmNlQmFja2dyb3VuZFNoZWxsQXJncxIUCgx0b29sX2NhbGxfaWQYASABKAkilQEKGkZvcmNlQmFja2dyb3VuZFNoZWxsUmVzdWx0EjQKBnN0YXR1cxgBIAEoDjIkLmFnZW50LnYxLkZvcmNlQmFja2dyb3VuZFNoZWxsU3RhdHVzEjAKDHNoZWxsX3Jlc3VsdBgCIAEoCzIVLmFnZW50LnYxLlNoZWxsUmVzdWx0SACIAQFCDwoNX3NoZWxsX3Jlc3VsdCJBChVIb29rQWRkaXRpb25hbENvbnRleHQSFwoPaG9va19ldmVudF9uYW1lGAEgASgJEg8KB2NvbnRlbnQYAiABKAkiWwoWU2hlbGxTdHJlYW1Ib29rQ29udGV4dBJBChhob29rX2FkZGl0aW9uYWxfY29udGV4dHMYASADKAsyHy5hZ2VudC52MS5Ib29rQWRkaXRpb25hbENvbnRleHQiSwoMU3ViYWdlbnRBcmdzEhQKDHRvb2xfY2FsbF9pZBgBIAEoCRIVCg1zdWJhZ2VudF90eXBlGAIgASgJEg4KBnByb21wdBgEIAEoCSLbAQoPU3ViYWdlbnRTdWNjZXNzEhAKCGFnZW50X2lkGAEgASgJEhoKDWZpbmFsX21lc3NhZ2UYAiABKAlIAIgBARIXCg90b29sX2NhbGxfY291bnQYAyABKAUSPQoRYmFja2dyb3VuZF9yZWFzb24YBCABKA4yIi5hZ2VudC52MS5TdWJhZ2VudEJhY2tncm91bmRSZWFzb24SHAoPdHJhbnNjcmlwdF9wYXRoGAUgASgJSAGIAQFCEAoOX2ZpbmFsX21lc3NhZ2VCEgoQX3RyYW5zY3JpcHRfcGF0aCJCCg1TdWJhZ2VudEVycm9yEhUKCGFnZW50X2lkGAEgASgJSACIAQESDQoFZXJyb3IYAiABKAlCCwoJX2FnZW50X2lkInIKDlN1YmFnZW50UmVzdWx0EiwKB3N1Y2Nlc3MYASABKAsyGS5hZ2VudC52MS5TdWJhZ2VudFN1Y2Nlc3NIABIoCgVlcnJvchgCIAEoCzIXLmFnZW50LnYxLlN1YmFnZW50RXJyb3JIAEIICgZyZXN1bHQiOQoRU3ViYWdlbnRBd2FpdEFyZ3MSEAoIYWdlbnRfaWQYASABKAkSEgoKdGltZW91dF9tcxgCIAEoDSKiAQoVU3ViYWdlbnRBd2FpdENvbXBsZXRlEhAKCGFnZW50X2lkGAEgASgJEhwKD3RyYW5zY3JpcHRfcGF0aBgCIAEoCUgAiAEBEhcKD3Rvb2xfY2FsbF9jb3VudBgDIAEoBRIaCg1maW5hbF9tZXNzYWdlGAQgASgJSAGIAQFCEgoQX3RyYW5zY3JpcHRfcGF0aEIQCg5fZmluYWxfbWVzc2FnZSJfChlTdWJhZ2VudEF3YWl0U3RpbGxSdW5uaW5nEhAKCGFnZW50X2lkGAEgASgJEhwKD3RyYW5zY3JpcHRfcGF0aBgCIAEoCUgAiAEBQhIKEF90cmFuc2NyaXB0X3BhdGgiKQoVU3ViYWdlbnRBd2FpdE5vdEZvdW5kEhAKCGFnZW50X2lkGAEgASgJIkcKElN1YmFnZW50QXdhaXRFcnJvchIVCghhZ2VudF9pZBgBIAEoCUgAiAEBEg0KBWVycm9yGAIgASgJQgsKCV9hZ2VudF9pZCL3AQoTU3ViYWdlbnRBd2FpdFJlc3VsdBIzCghjb21wbGV0ZRgBIAEoCzIfLmFnZW50LnYxLlN1YmFnZW50QXdhaXRDb21wbGV0ZUgAEjwKDXN0aWxsX3J1bm5pbmcYAiABKAsyIy5hZ2VudC52MS5TdWJhZ2VudEF3YWl0U3RpbGxSdW5uaW5nSAASNAoJbm90X2ZvdW5kGAMgASgLMh8uYWdlbnQudjEuU3ViYWdlbnRBd2FpdE5vdEZvdW5kSAASLQoFZXJyb3IYBCABKAsyHC5hZ2VudC52MS5TdWJhZ2VudEF3YWl0RXJyb3JIAEIICgZyZXN1bHQiMwobRm9yY2VCYWNrZ3JvdW5kU3ViYWdlbnRBcmdzEhQKDHRvb2xfY2FsbF9pZBgBIAEoCSJYCh1Gb3JjZUJhY2tncm91bmRTdWJhZ2VudFJlc3VsdBI3CgZzdGF0dXMYASABKA4yJy5hZ2VudC52MS5Gb3JjZUJhY2tncm91bmRTdWJhZ2VudFN0YXR1cyIYChZQcmVDb21wYWN0UmVxdWVzdFF1ZXJ5IhsKGVN1YmFnZW50U3RhcnRSZXF1ZXN0UXVlcnkiGgoYU3ViYWdlbnRTdG9wUmVxdWVzdFF1ZXJ5IhgKFlByZVRvb2xVc2VSZXF1ZXN0UXVlcnkiGQoXUG9zdFRvb2xVc2VSZXF1ZXN0UXVlcnkiIAoeUG9zdFRvb2xVc2VGYWlsdXJlUmVxdWVzdFF1ZXJ5IiAKHkJlZm9yZVN1Ym1pdFByb21wdFJlcXVlc3RRdWVyeSIgCh5BZnRlckFnZW50UmVzcG9uc2VSZXF1ZXN0UXVlcnkiHwodQWZ0ZXJBZ2VudFRob3VnaHRSZXF1ZXN0UXVlcnkiEgoQU3RvcFJlcXVlc3RRdWVyeSJHChlQcmVDb21wYWN0UmVxdWVzdFJlc3BvbnNlEhkKDHVzZXJfbWVzc2FnZRgBIAEoCUgAiAEBQg8KDV91c2VyX21lc3NhZ2UiqgEKHFN1YmFnZW50U3RhcnRSZXF1ZXN0UmVzcG9uc2USFwoKcGVybWlzc2lvbhgBIAEoCUgAiAEBEhkKDHVzZXJfbWVzc2FnZRgCIAEoCUgBiAEBEh8KEmFkZGl0aW9uYWxfY29udGV4dBgDIAEoCUgCiAEBQg0KC19wZXJtaXNzaW9uQg8KDV91c2VyX21lc3NhZ2VCFQoTX2FkZGl0aW9uYWxfY29udGV4dCKJAQobU3ViYWdlbnRTdG9wUmVxdWVzdFJlc3BvbnNlEh0KEGZvbGxvd3VwX21lc3NhZ2UYASABKAlIAIgBARIfChJhZGRpdGlvbmFsX2NvbnRleHQYAiABKAlIAYgBAUITChFfZm9sbG93dXBfbWVzc2FnZUIVChNfYWRkaXRpb25hbF9jb250ZXh0IoMCChlQcmVUb29sVXNlUmVxdWVzdFJlc3BvbnNlEhcKCnBlcm1pc3Npb24YASABKAlIAIgBARIZCgx1c2VyX21lc3NhZ2UYAiABKAlIAYgBARIaCg1hZ2VudF9tZXNzYWdlGAMgASgJSAKIAQESGgoNdXBkYXRlZF9pbnB1dBgEIAEoCUgDiAEBEh8KEmFkZGl0aW9uYWxfY29udGV4dBgFIAEoCUgEiAEBQg0KC19wZXJtaXNzaW9uQg8KDV91c2VyX21lc3NhZ2VCEAoOX2FnZW50X21lc3NhZ2VCEAoOX3VwZGF0ZWRfaW5wdXRCFQoTX2FkZGl0aW9uYWxfY29udGV4dCJUChpQb3N0VG9vbFVzZVJlcXVlc3RSZXNwb25zZRIfChJhZGRpdGlvbmFsX2NvbnRleHQYASABKAlIAIgBAUIVChNfYWRkaXRpb25hbF9jb250ZXh0IlsKIVBvc3RUb29sVXNlRmFpbHVyZVJlcXVlc3RSZXNwb25zZRIfChJhZGRpdGlvbmFsX2NvbnRleHQYASABKAlIAIgBAUIVChNfYWRkaXRpb25hbF9jb250ZXh0IqsBCiFCZWZvcmVTdWJtaXRQcm9tcHRSZXF1ZXN0UmVzcG9uc2USFQoIY29udGludWUYASABKAhIAIgBARIZCgx1c2VyX21lc3NhZ2UYAiABKAlIAYgBARIfChJhZGRpdGlvbmFsX2NvbnRleHQYAyABKAlIAogBAUILCglfY29udGludWVCDwoNX3VzZXJfbWVzc2FnZUIVChNfYWRkaXRpb25hbF9jb250ZXh0IiMKIUFmdGVyQWdlbnRSZXNwb25zZVJlcXVlc3RSZXNwb25zZSIiCiBBZnRlckFnZW50VGhvdWdodFJlcXVlc3RSZXNwb25zZSJJChNTdG9wUmVxdWVzdFJlc3BvbnNlEh0KEGZvbGxvd3VwX21lc3NhZ2UYASABKAlIAIgBAUITChFfZm9sbG93dXBfbWVzc2FnZSKdBQoSRXhlY3V0ZUhvb2tSZXF1ZXN0EjcKC3ByZV9jb21wYWN0GAEgASgLMiAuYWdlbnQudjEuUHJlQ29tcGFjdFJlcXVlc3RRdWVyeUgAEj0KDnN1YmFnZW50X3N0YXJ0GAIgASgLMiMuYWdlbnQudjEuU3ViYWdlbnRTdGFydFJlcXVlc3RRdWVyeUgAEjsKDXN1YmFnZW50X3N0b3AYAyABKAsyIi5hZ2VudC52MS5TdWJhZ2VudFN0b3BSZXF1ZXN0UXVlcnlIABI4CgxwcmVfdG9vbF91c2UYBCABKAsyIC5hZ2VudC52MS5QcmVUb29sVXNlUmVxdWVzdFF1ZXJ5SAASOgoNcG9zdF90b29sX3VzZRgFIAEoCzIhLmFnZW50LnYxLlBvc3RUb29sVXNlUmVxdWVzdFF1ZXJ5SAASSQoVcG9zdF90b29sX3VzZV9mYWlsdXJlGAYgASgLMiguYWdlbnQudjEuUG9zdFRvb2xVc2VGYWlsdXJlUmVxdWVzdFF1ZXJ5SAASSAoUYmVmb3JlX3N1Ym1pdF9wcm9tcHQYByABKAsyKC5hZ2VudC52MS5CZWZvcmVTdWJtaXRQcm9tcHRSZXF1ZXN0UXVlcnlIABJIChRhZnRlcl9hZ2VudF9yZXNwb25zZRgIIAEoCzIoLmFnZW50LnYxLkFmdGVyQWdlbnRSZXNwb25zZVJlcXVlc3RRdWVyeUgAEkYKE2FmdGVyX2FnZW50X3Rob3VnaHQYCSABKAsyJy5hZ2VudC52MS5BZnRlckFnZW50VGhvdWdodFJlcXVlc3RRdWVyeUgAEioKBHN0b3AYCyABKAsyGi5hZ2VudC52MS5TdG9wUmVxdWVzdFF1ZXJ5SABCCQoHcmVxdWVzdCK9BQoTRXhlY3V0ZUhvb2tSZXNwb25zZRI6CgtwcmVfY29tcGFjdBgBIAEoCzIjLmFnZW50LnYxLlByZUNvbXBhY3RSZXF1ZXN0UmVzcG9uc2VIABJACg5zdWJhZ2VudF9zdGFydBgCIAEoCzImLmFnZW50LnYxLlN1YmFnZW50U3RhcnRSZXF1ZXN0UmVzcG9uc2VIABI+Cg1zdWJhZ2VudF9zdG9wGAMgASgLMiUuYWdlbnQudjEuU3ViYWdlbnRTdG9wUmVxdWVzdFJlc3BvbnNlSAASOwoMcHJlX3Rvb2xfdXNlGAQgASgLMiMuYWdlbnQudjEuUHJlVG9vbFVzZVJlcXVlc3RSZXNwb25zZUgAEj0KDXBvc3RfdG9vbF91c2UYBSABKAsyJC5hZ2VudC52MS5Qb3N0VG9vbFVzZVJlcXVlc3RSZXNwb25zZUgAEkwKFXBvc3RfdG9vbF91c2VfZmFpbHVyZRgGIAEoCzIrLmFnZW50LnYxLlBvc3RUb29sVXNlRmFpbHVyZVJlcXVlc3RSZXNwb25zZUgAEksKFGJlZm9yZV9zdWJtaXRfcHJvbXB0GAcgASgLMisuYWdlbnQudjEuQmVmb3JlU3VibWl0UHJvbXB0UmVxdWVzdFJlc3BvbnNlSAASSwoUYWZ0ZXJfYWdlbnRfcmVzcG9uc2UYCCABKAsyKy5hZ2VudC52MS5BZnRlckFnZW50UmVzcG9uc2VSZXF1ZXN0UmVzcG9uc2VIABJJChNhZnRlcl9hZ2VudF90aG91Z2h0GAkgASgLMiouYWdlbnQudjEuQWZ0ZXJBZ2VudFRob3VnaHRSZXF1ZXN0UmVzcG9uc2VIABItCgRzdG9wGAsgASgLMh0uYWdlbnQudjEuU3RvcFJlcXVlc3RSZXNwb25zZUgAQgoKCHJlc3BvbnNlIkAKD0V4ZWN1dGVIb29rQXJncxItCgdyZXF1ZXN0GAEgASgLMhwuYWdlbnQudjEuRXhlY3V0ZUhvb2tSZXF1ZXN0IkQKEUV4ZWN1dGVIb29rUmVzdWx0Ei8KCHJlc3BvbnNlGAEgASgLMh0uYWdlbnQudjEuRXhlY3V0ZUhvb2tSZXNwb25zZSIlChNTbWFydE1vZGVSaXNrVGFyZ2V0Eg4KBmFjdGlvbhgBIAEoCSJHCiZTbWFydE1vZGVDbGFzc2lmaWVyQ29udmVyc2F0aW9uTWVzc2FnZRIMCgRyb2xlGAEgASgJEg8KB2NvbnRlbnQYAiABKAki7gEKF1NtYXJ0TW9kZUNsYXNzaWZpZXJBcmdzEhQKDHRvb2xfY2FsbF9pZBgBIAEoCRIjChZwYXJlbnRfY29udmVyc2F0aW9uX2lkGAIgASgJSACIAQESLQoGdGFyZ2V0GAMgASgLMh0uYWdlbnQudjEuU21hcnRNb2RlUmlza1RhcmdldBJOChRjb252ZXJzYXRpb25fY29udGV4dBgEIAMoCzIwLmFnZW50LnYxLlNtYXJ0TW9kZUNsYXNzaWZpZXJDb252ZXJzYXRpb25NZXNzYWdlQhkKF19wYXJlbnRfY29udmVyc2F0aW9uX2lkIoEBChpTbWFydE1vZGVDbGFzc2lmaWVyU3VjY2VzcxI3CghkZWNpc2lvbhgBIAEoDjIlLmFnZW50LnYxLlNtYXJ0TW9kZUNsYXNzaWZpZXJEZWNpc2lvbhIZCgxibG9ja19yZWFzb24YAiABKAlIAIgBAUIPCg1fYmxvY2tfcmVhc29uIikKGFNtYXJ0TW9kZUNsYXNzaWZpZXJFcnJvchINCgVlcnJvchgBIAEoCSKTAQoZU21hcnRNb2RlQ2xhc3NpZmllclJlc3VsdBI3CgdzdWNjZXNzGAEgASgLMiQuYWdlbnQudjEuU21hcnRNb2RlQ2xhc3NpZmllclN1Y2Nlc3NIABIzCgVlcnJvchgCIAEoCzIiLmFnZW50LnYxLlNtYXJ0TW9kZUNsYXNzaWZpZXJFcnJvckgAQggKBnJlc3VsdCI7ChVDYW52YXNEaWFnbm9zdGljc0FyZ3MSDAoEcGF0aBgBIAEoCRIUCgx0b29sX2NhbGxfaWQYAiABKAkiUwoYQ2FudmFzRGlhZ25vc3RpY3NTdWNjZXNzEgwKBHBhdGgYASABKAkSKQoLZGlhZ25vc3RpY3MYAiADKAsyFC5hZ2VudC52MS5EaWFnbm9zdGljIjUKFkNhbnZhc0RpYWdub3N0aWNzRXJyb3ISDAoEcGF0aBgBIAEoCRINCgVlcnJvchgCIAEoCSKNAQoXQ2FudmFzRGlhZ25vc3RpY3NSZXN1bHQSNQoHc3VjY2VzcxgBIAEoCzIiLmFnZW50LnYxLkNhbnZhc0RpYWdub3N0aWNzU3VjY2Vzc0gAEjEKBWVycm9yGAIgASgLMiAuYWdlbnQudjEuQ2FudmFzRGlhZ25vc3RpY3NFcnJvckgAQggKBnJlc3VsdCKsAQoVQ29udmVyc2F0aW9uU2VhcmNoSGl0EhcKD2NvbnZlcnNhdGlvbl9pZBgBIAEoCRINCgV0aXRsZRgCIAEoCRIyCgZzb3VyY2UYAyABKA4yIi5hZ2VudC52MS5Db252ZXJzYXRpb25TZWFyY2hTb3VyY2USFQoNdXBkYXRlZF9hdF9tcxgEIAEoAxIUCgdzbmlwcGV0GAUgASgJSACIAQFCCgoIX3NuaXBwZXQiggEKGUNvbnZlcnNhdGlvblNlYXJjaFN1Y2Nlc3MSLQoEaGl0cxgBIAMoCzIfLmFnZW50LnYxLkNvbnZlcnNhdGlvblNlYXJjaEhpdBIRCgl0cnVuY2F0ZWQYAiABKAgSDwoHcGFydGlhbBgDIAEoCBISCgpyZWJ1aWxkaW5nGAQgASgIIigKF0NvbnZlcnNhdGlvblNlYXJjaEVycm9yEg0KBWVycm9yGAEgASgJIlsKFkNvbnZlcnNhdGlvblNlYXJjaEFyZ3MSDQoFcXVlcnkYASABKAkSFAoMdG9vbF9jYWxsX2lkGAIgASgJEhIKBWxpbWl0GAMgASgFSACIAQFCCAoGX2xpbWl0IpABChhDb252ZXJzYXRpb25TZWFyY2hSZXN1bHQSNgoHc3VjY2VzcxgBIAEoCzIjLmFnZW50LnYxLkNvbnZlcnNhdGlvblNlYXJjaFN1Y2Nlc3NIABIyCgVlcnJvchgCIAEoCzIhLmFnZW50LnYxLkNvbnZlcnNhdGlvblNlYXJjaEVycm9ySABCCAoGcmVzdWx0IlUKGEFnZW50U3RvcmVDb25mbGljdEN1cnNvchIVCg1qb3VybmFsX2Vwb2NoGAEgASgJEgsKA3NlcRgCIAEoBBIVCg1sYXN0X2V2ZW50X2lkGAMgASgJIqUDChdBZ2VudFN0b3JlQ29uZmxpY3RFdmVudBIJCgF2GAEgASgNEhAKCGV2ZW50X2lkGAIgASgJEhUKDWpvdXJuYWxfZXBvY2gYAyABKAkSCwoDc2VxGAQgASgEEg0KBXRzX21zGAUgASgEEgwKBGtpbmQYBiABKAkSFQoIc3RvcmVfaWQYByABKAlIAIgBARIeChFvcmlnaW5hbF9yZWxfcGF0aBgIIAEoCUgBiAEBEh4KEWNvbmZsaWN0X3JlbF9wYXRoGAkgASgJSAKIAQESHgoRb3JpZ2luYWxfYWJzX3BhdGgYCiABKAlIA4gBARIeChFjb25mbGljdF9hYnNfcGF0aBgLIAEoCUgEiAEBEhwKD3ByZXNlcnZlZF9ieXRlcxgMIAEoBEgFiAEBQgsKCV9zdG9yZV9pZEIUChJfb3JpZ2luYWxfcmVsX3BhdGhCFAoSX2NvbmZsaWN0X3JlbF9wYXRoQhQKEl9vcmlnaW5hbF9hYnNfcGF0aEIUChJfY29uZmxpY3RfYWJzX3BhdGhCEgoQX3ByZXNlcnZlZF9ieXRlcyKUAQoZQWdlbnRTdG9yZUNvbmZsaWN0U3VjY2VzcxIxCgZldmVudHMYASADKAsyIS5hZ2VudC52MS5BZ2VudFN0b3JlQ29uZmxpY3RFdmVudBI3CgtuZXh0X2N1cnNvchgCIAEoCzIiLmFnZW50LnYxLkFnZW50U3RvcmVDb25mbGljdEN1cnNvchILCgNnYXAYAyABKAgiKAoXQWdlbnRTdG9yZUNvbmZsaWN0RXJyb3ISDQoFZXJyb3IYASABKAkifgoWQWdlbnRTdG9yZUNvbmZsaWN0QXJncxI3CgZjdXJzb3IYASABKAsyIi5hZ2VudC52MS5BZ2VudFN0b3JlQ29uZmxpY3RDdXJzb3JIAIgBARIUCgdhZHZhbmNlGAIgASgISAGIAQFCCQoHX2N1cnNvckIKCghfYWR2YW5jZSKQAQoYQWdlbnRTdG9yZUNvbmZsaWN0UmVzdWx0EjYKB3N1Y2Nlc3MYASABKAsyIy5hZ2VudC52MS5BZ2VudFN0b3JlQ29uZmxpY3RTdWNjZXNzSAASMgoFZXJyb3IYAiABKAsyIS5hZ2VudC52MS5BZ2VudFN0b3JlQ29uZmxpY3RFcnJvckgAQggKBnJlc3VsdCJ8Cg5GaWxlRGlmZl9DaHVuaxIPCgdjb250ZW50GAEgASgJEg0KBWxpbmVzGAIgAygJEhEKCW9sZF9zdGFydBgDIAEoBRIRCglvbGRfbGluZXMYBCABKAUSEQoJbmV3X3N0YXJ0GAUgASgFEhEKCW5ld19saW5lcxgGIAEoBSKQAgoIRmlsZURpZmYSDQoFYWRkZWQYBCABKAUSDwoHcmVtb3ZlZBgFIAEoBRIMCgRmcm9tGAEgASgJEgoKAnRvGAIgASgJEigKBmNodW5rcxgDIAMoCzIYLmFnZW50LnYxLkZpbGVEaWZmX0NodW5rEiEKFGJlZm9yZV9maWxlX2NvbnRlbnRzGAYgASgJSACIAQESIAoTYWZ0ZXJfZmlsZV9jb250ZW50cxgHIAEoCUgBiAEBEhkKDGlzX2dlbmVyYXRlZBgIIAEoCEgCiAEBQhcKFV9iZWZvcmVfZmlsZV9jb250ZW50c0IWChRfYWZ0ZXJfZmlsZV9jb250ZW50c0IPCg1faXNfZ2VuZXJhdGVkIlsKB0dpdERpZmYSIQoFZGlmZnMYASADKAsyEi5hZ2VudC52MS5GaWxlRGlmZhItCglkaWZmX3R5cGUYAiABKA4yGi5hZ2VudC52MS5HaXREaWZmX0RpZmZUeXBlImgKHUdldERpZmZSZXNwb25zZV9TdWJtb2R1bGVEaWZmEhUKDXJlbGF0aXZlX3BhdGgYASABKAkSHwoEZGlmZhgCIAEoCzIRLmFnZW50LnYxLkdpdERpZmYSDwoHZXJyb3JlZBgDIAEoCCLyAwoOR2V0RGlmZlJlcXVlc3QSCwoDY3dkGAEgASgJEgsKA3JlZhgCIAEoCRIQCghiYXNlX3JlZhgDIAEoCRISCgptZXJnZV9iYXNlGAQgASgIEhQKDHRhcmdldF9wYXRocxgFIAMoCRIiChV1bmlmaWVkX2NvbnRleHRfbGluZXMYBiABKAVIAIgBARIbChNtYXhfdW50cmFja2VkX2ZpbGVzGAcgASgFEh8KF3N1Ym1vZHVsZV9yZWN1cnNlX2RlcHRoGAkgASgFEh0KFWluY2x1ZGVfc3BhY2VfY2hhbmdlcxgKIAEoCBIWCg5jb21taXR0ZWRfb25seRgLIAEoCBIYChBjb21wdXRlX3BhdGNoX2lkGAwgASgIEhwKD3JldHVybl9oZWFkX3NoYRgNIAEoCEgBiAEBEh8KEm1heF9yZXNwb25zZV9ieXRlcxgOIAEoBUgCiAEBEkEKDW91dHB1dF9mb3JtYXQYCCABKA4yJS5hZ2VudC52MS5HZXREaWZmUmVxdWVzdF9PdXRwdXRGb3JtYXRIA4gBAUIYChZfdW5pZmllZF9jb250ZXh0X2xpbmVzQhIKEF9yZXR1cm5faGVhZF9zaGFCFQoTX21heF9yZXNwb25zZV9ieXRlc0IQCg5fb3V0cHV0X2Zvcm1hdCL+AQoPR2V0RGlmZlJlc3BvbnNlEh8KBGRpZmYYASABKAsyES5hZ2VudC52MS5HaXREaWZmEkAKD3N1Ym1vZHVsZV9kaWZmcxgCIAMoCzInLmFnZW50LnYxLkdldERpZmZSZXNwb25zZV9TdWJtb2R1bGVEaWZmEhUKCHBhdGNoX2lkGAMgASgJSACIAQESFQoIaGVhZF9zaGEYBCABKAlIAYgBARIkChdoYXNfdW5jb21taXR0ZWRfY2hhbmdlcxgFIAEoCEgCiAEBQgsKCV9wYXRjaF9pZEILCglfaGVhZF9zaGFCGgoYX2hhc191bmNvbW1pdHRlZF9jaGFuZ2VzImQKDlBpUmVhZFRvb2xDYWxsEiYKBGFyZ3MYASABKAsyGC5hZ2VudC52MS5QaVJlYWRFeGVjQXJncxIqCgZyZXN1bHQYAiABKAsyGi5hZ2VudC52MS5QaVJlYWRFeGVjUmVzdWx0ImQKDlBpQmFzaFRvb2xDYWxsEiYKBGFyZ3MYASABKAsyGC5hZ2VudC52MS5QaUJhc2hFeGVjQXJncxIqCgZyZXN1bHQYAiABKAsyGi5hZ2VudC52MS5QaUJhc2hFeGVjUmVzdWx0ImQKDlBpRWRpdFRvb2xDYWxsEiYKBGFyZ3MYASABKAsyGC5hZ2VudC52MS5QaUVkaXRFeGVjQXJncxIqCgZyZXN1bHQYAiABKAsyGi5hZ2VudC52MS5QaUVkaXRFeGVjUmVzdWx0ImcKD1BpV3JpdGVUb29sQ2FsbBInCgRhcmdzGAEgASgLMhkuYWdlbnQudjEuUGlXcml0ZUV4ZWNBcmdzEisKBnJlc3VsdBgCIAEoCzIbLmFnZW50LnYxLlBpV3JpdGVFeGVjUmVzdWx0ImQKDlBpR3JlcFRvb2xDYWxsEiYKBGFyZ3MYASABKAsyGC5hZ2VudC52MS5QaUdyZXBFeGVjQXJncxIqCgZyZXN1bHQYAiABKAsyGi5hZ2VudC52MS5QaUdyZXBFeGVjUmVzdWx0ImQKDlBpRmluZFRvb2xDYWxsEiYKBGFyZ3MYASABKAsyGC5hZ2VudC52MS5QaUZpbmRFeGVjQXJncxIqCgZyZXN1bHQYAiABKAsyGi5hZ2VudC52MS5QaUZpbmRFeGVjUmVzdWx0Il4KDFBpTHNUb29sQ2FsbBIkCgRhcmdzGAEgASgLMhYuYWdlbnQudjEuUGlMc0V4ZWNBcmdzEigKBnJlc3VsdBgCIAEoCzIYLmFnZW50LnYxLlBpTHNFeGVjUmVzdWx0IoEBChtTZWFyY2hDb252ZXJzYXRpb25zVG9vbENhbGwSLgoEYXJncxgBIAEoCzIgLmFnZW50LnYxLkNvbnZlcnNhdGlvblNlYXJjaEFyZ3MSMgoGcmVzdWx0GAIgASgLMiIuYWdlbnQudjEuQ29udmVyc2F0aW9uU2VhcmNoUmVzdWx0IjkKGkNvbm5lY3RTY21HaXRodWJSZXBvc2l0b3J5Eg0KBW93bmVyGAEgASgJEgwKBHJlcG8YAiABKAkifgoQQ29ubmVjdFNjbUdpdGh1YhI4CgpyZXBvc2l0b3J5GAEgASgLMiQuYWdlbnQudjEuQ29ubmVjdFNjbUdpdGh1YlJlcG9zaXRvcnkSHAoPZ2hlX2FwcGxpY2F0aW9uGAIgASgJSACIAQFCEgoQX2doZV9hcHBsaWNhdGlvbiJeCg5Db25uZWN0U2NtQXJncxIUCgx0b29sX2NhbGxfaWQYASABKAkSLAoGZ2l0aHViGAIgASgLMhouYWdlbnQudjEuQ29ubmVjdFNjbUdpdGh1YkgAQggKBnRhcmdldCITChFDb25uZWN0U2NtU3VjY2VzcyIgCg9Db25uZWN0U2NtRXJyb3ISDQoFZXJyb3IYASABKAkiJAoSQ29ubmVjdFNjbVJlamVjdGVkEg4KBnJlYXNvbhgBIAEoCSKqAQoQQ29ubmVjdFNjbVJlc3VsdBIuCgdzdWNjZXNzGAEgASgLMhsuYWdlbnQudjEuQ29ubmVjdFNjbVN1Y2Nlc3NIABIqCgVlcnJvchgCIAEoCzIZLmFnZW50LnYxLkNvbm5lY3RTY21FcnJvckgAEjAKCHJlamVjdGVkGAMgASgLMhwuYWdlbnQudjEuQ29ubmVjdFNjbVJlamVjdGVkSABCCAoGcmVzdWx0ImgKEkNvbm5lY3RTY21Ub29sQ2FsbBImCgRhcmdzGAEgASgLMhguYWdlbnQudjEuQ29ubmVjdFNjbUFyZ3MSKgoGcmVzdWx0GAIgASgLMhouYWdlbnQudjEuQ29ubmVjdFNjbVJlc3VsdCqIAQodQXBwbGllZEFnZW50Q2hhbmdlX0NoYW5nZVR5cGUSGwoXQ0hBTkdFX1RZUEVfVU5TUEVDSUZJRUQQABIXChNDSEFOR0VfVFlQRV9DUkVBVEVEEAESGAoUQ0hBTkdFX1RZUEVfTU9ESUZJRUQQAhIXChNDSEFOR0VfVFlQRV9ERUxFVEVEEAMqpAEKC01vdXNlQnV0dG9uEhwKGE1PVVNFX0JVVFRPTl9VTlNQRUNJRklFRBAAEhUKEU1PVVNFX0JVVFRPTl9MRUZUEAESFgoSTU9VU0VfQlVUVE9OX1JJR0hUEAISFwoTTU9VU0VfQlVUVE9OX01JRERMRRADEhUKEU1PVVNFX0JVVFRPTl9CQUNLEAQSGAoUTU9VU0VfQlVUVE9OX0ZPUldBUkQQBSqeAQoPU2Nyb2xsRGlyZWN0aW9uEiAKHFNDUk9MTF9ESVJFQ1RJT05fVU5TUEVDSUZJRUQQABIXChNTQ1JPTExfRElSRUNUSU9OX1VQEAESGQoVU0NST0xMX0RJUkVDVElPTl9ET1dOEAISGQoVU0NST0xMX0RJUkVDVElPTl9MRUZUEAMSGgoWU0NST0xMX0RJUkVDVElPTl9SSUdIVBAEKnAKEEN1cnNvclJ1bGVTb3VyY2USIgoeQ1VSU09SX1JVTEVfU09VUkNFX1VOU1BFQ0lGSUVEEAASGwoXQ1VSU09SX1JVTEVfU09VUkNFX1RFQU0QARIbChdDVVJTT1JfUlVMRV9TT1VSQ0VfVVNFUhACKrwBChJEaWFnbm9zdGljU2V2ZXJpdHkSIwofRElBR05PU1RJQ19TRVZFUklUWV9VTlNQRUNJRklFRBAAEh0KGURJQUdOT1NUSUNfU0VWRVJJVFlfRVJST1IQARIfChtESUFHTk9TVElDX1NFVkVSSVRZX1dBUk5JTkcQAhIjCh9ESUFHTk9TVElDX1NFVkVSSVRZX0lORk9STUFUSU9OEAMSHAoYRElBR05PU1RJQ19TRVZFUklUWV9ISU5UEAQqnAEKDVJlY29yZGluZ01vZGUSHgoaUkVDT1JESU5HX01PREVfVU5TUEVDSUZJRUQQABIiCh5SRUNPUkRJTkdfTU9ERV9TVEFSVF9SRUNPUkRJTkcQARIhCh1SRUNPUkRJTkdfTU9ERV9TQVZFX1JFQ09SRElORxACEiQKIFJFQ09SRElOR19NT0RFX0RJU0NBUkRfUkVDT1JESU5HEAMqkwEKH1JlcXVlc3RlZEZpbGVQYXRoUmVqZWN0ZWRSZWFzb24SMwovUkVRVUVTVEVEX0ZJTEVfUEFUSF9SRUpFQ1RFRF9SRUFTT05fVU5TUEVDSUZJRUQQABI7CjdSRVFVRVNURURfRklMRV9QQVRIX1JFSkVDVEVEX1JFQVNPTl9TTEFTSEVTX05PVF9BTExPV0VEEAEqrQEKC1BhY2thZ2VUeXBlEhwKGFBBQ0tBR0VfVFlQRV9VTlNQRUNJRklFRBAAEh8KG1BBQ0tBR0VfVFlQRV9DVVJTT1JfUFJPSkVDVBABEiAKHFBBQ0tBR0VfVFlQRV9DVVJTT1JfUEVSU09OQUwQAhIdChlQQUNLQUdFX1RZUEVfQ0xBVURFX1NLSUxMEAMSHgoaUEFDS0FHRV9UWVBFX0NMQVVERV9QTFVHSU4QBCp9ChJTYW5kYm94UG9saWN5X1R5cGUSFAoQVFlQRV9VTlNQRUNJRklFRBAAEhYKElRZUEVfSU5TRUNVUkVfTk9ORRABEhwKGFRZUEVfV09SS1NQQUNFX1JFQURXUklURRACEhsKF1RZUEVfV09SS1NQQUNFX1JFQURPTkxZEAMqcQoPVGltZW91dEJlaGF2aW9yEiAKHFRJTUVPVVRfQkVIQVZJT1JfVU5TUEVDSUZJRUQQABIbChdUSU1FT1VUX0JFSEFWSU9SX0NBTkNFTBABEh8KG1RJTUVPVVRfQkVIQVZJT1JfQkFDS0dST1VORBACKnkKEFNoZWxsQWJvcnRSZWFzb24SIgoeU0hFTExfQUJPUlRfUkVBU09OX1VOU1BFQ0lGSUVEEAASIQodU0hFTExfQUJPUlRfUkVBU09OX1VTRVJfQUJPUlQQARIeChpTSEVMTF9BQk9SVF9SRUFTT05fVElNRU9VVBACKqoBChxDdXN0b21TdWJhZ2VudFBlcm1pc3Npb25Nb2RlEi8KK0NVU1RPTV9TVUJBR0VOVF9QRVJNSVNTSU9OX01PREVfVU5TUEVDSUZJRUQQABIrCidDVVNUT01fU1VCQUdFTlRfUEVSTUlTU0lPTl9NT0RFX0RFRkFVTFQQARIsCihDVVNUT01fU1VCQUdFTlRfUEVSTUlTU0lPTl9NT0RFX1JFQURPTkxZEAIqlQEKClRvZG9TdGF0dXMSGwoXVE9ET19TVEFUVVNfVU5TUEVDSUZJRUQQABIXChNUT0RPX1NUQVRVU19QRU5ESU5HEAESGwoXVE9ET19TVEFUVVNfSU5fUFJPR1JFU1MQAhIZChVUT0RPX1NUQVRVU19DT01QTEVURUQQAxIZChVUT0RPX1NUQVRVU19DQU5DRUxMRUQQBCpmCghDbGllbnRPUxIZChVDTElFTlRfT1NfVU5TUEVDSUZJRUQQABIVChFDTElFTlRfT1NfV0lORE9XUxABEhMKD0NMSUVOVF9PU19NQUNPUxACEhMKD0NMSUVOVF9PU19MSU5VWBADKuwBChxBcnRpZmFjdFVwbG9hZERpc3BhdGNoU3RhdHVzEi8KK0FSVElGQUNUX1VQTE9BRF9ESVNQQVRDSF9TVEFUVVNfVU5TUEVDSUZJRUQQABIsCihBUlRJRkFDVF9VUExPQURfRElTUEFUQ0hfU1RBVFVTX0FDQ0VQVEVEEAESLAooQVJUSUZBQ1RfVVBMT0FEX0RJU1BBVENIX1NUQVRVU19SRUpFQ1RFRBACEj8KO0FSVElGQUNUX1VQTE9BRF9ESVNQQVRDSF9TVEFUVVNfU0tJUFBFRF9BTFJFQURZX0lOX1BST0dSRVNTEAMqVwoKRnJhbWVfS2luZBIUChBLSU5EX1VOU1BFQ0lGSUVEEAASEAoMS0lORF9SRVFVRVNUEAESEQoNS0lORF9SRVNQT05TRRACEg4KCktJTkRfRVJST1IQAyqwAgoXQnVnYm90RGVlcGxpbmtFdmVudEtpbmQSKgomQlVHQk9UX0RFRVBMSU5LX0VWRU5UX0tJTkRfVU5TUEVDSUZJRUQQABImCiJCVUdCT1RfREVFUExJTktfRVZFTlRfS0lORF9DTElDS0VEEAESMwovQlVHQk9UX0RFRVBMSU5LX0VWRU5UX0tJTkRfSEFORExFRF9ESUFMT0dfU0hPV04QAhIzCi9CVUdCT1RfREVFUExJTktfRVZFTlRfS0lORF9IQU5ETEVEX0NIQVRfQ1JFQVRFRBADEiQKIEJVR0JPVF9ERUVQTElOS19FVkVOVF9LSU5EX0VSUk9SEAQSMQotQlVHQk9UX0RFRVBMSU5LX0VWRU5UX0tJTkRfSEFORExFRF9GSVhfSU5fV0VCEAUqygEKLENvbW1hbmRDbGFzc2lmaWVyUmVzdWx0X1N1Z2dlc3RlZFNhbmRib3hNb2RlEiYKIlNVR0dFU1RFRF9TQU5EQk9YX01PREVfVU5TUEVDSUZJRUQQABIiCh5TVUdHRVNURURfU0FOREJPWF9NT0RFX1NBTkRCT1gQARIlCiFTVUdHRVNURURfU0FOREJPWF9NT0RFX05PX1NBTkRCT1gQAhInCiNTVUdHRVNURURfU0FOREJPWF9NT0RFX1VOREVURVJNSU5FRBADKpABCiFTaGVsbEhvb2tBcHByb3ZhbFJlcXVpcmVtZW50X0tpbmQSNAowU0hFTExfSE9PS19BUFBST1ZBTF9SRVFVSVJFTUVOVF9LSU5EX1VOU1BFQ0lGSUVEEAASNQoxU0hFTExfSE9PS19BUFBST1ZBTF9SRVFVSVJFTUVOVF9LSU5EX0ZPUkNFX1BST01QVBABKo8BChVTaGVsbEJhY2tncm91bmRSZWFzb24SJwojU0hFTExfQkFDS0dST1VORF9SRUFTT05fVU5TUEVDSUZJRUQQABIjCh9TSEVMTF9CQUNLR1JPVU5EX1JFQVNPTl9USU1FT1VUEAESKAokU0hFTExfQkFDS0dST1VORF9SRUFTT05fVVNFUl9SRVFVRVNUEAIqpAEKGkZvcmNlQmFja2dyb3VuZFNoZWxsU3RhdHVzEi0KKUZPUkNFX0JBQ0tHUk9VTkRfU0hFTExfU1RBVFVTX1VOU1BFQ0lGSUVEEAASKgomRk9SQ0VfQkFDS0dST1VORF9TSEVMTF9TVEFUVVNfQUNDRVBURUQQARIrCidGT1JDRV9CQUNLR1JPVU5EX1NIRUxMX1NUQVRVU19OT1RfRk9VTkQQAirSAQoYU3ViYWdlbnRCYWNrZ3JvdW5kUmVhc29uEioKJlNVQkFHRU5UX0JBQ0tHUk9VTkRfUkVBU09OX1VOU1BFQ0lGSUVEEAASLAooU1VCQUdFTlRfQkFDS0dST1VORF9SRUFTT05fQUdFTlRfUkVRVUVTVBABEisKJ1NVQkFHRU5UX0JBQ0tHUk9VTkRfUkVBU09OX1VTRVJfUkVRVUVTVBACEi8KK1NVQkFHRU5UX0JBQ0tHUk9VTkRfUkVBU09OX1FVRVVFRF9GT0xMT1dfVVAQAyqwAQodRm9yY2VCYWNrZ3JvdW5kU3ViYWdlbnRTdGF0dXMSMAosRk9SQ0VfQkFDS0dST1VORF9TVUJBR0VOVF9TVEFUVVNfVU5TUEVDSUZJRUQQABItCilGT1JDRV9CQUNLR1JPVU5EX1NVQkFHRU5UX1NUQVRVU19BQ0NFUFRFRBABEi4KKkZPUkNFX0JBQ0tHUk9VTkRfU1VCQUdFTlRfU1RBVFVTX05PVF9GT1VORBACKqEBChtTbWFydE1vZGVDbGFzc2lmaWVyRGVjaXNpb24SLgoqU01BUlRfTU9ERV9DTEFTU0lGSUVSX0RFQ0lTSU9OX1VOU1BFQ0lGSUVEEAASKAokU01BUlRfTU9ERV9DTEFTU0lGSUVSX0RFQ0lTSU9OX0FMTE9XEAESKAokU01BUlRfTU9ERV9DTEFTU0lGSUVSX0RFQ0lTSU9OX0JMT0NLEAIqmAEKGENvbnZlcnNhdGlvblNlYXJjaFNvdXJjZRIqCiZDT05WRVJTQVRJT05fU0VBUkNIX1NPVVJDRV9VTlNQRUNJRklFRBAAEiQKIENPTlZFUlNBVElPTl9TRUFSQ0hfU09VUkNFX0xPQ0FMEAESKgomQ09OVkVSU0FUSU9OX1NFQVJDSF9TT1VSQ0VfQ0xPVURfQ0FDSEUQAirTAQobR2V0RGlmZlJlcXVlc3RfT3V0cHV0Rm9ybWF0Eh0KGU9VVFBVVF9GT1JNQVRfVU5TUEVDSUZJRUQQABIdChlPVVRQVVRfRk9STUFUX05BTUVfU1RBVFVTEAESKQolT1VUUFVUX0ZPUk1BVF9OQU1FX1NUQVRVU19BTkRfTlVNU1RBVBACEhwKGE9VVFBVVF9GT1JNQVRfRklMRV9ESUZGUxADEi0KKU9VVFBVVF9GT1JNQVRfRElGRlNfV0lUSF9CRUZPUkVfQU5EX0FGVEVSEAQqcQoQR2l0RGlmZl9EaWZmVHlwZRIZChVESUZGX1RZUEVfVU5TUEVDSUZJRUQQABIaChZESUZGX1RZUEVfRElGRl9UT19IRUFEEAESJgoiRElGRl9UWVBFX0RJRkZfRlJPTV9CUkFOQ0hfVE9fTUFJThACMocECgxBZ2VudFNlcnZpY2USQQoDUnVuEhwuYWdlbnQudjEuQWdlbnRDbGllbnRNZXNzYWdlGhwuYWdlbnQudjEuQWdlbnRTZXJ2ZXJNZXNzYWdlEj8KBlJ1blNTRRIXLmFnZW50LnYxLkJpZGlSZXF1ZXN0SWQaHC5hZ2VudC52MS5BZ2VudFNlcnZlck1lc3NhZ2USRAoJTmFtZUFnZW50EhouYWdlbnQudjEuTmFtZUFnZW50UmVxdWVzdBobLmFnZW50LnYxLk5hbWVBZ2VudFJlc3BvbnNlElYKD0dldFVzYWJsZU1vZGVscxIgLmFnZW50LnYxLkdldFVzYWJsZU1vZGVsc1JlcXVlc3QaIS5hZ2VudC52MS5HZXRVc2FibGVNb2RlbHNSZXNwb25zZRJoChVHZXREZWZhdWx0TW9kZWxGb3JDbGkSJi5hZ2VudC52MS5HZXREZWZhdWx0TW9kZWxGb3JDbGlSZXF1ZXN0GicuYWdlbnQudjEuR2V0RGVmYXVsdE1vZGVsRm9yQ2xpUmVzcG9uc2USawoWR2V0QWxsb3dlZE1vZGVsSW50ZW50cxInLmFnZW50LnYxLkdldEFsbG93ZWRNb2RlbEludGVudHNSZXF1ZXN0GiguYWdlbnQudjEuR2V0QWxsb3dlZE1vZGVsSW50ZW50c1Jlc3BvbnNlMrUICg5Db250cm9sU2VydmljZRJNCgxSZWFkVGV4dEZpbGUSHS5hZ2VudC52MS5SZWFkVGV4dEZpbGVSZXF1ZXN0Gh4uYWdlbnQudjEuUmVhZFRleHRGaWxlUmVzcG9uc2USUAoNV3JpdGVUZXh0RmlsZRIeLmFnZW50LnYxLldyaXRlVGV4dEZpbGVSZXF1ZXN0Gh8uYWdlbnQudjEuV3JpdGVUZXh0RmlsZVJlc3BvbnNlElMKDlJlYWRCaW5hcnlGaWxlEh8uYWdlbnQudjEuUmVhZEJpbmFyeUZpbGVSZXF1ZXN0GiAuYWdlbnQudjEuUmVhZEJpbmFyeUZpbGVSZXNwb25zZRJWCg9Xcml0ZUJpbmFyeUZpbGUSIC5hZ2VudC52MS5Xcml0ZUJpbmFyeUZpbGVSZXF1ZXN0GiEuYWdlbnQudjEuV3JpdGVCaW5hcnlGaWxlUmVzcG9uc2USbgoXR2V0V29ya3NwYWNlQ2hhbmdlc0hhc2gSKC5hZ2VudC52MS5HZXRXb3Jrc3BhY2VDaGFuZ2VzSGFzaFJlcXVlc3QaKS5hZ2VudC52MS5HZXRXb3Jrc3BhY2VDaGFuZ2VzSGFzaFJlc3BvbnNlEnEKGFJlZnJlc2hHaXRodWJBY2Nlc3NUb2tlbhIpLmFnZW50LnYxLlJlZnJlc2hHaXRodWJBY2Nlc3NUb2tlblJlcXVlc3QaKi5hZ2VudC52MS5SZWZyZXNoR2l0aHViQWNjZXNzVG9rZW5SZXNwb25zZRJrChZXYXJtUmVtb3RlQWNjZXNzU2VydmVyEicuYWdlbnQudjEuV2FybVJlbW90ZUFjY2Vzc1NlcnZlclJlcXVlc3QaKC5hZ2VudC52MS5XYXJtUmVtb3RlQWNjZXNzU2VydmVyUmVzcG9uc2USUAoNTGlzdEFydGlmYWN0cxIeLmFnZW50LnYxLkxpc3RBcnRpZmFjdHNSZXF1ZXN0Gh8uYWdlbnQudjEuTGlzdEFydGlmYWN0c1Jlc3BvbnNlElYKD1VwbG9hZEFydGlmYWN0cxIgLmFnZW50LnYxLlVwbG9hZEFydGlmYWN0c1JlcXVlc3QaIS5hZ2VudC52MS5VcGxvYWRBcnRpZmFjdHNSZXNwb25zZRJiChNHZXRNY3BSZWZyZXNoVG9rZW5zEiQuYWdlbnQudjEuR2V0TWNwUmVmcmVzaFRva2Vuc1JlcXVlc3QaJS5hZ2VudC52MS5HZXRNY3BSZWZyZXNoVG9rZW5zUmVzcG9uc2USdwoaVXBkYXRlRW52aXJvbm1lbnRWYXJpYWJsZXMSKy5hZ2VudC52MS5VcGRhdGVFbnZpcm9ubWVudFZhcmlhYmxlc1JlcXVlc3QaLC5hZ2VudC52MS5VcGRhdGVFbnZpcm9ubWVudFZhcmlhYmxlc1Jlc3BvbnNlMg0KC0V4ZWNTZXJ2aWNlMlEKIlByaXZhdGVXb3JrZXJCcmlkZ2VFeHRlcm5hbFNlcnZpY2USKwoHQ29ubmVjdBIPLmFnZW50LnYxLkZyYW1lGg8uYWdlbnQudjEuRnJhbWUyeAoQTGlmZWN5Y2xlU2VydmljZRIxCg1SZXNldEluc3RhbmNlEg8uYWdlbnQudjEuRW1wdHkaDy5hZ2VudC52MS5FbXB0eRIxCg1SZW5ld0luc3RhbmNlEg8uYWdlbnQudjEuRW1wdHkaDy5hZ2VudC52MS5FbXB0eWIGcHJvdG8z"); /** * @generated from message agent.v1.GlobToolResult @@ -1336,7 +1336,71 @@ export type ToolCall = Message<"agent.v1.ToolCall"> & { */ value: StartGrindPlanningToolCall; case: "startGrindPlanningToolCall"; + } | { + /** + * @generated from field: agent.v1.PiReadToolCall pi_read_tool_call = 61; + */ + value: PiReadToolCall; + case: "piReadToolCall"; + } | { + /** + * @generated from field: agent.v1.PiBashToolCall pi_bash_tool_call = 62; + */ + value: PiBashToolCall; + case: "piBashToolCall"; + } | { + /** + * @generated from field: agent.v1.PiEditToolCall pi_edit_tool_call = 63; + */ + value: PiEditToolCall; + case: "piEditToolCall"; + } | { + /** + * @generated from field: agent.v1.PiWriteToolCall pi_write_tool_call = 64; + */ + value: PiWriteToolCall; + case: "piWriteToolCall"; + } | { + /** + * @generated from field: agent.v1.PiGrepToolCall pi_grep_tool_call = 65; + */ + value: PiGrepToolCall; + case: "piGrepToolCall"; + } | { + /** + * @generated from field: agent.v1.PiFindToolCall pi_find_tool_call = 66; + */ + value: PiFindToolCall; + case: "piFindToolCall"; + } | { + /** + * @generated from field: agent.v1.PiLsToolCall pi_ls_tool_call = 67; + */ + value: PiLsToolCall; + case: "piLsToolCall"; + } | { + /** + * @generated from field: agent.v1.ConnectScmToolCall connect_scm_tool_call = 68; + */ + value: ConnectScmToolCall; + case: "connectScmToolCall"; + } | { + /** + * @generated from field: agent.v1.SearchConversationsToolCall search_conversations_tool_call = 69; + */ + value: SearchConversationsToolCall; + case: "searchConversationsToolCall"; } | { case: undefined; value?: undefined }; + + /** + * Modern builds carry the call id on the envelope instead of inside each + * variant's args. Fields 37-53, 55, 56, 58 (further tool variants) and 54 + * (hook_additional_contexts), 59/60 (started_at_ms/completed_at_ms) are not + * modelled and decode into unknown fields; do not reuse those numbers. + * + * @generated from field: optional string tool_call_id = 57; + */ + toolCallId?: string | undefined; }; /** @@ -18061,6 +18125,358 @@ export type GetDiffResponse = Message<"agent.v1.GetDiffResponse"> & { export const GetDiffResponseSchema: GenMessage = /*@__PURE__*/ messageDesc(file_agent, 610); +/** + * @generated from message agent.v1.PiReadToolCall + */ +export type PiReadToolCall = Message<"agent.v1.PiReadToolCall"> & { + /** + * @generated from field: agent.v1.PiReadExecArgs args = 1; + */ + args?: PiReadExecArgs | undefined; + + /** + * @generated from field: agent.v1.PiReadExecResult result = 2; + */ + result?: PiReadExecResult | undefined; +}; + +/** + * Describes the message agent.v1.PiReadToolCall. + * Use `create(PiReadToolCallSchema)` to create a new message. + */ +export const PiReadToolCallSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_agent, 611); + +/** + * @generated from message agent.v1.PiBashToolCall + */ +export type PiBashToolCall = Message<"agent.v1.PiBashToolCall"> & { + /** + * @generated from field: agent.v1.PiBashExecArgs args = 1; + */ + args?: PiBashExecArgs | undefined; + + /** + * @generated from field: agent.v1.PiBashExecResult result = 2; + */ + result?: PiBashExecResult | undefined; +}; + +/** + * Describes the message agent.v1.PiBashToolCall. + * Use `create(PiBashToolCallSchema)` to create a new message. + */ +export const PiBashToolCallSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_agent, 612); + +/** + * @generated from message agent.v1.PiEditToolCall + */ +export type PiEditToolCall = Message<"agent.v1.PiEditToolCall"> & { + /** + * @generated from field: agent.v1.PiEditExecArgs args = 1; + */ + args?: PiEditExecArgs | undefined; + + /** + * @generated from field: agent.v1.PiEditExecResult result = 2; + */ + result?: PiEditExecResult | undefined; +}; + +/** + * Describes the message agent.v1.PiEditToolCall. + * Use `create(PiEditToolCallSchema)` to create a new message. + */ +export const PiEditToolCallSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_agent, 613); + +/** + * @generated from message agent.v1.PiWriteToolCall + */ +export type PiWriteToolCall = Message<"agent.v1.PiWriteToolCall"> & { + /** + * @generated from field: agent.v1.PiWriteExecArgs args = 1; + */ + args?: PiWriteExecArgs | undefined; + + /** + * @generated from field: agent.v1.PiWriteExecResult result = 2; + */ + result?: PiWriteExecResult | undefined; +}; + +/** + * Describes the message agent.v1.PiWriteToolCall. + * Use `create(PiWriteToolCallSchema)` to create a new message. + */ +export const PiWriteToolCallSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_agent, 614); + +/** + * @generated from message agent.v1.PiGrepToolCall + */ +export type PiGrepToolCall = Message<"agent.v1.PiGrepToolCall"> & { + /** + * @generated from field: agent.v1.PiGrepExecArgs args = 1; + */ + args?: PiGrepExecArgs | undefined; + + /** + * @generated from field: agent.v1.PiGrepExecResult result = 2; + */ + result?: PiGrepExecResult | undefined; +}; + +/** + * Describes the message agent.v1.PiGrepToolCall. + * Use `create(PiGrepToolCallSchema)` to create a new message. + */ +export const PiGrepToolCallSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_agent, 615); + +/** + * @generated from message agent.v1.PiFindToolCall + */ +export type PiFindToolCall = Message<"agent.v1.PiFindToolCall"> & { + /** + * @generated from field: agent.v1.PiFindExecArgs args = 1; + */ + args?: PiFindExecArgs | undefined; + + /** + * @generated from field: agent.v1.PiFindExecResult result = 2; + */ + result?: PiFindExecResult | undefined; +}; + +/** + * Describes the message agent.v1.PiFindToolCall. + * Use `create(PiFindToolCallSchema)` to create a new message. + */ +export const PiFindToolCallSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_agent, 616); + +/** + * @generated from message agent.v1.PiLsToolCall + */ +export type PiLsToolCall = Message<"agent.v1.PiLsToolCall"> & { + /** + * @generated from field: agent.v1.PiLsExecArgs args = 1; + */ + args?: PiLsExecArgs | undefined; + + /** + * @generated from field: agent.v1.PiLsExecResult result = 2; + */ + result?: PiLsExecResult | undefined; +}; + +/** + * Describes the message agent.v1.PiLsToolCall. + * Use `create(PiLsToolCallSchema)` to create a new message. + */ +export const PiLsToolCallSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_agent, 617); + +/** + * @generated from message agent.v1.SearchConversationsToolCall + */ +export type SearchConversationsToolCall = Message<"agent.v1.SearchConversationsToolCall"> & { + /** + * @generated from field: agent.v1.ConversationSearchArgs args = 1; + */ + args?: ConversationSearchArgs | undefined; + + /** + * @generated from field: agent.v1.ConversationSearchResult result = 2; + */ + result?: ConversationSearchResult | undefined; +}; + +/** + * Describes the message agent.v1.SearchConversationsToolCall. + * Use `create(SearchConversationsToolCallSchema)` to create a new message. + */ +export const SearchConversationsToolCallSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_agent, 618); + +/** + * @generated from message agent.v1.ConnectScmGithubRepository + */ +export type ConnectScmGithubRepository = Message<"agent.v1.ConnectScmGithubRepository"> & { + /** + * @generated from field: string owner = 1; + */ + owner: string; + + /** + * @generated from field: string repo = 2; + */ + repo: string; +}; + +/** + * Describes the message agent.v1.ConnectScmGithubRepository. + * Use `create(ConnectScmGithubRepositorySchema)` to create a new message. + */ +export const ConnectScmGithubRepositorySchema: GenMessage = /*@__PURE__*/ + messageDesc(file_agent, 619); + +/** + * @generated from message agent.v1.ConnectScmGithub + */ +export type ConnectScmGithub = Message<"agent.v1.ConnectScmGithub"> & { + /** + * @generated from field: agent.v1.ConnectScmGithubRepository repository = 1; + */ + repository?: ConnectScmGithubRepository | undefined; + + /** + * @generated from field: optional string ghe_application = 2; + */ + gheApplication?: string | undefined; +}; + +/** + * Describes the message agent.v1.ConnectScmGithub. + * Use `create(ConnectScmGithubSchema)` to create a new message. + */ +export const ConnectScmGithubSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_agent, 620); + +/** + * @generated from message agent.v1.ConnectScmArgs + */ +export type ConnectScmArgs = Message<"agent.v1.ConnectScmArgs"> & { + /** + * @generated from field: string tool_call_id = 1; + */ + toolCallId: string; + + /** + * @generated from oneof agent.v1.ConnectScmArgs.target + */ + target: { + /** + * @generated from field: agent.v1.ConnectScmGithub github = 2; + */ + value: ConnectScmGithub; + case: "github"; + } | { case: undefined; value?: undefined }; +}; + +/** + * Describes the message agent.v1.ConnectScmArgs. + * Use `create(ConnectScmArgsSchema)` to create a new message. + */ +export const ConnectScmArgsSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_agent, 621); + +/** + * @generated from message agent.v1.ConnectScmSuccess + */ +export type ConnectScmSuccess = Message<"agent.v1.ConnectScmSuccess"> & { +}; + +/** + * Describes the message agent.v1.ConnectScmSuccess. + * Use `create(ConnectScmSuccessSchema)` to create a new message. + */ +export const ConnectScmSuccessSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_agent, 622); + +/** + * @generated from message agent.v1.ConnectScmError + */ +export type ConnectScmError = Message<"agent.v1.ConnectScmError"> & { + /** + * @generated from field: string error = 1; + */ + error: string; +}; + +/** + * Describes the message agent.v1.ConnectScmError. + * Use `create(ConnectScmErrorSchema)` to create a new message. + */ +export const ConnectScmErrorSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_agent, 623); + +/** + * @generated from message agent.v1.ConnectScmRejected + */ +export type ConnectScmRejected = Message<"agent.v1.ConnectScmRejected"> & { + /** + * @generated from field: string reason = 1; + */ + reason: string; +}; + +/** + * Describes the message agent.v1.ConnectScmRejected. + * Use `create(ConnectScmRejectedSchema)` to create a new message. + */ +export const ConnectScmRejectedSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_agent, 624); + +/** + * @generated from message agent.v1.ConnectScmResult + */ +export type ConnectScmResult = Message<"agent.v1.ConnectScmResult"> & { + /** + * @generated from oneof agent.v1.ConnectScmResult.result + */ + result: { + /** + * @generated from field: agent.v1.ConnectScmSuccess success = 1; + */ + value: ConnectScmSuccess; + case: "success"; + } | { + /** + * @generated from field: agent.v1.ConnectScmError error = 2; + */ + value: ConnectScmError; + case: "error"; + } | { + /** + * @generated from field: agent.v1.ConnectScmRejected rejected = 3; + */ + value: ConnectScmRejected; + case: "rejected"; + } | { case: undefined; value?: undefined }; +}; + +/** + * Describes the message agent.v1.ConnectScmResult. + * Use `create(ConnectScmResultSchema)` to create a new message. + */ +export const ConnectScmResultSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_agent, 625); + +/** + * @generated from message agent.v1.ConnectScmToolCall + */ +export type ConnectScmToolCall = Message<"agent.v1.ConnectScmToolCall"> & { + /** + * @generated from field: agent.v1.ConnectScmArgs args = 1; + */ + args?: ConnectScmArgs | undefined; + + /** + * @generated from field: agent.v1.ConnectScmResult result = 2; + */ + result?: ConnectScmResult | undefined; +}; + +/** + * Describes the message agent.v1.ConnectScmToolCall. + * Use `create(ConnectScmToolCallSchema)` to create a new message. + */ +export const ConnectScmToolCallSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_agent, 626); + /** * @generated from enum agent.v1.AppliedAgentChange_ChangeType */ diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 6859f52d6..a175d40cf 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -161,6 +161,9 @@ - Fixed MiMo models using hashline edit mode by default despite needing the same replace-mode fallback as Kimi. ([#3772](https://github.com/can1357/oh-my-pi/issues/3772)) - Fixed `omp` refusing to start on Windows when no `bash.exe` is discoverable — most visibly with scoop-installed Git, whose manifest shims `sh.exe`/`git.exe` but never `bash.exe`, so PATH lookup missed it. Startup threw `No bash shell found` while merely building the bash tool description, even though bash tool commands always execute in the embedded brush-core shell and need no host bash. Shell discovery now also checks `GIT_INSTALL_ROOT`, scoop and per-user Git for Windows install roots, and `sh.exe` on PATH, then falls back to `cmd.exe` for the spawn-only paths (interactive PTY, ACP client terminals) instead of failing; the cmd fallback is never used to wrap user-shell commands — brush runs the POSIX line directly. - Added a selectable voice setting for `/live` realtime sessions ([#6566](https://github.com/can1357/oh-my-pi/issues/6566)). +### Added + +- The Cursor exec bridge serves the seven modern Pi tool frames, mapping each to its local equivalent: `pi_read`/`pi_ls` → `read`, `pi_bash` → `bash`, `pi_edit` → `edit`, `pi_write` → `write`, `pi_grep` → `grep`, and `pi_find` → `glob`. The frames are a separate wire family from the legacy args, not aliases, so each mapping is a real translation — `pi_grep`'s `ignore_case` is the inverse of the local tool's case-sensitivity flag, `pi_find` searches filenames rather than contents, and `pi_edit`'s replacements are renamed to the local snake_case pairs. ## [17.1.4] - 2026-07-26 diff --git a/packages/coding-agent/src/cursor.ts b/packages/coding-agent/src/cursor.ts index 7c30755a6..e06b72866 100644 --- a/packages/coding-agent/src/cursor.ts +++ b/packages/coding-agent/src/cursor.ts @@ -401,6 +401,75 @@ export class CursorExecHandlers implements ICursorExecHandlers { }); return toolResultMessage; } + /** + * Modern Cursor CLI Pi tool frames (`ExecServerMessage` 45-51). + * + * These are a separate frame family from the legacy `read`/`shell`/... set, + * not aliases: different args, different result oneofs, and no `tool_call_id` + * (the provider mints one and passes it in `call.toolCallId`). Each maps onto + * the local tool with matching semantics, so the same approval, sandboxing + * and event plumbing applies as for a model-issued call. + */ + async piRead(call: Parameters>[0]) { + return await executeTool(this.options, "read", call.toolCallId, { path: call.args.path }); + } + + async piBash(call: Parameters>[0]) { + const { timeout } = call.args; + return await executeTool(this.options, "bash", call.toolCallId, { + command: call.args.command, + timeout: timeout && timeout > 0 ? timeout : undefined, + }); + } + + /** + * `PiEditExecArgs` is the local `edit` tool's replace mode verbatim: a path + * plus `old_text`/`new_text` pairs. The tool's schema is snake_case, so the + * proto's camelCase accessors are mapped back on the way in. + */ + async piEdit(call: Parameters>[0]) { + return await executeTool(this.options, "edit", call.toolCallId, { + path: call.args.path, + edits: call.args.edits.map(edit => ({ old_text: edit.oldText, new_text: edit.newText })), + }); + } + + async piWrite(call: Parameters>[0]) { + return await executeTool(this.options, "write", call.toolCallId, { + path: call.args.path, + content: call.args.content, + }); + } + + async piGrep(call: Parameters>[0]) { + const { pattern, path, glob, ignoreCase } = call.args; + // Same arg mapping as the legacy `grep` handler: the local tool takes one + // path spec, and its `case` flag is case-SENSITIVITY, the inverse of the + // frame's `ignore_case`. + return await executeTool(this.options, "grep", call.toolCallId, { + pattern, + path: glob ? `${path || "."}/${glob}` : path || ".", + case: ignoreCase === true ? false : undefined, + }); + } + + /** + * `pi_find` is a filename search, which is the local `glob` tool — not + * `grep`. Its `pattern` is a glob, joined onto `path` because `glob` takes a + * single combined path spec. + */ + async piFind(call: Parameters>[0]) { + const { pattern, path, limit } = call.args; + return await executeTool(this.options, "glob", call.toolCallId, { + path: path ? `${path}/${pattern}` : pattern, + limit: limit && limit > 0 ? limit : undefined, + }); + } + + /** Redirected to `read`, which lists directories — same as the legacy `ls`. */ + async piLs(call: Parameters>[0]) { + return await executeTool(this.options, "read", call.toolCallId, { path: call.args.path || "." }); + } /** * Settle a completed native Cursor todo call, mirroring its list when the diff --git a/packages/coding-agent/test/cursor-exec.test.ts b/packages/coding-agent/test/cursor-exec.test.ts index 2827cb782..74a386147 100644 --- a/packages/coding-agent/test/cursor-exec.test.ts +++ b/packages/coding-agent/test/cursor-exec.test.ts @@ -244,6 +244,7 @@ function newBlockState(): BlockState { return toolCall; }, firstTokenTime: undefined, + openToolCalls: new Map(), resolvedMcpToolCallIds: new Set(), setTextBlock: b => { textBlock = b; @@ -430,3 +431,96 @@ describe("CursorExecHandlers native delete gating (issue #5680)", () => { expect(await Bun.file(movedTarget).exists()).toBe(false); }); }); + +// The Pi frames (`ExecServerMessage` 45-51) are a separate wire family from the +// legacy `read`/`shell`/`grep` args, with different field names and different +// semantics. Each bridge handler therefore performs a real translation, and a +// wrong one silently searches the wrong thing instead of failing. +describe("CursorExecHandlers Pi frame translation", () => { + let cwd: string; + + beforeEach(async () => { + cwd = await fs.mkdtemp(path.join(os.tmpdir(), "cursor-pi-test-")); + }); + + afterEach(async () => { + await removeWithRetries(cwd); + }); + + /** Captures the args one local tool was invoked with. */ + function recordingHandlers(toolName: string): { handlers: CursorExecHandlers; calls: unknown[] } { + const calls: unknown[] = []; + const tool: AgentTool = { + name: toolName, + label: toolName, + description: "records its args", + parameters: type({}), + execute: async (_toolCallId: string, params: unknown) => { + calls.push(params); + return { content: [{ type: "text" as const, text: "ok" }] }; + }, + }; + const handlers = new CursorExecHandlers({ cwd, tools: new Map([[toolName, tool]]) }); + return { handlers, calls }; + } + + it("inverts pi_grep's ignore_case into the local tool's case-sensitivity flag", async () => { + // `ignore_case` and `case` are opposites. Passing the frame's value + // straight through would flip every search's matching. + const { handlers, calls } = recordingHandlers("grep"); + + await handlers.piGrep({ toolCallId: "c1", args: { pattern: "x", ignoreCase: true } } as never); + await handlers.piGrep({ toolCallId: "c2", args: { pattern: "x", ignoreCase: false } } as never); + + expect(calls).toEqual([ + { pattern: "x", path: ".", case: false }, + // Case-sensitive is the local default, so `false` maps to "unset", + // not to `case: true`. + { pattern: "x", path: ".", case: undefined }, + ]); + }); + + it("folds pi_grep's separate glob onto the local tool's single path spec", async () => { + const { handlers, calls } = recordingHandlers("grep"); + + await handlers.piGrep({ toolCallId: "c1", args: { pattern: "x", path: "src", glob: "**/*.ts" } } as never); + await handlers.piGrep({ toolCallId: "c2", args: { pattern: "x", glob: "**/*.ts" } } as never); + + expect((calls[0] as { path: string }).path).toBe("src/**/*.ts"); + expect((calls[1] as { path: string }).path).toBe("./**/*.ts"); + }); + + it("routes pi_find to glob, not grep, joining its pattern onto the path", async () => { + // `pi_find` searches filenames. Routing it to `grep` would search file + // contents for the glob text and return nothing. + const { handlers, calls } = recordingHandlers("glob"); + + await handlers.piFind({ toolCallId: "c1", args: { pattern: "*.ts", path: "src", limit: 10 } } as never); + await handlers.piFind({ toolCallId: "c2", args: { pattern: "*.ts", limit: 0 } } as never); + + expect(calls).toEqual([ + { path: "src/*.ts", limit: 10 }, + // A zero limit is protobuf's unset, not a request for zero results. + { path: "*.ts", limit: undefined }, + ]); + }); + + it("renames pi_edit's camelCase replacements to the local tool's snake_case pairs", async () => { + const { handlers, calls } = recordingHandlers("edit"); + + await handlers.piEdit({ + toolCallId: "c1", + args: { path: "a.ts", edits: [{ oldText: "before", newText: "after" }] }, + } as never); + + expect(calls[0]).toEqual({ path: "a.ts", edits: [{ old_text: "before", new_text: "after" }] }); + }); + + it("lists directories for pi_ls through read, defaulting an empty path to cwd", async () => { + const { handlers, calls } = recordingHandlers("read"); + + await handlers.piLs({ toolCallId: "c1", args: { path: "" } } as never); + + expect(calls[0]).toEqual({ path: "." }); + }); +});