red-green-refactor-cycle-so.../transcripts/socrates-uk-session.html

4329 lines
607 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Session Export</title>
<style>
:root {
--accent: #5a8080;
--border: #547da7;
--borderAccent: #5a8080;
--borderMuted: #b0b0b0;
--success: #588458;
--error: #aa5555;
--warning: #9a7326;
--muted: #6c6c6c;
--dim: #767676;
--text: #1f2328;
--thinkingText: #6c6c6c;
--selectedBg: #d0d0e0;
--userMessageBg: #e8e8e8;
--userMessageText: #1f2328;
--customMessageBg: #ede7f6;
--customMessageText: #1f2328;
--customMessageLabel: #7e57c2;
--toolPendingBg: #e8e8f0;
--toolSuccessBg: #e8f0e8;
--toolErrorBg: #f0e8e8;
--toolTitle: #1f2328;
--toolOutput: #6c6c6c;
--mdHeading: #9a7326;
--mdLink: #547da7;
--mdLinkUrl: #767676;
--mdCode: #5a8080;
--mdCodeBlock: #588458;
--mdCodeBlockBorder: #6c6c6c;
--mdQuote: #6c6c6c;
--mdQuoteBorder: #6c6c6c;
--mdHr: #6c6c6c;
--mdListBullet: #588458;
--toolDiffAdded: #588458;
--toolDiffRemoved: #aa5555;
--toolDiffContext: #6c6c6c;
--syntaxComment: #008000;
--syntaxKeyword: #0000FF;
--syntaxFunction: #795E26;
--syntaxVariable: #001080;
--syntaxString: #A31515;
--syntaxNumber: #098658;
--syntaxType: #267F99;
--syntaxOperator: #000000;
--syntaxPunctuation: #000000;
--thinkingOff: #b0b0b0;
--thinkingMinimal: #767676;
--thinkingLow: #547da7;
--thinkingMedium: #5a8080;
--thinkingHigh: #875f87;
--thinkingXhigh: #8b008b;
--bashMode: #588458;
--exportPageBg: #f8f8f8;
--exportCardBg: #ffffff;
--exportInfoBg: #fffae6;
--body-bg: #f8f8f8;
--container-bg: #ffffff;
--info-bg: #fffae6;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
:root {
--line-height: 18px; /* 12px font * 1.5 */
--sidebar-width: 400px;
--sidebar-min-width: 240px;
--sidebar-max-width: 840px;
--sidebar-resizer-width: 6px;
}
body {
font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;
font-size: 12px;
line-height: var(--line-height);
color: var(--text);
background: var(--body-bg);
}
body.sidebar-resizing {
cursor: col-resize;
user-select: none;
}
#app {
display: flex;
min-height: 100vh;
}
/* Sidebar */
#sidebar {
width: var(--sidebar-width);
min-width: var(--sidebar-width);
max-width: var(--sidebar-width);
background: var(--container-bg);
flex-shrink: 0;
display: flex;
flex-direction: column;
position: sticky;
top: 0;
height: 100vh;
border-right: 1px solid var(--dim);
}
#sidebar-resizer {
width: var(--sidebar-resizer-width);
flex-shrink: 0;
position: sticky;
top: 0;
height: 100vh;
cursor: col-resize;
touch-action: none;
background: transparent;
border-right: 1px solid transparent;
}
#sidebar-resizer:hover,
body.sidebar-resizing #sidebar-resizer {
background: var(--selectedBg);
border-right-color: var(--dim);
}
.sidebar-header {
padding: 8px 12px;
flex-shrink: 0;
}
.sidebar-controls {
padding: 8px 8px 4px 8px;
}
.sidebar-search {
width: 100%;
box-sizing: border-box;
padding: 4px 8px;
font-size: 11px;
font-family: inherit;
background: var(--body-bg);
color: var(--text);
border: 1px solid var(--dim);
border-radius: 3px;
}
.sidebar-filters {
display: flex;
padding: 4px 8px 8px 8px;
gap: 4px;
align-items: center;
flex-wrap: wrap;
}
.sidebar-search:focus {
outline: none;
border-color: var(--accent);
}
.sidebar-search::placeholder {
color: var(--muted);
}
.filter-btn {
padding: 3px 8px;
font-size: 10px;
font-family: inherit;
background: transparent;
color: var(--muted);
border: 1px solid var(--dim);
border-radius: 3px;
cursor: pointer;
}
.filter-btn:hover {
color: var(--text);
border-color: var(--text);
}
.filter-btn.active {
background: var(--accent);
color: var(--body-bg);
border-color: var(--accent);
}
.sidebar-close {
display: none;
padding: 3px 8px;
font-size: 12px;
font-family: inherit;
background: transparent;
color: var(--muted);
border: 1px solid var(--dim);
border-radius: 3px;
cursor: pointer;
margin-left: auto;
}
.sidebar-close:hover {
color: var(--text);
border-color: var(--text);
}
.tree-container {
flex: 1;
overflow: auto;
padding: 4px 0;
}
.tree-node {
padding: 0 8px;
cursor: pointer;
display: flex;
align-items: baseline;
font-size: 11px;
line-height: 13px;
white-space: nowrap;
}
.tree-node:hover {
background: var(--selectedBg);
}
.tree-node.active {
background: var(--selectedBg);
}
.tree-node.active .tree-content {
font-weight: bold;
}
.tree-node.in-path {
background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.tree-node:not(.in-path) {
opacity: 0.5;
}
.tree-node:not(.in-path):hover {
opacity: 1;
}
.tree-prefix {
color: var(--muted);
flex-shrink: 0;
font-family: monospace;
white-space: pre;
}
.tree-marker {
color: var(--accent);
flex-shrink: 0;
}
.tree-content {
color: var(--text);
}
.tree-role-user {
color: var(--accent);
}
.tree-role-skill {
color: var(--customMessageLabel);
}
.tree-role-assistant {
color: var(--success);
}
.tree-role-tool {
color: var(--muted);
}
.tree-muted {
color: var(--muted);
}
.tree-error {
color: var(--error);
}
.tree-compaction {
color: var(--borderAccent);
}
.tree-branch-summary {
color: var(--warning);
}
.tree-custom-message {
color: var(--customMessageLabel);
}
.tree-status {
padding: 4px 12px;
font-size: 10px;
color: var(--muted);
flex-shrink: 0;
}
/* Main content */
#content {
flex: 1;
min-width: 0;
overflow-y: auto;
padding: var(--line-height) calc(var(--line-height) * 2);
display: flex;
flex-direction: column;
align-items: center;
}
#content > * {
width: 100%;
max-width: 800px;
}
/* Help bar */
.help-bar {
font-size: 11px;
color: var(--warning);
margin-bottom: var(--line-height);
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12px;
}
.help-hint {
flex: 1 1 240px;
}
.help-actions {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
}
.header-toggle-btn,
.download-json-btn {
font-size: 10px;
padding: 2px 8px;
background: var(--container-bg);
border: 1px solid var(--border);
border-radius: 3px;
color: var(--text);
cursor: pointer;
font-family: inherit;
}
.header-toggle-btn:hover,
.download-json-btn:hover {
background: var(--hover);
border-color: var(--borderAccent);
}
/* Header */
.header {
background: var(--container-bg);
border-radius: 4px;
padding: var(--line-height);
margin-bottom: var(--line-height);
}
.header h1 {
font-size: 12px;
font-weight: bold;
color: var(--borderAccent);
margin-bottom: var(--line-height);
}
.header-info {
display: flex;
flex-direction: column;
gap: 0;
font-size: 11px;
}
.info-item {
color: var(--dim);
display: flex;
align-items: baseline;
}
.info-label {
font-weight: 600;
margin-right: 8px;
min-width: 100px;
}
.info-value {
color: var(--text);
flex: 1;
}
/* Messages */
#messages {
display: flex;
flex-direction: column;
gap: var(--line-height);
}
.message-timestamp {
font-size: 10px;
color: var(--dim);
opacity: 0.8;
}
.user-message {
background: var(--userMessageBg);
color: var(--userMessageText);
padding: var(--line-height);
border-radius: 4px;
position: relative;
}
.assistant-message {
padding: 0;
position: relative;
}
/* Copy link button - appears on hover */
.copy-link-btn {
position: absolute;
top: 8px;
right: 8px;
width: 28px;
height: 28px;
padding: 6px;
background: var(--container-bg);
border: 1px solid var(--dim);
border-radius: 4px;
color: var(--muted);
cursor: pointer;
opacity: 0;
transition: opacity 0.15s, background 0.15s, color 0.15s;
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
}
.user-message:hover .copy-link-btn,
.assistant-message:hover .copy-link-btn,
.skill-user-entry:hover .copy-link-btn {
opacity: 1;
}
.copy-link-btn:hover {
background: var(--accent);
color: var(--body-bg);
border-color: var(--accent);
}
.copy-link-btn.copied {
background: var(--success, #22c55e);
color: white;
border-color: var(--success, #22c55e);
}
/* Highlight effect for deep-linked messages */
.user-message.highlight,
.assistant-message.highlight {
animation: highlight-pulse 2s ease-out;
}
@keyframes highlight-pulse {
0% {
box-shadow: 0 0 0 3px var(--accent);
}
100% {
box-shadow: 0 0 0 0 transparent;
}
}
.assistant-message > .message-timestamp {
padding-left: var(--line-height);
}
.assistant-text {
padding: var(--line-height);
padding-bottom: 0;
}
.message-timestamp + .assistant-text,
.message-timestamp + .thinking-block {
padding-top: 0;
}
.thinking-block + .assistant-text {
padding-top: 0;
}
.thinking-text {
padding: var(--line-height);
color: var(--thinkingText);
font-style: italic;
white-space: pre-wrap;
}
.message-timestamp + .thinking-block .thinking-text,
.message-timestamp + .thinking-block .thinking-collapsed {
padding-top: 0;
}
.thinking-collapsed {
display: none;
padding: var(--line-height);
color: var(--thinkingText);
font-style: italic;
}
/* Tool execution */
.tool-execution {
padding: var(--line-height);
border-radius: 4px;
}
.tool-execution + .tool-execution {
margin-top: var(--line-height);
}
.assistant-text + .tool-execution {
margin-top: var(--line-height);
}
.tool-execution.pending { background: var(--toolPendingBg); }
.tool-execution.success { background: var(--toolSuccessBg); }
.tool-execution.error { background: var(--toolErrorBg); }
.tool-header, .tool-name {
font-weight: bold;
}
.tool-path {
color: var(--accent);
word-break: break-all;
}
.line-numbers {
color: var(--warning);
}
.line-count {
color: var(--dim);
}
.tool-command {
font-weight: bold;
white-space: pre-wrap;
word-wrap: break-word;
overflow-wrap: break-word;
word-break: break-word;
}
.tool-output {
margin-top: var(--line-height);
color: var(--toolOutput);
word-wrap: break-word;
overflow-wrap: break-word;
word-break: break-word;
font-family: inherit;
overflow-x: auto;
}
.tool-output > div,
.output-preview > div,
.output-full > div {
margin: 0;
padding: 0;
line-height: var(--line-height);
}
.tool-output > div:not(.output-preview):not(.output-full),
.output-preview > div:not(.expand-hint),
.output-full > div:not(.expand-hint) {
white-space: pre-wrap;
}
.tool-output pre {
margin: 0;
padding: 0;
font-family: inherit;
color: inherit;
white-space: pre-wrap;
word-wrap: break-word;
overflow-wrap: break-word;
}
.tool-output code {
padding: 0;
background: none;
color: var(--text);
}
.tool-output.expandable {
cursor: pointer;
}
.tool-output.expandable:hover {
opacity: 0.9;
}
.tool-output.expandable .output-full {
display: none;
}
.tool-output.expandable.expanded .output-preview {
display: none;
}
.tool-output.expandable.expanded .output-full {
display: block;
}
.ansi-line {
white-space: pre;
}
.tool-images {
}
.tool-image {
max-width: 100%;
max-height: 500px;
border-radius: 4px;
margin: var(--line-height) 0;
}
.expand-hint {
color: var(--toolOutput);
}
/* Diff */
.tool-diff {
font-size: 11px;
overflow-x: auto;
white-space: pre;
}
.diff-added { color: var(--toolDiffAdded); }
.diff-removed { color: var(--toolDiffRemoved); }
.diff-context { color: var(--toolDiffContext); }
/* Model change */
.model-change {
padding: 0 var(--line-height);
color: var(--dim);
font-size: 11px;
}
.model-name {
color: var(--borderAccent);
font-weight: bold;
}
/* Compaction / Branch Summary - matches customMessage colors from TUI */
.compaction {
background: var(--customMessageBg);
border-radius: 4px;
padding: var(--line-height);
cursor: pointer;
}
.compaction-label {
color: var(--customMessageLabel);
font-weight: bold;
}
.compaction-collapsed {
color: var(--customMessageText);
}
.compaction-content {
display: none;
color: var(--customMessageText);
white-space: pre-wrap;
margin-top: var(--line-height);
}
.compaction.expanded .compaction-collapsed {
display: none;
}
.compaction.expanded .compaction-content {
display: block;
}
/* System prompt */
.system-prompt {
background: var(--customMessageBg);
padding: var(--line-height);
border-radius: 4px;
margin-bottom: var(--line-height);
}
.system-prompt.expandable {
cursor: pointer;
}
.system-prompt-header {
font-weight: bold;
color: var(--customMessageLabel);
}
.system-prompt-preview {
color: var(--customMessageText);
white-space: pre-wrap;
word-wrap: break-word;
font-size: 11px;
margin-top: var(--line-height);
}
.system-prompt-expand-hint {
color: var(--muted);
font-style: italic;
margin-top: 4px;
}
.system-prompt-full {
display: none;
color: var(--customMessageText);
white-space: pre-wrap;
word-wrap: break-word;
font-size: 11px;
margin-top: var(--line-height);
}
.system-prompt.expanded .system-prompt-preview,
.system-prompt.expanded .system-prompt-expand-hint {
display: none;
}
.system-prompt.expanded .system-prompt-full {
display: block;
}
.system-prompt.provider-prompt {
border-left: 3px solid var(--warning);
}
.system-prompt-note {
font-size: 10px;
font-style: italic;
color: var(--muted);
margin-top: 4px;
}
/* Tools list */
.tools-list {
background: var(--customMessageBg);
padding: var(--line-height);
border-radius: 4px;
margin-bottom: var(--line-height);
}
.tools-header {
font-weight: bold;
color: var(--customMessageLabel);
margin-bottom: var(--line-height);
}
.tool-item {
font-size: 11px;
}
.tool-item-name {
font-weight: bold;
color: var(--text);
}
.tool-item-desc {
color: var(--dim);
}
.tool-params-hint {
color: var(--muted);
font-style: italic;
}
.tool-item:has(.tool-params-hint) {
cursor: pointer;
}
.tool-params-hint::after {
content: '[click to show parameters]';
}
.tool-item.params-expanded .tool-params-hint::after {
content: '[hide parameters]';
}
.tool-params-content {
display: none;
margin-top: 4px;
margin-left: 12px;
padding-left: 8px;
border-left: 1px solid var(--dim);
}
.tool-item.params-expanded .tool-params-content {
display: block;
}
.tool-param {
margin-bottom: 4px;
font-size: 11px;
}
.tool-param-name {
font-weight: bold;
color: var(--text);
}
.tool-param-type {
color: var(--dim);
font-style: italic;
}
.tool-param-required {
color: var(--warning, #e8a838);
font-size: 10px;
}
.tool-param-optional {
color: var(--dim);
font-size: 10px;
}
.tool-param-desc {
color: var(--dim);
margin-left: 8px;
}
/* Hook/custom messages */
.hook-message {
background: var(--customMessageBg);
color: var(--customMessageText);
padding: var(--line-height);
border-radius: 4px;
}
.hook-type {
color: var(--customMessageLabel);
font-weight: bold;
}
/* Skill invocation - matches compaction style (clickable, collapsed by default) */
.skill-invocation {
background: var(--customMessageBg);
border-radius: 4px;
padding: var(--line-height);
cursor: pointer;
}
.skill-invocation-label {
color: var(--customMessageLabel);
font-weight: bold;
}
.skill-invocation-collapsed {
color: var(--customMessageText);
}
.skill-invocation-content {
display: none;
color: var(--customMessageText);
margin-top: var(--line-height);
}
.skill-invocation.expanded .skill-invocation-collapsed {
display: none;
}
.skill-invocation.expanded .skill-invocation-content {
display: block;
}
.skill-invocation + .user-message {
margin-top: var(--line-height);
}
.skill-user-entry {
position: relative;
}
/* Branch summary */
.branch-summary {
background: var(--customMessageBg);
padding: var(--line-height);
border-radius: 4px;
}
.branch-summary-header {
font-weight: bold;
color: var(--borderAccent);
}
/* Error */
.error-text {
color: var(--error);
padding: 0 var(--line-height);
}
.tool-error {
color: var(--error);
}
/* Images */
.message-images {
margin-bottom: 12px;
}
.message-image {
max-width: 100%;
max-height: 400px;
border-radius: 4px;
margin: var(--line-height) 0;
}
/* Markdown content */
.markdown-content h1,
.markdown-content h2,
.markdown-content h3,
.markdown-content h4,
.markdown-content h5,
.markdown-content h6 {
color: var(--mdHeading);
margin: var(--line-height) 0 0 0;
font-weight: bold;
}
.markdown-content h1 { font-size: 1em; }
.markdown-content h2 { font-size: 1em; }
.markdown-content h3 { font-size: 1em; }
.markdown-content h4 { font-size: 1em; }
.markdown-content h5 { font-size: 1em; }
.markdown-content h6 { font-size: 1em; }
.markdown-content p { margin: 0; }
.markdown-content p + p { margin-top: var(--line-height); }
.markdown-content a {
color: var(--mdLink);
text-decoration: underline;
}
.markdown-content code {
background: rgba(128, 128, 128, 0.2);
color: var(--mdCode);
padding: 0 4px;
border-radius: 3px;
font-family: inherit;
}
.markdown-content pre {
background: transparent;
margin: var(--line-height) 0;
overflow-x: auto;
}
.markdown-content pre code {
display: block;
background: none;
color: var(--text);
}
.markdown-content blockquote {
border-left: 3px solid var(--mdQuoteBorder);
padding-left: var(--line-height);
margin: var(--line-height) 0;
color: var(--mdQuote);
font-style: italic;
}
.markdown-content ul,
.markdown-content ol {
margin: var(--line-height) 0;
padding-left: calc(var(--line-height) * 2);
}
.markdown-content li { margin: 0; }
.markdown-content li::marker { color: var(--mdListBullet); }
.markdown-content hr {
border: none;
border-top: 1px solid var(--mdHr);
margin: var(--line-height) 0;
}
.markdown-content table {
border-collapse: collapse;
margin: 0.5em 0;
width: 100%;
}
.markdown-content th,
.markdown-content td {
border: 1px solid var(--mdCodeBlockBorder);
padding: 6px 10px;
text-align: left;
}
.markdown-content th {
background: rgba(128, 128, 128, 0.1);
font-weight: bold;
}
.markdown-content img {
max-width: 100%;
border-radius: 4px;
}
/* Syntax highlighting */
.hljs { background: transparent; color: var(--text); }
.hljs-comment, .hljs-quote { color: var(--syntaxComment); }
.hljs-keyword, .hljs-selector-tag { color: var(--syntaxKeyword); }
.hljs-number, .hljs-literal { color: var(--syntaxNumber); }
.hljs-string, .hljs-doctag { color: var(--syntaxString); }
/* Function names: hljs v11 uses .hljs-title.function_ compound class */
.hljs-function, .hljs-title, .hljs-title.function_, .hljs-section, .hljs-name { color: var(--syntaxFunction); }
/* Types: hljs v11 uses .hljs-title.class_ for class names */
.hljs-type, .hljs-class, .hljs-title.class_, .hljs-built_in { color: var(--syntaxType); }
.hljs-attr, .hljs-variable, .hljs-variable.language_, .hljs-params, .hljs-property { color: var(--syntaxVariable); }
.hljs-meta, .hljs-meta .hljs-keyword, .hljs-meta .hljs-string { color: var(--syntaxKeyword); }
.hljs-operator { color: var(--syntaxOperator); }
.hljs-punctuation { color: var(--syntaxPunctuation); }
.hljs-subst { color: var(--text); }
/* Footer */
.footer {
margin-top: 48px;
padding: 20px;
text-align: center;
color: var(--dim);
font-size: 10px;
}
/* Mobile */
#hamburger {
display: none;
position: fixed;
top: 10px;
left: 10px;
z-index: 100;
padding: 3px 8px;
font-size: 12px;
font-family: inherit;
background: transparent;
color: var(--muted);
border: 1px solid var(--dim);
border-radius: 3px;
cursor: pointer;
}
#hamburger:hover {
color: var(--text);
border-color: var(--text);
}
#sidebar-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 98;
}
@media (max-width: 900px) {
#sidebar {
position: fixed;
left: 0;
width: min(var(--sidebar-width), 100vw);
min-width: min(var(--sidebar-width), 100vw);
max-width: min(var(--sidebar-width), 100vw);
top: 0;
bottom: 0;
height: 100vh;
z-index: 99;
transform: translateX(-100%);
transition: transform 0.3s;
}
#sidebar.open {
transform: translateX(0);
}
#sidebar-resizer {
display: none;
}
#sidebar-overlay.open {
display: block;
}
#hamburger {
display: block;
}
.sidebar-close {
display: block;
}
#content {
padding: var(--line-height) 16px;
}
#content > * {
max-width: 100%;
}
}
@media print {
#sidebar, #sidebar-resizer, #sidebar-toggle { display: none !important; }
body { background: white; color: black; }
#content { max-width: none; }
}
</style>
</head>
<body>
<button id="hamburger" title="Open sidebar"><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" stroke="none"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="12" r="2.5"/><rect x="5" y="6" width="2" height="12"/><path d="M6 12h10c1 0 2 0 2-2V8"/></svg></button>
<div id="sidebar-overlay"></div>
<div id="app">
<aside id="sidebar">
<div class="sidebar-header">
<div class="sidebar-controls">
<input type="text" class="sidebar-search" id="tree-search" placeholder="Search...">
</div>
<div class="sidebar-filters">
<button class="filter-btn active" data-filter="default" title="Hide settings entries">Default</button>
<button class="filter-btn" data-filter="no-tools" title="Default minus tool results">No-tools</button>
<button class="filter-btn" data-filter="user-only" title="Only user messages">User</button>
<button class="filter-btn" data-filter="labeled-only" title="Only labeled entries">Labeled</button>
<button class="filter-btn" data-filter="all" title="Show everything">All</button>
<button class="sidebar-close" id="sidebar-close" title="Close"></button>
</div>
</div>
<div class="tree-container" id="tree-container"></div>
<div class="tree-status" id="tree-status"></div>
</aside>
<div id="sidebar-resizer" role="separator" aria-orientation="vertical" aria-label="Resize session tree sidebar"></div>
<main id="content">
<div id="header-container"></div>
<div id="messages"></div>
</main>
<div id="image-modal" class="image-modal">
<img id="modal-image" src="" alt="">
</div>
</div>
<script id="session-data" type="application/json">eyJoZWFkZXIiOnsidHlwZSI6InNlc3Npb24iLCJ2ZXJzaW9uIjozLCJpZCI6IjAxOWVlNGFlLTYzNjQtNzA3MS1iNDliLThiNzY3MWYwZGYzZSIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTA6NTg6MTQuNTAwWiIsImN3ZCI6Ii9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrIn0sImVudHJpZXMiOlt7InR5cGUiOiJtb2RlbF9jaGFuZ2UiLCJpZCI6ImU3MjMzOThmIiwicGFyZW50SWQiOm51bGwsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTA6NTg6MTQuNTMzWiIsInByb3ZpZGVyIjoib3BlbnJvdXRlciIsIm1vZGVsSWQiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaCJ9LHsidHlwZSI6InRoaW5raW5nX2xldmVsX2NoYW5nZSIsImlkIjoiMzUyNzBlMjciLCJwYXJlbnRJZCI6ImU3MjMzOThmIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMDo1ODoxNC41MzNaIiwidGhpbmtpbmdMZXZlbCI6ImhpZ2gifSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiIxYjlmN2Y0MiIsInBhcmVudElkIjoiMzUyNzBlMjciLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjAzOjAyLjI5MloiLCJtZXNzYWdlIjp7InJvbGUiOiJ1c2VyIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0Ijoid3JpdGUgaGFpa3UifV0sInRpbWVzdGFtcCI6MTc4MTk1MzM4MjI4N319LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6IjViMzkyODIwIiwicGFyZW50SWQiOiIxYjlmN2Y0MiIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MDM6MDUuNTYzWiIsIm1lc3NhZ2UiOnsicm9sZSI6ImFzc2lzdGFudCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0aGlua2luZyIsInRoaW5raW5nIjoiVGhlIHVzZXIgd2FudHMgbWUgdG8gd3JpdGUgYSBoYWlrdS4gTGV0IG1lIHRoaW5rIG9mIGEgZ29vZCBvbmUuXG5cbkEgaGFpa3UgaXMgYSB0cmFkaXRpb25hbCBKYXBhbmVzZSBwb2VtIHdpdGggdGhyZWUgbGluZXMgLSA1IHN5bGxhYmxlcywgNyBzeWxsYWJsZXMsIDUgc3lsbGFibGVzLiIsInRoaW5raW5nU2lnbmF0dXJlIjoicmVhc29uaW5nIn0seyJ0eXBlIjoidGV4dCIsInRleHQiOiJJbiB0aGUgcXVpZXQgd29ybGQsXG5lcnJvcnMgYmxvb20gbGlrZSBjaGVycnkgdHJlZXMg4oCUXG50ZXN0cyB0dXJuIGludG8gZ3JlZW4uIn1dLCJhcGkiOiJvcGVuYWktY29tcGxldGlvbnMiLCJwcm92aWRlciI6Im9wZW5yb3V0ZXIiLCJtb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoIiwidXNhZ2UiOnsiaW5wdXQiOjEwMzgsIm91dHB1dCI6NjAsImNhY2hlUmVhZCI6NTEyLCJjYWNoZVdyaXRlIjowLCJ0b3RhbFRva2VucyI6MTYxMCwiY29zdCI6eyJpbnB1dCI6MC4wMDAwOTM0Miwib3V0cHV0IjowLjAwMDAxMDgsImNhY2hlUmVhZCI6MC4wMDAwMTAyNCwiY2FjaGVXcml0ZSI6MCwidG90YWwiOjAuMDAwMTE0NDZ9fSwic3RvcFJlYXNvbiI6InN0b3AiLCJ0aW1lc3RhbXAiOjE3ODE5NTMzODIzMzgsInJlc3BvbnNlSWQiOiJnZW4tMTc4MTk1MzM4Mi0wODlKZm1MUU9tWFJJbkJTRjg1ViIsInJlc3BvbnNlTW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaC0yMDI2MDQyMyJ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiJkYmQ4NzBjNCIsInBhcmVudElkIjoiNWIzOTI4MjAiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjA4OjQxLjI3N1oiLCJtZXNzYWdlIjp7InJvbGUiOiJ1c2VyIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiZGVzY3JpYmUgdGhpcyByZXBvc2l0b3J5In1dLCJ0aW1lc3RhbXAiOjE3ODE5NTM2OTE2MDF9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiJjMjdhNzRlOCIsInBhcmVudElkIjoiZGJkODcwYzQiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjA4OjQ1LjExNVoiLCJtZXNzYWdlIjp7InJvbGUiOiJhc3Npc3RhbnQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGhpbmtpbmciLCJ0aGlua2luZyI6IlRoZSB1c2VyIHdhbnRzIG1lIHRvIGRlc2NyaWJlIHRoaXMgcmVwb3NpdG9yeS4gTGV0IG1lIGxvb2sgYXJvdW5kIHRvIHVuZGVyc3RhbmQgd2hhdCBpdCBpcy4iLCJ0aGlua2luZ1NpZ25hdHVyZSI6InJlYXNvbmluZyJ9LHsidHlwZSI6InRvb2xDYWxsIiwiaWQiOiJjYWxsX2FhNWZjMWQyOThhMTQwNWZhMjRmMjJlOSIsIm5hbWUiOiJiYXNoIiwiYXJndW1lbnRzIjp7ImNvbW1hbmQiOiJmaW5kIC9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrIC10eXBlIGYgfCBoZWFkIC01MCJ9fV0sImFwaSI6Im9wZW5haS1jb21wbGV0aW9ucyIsInByb3ZpZGVyIjoib3BlbnJvdXRlciIsIm1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2giLCJ1c2FnZSI6eyJpbnB1dCI6MTU5MSwib3V0cHV0Ijo5MSwiY2FjaGVSZWFkIjowLCJjYWNoZVdyaXRlIjowLCJ0b3RhbFRva2VucyI6MTY4MiwiY29zdCI6eyJpbnB1dCI6MC4wMDAxNDMxOSwib3V0cHV0IjowLjAwMDAxNjM4LCJjYWNoZVJlYWQiOjAsImNhY2hlV3JpdGUiOjAsInRvdGFsIjowLjAwMDE1OTU3fX0sInN0b3BSZWFzb24iOiJ0b29sVXNlIiwidGltZXN0YW1wIjoxNzgxOTUzNzIxMjc5LCJyZXNwb25zZUlkIjoiZ2VuLTE3ODE5NTM3MjEtT3Y2QjRkNGRhMjg4azF4VHRRY28iLCJyZXNwb25zZU1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2gtMjAyNjA0MjMifX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiMWFhY2RmNjUiLCJwYXJlbnRJZCI6ImMyN2E3NGU4IiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMTowODo0NS4xNDJaIiwibWVzc2FnZSI6eyJyb2xlIjoidG9vbFJlc3VsdCIsInRvb2xDYWxsSWQiOiJjYWxsX2FhNWZjMWQyOThhMTQwNWZhMjRmMjJlOSIsInRvb2xOYW1lIjoiYmFzaCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6Ii9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrL21pc2UudG9tbFxuL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvLmdpdC9jb25maWdcbi9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrLy5naXQvSEVBRFxuL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvLmdpdC9pbmZvL2V4Y2x1ZGVcbi9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrLy5naXQvZGVzY3JpcHRpb25cbi9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrLy5naXQvaG9va3MvY29tbWl0LW1zZy5zYW1wbGVcbi9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrLy5naXQvaG9va3MvcHJlLXJlYmFzZS5zYW1wbGVcbi9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrLy5naXQvaG9va3Mvc2VuZGVtYWlsLXZhbGlkYXRlLnNhbXBsZVxuL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvLmdpdC9ob29rcy9wcmUtY29tbWl0LnNhbXBsZVxuL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvLmdpdC9ob29rcy9hcHBseXBhdGNoLW1zZy5zYW1wbGVcbi9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrLy5naXQvaG9va3MvZnNtb25pdG9yLXdhdGNobWFuLnNhbXBsZVxuL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvLmdpdC9ob29rcy9wcmUtcmVjZWl2ZS5zYW1wbGVcbi9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrLy5naXQvaG9va3MvcHJlcGFyZS1jb21taXQtbXNnLnNhbXBsZVxuL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvLmdpdC9ob29rcy9wb3N0LXVwZGF0ZS5zYW1wbGVcbi9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrLy5naXQvaG9va3MvcHJlLW1lcmdlLWNvbW1pdC5zYW1wbGVcbi9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrLy5naXQvaG9va3MvcHJlLWFwcGx5cGF0Y2guc2FtcGxlXG4vVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ay8uZ2l0L2hvb2tzL3ByZS1wdXNoLnNhbXBsZVxuL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvLmdpdC9ob29rcy91cGRhdGUuc2FtcGxlXG4vVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ay8uZ2l0L2hvb2tzL3B1c2gtdG8tY2hlY2tvdXQuc2FtcGxlXG4vVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ay8ucGkvbGxtLW1ldHJpY3MubG9nXG4vVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ay8uaWRlYS92Y3MueG1sXG4vVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ay8uaWRlYS8uZ2l0aWdub3JlXG4vVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ay8uaWRlYS93b3Jrc3BhY2UueG1sXG4vVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ay8uaWRlYS9tb2R1bGVzLnhtbFxuL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvLmlkZWEvcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrLmltbFxuIn1dLCJpc0Vycm9yIjpmYWxzZSwidGltZXN0YW1wIjoxNzgxOTUzNzI1MTQyfX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiMzFlMjU3YjQiLCJwYXJlbnRJZCI6IjFhYWNkZjY1IiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMTowODo0OS4wMTdaIiwibWVzc2FnZSI6eyJyb2xlIjoiYXNzaXN0YW50IiwiY29udGVudCI6W3sidHlwZSI6InRoaW5raW5nIiwidGhpbmtpbmciOiJUaGUgcmVwb3NpdG9yeSBzZWVtcyBmYWlybHkgbWluaW1hbC4gTGV0IG1lIGNoZWNrIGlmIHRoZXJlIGFyZSBhbnkgbm9uLWdpdCwgbm9uLWlkZWEgZmlsZXMgdGhhdCBnaXZlIG1vcmUgaW5mb3JtYXRpb24uIiwidGhpbmtpbmdTaWduYXR1cmUiOiJyZWFzb25pbmcifSx7InR5cGUiOiJ0b29sQ2FsbCIsImlkIjoiY2FsbF8yZTcwZmMwZWNjOTM0MTY0YmNhZDFmMzAiLCJuYW1lIjoicmVhZCIsImFyZ3VtZW50cyI6eyJwYXRoIjoiL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvbWlzZS50b21sIn19LHsidHlwZSI6InRvb2xDYWxsIiwiaWQiOiJjYWxsX2I0MTBhNzlhYWZmMjQ4OGRiZjA3YjcwYyIsIm5hbWUiOiJiYXNoIiwiYXJndW1lbnRzIjp7ImNvbW1hbmQiOiJjZCAvVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ayAmJiBnaXQgbG9nIC0tb25lbGluZSAtMTAifX0seyJ0eXBlIjoidG9vbENhbGwiLCJpZCI6ImNhbGxfNzliOTJjYjM0ODQ5NGM5MGEyOTk3M2I1IiwibmFtZSI6ImJhc2giLCJhcmd1bWVudHMiOnsiY29tbWFuZCI6ImNkIC9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrICYmIGdpdCByZW1vdGUgLXYifX1dLCJhcGkiOiJvcGVuYWktY29tcGxldGlvbnMiLCJwcm92aWRlciI6Im9wZW5yb3V0ZXIiLCJtb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoIiwidXNhZ2UiOnsiaW5wdXQiOjkxMywib3V0cHV0IjoyMDgsImNhY2hlUmVhZCI6MTUzNiwiY2FjaGVXcml0ZSI6MCwidG90YWxUb2tlbnMiOjI2NTcsImNvc3QiOnsiaW5wdXQiOjAuMDAwMDgyMTcsIm91dHB1dCI6MC4wMDAwMzc0NCwiY2FjaGVSZWFkIjowLjAwMDAzMDcyMDAwMDAwMDAwMDAwNCwiY2FjaGVXcml0ZSI6MCwidG90YWwiOjAuMDAwMTUwMzN9fSwic3RvcFJlYXNvbiI6InRvb2xVc2UiLCJ0aW1lc3RhbXAiOjE3ODE5NTM3MjUxNDMsInJlc3BvbnNlSWQiOiJnZW4tMTc4MTk1MzcyNS1xM3FhMUxIREZFVlRYRmpEMlE3VCIsInJlc3BvbnNlTW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaC0yMDI2MDQyMyJ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiIwN2E5YmZkZCIsInBhcmVudElkIjoiMzFlMjU3YjQiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjA4OjQ5LjA1MVoiLCJtZXNzYWdlIjp7InJvbGUiOiJ0b29sUmVzdWx0IiwidG9vbENhbGxJZCI6ImNhbGxfMmU3MGZjMGVjYzkzNDE2NGJjYWQxZjMwIiwidG9vbE5hbWUiOiJyZWFkIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiW3Rvb2xzXVxubm9kZSA9IFwiMjRcIlxuIn1dLCJpc0Vycm9yIjpmYWxzZSwidGltZXN0YW1wIjoxNzgxOTUzNzI5MDUxfX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiNjRiNzUxZmUiLCJwYXJlbnRJZCI6IjA3YTliZmRkIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMTowODo0OS4wNTFaIiwibWVzc2FnZSI6eyJyb2xlIjoidG9vbFJlc3VsdCIsInRvb2xDYWxsSWQiOiJjYWxsX2I0MTBhNzlhYWZmMjQ4OGRiZjA3YjcwYyIsInRvb2xOYW1lIjoiYmFzaCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImZhdGFsOiB5b3VyIGN1cnJlbnQgYnJhbmNoICdtYWluJyBkb2VzIG5vdCBoYXZlIGFueSBjb21taXRzIHlldFxuXG5cbkNvbW1hbmQgZXhpdGVkIHdpdGggY29kZSAxMjgifV0sImRldGFpbHMiOnt9LCJpc0Vycm9yIjp0cnVlLCJ0aW1lc3RhbXAiOjE3ODE5NTM3MjkwNTF9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiI4N2ZiNDFjMiIsInBhcmVudElkIjoiNjRiNzUxZmUiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjA4OjQ5LjA1MVoiLCJtZXNzYWdlIjp7InJvbGUiOiJ0b29sUmVzdWx0IiwidG9vbENhbGxJZCI6ImNhbGxfNzliOTJjYjM0ODQ5NGM5MGEyOTk3M2I1IiwidG9vbE5hbWUiOiJiYXNoIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiKG5vIG91dHB1dCkifV0sImlzRXJyb3IiOmZhbHNlLCJ0aW1lc3RhbXAiOjE3ODE5NTM3MjkwNTF9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiIwZmJjYmRhNiIsInBhcmVudElkIjoiODdmYjQxYzIiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjA4OjUzLjUyN1oiLCJtZXNzYWdlIjp7InJvbGUiOiJhc3Npc3RhbnQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGhpbmtpbmciLCJ0aGlua2luZyI6IlRoaXMgaXMgYSB2ZXJ5IG1pbmltYWwgcmVwb3NpdG9yeSDigJQganVzdCBhbiBlbXB0eSBnaXQgcmVwbyB3aXRoIGEgYG1pc2UudG9tbGAgZmlsZSB0aGF0IHNwZWNpZmllcyBOb2RlLmpzIHZlcnNpb24gMjQuIFRoZSBwYXRoIHN1Z2dlc3RzIGl0J3MgYSBzcGlrZSBwcm9qZWN0IHJlbGF0ZWQgdG8gTExNcyBhbmQgdGhlIHJlZC1ncmVlbi1yZWZhY3RvciBjeWNsZSwgd2l0aCBcInNvY3JhdGVzLXVrXCIgaW4gdGhlIG5hbWUsIHBvc3NpYmx5IHJlZmVyZW5jaW5nIHRoZSBTb2NyYXRlcyBVSyBwcm9ncmFtLiIsInRoaW5raW5nU2lnbmF0dXJlIjoicmVhc29uaW5nIn0seyJ0eXBlIjoidGV4dCIsInRleHQiOiJUaGlzIGlzIGEgKipiYXJlLWJvbmVzIHNwaWtlIHJlcG9zaXRvcnkqKiDigJQgYW4gZXhwZXJpbWVudGFsIHNhbmRib3guIEl0IGNvbnRhaW5zOlxuXG4tICoqYG1pc2UudG9tbGAqKiDigJQgYSBzaW5nbGUgY29uZmlnIGZpbGUgcGlubmluZyBOb2RlLmpzIHRvIHZlcnNpb24gYDI0YCAodmlhIGBtaXNlYCB2ZXJzaW9uIG1hbmFnZXIpXG4tICoqQW4gZW1wdHkgZ2l0IHJlcG9zaXRvcnkqKiDigJQgbm8gY29tbWl0cyB5ZXQsIG5vIHJlbW90ZSBjb25maWd1cmVkXG5cbkJhc2VkIG9uIHRoZSBkaXJlY3RvcnkgbmFtZSBgcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrYCwgdGhpcyBsb29rcyBsaWtlIGl0IHdhcyBzZXQgdXAgdG8gZXhwZXJpbWVudCB3aXRoIHRoZSAqKlJlZC1HcmVlbi1SZWZhY3RvciAoVEREKSBsb29wKiogaW4gdGhlIGNvbnRleHQgb2YgYW4gTExNIGNvZGluZyBhc3Npc3RhbnQsIHBvc3NpYmx5IGZvciB0aGUgKipTb2NyYXRlcyBVSyoqIHByb2dyYW0uIEl0J3MgZXNzZW50aWFsbHkgYSBibGFuayBjYW52YXMgd2FpdGluZyBmb3IgY29kZSB0byBiZSB3cml0dGVuLiJ9XSwiYXBpIjoib3BlbmFpLWNvbXBsZXRpb25zIiwicHJvdmlkZXIiOiJvcGVucm91dGVyIiwibW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaCIsInVzYWdlIjp7ImlucHV0Ijo0MTEsIm91dHB1dCI6MjExLCJjYWNoZVJlYWQiOjIzMDQsImNhY2hlV3JpdGUiOjAsInRvdGFsVG9rZW5zIjoyOTI2LCJjb3N0Ijp7ImlucHV0IjowLjAwMDAzNjk4OTk5OTk5OTk5OTk5Nywib3V0cHV0IjowLjAwMDAzNzk4LCJjYWNoZVJlYWQiOjAuMDAwMDQ2MDgsImNhY2hlV3JpdGUiOjAsInRvdGFsIjowLjAwMDEyMTA0OTk5OTk5OTk5OTk5fX0sInN0b3BSZWFzb24iOiJzdG9wIiwidGltZXN0YW1wIjoxNzgxOTUzNzI5MDUyLCJyZXNwb25zZUlkIjoiZ2VuLTE3ODE5NTM3MjktTzlIRkZpajhETHc3UWlzeWtJZEUiLCJyZXNwb25zZU1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2gtMjAyNjA0MjMifX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiMjc2MjliMWQiLCJwYXJlbnRJZCI6IjBmYmNiZGE2IiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToxMTo0OC41NDZaIiwibWVzc2FnZSI6eyJyb2xlIjoidXNlciIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6IndoYXQgaXMgdGhlIGVxdWl2YWxlbnQgb2YgYSBob29rIGluIFBpIn1dLCJ0aW1lc3RhbXAiOjE3ODE5NTM5MDg1NDZ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiI1NTNjOGU3MyIsInBhcmVudElkIjoiMjc2MjliMWQiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjExOjUxLjU4OVoiLCJtZXNzYWdlIjp7InJvbGUiOiJhc3Npc3RhbnQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGhpbmtpbmciLCJ0aGlua2luZyI6IlRoZSB1c2VyIGlzIGFza2luZyBhYm91dCBob29rcyBpbiBQaS4gTGV0IG1lIHJlYWQgdGhlIHJlbGV2YW50IGRvY3VtZW50YXRpb24gYWJvdXQgUGkncyBleHRlbnNpb24gc3lzdGVtIHRvIGZpbmQgb3V0IGFib3V0IGhvb2tzLiIsInRoaW5raW5nU2lnbmF0dXJlIjoicmVhc29uaW5nIn0seyJ0eXBlIjoidG9vbENhbGwiLCJpZCI6ImNhbGxfZmI1NTIxNjFlNzkzNDliMmE4OGNkOWZjIiwibmFtZSI6ImJhc2giLCJhcmd1bWVudHMiOnsiY29tbWFuZCI6ImxzIC9Vc2Vycy93aWxsZW0vLmxvY2FsL3NoYXJlL21pc2UvaW5zdGFsbHMvbm9kZS8yNC4wLjEvbGliL25vZGVfbW9kdWxlcy9AZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50L2RvY3MvIn19XSwiYXBpIjoib3BlbmFpLWNvbXBsZXRpb25zIiwicHJvdmlkZXIiOiJvcGVucm91dGVyIiwibW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaCIsInVzYWdlIjp7ImlucHV0IjoyOTIxLCJvdXRwdXQiOjEwNSwiY2FjaGVSZWFkIjowLCJjYWNoZVdyaXRlIjowLCJ0b3RhbFRva2VucyI6MzAyNiwiY29zdCI6eyJpbnB1dCI6MC4wMDAyNjI4OSwib3V0cHV0IjowLjAwMDAxODksImNhY2hlUmVhZCI6MCwiY2FjaGVXcml0ZSI6MCwidG90YWwiOjAuMDAwMjgxNzg5OTk5OTk5OTk5OTd9fSwic3RvcFJlYXNvbiI6InRvb2xVc2UiLCJ0aW1lc3RhbXAiOjE3ODE5NTM5MDg1NDgsInJlc3BvbnNlSWQiOiJnZW4tMTc4MTk1MzkwOC0xS2NiUkdLU3FFeTRVV3FPZ2V2ZCIsInJlc3BvbnNlTW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaC0yMDI2MDQyMyJ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiI4NTJmOTZhMSIsInBhcmVudElkIjoiNTUzYzhlNzMiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjExOjUxLjU5OVoiLCJtZXNzYWdlIjp7InJvbGUiOiJ0b29sUmVzdWx0IiwidG9vbENhbGxJZCI6ImNhbGxfZmI1NTIxNjFlNzkzNDliMmE4OGNkOWZjIiwidG9vbE5hbWUiOiJiYXNoIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiY29tcGFjdGlvbi5tZFxuY29udGFpbmVyaXphdGlvbi5tZFxuY3VzdG9tLXByb3ZpZGVyLm1kXG5kZXZlbG9wbWVudC5tZFxuZG9jcy5qc29uXG5leHRlbnNpb25zLm1kXG5pbWFnZXNcbmluZGV4Lm1kXG5qc29uLm1kXG5rZXliaW5kaW5ncy5tZFxubW9kZWxzLm1kXG5wYWNrYWdlcy5tZFxucHJvbXB0LXRlbXBsYXRlcy5tZFxucHJvdmlkZXJzLm1kXG5xdWlja3N0YXJ0Lm1kXG5ycGMubWRcbnNkay5tZFxuc2VjdXJpdHkubWRcbnNlc3Npb24tZm9ybWF0Lm1kXG5zZXNzaW9ucy5tZFxuc2V0dGluZ3MubWRcbnNoZWxsLWFsaWFzZXMubWRcbnNraWxscy5tZFxudGVybWluYWwtc2V0dXAubWRcbnRlcm11eC5tZFxudGhlbWVzLm1kXG50bXV4Lm1kXG50dWkubWRcbnVzYWdlLm1kXG53aW5kb3dzLm1kXG4ifV0sImlzRXJyb3IiOmZhbHNlLCJ0aW1lc3RhbXAiOjE3ODE5NTM5MTE1OTl9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiJlNDVmM2Y3OSIsInBhcmVudElkIjoiODUyZjk2YTEiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjEyOjAwLjI2MloiLCJtZXNzYWdlIjp7InJvbGUiOiJhc3Npc3RhbnQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGhpbmtpbmciLCJ0aGlua2luZyI6IkxldCBtZSByZWFkIHRoZSBleHRlbnNpb25zLm1kIHRvIGZpbmQgb3V0IGFib3V0IGhvb2tzLCBhbmQgYWxzbyB0aGUgc2tpbGxzLm1kIGFuZCBwcm9tcHQtdGVtcGxhdGVzLm1kIHNpbmNlIGhvb2tzIG1pZ2h0IHJlbGF0ZSB0byB0aG9zZS4iLCJ0aGlua2luZ1NpZ25hdHVyZSI6InJlYXNvbmluZyJ9LHsidHlwZSI6InRvb2xDYWxsIiwiaWQiOiJjYWxsXzAwX3dxeUR1WW5uaVNrR2Flc051YkFDOTkyNSIsIm5hbWUiOiJyZWFkIiwiYXJndW1lbnRzIjp7InBhdGgiOiIvVXNlcnMvd2lsbGVtLy5sb2NhbC9zaGFyZS9taXNlL2luc3RhbGxzL25vZGUvMjQuMC4xL2xpYi9ub2RlX21vZHVsZXMvQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudC9kb2NzL2V4dGVuc2lvbnMubWQifX0seyJ0eXBlIjoidG9vbENhbGwiLCJpZCI6ImNhbGxfMDFfSjVnVHVCa3VCcVpwdWZ6VTI1TkU4OTA0IiwibmFtZSI6InJlYWQiLCJhcmd1bWVudHMiOnsicGF0aCI6Ii9Vc2Vycy93aWxsZW0vLmxvY2FsL3NoYXJlL21pc2UvaW5zdGFsbHMvbm9kZS8yNC4wLjEvbGliL25vZGVfbW9kdWxlcy9AZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50L2RvY3Mvc2tpbGxzLm1kIn19LHsidHlwZSI6InRvb2xDYWxsIiwiaWQiOiJjYWxsXzAyX1hnS2xrdnlFMU5TUWNmUklkN0hlNjI0NCIsIm5hbWUiOiJyZWFkIiwiYXJndW1lbnRzIjp7InBhdGgiOiIvVXNlcnMvd2lsbGVtLy5sb2NhbC9zaGFyZS9taXNlL2luc3RhbGxzL25vZGUvMjQuMC4xL2xpYi9ub2RlX21vZHVsZXMvQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudC9kb2NzL3Byb21wdC10ZW1wbGF0ZXMubWQifX1dLCJhcGkiOiJvcGVuYWktY29tcGxldGlvbnMiLCJwcm92aWRlciI6Im9wZW5yb3V0ZXIiLCJtb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoIiwidXNhZ2UiOnsiaW5wdXQiOjE2MTYsIm91dHB1dCI6MjQxLCJjYWNoZVJlYWQiOjE1MzYsImNhY2hlV3JpdGUiOjAsInRvdGFsVG9rZW5zIjozMzkzLCJjb3N0Ijp7ImlucHV0IjowLjAwMDE0NTQ0LCJvdXRwdXQiOjAuMDAwMDQzMzgsImNhY2hlUmVhZCI6MC4wMDAwMzA3MjAwMDAwMDAwMDAwMDQsImNhY2hlV3JpdGUiOjAsInRvdGFsIjowLjAwMDIxOTU0fX0sInN0b3BSZWFzb24iOiJ0b29sVXNlIiwidGltZXN0YW1wIjoxNzgxOTUzOTExNjAwLCJyZXNwb25zZUlkIjoiZ2VuLTE3ODE5NTM5MTEtcmRxMFQwSUY0a1VKYWJnRlNIa0kiLCJyZXNwb25zZU1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2gtMjAyNjA0MjMifX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiMWViZWM4ZmEiLCJwYXJlbnRJZCI6ImU0NWYzZjc5IiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToxMjowMC4yNzFaIiwibWVzc2FnZSI6eyJyb2xlIjoidG9vbFJlc3VsdCIsInRvb2xDYWxsSWQiOiJjYWxsXzAwX3dxeUR1WW5uaVNrR2Flc051YkFDOTkyNSIsInRvb2xOYW1lIjoicmVhZCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6Ij4gcGkgY2FuIGNyZWF0ZSBleHRlbnNpb25zLiBBc2sgaXQgdG8gYnVpbGQgb25lIGZvciB5b3VyIHVzZSBjYXNlLlxuXG4jIEV4dGVuc2lvbnNcblxuRXh0ZW5zaW9ucyBhcmUgVHlwZVNjcmlwdCBtb2R1bGVzIHRoYXQgZXh0ZW5kIHBpJ3MgYmVoYXZpb3IuIFRoZXkgY2FuIHN1YnNjcmliZSB0byBsaWZlY3ljbGUgZXZlbnRzLCByZWdpc3RlciBjdXN0b20gdG9vbHMgY2FsbGFibGUgYnkgdGhlIExMTSwgYWRkIGNvbW1hbmRzLCBhbmQgbW9yZS5cblxuPiAqKlBsYWNlbWVudCBmb3IgL3JlbG9hZDoqKiBQdXQgZXh0ZW5zaW9ucyBpbiBgfi8ucGkvYWdlbnQvZXh0ZW5zaW9ucy9gIChnbG9iYWwpIG9yIGAucGkvZXh0ZW5zaW9ucy9gIChwcm9qZWN0LWxvY2FsKSBmb3IgYXV0by1kaXNjb3ZlcnkuIFVzZSBgcGkgLWUgLi9wYXRoLnRzYCBvbmx5IGZvciBxdWljayB0ZXN0cy4gRXh0ZW5zaW9ucyBpbiBhdXRvLWRpc2NvdmVyZWQgbG9jYXRpb25zIGNhbiBiZSBob3QtcmVsb2FkZWQgd2l0aCBgL3JlbG9hZGAuXG5cbioqS2V5IGNhcGFiaWxpdGllczoqKlxuLSAqKkN1c3RvbSB0b29scyoqIC0gUmVnaXN0ZXIgdG9vbHMgdGhlIExMTSBjYW4gY2FsbCB2aWEgYHBpLnJlZ2lzdGVyVG9vbCgpYFxuLSAqKkV2ZW50IGludGVyY2VwdGlvbioqIC0gQmxvY2sgb3IgbW9kaWZ5IHRvb2wgY2FsbHMsIGluamVjdCBjb250ZXh0LCBjdXN0b21pemUgY29tcGFjdGlvblxuLSAqKlVzZXIgaW50ZXJhY3Rpb24qKiAtIFByb21wdCB1c2VycyB2aWEgYGN0eC51aWAgKHNlbGVjdCwgY29uZmlybSwgaW5wdXQsIG5vdGlmeSlcbi0gKipDdXN0b20gVUkgY29tcG9uZW50cyoqIC0gRnVsbCBUVUkgY29tcG9uZW50cyB3aXRoIGtleWJvYXJkIGlucHV0IHZpYSBgY3R4LnVpLmN1c3RvbSgpYCBmb3IgY29tcGxleCBpbnRlcmFjdGlvbnNcbi0gKipDdXN0b20gY29tbWFuZHMqKiAtIFJlZ2lzdGVyIGNvbW1hbmRzIGxpa2UgYC9teWNvbW1hbmRgIHZpYSBgcGkucmVnaXN0ZXJDb21tYW5kKClgXG4tICoqU2Vzc2lvbiBwZXJzaXN0ZW5jZSoqIC0gU3RvcmUgc3RhdGUgdGhhdCBzdXJ2aXZlcyByZXN0YXJ0cyB2aWEgYHBpLmFwcGVuZEVudHJ5KClgXG4tICoqQ3VzdG9tIHJlbmRlcmluZyoqIC0gQ29udHJvbCBob3cgdG9vbCBjYWxscy9yZXN1bHRzIGFuZCBtZXNzYWdlcyBhcHBlYXIgaW4gVFVJXG5cbioqRXhhbXBsZSB1c2UgY2FzZXM6Kipcbi0gUGVybWlzc2lvbiBnYXRlcyAoY29uZmlybSBiZWZvcmUgYHJtIC1yZmAsIGBzdWRvYCwgZXRjLilcbi0gR2l0IGNoZWNrcG9pbnRpbmcgKHN0YXNoIGF0IGVhY2ggdHVybiwgcmVzdG9yZSBvbiBicmFuY2gpXG4tIFBhdGggcHJvdGVjdGlvbiAoYmxvY2sgd3JpdGVzIHRvIGAuZW52YCwgYG5vZGVfbW9kdWxlcy9gKVxuLSBDdXN0b20gY29tcGFjdGlvbiAoc3VtbWFyaXplIGNvbnZlcnNhdGlvbiB5b3VyIHdheSlcbi0gQ29udmVyc2F0aW9uIHN1bW1hcmllcyAoc2VlIGBzdW1tYXJpemUudHNgIGV4YW1wbGUpXG4tIEludGVyYWN0aXZlIHRvb2xzIChxdWVzdGlvbnMsIHdpemFyZHMsIGN1c3RvbSBkaWFsb2dzKVxuLSBTdGF0ZWZ1bCB0b29scyAodG9kbyBsaXN0cywgY29ubmVjdGlvbiBwb29scylcbi0gRXh0ZXJuYWwgaW50ZWdyYXRpb25zIChmaWxlIHdhdGNoZXJzLCB3ZWJob29rcywgQ0kgdHJpZ2dlcnMpXG4tIEdhbWVzIHdoaWxlIHlvdSB3YWl0IChzZWUgYHNuYWtlLnRzYCBleGFtcGxlKVxuXG5TZWUgW2V4YW1wbGVzL2V4dGVuc2lvbnMvXSguLi9leGFtcGxlcy9leHRlbnNpb25zLykgZm9yIHdvcmtpbmcgaW1wbGVtZW50YXRpb25zLlxuXG4jIyBUYWJsZSBvZiBDb250ZW50c1xuXG4tIFtRdWljayBTdGFydF0oI3F1aWNrLXN0YXJ0KVxuLSBbRXh0ZW5zaW9uIExvY2F0aW9uc10oI2V4dGVuc2lvbi1sb2NhdGlvbnMpXG4tIFtBdmFpbGFibGUgSW1wb3J0c10oI2F2YWlsYWJsZS1pbXBvcnRzKVxuLSBbV3JpdGluZyBhbiBFeHRlbnNpb25dKCN3cml0aW5nLWFuLWV4dGVuc2lvbilcbiAgLSBbRXh0ZW5zaW9uIFN0eWxlc10oI2V4dGVuc2lvbi1zdHlsZXMpXG4tIFtFdmVudHNdKCNldmVudHMpXG4gIC0gW0xpZmVjeWNsZSBPdmVydmlld10oI2xpZmVjeWNsZS1vdmVydmlldylcbiAgLSBbUmVzb3VyY2UgRXZlbnRzXSgjcmVzb3VyY2UtZXZlbnRzKVxuICAtIFtTZXNzaW9uIEV2ZW50c10oI3Nlc3Npb24tZXZlbnRzKVxuICAtIFtBZ2VudCBFdmVudHNdKCNhZ2VudC1ldmVudHMpXG4gIC0gW01vZGVsIEV2ZW50c10oI21vZGVsLWV2ZW50cylcbiAgLSBbVG9vbCBFdmVudHNdKCN0b29sLWV2ZW50cylcbi0gW0V4dGVuc2lvbkNvbnRleHRdKCNleHRlbnNpb25jb250ZXh0KVxuLSBbRXh0ZW5zaW9uQ29tbWFuZENvbnRleHRdKCNleHRlbnNpb25jb21tYW5kY29udGV4dClcbi0gW0V4dGVuc2lvbkFQSSBNZXRob2RzXSgjZXh0ZW5zaW9uYXBpLW1ldGhvZHMpXG4tIFtTdGF0ZSBNYW5hZ2VtZW50XSgjc3RhdGUtbWFuYWdlbWVudClcbi0gW0N1c3RvbSBUb29sc10oI2N1c3RvbS10b29scylcbi0gW0N1c3RvbSBVSV0oI2N1c3RvbS11aSlcbi0gW0Vycm9yIEhhbmRsaW5nXSgjZXJyb3ItaGFuZGxpbmcpXG4tIFtNb2RlIEJlaGF2aW9yXSgjbW9kZS1iZWhhdmlvcilcbi0gW0V4YW1wbGVzIFJlZmVyZW5jZV0oI2V4YW1wbGVzLXJlZmVyZW5jZSlcblxuIyMgUXVpY2sgU3RhcnRcblxuQ3JlYXRlIGB+Ly5waS9hZ2VudC9leHRlbnNpb25zL215LWV4dGVuc2lvbi50c2A6XG5cbmBgYHR5cGVzY3JpcHRcbmltcG9ydCB0eXBlIHsgRXh0ZW5zaW9uQVBJIH0gZnJvbSBcIkBlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnRcIjtcbmltcG9ydCB7IFR5cGUgfSBmcm9tIFwidHlwZWJveFwiO1xuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiAocGk6IEV4dGVuc2lvbkFQSSkge1xuICAvLyBSZWFjdCB0byBldmVudHNcbiAgcGkub24oXCJzZXNzaW9uX3N0YXJ0XCIsIGFzeW5jIChfZXZlbnQsIGN0eCkgPT4ge1xuICAgIGN0eC51aS5ub3RpZnkoXCJFeHRlbnNpb24gbG9hZGVkIVwiLCBcImluZm9cIik7XG4gIH0pO1xuXG4gIHBpLm9uKFwidG9vbF9jYWxsXCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gICAgaWYgKGV2ZW50LnRvb2xOYW1lID09PSBcImJhc2hcIiAmJiBldmVudC5pbnB1dC5jb21tYW5kPy5pbmNsdWRlcyhcInJtIC1yZlwiKSkge1xuICAgICAgY29uc3Qgb2sgPSBhd2FpdCBjdHgudWkuY29uZmlybShcIkRhbmdlcm91cyFcIiwgXCJBbGxvdyBybSAtcmY/XCIpO1xuICAgICAgaWYgKCFvaykgcmV0dXJuIHsgYmxvY2s6IHRydWUsIHJlYXNvbjogXCJCbG9ja2VkIGJ5IHVzZXJcIiB9O1xuICAgIH1cbiAgfSk7XG5cbiAgLy8gUmVnaXN0ZXIgYSBjdXN0b20gdG9vbFxuICBwaS5yZWdpc3RlclRvb2woe1xuICAgIG5hbWU6IFwiZ3JlZXRcIixcbiAgICBsYWJlbDogXCJHcmVldFwiLFxuICAgIGRlc2NyaXB0aW9uOiBcIkdyZWV0IHNvbWVvbmUgYnkgbmFtZVwiLFxuICAgIHBhcmFtZXRlcnM6IFR5cGUuT2JqZWN0KHtcbiAgICAgIG5hbWU6IFR5cGUuU3RyaW5nKHsgZGVzY3JpcHRpb246IFwiTmFtZSB0byBncmVldFwiIH0pLFxuICAgIH0pLFxuICAgIGFzeW5jIGV4ZWN1dGUodG9vbENhbGxJZCwgcGFyYW1zLCBzaWduYWwsIG9uVXBkYXRlLCBjdHgpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGNvbnRlbnQ6IFt7IHR5cGU6IFwidGV4dFwiLCB0ZXh0OiBgSGVsbG8sICR7cGFyYW1zLm5hbWV9IWAgfV0sXG4gICAgICAgIGRldGFpbHM6IHt9LFxuICAgICAgfTtcbiAgICB9LFxuICB9KTtcblxuICAvLyBSZWdpc3RlciBhIGNvbW1hbmRcbiAgcGkucmVnaXN0ZXJDb21tYW5kKFwiaGVsbG9cIiwge1xuICAgIGRlc2NyaXB0aW9uOiBcIlNheSBoZWxsb1wiLFxuICAgIGhhbmRsZXI6IGFzeW5jIChhcmdzLCBjdHgpID0+IHtcbiAgICAgIGN0eC51aS5ub3RpZnkoYEhlbGxvICR7YXJncyB8fCBcIndvcmxkXCJ9IWAsIFwiaW5mb1wiKTtcbiAgICB9LFxuICB9KTtcbn1cbmBgYFxuXG5UZXN0IHdpdGggYC0tZXh0ZW5zaW9uYCAob3IgYC1lYCkgZmxhZzpcblxuYGBgYmFzaFxucGkgLWUgLi9teS1leHRlbnNpb24udHNcbmBgYFxuXG4jIyBFeHRlbnNpb24gTG9jYXRpb25zXG5cbj4gKipTZWN1cml0eToqKiBFeHRlbnNpb25zIHJ1biB3aXRoIHlvdXIgZnVsbCBzeXN0ZW0gcGVybWlzc2lvbnMgYW5kIGNhbiBleGVjdXRlIGFyYml0cmFyeSBjb2RlLiBPbmx5IGluc3RhbGwgZnJvbSBzb3VyY2VzIHlvdSB0cnVzdC5cblxuRXh0ZW5zaW9ucyBhcmUgYXV0by1kaXNjb3ZlcmVkIGZyb20gdHJ1c3RlZCBsb2NhdGlvbnMuIFByb2plY3QtbG9jYWwgYC5waS9leHRlbnNpb25zYCBlbnRyaWVzIGxvYWQgb25seSBhZnRlciB0aGUgcHJvamVjdCBpcyB0cnVzdGVkLlxuXG58IExvY2F0aW9uIHwgU2NvcGUgfFxufC0tLS0tLS0tLS18LS0tLS0tLXxcbnwgYH4vLnBpL2FnZW50L2V4dGVuc2lvbnMvKi50c2AgfCBHbG9iYWwgKGFsbCBwcm9qZWN0cykgfFxufCBgfi8ucGkvYWdlbnQvZXh0ZW5zaW9ucy8qL2luZGV4LnRzYCB8IEdsb2JhbCAoc3ViZGlyZWN0b3J5KSB8XG58IGAucGkvZXh0ZW5zaW9ucy8qLnRzYCB8IFByb2plY3QtbG9jYWwgfFxufCBgLnBpL2V4dGVuc2lvbnMvKi9pbmRleC50c2AgfCBQcm9qZWN0LWxvY2FsIChzdWJkaXJlY3RvcnkpIHxcblxuQWRkaXRpb25hbCBwYXRocyB2aWEgYHNldHRpbmdzLmpzb25gOlxuXG5gYGBqc29uXG57XG4gIFwicGFja2FnZXNcIjogW1xuICAgIFwibnBtOkBmb28vYmFyQDEuMC4wXCIsXG4gICAgXCJnaXQ6Z2l0aHViLmNvbS91c2VyL3JlcG9AdjFcIlxuICBdLFxuICBcImV4dGVuc2lvbnNcIjogW1xuICAgIFwiL3BhdGgvdG8vbG9jYWwvZXh0ZW5zaW9uLnRzXCIsXG4gICAgXCIvcGF0aC90by9sb2NhbC9leHRlbnNpb24vZGlyXCJcbiAgXVxufVxuYGBgXG5cblRvIHNoYXJlIGV4dGVuc2lvbnMgdmlhIG5wbSBvciBnaXQgYXMgcGkgcGFja2FnZXMsIHNlZSBbcGFja2FnZXMubWRdKHBhY2thZ2VzLm1kKS5cblxuIyMgQXZhaWxhYmxlIEltcG9ydHNcblxufCBQYWNrYWdlIHwgUHVycG9zZSB8XG58LS0tLS0tLS0tfC0tLS0tLS0tLXxcbnwgYEBlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnRgIHwgRXh0ZW5zaW9uIHR5cGVzIChgRXh0ZW5zaW9uQVBJYCwgYEV4dGVuc2lvbkNvbnRleHRgLCBldmVudHMpIHxcbnwgYHR5cGVib3hgIHwgU2NoZW1hIGRlZmluaXRpb25zIGZvciB0b29sIHBhcmFtZXRlcnMgfFxufCBgQGVhcmVuZGlsLXdvcmtzL3BpLWFpYCB8IEFJIHV0aWxpdGllcyAoYFN0cmluZ0VudW1gIGZvciBHb29nbGUtY29tcGF0aWJsZSBlbnVtcykgfFxufCBgQGVhcmVuZGlsLXdvcmtzL3BpLXR1aWAgfCBUVUkgY29tcG9uZW50cyBmb3IgY3VzdG9tIHJlbmRlcmluZyB8XG5cbm5wbSBkZXBlbmRlbmNpZXMgd29yayB0b28uIEFkZCBhIGBwYWNrYWdlLmpzb25gIG5leHQgdG8geW91ciBleHRlbnNpb24gKG9yIGluIGEgcGFyZW50IGRpcmVjdG9yeSksIHJ1biBgbnBtIGluc3RhbGxgLCBhbmQgaW1wb3J0cyBmcm9tIGBub2RlX21vZHVsZXMvYCBhcmUgcmVzb2x2ZWQgYXV0b21hdGljYWxseS5cblxuRm9yIGRpc3RyaWJ1dGVkIHBpIHBhY2thZ2VzIGluc3RhbGxlZCB3aXRoIGBwaSBpbnN0YWxsYCAobnBtIG9yIGdpdCksIHJ1bnRpbWUgZGVwcyBtdXN0IGJlIGluIGBkZXBlbmRlbmNpZXNgLiBQYWNrYWdlIGluc3RhbGxhdGlvbiB1c2VzIHByb2R1Y3Rpb24gaW5zdGFsbHMgKGBucG0gaW5zdGFsbCAtLW9taXQ9ZGV2YCkgYnkgZGVmYXVsdCwgc28gYGRldkRlcGVuZGVuY2llc2AgYXJlIG5vdCBhdmFpbGFibGUgYXQgcnVudGltZTsgd2hlbiBgbnBtQ29tbWFuZGAgaXMgY29uZmlndXJlZCwgZ2l0IHBhY2thZ2VzIHVzZSBwbGFpbiBgaW5zdGFsbGAgZm9yIGNvbXBhdGliaWxpdHkgd2l0aCB3cmFwcGVycy5cblxuTm9kZS5qcyBidWlsdC1pbnMgKGBub2RlOmZzYCwgYG5vZGU6cGF0aGAsIGV0Yy4pIGFyZSBhbHNvIGF2YWlsYWJsZS5cblxuIyMgV3JpdGluZyBhbiBFeHRlbnNpb25cblxuQW4gZXh0ZW5zaW9uIGV4cG9ydHMgYSBkZWZhdWx0IGZhY3RvcnkgZnVuY3Rpb24gdGhhdCByZWNlaXZlcyBgRXh0ZW5zaW9uQVBJYC4gVGhlIGZhY3RvcnkgY2FuIGJlIHN5bmNocm9ub3VzIG9yIGFzeW5jaHJvbm91czpcblxuYGBgdHlwZXNjcmlwdFxuaW1wb3J0IHR5cGUgeyBFeHRlbnNpb25BUEkgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudFwiO1xuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiAocGk6IEV4dGVuc2lvbkFQSSkge1xuICAvLyBTdWJzY3JpYmUgdG8gZXZlbnRzXG4gIHBpLm9uKFwiZXZlbnRfbmFtZVwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAgIC8vIGN0eC51aSBmb3IgdXNlciBpbnRlcmFjdGlvblxuICAgIGNvbnN0IG9rID0gYXdhaXQgY3R4LnVpLmNvbmZpcm0oXCJUaXRsZVwiLCBcIkFyZSB5b3Ugc3VyZT9cIik7XG4gICAgY3R4LnVpLm5vdGlmeShcIkRvbmUhXCIsIFwiaW5mb1wiKTtcbiAgICBjdHgudWkuc2V0U3RhdHVzKFwibXktZXh0XCIsIFwiUHJvY2Vzc2luZy4uLlwiKTsgIC8vIEZvb3RlciBzdGF0dXNcbiAgICBjdHgudWkuc2V0V2lkZ2V0KFwibXktZXh0XCIsIFtcIkxpbmUgMVwiLCBcIkxpbmUgMlwiXSk7ICAvLyBXaWRnZXQgYWJvdmUgZWRpdG9yIChkZWZhdWx0KVxuICB9KTtcblxuICAvLyBSZWdpc3RlciB0b29scywgY29tbWFuZHMsIHNob3J0Y3V0cywgZmxhZ3NcbiAgcGkucmVnaXN0ZXJUb29sKHsgLi4uIH0pO1xuICBwaS5yZWdpc3RlckNvbW1hbmQoXCJuYW1lXCIsIHsgLi4uIH0pO1xuICBwaS5yZWdpc3RlclNob3J0Y3V0KFwiY3RybCt4XCIsIHsgLi4uIH0pO1xuICBwaS5yZWdpc3RlckZsYWcoXCJteS1mbGFnXCIsIHsgLi4uIH0pO1xufVxuYGBgXG5cbkV4dGVuc2lvbnMgYXJlIGxvYWRlZCB2aWEgW2ppdGldKGh0dHBzOi8vZ2l0aHViLmNvbS91bmpzL2ppdGkpLCBzbyBUeXBlU2NyaXB0IHdvcmtzIHdpdGhvdXQgY29tcGlsYXRpb24uXG5cbklmIHRoZSBmYWN0b3J5IHJldHVybnMgYSBgUHJvbWlzZWAsIHBpIGF3YWl0cyBpdCBiZWZvcmUgY29udGludWluZyBzdGFydHVwLiBUaGF0IG1lYW5zIGFzeW5jIGluaXRpYWxpemF0aW9uIGNvbXBsZXRlcyBiZWZvcmUgYHNlc3Npb25fc3RhcnRgLCBiZWZvcmUgYHJlc291cmNlc19kaXNjb3ZlcmAsIGFuZCBiZWZvcmUgcHJvdmlkZXIgcmVnaXN0cmF0aW9ucyBxdWV1ZWQgdmlhIGBwaS5yZWdpc3RlclByb3ZpZGVyKClgIGFyZSBmbHVzaGVkLlxuXG4jIyMgQXN5bmMgZmFjdG9yeSBmdW5jdGlvbnNcblxuVXNlIGFuIGFzeW5jIGZhY3RvcnkgZm9yIG9uZS10aW1lIHN0YXJ0dXAgd29yayBzdWNoIGFzIGZldGNoaW5nIHJlbW90ZSBjb25maWd1cmF0aW9uIG9yIGR5bmFtaWNhbGx5IGRpc2NvdmVyaW5nIGF2YWlsYWJsZSBtb2RlbHMuXG5cbmBgYHR5cGVzY3JpcHRcbmltcG9ydCB0eXBlIHsgRXh0ZW5zaW9uQVBJIH0gZnJvbSBcIkBlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnRcIjtcblxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgZnVuY3Rpb24gKHBpOiBFeHRlbnNpb25BUEkpIHtcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChcImh0dHA6Ly9sb2NhbGhvc3Q6MTIzNC92MS9tb2RlbHNcIik7XG4gIGNvbnN0IHBheWxvYWQgPSAoYXdhaXQgcmVzcG9uc2UuanNvbigpKSBhcyB7XG4gICAgZGF0YTogQXJyYXk8e1xuICAgICAgaWQ6IHN0cmluZztcbiAgICAgIG5hbWU/OiBzdHJpbmc7XG4gICAgICBjb250ZXh0X3dpbmRvdz86IG51bWJlcjtcbiAgICAgIG1heF90b2tlbnM/OiBudW1iZXI7XG4gICAgfT47XG4gIH07XG5cbiAgcGkucmVnaXN0ZXJQcm92aWRlcihcImxvY2FsLW9wZW5haVwiLCB7XG4gICAgYmFzZVVybDogXCJodHRwOi8vbG9jYWxob3N0OjEyMzQvdjFcIixcbiAgICBhcGlLZXk6IFwiJExPQ0FMX09QRU5BSV9BUElfS0VZXCIsXG4gICAgYXBpOiBcIm9wZW5haS1jb21wbGV0aW9uc1wiLFxuICAgIG1vZGVsczogcGF5bG9hZC5kYXRhLm1hcCgobW9kZWwpID0+ICh7XG4gICAgICBpZDogbW9kZWwuaWQsXG4gICAgICBuYW1lOiBtb2RlbC5uYW1lID8/IG1vZGVsLmlkLFxuICAgICAgcmVhc29uaW5nOiBmYWxzZSxcbiAgICAgIGlucHV0OiBbXCJ0ZXh0XCJdLFxuICAgICAgY29zdDogeyBpbnB1dDogMCwgb3V0cHV0OiAwLCBjYWNoZVJlYWQ6IDAsIGNhY2hlV3JpdGU6IDAgfSxcbiAgICAgIGNvbnRleHRXaW5kb3c6IG1vZGVsLmNvbnRleHRfd2luZG93ID8/IDEyODAwMCxcbiAgICAgIG1heFRva2VuczogbW9kZWwubWF4X3Rva2VucyA/PyA0MDk2LFxuICAgIH0pKSxcbiAgfSk7XG59XG5gYGBcblxuVGhpcyBwYXR0ZXJuIG1ha2VzIHRoZSBmZXRjaGVkIG1vZGVscyBhdmFpbGFibGUgZHVyaW5nIG5vcm1hbCBzdGFydHVwIGFuZCB0byBgcGkgLS1saXN0LW1vZGVsc2AuXG5cbiMjIyBMb25nLWxpdmVkIHJlc291cmNlcyBhbmQgc2h1dGRvd25cblxuRXh0ZW5zaW9uIGZhY3RvcmllcyBtYXkgcnVuIGluIGludm9jYXRpb25zIHRoYXQgbmV2ZXIgc3RhcnQgYSBzZXNzaW9uLiBEbyBub3Qgc3RhcnQgYmFja2dyb3VuZCByZXNvdXJjZXMgc3VjaCBhcyBwcm9jZXNzZXMsIHNvY2tldHMsIGZpbGUgd2F0Y2hlcnMsIG9yIHRpbWVycyBmcm9tIHRoZSBmYWN0b3J5LlxuXG5EZWZlciBiYWNrZ3JvdW5kIHJlc291cmNlIHN0YXJ0dXAgdW50aWwgYHNlc3Npb25fc3RhcnRgIG9yIHRoZSBjb21tYW5kL3Rvb2wvZXZlbnQgdGhhdCBuZWVkcyB0aGUgcmVzb3VyY2UuIFJlZ2lzdGVyIGFuIGlkZW1wb3RlbnQgYHNlc3Npb25fc2h1dGRvd25gIGhhbmRsZXIgdG8gY2xvc2UgYW55IHNlc3Npb24tc2NvcGVkIHJlc291cmNlcyB5b3Ugc3RhcnQuXG5cbiMjIyBFeHRlbnNpb24gU3R5bGVzXG5cbioqU2luZ2xlIGZpbGUqKiAtIHNpbXBsZXN0LCBmb3Igc21hbGwgZXh0ZW5zaW9uczpcblxuYGBgXG5+Ly5waS9hZ2VudC9leHRlbnNpb25zL1xu4pSU4pSA4pSAIG15LWV4dGVuc2lvbi50c1xuYGBgXG5cbioqRGlyZWN0b3J5IHdpdGggaW5kZXgudHMqKiAtIGZvciBtdWx0aS1maWxlIGV4dGVuc2lvbnM6XG5cbmBgYFxufi8ucGkvYWdlbnQvZXh0ZW5zaW9ucy9cbuKUlOKUgOKUgCBteS1leHRlbnNpb24vXG4gICAg4pSc4pSA4pSAIGluZGV4LnRzICAgICAgICAjIEVudHJ5IHBvaW50IChleHBvcnRzIGRlZmF1bHQgZnVuY3Rpb24pXG4gICAg4pSc4pSA4pSAIHRvb2xzLnRzICAgICAgICAjIEhlbHBlciBtb2R1bGVcbiAgICDilJTilIDilIAgdXRpbHMudHMgICAgICAgICMgSGVscGVyIG1vZHVsZVxuYGBgXG5cbioqUGFja2FnZSB3aXRoIGRlcGVuZGVuY2llcyoqIC0gZm9yIGV4dGVuc2lvbnMgdGhhdCBuZWVkIG5wbSBwYWNrYWdlczpcblxuYGBgXG5+Ly5waS9hZ2VudC9leHRlbnNpb25zL1xu4pSU4pSA4pSAIG15LWV4dGVuc2lvbi9cbiAgICDilJzilIDilIAgcGFja2FnZS5qc29uICAgICMgRGVjbGFyZXMgZGVwZW5kZW5jaWVzIGFuZCBlbnRyeSBwb2ludHNcbiAgICDilJzilIDilIAgcGFja2FnZS1sb2NrLmpzb25cbiAgICDilJzilIDilIAgbm9kZV9tb2R1bGVzLyAgICMgQWZ0ZXIgbnBtIGluc3RhbGxcbiAgICDilJTilIDilIAgc3JjL1xuICAgICAgICDilJTilIDilIAgaW5kZXgudHNcbmBgYFxuXG5gYGBqc29uXG4vLyBwYWNrYWdlLmpzb25cbntcbiAgXCJuYW1lXCI6IFwibXktZXh0ZW5zaW9uXCIsXG4gIFwiZGVwZW5kZW5jaWVzXCI6IHtcbiAgICBcInpvZFwiOiBcIl4zLjAuMFwiLFxuICAgIFwiY2hhbGtcIjogXCJeNS4wLjBcIlxuICB9LFxuICBcInBpXCI6IHtcbiAgICBcImV4dGVuc2lvbnNcIjogW1wiLi9zcmMvaW5kZXgudHNcIl1cbiAgfVxufVxuYGBgXG5cblJ1biBgbnBtIGluc3RhbGxgIGluIHRoZSBleHRlbnNpb24gZGlyZWN0b3J5LCB0aGVuIGltcG9ydHMgZnJvbSBgbm9kZV9tb2R1bGVzL2Agd29yayBhdXRvbWF0aWNhbGx5LlxuXG4jIyBFdmVudHNcblxuIyMjIExpZmVjeWNsZSBPdmVydmlld1xuXG5gYGBcbnBpIHN0YXJ0c1xuICDilIJcbiAg4pSc4pSA4pa6IHByb2plY3RfdHJ1c3QgKHVzZXIvZ2xvYmFsIGFuZCBDTEkgZXh0ZW5zaW9ucyBvbmx5LCBiZWZvcmUgcHJvamVjdCByZXNvdXJjZXMgbG9hZClcbiAg4pSc4pSA4pa6IHNlc3Npb25fc3RhcnQgeyByZWFzb246IFwic3RhcnR1cFwiIH1cbiAg4pSU4pSA4pa6IHJlc291cmNlc19kaXNjb3ZlciB7IHJlYXNvbjogXCJzdGFydHVwXCIgfVxuICAgICAg4pSCXG4gICAgICDilrxcbnVzZXIgc2VuZHMgcHJvbXB0IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUkFxuICDilIIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKUglxuICDilJzilIDilrogKGV4dGVuc2lvbiBjb21tYW5kcyBjaGVja2VkIGZpcnN0LCBieXBhc3MgaWYgZm91bmQpICDilIJcbiAg4pSc4pSA4pa6IGlucHV0IChjYW4gaW50ZXJjZXB0LCB0cmFuc2Zvcm0sIG9yIGhhbmRsZSkgICAgICAgICAg4pSCXG4gIOKUnOKUgOKWuiAoc2tpbGwvdGVtcGxhdGUgZXhwYW5zaW9uIGlmIG5vdCBoYW5kbGVkKSAgICAgICAgICAgIOKUglxuICDilJzilIDilrogYmVmb3JlX2FnZW50X3N0YXJ0IChjYW4gaW5qZWN0IG1lc3NhZ2UsIG1vZGlmeSBzeXN0ZW0gcHJvbXB0KVxuICDilJzilIDilrogYWdlbnRfc3RhcnQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDilIJcbiAg4pSc4pSA4pa6IG1lc3NhZ2Vfc3RhcnQgLyBtZXNzYWdlX3VwZGF0ZSAvIG1lc3NhZ2VfZW5kICAgICAgICAg4pSCXG4gIOKUgiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4pSCXG4gIOKUgiAgIOKUjOKUgOKUgOKUgCB0dXJuIChyZXBlYXRzIHdoaWxlIExMTSBjYWxscyB0b29scykg4pSA4pSA4pSA4pSQICAgICAgIOKUglxuICDilIIgICDilIIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKUgiAgICAgICDilIJcbiAg4pSCICAg4pSc4pSA4pa6IHR1cm5fc3RhcnQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4pSCICAgICAgIOKUglxuICDilIIgICDilJzilIDilrogY29udGV4dCAoY2FuIG1vZGlmeSBtZXNzYWdlcykgICAgICAgICAgICDilIIgICAgICAg4pSCXG4gIOKUgiAgIOKUnOKUgOKWuiBiZWZvcmVfcHJvdmlkZXJfcmVxdWVzdCAoY2FuIGluc3BlY3Qgb3IgcmVwbGFjZSBwYXlsb2FkKVxuICDilIIgICDilJzilIDilrogYWZ0ZXJfcHJvdmlkZXJfcmVzcG9uc2UgKHN0YXR1cyArIGhlYWRlcnMsIGJlZm9yZSBzdHJlYW0gY29uc3VtZSlcbiAg4pSCICAg4pSCICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDilIIgICAgICAg4pSCXG4gIOKUgiAgIOKUgiAgIExMTSByZXNwb25kcywgbWF5IGNhbGwgdG9vbHM6ICAgICAgICAgICAg4pSCICAgICAgIOKUglxuICDilIIgICDilIIgICAgIOKUnOKUgOKWuiB0b29sX2V4ZWN1dGlvbl9zdGFydCAgICAgICAgICAgICAgIOKUgiAgICAgICDilIJcbiAg4pSCICAg4pSCICAgICDilJzilIDilrogdG9vbF9jYWxsIChjYW4gYmxvY2spICAgICAgICAgICAgICDilIIgICAgICAg4pSCXG4gIOKUgiAgIOKUgiAgICAg4pSc4pSA4pa6IHRvb2xfZXhlY3V0aW9uX3VwZGF0ZSAgICAgICAgICAgICAg4pSCICAgICAgIOKUglxuICDilIIgICDilIIgICAgIOKUnOKUgOKWuiB0b29sX3Jlc3VsdCAoY2FuIG1vZGlmeSkgICAgICAgICAgIOKUgiAgICAgICDilIJcbiAg4pSCICAg4pSCICAgICDilJTilIDilrogdG9vbF9leGVjdXRpb25fZW5kICAgICAgICAgICAgICAgICDilIIgICAgICAg4pSCXG4gIOKUgiAgIOKUgiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4pSCICAgICAgIOKUglxuICDilIIgICDilJTilIDilrogdHVybl9lbmQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDilIIgICAgICAg4pSCXG4gIOKUgiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4pSCXG4gIOKUlOKUgOKWuiBhZ2VudF9lbmQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKUglxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDilIJcbnVzZXIgc2VuZHMgYW5vdGhlciBwcm9tcHQg4peE4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSYXG5cbi9uZXcgKG5ldyBzZXNzaW9uKSBvciAvcmVzdW1lIChzd2l0Y2ggc2Vzc2lvbilcbiAg4pSc4pSA4pa6IHNlc3Npb25fYmVmb3JlX3N3aXRjaCAoY2FuIGNhbmNlbClcbiAg4pSc4pSA4pa6IHNlc3Npb25fc2h1dGRvd25cbiAg4pSc4pSA4pa6IHNlc3Npb25fc3RhcnQgeyByZWFzb246IFwibmV3XCIgfCBcInJlc3VtZVwiLCBwcmV2aW91c1Nlc3Npb25GaWxlPyB9XG4gIOKUlOKUgOKWuiByZXNvdXJjZXNfZGlzY292ZXIgeyByZWFzb246IFwic3RhcnR1cFwiIH1cblxuL2Zvcmsgb3IgL2Nsb25lXG4gIOKUnOKUgOKWuiBzZXNzaW9uX2JlZm9yZV9mb3JrIChjYW4gY2FuY2VsKVxuICDilJzilIDilrogc2Vzc2lvbl9zaHV0ZG93blxuICDilJzilIDilrogc2Vzc2lvbl9zdGFydCB7IHJlYXNvbjogXCJmb3JrXCIsIHByZXZpb3VzU2Vzc2lvbkZpbGUgfVxuICDilJTilIDilrogcmVzb3VyY2VzX2Rpc2NvdmVyIHsgcmVhc29uOiBcInN0YXJ0dXBcIiB9XG5cbi9jb21wYWN0IG9yIGF1dG8tY29tcGFjdGlvblxuICDilJzilIDilrogc2Vzc2lvbl9iZWZvcmVfY29tcGFjdCAoY2FuIGNhbmNlbCBvciBjdXN0b21pemUpXG4gIOKUlOKUgOKWuiBzZXNzaW9uX2NvbXBhY3RcblxuL3RyZWUgbmF2aWdhdGlvblxuICDilJzilIDilrogc2Vzc2lvbl9iZWZvcmVfdHJlZSAoY2FuIGNhbmNlbCBvciBjdXN0b21pemUpXG4gIOKUlOKUgOKWuiBzZXNzaW9uX3RyZWVcblxuL21vZGVsIG9yIEN0cmwrUCAobW9kZWwgc2VsZWN0aW9uL2N5Y2xpbmcpXG4gIOKUnOKUgOKWuiB0aGlua2luZ19sZXZlbF9zZWxlY3QgKGlmIG1vZGVsIGNoYW5nZSBjaGFuZ2VzL2NsYW1wcyB0aGlua2luZyBsZXZlbClcbiAg4pSU4pSA4pa6IG1vZGVsX3NlbGVjdFxuXG50aGlua2luZyBsZXZlbCBjaGFuZ2VzIChzZXR0aW5ncywga2V5YmluZGluZywgcGkuc2V0VGhpbmtpbmdMZXZlbCgpKVxuICDilJTilIDilrogdGhpbmtpbmdfbGV2ZWxfc2VsZWN0XG5cbmV4aXQgKEN0cmwrQywgQ3RybCtELCBTSUdIVVAsIFNJR1RFUk0pXG4gIOKUlOKUgOKWuiBzZXNzaW9uX3NodXRkb3duXG5gYGBcblxuIyMjIFN0YXJ0dXAgRXZlbnRzXG5cbiMjIyMgcHJvamVjdF90cnVzdFxuXG5GaXJlZCBiZWZvcmUgcGkgZGVjaWRlcyB3aGV0aGVyIHRvIHRydXN0IGEgcHJvamVjdCB3aXRoIGR5bmFtaWMgY29uZmlncyAoYC5waWAgb3IgYC5hZ2VudHMvc2tpbGxzYCkuIEl0IHJ1bnMgZHVyaW5nIHN0YXJ0dXAgYW5kIHdoZW4gc2Vzc2lvbiByZXBsYWNlbWVudCAoZm9yIGV4YW1wbGUgYC9yZXN1bWVgKSBlbnRlcnMgYSBjd2Qgd2hvc2UgdHJ1c3QgaGFzIG5vdCBiZWVuIHJlc29sdmVkIGluIHRoZSBjdXJyZW50IHByb2Nlc3MuIE9ubHkgdXNlci9nbG9iYWwgZXh0ZW5zaW9ucyBhbmQgQ0xJIGAtZWAgZXh0ZW5zaW9ucyBwYXJ0aWNpcGF0ZTsgcHJvamVjdC1sb2NhbCBleHRlbnNpb25zIGFyZSBub3QgbG9hZGVkIHVudGlsIGFmdGVyIHRydXN0IGlzIHJlc29sdmVkLlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcInByb2plY3RfdHJ1c3RcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQuY3dkIC0gY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeVxuICAvLyBjdHggaGFzIGEgbGltaXRlZCB0cnVzdCBjb250ZXh0OiBjd2QsIG1vZGUsIGhhc1VJLCBhbmQgc2VsZWN0L2NvbmZpcm0vaW5wdXQvbm90aWZ5IFVJIGhlbHBlcnNcbiAgaWYgKGF3YWl0IGN0eC51aS5jb25maXJtKFwiVHJ1c3QgcHJvamVjdD9cIiwgZXZlbnQuY3dkKSkge1xuICAgIHJldHVybiB7IHRydXN0ZWQ6IFwieWVzXCIsIHJlbWVtYmVyOiB0cnVlIH07XG4gIH1cbiAgcmV0dXJuIHsgdHJ1c3RlZDogXCJ1bmRlY2lkZWRcIiB9O1xufSk7XG5gYGBcblxuQSBgcHJvamVjdF90cnVzdGAgaGFuZGxlciBtdXN0IHJldHVybiBgeyB0cnVzdGVkOiBcInllc1wiIHwgXCJub1wiIHwgXCJ1bmRlY2lkZWRcIiB9YC4gQSB1c2VyL2dsb2JhbCBvciBDTEkgZXh0ZW5zaW9uIHRoYXQgcmV0dXJucyBgXCJ5ZXNcImAgb3IgYFwibm9cImAgb3ducyB0aGUgZGVjaXNpb247IHRoZSBmaXJzdCB5ZXMvbm8gZGVjaXNpb24gd2lucyBhbmQgc3VwcHJlc3NlcyB0aGUgYnVpbHQtaW4gdHJ1c3QgcHJvbXB0LiBVc2UgYHJlbWVtYmVyOiB0cnVlYCB0byBwZXJzaXN0IGEgeWVzL25vIGRlY2lzaW9uOyBvdGhlcndpc2UgaXQgYXBwbGllcyBvbmx5IHRvIHRoZSBjdXJyZW50IHByb2Nlc3MuIFJldHVybiBgXCJ1bmRlY2lkZWRcImAgdG8gbGV0IGxhdGVyIGhhbmRsZXJzIG9yIHRoZSBidWlsdC1pbiB0cnVzdCBmbG93IGRlY2lkZS4gQ2hlY2sgYGN0eC5oYXNVSWAgYmVmb3JlIHByb21wdGluZy4gSWYgbm8gaGFuZGxlciByZXR1cm5zIHllcy9ubywgbm9ybWFsIHRydXN0IHJlc29sdXRpb24gY29udGludWVzOiBzYXZlZCBgdHJ1c3QuanNvbmAgZGVjaXNpb25zIGFwcGx5IGZpcnN0LCB0aGVuIGBkZWZhdWx0UHJvamVjdFRydXN0YCBjb250cm9scyB3aGV0aGVyIHBpIGFza3MsIHRydXN0cywgb3IgZGVjbGluZXMgYnkgZGVmYXVsdC5cblxuIyMjIFJlc291cmNlIEV2ZW50c1xuXG4jIyMjIHJlc291cmNlc19kaXNjb3ZlclxuXG5GaXJlZCBhZnRlciBgc2Vzc2lvbl9zdGFydGAgc28gZXh0ZW5zaW9ucyBjYW4gY29udHJpYnV0ZSBhZGRpdGlvbmFsIHNraWxsLCBwcm9tcHQsIGFuZCB0aGVtZSBwYXRocy5cblRoZSBzdGFydHVwIHBhdGggdXNlcyBgcmVhc29uOiBcInN0YXJ0dXBcImAuIFJlbG9hZCB1c2VzIGByZWFzb246IFwicmVsb2FkXCJgLlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcInJlc291cmNlc19kaXNjb3ZlclwiLCBhc3luYyAoZXZlbnQsIF9jdHgpID0+IHtcbiAgLy8gZXZlbnQuY3dkIC0gY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeVxuICAvLyBldmVudC5yZWFzb24gLSBcInN0YXJ0dXBcIiB8IFwicmVsb2FkXCJcbiAgcmV0dXJuIHtcbiAgICBza2lsbFBhdGhzOiBbXCIvcGF0aC90by9za2lsbHNcIl0sXG4gICAgcHJvbXB0UGF0aHM6IFtcIi9wYXRoL3RvL3Byb21wdHNcIl0sXG4gICAgdGhlbWVQYXRoczogW1wiL3BhdGgvdG8vdGhlbWVzXCJdLFxuICB9O1xufSk7XG5gYGBcblxuIyMjIFNlc3Npb24gRXZlbnRzXG5cblNlZSBbU2Vzc2lvbiBGb3JtYXRdKHNlc3Npb24tZm9ybWF0Lm1kKSBmb3Igc2Vzc2lvbiBzdG9yYWdlIGludGVybmFscyBhbmQgdGhlIFNlc3Npb25NYW5hZ2VyIEFQSS5cblxuIyMjIyBzZXNzaW9uX3N0YXJ0XG5cbkZpcmVkIHdoZW4gYSBzZXNzaW9uIGlzIHN0YXJ0ZWQsIGxvYWRlZCwgb3IgcmVsb2FkZWQuXG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwic2Vzc2lvbl9zdGFydFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAvLyBldmVudC5yZWFzb24gLSBcInN0YXJ0dXBcIiB8IFwicmVsb2FkXCIgfCBcIm5ld1wiIHwgXCJyZXN1bWVcIiB8IFwiZm9ya1wiXG4gIC8vIGV2ZW50LnByZXZpb3VzU2Vzc2lvbkZpbGUgLSBwcmVzZW50IGZvciBcIm5ld1wiLCBcInJlc3VtZVwiLCBhbmQgXCJmb3JrXCJcbiAgY3R4LnVpLm5vdGlmeShgU2Vzc2lvbjogJHtjdHguc2Vzc2lvbk1hbmFnZXIuZ2V0U2Vzc2lvbkZpbGUoKSA/PyBcImVwaGVtZXJhbFwifWAsIFwiaW5mb1wiKTtcbn0pO1xuYGBgXG5cbiMjIyMgc2Vzc2lvbl9iZWZvcmVfc3dpdGNoXG5cbkZpcmVkIGJlZm9yZSBzdGFydGluZyBhIG5ldyBzZXNzaW9uIChgL25ld2ApIG9yIHN3aXRjaGluZyBzZXNzaW9ucyAoYC9yZXN1bWVgKS5cblxuYGBgdHlwZXNjcmlwdFxucGkub24oXCJzZXNzaW9uX2JlZm9yZV9zd2l0Y2hcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQucmVhc29uIC0gXCJuZXdcIiBvciBcInJlc3VtZVwiXG4gIC8vIGV2ZW50LnRhcmdldFNlc3Npb25GaWxlIC0gc2Vzc2lvbiB3ZSdyZSBzd2l0Y2hpbmcgdG8gKG9ubHkgZm9yIFwicmVzdW1lXCIpXG5cbiAgaWYgKGV2ZW50LnJlYXNvbiA9PT0gXCJuZXdcIikge1xuICAgIGNvbnN0IG9rID0gYXdhaXQgY3R4LnVpLmNvbmZpcm0oXCJDbGVhcj9cIiwgXCJEZWxldGUgYWxsIG1lc3NhZ2VzP1wiKTtcbiAgICBpZiAoIW9rKSByZXR1cm4geyBjYW5jZWw6IHRydWUgfTtcbiAgfVxufSk7XG5gYGBcblxuQWZ0ZXIgYSBzdWNjZXNzZnVsIHN3aXRjaCBvciBuZXctc2Vzc2lvbiBhY3Rpb24sIHBpIGVtaXRzIGBzZXNzaW9uX3NodXRkb3duYCBmb3IgdGhlIG9sZCBleHRlbnNpb24gaW5zdGFuY2UsIHJlbG9hZHMgYW5kIHJlYmluZHMgZXh0ZW5zaW9ucyBmb3IgdGhlIG5ldyBzZXNzaW9uLCB0aGVuIGVtaXRzIGBzZXNzaW9uX3N0YXJ0YCB3aXRoIGByZWFzb246IFwibmV3XCIgfCBcInJlc3VtZVwiYCBhbmQgYHByZXZpb3VzU2Vzc2lvbkZpbGVgLlxuRG8gY2xlYW51cCB3b3JrIGluIGBzZXNzaW9uX3NodXRkb3duYCwgdGhlbiByZWVzdGFibGlzaCBhbnkgaW4tbWVtb3J5IHN0YXRlIGluIGBzZXNzaW9uX3N0YXJ0YC5cblxuIyMjIyBzZXNzaW9uX2JlZm9yZV9mb3JrXG5cbkZpcmVkIHdoZW4gZm9ya2luZyB2aWEgYC9mb3JrYCBvciBjbG9uaW5nIHZpYSBgL2Nsb25lYC5cblxuYGBgdHlwZXNjcmlwdFxucGkub24oXCJzZXNzaW9uX2JlZm9yZV9mb3JrXCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIC8vIGV2ZW50LmVudHJ5SWQgLSBJRCBvZiB0aGUgc2VsZWN0ZWQgZW50cnlcbiAgLy8gZXZlbnQucG9zaXRpb24gLSBcImJlZm9yZVwiIGZvciAvZm9yaywgXCJhdFwiIGZvciAvY2xvbmVcbiAgcmV0dXJuIHsgY2FuY2VsOiB0cnVlIH07IC8vIENhbmNlbCBmb3JrL2Nsb25lXG4gIC8vIE9SXG4gIHJldHVybiB7IHNraXBDb252ZXJzYXRpb25SZXN0b3JlOiB0cnVlIH07IC8vIFJlc2VydmVkIGZvciBmdXR1cmUgY29udmVyc2F0aW9uIHJlc3RvcmUgY29udHJvbFxufSk7XG5gYGBcblxuQWZ0ZXIgYSBzdWNjZXNzZnVsIGZvcmsgb3IgY2xvbmUsIHBpIGVtaXRzIGBzZXNzaW9uX3NodXRkb3duYCBmb3IgdGhlIG9sZCBleHRlbnNpb24gaW5zdGFuY2UsIHJlbG9hZHMgYW5kIHJlYmluZHMgZXh0ZW5zaW9ucyBmb3IgdGhlIG5ldyBzZXNzaW9uLCB0aGVuIGVtaXRzIGBzZXNzaW9uX3N0YXJ0YCB3aXRoIGByZWFzb246IFwiZm9ya1wiYCBhbmQgYHByZXZpb3VzU2Vzc2lvbkZpbGVgLlxuRG8gY2xlYW51cCB3b3JrIGluIGBzZXNzaW9uX3NodXRkb3duYCwgdGhlbiByZWVzdGFibGlzaCBhbnkgaW4tbWVtb3J5IHN0YXRlIGluIGBzZXNzaW9uX3N0YXJ0YC5cblxuIyMjIyBzZXNzaW9uX2JlZm9yZV9jb21wYWN0IC8gc2Vzc2lvbl9jb21wYWN0XG5cbkZpcmVkIG9uIGNvbXBhY3Rpb24uIFNlZSBbY29tcGFjdGlvbi5tZF0oY29tcGFjdGlvbi5tZCkgZm9yIGRldGFpbHMuXG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwic2Vzc2lvbl9iZWZvcmVfY29tcGFjdFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICBjb25zdCB7IHByZXBhcmF0aW9uLCBicmFuY2hFbnRyaWVzLCBjdXN0b21JbnN0cnVjdGlvbnMsIHNpZ25hbCB9ID0gZXZlbnQ7XG5cbiAgLy8gQ2FuY2VsOlxuICByZXR1cm4geyBjYW5jZWw6IHRydWUgfTtcblxuICAvLyBDdXN0b20gc3VtbWFyeTpcbiAgcmV0dXJuIHtcbiAgICBjb21wYWN0aW9uOiB7XG4gICAgICBzdW1tYXJ5OiBcIi4uLlwiLFxuICAgICAgZmlyc3RLZXB0RW50cnlJZDogcHJlcGFyYXRpb24uZmlyc3RLZXB0RW50cnlJZCxcbiAgICAgIHRva2Vuc0JlZm9yZTogcHJlcGFyYXRpb24udG9rZW5zQmVmb3JlLFxuICAgIH1cbiAgfTtcbn0pO1xuXG5waS5vbihcInNlc3Npb25fY29tcGFjdFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAvLyBldmVudC5jb21wYWN0aW9uRW50cnkgLSB0aGUgc2F2ZWQgY29tcGFjdGlvblxuICAvLyBldmVudC5mcm9tRXh0ZW5zaW9uIC0gd2hldGhlciBleHRlbnNpb24gcHJvdmlkZWQgaXRcbn0pO1xuYGBgXG5cbiMjIyMgc2Vzc2lvbl9iZWZvcmVfdHJlZSAvIHNlc3Npb25fdHJlZVxuXG5GaXJlZCBvbiBgL3RyZWVgIG5hdmlnYXRpb24uIFNlZSBbU2Vzc2lvbnNdKHNlc3Npb25zLm1kKSBmb3IgdHJlZSBuYXZpZ2F0aW9uIGNvbmNlcHRzLlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcInNlc3Npb25fYmVmb3JlX3RyZWVcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgY29uc3QgeyBwcmVwYXJhdGlvbiwgc2lnbmFsIH0gPSBldmVudDtcbiAgcmV0dXJuIHsgY2FuY2VsOiB0cnVlIH07XG4gIC8vIE9SIHByb3ZpZGUgY3VzdG9tIHN1bW1hcnk6XG4gIHJldHVybiB7IHN1bW1hcnk6IHsgc3VtbWFyeTogXCIuLi5cIiwgZGV0YWlsczoge30gfSB9O1xufSk7XG5cbnBpLm9uKFwic2Vzc2lvbl90cmVlXCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIC8vIGV2ZW50Lm5ld0xlYWZJZCwgb2xkTGVhZklkLCBzdW1tYXJ5RW50cnksIGZyb21FeHRlbnNpb25cbn0pO1xuYGBgXG5cbiMjIyMgc2Vzc2lvbl9zaHV0ZG93blxuXG5GaXJlZCBiZWZvcmUgYSBzdGFydGVkIHNlc3Npb24gcnVudGltZSBpcyB0b3JuIGRvd24uIFVzZSB0aGlzIHRvIGNsZWFuIHVwIHJlc291cmNlcyBvcGVuZWQgZnJvbSBgc2Vzc2lvbl9zdGFydGAgb3Igb3RoZXIgc2Vzc2lvbi1zY29wZWQgaG9va3MuXG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwic2Vzc2lvbl9zaHV0ZG93blwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAvLyBldmVudC5yZWFzb24gLSBcInF1aXRcIiB8IFwicmVsb2FkXCIgfCBcIm5ld1wiIHwgXCJyZXN1bWVcIiB8IFwiZm9ya1wiXG4gIC8vIGV2ZW50LnRhcmdldFNlc3Npb25GaWxlIC0gZGVzdGluYXRpb24gc2Vzc2lvbiBmb3Igc2Vzc2lvbiByZXBsYWNlbWVudCBmbG93c1xuICAvLyBDbGVhbnVwLCBzYXZlIHN0YXRlLCBldGMuXG59KTtcbmBgYFxuXG4jIyMgQWdlbnQgRXZlbnRzXG5cbiMjIyMgYmVmb3JlX2FnZW50X3N0YXJ0XG5cbkZpcmVkIGFmdGVyIHVzZXIgc3VibWl0cyBwcm9tcHQsIGJlZm9yZSBhZ2VudCBsb29wLiBDYW4gaW5qZWN0IGEgbWVzc2FnZSBhbmQvb3IgbW9kaWZ5IHRoZSBzeXN0ZW0gcHJvbXB0LlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcImJlZm9yZV9hZ2VudF9zdGFydFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAvLyBldmVudC5wcm9tcHQgLSB1c2VyJ3MgcHJvbXB0IHRleHRcbiAgLy8gZXZlbnQuaW1hZ2VzIC0gYXR0YWNoZWQgaW1hZ2VzIChpZiBhbnkpXG4gIC8vIGV2ZW50LnN5c3RlbVByb21wdCAtIGN1cnJlbnQgY2hhaW5lZCBzeXN0ZW0gcHJvbXB0IGZvciB0aGlzIGhhbmRsZXJcbiAgLy8gICAoaW5jbHVkZXMgY2hhbmdlcyBmcm9tIGVhcmxpZXIgYmVmb3JlX2FnZW50X3N0YXJ0IGhhbmRsZXJzKVxuICAvLyBldmVudC5zeXN0ZW1Qcm9tcHRPcHRpb25zIC0gc3RydWN0dXJlZCBvcHRpb25zIHVzZWQgdG8gYnVpbGQgdGhlIHN5c3RlbSBwcm9tcHRcbiAgLy8gICAuY3VzdG9tUHJvbXB0IC0gYW55IGN1c3RvbSBzeXN0ZW0gcHJvbXB0IChmcm9tIC0tc3lzdGVtLXByb21wdCwgU1lTVEVNLm1kLCBvciBjdXN0b20gdGVtcGxhdGVzKVxuICAvLyAgIC5zZWxlY3RlZFRvb2xzIC0gdG9vbHMgY3VycmVudGx5IGFjdGl2ZSBpbiB0aGUgcHJvbXB0XG4gIC8vICAgLnRvb2xTbmlwcGV0cyAtIG9uZS1saW5lIGRlc2NyaXB0aW9ucyBmb3IgZWFjaCB0b29sXG4gIC8vICAgLnByb21wdEd1aWRlbGluZXMgLSBjdXN0b20gZ3VpZGVsaW5lIGJ1bGxldHNcbiAgLy8gICAuYXBwZW5kU3lzdGVtUHJvbXB0IC0gdGV4dCBmcm9tIC0tYXBwZW5kLXN5c3RlbS1wcm9tcHQgZmxhZ3NcbiAgLy8gICAuY3dkIC0gd29ya2luZyBkaXJlY3RvcnlcbiAgLy8gICAuY29udGV4dEZpbGVzIC0gQUdFTlRTLm1kIGZpbGVzIGFuZCBvdGhlciBsb2FkZWQgY29udGV4dCBmaWxlc1xuICAvLyAgIC5za2lsbHMgLSBsb2FkZWQgc2tpbGxzXG5cbiAgcmV0dXJuIHtcbiAgICAvLyBJbmplY3QgYSBwZXJzaXN0ZW50IG1lc3NhZ2UgKHN0b3JlZCBpbiBzZXNzaW9uLCBzZW50IHRvIExMTSlcbiAgICBtZXNzYWdlOiB7XG4gICAgICBjdXN0b21UeXBlOiBcIm15LWV4dGVuc2lvblwiLFxuICAgICAgY29udGVudDogXCJBZGRpdGlvbmFsIGNvbnRleHQgZm9yIHRoZSBMTE1cIixcbiAgICAgIGRpc3BsYXk6IHRydWUsXG4gICAgfSxcbiAgICAvLyBSZXBsYWNlIHRoZSBzeXN0ZW0gcHJvbXB0IGZvciB0aGlzIHR1cm4gKGNoYWluZWQgYWNyb3NzIGV4dGVuc2lvbnMpXG4gICAgc3lzdGVtUHJvbXB0OiBldmVudC5zeXN0ZW1Qcm9tcHQgKyBcIlxcblxcbkV4dHJhIGluc3RydWN0aW9ucyBmb3IgdGhpcyB0dXJuLi4uXCIsXG4gIH07XG59KTtcbmBgYFxuXG5UaGUgYHN5c3RlbVByb21wdE9wdGlvbnNgIGZpZWxkIGdpdmVzIGV4dGVuc2lvbnMgYWNjZXNzIHRvIHRoZSBzYW1lIHN0cnVjdHVyZWQgZGF0YSBQaSB1c2VzIHRvIGJ1aWxkIHRoZSBzeXN0ZW0gcHJvbXB0LiBUaGlzIGxldHMgeW91IGluc3BlY3Qgd2hhdCBQaSBoYXMgbG9hZGVkIOKAlCBjdXN0b20gcHJvbXB0cywgZ3VpZGVsaW5lcywgdG9vbCBzbmlwcGV0cywgY29udGV4dCBmaWxlcywgc2tpbGxzIOKAlCB3aXRob3V0IHJlLWRpc2NvdmVyaW5nIHJlc291cmNlcyBvciByZS1wYXJzaW5nIGZsYWdzLiBVc2UgaXQgd2hlbiB5b3VyIGV4dGVuc2lvbiBuZWVkcyB0byBtYWtlIGRlZXAsIGluZm9ybWVkIGNoYW5nZXMgdG8gdGhlIHN5c3RlbSBwcm9tcHQgd2hpbGUgcmVzcGVjdGluZyB1c2VyLXByb3ZpZGVkIGNvbmZpZ3VyYXRpb24uXG5cbkluc2lkZSBgYmVmb3JlX2FnZW50X3N0YXJ0YCwgYGV2ZW50LnN5c3RlbVByb21wdGAgYW5kIGBjdHguZ2V0U3lzdGVtUHJvbXB0KClgIGJvdGggcmVmbGVjdCB0aGUgY2hhaW5lZCBzeXN0ZW0gcHJvbXB0IGFzIG9mIHRoZSBjdXJyZW50IGhhbmRsZXIuIExhdGVyIGBiZWZvcmVfYWdlbnRfc3RhcnRgIGhhbmRsZXJzIGNhbiBzdGlsbCBtb2RpZnkgaXQgYWdhaW4uXG5cbiMjIyMgYWdlbnRfc3RhcnQgLyBhZ2VudF9lbmRcblxuRmlyZWQgb25jZSBwZXIgdXNlciBwcm9tcHQuXG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwiYWdlbnRfc3RhcnRcIiwgYXN5bmMgKF9ldmVudCwgY3R4KSA9PiB7fSk7XG5cbnBpLm9uKFwiYWdlbnRfZW5kXCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIC8vIGV2ZW50Lm1lc3NhZ2VzIC0gbWVzc2FnZXMgZnJvbSB0aGlzIHByb21wdFxufSk7XG5gYGBcblxuIyMjIyB0dXJuX3N0YXJ0IC8gdHVybl9lbmRcblxuRmlyZWQgZm9yIGVhY2ggdHVybiAob25lIExMTSByZXNwb25zZSArIHRvb2wgY2FsbHMpLlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcInR1cm5fc3RhcnRcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQudHVybkluZGV4LCBldmVudC50aW1lc3RhbXBcbn0pO1xuXG5waS5vbihcInR1cm5fZW5kXCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIC8vIGV2ZW50LnR1cm5JbmRleCwgZXZlbnQubWVzc2FnZSwgZXZlbnQudG9vbFJlc3VsdHNcbn0pO1xuYGBgXG5cbiMjIyMgbWVzc2FnZV9zdGFydCAvIG1lc3NhZ2VfdXBkYXRlIC8gbWVzc2FnZV9lbmRcblxuRmlyZWQgZm9yIG1lc3NhZ2UgbGlmZWN5Y2xlIHVwZGF0ZXMuXG5cbi0gYG1lc3NhZ2Vfc3RhcnRgIGFuZCBgbWVzc2FnZV9lbmRgIGZpcmUgZm9yIHVzZXIsIGFzc2lzdGFudCwgYW5kIHRvb2xSZXN1bHQgbWVzc2FnZXMuXG4tIGBtZXNzYWdlX3VwZGF0ZWAgZmlyZXMgZm9yIGFzc2lzdGFudCBzdHJlYW1pbmcgdXBkYXRlcy5cbi0gYG1lc3NhZ2VfZW5kYCBoYW5kbGVycyBjYW4gcmV0dXJuIGB7IG1lc3NhZ2UgfWAgdG8gcmVwbGFjZSB0aGUgZmluYWxpemVkIG1lc3NhZ2UuIFRoZSByZXBsYWNlbWVudCBtdXN0IGtlZXAgdGhlIHNhbWUgYHJvbGVgLlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcIm1lc3NhZ2Vfc3RhcnRcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQubWVzc2FnZVxufSk7XG5cbnBpLm9uKFwibWVzc2FnZV91cGRhdGVcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQubWVzc2FnZVxuICAvLyBldmVudC5hc3Npc3RhbnRNZXNzYWdlRXZlbnQgKHRva2VuLWJ5LXRva2VuIHN0cmVhbSBldmVudClcbn0pO1xuXG5waS5vbihcIm1lc3NhZ2VfZW5kXCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIGlmIChldmVudC5tZXNzYWdlLnJvbGUgIT09IFwiYXNzaXN0YW50XCIpIHJldHVybjtcblxuICByZXR1cm4ge1xuICAgIG1lc3NhZ2U6IHtcbiAgICAgIC4uLmV2ZW50Lm1lc3NhZ2UsXG4gICAgICB1c2FnZToge1xuICAgICAgICAuLi5ldmVudC5tZXNzYWdlLnVzYWdlLFxuICAgICAgICBjb3N0OiB7XG4gICAgICAgICAgLi4uZXZlbnQubWVzc2FnZS51c2FnZS5jb3N0LFxuICAgICAgICAgIHRvdGFsOiAwLjEyMyxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfTtcbn0pO1xuYGBgXG5cbiMjIyMgdG9vbF9leGVjdXRpb25fc3RhcnQgLyB0b29sX2V4ZWN1dGlvbl91cGRhdGUgLyB0b29sX2V4ZWN1dGlvbl9lbmRcblxuRmlyZWQgZm9yIHRvb2wgZXhlY3V0aW9uIGxpZmVjeWNsZSB1cGRhdGVzLlxuXG5JbiBwYXJhbGxlbCB0b29sIG1vZGU6XG4tIGB0b29sX2V4ZWN1dGlvbl9zdGFydGAgaXMgZW1pdHRlZCBpbiBhc3Npc3RhbnQgc291cmNlIG9yZGVyIGR1cmluZyB0aGUgcHJlZmxpZ2h0IHBoYXNlXG4tIGB0b29sX2V4ZWN1dGlvbl91cGRhdGVgIGV2ZW50cyBtYXkgaW50ZXJsZWF2ZSBhY3Jvc3MgdG9vbHNcbi0gYHRvb2xfZXhlY3V0aW9uX2VuZGAgaXMgZW1pdHRlZCBpbiB0b29sIGNvbXBsZXRpb24gb3JkZXIgYWZ0ZXIgZWFjaCB0b29sIGlzIGZpbmFsaXplZFxuLSBmaW5hbCBgdG9vbFJlc3VsdGAgbWVzc2FnZSBldmVudHMgYXJlIHN0aWxsIGVtaXR0ZWQgbGF0ZXIgaW4gYXNzaXN0YW50IHNvdXJjZSBvcmRlclxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcInRvb2xfZXhlY3V0aW9uX3N0YXJ0XCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIC8vIGV2ZW50LnRvb2xDYWxsSWQsIGV2ZW50LnRvb2xOYW1lLCBldmVudC5hcmdzXG59KTtcblxucGkub24oXCJ0b29sX2V4ZWN1dGlvbl91cGRhdGVcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQudG9vbENhbGxJZCwgZXZlbnQudG9vbE5hbWUsIGV2ZW50LmFyZ3MsIGV2ZW50LnBhcnRpYWxSZXN1bHRcbn0pO1xuXG5waS5vbihcInRvb2xfZXhlY3V0aW9uX2VuZFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAvLyBldmVudC50b29sQ2FsbElkLCBldmVudC50b29sTmFtZSwgZXZlbnQucmVzdWx0LCBldmVudC5pc0Vycm9yXG59KTtcbmBgYFxuXG4jIyMjIGNvbnRleHRcblxuRmlyZWQgYmVmb3JlIGVhY2ggTExNIGNhbGwuIE1vZGlmeSBtZXNzYWdlcyBub24tZGVzdHJ1Y3RpdmVseS4gU2VlIFtTZXNzaW9uIEZvcm1hdF0oc2Vzc2lvbi1mb3JtYXQubWQpIGZvciBtZXNzYWdlIHR5cGVzLlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcImNvbnRleHRcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQubWVzc2FnZXMgLSBkZWVwIGNvcHksIHNhZmUgdG8gbW9kaWZ5XG4gIGNvbnN0IGZpbHRlcmVkID0gZXZlbnQubWVzc2FnZXMuZmlsdGVyKG0gPT4gIXNob3VsZFBydW5lKG0pKTtcbiAgcmV0dXJuIHsgbWVzc2FnZXM6IGZpbHRlcmVkIH07XG59KTtcbmBgYFxuXG4jIyMjIGJlZm9yZV9wcm92aWRlcl9yZXF1ZXN0XG5cbkZpcmVkIGFmdGVyIHRoZSBwcm92aWRlci1zcGVjaWZpYyBwYXlsb2FkIGlzIGJ1aWx0LCByaWdodCBiZWZvcmUgdGhlIHJlcXVlc3QgaXMgc2VudC4gSGFuZGxlcnMgcnVuIGluIGV4dGVuc2lvbiBsb2FkIG9yZGVyLiBSZXR1cm5pbmcgYHVuZGVmaW5lZGAga2VlcHMgdGhlIHBheWxvYWQgdW5jaGFuZ2VkLiBSZXR1cm5pbmcgYW55IG90aGVyIHZhbHVlIHJlcGxhY2VzIHRoZSBwYXlsb2FkIGZvciBsYXRlciBoYW5kbGVycyBhbmQgZm9yIHRoZSBhY3R1YWwgcmVxdWVzdC5cblxuVGhpcyBob29rIGNhbiByZXdyaXRlIHByb3ZpZGVyLWxldmVsIHN5c3RlbSBpbnN0cnVjdGlvbnMgb3IgcmVtb3ZlIHRoZW0gZW50aXJlbHkuIFRob3NlIHBheWxvYWQtbGV2ZWwgY2hhbmdlcyBhcmUgbm90IHJlZmxlY3RlZCBieSBgY3R4LmdldFN5c3RlbVByb21wdCgpYCwgd2hpY2ggcmVwb3J0cyBQaSdzIHN5c3RlbSBwcm9tcHQgc3RyaW5nIHJhdGhlciB0aGFuIHRoZSBmaW5hbCBzZXJpYWxpemVkIHByb3ZpZGVyIHBheWxvYWQuXG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwiYmVmb3JlX3Byb3ZpZGVyX3JlcXVlc3RcIiwgKGV2ZW50LCBjdHgpID0+IHtcbiAgY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkoZXZlbnQucGF5bG9hZCwgbnVsbCwgMikpO1xuXG4gIC8vIE9wdGlvbmFsOiByZXBsYWNlIHBheWxvYWRcbiAgLy8gcmV0dXJuIHsgLi4uZXZlbnQucGF5bG9hZCwgdGVtcGVyYXR1cmU6IDAgfTtcbn0pO1xuYGBgXG5cblRoaXMgaXMgbWFpbmx5IHVzZWZ1bCBmb3IgZGVidWdnaW5nIHByb3ZpZGVyIHNlcmlhbGl6YXRpb24gYW5kIGNhY2hlIGJlaGF2aW9yLlxuXG4jIyMjIGFmdGVyX3Byb3ZpZGVyX3Jlc3BvbnNlXG5cbkZpcmVkIGFmdGVyIGFuIEhUVFAgcmVzcG9uc2UgaXMgcmVjZWl2ZWQgYW5kIGJlZm9yZSBpdHMgc3RyZWFtIGJvZHkgaXMgY29uc3VtZWQuIEhhbmRsZXJzIHJ1biBpbiBleHRlbnNpb24gbG9hZCBvcmRlci5cblxuYGBgdHlwZXNjcmlwdFxucGkub24oXCJhZnRlcl9wcm92aWRlcl9yZXNwb25zZVwiLCAoZXZlbnQsIGN0eCkgPT4ge1xuICAvLyBldmVudC5zdGF0dXMgLSBIVFRQIHN0YXR1cyBjb2RlXG4gIC8vIGV2ZW50LmhlYWRlcnMgLSBub3JtYWxpemVkIHJlc3BvbnNlIGhlYWRlcnNcbiAgaWYgKGV2ZW50LnN0YXR1cyA9PT0gNDI5KSB7XG4gICAgY29uc29sZS5sb2coXCJyYXRlIGxpbWl0ZWRcIiwgZXZlbnQuaGVhZGVyc1tcInJldHJ5LWFmdGVyXCJdKTtcbiAgfVxufSk7XG5gYGBcblxuSGVhZGVyIGF2YWlsYWJpbGl0eSBkZXBlbmRzIG9uIHByb3ZpZGVyIGFuZCB0cmFuc3BvcnQuIFByb3ZpZGVycyB0aGF0IGFic3RyYWN0IEhUVFAgcmVzcG9uc2VzIG1heSBub3QgZXhwb3NlIGhlYWRlcnMuXG5cbiMjIyBNb2RlbCBFdmVudHNcblxuIyMjIyBtb2RlbF9zZWxlY3RcblxuRmlyZWQgd2hlbiB0aGUgbW9kZWwgY2hhbmdlcyB2aWEgYC9tb2RlbGAgY29tbWFuZCwgbW9kZWwgY3ljbGluZyAoYEN0cmwrUGApLCBvciBzZXNzaW9uIHJlc3RvcmUuXG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwibW9kZWxfc2VsZWN0XCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIC8vIGV2ZW50Lm1vZGVsIC0gbmV3bHkgc2VsZWN0ZWQgbW9kZWxcbiAgLy8gZXZlbnQucHJldmlvdXNNb2RlbCAtIHByZXZpb3VzIG1vZGVsICh1bmRlZmluZWQgaWYgZmlyc3Qgc2VsZWN0aW9uKVxuICAvLyBldmVudC5zb3VyY2UgLSBcInNldFwiIHwgXCJjeWNsZVwiIHwgXCJyZXN0b3JlXCJcblxuICBjb25zdCBwcmV2ID0gZXZlbnQucHJldmlvdXNNb2RlbFxuICAgID8gYCR7ZXZlbnQucHJldmlvdXNNb2RlbC5wcm92aWRlcn0vJHtldmVudC5wcmV2aW91c01vZGVsLmlkfWBcbiAgICA6IFwibm9uZVwiO1xuICBjb25zdCBuZXh0ID0gYCR7ZXZlbnQubW9kZWwucHJvdmlkZXJ9LyR7ZXZlbnQubW9kZWwuaWR9YDtcblxuICBjdHgudWkubm90aWZ5KGBNb2RlbCBjaGFuZ2VkICgke2V2ZW50LnNvdXJjZX0pOiAke3ByZXZ9IC0+ICR7bmV4dH1gLCBcImluZm9cIik7XG59KTtcbmBgYFxuXG5Vc2UgdGhpcyB0byB1cGRhdGUgVUkgZWxlbWVudHMgKHN0YXR1cyBiYXJzLCBmb290ZXJzKSBvciBwZXJmb3JtIG1vZGVsLXNwZWNpZmljIGluaXRpYWxpemF0aW9uIHdoZW4gdGhlIGFjdGl2ZSBtb2RlbCBjaGFuZ2VzLlxuXG4jIyMjIHRoaW5raW5nX2xldmVsX3NlbGVjdFxuXG5GaXJlZCB3aGVuIHRoZSB0aGlua2luZyBsZXZlbCBjaGFuZ2VzLiBUaGlzIGlzIG5vdGlmaWNhdGlvbi1vbmx5OyBoYW5kbGVyIHJldHVybiB2YWx1ZXMgYXJlIGlnbm9yZWQuXG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwidGhpbmtpbmdfbGV2ZWxfc2VsZWN0XCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIC8vIGV2ZW50LmxldmVsIC0gbmV3bHkgc2VsZWN0ZWQgdGhpbmtpbmcgbGV2ZWxcbiAgLy8gZXZlbnQucHJldmlvdXNMZXZlbCAtIHByZXZpb3VzIHRoaW5raW5nIGxldmVsXG5cbiAgY3R4LnVpLnNldFN0YXR1cyhcInRoaW5raW5nXCIsIGB0aGlua2luZzogJHtldmVudC5sZXZlbH1gKTtcbn0pO1xuYGBgXG5cblVzZSB0aGlzIHRvIHVwZGF0ZSBleHRlbnNpb24gVUkgd2hlbiBgcGkuc2V0VGhpbmtpbmdMZXZlbCgpYCwgbW9kZWwgY2hhbmdlcywgb3IgYnVpbHQtaW4gdGhpbmtpbmctbGV2ZWwgY29udHJvbHMgY2hhbmdlIHRoZSBhY3RpdmUgdGhpbmtpbmcgbGV2ZWwuXG5cbiMjIyBUb29sIEV2ZW50c1xuXG4jIyMjIHRvb2xfY2FsbFxuXG5GaXJlZCBhZnRlciBgdG9vbF9leGVjdXRpb25fc3RhcnRgLCBiZWZvcmUgdGhlIHRvb2wgZXhlY3V0ZXMuICoqQ2FuIGJsb2NrLioqIFVzZSBgaXNUb29sQ2FsbEV2ZW50VHlwZWAgdG8gbmFycm93IGFuZCBnZXQgdHlwZWQgaW5wdXRzLlxuXG5CZWZvcmUgYHRvb2xfY2FsbGAgcnVucywgcGkgd2FpdHMgZm9yIHByZXZpb3VzbHkgZW1pdHRlZCBBZ2VudCBldmVudHMgdG8gZmluaXNoIGRyYWluaW5nIHRocm91Z2ggYEFnZW50U2Vzc2lvbmAuIFRoaXMgbWVhbnMgYGN0eC5zZXNzaW9uTWFuYWdlcmAgaXMgdXAgdG8gZGF0ZSB0aHJvdWdoIHRoZSBjdXJyZW50IGFzc2lzdGFudCB0b29sLWNhbGxpbmcgbWVzc2FnZS5cblxuSW4gdGhlIGRlZmF1bHQgcGFyYWxsZWwgdG9vbCBleGVjdXRpb24gbW9kZSwgc2libGluZyB0b29sIGNhbGxzIGZyb20gdGhlIHNhbWUgYXNzaXN0YW50IG1lc3NhZ2UgYXJlIHByZWZsaWdodGVkIHNlcXVlbnRpYWxseSwgdGhlbiBleGVjdXRlZCBjb25jdXJyZW50bHkuIGB0b29sX2NhbGxgIGlzIG5vdCBndWFyYW50ZWVkIHRvIHNlZSBzaWJsaW5nIHRvb2wgcmVzdWx0cyBmcm9tIHRoYXQgc2FtZSBhc3Npc3RhbnQgbWVzc2FnZSBpbiBgY3R4LnNlc3Npb25NYW5hZ2VyYC5cblxuYGV2ZW50LmlucHV0YCBpcyBtdXRhYmxlLiBNdXRhdGUgaXQgaW4gcGxhY2UgdG8gcGF0Y2ggdG9vbCBhcmd1bWVudHMgYmVmb3JlIGV4ZWN1dGlvbi5cblxuQmVoYXZpb3IgZ3VhcmFudGVlczpcbi0gTXV0YXRpb25zIHRvIGBldmVudC5pbnB1dGAgYWZmZWN0IHRoZSBhY3R1YWwgdG9vbCBleGVjdXRpb25cbi0gTGF0ZXIgYHRvb2xfY2FsbGAgaGFuZGxlcnMgc2VlIG11dGF0aW9ucyBtYWRlIGJ5IGVhcmxpZXIgaGFuZGxlcnNcbi0gTm8gcmUtdmFsaWRhdGlvbiBpcyBwZXJmb3JtZWQgYWZ0ZXIgeW91ciBtdXRhdGlvblxuLSBSZXR1cm4gdmFsdWVzIGZyb20gYHRvb2xfY2FsbGAgb25seSBjb250cm9sIGJsb2NraW5nIHZpYSBgeyBibG9jazogdHJ1ZSwgcmVhc29uPzogc3RyaW5nIH1gXG5cbmBgYHR5cGVzY3JpcHRcbmltcG9ydCB7IGlzVG9vbENhbGxFdmVudFR5cGUgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudFwiO1xuXG5waS5vbihcInRvb2xfY2FsbFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAvLyBldmVudC50b29sTmFtZSAtIFwiYmFzaFwiLCBcInJlYWRcIiwgXCJ3cml0ZVwiLCBcImVkaXRcIiwgZXRjLlxuICAvLyBldmVudC50b29sQ2FsbElkXG4gIC8vIGV2ZW50LmlucHV0IC0gdG9vbCBwYXJhbWV0ZXJzIChtdXRhYmxlKVxuXG4gIC8vIEJ1aWx0LWluIHRvb2xzOiBubyB0eXBlIHBhcmFtcyBuZWVkZWRcbiAgaWYgKGlzVG9vbENhbGxFdmVudFR5cGUoXCJiYXNoXCIsIGV2ZW50KSkge1xuICAgIC8vIGV2ZW50LmlucHV0IGlzIHsgY29tbWFuZDogc3RyaW5nOyB0aW1lb3V0PzogbnVtYmVyIH1cbiAgICBldmVudC5pbnB1dC5jb21tYW5kID0gYHNvdXJjZSB+Ly5wcm9maWxlXFxuJHtldmVudC5pbnB1dC5jb21tYW5kfWA7XG5cbiAgICBpZiAoZXZlbnQuaW5wdXQuY29tbWFuZC5pbmNsdWRlcyhcInJtIC1yZlwiKSkge1xuICAgICAgcmV0dXJuIHsgYmxvY2s6IHRydWUsIHJlYXNvbjogXCJEYW5nZXJvdXMgY29tbWFuZFwiIH07XG4gICAgfVxuICB9XG5cbiAgaWYgKGlzVG9vbENhbGxFdmVudFR5cGUoXCJyZWFkXCIsIGV2ZW50KSkge1xuICAgIC8vIGV2ZW50LmlucHV0IGlzIHsgcGF0aDogc3RyaW5nOyBvZmZzZXQ/OiBudW1iZXI7IGxpbWl0PzogbnVtYmVyIH1cbiAgICBjb25zb2xlLmxvZyhgUmVhZGluZzogJHtldmVudC5pbnB1dC5wYXRofWApO1xuICB9XG59KTtcbmBgYFxuXG4jIyMjIFR5cGluZyBjdXN0b20gdG9vbCBpbnB1dFxuXG5DdXN0b20gdG9vbHMgc2hvdWxkIGV4cG9ydCB0aGVpciBpbnB1dCB0eXBlOlxuXG5gYGB0eXBlc2NyaXB0XG4vLyBteS1leHRlbnNpb24udHNcbmV4cG9ydCB0eXBlIE15VG9vbElucHV0ID0gU3RhdGljPHR5cGVvZiBteVRvb2xTY2hlbWE+O1xuYGBgXG5cblVzZSBgaXNUb29sQ2FsbEV2ZW50VHlwZWAgd2l0aCBleHBsaWNpdCB0eXBlIHBhcmFtZXRlcnM6XG5cbmBgYHR5cGVzY3JpcHRcbmltcG9ydCB7IGlzVG9vbENhbGxFdmVudFR5cGUgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudFwiO1xuaW1wb3J0IHR5cGUgeyBNeVRvb2xJbnB1dCB9IGZyb20gXCJteS1leHRlbnNpb25cIjtcblxucGkub24oXCJ0b29sX2NhbGxcIiwgKGV2ZW50KSA9PiB7XG4gIGlmIChpc1Rvb2xDYWxsRXZlbnRUeXBlPFwibXlfdG9vbFwiLCBNeVRvb2xJbnB1dD4oXCJteV90b29sXCIsIGV2ZW50KSkge1xuICAgIGV2ZW50LmlucHV0LmFjdGlvbjsgIC8vIHR5cGVkXG4gIH1cbn0pO1xuYGBgXG5cbiMjIyMgdG9vbF9yZXN1bHRcblxuRmlyZWQgYWZ0ZXIgdG9vbCBleGVjdXRpb24gZmluaXNoZXMgYW5kIGJlZm9yZSBgdG9vbF9leGVjdXRpb25fZW5kYCBwbHVzIHRoZSBmaW5hbCB0b29sIHJlc3VsdCBtZXNzYWdlIGV2ZW50cyBhcmUgZW1pdHRlZC4gKipDYW4gbW9kaWZ5IHJlc3VsdC4qKlxuXG5JbiBwYXJhbGxlbCB0b29sIG1vZGUsIGB0b29sX3Jlc3VsdGAgYW5kIGB0b29sX2V4ZWN1dGlvbl9lbmRgIG1heSBpbnRlcmxlYXZlIGluIHRvb2wgY29tcGxldGlvbiBvcmRlciwgd2hpbGUgZmluYWwgYHRvb2xSZXN1bHRgIG1lc3NhZ2UgZXZlbnRzIGFyZSBzdGlsbCBlbWl0dGVkIGxhdGVyIGluIGFzc2lzdGFudCBzb3VyY2Ugb3JkZXIuXG5cbmB0b29sX3Jlc3VsdGAgaGFuZGxlcnMgY2hhaW4gbGlrZSBtaWRkbGV3YXJlOlxuLSBIYW5kbGVycyBydW4gaW4gZXh0ZW5zaW9uIGxvYWQgb3JkZXJcbi0gRWFjaCBoYW5kbGVyIHNlZXMgdGhlIGxhdGVzdCByZXN1bHQgYWZ0ZXIgcHJldmlvdXMgaGFuZGxlciBjaGFuZ2VzXG4tIEhhbmRsZXJzIGNhbiByZXR1cm4gcGFydGlhbCBwYXRjaGVzIChgY29udGVudGAsIGBkZXRhaWxzYCwgb3IgYGlzRXJyb3JgKTsgb21pdHRlZCBmaWVsZHMga2VlcCB0aGVpciBjdXJyZW50IHZhbHVlc1xuXG5Vc2UgYGN0eC5zaWduYWxgIGZvciBuZXN0ZWQgYXN5bmMgd29yayBpbnNpZGUgdGhlIGhhbmRsZXIuIFRoaXMgbGV0cyBFc2MgY2FuY2VsIG1vZGVsIGNhbGxzLCBgZmV0Y2goKWAsIGFuZCBvdGhlciBhYm9ydC1hd2FyZSBvcGVyYXRpb25zIHN0YXJ0ZWQgYnkgdGhlIGV4dGVuc2lvbi5cblxuYGBgdHlwZXNjcmlwdFxuaW1wb3J0IHsgaXNCYXNoVG9vbFJlc3VsdCB9IGZyb20gXCJAZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50XCI7XG5cbnBpLm9uKFwidG9vbF9yZXN1bHRcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQudG9vbE5hbWUsIGV2ZW50LnRvb2xDYWxsSWQsIGV2ZW50LmlucHV0XG4gIC8vIGV2ZW50LmNvbnRlbnQsIGV2ZW50LmRldGFpbHMsIGV2ZW50LmlzRXJyb3JcblxuICBpZiAoaXNCYXNoVG9vbFJlc3VsdChldmVudCkpIHtcbiAgICAvLyBldmVudC5kZXRhaWxzIGlzIHR5cGVkIGFzIEJhc2hUb29sRGV0YWlsc1xuICB9XG5cbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChcImh0dHBzOi8vZXhhbXBsZS5jb20vc3VtbWFyaXplXCIsIHtcbiAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHsgY29udGVudDogZXZlbnQuY29udGVudCB9KSxcbiAgICBzaWduYWw6IGN0eC5zaWduYWwsXG4gIH0pO1xuXG4gIC8vIE1vZGlmeSByZXN1bHQ6XG4gIHJldHVybiB7IGNvbnRlbnQ6IFsuLi5dLCBkZXRhaWxzOiB7Li4ufSwgaXNFcnJvcjogZmFsc2UgfTtcbn0pO1xuYGBgXG5cbiMjIyBVc2VyIEJhc2ggRXZlbnRzXG5cbiMjIyMgdXNlcl9iYXNoXG5cbkZpcmVkIHdoZW4gdXNlciBleGVjdXRlcyBgIWAgb3IgYCEhYCBjb21tYW5kcy4gKipDYW4gaW50ZXJjZXB0LioqXG5cbmBgYHR5cGVzY3JpcHRcbmltcG9ydCB7IGNyZWF0ZUxvY2FsQmFzaE9wZXJhdGlvbnMgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudFwiO1xuXG5waS5vbihcInVzZXJfYmFzaFwiLCAoZXZlbnQsIGN0eCkgPT4ge1xuICAvLyBldmVudC5jb21tYW5kIC0gdGhlIGJhc2ggY29tbWFuZFxuICAvLyBldmVudC5leGNsdWRlRnJvbUNvbnRleHQgLSB0cnVlIGlmICEhIHByZWZpeFxuICAvLyBldmVudC5jd2QgLSB3b3JraW5nIGRpcmVjdG9yeVxuXG4gIC8vIE9wdGlvbiAxOiBQcm92aWRlIGN1c3RvbSBvcGVyYXRpb25zIChlLmcuLCBTU0gpXG4gIHJldHVybiB7IG9wZXJhdGlvbnM6IHJlbW90ZUJhc2hPcHMgfTtcblxuICAvLyBPcHRpb24gMjogV3JhcCBwaSdzIGJ1aWx0LWluIGxvY2FsIGJhc2ggYmFja2VuZFxuICBjb25zdCBsb2NhbCA9IGNyZWF0ZUxvY2FsQmFzaE9wZXJhdGlvbnMoKTtcbiAgcmV0dXJuIHtcbiAgICBvcGVyYXRpb25zOiB7XG4gICAgICBleGVjKGNvbW1hbmQsIGN3ZCwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gbG9jYWwuZXhlYyhgc291cmNlIH4vLnByb2ZpbGVcXG4ke2NvbW1hbmR9YCwgY3dkLCBvcHRpb25zKTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgLy8gT3B0aW9uIDM6IEZ1bGwgcmVwbGFjZW1lbnQgLSByZXR1cm4gcmVzdWx0IGRpcmVjdGx5XG4gIHJldHVybiB7IHJlc3VsdDogeyBvdXRwdXQ6IFwiLi4uXCIsIGV4aXRDb2RlOiAwLCBjYW5jZWxsZWQ6IGZhbHNlLCB0cnVuY2F0ZWQ6IGZhbHNlIH0gfTtcbn0pO1xuYGBgXG5cbiMjIyBJbnB1dCBFdmVudHNcblxuIyMjIyBpbnB1dFxuXG5GaXJlZCB3aGVuIHVzZXIgaW5wdXQgaXMgcmVjZWl2ZWQsIGFmdGVyIGV4dGVuc2lvbiBjb21tYW5kcyBhcmUgY2hlY2tlZCBidXQgYmVmb3JlIHNraWxsIGFuZCB0ZW1wbGF0ZSBleHBhbnNpb24uIFRoZSBldmVudCBzZWVzIHRoZSByYXcgaW5wdXQgdGV4dCwgc28gYC9za2lsbDpmb29gIGFuZCBgL3RlbXBsYXRlYCBhcmUgbm90IHlldCBleHBhbmRlZC5cblxuKipQcm9jZXNzaW5nIG9yZGVyOioqXG4xLiBFeHRlbnNpb24gY29tbWFuZHMgKGAvY21kYCkgY2hlY2tlZCBmaXJzdCAtIGlmIGZvdW5kLCBoYW5kbGVyIHJ1bnMgYW5kIGlucHV0IGV2ZW50IGlzIHNraXBwZWRcbjIuIGBpbnB1dGAgZXZlbnQgZmlyZXMgLSBjYW4gaW50ZXJjZXB0LCB0cmFuc2Zvcm0sIG9yIGhhbmRsZVxuMy4gSWYgbm90IGhhbmRsZWQ6IHNraWxsIGNvbW1hbmRzIChgL3NraWxsOm5hbWVgKSBleHBhbmRlZCB0byBza2lsbCBjb250ZW50XG40LiBJZiBub3QgaGFuZGxlZDogcHJvbXB0IHRlbXBsYXRlcyAoYC90ZW1wbGF0ZWApIGV4cGFuZGVkIHRvIHRlbXBsYXRlIGNvbnRlbnRcbjUuIEFnZW50IHByb2Nlc3NpbmcgYmVnaW5zIChgYmVmb3JlX2FnZW50X3N0YXJ0YCwgZXRjLilcblxuYGBgdHlwZXNjcmlwdFxucGkub24oXCJpbnB1dFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAvLyBldmVudC50ZXh0IC0gcmF3IGlucHV0IChiZWZvcmUgc2tpbGwvdGVtcGxhdGUgZXhwYW5zaW9uKVxuICAvLyBldmVudC5pbWFnZXMgLSBhdHRhY2hlZCBpbWFnZXMsIGlmIGFueVxuICAvLyBldmVudC5zb3VyY2UgLSBcImludGVyYWN0aXZlXCIgKHR5cGVkKSwgXCJycGNcIiAoQVBJKSwgb3IgXCJleHRlbnNpb25cIiAodmlhIHNlbmRVc2VyTWVzc2FnZSlcbiAgLy8gZXZlbnQuc3RyZWFtaW5nQmVoYXZpb3IgLSBcInN0ZWVyXCIgfCBcImZvbGxvd1VwXCIgfCB1bmRlZmluZWRcbiAgLy8gICB1bmRlZmluZWQgd2hlbiBpZGxlLCBcInN0ZWVyXCIgZm9yIG1pZC1zdHJlYW0gaW50ZXJydXB0cyxcbiAgLy8gICBcImZvbGxvd1VwXCIgZm9yIG1lc3NhZ2VzIHF1ZXVlZCB1bnRpbCB0aGUgYWdlbnQgZmluaXNoZXNcblxuICAvLyBUcmFuc2Zvcm06IHJld3JpdGUgaW5wdXQgYmVmb3JlIGV4cGFuc2lvblxuICBpZiAoZXZlbnQudGV4dC5zdGFydHNXaXRoKFwiP3F1aWNrIFwiKSlcbiAgICByZXR1cm4geyBhY3Rpb246IFwidHJhbnNmb3JtXCIsIHRleHQ6IGBSZXNwb25kIGJyaWVmbHk6ICR7ZXZlbnQudGV4dC5zbGljZSg3KX1gIH07XG5cbiAgLy8gSGFuZGxlOiByZXNwb25kIHdpdGhvdXQgTExNIChleHRlbnNpb24gc2hvd3MgaXRzIG93biBmZWVkYmFjaylcbiAgaWYgKGV2ZW50LnRleHQgPT09IFwicGluZ1wiKSB7XG4gICAgY3R4LnVpLm5vdGlmeShcInBvbmdcIiwgXCJpbmZvXCIpO1xuICAgIHJldHVybiB7IGFjdGlvbjogXCJoYW5kbGVkXCIgfTtcbiAgfVxuXG4gIC8vIFJvdXRlIGJ5IHNvdXJjZTogc2tpcCBwcm9jZXNzaW5nIGZvciBleHRlbnNpb24taW5qZWN0ZWQgbWVzc2FnZXNcbiAgaWYgKGV2ZW50LnNvdXJjZSA9PT0gXCJleHRlbnNpb25cIikgcmV0dXJuIHsgYWN0aW9uOiBcImNvbnRpbnVlXCIgfTtcblxuICAvLyBJbnRlcmNlcHQgc2tpbGwgY29tbWFuZHMgYmVmb3JlIGV4cGFuc2lvblxuICBpZiAoZXZlbnQudGV4dC5zdGFydHNXaXRoKFwiL3NraWxsOlwiKSkge1xuICAgIC8vIENvdWxkIHRyYW5zZm9ybSwgYmxvY2ssIG9yIGxldCBwYXNzIHRocm91Z2hcbiAgfVxuXG4gIHJldHVybiB7IGFjdGlvbjogXCJjb250aW51ZVwiIH07ICAvLyBEZWZhdWx0OiBwYXNzIHRocm91Z2ggdG8gZXhwYW5zaW9uXG59KTtcbmBgYFxuXG4qKlJlc3VsdHM6Kipcbi0gYGNvbnRpbnVlYCAtIHBhc3MgdGhyb3VnaCB1bmNoYW5nZWQgKGRlZmF1bHQgaWYgaGFuZGxlciByZXR1cm5zIG5vdGhpbmcpXG4tIGB0cmFuc2Zvcm1gIC0gbW9kaWZ5IHRleHQvaW1hZ2VzLCB0aGVuIGNvbnRpbnVlIHRvIGV4cGFuc2lvblxuLSBgaGFuZGxlZGAgLSBza2lwIGFnZW50IGVudGlyZWx5IChmaXJzdCBoYW5kbGVyIHRvIHJldHVybiB0aGlzIHdpbnMpXG5cblRyYW5zZm9ybXMgY2hhaW4gYWNyb3NzIGhhbmRsZXJzLiBTZWUgW2lucHV0LXRyYW5zZm9ybS50c10oLi4vZXhhbXBsZXMvZXh0ZW5zaW9ucy9pbnB1dC10cmFuc2Zvcm0udHMpIGFuZCBbaW5wdXQtdHJhbnNmb3JtLXN0cmVhbWluZy50c10oLi4vZXhhbXBsZXMvZXh0ZW5zaW9ucy9pbnB1dC10cmFuc2Zvcm0tc3RyZWFtaW5nLnRzKSBmb3IgYHN0cmVhbWluZ0JlaGF2aW9yYC1hd2FyZSByb3V0aW5nLlxuXG4jIyBFeHRlbnNpb25Db250ZXh0XG5cbkFsbCBoYW5kbGVycyByZWNlaXZlIGBjdHg6IEV4dGVuc2lvbkNvbnRleHRgLlxuXG4jIyMgY3R4LnVpXG5cblVJIG1ldGhvZHMgZm9yIHVzZXIgaW50ZXJhY3Rpb24uIFNlZSBbQ3VzdG9tIFVJXSgjY3VzdG9tLXVpKSBmb3IgZnVsbCBkZXRhaWxzLlxuXG4jIyMgY3R4Lm1vZGVcblxuQ3VycmVudCBydW4gbW9kZTogYFwidHVpXCJgLCBgXCJycGNcImAsIGBcImpzb25cImAsIG9yIGBcInByaW50XCJgLiBVc2UgYGN0eC5tb2RlID09PSBcInR1aVwiYCB0byBndWFyZCB0ZXJtaW5hbC1vbmx5IGZlYXR1cmVzIHN1Y2ggYXMgYGN1c3RvbSgpYCwgY29tcG9uZW50IGZhY3RvcmllcywgdGVybWluYWwgaW5wdXQsIGFuZCBkaXJlY3QgVFVJIHJlbmRlcmluZy5cblxuIyMjIGN0eC5oYXNVSVxuXG5gdHJ1ZWAgaW4gVFVJIGFuZCBSUEMgbW9kZXMuIGBmYWxzZWAgaW4gcHJpbnQgbW9kZSAoYC1wYCkgYW5kIEpTT04gbW9kZS4gVXNlIHRoaXMgdG8gZ3VhcmQgZGlhbG9nIG1ldGhvZHMgKGBzZWxlY3RgLCBgY29uZmlybWAsIGBpbnB1dGAsIGBlZGl0b3JgKSBhbmQgZmlyZS1hbmQtZm9yZ2V0IG1ldGhvZHMgKGBub3RpZnlgLCBgc2V0U3RhdHVzYCwgYHNldFdpZGdldGAsIGBzZXRUaXRsZWAsIGBzZXRFZGl0b3JUZXh0YCkgdGhhdCB3b3JrIGluIGJvdGggVFVJIGFuZCBSUEMgbW9kZXMuIEluIFJQQyBtb2RlLCBzb21lIFRVSS1zcGVjaWZpYyBtZXRob2RzIGFyZSBuby1vcHMgb3IgcmV0dXJuIGRlZmF1bHRzIChzZWUgW3JwYy5tZF0ocnBjLm1kI2V4dGVuc2lvbi11aS1wcm90b2NvbCkpLlxuXG4jIyMgY3R4LmN3ZFxuXG5DdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5LlxuXG5Vc2UgYENPTkZJR19ESVJfTkFNRWAgaW5zdGVhZCBvZiBoYXJkY29kaW5nIGAucGlgIHdoZW4gY29uc3RydWN0aW5nIHByb2plY3QtbG9jYWwgY29uZmlnIHBhdGhzLiBSZWJyYW5kZWQgZGlzdHJpYnV0aW9ucyBjYW4gdXNlIGEgZGlmZmVyZW50IGNvbmZpZyBkaXJlY3RvcnkgbmFtZS5cblxuYGBgdHlwZXNjcmlwdFxuaW1wb3J0IHsgQ09ORklHX0RJUl9OQU1FLCB0eXBlIEV4dGVuc2lvbkFQSSB9IGZyb20gXCJAZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50XCI7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiAocGk6IEV4dGVuc2lvbkFQSSkge1xuICBwaS5vbihcInNlc3Npb25fc3RhcnRcIiwgKF9ldmVudCwgY3R4KSA9PiB7XG4gICAgY29uc3QgcHJvamVjdENvbmZpZ1BhdGggPSBqb2luKGN0eC5jd2QsIENPTkZJR19ESVJfTkFNRSwgXCJteS1leHRlbnNpb24uanNvblwiKTtcbiAgICAvLyAuLi5cbiAgfSk7XG59XG5gYGBcblxuIyMjIGN0eC5pc1Byb2plY3RUcnVzdGVkKClcblxuUmV0dXJucyB3aGV0aGVyIHByb2plY3QtbG9jYWwgdHJ1c3QgaXMgYWN0aXZlIGZvciB0aGUgY3VycmVudCBzZXNzaW9uIGNvbnRleHQuIFRoaXMgaW5jbHVkZXMgdGVtcG9yYXJ5IHRydXN0IGRlY2lzaW9ucyBhbmQgQ0xJIHRydXN0IG92ZXJyaWRlcywgbm90IGp1c3Qgc2F2ZWQgZGVjaXNpb25zIGluIHRoZSBnbG9iYWwgdHJ1c3Qgc3RvcmUuXG5cblVzZSB0aGlzIGJlZm9yZSByZWFkaW5nIHByb2plY3QtbG9jYWwgZXh0ZW5zaW9uIGNvbmZpZ3VyYXRpb24gdGhhdCBzaG91bGQgb25seSBiZSBob25vcmVkIGZvciB0cnVzdGVkIHByb2plY3RzLlxuXG4jIyMgY3R4LnNlc3Npb25NYW5hZ2VyXG5cblJlYWQtb25seSBhY2Nlc3MgdG8gc2Vzc2lvbiBzdGF0ZS4gU2VlIFtTZXNzaW9uIEZvcm1hdF0oc2Vzc2lvbi1mb3JtYXQubWQpIGZvciB0aGUgZnVsbCBTZXNzaW9uTWFuYWdlciBBUEkgYW5kIGVudHJ5IHR5cGVzLlxuXG5Gb3IgYHRvb2xfY2FsbGAsIHRoaXMgc3RhdGUgaXMgc3luY2hyb25pemVkIHRocm91Z2ggdGhlIGN1cnJlbnQgYXNzaXN0YW50IG1lc3NhZ2UgYmVmb3JlIGhhbmRsZXJzIHJ1bi4gSW4gcGFyYWxsZWwgdG9vbCBleGVjdXRpb24gbW9kZSBpdCBpcyBzdGlsbCBub3QgZ3VhcmFudGVlZCB0byBpbmNsdWRlIHNpYmxpbmcgdG9vbCByZXN1bHRzIGZyb20gdGhlIHNhbWUgYXNzaXN0YW50IG1lc3NhZ2UuXG5cbmBgYHR5cGVzY3JpcHRcbmN0eC5zZXNzaW9uTWFuYWdlci5nZXRFbnRyaWVzKCkgICAgICAgLy8gQWxsIGVudHJpZXNcbmN0eC5zZXNzaW9uTWFuYWdlci5nZXRCcmFuY2goKSAgICAgICAgLy8gQ3VycmVudCBicmFuY2hcbmN0eC5zZXNzaW9uTWFuYWdlci5nZXRMZWFmSWQoKSAgICAgICAgLy8gQ3VycmVudCBsZWFmIGVudHJ5IElEXG5gYGBcblxuIyMjIGN0eC5tb2RlbFJlZ2lzdHJ5IC8gY3R4Lm1vZGVsXG5cbkFjY2VzcyB0byBtb2RlbHMgYW5kIEFQSSBrZXlzLlxuXG4jIyMgY3R4LnNpZ25hbFxuXG5UaGUgY3VycmVudCBhZ2VudCBhYm9ydCBzaWduYWwsIG9yIGB1bmRlZmluZWRgIHdoZW4gbm8gYWdlbnQgdHVybiBpcyBhY3RpdmUuXG5cblVzZSB0aGlzIGZvciBhYm9ydC1hd2FyZSBuZXN0ZWQgd29yayBzdGFydGVkIGJ5IGV4dGVuc2lvbiBoYW5kbGVycywgZm9yIGV4YW1wbGU6XG4tIGBmZXRjaCguLi4sIHsgc2lnbmFsOiBjdHguc2lnbmFsIH0pYFxuLSBtb2RlbCBjYWxscyB0aGF0IGFjY2VwdCBgc2lnbmFsYFxuLSBmaWxlIG9yIHByb2Nlc3MgaGVscGVycyB0aGF0IGFjY2VwdCBgQWJvcnRTaWduYWxgXG5cbmBjdHguc2lnbmFsYCBpcyB0eXBpY2FsbHkgZGVmaW5lZCBkdXJpbmcgYWN0aXZlIHR1cm4gZXZlbnRzIHN1Y2ggYXMgYHRvb2xfY2FsbGAsIGB0b29sX3Jlc3VsdGAsIGBtZXNzYWdlX3VwZGF0ZWAsIGFuZCBgdHVybl9lbmRgLlxuSXQgaXMgdXN1YWxseSBgdW5kZWZpbmVkYCBpbiBpZGxlIG9yIG5vbi10dXJuIGNvbnRleHRzIHN1Y2ggYXMgc2Vzc2lvbiBldmVudHMsIGV4dGVuc2lvbiBjb21tYW5kcywgYW5kIHNob3J0Y3V0cyBmaXJlZCB3aGlsZSBwaSBpcyBpZGxlLlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcInRvb2xfcmVzdWx0XCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goXCJodHRwczovL2V4YW1wbGUuY29tL2FwaVwiLCB7XG4gICAgbWV0aG9kOiBcIlBPU1RcIixcbiAgICBib2R5OiBKU09OLnN0cmluZ2lmeShldmVudCksXG4gICAgc2lnbmFsOiBjdHguc2lnbmFsLFxuICB9KTtcblxuICBjb25zdCBkYXRhID0gYXdhaXQgcmVzcG9uc2UuanNvbigpO1xuICByZXR1cm4geyBkZXRhaWxzOiBkYXRhIH07XG59KTtcbmBgYFxuXG4jIyMgY3R4LmlzSWRsZSgpIC8gY3R4LmFib3J0KCkgLyBjdHguaGFzUGVuZGluZ01lc3NhZ2VzKClcblxuQ29udHJvbCBmbG93IGhlbHBlcnMuXG5cbiMjIyBjdHguc2h1dGRvd24oKVxuXG5SZXF1ZXN0IGEgZ3JhY2VmdWwgc2h1dGRvd24gb2YgcGkuXG5cbi0gKipJbnRlcmFjdGl2ZSBtb2RlOioqIERlZmVycmVkIHVudGlsIHRoZSBhZ2VudCBiZWNvbWVzIGlkbGUgKGFmdGVyIHByb2Nlc3NpbmcgYWxsIHF1ZXVlZCBzdGVlcmluZyBhbmQgZm9sbG93LXVwIG1lc3NhZ2VzKS5cbi0gKipSUEMgbW9kZToqKiBEZWZlcnJlZCB1bnRpbCB0aGUgbmV4dCBpZGxlIHN0YXRlIChhZnRlciBjb21wbGV0aW5nIHRoZSBjdXJyZW50IGNvbW1hbmQgcmVzcG9uc2UsIHdoZW4gd2FpdGluZyBmb3IgdGhlIG5leHQgY29tbWFuZCkuXG4tICoqUHJpbnQgbW9kZToqKiBOby1vcC4gVGhlIHByb2Nlc3MgZXhpdHMgYXV0b21hdGljYWxseSB3aGVuIGFsbCBwcm9tcHRzIGFyZSBwcm9jZXNzZWQuXG5cbkVtaXRzIGBzZXNzaW9uX3NodXRkb3duYCBldmVudCB0byBhbGwgZXh0ZW5zaW9ucyBiZWZvcmUgZXhpdGluZy4gQXZhaWxhYmxlIGluIGFsbCBjb250ZXh0cyAoZXZlbnQgaGFuZGxlcnMsIHRvb2xzLCBjb21tYW5kcywgc2hvcnRjdXRzKS5cblxuYGBgdHlwZXNjcmlwdFxucGkub24oXCJ0b29sX2NhbGxcIiwgKGV2ZW50LCBjdHgpID0+IHtcbiAgaWYgKGlzRmF0YWwoZXZlbnQuaW5wdXQpKSB7XG4gICAgY3R4LnNodXRkb3duKCk7XG4gIH1cbn0pO1xuYGBgXG5cbiMjIyBjdHguZ2V0Q29udGV4dFVzYWdlKClcblxuUmV0dXJucyBjdXJyZW50IGNvbnRleHQgdXNhZ2UgZm9yIHRoZSBhY3RpdmUgbW9kZWwuIFVzZXMgbGFzdCBhc3Npc3RhbnQgdXNhZ2Ugd2hlbiBhdmFpbGFibGUsIHRoZW4gZXN0aW1hdGVzIHRva2VucyBmb3IgdHJhaWxpbmcgbWVzc2FnZXMuXG5cbmBgYHR5cGVzY3JpcHRcbmNvbnN0IHVzYWdlID0gY3R4LmdldENvbnRleHRVc2FnZSgpO1xuaWYgKHVzYWdlICYmIHVzYWdlLnRva2VucyA+IDEwMF8wMDApIHtcbiAgLy8gLi4uXG59XG5gYGBcblxuIyMjIGN0eC5jb21wYWN0KClcblxuVHJpZ2dlciBjb21wYWN0aW9uIHdpdGhvdXQgYXdhaXRpbmcgY29tcGxldGlvbi4gVXNlIGBvbkNvbXBsZXRlYCBhbmQgYG9uRXJyb3JgIGZvciBmb2xsb3ctdXAgYWN0aW9ucy5cblxuYGBgdHlwZXNjcmlwdFxuY3R4LmNvbXBhY3Qoe1xuICBjdXN0b21JbnN0cnVjdGlvbnM6IFwiRm9jdXMgb24gcmVjZW50IGNoYW5nZXNcIixcbiAgb25Db21wbGV0ZTogKHJlc3VsdCkgPT4ge1xuICAgIGN0eC51aS5ub3RpZnkoXCJDb21wYWN0aW9uIGNvbXBsZXRlZFwiLCBcImluZm9cIik7XG4gIH0sXG4gIG9uRXJyb3I6IChlcnJvcikgPT4ge1xuICAgIGN0eC51aS5ub3RpZnkoYENvbXBhY3Rpb24gZmFpbGVkOiAke2Vycm9yLm1lc3NhZ2V9YCwgXCJlcnJvclwiKTtcbiAgfSxcbn0pO1xuYGBgXG5cbiMjIyBjdHguZ2V0U3lzdGVtUHJvbXB0KClcblxuUmV0dXJucyBQaSdzIGN1cnJlbnQgc3lzdGVtIHByb21wdCBzdHJpbmcuXG5cbi0gRHVyaW5nIGBiZWZvcmVfYWdlbnRfc3RhcnRgLCB0aGlzIHJlZmxlY3RzIGNoYWluZWQgc3lzdGVtLXByb21wdCBjaGFuZ2VzIG1hZGUgc28gZmFyIGZvciB0aGUgY3VycmVudCB0dXJuLlxuLSBJdCBkb2VzIG5vdCBpbmNsdWRlIGxhdGVyIGBjb250ZXh0YCBtZXNzYWdlIG11dGF0aW9ucy5cbi0gSXQgZG9lcyBub3QgaW5jbHVkZSBgYmVmb3JlX3Byb3ZpZGVyX3JlcXVlc3RgIHBheWxvYWQgcmV3cml0ZXMuXG4tIElmIGxhdGVyLWxvYWRlZCBleHRlbnNpb25zIHJ1biBhZnRlciB5b3VycywgdGhleSBjYW4gc3RpbGwgY2hhbmdlIHdoYXQgaXMgdWx0aW1hdGVseSBzZW50LlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcImJlZm9yZV9hZ2VudF9zdGFydFwiLCAoZXZlbnQsIGN0eCkgPT4ge1xuICBjb25zdCBwcm9tcHQgPSBjdHguZ2V0U3lzdGVtUHJvbXB0KCk7XG4gIGNvbnNvbGUubG9nKGBTeXN0ZW0gcHJvbXB0IGxlbmd0aDogJHtwcm9tcHQubGVuZ3RofWApO1xufSk7XG5gYGBcblxuIyMgRXh0ZW5zaW9uQ29tbWFuZENvbnRleHRcblxuQ29tbWFuZCBoYW5kbGVycyByZWNlaXZlIGBFeHRlbnNpb25Db21tYW5kQ29udGV4dGAsIHdoaWNoIGV4dGVuZHMgYEV4dGVuc2lvbkNvbnRleHRgIHdpdGggc2Vzc2lvbiBjb250cm9sIG1ldGhvZHMuIFRoZXNlIGFyZSBvbmx5IGF2YWlsYWJsZSBpbiBjb21tYW5kcyBiZWNhdXNlIHRoZXkgY2FuIGRlYWRsb2NrIGlmIGNhbGxlZCBmcm9tIGV2ZW50IGhhbmRsZXJzLlxuXG4jIyMgY3R4LmdldFN5c3RlbVByb21wdE9wdGlvbnMoKVxuXG5SZXR1cm5zIHRoZSBiYXNlIGlucHV0cyBQaSBjdXJyZW50bHkgdXNlcyB0byBidWlsZCB0aGUgc3lzdGVtIHByb21wdC5cblxuYGBgdHlwZXNjcmlwdFxuY29uc3Qgb3B0aW9ucyA9IGN0eC5nZXRTeXN0ZW1Qcm9tcHRPcHRpb25zKCk7XG5jb25zdCBjb250ZXh0UGF0aHMgPSBvcHRpb25zLmNvbnRleHRGaWxlcz8ubWFwKChmaWxlKSA9PiBmaWxlLnBhdGgpID8/IFtdO1xuYGBgXG5cblRoaXMgaGFzIHRoZSBzYW1lIHNoYXBlIGFuZCBtdXRhYmlsaXR5IGFzIGBiZWZvcmVfYWdlbnRfc3RhcnRgIGBldmVudC5zeXN0ZW1Qcm9tcHRPcHRpb25zYDogY3VzdG9tIHByb21wdCwgYWN0aXZlIHRvb2xzLCB0b29sIHNuaXBwZXRzLCBwcm9tcHQgZ3VpZGVsaW5lcywgYXBwZW5kZWQgc3lzdGVtIHByb21wdCB0ZXh0LCBjd2QsIGxvYWRlZCBjb250ZXh0IGZpbGVzLCBhbmQgbG9hZGVkIHNraWxscy4gSXQgbWF5IGluY2x1ZGUgZnVsbCBjb250ZXh0IGZpbGUgY29udGVudHMsIHNvIHRyZWF0IGl0IGFzIHNlbnNpdGl2ZSBleHRlbnNpb24tbG9jYWwgZGF0YSBhbmQgYXZvaWQgZXhwb3NpbmcgaXQgdGhyb3VnaCBjb21tYW5kIGxpc3RzLCBsb2dzLCBvciBhdXRvY29tcGxldGUgbWV0YWRhdGEuXG5cblRoaXMgcmVwb3J0cyB0aGUgY3VycmVudCBiYXNlIHByb21wdCBpbnB1dHMuIEl0IGRvZXMgbm90IGluY2x1ZGUgcGVyLXR1cm4gYGJlZm9yZV9hZ2VudF9zdGFydGAgY2hhaW5lZCBzeXN0ZW0tcHJvbXB0IGNoYW5nZXMsIGxhdGVyIGBjb250ZXh0YCBldmVudCBtZXNzYWdlIG11dGF0aW9ucywgb3IgYGJlZm9yZV9wcm92aWRlcl9yZXF1ZXN0YCBwYXlsb2FkIHJld3JpdGVzLlxuXG4jIyMgY3R4LndhaXRGb3JJZGxlKClcblxuV2FpdCBmb3IgdGhlIGFnZW50IHRvIGZpbmlzaCBzdHJlYW1pbmc6XG5cbmBgYHR5cGVzY3JpcHRcbnBpLnJlZ2lzdGVyQ29tbWFuZChcIm15LWNtZFwiLCB7XG4gIGhhbmRsZXI6IGFzeW5jIChhcmdzLCBjdHgpID0+IHtcbiAgICBhd2FpdCBjdHgud2FpdEZvcklkbGUoKTtcbiAgICAvLyBBZ2VudCBpcyBub3cgaWRsZSwgc2FmZSB0byBtb2RpZnkgc2Vzc2lvblxuICB9LFxufSk7XG5gYGBcblxuIyMjIGN0eC5uZXdTZXNzaW9uKG9wdGlvbnM/KVxuXG5DcmVhdGUgYSBuZXcgc2Vzc2lvbjpcblxuYGBgdHlwZXNjcmlwdFxuY29uc3QgcGFyZW50U2Vzc2lvbiA9IGN0eC5zZXNzaW9uTWFuYWdlci5nZXRTZXNzaW9uRmlsZSgpO1xuY29uc3Qga2lja29mZiA9IFwiQ29udGludWUgaW4gdGhlIHJlcGxhY2VtZW50IHNlc3Npb25cIjtcblxuY29uc3QgcmVzdWx0ID0gYXdhaXQgY3R4Lm5ld1Nlc3Npb24oe1xuICBwYXJlbnRTZXNzaW9uLFxuICBzZXR1cDogYXN5bmMgKHNtKSA9PiB7XG4gICAgc20uYXBwZW5kTWVzc2FnZSh7XG4gICAgICByb2xlOiBcInVzZXJcIixcbiAgICAgIGNvbnRlbnQ6IFt7IHR5cGU6IFwidGV4dFwiLCB0ZXh0OiBcIkNvbnRleHQgZnJvbSBwcmV2aW91cyBzZXNzaW9uLi4uXCIgfV0sXG4gICAgICB0aW1lc3RhbXA6IERhdGUubm93KCksXG4gICAgfSk7XG4gIH0sXG4gIHdpdGhTZXNzaW9uOiBhc3luYyAoY3R4KSA9PiB7XG4gICAgLy8gVXNlIG9ubHkgdGhlIHJlcGxhY2VtZW50LXNlc3Npb24gY3R4IGhlcmUuXG4gICAgYXdhaXQgY3R4LnNlbmRVc2VyTWVzc2FnZShraWNrb2ZmKTtcbiAgfSxcbn0pO1xuXG5pZiAocmVzdWx0LmNhbmNlbGxlZCkge1xuICAvLyBBbiBleHRlbnNpb24gY2FuY2VsbGVkIHRoZSBuZXcgc2Vzc2lvblxufVxuYGBgXG5cbk9wdGlvbnM6XG4tIGBwYXJlbnRTZXNzaW9uYDogcGFyZW50IHNlc3Npb24gZmlsZSB0byByZWNvcmQgaW4gdGhlIG5ldyBzZXNzaW9uIGhlYWRlclxuLSBgc2V0dXBgOiBtdXRhdGUgdGhlIG5ldyBzZXNzaW9uJ3MgYFNlc3Npb25NYW5hZ2VyYCBiZWZvcmUgYHdpdGhTZXNzaW9uYCBydW5zXG4tIGB3aXRoU2Vzc2lvbmA6IHJ1biBwb3N0LXN3aXRjaCB3b3JrIGFnYWluc3QgYSBmcmVzaCByZXBsYWNlbWVudC1zZXNzaW9uIGNvbnRleHQuIERvIG5vdCB1c2UgY2FwdHVyZWQgb2xkIGBwaWAgLyBjb21tYW5kIGBjdHhgOyBzZWUgW1Nlc3Npb24gcmVwbGFjZW1lbnQgbGlmZWN5Y2xlIGFuZCBmb290Z3Vuc10oI3Nlc3Npb24tcmVwbGFjZW1lbnQtbGlmZWN5Y2xlLWFuZC1mb290Z3VucykuXG5cbiMjIyBjdHguZm9yayhlbnRyeUlkLCBvcHRpb25zPylcblxuRm9yayBmcm9tIGEgc3BlY2lmaWMgZW50cnksIGNyZWF0aW5nIGEgbmV3IHNlc3Npb24gZmlsZTpcblxuYGBgdHlwZXNjcmlwdFxuY29uc3QgcmVzdWx0ID0gYXdhaXQgY3R4LmZvcmsoXCJlbnRyeS1pZC0xMjNcIiwge1xuICB3aXRoU2Vzc2lvbjogYXN5bmMgKGN0eCkgPT4ge1xuICAgIC8vIFVzZSBvbmx5IHRoZSByZXBsYWNlbWVudC1zZXNzaW9uIGN0eCBoZXJlLlxuICAgIGN0eC51aS5ub3RpZnkoXCJOb3cgaW4gdGhlIGZvcmtlZCBzZXNzaW9uXCIsIFwiaW5mb1wiKTtcbiAgfSxcbn0pO1xuaWYgKHJlc3VsdC5jYW5jZWxsZWQpIHtcbiAgLy8gQW4gZXh0ZW5zaW9uIGNhbmNlbGxlZCB0aGUgZm9ya1xufVxuXG5jb25zdCBjbG9uZVJlc3VsdCA9IGF3YWl0IGN0eC5mb3JrKFwiZW50cnktaWQtNDU2XCIsIHsgcG9zaXRpb246IFwiYXRcIiB9KTtcbmlmIChjbG9uZVJlc3VsdC5jYW5jZWxsZWQpIHtcbiAgLy8gQW4gZXh0ZW5zaW9uIGNhbmNlbGxlZCB0aGUgY2xvbmVcbn1cbmBgYFxuXG5PcHRpb25zOlxuLSBgcG9zaXRpb25gOiBgXCJiZWZvcmVcImAgKGRlZmF1bHQpIGZvcmtzIGJlZm9yZSB0aGUgc2VsZWN0ZWQgdXNlciBtZXNzYWdlLCByZXN0b3JpbmcgdGhhdCBwcm9tcHQgaW50byB0aGUgZWRpdG9yXG4tIGBwb3NpdGlvbmA6IGBcImF0XCJgIGR1cGxpY2F0ZXMgdGhlIGFjdGl2ZSBwYXRoIHRocm91Z2ggdGhlIHNlbGVjdGVkIGVudHJ5IHdpdGhvdXQgcmVzdG9yaW5nIGVkaXRvciB0ZXh0XG4tIGB3aXRoU2Vzc2lvbmA6IHJ1biBwb3N0LXN3aXRjaCB3b3JrIGFnYWluc3QgYSBmcmVzaCByZXBsYWNlbWVudC1zZXNzaW9uIGNvbnRleHQuIERvIG5vdCB1c2UgY2FwdHVyZWQgb2xkIGBwaWAgLyBjb21tYW5kIGBjdHhgOyBzZWUgW1Nlc3Npb24gcmVwbGFjZW1lbnQgbGlmZWN5Y2xlIGFuZCBmb290Z3Vuc10oI3Nlc3Npb24tcmVwbGFjZW1lbnQtbGlmZWN5Y2xlLWFuZC1mb290Z3VucykuXG5cbiMjIyBjdHgubmF2aWdhdGVUcmVlKHRhcmdldElkLCBvcHRpb25zPylcblxuTmF2aWdhdGUgdG8gYSBkaWZmZXJlbnQgcG9pbnQgaW4gdGhlIHNlc3Npb24gdHJlZTpcblxuYGBgdHlwZXNjcmlwdFxuY29uc3QgcmVzdWx0ID0gYXdhaXQgY3R4Lm5hdmlnYXRlVHJlZShcImVudHJ5LWlkLTQ1NlwiLCB7XG4gIHN1bW1hcml6ZTogdHJ1ZSxcbiAgY3VzdG9tSW5zdHJ1Y3Rpb25zOiBcIkZvY3VzIG9uIGVycm9yIGhhbmRsaW5nIGNoYW5nZXNcIixcbiAgcmVwbGFjZUluc3RydWN0aW9uczogZmFsc2UsIC8vIHRydWUgPSByZXBsYWNlIGRlZmF1bHQgcHJvbXB0IGVudGlyZWx5XG4gIGxhYmVsOiBcInJldmlldy1jaGVja3BvaW50XCIsXG59KTtcbmBgYFxuXG5PcHRpb25zOlxuLSBgc3VtbWFyaXplYDogV2hldGhlciB0byBnZW5lcmF0ZSBhIHN1bW1hcnkgb2YgdGhlIGFiYW5kb25lZCBicmFuY2hcbi0gYGN1c3RvbUluc3RydWN0aW9uc2A6IEN1c3RvbSBpbnN0cnVjdGlvbnMgZm9yIHRoZSBzdW1tYXJpemVyXG4tIGByZXBsYWNlSW5zdHJ1Y3Rpb25zYDogSWYgdHJ1ZSwgYGN1c3RvbUluc3RydWN0aW9uc2AgcmVwbGFjZXMgdGhlIGRlZmF1bHQgcHJvbXB0IGluc3RlYWQgb2YgYmVpbmcgYXBwZW5kZWRcbi0gYGxhYmVsYDogTGFiZWwgdG8gYXR0YWNoIHRvIHRoZSBicmFuY2ggc3VtbWFyeSBlbnRyeSAob3IgdGFyZ2V0IGVudHJ5IGlmIG5vdCBzdW1tYXJpemluZylcblxuIyMjIGN0eC5zd2l0Y2hTZXNzaW9uKHNlc3Npb25QYXRoLCBvcHRpb25zPylcblxuU3dpdGNoIHRvIGEgZGlmZmVyZW50IHNlc3Npb24gZmlsZTpcblxuYGBgdHlwZXNjcmlwdFxuY29uc3QgcmVzdWx0ID0gYXdhaXQgY3R4LnN3aXRjaFNlc3Npb24oXCIvcGF0aC90by9zZXNzaW9uLmpzb25sXCIsIHtcbiAgd2l0aFNlc3Npb246IGFzeW5jIChjdHgpID0+IHtcbiAgICBhd2FpdCBjdHguc2VuZFVzZXJNZXNzYWdlKFwiUmVzdW1lIHdvcmsgaW4gdGhlIHJlcGxhY2VtZW50IHNlc3Npb25cIik7XG4gIH0sXG59KTtcbmlmIChyZXN1bHQuY2FuY2VsbGVkKSB7XG4gIC8vIEFuIGV4dGVuc2lvbiBjYW5jZWxsZWQgdGhlIHN3aXRjaCB2aWEgc2Vzc2lvbl9iZWZvcmVfc3dpdGNoXG59XG5gYGBcblxuT3B0aW9uczpcbi0gYHdpdGhTZXNzaW9uYDogcnVuIHBvc3Qtc3dpdGNoIHdvcmsgYWdhaW5zdCBhIGZyZXNoIHJlcGxhY2VtZW50LXNlc3Npb24gY29udGV4dC4gRG8gbm90IHVzZSBjYXB0dXJlZCBvbGQgYHBpYCAvIGNvbW1hbmQgYGN0eGA7IHNlZSBbU2Vzc2lvbiByZXBsYWNlbWVudCBsaWZlY3ljbGUgYW5kIGZvb3RndW5zXSgjc2Vzc2lvbi1yZXBsYWNlbWVudC1saWZlY3ljbGUtYW5kLWZvb3RndW5zKS5cblxuVG8gZGlzY292ZXIgYXZhaWxhYmxlIHNlc3Npb25zLCB1c2UgdGhlIHN0YXRpYyBgU2Vzc2lvbk1hbmFnZXIubGlzdCgpYCBvciBgU2Vzc2lvbk1hbmFnZXIubGlzdEFsbCgpYCBtZXRob2RzOlxuXG5gYGB0eXBlc2NyaXB0XG5pbXBvcnQgeyBTZXNzaW9uTWFuYWdlciB9IGZyb20gXCJAZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50XCI7XG5cbnBpLnJlZ2lzdGVyQ29tbWFuZChcInN3aXRjaFwiLCB7XG4gIGRlc2NyaXB0aW9uOiBcIlN3aXRjaCB0byBhbm90aGVyIHNlc3Npb25cIixcbiAgaGFuZGxlcjogYXN5bmMgKGFyZ3MsIGN0eCkgPT4ge1xuICAgIGNvbnN0IHNlc3Npb25zID0gYXdhaXQgU2Vzc2lvbk1hbmFnZXIubGlzdChjdHguY3dkKTtcbiAgICBpZiAoc2Vzc2lvbnMubGVuZ3RoID09PSAwKSByZXR1cm47XG4gICAgY29uc3QgY2hvaWNlID0gYXdhaXQgY3R4LnVpLnNlbGVjdChcbiAgICAgIFwiUGljayBzZXNzaW9uOlwiLFxuICAgICAgc2Vzc2lvbnMubWFwKHMgPT4gcy5maWxlKSxcbiAgICApO1xuICAgIGlmIChjaG9pY2UpIHtcbiAgICAgIGF3YWl0IGN0eC5zd2l0Y2hTZXNzaW9uKGNob2ljZSwge1xuICAgICAgICB3aXRoU2Vzc2lvbjogYXN5bmMgKGN0eCkgPT4ge1xuICAgICAgICAgIGN0eC51aS5ub3RpZnkoXCJTd2l0Y2hlZCBzZXNzaW9uXCIsIFwiaW5mb1wiKTtcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgIH1cbiAgfSxcbn0pO1xuYGBgXG5cbiMjIyBTZXNzaW9uIHJlcGxhY2VtZW50IGxpZmVjeWNsZSBhbmQgZm9vdGd1bnNcblxuYHdpdGhTZXNzaW9uYCByZWNlaXZlcyBhIGZyZXNoIGBSZXBsYWNlZFNlc3Npb25Db250ZXh0YCwgd2hpY2ggZXh0ZW5kcyBgRXh0ZW5zaW9uQ29tbWFuZENvbnRleHRgIHdpdGggYXN5bmMgYHNlbmRNZXNzYWdlKClgIGFuZCBgc2VuZFVzZXJNZXNzYWdlKClgIGhlbHBlcnMgYm91bmQgdG8gdGhlIHJlcGxhY2VtZW50IHNlc3Npb24uXG5cbkxpZmVjeWNsZSBhbmQgZm9vdGd1bnM6XG4tIGB3aXRoU2Vzc2lvbmAgcnVucyBvbmx5IGFmdGVyIHRoZSBvbGQgc2Vzc2lvbiBoYXMgZW1pdHRlZCBgc2Vzc2lvbl9zaHV0ZG93bmAsIHRoZSBvbGQgcnVudGltZSBoYXMgYmVlbiB0b3JuIGRvd24sIHRoZSByZXBsYWNlbWVudCBzZXNzaW9uIGhhcyBiZWVuIHJlYm91bmQsIGFuZCB0aGUgbmV3IGV4dGVuc2lvbiBpbnN0YW5jZSBoYXMgYWxyZWFkeSByZWNlaXZlZCBgc2Vzc2lvbl9zdGFydGAuXG4tIFRoZSBjYWxsYmFjayBzdGlsbCBleGVjdXRlcyBpbiB0aGUgb3JpZ2luYWwgY2xvc3VyZSwgbm90IGluc2lkZSB0aGUgbmV3IGV4dGVuc2lvbiBpbnN0YW5jZS4gVGhhdCBtZWFucyB5b3VyIG9sZCBleHRlbnNpb24gaW5zdGFuY2UgbWF5IGFscmVhZHkgaGF2ZSBydW4gaXRzIHNodXRkb3duIGNsZWFudXAgYmVmb3JlIGB3aXRoU2Vzc2lvbmAgc3RhcnRzLlxuLSBDYXB0dXJlZCBvbGQgYHBpYCAvIG9sZCBjb21tYW5kIGBjdHhgIHNlc3Npb24tYm91bmQgb2JqZWN0cyBhcmUgc3RhbGUgYWZ0ZXIgcmVwbGFjZW1lbnQgYW5kIHdpbGwgdGhyb3cgaWYgdXNlZC4gVXNlIG9ubHkgdGhlIGBjdHhgIHBhc3NlZCB0byBgd2l0aFNlc3Npb25gIGZvciBzZXNzaW9uLWJvdW5kIHdvcmsuXG4tIFByZXZpb3VzbHkgZXh0cmFjdGVkIHJhdyBvYmplY3RzIGFyZSBzdGlsbCB5b3VyIHJlc3BvbnNpYmlsaXR5LiBGb3IgZXhhbXBsZSwgaWYgeW91IGNhcHR1cmUgYGNvbnN0IHNtID0gY3R4LnNlc3Npb25NYW5hZ2VyYCBiZWZvcmUgcmVwbGFjZW1lbnQsIGBzbWAgaXMgc3RpbGwgdGhlIG9sZCBgU2Vzc2lvbk1hbmFnZXJgIG9iamVjdC4gRG8gbm90IHJldXNlIGl0IGFmdGVyIHJlcGxhY2VtZW50LlxuLSBDb2RlIGluIGB3aXRoU2Vzc2lvbmAgc2hvdWxkIGFzc3VtZSBhbnkgc3RhdGUgaW52YWxpZGF0ZWQgYnkgeW91ciBgc2Vzc2lvbl9zaHV0ZG93bmAgaGFuZGxlciBpcyBhbHJlYWR5IGdvbmUuIE9ubHkgY2FwdHVyZSBwbGFpbiBkYXRhIHRoYXQgc3Vydml2ZXMgc2h1dGRvd24gY2xlYW5seSwgc3VjaCBhcyBzdHJpbmdzLCBpZHMsIGFuZCBzZXJpYWxpemVkIGNvbmZpZy5cblxuU2FmZSBwYXR0ZXJuOlxuXG5gYGB0eXBlc2NyaXB0XG5waS5yZWdpc3RlckNvbW1hbmQoXCJoYW5kb2ZmXCIsIHtcbiAgaGFuZGxlcjogYXN5bmMgKF9hcmdzLCBjdHgpID0+IHtcbiAgICBjb25zdCBraWNrb2ZmID0gXCJDb250aW51ZSBmcm9tIHRoZSByZXBsYWNlbWVudCBzZXNzaW9uXCI7XG4gICAgYXdhaXQgY3R4Lm5ld1Nlc3Npb24oe1xuICAgICAgd2l0aFNlc3Npb246IGFzeW5jIChjdHgpID0+IHtcbiAgICAgICAgYXdhaXQgY3R4LnNlbmRVc2VyTWVzc2FnZShraWNrb2ZmKTtcbiAgICAgIH0sXG4gICAgfSk7XG4gIH0sXG59KTtcbmBgYFxuXG5VbnNhZmUgcGF0dGVybjpcblxuYGBgdHlwZXNjcmlwdFxucGkucmVnaXN0ZXJDb21tYW5kKFwiaGFuZG9mZlwiLCB7XG4gIGhhbmRsZXI6IGFzeW5jIChfYXJncywgY3R4KSA9PiB7XG4gICAgY29uc3Qgb2xkU2Vzc2lvbk1hbmFnZXIgPSBjdHguc2Vzc2lvbk1hbmFnZXI7XG4gICAgYXdhaXQgY3R4Lm5ld1Nlc3Npb24oe1xuICAgICAgd2l0aFNlc3Npb246IGFzeW5jIChfY3R4KSA9PiB7XG4gICAgICAgIC8vIHN0YWxlIG9sZCBvYmplY3RzOiBkbyBub3QgZG8gdGhpc1xuICAgICAgICBvbGRTZXNzaW9uTWFuYWdlci5nZXRTZXNzaW9uRmlsZSgpO1xuICAgICAgICBwaS5zZW5kVXNlck1lc3NhZ2UoXCJ3cm9uZ1wiKTtcbiAgICAgIH0sXG4gICAgfSk7XG4gIH0sXG59KTtcbmBgYFxuXG4jIyMgY3R4LnJlbG9hZCgpXG5cblJ1biB0aGUgc2FtZSByZWxvYWQgZmxvdyBhcyBgL3JlbG9hZGAuXG5cbmBgYHR5cGVzY3JpcHRcbnBpLnJlZ2lzdGVyQ29tbWFuZChcInJlbG9hZC1ydW50aW1lXCIsIHtcbiAgZGVzY3JpcHRpb246IFwiUmVsb2FkIGV4dGVuc2lvbnMsIHNraWxscywgcHJvbXB0cywgYW5kIHRoZW1lc1wiLFxuICBoYW5kbGVyOiBhc3luYyAoX2FyZ3MsIGN0eCkgPT4ge1xuICAgIGF3YWl0IGN0eC5yZWxvYWQoKTtcbiAgICByZXR1cm47XG4gIH0sXG59KTtcbmBgYFxuXG5JbXBvcnRhbnQgYmVoYXZpb3I6XG4tIGBhd2FpdCBjdHgucmVsb2FkKClgIGVtaXRzIGBzZXNzaW9uX3NodXRkb3duYCBmb3IgdGhlIGN1cnJlbnQgZXh0ZW5zaW9uIHJ1bnRpbWVcbi0gSXQgdGhlbiByZWxvYWRzIHJlc291cmNlcyBhbmQgZW1pdHMgYHNlc3Npb25fc3RhcnRgIHdpdGggYHJlYXNvbjogXCJyZWxvYWRcImAgYW5kIGByZXNvdXJjZXNfZGlzY292ZXJgIHdpdGggcmVhc29uIGBcInJlbG9hZFwiYFxuLSBUaGUgY3VycmVudGx5IHJ1bm5pbmcgY29tbWFuZCBoYW5kbGVyIHN0aWxsIGNvbnRpbnVlcyBpbiB0aGUgb2xkIGNhbGwgZnJhbWVcbi0gQ29kZSBhZnRlciBgYXdhaXQgY3R4LnJlbG9hZCgpYCBzdGlsbCBydW5zIGZyb20gdGhlIHByZS1yZWxvYWQgdmVyc2lvblxuLSBDb2RlIGFmdGVyIGBhd2FpdCBjdHgucmVsb2FkKClgIG11c3Qgbm90IGFzc3VtZSBvbGQgaW4tbWVtb3J5IGV4dGVuc2lvbiBzdGF0ZSBpcyBzdGlsbCB2YWxpZFxuLSBBZnRlciB0aGUgaGFuZGxlciByZXR1cm5zLCBmdXR1cmUgY29tbWFuZHMvZXZlbnRzL3Rvb2wgY2FsbHMgdXNlIHRoZSBuZXcgZXh0ZW5zaW9uIHZlcnNpb25cblxuRm9yIHByZWRpY3RhYmxlIGJlaGF2aW9yLCB0cmVhdCByZWxvYWQgYXMgdGVybWluYWwgZm9yIHRoYXQgaGFuZGxlciAoYGF3YWl0IGN0eC5yZWxvYWQoKTsgcmV0dXJuO2ApLlxuXG5Ub29scyBydW4gd2l0aCBgRXh0ZW5zaW9uQ29udGV4dGAsIHNvIHRoZXkgY2Fubm90IGNhbGwgYGN0eC5yZWxvYWQoKWAgZGlyZWN0bHkuIFVzZSBhIGNvbW1hbmQgYXMgdGhlIHJlbG9hZCBlbnRyeXBvaW50LCB0aGVuIGV4cG9zZSBhIHRvb2wgdGhhdCBxdWV1ZXMgdGhhdCBjb21tYW5kIGFzIGEgZm9sbG93LXVwIHVzZXIgbWVzc2FnZS5cblxuRXhhbXBsZSB0b29sIHRoZSBMTE0gY2FuIGNhbGwgdG8gdHJpZ2dlciByZWxvYWQ6XG5cbmBgYHR5cGVzY3JpcHRcbmltcG9ydCB0eXBlIHsgRXh0ZW5zaW9uQVBJIH0gZnJvbSBcIkBlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnRcIjtcbmltcG9ydCB7IFR5cGUgfSBmcm9tIFwidHlwZWJveFwiO1xuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiAocGk6IEV4dGVuc2lvbkFQSSkge1xuICBwaS5yZWdpc3RlckNvbW1hbmQoXCJyZWxvYWQtcnVudGltZVwiLCB7XG4gICAgZGVzY3JpcHRpb246IFwiUmVsb2FkIGV4dGVuc2lvbnMsIHNraWxscywgcHJvbXB0cywgYW5kIHRoZW1lc1wiLFxuICAgIGhhbmRsZXI6IGFzeW5jIChfYXJncywgY3R4KSA9PiB7XG4gICAgICBhd2FpdCBjdHgucmVsb2FkKCk7XG4gICAgICByZXR1cm47XG4gICAgfSxcbiAgfSk7XG5cbiAgcGkucmVnaXN0ZXJUb29sKHtcbiAgICBuYW1lOiBcInJlbG9hZF9ydW50aW1lXCIsXG4gICAgbGFiZWw6IFwiUmVsb2FkIFJ1bnRpbWVcIixcbiAgICBkZXNjcmlwdGlvbjogXCJSZWxvYWQgZXh0ZW5zaW9ucywgc2tpbGxzLCBwcm9tcHRzLCBhbmQgdGhlbWVzXCIsXG4gICAgcGFyYW1ldGVyczogVHlwZS5PYmplY3Qoe30pLFxuICAgIGFzeW5jIGV4ZWN1dGUoKSB7XG4gICAgICBwaS5zZW5kVXNlck1lc3NhZ2UoXCIvcmVsb2FkLXJ1bnRpbWVcIiwgeyBkZWxpdmVyQXM6IFwiZm9sbG93VXBcIiB9KTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGNvbnRlbnQ6IFt7IHR5cGU6IFwidGV4dFwiLCB0ZXh0OiBcIlF1ZXVlZCAvcmVsb2FkLXJ1bnRpbWUgYXMgYSBmb2xsb3ctdXAgY29tbWFuZC5cIiB9XSxcbiAgICAgIH07XG4gICAgfSxcbiAgfSk7XG59XG5gYGBcblxuIyMgRXh0ZW5zaW9uQVBJIE1ldGhvZHNcblxuIyMjIHBpLm9uKGV2ZW50LCBoYW5kbGVyKVxuXG5TdWJzY3JpYmUgdG8gZXZlbnRzLiBTZWUgW0V2ZW50c10oI2V2ZW50cykgZm9yIGV2ZW50IHR5cGVzIGFuZCByZXR1cm4gdmFsdWVzLlxuXG4jIyMgcGkucmVnaXN0ZXJUb29sKGRlZmluaXRpb24pXG5cblJlZ2lzdGVyIGEgY3VzdG9tIHRvb2wgY2FsbGFibGUgYnkgdGhlIExMTS4gU2VlIFtDdXN0b20gVG9vbHNdKCNjdXN0b20tdG9vbHMpIGZvciBmdWxsIGRldGFpbHMuXG5cbmBwaS5yZWdpc3RlclRvb2woKWAgd29ya3MgYm90aCBkdXJpbmcgZXh0ZW5zaW9uIGxvYWQgYW5kIGFmdGVyIHN0YXJ0dXAuIFlvdSBjYW4gY2FsbCBpdCBpbnNpZGUgYHNlc3Npb25fc3RhcnRgLCBjb21tYW5kIGhhbmRsZXJzLCBvciBvdGhlciBldmVudCBoYW5kbGVycy4gTmV3IHRvb2xzIGFyZSByZWZyZXNoZWQgaW1tZWRpYXRlbHkgaW4gdGhlIHNhbWUgc2Vzc2lvbiwgc28gdGhleSBhcHBlYXIgaW4gYHBpLmdldEFsbFRvb2xzKClgIGFuZCBhcmUgY2FsbGFibGUgYnkgdGhlIExMTSB3aXRob3V0IGAvcmVsb2FkYC5cblxuVXNlIGBwaS5zZXRBY3RpdmVUb29scygpYCB0byBlbmFibGUgb3IgZGlzYWJsZSB0b29scyAoaW5jbHVkaW5nIGR5bmFtaWNhbGx5IGFkZGVkIHRvb2xzKSBhdCBydW50aW1lLlxuXG5Vc2UgYHByb21wdFNuaXBwZXRgIHRvIG9wdCBhIGN1c3RvbSB0b29sIGludG8gYSBvbmUtbGluZSBlbnRyeSBpbiBgQXZhaWxhYmxlIHRvb2xzYCwgYW5kIGBwcm9tcHRHdWlkZWxpbmVzYCB0byBhcHBlbmQgdG9vbC1zcGVjaWZpYyBidWxsZXRzIHRvIHRoZSBkZWZhdWx0IGBHdWlkZWxpbmVzYCBzZWN0aW9uIHdoZW4gdGhlIHRvb2wgaXMgYWN0aXZlLlxuXG4qKkltcG9ydGFudDoqKiBgcHJvbXB0R3VpZGVsaW5lc2AgYnVsbGV0cyBhcmUgYXBwZW5kZWQgZmxhdCB0byB0aGUgYEd1aWRlbGluZXNgIHNlY3Rpb24gd2l0aCBubyB0b29sIG5hbWUgcHJlZml4LiBFYWNoIGd1aWRlbGluZSBtdXN0IG5hbWUgdGhlIHRvb2wgaXQgcmVmZXJzIHRvIOKAlCBhdm9pZCBcIlVzZSB0aGlzIHRvb2wgd2hlbi4uLlwiIGJlY2F1c2UgdGhlIExMTSBjYW5ub3QgdGVsbCB3aGljaCB0b29sIFwidGhpc1wiIG1lYW5zLiBXcml0ZSBcIlVzZSBteV90b29sIHdoZW4uLi5cIiBpbnN0ZWFkLlxuXG5TZWUgW2R5bmFtaWMtdG9vbHMudHNdKC4uL2V4YW1wbGVzL2V4dGVuc2lvbnMvZHluYW1pYy10b29scy50cykgZm9yIGEgZnVsbCBleGFtcGxlLlxuXG5gYGB0eXBlc2NyaXB0XG5pbXBvcnQgeyBUeXBlIH0gZnJvbSBcInR5cGVib3hcIjtcbmltcG9ydCB7IFN0cmluZ0VudW0gfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWFpXCI7XG5cbnBpLnJlZ2lzdGVyVG9vbCh7XG4gIG5hbWU6IFwibXlfdG9vbFwiLFxuICBsYWJlbDogXCJNeSBUb29sXCIsXG4gIGRlc2NyaXB0aW9uOiBcIldoYXQgdGhpcyB0b29sIGRvZXNcIixcbiAgcHJvbXB0U25pcHBldDogXCJTdW1tYXJpemUgb3IgdHJhbnNmb3JtIHRleHQgYWNjb3JkaW5nIHRvIGFjdGlvblwiLFxuICBwcm9tcHRHdWlkZWxpbmVzOiBbXCJVc2UgbXlfdG9vbCB3aGVuIHRoZSB1c2VyIGFza3MgdG8gc3VtbWFyaXplIHByZXZpb3VzbHkgZ2VuZXJhdGVkIHRleHQuXCJdLFxuICBwYXJhbWV0ZXJzOiBUeXBlLk9iamVjdCh7XG4gICAgYWN0aW9uOiBTdHJpbmdFbnVtKFtcImxpc3RcIiwgXCJhZGRcIl0gYXMgY29uc3QpLFxuICAgIHRleHQ6IFR5cGUuT3B0aW9uYWwoVHlwZS5TdHJpbmcoKSksXG4gIH0pLFxuICBwcmVwYXJlQXJndW1lbnRzKGFyZ3MpIHtcbiAgICAvLyBPcHRpb25hbCBjb21wYXRpYmlsaXR5IHNoaW0uIFJ1bnMgYmVmb3JlIHNjaGVtYSB2YWxpZGF0aW9uLlxuICAgIC8vIFJldHVybiB0aGUgY3VycmVudCBzY2hlbWEgc2hhcGUsIGZvciBleGFtcGxlIHRvIGZvbGQgbGVnYWN5IGZpZWxkc1xuICAgIC8vIGludG8gdGhlIG1vZGVybiBwYXJhbWV0ZXIgb2JqZWN0LlxuICAgIHJldHVybiBhcmdzO1xuICB9LFxuXG4gIGFzeW5jIGV4ZWN1dGUodG9vbENhbGxJZCwgcGFyYW1zLCBzaWduYWwsIG9uVXBkYXRlLCBjdHgpIHtcbiAgICAvLyBTdHJlYW0gcHJvZ3Jlc3NcbiAgICBvblVwZGF0ZT8uKHsgY29udGVudDogW3sgdHlwZTogXCJ0ZXh0XCIsIHRleHQ6IFwiV29ya2luZy4uLlwiIH1dIH0pO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGNvbnRlbnQ6IFt7IHR5cGU6IFwidGV4dFwiLCB0ZXh0OiBcIkRvbmVcIiB9XSxcbiAgICAgIGRldGFpbHM6IHsgcmVzdWx0OiBcIi4uLlwiIH0sXG4gICAgfTtcbiAgfSxcblxuICAvLyBPcHRpb25hbDogQ3VzdG9tIHJlbmRlcmluZ1xuICByZW5kZXJDYWxsKGFyZ3MsIHRoZW1lLCBjb250ZXh0KSB7IC4uLiB9LFxuICByZW5kZXJSZXN1bHQocmVzdWx0LCBvcHRpb25zLCB0aGVtZSwgY29udGV4dCkgeyAuLi4gfSxcbn0pO1xuYGBgXG5cbiMjIyBwaS5zZW5kTWVzc2FnZShtZXNzYWdlLCBvcHRpb25zPylcblxuSW5qZWN0IGEgY3VzdG9tIG1lc3NhZ2UgaW50byB0aGUgc2Vzc2lvbi5cblxuYGBgdHlwZXNjcmlwdFxucGkuc2VuZE1lc3NhZ2Uoe1xuICBjdXN0b21UeXBlOiBcIm15LWV4dGVuc2lvblwiLFxuICBjb250ZW50OiBcIk1lc3NhZ2UgdGV4dFwiLFxuICBkaXNwbGF5OiB0cnVlLFxuICBkZXRhaWxzOiB7IC4uLiB9LFxufSwge1xuICB0cmlnZ2VyVHVybjogdHJ1ZSxcbiAgZGVsaXZlckFzOiBcInN0ZWVyXCIsXG59KTtcbmBgYFxuXG4qKk9wdGlvbnM6Kipcbi0gYGRlbGl2ZXJBc2AgLSBEZWxpdmVyeSBtb2RlOlxuICAtIGBcInN0ZWVyXCJgIChkZWZhdWx0KSAtIFF1ZXVlcyB0aGUgbWVzc2FnZSB3aGlsZSBzdHJlYW1pbmcuIERlbGl2ZXJlZCBhZnRlciB0aGUgY3VycmVudCBhc3Npc3RhbnQgdHVybiBmaW5pc2hlcyBleGVjdXRpbmcgaXRzIHRvb2wgY2FsbHMsIGJlZm9yZSB0aGUgbmV4dCBMTE0gY2FsbC5cbiAgLSBgXCJmb2xsb3dVcFwiYCAtIFdhaXRzIGZvciBhZ2VudCB0byBmaW5pc2guIERlbGl2ZXJlZCBvbmx5IHdoZW4gYWdlbnQgaGFzIG5vIG1vcmUgdG9vbCBjYWxscy5cbiAgLSBgXCJuZXh0VHVyblwiYCAtIFF1ZXVlZCBmb3IgbmV4dCB1c2VyIHByb21wdC4gRG9lcyBub3QgaW50ZXJydXB0IG9yIHRyaWdnZXIgYW55dGhpbmcuXG4tIGB0cmlnZ2VyVHVybjogdHJ1ZWAgLSBJZiBhZ2VudCBpcyBpZGxlLCB0cmlnZ2VyIGFuIExMTSByZXNwb25zZSBpbW1lZGlhdGVseS4gT25seSBhcHBsaWVzIHRvIGBcInN0ZWVyXCJgIGFuZCBgXCJmb2xsb3dVcFwiYCBtb2RlcyAoaWdub3JlZCBmb3IgYFwibmV4dFR1cm5cImApLlxuXG4jIyMgcGkuc2VuZFVzZXJNZXNzYWdlKGNvbnRlbnQsIG9wdGlvbnM/KVxuXG5TZW5kIGEgdXNlciBtZXNzYWdlIHRvIHRoZSBhZ2VudC4gVW5saWtlIGBzZW5kTWVzc2FnZSgpYCB3aGljaCBzZW5kcyBjdXN0b20gbWVzc2FnZXMsIHRoaXMgc2VuZHMgYW4gYWN0dWFsIHVzZXIgbWVzc2FnZSB0aGF0IGFwcGVhcnMgYXMgaWYgdHlwZWQgYnkgdGhlIHVzZXIuIEFsd2F5cyB0cmlnZ2VycyBhIHR1cm4uXG5cbmBgYHR5cGVzY3JpcHRcbi8vIFNpbXBsZSB0ZXh0IG1lc3NhZ2VcbnBpLnNlbmRVc2VyTWVzc2FnZShcIldoYXQgaXMgMisyP1wiKTtcblxuLy8gV2l0aCBjb250ZW50IGFycmF5ICh0ZXh0ICsgaW1hZ2VzKVxucGkuc2VuZFVzZXJNZXNzYWdlKFtcbiAgeyB0eXBlOiBcInRleHRcIiwgdGV4dDogXCJEZXNjcmliZSB0aGlzIGltYWdlOlwiIH0sXG4gIHsgdHlwZTogXCJpbWFnZVwiLCBzb3VyY2U6IHsgdHlwZTogXCJiYXNlNjRcIiwgbWVkaWFUeXBlOiBcImltYWdlL3BuZ1wiLCBkYXRhOiBcIi4uLlwiIH0gfSxcbl0pO1xuXG4vLyBEdXJpbmcgc3RyZWFtaW5nIC0gbXVzdCBzcGVjaWZ5IGRlbGl2ZXJ5IG1vZGVcbnBpLnNlbmRVc2VyTWVzc2FnZShcIkZvY3VzIG9uIGVycm9yIGhhbmRsaW5nXCIsIHsgZGVsaXZlckFzOiBcInN0ZWVyXCIgfSk7XG5waS5zZW5kVXNlck1lc3NhZ2UoXCJBbmQgdGhlbiBzdW1tYXJpemVcIiwgeyBkZWxpdmVyQXM6IFwiZm9sbG93VXBcIiB9KTtcbmBgYFxuXG4qKk9wdGlvbnM6Kipcbi0gYGRlbGl2ZXJBc2AgLSBSZXF1aXJlZCB3aGVuIGFnZW50IGlzIHN0cmVhbWluZzpcbiAgLSBgXCJzdGVlclwiYCAtIFF1ZXVlcyB0aGUgbWVzc2FnZSBmb3IgZGVsaXZlcnkgYWZ0ZXIgdGhlIGN1cnJlbnQgYXNzaXN0YW50IHR1cm4gZmluaXNoZXMgZXhlY3V0aW5nIGl0cyB0b29sIGNhbGxzXG4gIC0gYFwiZm9sbG93VXBcImAgLSBXYWl0cyBmb3IgYWdlbnQgdG8gZmluaXNoIGFsbCB0b29sc1xuXG5XaGVuIG5vdCBzdHJlYW1pbmcsIHRoZSBtZXNzYWdlIGlzIHNlbnQgaW1tZWRpYXRlbHkgYW5kIHRyaWdnZXJzIGEgbmV3IHR1cm4uIFdoZW4gc3RyZWFtaW5nIHdpdGhvdXQgYGRlbGl2ZXJBc2AsIHRocm93cyBhbiBlcnJvci5cblxuU2VlIFtzZW5kLXVzZXItbWVzc2FnZS50c10oLi4vZXhhbXBsZXMvZXh0ZW5zaW9ucy9zZW5kLXVzZXItbWVzc2FnZS50cykgZm9yIGEgY29tcGxldGUgZXhhbXBsZS5cblxuIyMjIHBpLmFwcGVuZEVudHJ5KGN1c3RvbVR5cGUsIGRhdGE/KVxuXG5cbltTaG93aW5nIGxpbmVzIDEtMTM4NiBvZiAyNjc3ICg1MC4wS0IgbGltaXQpLiBVc2Ugb2Zmc2V0PTEzODcgdG8gY29udGludWUuXSJ9XSwiZGV0YWlscyI6eyJ0cnVuY2F0aW9uIjp7ImNvbnRlbnQiOiI+IHBpIGNhbiBjcmVhdGUgZXh0ZW5zaW9ucy4gQXNrIGl0IHRvIGJ1aWxkIG9uZSBmb3IgeW91ciB1c2UgY2FzZS5cblxuIyBFeHRlbnNpb25zXG5cbkV4dGVuc2lvbnMgYXJlIFR5cGVTY3JpcHQgbW9kdWxlcyB0aGF0IGV4dGVuZCBwaSdzIGJlaGF2aW9yLiBUaGV5IGNhbiBzdWJzY3JpYmUgdG8gbGlmZWN5Y2xlIGV2ZW50cywgcmVnaXN0ZXIgY3VzdG9tIHRvb2xzIGNhbGxhYmxlIGJ5IHRoZSBMTE0sIGFkZCBjb21tYW5kcywgYW5kIG1vcmUuXG5cbj4gKipQbGFjZW1lbnQgZm9yIC9yZWxvYWQ6KiogUHV0IGV4dGVuc2lvbnMgaW4gYH4vLnBpL2FnZW50L2V4dGVuc2lvbnMvYCAoZ2xvYmFsKSBvciBgLnBpL2V4dGVuc2lvbnMvYCAocHJvamVjdC1sb2NhbCkgZm9yIGF1dG8tZGlzY292ZXJ5LiBVc2UgYHBpIC1lIC4vcGF0aC50c2Agb25seSBmb3IgcXVpY2sgdGVzdHMuIEV4dGVuc2lvbnMgaW4gYXV0by1kaXNjb3ZlcmVkIGxvY2F0aW9ucyBjYW4gYmUgaG90LXJlbG9hZGVkIHdpdGggYC9yZWxvYWRgLlxuXG4qKktleSBjYXBhYmlsaXRpZXM6Kipcbi0gKipDdXN0b20gdG9vbHMqKiAtIFJlZ2lzdGVyIHRvb2xzIHRoZSBMTE0gY2FuIGNhbGwgdmlhIGBwaS5yZWdpc3RlclRvb2woKWBcbi0gKipFdmVudCBpbnRlcmNlcHRpb24qKiAtIEJsb2NrIG9yIG1vZGlmeSB0b29sIGNhbGxzLCBpbmplY3QgY29udGV4dCwgY3VzdG9taXplIGNvbXBhY3Rpb25cbi0gKipVc2VyIGludGVyYWN0aW9uKiogLSBQcm9tcHQgdXNlcnMgdmlhIGBjdHgudWlgIChzZWxlY3QsIGNvbmZpcm0sIGlucHV0LCBub3RpZnkpXG4tICoqQ3VzdG9tIFVJIGNvbXBvbmVudHMqKiAtIEZ1bGwgVFVJIGNvbXBvbmVudHMgd2l0aCBrZXlib2FyZCBpbnB1dCB2aWEgYGN0eC51aS5jdXN0b20oKWAgZm9yIGNvbXBsZXggaW50ZXJhY3Rpb25zXG4tICoqQ3VzdG9tIGNvbW1hbmRzKiogLSBSZWdpc3RlciBjb21tYW5kcyBsaWtlIGAvbXljb21tYW5kYCB2aWEgYHBpLnJlZ2lzdGVyQ29tbWFuZCgpYFxuLSAqKlNlc3Npb24gcGVyc2lzdGVuY2UqKiAtIFN0b3JlIHN0YXRlIHRoYXQgc3Vydml2ZXMgcmVzdGFydHMgdmlhIGBwaS5hcHBlbmRFbnRyeSgpYFxuLSAqKkN1c3RvbSByZW5kZXJpbmcqKiAtIENvbnRyb2wgaG93IHRvb2wgY2FsbHMvcmVzdWx0cyBhbmQgbWVzc2FnZXMgYXBwZWFyIGluIFRVSVxuXG4qKkV4YW1wbGUgdXNlIGNhc2VzOioqXG4tIFBlcm1pc3Npb24gZ2F0ZXMgKGNvbmZpcm0gYmVmb3JlIGBybSAtcmZgLCBgc3Vkb2AsIGV0Yy4pXG4tIEdpdCBjaGVja3BvaW50aW5nIChzdGFzaCBhdCBlYWNoIHR1cm4sIHJlc3RvcmUgb24gYnJhbmNoKVxuLSBQYXRoIHByb3RlY3Rpb24gKGJsb2NrIHdyaXRlcyB0byBgLmVudmAsIGBub2RlX21vZHVsZXMvYClcbi0gQ3VzdG9tIGNvbXBhY3Rpb24gKHN1bW1hcml6ZSBjb252ZXJzYXRpb24geW91ciB3YXkpXG4tIENvbnZlcnNhdGlvbiBzdW1tYXJpZXMgKHNlZSBgc3VtbWFyaXplLnRzYCBleGFtcGxlKVxuLSBJbnRlcmFjdGl2ZSB0b29scyAocXVlc3Rpb25zLCB3aXphcmRzLCBjdXN0b20gZGlhbG9ncylcbi0gU3RhdGVmdWwgdG9vbHMgKHRvZG8gbGlzdHMsIGNvbm5lY3Rpb24gcG9vbHMpXG4tIEV4dGVybmFsIGludGVncmF0aW9ucyAoZmlsZSB3YXRjaGVycywgd2ViaG9va3MsIENJIHRyaWdnZXJzKVxuLSBHYW1lcyB3aGlsZSB5b3Ugd2FpdCAoc2VlIGBzbmFrZS50c2AgZXhhbXBsZSlcblxuU2VlIFtleGFtcGxlcy9leHRlbnNpb25zL10oLi4vZXhhbXBsZXMvZXh0ZW5zaW9ucy8pIGZvciB3b3JraW5nIGltcGxlbWVudGF0aW9ucy5cblxuIyMgVGFibGUgb2YgQ29udGVudHNcblxuLSBbUXVpY2sgU3RhcnRdKCNxdWljay1zdGFydClcbi0gW0V4dGVuc2lvbiBMb2NhdGlvbnNdKCNleHRlbnNpb24tbG9jYXRpb25zKVxuLSBbQXZhaWxhYmxlIEltcG9ydHNdKCNhdmFpbGFibGUtaW1wb3J0cylcbi0gW1dyaXRpbmcgYW4gRXh0ZW5zaW9uXSgjd3JpdGluZy1hbi1leHRlbnNpb24pXG4gIC0gW0V4dGVuc2lvbiBTdHlsZXNdKCNleHRlbnNpb24tc3R5bGVzKVxuLSBbRXZlbnRzXSgjZXZlbnRzKVxuICAtIFtMaWZlY3ljbGUgT3ZlcnZpZXddKCNsaWZlY3ljbGUtb3ZlcnZpZXcpXG4gIC0gW1Jlc291cmNlIEV2ZW50c10oI3Jlc291cmNlLWV2ZW50cylcbiAgLSBbU2Vzc2lvbiBFdmVudHNdKCNzZXNzaW9uLWV2ZW50cylcbiAgLSBbQWdlbnQgRXZlbnRzXSgjYWdlbnQtZXZlbnRzKVxuICAtIFtNb2RlbCBFdmVudHNdKCNtb2RlbC1ldmVudHMpXG4gIC0gW1Rvb2wgRXZlbnRzXSgjdG9vbC1ldmVudHMpXG4tIFtFeHRlbnNpb25Db250ZXh0XSgjZXh0ZW5zaW9uY29udGV4dClcbi0gW0V4dGVuc2lvbkNvbW1hbmRDb250ZXh0XSgjZXh0ZW5zaW9uY29tbWFuZGNvbnRleHQpXG4tIFtFeHRlbnNpb25BUEkgTWV0aG9kc10oI2V4dGVuc2lvbmFwaS1tZXRob2RzKVxuLSBbU3RhdGUgTWFuYWdlbWVudF0oI3N0YXRlLW1hbmFnZW1lbnQpXG4tIFtDdXN0b20gVG9vbHNdKCNjdXN0b20tdG9vbHMpXG4tIFtDdXN0b20gVUldKCNjdXN0b20tdWkpXG4tIFtFcnJvciBIYW5kbGluZ10oI2Vycm9yLWhhbmRsaW5nKVxuLSBbTW9kZSBCZWhhdmlvcl0oI21vZGUtYmVoYXZpb3IpXG4tIFtFeGFtcGxlcyBSZWZlcmVuY2VdKCNleGFtcGxlcy1yZWZlcmVuY2UpXG5cbiMjIFF1aWNrIFN0YXJ0XG5cbkNyZWF0ZSBgfi8ucGkvYWdlbnQvZXh0ZW5zaW9ucy9teS1leHRlbnNpb24udHNgOlxuXG5gYGB0eXBlc2NyaXB0XG5pbXBvcnQgdHlwZSB7IEV4dGVuc2lvbkFQSSB9IGZyb20gXCJAZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50XCI7XG5pbXBvcnQgeyBUeXBlIH0gZnJvbSBcInR5cGVib3hcIjtcblxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gKHBpOiBFeHRlbnNpb25BUEkpIHtcbiAgLy8gUmVhY3QgdG8gZXZlbnRzXG4gIHBpLm9uKFwic2Vzc2lvbl9zdGFydFwiLCBhc3luYyAoX2V2ZW50LCBjdHgpID0+IHtcbiAgICBjdHgudWkubm90aWZ5KFwiRXh0ZW5zaW9uIGxvYWRlZCFcIiwgXCJpbmZvXCIpO1xuICB9KTtcblxuICBwaS5vbihcInRvb2xfY2FsbFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAgIGlmIChldmVudC50b29sTmFtZSA9PT0gXCJiYXNoXCIgJiYgZXZlbnQuaW5wdXQuY29tbWFuZD8uaW5jbHVkZXMoXCJybSAtcmZcIikpIHtcbiAgICAgIGNvbnN0IG9rID0gYXdhaXQgY3R4LnVpLmNvbmZpcm0oXCJEYW5nZXJvdXMhXCIsIFwiQWxsb3cgcm0gLXJmP1wiKTtcbiAgICAgIGlmICghb2spIHJldHVybiB7IGJsb2NrOiB0cnVlLCByZWFzb246IFwiQmxvY2tlZCBieSB1c2VyXCIgfTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIFJlZ2lzdGVyIGEgY3VzdG9tIHRvb2xcbiAgcGkucmVnaXN0ZXJUb29sKHtcbiAgICBuYW1lOiBcImdyZWV0XCIsXG4gICAgbGFiZWw6IFwiR3JlZXRcIixcbiAgICBkZXNjcmlwdGlvbjogXCJHcmVldCBzb21lb25lIGJ5IG5hbWVcIixcbiAgICBwYXJhbWV0ZXJzOiBUeXBlLk9iamVjdCh7XG4gICAgICBuYW1lOiBUeXBlLlN0cmluZyh7IGRlc2NyaXB0aW9uOiBcIk5hbWUgdG8gZ3JlZXRcIiB9KSxcbiAgICB9KSxcbiAgICBhc3luYyBleGVjdXRlKHRvb2xDYWxsSWQsIHBhcmFtcywgc2lnbmFsLCBvblVwZGF0ZSwgY3R4KSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBjb250ZW50OiBbeyB0eXBlOiBcInRleHRcIiwgdGV4dDogYEhlbGxvLCAke3BhcmFtcy5uYW1lfSFgIH1dLFxuICAgICAgICBkZXRhaWxzOiB7fSxcbiAgICAgIH07XG4gICAgfSxcbiAgfSk7XG5cbiAgLy8gUmVnaXN0ZXIgYSBjb21tYW5kXG4gIHBpLnJlZ2lzdGVyQ29tbWFuZChcImhlbGxvXCIsIHtcbiAgICBkZXNjcmlwdGlvbjogXCJTYXkgaGVsbG9cIixcbiAgICBoYW5kbGVyOiBhc3luYyAoYXJncywgY3R4KSA9PiB7XG4gICAgICBjdHgudWkubm90aWZ5KGBIZWxsbyAke2FyZ3MgfHwgXCJ3b3JsZFwifSFgLCBcImluZm9cIik7XG4gICAgfSxcbiAgfSk7XG59XG5gYGBcblxuVGVzdCB3aXRoIGAtLWV4dGVuc2lvbmAgKG9yIGAtZWApIGZsYWc6XG5cbmBgYGJhc2hcbnBpIC1lIC4vbXktZXh0ZW5zaW9uLnRzXG5gYGBcblxuIyMgRXh0ZW5zaW9uIExvY2F0aW9uc1xuXG4+ICoqU2VjdXJpdHk6KiogRXh0ZW5zaW9ucyBydW4gd2l0aCB5b3VyIGZ1bGwgc3lzdGVtIHBlcm1pc3Npb25zIGFuZCBjYW4gZXhlY3V0ZSBhcmJpdHJhcnkgY29kZS4gT25seSBpbnN0YWxsIGZyb20gc291cmNlcyB5b3UgdHJ1c3QuXG5cbkV4dGVuc2lvbnMgYXJlIGF1dG8tZGlzY292ZXJlZCBmcm9tIHRydXN0ZWQgbG9jYXRpb25zLiBQcm9qZWN0LWxvY2FsIGAucGkvZXh0ZW5zaW9uc2AgZW50cmllcyBsb2FkIG9ubHkgYWZ0ZXIgdGhlIHByb2plY3QgaXMgdHJ1c3RlZC5cblxufCBMb2NhdGlvbiB8IFNjb3BlIHxcbnwtLS0tLS0tLS0tfC0tLS0tLS18XG58IGB+Ly5waS9hZ2VudC9leHRlbnNpb25zLyoudHNgIHwgR2xvYmFsIChhbGwgcHJvamVjdHMpIHxcbnwgYH4vLnBpL2FnZW50L2V4dGVuc2lvbnMvKi9pbmRleC50c2AgfCBHbG9iYWwgKHN1YmRpcmVjdG9yeSkgfFxufCBgLnBpL2V4dGVuc2lvbnMvKi50c2AgfCBQcm9qZWN0LWxvY2FsIHxcbnwgYC5waS9leHRlbnNpb25zLyovaW5kZXgudHNgIHwgUHJvamVjdC1sb2NhbCAoc3ViZGlyZWN0b3J5KSB8XG5cbkFkZGl0aW9uYWwgcGF0aHMgdmlhIGBzZXR0aW5ncy5qc29uYDpcblxuYGBganNvblxue1xuICBcInBhY2thZ2VzXCI6IFtcbiAgICBcIm5wbTpAZm9vL2JhckAxLjAuMFwiLFxuICAgIFwiZ2l0OmdpdGh1Yi5jb20vdXNlci9yZXBvQHYxXCJcbiAgXSxcbiAgXCJleHRlbnNpb25zXCI6IFtcbiAgICBcIi9wYXRoL3RvL2xvY2FsL2V4dGVuc2lvbi50c1wiLFxuICAgIFwiL3BhdGgvdG8vbG9jYWwvZXh0ZW5zaW9uL2RpclwiXG4gIF1cbn1cbmBgYFxuXG5UbyBzaGFyZSBleHRlbnNpb25zIHZpYSBucG0gb3IgZ2l0IGFzIHBpIHBhY2thZ2VzLCBzZWUgW3BhY2thZ2VzLm1kXShwYWNrYWdlcy5tZCkuXG5cbiMjIEF2YWlsYWJsZSBJbXBvcnRzXG5cbnwgUGFja2FnZSB8IFB1cnBvc2UgfFxufC0tLS0tLS0tLXwtLS0tLS0tLS18XG58IGBAZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50YCB8IEV4dGVuc2lvbiB0eXBlcyAoYEV4dGVuc2lvbkFQSWAsIGBFeHRlbnNpb25Db250ZXh0YCwgZXZlbnRzKSB8XG58IGB0eXBlYm94YCB8IFNjaGVtYSBkZWZpbml0aW9ucyBmb3IgdG9vbCBwYXJhbWV0ZXJzIHxcbnwgYEBlYXJlbmRpbC13b3Jrcy9waS1haWAgfCBBSSB1dGlsaXRpZXMgKGBTdHJpbmdFbnVtYCBmb3IgR29vZ2xlLWNvbXBhdGlibGUgZW51bXMpIHxcbnwgYEBlYXJlbmRpbC13b3Jrcy9waS10dWlgIHwgVFVJIGNvbXBvbmVudHMgZm9yIGN1c3RvbSByZW5kZXJpbmcgfFxuXG5ucG0gZGVwZW5kZW5jaWVzIHdvcmsgdG9vLiBBZGQgYSBgcGFja2FnZS5qc29uYCBuZXh0IHRvIHlvdXIgZXh0ZW5zaW9uIChvciBpbiBhIHBhcmVudCBkaXJlY3RvcnkpLCBydW4gYG5wbSBpbnN0YWxsYCwgYW5kIGltcG9ydHMgZnJvbSBgbm9kZV9tb2R1bGVzL2AgYXJlIHJlc29sdmVkIGF1dG9tYXRpY2FsbHkuXG5cbkZvciBkaXN0cmlidXRlZCBwaSBwYWNrYWdlcyBpbnN0YWxsZWQgd2l0aCBgcGkgaW5zdGFsbGAgKG5wbSBvciBnaXQpLCBydW50aW1lIGRlcHMgbXVzdCBiZSBpbiBgZGVwZW5kZW5jaWVzYC4gUGFja2FnZSBpbnN0YWxsYXRpb24gdXNlcyBwcm9kdWN0aW9uIGluc3RhbGxzIChgbnBtIGluc3RhbGwgLS1vbWl0PWRldmApIGJ5IGRlZmF1bHQsIHNvIGBkZXZEZXBlbmRlbmNpZXNgIGFyZSBub3QgYXZhaWxhYmxlIGF0IHJ1bnRpbWU7IHdoZW4gYG5wbUNvbW1hbmRgIGlzIGNvbmZpZ3VyZWQsIGdpdCBwYWNrYWdlcyB1c2UgcGxhaW4gYGluc3RhbGxgIGZvciBjb21wYXRpYmlsaXR5IHdpdGggd3JhcHBlcnMuXG5cbk5vZGUuanMgYnVpbHQtaW5zIChgbm9kZTpmc2AsIGBub2RlOnBhdGhgLCBldGMuKSBhcmUgYWxzbyBhdmFpbGFibGUuXG5cbiMjIFdyaXRpbmcgYW4gRXh0ZW5zaW9uXG5cbkFuIGV4dGVuc2lvbiBleHBvcnRzIGEgZGVmYXVsdCBmYWN0b3J5IGZ1bmN0aW9uIHRoYXQgcmVjZWl2ZXMgYEV4dGVuc2lvbkFQSWAuIFRoZSBmYWN0b3J5IGNhbiBiZSBzeW5jaHJvbm91cyBvciBhc3luY2hyb25vdXM6XG5cbmBgYHR5cGVzY3JpcHRcbmltcG9ydCB0eXBlIHsgRXh0ZW5zaW9uQVBJIH0gZnJvbSBcIkBlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnRcIjtcblxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gKHBpOiBFeHRlbnNpb25BUEkpIHtcbiAgLy8gU3Vic2NyaWJlIHRvIGV2ZW50c1xuICBwaS5vbihcImV2ZW50X25hbWVcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgICAvLyBjdHgudWkgZm9yIHVzZXIgaW50ZXJhY3Rpb25cbiAgICBjb25zdCBvayA9IGF3YWl0IGN0eC51aS5jb25maXJtKFwiVGl0bGVcIiwgXCJBcmUgeW91IHN1cmU/XCIpO1xuICAgIGN0eC51aS5ub3RpZnkoXCJEb25lIVwiLCBcImluZm9cIik7XG4gICAgY3R4LnVpLnNldFN0YXR1cyhcIm15LWV4dFwiLCBcIlByb2Nlc3NpbmcuLi5cIik7ICAvLyBGb290ZXIgc3RhdHVzXG4gICAgY3R4LnVpLnNldFdpZGdldChcIm15LWV4dFwiLCBbXCJMaW5lIDFcIiwgXCJMaW5lIDJcIl0pOyAgLy8gV2lkZ2V0IGFib3ZlIGVkaXRvciAoZGVmYXVsdClcbiAgfSk7XG5cbiAgLy8gUmVnaXN0ZXIgdG9vbHMsIGNvbW1hbmRzLCBzaG9ydGN1dHMsIGZsYWdzXG4gIHBpLnJlZ2lzdGVyVG9vbCh7IC4uLiB9KTtcbiAgcGkucmVnaXN0ZXJDb21tYW5kKFwibmFtZVwiLCB7IC4uLiB9KTtcbiAgcGkucmVnaXN0ZXJTaG9ydGN1dChcImN0cmwreFwiLCB7IC4uLiB9KTtcbiAgcGkucmVnaXN0ZXJGbGFnKFwibXktZmxhZ1wiLCB7IC4uLiB9KTtcbn1cbmBgYFxuXG5FeHRlbnNpb25zIGFyZSBsb2FkZWQgdmlhIFtqaXRpXShodHRwczovL2dpdGh1Yi5jb20vdW5qcy9qaXRpKSwgc28gVHlwZVNjcmlwdCB3b3JrcyB3aXRob3V0IGNvbXBpbGF0aW9uLlxuXG5JZiB0aGUgZmFjdG9yeSByZXR1cm5zIGEgYFByb21pc2VgLCBwaSBhd2FpdHMgaXQgYmVmb3JlIGNvbnRpbnVpbmcgc3RhcnR1cC4gVGhhdCBtZWFucyBhc3luYyBpbml0aWFsaXphdGlvbiBjb21wbGV0ZXMgYmVmb3JlIGBzZXNzaW9uX3N0YXJ0YCwgYmVmb3JlIGByZXNvdXJjZXNfZGlzY292ZXJgLCBhbmQgYmVmb3JlIHByb3ZpZGVyIHJlZ2lzdHJhdGlvbnMgcXVldWVkIHZpYSBgcGkucmVnaXN0ZXJQcm92aWRlcigpYCBhcmUgZmx1c2hlZC5cblxuIyMjIEFzeW5jIGZhY3RvcnkgZnVuY3Rpb25zXG5cblVzZSBhbiBhc3luYyBmYWN0b3J5IGZvciBvbmUtdGltZSBzdGFydHVwIHdvcmsgc3VjaCBhcyBmZXRjaGluZyByZW1vdGUgY29uZmlndXJhdGlvbiBvciBkeW5hbWljYWxseSBkaXNjb3ZlcmluZyBhdmFpbGFibGUgbW9kZWxzLlxuXG5gYGB0eXBlc2NyaXB0XG5pbXBvcnQgdHlwZSB7IEV4dGVuc2lvbkFQSSB9IGZyb20gXCJAZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50XCI7XG5cbmV4cG9ydCBkZWZhdWx0IGFzeW5jIGZ1bmN0aW9uIChwaTogRXh0ZW5zaW9uQVBJKSB7XG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goXCJodHRwOi8vbG9jYWxob3N0OjEyMzQvdjEvbW9kZWxzXCIpO1xuICBjb25zdCBwYXlsb2FkID0gKGF3YWl0IHJlc3BvbnNlLmpzb24oKSkgYXMge1xuICAgIGRhdGE6IEFycmF5PHtcbiAgICAgIGlkOiBzdHJpbmc7XG4gICAgICBuYW1lPzogc3RyaW5nO1xuICAgICAgY29udGV4dF93aW5kb3c/OiBudW1iZXI7XG4gICAgICBtYXhfdG9rZW5zPzogbnVtYmVyO1xuICAgIH0+O1xuICB9O1xuXG4gIHBpLnJlZ2lzdGVyUHJvdmlkZXIoXCJsb2NhbC1vcGVuYWlcIiwge1xuICAgIGJhc2VVcmw6IFwiaHR0cDovL2xvY2FsaG9zdDoxMjM0L3YxXCIsXG4gICAgYXBpS2V5OiBcIiRMT0NBTF9PUEVOQUlfQVBJX0tFWVwiLFxuICAgIGFwaTogXCJvcGVuYWktY29tcGxldGlvbnNcIixcbiAgICBtb2RlbHM6IHBheWxvYWQuZGF0YS5tYXAoKG1vZGVsKSA9PiAoe1xuICAgICAgaWQ6IG1vZGVsLmlkLFxuICAgICAgbmFtZTogbW9kZWwubmFtZSA/PyBtb2RlbC5pZCxcbiAgICAgIHJlYXNvbmluZzogZmFsc2UsXG4gICAgICBpbnB1dDogW1widGV4dFwiXSxcbiAgICAgIGNvc3Q6IHsgaW5wdXQ6IDAsIG91dHB1dDogMCwgY2FjaGVSZWFkOiAwLCBjYWNoZVdyaXRlOiAwIH0sXG4gICAgICBjb250ZXh0V2luZG93OiBtb2RlbC5jb250ZXh0X3dpbmRvdyA/PyAxMjgwMDAsXG4gICAgICBtYXhUb2tlbnM6IG1vZGVsLm1heF90b2tlbnMgPz8gNDA5NixcbiAgICB9KSksXG4gIH0pO1xufVxuYGBgXG5cblRoaXMgcGF0dGVybiBtYWtlcyB0aGUgZmV0Y2hlZCBtb2RlbHMgYXZhaWxhYmxlIGR1cmluZyBub3JtYWwgc3RhcnR1cCBhbmQgdG8gYHBpIC0tbGlzdC1tb2RlbHNgLlxuXG4jIyMgTG9uZy1saXZlZCByZXNvdXJjZXMgYW5kIHNodXRkb3duXG5cbkV4dGVuc2lvbiBmYWN0b3JpZXMgbWF5IHJ1biBpbiBpbnZvY2F0aW9ucyB0aGF0IG5ldmVyIHN0YXJ0IGEgc2Vzc2lvbi4gRG8gbm90IHN0YXJ0IGJhY2tncm91bmQgcmVzb3VyY2VzIHN1Y2ggYXMgcHJvY2Vzc2VzLCBzb2NrZXRzLCBmaWxlIHdhdGNoZXJzLCBvciB0aW1lcnMgZnJvbSB0aGUgZmFjdG9yeS5cblxuRGVmZXIgYmFja2dyb3VuZCByZXNvdXJjZSBzdGFydHVwIHVudGlsIGBzZXNzaW9uX3N0YXJ0YCBvciB0aGUgY29tbWFuZC90b29sL2V2ZW50IHRoYXQgbmVlZHMgdGhlIHJlc291cmNlLiBSZWdpc3RlciBhbiBpZGVtcG90ZW50IGBzZXNzaW9uX3NodXRkb3duYCBoYW5kbGVyIHRvIGNsb3NlIGFueSBzZXNzaW9uLXNjb3BlZCByZXNvdXJjZXMgeW91IHN0YXJ0LlxuXG4jIyMgRXh0ZW5zaW9uIFN0eWxlc1xuXG4qKlNpbmdsZSBmaWxlKiogLSBzaW1wbGVzdCwgZm9yIHNtYWxsIGV4dGVuc2lvbnM6XG5cbmBgYFxufi8ucGkvYWdlbnQvZXh0ZW5zaW9ucy9cbuKUlOKUgOKUgCBteS1leHRlbnNpb24udHNcbmBgYFxuXG4qKkRpcmVjdG9yeSB3aXRoIGluZGV4LnRzKiogLSBmb3IgbXVsdGktZmlsZSBleHRlbnNpb25zOlxuXG5gYGBcbn4vLnBpL2FnZW50L2V4dGVuc2lvbnMvXG7ilJTilIDilIAgbXktZXh0ZW5zaW9uL1xuICAgIOKUnOKUgOKUgCBpbmRleC50cyAgICAgICAgIyBFbnRyeSBwb2ludCAoZXhwb3J0cyBkZWZhdWx0IGZ1bmN0aW9uKVxuICAgIOKUnOKUgOKUgCB0b29scy50cyAgICAgICAgIyBIZWxwZXIgbW9kdWxlXG4gICAg4pSU4pSA4pSAIHV0aWxzLnRzICAgICAgICAjIEhlbHBlciBtb2R1bGVcbmBgYFxuXG4qKlBhY2thZ2Ugd2l0aCBkZXBlbmRlbmNpZXMqKiAtIGZvciBleHRlbnNpb25zIHRoYXQgbmVlZCBucG0gcGFja2FnZXM6XG5cbmBgYFxufi8ucGkvYWdlbnQvZXh0ZW5zaW9ucy9cbuKUlOKUgOKUgCBteS1leHRlbnNpb24vXG4gICAg4pSc4pSA4pSAIHBhY2thZ2UuanNvbiAgICAjIERlY2xhcmVzIGRlcGVuZGVuY2llcyBhbmQgZW50cnkgcG9pbnRzXG4gICAg4pSc4pSA4pSAIHBhY2thZ2UtbG9jay5qc29uXG4gICAg4pSc4pSA4pSAIG5vZGVfbW9kdWxlcy8gICAjIEFmdGVyIG5wbSBpbnN0YWxsXG4gICAg4pSU4pSA4pSAIHNyYy9cbiAgICAgICAg4pSU4pSA4pSAIGluZGV4LnRzXG5gYGBcblxuYGBganNvblxuLy8gcGFja2FnZS5qc29uXG57XG4gIFwibmFtZVwiOiBcIm15LWV4dGVuc2lvblwiLFxuICBcImRlcGVuZGVuY2llc1wiOiB7XG4gICAgXCJ6b2RcIjogXCJeMy4wLjBcIixcbiAgICBcImNoYWxrXCI6IFwiXjUuMC4wXCJcbiAgfSxcbiAgXCJwaVwiOiB7XG4gICAgXCJleHRlbnNpb25zXCI6IFtcIi4vc3JjL2luZGV4LnRzXCJdXG4gIH1cbn1cbmBgYFxuXG5SdW4gYG5wbSBpbnN0YWxsYCBpbiB0aGUgZXh0ZW5zaW9uIGRpcmVjdG9yeSwgdGhlbiBpbXBvcnRzIGZyb20gYG5vZGVfbW9kdWxlcy9gIHdvcmsgYXV0b21hdGljYWxseS5cblxuIyMgRXZlbnRzXG5cbiMjIyBMaWZlY3ljbGUgT3ZlcnZpZXdcblxuYGBgXG5waSBzdGFydHNcbiAg4pSCXG4gIOKUnOKUgOKWuiBwcm9qZWN0X3RydXN0ICh1c2VyL2dsb2JhbCBhbmQgQ0xJIGV4dGVuc2lvbnMgb25seSwgYmVmb3JlIHByb2plY3QgcmVzb3VyY2VzIGxvYWQpXG4gIOKUnOKUgOKWuiBzZXNzaW9uX3N0YXJ0IHsgcmVhc29uOiBcInN0YXJ0dXBcIiB9XG4gIOKUlOKUgOKWuiByZXNvdXJjZXNfZGlzY292ZXIgeyByZWFzb246IFwic3RhcnR1cFwiIH1cbiAgICAgIOKUglxuICAgICAg4pa8XG51c2VyIHNlbmRzIHByb21wdCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilJBcbiAg4pSCICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDilIJcbiAg4pSc4pSA4pa6IChleHRlbnNpb24gY29tbWFuZHMgY2hlY2tlZCBmaXJzdCwgYnlwYXNzIGlmIGZvdW5kKSAg4pSCXG4gIOKUnOKUgOKWuiBpbnB1dCAoY2FuIGludGVyY2VwdCwgdHJhbnNmb3JtLCBvciBoYW5kbGUpICAgICAgICAgIOKUglxuICDilJzilIDilrogKHNraWxsL3RlbXBsYXRlIGV4cGFuc2lvbiBpZiBub3QgaGFuZGxlZCkgICAgICAgICAgICDilIJcbiAg4pSc4pSA4pa6IGJlZm9yZV9hZ2VudF9zdGFydCAoY2FuIGluamVjdCBtZXNzYWdlLCBtb2RpZnkgc3lzdGVtIHByb21wdClcbiAg4pSc4pSA4pa6IGFnZW50X3N0YXJ0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4pSCXG4gIOKUnOKUgOKWuiBtZXNzYWdlX3N0YXJ0IC8gbWVzc2FnZV91cGRhdGUgLyBtZXNzYWdlX2VuZCAgICAgICAgIOKUglxuICDilIIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKUglxuICDilIIgICDilIzilIDilIDilIAgdHVybiAocmVwZWF0cyB3aGlsZSBMTE0gY2FsbHMgdG9vbHMpIOKUgOKUgOKUgOKUkCAgICAgICDilIJcbiAg4pSCICAg4pSCICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDilIIgICAgICAg4pSCXG4gIOKUgiAgIOKUnOKUgOKWuiB0dXJuX3N0YXJ0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKUgiAgICAgICDilIJcbiAg4pSCICAg4pSc4pSA4pa6IGNvbnRleHQgKGNhbiBtb2RpZnkgbWVzc2FnZXMpICAgICAgICAgICAg4pSCICAgICAgIOKUglxuICDilIIgICDilJzilIDilrogYmVmb3JlX3Byb3ZpZGVyX3JlcXVlc3QgKGNhbiBpbnNwZWN0IG9yIHJlcGxhY2UgcGF5bG9hZClcbiAg4pSCICAg4pSc4pSA4pa6IGFmdGVyX3Byb3ZpZGVyX3Jlc3BvbnNlIChzdGF0dXMgKyBoZWFkZXJzLCBiZWZvcmUgc3RyZWFtIGNvbnN1bWUpXG4gIOKUgiAgIOKUgiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4pSCICAgICAgIOKUglxuICDilIIgICDilIIgICBMTE0gcmVzcG9uZHMsIG1heSBjYWxsIHRvb2xzOiAgICAgICAgICAgIOKUgiAgICAgICDilIJcbiAg4pSCICAg4pSCICAgICDilJzilIDilrogdG9vbF9leGVjdXRpb25fc3RhcnQgICAgICAgICAgICAgICDilIIgICAgICAg4pSCXG4gIOKUgiAgIOKUgiAgICAg4pSc4pSA4pa6IHRvb2xfY2FsbCAoY2FuIGJsb2NrKSAgICAgICAgICAgICAg4pSCICAgICAgIOKUglxuICDilIIgICDilIIgICAgIOKUnOKUgOKWuiB0b29sX2V4ZWN1dGlvbl91cGRhdGUgICAgICAgICAgICAgIOKUgiAgICAgICDilIJcbiAg4pSCICAg4pSCICAgICDilJzilIDilrogdG9vbF9yZXN1bHQgKGNhbiBtb2RpZnkpICAgICAgICAgICDilIIgICAgICAg4pSCXG4gIOKUgiAgIOKUgiAgICAg4pSU4pSA4pa6IHRvb2xfZXhlY3V0aW9uX2VuZCAgICAgICAgICAgICAgICAg4pSCICAgICAgIOKUglxuICDilIIgICDilIIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKUgiAgICAgICDilIJcbiAg4pSCICAg4pSU4pSA4pa6IHR1cm5fZW5kICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4pSCICAgICAgIOKUglxuICDilIIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKUglxuICDilJTilIDilrogYWdlbnRfZW5kICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDilIJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4pSCXG51c2VyIHNlbmRzIGFub3RoZXIgcHJvbXB0IOKXhOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUmFxuXG4vbmV3IChuZXcgc2Vzc2lvbikgb3IgL3Jlc3VtZSAoc3dpdGNoIHNlc3Npb24pXG4gIOKUnOKUgOKWuiBzZXNzaW9uX2JlZm9yZV9zd2l0Y2ggKGNhbiBjYW5jZWwpXG4gIOKUnOKUgOKWuiBzZXNzaW9uX3NodXRkb3duXG4gIOKUnOKUgOKWuiBzZXNzaW9uX3N0YXJ0IHsgcmVhc29uOiBcIm5ld1wiIHwgXCJyZXN1bWVcIiwgcHJldmlvdXNTZXNzaW9uRmlsZT8gfVxuICDilJTilIDilrogcmVzb3VyY2VzX2Rpc2NvdmVyIHsgcmVhc29uOiBcInN0YXJ0dXBcIiB9XG5cbi9mb3JrIG9yIC9jbG9uZVxuICDilJzilIDilrogc2Vzc2lvbl9iZWZvcmVfZm9yayAoY2FuIGNhbmNlbClcbiAg4pSc4pSA4pa6IHNlc3Npb25fc2h1dGRvd25cbiAg4pSc4pSA4pa6IHNlc3Npb25fc3RhcnQgeyByZWFzb246IFwiZm9ya1wiLCBwcmV2aW91c1Nlc3Npb25GaWxlIH1cbiAg4pSU4pSA4pa6IHJlc291cmNlc19kaXNjb3ZlciB7IHJlYXNvbjogXCJzdGFydHVwXCIgfVxuXG4vY29tcGFjdCBvciBhdXRvLWNvbXBhY3Rpb25cbiAg4pSc4pSA4pa6IHNlc3Npb25fYmVmb3JlX2NvbXBhY3QgKGNhbiBjYW5jZWwgb3IgY3VzdG9taXplKVxuICDilJTilIDilrogc2Vzc2lvbl9jb21wYWN0XG5cbi90cmVlIG5hdmlnYXRpb25cbiAg4pSc4pSA4pa6IHNlc3Npb25fYmVmb3JlX3RyZWUgKGNhbiBjYW5jZWwgb3IgY3VzdG9taXplKVxuICDilJTilIDilrogc2Vzc2lvbl90cmVlXG5cbi9tb2RlbCBvciBDdHJsK1AgKG1vZGVsIHNlbGVjdGlvbi9jeWNsaW5nKVxuICDilJzilIDilrogdGhpbmtpbmdfbGV2ZWxfc2VsZWN0IChpZiBtb2RlbCBjaGFuZ2UgY2hhbmdlcy9jbGFtcHMgdGhpbmtpbmcgbGV2ZWwpXG4gIOKUlOKUgOKWuiBtb2RlbF9zZWxlY3RcblxudGhpbmtpbmcgbGV2ZWwgY2hhbmdlcyAoc2V0dGluZ3MsIGtleWJpbmRpbmcsIHBpLnNldFRoaW5raW5nTGV2ZWwoKSlcbiAg4pSU4pSA4pa6IHRoaW5raW5nX2xldmVsX3NlbGVjdFxuXG5leGl0IChDdHJsK0MsIEN0cmwrRCwgU0lHSFVQLCBTSUdURVJNKVxuICDilJTilIDilrogc2Vzc2lvbl9zaHV0ZG93blxuYGBgXG5cbiMjIyBTdGFydHVwIEV2ZW50c1xuXG4jIyMjIHByb2plY3RfdHJ1c3RcblxuRmlyZWQgYmVmb3JlIHBpIGRlY2lkZXMgd2hldGhlciB0byB0cnVzdCBhIHByb2plY3Qgd2l0aCBkeW5hbWljIGNvbmZpZ3MgKGAucGlgIG9yIGAuYWdlbnRzL3NraWxsc2ApLiBJdCBydW5zIGR1cmluZyBzdGFydHVwIGFuZCB3aGVuIHNlc3Npb24gcmVwbGFjZW1lbnQgKGZvciBleGFtcGxlIGAvcmVzdW1lYCkgZW50ZXJzIGEgY3dkIHdob3NlIHRydXN0IGhhcyBub3QgYmVlbiByZXNvbHZlZCBpbiB0aGUgY3VycmVudCBwcm9jZXNzLiBPbmx5IHVzZXIvZ2xvYmFsIGV4dGVuc2lvbnMgYW5kIENMSSBgLWVgIGV4dGVuc2lvbnMgcGFydGljaXBhdGU7IHByb2plY3QtbG9jYWwgZXh0ZW5zaW9ucyBhcmUgbm90IGxvYWRlZCB1bnRpbCBhZnRlciB0cnVzdCBpcyByZXNvbHZlZC5cblxuYGBgdHlwZXNjcmlwdFxucGkub24oXCJwcm9qZWN0X3RydXN0XCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIC8vIGV2ZW50LmN3ZCAtIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnlcbiAgLy8gY3R4IGhhcyBhIGxpbWl0ZWQgdHJ1c3QgY29udGV4dDogY3dkLCBtb2RlLCBoYXNVSSwgYW5kIHNlbGVjdC9jb25maXJtL2lucHV0L25vdGlmeSBVSSBoZWxwZXJzXG4gIGlmIChhd2FpdCBjdHgudWkuY29uZmlybShcIlRydXN0IHByb2plY3Q/XCIsIGV2ZW50LmN3ZCkpIHtcbiAgICByZXR1cm4geyB0cnVzdGVkOiBcInllc1wiLCByZW1lbWJlcjogdHJ1ZSB9O1xuICB9XG4gIHJldHVybiB7IHRydXN0ZWQ6IFwidW5kZWNpZGVkXCIgfTtcbn0pO1xuYGBgXG5cbkEgYHByb2plY3RfdHJ1c3RgIGhhbmRsZXIgbXVzdCByZXR1cm4gYHsgdHJ1c3RlZDogXCJ5ZXNcIiB8IFwibm9cIiB8IFwidW5kZWNpZGVkXCIgfWAuIEEgdXNlci9nbG9iYWwgb3IgQ0xJIGV4dGVuc2lvbiB0aGF0IHJldHVybnMgYFwieWVzXCJgIG9yIGBcIm5vXCJgIG93bnMgdGhlIGRlY2lzaW9uOyB0aGUgZmlyc3QgeWVzL25vIGRlY2lzaW9uIHdpbnMgYW5kIHN1cHByZXNzZXMgdGhlIGJ1aWx0LWluIHRydXN0IHByb21wdC4gVXNlIGByZW1lbWJlcjogdHJ1ZWAgdG8gcGVyc2lzdCBhIHllcy9ubyBkZWNpc2lvbjsgb3RoZXJ3aXNlIGl0IGFwcGxpZXMgb25seSB0byB0aGUgY3VycmVudCBwcm9jZXNzLiBSZXR1cm4gYFwidW5kZWNpZGVkXCJgIHRvIGxldCBsYXRlciBoYW5kbGVycyBvciB0aGUgYnVpbHQtaW4gdHJ1c3QgZmxvdyBkZWNpZGUuIENoZWNrIGBjdHguaGFzVUlgIGJlZm9yZSBwcm9tcHRpbmcuIElmIG5vIGhhbmRsZXIgcmV0dXJucyB5ZXMvbm8sIG5vcm1hbCB0cnVzdCByZXNvbHV0aW9uIGNvbnRpbnVlczogc2F2ZWQgYHRydXN0Lmpzb25gIGRlY2lzaW9ucyBhcHBseSBmaXJzdCwgdGhlbiBgZGVmYXVsdFByb2plY3RUcnVzdGAgY29udHJvbHMgd2hldGhlciBwaSBhc2tzLCB0cnVzdHMsIG9yIGRlY2xpbmVzIGJ5IGRlZmF1bHQuXG5cbiMjIyBSZXNvdXJjZSBFdmVudHNcblxuIyMjIyByZXNvdXJjZXNfZGlzY292ZXJcblxuRmlyZWQgYWZ0ZXIgYHNlc3Npb25fc3RhcnRgIHNvIGV4dGVuc2lvbnMgY2FuIGNvbnRyaWJ1dGUgYWRkaXRpb25hbCBza2lsbCwgcHJvbXB0LCBhbmQgdGhlbWUgcGF0aHMuXG5UaGUgc3RhcnR1cCBwYXRoIHVzZXMgYHJlYXNvbjogXCJzdGFydHVwXCJgLiBSZWxvYWQgdXNlcyBgcmVhc29uOiBcInJlbG9hZFwiYC5cblxuYGBgdHlwZXNjcmlwdFxucGkub24oXCJyZXNvdXJjZXNfZGlzY292ZXJcIiwgYXN5bmMgKGV2ZW50LCBfY3R4KSA9PiB7XG4gIC8vIGV2ZW50LmN3ZCAtIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnlcbiAgLy8gZXZlbnQucmVhc29uIC0gXCJzdGFydHVwXCIgfCBcInJlbG9hZFwiXG4gIHJldHVybiB7XG4gICAgc2tpbGxQYXRoczogW1wiL3BhdGgvdG8vc2tpbGxzXCJdLFxuICAgIHByb21wdFBhdGhzOiBbXCIvcGF0aC90by9wcm9tcHRzXCJdLFxuICAgIHRoZW1lUGF0aHM6IFtcIi9wYXRoL3RvL3RoZW1lc1wiXSxcbiAgfTtcbn0pO1xuYGBgXG5cbiMjIyBTZXNzaW9uIEV2ZW50c1xuXG5TZWUgW1Nlc3Npb24gRm9ybWF0XShzZXNzaW9uLWZvcm1hdC5tZCkgZm9yIHNlc3Npb24gc3RvcmFnZSBpbnRlcm5hbHMgYW5kIHRoZSBTZXNzaW9uTWFuYWdlciBBUEkuXG5cbiMjIyMgc2Vzc2lvbl9zdGFydFxuXG5GaXJlZCB3aGVuIGEgc2Vzc2lvbiBpcyBzdGFydGVkLCBsb2FkZWQsIG9yIHJlbG9hZGVkLlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcInNlc3Npb25fc3RhcnRcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQucmVhc29uIC0gXCJzdGFydHVwXCIgfCBcInJlbG9hZFwiIHwgXCJuZXdcIiB8IFwicmVzdW1lXCIgfCBcImZvcmtcIlxuICAvLyBldmVudC5wcmV2aW91c1Nlc3Npb25GaWxlIC0gcHJlc2VudCBmb3IgXCJuZXdcIiwgXCJyZXN1bWVcIiwgYW5kIFwiZm9ya1wiXG4gIGN0eC51aS5ub3RpZnkoYFNlc3Npb246ICR7Y3R4LnNlc3Npb25NYW5hZ2VyLmdldFNlc3Npb25GaWxlKCkgPz8gXCJlcGhlbWVyYWxcIn1gLCBcImluZm9cIik7XG59KTtcbmBgYFxuXG4jIyMjIHNlc3Npb25fYmVmb3JlX3N3aXRjaFxuXG5GaXJlZCBiZWZvcmUgc3RhcnRpbmcgYSBuZXcgc2Vzc2lvbiAoYC9uZXdgKSBvciBzd2l0Y2hpbmcgc2Vzc2lvbnMgKGAvcmVzdW1lYCkuXG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwic2Vzc2lvbl9iZWZvcmVfc3dpdGNoXCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIC8vIGV2ZW50LnJlYXNvbiAtIFwibmV3XCIgb3IgXCJyZXN1bWVcIlxuICAvLyBldmVudC50YXJnZXRTZXNzaW9uRmlsZSAtIHNlc3Npb24gd2UncmUgc3dpdGNoaW5nIHRvIChvbmx5IGZvciBcInJlc3VtZVwiKVxuXG4gIGlmIChldmVudC5yZWFzb24gPT09IFwibmV3XCIpIHtcbiAgICBjb25zdCBvayA9IGF3YWl0IGN0eC51aS5jb25maXJtKFwiQ2xlYXI/XCIsIFwiRGVsZXRlIGFsbCBtZXNzYWdlcz9cIik7XG4gICAgaWYgKCFvaykgcmV0dXJuIHsgY2FuY2VsOiB0cnVlIH07XG4gIH1cbn0pO1xuYGBgXG5cbkFmdGVyIGEgc3VjY2Vzc2Z1bCBzd2l0Y2ggb3IgbmV3LXNlc3Npb24gYWN0aW9uLCBwaSBlbWl0cyBgc2Vzc2lvbl9zaHV0ZG93bmAgZm9yIHRoZSBvbGQgZXh0ZW5zaW9uIGluc3RhbmNlLCByZWxvYWRzIGFuZCByZWJpbmRzIGV4dGVuc2lvbnMgZm9yIHRoZSBuZXcgc2Vzc2lvbiwgdGhlbiBlbWl0cyBgc2Vzc2lvbl9zdGFydGAgd2l0aCBgcmVhc29uOiBcIm5ld1wiIHwgXCJyZXN1bWVcImAgYW5kIGBwcmV2aW91c1Nlc3Npb25GaWxlYC5cbkRvIGNsZWFudXAgd29yayBpbiBgc2Vzc2lvbl9zaHV0ZG93bmAsIHRoZW4gcmVlc3RhYmxpc2ggYW55IGluLW1lbW9yeSBzdGF0ZSBpbiBgc2Vzc2lvbl9zdGFydGAuXG5cbiMjIyMgc2Vzc2lvbl9iZWZvcmVfZm9ya1xuXG5GaXJlZCB3aGVuIGZvcmtpbmcgdmlhIGAvZm9ya2Agb3IgY2xvbmluZyB2aWEgYC9jbG9uZWAuXG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwic2Vzc2lvbl9iZWZvcmVfZm9ya1wiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAvLyBldmVudC5lbnRyeUlkIC0gSUQgb2YgdGhlIHNlbGVjdGVkIGVudHJ5XG4gIC8vIGV2ZW50LnBvc2l0aW9uIC0gXCJiZWZvcmVcIiBmb3IgL2ZvcmssIFwiYXRcIiBmb3IgL2Nsb25lXG4gIHJldHVybiB7IGNhbmNlbDogdHJ1ZSB9OyAvLyBDYW5jZWwgZm9yay9jbG9uZVxuICAvLyBPUlxuICByZXR1cm4geyBza2lwQ29udmVyc2F0aW9uUmVzdG9yZTogdHJ1ZSB9OyAvLyBSZXNlcnZlZCBmb3IgZnV0dXJlIGNvbnZlcnNhdGlvbiByZXN0b3JlIGNvbnRyb2xcbn0pO1xuYGBgXG5cbkFmdGVyIGEgc3VjY2Vzc2Z1bCBmb3JrIG9yIGNsb25lLCBwaSBlbWl0cyBgc2Vzc2lvbl9zaHV0ZG93bmAgZm9yIHRoZSBvbGQgZXh0ZW5zaW9uIGluc3RhbmNlLCByZWxvYWRzIGFuZCByZWJpbmRzIGV4dGVuc2lvbnMgZm9yIHRoZSBuZXcgc2Vzc2lvbiwgdGhlbiBlbWl0cyBgc2Vzc2lvbl9zdGFydGAgd2l0aCBgcmVhc29uOiBcImZvcmtcImAgYW5kIGBwcmV2aW91c1Nlc3Npb25GaWxlYC5cbkRvIGNsZWFudXAgd29yayBpbiBgc2Vzc2lvbl9zaHV0ZG93bmAsIHRoZW4gcmVlc3RhYmxpc2ggYW55IGluLW1lbW9yeSBzdGF0ZSBpbiBgc2Vzc2lvbl9zdGFydGAuXG5cbiMjIyMgc2Vzc2lvbl9iZWZvcmVfY29tcGFjdCAvIHNlc3Npb25fY29tcGFjdFxuXG5GaXJlZCBvbiBjb21wYWN0aW9uLiBTZWUgW2NvbXBhY3Rpb24ubWRdKGNvbXBhY3Rpb24ubWQpIGZvciBkZXRhaWxzLlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcInNlc3Npb25fYmVmb3JlX2NvbXBhY3RcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgY29uc3QgeyBwcmVwYXJhdGlvbiwgYnJhbmNoRW50cmllcywgY3VzdG9tSW5zdHJ1Y3Rpb25zLCBzaWduYWwgfSA9IGV2ZW50O1xuXG4gIC8vIENhbmNlbDpcbiAgcmV0dXJuIHsgY2FuY2VsOiB0cnVlIH07XG5cbiAgLy8gQ3VzdG9tIHN1bW1hcnk6XG4gIHJldHVybiB7XG4gICAgY29tcGFjdGlvbjoge1xuICAgICAgc3VtbWFyeTogXCIuLi5cIixcbiAgICAgIGZpcnN0S2VwdEVudHJ5SWQ6IHByZXBhcmF0aW9uLmZpcnN0S2VwdEVudHJ5SWQsXG4gICAgICB0b2tlbnNCZWZvcmU6IHByZXBhcmF0aW9uLnRva2Vuc0JlZm9yZSxcbiAgICB9XG4gIH07XG59KTtcblxucGkub24oXCJzZXNzaW9uX2NvbXBhY3RcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQuY29tcGFjdGlvbkVudHJ5IC0gdGhlIHNhdmVkIGNvbXBhY3Rpb25cbiAgLy8gZXZlbnQuZnJvbUV4dGVuc2lvbiAtIHdoZXRoZXIgZXh0ZW5zaW9uIHByb3ZpZGVkIGl0XG59KTtcbmBgYFxuXG4jIyMjIHNlc3Npb25fYmVmb3JlX3RyZWUgLyBzZXNzaW9uX3RyZWVcblxuRmlyZWQgb24gYC90cmVlYCBuYXZpZ2F0aW9uLiBTZWUgW1Nlc3Npb25zXShzZXNzaW9ucy5tZCkgZm9yIHRyZWUgbmF2aWdhdGlvbiBjb25jZXB0cy5cblxuYGBgdHlwZXNjcmlwdFxucGkub24oXCJzZXNzaW9uX2JlZm9yZV90cmVlXCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIGNvbnN0IHsgcHJlcGFyYXRpb24sIHNpZ25hbCB9ID0gZXZlbnQ7XG4gIHJldHVybiB7IGNhbmNlbDogdHJ1ZSB9O1xuICAvLyBPUiBwcm92aWRlIGN1c3RvbSBzdW1tYXJ5OlxuICByZXR1cm4geyBzdW1tYXJ5OiB7IHN1bW1hcnk6IFwiLi4uXCIsIGRldGFpbHM6IHt9IH0gfTtcbn0pO1xuXG5waS5vbihcInNlc3Npb25fdHJlZVwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAvLyBldmVudC5uZXdMZWFmSWQsIG9sZExlYWZJZCwgc3VtbWFyeUVudHJ5LCBmcm9tRXh0ZW5zaW9uXG59KTtcbmBgYFxuXG4jIyMjIHNlc3Npb25fc2h1dGRvd25cblxuRmlyZWQgYmVmb3JlIGEgc3RhcnRlZCBzZXNzaW9uIHJ1bnRpbWUgaXMgdG9ybiBkb3duLiBVc2UgdGhpcyB0byBjbGVhbiB1cCByZXNvdXJjZXMgb3BlbmVkIGZyb20gYHNlc3Npb25fc3RhcnRgIG9yIG90aGVyIHNlc3Npb24tc2NvcGVkIGhvb2tzLlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcInNlc3Npb25fc2h1dGRvd25cIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQucmVhc29uIC0gXCJxdWl0XCIgfCBcInJlbG9hZFwiIHwgXCJuZXdcIiB8IFwicmVzdW1lXCIgfCBcImZvcmtcIlxuICAvLyBldmVudC50YXJnZXRTZXNzaW9uRmlsZSAtIGRlc3RpbmF0aW9uIHNlc3Npb24gZm9yIHNlc3Npb24gcmVwbGFjZW1lbnQgZmxvd3NcbiAgLy8gQ2xlYW51cCwgc2F2ZSBzdGF0ZSwgZXRjLlxufSk7XG5gYGBcblxuIyMjIEFnZW50IEV2ZW50c1xuXG4jIyMjIGJlZm9yZV9hZ2VudF9zdGFydFxuXG5GaXJlZCBhZnRlciB1c2VyIHN1Ym1pdHMgcHJvbXB0LCBiZWZvcmUgYWdlbnQgbG9vcC4gQ2FuIGluamVjdCBhIG1lc3NhZ2UgYW5kL29yIG1vZGlmeSB0aGUgc3lzdGVtIHByb21wdC5cblxuYGBgdHlwZXNjcmlwdFxucGkub24oXCJiZWZvcmVfYWdlbnRfc3RhcnRcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQucHJvbXB0IC0gdXNlcidzIHByb21wdCB0ZXh0XG4gIC8vIGV2ZW50LmltYWdlcyAtIGF0dGFjaGVkIGltYWdlcyAoaWYgYW55KVxuICAvLyBldmVudC5zeXN0ZW1Qcm9tcHQgLSBjdXJyZW50IGNoYWluZWQgc3lzdGVtIHByb21wdCBmb3IgdGhpcyBoYW5kbGVyXG4gIC8vICAgKGluY2x1ZGVzIGNoYW5nZXMgZnJvbSBlYXJsaWVyIGJlZm9yZV9hZ2VudF9zdGFydCBoYW5kbGVycylcbiAgLy8gZXZlbnQuc3lzdGVtUHJvbXB0T3B0aW9ucyAtIHN0cnVjdHVyZWQgb3B0aW9ucyB1c2VkIHRvIGJ1aWxkIHRoZSBzeXN0ZW0gcHJvbXB0XG4gIC8vICAgLmN1c3RvbVByb21wdCAtIGFueSBjdXN0b20gc3lzdGVtIHByb21wdCAoZnJvbSAtLXN5c3RlbS1wcm9tcHQsIFNZU1RFTS5tZCwgb3IgY3VzdG9tIHRlbXBsYXRlcylcbiAgLy8gICAuc2VsZWN0ZWRUb29scyAtIHRvb2xzIGN1cnJlbnRseSBhY3RpdmUgaW4gdGhlIHByb21wdFxuICAvLyAgIC50b29sU25pcHBldHMgLSBvbmUtbGluZSBkZXNjcmlwdGlvbnMgZm9yIGVhY2ggdG9vbFxuICAvLyAgIC5wcm9tcHRHdWlkZWxpbmVzIC0gY3VzdG9tIGd1aWRlbGluZSBidWxsZXRzXG4gIC8vICAgLmFwcGVuZFN5c3RlbVByb21wdCAtIHRleHQgZnJvbSAtLWFwcGVuZC1zeXN0ZW0tcHJvbXB0IGZsYWdzXG4gIC8vICAgLmN3ZCAtIHdvcmtpbmcgZGlyZWN0b3J5XG4gIC8vICAgLmNvbnRleHRGaWxlcyAtIEFHRU5UUy5tZCBmaWxlcyBhbmQgb3RoZXIgbG9hZGVkIGNvbnRleHQgZmlsZXNcbiAgLy8gICAuc2tpbGxzIC0gbG9hZGVkIHNraWxsc1xuXG4gIHJldHVybiB7XG4gICAgLy8gSW5qZWN0IGEgcGVyc2lzdGVudCBtZXNzYWdlIChzdG9yZWQgaW4gc2Vzc2lvbiwgc2VudCB0byBMTE0pXG4gICAgbWVzc2FnZToge1xuICAgICAgY3VzdG9tVHlwZTogXCJteS1leHRlbnNpb25cIixcbiAgICAgIGNvbnRlbnQ6IFwiQWRkaXRpb25hbCBjb250ZXh0IGZvciB0aGUgTExNXCIsXG4gICAgICBkaXNwbGF5OiB0cnVlLFxuICAgIH0sXG4gICAgLy8gUmVwbGFjZSB0aGUgc3lzdGVtIHByb21wdCBmb3IgdGhpcyB0dXJuIChjaGFpbmVkIGFjcm9zcyBleHRlbnNpb25zKVxuICAgIHN5c3RlbVByb21wdDogZXZlbnQuc3lzdGVtUHJvbXB0ICsgXCJcXG5cXG5FeHRyYSBpbnN0cnVjdGlvbnMgZm9yIHRoaXMgdHVybi4uLlwiLFxuICB9O1xufSk7XG5gYGBcblxuVGhlIGBzeXN0ZW1Qcm9tcHRPcHRpb25zYCBmaWVsZCBnaXZlcyBleHRlbnNpb25zIGFjY2VzcyB0byB0aGUgc2FtZSBzdHJ1Y3R1cmVkIGRhdGEgUGkgdXNlcyB0byBidWlsZCB0aGUgc3lzdGVtIHByb21wdC4gVGhpcyBsZXRzIHlvdSBpbnNwZWN0IHdoYXQgUGkgaGFzIGxvYWRlZCDigJQgY3VzdG9tIHByb21wdHMsIGd1aWRlbGluZXMsIHRvb2wgc25pcHBldHMsIGNvbnRleHQgZmlsZXMsIHNraWxscyDigJQgd2l0aG91dCByZS1kaXNjb3ZlcmluZyByZXNvdXJjZXMgb3IgcmUtcGFyc2luZyBmbGFncy4gVXNlIGl0IHdoZW4geW91ciBleHRlbnNpb24gbmVlZHMgdG8gbWFrZSBkZWVwLCBpbmZvcm1lZCBjaGFuZ2VzIHRvIHRoZSBzeXN0ZW0gcHJvbXB0IHdoaWxlIHJlc3BlY3RpbmcgdXNlci1wcm92aWRlZCBjb25maWd1cmF0aW9uLlxuXG5JbnNpZGUgYGJlZm9yZV9hZ2VudF9zdGFydGAsIGBldmVudC5zeXN0ZW1Qcm9tcHRgIGFuZCBgY3R4LmdldFN5c3RlbVByb21wdCgpYCBib3RoIHJlZmxlY3QgdGhlIGNoYWluZWQgc3lzdGVtIHByb21wdCBhcyBvZiB0aGUgY3VycmVudCBoYW5kbGVyLiBMYXRlciBgYmVmb3JlX2FnZW50X3N0YXJ0YCBoYW5kbGVycyBjYW4gc3RpbGwgbW9kaWZ5IGl0IGFnYWluLlxuXG4jIyMjIGFnZW50X3N0YXJ0IC8gYWdlbnRfZW5kXG5cbkZpcmVkIG9uY2UgcGVyIHVzZXIgcHJvbXB0LlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcImFnZW50X3N0YXJ0XCIsIGFzeW5jIChfZXZlbnQsIGN0eCkgPT4ge30pO1xuXG5waS5vbihcImFnZW50X2VuZFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAvLyBldmVudC5tZXNzYWdlcyAtIG1lc3NhZ2VzIGZyb20gdGhpcyBwcm9tcHRcbn0pO1xuYGBgXG5cbiMjIyMgdHVybl9zdGFydCAvIHR1cm5fZW5kXG5cbkZpcmVkIGZvciBlYWNoIHR1cm4gKG9uZSBMTE0gcmVzcG9uc2UgKyB0b29sIGNhbGxzKS5cblxuYGBgdHlwZXNjcmlwdFxucGkub24oXCJ0dXJuX3N0YXJ0XCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIC8vIGV2ZW50LnR1cm5JbmRleCwgZXZlbnQudGltZXN0YW1wXG59KTtcblxucGkub24oXCJ0dXJuX2VuZFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAvLyBldmVudC50dXJuSW5kZXgsIGV2ZW50Lm1lc3NhZ2UsIGV2ZW50LnRvb2xSZXN1bHRzXG59KTtcbmBgYFxuXG4jIyMjIG1lc3NhZ2Vfc3RhcnQgLyBtZXNzYWdlX3VwZGF0ZSAvIG1lc3NhZ2VfZW5kXG5cbkZpcmVkIGZvciBtZXNzYWdlIGxpZmVjeWNsZSB1cGRhdGVzLlxuXG4tIGBtZXNzYWdlX3N0YXJ0YCBhbmQgYG1lc3NhZ2VfZW5kYCBmaXJlIGZvciB1c2VyLCBhc3Npc3RhbnQsIGFuZCB0b29sUmVzdWx0IG1lc3NhZ2VzLlxuLSBgbWVzc2FnZV91cGRhdGVgIGZpcmVzIGZvciBhc3Npc3RhbnQgc3RyZWFtaW5nIHVwZGF0ZXMuXG4tIGBtZXNzYWdlX2VuZGAgaGFuZGxlcnMgY2FuIHJldHVybiBgeyBtZXNzYWdlIH1gIHRvIHJlcGxhY2UgdGhlIGZpbmFsaXplZCBtZXNzYWdlLiBUaGUgcmVwbGFjZW1lbnQgbXVzdCBrZWVwIHRoZSBzYW1lIGByb2xlYC5cblxuYGBgdHlwZXNjcmlwdFxucGkub24oXCJtZXNzYWdlX3N0YXJ0XCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIC8vIGV2ZW50Lm1lc3NhZ2Vcbn0pO1xuXG5waS5vbihcIm1lc3NhZ2VfdXBkYXRlXCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIC8vIGV2ZW50Lm1lc3NhZ2VcbiAgLy8gZXZlbnQuYXNzaXN0YW50TWVzc2FnZUV2ZW50ICh0b2tlbi1ieS10b2tlbiBzdHJlYW0gZXZlbnQpXG59KTtcblxucGkub24oXCJtZXNzYWdlX2VuZFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICBpZiAoZXZlbnQubWVzc2FnZS5yb2xlICE9PSBcImFzc2lzdGFudFwiKSByZXR1cm47XG5cbiAgcmV0dXJuIHtcbiAgICBtZXNzYWdlOiB7XG4gICAgICAuLi5ldmVudC5tZXNzYWdlLFxuICAgICAgdXNhZ2U6IHtcbiAgICAgICAgLi4uZXZlbnQubWVzc2FnZS51c2FnZSxcbiAgICAgICAgY29zdDoge1xuICAgICAgICAgIC4uLmV2ZW50Lm1lc3NhZ2UudXNhZ2UuY29zdCxcbiAgICAgICAgICB0b3RhbDogMC4xMjMsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0sXG4gIH07XG59KTtcbmBgYFxuXG4jIyMjIHRvb2xfZXhlY3V0aW9uX3N0YXJ0IC8gdG9vbF9leGVjdXRpb25fdXBkYXRlIC8gdG9vbF9leGVjdXRpb25fZW5kXG5cbkZpcmVkIGZvciB0b29sIGV4ZWN1dGlvbiBsaWZlY3ljbGUgdXBkYXRlcy5cblxuSW4gcGFyYWxsZWwgdG9vbCBtb2RlOlxuLSBgdG9vbF9leGVjdXRpb25fc3RhcnRgIGlzIGVtaXR0ZWQgaW4gYXNzaXN0YW50IHNvdXJjZSBvcmRlciBkdXJpbmcgdGhlIHByZWZsaWdodCBwaGFzZVxuLSBgdG9vbF9leGVjdXRpb25fdXBkYXRlYCBldmVudHMgbWF5IGludGVybGVhdmUgYWNyb3NzIHRvb2xzXG4tIGB0b29sX2V4ZWN1dGlvbl9lbmRgIGlzIGVtaXR0ZWQgaW4gdG9vbCBjb21wbGV0aW9uIG9yZGVyIGFmdGVyIGVhY2ggdG9vbCBpcyBmaW5hbGl6ZWRcbi0gZmluYWwgYHRvb2xSZXN1bHRgIG1lc3NhZ2UgZXZlbnRzIGFyZSBzdGlsbCBlbWl0dGVkIGxhdGVyIGluIGFzc2lzdGFudCBzb3VyY2Ugb3JkZXJcblxuYGBgdHlwZXNjcmlwdFxucGkub24oXCJ0b29sX2V4ZWN1dGlvbl9zdGFydFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAvLyBldmVudC50b29sQ2FsbElkLCBldmVudC50b29sTmFtZSwgZXZlbnQuYXJnc1xufSk7XG5cbnBpLm9uKFwidG9vbF9leGVjdXRpb25fdXBkYXRlXCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIC8vIGV2ZW50LnRvb2xDYWxsSWQsIGV2ZW50LnRvb2xOYW1lLCBldmVudC5hcmdzLCBldmVudC5wYXJ0aWFsUmVzdWx0XG59KTtcblxucGkub24oXCJ0b29sX2V4ZWN1dGlvbl9lbmRcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQudG9vbENhbGxJZCwgZXZlbnQudG9vbE5hbWUsIGV2ZW50LnJlc3VsdCwgZXZlbnQuaXNFcnJvclxufSk7XG5gYGBcblxuIyMjIyBjb250ZXh0XG5cbkZpcmVkIGJlZm9yZSBlYWNoIExMTSBjYWxsLiBNb2RpZnkgbWVzc2FnZXMgbm9uLWRlc3RydWN0aXZlbHkuIFNlZSBbU2Vzc2lvbiBGb3JtYXRdKHNlc3Npb24tZm9ybWF0Lm1kKSBmb3IgbWVzc2FnZSB0eXBlcy5cblxuYGBgdHlwZXNjcmlwdFxucGkub24oXCJjb250ZXh0XCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIC8vIGV2ZW50Lm1lc3NhZ2VzIC0gZGVlcCBjb3B5LCBzYWZlIHRvIG1vZGlmeVxuICBjb25zdCBmaWx0ZXJlZCA9IGV2ZW50Lm1lc3NhZ2VzLmZpbHRlcihtID0+ICFzaG91bGRQcnVuZShtKSk7XG4gIHJldHVybiB7IG1lc3NhZ2VzOiBmaWx0ZXJlZCB9O1xufSk7XG5gYGBcblxuIyMjIyBiZWZvcmVfcHJvdmlkZXJfcmVxdWVzdFxuXG5GaXJlZCBhZnRlciB0aGUgcHJvdmlkZXItc3BlY2lmaWMgcGF5bG9hZCBpcyBidWlsdCwgcmlnaHQgYmVmb3JlIHRoZSByZXF1ZXN0IGlzIHNlbnQuIEhhbmRsZXJzIHJ1biBpbiBleHRlbnNpb24gbG9hZCBvcmRlci4gUmV0dXJuaW5nIGB1bmRlZmluZWRgIGtlZXBzIHRoZSBwYXlsb2FkIHVuY2hhbmdlZC4gUmV0dXJuaW5nIGFueSBvdGhlciB2YWx1ZSByZXBsYWNlcyB0aGUgcGF5bG9hZCBmb3IgbGF0ZXIgaGFuZGxlcnMgYW5kIGZvciB0aGUgYWN0dWFsIHJlcXVlc3QuXG5cblRoaXMgaG9vayBjYW4gcmV3cml0ZSBwcm92aWRlci1sZXZlbCBzeXN0ZW0gaW5zdHJ1Y3Rpb25zIG9yIHJlbW92ZSB0aGVtIGVudGlyZWx5LiBUaG9zZSBwYXlsb2FkLWxldmVsIGNoYW5nZXMgYXJlIG5vdCByZWZsZWN0ZWQgYnkgYGN0eC5nZXRTeXN0ZW1Qcm9tcHQoKWAsIHdoaWNoIHJlcG9ydHMgUGkncyBzeXN0ZW0gcHJvbXB0IHN0cmluZyByYXRoZXIgdGhhbiB0aGUgZmluYWwgc2VyaWFsaXplZCBwcm92aWRlciBwYXlsb2FkLlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcImJlZm9yZV9wcm92aWRlcl9yZXF1ZXN0XCIsIChldmVudCwgY3R4KSA9PiB7XG4gIGNvbnNvbGUubG9nKEpTT04uc3RyaW5naWZ5KGV2ZW50LnBheWxvYWQsIG51bGwsIDIpKTtcblxuICAvLyBPcHRpb25hbDogcmVwbGFjZSBwYXlsb2FkXG4gIC8vIHJldHVybiB7IC4uLmV2ZW50LnBheWxvYWQsIHRlbXBlcmF0dXJlOiAwIH07XG59KTtcbmBgYFxuXG5UaGlzIGlzIG1haW5seSB1c2VmdWwgZm9yIGRlYnVnZ2luZyBwcm92aWRlciBzZXJpYWxpemF0aW9uIGFuZCBjYWNoZSBiZWhhdmlvci5cblxuIyMjIyBhZnRlcl9wcm92aWRlcl9yZXNwb25zZVxuXG5GaXJlZCBhZnRlciBhbiBIVFRQIHJlc3BvbnNlIGlzIHJlY2VpdmVkIGFuZCBiZWZvcmUgaXRzIHN0cmVhbSBib2R5IGlzIGNvbnN1bWVkLiBIYW5kbGVycyBydW4gaW4gZXh0ZW5zaW9uIGxvYWQgb3JkZXIuXG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwiYWZ0ZXJfcHJvdmlkZXJfcmVzcG9uc2VcIiwgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQuc3RhdHVzIC0gSFRUUCBzdGF0dXMgY29kZVxuICAvLyBldmVudC5oZWFkZXJzIC0gbm9ybWFsaXplZCByZXNwb25zZSBoZWFkZXJzXG4gIGlmIChldmVudC5zdGF0dXMgPT09IDQyOSkge1xuICAgIGNvbnNvbGUubG9nKFwicmF0ZSBsaW1pdGVkXCIsIGV2ZW50LmhlYWRlcnNbXCJyZXRyeS1hZnRlclwiXSk7XG4gIH1cbn0pO1xuYGBgXG5cbkhlYWRlciBhdmFpbGFiaWxpdHkgZGVwZW5kcyBvbiBwcm92aWRlciBhbmQgdHJhbnNwb3J0LiBQcm92aWRlcnMgdGhhdCBhYnN0cmFjdCBIVFRQIHJlc3BvbnNlcyBtYXkgbm90IGV4cG9zZSBoZWFkZXJzLlxuXG4jIyMgTW9kZWwgRXZlbnRzXG5cbiMjIyMgbW9kZWxfc2VsZWN0XG5cbkZpcmVkIHdoZW4gdGhlIG1vZGVsIGNoYW5nZXMgdmlhIGAvbW9kZWxgIGNvbW1hbmQsIG1vZGVsIGN5Y2xpbmcgKGBDdHJsK1BgKSwgb3Igc2Vzc2lvbiByZXN0b3JlLlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcIm1vZGVsX3NlbGVjdFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAvLyBldmVudC5tb2RlbCAtIG5ld2x5IHNlbGVjdGVkIG1vZGVsXG4gIC8vIGV2ZW50LnByZXZpb3VzTW9kZWwgLSBwcmV2aW91cyBtb2RlbCAodW5kZWZpbmVkIGlmIGZpcnN0IHNlbGVjdGlvbilcbiAgLy8gZXZlbnQuc291cmNlIC0gXCJzZXRcIiB8IFwiY3ljbGVcIiB8IFwicmVzdG9yZVwiXG5cbiAgY29uc3QgcHJldiA9IGV2ZW50LnByZXZpb3VzTW9kZWxcbiAgICA/IGAke2V2ZW50LnByZXZpb3VzTW9kZWwucHJvdmlkZXJ9LyR7ZXZlbnQucHJldmlvdXNNb2RlbC5pZH1gXG4gICAgOiBcIm5vbmVcIjtcbiAgY29uc3QgbmV4dCA9IGAke2V2ZW50Lm1vZGVsLnByb3ZpZGVyfS8ke2V2ZW50Lm1vZGVsLmlkfWA7XG5cbiAgY3R4LnVpLm5vdGlmeShgTW9kZWwgY2hhbmdlZCAoJHtldmVudC5zb3VyY2V9KTogJHtwcmV2fSAtPiAke25leHR9YCwgXCJpbmZvXCIpO1xufSk7XG5gYGBcblxuVXNlIHRoaXMgdG8gdXBkYXRlIFVJIGVsZW1lbnRzIChzdGF0dXMgYmFycywgZm9vdGVycykgb3IgcGVyZm9ybSBtb2RlbC1zcGVjaWZpYyBpbml0aWFsaXphdGlvbiB3aGVuIHRoZSBhY3RpdmUgbW9kZWwgY2hhbmdlcy5cblxuIyMjIyB0aGlua2luZ19sZXZlbF9zZWxlY3RcblxuRmlyZWQgd2hlbiB0aGUgdGhpbmtpbmcgbGV2ZWwgY2hhbmdlcy4gVGhpcyBpcyBub3RpZmljYXRpb24tb25seTsgaGFuZGxlciByZXR1cm4gdmFsdWVzIGFyZSBpZ25vcmVkLlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcInRoaW5raW5nX2xldmVsX3NlbGVjdFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAvLyBldmVudC5sZXZlbCAtIG5ld2x5IHNlbGVjdGVkIHRoaW5raW5nIGxldmVsXG4gIC8vIGV2ZW50LnByZXZpb3VzTGV2ZWwgLSBwcmV2aW91cyB0aGlua2luZyBsZXZlbFxuXG4gIGN0eC51aS5zZXRTdGF0dXMoXCJ0aGlua2luZ1wiLCBgdGhpbmtpbmc6ICR7ZXZlbnQubGV2ZWx9YCk7XG59KTtcbmBgYFxuXG5Vc2UgdGhpcyB0byB1cGRhdGUgZXh0ZW5zaW9uIFVJIHdoZW4gYHBpLnNldFRoaW5raW5nTGV2ZWwoKWAsIG1vZGVsIGNoYW5nZXMsIG9yIGJ1aWx0LWluIHRoaW5raW5nLWxldmVsIGNvbnRyb2xzIGNoYW5nZSB0aGUgYWN0aXZlIHRoaW5raW5nIGxldmVsLlxuXG4jIyMgVG9vbCBFdmVudHNcblxuIyMjIyB0b29sX2NhbGxcblxuRmlyZWQgYWZ0ZXIgYHRvb2xfZXhlY3V0aW9uX3N0YXJ0YCwgYmVmb3JlIHRoZSB0b29sIGV4ZWN1dGVzLiAqKkNhbiBibG9jay4qKiBVc2UgYGlzVG9vbENhbGxFdmVudFR5cGVgIHRvIG5hcnJvdyBhbmQgZ2V0IHR5cGVkIGlucHV0cy5cblxuQmVmb3JlIGB0b29sX2NhbGxgIHJ1bnMsIHBpIHdhaXRzIGZvciBwcmV2aW91c2x5IGVtaXR0ZWQgQWdlbnQgZXZlbnRzIHRvIGZpbmlzaCBkcmFpbmluZyB0aHJvdWdoIGBBZ2VudFNlc3Npb25gLiBUaGlzIG1lYW5zIGBjdHguc2Vzc2lvbk1hbmFnZXJgIGlzIHVwIHRvIGRhdGUgdGhyb3VnaCB0aGUgY3VycmVudCBhc3Npc3RhbnQgdG9vbC1jYWxsaW5nIG1lc3NhZ2UuXG5cbkluIHRoZSBkZWZhdWx0IHBhcmFsbGVsIHRvb2wgZXhlY3V0aW9uIG1vZGUsIHNpYmxpbmcgdG9vbCBjYWxscyBmcm9tIHRoZSBzYW1lIGFzc2lzdGFudCBtZXNzYWdlIGFyZSBwcmVmbGlnaHRlZCBzZXF1ZW50aWFsbHksIHRoZW4gZXhlY3V0ZWQgY29uY3VycmVudGx5LiBgdG9vbF9jYWxsYCBpcyBub3QgZ3VhcmFudGVlZCB0byBzZWUgc2libGluZyB0b29sIHJlc3VsdHMgZnJvbSB0aGF0IHNhbWUgYXNzaXN0YW50IG1lc3NhZ2UgaW4gYGN0eC5zZXNzaW9uTWFuYWdlcmAuXG5cbmBldmVudC5pbnB1dGAgaXMgbXV0YWJsZS4gTXV0YXRlIGl0IGluIHBsYWNlIHRvIHBhdGNoIHRvb2wgYXJndW1lbnRzIGJlZm9yZSBleGVjdXRpb24uXG5cbkJlaGF2aW9yIGd1YXJhbnRlZXM6XG4tIE11dGF0aW9ucyB0byBgZXZlbnQuaW5wdXRgIGFmZmVjdCB0aGUgYWN0dWFsIHRvb2wgZXhlY3V0aW9uXG4tIExhdGVyIGB0b29sX2NhbGxgIGhhbmRsZXJzIHNlZSBtdXRhdGlvbnMgbWFkZSBieSBlYXJsaWVyIGhhbmRsZXJzXG4tIE5vIHJlLXZhbGlkYXRpb24gaXMgcGVyZm9ybWVkIGFmdGVyIHlvdXIgbXV0YXRpb25cbi0gUmV0dXJuIHZhbHVlcyBmcm9tIGB0b29sX2NhbGxgIG9ubHkgY29udHJvbCBibG9ja2luZyB2aWEgYHsgYmxvY2s6IHRydWUsIHJlYXNvbj86IHN0cmluZyB9YFxuXG5gYGB0eXBlc2NyaXB0XG5pbXBvcnQgeyBpc1Rvb2xDYWxsRXZlbnRUeXBlIH0gZnJvbSBcIkBlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnRcIjtcblxucGkub24oXCJ0b29sX2NhbGxcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQudG9vbE5hbWUgLSBcImJhc2hcIiwgXCJyZWFkXCIsIFwid3JpdGVcIiwgXCJlZGl0XCIsIGV0Yy5cbiAgLy8gZXZlbnQudG9vbENhbGxJZFxuICAvLyBldmVudC5pbnB1dCAtIHRvb2wgcGFyYW1ldGVycyAobXV0YWJsZSlcblxuICAvLyBCdWlsdC1pbiB0b29sczogbm8gdHlwZSBwYXJhbXMgbmVlZGVkXG4gIGlmIChpc1Rvb2xDYWxsRXZlbnRUeXBlKFwiYmFzaFwiLCBldmVudCkpIHtcbiAgICAvLyBldmVudC5pbnB1dCBpcyB7IGNvbW1hbmQ6IHN0cmluZzsgdGltZW91dD86IG51bWJlciB9XG4gICAgZXZlbnQuaW5wdXQuY29tbWFuZCA9IGBzb3VyY2Ugfi8ucHJvZmlsZVxcbiR7ZXZlbnQuaW5wdXQuY29tbWFuZH1gO1xuXG4gICAgaWYgKGV2ZW50LmlucHV0LmNvbW1hbmQuaW5jbHVkZXMoXCJybSAtcmZcIikpIHtcbiAgICAgIHJldHVybiB7IGJsb2NrOiB0cnVlLCByZWFzb246IFwiRGFuZ2Vyb3VzIGNvbW1hbmRcIiB9O1xuICAgIH1cbiAgfVxuXG4gIGlmIChpc1Rvb2xDYWxsRXZlbnRUeXBlKFwicmVhZFwiLCBldmVudCkpIHtcbiAgICAvLyBldmVudC5pbnB1dCBpcyB7IHBhdGg6IHN0cmluZzsgb2Zmc2V0PzogbnVtYmVyOyBsaW1pdD86IG51bWJlciB9XG4gICAgY29uc29sZS5sb2coYFJlYWRpbmc6ICR7ZXZlbnQuaW5wdXQucGF0aH1gKTtcbiAgfVxufSk7XG5gYGBcblxuIyMjIyBUeXBpbmcgY3VzdG9tIHRvb2wgaW5wdXRcblxuQ3VzdG9tIHRvb2xzIHNob3VsZCBleHBvcnQgdGhlaXIgaW5wdXQgdHlwZTpcblxuYGBgdHlwZXNjcmlwdFxuLy8gbXktZXh0ZW5zaW9uLnRzXG5leHBvcnQgdHlwZSBNeVRvb2xJbnB1dCA9IFN0YXRpYzx0eXBlb2YgbXlUb29sU2NoZW1hPjtcbmBgYFxuXG5Vc2UgYGlzVG9vbENhbGxFdmVudFR5cGVgIHdpdGggZXhwbGljaXQgdHlwZSBwYXJhbWV0ZXJzOlxuXG5gYGB0eXBlc2NyaXB0XG5pbXBvcnQgeyBpc1Rvb2xDYWxsRXZlbnRUeXBlIH0gZnJvbSBcIkBlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnRcIjtcbmltcG9ydCB0eXBlIHsgTXlUb29sSW5wdXQgfSBmcm9tIFwibXktZXh0ZW5zaW9uXCI7XG5cbnBpLm9uKFwidG9vbF9jYWxsXCIsIChldmVudCkgPT4ge1xuICBpZiAoaXNUb29sQ2FsbEV2ZW50VHlwZTxcIm15X3Rvb2xcIiwgTXlUb29sSW5wdXQ+KFwibXlfdG9vbFwiLCBldmVudCkpIHtcbiAgICBldmVudC5pbnB1dC5hY3Rpb247ICAvLyB0eXBlZFxuICB9XG59KTtcbmBgYFxuXG4jIyMjIHRvb2xfcmVzdWx0XG5cbkZpcmVkIGFmdGVyIHRvb2wgZXhlY3V0aW9uIGZpbmlzaGVzIGFuZCBiZWZvcmUgYHRvb2xfZXhlY3V0aW9uX2VuZGAgcGx1cyB0aGUgZmluYWwgdG9vbCByZXN1bHQgbWVzc2FnZSBldmVudHMgYXJlIGVtaXR0ZWQuICoqQ2FuIG1vZGlmeSByZXN1bHQuKipcblxuSW4gcGFyYWxsZWwgdG9vbCBtb2RlLCBgdG9vbF9yZXN1bHRgIGFuZCBgdG9vbF9leGVjdXRpb25fZW5kYCBtYXkgaW50ZXJsZWF2ZSBpbiB0b29sIGNvbXBsZXRpb24gb3JkZXIsIHdoaWxlIGZpbmFsIGB0b29sUmVzdWx0YCBtZXNzYWdlIGV2ZW50cyBhcmUgc3RpbGwgZW1pdHRlZCBsYXRlciBpbiBhc3Npc3RhbnQgc291cmNlIG9yZGVyLlxuXG5gdG9vbF9yZXN1bHRgIGhhbmRsZXJzIGNoYWluIGxpa2UgbWlkZGxld2FyZTpcbi0gSGFuZGxlcnMgcnVuIGluIGV4dGVuc2lvbiBsb2FkIG9yZGVyXG4tIEVhY2ggaGFuZGxlciBzZWVzIHRoZSBsYXRlc3QgcmVzdWx0IGFmdGVyIHByZXZpb3VzIGhhbmRsZXIgY2hhbmdlc1xuLSBIYW5kbGVycyBjYW4gcmV0dXJuIHBhcnRpYWwgcGF0Y2hlcyAoYGNvbnRlbnRgLCBgZGV0YWlsc2AsIG9yIGBpc0Vycm9yYCk7IG9taXR0ZWQgZmllbGRzIGtlZXAgdGhlaXIgY3VycmVudCB2YWx1ZXNcblxuVXNlIGBjdHguc2lnbmFsYCBmb3IgbmVzdGVkIGFzeW5jIHdvcmsgaW5zaWRlIHRoZSBoYW5kbGVyLiBUaGlzIGxldHMgRXNjIGNhbmNlbCBtb2RlbCBjYWxscywgYGZldGNoKClgLCBhbmQgb3RoZXIgYWJvcnQtYXdhcmUgb3BlcmF0aW9ucyBzdGFydGVkIGJ5IHRoZSBleHRlbnNpb24uXG5cbmBgYHR5cGVzY3JpcHRcbmltcG9ydCB7IGlzQmFzaFRvb2xSZXN1bHQgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudFwiO1xuXG5waS5vbihcInRvb2xfcmVzdWx0XCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIC8vIGV2ZW50LnRvb2xOYW1lLCBldmVudC50b29sQ2FsbElkLCBldmVudC5pbnB1dFxuICAvLyBldmVudC5jb250ZW50LCBldmVudC5kZXRhaWxzLCBldmVudC5pc0Vycm9yXG5cbiAgaWYgKGlzQmFzaFRvb2xSZXN1bHQoZXZlbnQpKSB7XG4gICAgLy8gZXZlbnQuZGV0YWlscyBpcyB0eXBlZCBhcyBCYXNoVG9vbERldGFpbHNcbiAgfVxuXG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goXCJodHRwczovL2V4YW1wbGUuY29tL3N1bW1hcml6ZVwiLCB7XG4gICAgbWV0aG9kOiBcIlBPU1RcIixcbiAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7IGNvbnRlbnQ6IGV2ZW50LmNvbnRlbnQgfSksXG4gICAgc2lnbmFsOiBjdHguc2lnbmFsLFxuICB9KTtcblxuICAvLyBNb2RpZnkgcmVzdWx0OlxuICByZXR1cm4geyBjb250ZW50OiBbLi4uXSwgZGV0YWlsczogey4uLn0sIGlzRXJyb3I6IGZhbHNlIH07XG59KTtcbmBgYFxuXG4jIyMgVXNlciBCYXNoIEV2ZW50c1xuXG4jIyMjIHVzZXJfYmFzaFxuXG5GaXJlZCB3aGVuIHVzZXIgZXhlY3V0ZXMgYCFgIG9yIGAhIWAgY29tbWFuZHMuICoqQ2FuIGludGVyY2VwdC4qKlxuXG5gYGB0eXBlc2NyaXB0XG5pbXBvcnQgeyBjcmVhdGVMb2NhbEJhc2hPcGVyYXRpb25zIH0gZnJvbSBcIkBlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnRcIjtcblxucGkub24oXCJ1c2VyX2Jhc2hcIiwgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQuY29tbWFuZCAtIHRoZSBiYXNoIGNvbW1hbmRcbiAgLy8gZXZlbnQuZXhjbHVkZUZyb21Db250ZXh0IC0gdHJ1ZSBpZiAhISBwcmVmaXhcbiAgLy8gZXZlbnQuY3dkIC0gd29ya2luZyBkaXJlY3RvcnlcblxuICAvLyBPcHRpb24gMTogUHJvdmlkZSBjdXN0b20gb3BlcmF0aW9ucyAoZS5nLiwgU1NIKVxuICByZXR1cm4geyBvcGVyYXRpb25zOiByZW1vdGVCYXNoT3BzIH07XG5cbiAgLy8gT3B0aW9uIDI6IFdyYXAgcGkncyBidWlsdC1pbiBsb2NhbCBiYXNoIGJhY2tlbmRcbiAgY29uc3QgbG9jYWwgPSBjcmVhdGVMb2NhbEJhc2hPcGVyYXRpb25zKCk7XG4gIHJldHVybiB7XG4gICAgb3BlcmF0aW9uczoge1xuICAgICAgZXhlYyhjb21tYW5kLCBjd2QsIG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIGxvY2FsLmV4ZWMoYHNvdXJjZSB+Ly5wcm9maWxlXFxuJHtjb21tYW5kfWAsIGN3ZCwgb3B0aW9ucyk7XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIC8vIE9wdGlvbiAzOiBGdWxsIHJlcGxhY2VtZW50IC0gcmV0dXJuIHJlc3VsdCBkaXJlY3RseVxuICByZXR1cm4geyByZXN1bHQ6IHsgb3V0cHV0OiBcIi4uLlwiLCBleGl0Q29kZTogMCwgY2FuY2VsbGVkOiBmYWxzZSwgdHJ1bmNhdGVkOiBmYWxzZSB9IH07XG59KTtcbmBgYFxuXG4jIyMgSW5wdXQgRXZlbnRzXG5cbiMjIyMgaW5wdXRcblxuRmlyZWQgd2hlbiB1c2VyIGlucHV0IGlzIHJlY2VpdmVkLCBhZnRlciBleHRlbnNpb24gY29tbWFuZHMgYXJlIGNoZWNrZWQgYnV0IGJlZm9yZSBza2lsbCBhbmQgdGVtcGxhdGUgZXhwYW5zaW9uLiBUaGUgZXZlbnQgc2VlcyB0aGUgcmF3IGlucHV0IHRleHQsIHNvIGAvc2tpbGw6Zm9vYCBhbmQgYC90ZW1wbGF0ZWAgYXJlIG5vdCB5ZXQgZXhwYW5kZWQuXG5cbioqUHJvY2Vzc2luZyBvcmRlcjoqKlxuMS4gRXh0ZW5zaW9uIGNvbW1hbmRzIChgL2NtZGApIGNoZWNrZWQgZmlyc3QgLSBpZiBmb3VuZCwgaGFuZGxlciBydW5zIGFuZCBpbnB1dCBldmVudCBpcyBza2lwcGVkXG4yLiBgaW5wdXRgIGV2ZW50IGZpcmVzIC0gY2FuIGludGVyY2VwdCwgdHJhbnNmb3JtLCBvciBoYW5kbGVcbjMuIElmIG5vdCBoYW5kbGVkOiBza2lsbCBjb21tYW5kcyAoYC9za2lsbDpuYW1lYCkgZXhwYW5kZWQgdG8gc2tpbGwgY29udGVudFxuNC4gSWYgbm90IGhhbmRsZWQ6IHByb21wdCB0ZW1wbGF0ZXMgKGAvdGVtcGxhdGVgKSBleHBhbmRlZCB0byB0ZW1wbGF0ZSBjb250ZW50XG41LiBBZ2VudCBwcm9jZXNzaW5nIGJlZ2lucyAoYGJlZm9yZV9hZ2VudF9zdGFydGAsIGV0Yy4pXG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwiaW5wdXRcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQudGV4dCAtIHJhdyBpbnB1dCAoYmVmb3JlIHNraWxsL3RlbXBsYXRlIGV4cGFuc2lvbilcbiAgLy8gZXZlbnQuaW1hZ2VzIC0gYXR0YWNoZWQgaW1hZ2VzLCBpZiBhbnlcbiAgLy8gZXZlbnQuc291cmNlIC0gXCJpbnRlcmFjdGl2ZVwiICh0eXBlZCksIFwicnBjXCIgKEFQSSksIG9yIFwiZXh0ZW5zaW9uXCIgKHZpYSBzZW5kVXNlck1lc3NhZ2UpXG4gIC8vIGV2ZW50LnN0cmVhbWluZ0JlaGF2aW9yIC0gXCJzdGVlclwiIHwgXCJmb2xsb3dVcFwiIHwgdW5kZWZpbmVkXG4gIC8vICAgdW5kZWZpbmVkIHdoZW4gaWRsZSwgXCJzdGVlclwiIGZvciBtaWQtc3RyZWFtIGludGVycnVwdHMsXG4gIC8vICAgXCJmb2xsb3dVcFwiIGZvciBtZXNzYWdlcyBxdWV1ZWQgdW50aWwgdGhlIGFnZW50IGZpbmlzaGVzXG5cbiAgLy8gVHJhbnNmb3JtOiByZXdyaXRlIGlucHV0IGJlZm9yZSBleHBhbnNpb25cbiAgaWYgKGV2ZW50LnRleHQuc3RhcnRzV2l0aChcIj9xdWljayBcIikpXG4gICAgcmV0dXJuIHsgYWN0aW9uOiBcInRyYW5zZm9ybVwiLCB0ZXh0OiBgUmVzcG9uZCBicmllZmx5OiAke2V2ZW50LnRleHQuc2xpY2UoNyl9YCB9O1xuXG4gIC8vIEhhbmRsZTogcmVzcG9uZCB3aXRob3V0IExMTSAoZXh0ZW5zaW9uIHNob3dzIGl0cyBvd24gZmVlZGJhY2spXG4gIGlmIChldmVudC50ZXh0ID09PSBcInBpbmdcIikge1xuICAgIGN0eC51aS5ub3RpZnkoXCJwb25nXCIsIFwiaW5mb1wiKTtcbiAgICByZXR1cm4geyBhY3Rpb246IFwiaGFuZGxlZFwiIH07XG4gIH1cblxuICAvLyBSb3V0ZSBieSBzb3VyY2U6IHNraXAgcHJvY2Vzc2luZyBmb3IgZXh0ZW5zaW9uLWluamVjdGVkIG1lc3NhZ2VzXG4gIGlmIChldmVudC5zb3VyY2UgPT09IFwiZXh0ZW5zaW9uXCIpIHJldHVybiB7IGFjdGlvbjogXCJjb250aW51ZVwiIH07XG5cbiAgLy8gSW50ZXJjZXB0IHNraWxsIGNvbW1hbmRzIGJlZm9yZSBleHBhbnNpb25cbiAgaWYgKGV2ZW50LnRleHQuc3RhcnRzV2l0aChcIi9za2lsbDpcIikpIHtcbiAgICAvLyBDb3VsZCB0cmFuc2Zvcm0sIGJsb2NrLCBvciBsZXQgcGFzcyB0aHJvdWdoXG4gIH1cblxuICByZXR1cm4geyBhY3Rpb246IFwiY29udGludWVcIiB9OyAgLy8gRGVmYXVsdDogcGFzcyB0aHJvdWdoIHRvIGV4cGFuc2lvblxufSk7XG5gYGBcblxuKipSZXN1bHRzOioqXG4tIGBjb250aW51ZWAgLSBwYXNzIHRocm91Z2ggdW5jaGFuZ2VkIChkZWZhdWx0IGlmIGhhbmRsZXIgcmV0dXJucyBub3RoaW5nKVxuLSBgdHJhbnNmb3JtYCAtIG1vZGlmeSB0ZXh0L2ltYWdlcywgdGhlbiBjb250aW51ZSB0byBleHBhbnNpb25cbi0gYGhhbmRsZWRgIC0gc2tpcCBhZ2VudCBlbnRpcmVseSAoZmlyc3QgaGFuZGxlciB0byByZXR1cm4gdGhpcyB3aW5zKVxuXG5UcmFuc2Zvcm1zIGNoYWluIGFjcm9zcyBoYW5kbGVycy4gU2VlIFtpbnB1dC10cmFuc2Zvcm0udHNdKC4uL2V4YW1wbGVzL2V4dGVuc2lvbnMvaW5wdXQtdHJhbnNmb3JtLnRzKSBhbmQgW2lucHV0LXRyYW5zZm9ybS1zdHJlYW1pbmcudHNdKC4uL2V4YW1wbGVzL2V4dGVuc2lvbnMvaW5wdXQtdHJhbnNmb3JtLXN0cmVhbWluZy50cykgZm9yIGBzdHJlYW1pbmdCZWhhdmlvcmAtYXdhcmUgcm91dGluZy5cblxuIyMgRXh0ZW5zaW9uQ29udGV4dFxuXG5BbGwgaGFuZGxlcnMgcmVjZWl2ZSBgY3R4OiBFeHRlbnNpb25Db250ZXh0YC5cblxuIyMjIGN0eC51aVxuXG5VSSBtZXRob2RzIGZvciB1c2VyIGludGVyYWN0aW9uLiBTZWUgW0N1c3RvbSBVSV0oI2N1c3RvbS11aSkgZm9yIGZ1bGwgZGV0YWlscy5cblxuIyMjIGN0eC5tb2RlXG5cbkN1cnJlbnQgcnVuIG1vZGU6IGBcInR1aVwiYCwgYFwicnBjXCJgLCBgXCJqc29uXCJgLCBvciBgXCJwcmludFwiYC4gVXNlIGBjdHgubW9kZSA9PT0gXCJ0dWlcImAgdG8gZ3VhcmQgdGVybWluYWwtb25seSBmZWF0dXJlcyBzdWNoIGFzIGBjdXN0b20oKWAsIGNvbXBvbmVudCBmYWN0b3JpZXMsIHRlcm1pbmFsIGlucHV0LCBhbmQgZGlyZWN0IFRVSSByZW5kZXJpbmcuXG5cbiMjIyBjdHguaGFzVUlcblxuYHRydWVgIGluIFRVSSBhbmQgUlBDIG1vZGVzLiBgZmFsc2VgIGluIHByaW50IG1vZGUgKGAtcGApIGFuZCBKU09OIG1vZGUuIFVzZSB0aGlzIHRvIGd1YXJkIGRpYWxvZyBtZXRob2RzIChgc2VsZWN0YCwgYGNvbmZpcm1gLCBgaW5wdXRgLCBgZWRpdG9yYCkgYW5kIGZpcmUtYW5kLWZvcmdldCBtZXRob2RzIChgbm90aWZ5YCwgYHNldFN0YXR1c2AsIGBzZXRXaWRnZXRgLCBgc2V0VGl0bGVgLCBgc2V0RWRpdG9yVGV4dGApIHRoYXQgd29yayBpbiBib3RoIFRVSSBhbmQgUlBDIG1vZGVzLiBJbiBSUEMgbW9kZSwgc29tZSBUVUktc3BlY2lmaWMgbWV0aG9kcyBhcmUgbm8tb3BzIG9yIHJldHVybiBkZWZhdWx0cyAoc2VlIFtycGMubWRdKHJwYy5tZCNleHRlbnNpb24tdWktcHJvdG9jb2wpKS5cblxuIyMjIGN0eC5jd2RcblxuQ3VycmVudCB3b3JraW5nIGRpcmVjdG9yeS5cblxuVXNlIGBDT05GSUdfRElSX05BTUVgIGluc3RlYWQgb2YgaGFyZGNvZGluZyBgLnBpYCB3aGVuIGNvbnN0cnVjdGluZyBwcm9qZWN0LWxvY2FsIGNvbmZpZyBwYXRocy4gUmVicmFuZGVkIGRpc3RyaWJ1dGlvbnMgY2FuIHVzZSBhIGRpZmZlcmVudCBjb25maWcgZGlyZWN0b3J5IG5hbWUuXG5cbmBgYHR5cGVzY3JpcHRcbmltcG9ydCB7IENPTkZJR19ESVJfTkFNRSwgdHlwZSBFeHRlbnNpb25BUEkgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudFwiO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcblxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gKHBpOiBFeHRlbnNpb25BUEkpIHtcbiAgcGkub24oXCJzZXNzaW9uX3N0YXJ0XCIsIChfZXZlbnQsIGN0eCkgPT4ge1xuICAgIGNvbnN0IHByb2plY3RDb25maWdQYXRoID0gam9pbihjdHguY3dkLCBDT05GSUdfRElSX05BTUUsIFwibXktZXh0ZW5zaW9uLmpzb25cIik7XG4gICAgLy8gLi4uXG4gIH0pO1xufVxuYGBgXG5cbiMjIyBjdHguaXNQcm9qZWN0VHJ1c3RlZCgpXG5cblJldHVybnMgd2hldGhlciBwcm9qZWN0LWxvY2FsIHRydXN0IGlzIGFjdGl2ZSBmb3IgdGhlIGN1cnJlbnQgc2Vzc2lvbiBjb250ZXh0LiBUaGlzIGluY2x1ZGVzIHRlbXBvcmFyeSB0cnVzdCBkZWNpc2lvbnMgYW5kIENMSSB0cnVzdCBvdmVycmlkZXMsIG5vdCBqdXN0IHNhdmVkIGRlY2lzaW9ucyBpbiB0aGUgZ2xvYmFsIHRydXN0IHN0b3JlLlxuXG5Vc2UgdGhpcyBiZWZvcmUgcmVhZGluZyBwcm9qZWN0LWxvY2FsIGV4dGVuc2lvbiBjb25maWd1cmF0aW9uIHRoYXQgc2hvdWxkIG9ubHkgYmUgaG9ub3JlZCBmb3IgdHJ1c3RlZCBwcm9qZWN0cy5cblxuIyMjIGN0eC5zZXNzaW9uTWFuYWdlclxuXG5SZWFkLW9ubHkgYWNjZXNzIHRvIHNlc3Npb24gc3RhdGUuIFNlZSBbU2Vzc2lvbiBGb3JtYXRdKHNlc3Npb24tZm9ybWF0Lm1kKSBmb3IgdGhlIGZ1bGwgU2Vzc2lvbk1hbmFnZXIgQVBJIGFuZCBlbnRyeSB0eXBlcy5cblxuRm9yIGB0b29sX2NhbGxgLCB0aGlzIHN0YXRlIGlzIHN5bmNocm9uaXplZCB0aHJvdWdoIHRoZSBjdXJyZW50IGFzc2lzdGFudCBtZXNzYWdlIGJlZm9yZSBoYW5kbGVycyBydW4uIEluIHBhcmFsbGVsIHRvb2wgZXhlY3V0aW9uIG1vZGUgaXQgaXMgc3RpbGwgbm90IGd1YXJhbnRlZWQgdG8gaW5jbHVkZSBzaWJsaW5nIHRvb2wgcmVzdWx0cyBmcm9tIHRoZSBzYW1lIGFzc2lzdGFudCBtZXNzYWdlLlxuXG5gYGB0eXBlc2NyaXB0XG5jdHguc2Vzc2lvbk1hbmFnZXIuZ2V0RW50cmllcygpICAgICAgIC8vIEFsbCBlbnRyaWVzXG5jdHguc2Vzc2lvbk1hbmFnZXIuZ2V0QnJhbmNoKCkgICAgICAgIC8vIEN1cnJlbnQgYnJhbmNoXG5jdHguc2Vzc2lvbk1hbmFnZXIuZ2V0TGVhZklkKCkgICAgICAgIC8vIEN1cnJlbnQgbGVhZiBlbnRyeSBJRFxuYGBgXG5cbiMjIyBjdHgubW9kZWxSZWdpc3RyeSAvIGN0eC5tb2RlbFxuXG5BY2Nlc3MgdG8gbW9kZWxzIGFuZCBBUEkga2V5cy5cblxuIyMjIGN0eC5zaWduYWxcblxuVGhlIGN1cnJlbnQgYWdlbnQgYWJvcnQgc2lnbmFsLCBvciBgdW5kZWZpbmVkYCB3aGVuIG5vIGFnZW50IHR1cm4gaXMgYWN0aXZlLlxuXG5Vc2UgdGhpcyBmb3IgYWJvcnQtYXdhcmUgbmVzdGVkIHdvcmsgc3RhcnRlZCBieSBleHRlbnNpb24gaGFuZGxlcnMsIGZvciBleGFtcGxlOlxuLSBgZmV0Y2goLi4uLCB7IHNpZ25hbDogY3R4LnNpZ25hbCB9KWBcbi0gbW9kZWwgY2FsbHMgdGhhdCBhY2NlcHQgYHNpZ25hbGBcbi0gZmlsZSBvciBwcm9jZXNzIGhlbHBlcnMgdGhhdCBhY2NlcHQgYEFib3J0U2lnbmFsYFxuXG5gY3R4LnNpZ25hbGAgaXMgdHlwaWNhbGx5IGRlZmluZWQgZHVyaW5nIGFjdGl2ZSB0dXJuIGV2ZW50cyBzdWNoIGFzIGB0b29sX2NhbGxgLCBgdG9vbF9yZXN1bHRgLCBgbWVzc2FnZV91cGRhdGVgLCBhbmQgYHR1cm5fZW5kYC5cbkl0IGlzIHVzdWFsbHkgYHVuZGVmaW5lZGAgaW4gaWRsZSBvciBub24tdHVybiBjb250ZXh0cyBzdWNoIGFzIHNlc3Npb24gZXZlbnRzLCBleHRlbnNpb24gY29tbWFuZHMsIGFuZCBzaG9ydGN1dHMgZmlyZWQgd2hpbGUgcGkgaXMgaWRsZS5cblxuYGBgdHlwZXNjcmlwdFxucGkub24oXCJ0b29sX3Jlc3VsdFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKFwiaHR0cHM6Ly9leGFtcGxlLmNvbS9hcGlcIiwge1xuICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgYm9keTogSlNPTi5zdHJpbmdpZnkoZXZlbnQpLFxuICAgIHNpZ25hbDogY3R4LnNpZ25hbCxcbiAgfSk7XG5cbiAgY29uc3QgZGF0YSA9IGF3YWl0IHJlc3BvbnNlLmpzb24oKTtcbiAgcmV0dXJuIHsgZGV0YWlsczogZGF0YSB9O1xufSk7XG5gYGBcblxuIyMjIGN0eC5pc0lkbGUoKSAvIGN0eC5hYm9ydCgpIC8gY3R4Lmhhc1BlbmRpbmdNZXNzYWdlcygpXG5cbkNvbnRyb2wgZmxvdyBoZWxwZXJzLlxuXG4jIyMgY3R4LnNodXRkb3duKClcblxuUmVxdWVzdCBhIGdyYWNlZnVsIHNodXRkb3duIG9mIHBpLlxuXG4tICoqSW50ZXJhY3RpdmUgbW9kZToqKiBEZWZlcnJlZCB1bnRpbCB0aGUgYWdlbnQgYmVjb21lcyBpZGxlIChhZnRlciBwcm9jZXNzaW5nIGFsbCBxdWV1ZWQgc3RlZXJpbmcgYW5kIGZvbGxvdy11cCBtZXNzYWdlcykuXG4tICoqUlBDIG1vZGU6KiogRGVmZXJyZWQgdW50aWwgdGhlIG5leHQgaWRsZSBzdGF0ZSAoYWZ0ZXIgY29tcGxldGluZyB0aGUgY3VycmVudCBjb21tYW5kIHJlc3BvbnNlLCB3aGVuIHdhaXRpbmcgZm9yIHRoZSBuZXh0IGNvbW1hbmQpLlxuLSAqKlByaW50IG1vZGU6KiogTm8tb3AuIFRoZSBwcm9jZXNzIGV4aXRzIGF1dG9tYXRpY2FsbHkgd2hlbiBhbGwgcHJvbXB0cyBhcmUgcHJvY2Vzc2VkLlxuXG5FbWl0cyBgc2Vzc2lvbl9zaHV0ZG93bmAgZXZlbnQgdG8gYWxsIGV4dGVuc2lvbnMgYmVmb3JlIGV4aXRpbmcuIEF2YWlsYWJsZSBpbiBhbGwgY29udGV4dHMgKGV2ZW50IGhhbmRsZXJzLCB0b29scywgY29tbWFuZHMsIHNob3J0Y3V0cykuXG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwidG9vbF9jYWxsXCIsIChldmVudCwgY3R4KSA9PiB7XG4gIGlmIChpc0ZhdGFsKGV2ZW50LmlucHV0KSkge1xuICAgIGN0eC5zaHV0ZG93bigpO1xuICB9XG59KTtcbmBgYFxuXG4jIyMgY3R4LmdldENvbnRleHRVc2FnZSgpXG5cblJldHVybnMgY3VycmVudCBjb250ZXh0IHVzYWdlIGZvciB0aGUgYWN0aXZlIG1vZGVsLiBVc2VzIGxhc3QgYXNzaXN0YW50IHVzYWdlIHdoZW4gYXZhaWxhYmxlLCB0aGVuIGVzdGltYXRlcyB0b2tlbnMgZm9yIHRyYWlsaW5nIG1lc3NhZ2VzLlxuXG5gYGB0eXBlc2NyaXB0XG5jb25zdCB1c2FnZSA9IGN0eC5nZXRDb250ZXh0VXNhZ2UoKTtcbmlmICh1c2FnZSAmJiB1c2FnZS50b2tlbnMgPiAxMDBfMDAwKSB7XG4gIC8vIC4uLlxufVxuYGBgXG5cbiMjIyBjdHguY29tcGFjdCgpXG5cblRyaWdnZXIgY29tcGFjdGlvbiB3aXRob3V0IGF3YWl0aW5nIGNvbXBsZXRpb24uIFVzZSBgb25Db21wbGV0ZWAgYW5kIGBvbkVycm9yYCBmb3IgZm9sbG93LXVwIGFjdGlvbnMuXG5cbmBgYHR5cGVzY3JpcHRcbmN0eC5jb21wYWN0KHtcbiAgY3VzdG9tSW5zdHJ1Y3Rpb25zOiBcIkZvY3VzIG9uIHJlY2VudCBjaGFuZ2VzXCIsXG4gIG9uQ29tcGxldGU6IChyZXN1bHQpID0+IHtcbiAgICBjdHgudWkubm90aWZ5KFwiQ29tcGFjdGlvbiBjb21wbGV0ZWRcIiwgXCJpbmZvXCIpO1xuICB9LFxuICBvbkVycm9yOiAoZXJyb3IpID0+IHtcbiAgICBjdHgudWkubm90aWZ5KGBDb21wYWN0aW9uIGZhaWxlZDogJHtlcnJvci5tZXNzYWdlfWAsIFwiZXJyb3JcIik7XG4gIH0sXG59KTtcbmBgYFxuXG4jIyMgY3R4LmdldFN5c3RlbVByb21wdCgpXG5cblJldHVybnMgUGkncyBjdXJyZW50IHN5c3RlbSBwcm9tcHQgc3RyaW5nLlxuXG4tIER1cmluZyBgYmVmb3JlX2FnZW50X3N0YXJ0YCwgdGhpcyByZWZsZWN0cyBjaGFpbmVkIHN5c3RlbS1wcm9tcHQgY2hhbmdlcyBtYWRlIHNvIGZhciBmb3IgdGhlIGN1cnJlbnQgdHVybi5cbi0gSXQgZG9lcyBub3QgaW5jbHVkZSBsYXRlciBgY29udGV4dGAgbWVzc2FnZSBtdXRhdGlvbnMuXG4tIEl0IGRvZXMgbm90IGluY2x1ZGUgYGJlZm9yZV9wcm92aWRlcl9yZXF1ZXN0YCBwYXlsb2FkIHJld3JpdGVzLlxuLSBJZiBsYXRlci1sb2FkZWQgZXh0ZW5zaW9ucyBydW4gYWZ0ZXIgeW91cnMsIHRoZXkgY2FuIHN0aWxsIGNoYW5nZSB3aGF0IGlzIHVsdGltYXRlbHkgc2VudC5cblxuYGBgdHlwZXNjcmlwdFxucGkub24oXCJiZWZvcmVfYWdlbnRfc3RhcnRcIiwgKGV2ZW50LCBjdHgpID0+IHtcbiAgY29uc3QgcHJvbXB0ID0gY3R4LmdldFN5c3RlbVByb21wdCgpO1xuICBjb25zb2xlLmxvZyhgU3lzdGVtIHByb21wdCBsZW5ndGg6ICR7cHJvbXB0Lmxlbmd0aH1gKTtcbn0pO1xuYGBgXG5cbiMjIEV4dGVuc2lvbkNvbW1hbmRDb250ZXh0XG5cbkNvbW1hbmQgaGFuZGxlcnMgcmVjZWl2ZSBgRXh0ZW5zaW9uQ29tbWFuZENvbnRleHRgLCB3aGljaCBleHRlbmRzIGBFeHRlbnNpb25Db250ZXh0YCB3aXRoIHNlc3Npb24gY29udHJvbCBtZXRob2RzLiBUaGVzZSBhcmUgb25seSBhdmFpbGFibGUgaW4gY29tbWFuZHMgYmVjYXVzZSB0aGV5IGNhbiBkZWFkbG9jayBpZiBjYWxsZWQgZnJvbSBldmVudCBoYW5kbGVycy5cblxuIyMjIGN0eC5nZXRTeXN0ZW1Qcm9tcHRPcHRpb25zKClcblxuUmV0dXJucyB0aGUgYmFzZSBpbnB1dHMgUGkgY3VycmVudGx5IHVzZXMgdG8gYnVpbGQgdGhlIHN5c3RlbSBwcm9tcHQuXG5cbmBgYHR5cGVzY3JpcHRcbmNvbnN0IG9wdGlvbnMgPSBjdHguZ2V0U3lzdGVtUHJvbXB0T3B0aW9ucygpO1xuY29uc3QgY29udGV4dFBhdGhzID0gb3B0aW9ucy5jb250ZXh0RmlsZXM/Lm1hcCgoZmlsZSkgPT4gZmlsZS5wYXRoKSA/PyBbXTtcbmBgYFxuXG5UaGlzIGhhcyB0aGUgc2FtZSBzaGFwZSBhbmQgbXV0YWJpbGl0eSBhcyBgYmVmb3JlX2FnZW50X3N0YXJ0YCBgZXZlbnQuc3lzdGVtUHJvbXB0T3B0aW9uc2A6IGN1c3RvbSBwcm9tcHQsIGFjdGl2ZSB0b29scywgdG9vbCBzbmlwcGV0cywgcHJvbXB0IGd1aWRlbGluZXMsIGFwcGVuZGVkIHN5c3RlbSBwcm9tcHQgdGV4dCwgY3dkLCBsb2FkZWQgY29udGV4dCBmaWxlcywgYW5kIGxvYWRlZCBza2lsbHMuIEl0IG1heSBpbmNsdWRlIGZ1bGwgY29udGV4dCBmaWxlIGNvbnRlbnRzLCBzbyB0cmVhdCBpdCBhcyBzZW5zaXRpdmUgZXh0ZW5zaW9uLWxvY2FsIGRhdGEgYW5kIGF2b2lkIGV4cG9zaW5nIGl0IHRocm91Z2ggY29tbWFuZCBsaXN0cywgbG9ncywgb3IgYXV0b2NvbXBsZXRlIG1ldGFkYXRhLlxuXG5UaGlzIHJlcG9ydHMgdGhlIGN1cnJlbnQgYmFzZSBwcm9tcHQgaW5wdXRzLiBJdCBkb2VzIG5vdCBpbmNsdWRlIHBlci10dXJuIGBiZWZvcmVfYWdlbnRfc3RhcnRgIGNoYWluZWQgc3lzdGVtLXByb21wdCBjaGFuZ2VzLCBsYXRlciBgY29udGV4dGAgZXZlbnQgbWVzc2FnZSBtdXRhdGlvbnMsIG9yIGBiZWZvcmVfcHJvdmlkZXJfcmVxdWVzdGAgcGF5bG9hZCByZXdyaXRlcy5cblxuIyMjIGN0eC53YWl0Rm9ySWRsZSgpXG5cbldhaXQgZm9yIHRoZSBhZ2VudCB0byBmaW5pc2ggc3RyZWFtaW5nOlxuXG5gYGB0eXBlc2NyaXB0XG5waS5yZWdpc3RlckNvbW1hbmQoXCJteS1jbWRcIiwge1xuICBoYW5kbGVyOiBhc3luYyAoYXJncywgY3R4KSA9PiB7XG4gICAgYXdhaXQgY3R4LndhaXRGb3JJZGxlKCk7XG4gICAgLy8gQWdlbnQgaXMgbm93IGlkbGUsIHNhZmUgdG8gbW9kaWZ5IHNlc3Npb25cbiAgfSxcbn0pO1xuYGBgXG5cbiMjIyBjdHgubmV3U2Vzc2lvbihvcHRpb25zPylcblxuQ3JlYXRlIGEgbmV3IHNlc3Npb246XG5cbmBgYHR5cGVzY3JpcHRcbmNvbnN0IHBhcmVudFNlc3Npb24gPSBjdHguc2Vzc2lvbk1hbmFnZXIuZ2V0U2Vzc2lvbkZpbGUoKTtcbmNvbnN0IGtpY2tvZmYgPSBcIkNvbnRpbnVlIGluIHRoZSByZXBsYWNlbWVudCBzZXNzaW9uXCI7XG5cbmNvbnN0IHJlc3VsdCA9IGF3YWl0IGN0eC5uZXdTZXNzaW9uKHtcbiAgcGFyZW50U2Vzc2lvbixcbiAgc2V0dXA6IGFzeW5jIChzbSkgPT4ge1xuICAgIHNtLmFwcGVuZE1lc3NhZ2Uoe1xuICAgICAgcm9sZTogXCJ1c2VyXCIsXG4gICAgICBjb250ZW50OiBbeyB0eXBlOiBcInRleHRcIiwgdGV4dDogXCJDb250ZXh0IGZyb20gcHJldmlvdXMgc2Vzc2lvbi4uLlwiIH1dLFxuICAgICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxuICAgIH0pO1xuICB9LFxuICB3aXRoU2Vzc2lvbjogYXN5bmMgKGN0eCkgPT4ge1xuICAgIC8vIFVzZSBvbmx5IHRoZSByZXBsYWNlbWVudC1zZXNzaW9uIGN0eCBoZXJlLlxuICAgIGF3YWl0IGN0eC5zZW5kVXNlck1lc3NhZ2Uoa2lja29mZik7XG4gIH0sXG59KTtcblxuaWYgKHJlc3VsdC5jYW5jZWxsZWQpIHtcbiAgLy8gQW4gZXh0ZW5zaW9uIGNhbmNlbGxlZCB0aGUgbmV3IHNlc3Npb25cbn1cbmBgYFxuXG5PcHRpb25zOlxuLSBgcGFyZW50U2Vzc2lvbmA6IHBhcmVudCBzZXNzaW9uIGZpbGUgdG8gcmVjb3JkIGluIHRoZSBuZXcgc2Vzc2lvbiBoZWFkZXJcbi0gYHNldHVwYDogbXV0YXRlIHRoZSBuZXcgc2Vzc2lvbidzIGBTZXNzaW9uTWFuYWdlcmAgYmVmb3JlIGB3aXRoU2Vzc2lvbmAgcnVuc1xuLSBgd2l0aFNlc3Npb25gOiBydW4gcG9zdC1zd2l0Y2ggd29yayBhZ2FpbnN0IGEgZnJlc2ggcmVwbGFjZW1lbnQtc2Vzc2lvbiBjb250ZXh0LiBEbyBub3QgdXNlIGNhcHR1cmVkIG9sZCBgcGlgIC8gY29tbWFuZCBgY3R4YDsgc2VlIFtTZXNzaW9uIHJlcGxhY2VtZW50IGxpZmVjeWNsZSBhbmQgZm9vdGd1bnNdKCNzZXNzaW9uLXJlcGxhY2VtZW50LWxpZmVjeWNsZS1hbmQtZm9vdGd1bnMpLlxuXG4jIyMgY3R4LmZvcmsoZW50cnlJZCwgb3B0aW9ucz8pXG5cbkZvcmsgZnJvbSBhIHNwZWNpZmljIGVudHJ5LCBjcmVhdGluZyBhIG5ldyBzZXNzaW9uIGZpbGU6XG5cbmBgYHR5cGVzY3JpcHRcbmNvbnN0IHJlc3VsdCA9IGF3YWl0IGN0eC5mb3JrKFwiZW50cnktaWQtMTIzXCIsIHtcbiAgd2l0aFNlc3Npb246IGFzeW5jIChjdHgpID0+IHtcbiAgICAvLyBVc2Ugb25seSB0aGUgcmVwbGFjZW1lbnQtc2Vzc2lvbiBjdHggaGVyZS5cbiAgICBjdHgudWkubm90aWZ5KFwiTm93IGluIHRoZSBmb3JrZWQgc2Vzc2lvblwiLCBcImluZm9cIik7XG4gIH0sXG59KTtcbmlmIChyZXN1bHQuY2FuY2VsbGVkKSB7XG4gIC8vIEFuIGV4dGVuc2lvbiBjYW5jZWxsZWQgdGhlIGZvcmtcbn1cblxuY29uc3QgY2xvbmVSZXN1bHQgPSBhd2FpdCBjdHguZm9yayhcImVudHJ5LWlkLTQ1NlwiLCB7IHBvc2l0aW9uOiBcImF0XCIgfSk7XG5pZiAoY2xvbmVSZXN1bHQuY2FuY2VsbGVkKSB7XG4gIC8vIEFuIGV4dGVuc2lvbiBjYW5jZWxsZWQgdGhlIGNsb25lXG59XG5gYGBcblxuT3B0aW9uczpcbi0gYHBvc2l0aW9uYDogYFwiYmVmb3JlXCJgIChkZWZhdWx0KSBmb3JrcyBiZWZvcmUgdGhlIHNlbGVjdGVkIHVzZXIgbWVzc2FnZSwgcmVzdG9yaW5nIHRoYXQgcHJvbXB0IGludG8gdGhlIGVkaXRvclxuLSBgcG9zaXRpb25gOiBgXCJhdFwiYCBkdXBsaWNhdGVzIHRoZSBhY3RpdmUgcGF0aCB0aHJvdWdoIHRoZSBzZWxlY3RlZCBlbnRyeSB3aXRob3V0IHJlc3RvcmluZyBlZGl0b3IgdGV4dFxuLSBgd2l0aFNlc3Npb25gOiBydW4gcG9zdC1zd2l0Y2ggd29yayBhZ2FpbnN0IGEgZnJlc2ggcmVwbGFjZW1lbnQtc2Vzc2lvbiBjb250ZXh0LiBEbyBub3QgdXNlIGNhcHR1cmVkIG9sZCBgcGlgIC8gY29tbWFuZCBgY3R4YDsgc2VlIFtTZXNzaW9uIHJlcGxhY2VtZW50IGxpZmVjeWNsZSBhbmQgZm9vdGd1bnNdKCNzZXNzaW9uLXJlcGxhY2VtZW50LWxpZmVjeWNsZS1hbmQtZm9vdGd1bnMpLlxuXG4jIyMgY3R4Lm5hdmlnYXRlVHJlZSh0YXJnZXRJZCwgb3B0aW9ucz8pXG5cbk5hdmlnYXRlIHRvIGEgZGlmZmVyZW50IHBvaW50IGluIHRoZSBzZXNzaW9uIHRyZWU6XG5cbmBgYHR5cGVzY3JpcHRcbmNvbnN0IHJlc3VsdCA9IGF3YWl0IGN0eC5uYXZpZ2F0ZVRyZWUoXCJlbnRyeS1pZC00NTZcIiwge1xuICBzdW1tYXJpemU6IHRydWUsXG4gIGN1c3RvbUluc3RydWN0aW9uczogXCJGb2N1cyBvbiBlcnJvciBoYW5kbGluZyBjaGFuZ2VzXCIsXG4gIHJlcGxhY2VJbnN0cnVjdGlvbnM6IGZhbHNlLCAvLyB0cnVlID0gcmVwbGFjZSBkZWZhdWx0IHByb21wdCBlbnRpcmVseVxuICBsYWJlbDogXCJyZXZpZXctY2hlY2twb2ludFwiLFxufSk7XG5gYGBcblxuT3B0aW9uczpcbi0gYHN1bW1hcml6ZWA6IFdoZXRoZXIgdG8gZ2VuZXJhdGUgYSBzdW1tYXJ5IG9mIHRoZSBhYmFuZG9uZWQgYnJhbmNoXG4tIGBjdXN0b21JbnN0cnVjdGlvbnNgOiBDdXN0b20gaW5zdHJ1Y3Rpb25zIGZvciB0aGUgc3VtbWFyaXplclxuLSBgcmVwbGFjZUluc3RydWN0aW9uc2A6IElmIHRydWUsIGBjdXN0b21JbnN0cnVjdGlvbnNgIHJlcGxhY2VzIHRoZSBkZWZhdWx0IHByb21wdCBpbnN0ZWFkIG9mIGJlaW5nIGFwcGVuZGVkXG4tIGBsYWJlbGA6IExhYmVsIHRvIGF0dGFjaCB0byB0aGUgYnJhbmNoIHN1bW1hcnkgZW50cnkgKG9yIHRhcmdldCBlbnRyeSBpZiBub3Qgc3VtbWFyaXppbmcpXG5cbiMjIyBjdHguc3dpdGNoU2Vzc2lvbihzZXNzaW9uUGF0aCwgb3B0aW9ucz8pXG5cblN3aXRjaCB0byBhIGRpZmZlcmVudCBzZXNzaW9uIGZpbGU6XG5cbmBgYHR5cGVzY3JpcHRcbmNvbnN0IHJlc3VsdCA9IGF3YWl0IGN0eC5zd2l0Y2hTZXNzaW9uKFwiL3BhdGgvdG8vc2Vzc2lvbi5qc29ubFwiLCB7XG4gIHdpdGhTZXNzaW9uOiBhc3luYyAoY3R4KSA9PiB7XG4gICAgYXdhaXQgY3R4LnNlbmRVc2VyTWVzc2FnZShcIlJlc3VtZSB3b3JrIGluIHRoZSByZXBsYWNlbWVudCBzZXNzaW9uXCIpO1xuICB9LFxufSk7XG5pZiAocmVzdWx0LmNhbmNlbGxlZCkge1xuICAvLyBBbiBleHRlbnNpb24gY2FuY2VsbGVkIHRoZSBzd2l0Y2ggdmlhIHNlc3Npb25fYmVmb3JlX3N3aXRjaFxufVxuYGBgXG5cbk9wdGlvbnM6XG4tIGB3aXRoU2Vzc2lvbmA6IHJ1biBwb3N0LXN3aXRjaCB3b3JrIGFnYWluc3QgYSBmcmVzaCByZXBsYWNlbWVudC1zZXNzaW9uIGNvbnRleHQuIERvIG5vdCB1c2UgY2FwdHVyZWQgb2xkIGBwaWAgLyBjb21tYW5kIGBjdHhgOyBzZWUgW1Nlc3Npb24gcmVwbGFjZW1lbnQgbGlmZWN5Y2xlIGFuZCBmb290Z3Vuc10oI3Nlc3Npb24tcmVwbGFjZW1lbnQtbGlmZWN5Y2xlLWFuZC1mb290Z3VucykuXG5cblRvIGRpc2NvdmVyIGF2YWlsYWJsZSBzZXNzaW9ucywgdXNlIHRoZSBzdGF0aWMgYFNlc3Npb25NYW5hZ2VyLmxpc3QoKWAgb3IgYFNlc3Npb25NYW5hZ2VyLmxpc3RBbGwoKWAgbWV0aG9kczpcblxuYGBgdHlwZXNjcmlwdFxuaW1wb3J0IHsgU2Vzc2lvbk1hbmFnZXIgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudFwiO1xuXG5waS5yZWdpc3RlckNvbW1hbmQoXCJzd2l0Y2hcIiwge1xuICBkZXNjcmlwdGlvbjogXCJTd2l0Y2ggdG8gYW5vdGhlciBzZXNzaW9uXCIsXG4gIGhhbmRsZXI6IGFzeW5jIChhcmdzLCBjdHgpID0+IHtcbiAgICBjb25zdCBzZXNzaW9ucyA9IGF3YWl0IFNlc3Npb25NYW5hZ2VyLmxpc3QoY3R4LmN3ZCk7XG4gICAgaWYgKHNlc3Npb25zLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuICAgIGNvbnN0IGNob2ljZSA9IGF3YWl0IGN0eC51aS5zZWxlY3QoXG4gICAgICBcIlBpY2sgc2Vzc2lvbjpcIixcbiAgICAgIHNlc3Npb25zLm1hcChzID0+IHMuZmlsZSksXG4gICAgKTtcbiAgICBpZiAoY2hvaWNlKSB7XG4gICAgICBhd2FpdCBjdHguc3dpdGNoU2Vzc2lvbihjaG9pY2UsIHtcbiAgICAgICAgd2l0aFNlc3Npb246IGFzeW5jIChjdHgpID0+IHtcbiAgICAgICAgICBjdHgudWkubm90aWZ5KFwiU3dpdGNoZWQgc2Vzc2lvblwiLCBcImluZm9cIik7XG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICB9XG4gIH0sXG59KTtcbmBgYFxuXG4jIyMgU2Vzc2lvbiByZXBsYWNlbWVudCBsaWZlY3ljbGUgYW5kIGZvb3RndW5zXG5cbmB3aXRoU2Vzc2lvbmAgcmVjZWl2ZXMgYSBmcmVzaCBgUmVwbGFjZWRTZXNzaW9uQ29udGV4dGAsIHdoaWNoIGV4dGVuZHMgYEV4dGVuc2lvbkNvbW1hbmRDb250ZXh0YCB3aXRoIGFzeW5jIGBzZW5kTWVzc2FnZSgpYCBhbmQgYHNlbmRVc2VyTWVzc2FnZSgpYCBoZWxwZXJzIGJvdW5kIHRvIHRoZSByZXBsYWNlbWVudCBzZXNzaW9uLlxuXG5MaWZlY3ljbGUgYW5kIGZvb3RndW5zOlxuLSBgd2l0aFNlc3Npb25gIHJ1bnMgb25seSBhZnRlciB0aGUgb2xkIHNlc3Npb24gaGFzIGVtaXR0ZWQgYHNlc3Npb25fc2h1dGRvd25gLCB0aGUgb2xkIHJ1bnRpbWUgaGFzIGJlZW4gdG9ybiBkb3duLCB0aGUgcmVwbGFjZW1lbnQgc2Vzc2lvbiBoYXMgYmVlbiByZWJvdW5kLCBhbmQgdGhlIG5ldyBleHRlbnNpb24gaW5zdGFuY2UgaGFzIGFscmVhZHkgcmVjZWl2ZWQgYHNlc3Npb25fc3RhcnRgLlxuLSBUaGUgY2FsbGJhY2sgc3RpbGwgZXhlY3V0ZXMgaW4gdGhlIG9yaWdpbmFsIGNsb3N1cmUsIG5vdCBpbnNpZGUgdGhlIG5ldyBleHRlbnNpb24gaW5zdGFuY2UuIFRoYXQgbWVhbnMgeW91ciBvbGQgZXh0ZW5zaW9uIGluc3RhbmNlIG1heSBhbHJlYWR5IGhhdmUgcnVuIGl0cyBzaHV0ZG93biBjbGVhbnVwIGJlZm9yZSBgd2l0aFNlc3Npb25gIHN0YXJ0cy5cbi0gQ2FwdHVyZWQgb2xkIGBwaWAgLyBvbGQgY29tbWFuZCBgY3R4YCBzZXNzaW9uLWJvdW5kIG9iamVjdHMgYXJlIHN0YWxlIGFmdGVyIHJlcGxhY2VtZW50IGFuZCB3aWxsIHRocm93IGlmIHVzZWQuIFVzZSBvbmx5IHRoZSBgY3R4YCBwYXNzZWQgdG8gYHdpdGhTZXNzaW9uYCBmb3Igc2Vzc2lvbi1ib3VuZCB3b3JrLlxuLSBQcmV2aW91c2x5IGV4dHJhY3RlZCByYXcgb2JqZWN0cyBhcmUgc3RpbGwgeW91ciByZXNwb25zaWJpbGl0eS4gRm9yIGV4YW1wbGUsIGlmIHlvdSBjYXB0dXJlIGBjb25zdCBzbSA9IGN0eC5zZXNzaW9uTWFuYWdlcmAgYmVmb3JlIHJlcGxhY2VtZW50LCBgc21gIGlzIHN0aWxsIHRoZSBvbGQgYFNlc3Npb25NYW5hZ2VyYCBvYmplY3QuIERvIG5vdCByZXVzZSBpdCBhZnRlciByZXBsYWNlbWVudC5cbi0gQ29kZSBpbiBgd2l0aFNlc3Npb25gIHNob3VsZCBhc3N1bWUgYW55IHN0YXRlIGludmFsaWRhdGVkIGJ5IHlvdXIgYHNlc3Npb25fc2h1dGRvd25gIGhhbmRsZXIgaXMgYWxyZWFkeSBnb25lLiBPbmx5IGNhcHR1cmUgcGxhaW4gZGF0YSB0aGF0IHN1cnZpdmVzIHNodXRkb3duIGNsZWFubHksIHN1Y2ggYXMgc3RyaW5ncywgaWRzLCBhbmQgc2VyaWFsaXplZCBjb25maWcuXG5cblNhZmUgcGF0dGVybjpcblxuYGBgdHlwZXNjcmlwdFxucGkucmVnaXN0ZXJDb21tYW5kKFwiaGFuZG9mZlwiLCB7XG4gIGhhbmRsZXI6IGFzeW5jIChfYXJncywgY3R4KSA9PiB7XG4gICAgY29uc3Qga2lja29mZiA9IFwiQ29udGludWUgZnJvbSB0aGUgcmVwbGFjZW1lbnQgc2Vzc2lvblwiO1xuICAgIGF3YWl0IGN0eC5uZXdTZXNzaW9uKHtcbiAgICAgIHdpdGhTZXNzaW9uOiBhc3luYyAoY3R4KSA9PiB7XG4gICAgICAgIGF3YWl0IGN0eC5zZW5kVXNlck1lc3NhZ2Uoa2lja29mZik7XG4gICAgICB9LFxuICAgIH0pO1xuICB9LFxufSk7XG5gYGBcblxuVW5zYWZlIHBhdHRlcm46XG5cbmBgYHR5cGVzY3JpcHRcbnBpLnJlZ2lzdGVyQ29tbWFuZChcImhhbmRvZmZcIiwge1xuICBoYW5kbGVyOiBhc3luYyAoX2FyZ3MsIGN0eCkgPT4ge1xuICAgIGNvbnN0IG9sZFNlc3Npb25NYW5hZ2VyID0gY3R4LnNlc3Npb25NYW5hZ2VyO1xuICAgIGF3YWl0IGN0eC5uZXdTZXNzaW9uKHtcbiAgICAgIHdpdGhTZXNzaW9uOiBhc3luYyAoX2N0eCkgPT4ge1xuICAgICAgICAvLyBzdGFsZSBvbGQgb2JqZWN0czogZG8gbm90IGRvIHRoaXNcbiAgICAgICAgb2xkU2Vzc2lvbk1hbmFnZXIuZ2V0U2Vzc2lvbkZpbGUoKTtcbiAgICAgICAgcGkuc2VuZFVzZXJNZXNzYWdlKFwid3JvbmdcIik7XG4gICAgICB9LFxuICAgIH0pO1xuICB9LFxufSk7XG5gYGBcblxuIyMjIGN0eC5yZWxvYWQoKVxuXG5SdW4gdGhlIHNhbWUgcmVsb2FkIGZsb3cgYXMgYC9yZWxvYWRgLlxuXG5gYGB0eXBlc2NyaXB0XG5waS5yZWdpc3RlckNvbW1hbmQoXCJyZWxvYWQtcnVudGltZVwiLCB7XG4gIGRlc2NyaXB0aW9uOiBcIlJlbG9hZCBleHRlbnNpb25zLCBza2lsbHMsIHByb21wdHMsIGFuZCB0aGVtZXNcIixcbiAgaGFuZGxlcjogYXN5bmMgKF9hcmdzLCBjdHgpID0+IHtcbiAgICBhd2FpdCBjdHgucmVsb2FkKCk7XG4gICAgcmV0dXJuO1xuICB9LFxufSk7XG5gYGBcblxuSW1wb3J0YW50IGJlaGF2aW9yOlxuLSBgYXdhaXQgY3R4LnJlbG9hZCgpYCBlbWl0cyBgc2Vzc2lvbl9zaHV0ZG93bmAgZm9yIHRoZSBjdXJyZW50IGV4dGVuc2lvbiBydW50aW1lXG4tIEl0IHRoZW4gcmVsb2FkcyByZXNvdXJjZXMgYW5kIGVtaXRzIGBzZXNzaW9uX3N0YXJ0YCB3aXRoIGByZWFzb246IFwicmVsb2FkXCJgIGFuZCBgcmVzb3VyY2VzX2Rpc2NvdmVyYCB3aXRoIHJlYXNvbiBgXCJyZWxvYWRcImBcbi0gVGhlIGN1cnJlbnRseSBydW5uaW5nIGNvbW1hbmQgaGFuZGxlciBzdGlsbCBjb250aW51ZXMgaW4gdGhlIG9sZCBjYWxsIGZyYW1lXG4tIENvZGUgYWZ0ZXIgYGF3YWl0IGN0eC5yZWxvYWQoKWAgc3RpbGwgcnVucyBmcm9tIHRoZSBwcmUtcmVsb2FkIHZlcnNpb25cbi0gQ29kZSBhZnRlciBgYXdhaXQgY3R4LnJlbG9hZCgpYCBtdXN0IG5vdCBhc3N1bWUgb2xkIGluLW1lbW9yeSBleHRlbnNpb24gc3RhdGUgaXMgc3RpbGwgdmFsaWRcbi0gQWZ0ZXIgdGhlIGhhbmRsZXIgcmV0dXJucywgZnV0dXJlIGNvbW1hbmRzL2V2ZW50cy90b29sIGNhbGxzIHVzZSB0aGUgbmV3IGV4dGVuc2lvbiB2ZXJzaW9uXG5cbkZvciBwcmVkaWN0YWJsZSBiZWhhdmlvciwgdHJlYXQgcmVsb2FkIGFzIHRlcm1pbmFsIGZvciB0aGF0IGhhbmRsZXIgKGBhd2FpdCBjdHgucmVsb2FkKCk7IHJldHVybjtgKS5cblxuVG9vbHMgcnVuIHdpdGggYEV4dGVuc2lvbkNvbnRleHRgLCBzbyB0aGV5IGNhbm5vdCBjYWxsIGBjdHgucmVsb2FkKClgIGRpcmVjdGx5LiBVc2UgYSBjb21tYW5kIGFzIHRoZSByZWxvYWQgZW50cnlwb2ludCwgdGhlbiBleHBvc2UgYSB0b29sIHRoYXQgcXVldWVzIHRoYXQgY29tbWFuZCBhcyBhIGZvbGxvdy11cCB1c2VyIG1lc3NhZ2UuXG5cbkV4YW1wbGUgdG9vbCB0aGUgTExNIGNhbiBjYWxsIHRvIHRyaWdnZXIgcmVsb2FkOlxuXG5gYGB0eXBlc2NyaXB0XG5pbXBvcnQgdHlwZSB7IEV4dGVuc2lvbkFQSSB9IGZyb20gXCJAZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50XCI7XG5pbXBvcnQgeyBUeXBlIH0gZnJvbSBcInR5cGVib3hcIjtcblxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gKHBpOiBFeHRlbnNpb25BUEkpIHtcbiAgcGkucmVnaXN0ZXJDb21tYW5kKFwicmVsb2FkLXJ1bnRpbWVcIiwge1xuICAgIGRlc2NyaXB0aW9uOiBcIlJlbG9hZCBleHRlbnNpb25zLCBza2lsbHMsIHByb21wdHMsIGFuZCB0aGVtZXNcIixcbiAgICBoYW5kbGVyOiBhc3luYyAoX2FyZ3MsIGN0eCkgPT4ge1xuICAgICAgYXdhaXQgY3R4LnJlbG9hZCgpO1xuICAgICAgcmV0dXJuO1xuICAgIH0sXG4gIH0pO1xuXG4gIHBpLnJlZ2lzdGVyVG9vbCh7XG4gICAgbmFtZTogXCJyZWxvYWRfcnVudGltZVwiLFxuICAgIGxhYmVsOiBcIlJlbG9hZCBSdW50aW1lXCIsXG4gICAgZGVzY3JpcHRpb246IFwiUmVsb2FkIGV4dGVuc2lvbnMsIHNraWxscywgcHJvbXB0cywgYW5kIHRoZW1lc1wiLFxuICAgIHBhcmFtZXRlcnM6IFR5cGUuT2JqZWN0KHt9KSxcbiAgICBhc3luYyBleGVjdXRlKCkge1xuICAgICAgcGkuc2VuZFVzZXJNZXNzYWdlKFwiL3JlbG9hZC1ydW50aW1lXCIsIHsgZGVsaXZlckFzOiBcImZvbGxvd1VwXCIgfSk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBjb250ZW50OiBbeyB0eXBlOiBcInRleHRcIiwgdGV4dDogXCJRdWV1ZWQgL3JlbG9hZC1ydW50aW1lIGFzIGEgZm9sbG93LXVwIGNvbW1hbmQuXCIgfV0sXG4gICAgICB9O1xuICAgIH0sXG4gIH0pO1xufVxuYGBgXG5cbiMjIEV4dGVuc2lvbkFQSSBNZXRob2RzXG5cbiMjIyBwaS5vbihldmVudCwgaGFuZGxlcilcblxuU3Vic2NyaWJlIHRvIGV2ZW50cy4gU2VlIFtFdmVudHNdKCNldmVudHMpIGZvciBldmVudCB0eXBlcyBhbmQgcmV0dXJuIHZhbHVlcy5cblxuIyMjIHBpLnJlZ2lzdGVyVG9vbChkZWZpbml0aW9uKVxuXG5SZWdpc3RlciBhIGN1c3RvbSB0b29sIGNhbGxhYmxlIGJ5IHRoZSBMTE0uIFNlZSBbQ3VzdG9tIFRvb2xzXSgjY3VzdG9tLXRvb2xzKSBmb3IgZnVsbCBkZXRhaWxzLlxuXG5gcGkucmVnaXN0ZXJUb29sKClgIHdvcmtzIGJvdGggZHVyaW5nIGV4dGVuc2lvbiBsb2FkIGFuZCBhZnRlciBzdGFydHVwLiBZb3UgY2FuIGNhbGwgaXQgaW5zaWRlIGBzZXNzaW9uX3N0YXJ0YCwgY29tbWFuZCBoYW5kbGVycywgb3Igb3RoZXIgZXZlbnQgaGFuZGxlcnMuIE5ldyB0b29scyBhcmUgcmVmcmVzaGVkIGltbWVkaWF0ZWx5IGluIHRoZSBzYW1lIHNlc3Npb24sIHNvIHRoZXkgYXBwZWFyIGluIGBwaS5nZXRBbGxUb29scygpYCBhbmQgYXJlIGNhbGxhYmxlIGJ5IHRoZSBMTE0gd2l0aG91dCBgL3JlbG9hZGAuXG5cblVzZSBgcGkuc2V0QWN0aXZlVG9vbHMoKWAgdG8gZW5hYmxlIG9yIGRpc2FibGUgdG9vbHMgKGluY2x1ZGluZyBkeW5hbWljYWxseSBhZGRlZCB0b29scykgYXQgcnVudGltZS5cblxuVXNlIGBwcm9tcHRTbmlwcGV0YCB0byBvcHQgYSBjdXN0b20gdG9vbCBpbnRvIGEgb25lLWxpbmUgZW50cnkgaW4gYEF2YWlsYWJsZSB0b29sc2AsIGFuZCBgcHJvbXB0R3VpZGVsaW5lc2AgdG8gYXBwZW5kIHRvb2wtc3BlY2lmaWMgYnVsbGV0cyB0byB0aGUgZGVmYXVsdCBgR3VpZGVsaW5lc2Agc2VjdGlvbiB3aGVuIHRoZSB0b29sIGlzIGFjdGl2ZS5cblxuKipJbXBvcnRhbnQ6KiogYHByb21wdEd1aWRlbGluZXNgIGJ1bGxldHMgYXJlIGFwcGVuZGVkIGZsYXQgdG8gdGhlIGBHdWlkZWxpbmVzYCBzZWN0aW9uIHdpdGggbm8gdG9vbCBuYW1lIHByZWZpeC4gRWFjaCBndWlkZWxpbmUgbXVzdCBuYW1lIHRoZSB0b29sIGl0IHJlZmVycyB0byDigJQgYXZvaWQgXCJVc2UgdGhpcyB0b29sIHdoZW4uLi5cIiBiZWNhdXNlIHRoZSBMTE0gY2Fubm90IHRlbGwgd2hpY2ggdG9vbCBcInRoaXNcIiBtZWFucy4gV3JpdGUgXCJVc2UgbXlfdG9vbCB3aGVuLi4uXCIgaW5zdGVhZC5cblxuU2VlIFtkeW5hbWljLXRvb2xzLnRzXSguLi9leGFtcGxlcy9leHRlbnNpb25zL2R5bmFtaWMtdG9vbHMudHMpIGZvciBhIGZ1bGwgZXhhbXBsZS5cblxuYGBgdHlwZXNjcmlwdFxuaW1wb3J0IHsgVHlwZSB9IGZyb20gXCJ0eXBlYm94XCI7XG5pbXBvcnQgeyBTdHJpbmdFbnVtIH0gZnJvbSBcIkBlYXJlbmRpbC13b3Jrcy9waS1haVwiO1xuXG5waS5yZWdpc3RlclRvb2woe1xuICBuYW1lOiBcIm15X3Rvb2xcIixcbiAgbGFiZWw6IFwiTXkgVG9vbFwiLFxuICBkZXNjcmlwdGlvbjogXCJXaGF0IHRoaXMgdG9vbCBkb2VzXCIsXG4gIHByb21wdFNuaXBwZXQ6IFwiU3VtbWFyaXplIG9yIHRyYW5zZm9ybSB0ZXh0IGFjY29yZGluZyB0byBhY3Rpb25cIixcbiAgcHJvbXB0R3VpZGVsaW5lczogW1wiVXNlIG15X3Rvb2wgd2hlbiB0aGUgdXNlciBhc2tzIHRvIHN1bW1hcml6ZSBwcmV2aW91c2x5IGdlbmVyYXRlZCB0ZXh0LlwiXSxcbiAgcGFyYW1ldGVyczogVHlwZS5PYmplY3Qoe1xuICAgIGFjdGlvbjogU3RyaW5nRW51bShbXCJsaXN0XCIsIFwiYWRkXCJdIGFzIGNvbnN0KSxcbiAgICB0ZXh0OiBUeXBlLk9wdGlvbmFsKFR5cGUuU3RyaW5nKCkpLFxuICB9KSxcbiAgcHJlcGFyZUFyZ3VtZW50cyhhcmdzKSB7XG4gICAgLy8gT3B0aW9uYWwgY29tcGF0aWJpbGl0eSBzaGltLiBSdW5zIGJlZm9yZSBzY2hlbWEgdmFsaWRhdGlvbi5cbiAgICAvLyBSZXR1cm4gdGhlIGN1cnJlbnQgc2NoZW1hIHNoYXBlLCBmb3IgZXhhbXBsZSB0byBmb2xkIGxlZ2FjeSBmaWVsZHNcbiAgICAvLyBpbnRvIHRoZSBtb2Rlcm4gcGFyYW1ldGVyIG9iamVjdC5cbiAgICByZXR1cm4gYXJncztcbiAgfSxcblxuICBhc3luYyBleGVjdXRlKHRvb2xDYWxsSWQsIHBhcmFtcywgc2lnbmFsLCBvblVwZGF0ZSwgY3R4KSB7XG4gICAgLy8gU3RyZWFtIHByb2dyZXNzXG4gICAgb25VcGRhdGU/Lih7IGNvbnRlbnQ6IFt7IHR5cGU6IFwidGV4dFwiLCB0ZXh0OiBcIldvcmtpbmcuLi5cIiB9XSB9KTtcblxuICAgIHJldHVybiB7XG4gICAgICBjb250ZW50OiBbeyB0eXBlOiBcInRleHRcIiwgdGV4dDogXCJEb25lXCIgfV0sXG4gICAgICBkZXRhaWxzOiB7IHJlc3VsdDogXCIuLi5cIiB9LFxuICAgIH07XG4gIH0sXG5cbiAgLy8gT3B0aW9uYWw6IEN1c3RvbSByZW5kZXJpbmdcbiAgcmVuZGVyQ2FsbChhcmdzLCB0aGVtZSwgY29udGV4dCkgeyAuLi4gfSxcbiAgcmVuZGVyUmVzdWx0KHJlc3VsdCwgb3B0aW9ucywgdGhlbWUsIGNvbnRleHQpIHsgLi4uIH0sXG59KTtcbmBgYFxuXG4jIyMgcGkuc2VuZE1lc3NhZ2UobWVzc2FnZSwgb3B0aW9ucz8pXG5cbkluamVjdCBhIGN1c3RvbSBtZXNzYWdlIGludG8gdGhlIHNlc3Npb24uXG5cbmBgYHR5cGVzY3JpcHRcbnBpLnNlbmRNZXNzYWdlKHtcbiAgY3VzdG9tVHlwZTogXCJteS1leHRlbnNpb25cIixcbiAgY29udGVudDogXCJNZXNzYWdlIHRleHRcIixcbiAgZGlzcGxheTogdHJ1ZSxcbiAgZGV0YWlsczogeyAuLi4gfSxcbn0sIHtcbiAgdHJpZ2dlclR1cm46IHRydWUsXG4gIGRlbGl2ZXJBczogXCJzdGVlclwiLFxufSk7XG5gYGBcblxuKipPcHRpb25zOioqXG4tIGBkZWxpdmVyQXNgIC0gRGVsaXZlcnkgbW9kZTpcbiAgLSBgXCJzdGVlclwiYCAoZGVmYXVsdCkgLSBRdWV1ZXMgdGhlIG1lc3NhZ2Ugd2hpbGUgc3RyZWFtaW5nLiBEZWxpdmVyZWQgYWZ0ZXIgdGhlIGN1cnJlbnQgYXNzaXN0YW50IHR1cm4gZmluaXNoZXMgZXhlY3V0aW5nIGl0cyB0b29sIGNhbGxzLCBiZWZvcmUgdGhlIG5leHQgTExNIGNhbGwuXG4gIC0gYFwiZm9sbG93VXBcImAgLSBXYWl0cyBmb3IgYWdlbnQgdG8gZmluaXNoLiBEZWxpdmVyZWQgb25seSB3aGVuIGFnZW50IGhhcyBubyBtb3JlIHRvb2wgY2FsbHMuXG4gIC0gYFwibmV4dFR1cm5cImAgLSBRdWV1ZWQgZm9yIG5leHQgdXNlciBwcm9tcHQuIERvZXMgbm90IGludGVycnVwdCBvciB0cmlnZ2VyIGFueXRoaW5nLlxuLSBgdHJpZ2dlclR1cm46IHRydWVgIC0gSWYgYWdlbnQgaXMgaWRsZSwgdHJpZ2dlciBhbiBMTE0gcmVzcG9uc2UgaW1tZWRpYXRlbHkuIE9ubHkgYXBwbGllcyB0byBgXCJzdGVlclwiYCBhbmQgYFwiZm9sbG93VXBcImAgbW9kZXMgKGlnbm9yZWQgZm9yIGBcIm5leHRUdXJuXCJgKS5cblxuIyMjIHBpLnNlbmRVc2VyTWVzc2FnZShjb250ZW50LCBvcHRpb25zPylcblxuU2VuZCBhIHVzZXIgbWVzc2FnZSB0byB0aGUgYWdlbnQuIFVubGlrZSBgc2VuZE1lc3NhZ2UoKWAgd2hpY2ggc2VuZHMgY3VzdG9tIG1lc3NhZ2VzLCB0aGlzIHNlbmRzIGFuIGFjdHVhbCB1c2VyIG1lc3NhZ2UgdGhhdCBhcHBlYXJzIGFzIGlmIHR5cGVkIGJ5IHRoZSB1c2VyLiBBbHdheXMgdHJpZ2dlcnMgYSB0dXJuLlxuXG5gYGB0eXBlc2NyaXB0XG4vLyBTaW1wbGUgdGV4dCBtZXNzYWdlXG5waS5zZW5kVXNlck1lc3NhZ2UoXCJXaGF0IGlzIDIrMj9cIik7XG5cbi8vIFdpdGggY29udGVudCBhcnJheSAodGV4dCArIGltYWdlcylcbnBpLnNlbmRVc2VyTWVzc2FnZShbXG4gIHsgdHlwZTogXCJ0ZXh0XCIsIHRleHQ6IFwiRGVzY3JpYmUgdGhpcyBpbWFnZTpcIiB9LFxuICB7IHR5cGU6IFwiaW1hZ2VcIiwgc291cmNlOiB7IHR5cGU6IFwiYmFzZTY0XCIsIG1lZGlhVHlwZTogXCJpbWFnZS9wbmdcIiwgZGF0YTogXCIuLi5cIiB9IH0sXG5dKTtcblxuLy8gRHVyaW5nIHN0cmVhbWluZyAtIG11c3Qgc3BlY2lmeSBkZWxpdmVyeSBtb2RlXG5waS5zZW5kVXNlck1lc3NhZ2UoXCJGb2N1cyBvbiBlcnJvciBoYW5kbGluZ1wiLCB7IGRlbGl2ZXJBczogXCJzdGVlclwiIH0pO1xucGkuc2VuZFVzZXJNZXNzYWdlKFwiQW5kIHRoZW4gc3VtbWFyaXplXCIsIHsgZGVsaXZlckFzOiBcImZvbGxvd1VwXCIgfSk7XG5gYGBcblxuKipPcHRpb25zOioqXG4tIGBkZWxpdmVyQXNgIC0gUmVxdWlyZWQgd2hlbiBhZ2VudCBpcyBzdHJlYW1pbmc6XG4gIC0gYFwic3RlZXJcImAgLSBRdWV1ZXMgdGhlIG1lc3NhZ2UgZm9yIGRlbGl2ZXJ5IGFmdGVyIHRoZSBjdXJyZW50IGFzc2lzdGFudCB0dXJuIGZpbmlzaGVzIGV4ZWN1dGluZyBpdHMgdG9vbCBjYWxsc1xuICAtIGBcImZvbGxvd1VwXCJgIC0gV2FpdHMgZm9yIGFnZW50IHRvIGZpbmlzaCBhbGwgdG9vbHNcblxuV2hlbiBub3Qgc3RyZWFtaW5nLCB0aGUgbWVzc2FnZSBpcyBzZW50IGltbWVkaWF0ZWx5IGFuZCB0cmlnZ2VycyBhIG5ldyB0dXJuLiBXaGVuIHN0cmVhbWluZyB3aXRob3V0IGBkZWxpdmVyQXNgLCB0aHJvd3MgYW4gZXJyb3IuXG5cblNlZSBbc2VuZC11c2VyLW1lc3NhZ2UudHNdKC4uL2V4YW1wbGVzL2V4dGVuc2lvbnMvc2VuZC11c2VyLW1lc3NhZ2UudHMpIGZvciBhIGNvbXBsZXRlIGV4YW1wbGUuXG5cbiMjIyBwaS5hcHBlbmRFbnRyeShjdXN0b21UeXBlLCBkYXRhPylcbiIsInRydW5jYXRlZCI6dHJ1ZSwidHJ1bmNhdGVkQnkiOiJieXRlcyIsInRvdGFsTGluZXMiOjI2NzYsInRvdGFsQnl0ZXMiOjEwMzM1MCwib3V0cHV0TGluZXMiOjEzODYsIm91dHB1dEJ5dGVzIjo1MTE3NiwibGFzdExpbmVQYXJ0aWFsIjpmYWxzZSwiZmlyc3RMaW5lRXhjZWVkc0xpbWl0IjpmYWxzZSwibWF4TGluZXMiOjIwMDAsIm1heEJ5dGVzIjo1MTIwMH19LCJpc0Vycm9yIjpmYWxzZSwidGltZXN0YW1wIjoxNzgxOTUzOTIwMjcxfX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiOGM3YjYxMjgiLCJwYXJlbnRJZCI6IjFlYmVjOGZhIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToxMjowMC4yNzJaIiwibWVzc2FnZSI6eyJyb2xlIjoidG9vbFJlc3VsdCIsInRvb2xDYWxsSWQiOiJjYWxsXzAxX0o1Z1R1Qmt1QnFacHVmelUyNU5FODkwNCIsInRvb2xOYW1lIjoicmVhZCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6Ij4gcGkgY2FuIGNyZWF0ZSBza2lsbHMuIEFzayBpdCB0byBidWlsZCBvbmUgZm9yIHlvdXIgdXNlIGNhc2UuXG5cbiMgU2tpbGxzXG5cblNraWxscyBhcmUgc2VsZi1jb250YWluZWQgY2FwYWJpbGl0eSBwYWNrYWdlcyB0aGF0IHRoZSBhZ2VudCBsb2FkcyBvbi1kZW1hbmQuIEEgc2tpbGwgcHJvdmlkZXMgc3BlY2lhbGl6ZWQgd29ya2Zsb3dzLCBzZXR1cCBpbnN0cnVjdGlvbnMsIGhlbHBlciBzY3JpcHRzLCBhbmQgcmVmZXJlbmNlIGRvY3VtZW50YXRpb24gZm9yIHNwZWNpZmljIHRhc2tzLlxuXG5QaSBpbXBsZW1lbnRzIHRoZSBbQWdlbnQgU2tpbGxzIHN0YW5kYXJkXShodHRwczovL2FnZW50c2tpbGxzLmlvL3NwZWNpZmljYXRpb24pLCB3YXJuaW5nIGFib3V0IG1vc3QgdmlvbGF0aW9ucyBidXQgcmVtYWluaW5nIGxlbmllbnQuIFBpIGFsbG93cyBza2lsbCBuYW1lcyB0byBkaWZmZXIgZnJvbSB0aGVpciBwYXJlbnQgZGlyZWN0b3J5IGV2ZW4gdGhvdWdoIHRoZSBzdGFuZGFyZCBkaXNhbGxvd3MgaXQ7IHRoYXQgcnVsZSBpcyBzdWJvcHRpbWFsIGZvciBzaGFyZWQgc2tpbGwgZGlyZWN0b3JpZXMgdXNlZCBhY3Jvc3MgbXVsdGlwbGUgYWdlbnQgaGFybmVzc2VzLlxuXG4jIyBUYWJsZSBvZiBDb250ZW50c1xuXG4tIFtMb2NhdGlvbnNdKCNsb2NhdGlvbnMpXG4tIFtIb3cgU2tpbGxzIFdvcmtdKCNob3ctc2tpbGxzLXdvcmspXG4tIFtTa2lsbCBDb21tYW5kc10oI3NraWxsLWNvbW1hbmRzKVxuLSBbU2tpbGwgU3RydWN0dXJlXSgjc2tpbGwtc3RydWN0dXJlKVxuLSBbRnJvbnRtYXR0ZXJdKCNmcm9udG1hdHRlcilcbi0gW1ZhbGlkYXRpb25dKCN2YWxpZGF0aW9uKVxuLSBbRXhhbXBsZV0oI2V4YW1wbGUpXG4tIFtTa2lsbCBSZXBvc2l0b3JpZXNdKCNza2lsbC1yZXBvc2l0b3JpZXMpXG5cbiMjIExvY2F0aW9uc1xuXG4+ICoqU2VjdXJpdHk6KiogU2tpbGxzIGNhbiBpbnN0cnVjdCB0aGUgbW9kZWwgdG8gcGVyZm9ybSBhbnkgYWN0aW9uIGFuZCBtYXkgaW5jbHVkZSBleGVjdXRhYmxlIGNvZGUgdGhlIG1vZGVsIGludm9rZXMuIFJldmlldyBza2lsbCBjb250ZW50IGJlZm9yZSB1c2UuXG5cblBpIGxvYWRzIHNraWxscyBmcm9tOlxuXG4tIEdsb2JhbDpcbiAgLSBgfi8ucGkvYWdlbnQvc2tpbGxzL2BcbiAgLSBgfi8uYWdlbnRzL3NraWxscy9gXG4tIFByb2plY3QgKG9ubHkgYWZ0ZXIgdGhlIHByb2plY3QgaXMgdHJ1c3RlZCk6XG4gIC0gYC5waS9za2lsbHMvYFxuICAtIGAuYWdlbnRzL3NraWxscy9gIGluIGBjd2RgIGFuZCBhbmNlc3RvciBkaXJlY3RvcmllcyAodXAgdG8gZ2l0IHJlcG8gcm9vdCwgb3IgZmlsZXN5c3RlbSByb290IHdoZW4gbm90IGluIGEgcmVwbylcbi0gUGFja2FnZXM6IGBza2lsbHMvYCBkaXJlY3RvcmllcyBvciBgcGkuc2tpbGxzYCBlbnRyaWVzIGluIGBwYWNrYWdlLmpzb25gXG4tIFNldHRpbmdzOiBgc2tpbGxzYCBhcnJheSB3aXRoIGZpbGVzIG9yIGRpcmVjdG9yaWVzXG4tIENMSTogYC0tc2tpbGwgPHBhdGg+YCAocmVwZWF0YWJsZSwgYWRkaXRpdmUgZXZlbiB3aXRoIGAtLW5vLXNraWxsc2ApXG5cbkRpc2NvdmVyeSBydWxlczpcbi0gSW4gYH4vLnBpL2FnZW50L3NraWxscy9gIGFuZCBgLnBpL3NraWxscy9gLCBkaXJlY3Qgcm9vdCBgLm1kYCBmaWxlcyBhcmUgZGlzY292ZXJlZCBhcyBpbmRpdmlkdWFsIHNraWxsc1xuLSBJbiBhbGwgc2tpbGwgbG9jYXRpb25zLCBkaXJlY3RvcmllcyBjb250YWluaW5nIGBTS0lMTC5tZGAgYXJlIGRpc2NvdmVyZWQgcmVjdXJzaXZlbHlcbi0gSW4gYH4vLmFnZW50cy9za2lsbHMvYCBhbmQgcHJvamVjdCBgLmFnZW50cy9za2lsbHMvYCwgcm9vdCBgLm1kYCBmaWxlcyBhcmUgaWdub3JlZFxuXG5EaXNhYmxlIGRpc2NvdmVyeSB3aXRoIGAtLW5vLXNraWxsc2AgKGV4cGxpY2l0IGAtLXNraWxsYCBwYXRocyBzdGlsbCBsb2FkKS5cblxuIyMjIFVzaW5nIFNraWxscyBmcm9tIE90aGVyIEhhcm5lc3Nlc1xuXG5UbyB1c2Ugc2tpbGxzIGZyb20gQ2xhdWRlIENvZGUgb3IgT3BlbkFJIENvZGV4LCBhZGQgdGhlaXIgZGlyZWN0b3JpZXMgdG8gc2V0dGluZ3M6XG5cbmBgYGpzb25cbntcbiAgXCJza2lsbHNcIjogW1xuICAgIFwifi8uY2xhdWRlL3NraWxsc1wiLFxuICAgIFwifi8uY29kZXgvc2tpbGxzXCJcbiAgXVxufVxuYGBgXG5cbkZvciBwcm9qZWN0LWxldmVsIENsYXVkZSBDb2RlIHNraWxscywgYWRkIHRvIGAucGkvc2V0dGluZ3MuanNvbmA6XG5cbmBgYGpzb25cbntcbiAgXCJza2lsbHNcIjogW1wiLi4vLmNsYXVkZS9za2lsbHNcIl1cbn1cbmBgYFxuXG4jIyBIb3cgU2tpbGxzIFdvcmtcblxuMS4gQXQgc3RhcnR1cCwgcGkgc2NhbnMgc2tpbGwgbG9jYXRpb25zIGFuZCBleHRyYWN0cyBuYW1lcyBhbmQgZGVzY3JpcHRpb25zXG4yLiBUaGUgc3lzdGVtIHByb21wdCBpbmNsdWRlcyBhdmFpbGFibGUgc2tpbGxzIGluIFhNTCBmb3JtYXQgcGVyIHRoZSBbc3BlY2lmaWNhdGlvbl0oaHR0cHM6Ly9hZ2VudHNraWxscy5pby9pbnRlZ3JhdGUtc2tpbGxzKVxuMy4gV2hlbiBhIHRhc2sgbWF0Y2hlcywgdGhlIGFnZW50IHVzZXMgYHJlYWRgIHRvIGxvYWQgdGhlIGZ1bGwgU0tJTEwubWQgKG1vZGVscyBkb24ndCBhbHdheXMgZG8gdGhpczsgdXNlIHByb21wdGluZyBvciBgL3NraWxsOm5hbWVgIHRvIGZvcmNlIGl0KVxuNC4gVGhlIGFnZW50IGZvbGxvd3MgdGhlIGluc3RydWN0aW9ucywgdXNpbmcgcmVsYXRpdmUgcGF0aHMgdG8gcmVmZXJlbmNlIHNjcmlwdHMgYW5kIGFzc2V0c1xuXG5UaGlzIGlzIHByb2dyZXNzaXZlIGRpc2Nsb3N1cmU6IG9ubHkgZGVzY3JpcHRpb25zIGFyZSBhbHdheXMgaW4gY29udGV4dCwgZnVsbCBpbnN0cnVjdGlvbnMgbG9hZCBvbi1kZW1hbmQuXG5cbiMjIFNraWxsIENvbW1hbmRzXG5cblNraWxscyByZWdpc3RlciBhcyBgL3NraWxsOm5hbWVgIGNvbW1hbmRzOlxuXG5gYGBiYXNoXG4vc2tpbGw6YnJhdmUtc2VhcmNoICAgICAgICAgICAjIExvYWQgYW5kIGV4ZWN1dGUgdGhlIHNraWxsXG4vc2tpbGw6cGRmLXRvb2xzIGV4dHJhY3QgICAgICAjIExvYWQgc2tpbGwgd2l0aCBhcmd1bWVudHNcbmBgYFxuXG5Bcmd1bWVudHMgYWZ0ZXIgdGhlIGNvbW1hbmQgYXJlIGFwcGVuZGVkIHRvIHRoZSBza2lsbCBjb250ZW50IGFzIGBVc2VyOiA8YXJncz5gLlxuXG5Ub2dnbGUgc2tpbGwgY29tbWFuZHMgdmlhIGAvc2V0dGluZ3NgIGluIGludGVyYWN0aXZlIG1vZGUgb3IgaW4gYHNldHRpbmdzLmpzb25gOlxuXG5gYGBqc29uXG57XG4gIFwiZW5hYmxlU2tpbGxDb21tYW5kc1wiOiB0cnVlXG59XG5gYGBcblxuIyMgU2tpbGwgU3RydWN0dXJlXG5cbkEgc2tpbGwgaXMgYSBkaXJlY3Rvcnkgd2l0aCBhIGBTS0lMTC5tZGAgZmlsZS4gRXZlcnl0aGluZyBlbHNlIGlzIGZyZWVmb3JtLlxuXG5gYGBcbm15LXNraWxsL1xu4pSc4pSA4pSAIFNLSUxMLm1kICAgICAgICAgICAgICAjIFJlcXVpcmVkOiBmcm9udG1hdHRlciArIGluc3RydWN0aW9uc1xu4pSc4pSA4pSAIHNjcmlwdHMvICAgICAgICAgICAgICAjIEhlbHBlciBzY3JpcHRzXG7ilIIgICDilJTilIDilIAgcHJvY2Vzcy5zaFxu4pSc4pSA4pSAIHJlZmVyZW5jZXMvICAgICAgICAgICAjIERldGFpbGVkIGRvY3MgbG9hZGVkIG9uLWRlbWFuZFxu4pSCICAg4pSU4pSA4pSAIGFwaS1yZWZlcmVuY2UubWRcbuKUlOKUgOKUgCBhc3NldHMvXG4gICAg4pSU4pSA4pSAIHRlbXBsYXRlLmpzb25cbmBgYFxuXG4jIyMgU0tJTEwubWQgRm9ybWF0XG5cbmBgYGBtYXJrZG93blxuLS0tXG5uYW1lOiBteS1za2lsbFxuZGVzY3JpcHRpb246IFdoYXQgdGhpcyBza2lsbCBkb2VzIGFuZCB3aGVuIHRvIHVzZSBpdC4gQmUgc3BlY2lmaWMuXG4tLS1cblxuIyBNeSBTa2lsbFxuXG4jIyBTZXR1cFxuXG5SdW4gb25jZSBiZWZvcmUgZmlyc3QgdXNlOlxuYGBgYmFzaFxuY2QgL3BhdGgvdG8vc2tpbGwgJiYgbnBtIGluc3RhbGxcbmBgYFxuXG4jIyBVc2FnZVxuXG5gYGBiYXNoXG4uL3NjcmlwdHMvcHJvY2Vzcy5zaCA8aW5wdXQ+XG5gYGBcbmBgYGBcblxuVXNlIHJlbGF0aXZlIHBhdGhzIGZyb20gdGhlIHNraWxsIGRpcmVjdG9yeTpcblxuYGBgbWFya2Rvd25cblNlZSBbdGhlIHJlZmVyZW5jZSBndWlkZV0ocmVmZXJlbmNlcy9SRUZFUkVOQ0UubWQpIGZvciBkZXRhaWxzLlxuYGBgXG5cbiMjIEZyb250bWF0dGVyXG5cblBlciB0aGUgW0FnZW50IFNraWxscyBzcGVjaWZpY2F0aW9uXShodHRwczovL2FnZW50c2tpbGxzLmlvL3NwZWNpZmljYXRpb24jZnJvbnRtYXR0ZXItcmVxdWlyZWQpOlxuXG58IEZpZWxkIHwgUmVxdWlyZWQgfCBEZXNjcmlwdGlvbiB8XG58LS0tLS0tLXwtLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS18XG58IGBuYW1lYCB8IFllcyB8IE1heCA2NCBjaGFycy4gTG93ZXJjYXNlIGEteiwgMC05LCBoeXBoZW5zLiBVbmxpa2UgdGhlIHN0YW5kYXJkLCBQaSBkb2VzIG5vdCByZXF1aXJlIHRoaXMgdG8gbWF0Y2ggdGhlIHBhcmVudCBkaXJlY3RvcnkgYmVjYXVzZSB0aGF0IHN0YW5kYXJkIHJlcXVpcmVtZW50IGlzIHN1Ym9wdGltYWwgZm9yIHNoYXJlZCBza2lsbCBkaXJlY3Rvcmllcy4gfFxufCBgZGVzY3JpcHRpb25gIHwgWWVzIHwgTWF4IDEwMjQgY2hhcnMuIFdoYXQgdGhlIHNraWxsIGRvZXMgYW5kIHdoZW4gdG8gdXNlIGl0LiB8XG58IGBsaWNlbnNlYCB8IE5vIHwgTGljZW5zZSBuYW1lIG9yIHJlZmVyZW5jZSB0byBidW5kbGVkIGZpbGUuIHxcbnwgYGNvbXBhdGliaWxpdHlgIHwgTm8gfCBNYXggNTAwIGNoYXJzLiBFbnZpcm9ubWVudCByZXF1aXJlbWVudHMuIHxcbnwgYG1ldGFkYXRhYCB8IE5vIHwgQXJiaXRyYXJ5IGtleS12YWx1ZSBtYXBwaW5nLiB8XG58IGBhbGxvd2VkLXRvb2xzYCB8IE5vIHwgU3BhY2UtZGVsaW1pdGVkIGxpc3Qgb2YgcHJlLWFwcHJvdmVkIHRvb2xzIChleHBlcmltZW50YWwpLiB8XG58IGBkaXNhYmxlLW1vZGVsLWludm9jYXRpb25gIHwgTm8gfCBXaGVuIGB0cnVlYCwgc2tpbGwgaXMgaGlkZGVuIGZyb20gc3lzdGVtIHByb21wdC4gVXNlcnMgbXVzdCB1c2UgYC9za2lsbDpuYW1lYC4gfFxuXG4jIyMgTmFtZSBSdWxlc1xuXG4tIDEtNjQgY2hhcmFjdGVyc1xuLSBMb3dlcmNhc2UgbGV0dGVycywgbnVtYmVycywgaHlwaGVucyBvbmx5XG4tIE5vIGxlYWRpbmcvdHJhaWxpbmcgaHlwaGVuc1xuLSBObyBjb25zZWN1dGl2ZSBoeXBoZW5zXG5QaSBkb2VzIG5vdCByZXF1aXJlIHRoZSBuYW1lIHRvIG1hdGNoIHRoZSBwYXJlbnQgZGlyZWN0b3J5LiBUaGUgQWdlbnQgU2tpbGxzIHN0YW5kYXJkIGRvZXMsIGJ1dCB0aGF0IHJlcXVpcmVtZW50IGlzIHN1Ym9wdGltYWwgZm9yIHNoYXJlZCBza2lsbCBkaXJlY3RvcmllcyB1c2VkIGJ5IG11bHRpcGxlIHRvb2xzLlxuXG5WYWxpZDogYHBkZi1wcm9jZXNzaW5nYCwgYGRhdGEtYW5hbHlzaXNgLCBgY29kZS1yZXZpZXdgXG5JbnZhbGlkOiBgUERGLVByb2Nlc3NpbmdgLCBgLXBkZmAsIGBwZGYtLXByb2Nlc3NpbmdgXG5cbiMjIyBEZXNjcmlwdGlvbiBCZXN0IFByYWN0aWNlc1xuXG5UaGUgZGVzY3JpcHRpb24gZGV0ZXJtaW5lcyB3aGVuIHRoZSBhZ2VudCBsb2FkcyB0aGUgc2tpbGwuIEJlIHNwZWNpZmljLlxuXG5Hb29kOlxuYGBgeWFtbFxuZGVzY3JpcHRpb246IEV4dHJhY3RzIHRleHQgYW5kIHRhYmxlcyBmcm9tIFBERiBmaWxlcywgZmlsbHMgUERGIGZvcm1zLCBhbmQgbWVyZ2VzIG11bHRpcGxlIFBERnMuIFVzZSB3aGVuIHdvcmtpbmcgd2l0aCBQREYgZG9jdW1lbnRzLlxuYGBgXG5cblBvb3I6XG5gYGB5YW1sXG5kZXNjcmlwdGlvbjogSGVscHMgd2l0aCBQREZzLlxuYGBgXG5cbiMjIFZhbGlkYXRpb25cblxuUGkgdmFsaWRhdGVzIHNraWxscyBhZ2FpbnN0IHRoZSBBZ2VudCBTa2lsbHMgc3RhbmRhcmQuIE1vc3QgaXNzdWVzIHByb2R1Y2Ugd2FybmluZ3MgYnV0IHN0aWxsIGxvYWQgdGhlIHNraWxsOlxuXG4tIE5hbWUgZXhjZWVkcyA2NCBjaGFyYWN0ZXJzIG9yIGNvbnRhaW5zIGludmFsaWQgY2hhcmFjdGVyc1xuLSBOYW1lIHN0YXJ0cy9lbmRzIHdpdGggaHlwaGVuIG9yIGhhcyBjb25zZWN1dGl2ZSBoeXBoZW5zXG4tIERlc2NyaXB0aW9uIGV4Y2VlZHMgMTAyNCBjaGFyYWN0ZXJzXG5cblVua25vd24gZnJvbnRtYXR0ZXIgZmllbGRzIGFyZSBpZ25vcmVkLlxuXG4qKkV4Y2VwdGlvbjoqKiBTa2lsbHMgd2l0aCBtaXNzaW5nIGRlc2NyaXB0aW9uIGFyZSBub3QgbG9hZGVkLlxuXG5OYW1lIGNvbGxpc2lvbnMgKHNhbWUgbmFtZSBmcm9tIGRpZmZlcmVudCBsb2NhdGlvbnMpIHdhcm4gYW5kIGtlZXAgdGhlIGZpcnN0IHNraWxsIGZvdW5kLlxuXG4jIyBFeGFtcGxlXG5cbmBgYFxuYnJhdmUtc2VhcmNoL1xu4pSc4pSA4pSAIFNLSUxMLm1kXG7ilJzilIDilIAgc2VhcmNoLmpzXG7ilJTilIDilIAgY29udGVudC5qc1xuYGBgXG5cbioqU0tJTEwubWQ6KipcbmBgYGBtYXJrZG93blxuLS0tXG5uYW1lOiBicmF2ZS1zZWFyY2hcbmRlc2NyaXB0aW9uOiBXZWIgc2VhcmNoIGFuZCBjb250ZW50IGV4dHJhY3Rpb24gdmlhIEJyYXZlIFNlYXJjaCBBUEkuIFVzZSBmb3Igc2VhcmNoaW5nIGRvY3VtZW50YXRpb24sIGZhY3RzLCBvciBhbnkgd2ViIGNvbnRlbnQuXG4tLS1cblxuIyBCcmF2ZSBTZWFyY2hcblxuIyMgU2V0dXBcblxuYGBgYmFzaFxuY2QgL3BhdGgvdG8vYnJhdmUtc2VhcmNoICYmIG5wbSBpbnN0YWxsXG5gYGBcblxuIyMgU2VhcmNoXG5cbmBgYGJhc2hcbi4vc2VhcmNoLmpzIFwicXVlcnlcIiAgICAgICAgICAgICAgIyBCYXNpYyBzZWFyY2hcbi4vc2VhcmNoLmpzIFwicXVlcnlcIiAtLWNvbnRlbnQgICAgIyBJbmNsdWRlIHBhZ2UgY29udGVudFxuYGBgXG5cbiMjIEV4dHJhY3QgUGFnZSBDb250ZW50XG5cbmBgYGJhc2hcbi4vY29udGVudC5qcyBodHRwczovL2V4YW1wbGUuY29tXG5gYGBcbmBgYGBcblxuIyMgU2tpbGwgUmVwb3NpdG9yaWVzXG5cbi0gW0FudGhyb3BpYyBTa2lsbHNdKGh0dHBzOi8vZ2l0aHViLmNvbS9hbnRocm9waWNzL3NraWxscykgLSBEb2N1bWVudCBwcm9jZXNzaW5nIChkb2N4LCBwZGYsIHBwdHgsIHhsc3gpLCB3ZWIgZGV2ZWxvcG1lbnRcbi0gW1BpIFNraWxsc10oaHR0cHM6Ly9naXRodWIuY29tL2JhZGxvZ2ljL3BpLXNraWxscykgLSBXZWIgc2VhcmNoLCBicm93c2VyIGF1dG9tYXRpb24sIEdvb2dsZSBBUElzLCB0cmFuc2NyaXB0aW9uXG4ifV0sImlzRXJyb3IiOmZhbHNlLCJ0aW1lc3RhbXAiOjE3ODE5NTM5MjAyNzJ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiIwMGM5M2Q4OCIsInBhcmVudElkIjoiOGM3YjYxMjgiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjEyOjAwLjI3MloiLCJtZXNzYWdlIjp7InJvbGUiOiJ0b29sUmVzdWx0IiwidG9vbENhbGxJZCI6ImNhbGxfMDJfWGdLbGt2eUUxTlNRY2ZSSWQ3SGU2MjQ0IiwidG9vbE5hbWUiOiJyZWFkIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiPiBwaSBjYW4gY3JlYXRlIHByb21wdCB0ZW1wbGF0ZXMuIEFzayBpdCB0byBidWlsZCBvbmUgZm9yIHlvdXIgd29ya2Zsb3cuXG5cbiMgUHJvbXB0IFRlbXBsYXRlc1xuXG5Qcm9tcHQgdGVtcGxhdGVzIGFyZSBNYXJrZG93biBzbmlwcGV0cyB0aGF0IGV4cGFuZCBpbnRvIGZ1bGwgcHJvbXB0cy4gVHlwZSBgL25hbWVgIGluIHRoZSBlZGl0b3IgdG8gaW52b2tlIGEgdGVtcGxhdGUsIHdoZXJlIGBuYW1lYCBpcyB0aGUgZmlsZW5hbWUgd2l0aG91dCBgLm1kYC5cblxuIyMgTG9jYXRpb25zXG5cblBpIGxvYWRzIHByb21wdCB0ZW1wbGF0ZXMgZnJvbTpcblxuLSBHbG9iYWw6IGB+Ly5waS9hZ2VudC9wcm9tcHRzLyoubWRgXG4tIFByb2plY3Q6IGAucGkvcHJvbXB0cy8qLm1kYCAob25seSBhZnRlciB0aGUgcHJvamVjdCBpcyB0cnVzdGVkKVxuLSBQYWNrYWdlczogYHByb21wdHMvYCBkaXJlY3RvcmllcyBvciBgcGkucHJvbXB0c2AgZW50cmllcyBpbiBgcGFja2FnZS5qc29uYFxuLSBTZXR0aW5nczogYHByb21wdHNgIGFycmF5IHdpdGggZmlsZXMgb3IgZGlyZWN0b3JpZXNcbi0gQ0xJOiBgLS1wcm9tcHQtdGVtcGxhdGUgPHBhdGg+YCAocmVwZWF0YWJsZSlcblxuRGlzYWJsZSBkaXNjb3Zlcnkgd2l0aCBgLS1uby1wcm9tcHQtdGVtcGxhdGVzYC5cblxuIyMgRm9ybWF0XG5cbmBgYG1hcmtkb3duXG4tLS1cbmRlc2NyaXB0aW9uOiBSZXZpZXcgc3RhZ2VkIGdpdCBjaGFuZ2VzXG4tLS1cblJldmlldyB0aGUgc3RhZ2VkIGNoYW5nZXMgKGBnaXQgZGlmZiAtLWNhY2hlZGApLiBGb2N1cyBvbjpcbi0gQnVncyBhbmQgbG9naWMgZXJyb3JzXG4tIFNlY3VyaXR5IGlzc3Vlc1xuLSBFcnJvciBoYW5kbGluZyBnYXBzXG5gYGBcblxuLSBUaGUgZmlsZW5hbWUgYmVjb21lcyB0aGUgY29tbWFuZCBuYW1lLiBgcmV2aWV3Lm1kYCBiZWNvbWVzIGAvcmV2aWV3YC5cbi0gYGRlc2NyaXB0aW9uYCBpcyBvcHRpb25hbC4gSWYgbWlzc2luZywgdGhlIGZpcnN0IG5vbi1lbXB0eSBsaW5lIGlzIHVzZWQuXG4tIGBhcmd1bWVudC1oaW50YCBpcyBvcHRpb25hbC4gV2hlbiBzZXQsIHRoZSBoaW50IGlzIGRpc3BsYXllZCBiZWZvcmUgdGhlIGRlc2NyaXB0aW9uIGluIHRoZSBhdXRvY29tcGxldGUgZHJvcGRvd24uXG5cbiMjIyBBcmd1bWVudCBIaW50c1xuXG5Vc2UgYGFyZ3VtZW50LWhpbnRgIGluIGZyb250bWF0dGVyIHRvIHNob3cgZXhwZWN0ZWQgYXJndW1lbnRzIGluIGF1dG9jb21wbGV0ZS4gVXNlIGA8YW5nbGUgYnJhY2tldHM+YCBmb3IgcmVxdWlyZWQgYXJndW1lbnRzIGFuZCBgW3NxdWFyZSBicmFja2V0c11gIGZvciBvcHRpb25hbCBvbmVzOlxuXG5gYGBtYXJrZG93blxuLS0tXG5kZXNjcmlwdGlvbjogUmV2aWV3IFBScyBmcm9tIFVSTHMgd2l0aCBzdHJ1Y3R1cmVkIGlzc3VlIGFuZCBjb2RlIGFuYWx5c2lzXG5hcmd1bWVudC1oaW50OiBcIjxQUi1VUkw+XCJcbi0tLVxuYGBgXG5cblRoaXMgcmVuZGVycyBpbiB0aGUgYXV0b2NvbXBsZXRlIGRyb3Bkb3duIGFzOlxuXG5gYGBcbuKGkiBwciAgIDxQUi1VUkw+ICAgICAgIOKAlCBSZXZpZXcgUFJzIGZyb20gVVJMcyB3aXRoIHN0cnVjdHVyZWQgaXNzdWUgYW5kIGNvZGUgYW5hbHlzaXNcbiAgaXMgICA8aXNzdWU+ICAgICAgICDigJQgQW5hbHl6ZSBHaXRIdWIgaXNzdWVzIChidWdzIG9yIGZlYXR1cmUgcmVxdWVzdHMpXG4gIHdyICAgW2luc3RydWN0aW9uc10g4oCUIEZpbmlzaCB0aGUgY3VycmVudCB0YXNrIGVuZC10by1lbmRcbiAgY2wgICDigJQgQXVkaXQgY2hhbmdlbG9nIGVudHJpZXMgYmVmb3JlIHJlbGVhc2VcbmBgYFxuXG4jIyBVc2FnZVxuXG5UeXBlIGAvYCBmb2xsb3dlZCBieSB0aGUgdGVtcGxhdGUgbmFtZSBpbiB0aGUgZWRpdG9yLiBBdXRvY29tcGxldGUgc2hvd3MgYXZhaWxhYmxlIHRlbXBsYXRlcyB3aXRoIGRlc2NyaXB0aW9ucy5cblxuYGBgXG4vcmV2aWV3ICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBFeHBhbmRzIHJldmlldy5tZFxuL2NvbXBvbmVudCBCdXR0b24gICAgICAgICAgICAgICAgICMgRXhwYW5kcyB3aXRoIGFyZ3VtZW50XG4vY29tcG9uZW50IEJ1dHRvbiBcImNsaWNrIGhhbmRsZXJcIiAjIE11bHRpcGxlIGFyZ3VtZW50c1xuYGBgXG5cbiMjIEFyZ3VtZW50c1xuXG5UZW1wbGF0ZXMgc3VwcG9ydCBwb3NpdGlvbmFsIGFyZ3VtZW50cywgZGVmYXVsdHMsIGFuZCBzaW1wbGUgc2xpY2luZzpcblxuLSBgJDFgLCBgJDJgLCAuLi4gcG9zaXRpb25hbCBhcmdzXG4tIGAkQGAgb3IgYCRBUkdVTUVOVFNgIGZvciBhbGwgYXJncyBqb2luZWRcbi0gYCR7MTotZGVmYXVsdH1gIHVzZXMgYXJnIDEgd2hlbiBwcmVzZW50L25vbi1lbXB0eSwgb3RoZXJ3aXNlIGBkZWZhdWx0YFxuLSBgJHtAOk59YCBmb3IgYXJncyBmcm9tIHRoZSBOdGggcG9zaXRpb24gKDEtaW5kZXhlZClcbi0gYCR7QDpOOkx9YCBmb3IgYExgIGFyZ3Mgc3RhcnRpbmcgYXQgTlxuXG5FeGFtcGxlOlxuXG5gYGBtYXJrZG93blxuLS0tXG5kZXNjcmlwdGlvbjogQ3JlYXRlIGEgY29tcG9uZW50XG4tLS1cbkNyZWF0ZSBhIFJlYWN0IGNvbXBvbmVudCBuYW1lZCAkMSB3aXRoIGZlYXR1cmVzOiAkQFxuYGBgXG5cbkRlZmF1bHQgdmFsdWVzIGFyZSB1c2VmdWwgZm9yIG9wdGlvbmFsIGFyZ3VtZW50czpcblxuYGBgbWFya2Rvd25cblN1bW1hcml6ZSB0aGUgY3VycmVudCBzdGF0ZSBpbiAkezE6LTd9IGJ1bGxldCBwb2ludHMuXG5gYGBcblxuVXNhZ2U6IGAvY29tcG9uZW50IEJ1dHRvbiBcIm9uQ2xpY2sgaGFuZGxlclwiIFwiZGlzYWJsZWQgc3VwcG9ydFwiYFxuXG4jIyBMb2FkaW5nIFJ1bGVzXG5cbi0gVGVtcGxhdGUgZGlzY292ZXJ5IGluIGBwcm9tcHRzL2AgaXMgbm9uLXJlY3Vyc2l2ZS5cbi0gSWYgeW91IHdhbnQgdGVtcGxhdGVzIGluIHN1YmRpcmVjdG9yaWVzLCBhZGQgdGhlbSBleHBsaWNpdGx5IHZpYSBgcHJvbXB0c2Agc2V0dGluZ3Mgb3IgYSBwYWNrYWdlIG1hbmlmZXN0LlxuIn1dLCJpc0Vycm9yIjpmYWxzZSwidGltZXN0YW1wIjoxNzgxOTUzOTIwMjcyfX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiNGQ0OWU4NzEiLCJwYXJlbnRJZCI6IjAwYzkzZDg4IiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToxMjoxMi44MTdaIiwibWVzc2FnZSI6eyJyb2xlIjoiYXNzaXN0YW50IiwiY29udGVudCI6W3sidHlwZSI6InRoaW5raW5nIiwidGhpbmtpbmciOiJUaGUgdXNlciBpcyBhc2tpbmcgYWJvdXQgdGhlIGVxdWl2YWxlbnQgb2YgYSBcImhvb2tcIiBpbiBQaS4gQmFzZWQgb24gdGhlIGRvY3VtZW50YXRpb24gSSd2ZSByZWFkLCBQaSBkb2Vzbid0IHVzZSB0aGUgdGVybSBcImhvb2tzXCIgZGlyZWN0bHksIGJ1dCBoYXMgc2V2ZXJhbCBlcXVpdmFsZW50IGNvbmNlcHRzIGRlcGVuZGluZyBvbiB3aGF0IGtpbmQgb2YgXCJob29rXCIgeW91J3JlIHJlZmVycmluZyB0by4gTGV0IG1lIHRoaW5rIGFib3V0IHRoZSBkaWZmZXJlbnQgdHlwZXMgb2YgaG9va3MgaW4gb3RoZXIgY29udGV4dHM6XG5cbjEuICoqR2l0IGhvb2tzKiogKGxpa2UgcHJlLWNvbW1pdCwgcG9zdC1jb21taXQpIC0gVGhlc2UgYXJlIGxpZmVjeWNsZSBldmVudCBoYW5kbGVyc1xuMi4gKipSZWFjdCBob29rcyoqIChsaWtlIHVzZVN0YXRlLCB1c2VFZmZlY3QpIC0gVGhlc2UgYXJlIHN0YXRlL2xpZmVjeWNsZSBwcmltaXRpdmVzXG4zLiAqKlBsdWdpbiBob29rcyoqIChsaWtlIFdvcmRQcmVzcyBob29rcywgVlMgQ29kZSBleHRlbnNpb24gaG9va3MpIC0gVGhlc2UgYXJlIGV4dGVuc2lvbiBwb2ludHNcblxuSW4gUGksIHRoZSBjbG9zZXN0IGVxdWl2YWxlbnRzIGFyZTpcblxuMS4gKipFdmVudHMqKiAtIGBwaS5vbihcImV2ZW50X25hbWVcIiwgaGFuZGxlcilgIGlzIHRoZSBwcmltYXJ5IGhvb2sgbWVjaGFuaXNtLiBFdmVudHMgaW5jbHVkZSBgdG9vbF9jYWxsYCwgYHNlc3Npb25fc3RhcnRgLCBgYmVmb3JlX2FnZW50X3N0YXJ0YCwgYG1lc3NhZ2Vfc3RhcnQvZW5kYCwgYHR1cm5fc3RhcnQvZW5kYCwgZXRjLiBUaGVzZSBhcmUgbGlmZWN5Y2xlIGhvb2tzIHRoYXQgbGV0IGV4dGVuc2lvbnMgaW50ZXJjZXB0IGFuZCBtb2RpZnkgYmVoYXZpb3IuXG5cbjIuICoqQ3VzdG9tIHRvb2xzKiogLSBgcGkucmVnaXN0ZXJUb29sKClgIC0gUmVnaXN0ZXIgdG9vbHMgdGhhdCB0aGUgTExNIGNhbiBjYWxsLCBzaW1pbGFyIHRvIHByb3ZpZGluZyBuZXcgY2FwYWJpbGl0aWVzXG5cbjMuICoqQ3VzdG9tIGNvbW1hbmRzKiogLSBgcGkucmVnaXN0ZXJDb21tYW5kKClgIC0gUmVnaXN0ZXIgYC9jb21tYW5kYCBoYW5kbGVyc1xuXG40LiAqKlNob3J0Y3V0cyoqIC0gYHBpLnJlZ2lzdGVyU2hvcnRjdXQoKWAgLSBLZXlib2FyZCBzaG9ydGN1dCBob29rc1xuXG41LiAqKkZsYWdzKiogLSBgcGkucmVnaXN0ZXJGbGFnKClgIC0gQ0xJIGZsYWcgaG9va3NcblxuVGhlIG1haW4gYW5zd2VyIHRvIFwid2hhdCBpcyB0aGUgZXF1aXZhbGVudCBvZiBhIGhvb2sgaW4gUGlcIiB3b3VsZCBiZSB0aGUgKipFdmVudHMqKiBzeXN0ZW0gKGBwaS5vbigpYCksIGFzIGl0IGRpcmVjdGx5IG1hcHMgdG8gdGhlIGNvbmNlcHQgb2YgbGlmZWN5Y2xlIGhvb2tzIHRoYXQgbW9zdCBkZXZlbG9wZXJzIGFyZSBmYW1pbGlhciB3aXRoLiBcblxuTGV0IG1lIHByb3ZpZGUgYSBjbGVhciwgY29tcHJlaGVuc2l2ZSBhbnN3ZXIuIiwidGhpbmtpbmdTaWduYXR1cmUiOiJyZWFzb25pbmcifSx7InR5cGUiOiJ0ZXh0IiwidGV4dCI6IkluIFBpLCB0aGUgZXF1aXZhbGVudCBvZiBhICoqaG9vayoqIGRlcGVuZHMgb24gd2hpY2gga2luZCBvZiBob29rIHlvdSBtZWFuLCBidXQgaGVyZSBhcmUgdGhlIGNsb3Nlc3QgYW5hbG9ndWVzOlxuXG4jIyAxLiBFdmVudHMgKGBwaS5vbigpYCkg4oCUIHRoZSBjbG9zZXN0IHRvIGdlbmVyYWwtcHVycG9zZSBcImhvb2tzXCJcblxuVGhpcyBpcyB0aGUgcHJpbWFyeSBob29rIG1lY2hhbmlzbS4gRXZlbnRzIGxldCB5b3UgaW50ZXJjZXB0IGxpZmVjeWNsZSBtb21lbnRzIGFuZCBtb2RpZnkgYmVoYXZpb3IsIG11Y2ggbGlrZSBHaXQgaG9va3Mgb3IgV29yZFByZXNzL1ZTIENvZGUgaG9va3MuXG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwidG9vbF9jYWxsXCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIC8vIEludGVyY2VwdCBhbmQgcG90ZW50aWFsbHkgYmxvY2sgYSB0b29sIGNhbGxcbiAgaWYgKGV2ZW50LnRvb2xOYW1lID09PSBcImJhc2hcIiAmJiBldmVudC5pbnB1dC5jb21tYW5kPy5pbmNsdWRlcyhcInJtIC1yZlwiKSkge1xuICAgIHJldHVybiB7IGJsb2NrOiB0cnVlLCByZWFzb246IFwiRGFuZ2Vyb3VzIGNvbW1hbmQgYmxvY2tlZFwiIH07XG4gIH1cbn0pO1xuXG5waS5vbihcInNlc3Npb25fc3RhcnRcIiwgYXN5bmMgKF9ldmVudCwgY3R4KSA9PiB7XG4gIC8vIFJ1biBjb2RlIHdoZW4gYSBzZXNzaW9uIHN0YXJ0c1xuICBjdHgudWkubm90aWZ5KFwiU2Vzc2lvbiBzdGFydGVkIVwiLCBcImluZm9cIik7XG59KTtcbmBgYFxuXG5BdmFpbGFibGUgZXZlbnRzIHNwYW4gdGhlIGZ1bGwgbGlmZWN5Y2xlIOKAlCBzdGFydHVwIChgc2Vzc2lvbl9zdGFydGApLCBhZ2VudCB0dXJucyAoYGJlZm9yZV9hZ2VudF9zdGFydGAsIGB0dXJuX3N0YXJ0L2VuZGApLCB0b29sIGV4ZWN1dGlvbiAoYHRvb2xfY2FsbGAsIGB0b29sX3Jlc3VsdGApLCBtZXNzYWdlcyAoYG1lc3NhZ2Vfc3RhcnQvZW5kYCksIHNlc3Npb24gdHJhbnNpdGlvbnMgKGBzZXNzaW9uX2JlZm9yZV9zd2l0Y2hgLCBgc2Vzc2lvbl9zaHV0ZG93bmApLCBtb2RlbCBjaGFuZ2VzIChgbW9kZWxfc2VsZWN0YCksIGFuZCBtb3JlLlxuXG4jIyAyLiBDdXN0b20gQ29tbWFuZHMg4oCUIGxpa2Ugc2xhc2ggY29tbWFuZCBob29rc1xuXG5gcGkucmVnaXN0ZXJDb21tYW5kKClgIGlzIGxpa2UgcmVnaXN0ZXJpbmcgYSBjdXN0b20gYC9jb21tYW5kYCBob29rLlxuXG5gYGB0eXBlc2NyaXB0XG5waS5yZWdpc3RlckNvbW1hbmQoXCJoZWxsb1wiLCB7XG4gIGRlc2NyaXB0aW9uOiBcIlNheSBoZWxsb1wiLFxuICBoYW5kbGVyOiBhc3luYyAoYXJncywgY3R4KSA9PiB7XG4gICAgY3R4LnVpLm5vdGlmeShgSGVsbG8gJHthcmdzIHx8IFwid29ybGRcIn0hYCwgXCJpbmZvXCIpO1xuICB9LFxufSk7XG5gYGBcblxuIyMgMy4gQ3VzdG9tIFRvb2xzIOKAlCBsaWtlIHByb3ZpZGluZyBuZXcgY2FwYWJpbGl0aWVzIHRvIHRoZSBMTE1cblxuYHBpLnJlZ2lzdGVyVG9vbCgpYCByZWdpc3RlcnMgYSB0b29sIHRoZSBBSSBtb2RlbCBjYW4gY2FsbCwgc2ltaWxhciB0byBhZGRpbmcgbmV3IEFQSSBlbmRwb2ludHMuXG5cbiMjIDQuIFNob3J0Y3V0cyDigJQga2V5Ym9hcmQgc2hvcnRjdXQgaG9va3NcblxuYHBpLnJlZ2lzdGVyU2hvcnRjdXQoXCJjdHJsK3hcIiwgeyBoYW5kbGVyOiAuLi4gfSlgIGhvb2tzIGludG8ga2V5Ym9hcmQgaW5wdXQuXG5cbiMjIDUuIElucHV0IGV2ZW50cyDigJQgaW50ZXJjZXB0aW5nIHVzZXIgaW5wdXRcblxuVGhlIGBpbnB1dGAgZXZlbnQgbGV0cyB5b3UgaW50ZXJjZXB0LCB0cmFuc2Zvcm0sIG9yIGhhbmRsZSB1c2VyIGlucHV0IGJlZm9yZSBpdCByZWFjaGVzIHRoZSBhZ2VudCDigJQgc2ltaWxhciB0byBtaWRkbGV3YXJlIGhvb2tzLlxuXG4tLS1cblxuKipJbiBzaG9ydDoqKiBgcGkub24oKWAgZXZlbnRzIGFyZSB0aGUgbW9zdCBnZW5lcmFsLXB1cnBvc2UgZXF1aXZhbGVudCBvZiBob29rcy4gVGhleSBsZXQgeW91IHRhcCBpbnRvIHRoZSBhZ2VudCdzIGxpZmVjeWNsZSwgaW50ZXJjZXB0IHRvb2wgY2FsbHMsIG1vZGlmeSBjb250ZXh0LCBhbmQgY3VzdG9taXplIGJlaGF2aW9yIOKAlCBhbGwgZnJvbSBhIFR5cGVTY3JpcHQgZXh0ZW5zaW9uLiJ9XSwiYXBpIjoib3BlbmFpLWNvbXBsZXRpb25zIiwicHJvdmlkZXIiOiJvcGVucm91dGVyIiwibW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaCIsInVzYWdlIjp7ImlucHV0IjoxNzA0Nywib3V0cHV0Ijo4MjYsImNhY2hlUmVhZCI6MTAyNCwiY2FjaGVXcml0ZSI6MCwidG90YWxUb2tlbnMiOjE4ODk3LCJjb3N0Ijp7ImlucHV0IjowLjAwMTUzNDIzLCJvdXRwdXQiOjAuMDAwMTQ4NjgsImNhY2hlUmVhZCI6MC4wMDAwMjA0OCwiY2FjaGVXcml0ZSI6MCwidG90YWwiOjAuMDAxNzAzMzl9fSwic3RvcFJlYXNvbiI6InN0b3AiLCJ0aW1lc3RhbXAiOjE3ODE5NTM5MjAyNzMsInJlc3BvbnNlSWQiOiJnZW4tMTc4MTk1MzkyMC1JaHZnMHc5U2sxQ3FBZ1l4Ylk1NiIsInJlc3BvbnNlTW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaC0yMDI2MDQyMyJ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiI2MzAxY2Q5ZiIsInBhcmVudElkIjoiNGQ0OWU4NzEiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjE2OjMyLjQ3M1oiLCJtZXNzYWdlIjp7InJvbGUiOiJ1c2VyIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiSSB3YW50IHRvIHNjYWZmb2xkIGEgdGlueSB0eXBlc2NyaXB0IHByb2plY3Qgd2l0aCBvbmUgcGFzc2luZyB0ZXN0IC0gdXNlIHZpdGVzdC4gQ3JlYXRlIHBhY2thZ2UuanNvbiwgSSB3aWxsIGluc3RhbGwuIn1dLCJ0aW1lc3RhbXAiOjE3ODE5NTQxOTI0NzF9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiI4ZTA4N2JiMyIsInBhcmVudElkIjoiNjMwMWNkOWYiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjE2OjQyLjQwNFoiLCJtZXNzYWdlIjp7InJvbGUiOiJhc3Npc3RhbnQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGhpbmtpbmciLCJ0aGlua2luZyI6IlRoZSB1c2VyIHdhbnRzIG1lIHRvIHNjYWZmb2xkIGEgdGlueSBUeXBlU2NyaXB0IHByb2plY3Qgd2l0aCBvbmUgcGFzc2luZyB0ZXN0IHVzaW5nIHZpdGVzdC4gTGV0IG1lIGNyZWF0ZSB0aGUgbmVjZXNzYXJ5IGZpbGVzOlxuXG4xLiBgcGFja2FnZS5qc29uYCAtIHdpdGggdml0ZXN0IGFuZCB0eXBlc2NyaXB0IGRlcGVuZGVuY2llc1xuMi4gYHRzY29uZmlnLmpzb25gIC0gVHlwZVNjcmlwdCBjb25maWdcbjMuIEEgc291cmNlIGZpbGUgd2l0aCBhIHNpbXBsZSBmdW5jdGlvblxuNC4gQSB0ZXN0IGZpbGUgd2l0aCBvbmUgcGFzc2luZyB0ZXN0XG5cbkxldCBtZSBjcmVhdGUgdGhlc2UgZmlsZXMgaW4gdGhlIGN1cnJlbnQgcmVwb3NpdG9yeS4iLCJ0aGlua2luZ1NpZ25hdHVyZSI6InJlYXNvbmluZyJ9LHsidHlwZSI6InRvb2xDYWxsIiwiaWQiOiJjYWxsXzI1ZDgwYWFmZTllYzQ0MDY5ZGUyNTkyOSIsIm5hbWUiOiJ3cml0ZSIsImFyZ3VtZW50cyI6eyJwYXRoIjoiL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvcGFja2FnZS5qc29uIiwiY29udGVudCI6IntcbiAgXCJuYW1lXCI6IFwicmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrXCIsXG4gIFwidmVyc2lvblwiOiBcIjAuMC4xXCIsXG4gIFwidHlwZVwiOiBcIm1vZHVsZVwiLFxuICBcInNjcmlwdHNcIjoge1xuICAgIFwidGVzdFwiOiBcInZpdGVzdCBydW5cIixcbiAgICBcInRlc3Q6d2F0Y2hcIjogXCJ2aXRlc3RcIlxuICB9LFxuICBcImRldkRlcGVuZGVuY2llc1wiOiB7XG4gICAgXCJ0eXBlc2NyaXB0XCI6IFwiXjUuNy4wXCIsXG4gICAgXCJ2aXRlc3RcIjogXCJeMy4wLjBcIlxuICB9XG59In19LHsidHlwZSI6InRvb2xDYWxsIiwiaWQiOiJjYWxsXzcxOTVjOThiYWJlYTQ5NjA4ZTI5YjM5NyIsIm5hbWUiOiJ3cml0ZSIsImFyZ3VtZW50cyI6eyJwYXRoIjoiL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvdHNjb25maWcuanNvbiIsImNvbnRlbnQiOiJ7XG4gIFwiY29tcGlsZXJPcHRpb25zXCI6IHtcbiAgICBcInRhcmdldFwiOiBcIkVTMjAyMlwiLFxuICAgIFwibW9kdWxlXCI6IFwiRVNOZXh0XCIsXG4gICAgXCJtb2R1bGVSZXNvbHV0aW9uXCI6IFwiYnVuZGxlclwiLFxuICAgIFwic3RyaWN0XCI6IHRydWUsXG4gICAgXCJlc01vZHVsZUludGVyb3BcIjogdHJ1ZSxcbiAgICBcInNraXBMaWJDaGVja1wiOiB0cnVlLFxuICAgIFwib3V0RGlyXCI6IFwiZGlzdFwiXG4gIH0sXG4gIFwiaW5jbHVkZVwiOiBbXCJzcmNcIl1cbn0ifX0seyJ0eXBlIjoidG9vbENhbGwiLCJpZCI6ImNhbGxfMjgyOGE2OTg0ZDQ0NGJmZTk5ODllZDI0IiwibmFtZSI6IndyaXRlIiwiYXJndW1lbnRzIjp7InBhdGgiOiIvVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ay9zcmMvZ3JlZXQudHMiLCJjb250ZW50IjoiZXhwb3J0IGZ1bmN0aW9uIGdyZWV0KG5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBgSGVsbG8sICR7bmFtZX0hYDtcbn0ifX0seyJ0eXBlIjoidG9vbENhbGwiLCJpZCI6ImNhbGxfMjgwOWRkMjY2MWY5NDIxY2IzZmQ1NDdiIiwibmFtZSI6IndyaXRlIiwiYXJndW1lbnRzIjp7InBhdGgiOiIvVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ay9zcmMvZ3JlZXQudGVzdC50cyIsImNvbnRlbnQiOiJpbXBvcnQgeyBkZXNjcmliZSwgaXQsIGV4cGVjdCB9IGZyb20gXCJ2aXRlc3RcIjtcbmltcG9ydCB7IGdyZWV0IH0gZnJvbSBcIi4vZ3JlZXQuanNcIjtcblxuZGVzY3JpYmUoXCJncmVldFwiLCAoKSA9PiB7XG4gIGl0KFwicmV0dXJucyBhIGdyZWV0aW5nIGZvciBhIGdpdmVuIG5hbWVcIiwgKCkgPT4ge1xuICAgIGV4cGVjdChncmVldChcIldvcmxkXCIpKS50b0JlKFwiSGVsbG8sIFdvcmxkIVwiKTtcbiAgfSk7XG59KTsifX1dLCJhcGkiOiJvcGVuYWktY29tcGxldGlvbnMiLCJwcm92aWRlciI6Im9wZW5yb3V0ZXIiLCJtb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoIiwidXNhZ2UiOnsiaW5wdXQiOjEwMDYsIm91dHB1dCI6NjE5LCJjYWNoZVJlYWQiOjE3OTIwLCJjYWNoZVdyaXRlIjowLCJ0b3RhbFRva2VucyI6MTk1NDUsImNvc3QiOnsiaW5wdXQiOjAuMDAwMDkwNTQsIm91dHB1dCI6MC4wMDAxMTE0MiwiY2FjaGVSZWFkIjowLjAwMDM1ODQsImNhY2hlV3JpdGUiOjAsInRvdGFsIjowLjAwMDU2MDM2fX0sInN0b3BSZWFzb24iOiJ0b29sVXNlIiwidGltZXN0YW1wIjoxNzgxOTU0MTkyNDc0LCJyZXNwb25zZUlkIjoiZ2VuLTE3ODE5NTQxOTItR0xYb01McGRZdzVuUUNSRTZ0V0QiLCJyZXNwb25zZU1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2gtMjAyNjA0MjMifX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiYWE3MDVlZDYiLCJwYXJlbnRJZCI6IjhlMDg3YmIzIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToxNjo0Mi40MTVaIiwibWVzc2FnZSI6eyJyb2xlIjoidG9vbFJlc3VsdCIsInRvb2xDYWxsSWQiOiJjYWxsXzI1ZDgwYWFmZTllYzQ0MDY5ZGUyNTkyOSIsInRvb2xOYW1lIjoid3JpdGUiLCJjb250ZW50IjpbeyJ0eXBlIjoidGV4dCIsInRleHQiOiJTdWNjZXNzZnVsbHkgd3JvdGUgMjQ2IGJ5dGVzIHRvIC9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrL3BhY2thZ2UuanNvbiJ9XSwiaXNFcnJvciI6ZmFsc2UsInRpbWVzdGFtcCI6MTc4MTk1NDIwMjQxNX19LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6ImU3ODlmODY3IiwicGFyZW50SWQiOiJhYTcwNWVkNiIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MTY6NDIuNDE1WiIsIm1lc3NhZ2UiOnsicm9sZSI6InRvb2xSZXN1bHQiLCJ0b29sQ2FsbElkIjoiY2FsbF83MTk1Yzk4YmFiZWE0OTYwOGUyOWIzOTciLCJ0b29sTmFtZSI6IndyaXRlIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiU3VjY2Vzc2Z1bGx5IHdyb3RlIDIzMSBieXRlcyB0byAvVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ay90c2NvbmZpZy5qc29uIn1dLCJpc0Vycm9yIjpmYWxzZSwidGltZXN0YW1wIjoxNzgxOTU0MjAyNDE1fX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiNTUyZGQyYWUiLCJwYXJlbnRJZCI6ImU3ODlmODY3IiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToxNjo0Mi40MTVaIiwibWVzc2FnZSI6eyJyb2xlIjoidG9vbFJlc3VsdCIsInRvb2xDYWxsSWQiOiJjYWxsXzI4MjhhNjk4NGQ0NDRiZmU5OTg5ZWQyNCIsInRvb2xOYW1lIjoid3JpdGUiLCJjb250ZW50IjpbeyJ0eXBlIjoidGV4dCIsInRleHQiOiJTdWNjZXNzZnVsbHkgd3JvdGUgNzUgYnl0ZXMgdG8gL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvc3JjL2dyZWV0LnRzIn1dLCJpc0Vycm9yIjpmYWxzZSwidGltZXN0YW1wIjoxNzgxOTU0MjAyNDE1fX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiODY3MTZkNzAiLCJwYXJlbnRJZCI6IjU1MmRkMmFlIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToxNjo0Mi40MTZaIiwibWVzc2FnZSI6eyJyb2xlIjoidG9vbFJlc3VsdCIsInRvb2xDYWxsSWQiOiJjYWxsXzI4MDlkZDI2NjFmOTQyMWNiM2ZkNTQ3YiIsInRvb2xOYW1lIjoid3JpdGUiLCJjb250ZW50IjpbeyJ0eXBlIjoidGV4dCIsInRleHQiOiJTdWNjZXNzZnVsbHkgd3JvdGUgMjIxIGJ5dGVzIHRvIC9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrL3NyYy9ncmVldC50ZXN0LnRzIn1dLCJpc0Vycm9yIjpmYWxzZSwidGltZXN0YW1wIjoxNzgxOTU0MjAyNDE2fX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiMjJiMTc4MzciLCJwYXJlbnRJZCI6Ijg2NzE2ZDcwIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToxNjo0Ni4wMzhaIiwibWVzc2FnZSI6eyJyb2xlIjoiYXNzaXN0YW50IiwiY29udGVudCI6W3sidHlwZSI6InRoaW5raW5nIiwidGhpbmtpbmciOiJBbGwgZmlsZXMgYXJlIGNyZWF0ZWQuIExldCBtZSBzdW1tYXJpemUgd2hhdCB3YXMgY3JlYXRlZC4iLCJ0aGlua2luZ1NpZ25hdHVyZSI6InJlYXNvbmluZyJ9LHsidHlwZSI6InRleHQiLCJ0ZXh0IjoiRG9uZSEgSGVyZSdzIHdoYXQgd2FzIHNjYWZmb2xkZWQ6XG5cbmBgYFxuc3JjL1xu4pSc4pSA4pSAIGdyZWV0LnRzICAgICAgICAgIOKAlCBTaW1wbGUgZnVuY3Rpb246IGBncmVldChuYW1lKWAgcmV0dXJucyBgXCJIZWxsbywge25hbWV9IVwiYFxu4pSU4pSA4pSAIGdyZWV0LnRlc3QudHMgICAgIOKAlCBPbmUgcGFzc2luZyB0ZXN0IGZvciBgZ3JlZXQoXCJXb3JsZFwiKWBcbnBhY2thZ2UuanNvbiAgICAgICAgICDigJQgU2NyaXB0czogYG5wbSB0ZXN0YCAodml0ZXN0IHJ1biksIGBucG0gcnVuIHRlc3Q6d2F0Y2hgXG50c2NvbmZpZy5qc29uICAgICAgICAg4oCUIFR5cGVTY3JpcHQgY29uZmlnIChFUzIwMjIsIGJ1bmRsZXIgbW9kdWxlIHJlc29sdXRpb24pXG5gYGBcblxuKipUbyBydW4gdGhlIHRlc3QqKiwgaW5zdGFsbCBkZXBzIHRoZW46XG5cbmBgYGJhc2hcbm5wbSBpbnN0YWxsXG5ucG0gdGVzdFxuYGBgXG5cblRoZSB0ZXN0IGFzc2VydHMgYGdyZWV0KFwiV29ybGRcIilgIHJldHVybnMgYFwiSGVsbG8sIFdvcmxkIVwiYCDigJQgaXQgc2hvdWxkIHBhc3MgZ3JlZW4gb24gZmlyc3QgcnVuLCByZWFkeSB0byBraWNrIG9mZiBhIHJlZC1ncmVlbi1yZWZhY3RvciBjeWNsZS4ifV0sImFwaSI6Im9wZW5haS1jb21wbGV0aW9ucyIsInByb3ZpZGVyIjoib3BlbnJvdXRlciIsIm1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2giLCJ1c2FnZSI6eyJpbnB1dCI6MTkxNzksIm91dHB1dCI6MTY5LCJjYWNoZVJlYWQiOjUxMiwiY2FjaGVXcml0ZSI6MCwidG90YWxUb2tlbnMiOjE5ODYwLCJjb3N0Ijp7ImlucHV0IjowLjAwMTcyNjEwOTk5OTk5OTk5OTksIm91dHB1dCI6MC4wMDAwMzA0MiwiY2FjaGVSZWFkIjowLjAwMDAxMDI0LCJjYWNoZVdyaXRlIjowLCJ0b3RhbCI6MC4wMDE3NjY3Njk5OTk5OTk5OTk4fX0sInN0b3BSZWFzb24iOiJzdG9wIiwidGltZXN0YW1wIjoxNzgxOTU0MjAyNDE2LCJyZXNwb25zZUlkIjoiZ2VuLTE3ODE5NTQyMDItRkhER0U2MUJyRzRMYWhaVkxqTHgiLCJyZXNwb25zZU1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2gtMjAyNjA0MjMifX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiMGIyYmEzOGIiLCJwYXJlbnRJZCI6IjIyYjE3ODM3IiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToxNjo1OS4zODFaIiwibWVzc2FnZSI6eyJyb2xlIjoiYmFzaEV4ZWN1dGlvbiIsImNvbW1hbmQiOiJjYXQgcGFja2FnZS5qc29uIiwib3V0cHV0Ijoie1xuICBcIm5hbWVcIjogXCJyZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWtcIixcbiAgXCJ2ZXJzaW9uXCI6IFwiMC4wLjFcIixcbiAgXCJ0eXBlXCI6IFwibW9kdWxlXCIsXG4gIFwic2NyaXB0c1wiOiB7XG4gICAgXCJ0ZXN0XCI6IFwidml0ZXN0IHJ1blwiLFxuICAgIFwidGVzdDp3YXRjaFwiOiBcInZpdGVzdFwiXG4gIH0sXG4gIFwiZGV2RGVwZW5kZW5jaWVzXCI6IHtcbiAgICBcInR5cGVzY3JpcHRcIjogXCJeNS43LjBcIixcbiAgICBcInZpdGVzdFwiOiBcIl4zLjAuMFwiXG4gIH1cbn0iLCJleGl0Q29kZSI6MCwiY2FuY2VsbGVkIjpmYWxzZSwidHJ1bmNhdGVkIjpmYWxzZSwidGltZXN0YW1wIjoxNzgxOTU0MjE5MzgxLCJleGNsdWRlRnJvbUNvbnRleHQiOmZhbHNlfX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiNjAwMDQyYjYiLCJwYXJlbnRJZCI6IjBiMmJhMzhiIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToxNzozNC40NTlaIiwibWVzc2FnZSI6eyJyb2xlIjoidXNlciIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6InJ1biB0aGUgdGVzdHMifV0sInRpbWVzdGFtcCI6MTc4MTk1NDI1NDQ1OH19LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6ImQ3ZjA0NGJkIiwicGFyZW50SWQiOiI2MDAwNDJiNiIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MTc6NDAuNTYyWiIsIm1lc3NhZ2UiOnsicm9sZSI6ImFzc2lzdGFudCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0aGlua2luZyIsInRoaW5raW5nIjoiVGhlIHVzZXIgd2FudHMgbWUgdG8gcnVuIHRoZSB0ZXN0cy4gTGV0IG1lIGV4ZWN1dGUgYG5wbSB0ZXN0YCBpbiB0aGUgcHJvamVjdCBkaXJlY3RvcnkuIiwidGhpbmtpbmdTaWduYXR1cmUiOiJyZWFzb25pbmcifSx7InR5cGUiOiJ0b29sQ2FsbCIsImlkIjoiY2FsbF8yNGVhNTViMzg1MzQ0NjA0YWIzMjQ1OTEiLCJuYW1lIjoiYmFzaCIsImFyZ3VtZW50cyI6eyJjb21tYW5kIjoiY2QgL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsgJiYgbnBtIHRlc3QifX1dLCJhcGkiOiJvcGVuYWktY29tcGxldGlvbnMiLCJwcm92aWRlciI6Im9wZW5yb3V0ZXIiLCJtb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoIiwidXNhZ2UiOnsiaW5wdXQiOjEyOTUsIm91dHB1dCI6ODksImNhY2hlUmVhZCI6MTg2ODgsImNhY2hlV3JpdGUiOjAsInRvdGFsVG9rZW5zIjoyMDA3MiwiY29zdCI6eyJpbnB1dCI6MC4wMDAxMTY1NSwib3V0cHV0IjowLjAwMDAxNjAyLCJjYWNoZVJlYWQiOjAuMDAwMzczNzYsImNhY2hlV3JpdGUiOjAsInRvdGFsIjowLjAwMDUwNjMyOTk5OTk5OTk5OTl9fSwic3RvcFJlYXNvbiI6InRvb2xVc2UiLCJ0aW1lc3RhbXAiOjE3ODE5NTQyNTQ0NjIsInJlc3BvbnNlSWQiOiJnZW4tMTc4MTk1NDI1Ni16eVc2V2FkVXM3SzdwNHZVMlZxTCIsInJlc3BvbnNlTW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaC0yMDI2MDQyMyJ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiI5OTY0N2RmZCIsInBhcmVudElkIjoiZDdmMDQ0YmQiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjE3OjQxLjYyNVoiLCJtZXNzYWdlIjp7InJvbGUiOiJ0b29sUmVzdWx0IiwidG9vbENhbGxJZCI6ImNhbGxfMjRlYTU1YjM4NTM0NDYwNGFiMzI0NTkxIiwidG9vbE5hbWUiOiJiYXNoIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiXG4+IHJlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11a0AwLjAuMSB0ZXN0XG4+IHZpdGVzdCBydW5cblxuXG4gUlVOICB2My4yLjYgL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWtcblxuIOKckyBzcmMvZ3JlZXQudGVzdC50cyAoMSB0ZXN0KSAxbXNcblxuIFRlc3QgRmlsZXMgIDEgcGFzc2VkICgxKVxuICAgICAgVGVzdHMgIDEgcGFzc2VkICgxKVxuICAgU3RhcnQgYXQgIDEyOjE3OjQxXG4gICBEdXJhdGlvbiAgMjQybXMgKHRyYW5zZm9ybSAyN21zLCBzZXR1cCAwbXMsIGNvbGxlY3QgNTRtcywgdGVzdHMgMW1zLCBlbnZpcm9ubWVudCAwbXMsIHByZXBhcmUgMzdtcylcblxuIn1dLCJpc0Vycm9yIjpmYWxzZSwidGltZXN0YW1wIjoxNzgxOTU0MjYxNjI1fX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiNWYzMmNjNDEiLCJwYXJlbnRJZCI6Ijk5NjQ3ZGZkIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToxNzo0NS43NTZaIiwibWVzc2FnZSI6eyJyb2xlIjoiYXNzaXN0YW50IiwiY29udGVudCI6W3sidHlwZSI6InRoaW5raW5nIiwidGhpbmtpbmciOiJUaGUgdGVzdHMgcGFzc2VkLiBMZXQgbWUgdGVsbCB0aGUgdXNlci4iLCJ0aGlua2luZ1NpZ25hdHVyZSI6InJlYXNvbmluZyJ9LHsidHlwZSI6InRleHQiLCJ0ZXh0IjoiQWxsIGdyZWVuISDinJNcblxuYGBgXG4g4pyTIHNyYy9ncmVldC50ZXN0LnRzICgxIHRlc3QpIDFtc1xuXG4gVGVzdCBGaWxlcyAgMSBwYXNzZWQgKDEpXG4gICAgICBUZXN0cyAgMSBwYXNzZWQgKDEpXG5gYGBcblxuVGhlIHJlZC1ncmVlbi1yZWZhY3RvciBjeWNsZSBpcyByZWFkeSB0byBnbyDigJQganVzdCBvbmUgcGFzc2luZyB0ZXN0IHRvIHN0YXJ0IGZyb20uIn1dLCJhcGkiOiJvcGVuYWktY29tcGxldGlvbnMiLCJwcm92aWRlciI6Im9wZW5yb3V0ZXIiLCJtb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoIiwidXNhZ2UiOnsiaW5wdXQiOjIwMTk1LCJvdXRwdXQiOjY4LCJjYWNoZVJlYWQiOjAsImNhY2hlV3JpdGUiOjAsInRvdGFsVG9rZW5zIjoyMDI2MywiY29zdCI6eyJpbnB1dCI6MC4wMDE4MTc1NSwib3V0cHV0IjowLjAwMDAxMjI0LCJjYWNoZVJlYWQiOjAsImNhY2hlV3JpdGUiOjAsInRvdGFsIjowLjAwMTgyOTc5fX0sInN0b3BSZWFzb24iOiJzdG9wIiwidGltZXN0YW1wIjoxNzgxOTU0MjYxNjI1LCJyZXNwb25zZUlkIjoiZ2VuLTE3ODE5NTQyNjEtOG1qaUtFZzhRVU15WXY0eG1CMEEiLCJyZXNwb25zZU1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2gtMjAyNjA0MjMifX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiMzQ4NWIwZWEiLCJwYXJlbnRJZCI6IjVmMzJjYzQxIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToxODo0NS42ODZaIiwibWVzc2FnZSI6eyJyb2xlIjoidXNlciIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6Ikkgd291bGQgbGlrZSBhIHNtYWxsIGV4dGVuc2lvbiB0aGF0IHNob3dzIGEgZ3JlZW4gZG90IHdoZW5ldmVyIHRoZSB0ZXN0cyBoYXZlIHBhc3NlZC4gR2l2ZSBtZSBzb21lIG9wdGlvbnMuIn1dLCJ0aW1lc3RhbXAiOjE3ODE5NTQzMjU2ODV9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiJlMWI2NTQ1YyIsInBhcmVudElkIjoiMzQ4NWIwZWEiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjE4OjUxLjg3OVoiLCJtZXNzYWdlIjp7InJvbGUiOiJhc3Npc3RhbnQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGhpbmtpbmciLCJ0aGlua2luZyI6IlRoZSB1c2VyIHdhbnRzIGEgUGkgZXh0ZW5zaW9uIHRoYXQgc2hvd3MgYSBncmVlbiBkb3Qgd2hlbmV2ZXIgdGVzdHMgaGF2ZSBwYXNzZWQuIExldCBtZSB0aGluayBhYm91dCB3aGF0IGFwcHJvYWNoZXMgYXJlIHBvc3NpYmxlLlxuXG5MZXQgbWUgcmVhZCB0aGUgZXh0ZW5zaW9ucyBkb2NzIG1vcmUgY2FyZWZ1bGx5IGZvciByZWxldmFudCBwYXR0ZXJucywgYW5kIGFsc28gbG9vayBhdCB0aGUgVFVJIGRvY3MgYW5kIGV4YW1wbGVzIHRvIHVuZGVyc3RhbmQgd2hhdCdzIHBvc3NpYmxlIGZvciBzaG93aW5nIHN0YXR1cyBpbmRpY2F0b3JzLiIsInRoaW5raW5nU2lnbmF0dXJlIjoicmVhc29uaW5nIn0seyJ0eXBlIjoidG9vbENhbGwiLCJpZCI6ImNhbGxfNmI1MWEyMzJkMzU5NGZiMThlZTQwMDEyIiwibmFtZSI6InJlYWQiLCJhcmd1bWVudHMiOnsicGF0aCI6Ii9Vc2Vycy93aWxsZW0vLmxvY2FsL3NoYXJlL21pc2UvaW5zdGFsbHMvbm9kZS8yNC4wLjEvbGliL25vZGVfbW9kdWxlcy9AZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50L2RvY3MvdHVpLm1kIn19LHsidHlwZSI6InRvb2xDYWxsIiwiaWQiOiJjYWxsX2MzMDI0ODZmNWIzMjQxOGRhNWE5YzZlYSIsIm5hbWUiOiJiYXNoIiwiYXJndW1lbnRzIjp7ImNvbW1hbmQiOiJscyAvVXNlcnMvd2lsbGVtLy5sb2NhbC9zaGFyZS9taXNlL2luc3RhbGxzL25vZGUvMjQuMC4xL2xpYi9ub2RlX21vZHVsZXMvQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudC9leGFtcGxlcy9leHRlbnNpb25zLyJ9fV0sImFwaSI6Im9wZW5haS1jb21wbGV0aW9ucyIsInByb3ZpZGVyIjoib3BlbnJvdXRlciIsIm1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2giLCJ1c2FnZSI6eyJpbnB1dCI6MTg1Niwib3V0cHV0IjoyMDQsImNhY2hlUmVhZCI6MTg0MzIsImNhY2hlV3JpdGUiOjAsInRvdGFsVG9rZW5zIjoyMDQ5MiwiY29zdCI6eyJpbnB1dCI6MC4wMDAxNjcwNCwib3V0cHV0IjowLjAwMDAzNjcyLCJjYWNoZVJlYWQiOjAuMDAwMzY4NjQsImNhY2hlV3JpdGUiOjAsInRvdGFsIjowLjAwMDU3MjR9fSwic3RvcFJlYXNvbiI6InRvb2xVc2UiLCJ0aW1lc3RhbXAiOjE3ODE5NTQzMjU2ODcsInJlc3BvbnNlSWQiOiJnZW4tMTc4MTk1NDMyNi1Wb2RuRGJHSDdPa0dDSFIzanNYRCIsInJlc3BvbnNlTW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaC0yMDI2MDQyMyJ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiIwMzkxZjI3NiIsInBhcmVudElkIjoiZTFiNjU0NWMiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjE4OjUxLjg5NloiLCJtZXNzYWdlIjp7InJvbGUiOiJ0b29sUmVzdWx0IiwidG9vbENhbGxJZCI6ImNhbGxfNmI1MWEyMzJkMzU5NGZiMThlZTQwMDEyIiwidG9vbE5hbWUiOiJyZWFkIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiPiBwaSBjYW4gY3JlYXRlIFRVSSBjb21wb25lbnRzLiBBc2sgaXQgdG8gYnVpbGQgb25lIGZvciB5b3VyIHVzZSBjYXNlLlxuXG4jIFRVSSBDb21wb25lbnRzXG5cbkV4dGVuc2lvbnMgYW5kIGN1c3RvbSB0b29scyBjYW4gcmVuZGVyIGN1c3RvbSBUVUkgY29tcG9uZW50cyBmb3IgaW50ZXJhY3RpdmUgdXNlciBpbnRlcmZhY2VzLiBUaGlzIHBhZ2UgY292ZXJzIHRoZSBjb21wb25lbnQgc3lzdGVtIGFuZCBhdmFpbGFibGUgYnVpbGRpbmcgYmxvY2tzLlxuXG4qKlNvdXJjZToqKiBbYEBlYXJlbmRpbC13b3Jrcy9waS10dWlgXShodHRwczovL2dpdGh1Yi5jb20vZWFyZW5kaWwtd29ya3MvcGktbW9uby90cmVlL21haW4vcGFja2FnZXMvdHVpKVxuXG4jIyBDb21wb25lbnQgSW50ZXJmYWNlXG5cbkFsbCBjb21wb25lbnRzIGltcGxlbWVudDpcblxuYGBgdHlwZXNjcmlwdFxuaW50ZXJmYWNlIENvbXBvbmVudCB7XG4gIHJlbmRlcih3aWR0aDogbnVtYmVyKTogc3RyaW5nW107XG4gIGhhbmRsZUlucHV0PyhkYXRhOiBzdHJpbmcpOiB2b2lkO1xuICB3YW50c0tleVJlbGVhc2U/OiBib29sZWFuO1xuICBpbnZhbGlkYXRlKCk6IHZvaWQ7XG59XG5gYGBcblxufCBNZXRob2QgfCBEZXNjcmlwdGlvbiB8XG58LS0tLS0tLS18LS0tLS0tLS0tLS0tLXxcbnwgYHJlbmRlcih3aWR0aClgIHwgUmV0dXJuIGFycmF5IG9mIHN0cmluZ3MgKG9uZSBwZXIgbGluZSkuIEVhY2ggbGluZSAqKm11c3Qgbm90IGV4Y2VlZCBgd2lkdGhgKiouIHxcbnwgYGhhbmRsZUlucHV0PyhkYXRhKWAgfCBSZWNlaXZlIGtleWJvYXJkIGlucHV0IHdoZW4gY29tcG9uZW50IGhhcyBmb2N1cy4gfFxufCBgd2FudHNLZXlSZWxlYXNlP2AgfCBJZiB0cnVlLCBjb21wb25lbnQgcmVjZWl2ZXMga2V5IHJlbGVhc2UgZXZlbnRzIChLaXR0eSBwcm90b2NvbCkuIERlZmF1bHQ6IGZhbHNlLiB8XG58IGBpbnZhbGlkYXRlKClgIHwgQ2xlYXIgY2FjaGVkIHJlbmRlciBzdGF0ZS4gQ2FsbGVkIG9uIHRoZW1lIGNoYW5nZXMuIHxcblxuVGhlIFRVSSBhcHBlbmRzIGEgZnVsbCBTR1IgcmVzZXQgYW5kIE9TQyA4IHJlc2V0IGF0IHRoZSBlbmQgb2YgZWFjaCByZW5kZXJlZCBsaW5lLiBTdHlsZXMgZG8gbm90IGNhcnJ5IGFjcm9zcyBsaW5lcy4gSWYgeW91IGVtaXQgbXVsdGktbGluZSB0ZXh0IHdpdGggc3R5bGluZywgcmVhcHBseSBzdHlsZXMgcGVyIGxpbmUgb3IgdXNlIGB3cmFwVGV4dFdpdGhBbnNpKClgIHNvIHN0eWxlcyBhcmUgcHJlc2VydmVkIGZvciBlYWNoIHdyYXBwZWQgbGluZS5cblxuIyMgRm9jdXNhYmxlIEludGVyZmFjZSAoSU1FIFN1cHBvcnQpXG5cbkNvbXBvbmVudHMgdGhhdCBkaXNwbGF5IGEgdGV4dCBjdXJzb3IgYW5kIG5lZWQgSU1FIChJbnB1dCBNZXRob2QgRWRpdG9yKSBzdXBwb3J0IHNob3VsZCBpbXBsZW1lbnQgdGhlIGBGb2N1c2FibGVgIGludGVyZmFjZTpcblxuYGBgdHlwZXNjcmlwdFxuaW1wb3J0IHsgQ1VSU09SX01BUktFUiwgdHlwZSBDb21wb25lbnQsIHR5cGUgRm9jdXNhYmxlIH0gZnJvbSBcIkBlYXJlbmRpbC13b3Jrcy9waS10dWlcIjtcblxuY2xhc3MgTXlJbnB1dCBpbXBsZW1lbnRzIENvbXBvbmVudCwgRm9jdXNhYmxlIHtcbiAgZm9jdXNlZDogYm9vbGVhbiA9IGZhbHNlOyAgLy8gU2V0IGJ5IFRVSSB3aGVuIGZvY3VzIGNoYW5nZXNcbiAgXG4gIHJlbmRlcih3aWR0aDogbnVtYmVyKTogc3RyaW5nW10ge1xuICAgIGNvbnN0IG1hcmtlciA9IHRoaXMuZm9jdXNlZCA/IENVUlNPUl9NQVJLRVIgOiBcIlwiO1xuICAgIC8vIEVtaXQgbWFya2VyIHJpZ2h0IGJlZm9yZSB0aGUgZmFrZSBjdXJzb3JcbiAgICByZXR1cm4gW2A+ICR7YmVmb3JlQ3Vyc29yfSR7bWFya2VyfVxceDFiWzdtJHthdEN1cnNvcn1cXHgxYlsyN20ke2FmdGVyQ3Vyc29yfWBdO1xuICB9XG59XG5gYGBcblxuV2hlbiBhIGBGb2N1c2FibGVgIGNvbXBvbmVudCBoYXMgZm9jdXMsIFRVSTpcbjEuIFNldHMgYGZvY3VzZWQgPSB0cnVlYCBvbiB0aGUgY29tcG9uZW50XG4yLiBTY2FucyByZW5kZXJlZCBvdXRwdXQgZm9yIGBDVVJTT1JfTUFSS0VSYCAoYSB6ZXJvLXdpZHRoIEFQQyBlc2NhcGUgc2VxdWVuY2UpXG4zLiBQb3NpdGlvbnMgdGhlIGhhcmR3YXJlIHRlcm1pbmFsIGN1cnNvciBhdCB0aGF0IGxvY2F0aW9uXG40LiBTaG93cyB0aGUgaGFyZHdhcmUgY3Vyc29yIG9ubHkgd2hlbiBgc2hvd0hhcmR3YXJlQ3Vyc29yYCBpcyBlbmFibGVkXG5cblRoZSBjdXJzb3IgcmVtYWlucyBoaWRkZW4gYnkgZGVmYXVsdC4gVGhpcyBrZWVwcyB0aGUgZmFrZSBjdXJzb3IgcmVuZGVyaW5nLCB3aGlsZSBzdGlsbCBwb3NpdGlvbmluZyB0aGUgaGFyZHdhcmUgY3Vyc29yIGZvciB0ZXJtaW5hbHMgdGhhdCB0cmFjayBJTUUgY2FuZGlkYXRlIHdpbmRvd3Mgd2l0aCBoaWRkZW4gY3Vyc29ycy4gU29tZSB0ZXJtaW5hbHMgcmVxdWlyZSBhIHZpc2libGUgaGFyZHdhcmUgY3Vyc29yIGZvciBJTUUgcG9zaXRpb25pbmc7IGVuYWJsZSBpdCB3aXRoIGBzaG93SGFyZHdhcmVDdXJzb3JgLCBgc2V0U2hvd0hhcmR3YXJlQ3Vyc29yKHRydWUpYCwgb3IgYFBJX0hBUkRXQVJFX0NVUlNPUj0xYC4gVGhlIGBFZGl0b3JgIGFuZCBgSW5wdXRgIGJ1aWx0LWluIGNvbXBvbmVudHMgYWxyZWFkeSBpbXBsZW1lbnQgdGhpcyBpbnRlcmZhY2UuXG5cbiMjIyBDb250YWluZXIgQ29tcG9uZW50cyB3aXRoIEVtYmVkZGVkIElucHV0c1xuXG5XaGVuIGEgY29udGFpbmVyIGNvbXBvbmVudCAoZGlhbG9nLCBzZWxlY3RvciwgZXRjLikgY29udGFpbnMgYW4gYElucHV0YCBvciBgRWRpdG9yYCBjaGlsZCwgdGhlIGNvbnRhaW5lciBtdXN0IGltcGxlbWVudCBgRm9jdXNhYmxlYCBhbmQgcHJvcGFnYXRlIHRoZSBmb2N1cyBzdGF0ZSB0byB0aGUgY2hpbGQuIE90aGVyd2lzZSwgdGhlIGhhcmR3YXJlIGN1cnNvciB3b24ndCBiZSBwb3NpdGlvbmVkIGNvcnJlY3RseSBmb3IgSU1FIGlucHV0LlxuXG5gYGB0eXBlc2NyaXB0XG5pbXBvcnQgeyBDb250YWluZXIsIHR5cGUgRm9jdXNhYmxlLCBJbnB1dCB9IGZyb20gXCJAZWFyZW5kaWwtd29ya3MvcGktdHVpXCI7XG5cbmNsYXNzIFNlYXJjaERpYWxvZyBleHRlbmRzIENvbnRhaW5lciBpbXBsZW1lbnRzIEZvY3VzYWJsZSB7XG4gIHByaXZhdGUgc2VhcmNoSW5wdXQ6IElucHV0O1xuXG4gIC8vIEZvY3VzYWJsZSBpbXBsZW1lbnRhdGlvbiAtIHByb3BhZ2F0ZSB0byBjaGlsZCBpbnB1dCBmb3IgSU1FIGN1cnNvciBwb3NpdGlvbmluZ1xuICBwcml2YXRlIF9mb2N1c2VkID0gZmFsc2U7XG4gIGdldCBmb2N1c2VkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9mb2N1c2VkO1xuICB9XG4gIHNldCBmb2N1c2VkKHZhbHVlOiBib29sZWFuKSB7XG4gICAgdGhpcy5fZm9jdXNlZCA9IHZhbHVlO1xuICAgIHRoaXMuc2VhcmNoSW5wdXQuZm9jdXNlZCA9IHZhbHVlO1xuICB9XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgc3VwZXIoKTtcbiAgICB0aGlzLnNlYXJjaElucHV0ID0gbmV3IElucHV0KCk7XG4gICAgdGhpcy5hZGRDaGlsZCh0aGlzLnNlYXJjaElucHV0KTtcbiAgfVxufVxuYGBgXG5cbldpdGhvdXQgdGhpcyBwcm9wYWdhdGlvbiwgdHlwaW5nIHdpdGggYW4gSU1FIChDaGluZXNlLCBKYXBhbmVzZSwgS29yZWFuLCBldGMuKSB3aWxsIHNob3cgdGhlIGNhbmRpZGF0ZSB3aW5kb3cgaW4gdGhlIHdyb25nIHBvc2l0aW9uIG9uIHNjcmVlbi5cblxuIyMgVXNpbmcgQ29tcG9uZW50c1xuXG4qKkluIGV4dGVuc2lvbnMqKiB2aWEgYGN0eC51aS5jdXN0b20oKWA6XG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwic2Vzc2lvbl9zdGFydFwiLCBhc3luYyAoX2V2ZW50LCBjdHgpID0+IHtcbiAgY29uc3QgaGFuZGxlID0gY3R4LnVpLmN1c3RvbShteUNvbXBvbmVudCk7XG4gIC8vIGhhbmRsZS5yZXF1ZXN0UmVuZGVyKCkgLSB0cmlnZ2VyIHJlLXJlbmRlclxuICAvLyBoYW5kbGUuY2xvc2UoKSAtIHJlc3RvcmUgbm9ybWFsIFVJXG59KTtcbmBgYFxuXG4qKkluIGN1c3RvbSB0b29scyoqIHZpYSBgcGkudWkuY3VzdG9tKClgOlxuXG5gYGB0eXBlc2NyaXB0XG5hc3luYyBleGVjdXRlKHRvb2xDYWxsSWQsIHBhcmFtcywgb25VcGRhdGUsIGN0eCwgc2lnbmFsKSB7XG4gIGNvbnN0IGhhbmRsZSA9IHBpLnVpLmN1c3RvbShteUNvbXBvbmVudCk7XG4gIC8vIC4uLlxuICBoYW5kbGUuY2xvc2UoKTtcbn1cbmBgYFxuXG4jIyBPdmVybGF5c1xuXG5PdmVybGF5cyByZW5kZXIgY29tcG9uZW50cyBvbiB0b3Agb2YgZXhpc3RpbmcgY29udGVudCB3aXRob3V0IGNsZWFyaW5nIHRoZSBzY3JlZW4uIFBhc3MgYHsgb3ZlcmxheTogdHJ1ZSB9YCB0byBgY3R4LnVpLmN1c3RvbSgpYDpcblxuYGBgdHlwZXNjcmlwdFxuY29uc3QgcmVzdWx0ID0gYXdhaXQgY3R4LnVpLmN1c3RvbTxzdHJpbmcgfCBudWxsPihcbiAgKHR1aSwgdGhlbWUsIGtleWJpbmRpbmdzLCBkb25lKSA9PiBuZXcgTXlEaWFsb2coeyBvbkNsb3NlOiBkb25lIH0pLFxuICB7IG92ZXJsYXk6IHRydWUgfVxuKTtcbmBgYFxuXG5Gb3IgcG9zaXRpb25pbmcgYW5kIHNpemluZywgdXNlIGBvdmVybGF5T3B0aW9uc2A6XG5cbmBgYHR5cGVzY3JpcHRcbmNvbnN0IHJlc3VsdCA9IGF3YWl0IGN0eC51aS5jdXN0b208c3RyaW5nIHwgbnVsbD4oXG4gICh0dWksIHRoZW1lLCBrZXliaW5kaW5ncywgZG9uZSkgPT4gbmV3IFNpZGVQYW5lbCh7IG9uQ2xvc2U6IGRvbmUgfSksXG4gIHtcbiAgICBvdmVybGF5OiB0cnVlLFxuICAgIG92ZXJsYXlPcHRpb25zOiB7XG4gICAgICAvLyBTaXplOiBudW1iZXIgb3IgcGVyY2VudGFnZSBzdHJpbmdcbiAgICAgIHdpZHRoOiBcIjUwJVwiLCAgICAgICAgICAvLyA1MCUgb2YgdGVybWluYWwgd2lkdGhcbiAgICAgIG1pbldpZHRoOiA0MCwgICAgICAgICAgLy8gbWluaW11bSA0MCBjb2x1bW5zXG4gICAgICBtYXhIZWlnaHQ6IFwiODAlXCIsICAgICAgLy8gbWF4IDgwJSBvZiB0ZXJtaW5hbCBoZWlnaHRcblxuICAgICAgLy8gUG9zaXRpb246IGFuY2hvci1iYXNlZCAoZGVmYXVsdDogXCJjZW50ZXJcIilcbiAgICAgIGFuY2hvcjogXCJyaWdodC1jZW50ZXJcIiwgLy8gOSBwb3NpdGlvbnM6IGNlbnRlciwgdG9wLWxlZnQsIHRvcC1jZW50ZXIsIGV0Yy5cbiAgICAgIG9mZnNldFg6IC0yLCAgICAgICAgICAgIC8vIG9mZnNldCBmcm9tIGFuY2hvclxuICAgICAgb2Zmc2V0WTogMCxcblxuICAgICAgLy8gT3IgcGVyY2VudGFnZS9hYnNvbHV0ZSBwb3NpdGlvbmluZ1xuICAgICAgcm93OiBcIjI1JVwiLCAgICAgICAgICAgIC8vIDI1JSBmcm9tIHRvcFxuICAgICAgY29sOiAxMCwgICAgICAgICAgICAgICAvLyBjb2x1bW4gMTBcblxuICAgICAgLy8gTWFyZ2luc1xuICAgICAgbWFyZ2luOiAyLCAgICAgICAgICAgICAvLyBhbGwgc2lkZXMsIG9yIHsgdG9wLCByaWdodCwgYm90dG9tLCBsZWZ0IH1cblxuICAgICAgLy8gUmVzcG9uc2l2ZTogaGlkZSBvbiBuYXJyb3cgdGVybWluYWxzXG4gICAgICB2aXNpYmxlOiAodGVybVdpZHRoLCB0ZXJtSGVpZ2h0KSA9PiB0ZXJtV2lkdGggPj0gODAsXG4gICAgfSxcbiAgICAvLyBHZXQgaGFuZGxlIGZvciBwcm9ncmFtbWF0aWMgZm9jdXMgYW5kIHZpc2liaWxpdHkgY29udHJvbFxuICAgIG9uSGFuZGxlOiAoaGFuZGxlKSA9PiB7XG4gICAgICAvLyBoYW5kbGUuZm9jdXMoKSAtIGZvY3VzIHRoaXMgb3ZlcmxheSBhbmQgYnJpbmcgaXQgdG8gdGhlIHZpc3VhbCBmcm9udFxuICAgICAgLy8gaGFuZGxlLnVuZm9jdXMoKSAtIHJlbGVhc2UgaW5wdXQgdG8gbm9ybWFsIGZhbGxiYWNrXG4gICAgICAvLyBoYW5kbGUudW5mb2N1cyh7IHRhcmdldCB9KSAtIHJlbGVhc2UgaW5wdXQgdG8gYSBzcGVjaWZpYyBjb21wb25lbnQgb3IgbnVsbFxuICAgICAgLy8gaGFuZGxlLnNldEhpZGRlbih0cnVlL2ZhbHNlKSAtIHRvZ2dsZSB2aXNpYmlsaXR5XG4gICAgICAvLyBoYW5kbGUuaGlkZSgpIC0gcGVybWFuZW50bHkgcmVtb3ZlXG4gICAgfSxcbiAgfVxuKTtcbmBgYFxuXG4jIyMgT3ZlcmxheSBGb2N1c1xuXG5BIGZvY3VzZWQgdmlzaWJsZSBvdmVybGF5IGtlZXBzIGlucHV0IG93bmVyc2hpcCBhY3Jvc3MgdGVtcG9yYXJ5IG5vbi1vdmVybGF5IFVJLiBJZiBhbiBvdmVybGF5IG9wZW5zIGFub3RoZXIgYGN0eC51aS5jdXN0b20oKWAgY29tcG9uZW50IHdpdGhvdXQgYHsgb3ZlcmxheTogdHJ1ZSB9YCwgdGhhdCByZXBsYWNlbWVudCBVSSByZWNlaXZlcyBpbnB1dCB3aGlsZSBpdCBpcyBhY3RpdmU7IHdoZW4gaXQgY2xvc2VzLCB0aGUgZm9jdXNlZCBvdmVybGF5IGNhbiByZWNsYWltIGlucHV0LlxuXG5Vc2UgYGhhbmRsZS51bmZvY3VzKClgIHdoZW4gYSB2aXNpYmxlIG92ZXJsYXkgc2hvdWxkIHN0b3Agb3duaW5nIGlucHV0IGFuZCBsZXQgVFVJIGZhbGwgYmFjayB0byBhbm90aGVyIHZpc2libGUgY2FwdHVyaW5nIG92ZXJsYXkgb3IgdGhlIHByZXZpb3VzIGZvY3VzIHRhcmdldC4gVXNlIGBoYW5kbGUudW5mb2N1cyh7IHRhcmdldCB9KWAgd2hlbiBhIHNwZWNpZmljIGNvbXBvbmVudCBzaG91bGQgcmVjZWl2ZSBpbnB1dCB3aGlsZSB0aGUgb3ZlcmxheSBzdGF5cyB2aXNpYmxlLiBQYXNzaW5nIGB7IHRhcmdldDogbnVsbCB9YCBpbnRlbnRpb25hbGx5IGxlYXZlcyBubyBmb2N1c2VkIGNvbXBvbmVudCB1bnRpbCBmb2N1cyBpcyBzZXQgYWdhaW4uXG5cbiMjIyBPdmVybGF5IExpZmVjeWNsZVxuXG5PdmVybGF5IGNvbXBvbmVudHMgYXJlIGRpc3Bvc2VkIHdoZW4gY2xvc2VkLiBEb24ndCByZXVzZSByZWZlcmVuY2VzIC0gY3JlYXRlIGZyZXNoIGluc3RhbmNlczpcblxuYGBgdHlwZXNjcmlwdFxuLy8gV3JvbmcgLSBzdGFsZSByZWZlcmVuY2VcbmxldCBtZW51OiBNZW51Q29tcG9uZW50O1xuYXdhaXQgY3R4LnVpLmN1c3RvbSgoXywgX18sIF9fXywgZG9uZSkgPT4ge1xuICBtZW51ID0gbmV3IE1lbnVDb21wb25lbnQoZG9uZSk7XG4gIHJldHVybiBtZW51O1xufSwgeyBvdmVybGF5OiB0cnVlIH0pO1xuc2V0QWN0aXZlQ29tcG9uZW50KG1lbnUpOyAgLy8gRGlzcG9zZWRcblxuLy8gQ29ycmVjdCAtIHJlLWNhbGwgdG8gcmUtc2hvd1xuY29uc3Qgc2hvd01lbnUgPSAoKSA9PiBjdHgudWkuY3VzdG9tKChfLCBfXywgX19fLCBkb25lKSA9PiBcbiAgbmV3IE1lbnVDb21wb25lbnQoZG9uZSksIHsgb3ZlcmxheTogdHJ1ZSB9KTtcblxuYXdhaXQgc2hvd01lbnUoKTsgIC8vIEZpcnN0IHNob3dcbmF3YWl0IHNob3dNZW51KCk7ICAvLyBcIkJhY2tcIiA9IGp1c3QgY2FsbCBhZ2FpblxuYGBgXG5cblNlZSBbb3ZlcmxheS1xYS10ZXN0cy50c10oLi4vZXhhbXBsZXMvZXh0ZW5zaW9ucy9vdmVybGF5LXFhLXRlc3RzLnRzKSBmb3IgY29tcHJlaGVuc2l2ZSBleGFtcGxlcyBjb3ZlcmluZyBhbmNob3JzLCBtYXJnaW5zLCBzdGFja2luZywgcmVzcG9uc2l2ZSB2aXNpYmlsaXR5LCBhbmQgYW5pbWF0aW9uLlxuXG4jIyBCdWlsdC1pbiBDb21wb25lbnRzXG5cbkltcG9ydCBmcm9tIGBAZWFyZW5kaWwtd29ya3MvcGktdHVpYDpcblxuYGBgdHlwZXNjcmlwdFxuaW1wb3J0IHsgVGV4dCwgQm94LCBDb250YWluZXIsIFNwYWNlciwgTWFya2Rvd24gfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLXR1aVwiO1xuYGBgXG5cbiMjIyBUZXh0XG5cbk11bHRpLWxpbmUgdGV4dCB3aXRoIHdvcmQgd3JhcHBpbmcuXG5cbmBgYHR5cGVzY3JpcHRcbmNvbnN0IHRleHQgPSBuZXcgVGV4dChcbiAgXCJIZWxsbyBXb3JsZFwiLCAgICAvLyBjb250ZW50XG4gIDEsICAgICAgICAgICAgICAgIC8vIHBhZGRpbmdYIChkZWZhdWx0OiAxKVxuICAxLCAgICAgICAgICAgICAgICAvLyBwYWRkaW5nWSAoZGVmYXVsdDogMSlcbiAgKHMpID0+IGJnR3JheShzKSAgLy8gb3B0aW9uYWwgYmFja2dyb3VuZCBmdW5jdGlvblxuKTtcbnRleHQuc2V0VGV4dChcIlVwZGF0ZWRcIik7XG5gYGBcblxuIyMjIEJveFxuXG5Db250YWluZXIgd2l0aCBwYWRkaW5nIGFuZCBiYWNrZ3JvdW5kIGNvbG9yLlxuXG5gYGB0eXBlc2NyaXB0XG5jb25zdCBib3ggPSBuZXcgQm94KFxuICAxLCAgICAgICAgICAgICAgICAvLyBwYWRkaW5nWFxuICAxLCAgICAgICAgICAgICAgICAvLyBwYWRkaW5nWVxuICAocykgPT4gYmdHcmF5KHMpICAvLyBiYWNrZ3JvdW5kIGZ1bmN0aW9uXG4pO1xuYm94LmFkZENoaWxkKG5ldyBUZXh0KFwiQ29udGVudFwiLCAwLCAwKSk7XG5ib3guc2V0QmdGbigocykgPT4gYmdCbHVlKHMpKTtcbmBgYFxuXG4jIyMgQ29udGFpbmVyXG5cbkdyb3VwcyBjaGlsZCBjb21wb25lbnRzIHZlcnRpY2FsbHkuXG5cbmBgYHR5cGVzY3JpcHRcbmNvbnN0IGNvbnRhaW5lciA9IG5ldyBDb250YWluZXIoKTtcbmNvbnRhaW5lci5hZGRDaGlsZChjb21wb25lbnQxKTtcbmNvbnRhaW5lci5hZGRDaGlsZChjb21wb25lbnQyKTtcbmNvbnRhaW5lci5yZW1vdmVDaGlsZChjb21wb25lbnQxKTtcbmBgYFxuXG4jIyMgU3BhY2VyXG5cbkVtcHR5IHZlcnRpY2FsIHNwYWNlLlxuXG5gYGB0eXBlc2NyaXB0XG5jb25zdCBzcGFjZXIgPSBuZXcgU3BhY2VyKDIpOyAgLy8gMiBlbXB0eSBsaW5lc1xuYGBgXG5cbiMjIyBNYXJrZG93blxuXG5SZW5kZXJzIG1hcmtkb3duIHdpdGggc3ludGF4IGhpZ2hsaWdodGluZy5cblxuYGBgdHlwZXNjcmlwdFxuY29uc3QgbWQgPSBuZXcgTWFya2Rvd24oXG4gIFwiIyBUaXRsZVxcblxcblNvbWUgKipib2xkKiogdGV4dFwiLFxuICAxLCAgICAgICAgLy8gcGFkZGluZ1hcbiAgMSwgICAgICAgIC8vIHBhZGRpbmdZXG4gIHRoZW1lICAgICAvLyBNYXJrZG93blRoZW1lIChzZWUgYmVsb3cpXG4pO1xubWQuc2V0VGV4dChcIlVwZGF0ZWQgbWFya2Rvd25cIik7XG5gYGBcblxuIyMjIEltYWdlXG5cblJlbmRlcnMgaW1hZ2VzIGluIHN1cHBvcnRlZCB0ZXJtaW5hbHMgKEtpdHR5LCBpVGVybTIsIEdob3N0dHksIFdlelRlcm0sIFdhcnApLlxuXG5gYGB0eXBlc2NyaXB0XG5jb25zdCBpbWFnZSA9IG5ldyBJbWFnZShcbiAgYmFzZTY0RGF0YSwgICAvLyBiYXNlNjQtZW5jb2RlZCBpbWFnZVxuICBcImltYWdlL3BuZ1wiLCAgLy8gTUlNRSB0eXBlXG4gIHRoZW1lLCAgICAgICAgLy8gSW1hZ2VUaGVtZVxuICB7IG1heFdpZHRoQ2VsbHM6IDgwLCBtYXhIZWlnaHRDZWxsczogMjQgfVxuKTtcbmBgYFxuXG4jIyBLZXlib2FyZCBJbnB1dFxuXG5Vc2UgYG1hdGNoZXNLZXkoKWAgZm9yIGtleSBkZXRlY3Rpb246XG5cbmBgYHR5cGVzY3JpcHRcbmltcG9ydCB7IG1hdGNoZXNLZXksIEtleSB9IGZyb20gXCJAZWFyZW5kaWwtd29ya3MvcGktdHVpXCI7XG5cbmhhbmRsZUlucHV0KGRhdGE6IHN0cmluZykge1xuICBpZiAobWF0Y2hlc0tleShkYXRhLCBLZXkudXApKSB7XG4gICAgdGhpcy5zZWxlY3RlZEluZGV4LS07XG4gIH0gZWxzZSBpZiAobWF0Y2hlc0tleShkYXRhLCBLZXkuZW50ZXIpKSB7XG4gICAgdGhpcy5vblNlbGVjdD8uKHRoaXMuc2VsZWN0ZWRJbmRleCk7XG4gIH0gZWxzZSBpZiAobWF0Y2hlc0tleShkYXRhLCBLZXkuZXNjYXBlKSkge1xuICAgIHRoaXMub25DYW5jZWw/LigpO1xuICB9IGVsc2UgaWYgKG1hdGNoZXNLZXkoZGF0YSwgS2V5LmN0cmwoXCJjXCIpKSkge1xuICAgIC8vIEN0cmwrQ1xuICB9XG59XG5gYGBcblxuKipLZXkgaWRlbnRpZmllcnMqKiAodXNlIGBLZXkuKmAgZm9yIGF1dG9jb21wbGV0ZSwgb3Igc3RyaW5nIGxpdGVyYWxzKTpcbi0gQmFzaWMga2V5czogYEtleS5lbnRlcmAsIGBLZXkuZXNjYXBlYCwgYEtleS50YWJgLCBgS2V5LnNwYWNlYCwgYEtleS5iYWNrc3BhY2VgLCBgS2V5LmRlbGV0ZWAsIGBLZXkuaG9tZWAsIGBLZXkuZW5kYFxuLSBBcnJvdyBrZXlzOiBgS2V5LnVwYCwgYEtleS5kb3duYCwgYEtleS5sZWZ0YCwgYEtleS5yaWdodGBcbi0gV2l0aCBtb2RpZmllcnM6IGBLZXkuY3RybChcImNcIilgLCBgS2V5LnNoaWZ0KFwidGFiXCIpYCwgYEtleS5hbHQoXCJsZWZ0XCIpYCwgYEtleS5jdHJsU2hpZnQoXCJwXCIpYFxuLSBTdHJpbmcgZm9ybWF0IGFsc28gd29ya3M6IGBcImVudGVyXCJgLCBgXCJjdHJsK2NcImAsIGBcInNoaWZ0K3RhYlwiYCwgYFwiY3RybCtzaGlmdCtwXCJgXG5cbiMjIExpbmUgV2lkdGhcblxuKipDcml0aWNhbDoqKiBFYWNoIGxpbmUgZnJvbSBgcmVuZGVyKClgIG11c3Qgbm90IGV4Y2VlZCB0aGUgYHdpZHRoYCBwYXJhbWV0ZXIuXG5cbmBgYHR5cGVzY3JpcHRcbmltcG9ydCB7IHZpc2libGVXaWR0aCwgdHJ1bmNhdGVUb1dpZHRoIH0gZnJvbSBcIkBlYXJlbmRpbC13b3Jrcy9waS10dWlcIjtcblxucmVuZGVyKHdpZHRoOiBudW1iZXIpOiBzdHJpbmdbXSB7XG4gIC8vIFRydW5jYXRlIGxvbmcgbGluZXNcbiAgcmV0dXJuIFt0cnVuY2F0ZVRvV2lkdGgodGhpcy50ZXh0LCB3aWR0aCldO1xufVxuYGBgXG5cblV0aWxpdGllczpcbi0gYHZpc2libGVXaWR0aChzdHIpYCAtIEdldCBkaXNwbGF5IHdpZHRoIChpZ25vcmVzIEFOU0kgY29kZXMpXG4tIGB0cnVuY2F0ZVRvV2lkdGgoc3RyLCB3aWR0aCwgZWxsaXBzaXM/KWAgLSBUcnVuY2F0ZSB3aXRoIG9wdGlvbmFsIGVsbGlwc2lzXG4tIGB3cmFwVGV4dFdpdGhBbnNpKHN0ciwgd2lkdGgpYCAtIFdvcmQgd3JhcCBwcmVzZXJ2aW5nIEFOU0kgY29kZXNcblxuIyMgQ3JlYXRpbmcgQ3VzdG9tIENvbXBvbmVudHNcblxuRXhhbXBsZTogSW50ZXJhY3RpdmUgc2VsZWN0b3JcblxuYGBgdHlwZXNjcmlwdFxuaW1wb3J0IHtcbiAgbWF0Y2hlc0tleSwgS2V5LFxuICB0cnVuY2F0ZVRvV2lkdGgsIHZpc2libGVXaWR0aFxufSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLXR1aVwiO1xuXG5jbGFzcyBNeVNlbGVjdG9yIHtcbiAgcHJpdmF0ZSBpdGVtczogc3RyaW5nW107XG4gIHByaXZhdGUgc2VsZWN0ZWQgPSAwO1xuICBwcml2YXRlIGNhY2hlZFdpZHRoPzogbnVtYmVyO1xuICBwcml2YXRlIGNhY2hlZExpbmVzPzogc3RyaW5nW107XG4gIFxuICBwdWJsaWMgb25TZWxlY3Q/OiAoaXRlbTogc3RyaW5nKSA9PiB2b2lkO1xuICBwdWJsaWMgb25DYW5jZWw/OiAoKSA9PiB2b2lkO1xuXG4gIGNvbnN0cnVjdG9yKGl0ZW1zOiBzdHJpbmdbXSkge1xuICAgIHRoaXMuaXRlbXMgPSBpdGVtcztcbiAgfVxuXG4gIGhhbmRsZUlucHV0KGRhdGE6IHN0cmluZyk6IHZvaWQge1xuICAgIGlmIChtYXRjaGVzS2V5KGRhdGEsIEtleS51cCkgJiYgdGhpcy5zZWxlY3RlZCA+IDApIHtcbiAgICAgIHRoaXMuc2VsZWN0ZWQtLTtcbiAgICAgIHRoaXMuaW52YWxpZGF0ZSgpO1xuICAgIH0gZWxzZSBpZiAobWF0Y2hlc0tleShkYXRhLCBLZXkuZG93bikgJiYgdGhpcy5zZWxlY3RlZCA8IHRoaXMuaXRlbXMubGVuZ3RoIC0gMSkge1xuICAgICAgdGhpcy5zZWxlY3RlZCsrO1xuICAgICAgdGhpcy5pbnZhbGlkYXRlKCk7XG4gICAgfSBlbHNlIGlmIChtYXRjaGVzS2V5KGRhdGEsIEtleS5lbnRlcikpIHtcbiAgICAgIHRoaXMub25TZWxlY3Q/Lih0aGlzLml0ZW1zW3RoaXMuc2VsZWN0ZWRdKTtcbiAgICB9IGVsc2UgaWYgKG1hdGNoZXNLZXkoZGF0YSwgS2V5LmVzY2FwZSkpIHtcbiAgICAgIHRoaXMub25DYW5jZWw/LigpO1xuICAgIH1cbiAgfVxuXG4gIHJlbmRlcih3aWR0aDogbnVtYmVyKTogc3RyaW5nW10ge1xuICAgIGlmICh0aGlzLmNhY2hlZExpbmVzICYmIHRoaXMuY2FjaGVkV2lkdGggPT09IHdpZHRoKSB7XG4gICAgICByZXR1cm4gdGhpcy5jYWNoZWRMaW5lcztcbiAgICB9XG5cbiAgICB0aGlzLmNhY2hlZExpbmVzID0gdGhpcy5pdGVtcy5tYXAoKGl0ZW0sIGkpID0+IHtcbiAgICAgIGNvbnN0IHByZWZpeCA9IGkgPT09IHRoaXMuc2VsZWN0ZWQgPyBcIj4gXCIgOiBcIiAgXCI7XG4gICAgICByZXR1cm4gdHJ1bmNhdGVUb1dpZHRoKHByZWZpeCArIGl0ZW0sIHdpZHRoKTtcbiAgICB9KTtcbiAgICB0aGlzLmNhY2hlZFdpZHRoID0gd2lkdGg7XG4gICAgcmV0dXJuIHRoaXMuY2FjaGVkTGluZXM7XG4gIH1cblxuICBpbnZhbGlkYXRlKCk6IHZvaWQge1xuICAgIHRoaXMuY2FjaGVkV2lkdGggPSB1bmRlZmluZWQ7XG4gICAgdGhpcy5jYWNoZWRMaW5lcyA9IHVuZGVmaW5lZDtcbiAgfVxufVxuYGBgXG5cblVzYWdlIGluIGFuIGV4dGVuc2lvbjpcblxuYGBgdHlwZXNjcmlwdFxucGkucmVnaXN0ZXJDb21tYW5kKFwicGlja1wiLCB7XG4gIGRlc2NyaXB0aW9uOiBcIlBpY2sgYW4gaXRlbVwiLFxuICBoYW5kbGVyOiBhc3luYyAoYXJncywgY3R4KSA9PiB7XG4gICAgY29uc3QgaXRlbXMgPSBbXCJPcHRpb24gQVwiLCBcIk9wdGlvbiBCXCIsIFwiT3B0aW9uIENcIl07XG4gICAgY29uc3Qgc2VsZWN0b3IgPSBuZXcgTXlTZWxlY3RvcihpdGVtcyk7XG4gICAgXG4gICAgbGV0IGhhbmRsZTogeyBjbG9zZTogKCkgPT4gdm9pZDsgcmVxdWVzdFJlbmRlcjogKCkgPT4gdm9pZCB9O1xuICAgIFxuICAgIGF3YWl0IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlKSA9PiB7XG4gICAgICBzZWxlY3Rvci5vblNlbGVjdCA9IChpdGVtKSA9PiB7XG4gICAgICAgIGN0eC51aS5ub3RpZnkoYFNlbGVjdGVkOiAke2l0ZW19YCwgXCJpbmZvXCIpO1xuICAgICAgICBoYW5kbGUuY2xvc2UoKTtcbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgfTtcbiAgICAgIHNlbGVjdG9yLm9uQ2FuY2VsID0gKCkgPT4ge1xuICAgICAgICBoYW5kbGUuY2xvc2UoKTtcbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgfTtcbiAgICAgIGhhbmRsZSA9IGN0eC51aS5jdXN0b20oc2VsZWN0b3IpO1xuICAgIH0pO1xuICB9XG59KTtcbmBgYFxuXG4jIyBUaGVtaW5nXG5cbkNvbXBvbmVudHMgYWNjZXB0IHRoZW1lIG9iamVjdHMgZm9yIHN0eWxpbmcuXG5cbioqSW4gYHJlbmRlckNhbGxgL2ByZW5kZXJSZXN1bHRgKiosIHVzZSB0aGUgYHRoZW1lYCBwYXJhbWV0ZXI6XG5cbmBgYHR5cGVzY3JpcHRcbnJlbmRlclJlc3VsdChyZXN1bHQsIG9wdGlvbnMsIHRoZW1lLCBjb250ZXh0KSB7XG4gIC8vIFVzZSB0aGVtZS5mZygpIGZvciBmb3JlZ3JvdW5kIGNvbG9yc1xuICByZXR1cm4gbmV3IFRleHQodGhlbWUuZmcoXCJzdWNjZXNzXCIsIFwiRG9uZSFcIiksIDAsIDApO1xuICBcbiAgLy8gVXNlIHRoZW1lLmJnKCkgZm9yIGJhY2tncm91bmQgY29sb3JzXG4gIGNvbnN0IHN0eWxlZCA9IHRoZW1lLmJnKFwidG9vbFBlbmRpbmdCZ1wiLCB0aGVtZS5mZyhcImFjY2VudFwiLCBcInRleHRcIikpO1xufVxuYGBgXG5cbioqRm9yZWdyb3VuZCBjb2xvcnMqKiAoYHRoZW1lLmZnKGNvbG9yLCB0ZXh0KWApOlxuXG58IENhdGVnb3J5IHwgQ29sb3JzIHxcbnwtLS0tLS0tLS0tfC0tLS0tLS0tfFxufCBHZW5lcmFsIHwgYHRleHRgLCBgYWNjZW50YCwgYG11dGVkYCwgYGRpbWAgfFxufCBTdGF0dXMgfCBgc3VjY2Vzc2AsIGBlcnJvcmAsIGB3YXJuaW5nYCB8XG58IEJvcmRlcnMgfCBgYm9yZGVyYCwgYGJvcmRlckFjY2VudGAsIGBib3JkZXJNdXRlZGAgfFxufCBNZXNzYWdlcyB8IGB1c2VyTWVzc2FnZVRleHRgLCBgY3VzdG9tTWVzc2FnZVRleHRgLCBgY3VzdG9tTWVzc2FnZUxhYmVsYCB8XG58IFRvb2xzIHwgYHRvb2xUaXRsZWAsIGB0b29sT3V0cHV0YCB8XG58IERpZmZzIHwgYHRvb2xEaWZmQWRkZWRgLCBgdG9vbERpZmZSZW1vdmVkYCwgYHRvb2xEaWZmQ29udGV4dGAgfFxufCBNYXJrZG93biB8IGBtZEhlYWRpbmdgLCBgbWRMaW5rYCwgYG1kTGlua1VybGAsIGBtZENvZGVgLCBgbWRDb2RlQmxvY2tgLCBgbWRDb2RlQmxvY2tCb3JkZXJgLCBgbWRRdW90ZWAsIGBtZFF1b3RlQm9yZGVyYCwgYG1kSHJgLCBgbWRMaXN0QnVsbGV0YCB8XG58IFN5bnRheCB8IGBzeW50YXhDb21tZW50YCwgYHN5bnRheEtleXdvcmRgLCBgc3ludGF4RnVuY3Rpb25gLCBgc3ludGF4VmFyaWFibGVgLCBgc3ludGF4U3RyaW5nYCwgYHN5bnRheE51bWJlcmAsIGBzeW50YXhUeXBlYCwgYHN5bnRheE9wZXJhdG9yYCwgYHN5bnRheFB1bmN0dWF0aW9uYCB8XG58IFRoaW5raW5nIHwgYHRoaW5raW5nT2ZmYCwgYHRoaW5raW5nTWluaW1hbGAsIGB0aGlua2luZ0xvd2AsIGB0aGlua2luZ01lZGl1bWAsIGB0aGlua2luZ0hpZ2hgLCBgdGhpbmtpbmdYaGlnaGAgfFxufCBNb2RlcyB8IGBiYXNoTW9kZWAgfFxuXG4qKkJhY2tncm91bmQgY29sb3JzKiogKGB0aGVtZS5iZyhjb2xvciwgdGV4dClgKTpcblxuYHNlbGVjdGVkQmdgLCBgdXNlck1lc3NhZ2VCZ2AsIGBjdXN0b21NZXNzYWdlQmdgLCBgdG9vbFBlbmRpbmdCZ2AsIGB0b29sU3VjY2Vzc0JnYCwgYHRvb2xFcnJvckJnYFxuXG4qKkZvciBNYXJrZG93bioqLCB1c2UgYGdldE1hcmtkb3duVGhlbWUoKWA6XG5cbmBgYHR5cGVzY3JpcHRcbmltcG9ydCB7IGdldE1hcmtkb3duVGhlbWUgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudFwiO1xuaW1wb3J0IHsgTWFya2Rvd24gfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLXR1aVwiO1xuXG5yZW5kZXJSZXN1bHQocmVzdWx0LCBvcHRpb25zLCB0aGVtZSwgY29udGV4dCkge1xuICBjb25zdCBtZFRoZW1lID0gZ2V0TWFya2Rvd25UaGVtZSgpO1xuICByZXR1cm4gbmV3IE1hcmtkb3duKHJlc3VsdC5kZXRhaWxzLm1hcmtkb3duLCAwLCAwLCBtZFRoZW1lKTtcbn1cbmBgYFxuXG4qKkZvciBjdXN0b20gY29tcG9uZW50cyoqLCBkZWZpbmUgeW91ciBvd24gdGhlbWUgaW50ZXJmYWNlOlxuXG5gYGB0eXBlc2NyaXB0XG5pbnRlcmZhY2UgTXlUaGVtZSB7XG4gIHNlbGVjdGVkOiAoczogc3RyaW5nKSA9PiBzdHJpbmc7XG4gIG5vcm1hbDogKHM6IHN0cmluZykgPT4gc3RyaW5nO1xufVxuYGBgXG5cbiMjIERlYnVnIGxvZ2dpbmdcblxuU2V0IGBQSV9UVUlfV1JJVEVfTE9HYCB0byBjYXB0dXJlIHRoZSByYXcgQU5TSSBzdHJlYW0gd3JpdHRlbiB0byBzdGRvdXQuXG5cbmBgYGJhc2hcblBJX1RVSV9XUklURV9MT0c9L3RtcC90dWktYW5zaS5sb2cgbnB4IHRzeCBwYWNrYWdlcy90dWkvdGVzdC9jaGF0LXNpbXBsZS50c1xuYGBgXG5cbiMjIFBlcmZvcm1hbmNlXG5cbkNhY2hlIHJlbmRlcmVkIG91dHB1dCB3aGVuIHBvc3NpYmxlOlxuXG5gYGB0eXBlc2NyaXB0XG5jbGFzcyBDYWNoZWRDb21wb25lbnQge1xuICBwcml2YXRlIGNhY2hlZFdpZHRoPzogbnVtYmVyO1xuICBwcml2YXRlIGNhY2hlZExpbmVzPzogc3RyaW5nW107XG5cbiAgcmVuZGVyKHdpZHRoOiBudW1iZXIpOiBzdHJpbmdbXSB7XG4gICAgaWYgKHRoaXMuY2FjaGVkTGluZXMgJiYgdGhpcy5jYWNoZWRXaWR0aCA9PT0gd2lkdGgpIHtcbiAgICAgIHJldHVybiB0aGlzLmNhY2hlZExpbmVzO1xuICAgIH1cbiAgICAvLyAuLi4gY29tcHV0ZSBsaW5lcyAuLi5cbiAgICB0aGlzLmNhY2hlZFdpZHRoID0gd2lkdGg7XG4gICAgdGhpcy5jYWNoZWRMaW5lcyA9IGxpbmVzO1xuICAgIHJldHVybiBsaW5lcztcbiAgfVxuXG4gIGludmFsaWRhdGUoKTogdm9pZCB7XG4gICAgdGhpcy5jYWNoZWRXaWR0aCA9IHVuZGVmaW5lZDtcbiAgICB0aGlzLmNhY2hlZExpbmVzID0gdW5kZWZpbmVkO1xuICB9XG59XG5gYGBcblxuQ2FsbCBgaW52YWxpZGF0ZSgpYCB3aGVuIHN0YXRlIGNoYW5nZXMsIHRoZW4gYGhhbmRsZS5yZXF1ZXN0UmVuZGVyKClgIHRvIHRyaWdnZXIgcmUtcmVuZGVyLlxuXG4jIyBJbnZhbGlkYXRpb24gYW5kIFRoZW1lIENoYW5nZXNcblxuV2hlbiB0aGUgdGhlbWUgY2hhbmdlcywgdGhlIFRVSSBjYWxscyBgaW52YWxpZGF0ZSgpYCBvbiBhbGwgY29tcG9uZW50cyB0byBjbGVhciB0aGVpciBjYWNoZXMuIENvbXBvbmVudHMgbXVzdCBwcm9wZXJseSBpbXBsZW1lbnQgYGludmFsaWRhdGUoKWAgdG8gZW5zdXJlIHRoZW1lIGNoYW5nZXMgdGFrZSBlZmZlY3QuXG5cbiMjIyBUaGUgUHJvYmxlbVxuXG5JZiBhIGNvbXBvbmVudCBwcmUtYmFrZXMgdGhlbWUgY29sb3JzIGludG8gc3RyaW5ncyAodmlhIGB0aGVtZS5mZygpYCwgYHRoZW1lLmJnKClgLCBldGMuKSBhbmQgY2FjaGVzIHRoZW0sIHRoZSBjYWNoZWQgc3RyaW5ncyBjb250YWluIEFOU0kgZXNjYXBlIGNvZGVzIGZyb20gdGhlIG9sZCB0aGVtZS4gU2ltcGx5IGNsZWFyaW5nIHRoZSByZW5kZXIgY2FjaGUgaXNuJ3QgZW5vdWdoIGlmIHRoZSBjb21wb25lbnQgc3RvcmVzIHRoZSB0aGVtZWQgY29udGVudCBzZXBhcmF0ZWx5LlxuXG4qKldyb25nIGFwcHJvYWNoKiogKHRoZW1lIGNvbG9ycyB3b24ndCB1cGRhdGUpOlxuXG5gYGB0eXBlc2NyaXB0XG5jbGFzcyBCYWRDb21wb25lbnQgZXh0ZW5kcyBDb250YWluZXIge1xuICBwcml2YXRlIGNvbnRlbnQ6IFRleHQ7XG5cbiAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nLCB0aGVtZTogVGhlbWUpIHtcbiAgICBzdXBlcigpO1xuICAgIC8vIFByZS1iYWtlZCB0aGVtZSBjb2xvcnMgc3RvcmVkIGluIFRleHQgY29tcG9uZW50XG4gICAgdGhpcy5jb250ZW50ID0gbmV3IFRleHQodGhlbWUuZmcoXCJhY2NlbnRcIiwgbWVzc2FnZSksIDEsIDApO1xuICAgIHRoaXMuYWRkQ2hpbGQodGhpcy5jb250ZW50KTtcbiAgfVxuICAvLyBObyBpbnZhbGlkYXRlIG92ZXJyaWRlIC0gcGFyZW50J3MgaW52YWxpZGF0ZSBvbmx5IGNsZWFyc1xuICAvLyBjaGlsZCByZW5kZXIgY2FjaGVzLCBub3QgdGhlIHByZS1iYWtlZCBjb250ZW50XG59XG5gYGBcblxuIyMjIFRoZSBTb2x1dGlvblxuXG5Db21wb25lbnRzIHRoYXQgYnVpbGQgY29udGVudCB3aXRoIHRoZW1lIGNvbG9ycyBtdXN0IHJlYnVpbGQgdGhhdCBjb250ZW50IHdoZW4gYGludmFsaWRhdGUoKWAgaXMgY2FsbGVkOlxuXG5gYGB0eXBlc2NyaXB0XG5jbGFzcyBHb29kQ29tcG9uZW50IGV4dGVuZHMgQ29udGFpbmVyIHtcbiAgcHJpdmF0ZSBtZXNzYWdlOiBzdHJpbmc7XG4gIHByaXZhdGUgY29udGVudDogVGV4dDtcblxuICBjb25zdHJ1Y3RvcihtZXNzYWdlOiBzdHJpbmcpIHtcbiAgICBzdXBlcigpO1xuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XG4gICAgdGhpcy5jb250ZW50ID0gbmV3IFRleHQoXCJcIiwgMSwgMCk7XG4gICAgdGhpcy5hZGRDaGlsZCh0aGlzLmNvbnRlbnQpO1xuICAgIHRoaXMudXBkYXRlRGlzcGxheSgpO1xuICB9XG5cbiAgcHJpdmF0ZSB1cGRhdGVEaXNwbGF5KCk6IHZvaWQge1xuICAgIC8vIFJlYnVpbGQgY29udGVudCB3aXRoIGN1cnJlbnQgdGhlbWVcbiAgICB0aGlzLmNvbnRlbnQuc2V0VGV4dCh0aGVtZS5mZyhcImFjY2VudFwiLCB0aGlzLm1lc3NhZ2UpKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGludmFsaWRhdGUoKTogdm9pZCB7XG4gICAgc3VwZXIuaW52YWxpZGF0ZSgpOyAgLy8gQ2xlYXIgY2hpbGQgY2FjaGVzXG4gICAgdGhpcy51cGRhdGVEaXNwbGF5KCk7IC8vIFJlYnVpbGQgd2l0aCBuZXcgdGhlbWVcbiAgfVxufVxuYGBgXG5cbiMjIyBQYXR0ZXJuOiBSZWJ1aWxkIG9uIEludmFsaWRhdGVcblxuRm9yIGNvbXBvbmVudHMgd2l0aCBjb21wbGV4IGNvbnRlbnQ6XG5cbmBgYHR5cGVzY3JpcHRcbmNsYXNzIENvbXBsZXhDb21wb25lbnQgZXh0ZW5kcyBDb250YWluZXIge1xuICBwcml2YXRlIGRhdGE6IFNvbWVEYXRhO1xuXG4gIGNvbnN0cnVjdG9yKGRhdGE6IFNvbWVEYXRhKSB7XG4gICAgc3VwZXIoKTtcbiAgICB0aGlzLmRhdGEgPSBkYXRhO1xuICAgIHRoaXMucmVidWlsZCgpO1xuICB9XG5cbiAgcHJpdmF0ZSByZWJ1aWxkKCk6IHZvaWQge1xuICAgIHRoaXMuY2xlYXIoKTsgIC8vIFJlbW92ZSBhbGwgY2hpbGRyZW5cblxuICAgIC8vIEJ1aWxkIFVJIHdpdGggY3VycmVudCB0aGVtZVxuICAgIHRoaXMuYWRkQ2hpbGQobmV3IFRleHQodGhlbWUuZmcoXCJhY2NlbnRcIiwgdGhlbWUuYm9sZChcIlRpdGxlXCIpKSwgMSwgMCkpO1xuICAgIHRoaXMuYWRkQ2hpbGQobmV3IFNwYWNlcigxKSk7XG5cbiAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgdGhpcy5kYXRhLml0ZW1zKSB7XG4gICAgICBjb25zdCBjb2xvciA9IGl0ZW0uYWN0aXZlID8gXCJzdWNjZXNzXCIgOiBcIm11dGVkXCI7XG4gICAgICB0aGlzLmFkZENoaWxkKG5ldyBUZXh0KHRoZW1lLmZnKGNvbG9yLCBpdGVtLmxhYmVsKSwgMSwgMCkpO1xuICAgIH1cbiAgfVxuXG4gIG92ZXJyaWRlIGludmFsaWRhdGUoKTogdm9pZCB7XG4gICAgc3VwZXIuaW52YWxpZGF0ZSgpO1xuICAgIHRoaXMucmVidWlsZCgpO1xuICB9XG59XG5gYGBcblxuIyMjIFdoZW4gVGhpcyBNYXR0ZXJzXG5cblRoaXMgcGF0dGVybiBpcyBuZWVkZWQgd2hlbjpcblxuMS4gKipQcmUtYmFraW5nIHRoZW1lIGNvbG9ycyoqIC0gVXNpbmcgYHRoZW1lLmZnKClgIG9yIGB0aGVtZS5iZygpYCB0byBjcmVhdGUgc3R5bGVkIHN0cmluZ3Mgc3RvcmVkIGluIGNoaWxkIGNvbXBvbmVudHNcbjIuICoqU3ludGF4IGhpZ2hsaWdodGluZyoqIC0gVXNpbmcgYGhpZ2hsaWdodENvZGUoKWAgd2hpY2ggYXBwbGllcyB0aGVtZS1iYXNlZCBzeW50YXggY29sb3JzXG4zLiAqKkNvbXBsZXggbGF5b3V0cyoqIC0gQnVpbGRpbmcgY2hpbGQgY29tcG9uZW50IHRyZWVzIHRoYXQgZW1iZWQgdGhlbWUgY29sb3JzXG5cblRoaXMgcGF0dGVybiBpcyBOT1QgbmVlZGVkIHdoZW46XG5cbjEuICoqVXNpbmcgdGhlbWUgY2FsbGJhY2tzKiogLSBQYXNzaW5nIGZ1bmN0aW9ucyBsaWtlIGAodGV4dCkgPT4gdGhlbWUuZmcoXCJhY2NlbnRcIiwgdGV4dClgIHRoYXQgYXJlIGNhbGxlZCBkdXJpbmcgcmVuZGVyXG4yLiAqKlNpbXBsZSBjb250YWluZXJzKiogLSBKdXN0IGdyb3VwaW5nIG90aGVyIGNvbXBvbmVudHMgd2l0aG91dCBhZGRpbmcgdGhlbWVkIGNvbnRlbnRcbjMuICoqU3RhdGVsZXNzIHJlbmRlcioqIC0gQ29tcHV0aW5nIHRoZW1lZCBvdXRwdXQgZnJlc2ggaW4gZXZlcnkgYHJlbmRlcigpYCBjYWxsIChubyBjYWNoaW5nKVxuXG4jIyBDb21tb24gUGF0dGVybnNcblxuVGhlc2UgcGF0dGVybnMgY292ZXIgdGhlIG1vc3QgY29tbW9uIFVJIG5lZWRzIGluIGV4dGVuc2lvbnMuICoqQ29weSB0aGVzZSBwYXR0ZXJucyBpbnN0ZWFkIG9mIGJ1aWxkaW5nIGZyb20gc2NyYXRjaC4qKlxuXG4jIyMgUGF0dGVybiAxOiBTZWxlY3Rpb24gRGlhbG9nIChTZWxlY3RMaXN0KVxuXG5Gb3IgbGV0dGluZyB1c2VycyBwaWNrIGZyb20gYSBsaXN0IG9mIG9wdGlvbnMuIFVzZSBgU2VsZWN0TGlzdGAgZnJvbSBgQGVhcmVuZGlsLXdvcmtzL3BpLXR1aWAgd2l0aCBgRHluYW1pY0JvcmRlcmAgZm9yIGZyYW1pbmcuXG5cbmBgYHR5cGVzY3JpcHRcbmltcG9ydCB0eXBlIHsgRXh0ZW5zaW9uQVBJIH0gZnJvbSBcIkBlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnRcIjtcbmltcG9ydCB7IER5bmFtaWNCb3JkZXIgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudFwiO1xuaW1wb3J0IHsgQ29udGFpbmVyLCB0eXBlIFNlbGVjdEl0ZW0sIFNlbGVjdExpc3QsIFRleHQgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLXR1aVwiO1xuXG5waS5yZWdpc3RlckNvbW1hbmQoXCJwaWNrXCIsIHtcbiAgaGFuZGxlcjogYXN5bmMgKF9hcmdzLCBjdHgpID0+IHtcbiAgICBjb25zdCBpdGVtczogU2VsZWN0SXRlbVtdID0gW1xuICAgICAgeyB2YWx1ZTogXCJvcHQxXCIsIGxhYmVsOiBcIk9wdGlvbiAxXCIsIGRlc2NyaXB0aW9uOiBcIkZpcnN0IG9wdGlvblwiIH0sXG4gICAgICB7IHZhbHVlOiBcIm9wdDJcIiwgbGFiZWw6IFwiT3B0aW9uIDJcIiwgZGVzY3JpcHRpb246IFwiU2Vjb25kIG9wdGlvblwiIH0sXG4gICAgICB7IHZhbHVlOiBcIm9wdDNcIiwgbGFiZWw6IFwiT3B0aW9uIDNcIiB9LCAgLy8gZGVzY3JpcHRpb24gaXMgb3B0aW9uYWxcbiAgICBdO1xuXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY3R4LnVpLmN1c3RvbTxzdHJpbmcgfCBudWxsPigodHVpLCB0aGVtZSwgX2tiLCBkb25lKSA9PiB7XG4gICAgICBjb25zdCBjb250YWluZXIgPSBuZXcgQ29udGFpbmVyKCk7XG5cbiAgICAgIC8vIFRvcCBib3JkZXJcbiAgICAgIGNvbnRhaW5lci5hZGRDaGlsZChuZXcgRHluYW1pY0JvcmRlcigoczogc3RyaW5nKSA9PiB0aGVtZS5mZyhcImFjY2VudFwiLCBzKSkpO1xuXG4gICAgICAvLyBUaXRsZVxuICAgICAgY29udGFpbmVyLmFkZENoaWxkKG5ldyBUZXh0KHRoZW1lLmZnKFwiYWNjZW50XCIsIHRoZW1lLmJvbGQoXCJQaWNrIGFuIE9wdGlvblwiKSksIDEsIDApKTtcblxuICAgICAgLy8gU2VsZWN0TGlzdCB3aXRoIHRoZW1lXG4gICAgICBjb25zdCBzZWxlY3RMaXN0ID0gbmV3IFNlbGVjdExpc3QoaXRlbXMsIE1hdGgubWluKGl0ZW1zLmxlbmd0aCwgMTApLCB7XG4gICAgICAgIHNlbGVjdGVkUHJlZml4OiAodCkgPT4gdGhlbWUuZmcoXCJhY2NlbnRcIiwgdCksXG4gICAgICAgIHNlbGVjdGVkVGV4dDogKHQpID0+IHRoZW1lLmZnKFwiYWNjZW50XCIsIHQpLFxuICAgICAgICBkZXNjcmlwdGlvbjogKHQpID0+IHRoZW1lLmZnKFwibXV0ZWRcIiwgdCksXG4gICAgICAgIHNjcm9sbEluZm86ICh0KSA9PiB0aGVtZS5mZyhcImRpbVwiLCB0KSxcbiAgICAgICAgbm9NYXRjaDogKHQpID0+IHRoZW1lLmZnKFwid2FybmluZ1wiLCB0KSxcbiAgICAgIH0pO1xuICAgICAgc2VsZWN0TGlzdC5vblNlbGVjdCA9IChpdGVtKSA9PiBkb25lKGl0ZW0udmFsdWUpO1xuICAgICAgc2VsZWN0TGlzdC5vbkNhbmNlbCA9ICgpID0+IGRvbmUobnVsbCk7XG4gICAgICBjb250YWluZXIuYWRkQ2hpbGQoc2VsZWN0TGlzdCk7XG5cbiAgICAgIC8vIEhlbHAgdGV4dFxuICAgICAgY29udGFpbmVyLmFkZENoaWxkKG5ldyBUZXh0KHRoZW1lLmZnKFwiZGltXCIsIFwi4oaR4oaTIG5hdmlnYXRlIOKAoiBlbnRlciBzZWxlY3Qg4oCiIGVzYyBjYW5jZWxcIiksIDEsIDApKTtcblxuICAgICAgLy8gQm90dG9tIGJvcmRlclxuICAgICAgY29udGFpbmVyLmFkZENoaWxkKG5ldyBEeW5hbWljQm9yZGVyKChzOiBzdHJpbmcpID0+IHRoZW1lLmZnKFwiYWNjZW50XCIsIHMpKSk7XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIHJlbmRlcjogKHcpID0+IGNvbnRhaW5lci5yZW5kZXIodyksXG4gICAgICAgIGludmFsaWRhdGU6ICgpID0+IGNvbnRhaW5lci5pbnZhbGlkYXRlKCksXG4gICAgICAgIGhhbmRsZUlucHV0OiAoZGF0YSkgPT4geyBzZWxlY3RMaXN0LmhhbmRsZUlucHV0KGRhdGEpOyB0dWkucmVxdWVzdFJlbmRlcigpOyB9LFxuICAgICAgfTtcbiAgICB9KTtcblxuICAgIGlmIChyZXN1bHQpIHtcbiAgICAgIGN0eC51aS5ub3RpZnkoYFNlbGVjdGVkOiAke3Jlc3VsdH1gLCBcImluZm9cIik7XG4gICAgfVxuICB9LFxufSk7XG5gYGBcblxuKipFeGFtcGxlczoqKiBbcHJlc2V0LnRzXSguLi9leGFtcGxlcy9leHRlbnNpb25zL3ByZXNldC50cyksIFt0b29scy50c10oLi4vZXhhbXBsZXMvZXh0ZW5zaW9ucy90b29scy50cylcblxuIyMjIFBhdHRlcm4gMjogQXN5bmMgT3BlcmF0aW9uIHdpdGggQ2FuY2VsIChCb3JkZXJlZExvYWRlcilcblxuRm9yIG9wZXJhdGlvbnMgdGhhdCB0YWtlIHRpbWUgYW5kIHNob3VsZCBiZSBjYW5jZWxsYWJsZS4gYEJvcmRlcmVkTG9hZGVyYCBzaG93cyBhIHNwaW5uZXIgYW5kIGhhbmRsZXMgZXNjYXBlIHRvIGNhbmNlbC5cblxuYGBgdHlwZXNjcmlwdFxuaW1wb3J0IHsgQm9yZGVyZWRMb2FkZXIgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudFwiO1xuXG5waS5yZWdpc3RlckNvbW1hbmQoXCJmZXRjaFwiLCB7XG4gIGhhbmRsZXI6IGFzeW5jIChfYXJncywgY3R4KSA9PiB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY3R4LnVpLmN1c3RvbTxzdHJpbmcgfCBudWxsPigodHVpLCB0aGVtZSwgX2tiLCBkb25lKSA9PiB7XG4gICAgICBjb25zdCBsb2FkZXIgPSBuZXcgQm9yZGVyZWRMb2FkZXIodHVpLCB0aGVtZSwgXCJGZXRjaGluZyBkYXRhLi4uXCIpO1xuICAgICAgbG9hZGVyLm9uQWJvcnQgPSAoKSA9PiBkb25lKG51bGwpO1xuXG4gICAgICAvLyBEbyBhc3luYyB3b3JrXG4gICAgICBmZXRjaERhdGEobG9hZGVyLnNpZ25hbClcbiAgICAgICAgLnRoZW4oKGRhdGEpID0+IGRvbmUoZGF0YSkpXG4gICAgICAgIC5jYXRjaCgoKSA9PiBkb25lKG51bGwpKTtcblxuICAgICAgcmV0dXJuIGxvYWRlcjtcbiAgICB9KTtcblxuICAgIGlmIChyZXN1bHQgPT09IG51bGwpIHtcbiAgICAgIGN0eC51aS5ub3RpZnkoXCJDYW5jZWxsZWRcIiwgXCJpbmZvXCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjdHgudWkuc2V0RWRpdG9yVGV4dChyZXN1bHQpO1xuICAgIH1cbiAgfSxcbn0pO1xuYGBgXG5cbioqRXhhbXBsZXM6KiogW3FuYS50c10oLi4vZXhhbXBsZXMvZXh0ZW5zaW9ucy9xbmEudHMpLCBbaGFuZG9mZi50c10oLi4vZXhhbXBsZXMvZXh0ZW5zaW9ucy9oYW5kb2ZmLnRzKVxuXG4jIyMgUGF0dGVybiAzOiBTZXR0aW5ncy9Ub2dnbGVzIChTZXR0aW5nc0xpc3QpXG5cbkZvciB0b2dnbGluZyBtdWx0aXBsZSBzZXR0aW5ncy4gVXNlIGBTZXR0aW5nc0xpc3RgIGZyb20gYEBlYXJlbmRpbC13b3Jrcy9waS10dWlgIHdpdGggYGdldFNldHRpbmdzTGlzdFRoZW1lKClgLlxuXG5gYGB0eXBlc2NyaXB0XG5pbXBvcnQgeyBnZXRTZXR0aW5nc0xpc3RUaGVtZSB9IGZyb20gXCJAZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50XCI7XG5pbXBvcnQgeyBDb250YWluZXIsIHR5cGUgU2V0dGluZ0l0ZW0sIFNldHRpbmdzTGlzdCwgVGV4dCB9IGZyb20gXCJAZWFyZW5kaWwtd29ya3MvcGktdHVpXCI7XG5cbnBpLnJlZ2lzdGVyQ29tbWFuZChcInNldHRpbmdzXCIsIHtcbiAgaGFuZGxlcjogYXN5bmMgKF9hcmdzLCBjdHgpID0+IHtcbiAgICBjb25zdCBpdGVtczogU2V0dGluZ0l0ZW1bXSA9IFtcbiAgICAgIHsgaWQ6IFwidmVyYm9zZVwiLCBsYWJlbDogXCJWZXJib3NlIG1vZGVcIiwgY3VycmVudFZhbHVlOiBcIm9mZlwiLCB2YWx1ZXM6IFtcIm9uXCIsIFwib2ZmXCJdIH0sXG4gICAgICB7IGlkOiBcImNvbG9yXCIsIGxhYmVsOiBcIkNvbG9yIG91dHB1dFwiLCBjdXJyZW50VmFsdWU6IFwib25cIiwgdmFsdWVzOiBbXCJvblwiLCBcIm9mZlwiXSB9LFxuICAgIF07XG5cbiAgICBhd2FpdCBjdHgudWkuY3VzdG9tKChfdHVpLCB0aGVtZSwgX2tiLCBkb25lKSA9PiB7XG4gICAgICBjb25zdCBjb250YWluZXIgPSBuZXcgQ29udGFpbmVyKCk7XG4gICAgICBjb250YWluZXIuYWRkQ2hpbGQobmV3IFRleHQodGhlbWUuZmcoXCJhY2NlbnRcIiwgdGhlbWUuYm9sZChcIlNldHRpbmdzXCIpKSwgMSwgMSkpO1xuXG4gICAgICBjb25zdCBzZXR0aW5nc0xpc3QgPSBuZXcgU2V0dGluZ3NMaXN0KFxuICAgICAgICBpdGVtcyxcbiAgICAgICAgTWF0aC5taW4oaXRlbXMubGVuZ3RoICsgMiwgMTUpLFxuICAgICAgICBnZXRTZXR0aW5nc0xpc3RUaGVtZSgpLFxuICAgICAgICAoaWQsIG5ld1ZhbHVlKSA9PiB7XG4gICAgICAgICAgLy8gSGFuZGxlIHZhbHVlIGNoYW5nZVxuICAgICAgICAgIGN0eC51aS5ub3RpZnkoYCR7aWR9ID0gJHtuZXdWYWx1ZX1gLCBcImluZm9cIik7XG4gICAgICAgIH0sXG4gICAgICAgICgpID0+IGRvbmUodW5kZWZpbmVkKSwgIC8vIE9uIGNsb3NlXG4gICAgICAgIHsgZW5hYmxlU2VhcmNoOiB0cnVlIH0sIC8vIE9wdGlvbmFsOiBlbmFibGUgZnV6enkgc2VhcmNoIGJ5IGxhYmVsXG4gICAgICApO1xuICAgICAgY29udGFpbmVyLmFkZENoaWxkKHNldHRpbmdzTGlzdCk7XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIHJlbmRlcjogKHcpID0+IGNvbnRhaW5lci5yZW5kZXIodyksXG4gICAgICAgIGludmFsaWRhdGU6ICgpID0+IGNvbnRhaW5lci5pbnZhbGlkYXRlKCksXG4gICAgICAgIGhhbmRsZUlucHV0OiAoZGF0YSkgPT4gc2V0dGluZ3NMaXN0LmhhbmRsZUlucHV0Py4oZGF0YSksXG4gICAgICB9O1xuICAgIH0pO1xuICB9LFxufSk7XG5gYGBcblxuKipFeGFtcGxlczoqKiBbdG9vbHMudHNdKC4uL2V4YW1wbGVzL2V4dGVuc2lvbnMvdG9vbHMudHMpXG5cbiMjIyBQYXR0ZXJuIDQ6IFBlcnNpc3RlbnQgU3RhdHVzIEluZGljYXRvclxuXG5TaG93IHN0YXR1cyBpbiB0aGUgZm9vdGVyIHRoYXQgcGVyc2lzdHMgYWNyb3NzIHJlbmRlcnMuIEdvb2QgZm9yIG1vZGUgaW5kaWNhdG9ycy5cblxuYGBgdHlwZXNjcmlwdFxuLy8gU2V0IHN0YXR1cyAoc2hvd24gaW4gZm9vdGVyKVxuY3R4LnVpLnNldFN0YXR1cyhcIm15LWV4dFwiLCBjdHgudWkudGhlbWUuZmcoXCJhY2NlbnRcIiwgXCLil48gYWN0aXZlXCIpKTtcblxuLy8gQ2xlYXIgc3RhdHVzXG5jdHgudWkuc2V0U3RhdHVzKFwibXktZXh0XCIsIHVuZGVmaW5lZCk7XG5gYGBcblxuKipFeGFtcGxlczoqKiBbc3RhdHVzLWxpbmUudHNdKC4uL2V4YW1wbGVzL2V4dGVuc2lvbnMvc3RhdHVzLWxpbmUudHMpLCBbcGxhbi1tb2RlLnRzXSguLi9leGFtcGxlcy9leHRlbnNpb25zL3BsYW4tbW9kZS50cyksIFtwcmVzZXQudHNdKC4uL2V4YW1wbGVzL2V4dGVuc2lvbnMvcHJlc2V0LnRzKVxuXG4jIyMgUGF0dGVybiA0YjogV29ya2luZyBJbmRpY2F0b3IgQ3VzdG9taXphdGlvblxuXG5DdXN0b21pemUgdGhlIGlubGluZSB3b3JraW5nIGluZGljYXRvciBzaG93biB3aGlsZSBwaSBpcyBzdHJlYW1pbmcgYSByZXNwb25zZS5cblxuYGBgdHlwZXNjcmlwdFxuLy8gU3RhdGljIGluZGljYXRvclxuY3R4LnVpLnNldFdvcmtpbmdJbmRpY2F0b3IoeyBmcmFtZXM6IFtjdHgudWkudGhlbWUuZmcoXCJhY2NlbnRcIiwgXCLil49cIildIH0pO1xuXG4vLyBDdXN0b20gYW5pbWF0ZWQgaW5kaWNhdG9yXG5jdHgudWkuc2V0V29ya2luZ0luZGljYXRvcih7XG4gIGZyYW1lczogW1xuICAgIGN0eC51aS50aGVtZS5mZyhcImRpbVwiLCBcIsK3XCIpLFxuICAgIGN0eC51aS50aGVtZS5mZyhcIm11dGVkXCIsIFwi4oCiXCIpLFxuICAgIGN0eC51aS50aGVtZS5mZyhcImFjY2VudFwiLCBcIuKXj1wiKSxcbiAgICBjdHgudWkudGhlbWUuZmcoXCJtdXRlZFwiLCBcIuKAolwiKSxcbiAgXSxcbiAgaW50ZXJ2YWxNczogMTIwLFxufSk7XG5cbi8vIEhpZGUgdGhlIGluZGljYXRvciBlbnRpcmVseVxuY3R4LnVpLnNldFdvcmtpbmdJbmRpY2F0b3IoeyBmcmFtZXM6IFtdIH0pO1xuXG4vLyBSZXN0b3JlIHBpJ3MgZGVmYXVsdCBzcGlubmVyXG5jdHgudWkuc2V0V29ya2luZ0luZGljYXRvcigpO1xuYGBgXG5cblRoaXMgb25seSBhZmZlY3RzIHRoZSBub3JtYWwgc3RyZWFtaW5nIHdvcmtpbmcgaW5kaWNhdG9yLiBDb21wYWN0aW9uIGFuZCByZXRyeSBsb2FkZXJzIGtlZXAgdGhlaXIgYnVpbHQtaW4gc3R5bGluZy4gQ3VzdG9tIGZyYW1lcyBhcmUgcmVuZGVyZWQgdmVyYmF0aW0sIHNvIGV4dGVuc2lvbnMgbXVzdCBhZGQgdGhlaXIgb3duIGNvbG9ycyB3aGVuIG5lZWRlZC5cblxuKipFeGFtcGxlczoqKiBbd29ya2luZy1pbmRpY2F0b3IudHNdKC4uL2V4YW1wbGVzL2V4dGVuc2lvbnMvd29ya2luZy1pbmRpY2F0b3IudHMpXG5cbiMjIyBQYXR0ZXJuIDU6IFdpZGdldHMgQWJvdmUvQmVsb3cgRWRpdG9yXG5cblNob3cgcGVyc2lzdGVudCBjb250ZW50IGFib3ZlIG9yIGJlbG93IHRoZSBpbnB1dCBlZGl0b3IuIEdvb2QgZm9yIHRvZG8gbGlzdHMsIHByb2dyZXNzLlxuXG5gYGB0eXBlc2NyaXB0XG4vLyBTaW1wbGUgc3RyaW5nIGFycmF5IChhYm92ZSBlZGl0b3IgYnkgZGVmYXVsdClcbmN0eC51aS5zZXRXaWRnZXQoXCJteS13aWRnZXRcIiwgW1wiTGluZSAxXCIsIFwiTGluZSAyXCJdKTtcblxuLy8gUmVuZGVyIGJlbG93IHRoZSBlZGl0b3JcbmN0eC51aS5zZXRXaWRnZXQoXCJteS13aWRnZXRcIiwgW1wiTGluZSAxXCIsIFwiTGluZSAyXCJdLCB7IHBsYWNlbWVudDogXCJiZWxvd0VkaXRvclwiIH0pO1xuXG4vLyBPciB3aXRoIHRoZW1lXG5jdHgudWkuc2V0V2lkZ2V0KFwibXktd2lkZ2V0XCIsIChfdHVpLCB0aGVtZSkgPT4ge1xuICBjb25zdCBsaW5lcyA9IGl0ZW1zLm1hcCgoaXRlbSwgaSkgPT5cbiAgICBpdGVtLmRvbmVcbiAgICAgID8gdGhlbWUuZmcoXCJzdWNjZXNzXCIsIFwi4pyTIFwiKSArIHRoZW1lLmZnKFwibXV0ZWRcIiwgaXRlbS50ZXh0KVxuICAgICAgOiB0aGVtZS5mZyhcImRpbVwiLCBcIuKXiyBcIikgKyBpdGVtLnRleHRcbiAgKTtcbiAgcmV0dXJuIHtcbiAgICByZW5kZXI6ICgpID0+IGxpbmVzLFxuICAgIGludmFsaWRhdGU6ICgpID0+IHt9LFxuICB9O1xufSk7XG5cbi8vIENsZWFyXG5jdHgudWkuc2V0V2lkZ2V0KFwibXktd2lkZ2V0XCIsIHVuZGVmaW5lZCk7XG5gYGBcblxuKipFeGFtcGxlczoqKiBbcGxhbi1tb2RlLnRzXSguLi9leGFtcGxlcy9leHRlbnNpb25zL3BsYW4tbW9kZS50cylcblxuIyMjIFBhdHRlcm4gNjogQ3VzdG9tIEZvb3RlclxuXG5SZXBsYWNlIHRoZSBmb290ZXIuIGBmb290ZXJEYXRhYCBleHBvc2VzIGRhdGEgbm90IG90aGVyd2lzZSBhY2Nlc3NpYmxlIHRvIGV4dGVuc2lvbnMuXG5cbmBgYHR5cGVzY3JpcHRcbmN0eC51aS5zZXRGb290ZXIoKHR1aSwgdGhlbWUsIGZvb3RlckRhdGEpID0+ICh7XG4gIGludmFsaWRhdGUoKSB7fSxcbiAgcmVuZGVyKHdpZHRoOiBudW1iZXIpOiBzdHJpbmdbXSB7XG4gICAgLy8gZm9vdGVyRGF0YS5nZXRHaXRCcmFuY2goKTogc3RyaW5nIHwgbnVsbFxuICAgIC8vIGZvb3RlckRhdGEuZ2V0RXh0ZW5zaW9uU3RhdHVzZXMoKTogUmVhZG9ubHlNYXA8c3RyaW5nLCBzdHJpbmc+XG4gICAgcmV0dXJuIFtgJHtjdHgubW9kZWw/LmlkfSAoJHtmb290ZXJEYXRhLmdldEdpdEJyYW5jaCgpIHx8IFwibm8gZ2l0XCJ9KWBdO1xuICB9LFxuICBkaXNwb3NlOiBmb290ZXJEYXRhLm9uQnJhbmNoQ2hhbmdlKCgpID0+IHR1aS5yZXF1ZXN0UmVuZGVyKCkpLCAvLyByZWFjdGl2ZVxufSkpO1xuXG5jdHgudWkuc2V0Rm9vdGVyKHVuZGVmaW5lZCk7IC8vIHJlc3RvcmUgZGVmYXVsdFxuYGBgXG5cblRva2VuIHN0YXRzIGF2YWlsYWJsZSB2aWEgYGN0eC5zZXNzaW9uTWFuYWdlci5nZXRCcmFuY2goKWAgYW5kIGBjdHgubW9kZWxgLlxuXG4qKkV4YW1wbGVzOioqIFtjdXN0b20tZm9vdGVyLnRzXSguLi9leGFtcGxlcy9leHRlbnNpb25zL2N1c3RvbS1mb290ZXIudHMpXG5cbiMjIyBQYXR0ZXJuIDc6IEN1c3RvbSBFZGl0b3IgKHZpbSBtb2RlLCBldGMuKVxuXG5SZXBsYWNlIHRoZSBtYWluIGlucHV0IGVkaXRvciB3aXRoIGEgY3VzdG9tIGltcGxlbWVudGF0aW9uLiBVc2VmdWwgZm9yIG1vZGFsIGVkaXRpbmcgKHZpbSksIGRpZmZlcmVudCBrZXliaW5kaW5ncyAoZW1hY3MpLCBvciBzcGVjaWFsaXplZCBpbnB1dCBoYW5kbGluZy5cblxuYGBgdHlwZXNjcmlwdFxuaW1wb3J0IHsgQ3VzdG9tRWRpdG9yLCB0eXBlIEV4dGVuc2lvbkFQSSB9IGZyb20gXCJAZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50XCI7XG5pbXBvcnQgeyBtYXRjaGVzS2V5LCB0cnVuY2F0ZVRvV2lkdGggfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLXR1aVwiO1xuXG50eXBlIE1vZGUgPSBcIm5vcm1hbFwiIHwgXCJpbnNlcnRcIjtcblxuY2xhc3MgVmltRWRpdG9yIGV4dGVuZHMgQ3VzdG9tRWRpdG9yIHtcbiAgcHJpdmF0ZSBtb2RlOiBNb2RlID0gXCJpbnNlcnRcIjtcblxuICBoYW5kbGVJbnB1dChkYXRhOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAvLyBFc2NhcGU6IHN3aXRjaCB0byBub3JtYWwgbW9kZSwgb3IgcGFzcyB0aHJvdWdoIGZvciBhcHAgaGFuZGxpbmdcbiAgICBpZiAobWF0Y2hlc0tleShkYXRhLCBcImVzY2FwZVwiKSkge1xuICAgICAgaWYgKHRoaXMubW9kZSA9PT0gXCJpbnNlcnRcIikge1xuICAgICAgICB0aGlzLm1vZGUgPSBcIm5vcm1hbFwiO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICAvLyBJbiBub3JtYWwgbW9kZSwgZXNjYXBlIGFib3J0cyBhZ2VudCAoaGFuZGxlZCBieSBDdXN0b21FZGl0b3IpXG4gICAgICBzdXBlci5oYW5kbGVJbnB1dChkYXRhKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBJbnNlcnQgbW9kZTogcGFzcyBldmVyeXRoaW5nIHRvIEN1c3RvbUVkaXRvclxuICAgIGlmICh0aGlzLm1vZGUgPT09IFwiaW5zZXJ0XCIpIHtcbiAgICAgIHN1cGVyLmhhbmRsZUlucHV0KGRhdGEpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIE5vcm1hbCBtb2RlOiB2aW0tc3R5bGUgbmF2aWdhdGlvblxuICAgIHN3aXRjaCAoZGF0YSkge1xuICAgICAgY2FzZSBcImlcIjogdGhpcy5tb2RlID0gXCJpbnNlcnRcIjsgcmV0dXJuO1xuICAgICAgY2FzZSBcImhcIjogc3VwZXIuaGFuZGxlSW5wdXQoXCJcXHgxYltEXCIpOyByZXR1cm47IC8vIExlZnRcbiAgICAgIGNhc2UgXCJqXCI6IHN1cGVyLmhhbmRsZUlucHV0KFwiXFx4MWJbQlwiKTsgcmV0dXJuOyAvLyBEb3duXG4gICAgICBjYXNlIFwia1wiOiBzdXBlci5oYW5kbGVJbnB1dChcIlxceDFiW0FcIik7IHJldHVybjsgLy8gVXBcbiAgICAgIGNhc2UgXCJsXCI6IHN1cGVyLmhhbmRsZUlucHV0KFwiXFx4MWJbQ1wiKTsgcmV0dXJuOyAvLyBSaWdodFxuICAgIH1cbiAgICAvLyBQYXNzIHVuaGFuZGxlZCBrZXlzIHRvIHN1cGVyIChjdHJsK2MsIGV0Yy4pLCBidXQgZmlsdGVyIHByaW50YWJsZSBjaGFyc1xuICAgIGlmIChkYXRhLmxlbmd0aCA9PT0gMSAmJiBkYXRhLmNoYXJDb2RlQXQoMCkgPj0gMzIpIHJldHVybjtcbiAgICBzdXBlci5oYW5kbGVJbnB1dChkYXRhKTtcbiAgfVxuXG4gIHJlbmRlcih3aWR0aDogbnVtYmVyKTogc3RyaW5nW10ge1xuICAgIGNvbnN0IGxpbmVzID0gc3VwZXIucmVuZGVyKHdpZHRoKTtcbiAgICAvLyBBZGQgbW9kZSBpbmRpY2F0b3IgdG8gYm90dG9tIGJvcmRlciAodXNlIHRydW5jYXRlVG9XaWR0aCBmb3IgQU5TSS1zYWZlIHRydW5jYXRpb24pXG4gICAgaWYgKGxpbmVzLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IGxhYmVsID0gdGhpcy5tb2RlID09PSBcIm5vcm1hbFwiID8gXCIgTk9STUFMIFwiIDogXCIgSU5TRVJUIFwiO1xuICAgICAgY29uc3QgbGFzdExpbmUgPSBsaW5lc1tsaW5lcy5sZW5ndGggLSAxXSE7XG4gICAgICAvLyBQYXNzIFwiXCIgYXMgZWxsaXBzaXMgdG8gYXZvaWQgYWRkaW5nIFwiLi4uXCIgd2hlbiB0cnVuY2F0aW5nXG4gICAgICBsaW5lc1tsaW5lcy5sZW5ndGggLSAxXSA9IHRydW5jYXRlVG9XaWR0aChsYXN0TGluZSwgd2lkdGggLSBsYWJlbC5sZW5ndGgsIFwiXCIpICsgbGFiZWw7XG4gICAgfVxuICAgIHJldHVybiBsaW5lcztcbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiAocGk6IEV4dGVuc2lvbkFQSSkge1xuICBwaS5vbihcInNlc3Npb25fc3RhcnRcIiwgKF9ldmVudCwgY3R4KSA9PiB7XG4gICAgLy8gRmFjdG9yeSByZWNlaXZlcyB0aGVtZSBhbmQga2V5YmluZGluZ3MgZnJvbSB0aGUgYXBwXG4gICAgY3R4LnVpLnNldEVkaXRvckNvbXBvbmVudCgodHVpLCB0aGVtZSwga2V5YmluZGluZ3MpID0+XG4gICAgICBuZXcgVmltRWRpdG9yKHRoZW1lLCBrZXliaW5kaW5ncylcbiAgICApO1xuICB9KTtcbn1cbmBgYFxuXG4qKktleSBwb2ludHM6KipcblxuLSAqKkV4dGVuZCBgQ3VzdG9tRWRpdG9yYCoqIChub3QgYmFzZSBgRWRpdG9yYCkgdG8gZ2V0IGFwcCBrZXliaW5kaW5ncyAoZXNjYXBlIHRvIGFib3J0LCBjdHJsK2QgdG8gZXhpdCwgbW9kZWwgc3dpdGNoaW5nLCBldGMuKVxuLSAqKkNhbGwgYHN1cGVyLmhhbmRsZUlucHV0KGRhdGEpYCoqIGZvciBrZXlzIHlvdSBkb24ndCBoYW5kbGVcbi0gKipGYWN0b3J5IHBhdHRlcm4qKjogYHNldEVkaXRvckNvbXBvbmVudGAgcmVjZWl2ZXMgYSBmYWN0b3J5IGZ1bmN0aW9uIHRoYXQgZ2V0cyBgdHVpYCwgYHRoZW1lYCwgYW5kIGBrZXliaW5kaW5nc2Bcbi0gKipQYXNzIGB1bmRlZmluZWRgKiogdG8gcmVzdG9yZSB0aGUgZGVmYXVsdCBlZGl0b3I6IGBjdHgudWkuc2V0RWRpdG9yQ29tcG9uZW50KHVuZGVmaW5lZClgXG5cbioqRXhhbXBsZXM6KiogW21vZGFsLWVkaXRvci50c10oLi4vZXhhbXBsZXMvZXh0ZW5zaW9ucy9tb2RhbC1lZGl0b3IudHMpXG5cbiMjIEtleSBSdWxlc1xuXG4xLiAqKkFsd2F5cyB1c2UgdGhlbWUgZnJvbSBjYWxsYmFjayoqIC0gRG9uJ3QgaW1wb3J0IHRoZW1lIGRpcmVjdGx5LiBVc2UgYHRoZW1lYCBmcm9tIHRoZSBgY3R4LnVpLmN1c3RvbSgodHVpLCB0aGVtZSwga2V5YmluZGluZ3MsIGRvbmUpID0+IC4uLilgIGNhbGxiYWNrLlxuXG4yLiAqKkFsd2F5cyB0eXBlIER5bmFtaWNCb3JkZXIgY29sb3IgcGFyYW0qKiAtIFdyaXRlIGAoczogc3RyaW5nKSA9PiB0aGVtZS5mZyhcImFjY2VudFwiLCBzKWAsIG5vdCBgKHMpID0+IHRoZW1lLmZnKFwiYWNjZW50XCIsIHMpYC5cblxuMy4gKipDYWxsIHR1aS5yZXF1ZXN0UmVuZGVyKCkgYWZ0ZXIgc3RhdGUgY2hhbmdlcyoqIC0gSW4gYGhhbmRsZUlucHV0YCwgY2FsbCBgdHVpLnJlcXVlc3RSZW5kZXIoKWAgYWZ0ZXIgdXBkYXRpbmcgc3RhdGUuXG5cbjQuICoqUmV0dXJuIHRoZSB0aHJlZS1tZXRob2Qgb2JqZWN0KiogLSBDdXN0b20gY29tcG9uZW50cyBuZWVkIGB7IHJlbmRlciwgaW52YWxpZGF0ZSwgaGFuZGxlSW5wdXQgfWAuXG5cbjUuICoqVXNlIGV4aXN0aW5nIGNvbXBvbmVudHMqKiAtIGBTZWxlY3RMaXN0YCwgYFNldHRpbmdzTGlzdGAsIGBCb3JkZXJlZExvYWRlcmAgY292ZXIgOTAlIG9mIGNhc2VzLiBEb24ndCByZWJ1aWxkIHRoZW0uXG5cbiMjIEV4YW1wbGVzXG5cbi0gKipTZWxlY3Rpb24gVUkqKjogW2V4YW1wbGVzL2V4dGVuc2lvbnMvcHJlc2V0LnRzXSguLi9leGFtcGxlcy9leHRlbnNpb25zL3ByZXNldC50cykgLSBTZWxlY3RMaXN0IHdpdGggRHluYW1pY0JvcmRlciBmcmFtaW5nXG4tICoqQXN5bmMgd2l0aCBjYW5jZWwqKjogW2V4YW1wbGVzL2V4dGVuc2lvbnMvcW5hLnRzXSguLi9leGFtcGxlcy9leHRlbnNpb25zL3FuYS50cykgLSBCb3JkZXJlZExvYWRlciBmb3IgTExNIGNhbGxzXG4tICoqU2V0dGluZ3MgdG9nZ2xlcyoqOiBbZXhhbXBsZXMvZXh0ZW5zaW9ucy90b29scy50c10oLi4vZXhhbXBsZXMvZXh0ZW5zaW9ucy90b29scy50cykgLSBTZXR0aW5nc0xpc3QgZm9yIHRvb2wgZW5hYmxlL2Rpc2FibGVcbi0gKipTdGF0dXMgaW5kaWNhdG9ycyoqOiBbZXhhbXBsZXMvZXh0ZW5zaW9ucy9wbGFuLW1vZGUudHNdKC4uL2V4YW1wbGVzL2V4dGVuc2lvbnMvcGxhbi1tb2RlLnRzKSAtIHNldFN0YXR1cyBhbmQgc2V0V2lkZ2V0XG4tICoqV29ya2luZyBpbmRpY2F0b3IqKjogW2V4YW1wbGVzL2V4dGVuc2lvbnMvd29ya2luZy1pbmRpY2F0b3IudHNdKC4uL2V4YW1wbGVzL2V4dGVuc2lvbnMvd29ya2luZy1pbmRpY2F0b3IudHMpIC0gc2V0V29ya2luZ0luZGljYXRvclxuLSAqKkN1c3RvbSBmb290ZXIqKjogW2V4YW1wbGVzL2V4dGVuc2lvbnMvY3VzdG9tLWZvb3Rlci50c10oLi4vZXhhbXBsZXMvZXh0ZW5zaW9ucy9jdXN0b20tZm9vdGVyLnRzKSAtIHNldEZvb3RlciB3aXRoIHN0YXRzXG4tICoqQ3VzdG9tIGVkaXRvcioqOiBbZXhhbXBsZXMvZXh0ZW5zaW9ucy9tb2RhbC1lZGl0b3IudHNdKC4uL2V4YW1wbGVzL2V4dGVuc2lvbnMvbW9kYWwtZWRpdG9yLnRzKSAtIFZpbS1saWtlIG1vZGFsIGVkaXRpbmdcbi0gKipTbmFrZSBnYW1lKio6IFtleGFtcGxlcy9leHRlbnNpb25zL3NuYWtlLnRzXSguLi9leGFtcGxlcy9leHRlbnNpb25zL3NuYWtlLnRzKSAtIEZ1bGwgZ2FtZSB3aXRoIGtleWJvYXJkIGlucHV0LCBnYW1lIGxvb3Bcbi0gKipDdXN0b20gdG9vbCByZW5kZXJpbmcqKjogW2V4YW1wbGVzL2V4dGVuc2lvbnMvdG9kby50c10oLi4vZXhhbXBsZXMvZXh0ZW5zaW9ucy90b2RvLnRzKSAtIHJlbmRlckNhbGwgYW5kIHJlbmRlclJlc3VsdFxuIn1dLCJpc0Vycm9yIjpmYWxzZSwidGltZXN0YW1wIjoxNzgxOTU0MzMxODk2fX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiNGJkMzYyZTAiLCJwYXJlbnRJZCI6IjAzOTFmMjc2IiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToxODo1MS44OTZaIiwibWVzc2FnZSI6eyJyb2xlIjoidG9vbFJlc3VsdCIsInRvb2xDYWxsSWQiOiJjYWxsX2MzMDI0ODZmNWIzMjQxOGRhNWE5YzZlYSIsInRvb2xOYW1lIjoiYmFzaCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImF1dG8tY29tbWl0LW9uLWV4aXQudHNcbmJhc2gtc3Bhd24taG9vay50c1xuYm9va21hcmsudHNcbmJvcmRlci1zdGF0dXMtZWRpdG9yLnRzXG5idWlsdC1pbi10b29sLXJlbmRlcmVyLnRzXG5jbGF1ZGUtcnVsZXMudHNcbmNvbW1hbmRzLnRzXG5jb25maXJtLWRlc3RydWN0aXZlLnRzXG5jdXN0b20tY29tcGFjdGlvbi50c1xuY3VzdG9tLWZvb3Rlci50c1xuY3VzdG9tLWhlYWRlci50c1xuY3VzdG9tLXByb3ZpZGVyLWFudGhyb3BpY1xuY3VzdG9tLXByb3ZpZGVyLWdpdGxhYi1kdW9cbmRpcnR5LXJlcG8tZ3VhcmQudHNcbmRvb20tb3ZlcmxheVxuZHluYW1pYy1yZXNvdXJjZXNcbmR5bmFtaWMtdG9vbHMudHNcbmV2ZW50LWJ1cy50c1xuZmlsZS10cmlnZ2VyLnRzXG5naXQtY2hlY2twb2ludC50c1xuZ2l0LW1lcmdlLWFuZC1yZXNvbHZlLnRzXG5naXRodWItaXNzdWUtYXV0b2NvbXBsZXRlLnRzXG5nb25kb2xpblxuaGFuZG9mZi50c1xuaGVsbG8udHNcbmhpZGRlbi10aGlua2luZy1sYWJlbC50c1xuaW5saW5lLWJhc2gudHNcbmlucHV0LXRyYW5zZm9ybS1zdHJlYW1pbmcudHNcbmlucHV0LXRyYW5zZm9ybS50c1xuaW50ZXJhY3RpdmUtc2hlbGwudHNcbm1hYy1zeXN0ZW0tdGhlbWUudHNcbm1lc3NhZ2UtcmVuZGVyZXIudHNcbm1pbmltYWwtbW9kZS50c1xubW9kYWwtZWRpdG9yLnRzXG5tb2RlbC1zdGF0dXMudHNcbm5vdGlmeS50c1xub3ZlcmxheS1xYS10ZXN0cy50c1xub3ZlcmxheS10ZXN0LnRzXG5wZXJtaXNzaW9uLWdhdGUudHNcbnBpcmF0ZS50c1xucGxhbi1tb2RlXG5wcmVzZXQudHNcbnByb2plY3QtdHJ1c3QudHNcbnByb21wdC1jdXN0b21pemVyLnRzXG5wcm90ZWN0ZWQtcGF0aHMudHNcbnByb3ZpZGVyLXBheWxvYWQudHNcbnFuYS50c1xucXVlc3Rpb24udHNcbnF1ZXN0aW9ubmFpcmUudHNcbnJhaW5ib3ctZWRpdG9yLnRzXG5SRUFETUUubWRcbnJlbG9hZC1ydW50aW1lLnRzXG5ycGMtZGVtby50c1xuc2FuZGJveFxuc2VuZC11c2VyLW1lc3NhZ2UudHNcbnNlc3Npb24tbmFtZS50c1xuc2h1dGRvd24tY29tbWFuZC50c1xuc25ha2UudHNcbnNwYWNlLWludmFkZXJzLnRzXG5zc2gudHNcbnN0YXR1cy1saW5lLnRzXG5zdHJ1Y3R1cmVkLW91dHB1dC50c1xuc3ViYWdlbnRcbnN1bW1hcml6ZS50c1xuc3lzdGVtLXByb21wdC1oZWFkZXIudHNcbnRpYy10YWMtdG9lLnRzXG50aW1lZC1jb25maXJtLnRzXG50aXRsZWJhci1zcGlubmVyLnRzXG50b2RvLnRzXG50b29sLW92ZXJyaWRlLnRzXG50b29scy50c1xudHJpZ2dlci1jb21wYWN0LnRzXG50cnVuY2F0ZWQtdG9vbC50c1xud2lkZ2V0LXBsYWNlbWVudC50c1xud2l0aC1kZXBzXG53b3JraW5nLWluZGljYXRvci50c1xud29ya2luZy1tZXNzYWdlLXRlc3QudHNcbiJ9XSwiaXNFcnJvciI6ZmFsc2UsInRpbWVzdGFtcCI6MTc4MTk1NDMzMTg5Nn19LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6IjY3MDc0NDU5IiwicGFyZW50SWQiOiI0YmQzNjJlMCIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MTk6MDYuMjM5WiIsIm1lc3NhZ2UiOnsicm9sZSI6ImFzc2lzdGFudCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0aGlua2luZyIsInRoaW5raW5nIjoiTm93IEkgaGF2ZSBhIGdvb2QgdW5kZXJzdGFuZGluZyBvZiB0aGUgcmVsZXZhbnQgQVBJcy4gVGhlIHVzZXIgd2FudHMgYSBzbWFsbCBleHRlbnNpb24gdGhhdCBzaG93cyBhIGdyZWVuIGRvdCB3aGVuZXZlciB0ZXN0cyBoYXZlIHBhc3NlZC4gTGV0IG1lIHRoaW5rIGFib3V0IHRoZSBvcHRpb25zOlxuXG5UaGVyZSBhcmUgc2V2ZXJhbCBhcHByb2FjaGVzOlxuXG4xLiAqKmBjdHgudWkuc2V0U3RhdHVzKClgKiogLSBTaG93cyBhIHBlcnNpc3RlbnQgaW5kaWNhdG9yIGluIHRoZSBmb290ZXIuIFNpbXBsZSwgcGVyc2lzdGVudCBhY3Jvc3MgcmVuZGVycy5cblxuMi4gKipgY3R4LnVpLnNldFdvcmtpbmdJbmRpY2F0b3IoKWAqKiAtIEN1c3RvbWl6ZXMgdGhlIHdvcmtpbmcgaW5kaWNhdG9yLiBPbmx5IHNob3dzIHdoaWxlIHBpIGlzIHN0cmVhbWluZy5cblxuMy4gKipgY3R4LnVpLnNldFdpZGdldCgpYCoqIC0gU2hvd3MgY29udGVudCBhYm92ZSBvciBiZWxvdyB0aGUgZWRpdG9yLiBNb3JlIHZpc2libGUgdGhhbiBzdGF0dXMuXG5cbjQuICoqQ3VzdG9tIGZvb3RlciB2aWEgYGN0eC51aS5zZXRGb290ZXIoKWAqKiAtIEZ1bGwgZm9vdGVyIHJlcGxhY2VtZW50LlxuXG41LiAqKlRVSSBjdXN0b20gY29tcG9uZW50IHdpdGggYGN0eC51aS5jdXN0b20oKWAqKiAtIEZ1bGwgb3ZlcmxheS9jb21wb25lbnQsIGJ1dCBvdmVya2lsbCBmb3IgYSBzaW1wbGUgZG90LlxuXG5UaGUga2V5IGNoYWxsZW5nZSBpczogaG93IGRvZXMgdGhlIGV4dGVuc2lvbiBrbm93IHdoZW4gdGVzdHMgaGF2ZSBwYXNzZWQ/IFRoZSBleHRlbnNpb24gbmVlZHMgdG8gZGV0ZWN0IHdoZW4gdGhlIExMTSBydW5zIGBucG0gdGVzdGAgb3IgYG5weCB2aXRlc3RgIGFuZCB0aGUgb3V0cHV0IHNob3dzIHRlc3RzIHBhc3NpbmcuXG5cbkxvb2tpbmcgYXQgdGhlIGV2ZW50cywgdGhlIG1vc3QgbmF0dXJhbCBhcHByb2FjaCB3b3VsZCBiZTpcblxuLSBMaXN0ZW4gdG8gYHRvb2xfcmVzdWx0YCBldmVudHMgZm9yIGBiYXNoYCB0b29sIGNhbGxzXG4tIENoZWNrIGlmIHRoZSBjb21tYW5kIGluY2x1ZGVzIGBucG0gdGVzdGAsIGB2aXRlc3RgLCBvciBzaW1pbGFyXG4tIFBhcnNlIHRoZSBvdXRwdXQgdG8gc2VlIGlmIHRlc3RzIHBhc3NlZFxuLSBVcGRhdGUgYSBzdGF0dXMgaW5kaWNhdG9yIGFjY29yZGluZ2x5XG5cbkxldCBtZSB0aGluayBvZiBkaWZmZXJlbnQgb3B0aW9uczpcblxuKipPcHRpb24gMTogU3RhdHVzIGluZGljYXRvciAoc2V0U3RhdHVzKSoqIC0gU2hvdyBhIGdyZWVuL3JlZCBkb3QgaW4gdGhlIGZvb3Rlci4gU2ltcGxlIGltcGxlbWVudGF0aW9uLlxuXG4qKk9wdGlvbiAyOiBXaWRnZXQgYWJvdmUvYmVsb3cgZWRpdG9yKiogLSBTaG93IHRlc3Qgc3RhdHVzIGFzIGEgd2lkZ2V0LCB3aXRoIG1vcmUgZGV0YWlsIChlLmcuLCBcIuKckyB0ZXN0cyBwYXNzZWRcIiBvciBcIuKclyB0ZXN0cyBmYWlsZWRcIikuXG5cbioqT3B0aW9uIDM6IFdvcmtpbmcgaW5kaWNhdG9yIGN1c3RvbWl6YXRpb24qKiAtIENoYW5nZSB0aGUgc3Bpbm5lciB0byBzaG93IHRlc3Qgc3RhdHVzLlxuXG4qKk9wdGlvbiA0OiBDdXN0b20gZm9vdGVyKiogLSBSZXBsYWNlIHRoZSBmb290ZXIgdG8gaW5jbHVkZSB0ZXN0IHN0YXR1cyBhbG9uZ3NpZGUgb3RoZXIgaW5mby5cblxuTGV0IG1lIHByZXNlbnQgdGhlc2Ugb3B0aW9ucyB0byB0aGUgdXNlciB3aXRoIGJyaWVmIGRlc2NyaXB0aW9ucyBvZiB0cmFkZS1vZmZzLiIsInRoaW5raW5nU2lnbmF0dXJlIjoicmVhc29uaW5nIn0seyJ0eXBlIjoidGV4dCIsInRleHQiOiJHcmVhdCBkb2NzISBMZXQgbWUgc2tldGNoIG91dCB0aGUgYXBwcm9hY2hlcy5cblxuVGhlIGNvcmUgbWVjaGFuaXNtIGhvb2tzIGludG8gYHRvb2xfcmVzdWx0YCBmb3IgYGJhc2hgIGNhbGxzLCBkZXRlY3RzIGBucG0gdGVzdGAgLyBgdml0ZXN0YCBydW5zLCBwYXJzZXMgdGhlIG91dHB1dCBmb3IgcGFzcy9mYWlsLCBhbmQgdXBkYXRlcyBhbiBpbmRpY2F0b3IuIEhlcmUgYXJlIHRoZSBvcHRpb25zOlxuXG4tLS1cblxuIyMjIE9wdGlvbiAxOiBGb290ZXIgU3RhdHVzIChgY3R4LnVpLnNldFN0YXR1c2ApXG5cbioqU2ltcGxlc3QuKiogQSBjb2xvcmVkIGRvdCBpbiB0aGUgZm9vdGVyIGxpbmUgdGhhdCBwZXJzaXN0cyBhY3Jvc3MgcmVuZGVycy5cblxuIVtmb290ZXIgZG90XShodHRwczovL3ZpYS5wbGFjZWhvbGRlci5jb20vMTUvMDBmZjAwLzAwMDAwMD90ZXh0PSspIFNob3dzIGFzIGDil48gdGVzdHM6cGFzc2Agb3IgYOKXjyB0ZXN0czpmYWlsYCBpbiB0aGUgZm9vdGVyLlxuXG5gYGB0eXBlc2NyaXB0XG5waS5vbihcInRvb2xfcmVzdWx0XCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gIGlmIChpc0Jhc2hUb29sUmVzdWx0KGV2ZW50KSAmJiBpc1Rlc3RDb21tYW5kKGV2ZW50LmlucHV0LmNvbW1hbmQpKSB7XG4gICAgY29uc3QgcGFzc2VkID0gL1Rlc3RzXFxzKzFcXHMrcGFzc2VkLy50ZXN0KGV2ZW50LmNvbnRlbnRbMF0/LnRleHQgPz8gXCJcIik7XG4gICAgY3R4LnVpLnNldFN0YXR1cyhcInRlc3Qtc3RhdHVzXCIsXG4gICAgICBwYXNzZWRcbiAgICAgICAgPyBjdHgudWkudGhlbWUuZmcoXCJzdWNjZXNzXCIsIFwi4pePIHRlc3RzOnBhc3NcIilcbiAgICAgICAgOiBjdHgudWkudGhlbWUuZmcoXCJlcnJvclwiLCBcIuKXjyB0ZXN0czpmYWlsXCIpXG4gICAgKTtcbiAgfVxufSk7XG5gYGBcblxuKipQcm9zOioqIH4xMCBsaW5lcywgbm8gZGVwcywgcGVyc2lzdHMgYWNyb3NzIHR1cm5zLiAqKkNvbnM6KiogU21hbGwgaW5kaWNhdG9yLCBlYXN5IHRvIG1pc3MuXG5cbi0tLVxuXG4jIyMgT3B0aW9uIDI6IFdpZGdldCBBYm92ZSBFZGl0b3IgKGBjdHgudWkuc2V0V2lkZ2V0YClcblxuTW9yZSB2aXNpYmxlIOKAlCBzaXRzIHJpZ2h0IGFib3ZlIHRoZSBpbnB1dCBhcmVhLiBTaG93cyBhIGNvbG9yZWQgZG90ICsgbGFzdCB0ZXN0IHN1bW1hcnkuXG5cbmBgYFxuIOKUgOKUgCDilIDilIAg4pSA4pSAIOKUgOKUgCDilIDilIAg4pSA4pSAIOKUgOKUgCDilIDilIAg4pSA4pSAXG4g4pePIDEgdGVzdCBwYXNzZWQgKDI0Mm1zKVxuIOKUgOKUgCDilIDilIAg4pSA4pSAIOKUgOKUgCDilIDilIAg4pSA4pSAIOKUgOKUgCDilIDilIAg4pSA4pSAXG4gPiBucG0gdGVzdFxuYGBgXG5cbioqUHJvczoqKiBNb3JlIGRldGFpbCwgcmlnaHQgaW4gdGhlIHVzZXIncyBleWVsaW5lLiAqKkNvbnM6KiogVGFrZXMgc2NyZWVuIHNwYWNlOyBuZWVkIHRvIG1hbmFnZSBzdGF0ZS5cblxuLS0tXG5cbiMjIyBPcHRpb24gMzogV29ya2luZyBJbmRpY2F0b3IgKGBjdHgudWkuc2V0V29ya2luZ0luZGljYXRvcmApXG5cblRoZSBsaXR0bGUgYW5pbWF0ZWQgc3Bpbm5lciBuZXh0IHRvIHRoZSBtb2RlbCBuYW1lIGJlY29tZXMgYSBncmVlbiBkb3Qgd2hlbiBpZGxlIGFmdGVyIHBhc3NpbmcgdGVzdHMuIEZ1biBhbmQgc3VidGxlLlxuXG5gYGB0eXBlc2NyaXB0XG4vLyBBdCBpZGxlIHdpdGggZ3JlZW4gZG90OlxuY3R4LnVpLnNldFdvcmtpbmdJbmRpY2F0b3IoeyBmcmFtZXM6IFt0aGVtZS5mZyhcInN1Y2Nlc3NcIiwgXCLil49cIildIH0pO1xuYGBgXG5cbioqUHJvczoqKiBaZXJvIGV4dHJhIHNjcmVlbiBzcGFjZSwgY2xldmVyLiAqKkNvbnM6KiogT25seSB2aXNpYmxlIHdoZW4gcGkgaXMgaWRsZS93b3JraW5nIOKAlCBubyBwZXJzaXN0ZW50IHN0YXRlLiBHZXRzIG92ZXJyaWRkZW4gYnkgb3RoZXIgd29ya2luZyBpbmRpY2F0b3IgY2hhbmdlcy5cblxuLS0tXG5cbiMjIyBPcHRpb24gNDogQ3VzdG9tIEZvb3RlciAoYGN0eC51aS5zZXRGb290ZXJgKVxuXG5SZXBsYWNlIHRoZSBmb290ZXIgZW50aXJlbHkgdG8gc2hvdyBtb2RlbCArIHRlc3Qgc3RhdHVzICsgZ2l0IGJyYW5jaC4gTW9zdCBwb2xpc2hlZC5cblxuYGBgXG7il48gdGVzdHM6cGFzcyAg4pSCICBncHQtNG8gIOKUgiAgbWFpblxuYGBgXG5cbioqUHJvczoqKiBDb21wbGV0ZSBjb250cm9sLCBwcm8tbG9va2luZy4gKipDb25zOioqIH4zMC00MCBsaW5lcywgeW91IG93biB0aGUgd2hvbGUgZm9vdGVyLlxuXG4tLS1cblxuIyMjIFdoaWNoIG9uZSBkbyB5b3UgbGlrZT8gSSBjYW4gaW1wbGVtZW50IGFueSBvZiB0aGVtIGluc3RhbnRseS4ifV0sImFwaSI6Im9wZW5haS1jb21wbGV0aW9ucyIsInByb3ZpZGVyIjoib3BlbnJvdXRlciIsIm1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2giLCJ1c2FnZSI6eyJpbnB1dCI6ODcyMiwib3V0cHV0Ijo5ODUsImNhY2hlUmVhZCI6MTk5NjgsImNhY2hlV3JpdGUiOjAsInRvdGFsVG9rZW5zIjoyOTY3NSwiY29zdCI6eyJpbnB1dCI6MC4wMDA3ODQ5OCwib3V0cHV0IjowLjAwMDE3NzMsImNhY2hlUmVhZCI6MC4wMDAzOTkzNiwiY2FjaGVXcml0ZSI6MCwidG90YWwiOjAuMDAxMzYxNjQwMDAwMDAwMDAwMX19LCJzdG9wUmVhc29uIjoic3RvcCIsInRpbWVzdGFtcCI6MTc4MTk1NDMzMTg5NywicmVzcG9uc2VJZCI6Imdlbi0xNzgxOTU0MzMxLTR5UlpFSnB4bnUydGFydlJFQU1PIiwicmVzcG9uc2VNb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoLTIwMjYwNDIzIn19LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6IjhiMDhmNjZiIiwicGFyZW50SWQiOiI2NzA3NDQ1OSIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MjI6MjIuMjcxWiIsIm1lc3NhZ2UiOnsicm9sZSI6InVzZXIiLCJjb250ZW50IjpbeyJ0eXBlIjoidGV4dCIsInRleHQiOiJPcHRpb24gMi4gZXhwbGFpbiB0byBtZSBob3cgeW91IHdvdWxkIGRvIHRoaXMsIEkgd2FudCB0byBsZWFybiBob3cgZXhlbnNpb25zIHdvcmsuIn1dLCJ0aW1lc3RhbXAiOjE3ODE5NTQ1NDIyNzB9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiI5MDE1NGEzYyIsInBhcmVudElkIjoiOGIwOGY2NmIiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjIyOjI4Ljc4NloiLCJtZXNzYWdlIjp7InJvbGUiOiJhc3Npc3RhbnQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGhpbmtpbmciLCJ0aGlua2luZyI6IlRoZSB1c2VyIHdhbnRzIHRvIGxlYXJuIGhvdyBleHRlbnNpb25zIHdvcmsgYnkgd2Fsa2luZyB0aHJvdWdoIE9wdGlvbiAyIChXaWRnZXQgQWJvdmUgRWRpdG9yKS4gTGV0IG1lIGV4cGxhaW4gdGhlIGFyY2hpdGVjdHVyZSBzdGVwIGJ5IHN0ZXAsIHRoZW4gaW1wbGVtZW50IGl0IHRvZ2V0aGVyLlxuXG5MZXQgbWUgZmlyc3QgdW5kZXJzdGFuZCB3aGF0IHdlIG5lZWQ6XG5cbjEuIExpc3RlbiB0byBgdG9vbF9yZXN1bHRgIGV2ZW50cyBmb3IgYmFzaCBjb21tYW5kcyB0aGF0IHJ1biB0ZXN0c1xuMi4gUGFyc2UgdGhlIG91dHB1dCB0byBkZXRlcm1pbmUgaWYgdGVzdHMgcGFzc2VkXG4zLiBVc2UgYGN0eC51aS5zZXRXaWRnZXQoKWAgdG8gc2hvdyB0aGUgc3RhdHVzIGFib3ZlIHRoZSBlZGl0b3JcblxuTGV0IG1lIGFsc28gbG9vayBhdCB0aGUgcmVsZXZhbnQgaW1wb3J0cyBhbmQgdHlwZXMgYXZhaWxhYmxlLlxuXG5JIHNob3VsZCByZWFkIHRoZSBleGlzdGluZyBleGFtcGxlcyBmb3Igd2lkZ2V0cyB0byBzaG93IHRoZW0gYSBjb25jcmV0ZSBwYXR0ZXJuLiIsInRoaW5raW5nU2lnbmF0dXJlIjoicmVhc29uaW5nIn0seyJ0eXBlIjoidG9vbENhbGwiLCJpZCI6ImNhbGxfMDBfeTFIQWtiZ1NpcXFNYlBvSVR3UGk4NDQwIiwibmFtZSI6InJlYWQiLCJhcmd1bWVudHMiOnsicGF0aCI6Ii9Vc2Vycy93aWxsZW0vLmxvY2FsL3NoYXJlL21pc2UvaW5zdGFsbHMvbm9kZS8yNC4wLjEvbGliL25vZGVfbW9kdWxlcy9AZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50L2V4YW1wbGVzL2V4dGVuc2lvbnMvd2lkZ2V0LXBsYWNlbWVudC50cyJ9fSx7InR5cGUiOiJ0b29sQ2FsbCIsImlkIjoiY2FsbF8wMV9Cb3JtemZIaVpOOWNYczMxWTdycjc4NDMiLCJuYW1lIjoicmVhZCIsImFyZ3VtZW50cyI6eyJwYXRoIjoiL1VzZXJzL3dpbGxlbS8ubG9jYWwvc2hhcmUvbWlzZS9pbnN0YWxscy9ub2RlLzI0LjAuMS9saWIvbm9kZV9tb2R1bGVzL0BlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnQvZXhhbXBsZXMvZXh0ZW5zaW9ucy9wbGFuLW1vZGUvaW5kZXgudHMifX1dLCJhcGkiOiJvcGVuYWktY29tcGxldGlvbnMiLCJwcm92aWRlciI6Im9wZW5yb3V0ZXIiLCJtb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoIiwidXNhZ2UiOnsiaW5wdXQiOjI2MzU0LCJvdXRwdXQiOjI2NSwiY2FjaGVSZWFkIjozMzI4LCJjYWNoZVdyaXRlIjowLCJ0b3RhbFRva2VucyI6Mjk5NDcsImNvc3QiOnsiaW5wdXQiOjAuMDAyMzcxODYsIm91dHB1dCI6MC4wMDAwNDc3LCJjYWNoZVJlYWQiOjAuMDAwMDY2NTYsImNhY2hlV3JpdGUiOjAsInRvdGFsIjowLjAwMjQ4NjExOTk5OTk5OTk5OTZ9fSwic3RvcFJlYXNvbiI6InRvb2xVc2UiLCJ0aW1lc3RhbXAiOjE3ODE5NTQ1NDIyNzIsInJlc3BvbnNlSWQiOiJnZW4tMTc4MTk1NDU0Mi1KWk1rc1p0RE1XWUd1SFIxZnIwVCIsInJlc3BvbnNlTW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaC0yMDI2MDQyMyJ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiIwZTFiMzI4OSIsInBhcmVudElkIjoiOTAxNTRhM2MiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjIyOjI4Ljc5M1oiLCJtZXNzYWdlIjp7InJvbGUiOiJ0b29sUmVzdWx0IiwidG9vbENhbGxJZCI6ImNhbGxfMDBfeTFIQWtiZ1NpcXFNYlBvSVR3UGk4NDQwIiwidG9vbE5hbWUiOiJyZWFkIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiaW1wb3J0IHR5cGUgeyBFeHRlbnNpb25BUEkgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudFwiO1xuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB3aWRnZXRQbGFjZW1lbnRFeHRlbnNpb24ocGk6IEV4dGVuc2lvbkFQSSkge1xuXHRwaS5vbihcInNlc3Npb25fc3RhcnRcIiwgKF9ldmVudCwgY3R4KSA9PiB7XG5cdFx0aWYgKCFjdHguaGFzVUkpIHJldHVybjtcblx0XHRjdHgudWkuc2V0V2lkZ2V0KFwid2lkZ2V0LWFib3ZlXCIsIFtcIkFib3ZlIGVkaXRvciB3aWRnZXRcIl0pO1xuXHRcdGN0eC51aS5zZXRXaWRnZXQoXCJ3aWRnZXQtYmVsb3dcIiwgW1wiQmVsb3cgZWRpdG9yIHdpZGdldFwiXSwgeyBwbGFjZW1lbnQ6IFwiYmVsb3dFZGl0b3JcIiB9KTtcblx0fSk7XG59XG4ifV0sImlzRXJyb3IiOmZhbHNlLCJ0aW1lc3RhbXAiOjE3ODE5NTQ1NDg3OTN9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiJjMjNhNzk1MSIsInBhcmVudElkIjoiMGUxYjMyODkiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjIyOjI4Ljc5M1oiLCJtZXNzYWdlIjp7InJvbGUiOiJ0b29sUmVzdWx0IiwidG9vbENhbGxJZCI6ImNhbGxfMDFfQm9ybXpmSGlaTjljWHMzMVk3cnI3ODQzIiwidG9vbE5hbWUiOiJyZWFkIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiLyoqXG4gKiBQbGFuIE1vZGUgRXh0ZW5zaW9uXG4gKlxuICogUmVhZC1vbmx5IGV4cGxvcmF0aW9uIG1vZGUgZm9yIHNhZmUgY29kZSBhbmFseXNpcy5cbiAqIFdoZW4gZW5hYmxlZCwgb25seSByZWFkLW9ubHkgdG9vbHMgYXJlIGF2YWlsYWJsZS5cbiAqXG4gKiBGZWF0dXJlczpcbiAqIC0gL3BsYW4gY29tbWFuZCBvciBDdHJsK0FsdCtQIHRvIHRvZ2dsZVxuICogLSBCYXNoIHJlc3RyaWN0ZWQgdG8gYWxsb3dsaXN0ZWQgcmVhZC1vbmx5IGNvbW1hbmRzXG4gKiAtIEV4dHJhY3RzIG51bWJlcmVkIHBsYW4gc3RlcHMgZnJvbSBcIlBsYW46XCIgc2VjdGlvbnNcbiAqIC0gW0RPTkU6bl0gbWFya2VycyB0byBjb21wbGV0ZSBzdGVwcyBkdXJpbmcgZXhlY3V0aW9uXG4gKiAtIFByb2dyZXNzIHRyYWNraW5nIHdpZGdldCBkdXJpbmcgZXhlY3V0aW9uXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBBZ2VudE1lc3NhZ2UgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWFnZW50LWNvcmVcIjtcbmltcG9ydCB0eXBlIHsgQXNzaXN0YW50TWVzc2FnZSwgVGV4dENvbnRlbnQgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWFpXCI7XG5pbXBvcnQgdHlwZSB7IEV4dGVuc2lvbkFQSSwgRXh0ZW5zaW9uQ29udGV4dCB9IGZyb20gXCJAZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50XCI7XG5pbXBvcnQgeyBLZXkgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLXR1aVwiO1xuaW1wb3J0IHsgZXh0cmFjdFRvZG9JdGVtcywgaXNTYWZlQ29tbWFuZCwgbWFya0NvbXBsZXRlZFN0ZXBzLCB0eXBlIFRvZG9JdGVtIH0gZnJvbSBcIi4vdXRpbHMudHNcIjtcblxuLy8gVG9vbHNcbmNvbnN0IFBMQU5fTU9ERV9UT09MUyA9IFtcInJlYWRcIiwgXCJiYXNoXCIsIFwiZ3JlcFwiLCBcImZpbmRcIiwgXCJsc1wiLCBcInF1ZXN0aW9ubmFpcmVcIl07XG5jb25zdCBOT1JNQUxfTU9ERV9UT09MUyA9IFtcInJlYWRcIiwgXCJiYXNoXCIsIFwiZWRpdFwiLCBcIndyaXRlXCJdO1xuXG4vLyBUeXBlIGd1YXJkIGZvciBhc3Npc3RhbnQgbWVzc2FnZXNcbmZ1bmN0aW9uIGlzQXNzaXN0YW50TWVzc2FnZShtOiBBZ2VudE1lc3NhZ2UpOiBtIGlzIEFzc2lzdGFudE1lc3NhZ2Uge1xuXHRyZXR1cm4gbS5yb2xlID09PSBcImFzc2lzdGFudFwiICYmIEFycmF5LmlzQXJyYXkobS5jb250ZW50KTtcbn1cblxuLy8gRXh0cmFjdCB0ZXh0IGNvbnRlbnQgZnJvbSBhbiBhc3Npc3RhbnQgbWVzc2FnZVxuZnVuY3Rpb24gZ2V0VGV4dENvbnRlbnQobWVzc2FnZTogQXNzaXN0YW50TWVzc2FnZSk6IHN0cmluZyB7XG5cdHJldHVybiBtZXNzYWdlLmNvbnRlbnRcblx0XHQuZmlsdGVyKChibG9jayk6IGJsb2NrIGlzIFRleHRDb250ZW50ID0+IGJsb2NrLnR5cGUgPT09IFwidGV4dFwiKVxuXHRcdC5tYXAoKGJsb2NrKSA9PiBibG9jay50ZXh0KVxuXHRcdC5qb2luKFwiXFxuXCIpO1xufVxuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBwbGFuTW9kZUV4dGVuc2lvbihwaTogRXh0ZW5zaW9uQVBJKTogdm9pZCB7XG5cdGxldCBwbGFuTW9kZUVuYWJsZWQgPSBmYWxzZTtcblx0bGV0IGV4ZWN1dGlvbk1vZGUgPSBmYWxzZTtcblx0bGV0IHRvZG9JdGVtczogVG9kb0l0ZW1bXSA9IFtdO1xuXG5cdHBpLnJlZ2lzdGVyRmxhZyhcInBsYW5cIiwge1xuXHRcdGRlc2NyaXB0aW9uOiBcIlN0YXJ0IGluIHBsYW4gbW9kZSAocmVhZC1vbmx5IGV4cGxvcmF0aW9uKVwiLFxuXHRcdHR5cGU6IFwiYm9vbGVhblwiLFxuXHRcdGRlZmF1bHQ6IGZhbHNlLFxuXHR9KTtcblxuXHRmdW5jdGlvbiB1cGRhdGVTdGF0dXMoY3R4OiBFeHRlbnNpb25Db250ZXh0KTogdm9pZCB7XG5cdFx0Ly8gRm9vdGVyIHN0YXR1c1xuXHRcdGlmIChleGVjdXRpb25Nb2RlICYmIHRvZG9JdGVtcy5sZW5ndGggPiAwKSB7XG5cdFx0XHRjb25zdCBjb21wbGV0ZWQgPSB0b2RvSXRlbXMuZmlsdGVyKCh0KSA9PiB0LmNvbXBsZXRlZCkubGVuZ3RoO1xuXHRcdFx0Y3R4LnVpLnNldFN0YXR1cyhcInBsYW4tbW9kZVwiLCBjdHgudWkudGhlbWUuZmcoXCJhY2NlbnRcIiwgYPCfk4sgJHtjb21wbGV0ZWR9LyR7dG9kb0l0ZW1zLmxlbmd0aH1gKSk7XG5cdFx0fSBlbHNlIGlmIChwbGFuTW9kZUVuYWJsZWQpIHtcblx0XHRcdGN0eC51aS5zZXRTdGF0dXMoXCJwbGFuLW1vZGVcIiwgY3R4LnVpLnRoZW1lLmZnKFwid2FybmluZ1wiLCBcIuKPuCBwbGFuXCIpKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Y3R4LnVpLnNldFN0YXR1cyhcInBsYW4tbW9kZVwiLCB1bmRlZmluZWQpO1xuXHRcdH1cblxuXHRcdC8vIFdpZGdldCBzaG93aW5nIHRvZG8gbGlzdFxuXHRcdGlmIChleGVjdXRpb25Nb2RlICYmIHRvZG9JdGVtcy5sZW5ndGggPiAwKSB7XG5cdFx0XHRjb25zdCBsaW5lcyA9IHRvZG9JdGVtcy5tYXAoKGl0ZW0pID0+IHtcblx0XHRcdFx0aWYgKGl0ZW0uY29tcGxldGVkKSB7XG5cdFx0XHRcdFx0cmV0dXJuIChcblx0XHRcdFx0XHRcdGN0eC51aS50aGVtZS5mZyhcInN1Y2Nlc3NcIiwgXCLimJEgXCIpICsgY3R4LnVpLnRoZW1lLmZnKFwibXV0ZWRcIiwgY3R4LnVpLnRoZW1lLnN0cmlrZXRocm91Z2goaXRlbS50ZXh0KSlcblx0XHRcdFx0XHQpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBgJHtjdHgudWkudGhlbWUuZmcoXCJtdXRlZFwiLCBcIuKYkCBcIil9JHtpdGVtLnRleHR9YDtcblx0XHRcdH0pO1xuXHRcdFx0Y3R4LnVpLnNldFdpZGdldChcInBsYW4tdG9kb3NcIiwgbGluZXMpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRjdHgudWkuc2V0V2lkZ2V0KFwicGxhbi10b2Rvc1wiLCB1bmRlZmluZWQpO1xuXHRcdH1cblx0fVxuXG5cdGZ1bmN0aW9uIHRvZ2dsZVBsYW5Nb2RlKGN0eDogRXh0ZW5zaW9uQ29udGV4dCk6IHZvaWQge1xuXHRcdHBsYW5Nb2RlRW5hYmxlZCA9ICFwbGFuTW9kZUVuYWJsZWQ7XG5cdFx0ZXhlY3V0aW9uTW9kZSA9IGZhbHNlO1xuXHRcdHRvZG9JdGVtcyA9IFtdO1xuXG5cdFx0aWYgKHBsYW5Nb2RlRW5hYmxlZCkge1xuXHRcdFx0cGkuc2V0QWN0aXZlVG9vbHMoUExBTl9NT0RFX1RPT0xTKTtcblx0XHRcdGN0eC51aS5ub3RpZnkoYFBsYW4gbW9kZSBlbmFibGVkLiBUb29sczogJHtQTEFOX01PREVfVE9PTFMuam9pbihcIiwgXCIpfWApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRwaS5zZXRBY3RpdmVUb29scyhOT1JNQUxfTU9ERV9UT09MUyk7XG5cdFx0XHRjdHgudWkubm90aWZ5KFwiUGxhbiBtb2RlIGRpc2FibGVkLiBGdWxsIGFjY2VzcyByZXN0b3JlZC5cIik7XG5cdFx0fVxuXHRcdHVwZGF0ZVN0YXR1cyhjdHgpO1xuXHR9XG5cblx0ZnVuY3Rpb24gcGVyc2lzdFN0YXRlKCk6IHZvaWQge1xuXHRcdHBpLmFwcGVuZEVudHJ5KFwicGxhbi1tb2RlXCIsIHtcblx0XHRcdGVuYWJsZWQ6IHBsYW5Nb2RlRW5hYmxlZCxcblx0XHRcdHRvZG9zOiB0b2RvSXRlbXMsXG5cdFx0XHRleGVjdXRpbmc6IGV4ZWN1dGlvbk1vZGUsXG5cdFx0fSk7XG5cdH1cblxuXHRwaS5yZWdpc3RlckNvbW1hbmQoXCJwbGFuXCIsIHtcblx0XHRkZXNjcmlwdGlvbjogXCJUb2dnbGUgcGxhbiBtb2RlIChyZWFkLW9ubHkgZXhwbG9yYXRpb24pXCIsXG5cdFx0aGFuZGxlcjogYXN5bmMgKF9hcmdzLCBjdHgpID0+IHRvZ2dsZVBsYW5Nb2RlKGN0eCksXG5cdH0pO1xuXG5cdHBpLnJlZ2lzdGVyQ29tbWFuZChcInRvZG9zXCIsIHtcblx0XHRkZXNjcmlwdGlvbjogXCJTaG93IGN1cnJlbnQgcGxhbiB0b2RvIGxpc3RcIixcblx0XHRoYW5kbGVyOiBhc3luYyAoX2FyZ3MsIGN0eCkgPT4ge1xuXHRcdFx0aWYgKHRvZG9JdGVtcy5sZW5ndGggPT09IDApIHtcblx0XHRcdFx0Y3R4LnVpLm5vdGlmeShcIk5vIHRvZG9zLiBDcmVhdGUgYSBwbGFuIGZpcnN0IHdpdGggL3BsYW5cIiwgXCJpbmZvXCIpO1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cdFx0XHRjb25zdCBsaXN0ID0gdG9kb0l0ZW1zLm1hcCgoaXRlbSwgaSkgPT4gYCR7aSArIDF9LiAke2l0ZW0uY29tcGxldGVkID8gXCLinJNcIiA6IFwi4peLXCJ9ICR7aXRlbS50ZXh0fWApLmpvaW4oXCJcXG5cIik7XG5cdFx0XHRjdHgudWkubm90aWZ5KGBQbGFuIFByb2dyZXNzOlxcbiR7bGlzdH1gLCBcImluZm9cIik7XG5cdFx0fSxcblx0fSk7XG5cblx0cGkucmVnaXN0ZXJTaG9ydGN1dChLZXkuY3RybEFsdChcInBcIiksIHtcblx0XHRkZXNjcmlwdGlvbjogXCJUb2dnbGUgcGxhbiBtb2RlXCIsXG5cdFx0aGFuZGxlcjogYXN5bmMgKGN0eCkgPT4gdG9nZ2xlUGxhbk1vZGUoY3R4KSxcblx0fSk7XG5cblx0Ly8gQmxvY2sgZGVzdHJ1Y3RpdmUgYmFzaCBjb21tYW5kcyBpbiBwbGFuIG1vZGVcblx0cGkub24oXCJ0b29sX2NhbGxcIiwgYXN5bmMgKGV2ZW50KSA9PiB7XG5cdFx0aWYgKCFwbGFuTW9kZUVuYWJsZWQgfHwgZXZlbnQudG9vbE5hbWUgIT09IFwiYmFzaFwiKSByZXR1cm47XG5cblx0XHRjb25zdCBjb21tYW5kID0gZXZlbnQuaW5wdXQuY29tbWFuZCBhcyBzdHJpbmc7XG5cdFx0aWYgKCFpc1NhZmVDb21tYW5kKGNvbW1hbmQpKSB7XG5cdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRibG9jazogdHJ1ZSxcblx0XHRcdFx0cmVhc29uOiBgUGxhbiBtb2RlOiBjb21tYW5kIGJsb2NrZWQgKG5vdCBhbGxvd2xpc3RlZCkuIFVzZSAvcGxhbiB0byBkaXNhYmxlIHBsYW4gbW9kZSBmaXJzdC5cXG5Db21tYW5kOiAke2NvbW1hbmR9YCxcblx0XHRcdH07XG5cdFx0fVxuXHR9KTtcblxuXHQvLyBGaWx0ZXIgb3V0IHN0YWxlIHBsYW4gbW9kZSBjb250ZXh0IHdoZW4gbm90IGluIHBsYW4gbW9kZVxuXHRwaS5vbihcImNvbnRleHRcIiwgYXN5bmMgKGV2ZW50KSA9PiB7XG5cdFx0aWYgKHBsYW5Nb2RlRW5hYmxlZCkgcmV0dXJuO1xuXG5cdFx0cmV0dXJuIHtcblx0XHRcdG1lc3NhZ2VzOiBldmVudC5tZXNzYWdlcy5maWx0ZXIoKG0pID0+IHtcblx0XHRcdFx0Y29uc3QgbXNnID0gbSBhcyBBZ2VudE1lc3NhZ2UgJiB7IGN1c3RvbVR5cGU/OiBzdHJpbmcgfTtcblx0XHRcdFx0aWYgKG1zZy5jdXN0b21UeXBlID09PSBcInBsYW4tbW9kZS1jb250ZXh0XCIpIHJldHVybiBmYWxzZTtcblx0XHRcdFx0aWYgKG1zZy5yb2xlICE9PSBcInVzZXJcIikgcmV0dXJuIHRydWU7XG5cblx0XHRcdFx0Y29uc3QgY29udGVudCA9IG1zZy5jb250ZW50O1xuXHRcdFx0XHRpZiAodHlwZW9mIGNvbnRlbnQgPT09IFwic3RyaW5nXCIpIHtcblx0XHRcdFx0XHRyZXR1cm4gIWNvbnRlbnQuaW5jbHVkZXMoXCJbUExBTiBNT0RFIEFDVElWRV1cIik7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKEFycmF5LmlzQXJyYXkoY29udGVudCkpIHtcblx0XHRcdFx0XHRyZXR1cm4gIWNvbnRlbnQuc29tZShcblx0XHRcdFx0XHRcdChjKSA9PiBjLnR5cGUgPT09IFwidGV4dFwiICYmIChjIGFzIFRleHRDb250ZW50KS50ZXh0Py5pbmNsdWRlcyhcIltQTEFOIE1PREUgQUNUSVZFXVwiKSxcblx0XHRcdFx0XHQpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fSksXG5cdFx0fTtcblx0fSk7XG5cblx0Ly8gSW5qZWN0IHBsYW4vZXhlY3V0aW9uIGNvbnRleHQgYmVmb3JlIGFnZW50IHN0YXJ0c1xuXHRwaS5vbihcImJlZm9yZV9hZ2VudF9zdGFydFwiLCBhc3luYyAoKSA9PiB7XG5cdFx0aWYgKHBsYW5Nb2RlRW5hYmxlZCkge1xuXHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0bWVzc2FnZToge1xuXHRcdFx0XHRcdGN1c3RvbVR5cGU6IFwicGxhbi1tb2RlLWNvbnRleHRcIixcblx0XHRcdFx0XHRjb250ZW50OiBgW1BMQU4gTU9ERSBBQ1RJVkVdXG5Zb3UgYXJlIGluIHBsYW4gbW9kZSAtIGEgcmVhZC1vbmx5IGV4cGxvcmF0aW9uIG1vZGUgZm9yIHNhZmUgY29kZSBhbmFseXNpcy5cblxuUmVzdHJpY3Rpb25zOlxuLSBZb3UgY2FuIG9ubHkgdXNlOiByZWFkLCBiYXNoLCBncmVwLCBmaW5kLCBscywgcXVlc3Rpb25uYWlyZVxuLSBZb3UgQ0FOTk9UIHVzZTogZWRpdCwgd3JpdGUgKGZpbGUgbW9kaWZpY2F0aW9ucyBhcmUgZGlzYWJsZWQpXG4tIEJhc2ggaXMgcmVzdHJpY3RlZCB0byBhbiBhbGxvd2xpc3Qgb2YgcmVhZC1vbmx5IGNvbW1hbmRzXG5cbkFzayBjbGFyaWZ5aW5nIHF1ZXN0aW9ucyB1c2luZyB0aGUgcXVlc3Rpb25uYWlyZSB0b29sLlxuVXNlIGJyYXZlLXNlYXJjaCBza2lsbCB2aWEgYmFzaCBmb3Igd2ViIHJlc2VhcmNoLlxuXG5DcmVhdGUgYSBkZXRhaWxlZCBudW1iZXJlZCBwbGFuIHVuZGVyIGEgXCJQbGFuOlwiIGhlYWRlcjpcblxuUGxhbjpcbjEuIEZpcnN0IHN0ZXAgZGVzY3JpcHRpb25cbjIuIFNlY29uZCBzdGVwIGRlc2NyaXB0aW9uXG4uLi5cblxuRG8gTk9UIGF0dGVtcHQgdG8gbWFrZSBjaGFuZ2VzIC0ganVzdCBkZXNjcmliZSB3aGF0IHlvdSB3b3VsZCBkby5gLFxuXHRcdFx0XHRcdGRpc3BsYXk6IGZhbHNlLFxuXHRcdFx0XHR9LFxuXHRcdFx0fTtcblx0XHR9XG5cblx0XHRpZiAoZXhlY3V0aW9uTW9kZSAmJiB0b2RvSXRlbXMubGVuZ3RoID4gMCkge1xuXHRcdFx0Y29uc3QgcmVtYWluaW5nID0gdG9kb0l0ZW1zLmZpbHRlcigodCkgPT4gIXQuY29tcGxldGVkKTtcblx0XHRcdGNvbnN0IHRvZG9MaXN0ID0gcmVtYWluaW5nLm1hcCgodCkgPT4gYCR7dC5zdGVwfS4gJHt0LnRleHR9YCkuam9pbihcIlxcblwiKTtcblx0XHRcdHJldHVybiB7XG5cdFx0XHRcdG1lc3NhZ2U6IHtcblx0XHRcdFx0XHRjdXN0b21UeXBlOiBcInBsYW4tZXhlY3V0aW9uLWNvbnRleHRcIixcblx0XHRcdFx0XHRjb250ZW50OiBgW0VYRUNVVElORyBQTEFOIC0gRnVsbCB0b29sIGFjY2VzcyBlbmFibGVkXVxuXG5SZW1haW5pbmcgc3RlcHM6XG4ke3RvZG9MaXN0fVxuXG5FeGVjdXRlIGVhY2ggc3RlcCBpbiBvcmRlci5cbkFmdGVyIGNvbXBsZXRpbmcgYSBzdGVwLCBpbmNsdWRlIGEgW0RPTkU6bl0gdGFnIGluIHlvdXIgcmVzcG9uc2UuYCxcblx0XHRcdFx0XHRkaXNwbGF5OiBmYWxzZSxcblx0XHRcdFx0fSxcblx0XHRcdH07XG5cdFx0fVxuXHR9KTtcblxuXHQvLyBUcmFjayBwcm9ncmVzcyBhZnRlciBlYWNoIHR1cm5cblx0cGkub24oXCJ0dXJuX2VuZFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuXHRcdGlmICghZXhlY3V0aW9uTW9kZSB8fCB0b2RvSXRlbXMubGVuZ3RoID09PSAwKSByZXR1cm47XG5cdFx0aWYgKCFpc0Fzc2lzdGFudE1lc3NhZ2UoZXZlbnQubWVzc2FnZSkpIHJldHVybjtcblxuXHRcdGNvbnN0IHRleHQgPSBnZXRUZXh0Q29udGVudChldmVudC5tZXNzYWdlKTtcblx0XHRpZiAobWFya0NvbXBsZXRlZFN0ZXBzKHRleHQsIHRvZG9JdGVtcykgPiAwKSB7XG5cdFx0XHR1cGRhdGVTdGF0dXMoY3R4KTtcblx0XHR9XG5cdFx0cGVyc2lzdFN0YXRlKCk7XG5cdH0pO1xuXG5cdC8vIEhhbmRsZSBwbGFuIGNvbXBsZXRpb24gYW5kIHBsYW4gbW9kZSBVSVxuXHRwaS5vbihcImFnZW50X2VuZFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuXHRcdC8vIENoZWNrIGlmIGV4ZWN1dGlvbiBpcyBjb21wbGV0ZVxuXHRcdGlmIChleGVjdXRpb25Nb2RlICYmIHRvZG9JdGVtcy5sZW5ndGggPiAwKSB7XG5cdFx0XHRpZiAodG9kb0l0ZW1zLmV2ZXJ5KCh0KSA9PiB0LmNvbXBsZXRlZCkpIHtcblx0XHRcdFx0Y29uc3QgY29tcGxldGVkTGlzdCA9IHRvZG9JdGVtcy5tYXAoKHQpID0+IGB+fiR7dC50ZXh0fX5+YCkuam9pbihcIlxcblwiKTtcblx0XHRcdFx0cGkuc2VuZE1lc3NhZ2UoXG5cdFx0XHRcdFx0eyBjdXN0b21UeXBlOiBcInBsYW4tY29tcGxldGVcIiwgY29udGVudDogYCoqUGxhbiBDb21wbGV0ZSEqKiDinJNcXG5cXG4ke2NvbXBsZXRlZExpc3R9YCwgZGlzcGxheTogdHJ1ZSB9LFxuXHRcdFx0XHRcdHsgdHJpZ2dlclR1cm46IGZhbHNlIH0sXG5cdFx0XHRcdCk7XG5cdFx0XHRcdGV4ZWN1dGlvbk1vZGUgPSBmYWxzZTtcblx0XHRcdFx0dG9kb0l0ZW1zID0gW107XG5cdFx0XHRcdHBpLnNldEFjdGl2ZVRvb2xzKE5PUk1BTF9NT0RFX1RPT0xTKTtcblx0XHRcdFx0dXBkYXRlU3RhdHVzKGN0eCk7XG5cdFx0XHRcdHBlcnNpc3RTdGF0ZSgpOyAvLyBTYXZlIGNsZWFyZWQgc3RhdGUgc28gcmVzdW1lIGRvZXNuJ3QgcmVzdG9yZSBvbGQgZXhlY3V0aW9uIG1vZGVcblx0XHRcdH1cblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIXBsYW5Nb2RlRW5hYmxlZCB8fCAhY3R4Lmhhc1VJKSByZXR1cm47XG5cblx0XHQvLyBFeHRyYWN0IHRvZG9zIGZyb20gbGFzdCBhc3Npc3RhbnQgbWVzc2FnZVxuXHRcdGNvbnN0IGxhc3RBc3Npc3RhbnQgPSBbLi4uZXZlbnQubWVzc2FnZXNdLnJldmVyc2UoKS5maW5kKGlzQXNzaXN0YW50TWVzc2FnZSk7XG5cdFx0aWYgKGxhc3RBc3Npc3RhbnQpIHtcblx0XHRcdGNvbnN0IGV4dHJhY3RlZCA9IGV4dHJhY3RUb2RvSXRlbXMoZ2V0VGV4dENvbnRlbnQobGFzdEFzc2lzdGFudCkpO1xuXHRcdFx0aWYgKGV4dHJhY3RlZC5sZW5ndGggPiAwKSB7XG5cdFx0XHRcdHRvZG9JdGVtcyA9IGV4dHJhY3RlZDtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBTaG93IHBsYW4gc3RlcHMgYW5kIHByb21wdCBmb3IgbmV4dCBhY3Rpb25cblx0XHRpZiAodG9kb0l0ZW1zLmxlbmd0aCA+IDApIHtcblx0XHRcdGNvbnN0IHRvZG9MaXN0VGV4dCA9IHRvZG9JdGVtcy5tYXAoKHQsIGkpID0+IGAke2kgKyAxfS4g4piQICR7dC50ZXh0fWApLmpvaW4oXCJcXG5cIik7XG5cdFx0XHRwaS5zZW5kTWVzc2FnZShcblx0XHRcdFx0e1xuXHRcdFx0XHRcdGN1c3RvbVR5cGU6IFwicGxhbi10b2RvLWxpc3RcIixcblx0XHRcdFx0XHRjb250ZW50OiBgKipQbGFuIFN0ZXBzICgke3RvZG9JdGVtcy5sZW5ndGh9KToqKlxcblxcbiR7dG9kb0xpc3RUZXh0fWAsXG5cdFx0XHRcdFx0ZGlzcGxheTogdHJ1ZSxcblx0XHRcdFx0fSxcblx0XHRcdFx0eyB0cmlnZ2VyVHVybjogZmFsc2UgfSxcblx0XHRcdCk7XG5cdFx0fVxuXG5cdFx0Y29uc3QgY2hvaWNlID0gYXdhaXQgY3R4LnVpLnNlbGVjdChcIlBsYW4gbW9kZSAtIHdoYXQgbmV4dD9cIiwgW1xuXHRcdFx0dG9kb0l0ZW1zLmxlbmd0aCA+IDAgPyBcIkV4ZWN1dGUgdGhlIHBsYW4gKHRyYWNrIHByb2dyZXNzKVwiIDogXCJFeGVjdXRlIHRoZSBwbGFuXCIsXG5cdFx0XHRcIlN0YXkgaW4gcGxhbiBtb2RlXCIsXG5cdFx0XHRcIlJlZmluZSB0aGUgcGxhblwiLFxuXHRcdF0pO1xuXG5cdFx0aWYgKGNob2ljZT8uc3RhcnRzV2l0aChcIkV4ZWN1dGVcIikpIHtcblx0XHRcdHBsYW5Nb2RlRW5hYmxlZCA9IGZhbHNlO1xuXHRcdFx0ZXhlY3V0aW9uTW9kZSA9IHRvZG9JdGVtcy5sZW5ndGggPiAwO1xuXHRcdFx0cGkuc2V0QWN0aXZlVG9vbHMoTk9STUFMX01PREVfVE9PTFMpO1xuXHRcdFx0dXBkYXRlU3RhdHVzKGN0eCk7XG5cblx0XHRcdGNvbnN0IGV4ZWNNZXNzYWdlID1cblx0XHRcdFx0dG9kb0l0ZW1zLmxlbmd0aCA+IDBcblx0XHRcdFx0XHQ/IGBFeGVjdXRlIHRoZSBwbGFuLiBTdGFydCB3aXRoOiAke3RvZG9JdGVtc1swXS50ZXh0fWBcblx0XHRcdFx0XHQ6IFwiRXhlY3V0ZSB0aGUgcGxhbiB5b3UganVzdCBjcmVhdGVkLlwiO1xuXHRcdFx0cGkuc2VuZE1lc3NhZ2UoXG5cdFx0XHRcdHsgY3VzdG9tVHlwZTogXCJwbGFuLW1vZGUtZXhlY3V0ZVwiLCBjb250ZW50OiBleGVjTWVzc2FnZSwgZGlzcGxheTogdHJ1ZSB9LFxuXHRcdFx0XHR7IHRyaWdnZXJUdXJuOiB0cnVlIH0sXG5cdFx0XHQpO1xuXHRcdH0gZWxzZSBpZiAoY2hvaWNlID09PSBcIlJlZmluZSB0aGUgcGxhblwiKSB7XG5cdFx0XHRjb25zdCByZWZpbmVtZW50ID0gYXdhaXQgY3R4LnVpLmVkaXRvcihcIlJlZmluZSB0aGUgcGxhbjpcIiwgXCJcIik7XG5cdFx0XHRpZiAocmVmaW5lbWVudD8udHJpbSgpKSB7XG5cdFx0XHRcdHBpLnNlbmRVc2VyTWVzc2FnZShyZWZpbmVtZW50LnRyaW0oKSk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9KTtcblxuXHQvLyBSZXN0b3JlIHN0YXRlIG9uIHNlc3Npb24gc3RhcnQvcmVzdW1lXG5cdHBpLm9uKFwic2Vzc2lvbl9zdGFydFwiLCBhc3luYyAoX2V2ZW50LCBjdHgpID0+IHtcblx0XHRpZiAocGkuZ2V0RmxhZyhcInBsYW5cIikgPT09IHRydWUpIHtcblx0XHRcdHBsYW5Nb2RlRW5hYmxlZCA9IHRydWU7XG5cdFx0fVxuXG5cdFx0Y29uc3QgZW50cmllcyA9IGN0eC5zZXNzaW9uTWFuYWdlci5nZXRFbnRyaWVzKCk7XG5cblx0XHQvLyBSZXN0b3JlIHBlcnNpc3RlZCBzdGF0ZVxuXHRcdGNvbnN0IHBsYW5Nb2RlRW50cnkgPSBlbnRyaWVzXG5cdFx0XHQuZmlsdGVyKChlOiB7IHR5cGU6IHN0cmluZzsgY3VzdG9tVHlwZT86IHN0cmluZyB9KSA9PiBlLnR5cGUgPT09IFwiY3VzdG9tXCIgJiYgZS5jdXN0b21UeXBlID09PSBcInBsYW4tbW9kZVwiKVxuXHRcdFx0LnBvcCgpIGFzIHsgZGF0YT86IHsgZW5hYmxlZDogYm9vbGVhbjsgdG9kb3M/OiBUb2RvSXRlbVtdOyBleGVjdXRpbmc/OiBib29sZWFuIH0gfSB8IHVuZGVmaW5lZDtcblxuXHRcdGlmIChwbGFuTW9kZUVudHJ5Py5kYXRhKSB7XG5cdFx0XHRwbGFuTW9kZUVuYWJsZWQgPSBwbGFuTW9kZUVudHJ5LmRhdGEuZW5hYmxlZCA/PyBwbGFuTW9kZUVuYWJsZWQ7XG5cdFx0XHR0b2RvSXRlbXMgPSBwbGFuTW9kZUVudHJ5LmRhdGEudG9kb3MgPz8gdG9kb0l0ZW1zO1xuXHRcdFx0ZXhlY3V0aW9uTW9kZSA9IHBsYW5Nb2RlRW50cnkuZGF0YS5leGVjdXRpbmcgPz8gZXhlY3V0aW9uTW9kZTtcblx0XHR9XG5cblx0XHQvLyBPbiByZXN1bWU6IHJlLXNjYW4gbWVzc2FnZXMgdG8gcmVidWlsZCBjb21wbGV0aW9uIHN0YXRlXG5cdFx0Ly8gT25seSBzY2FuIG1lc3NhZ2VzIEFGVEVSIHRoZSBsYXN0IFwicGxhbi1tb2RlLWV4ZWN1dGVcIiB0byBhdm9pZCBwaWNraW5nIHVwIFtET05FOm5dIGZyb20gcHJldmlvdXMgcGxhbnNcblx0XHRjb25zdCBpc1Jlc3VtZSA9IHBsYW5Nb2RlRW50cnkgIT09IHVuZGVmaW5lZDtcblx0XHRpZiAoaXNSZXN1bWUgJiYgZXhlY3V0aW9uTW9kZSAmJiB0b2RvSXRlbXMubGVuZ3RoID4gMCkge1xuXHRcdFx0Ly8gRmluZCB0aGUgaW5kZXggb2YgdGhlIGxhc3QgcGxhbi1tb2RlLWV4ZWN1dGUgZW50cnkgKG1hcmtzIHdoZW4gY3VycmVudCBleGVjdXRpb24gc3RhcnRlZClcblx0XHRcdGxldCBleGVjdXRlSW5kZXggPSAtMTtcblx0XHRcdGZvciAobGV0IGkgPSBlbnRyaWVzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG5cdFx0XHRcdGNvbnN0IGVudHJ5ID0gZW50cmllc1tpXSBhcyB7IHR5cGU6IHN0cmluZzsgY3VzdG9tVHlwZT86IHN0cmluZyB9O1xuXHRcdFx0XHRpZiAoZW50cnkuY3VzdG9tVHlwZSA9PT0gXCJwbGFuLW1vZGUtZXhlY3V0ZVwiKSB7XG5cdFx0XHRcdFx0ZXhlY3V0ZUluZGV4ID0gaTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBPbmx5IHNjYW4gbWVzc2FnZXMgYWZ0ZXIgdGhlIGV4ZWN1dGUgbWFya2VyXG5cdFx0XHRjb25zdCBtZXNzYWdlczogQXNzaXN0YW50TWVzc2FnZVtdID0gW107XG5cdFx0XHRmb3IgKGxldCBpID0gZXhlY3V0ZUluZGV4ICsgMTsgaSA8IGVudHJpZXMubGVuZ3RoOyBpKyspIHtcblx0XHRcdFx0Y29uc3QgZW50cnkgPSBlbnRyaWVzW2ldO1xuXHRcdFx0XHRpZiAoZW50cnkudHlwZSA9PT0gXCJtZXNzYWdlXCIgJiYgXCJtZXNzYWdlXCIgaW4gZW50cnkgJiYgaXNBc3Npc3RhbnRNZXNzYWdlKGVudHJ5Lm1lc3NhZ2UgYXMgQWdlbnRNZXNzYWdlKSkge1xuXHRcdFx0XHRcdG1lc3NhZ2VzLnB1c2goZW50cnkubWVzc2FnZSBhcyBBc3Npc3RhbnRNZXNzYWdlKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0Y29uc3QgYWxsVGV4dCA9IG1lc3NhZ2VzLm1hcChnZXRUZXh0Q29udGVudCkuam9pbihcIlxcblwiKTtcblx0XHRcdG1hcmtDb21wbGV0ZWRTdGVwcyhhbGxUZXh0LCB0b2RvSXRlbXMpO1xuXHRcdH1cblxuXHRcdGlmIChwbGFuTW9kZUVuYWJsZWQpIHtcblx0XHRcdHBpLnNldEFjdGl2ZVRvb2xzKFBMQU5fTU9ERV9UT09MUyk7XG5cdFx0fVxuXHRcdHVwZGF0ZVN0YXR1cyhjdHgpO1xuXHR9KTtcbn1cbiJ9XSwiaXNFcnJvciI6ZmFsc2UsInRpbWVzdGFtcCI6MTc4MTk1NDU0ODc5M319LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6ImU1MTM0YjQ4IiwicGFyZW50SWQiOiJjMjNhNzk1MSIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MjI6MzMuNjcwWiIsIm1lc3NhZ2UiOnsicm9sZSI6ImFzc2lzdGFudCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0aGlua2luZyIsInRoaW5raW5nIjoiTm93IGxldCBtZSBhbHNvIGxvb2sgYXQgdGhlIHR5cGVzIGZvciB0b29sX3Jlc3VsdCBhbmQgaXNCYXNoVG9vbFJlc3VsdCB0byB1bmRlcnN0YW5kIHRoZSBBUEkgYmV0dGVyLCB0aGVuIEkgY2FuIGV4cGxhaW4gdGhvcm91Z2hseS4iLCJ0aGlua2luZ1NpZ25hdHVyZSI6InJlYXNvbmluZyJ9LHsidHlwZSI6InRleHQiLCJ0ZXh0IjoiTm93IGxldCBtZSBhbHNvIGNoZWNrIHdoYXQgYGlzQmFzaFRvb2xSZXN1bHRgIGFuZCByZWxhdGVkIHR5cGVzIGxvb2sgbGlrZToifSx7InR5cGUiOiJ0b29sQ2FsbCIsImlkIjoiY2FsbF8wMF81RUdYNHQzOXhsbU5nQnB5SmVIRTY5NzMiLCJuYW1lIjoicmVhZCIsImFyZ3VtZW50cyI6eyJwYXRoIjoiL1VzZXJzL3dpbGxlbS8ubG9jYWwvc2hhcmUvbWlzZS9pbnN0YWxscy9ub2RlLzI0LjAuMS9saWIvbm9kZV9tb2R1bGVzL0BlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnQvZXhhbXBsZXMvZXh0ZW5zaW9ucy9zdGF0dXMtbGluZS50cyJ9fSx7InR5cGUiOiJ0b29sQ2FsbCIsImlkIjoiY2FsbF8wMV80MHFIeW1ncnUwbHFUdTFiWWIwcjA5MTgiLCJuYW1lIjoicmVhZCIsImFyZ3VtZW50cyI6eyJwYXRoIjoiL1VzZXJzL3dpbGxlbS8ubG9jYWwvc2hhcmUvbWlzZS9pbnN0YWxscy9ub2RlLzI0LjAuMS9saWIvbm9kZV9tb2R1bGVzL0BlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnQvZXhhbXBsZXMvZXh0ZW5zaW9ucy90b29sLW92ZXJyaWRlLnRzIn19XSwiYXBpIjoib3BlbmFpLWNvbXBsZXRpb25zIiwicHJvdmlkZXIiOiJvcGVucm91dGVyIiwibW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaCIsInVzYWdlIjp7ImlucHV0IjoxMzIyNywib3V0cHV0IjoyMDAsImNhY2hlUmVhZCI6MTk4NDAsImNhY2hlV3JpdGUiOjAsInRvdGFsVG9rZW5zIjozMzI2NywiY29zdCI6eyJpbnB1dCI6MC4wMDExOTA0Mywib3V0cHV0IjowLjAwMDAzNiwiY2FjaGVSZWFkIjowLjAwMDM5NjgsImNhY2hlV3JpdGUiOjAsInRvdGFsIjowLjAwMTYyMzIyOTk5OTk5OTk5OTh9fSwic3RvcFJlYXNvbiI6InRvb2xVc2UiLCJ0aW1lc3RhbXAiOjE3ODE5NTQ1NDg3OTUsInJlc3BvbnNlSWQiOiJnZW4tMTc4MTk1NDU0OC1yS0NINnZ2ampXbVp3QTYzTWZWOSIsInJlc3BvbnNlTW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaC0yMDI2MDQyMyJ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiJiNzU3YjY3ZSIsInBhcmVudElkIjoiZTUxMzRiNDgiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjIyOjMzLjY3N1oiLCJtZXNzYWdlIjp7InJvbGUiOiJ0b29sUmVzdWx0IiwidG9vbENhbGxJZCI6ImNhbGxfMDBfNUVHWDR0Mzl4bG1OZ0JweUplSEU2OTczIiwidG9vbE5hbWUiOiJyZWFkIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiLyoqXG4gKiBTdGF0dXMgTGluZSBFeHRlbnNpb25cbiAqXG4gKiBEZW1vbnN0cmF0ZXMgY3R4LnVpLnNldFN0YXR1cygpIGZvciBkaXNwbGF5aW5nIHBlcnNpc3RlbnQgc3RhdHVzIHRleHQgaW4gdGhlIGZvb3Rlci5cbiAqIFNob3dzIHR1cm4gcHJvZ3Jlc3Mgd2l0aCB0aGVtZWQgY29sb3JzLlxuICovXG5cbmltcG9ydCB0eXBlIHsgRXh0ZW5zaW9uQVBJIH0gZnJvbSBcIkBlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnRcIjtcblxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gKHBpOiBFeHRlbnNpb25BUEkpIHtcblx0bGV0IHR1cm5Db3VudCA9IDA7XG5cblx0cGkub24oXCJzZXNzaW9uX3N0YXJ0XCIsIGFzeW5jIChfZXZlbnQsIGN0eCkgPT4ge1xuXHRcdGNvbnN0IHRoZW1lID0gY3R4LnVpLnRoZW1lO1xuXHRcdGN0eC51aS5zZXRTdGF0dXMoXCJzdGF0dXMtZGVtb1wiLCB0aGVtZS5mZyhcImRpbVwiLCBcIlJlYWR5XCIpKTtcblx0fSk7XG5cblx0cGkub24oXCJ0dXJuX3N0YXJ0XCIsIGFzeW5jIChfZXZlbnQsIGN0eCkgPT4ge1xuXHRcdHR1cm5Db3VudCsrO1xuXHRcdGNvbnN0IHRoZW1lID0gY3R4LnVpLnRoZW1lO1xuXHRcdGNvbnN0IHNwaW5uZXIgPSB0aGVtZS5mZyhcImFjY2VudFwiLCBcIuKXj1wiKTtcblx0XHRjb25zdCB0ZXh0ID0gdGhlbWUuZmcoXCJkaW1cIiwgYCBUdXJuICR7dHVybkNvdW50fS4uLmApO1xuXHRcdGN0eC51aS5zZXRTdGF0dXMoXCJzdGF0dXMtZGVtb1wiLCBzcGlubmVyICsgdGV4dCk7XG5cdH0pO1xuXG5cdHBpLm9uKFwidHVybl9lbmRcIiwgYXN5bmMgKF9ldmVudCwgY3R4KSA9PiB7XG5cdFx0Y29uc3QgdGhlbWUgPSBjdHgudWkudGhlbWU7XG5cdFx0Y29uc3QgY2hlY2sgPSB0aGVtZS5mZyhcInN1Y2Nlc3NcIiwgXCLinJNcIik7XG5cdFx0Y29uc3QgdGV4dCA9IHRoZW1lLmZnKFwiZGltXCIsIGAgVHVybiAke3R1cm5Db3VudH0gY29tcGxldGVgKTtcblx0XHRjdHgudWkuc2V0U3RhdHVzKFwic3RhdHVzLWRlbW9cIiwgY2hlY2sgKyB0ZXh0KTtcblx0fSk7XG59XG4ifV0sImlzRXJyb3IiOmZhbHNlLCJ0aW1lc3RhbXAiOjE3ODE5NTQ1NTM2Nzd9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiJhZDYxNWZiYyIsInBhcmVudElkIjoiYjc1N2I2N2UiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjIyOjMzLjY3OFoiLCJtZXNzYWdlIjp7InJvbGUiOiJ0b29sUmVzdWx0IiwidG9vbENhbGxJZCI6ImNhbGxfMDFfNDBxSHltZ3J1MGxxVHUxYlliMHIwOTE4IiwidG9vbE5hbWUiOiJyZWFkIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiLyoqXG4gKiBUb29sIE92ZXJyaWRlIEV4YW1wbGUgLSBEZW1vbnN0cmF0ZXMgb3ZlcnJpZGluZyBidWlsdC1pbiB0b29sc1xuICpcbiAqIEV4dGVuc2lvbnMgY2FuIHJlZ2lzdGVyIHRvb2xzIHdpdGggdGhlIHNhbWUgbmFtZSBhcyBidWlsdC1pbiB0b29scyB0byByZXBsYWNlIHRoZW0uXG4gKiBUaGlzIGlzIHVzZWZ1bCBmb3I6XG4gKiAtIEFkZGluZyBsb2dnaW5nIG9yIGF1ZGl0aW5nIHRvIHRvb2wgY2FsbHNcbiAqIC0gSW1wbGVtZW50aW5nIGFjY2VzcyBjb250cm9sIG9yIHNhbmRib3hpbmdcbiAqIC0gUm91dGluZyB0b29sIGNhbGxzIHRvIHJlbW90ZSBzeXN0ZW1zIChlLmcuLCBwaS1zc2gtcmVtb3RlKVxuICogLSBNb2RpZnlpbmcgdG9vbCBiZWhhdmlvciBmb3Igc3BlY2lmaWMgd29ya2Zsb3dzXG4gKlxuICogVGhpcyBleGFtcGxlIG92ZXJyaWRlcyB0aGUgYHJlYWRgIHRvb2wgdG86XG4gKiAxLiBMb2cgYWxsIGZpbGUgYWNjZXNzIHRvIGEgbG9nIGZpbGVcbiAqIDIuIEJsb2NrIGFjY2VzcyB0byBzZW5zaXRpdmUgcGF0aHMgKGUuZy4sIC5lbnYgZmlsZXMpXG4gKiAzLiBEZWxlZ2F0ZSB0byB0aGUgb3JpZ2luYWwgcmVhZCBpbXBsZW1lbnRhdGlvbiBmb3IgYWxsb3dlZCBmaWxlc1xuICpcbiAqIFNpbmNlIG5vIGN1c3RvbSByZW5kZXJDYWxsL3JlbmRlclJlc3VsdCBhcmUgcHJvdmlkZWQsIHRoZSBidWlsdC1pbiByZW5kZXJlclxuICogaXMgdXNlZCBhdXRvbWF0aWNhbGx5IChzeW50YXggaGlnaGxpZ2h0aW5nLCBsaW5lIG51bWJlcnMsIHRydW5jYXRpb24gd2FybmluZ3MpLlxuICpcbiAqIFVzYWdlOlxuICogICBwaSAtZSAuL3Rvb2wtb3ZlcnJpZGUudHNcbiAqL1xuXG5pbXBvcnQgdHlwZSB7IFRleHRDb250ZW50IH0gZnJvbSBcIkBlYXJlbmRpbC13b3Jrcy9waS1haVwiO1xuaW1wb3J0IHsgdHlwZSBFeHRlbnNpb25BUEksIGdldEFnZW50RGlyLCB3aXRoRmlsZU11dGF0aW9uUXVldWUgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudFwiO1xuaW1wb3J0IHsgY29uc3RhbnRzLCByZWFkRmlsZVN5bmMgfSBmcm9tIFwiZnNcIjtcbmltcG9ydCB7IGFjY2VzcywgYXBwZW5kRmlsZSwgcmVhZEZpbGUgfSBmcm9tIFwiZnMvcHJvbWlzZXNcIjtcbmltcG9ydCB7IGpvaW4sIHJlc29sdmUgfSBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgVHlwZSB9IGZyb20gXCJ0eXBlYm94XCI7XG5cbmNvbnN0IExPR19GSUxFID0gam9pbihnZXRBZ2VudERpcigpLCBcInJlYWQtYWNjZXNzLmxvZ1wiKTtcblxuLy8gUGF0aHMgdGhhdCBhcmUgYmxvY2tlZCBmcm9tIHJlYWRpbmdcbmNvbnN0IEJMT0NLRURfUEFUVEVSTlMgPSBbXG5cdC9cXC5lbnYkLyxcblx0L1xcLmVudlxcLi4rJC8sXG5cdC9zZWNyZXRzP1xcLihqc29ufHlhbWx8eW1sfHRvbWwpJC9pLFxuXHQvY3JlZGVudGlhbHM/XFwuKGpzb258eWFtbHx5bWx8dG9tbCkkL2ksXG5cdC9cXC9cXC5zc2hcXC8vLFxuXHQvXFwvXFwuYXdzXFwvLyxcblx0L1xcL1xcLmdudXBnXFwvLyxcbl07XG5cbmZ1bmN0aW9uIGlzQmxvY2tlZFBhdGgocGF0aDogc3RyaW5nKTogYm9vbGVhbiB7XG5cdHJldHVybiBCTE9DS0VEX1BBVFRFUk5TLnNvbWUoKHBhdHRlcm4pID0+IHBhdHRlcm4udGVzdChwYXRoKSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGxvZ0FjY2VzcyhwYXRoOiBzdHJpbmcsIGFsbG93ZWQ6IGJvb2xlYW4sIHJlYXNvbj86IHN0cmluZykge1xuXHRjb25zdCB0aW1lc3RhbXAgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCk7XG5cdGNvbnN0IHN0YXR1cyA9IGFsbG93ZWQgPyBcIkFMTE9XRURcIiA6IFwiQkxPQ0tFRFwiO1xuXHRjb25zdCBtc2cgPSByZWFzb24gPyBgICgke3JlYXNvbn0pYCA6IFwiXCI7XG5cdGNvbnN0IGxpbmUgPSBgWyR7dGltZXN0YW1wfV0gJHtzdGF0dXN9OiAke3BhdGh9JHttc2d9XFxuYDtcblxuXHR0cnkge1xuXHRcdGF3YWl0IHdpdGhGaWxlTXV0YXRpb25RdWV1ZShMT0dfRklMRSwgYXN5bmMgKCkgPT4ge1xuXHRcdFx0YXdhaXQgYXBwZW5kRmlsZShMT0dfRklMRSwgbGluZSk7XG5cdFx0fSk7XG5cdH0gY2F0Y2gge1xuXHRcdC8vIElnbm9yZSBsb2dnaW5nIGVycm9yc1xuXHR9XG59XG5cbmNvbnN0IHJlYWRTY2hlbWEgPSBUeXBlLk9iamVjdCh7XG5cdHBhdGg6IFR5cGUuU3RyaW5nKHsgZGVzY3JpcHRpb246IFwiUGF0aCB0byB0aGUgZmlsZSB0byByZWFkIChyZWxhdGl2ZSBvciBhYnNvbHV0ZSlcIiB9KSxcblx0b2Zmc2V0OiBUeXBlLk9wdGlvbmFsKFR5cGUuTnVtYmVyKHsgZGVzY3JpcHRpb246IFwiTGluZSBudW1iZXIgdG8gc3RhcnQgcmVhZGluZyBmcm9tICgxLWluZGV4ZWQpXCIgfSkpLFxuXHRsaW1pdDogVHlwZS5PcHRpb25hbChUeXBlLk51bWJlcih7IGRlc2NyaXB0aW9uOiBcIk1heGltdW0gbnVtYmVyIG9mIGxpbmVzIHRvIHJlYWRcIiB9KSksXG59KTtcblxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gKHBpOiBFeHRlbnNpb25BUEkpIHtcblx0cGkucmVnaXN0ZXJUb29sKHtcblx0XHRuYW1lOiBcInJlYWRcIiwgLy8gU2FtZSBuYW1lIGFzIGJ1aWx0LWluIC0gdGhpcyB3aWxsIG92ZXJyaWRlIGl0XG5cdFx0bGFiZWw6IFwicmVhZCAoYXVkaXRlZClcIixcblx0XHRkZXNjcmlwdGlvbjpcblx0XHRcdFwiUmVhZCB0aGUgY29udGVudHMgb2YgYSBmaWxlIHdpdGggYWNjZXNzIGxvZ2dpbmcuIFNvbWUgc2Vuc2l0aXZlIHBhdGhzICguZW52LCBzZWNyZXRzLCBjcmVkZW50aWFscykgYXJlIGJsb2NrZWQuXCIsXG5cdFx0cGFyYW1ldGVyczogcmVhZFNjaGVtYSxcblxuXHRcdGFzeW5jIGV4ZWN1dGUoX3Rvb2xDYWxsSWQsIHBhcmFtcywgX3NpZ25hbCwgX29uVXBkYXRlLCBjdHgpIHtcblx0XHRcdGNvbnN0IHsgcGF0aCwgb2Zmc2V0LCBsaW1pdCB9ID0gcGFyYW1zO1xuXHRcdFx0Y29uc3QgYWJzb2x1dGVQYXRoID0gcmVzb2x2ZShjdHguY3dkLCBwYXRoKTtcblxuXHRcdFx0Ly8gQ2hlY2sgaWYgcGF0aCBpcyBibG9ja2VkXG5cdFx0XHRpZiAoaXNCbG9ja2VkUGF0aChhYnNvbHV0ZVBhdGgpKSB7XG5cdFx0XHRcdGF3YWl0IGxvZ0FjY2VzcyhhYnNvbHV0ZVBhdGgsIGZhbHNlLCBcIm1hdGNoZXMgYmxvY2tlZCBwYXR0ZXJuXCIpO1xuXHRcdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRcdGNvbnRlbnQ6IFtcblx0XHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdFx0dHlwZTogXCJ0ZXh0XCIsXG5cdFx0XHRcdFx0XHRcdHRleHQ6IGBBY2Nlc3MgZGVuaWVkOiBcIiR7cGF0aH1cIiBtYXRjaGVzIGEgYmxvY2tlZCBwYXR0ZXJuIChzZW5zaXRpdmUgZmlsZSkuIFRoaXMgdG9vbCBibG9ja3MgYWNjZXNzIHRvIC5lbnYgZmlsZXMsIHNlY3JldHMsIGNyZWRlbnRpYWxzLCBhbmQgU1NIL0FXUy9HUEcgZGlyZWN0b3JpZXMuYCxcblx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XSxcblx0XHRcdFx0XHRkZXRhaWxzOiB7IGJsb2NrZWQ6IHRydWUgfSxcblx0XHRcdFx0fTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gTG9nIGFsbG93ZWQgYWNjZXNzXG5cdFx0XHRhd2FpdCBsb2dBY2Nlc3MoYWJzb2x1dGVQYXRoLCB0cnVlKTtcblxuXHRcdFx0Ly8gUGVyZm9ybSB0aGUgYWN0dWFsIHJlYWQgKHNpbXBsaWZpZWQgaW1wbGVtZW50YXRpb24pXG5cdFx0XHR0cnkge1xuXHRcdFx0XHRhd2FpdCBhY2Nlc3MoYWJzb2x1dGVQYXRoLCBjb25zdGFudHMuUl9PSyk7XG5cdFx0XHRcdGNvbnN0IGNvbnRlbnQgPSBhd2FpdCByZWFkRmlsZShhYnNvbHV0ZVBhdGgsIFwidXRmLThcIik7XG5cdFx0XHRcdGNvbnN0IGxpbmVzID0gY29udGVudC5zcGxpdChcIlxcblwiKTtcblxuXHRcdFx0XHQvLyBBcHBseSBvZmZzZXQgYW5kIGxpbWl0XG5cdFx0XHRcdGNvbnN0IHN0YXJ0TGluZSA9IG9mZnNldCA/IE1hdGgubWF4KDAsIG9mZnNldCAtIDEpIDogMDtcblx0XHRcdFx0Y29uc3QgZW5kTGluZSA9IGxpbWl0ID8gc3RhcnRMaW5lICsgbGltaXQgOiBsaW5lcy5sZW5ndGg7XG5cdFx0XHRcdGNvbnN0IHNlbGVjdGVkTGluZXMgPSBsaW5lcy5zbGljZShzdGFydExpbmUsIGVuZExpbmUpO1xuXG5cdFx0XHRcdC8vIEJhc2ljIHRydW5jYXRpb24gKDUwS0IgbGltaXQpXG5cdFx0XHRcdGxldCB0ZXh0ID0gc2VsZWN0ZWRMaW5lcy5qb2luKFwiXFxuXCIpO1xuXHRcdFx0XHRjb25zdCBtYXhCeXRlcyA9IDUwICogMTAyNDtcblx0XHRcdFx0aWYgKEJ1ZmZlci5ieXRlTGVuZ3RoKHRleHQsIFwidXRmLThcIikgPiBtYXhCeXRlcykge1xuXHRcdFx0XHRcdHRleHQgPSBgJHt0ZXh0LnNsaWNlKDAsIG1heEJ5dGVzKX1cXG5cXG5bT3V0cHV0IHRydW5jYXRlZCBhdCA1MEtCXWA7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRcdGNvbnRlbnQ6IFt7IHR5cGU6IFwidGV4dFwiLCB0ZXh0IH1dIGFzIFRleHRDb250ZW50W10sXG5cdFx0XHRcdFx0ZGV0YWlsczogeyBsaW5lczogbGluZXMubGVuZ3RoIH0sXG5cdFx0XHRcdH07XG5cdFx0XHR9IGNhdGNoIChlcnJvcjogYW55KSB7XG5cdFx0XHRcdHJldHVybiB7XG5cdFx0XHRcdFx0Y29udGVudDogW3sgdHlwZTogXCJ0ZXh0XCIsIHRleHQ6IGBFcnJvciByZWFkaW5nIGZpbGU6ICR7ZXJyb3IubWVzc2FnZX1gIH1dIGFzIFRleHRDb250ZW50W10sXG5cdFx0XHRcdFx0ZGV0YWlsczogeyBlcnJvcjogdHJ1ZSB9LFxuXHRcdFx0XHR9O1xuXHRcdFx0fVxuXHRcdH0sXG5cblx0XHQvLyBObyByZW5kZXJDYWxsL3JlbmRlclJlc3VsdCAtIHVzZXMgYnVpbHQtaW4gcmVuZGVyZXIgYXV0b21hdGljYWxseVxuXHRcdC8vIChzeW50YXggaGlnaGxpZ2h0aW5nLCBsaW5lIG51bWJlcnMsIHRydW5jYXRpb24gd2FybmluZ3MsIGV0Yy4pXG5cdH0pO1xuXG5cdC8vIEFsc28gcmVnaXN0ZXIgYSBjb21tYW5kIHRvIHZpZXcgdGhlIGFjY2VzcyBsb2dcblx0cGkucmVnaXN0ZXJDb21tYW5kKFwicmVhZC1sb2dcIiwge1xuXHRcdGRlc2NyaXB0aW9uOiBcIlZpZXcgdGhlIGZpbGUgYWNjZXNzIGxvZ1wiLFxuXHRcdGhhbmRsZXI6IGFzeW5jIChfYXJncywgY3R4KSA9PiB7XG5cdFx0XHR0cnkge1xuXHRcdFx0XHRjb25zdCBsb2cgPSByZWFkRmlsZVN5bmMoTE9HX0ZJTEUsIFwidXRmLThcIik7XG5cdFx0XHRcdGNvbnN0IGxpbmVzID0gbG9nLnRyaW0oKS5zcGxpdChcIlxcblwiKS5zbGljZSgtMjApOyAvLyBMYXN0IDIwIGVudHJpZXNcblx0XHRcdFx0Y3R4LnVpLm5vdGlmeShgUmVjZW50IGZpbGUgYWNjZXNzOlxcbiR7bGluZXMuam9pbihcIlxcblwiKX1gLCBcImluZm9cIik7XG5cdFx0XHR9IGNhdGNoIHtcblx0XHRcdFx0Y3R4LnVpLm5vdGlmeShcIk5vIGFjY2VzcyBsb2cgZm91bmRcIiwgXCJpbmZvXCIpO1xuXHRcdFx0fVxuXHRcdH0sXG5cdH0pO1xufVxuIn1dLCJpc0Vycm9yIjpmYWxzZSwidGltZXN0YW1wIjoxNzgxOTU0NTUzNjc4fX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiYjY1Zjg3NjkiLCJwYXJlbnRJZCI6ImFkNjE1ZmJjIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToyMzowNi41NzlaIiwibWVzc2FnZSI6eyJyb2xlIjoiYXNzaXN0YW50IiwiY29udGVudCI6W3sidHlwZSI6InRoaW5raW5nIiwidGhpbmtpbmciOiJOb3cgSSBoYXZlIGEgdGhvcm91Z2ggdW5kZXJzdGFuZGluZy4gTGV0IG1lIGV4cGxhaW4gaG93IGV4dGVuc2lvbnMgd29yayBzdGVwIGJ5IHN0ZXAsIGZvY3VzaW5nIG9uIHRoZSBhcmNoaXRlY3R1cmUgYW5kIHRoZW4gaG93IE9wdGlvbiAyIHdvdWxkIHdvcmsgc3BlY2lmaWNhbGx5LlxuXG5MZXQgbWUgc3RydWN0dXJlIHRoZSBleHBsYW5hdGlvbjpcblxuMS4gKipXaGF0IGlzIGFuIGV4dGVuc2lvbj8qKiAtIEEgVHlwZVNjcmlwdCBtb2R1bGUgdGhhdCBleHBvcnRzIGEgZmFjdG9yeSBmdW5jdGlvblxuMi4gKipFeHRlbnNpb24gbGlmZWN5Y2xlKiogLSBIb3cgdGhleSBsb2FkLCB0aGUgZXZlbnQgc3lzdGVtXG4zLiAqKlRoZSBldmVudCB3ZSBuZWVkOiBgdG9vbF9yZXN1bHRgKiogLSBGaXJlZCBhZnRlciBldmVyeSB0b29sIGV4ZWN1dGlvblxuNC4gKipEZXRlY3RpbmcgdGVzdCBjb21tYW5kcyoqIC0gUGFyc2UgdGhlIGJhc2ggY29tbWFuZFxuNS4gKipQYXJzaW5nIHZpdGVzdCBvdXRwdXQqKiAtIFJlZ2V4IGZvciBwYXNzL2ZhaWxcbjYuICoqVXNpbmcgYGN0eC51aS5zZXRXaWRnZXQoKWAqKiAtIFBlcnNpc3RlbnQgd2lkZ2V0IGFib3ZlIHRoZSBlZGl0b3JcbjcuICoqUHV0dGluZyBpdCBhbGwgdG9nZXRoZXIqKiAtIFRoZSBmdWxsIGV4dGVuc2lvblxuXG5MZXQgbWUgd3JpdGUgdGhpcyB1cCBjbGVhcmx5LiIsInRoaW5raW5nU2lnbmF0dXJlIjoicmVhc29uaW5nIn0seyJ0eXBlIjoidGV4dCIsInRleHQiOiJMZXQgbWUgd2FsayB0aHJvdWdoIHRoZSBhcmNoaXRlY3R1cmUgc3RlcCBieSBzdGVwLlxuXG4tLS1cblxuIyMgSG93IFBpIEV4dGVuc2lvbnMgV29yayDigJQgVGhlIEJpZyBQaWN0dXJlXG5cbkFuIGV4dGVuc2lvbiBpcyBhICoqVHlwZVNjcmlwdCBmaWxlKiogdGhhdCBleHBvcnRzIGEgZGVmYXVsdCBmdW5jdGlvbi4gUGkgbG9hZHMgaXQgYXQgc3RhcnR1cCBhbmQgY2FsbHMgeW91ciBmdW5jdGlvbiB3aXRoIGFuIGBFeHRlbnNpb25BUElgIG9iamVjdCDigJQgeW91ciBob29rIGludG8gZXZlcnl0aGluZy5cblxuYGBgdHlwZXNjcmlwdFxuLy8gVGhlIHNpbXBsZXN0IHBvc3NpYmxlIGV4dGVuc2lvblxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gKHBpOiBFeHRlbnNpb25BUEkpIHtcbiAgLy8gcGkgaXMgeW91ciBBUEkgb2JqZWN0IOKAlCByZWdpc3RlciB0b29scywgc3Vic2NyaWJlIHRvIGV2ZW50cywgZXRjLlxufVxuYGBgXG5cbiMjIyBUaGUgRXZlbnQgU3lzdGVtXG5cbkV2ZXJ5dGhpbmcgaW4gUGkgcnVucyBvbiAqKmV2ZW50cyoqLiBUaGluayBvZiBpdCBsaWtlIE5vZGUuanMncyBgRXZlbnRFbWl0dGVyYCBvciBhIHdlYmhvb2sgc3lzdGVtIOKAlCBldmVudHMgZmlyZSBhdCBldmVyeSBsaWZlY3ljbGUgbW9tZW50OlxuXG5gYGBcblVzZXIgdHlwZXMgcHJvbXB0IOKGkiBpbnB1dCDihpIgYmVmb3JlX2FnZW50X3N0YXJ0IOKGkiBhZ2VudF9zdGFydFxuICDihpIgdHVybl9zdGFydCDihpIgY29udGV4dCDihpIgTExNIGNhbGxzIHRvb2wg4oaSIHRvb2xfY2FsbCDihpIgdG9vbCBleGVjdXRlcyDihpIgdG9vbF9yZXN1bHRcbiAg4oaSIHR1cm5fZW5kIOKGkiBhZ2VudF9lbmRcbmBgYFxuXG5Zb3Ugc3Vic2NyaWJlIHdpdGggYHBpLm9uKFwiZXZlbnRfbmFtZVwiLCBoYW5kbGVyKWA6XG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwidG9vbF9yZXN1bHRcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gRmlyZXMgYWZ0ZXIgZXZlcnkgc2luZ2xlIHRvb2wgZXhlY3V0aW9uIChiYXNoLCByZWFkLCB3cml0ZSwgZWRpdC4uLilcbiAgLy8gZXZlbnQudG9vbE5hbWUg4oCUIFwiYmFzaFwiXG4gIC8vIGV2ZW50LmNvbnRlbnQgIOKAlCB0aGUgdG9vbCdzIG91dHB1dFxuICAvLyBjdHgudWkgICAgICAgICDigJQgVUkgaGVscGVycyAoc2V0V2lkZ2V0LCBzZXRTdGF0dXMsIG5vdGlmeS4uLilcbn0pO1xuYGBgXG5cbkhhbmRsZXJzIGNhbiAqKmJsb2NrKiosICoqbW9kaWZ5KiosIG9yIGp1c3QgKipvYnNlcnZlKiog4oCUIGRlcGVuZGluZyBvbiB0aGUgZXZlbnQgdHlwZS5cblxuLS0tXG5cbiMjIEZvciBPdXIgVGVzdCBEb3Q6IFN0ZXAgYnkgU3RlcFxuXG4jIyMgU3RlcCAxIOKAlCBUaGUgcmlnaHQgZXZlbnRcblxuV2UgbmVlZCB0byBydW4gKiphZnRlcioqIHRoZSBMTE0gcnVucyBgbnBtIHRlc3RgLiBUaGF0J3MgdGhlIGB0b29sX3Jlc3VsdGAgZXZlbnQ6XG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwidG9vbF9yZXN1bHRcIiwgYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgLy8gZXZlbnQudG9vbE5hbWUg4oCUIHdoaWNoIHRvb2wgd2FzIGNhbGxlZCAoXCJiYXNoXCIsIFwicmVhZFwiLCBldGMuKVxuICAvLyBldmVudC5pbnB1dCAgICDigJQgdGhlIG9yaWdpbmFsIGFyZ3VtZW50cyAoZS5nLiwgeyBjb21tYW5kOiBcIm5wbSB0ZXN0XCIgfSlcbiAgLy8gZXZlbnQuY29udGVudCAg4oCUIHRoZSBvdXRwdXQgKGFycmF5IG9mIHsgdHlwZSwgdGV4dCB9KVxuICAvLyBldmVudC5pc0Vycm9yICDigJQgd2hldGhlciBpdCBlcnJvcmVkXG59KTtcbmBgYFxuXG5CdXQgdGhpcyBmaXJlcyBmb3IgKipldmVyeSoqIHRvb2wgY2FsbCDigJQgcmVhZHMsIHdyaXRlcywgZWRpdHMuIFdlIG9ubHkgY2FyZSBhYm91dCB0ZXN0IHJ1bnMuXG5cbiMjIyBTdGVwIDIg4oCUIEZpbHRlciB0byB0ZXN0IGNvbW1hbmRzXG5cbldlIGNoZWNrIGlmIHRoZSBiYXNoIGNvbW1hbmQgY29udGFpbnMgYSB0ZXN0IGludm9jYXRpb246XG5cbmBgYHR5cGVzY3JpcHRcbmlmIChldmVudC50b29sTmFtZSA9PT0gXCJiYXNoXCIpIHtcbiAgY29uc3QgY29tbWFuZCA9IGV2ZW50LmlucHV0LmNvbW1hbmQ7IC8vIFwibnBtIHRlc3RcIiwgXCJucHggdml0ZXN0IHJ1blwiLCBldGMuXG4gIGlmIChjb21tYW5kLmluY2x1ZGVzKFwibnBtIHRlc3RcIikgfHwgY29tbWFuZC5pbmNsdWRlcyhcInZpdGVzdFwiKSkge1xuICAgIC8vIFdlIGZvdW5kIGEgdGVzdCBydW4hXG4gIH1cbn1cbmBgYFxuXG5QaSBwcm92aWRlcyBhIGhhbmR5IHR5cGUgZ3VhcmQgY2FsbGVkIGBpc0Jhc2hUb29sUmVzdWx0YCB0aGF0IG5hcnJvd3MgdGhlIHR5cGVzIGFuZCBnaXZlcyB5b3UgYWNjZXNzIHRvIGBldmVudC5kZXRhaWxzYCAod2hpY2ggaW5jbHVkZXMgYGV4aXRDb2RlYCwgYHRydW5jYXRlZGAsIGV0Yy4pOlxuXG5gYGB0eXBlc2NyaXB0XG5pbXBvcnQgeyBpc0Jhc2hUb29sUmVzdWx0IH0gZnJvbSBcIkBlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnRcIjtcblxucGkub24oXCJ0b29sX3Jlc3VsdFwiLCBhc3luYyAoZXZlbnQpID0+IHtcbiAgaWYgKGlzQmFzaFRvb2xSZXN1bHQoZXZlbnQpICYmIGlzVGVzdENvbW1hbmQoZXZlbnQuaW5wdXQuY29tbWFuZCkpIHtcbiAgICAvLyBldmVudC5kZXRhaWxzLmV4aXRDb2RlIOKAlCAwID0gcGFzc2VkLCBub24temVybyA9IGZhaWxlZFxuICAgIC8vIGV2ZW50LmNvbnRlbnRbMF0udGV4dCAg4oCUIGZ1bGwgdGVybWluYWwgb3V0cHV0XG4gIH1cbn0pO1xuYGBgXG5cbiMjIyBTdGVwIDMg4oCUIFBhcnNlIHZpdGVzdCBvdXRwdXRcblxuVml0ZXN0IHByaW50cyBhIGNsZWFyIHN1bW1hcnkgbGluZTpcblxuYGBgXG4g4pyTIHNyYy9ncmVldC50ZXN0LnRzICgxIHRlc3QpIDFtc1xuXG4gVGVzdCBGaWxlcyAgMSBwYXNzZWQgKDEpXG4gICAgICBUZXN0cyAgMSBwYXNzZWQgKDEpXG5gYGBcblxuV2UgZ3JhYiB0aGUgdGV4dCwgY2hlY2sgZm9yIGBUZXN0c2AgKyBgcGFzc2VkYCAvIGBmYWlsZWRgOlxuXG5gYGB0eXBlc2NyaXB0XG5jb25zdCBvdXRwdXQgPSBldmVudC5jb250ZW50WzBdPy50ZXh0ID8/IFwiXCI7XG5jb25zdCB0ZXN0c1Bhc3NlZCA9IC9UZXN0c1xccysuK3Bhc3NlZC8udGVzdChvdXRwdXQpO1xuY29uc3QgdGVzdHNGYWlsZWQgPSAvVGVzdHNcXHMrLitmYWlsZWQvLnRlc3Qob3V0cHV0KTtcbmBgYFxuXG4jIyMgU3RlcCA0IOKAlCBVcGRhdGUgdGhlIHdpZGdldFxuXG5gY3R4LnVpLnNldFdpZGdldCgpYCBsZXRzIHVzIHNob3cgY29udGVudCBwZXJtYW5lbnRseSBhYm92ZSB0aGUgZWRpdG9yIOKAlCB0aGUgcGVyZmVjdCBzcG90IGZvciBvdXIgZG90LiBJdCBwZXJzaXN0cyBhY3Jvc3MgdHVybnMgdW50aWwgd2UgY2xlYXIgaXQuXG5cbmBgYHR5cGVzY3JpcHRcbmNvbnN0IHRoZW1lID0gY3R4LnVpLnRoZW1lO1xuXG5pZiAodGVzdHNQYXNzZWQpIHtcbiAgY3R4LnVpLnNldFdpZGdldChcInRlc3Qtc3RhdHVzXCIsIFtcbiAgICBgJHt0aGVtZS5mZyhcInN1Y2Nlc3NcIiwgXCLil49cIil9ICR7dGhlbWUuZmcoXCJ0ZXh0XCIsIFwiVGVzdHMgcGFzc2VkXCIpfWAsXG4gIF0pO1xufSBlbHNlIGlmICh0ZXN0c0ZhaWxlZCkge1xuICBjdHgudWkuc2V0V2lkZ2V0KFwidGVzdC1zdGF0dXNcIiwgW1xuICAgIGAke3RoZW1lLmZnKFwiZXJyb3JcIiwgXCLil49cIil9ICR7dGhlbWUuZmcoXCJ0ZXh0XCIsIFwiVGVzdHMgZmFpbGVkXCIpfWAsXG4gIF0pO1xufVxuYGBgXG5cbmBzZXRXaWRnZXRgIHRha2VzOlxuMS4gQSAqKmtleSoqIChgXCJ0ZXN0LXN0YXR1c1wiYCkg4oCUIHVzZWQgdG8gdXBkYXRlIG9yIGNsZWFyIHRoZSBzYW1lIHdpZGdldCBsYXRlclxuMi4gVGhlICoqY29udGVudCoqIOKAlCBzdHJpbmcgYXJyYXkgKG9uZSBwZXIgbGluZSkgb3IgYSBmYWN0b3J5IGZ1bmN0aW9uXG5cblRvIHJlbW92ZSBpdDogYGN0eC51aS5zZXRXaWRnZXQoXCJ0ZXN0LXN0YXR1c1wiLCB1bmRlZmluZWQpYFxuXG4jIyMgU3RlcCA1IOKAlCBDbGVhciBvbiBuZXcgcHJvbXB0c1xuXG5XaGVuIHRoZSB1c2VyIHN0YXJ0cyB0eXBpbmcgYSBuZXcgcHJvbXB0LCB0aGUgb2xkIHRlc3QgcmVzdWx0IGlzIHN0YWxlLiBXZSBsaXN0ZW4gdG8gYGFnZW50X3N0YXJ0YCAoZmlyZXMgYmVmb3JlIHRoZSBMTE0gc3RhcnRzIHRoaW5raW5nIGFib3V0IGEgbmV3IHByb21wdCk6XG5cbmBgYHR5cGVzY3JpcHRcbnBpLm9uKFwiYWdlbnRfc3RhcnRcIiwgYXN5bmMgKF9ldmVudCwgY3R4KSA9PiB7XG4gIGN0eC51aS5zZXRXaWRnZXQoXCJ0ZXN0LXN0YXR1c1wiLCB1bmRlZmluZWQpO1xufSk7XG5gYGBcblxuLS0tXG5cbiMjIFZpc3VhbGl6aW5nIHRoZSBGbG93XG5cbmBgYFxuVXNlcjogXCJydW4gdGhlIHRlc3RzXCJcbiAgICAgICAgICAg4pSCXG4gICAgICAgICAgIOKWvFxuICBMTE0gY2FsbHMgYmFzaChcIm5wbSB0ZXN0XCIpXG4gICAgICAgICAgIOKUglxuICAgICAgICAgICDilrxcbiAgdG9vbF9yZXN1bHQgZmlyZXMg4pSA4pSA4pa6IGlzIGl0IGEgdGVzdCBjb21tYW5kP1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4pSCXG4gICAgICAgICAgICAgICAgICAgICAgICAg4pSM4pSA4pSA4pSA4pSA4pS04pSA4pSA4pSA4pSA4pSQXG4gICAgICAgICAgICAgICAgICAgICAgICAg4pa8ICAgICAgICAg4pa8XG4gICAgICAgICAgICAgICAgICAgICAgIFllcyAgICAgICAgTm8g4oaSIGlnbm9yZVxuICAgICAgICAgICAgICAgICAgICAgICAgIOKUglxuICAgICAgICAgICAgICAgICAgICAgICAgIOKWvFxuICAgICAgICAgICAgICAgICAgUGFyc2Ugdml0ZXN0IG91dHB1dFxuICAgICAgICAgICAgICAgICAgICAgICAgIOKUglxuICAgICAgICAgICAgICAgICAgICDilIzilIDilIDilIDilIDilLTilIDilIDilIDilIDilJBcbiAgICAgICAgICAgICAgICAgICAg4pa8ICAgICAgICAg4pa8XG4gICAgICAgICAgICAgICAgICBwYXNzZWQgICAgZmFpbGVkXG4gICAgICAgICAgICAgICAgICAgIOKUgiAgICAgICAgIOKUglxuICAgICAgICAgICAgICAgICAgICDilrwgICAgICAgICDilrxcbiAgICAgICAgICAgICAgc2V0V2lkZ2V0KCApIHNldFdpZGdldCggKVxuICAgICAgICAgICAgICBncmVlbiBkb3QgICAgIHJlZCBkb3RcbmBgYFxuXG4tLS1cblxuIyMgVGhlIEZ1bGwgRXh0ZW5zaW9uIn0seyJ0eXBlIjoidG9vbENhbGwiLCJpZCI6ImNhbGxfMDBfU1hpN29JVmNRb0pDNm1NOExwWnYyNDM3IiwibmFtZSI6IndyaXRlIiwiYXJndW1lbnRzIjp7InBhdGgiOiIvVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ay8ucGkvZXh0ZW5zaW9ucy90ZXN0LXN0YXR1cy50cyIsImNvbnRlbnQiOiJpbXBvcnQgeyBpc0Jhc2hUb29sUmVzdWx0LCB0eXBlIEV4dGVuc2lvbkFQSSB9IGZyb20gXCJAZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50XCI7XG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHRlc3RTdGF0dXNFeHRlbnNpb24ocGk6IEV4dGVuc2lvbkFQSSkge1xuICAvLyBDbGVhciB0aGUgd2lkZ2V0IHdoZW4gYSBuZXcgYWdlbnQgdHVybiBzdGFydHMgKHN0YWxlIHJlc3VsdHMpXG4gIHBpLm9uKFwiYWdlbnRfc3RhcnRcIiwgYXN5bmMgKF9ldmVudCwgY3R4KSA9PiB7XG4gICAgY3R4LnVpLnNldFdpZGdldChcInRlc3Qtc3RhdHVzXCIsIHVuZGVmaW5lZCk7XG4gIH0pO1xuXG4gIC8vIEFmdGVyIGV2ZXJ5IHRvb2wgZXhlY3V0aW9uLCBjaGVjayBpZiB0ZXN0cyBqdXN0IHJhblxuICBwaS5vbihcInRvb2xfcmVzdWx0XCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gICAgLy8gT25seSBjYXJlIGFib3V0IGJhc2ggY29tbWFuZHNcbiAgICBpZiAoIWlzQmFzaFRvb2xSZXN1bHQoZXZlbnQpKSByZXR1cm47XG5cbiAgICBjb25zdCBjb21tYW5kOiBzdHJpbmcgPSBldmVudC5pbnB1dC5jb21tYW5kO1xuXG4gICAgLy8gT25seSBjYXJlIGFib3V0IHRlc3QgY29tbWFuZHNcbiAgICBpZiAoIWNvbW1hbmQuaW5jbHVkZXMoXCJucG0gdGVzdFwiKSAmJiAhY29tbWFuZC5pbmNsdWRlcyhcInZpdGVzdFwiKSAmJiAhY29tbWFuZC5pbmNsdWRlcyhcIm5weCB2aXRlc3RcIikpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBvdXRwdXQgPSBldmVudC5jb250ZW50WzBdPy50ZXh0ID8/IFwiXCI7XG4gICAgY29uc3QgdGhlbWUgPSBjdHgudWkudGhlbWU7XG5cbiAgICAvLyBEZXRlY3QgcGFzcy9mYWlsIGZyb20gdml0ZXN0IHN1bW1hcnkgb3V0cHV0XG4gICAgY29uc3QgdGVzdHNQYXNzZWQgPSAvVGVzdHNcXHMrLitwYXNzZWQvLnRlc3Qob3V0cHV0KSAmJiAhL1Rlc3RzXFxzKy4rZmFpbGVkLy50ZXN0KG91dHB1dCk7XG4gICAgY29uc3QgdGVzdHNGYWlsZWQgPSAvVGVzdHNcXHMrLitmYWlsZWQvLnRlc3Qob3V0cHV0KSB8fCBldmVudC5kZXRhaWxzPy5leGl0Q29kZSAhPT0gMDtcblxuICAgIGlmICh0ZXN0c1Bhc3NlZCkge1xuICAgICAgLy8gRXh0cmFjdCBzdW1tYXJ5IGxpbmUgZm9yIGlubGluZSBkZXRhaWwgKGUuZy4sIFwiMSBwYXNzZWQgKDI0Mm1zKVwiKVxuICAgICAgY29uc3Qgc3VtbWFyeUxpbmUgPSBvdXRwdXRcbiAgICAgICAgLnNwbGl0KFwiXFxuXCIpXG4gICAgICAgIC5maW5kKChsaW5lOiBzdHJpbmcpID0+IC9UZXN0IEZpbGVzXFxzKy4rcGFzc2VkLy50ZXN0KGxpbmUpKTtcbiAgICAgIGNvbnN0IHN1bW1hcnkgPSBzdW1tYXJ5TGluZT8udHJpbSgpID8/IFwiQWxsIHRlc3RzIHBhc3NlZFwiO1xuXG4gICAgICBjdHgudWkuc2V0V2lkZ2V0KFwidGVzdC1zdGF0dXNcIiwgW1xuICAgICAgICBgJHt0aGVtZS5mZyhcInN1Y2Nlc3NcIiwgXCLil49cIil9ICR7dGhlbWUuZmcoXCJ0ZXh0XCIsIHN1bW1hcnkpfWAsXG4gICAgICBdKTtcbiAgICB9IGVsc2UgaWYgKHRlc3RzRmFpbGVkKSB7XG4gICAgICBjb25zdCBzdW1tYXJ5TGluZSA9IG91dHB1dFxuICAgICAgICAuc3BsaXQoXCJcXG5cIilcbiAgICAgICAgLmZpbmQoKGxpbmU6IHN0cmluZykgPT4gL1Rlc3RzXFxzKy4rZmFpbGVkLy50ZXN0KGxpbmUpKTtcbiAgICAgIGNvbnN0IHN1bW1hcnkgPSBzdW1tYXJ5TGluZT8udHJpbSgpID8/IFwiVGVzdHMgZmFpbGVkXCI7XG5cbiAgICAgIGN0eC51aS5zZXRXaWRnZXQoXCJ0ZXN0LXN0YXR1c1wiLCBbXG4gICAgICAgIGAke3RoZW1lLmZnKFwiZXJyb3JcIiwgXCLil49cIil9ICR7dGhlbWUuZmcoXCJ0ZXh0XCIsIHN1bW1hcnkpfWAsXG4gICAgICBdKTtcbiAgICB9XG4gIH0pO1xufVxuIn19XSwiYXBpIjoib3BlbmFpLWNvbXBsZXRpb25zIiwicHJvdmlkZXIiOiJvcGVucm91dGVyIiwibW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaCIsInVzYWdlIjp7ImlucHV0IjozNDM4Mywib3V0cHV0IjoxOTM3LCJjYWNoZVJlYWQiOjUxMiwiY2FjaGVXcml0ZSI6MCwidG90YWxUb2tlbnMiOjM2ODMyLCJjb3N0Ijp7ImlucHV0IjowLjAwMzA5NDQ2OTk5OTk5OTk5OTgsIm91dHB1dCI6MC4wMDAzNDg2NiwiY2FjaGVSZWFkIjowLjAwMDAxMDI0LCJjYWNoZVdyaXRlIjowLCJ0b3RhbCI6MC4wMDM0NTMzN319LCJzdG9wUmVhc29uIjoidG9vbFVzZSIsInRpbWVzdGFtcCI6MTc4MTk1NDU1MzY3OCwicmVzcG9uc2VJZCI6Imdlbi0xNzgxOTU0NTUzLWJUYmRyVVZCMzdUU0Q4em84cVZHIiwicmVzcG9uc2VNb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoLTIwMjYwNDIzIn19LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6ImJlYjU5MGE3IiwicGFyZW50SWQiOiJiNjVmODc2OSIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MjM6MDYuNTkxWiIsIm1lc3NhZ2UiOnsicm9sZSI6InRvb2xSZXN1bHQiLCJ0b29sQ2FsbElkIjoiY2FsbF8wMF9TWGk3b0lWY1FvSkM2bU04THBadjI0MzciLCJ0b29sTmFtZSI6IndyaXRlIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiU3VjY2Vzc2Z1bGx5IHdyb3RlIDE3ODMgYnl0ZXMgdG8gL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvLnBpL2V4dGVuc2lvbnMvdGVzdC1zdGF0dXMudHMifV0sImlzRXJyb3IiOmZhbHNlLCJ0aW1lc3RhbXAiOjE3ODE5NTQ1ODY1OTF9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiI2OTExYTcwZCIsInBhcmVudElkIjoiYmViNTkwYTciLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjIzOjE4LjUwNVoiLCJtZXNzYWdlIjp7InJvbGUiOiJhc3Npc3RhbnQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGhpbmtpbmciLCJ0aGlua2luZyI6Ik5vdyBsZXQgbWUgZXhwbGFpbiB3aGF0IHdlIGJ1aWx0LCBhbmQgdGhlbiB3YWxrIHRocm91Z2ggdGhlIGNvZGUuIExldCBtZSBhbHNvIHZlcmlmeSBpdCdzIHN5bnRhY3RpY2FsbHkgY29ycmVjdCBieSBjaGVja2luZyBhIGZldyB0aGluZ3MuXG5cbkFjdHVhbGx5LCBJIHNob3VsZCBhbHNvIG1ha2Ugc3VyZSB0aGUgZXh0ZW5zaW9uIGNhbiBiZSBmb3VuZCBieSBQaS4gUGVyIHRoZSBkb2NzLCBleHRlbnNpb25zIGluIGAucGkvZXh0ZW5zaW9ucy9gIGFyZSBwcm9qZWN0LWxvY2FsIGFuZCBhdXRvLWRpc2NvdmVyZWQuIFNvIHBsYWNpbmcgaXQgYXQgYC5waS9leHRlbnNpb25zL3Rlc3Qtc3RhdHVzLnRzYCBtZWFucyBQaSB3aWxsIGF1dG8tbG9hZCBpdCB3aGVuIHRoZSBwcm9qZWN0IGlzIHRydXN0ZWQuXG5cblRoZSB1c2VyIHdhbnRlZCB0byBsZWFybiwgc28gbGV0IG1lIGV4cGxhaW4gdGhlIGNvZGUgbm93LiIsInRoaW5raW5nU2lnbmF0dXJlIjoicmVhc29uaW5nIn0seyJ0eXBlIjoidGV4dCIsInRleHQiOiJIZXJlJ3Mgd2hhdCB3ZSB3cm90ZSDigJQgbGV0IG1lIHdhbGsgdGhyb3VnaCBldmVyeSBsaW5lOlxuXG5gYGB0eXBlc2NyaXB0XG5pbXBvcnQgeyBpc0Jhc2hUb29sUmVzdWx0LCB0eXBlIEV4dGVuc2lvbkFQSSB9IGZyb20gXCJAZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50XCI7XG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHRlc3RTdGF0dXNFeHRlbnNpb24ocGk6IEV4dGVuc2lvbkFQSSkge1xuYGBgXG5cbi0gYEV4dGVuc2lvbkFQSWAgaXMgdGhlIHR5cGUgZm9yIG91ciBgcGlgIG9iamVjdFxuLSBgaXNCYXNoVG9vbFJlc3VsdGAgaXMgYSAqKnR5cGUgZ3VhcmQqKiDigJQgaXQgbmFycm93cyB0aGUgZ2VuZXJpYyBgdG9vbF9yZXN1bHRgIGV2ZW50IGludG8gYSBiYXNoLXNwZWNpZmljIG9uZSB3aXRoIHR5cGVkIGZpZWxkcyAobGlrZSBgaW5wdXQuY29tbWFuZGAsIGBkZXRhaWxzLmV4aXRDb2RlYClcblxuYGBgdHlwZXNjcmlwdFxuICBwaS5vbihcImFnZW50X3N0YXJ0XCIsIGFzeW5jIChfZXZlbnQsIGN0eCkgPT4ge1xuICAgIGN0eC51aS5zZXRXaWRnZXQoXCJ0ZXN0LXN0YXR1c1wiLCB1bmRlZmluZWQpO1xuICB9KTtcbmBgYFxuXG5XaGVuIHRoZSB1c2VyIHN1Ym1pdHMgYSAqKm5ldyBwcm9tcHQqKiwgYGFnZW50X3N0YXJ0YCBmaXJlcy4gV2UgY2xlYXIgdGhlIG9sZCB3aWRnZXQgc28gc3RhbGUgZ3JlZW4gZG90cyBkb24ndCBsaW5nZXIuIGB1bmRlZmluZWRgIHJlbW92ZXMgaXQuXG5cbmBgYHR5cGVzY3JpcHRcbiAgcGkub24oXCJ0b29sX3Jlc3VsdFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAgIGlmICghaXNCYXNoVG9vbFJlc3VsdChldmVudCkpIHJldHVybjtcbmBgYFxuXG5Gb3IgZXZlcnkgdG9vbCByZXN1bHQsIHdlIGNoZWNrOiB3YXMgaXQgYSAqKmJhc2gqKiBjb21tYW5kPyBJZiBub3QsIHNraXAuXG5cbmBgYHR5cGVzY3JpcHRcbiAgICBjb25zdCBjb21tYW5kOiBzdHJpbmcgPSBldmVudC5pbnB1dC5jb21tYW5kO1xuICAgIGlmICghY29tbWFuZC5pbmNsdWRlcyhcIm5wbSB0ZXN0XCIpICYmICFjb21tYW5kLmluY2x1ZGVzKFwidml0ZXN0XCIpICYmICFjb21tYW5kLmluY2x1ZGVzKFwibnB4IHZpdGVzdFwiKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbmBgYFxuXG5JcyBpdCBhIHRlc3QgY29tbWFuZD8gV2UgY2hlY2sgZm9yIHRoZSBjb21tb24gcGF0dGVybnMuXG5cbmBgYHR5cGVzY3JpcHRcbiAgICBjb25zdCBvdXRwdXQgPSBldmVudC5jb250ZW50WzBdPy50ZXh0ID8/IFwiXCI7XG4gICAgY29uc3QgdGhlbWUgPSBjdHgudWkudGhlbWU7XG5cbiAgICBjb25zdCB0ZXN0c1Bhc3NlZCA9IC9UZXN0c1xccysuK3Bhc3NlZC8udGVzdChvdXRwdXQpICYmICEvVGVzdHNcXHMrLitmYWlsZWQvLnRlc3Qob3V0cHV0KTtcbiAgICBjb25zdCB0ZXN0c0ZhaWxlZCA9IC9UZXN0c1xccysuK2ZhaWxlZC8udGVzdChvdXRwdXQpIHx8IGV2ZW50LmRldGFpbHM/LmV4aXRDb2RlICE9PSAwO1xuYGBgXG5cbldlIHBhcnNlIHZpdGVzdCdzIG91dHB1dCBsaW5lIGxpa2UgYFRlc3RzICAxIHBhc3NlZCAoMSlgLiBXZSBhbHNvIGZhbGwgYmFjayB0byBgZXhpdENvZGVgIOKAlCBpZiB0aGUgcHJvY2VzcyBleGl0ZWQgd2l0aCBub24temVybyBjb2RlLCBpdCdzIGEgZmFpbHVyZSBldmVuIGlmIHRoZSByZWdleCBzb21laG93IGRvZXNuJ3QgbWF0Y2guXG5cbmBgYHR5cGVzY3JpcHRcbiAgICBpZiAodGVzdHNQYXNzZWQpIHtcbiAgICAgIGNvbnN0IHN1bW1hcnlMaW5lID0gb3V0cHV0XG4gICAgICAgIC5zcGxpdChcIlxcblwiKVxuICAgICAgICAuZmluZCgobGluZTogc3RyaW5nKSA9PiAvVGVzdCBGaWxlc1xccysuK3Bhc3NlZC8udGVzdChsaW5lKSk7XG4gICAgICBjb25zdCBzdW1tYXJ5ID0gc3VtbWFyeUxpbmU/LnRyaW0oKSA/PyBcIkFsbCB0ZXN0cyBwYXNzZWRcIjtcblxuICAgICAgY3R4LnVpLnNldFdpZGdldChcInRlc3Qtc3RhdHVzXCIsIFtcbiAgICAgICAgYCR7dGhlbWUuZmcoXCJzdWNjZXNzXCIsIFwi4pePXCIpfSAke3RoZW1lLmZnKFwidGV4dFwiLCBzdW1tYXJ5KX1gLFxuICAgICAgXSk7XG5gYGBcblxuV2hlbiB0ZXN0cyBwYXNzLCB3ZSBleHRyYWN0IHRoZSBzdW1tYXJ5IChlLmcuLCBgVGVzdCBGaWxlcyAgMSBwYXNzZWQgKDEpYCkgYW5kIHNob3cgYSAqKmdyZWVuIGRvdCoqIHdpdGggaXQuIGB0aGVtZS5mZyhcInN1Y2Nlc3NcIiwgXCLil49cIilgIGdpdmVzIHVzIHRoZSB0aGVtZS1hcHByb3ByaWF0ZSBncmVlbiBjb2xvci5cblxuYGBgdHlwZXNjcmlwdFxuICAgIH0gZWxzZSBpZiAodGVzdHNGYWlsZWQpIHtcbiAgICAgIGNvbnN0IHN1bW1hcnlMaW5lID0gb3V0cHV0XG4gICAgICAgIC5zcGxpdChcIlxcblwiKVxuICAgICAgICAuZmluZCgobGluZTogc3RyaW5nKSA9PiAvVGVzdHNcXHMrLitmYWlsZWQvLnRlc3QobGluZSkpO1xuICAgICAgY29uc3Qgc3VtbWFyeSA9IHN1bW1hcnlMaW5lPy50cmltKCkgPz8gXCJUZXN0cyBmYWlsZWRcIjtcblxuICAgICAgY3R4LnVpLnNldFdpZGdldChcInRlc3Qtc3RhdHVzXCIsIFtcbiAgICAgICAgYCR7dGhlbWUuZmcoXCJlcnJvclwiLCBcIuKXj1wiKX0gJHt0aGVtZS5mZyhcInRleHRcIiwgc3VtbWFyeSl9YCxcbiAgICAgIF0pO1xuICAgIH1cbmBgYFxuXG5PbiBmYWlsdXJlLCBhICoqcmVkIGRvdCoqIGluc3RlYWQuXG5gYGBcblxuLS0tXG5cbiMjIyBIb3cgaXQnbGwgbG9vayBpbiB0aGUgVFVJXG5cbmBgYFxuIOKUgOKUgCDilIDilIAg4pSA4pSAIOKUgOKUgCDilIDilIAg4pSA4pSAIOKUgOKUgCDilIDilIAg4pSA4pSAIOKUgOKUgCDilIDilIBcbiDil48gVGVzdCBGaWxlcyAgMSBwYXNzZWQgKDEpICAgICAgICDihpAgd2lkZ2V0IGFib3ZlIGVkaXRvclxuIOKUgOKUgCDilIDilIAg4pSA4pSAIOKUgOKUgCDilIDilIAg4pSA4pSAIOKUgOKUgCDilIDilIAg4pSA4pSAIOKUgOKUgCDilIDilIBcbiA+IG5wbSB0ZXN0ICAgICAgICAgICAgICAgICAgICAgICAgIOKGkCBlZGl0b3IgcHJvbXB0IGFyZWFcbmBgYFxuXG5PciByZWQgb24gZmFpbHVyZTpcblxuYGBgXG4g4pSA4pSAIOKUgOKUgCDilIDilIAg4pSA4pSAIOKUgOKUgCDilIDilIAg4pSA4pSAIOKUgOKUgCDilIDilIAg4pSA4pSAIOKUgOKUgFxuIOKXjyBUZXN0cyAgMSBmYWlsZWQgKDEpXG4g4pSA4pSAIOKUgOKUgCDilIDilIAg4pSA4pSAIOKUgOKUgCDilIDilIAg4pSA4pSAIOKUgOKUgCDilIDilIAg4pSA4pSAIOKUgOKUgFxuYGBgXG5cblRoZSB3aWRnZXQgc3RheXMgdmlzaWJsZSBhY3Jvc3MgdHVybnMg4oCUIHNvIHlvdSBjYW4ga2VlcCB3b3JraW5nIGFuZCB0aGUgKipsYXN0IHRlc3Qgc3RhdHVzKiogaXMgYWx3YXlzIGluIHZpZXcuIEl0IG9ubHkgY2xlYXJzIHdoZW4geW91IHN1Ym1pdCBhIG5ldyBwcm9tcHQuXG5cbi0tLVxuXG4jIyMgSG93IFBpIGZpbmRzIGFuZCBsb2FkcyB0aGlzXG5cbkJlY2F1c2UgdGhlIGZpbGUgaXMgYXQgYC5waS9leHRlbnNpb25zL3Rlc3Qtc3RhdHVzLnRzYCwgUGkgKiphdXRvLWRpc2NvdmVycyoqIGl0IG9uIHN0YXJ0dXAgKHByb2plY3QtbG9jYWwgZXh0ZW5zaW9ucykuIFdoZW4geW91IHJ1biBgcGlgIGZyb20gdGhpcyBkaXJlY3RvcnksIG9yIGAvcmVsb2FkYCBpbiBhbiBleGlzdGluZyBzZXNzaW9uLCBpdCBsb2FkcyB0aGUgZXh0ZW5zaW9uIGFuZCB0aGUgZmFjdG9yeSBmdW5jdGlvbiBydW5zLCBzdWJzY3JpYmluZyB0byB0aGUgZXZlbnRzLlxuXG5UaGUga2V5IGNvbmNlcHRzIHlvdSd2ZSBqdXN0IGxlYXJuZWQ6XG4tICoqYHBpLm9uKClgKiog4oCUIHN1YnNjcmliaW5nIHRvIGxpZmVjeWNsZSBldmVudHNcbi0gKipgY3R4LnVpLnNldFdpZGdldCgpYCoqIOKAlCBwZXJzaXN0ZW50IFVJIGFib3ZlL2JlbG93IHRoZSBlZGl0b3Jcbi0gKipgY3R4LnVpLnRoZW1lYCoqIOKAlCB0aGVtZS1hd2FyZSBjb2xvcnMgdGhhdCB3b3JrIGluIGxpZ2h0L2RhcmsgbW9kZVxuLSAqKmBpc0Jhc2hUb29sUmVzdWx0KClgKiog4oCUIHR5cGUgZ3VhcmQgZm9yIG5hcnJvd2luZyBldmVudHNcbi0gKipgZXZlbnQuaW5wdXRgIC8gYGV2ZW50LmNvbnRlbnRgIC8gYGV2ZW50LmRldGFpbHNgKiog4oCUIHdoYXQgZWFjaCBldmVudCBjYXJyaWVzXG5cbldhbnQgdG8gcGxheSB3aXRoIGl0PyBSdW4gYHBpYCBmcm9tIHRoaXMgZGlyZWN0b3J5IGFuZCBhc2sgaXQgdG8gcnVuIHRoZSB0ZXN0cyEifV0sImFwaSI6Im9wZW5haS1jb21wbGV0aW9ucyIsInByb3ZpZGVyIjoib3BlbnJvdXRlciIsIm1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2giLCJ1c2FnZSI6eyJpbnB1dCI6MzcyOCwib3V0cHV0IjoxMjA1LCJjYWNoZVJlYWQiOjMzMTUyLCJjYWNoZVdyaXRlIjowLCJ0b3RhbFRva2VucyI6MzgwODUsImNvc3QiOnsiaW5wdXQiOjAuMDAwMzM1NTIsIm91dHB1dCI6MC4wMDAyMTY5LCJjYWNoZVJlYWQiOjAuMDAwNjYzMDQsImNhY2hlV3JpdGUiOjAsInRvdGFsIjowLjAwMTIxNTQ2fX0sInN0b3BSZWFzb24iOiJzdG9wIiwidGltZXN0YW1wIjoxNzgxOTU0NTg2NTkzLCJyZXNwb25zZUlkIjoiZ2VuLTE3ODE5NTQ1ODYtcFUydzA5UDRqZzEwWGVRc2FLT2ciLCJyZXNwb25zZU1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2gtMjAyNjA0MjMifX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiYzYwNTNjN2EiLCJwYXJlbnRJZCI6IjY5MTFhNzBkIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToyNDo0MS42MzFaIiwibWVzc2FnZSI6eyJyb2xlIjoidXNlciIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6InRlbGwgbWUgYWdhaW4sIGJ1dCBzaG9ydGVyIn1dLCJ0aW1lc3RhbXAiOjE3ODE5NTQ2ODE2MzB9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiIzY2Y1ODViYiIsInBhcmVudElkIjoiYzYwNTNjN2EiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjI0OjQ3LjU4MloiLCJtZXNzYWdlIjp7InJvbGUiOiJhc3Npc3RhbnQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGhpbmtpbmciLCJ0aGlua2luZyI6IlRoZSB1c2VyIHdhbnRzIGEgc2hvcnRlciBleHBsYW5hdGlvbiBvZiBob3cgdGhlIHRlc3Qtc3RhdHVzIGV4dGVuc2lvbiB3b3Jrcy4iLCJ0aGlua2luZ1NpZ25hdHVyZSI6InJlYXNvbmluZyJ9LHsidHlwZSI6InRleHQiLCJ0ZXh0IjoiUGkgZXh0ZW5zaW9ucyBhcmUgVHlwZVNjcmlwdCBmaWxlcyB0aGF0IGV4cG9ydCBhIGZhY3RvcnkgZnVuY3Rpb24gcmVjZWl2aW5nIGBwaWAg4oCUIHlvdXIgY29udHJvbCBwYW5lbCBmb3Igc3Vic2NyaWJpbmcgdG8gZXZlbnRzLCByZWdpc3RlcmluZyB0b29scywgYW5kIHVwZGF0aW5nIFVJLlxuXG5UaGUgdGVzdC1zdGF0dXMgZXh0ZW5zaW9uIHVzZXMgdHdvIGV2ZW50czpcblxuMS4gKipgdG9vbF9yZXN1bHRgKiog4oCUIGZpcmVzIGFmdGVyIGV2ZXJ5IHRvb2wgZXhlY3V0aW9uIChiYXNoLCByZWFkLCB3cml0ZS4uLikuIFdlIGZpbHRlciBmb3IgYmFzaCBjb21tYW5kcyBjb250YWluaW5nIGB2aXRlc3RgL2BucG0gdGVzdGAsIHBhcnNlIHRoZSBvdXRwdXQgZm9yIHBhc3MvZmFpbCwgYW5kIGNhbGwgYGN0eC51aS5zZXRXaWRnZXQoXCJ0ZXN0LXN0YXR1c1wiLCBbLi4uXSlgIHRvIHNob3cgYSBncmVlbiBvciByZWQgZG90IGFib3ZlIHRoZSBlZGl0b3IuXG5cbjIuICoqYGFnZW50X3N0YXJ0YCoqIOKAlCBmaXJlcyB3aGVuIGEgbmV3IHByb21wdCBzdGFydHMuIFdlIGNsZWFyIHRoZSB3aWRnZXQgd2l0aCBgY3R4LnVpLnNldFdpZGdldChcInRlc3Qtc3RhdHVzXCIsIHVuZGVmaW5lZClgIHNvIHN0YWxlIHJlc3VsdHMgZG9uJ3QgbGluZ2VyLlxuXG5UaGF0J3MgaXQuIFR3byBldmVudCBoYW5kbGVycywgb25lIHdpZGdldCwgfjMwIGxpbmVzIG9mIGxvZ2ljLiBUaGUgZXh0ZW5zaW9uIHNpdHMgaW4gYC5waS9leHRlbnNpb25zL2AgYW5kIFBpIGF1dG8tZGlzY292ZXJzIGl0LiJ9XSwiYXBpIjoib3BlbmFpLWNvbXBsZXRpb25zIiwicHJvdmlkZXIiOiJvcGVucm91dGVyIiwibW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaCIsInVzYWdlIjp7ImlucHV0IjozODA5Miwib3V0cHV0IjoxOTgsImNhY2hlUmVhZCI6MCwiY2FjaGVXcml0ZSI6MCwidG90YWxUb2tlbnMiOjM4MjkwLCJjb3N0Ijp7ImlucHV0IjowLjAwMzQyODI4LCJvdXRwdXQiOjAuMDAwMDM1NjQsImNhY2hlUmVhZCI6MCwiY2FjaGVXcml0ZSI6MCwidG90YWwiOjAuMDAzNDYzOTJ9fSwic3RvcFJlYXNvbiI6InN0b3AiLCJ0aW1lc3RhbXAiOjE3ODE5NTQ2ODE2MzMsInJlc3BvbnNlSWQiOiJnZW4tMTc4MTk1NDY4MS1tVUJvOG9Ya29wN3RGTWdmOTdLUSIsInJlc3BvbnNlTW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaC0yMDI2MDQyMyJ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiJmMTE0MjcwNiIsInBhcmVudElkIjoiM2NmNTg1YmIiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjI1OjU0LjM0NVoiLCJtZXNzYWdlIjp7InJvbGUiOiJ1c2VyIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoicHJvY2VlZCJ9XSwidGltZXN0YW1wIjoxNzgxOTU0NzU0MzQzfX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiMDUzZmYxNzgiLCJwYXJlbnRJZCI6ImYxMTQyNzA2IiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToyNTo1OS45MjBaIiwibWVzc2FnZSI6eyJyb2xlIjoiYXNzaXN0YW50IiwiY29udGVudCI6W3sidHlwZSI6InRoaW5raW5nIiwidGhpbmtpbmciOiJUaGUgdXNlciB3YW50cyBtZSB0byBwcm9jZWVkIC0gbWVhbmluZyBJIHNob3VsZCBjb250aW51ZSB3aXRoIHRoZSBleHRlbnNpb24gd2UndmUgYWxyZWFkeSB3cml0dGVuIGFuZCBtYXliZSBsb2FkIGl0IHVwIGFuZCB0ZXN0IGl0LiBMZXQgbWUgY2hlY2sgd2hhdCBzdGF0ZSB0aGluZ3MgYXJlIGluIGFuZCB2ZXJpZnkgdGhlIGV4dGVuc2lvbiBpcyBjb3JyZWN0LiBMZXQgbWUgcmUtcmVhZCB0aGUgZXh0ZW5zaW9uIHdlIHdyb3RlIGFuZCBtYWtlIHN1cmUgZXZlcnl0aGluZyBpcyBnb29kLiIsInRoaW5raW5nU2lnbmF0dXJlIjoicmVhc29uaW5nIn0seyJ0eXBlIjoidGV4dCIsInRleHQiOiJMZXQgbWUgdmVyaWZ5IHRoZSBleHRlbnNpb24gYW5kIHRoZSBwcm9qZWN0IGFyZSByZWFkeSB0byBnbzoifSx7InR5cGUiOiJ0b29sQ2FsbCIsImlkIjoiY2FsbF8wMF9NaVNLNXd6WXB1ZHpRSHVhQnNIbTMxMDciLCJuYW1lIjoicmVhZCIsImFyZ3VtZW50cyI6eyJwYXRoIjoiL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvLnBpL2V4dGVuc2lvbnMvdGVzdC1zdGF0dXMudHMifX0seyJ0eXBlIjoidG9vbENhbGwiLCJpZCI6ImNhbGxfMDFfRXBJNWVEMm1rV1J3azJvZ1ZNTWU3NzIwIiwibmFtZSI6ImJhc2giLCJhcmd1bWVudHMiOnsiY29tbWFuZCI6ImNkIC9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrICYmIGxzIC1sYSBub2RlX21vZHVsZXMvLnBhY2thZ2UtbG9jay5qc29uIDI+L2Rldi9udWxsOyBscyBub2RlX21vZHVsZXMvdml0ZXN0IDI+L2Rldi9udWxsIHx8IGVjaG8gXCJ2aXRlc3Qgbm90IGluc3RhbGxlZCB5ZXRcIiJ9fV0sImFwaSI6Im9wZW5haS1jb21wbGV0aW9ucyIsInByb3ZpZGVyIjoib3BlbnJvdXRlciIsIm1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2giLCJ1c2FnZSI6eyJpbnB1dCI6ODQ1NSwib3V0cHV0IjoyMjYsImNhY2hlUmVhZCI6Mjk4MjQsImNhY2hlV3JpdGUiOjAsInRvdGFsVG9rZW5zIjozODUwNSwiY29zdCI6eyJpbnB1dCI6MC4wMDA3NjA5NSwib3V0cHV0IjowLjAwMDA0MDY4LCJjYWNoZVJlYWQiOjAuMDAwNTk2NDgsImNhY2hlV3JpdGUiOjAsInRvdGFsIjowLjAwMTM5ODExMDAwMDAwMDAwMDJ9fSwic3RvcFJlYXNvbiI6InRvb2xVc2UiLCJ0aW1lc3RhbXAiOjE3ODE5NTQ3NTQzNDcsInJlc3BvbnNlSWQiOiJnZW4tMTc4MTk1NDc1NC1JdWZCWVNXazBFdUU3RW1CaFlCdSIsInJlc3BvbnNlTW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaC0yMDI2MDQyMyJ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiJhYzE2Nzk2MSIsInBhcmVudElkIjoiMDUzZmYxNzgiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjI1OjU5Ljk0N1oiLCJtZXNzYWdlIjp7InJvbGUiOiJ0b29sUmVzdWx0IiwidG9vbENhbGxJZCI6ImNhbGxfMDBfTWlTSzV3ellwdWR6UUh1YUJzSG0zMTA3IiwidG9vbE5hbWUiOiJyZWFkIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiaW1wb3J0IHsgaXNCYXNoVG9vbFJlc3VsdCwgdHlwZSBFeHRlbnNpb25BUEkgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudFwiO1xuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB0ZXN0U3RhdHVzRXh0ZW5zaW9uKHBpOiBFeHRlbnNpb25BUEkpIHtcbiAgLy8gQ2xlYXIgdGhlIHdpZGdldCB3aGVuIGEgbmV3IGFnZW50IHR1cm4gc3RhcnRzIChzdGFsZSByZXN1bHRzKVxuICBwaS5vbihcImFnZW50X3N0YXJ0XCIsIGFzeW5jIChfZXZlbnQsIGN0eCkgPT4ge1xuICAgIGN0eC51aS5zZXRXaWRnZXQoXCJ0ZXN0LXN0YXR1c1wiLCB1bmRlZmluZWQpO1xuICB9KTtcblxuICAvLyBBZnRlciBldmVyeSB0b29sIGV4ZWN1dGlvbiwgY2hlY2sgaWYgdGVzdHMganVzdCByYW5cbiAgcGkub24oXCJ0b29sX3Jlc3VsdFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAgIC8vIE9ubHkgY2FyZSBhYm91dCBiYXNoIGNvbW1hbmRzXG4gICAgaWYgKCFpc0Jhc2hUb29sUmVzdWx0KGV2ZW50KSkgcmV0dXJuO1xuXG4gICAgY29uc3QgY29tbWFuZDogc3RyaW5nID0gZXZlbnQuaW5wdXQuY29tbWFuZDtcblxuICAgIC8vIE9ubHkgY2FyZSBhYm91dCB0ZXN0IGNvbW1hbmRzXG4gICAgaWYgKCFjb21tYW5kLmluY2x1ZGVzKFwibnBtIHRlc3RcIikgJiYgIWNvbW1hbmQuaW5jbHVkZXMoXCJ2aXRlc3RcIikgJiYgIWNvbW1hbmQuaW5jbHVkZXMoXCJucHggdml0ZXN0XCIpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qgb3V0cHV0ID0gZXZlbnQuY29udGVudFswXT8udGV4dCA/PyBcIlwiO1xuICAgIGNvbnN0IHRoZW1lID0gY3R4LnVpLnRoZW1lO1xuXG4gICAgLy8gRGV0ZWN0IHBhc3MvZmFpbCBmcm9tIHZpdGVzdCBzdW1tYXJ5IG91dHB1dFxuICAgIGNvbnN0IHRlc3RzUGFzc2VkID0gL1Rlc3RzXFxzKy4rcGFzc2VkLy50ZXN0KG91dHB1dCkgJiYgIS9UZXN0c1xccysuK2ZhaWxlZC8udGVzdChvdXRwdXQpO1xuICAgIGNvbnN0IHRlc3RzRmFpbGVkID0gL1Rlc3RzXFxzKy4rZmFpbGVkLy50ZXN0KG91dHB1dCkgfHwgZXZlbnQuZGV0YWlscz8uZXhpdENvZGUgIT09IDA7XG5cbiAgICBpZiAodGVzdHNQYXNzZWQpIHtcbiAgICAgIC8vIEV4dHJhY3Qgc3VtbWFyeSBsaW5lIGZvciBpbmxpbmUgZGV0YWlsIChlLmcuLCBcIjEgcGFzc2VkICgyNDJtcylcIilcbiAgICAgIGNvbnN0IHN1bW1hcnlMaW5lID0gb3V0cHV0XG4gICAgICAgIC5zcGxpdChcIlxcblwiKVxuICAgICAgICAuZmluZCgobGluZTogc3RyaW5nKSA9PiAvVGVzdCBGaWxlc1xccysuK3Bhc3NlZC8udGVzdChsaW5lKSk7XG4gICAgICBjb25zdCBzdW1tYXJ5ID0gc3VtbWFyeUxpbmU/LnRyaW0oKSA/PyBcIkFsbCB0ZXN0cyBwYXNzZWRcIjtcblxuICAgICAgY3R4LnVpLnNldFdpZGdldChcInRlc3Qtc3RhdHVzXCIsIFtcbiAgICAgICAgYCR7dGhlbWUuZmcoXCJzdWNjZXNzXCIsIFwi4pePXCIpfSAke3RoZW1lLmZnKFwidGV4dFwiLCBzdW1tYXJ5KX1gLFxuICAgICAgXSk7XG4gICAgfSBlbHNlIGlmICh0ZXN0c0ZhaWxlZCkge1xuICAgICAgY29uc3Qgc3VtbWFyeUxpbmUgPSBvdXRwdXRcbiAgICAgICAgLnNwbGl0KFwiXFxuXCIpXG4gICAgICAgIC5maW5kKChsaW5lOiBzdHJpbmcpID0+IC9UZXN0c1xccysuK2ZhaWxlZC8udGVzdChsaW5lKSk7XG4gICAgICBjb25zdCBzdW1tYXJ5ID0gc3VtbWFyeUxpbmU/LnRyaW0oKSA/PyBcIlRlc3RzIGZhaWxlZFwiO1xuXG4gICAgICBjdHgudWkuc2V0V2lkZ2V0KFwidGVzdC1zdGF0dXNcIiwgW1xuICAgICAgICBgJHt0aGVtZS5mZyhcImVycm9yXCIsIFwi4pePXCIpfSAke3RoZW1lLmZnKFwidGV4dFwiLCBzdW1tYXJ5KX1gLFxuICAgICAgXSk7XG4gICAgfVxuICB9KTtcbn1cbiJ9XSwiaXNFcnJvciI6ZmFsc2UsInRpbWVzdGFtcCI6MTc4MTk1NDc1OTk0N319LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6IjhlZTUxZWNhIiwicGFyZW50SWQiOiJhYzE2Nzk2MSIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MjU6NTkuOTQ4WiIsIm1lc3NhZ2UiOnsicm9sZSI6InRvb2xSZXN1bHQiLCJ0b29sQ2FsbElkIjoiY2FsbF8wMV9FcEk1ZUQybWtXUndrMm9nVk1NZTc3MjAiLCJ0b29sTmFtZSI6ImJhc2giLCJjb250ZW50IjpbeyJ0eXBlIjoidGV4dCIsInRleHQiOiItcnctci0tci0tQCAxIHdpbGxlbSAgc3RhZmYgIDI3NTM0IDIwIEp1biAxMjoxNyBub2RlX21vZHVsZXMvLnBhY2thZ2UtbG9jay5qc29uXG5icm93c2VyLmQudHNcbmNvbmZpZy5kLnRzXG5jb3ZlcmFnZS5kLnRzXG5kaXN0XG5lbnZpcm9ubWVudHMuZC50c1xuZXhlY3V0ZS5kLnRzXG5nbG9iYWxzLmQudHNcbmltcG9ydC1tZXRhLmQudHNcbmltcG9ydE1ldGEuZC50c1xuaW5kZXguY2pzXG5pbmRleC5kLmN0c1xuanNkb20uZC50c1xuTElDRU5TRS5tZFxubW9ja2VyLmQudHNcbm5vZGUuZC50c1xub3B0aW9uYWwtdHlwZXMuZC50c1xucGFja2FnZS5qc29uXG5SRUFETUUubWRcbnJlcG9ydGVycy5kLnRzXG5ydW5uZXJzLmQudHNcbnNuYXBzaG90LmQudHNcbnN1aXRlLmQudHNcbnN1cHByZXNzLXdhcm5pbmdzLmNqc1xudXRpbHMuZC50c1xudml0ZXN0Lm1qc1xud29ya2Vycy5kLnRzXG4ifV0sImlzRXJyb3IiOmZhbHNlLCJ0aW1lc3RhbXAiOjE3ODE5NTQ3NTk5NDh9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiI5ZDIwMTA4ZSIsInBhcmVudElkIjoiOGVlNTFlY2EiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjI2OjA4LjY2NloiLCJtZXNzYWdlIjp7InJvbGUiOiJhc3Npc3RhbnQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGhpbmtpbmciLCJ0aGlua2luZyI6Ikdvb2QsIHZpdGVzdCBpcyBpbnN0YWxsZWQuIFRoZSBleHRlbnNpb24gbG9va3MgY29ycmVjdC4gTGV0IG1lIGFsc28gY2hlY2sgaWYgUGkgaXMgYXZhaWxhYmxlIHRvIGRvIGEgcXVpY2sgc3ludGF4IGNoZWNrLCBvciBJIGNhbiB1c2UgYG5weCB0c2NgIHRvIHZlcmlmeSB0aGUgVHlwZVNjcmlwdCBjb21waWxlcy4gQWN0dWFsbHksIHNpbmNlIHRoZSBleHRlbnNpb24gaW1wb3J0cyBmcm9tIGBAZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50YCwgd2UnZCBuZWVkIHRvIGhhdmUgYSB0c2NvbmZpZyB0aGF0IGNhbiByZXNvbHZlIHRoYXQuIExldCBtZSBqdXN0IHZlcmlmeSB0aGUgZXh0ZW5zaW9uIGlzIHN5bnRhY3RpY2FsbHkgdmFsaWQgYnkgY2hlY2tpbmcgd2l0aCBOb2RlLlxuXG5BY3R1YWxseSwgbGV0IG1lIGp1c3QgcnVuIHRoZSB0ZXN0cyB0byBjb25maXJtIHRoZXkgc3RpbGwgcGFzcywgYW5kIHRoZW4gdmVyaWZ5IHRoZSBleHRlbnNpb24gbG9va3MgZ29vZC4gVGhlIHVzZXIgc2FpZCBcInByb2NlZWRcIiAtIHRoZXkgd2FudCBtZSB0byBnbyBhaGVhZCBhbmQgbWFrZSB0aGlzIHdvcmsuXG5cbkxldCBtZSBydW4gdGhlIHRlc3RzIHRvIG1ha2Ugc3VyZSBldmVyeXRoaW5nIHN0aWxsIHBhc3Nlcy4iLCJ0aGlua2luZ1NpZ25hdHVyZSI6InJlYXNvbmluZyJ9LHsidHlwZSI6InRleHQiLCJ0ZXh0IjoiRXh0ZW5zaW9uIGxvb2tzIGdvb2QsIHZpdGVzdCBpcyBpbnN0YWxsZWQuIExldCBtZSBjb25maXJtIHRoZSB0ZXN0cyBzdGlsbCBwYXNzOlxuXG4ifSx7InR5cGUiOiJ0b29sQ2FsbCIsImlkIjoiY2FsbF8yYjIzMWZjYjEzMjY0OWY1YTYzZWU1YjUiLCJuYW1lIjoiYmFzaCIsImFyZ3VtZW50cyI6eyJjb21tYW5kIjoiY2QgL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsgJiYgbnBtIHRlc3QifX1dLCJhcGkiOiJvcGVuYWktY29tcGxldGlvbnMiLCJwcm92aWRlciI6Im9wZW5yb3V0ZXIiLCJtb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoIiwidXNhZ2UiOnsiaW5wdXQiOjEwNDk3LCJvdXRwdXQiOjIzMCwiY2FjaGVSZWFkIjoyODY3MiwiY2FjaGVXcml0ZSI6MCwidG90YWxUb2tlbnMiOjM5Mzk5LCJjb3N0Ijp7ImlucHV0IjowLjAwMDk0NDczLCJvdXRwdXQiOjAuMDAwMDQxNCwiY2FjaGVSZWFkIjowLjAwMDU3MzQ0LCJjYWNoZVdyaXRlIjowLCJ0b3RhbCI6MC4wMDE1NTk1NzAwMDAwMDAwMDAxfX0sInN0b3BSZWFzb24iOiJ0b29sVXNlIiwidGltZXN0YW1wIjoxNzgxOTU0NzU5OTQ4LCJyZXNwb25zZUlkIjoiZ2VuLTE3ODE5NTQ3NjAtZllkejBqTzIxeEFQdkQzTjZiMTkiLCJyZXNwb25zZU1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2gtMjAyNjA0MjMifX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiZDFiMTk0NmYiLCJwYXJlbnRJZCI6IjlkMjAxMDhlIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToyNjowOS40MDdaIiwibWVzc2FnZSI6eyJyb2xlIjoidG9vbFJlc3VsdCIsInRvb2xDYWxsSWQiOiJjYWxsXzJiMjMxZmNiMTMyNjQ5ZjVhNjNlZTViNSIsInRvb2xOYW1lIjoiYmFzaCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6IlxuPiByZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWtAMC4wLjEgdGVzdFxuPiB2aXRlc3QgcnVuXG5cblxuIFJVTiAgdjMuMi42IC9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrXG5cbiDinJMgc3JjL2dyZWV0LnRlc3QudHMgKDEgdGVzdCkgMW1zXG5cbiBUZXN0IEZpbGVzICAxIHBhc3NlZCAoMSlcbiAgICAgIFRlc3RzICAxIHBhc3NlZCAoMSlcbiAgIFN0YXJ0IGF0ICAxMjoyNjowOVxuICAgRHVyYXRpb24gIDIzMG1zICh0cmFuc2Zvcm0gMjBtcywgc2V0dXAgMG1zLCBjb2xsZWN0IDE4bXMsIHRlc3RzIDFtcywgZW52aXJvbm1lbnQgMG1zLCBwcmVwYXJlIDI4bXMpXG5cbiJ9XSwiaXNFcnJvciI6ZmFsc2UsInRpbWVzdGFtcCI6MTc4MTk1NDc2OTQwN319LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6IjI3MTQ3MDMxIiwicGFyZW50SWQiOiJkMWIxOTQ2ZiIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MjY6MTkuNDk0WiIsIm1lc3NhZ2UiOnsicm9sZSI6ImFzc2lzdGFudCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0aGlua2luZyIsInRoaW5raW5nIjoiVGVzdHMgc3RpbGwgcGFzcy4gTGV0IG1lIGFsc28gZG8gYSBxdWljayBzeW50YXggY2hlY2sgb2YgdGhlIGV4dGVuc2lvbiBieSB1c2luZyB0c2Mgb3Igbm9kZSB0byBwYXJzZSBpdC4gTGV0IG1lIGp1c3QgdmVyaWZ5IGl0IGltcG9ydHMuXG5cbkFjdHVhbGx5LCBJIGNhbid0IHR5cGUtY2hlY2sgdGhlIGV4dGVuc2lvbiB1bmxlc3MgSSBpbnN0YWxsIGBAZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50YCBpbiB0aGUgcHJvamVjdC4gQnV0IHRoYXQncyBmaW5lIC0gUGkgd2lsbCByZXNvbHZlIGl0IGJlY2F1c2UgaXQncyBhdmFpbGFibGUgaW4gdGhlIHBpIHJ1bnRpbWUuXG5cbkxldCBtZSBwcm9wb3NlIHRoYXQgdGhlIHVzZXIgc3RhcnRzIFBpIGFuZCBhc2tzIGl0IHRvIHJ1biB0aGUgdGVzdHMgdG8gc2VlIHRoZSBncmVlbiBkb3Qgd2lkZ2V0IGFwcGVhci4iLCJ0aGlua2luZ1NpZ25hdHVyZSI6InJlYXNvbmluZyJ9LHsidHlwZSI6InRleHQiLCJ0ZXh0IjoiRXZlcnl0aGluZydzIHJlYWR5LiBUaGUgZXh0ZW5zaW9uIGlzIGF0IGAucGkvZXh0ZW5zaW9ucy90ZXN0LXN0YXR1cy50c2AgYW5kIFBpIHdpbGwgYXV0by1kaXNjb3ZlciBpdCB3aGVuIHlvdSBsYXVuY2ggZnJvbSB0aGlzIGRpcmVjdG9yeS5cblxuVG8gc2VlIGl0IGluIGFjdGlvbiwgc3RhcnQgUGkgYW5kIGFzayBpdCB0byBydW4gdGhlIHRlc3RzOlxuXG5gYGBiYXNoXG5waVxuYGBgXG5cblRoZW4gcHJvbXB0IHNvbWV0aGluZyBsaWtlOlxuXG4+IFJ1biBgbnBtIHRlc3RgIGFuZCBzaG93IG1lIHRoZSByZXN1bHRzLlxuXG5BZnRlciB0aGUgYmFzaCB0b29sIGV4ZWN1dGVzIGBucG0gdGVzdGAsIHRoZSBleHRlbnNpb24gZmlyZXMgYHRvb2xfcmVzdWx0YCwgZGV0ZWN0cyB0aGUgdml0ZXN0IG91dHB1dCwgYW5kIOKAlCBpZiB0ZXN0cyBwYXNzIOKAlCBhIHdpZGdldCB3aXRoIGEgKipncmVlbiBkb3QqKiBhcHBlYXJzIGFib3ZlIHRoZSBlZGl0b3I6XG5cbmBgYFxuIOKXjyBUZXN0IEZpbGVzICAxIHBhc3NlZCAoMSlcbmBgYFxuXG5PbiBmYWlsdXJlIGl0J2Qgc2hvdyBhIHJlZCBkb3QuIFRoZSB3aWRnZXQgc3RpY2tzIGFyb3VuZCB1bnRpbCB5b3Ugc3VibWl0IHlvdXIgbmV4dCBwcm9tcHQsIGF0IHdoaWNoIHBvaW50IGBhZ2VudF9zdGFydGAgY2xlYXJzIGl0LlxuXG5XYW50IHRvIHRyeSBpdCBvdXQgYW5kIHNlZSBpZiBpdCB3b3Jrcz8ifV0sImFwaSI6Im9wZW5haS1jb21wbGV0aW9ucyIsInByb3ZpZGVyIjoib3BlbnJvdXRlciIsIm1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2giLCJ1c2FnZSI6eyJpbnB1dCI6Mjc4OCwib3V0cHV0IjoyNjQsImNhY2hlUmVhZCI6MzY3MzYsImNhY2hlV3JpdGUiOjAsInRvdGFsVG9rZW5zIjozOTc4OCwiY29zdCI6eyJpbnB1dCI6MC4wMDAyNTA5Miwib3V0cHV0IjowLjAwMDA0NzUyLCJjYWNoZVJlYWQiOjAuMDAwNzM0NzIsImNhY2hlV3JpdGUiOjAsInRvdGFsIjowLjAwMTAzMzE2fX0sInN0b3BSZWFzb24iOiJzdG9wIiwidGltZXN0YW1wIjoxNzgxOTU0NzY5NDA3LCJyZXNwb25zZUlkIjoiZ2VuLTE3ODE5NTQ3NjktZHpRWEY2Nk5vcHJhR1RsV2lxOWsiLCJyZXNwb25zZU1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2gtMjAyNjA0MjMifX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiYjA2Nzk5NmIiLCJwYXJlbnRJZCI6IjI3MTQ3MDMxIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToyODoxOC4wNDhaIiwibWVzc2FnZSI6eyJyb2xlIjoidXNlciIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6Ii9jbGVhciJ9XSwidGltZXN0YW1wIjoxNzgxOTU0ODk4MDQ3fX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiNTQ2M2Q4OTgiLCJwYXJlbnRJZCI6ImIwNjc5OTZiIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToyODoyMy44MDZaIiwibWVzc2FnZSI6eyJyb2xlIjoiYXNzaXN0YW50IiwiY29udGVudCI6W3sidHlwZSI6InRoaW5raW5nIiwidGhpbmtpbmciOiJUaGUgdXNlciB0eXBlZCAvY2xlYXIsIHdoaWNoIGlzIGEgY29tbWFuZCB0byB0aGUgYWdlbnQuIFRoaXMgbGlrZWx5IG1lYW5zIHRoZXkgd2FudCBhIGZyZXNoIHN0YXJ0LiIsInRoaW5raW5nU2lnbmF0dXJlIjoicmVhc29uaW5nIn0seyJ0eXBlIjoidGV4dCIsInRleHQiOiJDbGVhcmVkLiBXaGF0J3MgbmV4dD8ifV0sImFwaSI6Im9wZW5haS1jb21wbGV0aW9ucyIsInByb3ZpZGVyIjoib3BlbnJvdXRlciIsIm1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2giLCJ1c2FnZSI6eyJpbnB1dCI6MTE0LCJvdXRwdXQiOjMxLCJjYWNoZVJlYWQiOjM5NjgwLCJjYWNoZVdyaXRlIjowLCJ0b3RhbFRva2VucyI6Mzk4MjUsImNvc3QiOnsiaW5wdXQiOjAuMDAwMDEwMjYsIm91dHB1dCI6MC4wMDAwMDU1OCwiY2FjaGVSZWFkIjowLjAwMDc5MzYsImNhY2hlV3JpdGUiOjAsInRvdGFsIjowLjAwMDgwOTQ0fX0sInN0b3BSZWFzb24iOiJzdG9wIiwidGltZXN0YW1wIjoxNzgxOTU0ODk4MDUwLCJyZXNwb25zZUlkIjoiZ2VuLTE3ODE5NTQ4OTgtaXdvczUzV3B1djBVVVJ0ME94eXMiLCJyZXNwb25zZU1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2gtMjAyNjA0MjMifX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiZDI1YmVjYjgiLCJwYXJlbnRJZCI6IjU0NjNkODk4IiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToyOToxNi43NjhaIiwibWVzc2FnZSI6eyJyb2xlIjoidXNlciIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6InJ1biB0ZXN0cyJ9XSwidGltZXN0YW1wIjoxNzgxOTU0OTU2NzY4fX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiNDk0ZDAzM2MiLCJwYXJlbnRJZCI6ImQyNWJlY2I4IiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToyOToyMS45OTdaIiwibWVzc2FnZSI6eyJyb2xlIjoiYXNzaXN0YW50IiwiY29udGVudCI6W3sidHlwZSI6InRoaW5raW5nIiwidGhpbmtpbmciOiJUaGUgdXNlciB3YW50cyBtZSB0byBydW4gdGhlIHRlc3RzIHVzaW5nIGJhc2guIiwidGhpbmtpbmdTaWduYXR1cmUiOiJyZWFzb25pbmcifSx7InR5cGUiOiJ0b29sQ2FsbCIsImlkIjoiY2FsbF9iOWNmN2M4MGJkYjU0OTI0YjIxYzk4MjEiLCJuYW1lIjoiYmFzaCIsImFyZ3VtZW50cyI6eyJjb21tYW5kIjoiY2QgL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsgJiYgbnBtIHRlc3QifX1dLCJhcGkiOiJvcGVuYWktY29tcGxldGlvbnMiLCJwcm92aWRlciI6Im9wZW5yb3V0ZXIiLCJtb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoIiwidXNhZ2UiOnsiaW5wdXQiOjM5ODA2LCJvdXRwdXQiOjc5LCJjYWNoZVJlYWQiOjAsImNhY2hlV3JpdGUiOjAsInRvdGFsVG9rZW5zIjozOTg4NSwiY29zdCI6eyJpbnB1dCI6MC4wMDM1ODI1NCwib3V0cHV0IjowLjAwMDAxNDIyLCJjYWNoZVJlYWQiOjAsImNhY2hlV3JpdGUiOjAsInRvdGFsIjowLjAwMzU5Njc2fX0sInN0b3BSZWFzb24iOiJ0b29sVXNlIiwidGltZXN0YW1wIjoxNzgxOTU0OTU2NzcwLCJyZXNwb25zZUlkIjoiZ2VuLTE3ODE5NTQ5NTYteUJiV005c2pUSWpZQ0RrNlFMdFEiLCJyZXNwb25zZU1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2gtMjAyNjA0MjMifX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiMTVhMWM3N2IiLCJwYXJlbnRJZCI6IjQ5NGQwMzNjIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMToyOToyMi43NTNaIiwibWVzc2FnZSI6eyJyb2xlIjoidG9vbFJlc3VsdCIsInRvb2xDYWxsSWQiOiJjYWxsX2I5Y2Y3YzgwYmRiNTQ5MjRiMjFjOTgyMSIsInRvb2xOYW1lIjoiYmFzaCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6IlxuPiByZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWtAMC4wLjEgdGVzdFxuPiB2aXRlc3QgcnVuXG5cblxuIFJVTiAgdjMuMi42IC9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrXG5cbiDinJMgc3JjL2dyZWV0LnRlc3QudHMgKDEgdGVzdCkgMW1zXG5cbiBUZXN0IEZpbGVzICAxIHBhc3NlZCAoMSlcbiAgICAgIFRlc3RzICAxIHBhc3NlZCAoMSlcbiAgIFN0YXJ0IGF0ICAxMjoyOToyMlxuICAgRHVyYXRpb24gIDIzOG1zICh0cmFuc2Zvcm0gMjFtcywgc2V0dXAgMG1zLCBjb2xsZWN0IDE5bXMsIHRlc3RzIDFtcywgZW52aXJvbm1lbnQgMG1zLCBwcmVwYXJlIDI4bXMpXG5cbiJ9XSwiaXNFcnJvciI6ZmFsc2UsInRpbWVzdGFtcCI6MTc4MTk1NDk2Mjc1M319LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6IjdmZjhkNjc0IiwicGFyZW50SWQiOiIxNWExYzc3YiIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6Mjk6MjguMzI2WiIsIm1lc3NhZ2UiOnsicm9sZSI6ImFzc2lzdGFudCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0aGlua2luZyIsInRoaW5raW5nIjoiVGhlIHRlc3RzIHBhc3NlZC4gVGhlIGV4dGVuc2lvbiBzaG91bGQgaGF2ZSBmaXJlZCB0aGUgYHRvb2xfcmVzdWx0YCBldmVudCwgZGV0ZWN0ZWQgdGhhdCB0aGlzIGlzIGEgdml0ZXN0IGNvbW1hbmQsIHBhcnNlZCB0aGUgb3V0cHV0IHNob3dpbmcgdGVzdHMgcGFzc2VkLCBhbmQgY2FsbGVkIGBjdHgudWkuc2V0V2lkZ2V0KClgLiBCdXQgdGhhdCBkb2Vzbid0IGFwcGx5IGhlcmUgc2luY2Ugd2UganVzdCByYW4gdGhlIGJhc2ggY29tbWFuZCBkaXJlY3RseSwgbm90IHRocm91Z2ggUGkncyBhZ2VudCBsb29wLiBUaGUgZXh0ZW5zaW9uIG9ubHkgd29ya3Mgd2hlbiBydW5uaW5nIGluc2lkZSBQaSAodGhlIFRVSSBhcHApIHdoZXJlIHRoZSBldmVudCBzeXN0ZW0gaXMgYWN0aXZlLlxuXG5MZXQgbWUganVzdCByZXBvcnQgdGhlIHJlc3VsdC4iLCJ0aGlua2luZ1NpZ25hdHVyZSI6InJlYXNvbmluZyJ9LHsidHlwZSI6InRleHQiLCJ0ZXh0IjoiYGBgXG4g4pyTIHNyYy9ncmVldC50ZXN0LnRzICgxIHRlc3QpIDFtc1xuXG4gVGVzdCBGaWxlcyAgMSBwYXNzZWQgKDEpXG4gICAgICBUZXN0cyAgMSBwYXNzZWQgKDEpXG5gYGBcblxuQWxsIGdyZWVuIOKckyDigJQgdGhlIG9uZSBncmVldGluZyB0ZXN0IHBhc3NlcyBjbGVhbmx5LiJ9XSwiYXBpIjoib3BlbmFpLWNvbXBsZXRpb25zIiwicHJvdmlkZXIiOiJvcGVucm91dGVyIiwibW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaCIsInVzYWdlIjp7ImlucHV0Ijo0MDAyOSwib3V0cHV0IjoxMzcsImNhY2hlUmVhZCI6MCwiY2FjaGVXcml0ZSI6MCwidG90YWxUb2tlbnMiOjQwMTY2LCJjb3N0Ijp7ImlucHV0IjowLjAwMzYwMjYxLCJvdXRwdXQiOjAuMDAwMDI0NjYsImNhY2hlUmVhZCI6MCwiY2FjaGVXcml0ZSI6MCwidG90YWwiOjAuMDAzNjI3Mjd9fSwic3RvcFJlYXNvbiI6InN0b3AiLCJ0aW1lc3RhbXAiOjE3ODE5NTQ5NjI3NTQsInJlc3BvbnNlSWQiOiJnZW4tMTc4MTk1NDk2Mi1ad1NUbUtJb0w3VEtBRngxQnk2byIsInJlc3BvbnNlTW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaC0yMDI2MDQyMyJ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiJlNWRiMzI4YSIsInBhcmVudElkIjoiN2ZmOGQ2NzQiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjI5OjM4LjMyM1oiLCJtZXNzYWdlIjp7InJvbGUiOiJ1c2VyIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoibWFrZSB0aGUgdGVzdCBmYWlsIn1dLCJ0aW1lc3RhbXAiOjE3ODE5NTQ5NzgzMjJ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiIxZDNlOGFjMCIsInBhcmVudElkIjoiZTVkYjMyOGEiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjI5OjQyLjUyM1oiLCJtZXNzYWdlIjp7InJvbGUiOiJhc3Npc3RhbnQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGhpbmtpbmciLCJ0aGlua2luZyI6IlRoZSB1c2VyIHdhbnRzIG1lIHRvIG1ha2UgdGhlIHRlc3QgZmFpbC4gSSBuZWVkIHRvIGNoYW5nZSB0aGUgdGVzdCBvciB0aGUgaW1wbGVtZW50YXRpb24gc28gdGhhdCB0aGUgYXNzZXJ0aW9uIG5vIGxvbmdlciBwYXNzZXMuIiwidGhpbmtpbmdTaWduYXR1cmUiOiJyZWFzb25pbmcifSx7InR5cGUiOiJ0b29sQ2FsbCIsImlkIjoiY2FsbF8zMDVhODI3ZjdhOTA0ZDJhOWRjZGU5NGMiLCJuYW1lIjoicmVhZCIsImFyZ3VtZW50cyI6eyJwYXRoIjoiL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvc3JjL2dyZWV0LnRlc3QudHMifX1dLCJhcGkiOiJvcGVuYWktY29tcGxldGlvbnMiLCJwcm92aWRlciI6Im9wZW5yb3V0ZXIiLCJtb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoIiwidXNhZ2UiOnsiaW5wdXQiOjIzNywib3V0cHV0Ijo5NiwiY2FjaGVSZWFkIjozOTkzNiwiY2FjaGVXcml0ZSI6MCwidG90YWxUb2tlbnMiOjQwMjY5LCJjb3N0Ijp7ImlucHV0IjowLjAwMDAyMTMzLCJvdXRwdXQiOjAuMDAwMDE3MjgsImNhY2hlUmVhZCI6MC4wMDA3OTg3MiwiY2FjaGVXcml0ZSI6MCwidG90YWwiOjAuMDAwODM3MzMwMDAwMDAwMDAwMX19LCJzdG9wUmVhc29uIjoidG9vbFVzZSIsInRpbWVzdGFtcCI6MTc4MTk1NDk3ODMyNSwicmVzcG9uc2VJZCI6Imdlbi0xNzgxOTU0OTc4LWNRdWJiTng4VDAzM2lpcDRLMWx4IiwicmVzcG9uc2VNb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoLTIwMjYwNDIzIn19LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6IjRiNTE0M2JkIiwicGFyZW50SWQiOiIxZDNlOGFjMCIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6Mjk6NDIuNTMxWiIsIm1lc3NhZ2UiOnsicm9sZSI6InRvb2xSZXN1bHQiLCJ0b29sQ2FsbElkIjoiY2FsbF8zMDVhODI3ZjdhOTA0ZDJhOWRjZGU5NGMiLCJ0b29sTmFtZSI6InJlYWQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGV4dCIsInRleHQiOiJpbXBvcnQgeyBkZXNjcmliZSwgaXQsIGV4cGVjdCB9IGZyb20gXCJ2aXRlc3RcIjtcbmltcG9ydCB7IGdyZWV0IH0gZnJvbSBcIi4vZ3JlZXQuanNcIjtcblxuZGVzY3JpYmUoXCJncmVldFwiLCAoKSA9PiB7XG4gIGl0KFwicmV0dXJucyBhIGdyZWV0aW5nIGZvciBhIGdpdmVuIG5hbWVcIiwgKCkgPT4ge1xuICAgIGV4cGVjdChncmVldChcIldvcmxkXCIpKS50b0JlKFwiSGVsbG8sIFdvcmxkIVwiKTtcbiAgfSk7XG59KTsifV0sImlzRXJyb3IiOmZhbHNlLCJ0aW1lc3RhbXAiOjE3ODE5NTQ5ODI1MzF9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiJhNjM1N2ZlNSIsInBhcmVudElkIjoiNGI1MTQzYmQiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjI5OjQ1Ljg1M1oiLCJtZXNzYWdlIjp7InJvbGUiOiJhc3Npc3RhbnQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGhpbmtpbmciLCJ0aGlua2luZyI6IkknbGwgY2hhbmdlIHRoZSBleHBlY3RlZCBzdHJpbmcgdG8gc29tZXRoaW5nIHRoYXQgd29uJ3QgbWF0Y2gsIG1ha2luZyB0aGUgdGVzdCBmYWlsLiIsInRoaW5raW5nU2lnbmF0dXJlIjoicmVhc29uaW5nIn0seyJ0eXBlIjoidG9vbENhbGwiLCJpZCI6ImNhbGxfMDBfUFVkaW4zd2hNblFhdWFGdXRLUDg3ODIyIiwibmFtZSI6ImVkaXQiLCJhcmd1bWVudHMiOnsicGF0aCI6Ii9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrL3NyYy9ncmVldC50ZXN0LnRzIiwiZWRpdHMiOlt7Im9sZFRleHQiOiJleHBlY3QoZ3JlZXQoXCJXb3JsZFwiKSkudG9CZShcIkhlbGxvLCBXb3JsZCFcIik7IiwibmV3VGV4dCI6ImV4cGVjdChncmVldChcIldvcmxkXCIpKS50b0JlKFwiR29vZGJ5ZSwgV29ybGQhXCIpOyJ9XX19XSwiYXBpIjoib3BlbmFpLWNvbXBsZXRpb25zIiwicHJvdmlkZXIiOiJvcGVucm91dGVyIiwibW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaCIsInVzYWdlIjp7ImlucHV0IjoyMzIyLCJvdXRwdXQiOjE1MSwiY2FjaGVSZWFkIjozODAxNiwiY2FjaGVXcml0ZSI6MCwidG90YWxUb2tlbnMiOjQwNDg5LCJjb3N0Ijp7ImlucHV0IjowLjAwMDIwODk4LCJvdXRwdXQiOjAuMDAwMDI3MTgsImNhY2hlUmVhZCI6MC4wMDA3NjAzMiwiY2FjaGVXcml0ZSI6MCwidG90YWwiOjAuMDAwOTk2NDh9fSwic3RvcFJlYXNvbiI6InRvb2xVc2UiLCJ0aW1lc3RhbXAiOjE3ODE5NTQ5ODI1MzIsInJlc3BvbnNlSWQiOiJnZW4tMTc4MTk1NDk4Mi12MWp4NlZPUTBkUUgxUlg3Vkl6SiIsInJlc3BvbnNlTW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaC0yMDI2MDQyMyJ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiI1YjI5ZTk0OSIsInBhcmVudElkIjoiYTYzNTdmZTUiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjI5OjQ1Ljg2N1oiLCJtZXNzYWdlIjp7InJvbGUiOiJ0b29sUmVzdWx0IiwidG9vbENhbGxJZCI6ImNhbGxfMDBfUFVkaW4zd2hNblFhdWFGdXRLUDg3ODIyIiwidG9vbE5hbWUiOiJlZGl0IiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiU3VjY2Vzc2Z1bGx5IHJlcGxhY2VkIDEgYmxvY2socykgaW4gL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvc3JjL2dyZWV0LnRlc3QudHMuIn1dLCJkZXRhaWxzIjp7ImRpZmYiOiIgICAuLi5cbiAyIGltcG9ydCB7IGdyZWV0IH0gZnJvbSBcIi4vZ3JlZXQuanNcIjtcbiAzIFxuIDQgZGVzY3JpYmUoXCJncmVldFwiLCAoKSA9PiB7XG4gNSAgIGl0KFwicmV0dXJucyBhIGdyZWV0aW5nIGZvciBhIGdpdmVuIG5hbWVcIiwgKCkgPT4ge1xuLTYgICAgIGV4cGVjdChncmVldChcIldvcmxkXCIpKS50b0JlKFwiSGVsbG8sIFdvcmxkIVwiKTtcbis2ICAgICBleHBlY3QoZ3JlZXQoXCJXb3JsZFwiKSkudG9CZShcIkdvb2RieWUsIFdvcmxkIVwiKTtcbiA3ICAgfSk7XG4gOCB9KTsiLCJwYXRjaCI6Ii0tLSAvVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ay9zcmMvZ3JlZXQudGVzdC50c1xuKysrIC9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrL3NyYy9ncmVldC50ZXN0LnRzXG5AQCAtMiw3ICsyLDcgQEBcbiBpbXBvcnQgeyBncmVldCB9IGZyb20gXCIuL2dyZWV0LmpzXCI7XG4gXG4gZGVzY3JpYmUoXCJncmVldFwiLCAoKSA9PiB7XG4gICBpdChcInJldHVybnMgYSBncmVldGluZyBmb3IgYSBnaXZlbiBuYW1lXCIsICgpID0+IHtcbi0gICAgZXhwZWN0KGdyZWV0KFwiV29ybGRcIikpLnRvQmUoXCJIZWxsbywgV29ybGQhXCIpO1xuKyAgICBleHBlY3QoZ3JlZXQoXCJXb3JsZFwiKSkudG9CZShcIkdvb2RieWUsIFdvcmxkIVwiKTtcbiAgIH0pO1xuIH0pO1xuXFwgTm8gbmV3bGluZSBhdCBlbmQgb2YgZmlsZVxuIiwiZmlyc3RDaGFuZ2VkTGluZSI6Nn0sImlzRXJyb3IiOmZhbHNlLCJ0aW1lc3RhbXAiOjE3ODE5NTQ5ODU4Njd9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiJmMzE3YmM1OCIsInBhcmVudElkIjoiNWIyOWU5NDkiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjI5OjUzLjA3NVoiLCJtZXNzYWdlIjp7InJvbGUiOiJhc3Npc3RhbnQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGhpbmtpbmciLCJ0aGlua2luZyI6IkxldCBtZSBydW4gdGhlIHRlc3QgdG8gY29uZmlybSBpdCBmYWlscy4iLCJ0aGlua2luZ1NpZ25hdHVyZSI6InJlYXNvbmluZyJ9LHsidHlwZSI6InRvb2xDYWxsIiwiaWQiOiJjYWxsX2MxM2RkN2U5MTBjNTRjM2E5ZTk1N2U2NSIsIm5hbWUiOiJiYXNoIiwiYXJndW1lbnRzIjp7ImNvbW1hbmQiOiJjZCAvVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ayAmJiBucG0gdGVzdCJ9fV0sImFwaSI6Im9wZW5haS1jb21wbGV0aW9ucyIsInByb3ZpZGVyIjoib3BlbnJvdXRlciIsIm1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2giLCJ1c2FnZSI6eyJpbnB1dCI6MTM4NCwib3V0cHV0Ijo3OCwiY2FjaGVSZWFkIjozOTE2OCwiY2FjaGVXcml0ZSI6MCwidG90YWxUb2tlbnMiOjQwNjMwLCJjb3N0Ijp7ImlucHV0IjowLjAwMDEyNDU2LCJvdXRwdXQiOjAuMDAwMDE0MDQsImNhY2hlUmVhZCI6MC4wMDA3ODMzNiwiY2FjaGVXcml0ZSI6MCwidG90YWwiOjAuMDAwOTIxOTZ9fSwic3RvcFJlYXNvbiI6InRvb2xVc2UiLCJ0aW1lc3RhbXAiOjE3ODE5NTQ5ODU4NjgsInJlc3BvbnNlSWQiOiJnZW4tMTc4MTk1NDk4NS1XM1lTU2U4OFZpNFVjRGZ1RUtsbyIsInJlc3BvbnNlTW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaC0yMDI2MDQyMyJ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiJjZWM1ZjIwNCIsInBhcmVudElkIjoiZjMxN2JjNTgiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjI5OjUzLjgwM1oiLCJtZXNzYWdlIjp7InJvbGUiOiJ0b29sUmVzdWx0IiwidG9vbENhbGxJZCI6ImNhbGxfYzEzZGQ3ZTkxMGM1NGMzYTllOTU3ZTY1IiwidG9vbE5hbWUiOiJiYXNoIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiXG4+IHJlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11a0AwLjAuMSB0ZXN0XG4+IHZpdGVzdCBydW5cblxuXG4gUlVOICB2My4yLjYgL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWtcblxuIOKdryBzcmMvZ3JlZXQudGVzdC50cyAoMSB0ZXN0IHwgMSBmYWlsZWQpIDRtc1xuICAgw5cgZ3JlZXQgPiByZXR1cm5zIGEgZ3JlZXRpbmcgZm9yIGEgZ2l2ZW4gbmFtZSAzbXNcbiAgICAg4oaSIGV4cGVjdGVkICdIZWxsbywgV29ybGQhJyB0byBiZSAnR29vZGJ5ZSwgV29ybGQhJyAvLyBPYmplY3QuaXMgZXF1YWxpdHlcblxu4o6v4o6v4o6v4o6v4o6v4o6v4o6vIEZhaWxlZCBUZXN0cyAxIOKOr+KOr+KOr+KOr+KOr+KOr+KOr1xuXG4gRkFJTCAgc3JjL2dyZWV0LnRlc3QudHMgPiBncmVldCA+IHJldHVybnMgYSBncmVldGluZyBmb3IgYSBnaXZlbiBuYW1lXG5Bc3NlcnRpb25FcnJvcjogZXhwZWN0ZWQgJ0hlbGxvLCBXb3JsZCEnIHRvIGJlICdHb29kYnllLCBXb3JsZCEnIC8vIE9iamVjdC5pcyBlcXVhbGl0eVxuXG5FeHBlY3RlZDogXHUwMDFiWzMybVwiXHUwMDFiWzdtR29vZGJ5ZVx1MDAxYlsyN20sIFdvcmxkIVwiXHUwMDFiWzM5bVxuUmVjZWl2ZWQ6IFx1MDAxYlszMW1cIlx1MDAxYls3bUhlbGxvXHUwMDFiWzI3bSwgV29ybGQhXCJcdTAwMWJbMzltXG5cbiDina8gc3JjL2dyZWV0LnRlc3QudHM6NjoyOFxuICAgICAgNHwgZGVzY3JpYmUoXCJncmVldFwiLCAoKSA9PiB7XG4gICAgICA1fCAgIGl0KFwicmV0dXJucyBhIGdyZWV0aW5nIGZvciBhIGdpdmVuIG5hbWVcIiwgKCkgPT4ge1xuICAgICAgNnwgICAgIGV4cGVjdChncmVldChcIldvcmxkXCIpKS50b0JlKFwiR29vZGJ5ZSwgV29ybGQhXCIpO1xuICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgXlxuICAgICAgN3wgICB9KTtcbiAgICAgIDh8IH0pO1xuXG7ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq9bMS8xXeKOr1xuXG5cbiBUZXN0IEZpbGVzICAxIGZhaWxlZCAoMSlcbiAgICAgIFRlc3RzICAxIGZhaWxlZCAoMSlcbiAgIFN0YXJ0IGF0ICAxMjoyOTo1M1xuICAgRHVyYXRpb24gIDIzM21zICh0cmFuc2Zvcm0gMjJtcywgc2V0dXAgMG1zLCBjb2xsZWN0IDE5bXMsIHRlc3RzIDRtcywgZW52aXJvbm1lbnQgMG1zLCBwcmVwYXJlIDMxbXMpXG5cblxuXG5Db21tYW5kIGV4aXRlZCB3aXRoIGNvZGUgMSJ9XSwiZGV0YWlscyI6e30sImlzRXJyb3IiOnRydWUsInRpbWVzdGFtcCI6MTc4MTk1NDk5MzgwM319LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6ImVjMzgyYjgyIiwicGFyZW50SWQiOiJjZWM1ZjIwNCIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MzA6MDAuMTM2WiIsIm1lc3NhZ2UiOnsicm9sZSI6ImFzc2lzdGFudCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6IlJlZCEg4p2MXG5cbmBgYFxuIOKdryBzcmMvZ3JlZXQudGVzdC50cyAoMSB0ZXN0IHwgMSBmYWlsZWQpXG4gICDinJcgZXhwZWN0ZWQgJ0hlbGxvLCBXb3JsZCEnIHRvIGJlICdHb29kYnllLCBXb3JsZCEnXG5gYGBcblxuVGhlIHRlc3QgZXhwZWN0cyBgXCJHb29kYnllLCBXb3JsZCFcImAgYnV0IGBncmVldChcIldvcmxkXCIpYCByZXR1cm5zIGBcIkhlbGxvLCBXb3JsZCFcImAuIFJlYWR5IHRvIG1ha2UgaXQgZ3JlZW4gYWdhaW4g4oCUIHdhbnQgbWUgdG8gZml4IHRoZSB0ZXN0IG9yIHRoZSBpbXBsZW1lbnRhdGlvbj8ifV0sImFwaSI6Im9wZW5haS1jb21wbGV0aW9ucyIsInByb3ZpZGVyIjoib3BlbnJvdXRlciIsIm1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2giLCJ1c2FnZSI6eyJpbnB1dCI6NjIxLCJvdXRwdXQiOjg2LCJjYWNoZVJlYWQiOjQwNDQ4LCJjYWNoZVdyaXRlIjowLCJ0b3RhbFRva2VucyI6NDExNTUsImNvc3QiOnsiaW5wdXQiOjAuMDAwMDU1ODksIm91dHB1dCI6MC4wMDAwMTU0OCwiY2FjaGVSZWFkIjowLjAwMDgwODk2MDAwMDAwMDAwMDEsImNhY2hlV3JpdGUiOjAsInRvdGFsIjowLjAwMDg4MDMzfX0sInN0b3BSZWFzb24iOiJzdG9wIiwidGltZXN0YW1wIjoxNzgxOTU0OTkzODA0LCJyZXNwb25zZUlkIjoiZ2VuLTE3ODE5NTQ5OTMtandvVDBrSXlPY3ZJZzNybFJXcEUiLCJyZXNwb25zZU1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2gtMjAyNjA0MjMifX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiYTg4NTVkYTAiLCJwYXJlbnRJZCI6ImVjMzgyYjgyIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMTozMDozMS4yMjNaIiwibWVzc2FnZSI6eyJyb2xlIjoidXNlciIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6IkdyZWF0LCB3ZSBoYXZlIHRoZSBUZXN0cyAgMSBmYWlsZWQgKDEpIHNob3dpbmcgYWZ0ZXIgdGhlIGFnZW50IGNvbXBsZXRlcywgYnV0IGl0IHNob3VsZCBwZXJzaXN0IGluIHRoZSBuZXh0IHR1cm4uIFdoYXQgZG8gd2UgbmVlZCB0byBkbz8ifV0sInRpbWVzdGFtcCI6MTc4MTk1NTAzMTIyMn19LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6IjEzNzIzNWY5IiwicGFyZW50SWQiOiJhODg1NWRhMCIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MzA6MzkuNzExWiIsIm1lc3NhZ2UiOnsicm9sZSI6ImFzc2lzdGFudCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0aGlua2luZyIsInRoaW5raW5nIjoiVGhlIHVzZXIgaXMgc2F5aW5nIHRoZSB0ZXN0IHN0YXR1cyB3aWRnZXQgYXBwZWFycyBhZnRlciB0aGUgdG9vbCBydW5zLCBidXQgaXQgZ2V0cyBjbGVhcmVkIG9uIHRoZSBuZXh0IHR1cm4uIExvb2tpbmcgYXQgb3VyIGV4dGVuc2lvbiwgd2UgbGlzdGVuIHRvIGBhZ2VudF9zdGFydGAgdG8gY2xlYXIgdGhlIHdpZGdldDpcblxuYGBgdHlwZXNjcmlwdFxucGkub24oXCJhZ2VudF9zdGFydFwiLCBhc3luYyAoX2V2ZW50LCBjdHgpID0+IHtcbiAgICBjdHgudWkuc2V0V2lkZ2V0KFwidGVzdC1zdGF0dXNcIiwgdW5kZWZpbmVkKTtcbn0pO1xuYGBgXG5cblRoZSBwcm9ibGVtIGlzOiBgYWdlbnRfc3RhcnRgIGZpcmVzIGF0IHRoZSBzdGFydCBvZiBFVkVSWSBhZ2VudCB0dXJuIC0gdGhhdCBtZWFucyB3aGVuZXZlciB0aGUgdXNlciBzZW5kcyBhIG5ldyBwcm9tcHQsIGl0IGNsZWFycyB0aGUgd2lkZ2V0IGltbWVkaWF0ZWx5IGJlZm9yZSB0aGUgTExNIGhhcyBhIGNoYW5jZSB0byBydW4gdGVzdHMgYWdhaW4uIFNvIHRoZSB0ZXN0IHJlc3VsdCBmcm9tIHRoZSBwcmV2aW91cyB0dXJuIGdldHMgd2lwZWQgYXMgc29vbiBhcyB0aGUgdXNlciB0eXBlcyBhbnl0aGluZywgZXZlbiBiZWZvcmUgbmV3IHRlc3RzIHJ1bi5cblxuVGhlIHVzZXIgd2FudHMgdGhlIHRlc3Qgc3RhdHVzIHRvIHBlcnNpc3QgdW50aWwgTkVXIHRlc3QgcmVzdWx0cyBjb21lIGluLiBTbyB3ZSBzaG91bGQgTk9UIGNsZWFyIG9uIGBhZ2VudF9zdGFydGAuIEluc3RlYWQsIHdlIHNob3VsZDpcblxuMS4gT25seSBjbGVhciB3aGVuIGEgTkVXIHRlc3QgcnVuIHByb2R1Y2VzIHJlc3VsdHMgKHdoaWNoIHdpbGwgbmF0dXJhbGx5IG92ZXJ3cml0ZSB0aGUgb2xkIHdpZGdldClcbjIuIE9yIGFsdGVybmF0aXZlbHksIGNsZWFyIGF0IHRoZSBzdGFydCBvZiBhIHRlc3QgY29tbWFuZCBleGVjdXRpb24gKHRvb2xfY2FsbCksIG5vdCBhdCBhZ2VudF9zdGFydFxuXG5TbyB0aGUgZml4IGlzOiByZW1vdmUgdGhlIGBhZ2VudF9zdGFydGAgaGFuZGxlciBlbnRpcmVseSwgb3IgY2hhbmdlIGl0IHRvIG9ubHkgY2xlYXIgd2hlbiB3ZSdyZSBhYm91dCB0byBydW4gbmV3IHRlc3RzIChpbiBgdG9vbF9jYWxsYCBiZWZvcmUgdGhlIHRlc3RzIGV4ZWN1dGUpLlxuXG5BY3R1YWxseSwgbGV0IG1lIHRoaW5rIG1vcmUgY2FyZWZ1bGx5LiBUaGUgdXNlciBzYWlkIFwiaXQgc2hvdWxkIHBlcnNpc3QgaW4gdGhlIG5leHQgdHVybi5cIiBTbyBpZiBJIHR5cGUgXCJydW4gdGVzdHNcIiBhbmQgdGhlIHRlc3RzIGZhaWwsIEkgc2VlIHRoZSByZWQgd2lkZ2V0LiBUaGVuIEkgdHlwZSBcImZpeCB0aGUgZ3JlZXRpbmcgZnVuY3Rpb25cIiAtIHRoZSBhZ2VudCBzdGFydHMgYSBuZXcgdHVybiwgYW5kIHRoZSB3aWRnZXQgZGlzYXBwZWFycy4gQnV0IHRoZSB0ZXN0cyBoYXZlbid0IGJlZW4gcmUtcnVuIHlldCEgVGhlIHRlc3Qgc3RhdHVzIGlzIHN0aWxsIHZhbGlkIC0gaXQncyB0aGUgbGFzdCBrbm93biB0ZXN0IHN0YXR1cy5cblxuU28gdGhlIGZpeCBpcyBzaW1wbHk6IGRvbid0IGNsZWFyIHRoZSB3aWRnZXQgb24gYGFnZW50X3N0YXJ0YC4gS2VlcCBpdCB1bnRpbCBhIG5ldyB0ZXN0IHJ1biBvdmVyd3JpdGVzIGl0LCBvciB1bnRpbCB0aGUgdXNlciBleHBsaWNpdGx5IGNsZWFycyBpdCwgb3IgbWF5YmUga2VlcCBpdCBhY3Jvc3Mgc2Vzc2lvbnMgZW50aXJlbHkuXG5cblRoZSBzaW1wbGVzdCBjaGFuZ2U6IHJlbW92ZSB0aGUgYGFnZW50X3N0YXJ0YCBoYW5kbGVyLiBUaGUgd2lkZ2V0IG9ubHkgZ2V0cyByZXBsYWNlZCB3aGVuIGEgbmV3IGB0b29sX3Jlc3VsdGAgd2l0aCBhIHRlc3QgY29tbWFuZCBmaXJlcywgd2hpY2ggbmF0dXJhbGx5IG92ZXJ3cml0ZXMgd2l0aCB0aGUgbmV3IHN0YXR1cy5cblxuTGV0IG1lIGltcGxlbWVudCB0aGF0LiIsInRoaW5raW5nU2lnbmF0dXJlIjoicmVhc29uaW5nIn0seyJ0eXBlIjoidGV4dCIsInRleHQiOiJUaGUgcHJvYmxlbSBpcyBpbiB0aGUgYGFnZW50X3N0YXJ0YCBoYW5kbGVyIOKAlCBpdCBjbGVhcnMgdGhlIHdpZGdldCBhdCB0aGUgc3RhcnQgb2YgKipldmVyeSoqIHR1cm4sIGV2ZW4gYmVmb3JlIHRoZSBMTE0gaGFzIGEgY2hhbmNlIHRvIHJ1biBuZXcgdGVzdHMuIFNvIGFzIHNvb24gYXMgeW91IHR5cGUgYW5vdGhlciBwcm9tcHQsIHRoZSB0ZXN0IHJlc3VsdCB2YW5pc2hlcy5cblxuVGhlIGZpeDogKipyZW1vdmUgdGhlIGBhZ2VudF9zdGFydGAgaGFuZGxlcioqLiBMZXQgdGhlIHdpZGdldCBwZXJzaXN0IHVudGlsIGEgbmV3IHRlc3QgcnVuIHByb2R1Y2VzIGZyZXNoIHJlc3VsdHMsIHdoaWNoIG5hdHVyYWxseSBvdmVyd3JpdGVzIGl0LiJ9LHsidHlwZSI6InRvb2xDYWxsIiwiaWQiOiJjYWxsXzAwX3dBZ1VLQndldHVvVGJ2aFB0Tk1tMDcyNSIsIm5hbWUiOiJlZGl0IiwiYXJndW1lbnRzIjp7InBhdGgiOiIvVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ay8ucGkvZXh0ZW5zaW9ucy90ZXN0LXN0YXR1cy50cyIsImVkaXRzIjpbeyJvbGRUZXh0IjoiZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdGVzdFN0YXR1c0V4dGVuc2lvbihwaTogRXh0ZW5zaW9uQVBJKSB7XG4gIC8vIENsZWFyIHRoZSB3aWRnZXQgd2hlbiBhIG5ldyBhZ2VudCB0dXJuIHN0YXJ0cyAoc3RhbGUgcmVzdWx0cylcbiAgcGkub24oXCJhZ2VudF9zdGFydFwiLCBhc3luYyAoX2V2ZW50LCBjdHgpID0+IHtcbiAgICBjdHgudWkuc2V0V2lkZ2V0KFwidGVzdC1zdGF0dXNcIiwgdW5kZWZpbmVkKTtcbiAgfSk7XG5cbiAgLy8gQWZ0ZXIgZXZlcnkgdG9vbCBleGVjdXRpb24sIGNoZWNrIGlmIHRlc3RzIGp1c3QgcmFuIiwibmV3VGV4dCI6ImV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHRlc3RTdGF0dXNFeHRlbnNpb24ocGk6IEV4dGVuc2lvbkFQSSkge1xuICAvLyBBZnRlciBldmVyeSB0b29sIGV4ZWN1dGlvbiwgY2hlY2sgaWYgdGVzdHMganVzdCByYW4ifV19fV0sImFwaSI6Im9wZW5haS1jb21wbGV0aW9ucyIsInByb3ZpZGVyIjoib3BlbnJvdXRlciIsIm1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2giLCJ1c2FnZSI6eyJpbnB1dCI6ODUzLCJvdXRwdXQiOjcxMiwiY2FjaGVSZWFkIjo0MDMyMCwiY2FjaGVXcml0ZSI6MCwidG90YWxUb2tlbnMiOjQxODg1LCJjb3N0Ijp7ImlucHV0IjowLjAwMDA3Njc3LCJvdXRwdXQiOjAuMDAwMTI4MTYsImNhY2hlUmVhZCI6MC4wMDA4MDY0LCJjYWNoZVdyaXRlIjowLCJ0b3RhbCI6MC4wMDEwMTEzM319LCJzdG9wUmVhc29uIjoidG9vbFVzZSIsInRpbWVzdGFtcCI6MTc4MTk1NTAzMTIyNCwicmVzcG9uc2VJZCI6Imdlbi0xNzgxOTU1MDMxLWVqMVJnZHV6bTJobVd3ZUZRZ2ltIiwicmVzcG9uc2VNb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoLTIwMjYwNDIzIn19LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6IjEzNGU3NWEwIiwicGFyZW50SWQiOiIxMzcyMzVmOSIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MzA6MzkuNzIwWiIsIm1lc3NhZ2UiOnsicm9sZSI6InRvb2xSZXN1bHQiLCJ0b29sQ2FsbElkIjoiY2FsbF8wMF93QWdVS0J3ZXR1b1RidmhQdE5NbTA3MjUiLCJ0b29sTmFtZSI6ImVkaXQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGV4dCIsInRleHQiOiJTdWNjZXNzZnVsbHkgcmVwbGFjZWQgMSBibG9jayhzKSBpbiAvVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ay8ucGkvZXh0ZW5zaW9ucy90ZXN0LXN0YXR1cy50cy4ifV0sImRldGFpbHMiOnsiZGlmZiI6IiAgMSBpbXBvcnQgeyBpc0Jhc2hUb29sUmVzdWx0LCB0eXBlIEV4dGVuc2lvbkFQSSB9IGZyb20gXCJAZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50XCI7XG4gIDIgXG4gIDMgZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdGVzdFN0YXR1c0V4dGVuc2lvbihwaTogRXh0ZW5zaW9uQVBJKSB7XG4tIDQgICAvLyBDbGVhciB0aGUgd2lkZ2V0IHdoZW4gYSBuZXcgYWdlbnQgdHVybiBzdGFydHMgKHN0YWxlIHJlc3VsdHMpXG4tIDUgICBwaS5vbihcImFnZW50X3N0YXJ0XCIsIGFzeW5jIChfZXZlbnQsIGN0eCkgPT4ge1xuLSA2ICAgICBjdHgudWkuc2V0V2lkZ2V0KFwidGVzdC1zdGF0dXNcIiwgdW5kZWZpbmVkKTtcbi0gNyAgIH0pO1xuLSA4IFxuICA5ICAgLy8gQWZ0ZXIgZXZlcnkgdG9vbCBleGVjdXRpb24sIGNoZWNrIGlmIHRlc3RzIGp1c3QgcmFuXG4gMTAgICBwaS5vbihcInRvb2xfcmVzdWx0XCIsIGFzeW5jIChldmVudCwgY3R4KSA9PiB7XG4gMTEgICAgIC8vIE9ubHkgY2FyZSBhYm91dCBiYXNoIGNvbW1hbmRzXG4gMTIgICAgIGlmICghaXNCYXNoVG9vbFJlc3VsdChldmVudCkpIHJldHVybjtcbiAgICAuLi4iLCJwYXRjaCI6Ii0tLSAvVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ay8ucGkvZXh0ZW5zaW9ucy90ZXN0LXN0YXR1cy50c1xuKysrIC9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrLy5waS9leHRlbnNpb25zL3Rlc3Qtc3RhdHVzLnRzXG5AQCAtMSwxMiArMSw3IEBAXG4gaW1wb3J0IHsgaXNCYXNoVG9vbFJlc3VsdCwgdHlwZSBFeHRlbnNpb25BUEkgfSBmcm9tIFwiQGVhcmVuZGlsLXdvcmtzL3BpLWNvZGluZy1hZ2VudFwiO1xuIFxuIGV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHRlc3RTdGF0dXNFeHRlbnNpb24ocGk6IEV4dGVuc2lvbkFQSSkge1xuLSAgLy8gQ2xlYXIgdGhlIHdpZGdldCB3aGVuIGEgbmV3IGFnZW50IHR1cm4gc3RhcnRzIChzdGFsZSByZXN1bHRzKVxuLSAgcGkub24oXCJhZ2VudF9zdGFydFwiLCBhc3luYyAoX2V2ZW50LCBjdHgpID0+IHtcbi0gICAgY3R4LnVpLnNldFdpZGdldChcInRlc3Qtc3RhdHVzXCIsIHVuZGVmaW5lZCk7XG4tICB9KTtcbi1cbiAgIC8vIEFmdGVyIGV2ZXJ5IHRvb2wgZXhlY3V0aW9uLCBjaGVjayBpZiB0ZXN0cyBqdXN0IHJhblxuICAgcGkub24oXCJ0b29sX3Jlc3VsdFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAgICAvLyBPbmx5IGNhcmUgYWJvdXQgYmFzaCBjb21tYW5kc1xuICAgICBpZiAoIWlzQmFzaFRvb2xSZXN1bHQoZXZlbnQpKSByZXR1cm47XG4iLCJmaXJzdENoYW5nZWRMaW5lIjo0fSwiaXNFcnJvciI6ZmFsc2UsInRpbWVzdGFtcCI6MTc4MTk1NTAzOTcyMH19LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6ImI4YTIyMjQ5IiwicGFyZW50SWQiOiIxMzRlNzVhMCIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MzA6NDIuOTA0WiIsIm1lc3NhZ2UiOnsicm9sZSI6ImFzc2lzdGFudCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0aGlua2luZyIsInRoaW5raW5nIjoiTGV0IG1lIHZlcmlmeSB0aGUgZmlsZSBsb29rcyBjb3JyZWN0LiIsInRoaW5raW5nU2lnbmF0dXJlIjoicmVhc29uaW5nIn0seyJ0eXBlIjoidGV4dCIsInRleHQiOiJOb3cgdGhlIHdpZGdldCBvbmx5IHVwZGF0ZXMgd2hlbiBhIG5ldyB0ZXN0IHJ1biBjb21wbGV0ZXMg4oCUIGl0IHN0YXlzIHZpc2libGUgYWNyb3NzIHR1cm5zIHVudGlsIGZyZXNoIHRlc3Qgb3V0cHV0IGFycml2ZXMuIn0seyJ0eXBlIjoidG9vbENhbGwiLCJpZCI6ImNhbGxfMDBfQWhGOEsxbWJlZ0lpb1NvQlNGbzY0NTk1IiwibmFtZSI6InJlYWQiLCJhcmd1bWVudHMiOnsicGF0aCI6Ii9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrLy5waS9leHRlbnNpb25zL3Rlc3Qtc3RhdHVzLnRzIn19XSwiYXBpIjoib3BlbmFpLWNvbXBsZXRpb25zIiwicHJvdmlkZXIiOiJvcGVucm91dGVyIiwibW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaCIsInVzYWdlIjp7ImlucHV0Ijo4NDMsIm91dHB1dCI6MTAwLCJjYWNoZVJlYWQiOjQxMDg4LCJjYWNoZVdyaXRlIjowLCJ0b3RhbFRva2VucyI6NDIwMzEsImNvc3QiOnsiaW5wdXQiOjAuMDAwMDc1ODcsIm91dHB1dCI6MC4wMDAwMTgsImNhY2hlUmVhZCI6MC4wMDA4MjE3NiwiY2FjaGVXcml0ZSI6MCwidG90YWwiOjAuMDAwOTE1NjMwMDAwMDAwMDAwMX19LCJzdG9wUmVhc29uIjoidG9vbFVzZSIsInRpbWVzdGFtcCI6MTc4MTk1NTAzOTcyMiwicmVzcG9uc2VJZCI6Imdlbi0xNzgxOTU1MDM5LUpGeG9ZTjREQ0ZmWFRLbDRMcGN6IiwicmVzcG9uc2VNb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoLTIwMjYwNDIzIn19LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6Ijc1NTk2ZjczIiwicGFyZW50SWQiOiJiOGEyMjI0OSIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MzA6NDIuOTA4WiIsIm1lc3NhZ2UiOnsicm9sZSI6InRvb2xSZXN1bHQiLCJ0b29sQ2FsbElkIjoiY2FsbF8wMF9BaEY4SzFtYmVnSWlvU29CU0ZvNjQ1OTUiLCJ0b29sTmFtZSI6InJlYWQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGV4dCIsInRleHQiOiJpbXBvcnQgeyBpc0Jhc2hUb29sUmVzdWx0LCB0eXBlIEV4dGVuc2lvbkFQSSB9IGZyb20gXCJAZWFyZW5kaWwtd29ya3MvcGktY29kaW5nLWFnZW50XCI7XG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHRlc3RTdGF0dXNFeHRlbnNpb24ocGk6IEV4dGVuc2lvbkFQSSkge1xuICAvLyBBZnRlciBldmVyeSB0b29sIGV4ZWN1dGlvbiwgY2hlY2sgaWYgdGVzdHMganVzdCByYW5cbiAgcGkub24oXCJ0b29sX3Jlc3VsdFwiLCBhc3luYyAoZXZlbnQsIGN0eCkgPT4ge1xuICAgIC8vIE9ubHkgY2FyZSBhYm91dCBiYXNoIGNvbW1hbmRzXG4gICAgaWYgKCFpc0Jhc2hUb29sUmVzdWx0KGV2ZW50KSkgcmV0dXJuO1xuXG4gICAgY29uc3QgY29tbWFuZDogc3RyaW5nID0gZXZlbnQuaW5wdXQuY29tbWFuZDtcblxuICAgIC8vIE9ubHkgY2FyZSBhYm91dCB0ZXN0IGNvbW1hbmRzXG4gICAgaWYgKCFjb21tYW5kLmluY2x1ZGVzKFwibnBtIHRlc3RcIikgJiYgIWNvbW1hbmQuaW5jbHVkZXMoXCJ2aXRlc3RcIikgJiYgIWNvbW1hbmQuaW5jbHVkZXMoXCJucHggdml0ZXN0XCIpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qgb3V0cHV0ID0gZXZlbnQuY29udGVudFswXT8udGV4dCA/PyBcIlwiO1xuICAgIGNvbnN0IHRoZW1lID0gY3R4LnVpLnRoZW1lO1xuXG4gICAgLy8gRGV0ZWN0IHBhc3MvZmFpbCBmcm9tIHZpdGVzdCBzdW1tYXJ5IG91dHB1dFxuICAgIGNvbnN0IHRlc3RzUGFzc2VkID0gL1Rlc3RzXFxzKy4rcGFzc2VkLy50ZXN0KG91dHB1dCkgJiYgIS9UZXN0c1xccysuK2ZhaWxlZC8udGVzdChvdXRwdXQpO1xuICAgIGNvbnN0IHRlc3RzRmFpbGVkID0gL1Rlc3RzXFxzKy4rZmFpbGVkLy50ZXN0KG91dHB1dCkgfHwgZXZlbnQuZGV0YWlscz8uZXhpdENvZGUgIT09IDA7XG5cbiAgICBpZiAodGVzdHNQYXNzZWQpIHtcbiAgICAgIC8vIEV4dHJhY3Qgc3VtbWFyeSBsaW5lIGZvciBpbmxpbmUgZGV0YWlsIChlLmcuLCBcIjEgcGFzc2VkICgyNDJtcylcIilcbiAgICAgIGNvbnN0IHN1bW1hcnlMaW5lID0gb3V0cHV0XG4gICAgICAgIC5zcGxpdChcIlxcblwiKVxuICAgICAgICAuZmluZCgobGluZTogc3RyaW5nKSA9PiAvVGVzdCBGaWxlc1xccysuK3Bhc3NlZC8udGVzdChsaW5lKSk7XG4gICAgICBjb25zdCBzdW1tYXJ5ID0gc3VtbWFyeUxpbmU/LnRyaW0oKSA/PyBcIkFsbCB0ZXN0cyBwYXNzZWRcIjtcblxuICAgICAgY3R4LnVpLnNldFdpZGdldChcInRlc3Qtc3RhdHVzXCIsIFtcbiAgICAgICAgYCR7dGhlbWUuZmcoXCJzdWNjZXNzXCIsIFwi4pePXCIpfSAke3RoZW1lLmZnKFwidGV4dFwiLCBzdW1tYXJ5KX1gLFxuICAgICAgXSk7XG4gICAgfSBlbHNlIGlmICh0ZXN0c0ZhaWxlZCkge1xuICAgICAgY29uc3Qgc3VtbWFyeUxpbmUgPSBvdXRwdXRcbiAgICAgICAgLnNwbGl0KFwiXFxuXCIpXG4gICAgICAgIC5maW5kKChsaW5lOiBzdHJpbmcpID0+IC9UZXN0c1xccysuK2ZhaWxlZC8udGVzdChsaW5lKSk7XG4gICAgICBjb25zdCBzdW1tYXJ5ID0gc3VtbWFyeUxpbmU/LnRyaW0oKSA/PyBcIlRlc3RzIGZhaWxlZFwiO1xuXG4gICAgICBjdHgudWkuc2V0V2lkZ2V0KFwidGVzdC1zdGF0dXNcIiwgW1xuICAgICAgICBgJHt0aGVtZS5mZyhcImVycm9yXCIsIFwi4pePXCIpfSAke3RoZW1lLmZnKFwidGV4dFwiLCBzdW1tYXJ5KX1gLFxuICAgICAgXSk7XG4gICAgfVxuICB9KTtcbn1cbiJ9XSwiaXNFcnJvciI6ZmFsc2UsInRpbWVzdGFtcCI6MTc4MTk1NTA0MjkwOH19LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6ImUzYzkyYzQ2IiwicGFyZW50SWQiOiI3NTU5NmY3MyIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MzA6NDguMDQzWiIsIm1lc3NhZ2UiOnsicm9sZSI6ImFzc2lzdGFudCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6IkNsZWFuIGFuZCBzaW1wbGUgbm93LiBUaGUgd2lkZ2V0IGZvbGxvd3MgdGhpcyBsaWZlY3ljbGU6XG5cbi0gKipVc2VyIGFza3MgdG8gcnVuIHRlc3RzKiog4oaSIExMTSBjYWxscyBgbnBtIHRlc3RgIOKGkiBgdG9vbF9yZXN1bHRgIGZpcmVzIOKGkiB3aWRnZXQgc2hvd3Mg4pePIGdyZWVuIG9yIOKXjyByZWRcbi0gKipVc2VyIHR5cGVzIG5leHQgcHJvbXB0Kiog4oaSIGFnZW50IHN0YXJ0cyBhIG5ldyB0dXJuIOKGkiAqKndpZGdldCBzdGF5cyoqIChubyBgYWdlbnRfc3RhcnRgIHRvIGNsZWFyIGl0KVxuLSAqKlRlc3RzIHJ1biBhZ2FpbioqIOKGkiBgdG9vbF9yZXN1bHRgIGZpcmVzIGFnYWluIOKGkiB3aWRnZXQgKip1cGRhdGVzKiogd2l0aCBmcmVzaCByZXN1bHRzXG5cbldhbnQgdG8gYC9yZWxvYWRgIGFuZCB0ZXN0IGl0IG91dD8ifV0sImFwaSI6Im9wZW5haS1jb21wbGV0aW9ucyIsInByb3ZpZGVyIjoib3BlbnJvdXRlciIsIm1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2giLCJ1c2FnZSI6eyJpbnB1dCI6Mjc5NSwib3V0cHV0IjoxMDUsImNhY2hlUmVhZCI6Mzk2ODAsImNhY2hlV3JpdGUiOjAsInRvdGFsVG9rZW5zIjo0MjU4MCwiY29zdCI6eyJpbnB1dCI6MC4wMDAyNTE1NSwib3V0cHV0IjowLjAwMDAxODksImNhY2hlUmVhZCI6MC4wMDA3OTM2LCJjYWNoZVdyaXRlIjowLCJ0b3RhbCI6MC4wMDEwNjQwNX19LCJzdG9wUmVhc29uIjoic3RvcCIsInRpbWVzdGFtcCI6MTc4MTk1NTA0MjkwOSwicmVzcG9uc2VJZCI6Imdlbi0xNzgxOTU1MDQyLXJoWmZKeE95QkJqNEZBOUo2ZnFyIiwicmVzcG9uc2VNb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoLTIwMjYwNDIzIn19LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6IjkyMTYwYjcwIiwicGFyZW50SWQiOiJlM2M5MmM0NiIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MzI6MzguMTQwWiIsIm1lc3NhZ2UiOnsicm9sZSI6InVzZXIiLCJjb250ZW50IjpbeyJ0eXBlIjoidGV4dCIsInRleHQiOiJydW4gdGVzdHMifV0sInRpbWVzdGFtcCI6MTc4MTk1NTE1ODEzOX19LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6IjU0ZjZmNzhmIiwicGFyZW50SWQiOiI5MjE2MGI3MCIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MzI6NDMuMDQ5WiIsIm1lc3NhZ2UiOnsicm9sZSI6ImFzc2lzdGFudCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0aGlua2luZyIsInRoaW5raW5nIjoiVGhlIHVzZXIgd2FudHMgbWUgdG8gcnVuIHRoZSB0ZXN0cyBhZ2Fpbi4iLCJ0aGlua2luZ1NpZ25hdHVyZSI6InJlYXNvbmluZyJ9LHsidHlwZSI6InRvb2xDYWxsIiwiaWQiOiJjYWxsXzAwX0lXb3JXWjVDVmZaUHZZZTBacGRrMjAwOSIsIm5hbWUiOiJiYXNoIiwiYXJndW1lbnRzIjp7ImNvbW1hbmQiOiJjZCAvVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ayAmJiBucG0gdGVzdCJ9fV0sImFwaSI6Im9wZW5haS1jb21wbGV0aW9ucyIsInByb3ZpZGVyIjoib3BlbnJvdXRlciIsIm1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2giLCJ1c2FnZSI6eyJpbnB1dCI6OTAsIm91dHB1dCI6NzcsImNhY2hlUmVhZCI6NDI0OTYsImNhY2hlV3JpdGUiOjAsInRvdGFsVG9rZW5zIjo0MjY2MywiY29zdCI6eyJpbnB1dCI6MC4wMDAwMDgxLCJvdXRwdXQiOjAuMDAwMDEzODYsImNhY2hlUmVhZCI6MC4wMDA4NDk5MiwiY2FjaGVXcml0ZSI6MCwidG90YWwiOjAuMDAwODcxODh9fSwic3RvcFJlYXNvbiI6InRvb2xVc2UiLCJ0aW1lc3RhbXAiOjE3ODE5NTUxNTgxNDIsInJlc3BvbnNlSWQiOiJnZW4tMTc4MTk1NTE1OC01U3ppWGY5Q3QzU1JmaXBmVlEyeSIsInJlc3BvbnNlTW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaC0yMDI2MDQyMyJ9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiI1ZWEwYjYzZCIsInBhcmVudElkIjoiNTRmNmY3OGYiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjMyOjQzLjgwNFoiLCJtZXNzYWdlIjp7InJvbGUiOiJ0b29sUmVzdWx0IiwidG9vbENhbGxJZCI6ImNhbGxfMDBfSVdvcldaNUNWZlpQdlllMFpwZGsyMDA5IiwidG9vbE5hbWUiOiJiYXNoIiwiY29udGVudCI6W3sidHlwZSI6InRleHQiLCJ0ZXh0IjoiXG4+IHJlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11a0AwLjAuMSB0ZXN0XG4+IHZpdGVzdCBydW5cblxuXG4gUlVOICB2My4yLjYgL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWtcblxuIOKdryBzcmMvZ3JlZXQudGVzdC50cyAoMSB0ZXN0IHwgMSBmYWlsZWQpIDRtc1xuICAgw5cgZ3JlZXQgPiByZXR1cm5zIGEgZ3JlZXRpbmcgZm9yIGEgZ2l2ZW4gbmFtZSAzbXNcbiAgICAg4oaSIGV4cGVjdGVkICdIZWxsbywgV29ybGQhJyB0byBiZSAnR29vZGJ5ZSwgV29ybGQhJyAvLyBPYmplY3QuaXMgZXF1YWxpdHlcblxu4o6v4o6v4o6v4o6v4o6v4o6v4o6vIEZhaWxlZCBUZXN0cyAxIOKOr+KOr+KOr+KOr+KOr+KOr+KOr1xuXG4gRkFJTCAgc3JjL2dyZWV0LnRlc3QudHMgPiBncmVldCA+IHJldHVybnMgYSBncmVldGluZyBmb3IgYSBnaXZlbiBuYW1lXG5Bc3NlcnRpb25FcnJvcjogZXhwZWN0ZWQgJ0hlbGxvLCBXb3JsZCEnIHRvIGJlICdHb29kYnllLCBXb3JsZCEnIC8vIE9iamVjdC5pcyBlcXVhbGl0eVxuXG5FeHBlY3RlZDogXHUwMDFiWzMybVwiXHUwMDFiWzdtR29vZGJ5ZVx1MDAxYlsyN20sIFdvcmxkIVwiXHUwMDFiWzM5bVxuUmVjZWl2ZWQ6IFx1MDAxYlszMW1cIlx1MDAxYls3bUhlbGxvXHUwMDFiWzI3bSwgV29ybGQhXCJcdTAwMWJbMzltXG5cbiDina8gc3JjL2dyZWV0LnRlc3QudHM6NjoyOFxuICAgICAgNHwgZGVzY3JpYmUoXCJncmVldFwiLCAoKSA9PiB7XG4gICAgICA1fCAgIGl0KFwicmV0dXJucyBhIGdyZWV0aW5nIGZvciBhIGdpdmVuIG5hbWVcIiwgKCkgPT4ge1xuICAgICAgNnwgICAgIGV4cGVjdChncmVldChcIldvcmxkXCIpKS50b0JlKFwiR29vZGJ5ZSwgV29ybGQhXCIpO1xuICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgXlxuICAgICAgN3wgICB9KTtcbiAgICAgIDh8IH0pO1xuXG7ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq/ijq9bMS8xXeKOr1xuXG5cbiBUZXN0IEZpbGVzICAxIGZhaWxlZCAoMSlcbiAgICAgIFRlc3RzICAxIGZhaWxlZCAoMSlcbiAgIFN0YXJ0IGF0ICAxMjozMjo0M1xuICAgRHVyYXRpb24gIDI0MG1zICh0cmFuc2Zvcm0gMjBtcywgc2V0dXAgMG1zLCBjb2xsZWN0IDE3bXMsIHRlc3RzIDRtcywgZW52aXJvbm1lbnQgMG1zLCBwcmVwYXJlIDI4bXMpXG5cblxuXG5Db21tYW5kIGV4aXRlZCB3aXRoIGNvZGUgMSJ9XSwiZGV0YWlscyI6e30sImlzRXJyb3IiOnRydWUsInRpbWVzdGFtcCI6MTc4MTk1NTE2MzgwNH19LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6IjliZjkzZGFhIiwicGFyZW50SWQiOiI1ZWEwYjYzZCIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MzI6NTMuNzAyWiIsIm1lc3NhZ2UiOnsicm9sZSI6ImFzc2lzdGFudCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6IlN0aWxsIHJlZDpcblxuYGBgXG4g4p2vIHNyYy9ncmVldC50ZXN0LnRzICgxIHRlc3QgfCAxIGZhaWxlZClcbiAgIOKclyBleHBlY3RlZCAnSGVsbG8sIFdvcmxkIScgdG8gYmUgJ0dvb2RieWUsIFdvcmxkISdcbmBgYFxuXG5SZWFkeSBmb3IgdGhlIGdyZWVuIHN0ZXAg4oCUIHdhbnQgbWUgdG8gZml4IHRoZSB0ZXN0IGJhY2ssIG9yIHVwZGF0ZSBgZ3JlZXQoKWAgdG8gcmV0dXJuIGBcIkdvb2RieWUsIFdvcmxkIVwiYCBpbnN0ZWFkPyJ9XSwiYXBpIjoib3BlbmFpLWNvbXBsZXRpb25zIiwicHJvdmlkZXIiOiJvcGVucm91dGVyIiwibW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaCIsInVzYWdlIjp7ImlucHV0IjoyMTY1LCJvdXRwdXQiOjcyLCJjYWNoZVJlYWQiOjQwOTYwLCJjYWNoZVdyaXRlIjowLCJ0b3RhbFRva2VucyI6NDMxOTcsImNvc3QiOnsiaW5wdXQiOjAuMDAwMTk0ODUsIm91dHB1dCI6MC4wMDAwMTI5NiwiY2FjaGVSZWFkIjowLjAwMDgxOTIsImNhY2hlV3JpdGUiOjAsInRvdGFsIjowLjAwMTAyNzAxfX0sInN0b3BSZWFzb24iOiJzdG9wIiwidGltZXN0YW1wIjoxNzgxOTU1MTYzODA0LCJyZXNwb25zZUlkIjoiZ2VuLTE3ODE5NTUxNjMtVEJUUWJCRTI5c1NpOU9JdDdSQUQiLCJyZXNwb25zZU1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2gtMjAyNjA0MjMifX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiZGY0MGU5YzUiLCJwYXJlbnRJZCI6IjliZjkzZGFhIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMTozMzowMy42MDNaIiwibWVzc2FnZSI6eyJyb2xlIjoidXNlciIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImZpeCB0aGUgdGVzdCJ9XSwidGltZXN0YW1wIjoxNzgxOTU1MTgzNjAyfX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiNDI5MTFiNTYiLCJwYXJlbnRJZCI6ImRmNDBlOWM1IiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMTozMzoxNS4xMjBaIiwibWVzc2FnZSI6eyJyb2xlIjoiYXNzaXN0YW50IiwiY29udGVudCI6W3sidHlwZSI6InRoaW5raW5nIiwidGhpbmtpbmciOiJUaGUgdXNlciB3YW50cyBtZSB0byBmaXggdGhlIHRlc3Qgc28gaXQgcGFzc2VzIGFnYWluLiBUaGUgdGVzdCBjdXJyZW50bHkgZXhwZWN0cyBcIkdvb2RieWUsIFdvcmxkIVwiIGJ1dCBncmVldCgpIHJldHVybnMgXCJIZWxsbywgV29ybGQhXCIuIEkgc2hvdWxkIHJldmVydCB0aGUgdGVzdCB0byBtYXRjaCB0aGUgaW1wbGVtZW50YXRpb24uIiwidGhpbmtpbmdTaWduYXR1cmUiOiJyZWFzb25pbmcifSx7InR5cGUiOiJ0b29sQ2FsbCIsImlkIjoiY2FsbF8wMF95bWpKOU9TNU9ueHJzVGxMQkZ2Mjg2OTUiLCJuYW1lIjoiZWRpdCIsImFyZ3VtZW50cyI6eyJwYXRoIjoiL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvc3JjL2dyZWV0LnRlc3QudHMiLCJlZGl0cyI6W3sib2xkVGV4dCI6ImV4cGVjdChncmVldChcIldvcmxkXCIpKS50b0JlKFwiR29vZGJ5ZSwgV29ybGQhXCIpOyIsIm5ld1RleHQiOiJleHBlY3QoZ3JlZXQoXCJXb3JsZFwiKSkudG9CZShcIkhlbGxvLCBXb3JsZCFcIik7In1dfX1dLCJhcGkiOiJvcGVuYWktY29tcGxldGlvbnMiLCJwcm92aWRlciI6Im9wZW5yb3V0ZXIiLCJtb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoIiwidXNhZ2UiOnsiaW5wdXQiOjU1Nywib3V0cHV0IjoxNzMsImNhY2hlUmVhZCI6NDI2MjQsImNhY2hlV3JpdGUiOjAsInRvdGFsVG9rZW5zIjo0MzM1NCwiY29zdCI6eyJpbnB1dCI6MC4wMDAwNTAxMjk5OTk5OTk5OTk5OTYsIm91dHB1dCI6MC4wMDAwMzExNCwiY2FjaGVSZWFkIjowLjAwMDg1MjQ4LCJjYWNoZVdyaXRlIjowLCJ0b3RhbCI6MC4wMDA5MzM3NDk5OTk5OTk5OTk5fX0sInN0b3BSZWFzb24iOiJ0b29sVXNlIiwidGltZXN0YW1wIjoxNzgxOTU1MTgzNjA1LCJyZXNwb25zZUlkIjoiZ2VuLTE3ODE5NTUxODMtaktoQm03aENrQVJaVVlOYmU1eU8iLCJyZXNwb25zZU1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2gtMjAyNjA0MjMifX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiZWY2M2E2N2UiLCJwYXJlbnRJZCI6IjQyOTExYjU2IiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMTozMzoxNS4xMjhaIiwibWVzc2FnZSI6eyJyb2xlIjoidG9vbFJlc3VsdCIsInRvb2xDYWxsSWQiOiJjYWxsXzAwX3ltako5T1M1T254cnNUbExCRnYyODY5NSIsInRvb2xOYW1lIjoiZWRpdCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6IlN1Y2Nlc3NmdWxseSByZXBsYWNlZCAxIGJsb2NrKHMpIGluIC9Vc2Vycy93aWxsZW0vZGV2L3NwaWtlcy9sbG0vcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrL3NyYy9ncmVldC50ZXN0LnRzLiJ9XSwiZGV0YWlscyI6eyJkaWZmIjoiICAgLi4uXG4gMiBpbXBvcnQgeyBncmVldCB9IGZyb20gXCIuL2dyZWV0LmpzXCI7XG4gMyBcbiA0IGRlc2NyaWJlKFwiZ3JlZXRcIiwgKCkgPT4ge1xuIDUgICBpdChcInJldHVybnMgYSBncmVldGluZyBmb3IgYSBnaXZlbiBuYW1lXCIsICgpID0+IHtcbi02ICAgICBleHBlY3QoZ3JlZXQoXCJXb3JsZFwiKSkudG9CZShcIkdvb2RieWUsIFdvcmxkIVwiKTtcbis2ICAgICBleHBlY3QoZ3JlZXQoXCJXb3JsZFwiKSkudG9CZShcIkhlbGxvLCBXb3JsZCFcIik7XG4gNyAgIH0pO1xuIDggfSk7IiwicGF0Y2giOiItLS0gL1VzZXJzL3dpbGxlbS9kZXYvc3Bpa2VzL2xsbS9yZWQtZ3JlZW4tcmVmYWN0b3ItY3ljbGUtc29jcmF0ZXMtdWsvc3JjL2dyZWV0LnRlc3QudHNcbisrKyAvVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ay9zcmMvZ3JlZXQudGVzdC50c1xuQEAgLTIsNyArMiw3IEBAXG4gaW1wb3J0IHsgZ3JlZXQgfSBmcm9tIFwiLi9ncmVldC5qc1wiO1xuIFxuIGRlc2NyaWJlKFwiZ3JlZXRcIiwgKCkgPT4ge1xuICAgaXQoXCJyZXR1cm5zIGEgZ3JlZXRpbmcgZm9yIGEgZ2l2ZW4gbmFtZVwiLCAoKSA9PiB7XG4tICAgIGV4cGVjdChncmVldChcIldvcmxkXCIpKS50b0JlKFwiR29vZGJ5ZSwgV29ybGQhXCIpO1xuKyAgICBleHBlY3QoZ3JlZXQoXCJXb3JsZFwiKSkudG9CZShcIkhlbGxvLCBXb3JsZCFcIik7XG4gICB9KTtcbiB9KTtcblxcIE5vIG5ld2xpbmUgYXQgZW5kIG9mIGZpbGVcbiIsImZpcnN0Q2hhbmdlZExpbmUiOjZ9LCJpc0Vycm9yIjpmYWxzZSwidGltZXN0YW1wIjoxNzgxOTU1MTk1MTI4fX0seyJ0eXBlIjoibWVzc2FnZSIsImlkIjoiY2VlMzM3MTUiLCJwYXJlbnRJZCI6ImVmNjNhNjdlIiwidGltZXN0YW1wIjoiMjAyNi0wNi0yMFQxMTozMzoyMS40NjBaIiwibWVzc2FnZSI6eyJyb2xlIjoiYXNzaXN0YW50IiwiY29udGVudCI6W3sidHlwZSI6InRvb2xDYWxsIiwiaWQiOiJjYWxsXzBmZTc0MzU0MjhkYzQ4MmU5NmVlODE5YSIsIm5hbWUiOiJiYXNoIiwiYXJndW1lbnRzIjp7ImNvbW1hbmQiOiJjZCAvVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ayAmJiBucG0gdGVzdCJ9fV0sImFwaSI6Im9wZW5haS1jb21wbGV0aW9ucyIsInByb3ZpZGVyIjoib3BlbnJvdXRlciIsIm1vZGVsIjoiZGVlcHNlZWsvZGVlcHNlZWstdjQtZmxhc2giLCJ1c2FnZSI6eyJpbnB1dCI6NDE4LCJvdXRwdXQiOjY4LCJjYWNoZVJlYWQiOjQzMDA4LCJjYWNoZVdyaXRlIjowLCJ0b3RhbFRva2VucyI6NDM0OTQsImNvc3QiOnsiaW5wdXQiOjAuMDAwMDM3NjIsIm91dHB1dCI6MC4wMDAwMTIyNCwiY2FjaGVSZWFkIjowLjAwMDg2MDE2LCJjYWNoZVdyaXRlIjowLCJ0b3RhbCI6MC4wMDA5MTAwMn19LCJzdG9wUmVhc29uIjoidG9vbFVzZSIsInRpbWVzdGFtcCI6MTc4MTk1NTE5NTEzMCwicmVzcG9uc2VJZCI6Imdlbi0xNzgxOTU1MTk1LXZtVVR2QWZnajB4RlV5T1JqNDhjIiwicmVzcG9uc2VNb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoLTIwMjYwNDIzIn19LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6ImI1ZTE0MThlIiwicGFyZW50SWQiOiJjZWUzMzcxNSIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTE6MzM6MjIuMTkwWiIsIm1lc3NhZ2UiOnsicm9sZSI6InRvb2xSZXN1bHQiLCJ0b29sQ2FsbElkIjoiY2FsbF8wZmU3NDM1NDI4ZGM0ODJlOTZlZTgxOWEiLCJ0b29sTmFtZSI6ImJhc2giLCJjb250ZW50IjpbeyJ0eXBlIjoidGV4dCIsInRleHQiOiJcbj4gcmVkLWdyZWVuLXJlZmFjdG9yLWN5Y2xlLXNvY3JhdGVzLXVrQDAuMC4xIHRlc3Rcbj4gdml0ZXN0IHJ1blxuXG5cbiBSVU4gIHYzLjIuNiAvVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11a1xuXG4g4pyTIHNyYy9ncmVldC50ZXN0LnRzICgxIHRlc3QpIDFtc1xuXG4gVGVzdCBGaWxlcyAgMSBwYXNzZWQgKDEpXG4gICAgICBUZXN0cyAgMSBwYXNzZWQgKDEpXG4gICBTdGFydCBhdCAgMTI6MzM6MjFcbiAgIER1cmF0aW9uICAyMzdtcyAodHJhbnNmb3JtIDIzbXMsIHNldHVwIDBtcywgY29sbGVjdCAyMW1zLCB0ZXN0cyAxbXMsIGVudmlyb25tZW50IDBtcywgcHJlcGFyZSAyOW1zKVxuXG4ifV0sImlzRXJyb3IiOmZhbHNlLCJ0aW1lc3RhbXAiOjE3ODE5NTUyMDIxOTB9fSx7InR5cGUiOiJtZXNzYWdlIiwiaWQiOiIyNTQ1ODBhYyIsInBhcmVudElkIjoiYjVlMTQxOGUiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTIwVDExOjMzOjI5LjA0M1oiLCJtZXNzYWdlIjp7InJvbGUiOiJhc3Npc3RhbnQiLCJjb250ZW50IjpbeyJ0eXBlIjoidGV4dCIsInRleHQiOiJCYWNrIHRvIGdyZWVuISDinJNcblxuYGBgXG4g4pyTIHNyYy9ncmVldC50ZXN0LnRzICgxIHRlc3QpIDFtc1xuIFRlc3QgRmlsZXMgIDEgcGFzc2VkICgxKVxuICAgICAgVGVzdHMgIDEgcGFzc2VkICgxKVxuYGBgXG5cblRoZSB3aWRnZXQgc2hvdWxkIG5vdyBzaG93OlxuXG5gYGBcbiDil48gVGVzdCBGaWxlcyAgMSBwYXNzZWQgKDEpXG5gYGBcblxuRnVsbCBjeWNsZSBjb21wbGV0ZSDigJQgcmVkIHRvIGdyZWVuLiJ9XSwiYXBpIjoib3BlbmFpLWNvbXBsZXRpb25zIiwicHJvdmlkZXIiOiJvcGVucm91dGVyIiwibW9kZWwiOiJkZWVwc2Vlay9kZWVwc2Vlay12NC1mbGFzaCIsInVzYWdlIjp7ImlucHV0IjozNDYsIm91dHB1dCI6NjQsImNhY2hlUmVhZCI6NDMyNjQsImNhY2hlV3JpdGUiOjAsInRvdGFsVG9rZW5zIjo0MzY3NCwiY29zdCI6eyJpbnB1dCI6MC4wMDAwMzExNCwib3V0cHV0IjowLjAwMDAxMTUyLCJjYWNoZVJlYWQiOjAuMDAwODY1MjgwMDAwMDAwMDAwMSwiY2FjaGVXcml0ZSI6MCwidG90YWwiOjAuMDAwOTA3OTQwMDAwMDAwMDAwMX19LCJzdG9wUmVhc29uIjoic3RvcCIsInRpbWVzdGFtcCI6MTc4MTk1NTIwMjE5MCwicmVzcG9uc2VJZCI6Imdlbi0xNzgxOTU1MjAyLTJRa3RXM25NTXZBbGg5ZDZJYjM0IiwicmVzcG9uc2VNb2RlbCI6ImRlZXBzZWVrL2RlZXBzZWVrLXY0LWZsYXNoLTIwMjYwNDIzIn19LHsidHlwZSI6Im1lc3NhZ2UiLCJpZCI6ImI4NmRlOTIyIiwicGFyZW50SWQiOiIyNTQ1ODBhYyIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMjBUMTQ6NTE6MjEuNjk4WiIsIm1lc3NhZ2UiOnsicm9sZSI6ImJhc2hFeGVjdXRpb24iLCJjb21tYW5kIjoibWtkaXIgdHJhbnNjcmlwdHMiLCJvdXRwdXQiOiIiLCJleGl0Q29kZSI6MCwiY2FuY2VsbGVkIjpmYWxzZSwidHJ1bmNhdGVkIjpmYWxzZSwidGltZXN0YW1wIjoxNzgxOTY3MDgxNjk4LCJleGNsdWRlRnJvbUNvbnRleHQiOmZhbHNlfX1dLCJsZWFmSWQiOiJiODZkZTkyMiIsInN5c3RlbVByb21wdCI6IllvdSBhcmUgYW4gZXhwZXJ0IGNvZGluZyBhc3Npc3RhbnQgb3BlcmF0aW5nIGluc2lkZSBwaSwgYSBjb2RpbmcgYWdlbnQgaGFybmVzcy4gWW91IGhlbHAgdXNlcnMgYnkgcmVhZGluZyBmaWxlcywgZXhlY3V0aW5nIGNvbW1hbmRzLCBlZGl0aW5nIGNvZGUsIGFuZCB3cml0aW5nIG5ldyBmaWxlcy5cblxuQXZhaWxhYmxlIHRvb2xzOlxuLSByZWFkOiBSZWFkIGZpbGUgY29udGVudHNcbi0gYmFzaDogRXhlY3V0ZSBiYXNoIGNvbW1hbmRzIChscywgZ3JlcCwgZmluZCwgZXRjLilcbi0gZWRpdDogTWFrZSBwcmVjaXNlIGZpbGUgZWRpdHMgd2l0aCBleGFjdCB0ZXh0IHJlcGxhY2VtZW50LCBpbmNsdWRpbmcgbXVsdGlwbGUgZGlzam9pbnQgZWRpdHMgaW4gb25lIGNhbGxcbi0gd3JpdGU6IENyZWF0ZSBvciBvdmVyd3JpdGUgZmlsZXNcblxuSW4gYWRkaXRpb24gdG8gdGhlIHRvb2xzIGFib3ZlLCB5b3UgbWF5IGhhdmUgYWNjZXNzIHRvIG90aGVyIGN1c3RvbSB0b29scyBkZXBlbmRpbmcgb24gdGhlIHByb2plY3QuXG5cbkd1aWRlbGluZXM6XG4tIFVzZSBiYXNoIGZvciBmaWxlIG9wZXJhdGlvbnMgbGlrZSBscywgcmcsIGZpbmRcbi0gVXNlIHJlYWQgdG8gZXhhbWluZSBmaWxlcyBpbnN0ZWFkIG9mIGNhdCBvciBzZWQuXG4tIFVzZSBlZGl0IGZvciBwcmVjaXNlIGNoYW5nZXMgKGVkaXRzW10ub2xkVGV4dCBtdXN0IG1hdGNoIGV4YWN0bHkpXG4tIFdoZW4gY2hhbmdpbmcgbXVsdGlwbGUgc2VwYXJhdGUgbG9jYXRpb25zIGluIG9uZSBmaWxlLCB1c2Ugb25lIGVkaXQgY2FsbCB3aXRoIG11bHRpcGxlIGVudHJpZXMgaW4gZWRpdHNbXSBpbnN0ZWFkIG9mIG11bHRpcGxlIGVkaXQgY2FsbHNcbi0gRWFjaCBlZGl0c1tdLm9sZFRleHQgaXMgbWF0Y2hlZCBhZ2FpbnN0IHRoZSBvcmlnaW5hbCBmaWxlLCBub3QgYWZ0ZXIgZWFybGllciBlZGl0cyBhcmUgYXBwbGllZC4gRG8gbm90IGVtaXQgb3ZlcmxhcHBpbmcgb3IgbmVzdGVkIGVkaXRzLiBNZXJnZSBuZWFyYnkgY2hhbmdlcyBpbnRvIG9uZSBlZGl0LlxuLSBLZWVwIGVkaXRzW10ub2xkVGV4dCBhcyBzbWFsbCBhcyBwb3NzaWJsZSB3aGlsZSBzdGlsbCBiZWluZyB1bmlxdWUgaW4gdGhlIGZpbGUuIERvIG5vdCBwYWQgd2l0aCBsYXJnZSB1bmNoYW5nZWQgcmVnaW9ucy5cbi0gVXNlIHdyaXRlIG9ubHkgZm9yIG5ldyBmaWxlcyBvciBjb21wbGV0ZSByZXdyaXRlcy5cbi0gQmUgY29uY2lzZSBpbiB5b3VyIHJlc3BvbnNlc1xuLSBTaG93IGZpbGUgcGF0aHMgY2xlYXJseSB3aGVuIHdvcmtpbmcgd2l0aCBmaWxlc1xuXG5QaSBkb2N1bWVudGF0aW9uIChyZWFkIG9ubHkgd2hlbiB0aGUgdXNlciBhc2tzIGFib3V0IHBpIGl0c2VsZiwgaXRzIFNESywgZXh0ZW5zaW9ucywgdGhlbWVzLCBza2lsbHMsIG9yIFRVSSk6XG4tIE1haW4gZG9jdW1lbnRhdGlvbjogL1VzZXJzL3dpbGxlbS8ubG9jYWwvc2hhcmUvbWlzZS9pbnN0YWxscy9ub2RlLzI0LjAuMS9saWIvbm9kZV9tb2R1bGVzL0BlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnQvUkVBRE1FLm1kXG4tIEFkZGl0aW9uYWwgZG9jczogL1VzZXJzL3dpbGxlbS8ubG9jYWwvc2hhcmUvbWlzZS9pbnN0YWxscy9ub2RlLzI0LjAuMS9saWIvbm9kZV9tb2R1bGVzL0BlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnQvZG9jc1xuLSBFeGFtcGxlczogL1VzZXJzL3dpbGxlbS8ubG9jYWwvc2hhcmUvbWlzZS9pbnN0YWxscy9ub2RlLzI0LjAuMS9saWIvbm9kZV9tb2R1bGVzL0BlYXJlbmRpbC13b3Jrcy9waS1jb2RpbmctYWdlbnQvZXhhbXBsZXMgKGV4dGVuc2lvbnMsIGN1c3RvbSB0b29scywgU0RLKVxuLSBXaGVuIHJlYWRpbmcgcGkgZG9jcyBvciBleGFtcGxlcywgcmVzb2x2ZSBkb2NzLy4uLiB1bmRlciBBZGRpdGlvbmFsIGRvY3MgYW5kIGV4YW1wbGVzLy4uLiB1bmRlciBFeGFtcGxlcywgbm90IHRoZSBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5XG4tIFdoZW4gYXNrZWQgYWJvdXQ6IGV4dGVuc2lvbnMgKGRvY3MvZXh0ZW5zaW9ucy5tZCwgZXhhbXBsZXMvZXh0ZW5zaW9ucy8pLCB0aGVtZXMgKGRvY3MvdGhlbWVzLm1kKSwgc2tpbGxzIChkb2NzL3NraWxscy5tZCksIHByb21wdCB0ZW1wbGF0ZXMgKGRvY3MvcHJvbXB0LXRlbXBsYXRlcy5tZCksIFRVSSBjb21wb25lbnRzIChkb2NzL3R1aS5tZCksIGtleWJpbmRpbmdzIChkb2NzL2tleWJpbmRpbmdzLm1kKSwgU0RLIGludGVncmF0aW9ucyAoZG9jcy9zZGsubWQpLCBjdXN0b20gcHJvdmlkZXJzIChkb2NzL2N1c3RvbS1wcm92aWRlci5tZCksIGFkZGluZyBtb2RlbHMgKGRvY3MvbW9kZWxzLm1kKSwgcGkgcGFja2FnZXMgKGRvY3MvcGFja2FnZXMubWQpXG4tIFdoZW4gd29ya2luZyBvbiBwaSB0b3BpY3MsIHJlYWQgdGhlIGRvY3MgYW5kIGV4YW1wbGVzLCBhbmQgZm9sbG93IC5tZCBjcm9zcy1yZWZlcmVuY2VzIGJlZm9yZSBpbXBsZW1lbnRpbmdcbi0gQWx3YXlzIHJlYWQgcGkgLm1kIGZpbGVzIGNvbXBsZXRlbHkgYW5kIGZvbGxvdyBsaW5rcyB0byByZWxhdGVkIGRvY3MgKGUuZy4sIHR1aS5tZCBmb3IgVFVJIEFQSSBkZXRhaWxzKVxuQ3VycmVudCBkYXRlOiAyMDI2LTA2LTIwXG5DdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5OiAvVXNlcnMvd2lsbGVtL2Rldi9zcGlrZXMvbGxtL3JlZC1ncmVlbi1yZWZhY3Rvci1jeWNsZS1zb2NyYXRlcy11ayIsInRvb2xzIjpbeyJuYW1lIjoicmVhZCIsImRlc2NyaXB0aW9uIjoiUmVhZCB0aGUgY29udGVudHMgb2YgYSBmaWxlLiBTdXBwb3J0cyB0ZXh0IGZpbGVzIGFuZCBpbWFnZXMgKGpwZywgcG5nLCBnaWYsIHdlYnApLiBJbWFnZXMgYXJlIHNlbnQgYXMgYXR0YWNobWVudHMuIEZvciB0ZXh0IGZpbGVzLCBvdXRwdXQgaXMgdHJ1bmNhdGVkIHRvIDIwMDAgbGluZXMgb3IgNTBLQiAod2hpY2hldmVyIGlzIGhpdCBmaXJzdCkuIFVzZSBvZmZzZXQvbGltaXQgZm9yIGxhcmdlIGZpbGVzLiBXaGVuIHlvdSBuZWVkIHRoZSBmdWxsIGZpbGUsIGNvbnRpbnVlIHdpdGggb2Zmc2V0IHVudGlsIGNvbXBsZXRlLiIsInBhcmFtZXRlcnMiOnsidHlwZSI6Im9iamVjdCIsInJlcXVpcmVkIjpbInBhdGgiXSwicHJvcGVydGllcyI6eyJwYXRoIjp7InR5cGUiOiJzdHJpbmciLCJkZXNjcmlwdGlvbiI6IlBhdGggdG8gdGhlIGZpbGUgdG8gcmVhZCAocmVsYXRpdmUgb3IgYWJzb2x1dGUpIn0sIm9mZnNldCI6eyJ0eXBlIjoibnVtYmVyIiwiZGVzY3JpcHRpb24iOiJMaW5lIG51bWJlciB0byBzdGFydCByZWFkaW5nIGZyb20gKDEtaW5kZXhlZCkifSwibGltaXQiOnsidHlwZSI6Im51bWJlciIsImRlc2NyaXB0aW9uIjoiTWF4aW11bSBudW1iZXIgb2YgbGluZXMgdG8gcmVhZCJ9fX19LHsibmFtZSI6ImJhc2giLCJkZXNjcmlwdGlvbiI6IkV4ZWN1dGUgYSBiYXNoIGNvbW1hbmQgaW4gdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnkuIFJldHVybnMgc3Rkb3V0IGFuZCBzdGRlcnIuIE91dHB1dCBpcyB0cnVuY2F0ZWQgdG8gbGFzdCAyMDAwIGxpbmVzIG9yIDUwS0IgKHdoaWNoZXZlciBpcyBoaXQgZmlyc3QpLiBJZiB0cnVuY2F0ZWQsIGZ1bGwgb3V0cHV0IGlzIHNhdmVkIHRvIGEgdGVtcCBmaWxlLiBPcHRpb25hbGx5IHByb3ZpZGUgYSB0aW1lb3V0IGluIHNlY29uZHMuIiwicGFyYW1ldGVycyI6eyJ0eXBlIjoib2JqZWN0IiwicmVxdWlyZWQiOlsiY29tbWFuZCJdLCJwcm9wZXJ0aWVzIjp7ImNvbW1hbmQiOnsidHlwZSI6InN0cmluZyIsImRlc2NyaXB0aW9uIjoiQmFzaCBjb21tYW5kIHRvIGV4ZWN1dGUifSwidGltZW91dCI6eyJ0eXBlIjoibnVtYmVyIiwiZGVzY3JpcHRpb24iOiJUaW1lb3V0IGluIHNlY29uZHMgKG9wdGlvbmFsLCBubyBkZWZhdWx0IHRpbWVvdXQpIn19fX0seyJuYW1lIjoiZWRpdCIsImRlc2NyaXB0aW9uIjoiRWRpdCBhIHNpbmdsZSBmaWxlIHVzaW5nIGV4YWN0IHRleHQgcmVwbGFjZW1lbnQuIEV2ZXJ5IGVkaXRzW10ub2xkVGV4dCBtdXN0IG1hdGNoIGEgdW5pcXVlLCBub24tb3ZlcmxhcHBpbmcgcmVnaW9uIG9mIHRoZSBvcmlnaW5hbCBmaWxlLiBJZiB0d28gY2hhbmdlcyBhZmZlY3QgdGhlIHNhbWUgYmxvY2sgb3IgbmVhcmJ5IGxpbmVzLCBtZXJnZSB0aGVtIGludG8gb25lIGVkaXQgaW5zdGVhZCBvZiBlbWl0dGluZyBvdmVybGFwcGluZyBlZGl0cy4gRG8gbm90IGluY2x1ZGUgbGFyZ2UgdW5jaGFuZ2VkIHJlZ2lvbnMganVzdCB0byBjb25uZWN0IGRpc3RhbnQgY2hhbmdlcy4iLCJwYXJhbWV0ZXJzIjp7InR5cGUiOiJvYmplY3QiLCJyZXF1aXJlZCI6WyJwYXRoIiwiZWRpdHMiXSwicHJvcGVydGllcyI6eyJwYXRoIjp7InR5cGUiOiJzdHJpbmciLCJkZXNjcmlwdGlvbiI6IlBhdGggdG8gdGhlIGZpbGUgdG8gZWRpdCAocmVsYXRpdmUgb3IgYWJzb2x1dGUpIn0sImVkaXRzIjp7InR5cGUiOiJhcnJheSIsIml0ZW1zIjp7InR5cGUiOiJvYmplY3QiLCJyZXF1aXJlZCI6WyJvbGRUZXh0IiwibmV3VGV4dCJdLCJwcm9wZXJ0aWVzIjp7Im9sZFRleHQiOnsidHlwZSI6InN0cmluZyIsImRlc2NyaXB0aW9uIjoiRXhhY3QgdGV4dCBmb3Igb25lIHRhcmdldGVkIHJlcGxhY2VtZW50LiBJdCBtdXN0IGJlIHVuaXF1ZSBpbiB0aGUgb3JpZ2luYWwgZmlsZSBhbmQgbXVzdCBub3Qgb3ZlcmxhcCB3aXRoIGFueSBvdGhlciBlZGl0c1tdLm9sZFRleHQgaW4gdGhlIHNhbWUgY2FsbC4ifSwibmV3VGV4dCI6eyJ0eXBlIjoic3RyaW5nIiwiZGVzY3JpcHRpb24iOiJSZXBsYWNlbWVudCB0ZXh0IGZvciB0aGlzIHRhcmdldGVkIGVkaXQuIn19LCJhZGRpdGlvbmFsUHJvcGVydGllcyI6ZmFsc2V9LCJkZXNjcmlwdGlvbiI6Ik9uZSBvciBtb3JlIHRhcmdldGVkIHJlcGxhY2VtZW50cy4gRWFjaCBlZGl0IGlzIG1hdGNoZWQgYWdhaW5zdCB0aGUgb3JpZ2luYWwgZmlsZSwgbm90IGluY3JlbWVudGFsbHkuIERvIG5vdCBpbmNsdWRlIG92ZXJsYXBwaW5nIG9yIG5lc3RlZCBlZGl0cy4gSWYgdHdvIGNoYW5nZXMgdG91Y2ggdGhlIHNhbWUgYmxvY2sgb3IgbmVhcmJ5IGxpbmVzLCBtZXJnZSB0aGVtIGludG8gb25lIGVkaXQgaW5zdGVhZC4ifX0sImFkZGl0aW9uYWxQcm9wZXJ0aWVzIjpmYWxzZX19LHsibmFtZSI6IndyaXRlIiwiZGVzY3JpcHRpb24iOiJXcml0ZSBjb250ZW50IHRvIGEgZmlsZS4gQ3JlYXRlcyB0aGUgZmlsZSBpZiBpdCBkb2Vzbid0IGV4aXN0LCBvdmVyd3JpdGVzIGlmIGl0IGRvZXMuIEF1dG9tYXRpY2FsbHkgY3JlYXRlcyBwYXJlbnQgZGlyZWN0b3JpZXMuIiwicGFyYW1ldGVycyI6eyJ0eXBlIjoib2JqZWN0IiwicmVxdWlyZWQiOlsicGF0aCIsImNvbnRlbnQiXSwicHJvcGVydGllcyI6eyJwYXRoIjp7InR5cGUiOiJzdHJpbmciLCJkZXNjcmlwdGlvbiI6IlBhdGggdG8gdGhlIGZpbGUgdG8gd3JpdGUgKHJlbGF0aXZlIG9yIGFic29sdXRlKSJ9LCJjb250ZW50Ijp7InR5cGUiOiJzdHJpbmciLCJkZXNjcmlwdGlvbiI6IkNvbnRlbnQgdG8gd3JpdGUgdG8gdGhlIGZpbGUifX19fV19</script>
<!-- Vendored libraries -->
<script>/**
* marked v18.0.5 - a markdown parser
* Copyright (c) 2018-2026, MarkedJS. (MIT License)
* Copyright (c) 2011-2018, Christopher Jeffrey. (MIT License)
* https://github.com/markedjs/marked
*/
/**
* DO NOT EDIT THIS FILE
* The code in this file is generated from files in ./src/
*/
(function(g,f){if(typeof exports=="object"&&typeof module<"u"){module.exports=f()}else if("function"==typeof define && define.amd){define("marked",f)}else {g["marked"]=f()}}(typeof globalThis < "u" ? globalThis : typeof self < "u" ? self : this,function(){var exports={};var __exports=exports;var module={exports};
"use strict";var N=Object.defineProperty;var Oe=Object.getOwnPropertyDescriptor;var we=Object.getOwnPropertyNames;var ye=Object.prototype.hasOwnProperty;var Pe=(l,e)=>{for(var t in e)N(l,t,{get:e[t],enumerable:!0})},Se=(l,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of we(e))!ye.call(l,s)&&s!==t&&N(l,s,{get:()=>e[s],enumerable:!(n=Oe(e,s))||n.enumerable});return l};var $e=l=>Se(N({},"__esModule",{value:!0}),l);var Rt={};Pe(Rt,{Hooks:()=>P,Lexer:()=>x,Marked:()=>C,Parser:()=>b,Renderer:()=>y,TextRenderer:()=>S,Tokenizer:()=>w,defaults:()=>T,getDefaults:()=>_,lexer:()=>bt,marked:()=>g,options:()=>ht,parse:()=>mt,parseInline:()=>ft,parser:()=>xt,setOptions:()=>kt,use:()=>dt,walkTokens:()=>gt});module.exports=$e(Rt);function _(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}var T=_();function Q(l){T=l}var z={exec:()=>null};function E(l){let e=[];return t=>{let n=Math.max(0,Math.min(3,t-1)),s=e[n];return s||(s=l(n),e[n]=s),s}}function d(l,e=""){let t=typeof l=="string"?l:l.source,n={replace:(s,r)=>{let i=typeof r=="string"?r:r.source;return i=i.replace(m.caret,"$1"),t=t.replace(s,i),n},getRegex:()=>new RegExp(t,e)};return n}var Le=((l="")=>{try{return!!new RegExp("(?<=1)(?<!1)"+l)}catch{return!1}})(),m={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] +\S/,listReplaceTask:/^\[[ xX]\] +/,listTaskCheckbox:/\[[ xX]\]/,anyLine:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^<a /i,endATag:/^<\/a>/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^</,endAngleBracket:/>$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:l=>new RegExp(`^( {0,3}${l})((?:[ ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:E(l=>new RegExp(`^ {0,${l}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`)),hrRegex:E(l=>new RegExp(`^ {0,${l}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`)),fencesBeginRegex:E(l=>new RegExp(`^ {0,${l}}(?:\`\`\`|~~~)`)),headingBeginRegex:E(l=>new RegExp(`^ {0,${l}}#`)),htmlBeginRegex:E(l=>new RegExp(`^ {0,${l}}<(?:[a-z].*>|!--)`,"i")),blockquoteBeginRegex:E(l=>new RegExp(`^ {0,${l}}>`))},_e=/^(?:[ \t]*(?:\n|$))+/,ze=/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,Me=/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,D=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,Ee=/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,F=/ {0,3}(?:[*+-]|\d{1,9}[.)])/,ae=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,le=d(ae).replace(/bull/g,F).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/\|table/g,"").getRegex(),Ie=d(ae).replace(/bull/g,F).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/table/g,/ {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(),U=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,Ae=/^[^\n]+/,K=/(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/,Ce=d(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",K).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),Be=d(/^(bull)([ \t][^\n]*?)?(?:\n|$)/).replace(/bull/g,F).getRegex(),H="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",W=/<!--(?:-?>|[\s\S]*?(?:-->|$))/,De=d("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))","i").replace("comment",W).replace("tag",H).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),ue=d(U).replace("hr",D).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\t]+[^ \\t\\n]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",H).getRegex(),qe=d(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",ue).getRegex(),X={blockquote:qe,code:ze,def:Ce,fences:Me,heading:Ee,hr:D,html:De,lheading:le,list:Be,newline:_e,paragraph:ue,table:z,text:Ae},ie=d("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",D).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3} )[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\t]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",H).getRegex(),ve={...X,lheading:Ie,table:ie,paragraph:d(U).replace("hr",D).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",ie).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\t]+[^ \\t\\n]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",H).getRegex()},He={...X,html:d(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment",W).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:z,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:d(U).replace("hr",D).replace("heading",` *#{1,6} *[^
]`).replace("lheading",le).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},Ze=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,Ge=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,pe=/^( {2,}|\\)\n(?!\s*$)/,Ne=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,I=/[\p{P}\p{S}]/u,Z=/[\s\p{P}\p{S}]/u,J=/[^\s\p{P}\p{S}]/u,Qe=d(/^((?![*_])punctSpace)/,"u").replace(/punctSpace/g,Z).getRegex(),ce=/(?!~)[\p{P}\p{S}]/u,je=/(?!~)[\s\p{P}\p{S}]/u,Fe=/(?:[^\s\p{P}\p{S}]|~)/u,Ue=d(/link|precode-code|html/,"g").replace("link",/\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-",Le?"(?<!`)()":"(^^|[^`])").replace("code",/(?<b>`+)[^`]+\k<b>(?!`)/).replace("html",/<(?! )[^<>]*?>/).getRegex(),he=/^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/,Ke=d(he,"u").replace(/punct/g,I).getRegex(),We=d(he,"u").replace(/punct/g,ce).getRegex(),ke="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)",Xe=d(ke,"gu").replace(/notPunctSpace/g,J).replace(/punctSpace/g,Z).replace(/punct/g,I).getRegex(),Je=d(ke,"gu").replace(/notPunctSpace/g,Fe).replace(/punctSpace/g,je).replace(/punct/g,ce).getRegex(),Ve=d("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,J).replace(/punctSpace/g,Z).replace(/punct/g,I).getRegex(),Ye=d(/^~~?(?:((?!~)punct)|[^\s~])/,"u").replace(/punct/g,I).getRegex(),et="^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)",tt=d(et,"gu").replace(/notPunctSpace/g,J).replace(/punctSpace/g,Z).replace(/punct/g,I).getRegex(),nt=d(/\\(punct)/,"gu").replace(/punct/g,I).getRegex(),rt=d(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),st=d(W).replace("(?:-->|$)","-->").getRegex(),it=d("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment",st).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),v=/(?:\[(?:\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/,ot=d(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?\s*\)/).replace("label",v).replace("href",/<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),de=d(/^!?\[(label)\]\[(ref)\]/).replace("label",v).replace("ref",K).getRegex(),ge=d(/^!?\[(ref)\](?:\[\])?/).replace("ref",K).getRegex(),at=d("reflink|nolink(?!\\()","g").replace("reflink",de).replace("nolink",ge).getRegex(),oe=/[hH][tT][tT][pP][sS]?|[fF][tT][pP]/,V={_backpedal:z,anyPunctuation:nt,autolink:rt,blockSkip:Ue,br:pe,code:Ge,del:z,delLDelim:z,delRDelim:z,emStrongLDelim:Ke,emStrongRDelimAst:Xe,emStrongRDelimUnd:Ve,escape:Ze,link:ot,nolink:ge,punctuation:Qe,reflink:de,reflinkSearch:at,tag:it,text:Ne,url:z},lt={...V,link:d(/^!?\[(label)\]\((.*?)\)/).replace("label",v).getRegex(),reflink:d(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",v).getRegex()},j={...V,emStrongRDelimAst:Je,emStrongLDelim:We,delLDelim:Ye,delRDelim:tt,url:d(/^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("protocol",oe).replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/,text:d(/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/).replace("protocol",oe).getRegex()},ut={...j,br:d(pe).replace("{2,}","*").getRegex(),text:d(j.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()},q={normal:X,gfm:ve,pedantic:He},A={normal:V,gfm:j,breaks:ut,pedantic:lt};var pt={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},fe=l=>pt[l];function O(l,e){if(e){if(m.escapeTest.test(l))return l.replace(m.escapeReplace,fe)}else if(m.escapeTestNoEncode.test(l))return l.replace(m.escapeReplaceNoEncode,fe);return l}function Y(l){try{l=encodeURI(l).replace(m.percentDecode,"%")}catch{return null}return l}function ee(l,e){let t=l.replace(m.findPipe,(r,i,o)=>{let u=!1,a=i;for(;--a>=0&&o[a]==="\\";)u=!u;return u?"|":" |"}),n=t.split(m.splitPipe),s=0;if(n[0].trim()||n.shift(),n.length>0&&!n.at(-1)?.trim()&&n.pop(),e)if(n.length>e)n.splice(e);else for(;n.length<e;)n.push("");for(;s<n.length;s++)n[s]=n[s].trim().replace(m.slashPipe,"|");return n}function L(l,e,t){let n=l.length;if(n===0)return"";let s=0;for(;s<n;){let r=l.charAt(n-s-1);if(r===e&&!t)s++;else if(r!==e&&t)s++;else break}return l.slice(0,n-s)}function te(l){let e=l.split(`
`),t=e.length-1;for(;t>=0&&m.blankLine.test(e[t]);)t--;return e.length-t<=2?l:e.slice(0,t+1).join(`
`)}function me(l,e){if(l.indexOf(e[1])===-1)return-1;let t=0;for(let n=0;n<l.length;n++)if(l[n]==="\\")n++;else if(l[n]===e[0])t++;else if(l[n]===e[1]&&(t--,t<0))return n;return t>0?-2:-1}function xe(l,e=0){let t=e,n="";for(let s of l)if(s===" "){let r=4-t%4;n+=" ".repeat(r),t+=r}else n+=s,t++;return n}function be(l,e,t,n,s){let r=e.href,i=e.title||null,o=l[1].replace(s.other.outputLinkReplace,"$1");n.state.inLink=!0;let u={type:l[0].charAt(0)==="!"?"image":"link",raw:t,href:r,title:i,text:o,tokens:n.inlineTokens(o)};return n.state.inLink=!1,u}function ct(l,e,t){let n=l.match(t.other.indentCodeCompensation);if(n===null)return e;let s=n[1];return e.split(`
`).map(r=>{let i=r.match(t.other.beginningSpace);if(i===null)return r;let[o]=i;return o.length>=s.length?r.slice(s.length):r}).join(`
`)}var w=class{options;rules;lexer;constructor(e){this.options=e||T}space(e){let t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return{type:"space",raw:t[0]}}code(e){let t=this.rules.block.code.exec(e);if(t){let n=this.options.pedantic?t[0]:te(t[0]),s=n.replace(this.rules.other.codeRemoveIndent,"");return{type:"code",raw:n,codeBlockStyle:"indented",text:s}}}fences(e){let t=this.rules.block.fences.exec(e);if(t){let n=t[0],s=ct(n,t[3]||"",this.rules);return{type:"code",raw:n,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:s}}}heading(e){let t=this.rules.block.heading.exec(e);if(t){let n=t[2].trim();if(this.rules.other.endingHash.test(n)){let s=L(n,"#");(this.options.pedantic||!s||this.rules.other.endingSpaceChar.test(s))&&(n=s.trim())}return{type:"heading",raw:L(t[0],`
`),depth:t[1].length,text:n,tokens:this.lexer.inline(n)}}}hr(e){let t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:L(t[0],`
`)}}blockquote(e){let t=this.rules.block.blockquote.exec(e);if(t){let n=L(t[0],`
`).split(`
`),s="",r="",i=[];for(;n.length>0;){let o=!1,u=[],a;for(a=0;a<n.length;a++)if(this.rules.other.blockquoteStart.test(n[a]))u.push(n[a]),o=!0;else if(!o)u.push(n[a]);else break;n=n.slice(a);let c=u.join(`
`),p=c.replace(this.rules.other.blockquoteSetextReplace,`
$1`).replace(this.rules.other.blockquoteSetextReplace2,"");s=s?`${s}
${c}`:c,r=r?`${r}
${p}`:p;let k=this.lexer.state.top;if(this.lexer.state.top=!0,this.lexer.blockTokens(p,i,!0),this.lexer.state.top=k,n.length===0)break;let h=i.at(-1);if(h?.type==="code")break;if(h?.type==="blockquote"){let R=h,f=R.raw+`
`+n.join(`
`),$=this.blockquote(f);i[i.length-1]=$,s=s.substring(0,s.length-R.raw.length)+$.raw,r=r.substring(0,r.length-R.text.length)+$.text;break}else if(h?.type==="list"){let R=h,f=R.raw+`
`+n.join(`
`),$=this.list(f);i[i.length-1]=$,s=s.substring(0,s.length-h.raw.length)+$.raw,r=r.substring(0,r.length-R.raw.length)+$.raw,n=f.substring(i.at(-1).raw.length).split(`
`);continue}}return{type:"blockquote",raw:s,tokens:i,text:r}}}list(e){let t=this.rules.block.list.exec(e);if(t){let n=t[1].trim(),s=n.length>1,r={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:!1,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");let i=this.rules.other.listItemRegex(n),o=!1;for(;e;){let a=!1,c="",p="";if(!(t=i.exec(e))||this.rules.block.hr.test(e))break;c=t[0],e=e.substring(c.length);let k=xe(t[2].split(`
`,1)[0],t[1].length),h=e.split(`
`,1)[0],R=!k.trim(),f=0;if(this.options.pedantic?(f=2,p=k.trimStart()):R?f=t[1].length+1:(f=k.search(this.rules.other.nonSpaceChar),f=f>4?1:f,p=k.slice(f),f+=t[1].length),R&&this.rules.other.blankLine.test(h)&&(c+=h+`
`,e=e.substring(h.length+1),a=!0),!a){let $=this.rules.other.nextBulletRegex(f),ne=this.rules.other.hrRegex(f),re=this.rules.other.fencesBeginRegex(f),se=this.rules.other.headingBeginRegex(f),Re=this.rules.other.htmlBeginRegex(f),Te=this.rules.other.blockquoteBeginRegex(f);for(;e;){let G=e.split(`
`,1)[0],B;if(h=G,this.options.pedantic?(h=h.replace(this.rules.other.listReplaceNesting," "),B=h):B=h.replace(this.rules.other.tabCharGlobal," "),re.test(h)||se.test(h)||Re.test(h)||Te.test(h)||$.test(h)||ne.test(h))break;if(B.search(this.rules.other.nonSpaceChar)>=f||!h.trim())p+=`
`+B.slice(f);else{if(R||k.replace(this.rules.other.tabCharGlobal," ").search(this.rules.other.nonSpaceChar)>=4||re.test(k)||se.test(k)||ne.test(k))break;p+=`
`+h}R=!h.trim(),c+=G+`
`,e=e.substring(G.length+1),k=B.slice(f)}}r.loose||(o?r.loose=!0:this.rules.other.doubleBlankLine.test(c)&&(o=!0)),r.items.push({type:"list_item",raw:c,task:!!this.options.gfm&&this.rules.other.listIsTask.test(p),loose:!1,text:p,tokens:[]}),r.raw+=c}let u=r.items.at(-1);if(u)u.raw=u.raw.trimEnd(),u.text=u.text.trimEnd();else return;r.raw=r.raw.trimEnd();for(let a of r.items){this.lexer.state.top=!1,a.tokens=this.lexer.blockTokens(a.text,[]);let c=a.tokens[0];if(a.task&&(c?.type==="text"||c?.type==="paragraph")){a.text=a.text.replace(this.rules.other.listReplaceTask,""),c.raw=c.raw.replace(this.rules.other.listReplaceTask,""),c.text=c.text.replace(this.rules.other.listReplaceTask,"");for(let k=this.lexer.inlineQueue.length-1;k>=0;k--)if(this.rules.other.listIsTask.test(this.lexer.inlineQueue[k].src)){this.lexer.inlineQueue[k].src=this.lexer.inlineQueue[k].src.replace(this.rules.other.listReplaceTask,"");break}let p=this.rules.other.listTaskCheckbox.exec(a.raw);if(p){let k={type:"checkbox",raw:p[0]+" ",checked:p[0]!=="[ ]"};a.checked=k.checked,r.loose?a.tokens[0]&&["paragraph","text"].includes(a.tokens[0].type)&&"tokens"in a.tokens[0]&&a.tokens[0].tokens?(a.tokens[0].raw=k.raw+a.tokens[0].raw,a.tokens[0].text=k.raw+a.tokens[0].text,a.tokens[0].tokens.unshift(k)):a.tokens.unshift({type:"paragraph",raw:k.raw,text:k.raw,tokens:[k]}):a.tokens.unshift(k)}}else a.task&&(a.task=!1);if(!r.loose){let p=a.tokens.filter(h=>h.type==="space"),k=p.length>0&&p.some(h=>this.rules.other.anyLine.test(h.raw));r.loose=k}}if(r.loose)for(let a of r.items){a.loose=!0;for(let c of a.tokens)c.type==="text"&&(c.type="paragraph")}return r}}html(e){let t=this.rules.block.html.exec(e);if(t){let n=te(t[0]);return{type:"html",block:!0,raw:n,pre:t[1]==="pre"||t[1]==="script"||t[1]==="style",text:n}}}def(e){let t=this.rules.block.def.exec(e);if(t){let n=t[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal," "),s=t[2]?t[2].replace(this.rules.other.hrefBrackets,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",r=t[3]?t[3].substring(1,t[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):t[3];return{type:"def",tag:n,raw:L(t[0],`
`),href:s,title:r}}}table(e){let t=this.rules.block.table.exec(e);if(!t||!this.rules.other.tableDelimiter.test(t[2]))return;let n=ee(t[1]),s=t[2].replace(this.rules.other.tableAlignChars,"").split("|"),r=t[3]?.trim()?t[3].replace(this.rules.other.tableRowBlankLine,"").split(`
`):[],i={type:"table",raw:L(t[0],`
`),header:[],align:[],rows:[]};if(n.length===s.length){for(let o of s)this.rules.other.tableAlignRight.test(o)?i.align.push("right"):this.rules.other.tableAlignCenter.test(o)?i.align.push("center"):this.rules.other.tableAlignLeft.test(o)?i.align.push("left"):i.align.push(null);for(let o=0;o<n.length;o++)i.header.push({text:n[o],tokens:this.lexer.inline(n[o]),header:!0,align:i.align[o]});for(let o of r)i.rows.push(ee(o,i.header.length).map((u,a)=>({text:u,tokens:this.lexer.inline(u),header:!1,align:i.align[a]})));return i}}lheading(e){let t=this.rules.block.lheading.exec(e);if(t){let n=t[1].trim();return{type:"heading",raw:L(t[0],`
`),depth:t[2].charAt(0)==="="?1:2,text:n,tokens:this.lexer.inline(n)}}}paragraph(e){let t=this.rules.block.paragraph.exec(e);if(t){let n=t[1].charAt(t[1].length-1)===`
`?t[1].slice(0,-1):t[1];return{type:"paragraph",raw:t[0],text:n,tokens:this.lexer.inline(n)}}}text(e){let t=this.rules.block.text.exec(e);if(t)return{type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){let t=this.rules.inline.escape.exec(e);if(t)return{type:"escape",raw:t[0],text:t[1]}}tag(e){let t=this.rules.inline.tag.exec(e);if(t)return!this.lexer.state.inLink&&this.rules.other.startATag.test(t[0])?this.lexer.state.inLink=!0:this.lexer.state.inLink&&this.rules.other.endATag.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:t[0]}}link(e){let t=this.rules.inline.link.exec(e);if(t){let n=t[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(n)){if(!this.rules.other.endAngleBracket.test(n))return;let i=L(n.slice(0,-1),"\\");if((n.length-i.length)%2===0)return}else{let i=me(t[2],"()");if(i===-2)return;if(i>-1){let u=(t[0].indexOf("!")===0?5:4)+t[1].length+i;t[2]=t[2].substring(0,i),t[0]=t[0].substring(0,u).trim(),t[3]=""}}let s=t[2],r="";if(this.options.pedantic){let i=this.rules.other.pedanticHrefTitle.exec(s);i&&(s=i[1],r=i[3])}else r=t[3]?t[3].slice(1,-1):"";return s=s.trim(),this.rules.other.startAngleBracket.test(s)&&(this.options.pedantic&&!this.rules.other.endAngleBracket.test(n)?s=s.slice(1):s=s.slice(1,-1)),be(t,{href:s&&s.replace(this.rules.inline.anyPunctuation,"$1"),title:r&&r.replace(this.rules.inline.anyPunctuation,"$1")},t[0],this.lexer,this.rules)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){let s=(n[2]||n[1]).replace(this.rules.other.multipleSpaceGlobal," "),r=t[s.toLowerCase()];if(!r){let i=n[0].charAt(0);return{type:"text",raw:i,text:i}}return be(n,r,n[0],this.lexer,this.rules)}}emStrong(e,t,n=""){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s||!s[1]&&!s[2]&&!s[3]&&!s[4]||s[4]&&n.match(this.rules.other.unicodeAlphaNumeric))return;if(!(s[1]||s[3]||"")||!n||this.rules.inline.punctuation.exec(n)){let i=[...s[0]].length-1,o,u,a=i,c=0,p=s[0][0]==="*"?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(p.lastIndex=0,t=t.slice(-1*e.length+i);(s=p.exec(t))!==null;){if(o=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!o)continue;if(u=[...o].length,s[3]||s[4]){a+=u;continue}else if((s[5]||s[6])&&i%3&&!((i+u)%3)){c+=u;continue}if(a-=u,a>0)continue;u=Math.min(u,u+a+c);let k=[...s[0]][0].length,h=e.slice(0,i+s.index+k+u);if(Math.min(i,u)%2){let f=h.slice(1,-1);return{type:"em",raw:h,text:f,tokens:this.lexer.inlineTokens(f)}}let R=h.slice(2,-2);return{type:"strong",raw:h,text:R,tokens:this.lexer.inlineTokens(R)}}}}codespan(e){let t=this.rules.inline.code.exec(e);if(t){let n=t[2].replace(this.rules.other.newLineCharGlobal," "),s=this.rules.other.nonSpaceChar.test(n),r=this.rules.other.startingSpaceChar.test(n)&&this.rules.other.endingSpaceChar.test(n);return s&&r&&(n=n.substring(1,n.length-1)),{type:"codespan",raw:t[0],text:n}}}br(e){let t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}}del(e,t,n=""){let s=this.rules.inline.delLDelim.exec(e);if(!s)return;if(!(s[1]||"")||!n||this.rules.inline.punctuation.exec(n)){let i=[...s[0]].length-1,o,u,a=i,c=this.rules.inline.delRDelim;for(c.lastIndex=0,t=t.slice(-1*e.length+i);(s=c.exec(t))!==null;){if(o=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!o||(u=[...o].length,u!==i))continue;if(s[3]||s[4]){a+=u;continue}if(a-=u,a>0)continue;u=Math.min(u,u+a);let p=[...s[0]][0].length,k=e.slice(0,i+s.index+p+u),h=k.slice(i,-i);return{type:"del",raw:k,text:h,tokens:this.lexer.inlineTokens(h)}}}}autolink(e){let t=this.rules.inline.autolink.exec(e);if(t){let n,s;return t[2]==="@"?(n=t[1],s="mailto:"+n):(n=t[1],s=n),{type:"link",raw:t[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let n,s;if(t[2]==="@")n=t[0],s="mailto:"+n;else{let r;do r=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??"";while(r!==t[0]);n=t[0],t[1]==="www."?s="http://"+t[0]:s=t[0]}return{type:"link",raw:t[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}inlineText(e){let t=this.rules.inline.text.exec(e);if(t){let n=this.lexer.state.inRawBlock;return{type:"text",raw:t[0],text:t[0],escaped:n}}}};var x=class l{tokens;options;state;inlineQueue;tokenizer;constructor(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||T,this.options.tokenizer=this.options.tokenizer||new w,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};let t={other:m,block:q.normal,inline:A.normal};this.options.pedantic?(t.block=q.pedantic,t.inline=A.pedantic):this.options.gfm&&(t.block=q.gfm,this.options.breaks?t.inline=A.breaks:t.inline=A.gfm),this.tokenizer.rules=t}static get rules(){return{block:q,inline:A}}static lex(e,t){return new l(t).lex(e)}static lexInline(e,t){return new l(t).inlineTokens(e)}lex(e){e=e.replace(m.carriageReturn,`
`),this.blockTokens(e,this.tokens);for(let t=0;t<this.inlineQueue.length;t++){let n=this.inlineQueue[t];this.inlineTokens(n.src,n.tokens)}return this.inlineQueue=[],this.tokens}blockTokens(e,t=[],n=!1){this.tokenizer.lexer=this,this.options.pedantic&&(e=e.replace(m.tabCharGlobal," ").replace(m.spaceLine,""));let s=1/0;for(;e;){if(e.length<s)s=e.length;else{this.infiniteLoopError(e.charCodeAt(0));break}let r;if(this.options.extensions?.block?.some(o=>(r=o.call({lexer:this},e,t))?(e=e.substring(r.raw.length),t.push(r),!0):!1))continue;if(r=this.tokenizer.space(e)){e=e.substring(r.raw.length);let o=t.at(-1);r.raw.length===1&&o!==void 0?o.raw+=`
`:t.push(r);continue}if(r=this.tokenizer.code(e)){e=e.substring(r.raw.length);let o=t.at(-1);o?.type==="paragraph"||o?.type==="text"?(o.raw+=(o.raw.endsWith(`
`)?"":`
`)+r.raw,o.text+=`
`+r.text,this.inlineQueue.at(-1).src=o.text):t.push(r);continue}if(r=this.tokenizer.fences(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.heading(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.hr(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.blockquote(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.list(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.html(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.def(e)){e=e.substring(r.raw.length);let o=t.at(-1);o?.type==="paragraph"||o?.type==="text"?(o.raw+=(o.raw.endsWith(`
`)?"":`
`)+r.raw,o.text+=`
`+r.raw,this.inlineQueue.at(-1).src=o.text):this.tokens.links[r.tag]||(this.tokens.links[r.tag]={href:r.href,title:r.title},t.push(r));continue}if(r=this.tokenizer.table(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.lheading(e)){e=e.substring(r.raw.length),t.push(r);continue}let i=e;if(this.options.extensions?.startBlock){let o=1/0,u=e.slice(1),a;this.options.extensions.startBlock.forEach(c=>{a=c.call({lexer:this},u),typeof a=="number"&&a>=0&&(o=Math.min(o,a))}),o<1/0&&o>=0&&(i=e.substring(0,o+1))}if(this.state.top&&(r=this.tokenizer.paragraph(i))){let o=t.at(-1);n&&o?.type==="paragraph"?(o.raw+=(o.raw.endsWith(`
`)?"":`
`)+r.raw,o.text+=`
`+r.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=o.text):t.push(r),n=i.length!==e.length,e=e.substring(r.raw.length);continue}if(r=this.tokenizer.text(e)){e=e.substring(r.raw.length);let o=t.at(-1);o?.type==="text"?(o.raw+=(o.raw.endsWith(`
`)?"":`
`)+r.raw,o.text+=`
`+r.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=o.text):t.push(r);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return this.state.top=!0,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){this.tokenizer.lexer=this;let n=e,s=null;if(this.tokens.links){let a=Object.keys(this.tokens.links);if(a.length>0)for(;(s=this.tokenizer.rules.inline.reflinkSearch.exec(n))!==null;)a.includes(s[0].slice(s[0].lastIndexOf("[")+1,-1))&&(n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;(s=this.tokenizer.rules.inline.anyPunctuation.exec(n))!==null;)n=n.slice(0,s.index)+"++"+n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);let r;for(;(s=this.tokenizer.rules.inline.blockSkip.exec(n))!==null;)r=s[2]?s[2].length:0,n=n.slice(0,s.index+r)+"["+"a".repeat(s[0].length-r-2)+"]"+n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);n=this.options.hooks?.emStrongMask?.call({lexer:this},n)??n;let i=!1,o="",u=1/0;for(;e;){if(e.length<u)u=e.length;else{this.infiniteLoopError(e.charCodeAt(0));break}i||(o=""),i=!1;let a;if(this.options.extensions?.inline?.some(p=>(a=p.call({lexer:this},e,t))?(e=e.substring(a.raw.length),t.push(a),!0):!1))continue;if(a=this.tokenizer.escape(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.tag(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.link(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(a.raw.length);let p=t.at(-1);a.type==="text"&&p?.type==="text"?(p.raw+=a.raw,p.text+=a.text):t.push(a);continue}if(a=this.tokenizer.emStrong(e,n,o)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.codespan(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.br(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.del(e,n,o)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.autolink(e)){e=e.substring(a.raw.length),t.push(a);continue}if(!this.state.inLink&&(a=this.tokenizer.url(e))){e=e.substring(a.raw.length),t.push(a);continue}let c=e;if(this.options.extensions?.startInline){let p=1/0,k=e.slice(1),h;this.options.extensions.startInline.forEach(R=>{h=R.call({lexer:this},k),typeof h=="number"&&h>=0&&(p=Math.min(p,h))}),p<1/0&&p>=0&&(c=e.substring(0,p+1))}if(a=this.tokenizer.inlineText(c)){e=e.substring(a.raw.length),a.raw.slice(-1)!=="_"&&(o=a.raw.slice(-1)),i=!0;let p=t.at(-1);p?.type==="text"?(p.raw+=a.raw,p.text+=a.text):t.push(a);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return t}infiniteLoopError(e){let t="Infinite loop on byte: "+e;if(this.options.silent)console.error(t);else throw new Error(t)}};var y=class{options;parser;constructor(e){this.options=e||T}space(e){return""}code({text:e,lang:t,escaped:n}){let s=(t||"").match(m.notSpaceStart)?.[0],r=e.replace(m.endingNewline,"")+`
`;return s?'<pre><code class="language-'+O(s)+'">'+(n?r:O(r,!0))+`</code></pre>
`:"<pre><code>"+(n?r:O(r,!0))+`</code></pre>
`}blockquote({tokens:e}){return`<blockquote>
${this.parser.parse(e)}</blockquote>
`}html({text:e}){return e}def(e){return""}heading({tokens:e,depth:t}){return`<h${t}>${this.parser.parseInline(e)}</h${t}>
`}hr(e){return`<hr>
`}list(e){let t=e.ordered,n=e.start,s="";for(let o=0;o<e.items.length;o++){let u=e.items[o];s+=this.listitem(u)}let r=t?"ol":"ul",i=t&&n!==1?' start="'+n+'"':"";return"<"+r+i+`>
`+s+"</"+r+`>
`}listitem(e){return`<li>${this.parser.parse(e.tokens)}</li>
`}checkbox({checked:e}){return"<input "+(e?'checked="" ':"")+'disabled="" type="checkbox"> '}paragraph({tokens:e}){return`<p>${this.parser.parseInline(e)}</p>
`}table(e){let t="",n="";for(let r=0;r<e.header.length;r++)n+=this.tablecell(e.header[r]);t+=this.tablerow({text:n});let s="";for(let r=0;r<e.rows.length;r++){let i=e.rows[r];n="";for(let o=0;o<i.length;o++)n+=this.tablecell(i[o]);s+=this.tablerow({text:n})}return s&&(s=`<tbody>${s}</tbody>`),`<table>
<thead>
`+t+`</thead>
`+s+`</table>
`}tablerow({text:e}){return`<tr>
${e}</tr>
`}tablecell(e){let t=this.parser.parseInline(e.tokens),n=e.header?"th":"td";return(e.align?`<${n} align="${e.align}">`:`<${n}>`)+t+`</${n}>
`}strong({tokens:e}){return`<strong>${this.parser.parseInline(e)}</strong>`}em({tokens:e}){return`<em>${this.parser.parseInline(e)}</em>`}codespan({text:e}){return`<code>${O(e,!0)}</code>`}br(e){return"<br>"}del({tokens:e}){return`<del>${this.parser.parseInline(e)}</del>`}link({href:e,title:t,tokens:n}){let s=this.parser.parseInline(n),r=Y(e);if(r===null)return s;e=r;let i='<a href="'+e+'"';return t&&(i+=' title="'+O(t)+'"'),i+=">"+s+"</a>",i}image({href:e,title:t,text:n,tokens:s}){s&&(n=this.parser.parseInline(s,this.parser.textRenderer));let r=Y(e);if(r===null)return O(n);e=r;let i=`<img src="${e}" alt="${O(n)}"`;return t&&(i+=` title="${O(t)}"`),i+=">",i}text(e){return"tokens"in e&&e.tokens?this.parser.parseInline(e.tokens):"escaped"in e&&e.escaped?e.text:O(e.text)}};var S=class{strong({text:e}){return e}em({text:e}){return e}codespan({text:e}){return e}del({text:e}){return e}html({text:e}){return e}text({text:e}){return e}link({text:e}){return""+e}image({text:e}){return""+e}br(){return""}checkbox({raw:e}){return e}};var b=class l{options;renderer;textRenderer;constructor(e){this.options=e||T,this.options.renderer=this.options.renderer||new y,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new S}static parse(e,t){return new l(t).parse(e)}static parseInline(e,t){return new l(t).parseInline(e)}parse(e){this.renderer.parser=this;let t="";for(let n=0;n<e.length;n++){let s=e[n];if(this.options.extensions?.renderers?.[s.type]){let i=s,o=this.options.extensions.renderers[i.type].call({parser:this},i);if(o!==!1||!["space","hr","heading","code","table","blockquote","list","html","def","paragraph","text"].includes(i.type)){t+=o||"";continue}}let r=s;switch(r.type){case"space":{t+=this.renderer.space(r);break}case"hr":{t+=this.renderer.hr(r);break}case"heading":{t+=this.renderer.heading(r);break}case"code":{t+=this.renderer.code(r);break}case"table":{t+=this.renderer.table(r);break}case"blockquote":{t+=this.renderer.blockquote(r);break}case"list":{t+=this.renderer.list(r);break}case"checkbox":{t+=this.renderer.checkbox(r);break}case"html":{t+=this.renderer.html(r);break}case"def":{t+=this.renderer.def(r);break}case"paragraph":{t+=this.renderer.paragraph(r);break}case"text":{t+=this.renderer.text(r);break}default:{let i='Token with "'+r.type+'" type was not found.';if(this.options.silent)return console.error(i),"";throw new Error(i)}}}return t}parseInline(e,t=this.renderer){this.renderer.parser=this;let n="";for(let s=0;s<e.length;s++){let r=e[s];if(this.options.extensions?.renderers?.[r.type]){let o=this.options.extensions.renderers[r.type].call({parser:this},r);if(o!==!1||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(r.type)){n+=o||"";continue}}let i=r;switch(i.type){case"escape":{n+=t.text(i);break}case"html":{n+=t.html(i);break}case"link":{n+=t.link(i);break}case"image":{n+=t.image(i);break}case"checkbox":{n+=t.checkbox(i);break}case"strong":{n+=t.strong(i);break}case"em":{n+=t.em(i);break}case"codespan":{n+=t.codespan(i);break}case"br":{n+=t.br(i);break}case"del":{n+=t.del(i);break}case"text":{n+=t.text(i);break}default:{let o='Token with "'+i.type+'" type was not found.';if(this.options.silent)return console.error(o),"";throw new Error(o)}}}return n}};var P=class{options;block;constructor(e){this.options=e||T}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens","emStrongMask"]);static passThroughHooksRespectAsync=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}emStrongMask(e){return e}provideLexer(e=this.block){return e?x.lex:x.lexInline}provideParser(e=this.block){return e?b.parse:b.parseInline}};var C=class{defaults=_();options=this.setOptions;parse=this.parseMarkdown(!0);parseInline=this.parseMarkdown(!1);Parser=b;Renderer=y;TextRenderer=S;Lexer=x;Tokenizer=w;Hooks=P;constructor(...e){this.use(...e)}walkTokens(e,t){let n=[];for(let s of e)switch(n=n.concat(t.call(this,s)),s.type){case"table":{let r=s;for(let i of r.header)n=n.concat(this.walkTokens(i.tokens,t));for(let i of r.rows)for(let o of i)n=n.concat(this.walkTokens(o.tokens,t));break}case"list":{let r=s;n=n.concat(this.walkTokens(r.items,t));break}default:{let r=s;this.defaults.extensions?.childTokens?.[r.type]?this.defaults.extensions.childTokens[r.type].forEach(i=>{let o=r[i].flat(1/0);n=n.concat(this.walkTokens(o,t))}):r.tokens&&(n=n.concat(this.walkTokens(r.tokens,t)))}}return n}use(...e){let t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(n=>{let s={...n};if(s.async=this.defaults.async||s.async||!1,n.extensions&&(n.extensions.forEach(r=>{if(!r.name)throw new Error("extension name required");if("renderer"in r){let i=t.renderers[r.name];i?t.renderers[r.name]=function(...o){let u=r.renderer.apply(this,o);return u===!1&&(u=i.apply(this,o)),u}:t.renderers[r.name]=r.renderer}if("tokenizer"in r){if(!r.level||r.level!=="block"&&r.level!=="inline")throw new Error("extension level must be 'block' or 'inline'");let i=t[r.level];i?i.unshift(r.tokenizer):t[r.level]=[r.tokenizer],r.start&&(r.level==="block"?t.startBlock?t.startBlock.push(r.start):t.startBlock=[r.start]:r.level==="inline"&&(t.startInline?t.startInline.push(r.start):t.startInline=[r.start]))}"childTokens"in r&&r.childTokens&&(t.childTokens[r.name]=r.childTokens)}),s.extensions=t),n.renderer){let r=this.defaults.renderer||new y(this.defaults);for(let i in n.renderer){if(!(i in r))throw new Error(`renderer '${i}' does not exist`);if(["options","parser"].includes(i))continue;let o=i,u=n.renderer[o],a=r[o];r[o]=(...c)=>{let p=u.apply(r,c);return p===!1&&(p=a.apply(r,c)),p||""}}s.renderer=r}if(n.tokenizer){let r=this.defaults.tokenizer||new w(this.defaults);for(let i in n.tokenizer){if(!(i in r))throw new Error(`tokenizer '${i}' does not exist`);if(["options","rules","lexer"].includes(i))continue;let o=i,u=n.tokenizer[o],a=r[o];r[o]=(...c)=>{let p=u.apply(r,c);return p===!1&&(p=a.apply(r,c)),p}}s.tokenizer=r}if(n.hooks){let r=this.defaults.hooks||new P;for(let i in n.hooks){if(!(i in r))throw new Error(`hook '${i}' does not exist`);if(["options","block"].includes(i))continue;let o=i,u=n.hooks[o],a=r[o];P.passThroughHooks.has(i)?r[o]=c=>{if(this.defaults.async&&P.passThroughHooksRespectAsync.has(i))return(async()=>{let k=await u.call(r,c);return a.call(r,k)})();let p=u.call(r,c);return a.call(r,p)}:r[o]=(...c)=>{if(this.defaults.async)return(async()=>{let k=await u.apply(r,c);return k===!1&&(k=await a.apply(r,c)),k})();let p=u.apply(r,c);return p===!1&&(p=a.apply(r,c)),p}}s.hooks=r}if(n.walkTokens){let r=this.defaults.walkTokens,i=n.walkTokens;s.walkTokens=function(o){let u=[];return u.push(i.call(this,o)),r&&(u=u.concat(r.call(this,o))),u}}this.defaults={...this.defaults,...s}}),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return x.lex(e,t??this.defaults)}parser(e,t){return b.parse(e,t??this.defaults)}parseMarkdown(e){return(n,s)=>{let r={...s},i={...this.defaults,...r},o=this.onError(!!i.silent,!!i.async);if(this.defaults.async===!0&&r.async===!1)return o(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(typeof n>"u"||n===null)return o(new Error("marked(): input parameter is undefined or null"));if(typeof n!="string")return o(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));if(i.hooks&&(i.hooks.options=i,i.hooks.block=e),i.async)return(async()=>{let u=i.hooks?await i.hooks.preprocess(n):n,c=await(i.hooks?await i.hooks.provideLexer(e):e?x.lex:x.lexInline)(u,i),p=i.hooks?await i.hooks.processAllTokens(c):c;i.walkTokens&&await Promise.all(this.walkTokens(p,i.walkTokens));let h=await(i.hooks?await i.hooks.provideParser(e):e?b.parse:b.parseInline)(p,i);return i.hooks?await i.hooks.postprocess(h):h})().catch(o);try{i.hooks&&(n=i.hooks.preprocess(n));let a=(i.hooks?i.hooks.provideLexer(e):e?x.lex:x.lexInline)(n,i);i.hooks&&(a=i.hooks.processAllTokens(a)),i.walkTokens&&this.walkTokens(a,i.walkTokens);let p=(i.hooks?i.hooks.provideParser(e):e?b.parse:b.parseInline)(a,i);return i.hooks&&(p=i.hooks.postprocess(p)),p}catch(u){return o(u)}}}onError(e,t){return n=>{if(n.message+=`
Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error occurred:</p><pre>"+O(n.message+"",!0)+"</pre>";return t?Promise.resolve(s):s}if(t)return Promise.reject(n);throw n}}};var M=new C;function g(l,e){return M.parse(l,e)}g.options=g.setOptions=function(l){return M.setOptions(l),g.defaults=M.defaults,Q(g.defaults),g};g.getDefaults=_;g.defaults=T;g.use=function(...l){return M.use(...l),g.defaults=M.defaults,Q(g.defaults),g};g.walkTokens=function(l,e){return M.walkTokens(l,e)};g.parseInline=M.parseInline;g.Parser=b;g.parser=b.parse;g.Renderer=y;g.TextRenderer=S;g.Lexer=x;g.lexer=x.lex;g.Tokenizer=w;g.Hooks=P;g.parse=g;var ht=g.options,kt=g.setOptions,dt=g.use,gt=g.walkTokens,ft=g.parseInline,mt=g,xt=b.parse,bt=x.lex;
if(__exports != exports)module.exports = exports;return module.exports}));
</script>
<!-- highlight.js -->
<script>/*!
Highlight.js v11.9.0 (git: f47103d4f1)
(c) 2006-2023 undefined and other contributors
License: BSD-3-Clause
*/
var hljs=function(){"use strict";function e(n){
return n instanceof Map?n.clear=n.delete=n.set=()=>{
throw Error("map is read-only")}:n instanceof Set&&(n.add=n.clear=n.delete=()=>{
throw Error("set is read-only")
}),Object.freeze(n),Object.getOwnPropertyNames(n).forEach((t=>{
const a=n[t],i=typeof a;"object"!==i&&"function"!==i||Object.isFrozen(a)||e(a)
})),n}class n{constructor(e){
void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}
ignoreMatch(){this.isMatchIgnored=!0}}function t(e){
return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;")
}function a(e,...n){const t=Object.create(null);for(const n in e)t[n]=e[n]
;return n.forEach((e=>{for(const n in e)t[n]=e[n]})),t}const i=e=>!!e.scope
;class r{constructor(e,n){
this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){
this.buffer+=t(e)}openNode(e){if(!i(e))return;const n=((e,{prefix:n})=>{
if(e.startsWith("language:"))return e.replace("language:","language-")
;if(e.includes(".")){const t=e.split(".")
;return[`${n}${t.shift()}`,...t.map(((e,n)=>`${e}${"_".repeat(n+1)}`))].join(" ")
}return`${n}${e}`})(e.scope,{prefix:this.classPrefix});this.span(n)}
closeNode(e){i(e)&&(this.buffer+="</span>")}value(){return this.buffer}span(e){
this.buffer+=`<span class="${e}">`}}const s=(e={})=>{const n={children:[]}
;return Object.assign(n,e),n};class o{constructor(){
this.rootNode=s(),this.stack=[this.rootNode]}get top(){
return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){
this.top.children.push(e)}openNode(e){const n=s({scope:e})
;this.add(n),this.stack.push(n)}closeNode(){
if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){
for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}
walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){
return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),
n.children.forEach((n=>this._walk(e,n))),e.closeNode(n)),e}static _collapse(e){
"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{
o._collapse(e)})))}}class l extends o{constructor(e){super(),this.options=e}
addText(e){""!==e&&this.add(e)}startScope(e){this.openNode(e)}endScope(){
this.closeNode()}__addSublanguage(e,n){const t=e.root
;n&&(t.scope="language:"+n),this.add(t)}toHTML(){
return new r(this,this.options).value()}finalize(){
return this.closeAllNodes(),!0}}function c(e){
return e?"string"==typeof e?e:e.source:null}function d(e){return b("(?=",e,")")}
function g(e){return b("(?:",e,")*")}function u(e){return b("(?:",e,")?")}
function b(...e){return e.map((e=>c(e))).join("")}function m(...e){const n=(e=>{
const n=e[e.length-1]
;return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{}
})(e);return"("+(n.capture?"":"?:")+e.map((e=>c(e))).join("|")+")"}
function p(e){return RegExp(e.toString()+"|").exec("").length-1}
const _=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./
;function h(e,{joinWith:n}){let t=0;return e.map((e=>{t+=1;const n=t
;let a=c(e),i="";for(;a.length>0;){const e=_.exec(a);if(!e){i+=a;break}
i+=a.substring(0,e.index),
a=a.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?i+="\\"+(Number(e[1])+n):(i+=e[0],
"("===e[0]&&t++)}return i})).map((e=>`(${e})`)).join(n)}
const f="[a-zA-Z]\\w*",E="[a-zA-Z_]\\w*",y="\\b\\d+(\\.\\d+)?",N="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",w="\\b(0b[01]+)",v={
begin:"\\\\[\\s\\S]",relevance:0},O={scope:"string",begin:"'",end:"'",
illegal:"\\n",contains:[v]},k={scope:"string",begin:'"',end:'"',illegal:"\\n",
contains:[v]},x=(e,n,t={})=>{const i=a({scope:"comment",begin:e,end:n,
contains:[]},t);i.contains.push({scope:"doctag",
begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",
end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0})
;const r=m("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/)
;return i.contains.push({begin:b(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),i
},M=x("//","$"),S=x("/\\*","\\*/"),A=x("#","$");var C=Object.freeze({
__proto__:null,APOS_STRING_MODE:O,BACKSLASH_ESCAPE:v,BINARY_NUMBER_MODE:{
scope:"number",begin:w,relevance:0},BINARY_NUMBER_RE:w,COMMENT:x,
C_BLOCK_COMMENT_MODE:S,C_LINE_COMMENT_MODE:M,C_NUMBER_MODE:{scope:"number",
begin:N,relevance:0},C_NUMBER_RE:N,END_SAME_AS_BEGIN:e=>Object.assign(e,{
"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{
n.data._beginMatch!==e[1]&&n.ignoreMatch()}}),HASH_COMMENT_MODE:A,IDENT_RE:f,
MATCH_NOTHING_RE:/\b\B/,METHOD_GUARD:{begin:"\\.\\s*"+E,relevance:0},
NUMBER_MODE:{scope:"number",begin:y,relevance:0},NUMBER_RE:y,
PHRASAL_WORDS_MODE:{
begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
},QUOTE_STRING_MODE:k,REGEXP_MODE:{scope:"regexp",begin:/\/(?=[^/\n]*\/)/,
end:/\/[gimuy]*/,contains:[v,{begin:/\[/,end:/\]/,relevance:0,contains:[v]}]},
RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",
SHEBANG:(e={})=>{const n=/^#![ ]*\//
;return e.binary&&(e.begin=b(n,/.*\b/,e.binary,/\b.*/)),a({scope:"meta",begin:n,
end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)},
TITLE_MODE:{scope:"title",begin:f,relevance:0},UNDERSCORE_IDENT_RE:E,
UNDERSCORE_TITLE_MODE:{scope:"title",begin:E,relevance:0}});function T(e,n){
"."===e.input[e.index-1]&&n.ignoreMatch()}function R(e,n){
void 0!==e.className&&(e.scope=e.className,delete e.className)}function D(e,n){
n&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",
e.__beforeBegin=T,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,
void 0===e.relevance&&(e.relevance=0))}function I(e,n){
Array.isArray(e.illegal)&&(e.illegal=m(...e.illegal))}function L(e,n){
if(e.match){
if(e.begin||e.end)throw Error("begin & end are not supported with match")
;e.begin=e.match,delete e.match}}function B(e,n){
void 0===e.relevance&&(e.relevance=1)}const $=(e,n)=>{if(!e.beforeMatch)return
;if(e.starts)throw Error("beforeMatch cannot be used with starts")
;const t=Object.assign({},e);Object.keys(e).forEach((n=>{delete e[n]
})),e.keywords=t.keywords,e.begin=b(t.beforeMatch,d(t.begin)),e.starts={
relevance:0,contains:[Object.assign(t,{endsParent:!0})]
},e.relevance=0,delete t.beforeMatch
},z=["of","and","for","in","not","or","if","then","parent","list","value"],F="keyword"
;function U(e,n,t=F){const a=Object.create(null)
;return"string"==typeof e?i(t,e.split(" ")):Array.isArray(e)?i(t,e):Object.keys(e).forEach((t=>{
Object.assign(a,U(e[t],n,t))})),a;function i(e,t){
n&&(t=t.map((e=>e.toLowerCase()))),t.forEach((n=>{const t=n.split("|")
;a[t[0]]=[e,j(t[0],t[1])]}))}}function j(e,n){
return n?Number(n):(e=>z.includes(e.toLowerCase()))(e)?0:1}const P={},K=e=>{
console.error(e)},H=(e,...n)=>{console.log("WARN: "+e,...n)},q=(e,n)=>{
P[`${e}/${n}`]||(console.log(`Deprecated as of ${e}. ${n}`),P[`${e}/${n}`]=!0)
},G=Error();function Z(e,n,{key:t}){let a=0;const i=e[t],r={},s={}
;for(let e=1;e<=n.length;e++)s[e+a]=i[e],r[e+a]=!0,a+=p(n[e-1])
;e[t]=s,e[t]._emit=r,e[t]._multi=!0}function W(e){(e=>{
e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope,
delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={
_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope
}),(e=>{if(Array.isArray(e.begin)){
if(e.skip||e.excludeBegin||e.returnBegin)throw K("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),
G
;if("object"!=typeof e.beginScope||null===e.beginScope)throw K("beginScope must be object"),
G;Z(e,e.begin,{key:"beginScope"}),e.begin=h(e.begin,{joinWith:""})}})(e),(e=>{
if(Array.isArray(e.end)){
if(e.skip||e.excludeEnd||e.returnEnd)throw K("skip, excludeEnd, returnEnd not compatible with endScope: {}"),
G
;if("object"!=typeof e.endScope||null===e.endScope)throw K("endScope must be object"),
G;Z(e,e.end,{key:"endScope"}),e.end=h(e.end,{joinWith:""})}})(e)}function Q(e){
function n(n,t){
return RegExp(c(n),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(t?"g":""))
}class t{constructor(){
this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}
addRule(e,n){
n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),
this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null)
;const e=this.regexes.map((e=>e[1]));this.matcherRe=n(h(e,{joinWith:"|"
}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex
;const n=this.matcherRe.exec(e);if(!n)return null
;const t=n.findIndex(((e,n)=>n>0&&void 0!==e)),a=this.matchIndexes[t]
;return n.splice(0,t),Object.assign(n,a)}}class i{constructor(){
this.rules=[],this.multiRegexes=[],
this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){
if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t
;return this.rules.slice(e).forEach((([e,t])=>n.addRule(e,t))),
n.compile(),this.multiRegexes[e]=n,n}resumingScanAtSamePosition(){
return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,n){
this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){
const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex
;let t=n.exec(e)
;if(this.resumingScanAtSamePosition())if(t&&t.index===this.lastIndex);else{
const n=this.getMatcher(0);n.lastIndex=this.lastIndex+1,t=n.exec(e)}
return t&&(this.regexIndex+=t.position+1,
this.regexIndex===this.count&&this.considerAll()),t}}
if(e.compilerExtensions||(e.compilerExtensions=[]),
e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.")
;return e.classNameAliases=a(e.classNameAliases||{}),function t(r,s){const o=r
;if(r.isCompiled)return o
;[R,L,W,$].forEach((e=>e(r,s))),e.compilerExtensions.forEach((e=>e(r,s))),
r.__beforeBegin=null,[D,I,B].forEach((e=>e(r,s))),r.isCompiled=!0;let l=null
;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords),
l=r.keywords.$pattern,
delete r.keywords.$pattern),l=l||/\w+/,r.keywords&&(r.keywords=U(r.keywords,e.case_insensitive)),
o.keywordPatternRe=n(l,!0),
s&&(r.begin||(r.begin=/\B|\b/),o.beginRe=n(o.begin),r.end||r.endsWithParent||(r.end=/\B|\b/),
r.end&&(o.endRe=n(o.end)),
o.terminatorEnd=c(o.end)||"",r.endsWithParent&&s.terminatorEnd&&(o.terminatorEnd+=(r.end?"|":"")+s.terminatorEnd)),
r.illegal&&(o.illegalRe=n(r.illegal)),
r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((n=>a(e,{
variants:null},n)))),e.cachedVariants?e.cachedVariants:X(e)?a(e,{
starts:e.starts?a(e.starts):null
}):Object.isFrozen(e)?a(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{t(e,o)
})),r.starts&&t(r.starts,s),o.matcher=(e=>{const n=new i
;return e.contains.forEach((e=>n.addRule(e.begin,{rule:e,type:"begin"
}))),e.terminatorEnd&&n.addRule(e.terminatorEnd,{type:"end"
}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n})(o),o}(e)}function X(e){
return!!e&&(e.endsWithParent||X(e.starts))}class V extends Error{
constructor(e,n){super(e),this.name="HTMLInjectionError",this.html=n}}
const J=t,Y=a,ee=Symbol("nomatch"),ne=t=>{
const a=Object.create(null),i=Object.create(null),r=[];let s=!0
;const o="Could not find the language '{}', did you forget to load/include a language module?",c={
disableAutodetect:!0,name:"Plain text",contains:[]};let p={
ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,
languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",
cssSelector:"pre code",languages:null,__emitter:l};function _(e){
return p.noHighlightRe.test(e)}function h(e,n,t){let a="",i=""
;"object"==typeof n?(a=e,
t=n.ignoreIllegals,i=n.language):(q("10.7.0","highlight(lang, code, ...args) has been deprecated."),
q("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),
i=e,a=n),void 0===t&&(t=!0);const r={code:a,language:i};x("before:highlight",r)
;const s=r.result?r.result:f(r.language,r.code,t)
;return s.code=r.code,x("after:highlight",s),s}function f(e,t,i,r){
const l=Object.create(null);function c(){if(!x.keywords)return void S.addText(A)
;let e=0;x.keywordPatternRe.lastIndex=0;let n=x.keywordPatternRe.exec(A),t=""
;for(;n;){t+=A.substring(e,n.index)
;const i=w.case_insensitive?n[0].toLowerCase():n[0],r=(a=i,x.keywords[a]);if(r){
const[e,a]=r
;if(S.addText(t),t="",l[i]=(l[i]||0)+1,l[i]<=7&&(C+=a),e.startsWith("_"))t+=n[0];else{
const t=w.classNameAliases[e]||e;g(n[0],t)}}else t+=n[0]
;e=x.keywordPatternRe.lastIndex,n=x.keywordPatternRe.exec(A)}var a
;t+=A.substring(e),S.addText(t)}function d(){null!=x.subLanguage?(()=>{
if(""===A)return;let e=null;if("string"==typeof x.subLanguage){
if(!a[x.subLanguage])return void S.addText(A)
;e=f(x.subLanguage,A,!0,M[x.subLanguage]),M[x.subLanguage]=e._top
}else e=E(A,x.subLanguage.length?x.subLanguage:null)
;x.relevance>0&&(C+=e.relevance),S.__addSublanguage(e._emitter,e.language)
})():c(),A=""}function g(e,n){
""!==e&&(S.startScope(n),S.addText(e),S.endScope())}function u(e,n){let t=1
;const a=n.length-1;for(;t<=a;){if(!e._emit[t]){t++;continue}
const a=w.classNameAliases[e[t]]||e[t],i=n[t];a?g(i,a):(A=i,c(),A=""),t++}}
function b(e,n){
return e.scope&&"string"==typeof e.scope&&S.openNode(w.classNameAliases[e.scope]||e.scope),
e.beginScope&&(e.beginScope._wrap?(g(A,w.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap),
A=""):e.beginScope._multi&&(u(e.beginScope,n),A="")),x=Object.create(e,{parent:{
value:x}}),x}function m(e,t,a){let i=((e,n)=>{const t=e&&e.exec(n)
;return t&&0===t.index})(e.endRe,a);if(i){if(e["on:end"]){const a=new n(e)
;e["on:end"](t,a),a.isMatchIgnored&&(i=!1)}if(i){
for(;e.endsParent&&e.parent;)e=e.parent;return e}}
if(e.endsWithParent)return m(e.parent,t,a)}function _(e){
return 0===x.matcher.regexIndex?(A+=e[0],1):(D=!0,0)}function h(e){
const n=e[0],a=t.substring(e.index),i=m(x,e,a);if(!i)return ee;const r=x
;x.endScope&&x.endScope._wrap?(d(),
g(n,x.endScope._wrap)):x.endScope&&x.endScope._multi?(d(),
u(x.endScope,e)):r.skip?A+=n:(r.returnEnd||r.excludeEnd||(A+=n),
d(),r.excludeEnd&&(A=n));do{
x.scope&&S.closeNode(),x.skip||x.subLanguage||(C+=x.relevance),x=x.parent
}while(x!==i.parent);return i.starts&&b(i.starts,e),r.returnEnd?0:n.length}
let y={};function N(a,r){const o=r&&r[0];if(A+=a,null==o)return d(),0
;if("begin"===y.type&&"end"===r.type&&y.index===r.index&&""===o){
if(A+=t.slice(r.index,r.index+1),!s){const n=Error(`0 width match regex (${e})`)
;throw n.languageName=e,n.badRule=y.rule,n}return 1}
if(y=r,"begin"===r.type)return(e=>{
const t=e[0],a=e.rule,i=new n(a),r=[a.__beforeBegin,a["on:begin"]]
;for(const n of r)if(n&&(n(e,i),i.isMatchIgnored))return _(t)
;return a.skip?A+=t:(a.excludeBegin&&(A+=t),
d(),a.returnBegin||a.excludeBegin||(A=t)),b(a,e),a.returnBegin?0:t.length})(r)
;if("illegal"===r.type&&!i){
const e=Error('Illegal lexeme "'+o+'" for mode "'+(x.scope||"<unnamed>")+'"')
;throw e.mode=x,e}if("end"===r.type){const e=h(r);if(e!==ee)return e}
if("illegal"===r.type&&""===o)return 1
;if(R>1e5&&R>3*r.index)throw Error("potential infinite loop, way more iterations than matches")
;return A+=o,o.length}const w=v(e)
;if(!w)throw K(o.replace("{}",e)),Error('Unknown language: "'+e+'"')
;const O=Q(w);let k="",x=r||O;const M={},S=new p.__emitter(p);(()=>{const e=[]
;for(let n=x;n!==w;n=n.parent)n.scope&&e.unshift(n.scope)
;e.forEach((e=>S.openNode(e)))})();let A="",C=0,T=0,R=0,D=!1;try{
if(w.__emitTokens)w.__emitTokens(t,S);else{for(x.matcher.considerAll();;){
R++,D?D=!1:x.matcher.considerAll(),x.matcher.lastIndex=T
;const e=x.matcher.exec(t);if(!e)break;const n=N(t.substring(T,e.index),e)
;T=e.index+n}N(t.substring(T))}return S.finalize(),k=S.toHTML(),{language:e,
value:k,relevance:C,illegal:!1,_emitter:S,_top:x}}catch(n){
if(n.message&&n.message.includes("Illegal"))return{language:e,value:J(t),
illegal:!0,relevance:0,_illegalBy:{message:n.message,index:T,
context:t.slice(T-100,T+100),mode:n.mode,resultSoFar:k},_emitter:S};if(s)return{
language:e,value:J(t),illegal:!1,relevance:0,errorRaised:n,_emitter:S,_top:x}
;throw n}}function E(e,n){n=n||p.languages||Object.keys(a);const t=(e=>{
const n={value:J(e),illegal:!1,relevance:0,_top:c,_emitter:new p.__emitter(p)}
;return n._emitter.addText(e),n})(e),i=n.filter(v).filter(k).map((n=>f(n,e,!1)))
;i.unshift(t);const r=i.sort(((e,n)=>{
if(e.relevance!==n.relevance)return n.relevance-e.relevance
;if(e.language&&n.language){if(v(e.language).supersetOf===n.language)return 1
;if(v(n.language).supersetOf===e.language)return-1}return 0})),[s,o]=r,l=s
;return l.secondBest=o,l}function y(e){let n=null;const t=(e=>{
let n=e.className+" ";n+=e.parentNode?e.parentNode.className:""
;const t=p.languageDetectRe.exec(n);if(t){const n=v(t[1])
;return n||(H(o.replace("{}",t[1])),
H("Falling back to no-highlight mode for this block.",e)),n?t[1]:"no-highlight"}
return n.split(/\s+/).find((e=>_(e)||v(e)))})(e);if(_(t))return
;if(x("before:highlightElement",{el:e,language:t
}),e.dataset.highlighted)return void console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",e)
;if(e.children.length>0&&(p.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),
console.warn("https://github.com/highlightjs/highlight.js/wiki/security"),
console.warn("The element with unescaped HTML:"),
console.warn(e)),p.throwUnescapedHTML))throw new V("One of your code blocks includes unescaped HTML.",e.innerHTML)
;n=e;const a=n.textContent,r=t?h(a,{language:t,ignoreIllegals:!0}):E(a)
;e.innerHTML=r.value,e.dataset.highlighted="yes",((e,n,t)=>{const a=n&&i[n]||t
;e.classList.add("hljs"),e.classList.add("language-"+a)
})(e,t,r.language),e.result={language:r.language,re:r.relevance,
relevance:r.relevance},r.secondBest&&(e.secondBest={
language:r.secondBest.language,relevance:r.secondBest.relevance
}),x("after:highlightElement",{el:e,result:r,text:a})}let N=!1;function w(){
"loading"!==document.readyState?document.querySelectorAll(p.cssSelector).forEach(y):N=!0
}function v(e){return e=(e||"").toLowerCase(),a[e]||a[i[e]]}
function O(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach((e=>{
i[e.toLowerCase()]=n}))}function k(e){const n=v(e)
;return n&&!n.disableAutodetect}function x(e,n){const t=e;r.forEach((e=>{
e[t]&&e[t](n)}))}
"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{
N&&w()}),!1),Object.assign(t,{highlight:h,highlightAuto:E,highlightAll:w,
highlightElement:y,
highlightBlock:e=>(q("10.7.0","highlightBlock will be removed entirely in v12.0"),
q("10.7.0","Please use highlightElement now."),y(e)),configure:e=>{p=Y(p,e)},
initHighlighting:()=>{
w(),q("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")},
initHighlightingOnLoad:()=>{
w(),q("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")
},registerLanguage:(e,n)=>{let i=null;try{i=n(t)}catch(n){
if(K("Language definition for '{}' could not be registered.".replace("{}",e)),
!s)throw n;K(n),i=c}
i.name||(i.name=e),a[e]=i,i.rawDefinition=n.bind(null,t),i.aliases&&O(i.aliases,{
languageName:e})},unregisterLanguage:e=>{delete a[e]
;for(const n of Object.keys(i))i[n]===e&&delete i[n]},
listLanguages:()=>Object.keys(a),getLanguage:v,registerAliases:O,
autoDetection:k,inherit:Y,addPlugin:e=>{(e=>{
e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=n=>{
e["before:highlightBlock"](Object.assign({block:n.el},n))
}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=n=>{
e["after:highlightBlock"](Object.assign({block:n.el},n))})})(e),r.push(e)},
removePlugin:e=>{const n=r.indexOf(e);-1!==n&&r.splice(n,1)}}),t.debugMode=()=>{
s=!1},t.safeMode=()=>{s=!0},t.versionString="11.9.0",t.regex={concat:b,
lookahead:d,either:m,optional:u,anyNumberOfTimes:g}
;for(const n in C)"object"==typeof C[n]&&e(C[n]);return Object.assign(t,C),t
},te=ne({});te.newInstance=()=>ne({});var ae=te;const ie=e=>({IMPORTANT:{
scope:"meta",begin:"!important"},BLOCK_COMMENT:e.C_BLOCK_COMMENT_MODE,HEXCOLOR:{
scope:"number",begin:/#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/},
FUNCTION_DISPATCH:{className:"built_in",begin:/[\w-]+(?=\()/},
ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$",
contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{
scope:"number",
begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",
relevance:0},CSS_VARIABLE:{className:"attr",begin:/--[A-Za-z_][A-Za-z0-9_-]*/}
}),re=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],se=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"],oe=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"],le=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],ce=["align-content","align-items","align-self","all","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","block-size","border","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","clip-path","clip-rule","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","content","content-visibility","counter-increment","counter-reset","cue","cue-after","cue-before","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","flow","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-synthesis","font-variant","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","gap","glyph-orientation-vertical","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inline-size","isolation","justify-content","left","letter-spacing","line-break","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-block","margin-block-end","margin-block-start","margin-bottom","margin-inline","margin-inline-end","margin-inline-start","margin-left","margin-right","margin-top","marks","mask","mask-border","mask-border-mode","mask-border-outset","mask-border-repeat","mask-border-slice","mask-border-source","mask-border-width","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-block","padding-block-end","padding-block-start","padding-bottom","padding-inline","padding-inline-end","padding-inline-start","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","pause","pause-after","pause-before","perspective","perspective-origin","pointer-events","position","quotes","resize","rest","rest-after","rest-before","right","row-gap","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-stop","scroll-snap-type","scrollbar-color","scrollbar-gutter","scrollbar-width","shape-image-threshold","shape-margin","shape-outside","speak","speak-as","src","tab-size","table-layout","text-align","text-align-all","text-align-last","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-indent","text-justify","text-orientation","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-box","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","z-index"].reverse(),de=oe.concat(le)
;var ge="[0-9](_*[0-9])*",ue=`\\.(${ge})`,be="[0-9a-fA-F](_*[0-9a-fA-F])*",me={
className:"number",variants:[{
begin:`(\\b(${ge})((${ue})|\\.)?|(${ue}))[eE][+-]?(${ge})[fFdD]?\\b`},{
begin:`\\b(${ge})((${ue})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{
begin:`(${ue})[fFdD]?\\b`},{begin:`\\b(${ge})[fFdD]\\b`},{
begin:`\\b0[xX]((${be})\\.?|(${be})?\\.(${be}))[pP][+-]?(${ge})[fFdD]?\\b`},{
begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${be})[lL]?\\b`},{
begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],
relevance:0};function pe(e,n,t){return-1===t?"":e.replace(n,(a=>pe(e,n,t-1)))}
const _e="[A-Za-z$_][0-9A-Za-z$_]*",he=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],fe=["true","false","null","undefined","NaN","Infinity"],Ee=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],ye=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],Ne=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],we=["arguments","this","super","console","window","document","localStorage","sessionStorage","module","global"],ve=[].concat(Ne,Ee,ye)
;function Oe(e){const n=e.regex,t=_e,a={begin:/<[A-Za-z0-9\\._:-]+/,
end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{
const t=e[0].length+e.index,a=e.input[t]
;if("<"===a||","===a)return void n.ignoreMatch();let i
;">"===a&&(((e,{after:n})=>{const t="</"+e[0].slice(1)
;return-1!==e.input.indexOf(t,n)})(e,{after:t})||n.ignoreMatch())
;const r=e.input.substring(t)
;((i=r.match(/^\s*=/))||(i=r.match(/^\s+extends\s+/))&&0===i.index)&&n.ignoreMatch()
}},i={$pattern:_e,keyword:he,literal:fe,built_in:ve,"variable.language":we
},r="[0-9](_?[0-9])*",s=`\\.(${r})`,o="0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*",l={
className:"number",variants:[{
begin:`(\\b(${o})((${s})|\\.)?|(${s}))[eE][+-]?(${r})\\b`},{
begin:`\\b(${o})\\b((${s})\\b|\\.)?|(${s})\\b`},{
begin:"\\b(0|[1-9](_?[0-9])*)n\\b"},{
begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b"},{
begin:"\\b0[bB][0-1](_?[0-1])*n?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*n?\\b"},{
begin:"\\b0[0-7]+n?\\b"}],relevance:0},c={className:"subst",begin:"\\$\\{",
end:"\\}",keywords:i,contains:[]},d={begin:"html`",end:"",starts:{end:"`",
returnEnd:!1,contains:[e.BACKSLASH_ESCAPE,c],subLanguage:"xml"}},g={
begin:"css`",end:"",starts:{end:"`",returnEnd:!1,
contains:[e.BACKSLASH_ESCAPE,c],subLanguage:"css"}},u={begin:"gql`",end:"",
starts:{end:"`",returnEnd:!1,contains:[e.BACKSLASH_ESCAPE,c],
subLanguage:"graphql"}},b={className:"string",begin:"`",end:"`",
contains:[e.BACKSLASH_ESCAPE,c]},m={className:"comment",
variants:[e.COMMENT(/\/\*\*(?!\/)/,"\\*/",{relevance:0,contains:[{
begin:"(?=@[A-Za-z]+)",relevance:0,contains:[{className:"doctag",
begin:"@[A-Za-z]+"},{className:"type",begin:"\\{",end:"\\}",excludeEnd:!0,
excludeBegin:!0,relevance:0},{className:"variable",begin:t+"(?=\\s*(-)|$)",
endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]
}),e.C_BLOCK_COMMENT_MODE,e.C_LINE_COMMENT_MODE]
},p=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,d,g,u,b,{match:/\$\d+/},l]
;c.contains=p.concat({begin:/\{/,end:/\}/,keywords:i,contains:["self"].concat(p)
});const _=[].concat(m,c.contains),h=_.concat([{begin:/\(/,end:/\)/,keywords:i,
contains:["self"].concat(_)}]),f={className:"params",begin:/\(/,end:/\)/,
excludeBegin:!0,excludeEnd:!0,keywords:i,contains:h},E={variants:[{
match:[/class/,/\s+/,t,/\s+/,/extends/,/\s+/,n.concat(t,"(",n.concat(/\./,t),")*")],
scope:{1:"keyword",3:"title.class",5:"keyword",7:"title.class.inherited"}},{
match:[/class/,/\s+/,t],scope:{1:"keyword",3:"title.class"}}]},y={relevance:0,
match:n.either(/\bJSON/,/\b[A-Z][a-z]+([A-Z][a-z]*|\d)*/,/\b[A-Z]{2,}([A-Z][a-z]+|\d)+([A-Z][a-z]*)*/,/\b[A-Z]{2,}[a-z]+([A-Z][a-z]+|\d)*([A-Z][a-z]*)*/),
className:"title.class",keywords:{_:[...Ee,...ye]}},N={variants:[{
match:[/function/,/\s+/,t,/(?=\s*\()/]},{match:[/function/,/\s*(?=\()/]}],
className:{1:"keyword",3:"title.function"},label:"func.def",contains:[f],
illegal:/%/},w={
match:n.concat(/\b/,(v=[...Ne,"super","import"],n.concat("(?!",v.join("|"),")")),t,n.lookahead(/\(/)),
className:"title.function",relevance:0};var v;const O={
begin:n.concat(/\./,n.lookahead(n.concat(t,/(?![0-9A-Za-z$_(])/))),end:t,
excludeBegin:!0,keywords:"prototype",className:"property",relevance:0},k={
match:[/get|set/,/\s+/,t,/(?=\()/],className:{1:"keyword",3:"title.function"},
contains:[{begin:/\(\)/},f]
},x="(\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)|"+e.UNDERSCORE_IDENT_RE+")\\s*=>",M={
match:[/const|var|let/,/\s+/,t,/\s*/,/=\s*/,/(async\s*)?/,n.lookahead(x)],
keywords:"async",className:{1:"keyword",3:"title.function"},contains:[f]}
;return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:i,exports:{
PARAMS_CONTAINS:h,CLASS_REFERENCE:y},illegal:/#(?![$_A-z])/,
contains:[e.SHEBANG({label:"shebang",binary:"node",relevance:5}),{
label:"use_strict",className:"meta",relevance:10,
begin:/^\s*['"]use (strict|asm)['"]/
},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,d,g,u,b,m,{match:/\$\d+/},l,y,{
className:"attr",begin:t+n.lookahead(":"),relevance:0},M,{
begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",
keywords:"return throw case",relevance:0,contains:[m,e.REGEXP_MODE,{
className:"function",begin:x,returnBegin:!0,end:"\\s*=>",contains:[{
className:"params",variants:[{begin:e.UNDERSCORE_IDENT_RE,relevance:0},{
className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,
excludeEnd:!0,keywords:i,contains:h}]}]},{begin:/,/,relevance:0},{match:/\s+/,
relevance:0},{variants:[{begin:"<>",end:"</>"},{
match:/<[A-Za-z0-9\\._:-]+\s*\/>/},{begin:a.begin,
"on:begin":a.isTrulyOpeningTag,end:a.end}],subLanguage:"xml",contains:[{
begin:a.begin,end:a.end,skip:!0,contains:["self"]}]}]},N,{
beginKeywords:"while if switch catch for"},{
begin:"\\b(?!function)"+e.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{",
returnBegin:!0,label:"func.def",contains:[f,e.inherit(e.TITLE_MODE,{begin:t,
className:"title.function"})]},{match:/\.\.\./,relevance:0},O,{match:"\\$"+t,
relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"},
contains:[f]},w,{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/,
className:"variable.constant"},E,k,{match:/\$[(.]/}]}}
const ke=e=>b(/\b/,e,/\w$/.test(e)?/\b/:/\B/),xe=["Protocol","Type"].map(ke),Me=["init","self"].map(ke),Se=["Any","Self"],Ae=["actor","any","associatedtype","async","await",/as\?/,/as!/,"as","borrowing","break","case","catch","class","consume","consuming","continue","convenience","copy","default","defer","deinit","didSet","distributed","do","dynamic","each","else","enum","extension","fallthrough",/fileprivate\(set\)/,"fileprivate","final","for","func","get","guard","if","import","indirect","infix",/init\?/,/init!/,"inout",/internal\(set\)/,"internal","in","is","isolated","nonisolated","lazy","let","macro","mutating","nonmutating",/open\(set\)/,"open","operator","optional","override","postfix","precedencegroup","prefix",/private\(set\)/,"private","protocol",/public\(set\)/,"public","repeat","required","rethrows","return","set","some","static","struct","subscript","super","switch","throws","throw",/try\?/,/try!/,"try","typealias",/unowned\(safe\)/,/unowned\(unsafe\)/,"unowned","var","weak","where","while","willSet"],Ce=["false","nil","true"],Te=["assignment","associativity","higherThan","left","lowerThan","none","right"],Re=["#colorLiteral","#column","#dsohandle","#else","#elseif","#endif","#error","#file","#fileID","#fileLiteral","#filePath","#function","#if","#imageLiteral","#keyPath","#line","#selector","#sourceLocation","#warning"],De=["abs","all","any","assert","assertionFailure","debugPrint","dump","fatalError","getVaList","isKnownUniquelyReferenced","max","min","numericCast","pointwiseMax","pointwiseMin","precondition","preconditionFailure","print","readLine","repeatElement","sequence","stride","swap","swift_unboxFromSwiftValueWithType","transcode","type","unsafeBitCast","unsafeDowncast","withExtendedLifetime","withUnsafeMutablePointer","withUnsafePointer","withVaList","withoutActuallyEscaping","zip"],Ie=m(/[/=\-+!*%<>&|^~?]/,/[\u00A1-\u00A7]/,/[\u00A9\u00AB]/,/[\u00AC\u00AE]/,/[\u00B0\u00B1]/,/[\u00B6\u00BB\u00BF\u00D7\u00F7]/,/[\u2016-\u2017]/,/[\u2020-\u2027]/,/[\u2030-\u203E]/,/[\u2041-\u2053]/,/[\u2055-\u205E]/,/[\u2190-\u23FF]/,/[\u2500-\u2775]/,/[\u2794-\u2BFF]/,/[\u2E00-\u2E7F]/,/[\u3001-\u3003]/,/[\u3008-\u3020]/,/[\u3030]/),Le=m(Ie,/[\u0300-\u036F]/,/[\u1DC0-\u1DFF]/,/[\u20D0-\u20FF]/,/[\uFE00-\uFE0F]/,/[\uFE20-\uFE2F]/),Be=b(Ie,Le,"*"),$e=m(/[a-zA-Z_]/,/[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,/[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,/[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,/[\u1E00-\u1FFF]/,/[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,/[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,/[\u2C00-\u2DFF\u2E80-\u2FFF]/,/[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,/[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,/[\uFE47-\uFEFE\uFF00-\uFFFD]/),ze=m($e,/\d/,/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/),Fe=b($e,ze,"*"),Ue=b(/[A-Z]/,ze,"*"),je=["attached","autoclosure",b(/convention\(/,m("swift","block","c"),/\)/),"discardableResult","dynamicCallable","dynamicMemberLookup","escaping","freestanding","frozen","GKInspectable","IBAction","IBDesignable","IBInspectable","IBOutlet","IBSegueAction","inlinable","main","nonobjc","NSApplicationMain","NSCopying","NSManaged",b(/objc\(/,Fe,/\)/),"objc","objcMembers","propertyWrapper","requires_stored_property_inits","resultBuilder","Sendable","testable","UIApplicationMain","unchecked","unknown","usableFromInline","warn_unqualified_access"],Pe=["iOS","iOSApplicationExtension","macOS","macOSApplicationExtension","macCatalyst","macCatalystApplicationExtension","watchOS","watchOSApplicationExtension","tvOS","tvOSApplicationExtension","swift"]
;var Ke=Object.freeze({__proto__:null,grmr_bash:e=>{const n=e.regex,t={},a={
begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]}
;Object.assign(t,{className:"variable",variants:[{
begin:n.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},a]});const i={
className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},r={
begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,
end:/(\w+)/,className:"string"})]}},s={className:"string",begin:/"/,end:/"/,
contains:[e.BACKSLASH_ESCAPE,t,i]};i.contains.push(s);const o={begin:/\$?\(\(/,
end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t]
},l=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10
}),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,
contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{
name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z][a-z0-9._-]+\b/,
keyword:["if","then","else","elif","fi","for","while","until","in","do","done","case","esac","function","select"],
literal:["true","false"],
built_in:["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset","alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","type","typeset","ulimit","unalias","set","shopt","autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp","chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"]
},contains:[l,e.SHEBANG(),c,o,e.HASH_COMMENT_MODE,r,{match:/(\/[a-z._-]+)+/},s,{
match:/\\"/},{className:"string",begin:/'/,end:/'/},{match:/\\'/},t]}},
grmr_c:e=>{const n=e.regex,t=e.COMMENT("//","$",{contains:[{begin:/\\\n/}]
}),a="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",r="("+a+"|"+n.optional(i)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",s={
className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{
match:/\batomic_[a-z]{3,6}\b/}]},o={className:"string",variants:[{
begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{
begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",
end:"'",illegal:"."},e.END_SAME_AS_BEGIN({
begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={
className:"number",variants:[{begin:"\\b(0b[01']+)"},{
begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)"
},{
begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"
}],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{
keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"
},contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{
className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},d={
className:"title",begin:n.optional(i)+e.IDENT_RE,relevance:0
},g=n.optional(i)+e.IDENT_RE+"\\s*\\(",u={
keyword:["asm","auto","break","case","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"],
type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal128","const","static","complex","bool","imaginary"],
literal:"true false NULL",
built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr"
},b=[c,s,t,e.C_BLOCK_COMMENT_MODE,l,o],m={variants:[{begin:/=/,end:/;/},{
begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],
keywords:u,contains:b.concat([{begin:/\(/,end:/\)/,keywords:u,
contains:b.concat(["self"]),relevance:0}]),relevance:0},p={
begin:"("+r+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,
keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:u,relevance:0},{
begin:g,returnBegin:!0,contains:[e.inherit(d,{className:"title.function"})],
relevance:0},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/,
keywords:u,relevance:0,contains:[t,e.C_BLOCK_COMMENT_MODE,o,l,s,{begin:/\(/,
end:/\)/,keywords:u,relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,o,l,s]
}]},s,t,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C",aliases:["h"],keywords:u,
disableAutodetect:!0,illegal:"</",contains:[].concat(m,p,b,[c,{
begin:e.IDENT_RE+"::",keywords:u},{className:"class",
beginKeywords:"enum class struct union",end:/[{;:<>=]/,contains:[{
beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:c,
strings:o,keywords:u}}},grmr_cpp:e=>{const n=e.regex,t=e.COMMENT("//","$",{
contains:[{begin:/\\\n/}]
}),a="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",r="(?!struct)("+a+"|"+n.optional(i)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",s={
className:"type",begin:"\\b[a-z\\d_]*_t\\b"},o={className:"string",variants:[{
begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{
begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",
end:"'",illegal:"."},e.END_SAME_AS_BEGIN({
begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={
className:"number",variants:[{begin:"\\b(0b[01']+)"},{
begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)"
},{
begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"
}],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{
keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"
},contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{
className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},d={
className:"title",begin:n.optional(i)+e.IDENT_RE,relevance:0
},g=n.optional(i)+e.IDENT_RE+"\\s*\\(",u={
type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"],
keyword:["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"],
literal:["NULL","false","nullopt","nullptr","true"],built_in:["_Pragma"],
_type_hints:["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"]
},b={className:"function.dispatch",relevance:0,keywords:{
_hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"]
},
begin:n.concat(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!switch)/,/(?!while)/,e.IDENT_RE,n.lookahead(/(<[^<>]+>|)\s*\(/))
},m=[b,c,s,t,e.C_BLOCK_COMMENT_MODE,l,o],p={variants:[{begin:/=/,end:/;/},{
begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],
keywords:u,contains:m.concat([{begin:/\(/,end:/\)/,keywords:u,
contains:m.concat(["self"]),relevance:0}]),relevance:0},_={className:"function",
begin:"("+r+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,
keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:u,relevance:0},{
begin:g,returnBegin:!0,contains:[d],relevance:0},{begin:/::/,relevance:0},{
begin:/:/,endsWithParent:!0,contains:[o,l]},{relevance:0,match:/,/},{
className:"params",begin:/\(/,end:/\)/,keywords:u,relevance:0,
contains:[t,e.C_BLOCK_COMMENT_MODE,o,l,s,{begin:/\(/,end:/\)/,keywords:u,
relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,o,l,s]}]
},s,t,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C++",
aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:u,illegal:"</",
classNameAliases:{"function.dispatch":"built_in"},
contains:[].concat(p,_,b,m,[c,{
begin:"\\b(deque|list|queue|priority_queue|pair|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array|tuple|optional|variant|function)\\s*<(?!<)",
end:">",keywords:u,contains:["self",s]},{begin:e.IDENT_RE+"::",keywords:u},{
match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/],
className:{1:"keyword",3:"title.class"}}])}},grmr_csharp:e=>{const n={
keyword:["abstract","as","base","break","case","catch","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","scoped","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","async","await","by","descending","equals","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","remove","select","set","unmanaged","value|0","var","when","where","with","yield"]),
built_in:["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"],
literal:["default","false","null","true"]},t=e.inherit(e.TITLE_MODE,{
begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{
begin:"\\b(0b[01']+)"},{
begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{
begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"
}],relevance:0},i={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}]
},r=e.inherit(i,{illegal:/\n/}),s={className:"subst",begin:/\{/,end:/\}/,
keywords:n},o=e.inherit(s,{illegal:/\n/}),l={className:"string",begin:/\$"/,
end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/
},e.BACKSLASH_ESCAPE,o]},c={className:"string",begin:/\$@"/,end:'"',contains:[{
begin:/\{\{/},{begin:/\}\}/},{begin:'""'},s]},d=e.inherit(c,{illegal:/\n/,
contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},o]})
;s.contains=[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE],
o.contains=[d,l,r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{
illegal:/\n/})];const g={variants:[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]
},u={begin:"<",end:">",contains:[{beginKeywords:"in out"},t]
},b=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",m={
begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"],
keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0,
contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{
begin:"\x3c!--|--\x3e"},{begin:"</?",end:">"}]}]
}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#",
end:"$",keywords:{
keyword:"if else elif endif define undef warning error line region endregion pragma checksum"
}},g,a,{beginKeywords:"class interface",relevance:0,end:/[{;=]/,
illegal:/[^\s:,]/,contains:[{beginKeywords:"where class"
},t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace",
relevance:0,end:/[{;=]/,illegal:/[^\s:]/,
contains:[t,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{
beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/,
contains:[t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta",
begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{
className:"string",begin:/"/,end:/"/}]},{
beginKeywords:"new return throw await else",relevance:0},{className:"function",
begin:"("+b+"\\s+)+"+e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0,
end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{
beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial",
relevance:0},{begin:e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0,
contains:[e.TITLE_MODE,u],relevance:0},{match:/\(\)/},{className:"params",
begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0,
contains:[g,a,e.C_BLOCK_COMMENT_MODE]
},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},m]}},grmr_css:e=>{
const n=e.regex,t=ie(e),a=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE];return{
name:"CSS",case_insensitive:!0,illegal:/[=|'\$]/,keywords:{
keyframePosition:"from to"},classNameAliases:{keyframePosition:"selector-tag"},
contains:[t.BLOCK_COMMENT,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/
},t.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0
},{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0
},t.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{
begin:":("+oe.join("|")+")"},{begin:":(:)?("+le.join("|")+")"}]
},t.CSS_VARIABLE,{className:"attribute",begin:"\\b("+ce.join("|")+")\\b"},{
begin:/:/,end:/[;}{]/,
contains:[t.BLOCK_COMMENT,t.HEXCOLOR,t.IMPORTANT,t.CSS_NUMBER_MODE,...a,{
begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri"
},contains:[...a,{className:"string",begin:/[^)]/,endsWithParent:!0,
excludeEnd:!0}]},t.FUNCTION_DISPATCH]},{begin:n.lookahead(/@/),end:"[{;]",
relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/
},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{
$pattern:/[a-z-]+/,keyword:"and or not only",attribute:se.join(" ")},contains:[{
begin:/[a-z-]+(?=:)/,className:"attribute"},...a,t.CSS_NUMBER_MODE]}]},{
className:"selector-tag",begin:"\\b("+re.join("|")+")\\b"}]}},grmr_diff:e=>{
const n=e.regex;return{name:"Diff",aliases:["patch"],contains:[{
className:"meta",relevance:10,
match:n.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/)
},{className:"comment",variants:[{
begin:n.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/),
end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{
className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/,
end:/$/}]}},grmr_go:e=>{const n={
keyword:["break","case","chan","const","continue","default","defer","else","fallthrough","for","func","go","goto","if","import","interface","map","package","range","return","select","struct","switch","type","var"],
type:["bool","byte","complex64","complex128","error","float32","float64","int8","int16","int32","int64","string","uint8","uint16","uint32","uint64","int","uint","uintptr","rune"],
literal:["true","false","iota","nil"],
built_in:["append","cap","close","complex","copy","imag","len","make","new","panic","print","println","real","recover","delete"]
};return{name:"Go",aliases:["golang"],keywords:n,illegal:"</",
contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"string",
variants:[e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{begin:"`",end:"`"}]},{
className:"number",variants:[{begin:e.C_NUMBER_RE+"[i]",relevance:1
},e.C_NUMBER_MODE]},{begin:/:=/},{className:"function",beginKeywords:"func",
end:"\\s*(\\{|$)",excludeEnd:!0,contains:[e.TITLE_MODE,{className:"params",
begin:/\(/,end:/\)/,endsParent:!0,keywords:n,illegal:/["']/}]}]}},
grmr_graphql:e=>{const n=e.regex;return{name:"GraphQL",aliases:["gql"],
case_insensitive:!0,disableAutodetect:!1,keywords:{
keyword:["query","mutation","subscription","type","input","schema","directive","interface","union","scalar","fragment","enum","on"],
literal:["true","false","null"]},
contains:[e.HASH_COMMENT_MODE,e.QUOTE_STRING_MODE,e.NUMBER_MODE,{
scope:"punctuation",match:/[.]{3}/,relevance:0},{scope:"punctuation",
begin:/[\!\(\)\:\=\[\]\{\|\}]{1}/,relevance:0},{scope:"variable",begin:/\$/,
end:/\W/,excludeEnd:!0,relevance:0},{scope:"meta",match:/@\w+/,excludeEnd:!0},{
scope:"symbol",begin:n.concat(/[_A-Za-z][_0-9A-Za-z]*/,n.lookahead(/\s*:/)),
relevance:0}],illegal:[/[;<']/,/BEGIN/]}},grmr_ini:e=>{const n=e.regex,t={
className:"number",relevance:0,variants:[{begin:/([+-]+)?[\d]+_[\d_]+/},{
begin:e.NUMBER_RE}]},a=e.COMMENT();a.variants=[{begin:/;/,end:/$/},{begin:/#/,
end:/$/}];const i={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{
begin:/\$\{(.*?)\}/}]},r={className:"literal",
begin:/\bon|off|true|false|yes|no\b/},s={className:"string",
contains:[e.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{
begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}]
},o={begin:/\[/,end:/\]/,contains:[a,r,i,s,t,"self"],relevance:0
},l=n.either(/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/);return{
name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/,
contains:[a,{className:"section",begin:/\[+/,end:/\]+/},{
begin:n.concat(l,"(\\s*\\.\\s*",l,")*",n.lookahead(/\s*=\s*[^#\s]/)),
className:"attr",starts:{end:/$/,contains:[a,o,r,i,s,t]}}]}},grmr_java:e=>{
const n=e.regex,t="[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*",a=t+pe("(?:<"+t+"~~~(?:\\s*,\\s*"+t+"~~~)*>)?",/~~~/g,2),i={
keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do","sealed","yield","permits"],
literal:["false","true","null"],
type:["char","boolean","long","float","int","byte","short","double"],
built_in:["super","this"]},r={className:"meta",begin:"@"+t,contains:[{
begin:/\(/,end:/\)/,contains:["self"]}]},s={className:"params",begin:/\(/,
end:/\)/,keywords:i,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0}
;return{name:"Java",aliases:["jsp"],keywords:i,illegal:/<\/|#/,
contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,
relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{
begin:/import java\.[a-z]+\./,keywords:"import",relevance:2
},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/,
className:"string",contains:[e.BACKSLASH_ESCAPE]
},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{
match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,t],className:{
1:"keyword",3:"title.class"}},{match:/non-sealed/,scope:"keyword"},{
begin:[n.concat(/(?!else)/,t),/\s+/,t,/\s+/,/=(?!=)/],className:{1:"type",
3:"variable",5:"operator"}},{begin:[/record/,/\s+/,t],className:{1:"keyword",
3:"title.class"},contains:[s,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{
beginKeywords:"new throw return else",relevance:0},{
begin:["(?:"+a+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{
2:"title.function"},keywords:i,contains:[{className:"params",begin:/\(/,
end:/\)/,keywords:i,relevance:0,
contains:[r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,me,e.C_BLOCK_COMMENT_MODE]
},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},me,r]}},grmr_javascript:Oe,
grmr_json:e=>{const n=["true","false","null"],t={scope:"literal",
beginKeywords:n.join(" ")};return{name:"JSON",keywords:{literal:n},contains:[{
className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},{
match:/[{}[\],:]/,className:"punctuation",relevance:0
},e.QUOTE_STRING_MODE,t,e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE],
illegal:"\\S"}},grmr_kotlin:e=>{const n={
keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual",
built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",
literal:"true false null"},t={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"
},a={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},i={
className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string",
variants:[{begin:'"""',end:'"""(?=[^"])',contains:[i,a]},{begin:"'",end:"'",
illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,
contains:[e.BACKSLASH_ESCAPE,i,a]}]};a.contains.push(r);const s={
className:"meta",
begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"
},o={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,
end:/\)/,contains:[e.inherit(r,{className:"string"}),"self"]}]
},l=me,c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),d={
variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,
contains:[]}]},g=d;return g.variants[1].contains=[d],d.variants[1].contains=[g],
{name:"Kotlin",aliases:["kt","kts"],keywords:n,
contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",
begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword",
begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",
begin:/@\w+/}]}},t,s,o,{className:"function",beginKeywords:"fun",end:"[(]|$",
returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{
begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,
contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin:/</,end:/>/,
keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,
endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,
endsWithParent:!0,contains:[d,e.C_LINE_COMMENT_MODE,c],relevance:0
},e.C_LINE_COMMENT_MODE,c,s,o,r,e.C_NUMBER_MODE]},c]},{
begin:[/class|interface|trait/,/\s+/,e.UNDERSCORE_IDENT_RE],beginScope:{
3:"title.class"},keywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,
illegal:"extends implements",contains:[{
beginKeywords:"public protected internal private constructor"
},e.UNDERSCORE_TITLE_MODE,{className:"type",begin:/</,end:/>/,excludeBegin:!0,
excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,){\s]|$/,
excludeBegin:!0,returnEnd:!0},s,o]},r,{className:"meta",begin:"^#!/usr/bin/env",
end:"$",illegal:"\n"},l]}},grmr_less:e=>{
const n=ie(e),t=de,a="[\\w-]+",i="("+a+"|@\\{"+a+"\\})",r=[],s=[],o=e=>({
className:"string",begin:"~?"+e+".*?"+e}),l=(e,n,t)=>({className:e,begin:n,
relevance:t}),c={$pattern:/[a-z-]+/,keyword:"and or not only",
attribute:se.join(" ")},d={begin:"\\(",end:"\\)",contains:s,keywords:c,
relevance:0}
;s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,o("'"),o('"'),n.CSS_NUMBER_MODE,{
begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]",
excludeEnd:!0}
},n.HEXCOLOR,d,l("variable","@@?"+a,10),l("variable","@\\{"+a+"\\}"),l("built_in","~?`[^`]*?`"),{
className:"attribute",begin:a+"\\s*:",end:":",returnBegin:!0,excludeEnd:!0
},n.IMPORTANT,{beginKeywords:"and not"},n.FUNCTION_DISPATCH);const g=s.concat({
begin:/\{/,end:/\}/,contains:r}),u={beginKeywords:"when",endsWithParent:!0,
contains:[{beginKeywords:"and not"}].concat(s)},b={begin:i+"\\s*:",
returnBegin:!0,end:/[;}]/,relevance:0,contains:[{begin:/-(webkit|moz|ms|o)-/
},n.CSS_VARIABLE,{className:"attribute",begin:"\\b("+ce.join("|")+")\\b",
end:/(?=:)/,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s}}]
},m={className:"keyword",
begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",
starts:{end:"[;{}]",keywords:c,returnEnd:!0,contains:s,relevance:0}},p={
className:"variable",variants:[{begin:"@"+a+"\\s*:",relevance:15},{begin:"@"+a
}],starts:{end:"[;}]",returnEnd:!0,contains:g}},_={variants:[{
begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:i,end:/\{/}],returnBegin:!0,
returnEnd:!0,illegal:"[<='$\"]",relevance:0,
contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,u,l("keyword","all\\b"),l("variable","@\\{"+a+"\\}"),{
begin:"\\b("+re.join("|")+")\\b",className:"selector-tag"
},n.CSS_NUMBER_MODE,l("selector-tag",i,0),l("selector-id","#"+i),l("selector-class","\\."+i,0),l("selector-tag","&",0),n.ATTRIBUTE_SELECTOR_MODE,{
className:"selector-pseudo",begin:":("+oe.join("|")+")"},{
className:"selector-pseudo",begin:":(:)?("+le.join("|")+")"},{begin:/\(/,
end:/\)/,relevance:0,contains:g},{begin:"!important"},n.FUNCTION_DISPATCH]},h={
begin:a+":(:)?"+`(${t.join("|")})`,returnBegin:!0,contains:[_]}
;return r.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,m,p,h,b,_,u,n.FUNCTION_DISPATCH),
{name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:r}},
grmr_lua:e=>{const n="\\[=*\\[",t="\\]=*\\]",a={begin:n,end:t,contains:["self"]
},i=[e.COMMENT("--(?!"+n+")","$"),e.COMMENT("--"+n,t,{contains:[a],relevance:10
})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE,
literal:"true false nil",
keyword:"and break do else elseif end for goto if in local not or repeat return then until while",
built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"
},contains:i.concat([{className:"function",beginKeywords:"function",end:"\\)",
contains:[e.inherit(e.TITLE_MODE,{
begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params",
begin:"\\(",endsWithParent:!0,contains:i}].concat(i)
},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string",
begin:n,end:t,contains:[a],relevance:5}])}},grmr_makefile:e=>{const n={
className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)",
contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%<?\^\+\*]/}]},t={className:"string",
begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,n]},a={className:"variable",
begin:/\$\([\w-]+\s/,end:/\)/,keywords:{
built_in:"subst patsubst strip findstring filter filter-out sort word wordlist firstword lastword dir notdir suffix basename addsuffix addprefix join wildcard realpath abspath error warning shell origin flavor foreach if or and call eval file value"
},contains:[n]},i={begin:"^"+e.UNDERSCORE_IDENT_RE+"\\s*(?=[:+?]?=)"},r={
className:"section",begin:/^[^\s]+:/,end:/$/,contains:[n]};return{
name:"Makefile",aliases:["mk","mak","make"],keywords:{$pattern:/[\w-]+/,
keyword:"define endef undefine ifdef ifndef ifeq ifneq else endif include -include sinclude override export unexport private vpath"
},contains:[e.HASH_COMMENT_MODE,n,t,a,i,{className:"meta",begin:/^\.PHONY:/,
end:/$/,keywords:{$pattern:/[\.\w]+/,keyword:".PHONY"}},r]}},grmr_markdown:e=>{
const n={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},t={
variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{
begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,
relevance:2},{
begin:e.regex.concat(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/),
relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{
begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/
},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,
returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",
excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",
end:"\\]",excludeBegin:!0,excludeEnd:!0}]},a={className:"strong",contains:[],
variants:[{begin:/_{2}(?!\s)/,end:/_{2}/},{begin:/\*{2}(?!\s)/,end:/\*{2}/}]
},i={className:"emphasis",contains:[],variants:[{begin:/\*(?![*\s])/,end:/\*/},{
begin:/_(?![_\s])/,end:/_/,relevance:0}]},r=e.inherit(a,{contains:[]
}),s=e.inherit(i,{contains:[]});a.contains.push(s),i.contains.push(r)
;let o=[n,t];return[a,i,r,s].forEach((e=>{e.contains=e.contains.concat(o)
})),o=o.concat(a,i),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{
className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:o},{
begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",
contains:o}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",
end:"\\s+",excludeEnd:!0},a,i,{className:"quote",begin:"^>\\s+",contains:o,
end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{
begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{
begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",
contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{
begin:"^[-\\*]{3,}",end:"$"},t,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{
className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{
className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}},grmr_objectivec:e=>{
const n=/[a-zA-Z@][a-zA-Z0-9_]*/,t={$pattern:n,
keyword:["@interface","@class","@protocol","@implementation"]};return{
name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"],
keywords:{"variable.language":["this","super"],$pattern:n,
keyword:["while","export","sizeof","typedef","const","struct","for","union","volatile","static","mutable","if","do","return","goto","enum","else","break","extern","asm","case","default","register","explicit","typename","switch","continue","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"],
literal:["false","true","FALSE","TRUE","nil","YES","NO","NULL"],
built_in:["dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"],
type:["int","float","char","unsigned","signed","short","long","double","wchar_t","unichar","void","bool","BOOL","id|0","_Bool"]
},illegal:"</",contains:[{className:"built_in",
begin:"\\b(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)\\w+"
},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.C_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{
className:"string",variants:[{begin:'@"',end:'"',illegal:"\\n",
contains:[e.BACKSLASH_ESCAPE]}]},{className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,
keywords:{
keyword:"if else elif endif define undef warning error line pragma ifdef ifndef include"
},contains:[{begin:/\\\n/,relevance:0},e.inherit(e.QUOTE_STRING_MODE,{
className:"string"}),{className:"string",begin:/<.*?>/,end:/$/,illegal:"\\n"
},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class",
begin:"("+t.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:t,
contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE,
relevance:0}]}},grmr_perl:e=>{const n=e.regex,t=/[dualxmsipngr]{0,12}/,a={
$pattern:/[\w.]+/,
keyword:"abs accept alarm and atan2 bind binmode bless break caller chdir chmod chomp chop chown chr chroot close closedir connect continue cos crypt dbmclose dbmopen defined delete die do dump each else elsif endgrent endhostent endnetent endprotoent endpwent endservent eof eval exec exists exit exp fcntl fileno flock for foreach fork format formline getc getgrent getgrgid getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr getnetbyname getnetent getpeername getpgrp getpriority getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid getservbyname getservbyport getservent getsockname getsockopt given glob gmtime goto grep gt hex if index int ioctl join keys kill last lc lcfirst length link listen local localtime log lstat lt ma map mkdir msgctl msgget msgrcv msgsnd my ne next no not oct open opendir or ord our pack package pipe pop pos print printf prototype push q|0 qq quotemeta qw qx rand read readdir readline readlink readpipe recv redo ref rename require reset return reverse rewinddir rindex rmdir say scalar seek seekdir select semctl semget semop send setgrent sethostent setnetent setpgrp setpriority setprotoent setpwent setservent setsockopt shift shmctl shmget shmread shmwrite shutdown sin sleep socket socketpair sort splice split sprintf sqrt srand stat state study sub substr symlink syscall sysopen sysread sysseek system syswrite tell telldir tie tied time times tr truncate uc ucfirst umask undef unless unlink unpack unshift untie until use utime values vec wait waitpid wantarray warn when while write x|0 xor y|0"
},i={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:a},r={begin:/->\{/,
end:/\}/},s={variants:[{begin:/\$\d/},{
begin:n.concat(/[$%@](\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,"(?![A-Za-z])(?![@$%])")
},{begin:/[$%@][^\s\w{]/,relevance:0}]
},o=[e.BACKSLASH_ESCAPE,i,s],l=[/!/,/\//,/\|/,/\?/,/'/,/"/,/#/],c=(e,a,i="\\1")=>{
const r="\\1"===i?i:n.concat(i,a)
;return n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,r,/(?:\\.|[^\\\/])*?/,i,t)
},d=(e,a,i)=>n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,i,t),g=[s,e.HASH_COMMENT_MODE,e.COMMENT(/^=\w/,/=cut/,{
endsWithParent:!0}),r,{className:"string",contains:o,variants:[{
begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[",
end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{
begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*<",end:">",
relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'",
contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`",
contains:[e.BACKSLASH_ESCAPE]},{begin:/\{\w+\}/,relevance:0},{
begin:"-?\\w+\\s*=>",relevance:0}]},{className:"number",
begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",
relevance:0},{
begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*",
keywords:"split return print reverse grep",relevance:0,
contains:[e.HASH_COMMENT_MODE,{className:"regexp",variants:[{
begin:c("s|tr|y",n.either(...l,{capture:!0}))},{begin:c("s|tr|y","\\(","\\)")},{
begin:c("s|tr|y","\\[","\\]")},{begin:c("s|tr|y","\\{","\\}")}],relevance:2},{
className:"regexp",variants:[{begin:/(m|qr)\/\//,relevance:0},{
begin:d("(?:m|qr)?",/\//,/\//)},{begin:d("m|qr",n.either(...l,{capture:!0
}),/\1/)},{begin:d("m|qr",/\(/,/\)/)},{begin:d("m|qr",/\[/,/\]/)},{
begin:d("m|qr",/\{/,/\}/)}]}]},{className:"function",beginKeywords:"sub",
end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{
begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$",
subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}]
}];return i.contains=g,r.contains=g,{name:"Perl",aliases:["pl","pm"],keywords:a,
contains:g}},grmr_php:e=>{
const n=e.regex,t=/(?![A-Za-z0-9])(?![$])/,a=n.concat(/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/,t),i=n.concat(/(\\?[A-Z][a-z0-9_\x7f-\xff]+|\\?[A-Z]+(?=[A-Z][a-z0-9_\x7f-\xff])){1,}/,t),r={
scope:"variable",match:"\\$+"+a},s={scope:"subst",variants:[{begin:/\$\w+/},{
begin:/\{\$/,end:/\}/}]},o=e.inherit(e.APOS_STRING_MODE,{illegal:null
}),l="[ \t\n]",c={scope:"string",variants:[e.inherit(e.QUOTE_STRING_MODE,{
illegal:null,contains:e.QUOTE_STRING_MODE.contains.concat(s)}),o,{
begin:/<<<[ \t]*(?:(\w+)|"(\w+)")\n/,end:/[ \t]*(\w+)\b/,
contains:e.QUOTE_STRING_MODE.contains.concat(s),"on:begin":(e,n)=>{
n.data._beginMatch=e[1]||e[2]},"on:end":(e,n)=>{
n.data._beginMatch!==e[1]&&n.ignoreMatch()}},e.END_SAME_AS_BEGIN({
begin:/<<<[ \t]*'(\w+)'\n/,end:/[ \t]*(\w+)\b/})]},d={scope:"number",variants:[{
begin:"\\b0[bB][01]+(?:_[01]+)*\\b"},{begin:"\\b0[oO][0-7]+(?:_[0-7]+)*\\b"},{
begin:"\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b"},{
begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?"
}],relevance:0
},g=["false","null","true"],u=["__CLASS__","__DIR__","__FILE__","__FUNCTION__","__COMPILER_HALT_OFFSET__","__LINE__","__METHOD__","__NAMESPACE__","__TRAIT__","die","echo","exit","include","include_once","print","require","require_once","array","abstract","and","as","binary","bool","boolean","break","callable","case","catch","class","clone","const","continue","declare","default","do","double","else","elseif","empty","enddeclare","endfor","endforeach","endif","endswitch","endwhile","enum","eval","extends","final","finally","float","for","foreach","from","global","goto","if","implements","instanceof","insteadof","int","integer","interface","isset","iterable","list","match|0","mixed","new","never","object","or","private","protected","public","readonly","real","return","string","switch","throw","trait","try","unset","use","var","void","while","xor","yield"],b=["Error|0","AppendIterator","ArgumentCountError","ArithmeticError","ArrayIterator","ArrayObject","AssertionError","BadFunctionCallException","BadMethodCallException","CachingIterator","CallbackFilterIterator","CompileError","Countable","DirectoryIterator","DivisionByZeroError","DomainException","EmptyIterator","ErrorException","Exception","FilesystemIterator","FilterIterator","GlobIterator","InfiniteIterator","InvalidArgumentException","IteratorIterator","LengthException","LimitIterator","LogicException","MultipleIterator","NoRewindIterator","OutOfBoundsException","OutOfRangeException","OuterIterator","OverflowException","ParentIterator","ParseError","RangeException","RecursiveArrayIterator","RecursiveCachingIterator","RecursiveCallbackFilterIterator","RecursiveDirectoryIterator","RecursiveFilterIterator","RecursiveIterator","RecursiveIteratorIterator","RecursiveRegexIterator","RecursiveTreeIterator","RegexIterator","RuntimeException","SeekableIterator","SplDoublyLinkedList","SplFileInfo","SplFileObject","SplFixedArray","SplHeap","SplMaxHeap","SplMinHeap","SplObjectStorage","SplObserver","SplPriorityQueue","SplQueue","SplStack","SplSubject","SplTempFileObject","TypeError","UnderflowException","UnexpectedValueException","UnhandledMatchError","ArrayAccess","BackedEnum","Closure","Fiber","Generator","Iterator","IteratorAggregate","Serializable","Stringable","Throwable","Traversable","UnitEnum","WeakReference","WeakMap","Directory","__PHP_Incomplete_Class","parent","php_user_filter","self","static","stdClass"],m={
keyword:u,literal:(e=>{const n=[];return e.forEach((e=>{
n.push(e),e.toLowerCase()===e?n.push(e.toUpperCase()):n.push(e.toLowerCase())
})),n})(g),built_in:b},p=e=>e.map((e=>e.replace(/\|\d+$/,""))),_={variants:[{
match:[/new/,n.concat(l,"+"),n.concat("(?!",p(b).join("\\b|"),"\\b)"),i],scope:{
1:"keyword",4:"title.class"}}]},h=n.concat(a,"\\b(?!\\()"),f={variants:[{
match:[n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{2:"variable.constant"
}},{match:[/::/,/class/],scope:{2:"variable.language"}},{
match:[i,n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{1:"title.class",
3:"variable.constant"}},{match:[i,n.concat("::",n.lookahead(/(?!class\b)/))],
scope:{1:"title.class"}},{match:[i,/::/,/class/],scope:{1:"title.class",
3:"variable.language"}}]},E={scope:"attr",
match:n.concat(a,n.lookahead(":"),n.lookahead(/(?!::)/))},y={relevance:0,
begin:/\(/,end:/\)/,keywords:m,contains:[E,r,f,e.C_BLOCK_COMMENT_MODE,c,d,_]
},N={relevance:0,
match:[/\b/,n.concat("(?!fn\\b|function\\b|",p(u).join("\\b|"),"|",p(b).join("\\b|"),"\\b)"),a,n.concat(l,"*"),n.lookahead(/(?=\()/)],
scope:{3:"title.function.invoke"},contains:[y]};y.contains.push(N)
;const w=[E,f,e.C_BLOCK_COMMENT_MODE,c,d,_];return{case_insensitive:!1,
keywords:m,contains:[{begin:n.concat(/#\[\s*/,i),beginScope:"meta",end:/]/,
endScope:"meta",keywords:{literal:g,keyword:["new","array"]},contains:[{
begin:/\[/,end:/]/,keywords:{literal:g,keyword:["new","array"]},
contains:["self",...w]},...w,{scope:"meta",match:i}]
},e.HASH_COMMENT_MODE,e.COMMENT("//","$"),e.COMMENT("/\\*","\\*/",{contains:[{
scope:"doctag",match:"@[A-Za-z]+"}]}),{match:/__halt_compiler\(\);/,
keywords:"__halt_compiler",starts:{scope:"comment",end:e.MATCH_NOTHING_RE,
contains:[{match:/\?>/,scope:"meta",endsParent:!0}]}},{scope:"meta",variants:[{
begin:/<\?php/,relevance:10},{begin:/<\?=/},{begin:/<\?/,relevance:.1},{
begin:/\?>/}]},{scope:"variable.language",match:/\$this\b/},r,N,f,{
match:[/const/,/\s/,a],scope:{1:"keyword",3:"variable.constant"}},_,{
scope:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/,
excludeEnd:!0,illegal:"[$%\\[]",contains:[{beginKeywords:"use"
},e.UNDERSCORE_TITLE_MODE,{begin:"=>",endsParent:!0},{scope:"params",
begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:m,
contains:["self",r,f,e.C_BLOCK_COMMENT_MODE,c,d]}]},{scope:"class",variants:[{
beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait",
illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{
beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{
beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/,
contains:[e.inherit(e.UNDERSCORE_TITLE_MODE,{scope:"title.class"})]},{
beginKeywords:"use",relevance:0,end:";",contains:[{
match:/\b(as|const|function)\b/,scope:"keyword"},e.UNDERSCORE_TITLE_MODE]},c,d]}
},grmr_php_template:e=>({name:"PHP template",subLanguage:"xml",contains:[{
begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*",
end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0
},e.inherit(e.APOS_STRING_MODE,{illegal:null,className:null,contains:null,
skip:!0}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null,className:null,
contains:null,skip:!0})]}]}),grmr_plaintext:e=>({name:"Plain text",
aliases:["text","txt"],disableAutodetect:!0}),grmr_python:e=>{
const n=e.regex,t=/[\p{XID_Start}_]\p{XID_Continue}*/u,a=["and","as","assert","async","await","break","case","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","match","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],i={
$pattern:/[A-Za-z]\w+|__\w+__/,keyword:a,
built_in:["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"],
literal:["__debug__","Ellipsis","False","None","NotImplemented","True"],
type:["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"]
},r={className:"meta",begin:/^(>>>|\.\.\.) /},s={className:"subst",begin:/\{/,
end:/\}/,keywords:i,illegal:/#/},o={begin:/\{\{/,relevance:0},l={
className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{
begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/,
contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{
begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/,
contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{
begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/,
contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/,
end:/"""/,contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([uU]|[rR])'/,end:/'/,
relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{
begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/,
end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/,
contains:[e.BACKSLASH_ESCAPE,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/,
contains:[e.BACKSLASH_ESCAPE,o,s]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]
},c="[0-9](_?[0-9])*",d=`(\\b(${c}))?\\.(${c})|\\b(${c})\\.`,g="\\b|"+a.join("|"),u={
className:"number",relevance:0,variants:[{
begin:`(\\b(${c})|(${d}))[eE][+-]?(${c})[jJ]?(?=${g})`},{begin:`(${d})[jJ]?`},{
begin:`\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${g})`},{
begin:`\\b0[bB](_?[01])+[lL]?(?=${g})`},{begin:`\\b0[oO](_?[0-7])+[lL]?(?=${g})`
},{begin:`\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${g})`},{begin:`\\b(${c})[jJ](?=${g})`
}]},b={className:"comment",begin:n.lookahead(/# type:/),end:/$/,keywords:i,
contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},m={
className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/,
end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:i,
contains:["self",r,u,l,e.HASH_COMMENT_MODE]}]};return s.contains=[l,u,r],{
name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:i,
illegal:/(<\/|\?)|=>/,contains:[r,u,{begin:/\bself\b/},{beginKeywords:"if",
relevance:0},l,b,e.HASH_COMMENT_MODE,{match:[/\bdef/,/\s+/,t],scope:{
1:"keyword",3:"title.function"},contains:[m]},{variants:[{
match:[/\bclass/,/\s+/,t,/\s*/,/\(\s*/,t,/\s*\)/]},{match:[/\bclass/,/\s+/,t]}],
scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{
className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[u,m,l]}]}},
grmr_python_repl:e=>({aliases:["pycon"],contains:[{className:"meta.prompt",
starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{
begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}),grmr_r:e=>{
const n=e.regex,t=/(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/,a=n.either(/0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/,/0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/,/(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/),i=/[=!<>:]=|\|\||&&|:::?|<-|<<-|->>|->|\|>|[-+*\/?!{{HIGHLIGHT_JS}}|:<=>@^~]|\*\*/,r=n.either(/[()]/,/[{}]/,/\[\[/,/[[\]]/,/\\/,/,/)
;return{name:"R",keywords:{$pattern:t,
keyword:"function if in break next repeat else for while",
literal:"NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10",
built_in:"LETTERS letters month.abb month.name pi T F abs acos acosh all any anyNA Arg as.call as.character as.complex as.double as.environment as.integer as.logical as.null.default as.numeric as.raw asin asinh atan atanh attr attributes baseenv browser c call ceiling class Conj cos cosh cospi cummax cummin cumprod cumsum digamma dim dimnames emptyenv exp expression floor forceAndCall gamma gc.time globalenv Im interactive invisible is.array is.atomic is.call is.character is.complex is.double is.environment is.expression is.finite is.function is.infinite is.integer is.language is.list is.logical is.matrix is.na is.name is.nan is.null is.numeric is.object is.pairlist is.raw is.recursive is.single is.symbol lazyLoadDBfetch length lgamma list log max min missing Mod names nargs nzchar oldClass on.exit pos.to.env proc.time prod quote range Re rep retracemem return round seq_along seq_len seq.int sign signif sin sinh sinpi sqrt standardGeneric substitute sum switch tan tanh tanpi tracemem trigamma trunc unclass untracemem UseMethod xtfrm"
},contains:[e.COMMENT(/#'/,/$/,{contains:[{scope:"doctag",match:/@examples/,
starts:{end:n.lookahead(n.either(/\n^#'\s*(?=@[a-zA-Z]+)/,/\n^(?!#')/)),
endsParent:!0}},{scope:"doctag",begin:"@param",end:/$/,contains:[{
scope:"variable",variants:[{match:t},{match:/`(?:\\.|[^`\\])+`/}],endsParent:!0
}]},{scope:"doctag",match:/@[a-zA-Z]+/},{scope:"keyword",match:/\\[a-zA-Z]+/}]
}),e.HASH_COMMENT_MODE,{scope:"string",contains:[e.BACKSLASH_ESCAPE],
variants:[e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\(/,end:/\)(-*)"/
}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\{/,end:/\}(-*)"/
}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\[/,end:/\](-*)"/
}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\(/,end:/\)(-*)'/
}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\{/,end:/\}(-*)'/
}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\[/,end:/\](-*)'/}),{begin:'"',end:'"',
relevance:0},{begin:"'",end:"'",relevance:0}]},{relevance:0,variants:[{scope:{
1:"operator",2:"number"},match:[i,a]},{scope:{1:"operator",2:"number"},
match:[/%[^%]*%/,a]},{scope:{1:"punctuation",2:"number"},match:[r,a]},{scope:{
2:"number"},match:[/[^a-zA-Z0-9._]|^/,a]}]},{scope:{3:"operator"},
match:[t,/\s+/,/<-/,/\s+/]},{scope:"operator",relevance:0,variants:[{match:i},{
match:/%[^%]*%/}]},{scope:"punctuation",relevance:0,match:r},{begin:"`",end:"`",
contains:[{begin:/\\./}]}]}},grmr_ruby:e=>{
const n=e.regex,t="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",a=n.either(/\b([A-Z]+[a-z0-9]+)+/,/\b([A-Z]+[a-z0-9]+)+[A-Z]+/),i=n.concat(a,/(::\w+)*/),r={
"variable.constant":["__FILE__","__LINE__","__ENCODING__"],
"variable.language":["self","super"],
keyword:["alias","and","begin","BEGIN","break","case","class","defined","do","else","elsif","end","END","ensure","for","if","in","module","next","not","or","redo","require","rescue","retry","return","then","undef","unless","until","when","while","yield","include","extend","prepend","public","private","protected","raise","throw"],
built_in:["proc","lambda","attr_accessor","attr_reader","attr_writer","define_method","private_constant","module_function"],
literal:["true","false","nil"]},s={className:"doctag",begin:"@[A-Za-z]+"},o={
begin:"#<",end:">"},l=[e.COMMENT("#","$",{contains:[s]
}),e.COMMENT("^=begin","^=end",{contains:[s],relevance:10
}),e.COMMENT("^__END__",e.MATCH_NOTHING_RE)],c={className:"subst",begin:/#\{/,
end:/\}/,keywords:r},d={className:"string",contains:[e.BACKSLASH_ESCAPE,c],
variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{
begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{
begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?</,end:/>/},{begin:/%[qQwWx]?\//,
end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{
begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{
begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{
begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{
begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{
begin:n.concat(/<<[-~]?'?/,n.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)),
contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,
contains:[e.BACKSLASH_ESCAPE,c]})]}]},g="[0-9](_?[0-9])*",u={className:"number",
relevance:0,variants:[{
begin:`\\b([1-9](_?[0-9])*|0)(\\.(${g}))?([eE][+-]?(${g})|r)?i?\\b`},{
begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b"
},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{
begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{
begin:"\\b0(_?[0-7])+r?i?\\b"}]},b={variants:[{match:/\(\)/},{
className:"params",begin:/\(/,end:/(?=\))/,excludeBegin:!0,endsParent:!0,
keywords:r}]},m=[d,{variants:[{match:[/class\s+/,i,/\s+<\s+/,i]},{
match:[/\b(class|module)\s+/,i]}],scope:{2:"title.class",
4:"title.class.inherited"},keywords:r},{match:[/(include|extend)\s+/,i],scope:{
2:"title.class"},keywords:r},{relevance:0,match:[i,/\.new[. (]/],scope:{
1:"title.class"}},{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/,
className:"variable.constant"},{relevance:0,match:a,scope:"title.class"},{
match:[/def/,/\s+/,t],scope:{1:"keyword",3:"title.function"},contains:[b]},{
begin:e.IDENT_RE+"::"},{className:"symbol",
begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol",
begin:":(?!\\s)",contains:[d,{begin:t}],relevance:0},u,{className:"variable",
begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{
className:"params",begin:/\|/,end:/\|/,excludeBegin:!0,excludeEnd:!0,
relevance:0,keywords:r},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",
keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c],
illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{
begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",
end:"\\][a-z]*"}]}].concat(o,l),relevance:0}].concat(o,l)
;c.contains=m,b.contains=m;const p=[{begin:/^\s*=>/,starts:{end:"$",contains:m}
},{className:"meta.prompt",
begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])",
starts:{end:"$",keywords:r,contains:m}}];return l.unshift(o),{name:"Ruby",
aliases:["rb","gemspec","podspec","thor","irb"],keywords:r,illegal:/\/\*/,
contains:[e.SHEBANG({binary:"ruby"})].concat(p).concat(l).concat(m)}},
grmr_rust:e=>{const n=e.regex,t={className:"title.function.invoke",relevance:0,
begin:n.concat(/\b/,/(?!let|for|while|if|else|match\b)/,e.IDENT_RE,n.lookahead(/\s*\(/))
},a="([ui](8|16|32|64|128|size)|f(32|64))?",i=["drop ","Copy","Send","Sized","Sync","Drop","Fn","FnMut","FnOnce","ToOwned","Clone","Debug","PartialEq","PartialOrd","Eq","Ord","AsRef","AsMut","Into","From","Default","Iterator","Extend","IntoIterator","DoubleEndedIterator","ExactSizeIterator","SliceConcatExt","ToString","assert!","assert_eq!","bitflags!","bytes!","cfg!","col!","concat!","concat_idents!","debug_assert!","debug_assert_eq!","env!","eprintln!","panic!","file!","format!","format_args!","include_bytes!","include_str!","line!","local_data_key!","module_path!","option_env!","print!","println!","select!","stringify!","try!","unimplemented!","unreachable!","vec!","write!","writeln!","macro_rules!","assert_ne!","debug_assert_ne!"],r=["i8","i16","i32","i64","i128","isize","u8","u16","u32","u64","u128","usize","f32","f64","str","char","bool","Box","Option","Result","String","Vec"]
;return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",type:r,
keyword:["abstract","as","async","await","become","box","break","const","continue","crate","do","dyn","else","enum","extern","false","final","fn","for","if","impl","in","let","loop","macro","match","mod","move","mut","override","priv","pub","ref","return","self","Self","static","struct","super","trait","true","try","type","typeof","unsafe","unsized","use","virtual","where","while","yield"],
literal:["true","false","Some","None","Ok","Err"],built_in:i},illegal:"</",
contains:[e.C_LINE_COMMENT_MODE,e.COMMENT("/\\*","\\*/",{contains:["self"]
}),e.inherit(e.QUOTE_STRING_MODE,{begin:/b?"/,illegal:null}),{
className:"string",variants:[{begin:/b?r(#*)"(.|\n)*?"\1(?!#)/},{
begin:/b?'\\?(x\w{2}|u\w{4}|U\w{8}|.)'/}]},{className:"symbol",
begin:/'[a-zA-Z_][a-zA-Z0-9_]*/},{className:"number",variants:[{
begin:"\\b0b([01_]+)"+a},{begin:"\\b0o([0-7_]+)"+a},{
begin:"\\b0x([A-Fa-f0-9_]+)"+a},{
begin:"\\b(\\d[\\d_]*(\\.[0-9_]+)?([eE][+-]?[0-9_]+)?)"+a}],relevance:0},{
begin:[/fn/,/\s+/,e.UNDERSCORE_IDENT_RE],className:{1:"keyword",
3:"title.function"}},{className:"meta",begin:"#!?\\[",end:"\\]",contains:[{
className:"string",begin:/"/,end:/"/}]},{
begin:[/let/,/\s+/,/(?:mut\s+)?/,e.UNDERSCORE_IDENT_RE],className:{1:"keyword",
3:"keyword",4:"variable"}},{
begin:[/for/,/\s+/,e.UNDERSCORE_IDENT_RE,/\s+/,/in/],className:{1:"keyword",
3:"variable",5:"keyword"}},{begin:[/type/,/\s+/,e.UNDERSCORE_IDENT_RE],
className:{1:"keyword",3:"title.class"}},{
begin:[/(?:trait|enum|struct|union|impl|for)/,/\s+/,e.UNDERSCORE_IDENT_RE],
className:{1:"keyword",3:"title.class"}},{begin:e.IDENT_RE+"::",keywords:{
keyword:"Self",built_in:i,type:r}},{className:"punctuation",begin:"->"},t]}},
grmr_scss:e=>{const n=ie(e),t=le,a=oe,i="@[a-z-]+",r={className:"variable",
begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b",relevance:0};return{name:"SCSS",
case_insensitive:!0,illegal:"[=/|']",
contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,n.CSS_NUMBER_MODE,{
className:"selector-id",begin:"#[A-Za-z0-9_-]+",relevance:0},{
className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0
},n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-tag",
begin:"\\b("+re.join("|")+")\\b",relevance:0},{className:"selector-pseudo",
begin:":("+a.join("|")+")"},{className:"selector-pseudo",
begin:":(:)?("+t.join("|")+")"},r,{begin:/\(/,end:/\)/,
contains:[n.CSS_NUMBER_MODE]},n.CSS_VARIABLE,{className:"attribute",
begin:"\\b("+ce.join("|")+")\\b"},{
begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"
},{begin:/:/,end:/[;}{]/,relevance:0,
contains:[n.BLOCK_COMMENT,r,n.HEXCOLOR,n.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.IMPORTANT,n.FUNCTION_DISPATCH]
},{begin:"@(page|font-face)",keywords:{$pattern:i,keyword:"@page @font-face"}},{
begin:"@",end:"[{;]",returnBegin:!0,keywords:{$pattern:/[a-z-]+/,
keyword:"and or not only",attribute:se.join(" ")},contains:[{begin:i,
className:"keyword"},{begin:/[a-z-]+(?=:)/,className:"attribute"
},r,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.HEXCOLOR,n.CSS_NUMBER_MODE]
},n.FUNCTION_DISPATCH]}},grmr_shell:e=>({name:"Shell Session",
aliases:["console","shellsession"],contains:[{className:"meta.prompt",
begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/,
subLanguage:"bash"}}]}),grmr_sql:e=>{
const n=e.regex,t=e.COMMENT("--","$"),a=["true","false","unknown"],i=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],r=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],s=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],o=r,l=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter((e=>!r.includes(e))),c={
begin:n.concat(/\b/,n.either(...o),/\s*\(/),relevance:0,keywords:{built_in:o}}
;return{name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{
$pattern:/\b[\w\.]+/,keyword:((e,{exceptions:n,when:t}={})=>{const a=t
;return n=n||[],e.map((e=>e.match(/\|\d+$/)||n.includes(e)?e:a(e)?e+"|0":e))
})(l,{when:e=>e.length<3}),literal:a,type:i,
built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"]
},contains:[{begin:n.either(...s),relevance:0,keywords:{$pattern:/[\w\.]+/,
keyword:l.concat(s),literal:a,type:i}},{className:"type",
begin:n.either("double precision","large object","with timezone","without timezone")
},c,{className:"variable",begin:/@[a-z0-9][a-z0-9_]*/},{className:"string",
variants:[{begin:/'/,end:/'/,contains:[{begin:/''/}]}]},{begin:/"/,end:/"/,
contains:[{begin:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,{
className:"operator",begin:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/,
relevance:0}]}},grmr_swift:e=>{const n={match:/\s+/,relevance:0
},t=e.COMMENT("/\\*","\\*/",{contains:["self"]}),a=[e.C_LINE_COMMENT_MODE,t],i={
match:[/\./,m(...xe,...Me)],className:{2:"keyword"}},r={match:b(/\./,m(...Ae)),
relevance:0},s=Ae.filter((e=>"string"==typeof e)).concat(["_|0"]),o={variants:[{
className:"keyword",
match:m(...Ae.filter((e=>"string"!=typeof e)).concat(Se).map(ke),...Me)}]},l={
$pattern:m(/\b\w+/,/#\w+/),keyword:s.concat(Re),literal:Ce},c=[i,r,o],g=[{
match:b(/\./,m(...De)),relevance:0},{className:"built_in",
match:b(/\b/,m(...De),/(?=\()/)}],u={match:/->/,relevance:0},p=[u,{
className:"operator",relevance:0,variants:[{match:Be},{match:`\\.(\\.|${Le})+`}]
}],_="([0-9]_*)+",h="([0-9a-fA-F]_*)+",f={className:"number",relevance:0,
variants:[{match:`\\b(${_})(\\.(${_}))?([eE][+-]?(${_}))?\\b`},{
match:`\\b0x(${h})(\\.(${h}))?([pP][+-]?(${_}))?\\b`},{match:/\b0o([0-7]_*)+\b/
},{match:/\b0b([01]_*)+\b/}]},E=(e="")=>({className:"subst",variants:[{
match:b(/\\/,e,/[0\\tnr"']/)},{match:b(/\\/,e,/u\{[0-9a-fA-F]{1,8}\}/)}]
}),y=(e="")=>({className:"subst",match:b(/\\/,e,/[\t ]*(?:[\r\n]|\r\n)/)
}),N=(e="")=>({className:"subst",label:"interpol",begin:b(/\\/,e,/\(/),end:/\)/
}),w=(e="")=>({begin:b(e,/"""/),end:b(/"""/,e),contains:[E(e),y(e),N(e)]
}),v=(e="")=>({begin:b(e,/"/),end:b(/"/,e),contains:[E(e),N(e)]}),O={
className:"string",
variants:[w(),w("#"),w("##"),w("###"),v(),v("#"),v("##"),v("###")]
},k=[e.BACKSLASH_ESCAPE,{begin:/\[/,end:/\]/,relevance:0,
contains:[e.BACKSLASH_ESCAPE]}],x={begin:/\/[^\s](?=[^/\n]*\/)/,end:/\//,
contains:k},M=e=>{const n=b(e,/\//),t=b(/\//,e);return{begin:n,end:t,
contains:[...k,{scope:"comment",begin:`#(?!.*${t})`,end:/$/}]}},S={
scope:"regexp",variants:[M("###"),M("##"),M("#"),x]},A={match:b(/`/,Fe,/`/)
},C=[A,{className:"variable",match:/\$\d+/},{className:"variable",
match:`\\${ze}+`}],T=[{match:/(@|#(un)?)available/,scope:"keyword",starts:{
contains:[{begin:/\(/,end:/\)/,keywords:Pe,contains:[...p,f,O]}]}},{
scope:"keyword",match:b(/@/,m(...je))},{scope:"meta",match:b(/@/,Fe)}],R={
match:d(/\b[A-Z]/),relevance:0,contains:[{className:"type",
match:b(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,ze,"+")
},{className:"type",match:Ue,relevance:0},{match:/[?!]+/,relevance:0},{
match:/\.\.\./,relevance:0},{match:b(/\s+&\s+/,d(Ue)),relevance:0}]},D={
begin:/</,end:/>/,keywords:l,contains:[...a,...c,...T,u,R]};R.contains.push(D)
;const I={begin:/\(/,end:/\)/,relevance:0,keywords:l,contains:["self",{
match:b(Fe,/\s*:/),keywords:"_|0",relevance:0
},...a,S,...c,...g,...p,f,O,...C,...T,R]},L={begin:/</,end:/>/,
keywords:"repeat each",contains:[...a,R]},B={begin:/\(/,end:/\)/,keywords:l,
contains:[{begin:m(d(b(Fe,/\s*:/)),d(b(Fe,/\s+/,Fe,/\s*:/))),end:/:/,
relevance:0,contains:[{className:"keyword",match:/\b_\b/},{className:"params",
match:Fe}]},...a,...c,...p,f,O,...T,R,I],endsParent:!0,illegal:/["']/},$={
match:[/(func|macro)/,/\s+/,m(A.match,Fe,Be)],className:{1:"keyword",
3:"title.function"},contains:[L,B,n],illegal:[/\[/,/%/]},z={
match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"},
contains:[L,B,n],illegal:/\[|%/},F={match:[/operator/,/\s+/,Be],className:{
1:"keyword",3:"title"}},U={begin:[/precedencegroup/,/\s+/,Ue],className:{
1:"keyword",3:"title"},contains:[R],keywords:[...Te,...Ce],end:/}/}
;for(const e of O.variants){const n=e.contains.find((e=>"interpol"===e.label))
;n.keywords=l;const t=[...c,...g,...p,f,O,...C];n.contains=[...t,{begin:/\(/,
end:/\)/,contains:["self",...t]}]}return{name:"Swift",keywords:l,
contains:[...a,$,z,{beginKeywords:"struct protocol class extension enum actor",
end:"\\{",excludeEnd:!0,keywords:l,contains:[e.inherit(e.TITLE_MODE,{
className:"title.class",begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/}),...c]
},F,U,{beginKeywords:"import",end:/$/,contains:[...a],relevance:0
},S,...c,...g,...p,f,O,...C,...T,R,I]}},grmr_typescript:e=>{
const n=Oe(e),t=_e,a=["any","void","number","boolean","string","object","never","symbol","bigint","unknown"],i={
beginKeywords:"namespace",end:/\{/,excludeEnd:!0,
contains:[n.exports.CLASS_REFERENCE]},r={beginKeywords:"interface",end:/\{/,
excludeEnd:!0,keywords:{keyword:"interface extends",built_in:a},
contains:[n.exports.CLASS_REFERENCE]},s={$pattern:_e,
keyword:he.concat(["type","namespace","interface","public","private","protected","implements","declare","abstract","readonly","enum","override"]),
literal:fe,built_in:ve.concat(a),"variable.language":we},o={className:"meta",
begin:"@"+t},l=(e,n,t)=>{const a=e.contains.findIndex((e=>e.label===n))
;if(-1===a)throw Error("can not find mode to replace");e.contains.splice(a,1,t)}
;return Object.assign(n.keywords,s),
n.exports.PARAMS_CONTAINS.push(o),n.contains=n.contains.concat([o,i,r]),
l(n,"shebang",e.SHEBANG()),l(n,"use_strict",{className:"meta",relevance:10,
begin:/^\s*['"]use strict['"]/
}),n.contains.find((e=>"func.def"===e.label)).relevance=0,Object.assign(n,{
name:"TypeScript",aliases:["ts","tsx","mts","cts"]}),n},grmr_vbnet:e=>{
const n=e.regex,t=/\d{1,2}\/\d{1,2}\/\d{4}/,a=/\d{4}-\d{1,2}-\d{1,2}/,i=/(\d|1[012])(:\d+){0,2} *(AM|PM)/,r=/\d{1,2}(:\d{1,2}){1,2}/,s={
className:"literal",variants:[{begin:n.concat(/# */,n.either(a,t),/ *#/)},{
begin:n.concat(/# */,r,/ *#/)},{begin:n.concat(/# */,i,/ *#/)},{
begin:n.concat(/# */,n.either(a,t),/ +/,n.either(i,r),/ *#/)}]
},o=e.COMMENT(/'''/,/$/,{contains:[{className:"doctag",begin:/<\/?/,end:/>/}]
}),l=e.COMMENT(null,/$/,{variants:[{begin:/'/},{begin:/([\t ]|^)REM(?=\s)/}]})
;return{name:"Visual Basic .NET",aliases:["vb"],case_insensitive:!0,
classNameAliases:{label:"symbol"},keywords:{
keyword:"addhandler alias aggregate ansi as async assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into iterator join key let lib loop me mid module mustinherit mustoverride mybase myclass namespace narrowing new next notinheritable notoverridable of off on operator option optional order overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly yield",
built_in:"addressof and andalso await directcast gettype getxmlnamespace is isfalse isnot istrue like mod nameof new not or orelse trycast typeof xor cbool cbyte cchar cdate cdbl cdec cint clng cobj csbyte cshort csng cstr cuint culng cushort",
type:"boolean byte char date decimal double integer long object sbyte short single string uinteger ulong ushort",
literal:"true false nothing"},
illegal:"//|\\{|\\}|endif|gosub|variant|wend|^\\$ ",contains:[{
className:"string",begin:/"(""|[^/n])"C\b/},{className:"string",begin:/"/,
end:/"/,illegal:/\n/,contains:[{begin:/""/}]},s,{className:"number",relevance:0,
variants:[{begin:/\b\d[\d_]*((\.[\d_]+(E[+-]?[\d_]+)?)|(E[+-]?[\d_]+))[RFD@!#]?/
},{begin:/\b\d[\d_]*((U?[SIL])|[%&])?/},{begin:/&H[\dA-F_]+((U?[SIL])|[%&])?/},{
begin:/&O[0-7_]+((U?[SIL])|[%&])?/},{begin:/&B[01_]+((U?[SIL])|[%&])?/}]},{
className:"label",begin:/^\w+:/},o,l,{className:"meta",
begin:/[\t ]*#(const|disable|else|elseif|enable|end|externalsource|if|region)\b/,
end:/$/,keywords:{
keyword:"const disable else elseif enable end externalsource if region then"},
contains:[l]}]}},grmr_wasm:e=>{e.regex;const n=e.COMMENT(/\(;/,/;\)/)
;return n.contains.push("self"),{name:"WebAssembly",keywords:{$pattern:/[\w.]+/,
keyword:["anyfunc","block","br","br_if","br_table","call","call_indirect","data","drop","elem","else","end","export","func","global.get","global.set","local.get","local.set","local.tee","get_global","get_local","global","if","import","local","loop","memory","memory.grow","memory.size","module","mut","nop","offset","param","result","return","select","set_global","set_local","start","table","tee_local","then","type","unreachable"]
},contains:[e.COMMENT(/;;/,/$/),n,{match:[/(?:offset|align)/,/\s*/,/=/],
className:{1:"keyword",3:"operator"}},{className:"variable",begin:/\$[\w_]+/},{
match:/(\((?!;)|\))+/,className:"punctuation",relevance:0},{
begin:[/(?:func|call|call_indirect)/,/\s+/,/\$[^\s)]+/],className:{1:"keyword",
3:"title.function"}},e.QUOTE_STRING_MODE,{match:/(i32|i64|f32|f64)(?!\.)/,
className:"type"},{className:"keyword",
match:/\b(f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|nearest|neg?|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|store(?:8|16|32)?|sqrt|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))\b/
},{className:"number",relevance:0,
match:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/
}]}},grmr_xml:e=>{
const n=e.regex,t=n.concat(/[\p{L}_]/u,n.optional(/[\p{L}0-9_.-]*:/u),/[\p{L}0-9_.-]*/u),a={
className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},i={begin:/\s/,
contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}]
},r=e.inherit(i,{begin:/\(/,end:/\)/}),s=e.inherit(e.APOS_STRING_MODE,{
className:"string"}),o=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),l={
endsWithParent:!0,illegal:/</,relevance:0,contains:[{className:"attr",
begin:/[\p{L}0-9._:-]+/u,relevance:0},{begin:/=\s*/,relevance:0,contains:[{
className:"string",endsParent:!0,variants:[{begin:/"/,end:/"/,contains:[a]},{
begin:/'/,end:/'/,contains:[a]},{begin:/[^\s"'=<>`]+/}]}]}]};return{
name:"HTML, XML",
aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],
case_insensitive:!0,unicodeRegex:!0,contains:[{className:"meta",begin:/<![a-z]/,
end:/>/,relevance:10,contains:[i,o,s,r,{begin:/\[/,end:/\]/,contains:[{
className:"meta",begin:/<![a-z]/,end:/>/,contains:[i,r,o,s]}]}]
},e.COMMENT(/<!--/,/-->/,{relevance:10}),{begin:/<!\[CDATA\[/,end:/\]\]>/,
relevance:10},a,{className:"meta",end:/\?>/,variants:[{begin:/<\?xml/,
relevance:10,contains:[o]},{begin:/<\?[a-z][a-z0-9]+/}]},{className:"tag",
begin:/<style(?=\s|>)/,end:/>/,keywords:{name:"style"},contains:[l],starts:{
end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",
begin:/<script(?=\s|>)/,end:/>/,keywords:{name:"script"},contains:[l],starts:{
end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{
className:"tag",begin:/<>|<\/>/},{className:"tag",
begin:n.concat(/</,n.lookahead(n.concat(t,n.either(/\/>/,/>/,/\s/)))),
end:/\/?>/,contains:[{className:"name",begin:t,relevance:0,starts:l}]},{
className:"tag",begin:n.concat(/<\//,n.lookahead(n.concat(t,/>/))),contains:[{
className:"name",begin:t,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]}
},grmr_yaml:e=>{
const n="true false yes no null",t="[\\w#;/?:@&=+$,.~*'()[\\]]+",a={
className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/
},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable",
variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(a,{
variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),r={
end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},s={begin:/\{/,
end:/\}/,contains:[r],illegal:"\\n",relevance:0},o={begin:"\\[",end:"\\]",
contains:[r],illegal:"\\n",relevance:0},l=[{className:"attr",variants:[{
begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{
begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$",
relevance:10},{className:"string",
begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{
begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,
relevance:0},{className:"type",begin:"!\\w+!"+t},{className:"type",
begin:"!<"+t+">"},{className:"type",begin:"!"+t},{className:"type",begin:"!!"+t
},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta",
begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)",
relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{
className:"number",
begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b"
},{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},s,o,a],c=[...l]
;return c.pop(),c.push(i),r.contains=c,{name:"YAML",case_insensitive:!0,
aliases:["yml"],contains:l}}});const He=ae;for(const e of Object.keys(Ke)){
const n=e.replace("grmr_","").replace("_","-");He.registerLanguage(n,Ke[e])}
return He}()
;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);</script>
<!-- Main application code -->
<script>
(function() {
'use strict';
// ============================================================
// DATA LOADING
// ============================================================
const base64 = document.getElementById('session-data').textContent;
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
const data = JSON.parse(new TextDecoder('utf-8').decode(bytes));
const { header, entries, leafId: defaultLeafId, systemPrompt, tools, renderedTools } = data;
// ============================================================
// URL PARAMETER HANDLING
// ============================================================
// Parse URL parameters for deep linking: leafId and targetId
// Check for injected params (when loaded in iframe via srcdoc) or use window.location
const injectedParams = document.querySelector('meta[name="pi-url-params"]');
const searchString = injectedParams ? injectedParams.content : window.location.search.substring(1);
const urlParams = new URLSearchParams(searchString);
const urlLeafId = urlParams.get('leafId');
const urlTargetId = urlParams.get('targetId');
// Use URL leafId if provided, otherwise fall back to session default
const leafId = urlLeafId || defaultLeafId;
// ============================================================
// DATA STRUCTURES
// ============================================================
// Entry lookup by ID
const byId = new Map();
for (const entry of entries) {
byId.set(entry.id, entry);
}
// Tool call lookup (toolCallId -> {name, arguments})
const toolCallMap = new Map();
for (const entry of entries) {
if (entry.type === 'message' && entry.message.role === 'assistant') {
const content = entry.message.content;
if (Array.isArray(content)) {
for (const block of content) {
if (block.type === 'toolCall') {
toolCallMap.set(block.id, { name: block.name, arguments: block.arguments });
}
}
}
}
}
// Label lookup (entryId -> label string)
// Labels are stored in 'label' entries that reference their target via targetId
const labelMap = new Map();
for (const entry of entries) {
if (entry.type === 'label' && entry.targetId && entry.label) {
labelMap.set(entry.targetId, entry.label);
}
}
// ============================================================
// TREE DATA PREPARATION (no DOM, pure data)
// ============================================================
/**
* Build tree structure from flat entries.
* Returns array of root nodes, each with { entry, children, label }.
*/
function buildTree() {
const nodeMap = new Map();
const roots = [];
// Create nodes
for (const entry of entries) {
nodeMap.set(entry.id, {
entry,
children: [],
label: labelMap.get(entry.id)
});
}
// Build parent-child relationships
for (const entry of entries) {
const node = nodeMap.get(entry.id);
if (entry.parentId === null || entry.parentId === undefined || entry.parentId === entry.id) {
roots.push(node);
} else {
const parent = nodeMap.get(entry.parentId);
if (parent) {
parent.children.push(node);
} else {
roots.push(node);
}
}
}
// Sort children by timestamp
function sortChildren(node) {
node.children.sort((a, b) =>
new Date(a.entry.timestamp).getTime() - new Date(b.entry.timestamp).getTime()
);
node.children.forEach(sortChildren);
}
roots.forEach(sortChildren);
return roots;
}
/**
* Build set of entry IDs on path from root to target.
*/
function buildActivePathIds(targetId) {
const ids = new Set();
let current = byId.get(targetId);
while (current) {
ids.add(current.id);
// Stop if no parent or self-referencing (root)
if (!current.parentId || current.parentId === current.id) {
break;
}
current = byId.get(current.parentId);
}
return ids;
}
/**
* Get array of entries from root to target (the conversation path).
*/
function getPath(targetId) {
const path = [];
let current = byId.get(targetId);
while (current) {
path.unshift(current);
// Stop if no parent or self-referencing (root)
if (!current.parentId || current.parentId === current.id) {
break;
}
current = byId.get(current.parentId);
}
return path;
}
// Tree node lookup for finding leaves
let treeNodeMap = null;
/**
* Find the newest leaf node reachable from a given node.
* This allows clicking any node in a branch to show the full branch.
* Children are sorted by timestamp, so the newest is always last.
*/
function findNewestLeaf(nodeId) {
// Build tree node map lazily
if (!treeNodeMap) {
treeNodeMap = new Map();
const tree = buildTree();
function mapNodes(node) {
treeNodeMap.set(node.entry.id, node);
node.children.forEach(mapNodes);
}
tree.forEach(mapNodes);
}
const node = treeNodeMap.get(nodeId);
if (!node) return nodeId;
// Follow the newest (last) child at each level
let current = node;
while (current.children.length > 0) {
current = current.children[current.children.length - 1];
}
return current.entry.id;
}
/**
* Flatten tree into list with indentation and connector info.
* Returns array of { node, indent, showConnector, isLast, gutters, isVirtualRootChild, multipleRoots }.
* Matches tree-selector.ts logic exactly.
*/
function flattenTree(roots, activePathIds) {
const result = [];
const multipleRoots = roots.length > 1;
// Mark which subtrees contain the active leaf
const containsActive = new Map();
function markActive(node) {
let has = activePathIds.has(node.entry.id);
for (const child of node.children) {
if (markActive(child)) has = true;
}
containsActive.set(node, has);
return has;
}
roots.forEach(markActive);
// Stack: [node, indent, justBranched, showConnector, isLast, gutters, isVirtualRootChild]
const stack = [];
// Add roots (prioritize branch containing active leaf)
const orderedRoots = [...roots].sort((a, b) =>
Number(containsActive.get(b)) - Number(containsActive.get(a))
);
for (let i = orderedRoots.length - 1; i >= 0; i--) {
const isLast = i === orderedRoots.length - 1;
stack.push([orderedRoots[i], multipleRoots ? 1 : 0, multipleRoots, multipleRoots, isLast, [], multipleRoots]);
}
while (stack.length > 0) {
const [node, indent, justBranched, showConnector, isLast, gutters, isVirtualRootChild] = stack.pop();
result.push({ node, indent, showConnector, isLast, gutters, isVirtualRootChild, multipleRoots });
const children = node.children;
const multipleChildren = children.length > 1;
// Order children (active branch first)
const orderedChildren = [...children].sort((a, b) =>
Number(containsActive.get(b)) - Number(containsActive.get(a))
);
// Calculate child indent (matches tree-selector.ts)
let childIndent;
if (multipleChildren) {
// Parent branches: children get +1
childIndent = indent + 1;
} else if (justBranched && indent > 0) {
// First generation after a branch: +1 for visual grouping
childIndent = indent + 1;
} else {
// Single-child chain: stay flat
childIndent = indent;
}
// Build gutters for children
const connectorDisplayed = showConnector && !isVirtualRootChild;
const currentDisplayIndent = multipleRoots ? Math.max(0, indent - 1) : indent;
const connectorPosition = Math.max(0, currentDisplayIndent - 1);
const childGutters = connectorDisplayed
? [...gutters, { position: connectorPosition, show: !isLast }]
: gutters;
// Add children in reverse order for stack
for (let i = orderedChildren.length - 1; i >= 0; i--) {
const childIsLast = i === orderedChildren.length - 1;
stack.push([orderedChildren[i], childIndent, multipleChildren, multipleChildren, childIsLast, childGutters, false]);
}
}
return result;
}
/**
* Build ASCII prefix string for tree node.
*/
function buildTreePrefix(flatNode) {
const { indent, showConnector, isLast, gutters, isVirtualRootChild, multipleRoots } = flatNode;
const displayIndent = multipleRoots ? Math.max(0, indent - 1) : indent;
const connector = showConnector && !isVirtualRootChild ? (isLast ? '└─ ' : '├─ ') : '';
const connectorPosition = connector ? displayIndent - 1 : -1;
const totalChars = displayIndent * 3;
const prefixChars = [];
for (let i = 0; i < totalChars; i++) {
const level = Math.floor(i / 3);
const posInLevel = i % 3;
const gutter = gutters.find(g => g.position === level);
if (gutter) {
prefixChars.push(posInLevel === 0 ? (gutter.show ? '│' : ' ') : ' ');
} else if (connector && level === connectorPosition) {
if (posInLevel === 0) {
prefixChars.push(isLast ? '└' : '├');
} else if (posInLevel === 1) {
prefixChars.push('─');
} else {
prefixChars.push(' ');
}
} else {
prefixChars.push(' ');
}
}
return prefixChars.join('');
}
// ============================================================
// FILTERING (pure data)
// ============================================================
let filterMode = 'default';
let searchQuery = '';
function hasTextContent(content) {
if (typeof content === 'string') return content.trim().length > 0;
if (Array.isArray(content)) {
for (const c of content) {
if (c.type === 'text' && c.text && c.text.trim().length > 0) return true;
}
}
return false;
}
function extractContent(content) {
if (typeof content === 'string') return content;
if (Array.isArray(content)) {
return content
.filter(c => c.type === 'text' && c.text)
.map(c => c.text)
.join('');
}
return '';
}
/**
* Parse a skill block from message text.
* Returns null if the text doesn't contain a skill block.
* Matches the format: <skill name="..." location="...">\n...\n</skill>\n\nuser message
*/
function parseSkillBlock(text) {
const match = text.match(/^<skill name="([^"]+)" location="([^"]+)">\n([\s\S]*?)\n<\/skill>(?:\n\n([\s\S]+))?$/);
if (!match) return null;
return {
name: match[1],
location: match[2],
content: match[3],
userMessage: match[4]?.trim() || undefined,
};
}
function getSearchableText(entry, label) {
const parts = [];
if (label) parts.push(label);
switch (entry.type) {
case 'message': {
const msg = entry.message;
parts.push(msg.role);
if (msg.content) parts.push(extractContent(msg.content));
if (msg.role === 'bashExecution' && msg.command) parts.push(msg.command);
break;
}
case 'custom_message':
parts.push(entry.customType);
parts.push(typeof entry.content === 'string' ? entry.content : extractContent(entry.content));
break;
case 'compaction':
parts.push('compaction');
break;
case 'branch_summary':
parts.push('branch summary', entry.summary);
break;
case 'model_change':
parts.push('model', entry.modelId);
break;
case 'thinking_level_change':
parts.push('thinking', entry.thinkingLevel);
break;
}
return parts.join(' ').toLowerCase();
}
/**
* Filter flat nodes based on current filterMode and searchQuery.
*/
function filterNodes(flatNodes, currentLeafId) {
const searchTokens = searchQuery.toLowerCase().split(/\s+/).filter(Boolean);
const filtered = flatNodes.filter(flatNode => {
const entry = flatNode.node.entry;
const label = flatNode.node.label;
const isCurrentLeaf = entry.id === currentLeafId;
// Always show current leaf
if (isCurrentLeaf) return true;
// Hide assistant messages with only tool calls (no text) unless error/aborted
if (entry.type === 'message' && entry.message.role === 'assistant') {
const msg = entry.message;
const hasText = hasTextContent(msg.content);
const isErrorOrAborted = msg.stopReason && msg.stopReason !== 'stop' && msg.stopReason !== 'toolUse';
if (!hasText && !isErrorOrAborted) return false;
}
// Apply filter mode
const isSettingsEntry = ['label', 'custom', 'model_change', 'thinking_level_change'].includes(entry.type);
let passesFilter = true;
switch (filterMode) {
case 'user-only':
passesFilter = entry.type === 'message' && entry.message.role === 'user';
break;
case 'no-tools':
passesFilter = !isSettingsEntry && !(entry.type === 'message' && entry.message.role === 'toolResult');
break;
case 'labeled-only':
passesFilter = label !== undefined;
break;
case 'all':
passesFilter = true;
break;
default: // 'default'
passesFilter = !isSettingsEntry;
break;
}
if (!passesFilter) return false;
// Apply search filter
if (searchTokens.length > 0) {
const nodeText = getSearchableText(entry, label);
if (!searchTokens.every(t => nodeText.includes(t))) return false;
}
return true;
});
// Recalculate visual structure based on visible tree
recalculateVisualStructure(filtered, flatNodes);
return filtered;
}
/**
* Recompute indentation/connectors for the filtered view
*
* Filtering can hide intermediate entries; descendants attach to the nearest visible ancestor.
* Keep indentation semantics aligned with flattenTree() so single-child chains don't drift right.
*/
function recalculateVisualStructure(filteredNodes, allFlatNodes) {
if (filteredNodes.length === 0) return;
const visibleIds = new Set(filteredNodes.map(n => n.node.entry.id));
// Build entry map for parent lookup (using full tree)
const entryMap = new Map();
for (const flatNode of allFlatNodes) {
entryMap.set(flatNode.node.entry.id, flatNode);
}
// Find nearest visible ancestor for a node
function findVisibleAncestor(nodeId) {
let currentId = entryMap.get(nodeId)?.node.entry.parentId;
while (currentId != null) {
if (visibleIds.has(currentId)) {
return currentId;
}
currentId = entryMap.get(currentId)?.node.entry.parentId;
}
return null;
}
// Build visible tree structure
const visibleParent = new Map();
const visibleChildren = new Map();
visibleChildren.set(null, []); // root-level nodes
for (const flatNode of filteredNodes) {
const nodeId = flatNode.node.entry.id;
const ancestorId = findVisibleAncestor(nodeId);
visibleParent.set(nodeId, ancestorId);
if (!visibleChildren.has(ancestorId)) {
visibleChildren.set(ancestorId, []);
}
visibleChildren.get(ancestorId).push(nodeId);
}
// Update multipleRoots based on visible roots
const visibleRootIds = visibleChildren.get(null);
const multipleRoots = visibleRootIds.length > 1;
// Build a map for quick lookup: nodeId → FlatNode
const filteredNodeMap = new Map();
for (const flatNode of filteredNodes) {
filteredNodeMap.set(flatNode.node.entry.id, flatNode);
}
// DFS traversal of visible tree, applying same indentation rules as flattenTree()
// Stack items: [nodeId, indent, justBranched, showConnector, isLast, gutters, isVirtualRootChild]
const stack = [];
// Add visible roots in reverse order (to process in forward order via stack)
for (let i = visibleRootIds.length - 1; i >= 0; i--) {
const isLast = i === visibleRootIds.length - 1;
stack.push([
visibleRootIds[i],
multipleRoots ? 1 : 0,
multipleRoots,
multipleRoots,
isLast,
[],
multipleRoots
]);
}
while (stack.length > 0) {
const [nodeId, indent, justBranched, showConnector, isLast, gutters, isVirtualRootChild] = stack.pop();
const flatNode = filteredNodeMap.get(nodeId);
if (!flatNode) continue;
// Update this node's visual properties
flatNode.indent = indent;
flatNode.showConnector = showConnector;
flatNode.isLast = isLast;
flatNode.gutters = gutters;
flatNode.isVirtualRootChild = isVirtualRootChild;
flatNode.multipleRoots = multipleRoots;
// Get visible children of this node
const children = visibleChildren.get(nodeId) || [];
const multipleChildren = children.length > 1;
// Calculate child indent using same rules as flattenTree():
// - Parent branches (multiple children): children get +1
// - Just branched and indent > 0: children get +1 for visual grouping
// - Single-child chain: stay flat
let childIndent;
if (multipleChildren) {
childIndent = indent + 1;
} else if (justBranched && indent > 0) {
childIndent = indent + 1;
} else {
childIndent = indent;
}
// Build gutters for children (same logic as flattenTree)
const connectorDisplayed = showConnector && !isVirtualRootChild;
const currentDisplayIndent = multipleRoots ? Math.max(0, indent - 1) : indent;
const connectorPosition = Math.max(0, currentDisplayIndent - 1);
const childGutters = connectorDisplayed
? [...gutters, { position: connectorPosition, show: !isLast }]
: gutters;
// Add children in reverse order (to process in forward order via stack)
for (let i = children.length - 1; i >= 0; i--) {
const childIsLast = i === children.length - 1;
stack.push([
children[i],
childIndent,
multipleChildren,
multipleChildren,
childIsLast,
childGutters,
false
]);
}
}
}
// ============================================================
// TREE DISPLAY TEXT (pure data -> string)
// ============================================================
function shortenPath(p) {
if (typeof p !== 'string') return '';
if (p.startsWith('/Users/')) {
const parts = p.split('/');
if (parts.length > 2) return '~' + p.slice(('/Users/' + parts[2]).length);
}
if (p.startsWith('/home/')) {
const parts = p.split('/');
if (parts.length > 2) return '~' + p.slice(('/home/' + parts[2]).length);
}
return p;
}
function formatToolCall(name, args) {
switch (name) {
case 'read': {
const path = shortenPath(String(args.path || args.file_path || ''));
const offset = args.offset;
const limit = args.limit;
let display = path;
if (offset !== undefined || limit !== undefined) {
const start = offset ?? 1;
const end = limit !== undefined ? start + limit - 1 : '';
display += `:${start}${end ? `-${end}` : ''}`;
}
return `[read: ${display}]`;
}
case 'write':
return `[write: ${shortenPath(String(args.path || args.file_path || ''))}]`;
case 'edit':
return `[edit: ${shortenPath(String(args.path || args.file_path || ''))}]`;
case 'bash': {
const rawCmd = String(args.command || '');
const cmd = rawCmd.replace(/[\n\t]/g, ' ').trim().slice(0, 50);
return `[bash: ${cmd}${rawCmd.length > 50 ? '...' : ''}]`;
}
case 'grep':
return `[grep: /${args.pattern || ''}/ in ${shortenPath(String(args.path || '.'))}]`;
case 'find':
return `[find: ${args.pattern || ''} in ${shortenPath(String(args.path || '.'))}]`;
case 'ls':
return `[ls: ${shortenPath(String(args.path || '.'))}]`;
default: {
const argsStr = JSON.stringify(args).slice(0, 40);
return `[${name}: ${argsStr}${JSON.stringify(args).length > 40 ? '...' : ''}]`;
}
}
}
function escapeHtml(text) {
return String(text)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function sanitizeMarkdownUrl(value) {
const href = String(value || '').trim().replace(/[\x00-\x1f\x7f]/g, '');
if (!href) return href;
const scheme = href.match(/^([A-Za-z][A-Za-z0-9+.-]*):/);
if (scheme && !/^(https?|mailto|tel|ftp)$/i.test(scheme[1])) {
return null;
}
return href;
}
/**
* Truncate string to maxLen chars, append "..." if truncated.
*/
function truncate(s, maxLen = 100) {
if (s.length <= maxLen) return s;
return s.slice(0, maxLen) + '...';
}
/**
* Get display text for tree node (returns HTML string).
*/
function getTreeNodeDisplayHtml(entry, label) {
const normalize = s => s.replace(/[\n\t]/g, ' ').trim();
const labelHtml = label ? `<span class="tree-label">[${escapeHtml(label)}]</span> ` : '';
switch (entry.type) {
case 'message': {
const msg = entry.message;
if (msg.role === 'user') {
const rawContent = extractContent(msg.content);
const skillBlock = parseSkillBlock(rawContent);
if (skillBlock) {
let treeHtml = labelHtml + `<span class="tree-role-skill">skill:</span> ${escapeHtml(skillBlock.name)}`;
if (skillBlock.userMessage) {
treeHtml += ` · <span class="tree-role-user">user:</span> ${escapeHtml(truncate(normalize(skillBlock.userMessage)))}`;
}
return treeHtml;
}
const content = truncate(normalize(rawContent));
return labelHtml + `<span class="tree-role-user">user:</span> ${escapeHtml(content)}`;
}
if (msg.role === 'assistant') {
const textContent = truncate(normalize(extractContent(msg.content)));
if (textContent) {
return labelHtml + `<span class="tree-role-assistant">assistant:</span> ${escapeHtml(textContent)}`;
}
if (msg.stopReason === 'aborted') {
return labelHtml + `<span class="tree-role-assistant">assistant:</span> <span class="tree-muted">(aborted)</span>`;
}
if (msg.errorMessage) {
return labelHtml + `<span class="tree-role-assistant">assistant:</span> <span class="tree-error">${escapeHtml(truncate(msg.errorMessage))}</span>`;
}
return labelHtml + `<span class="tree-role-assistant">assistant:</span> <span class="tree-muted">(no text)</span>`;
}
if (msg.role === 'toolResult') {
const toolCall = msg.toolCallId ? toolCallMap.get(msg.toolCallId) : null;
if (toolCall) {
return labelHtml + `<span class="tree-role-tool">${escapeHtml(formatToolCall(toolCall.name, toolCall.arguments))}</span>`;
}
return labelHtml + `<span class="tree-role-tool">[${escapeHtml(msg.toolName || 'tool')}]</span>`;
}
if (msg.role === 'bashExecution') {
const cmd = truncate(normalize(msg.command || ''));
return labelHtml + `<span class="tree-role-tool">[bash]:</span> ${escapeHtml(cmd)}`;
}
return labelHtml + `<span class="tree-muted">[${escapeHtml(msg.role)}]</span>`;
}
case 'compaction':
return labelHtml + `<span class="tree-compaction">[compaction: ${Math.round(entry.tokensBefore/1000)}k tokens]</span>`;
case 'branch_summary': {
const summary = truncate(normalize(entry.summary || ''));
return labelHtml + `<span class="tree-branch-summary">[branch summary]:</span> ${escapeHtml(summary)}`;
}
case 'custom_message': {
const content = typeof entry.content === 'string' ? entry.content : extractContent(entry.content);
return labelHtml + `<span class="tree-custom">[${escapeHtml(entry.customType)}]:</span> ${escapeHtml(truncate(normalize(content)))}`;
}
case 'model_change':
return labelHtml + `<span class="tree-muted">[model: ${escapeHtml(entry.modelId)}]</span>`;
case 'thinking_level_change':
return labelHtml + `<span class="tree-muted">[thinking: ${escapeHtml(entry.thinkingLevel)}]</span>`;
default:
return labelHtml + `<span class="tree-muted">[${escapeHtml(entry.type)}]</span>`;
}
}
// ============================================================
// TREE RENDERING (DOM manipulation)
// ============================================================
let currentLeafId = leafId;
let currentTargetId = urlTargetId || leafId;
let treeRendered = false;
function renderTree() {
const tree = buildTree();
const activePathIds = buildActivePathIds(currentLeafId);
const flatNodes = flattenTree(tree, activePathIds);
const filtered = filterNodes(flatNodes, currentLeafId);
const container = document.getElementById('tree-container');
// Full render only on first call or when filter/search changes
if (!treeRendered) {
container.innerHTML = '';
for (const flatNode of filtered) {
const entry = flatNode.node.entry;
const isOnPath = activePathIds.has(entry.id);
const isTarget = entry.id === currentTargetId;
const div = document.createElement('div');
div.className = 'tree-node';
if (isOnPath) div.classList.add('in-path');
if (isTarget) div.classList.add('active');
div.dataset.id = entry.id;
const prefix = buildTreePrefix(flatNode);
const prefixSpan = document.createElement('span');
prefixSpan.className = 'tree-prefix';
prefixSpan.textContent = prefix;
const marker = document.createElement('span');
marker.className = 'tree-marker';
marker.textContent = isOnPath ? '•' : ' ';
const content = document.createElement('span');
content.className = 'tree-content';
content.innerHTML = getTreeNodeDisplayHtml(entry, flatNode.node.label);
div.appendChild(prefixSpan);
div.appendChild(marker);
div.appendChild(content);
// Navigate to the newest leaf through this node, but scroll to the clicked node
div.addEventListener('click', () => {
if (window.getSelection().toString()) return;
const leafId = findNewestLeaf(entry.id);
navigateTo(leafId, 'target', entry.id);
});
container.appendChild(div);
}
treeRendered = true;
} else {
// Just update markers and classes
const nodes = container.querySelectorAll('.tree-node');
for (const node of nodes) {
const id = node.dataset.id;
const isOnPath = activePathIds.has(id);
const isTarget = id === currentTargetId;
node.classList.toggle('in-path', isOnPath);
node.classList.toggle('active', isTarget);
const marker = node.querySelector('.tree-marker');
if (marker) {
marker.textContent = isOnPath ? '•' : ' ';
}
}
}
document.getElementById('tree-status').textContent = `${filtered.length} / ${flatNodes.length} entries`;
// Scroll active node into view after layout
setTimeout(() => {
const activeNode = container.querySelector('.tree-node.active');
if (activeNode) {
activeNode.scrollIntoView({ block: 'nearest' });
}
}, 0);
}
function forceTreeRerender() {
treeRendered = false;
renderTree();
}
// ============================================================
// MESSAGE RENDERING
// ============================================================
function formatTokens(count) {
if (count < 1000) return count.toString();
if (count < 10000) return (count / 1000).toFixed(1) + 'k';
if (count < 1000000) return Math.round(count / 1000) + 'k';
return (count / 1000000).toFixed(1) + 'M';
}
function formatTimestamp(ts) {
if (!ts) return '';
const date = new Date(ts);
return date.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' });
}
function replaceTabs(text) {
return text.replace(/\t/g, ' ');
}
/** Safely coerce value to string for display. Returns null if invalid type. */
function str(value) {
if (typeof value === 'string') return value;
if (value == null) return '';
return null;
}
function getLanguageFromPath(filePath) {
const ext = filePath.split('.').pop()?.toLowerCase();
const extToLang = {
ts: 'typescript', tsx: 'typescript', js: 'javascript', jsx: 'javascript',
py: 'python', rb: 'ruby', rs: 'rust', go: 'go', java: 'java',
c: 'c', cpp: 'cpp', h: 'c', hpp: 'cpp', cs: 'csharp',
php: 'php', sh: 'bash', bash: 'bash', zsh: 'bash',
sql: 'sql', html: 'html', css: 'css', scss: 'scss',
json: 'json', yaml: 'yaml', yml: 'yaml', xml: 'xml',
md: 'markdown', dockerfile: 'dockerfile'
};
return extToLang[ext];
}
function findToolResult(toolCallId) {
for (const entry of entries) {
if (entry.type === 'message' && entry.message.role === 'toolResult') {
if (entry.message.toolCallId === toolCallId) {
return entry.message;
}
}
}
return null;
}
function formatExpandableOutput(text, maxLines, lang) {
text = replaceTabs(text);
const lines = text.split('\n');
const displayLines = lines.slice(0, maxLines);
const remaining = lines.length - maxLines;
if (lang) {
let highlighted;
try {
highlighted = hljs.highlight(text, { language: lang }).value;
} catch {
highlighted = escapeHtml(text);
}
if (remaining > 0) {
const previewCode = displayLines.join('\n');
let previewHighlighted;
try {
previewHighlighted = hljs.highlight(previewCode, { language: lang }).value;
} catch {
previewHighlighted = escapeHtml(previewCode);
}
return `<div class="tool-output expandable" onclick="if(window.getSelection().toString())return;this.classList.toggle('expanded')">
<div class="output-preview"><pre><code class="hljs">${previewHighlighted}</code></pre>
<div class="expand-hint">... (${remaining} more lines)</div></div>
<div class="output-full"><pre><code class="hljs">${highlighted}</code></pre></div></div>`;
}
return `<div class="tool-output"><pre><code class="hljs">${highlighted}</code></pre></div>`;
}
// Plain text output
if (remaining > 0) {
let out = '<div class="tool-output expandable" onclick="if(window.getSelection().toString())return;this.classList.toggle(\'expanded\')">';
out += '<div class="output-preview">';
for (const line of displayLines) {
out += `<div>${escapeHtml(replaceTabs(line))}</div>`;
}
out += `<div class="expand-hint">... (${remaining} more lines)</div></div>`;
out += '<div class="output-full">';
for (const line of lines) {
out += `<div>${escapeHtml(replaceTabs(line))}</div>`;
}
out += '</div></div>';
return out;
}
let out = '<div class="tool-output">';
for (const line of displayLines) {
out += `<div>${escapeHtml(replaceTabs(line))}</div>`;
}
out += '</div>';
return out;
}
function renderToolCall(call) {
const result = findToolResult(call.id);
const isError = result?.isError || false;
const statusClass = result ? (isError ? 'error' : 'success') : 'pending';
const getResultText = () => {
if (!result) return '';
const textBlocks = result.content.filter(c => c.type === 'text');
return textBlocks.map(c => c.text).join('\n');
};
const getResultImages = () => {
if (!result) return [];
return result.content.filter(c => c.type === 'image');
};
const renderResultImages = () => {
const images = getResultImages();
if (images.length === 0) return '';
return '<div class="tool-images">' +
images.map(img => `<img src="data:${escapeHtml(img.mimeType || 'image/png')};base64,${escapeHtml(img.data || '')}" class="tool-image" />`).join('') +
'</div>';
};
const toolDomId = `tool-call-${escapeHtml(call.id)}`;
let html = `<div class="tool-execution ${statusClass}" id="${toolDomId}">`;
const args = call.arguments || {};
const name = call.name;
const invalidArg = '<span class="tool-error">[invalid arg]</span>';
switch (name) {
case 'bash': {
const command = str(args.command);
const cmdDisplay = command === null ? invalidArg : escapeHtml(command || '...');
html += `<div class="tool-command">$ ${cmdDisplay}</div>`;
if (result) {
const output = getResultText().trim();
if (output) html += formatExpandableOutput(output, 5);
}
break;
}
case 'read': {
const filePath = str(args.file_path ?? args.path);
const offset = args.offset;
const limit = args.limit;
let pathHtml = filePath === null ? invalidArg : escapeHtml(shortenPath(filePath || ''));
if (filePath !== null && (offset !== undefined || limit !== undefined)) {
const startLine = offset ?? 1;
const endLine = limit !== undefined ? startLine + limit - 1 : '';
pathHtml += `<span class="line-numbers">:${startLine}${endLine ? '-' + endLine : ''}</span>`;
}
html += `<div class="tool-header"><span class="tool-name">read</span> <span class="tool-path">${pathHtml}</span></div>`;
if (result) {
html += renderResultImages();
const output = getResultText();
const lang = filePath ? getLanguageFromPath(filePath) : null;
if (output) html += formatExpandableOutput(output, 10, lang);
}
break;
}
case 'write': {
const filePath = str(args.file_path ?? args.path);
const content = str(args.content);
html += `<div class="tool-header"><span class="tool-name">write</span> <span class="tool-path">${filePath === null ? invalidArg : escapeHtml(shortenPath(filePath || ''))}</span>`;
if (content !== null && content) {
const lines = content.split('\n');
if (lines.length > 10) html += ` <span class="line-count">(${lines.length} lines)</span>`;
}
html += '</div>';
if (content === null) {
html += `<div class="tool-error">[invalid content arg - expected string]</div>`;
} else if (content) {
const lang = filePath ? getLanguageFromPath(filePath) : null;
html += formatExpandableOutput(content, 10, lang);
}
if (result) {
const output = getResultText().trim();
if (output) html += `<div class="tool-output"><div>${escapeHtml(output)}</div></div>`;
}
break;
}
case 'edit': {
const filePath = str(args.file_path ?? args.path);
html += `<div class="tool-header"><span class="tool-name">edit</span> <span class="tool-path">${filePath === null ? invalidArg : escapeHtml(shortenPath(filePath || ''))}</span></div>`;
if (result?.details?.diff) {
const diffLines = result.details.diff.split('\n');
html += '<div class="tool-diff">';
for (const line of diffLines) {
const cls = line.match(/^\+/) ? 'diff-added' : line.match(/^-/) ? 'diff-removed' : 'diff-context';
html += `<div class="${cls}">${escapeHtml(replaceTabs(line))}</div>`;
}
html += '</div>';
} else if (result) {
const output = getResultText().trim();
if (output) html += `<div class="tool-output"><pre>${escapeHtml(output)}</pre></div>`;
}
break;
}
case 'ls': {
const dirPath = str(args.path);
const limit = args.limit;
let pathHtml = dirPath === null ? invalidArg : escapeHtml(shortenPath(dirPath || '.'));
if (limit !== undefined) {
pathHtml += ` <span class="line-count">(limit ${escapeHtml(String(limit))})</span>`;
}
html += `<div class="tool-header"><span class="tool-name">ls</span> <span class="tool-path">${pathHtml}</span></div>`;
if (result) {
const output = getResultText().trim();
if (output) html += formatExpandableOutput(output, 20);
}
break;
}
default: {
// Check for pre-rendered custom tool HTML
const rendered = renderedTools?.[call.id];
if (rendered?.callHtml || rendered?.resultHtmlCollapsed || rendered?.resultHtmlExpanded) {
// Custom tool with pre-rendered HTML from TUI renderer
if (rendered.callHtml) {
html += `<div class="tool-header ansi-rendered">${rendered.callHtml}</div>`;
} else {
html += `<div class="tool-header"><span class="tool-name">${escapeHtml(name)}</span></div>`;
}
if (rendered.resultHtmlCollapsed && rendered.resultHtmlExpanded && rendered.resultHtmlCollapsed !== rendered.resultHtmlExpanded) {
// Both collapsed and expanded differ - render expandable section
html += `<div class="tool-output expandable ansi-rendered" onclick="if(window.getSelection().toString())return;this.classList.toggle('expanded')">
<div class="output-preview">${rendered.resultHtmlCollapsed}</div>
<div class="output-full">${rendered.resultHtmlExpanded}</div>
</div>`;
} else if (rendered.resultHtmlExpanded) {
// Only expanded exists (or collapsed is identical) - show directly
html += `<div class="tool-output ansi-rendered">${rendered.resultHtmlExpanded}</div>`;
} else if (result) {
// No pre-rendered result HTML - fallback to JSON
const output = getResultText();
if (output) html += formatExpandableOutput(output, 10);
}
} else {
// Fallback to JSON display (existing behavior)
html += `<div class="tool-header"><span class="tool-name">${escapeHtml(name)}</span></div>`;
html += `<div class="tool-output"><pre>${escapeHtml(JSON.stringify(args, null, 2))}</pre></div>`;
if (result) {
const output = getResultText();
if (output) html += formatExpandableOutput(output, 10);
}
}
}
}
html += '</div>';
return html;
}
/**
* Download the session data as a JSONL file.
* Reconstructs the original format: header line + entry lines.
*/
window.downloadSessionJson = function() {
// Build JSONL content: header first, then all entries
const lines = [];
if (header) {
lines.push(JSON.stringify({ type: 'header', ...header }));
}
for (const entry of entries) {
lines.push(JSON.stringify(entry));
}
const jsonlContent = lines.join('\n');
// Create download
const blob = new Blob([jsonlContent], { type: 'application/x-ndjson' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${header?.id || 'session'}.jsonl`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
/**
* Build a shareable URL for a specific message.
* URL format: base?gistId&leafId=<leafId>&targetId=<entryId>
*/
function buildShareUrl(entryId) {
// Check for injected base URL (used when loaded in iframe via srcdoc)
const baseUrlMeta = document.querySelector('meta[name="pi-share-base-url"]');
const baseUrl = baseUrlMeta ? baseUrlMeta.content : window.location.href.split('?')[0];
const url = new URL(window.location.href);
// Find the gist ID (first query param without value, e.g., ?abc123)
const gistId = Array.from(url.searchParams.keys()).find(k => !url.searchParams.get(k));
// Build the share URL
const params = new URLSearchParams();
params.set('leafId', currentLeafId);
params.set('targetId', entryId);
// If we have an injected base URL (iframe context), use it directly
if (baseUrlMeta) {
return `${baseUrl}&${params.toString()}`;
}
// Otherwise build from current location (direct file access)
url.search = gistId ? `?${gistId}&${params.toString()}` : `?${params.toString()}`;
return url.toString();
}
/**
* Copy text to clipboard with visual feedback.
* Uses navigator.clipboard with fallback to execCommand for HTTP contexts.
*/
async function copyToClipboard(text, button) {
let success = false;
try {
if (navigator.clipboard && navigator.clipboard.writeText) {
await navigator.clipboard.writeText(text);
success = true;
}
} catch (err) {
// Clipboard API failed, try fallback
}
// Fallback for HTTP or when Clipboard API is unavailable
if (!success) {
try {
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed';
textarea.style.opacity = '0';
document.body.appendChild(textarea);
textarea.select();
success = document.execCommand('copy');
document.body.removeChild(textarea);
} catch (err) {
console.error('Failed to copy:', err);
}
}
if (success && button) {
const originalHtml = button.innerHTML;
button.innerHTML = '✓';
button.classList.add('copied');
setTimeout(() => {
button.innerHTML = originalHtml;
button.classList.remove('copied');
}, 1500);
}
}
/**
* Render the copy-link button HTML for a message.
*/
function renderCopyLinkButton(entryId) {
return `<button class="copy-link-btn" data-entry-id="${escapeHtml(entryId)}" title="Copy link to this message">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/>
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>
</svg>
</button>`;
}
function renderEntry(entry) {
const ts = formatTimestamp(entry.timestamp);
const tsHtml = ts ? `<div class="message-timestamp">${ts}</div>` : '';
const entryDomId = `entry-${escapeHtml(entry.id)}`;
const copyBtnHtml = renderCopyLinkButton(entry.id);
if (entry.type === 'message') {
const msg = entry.message;
if (msg.role === 'user') {
const content = msg.content;
const text = typeof content === 'string' ? content :
content.filter(c => c.type === 'text').map(c => c.text).join('\n');
const skillBlock = parseSkillBlock(text);
if (skillBlock) {
// Collect images from content array
const images = Array.isArray(content) ? content.filter(c => c.type === 'image') : [];
const hasUserContent = skillBlock.userMessage || images.length > 0;
let html = `<div class="skill-user-entry" id="${entryDomId}">${copyBtnHtml}${tsHtml}`;
// Skill invocation (collapsed by default, click to expand)
html += `<div class="skill-invocation" onclick="if(window.getSelection().toString())return;this.classList.toggle('expanded')">
<div class="skill-invocation-label">[skill] ${escapeHtml(skillBlock.name)}</div>
<div class="skill-invocation-collapsed">${escapeHtml(skillBlock.name)} (click to expand)</div>
<div class="skill-invocation-content markdown-content">${safeMarkedParse(skillBlock.content)}</div>
</div>`;
// User message (separate block if present)
if (hasUserContent) {
html += '<div class="user-message">';
if (images.length > 0) {
html += '<div class="message-images">';
for (const img of images) {
html += `<img src="data:${escapeHtml(img.mimeType || 'image/png')};base64,${escapeHtml(img.data || '')}" class="message-image" />`;
}
html += '</div>';
}
if (skillBlock.userMessage) {
html += `<div class="markdown-content">${safeMarkedParse(skillBlock.userMessage)}</div>`;
}
html += '</div>';
}
html += '</div>';
return html;
}
// No skill block - normal user message
let html = `<div class="user-message" id="${entryDomId}">${copyBtnHtml}${tsHtml}`;
if (Array.isArray(content)) {
const images = content.filter(c => c.type === 'image');
if (images.length > 0) {
html += '<div class="message-images">';
for (const img of images) {
html += `<img src="data:${escapeHtml(img.mimeType || 'image/png')};base64,${escapeHtml(img.data || '')}" class="message-image" />`;
}
html += '</div>';
}
}
if (text.trim()) {
html += `<div class="markdown-content">${safeMarkedParse(text)}</div>`;
}
html += '</div>';
return html;
}
if (msg.role === 'assistant') {
let html = `<div class="assistant-message" id="${entryDomId}">${copyBtnHtml}${tsHtml}`;
for (const block of msg.content) {
if (block.type === 'text' && block.text.trim()) {
html += `<div class="assistant-text markdown-content">${safeMarkedParse(block.text)}</div>`;
} else if (block.type === 'thinking' && block.thinking.trim()) {
html += `<div class="thinking-block">
<div class="thinking-text">${escapeHtml(block.thinking)}</div>
<div class="thinking-collapsed">Thinking ...</div>
</div>`;
}
}
for (const block of msg.content) {
if (block.type === 'toolCall') {
html += renderToolCall(block);
}
}
if (msg.stopReason === 'aborted') {
html += '<div class="error-text">Aborted</div>';
} else if (msg.stopReason === 'error') {
html += `<div class="error-text">Error: ${escapeHtml(msg.errorMessage || 'Unknown error')}</div>`;
}
html += '</div>';
return html;
}
if (msg.role === 'bashExecution') {
const isError = msg.cancelled || (msg.exitCode !== 0 && msg.exitCode !== null);
let html = `<div class="tool-execution ${isError ? 'error' : 'success'}" id="${entryDomId}">${tsHtml}`;
html += `<div class="tool-command">$ ${escapeHtml(msg.command)}</div>`;
if (msg.output) html += formatExpandableOutput(msg.output, 10);
if (msg.cancelled) {
html += '<div style="color: var(--warning)">(cancelled)</div>';
} else if (msg.exitCode !== 0 && msg.exitCode !== null) {
html += `<div style="color: var(--error)">(exit ${msg.exitCode})</div>`;
}
html += '</div>';
return html;
}
if (msg.role === 'toolResult') return '';
}
if (entry.type === 'model_change') {
return `<div class="model-change" id="${entryDomId}">${tsHtml}Switched to model: <span class="model-name">${escapeHtml(entry.provider)}/${escapeHtml(entry.modelId)}</span></div>`;
}
if (entry.type === 'compaction') {
return `<div class="compaction" id="${entryDomId}" onclick="if(window.getSelection().toString())return;this.classList.toggle('expanded')">
<div class="compaction-label">[compaction]</div>
<div class="compaction-collapsed">Compacted from ${entry.tokensBefore.toLocaleString()} tokens</div>
<div class="compaction-content"><strong>Compacted from ${entry.tokensBefore.toLocaleString()} tokens</strong>\n\n${escapeHtml(entry.summary)}</div>
</div>`;
}
if (entry.type === 'branch_summary') {
return `<div class="branch-summary" id="${entryDomId}">${tsHtml}
<div class="branch-summary-header">Branch Summary</div>
<div class="markdown-content">${safeMarkedParse(entry.summary)}</div>
</div>`;
}
if (entry.type === 'custom_message' && entry.display) {
return `<div class="hook-message" id="${entryDomId}">${tsHtml}
<div class="hook-type">[${escapeHtml(entry.customType)}]</div>
<div class="markdown-content">${safeMarkedParse(typeof entry.content === 'string' ? entry.content : JSON.stringify(entry.content))}</div>
</div>`;
}
return '';
}
// ============================================================
// HEADER / STATS
// ============================================================
function computeStats(entryList) {
let userMessages = 0, assistantMessages = 0, toolResults = 0;
let customMessages = 0, compactions = 0, branchSummaries = 0, toolCalls = 0;
const tokens = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
const cost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
const models = new Set();
for (const entry of entryList) {
if (entry.type === 'message') {
const msg = entry.message;
if (msg.role === 'user') userMessages++;
if (msg.role === 'assistant') {
assistantMessages++;
if (msg.model) models.add(msg.provider ? `${msg.provider}/${msg.model}` : msg.model);
if (msg.usage) {
tokens.input += msg.usage.input || 0;
tokens.output += msg.usage.output || 0;
tokens.cacheRead += msg.usage.cacheRead || 0;
tokens.cacheWrite += msg.usage.cacheWrite || 0;
if (msg.usage.cost) {
cost.input += msg.usage.cost.input || 0;
cost.output += msg.usage.cost.output || 0;
cost.cacheRead += msg.usage.cost.cacheRead || 0;
cost.cacheWrite += msg.usage.cost.cacheWrite || 0;
}
}
toolCalls += msg.content.filter(c => c.type === 'toolCall').length;
}
if (msg.role === 'toolResult') toolResults++;
} else if (entry.type === 'compaction') {
compactions++;
} else if (entry.type === 'branch_summary') {
branchSummaries++;
} else if (entry.type === 'custom_message') {
customMessages++;
}
}
return { userMessages, assistantMessages, toolResults, customMessages, compactions, branchSummaries, toolCalls, tokens, cost, models: Array.from(models) };
}
const globalStats = computeStats(entries);
function renderHeader() {
const totalCost = globalStats.cost.input + globalStats.cost.output + globalStats.cost.cacheRead + globalStats.cost.cacheWrite;
const tokenParts = [];
if (globalStats.tokens.input) tokenParts.push(`${formatTokens(globalStats.tokens.input)}`);
if (globalStats.tokens.output) tokenParts.push(`${formatTokens(globalStats.tokens.output)}`);
if (globalStats.tokens.cacheRead) tokenParts.push(`R${formatTokens(globalStats.tokens.cacheRead)}`);
if (globalStats.tokens.cacheWrite) tokenParts.push(`W${formatTokens(globalStats.tokens.cacheWrite)}`);
const msgParts = [];
if (globalStats.userMessages) msgParts.push(`${globalStats.userMessages} user`);
if (globalStats.assistantMessages) msgParts.push(`${globalStats.assistantMessages} assistant`);
if (globalStats.toolResults) msgParts.push(`${globalStats.toolResults} tool results`);
if (globalStats.customMessages) msgParts.push(`${globalStats.customMessages} custom`);
if (globalStats.compactions) msgParts.push(`${globalStats.compactions} compactions`);
if (globalStats.branchSummaries) msgParts.push(`${globalStats.branchSummaries} branch summaries`);
let html = `
<div class="header">
<h1>Session: ${escapeHtml(header?.id || 'unknown')}</h1>
<div class="help-bar">
<span class="help-hint">T toggle thinking · O toggle tools</span>
<div class="help-actions">
<button type="button" class="header-toggle-btn" data-action="toggle-thinking" title="Toggle thinking (T)">Toggle thinking</button>
<button type="button" class="header-toggle-btn" data-action="toggle-tools" title="Toggle tools (O)">Toggle tools</button>
<button type="button" class="download-json-btn" onclick="downloadSessionJson()" title="Download session as JSONL">↓ JSONL</button>
</div>
</div>
<div class="header-info">
<div class="info-item"><span class="info-label">Date:</span><span class="info-value">${header?.timestamp ? new Date(header.timestamp).toLocaleString() : 'unknown'}</span></div>
<div class="info-item"><span class="info-label">Models:</span><span class="info-value">${escapeHtml(globalStats.models.join(', ') || 'unknown')}</span></div>
<div class="info-item"><span class="info-label">Messages:</span><span class="info-value">${msgParts.join(', ') || '0'}</span></div>
<div class="info-item"><span class="info-label">Tool Calls:</span><span class="info-value">${globalStats.toolCalls}</span></div>
<div class="info-item"><span class="info-label">Tokens:</span><span class="info-value">${tokenParts.join(' ') || '0'}</span></div>
<div class="info-item"><span class="info-label">Cost:</span><span class="info-value">${totalCost.toFixed(3)}</span></div>
</div>
</div>`;
// Render system prompt (user's base prompt, applies to all providers)
if (systemPrompt) {
const lines = systemPrompt.split('\n');
const previewLines = 10;
if (lines.length > previewLines) {
const preview = lines.slice(0, previewLines).join('\n');
const remaining = lines.length - previewLines;
html += `<div class="system-prompt expandable" onclick="if(window.getSelection().toString())return;this.classList.toggle('expanded')">
<div class="system-prompt-header">System Prompt</div>
<div class="system-prompt-preview">${escapeHtml(preview)}</div>
<div class="system-prompt-expand-hint">... (${remaining} more lines, click to expand)</div>
<div class="system-prompt-full">${escapeHtml(systemPrompt)}</div>
</div>`;
} else {
html += `<div class="system-prompt">
<div class="system-prompt-header">System Prompt</div>
<div class="system-prompt-full" style="display: block">${escapeHtml(systemPrompt)}</div>
</div>`;
}
}
if (tools && tools.length > 0) {
html += `<div class="tools-list">
<div class="tools-header">Available Tools</div>
<div class="tools-content">
${tools.map(t => {
const hasParams = t.parameters && typeof t.parameters === 'object' && t.parameters.properties && Object.keys(t.parameters.properties).length > 0;
if (!hasParams) {
return `<div class="tool-item"><span class="tool-item-name">${escapeHtml(t.name)}</span> - <span class="tool-item-desc">${escapeHtml(t.description)}</span></div>`;
}
const params = t.parameters;
const properties = params.properties;
const required = params.required || [];
let paramsHtml = '';
for (const [name, prop] of Object.entries(properties)) {
const isRequired = required.includes(name);
const typeStr = prop.type || 'any';
const reqLabel = isRequired ? '<span class="tool-param-required">required</span>' : '<span class="tool-param-optional">optional</span>';
paramsHtml += `<div class="tool-param"><span class="tool-param-name">${escapeHtml(name)}</span> <span class="tool-param-type">${escapeHtml(typeStr)}</span> ${reqLabel}`;
if (prop.description) {
paramsHtml += `<div class="tool-param-desc">${escapeHtml(prop.description)}</div>`;
}
paramsHtml += `</div>`;
}
return `<div class="tool-item" onclick="if(window.getSelection().toString())return;this.classList.toggle('params-expanded')"><span class="tool-item-name">${escapeHtml(t.name)}</span> - <span class="tool-item-desc">${escapeHtml(t.description)}</span> <span class="tool-params-hint"></span><div class="tool-params-content">${paramsHtml}</div></div>`;
}).join('')}
</div>
</div>`;
}
return html;
}
// ============================================================
// NAVIGATION
// ============================================================
// Cache for rendered entry DOM nodes
const entryCache = new Map();
function getScrollTargetElementId(entryId) {
const entry = byId.get(entryId);
if (entry?.type === 'message' && entry.message.role === 'toolResult' && entry.message.toolCallId) {
// getElementById() matches the parsed DOM id attribute, whose HTML entities
// were already resolved from the escaped id rendered by renderToolCall().
return `tool-call-${entry.message.toolCallId}`;
}
return `entry-${entryId}`;
}
function renderEntryToNode(entry) {
// Check cache first
if (entryCache.has(entry.id)) {
return entryCache.get(entry.id).cloneNode(true);
}
// Render to HTML string, then parse to node
const html = renderEntry(entry);
if (!html) return null;
const template = document.createElement('template');
template.innerHTML = html;
const node = template.content.firstElementChild;
// Cache the node
if (node) {
entryCache.set(entry.id, node.cloneNode(true));
}
return node;
}
function navigateTo(targetId, scrollMode = 'target', scrollToEntryId = null) {
currentLeafId = targetId;
currentTargetId = scrollToEntryId || targetId;
const path = getPath(targetId);
renderTree();
document.getElementById('header-container').innerHTML = renderHeader();
attachHeaderHandlers();
// Build messages using cached DOM nodes
const messagesEl = document.getElementById('messages');
const fragment = document.createDocumentFragment();
for (const entry of path) {
const node = renderEntryToNode(entry);
if (node) {
fragment.appendChild(node);
}
}
messagesEl.innerHTML = '';
messagesEl.appendChild(fragment);
// Attach click handlers for copy-link buttons
messagesEl.querySelectorAll('.copy-link-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
const entryId = btn.dataset.entryId;
const shareUrl = buildShareUrl(entryId);
copyToClipboard(shareUrl, btn);
});
});
// Use setTimeout(0) to ensure DOM is fully laid out before scrolling
setTimeout(() => {
const content = document.getElementById('content');
if (scrollMode === 'bottom') {
content.scrollTop = content.scrollHeight;
} else if (scrollMode === 'target') {
// If scrollToEntryId is provided, scroll to that specific entry.
// Tool result entries are rendered inside their assistant tool-call block,
// so route them to the visible tool-call element instead.
const scrollTargetId = scrollToEntryId || targetId;
const targetEl = document.getElementById(getScrollTargetElementId(scrollTargetId)) ||
document.getElementById(`entry-${scrollTargetId}`);
if (targetEl) {
targetEl.scrollIntoView({ block: 'center' });
// Briefly highlight the target message
if (scrollToEntryId) {
targetEl.classList.add('highlight');
setTimeout(() => targetEl.classList.remove('highlight'), 2000);
}
}
}
}, 0);
}
// ============================================================
// INITIALIZATION
// ============================================================
// Configure marked with syntax highlighting and TUI-compatible HTML handling
const strictStrikethroughRegex = /^(~~)(?=[^\s~])((?:\\.|[^\\])*?(?:\\.|[^\s~\\]))\1(?=[^~]|$)/;
marked.use({
breaks: true,
gfm: true,
tokenizer: {
// Treat HTML-like input as plain text so tags are shown verbatim,
// matching the TUI markdown renderer.
html() {
return undefined;
},
tag() {
return undefined;
},
del(src) {
const match = strictStrikethroughRegex.exec(src);
if (!match) return undefined;
return {
type: 'del',
raw: match[0],
text: match[2],
tokens: this.lexer.inlineTokens(match[2])
};
}
},
renderer: {
// Sanitize link URLs with a scheme allow-list. Browsers strip C0
// controls from schemes, so strip them before checking and emitting.
link(token) {
const href = sanitizeMarkdownUrl(token.href);
if (href === null) {
return this.parser.parseInline(token.tokens);
}
let out = '<a href="' + escapeHtml(href) + '"';
if (token.title) {
out += ' title="' + escapeHtml(token.title) + '"';
}
out += '>' + this.parser.parseInline(token.tokens) + '</a>';
return out;
},
// Sanitize image src URLs with the same scheme allow-list.
image(token) {
const href = sanitizeMarkdownUrl(token.href);
if (href === null) {
return escapeHtml(token.text || '');
}
let out = '<img src="' + escapeHtml(href) + '" alt="' + escapeHtml(token.text || '') + '"';
if (token.title) {
out += ' title="' + escapeHtml(token.title) + '"';
}
out += '>';
return out;
},
// Code blocks: syntax highlight, no HTML escaping
code(token) {
const code = token.text;
const lang = token.lang;
let highlighted;
if (lang && hljs.getLanguage(lang)) {
try {
highlighted = hljs.highlight(code, { language: lang }).value;
} catch {
highlighted = escapeHtml(code);
}
} else {
// Auto-detect language if not specified
try {
highlighted = hljs.highlightAuto(code).value;
} catch {
highlighted = escapeHtml(code);
}
}
return `<pre><code class="hljs">${highlighted}</code></pre>`;
},
// Inline code: escape HTML
codespan(token) {
return `<code>${escapeHtml(token.text)}</code>`;
}
}
});
// Simple marked parse (escaping handled in renderers)
function safeMarkedParse(text) {
return marked.parse(text);
}
// Search input
const searchInput = document.getElementById('tree-search');
searchInput.addEventListener('input', (e) => {
searchQuery = e.target.value;
forceTreeRerender();
});
// Filter buttons
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
filterMode = btn.dataset.filter;
forceTreeRerender();
});
});
// Sidebar toggle
const sidebar = document.getElementById('sidebar');
const overlay = document.getElementById('sidebar-overlay');
const hamburger = document.getElementById('hamburger');
const sidebarResizer = document.getElementById('sidebar-resizer');
const SIDEBAR_WIDTH_STORAGE_KEY = 'pi-share:v1:sidebar-width';
const MIN_CONTENT_WIDTH = 320;
function isMobileLayout() {
return window.matchMedia('(max-width: 900px)').matches;
}
function getSidebarBounds() {
const rootStyles = getComputedStyle(document.documentElement);
const minWidth = parseFloat(rootStyles.getPropertyValue('--sidebar-min-width')) || 240;
const maxWidth = parseFloat(rootStyles.getPropertyValue('--sidebar-max-width')) || 720;
const viewportMaxWidth = window.innerWidth - MIN_CONTENT_WIDTH;
return {
minWidth,
maxWidth: Math.max(minWidth, Math.min(maxWidth, viewportMaxWidth))
};
}
function clampSidebarWidth(width) {
const { minWidth, maxWidth } = getSidebarBounds();
return Math.max(minWidth, Math.min(maxWidth, width));
}
function applySidebarWidth(width) {
document.documentElement.style.setProperty('--sidebar-width', `${Math.round(clampSidebarWidth(width))}px`);
}
function loadSidebarWidth() {
try {
const raw = localStorage.getItem(SIDEBAR_WIDTH_STORAGE_KEY);
if (raw === null) return null;
const width = Number(raw);
return Number.isFinite(width) ? width : null;
} catch {
return null;
}
}
function saveSidebarWidth(width) {
try {
localStorage.setItem(SIDEBAR_WIDTH_STORAGE_KEY, String(Math.round(clampSidebarWidth(width))));
} catch {
// Ignore storage failures (e.g. private browsing restrictions)
}
}
function setupSidebarResize() {
const savedWidth = loadSidebarWidth();
if (savedWidth !== null) {
applySidebarWidth(savedWidth);
}
if (!sidebarResizer) return;
let cleanupDrag = null;
const stopDrag = (pointerId) => {
if (cleanupDrag) {
cleanupDrag(pointerId);
cleanupDrag = null;
}
};
sidebarResizer.addEventListener('pointerdown', (e) => {
if (isMobileLayout()) return;
e.preventDefault();
const startX = e.clientX;
const startWidth = sidebar.getBoundingClientRect().width;
document.body.classList.add('sidebar-resizing');
sidebarResizer.setPointerCapture?.(e.pointerId);
const onPointerMove = (event) => {
applySidebarWidth(startWidth + (event.clientX - startX));
};
cleanupDrag = (pointerIdToRelease) => {
document.body.classList.remove('sidebar-resizing');
sidebarResizer.releasePointerCapture?.(pointerIdToRelease);
window.removeEventListener('pointermove', onPointerMove);
window.removeEventListener('pointerup', onPointerUp);
window.removeEventListener('pointercancel', onPointerCancel);
saveSidebarWidth(sidebar.getBoundingClientRect().width);
};
const onPointerUp = (event) => stopDrag(event.pointerId);
const onPointerCancel = (event) => stopDrag(event.pointerId);
window.addEventListener('pointermove', onPointerMove);
window.addEventListener('pointerup', onPointerUp);
window.addEventListener('pointercancel', onPointerCancel);
});
sidebarResizer.addEventListener('dblclick', () => {
if (isMobileLayout()) return;
applySidebarWidth(400);
saveSidebarWidth(400);
});
window.addEventListener('resize', () => {
if (isMobileLayout()) return;
applySidebarWidth(sidebar.getBoundingClientRect().width);
});
}
setupSidebarResize();
hamburger.addEventListener('click', () => {
sidebar.classList.add('open');
overlay.classList.add('open');
hamburger.style.display = 'none';
});
const closeSidebar = () => {
sidebar.classList.remove('open');
overlay.classList.remove('open');
hamburger.style.display = '';
};
overlay.addEventListener('click', closeSidebar);
document.getElementById('sidebar-close').addEventListener('click', closeSidebar);
// Toggle states
let thinkingExpanded = true;
let toolOutputsExpanded = false;
const toggleThinking = () => {
thinkingExpanded = !thinkingExpanded;
document.querySelectorAll('.thinking-text').forEach(el => {
el.style.display = thinkingExpanded ? '' : 'none';
});
document.querySelectorAll('.thinking-collapsed').forEach(el => {
el.style.display = thinkingExpanded ? 'none' : 'block';
});
};
const toggleToolOutputs = () => {
toolOutputsExpanded = !toolOutputsExpanded;
document.querySelectorAll('.tool-output.expandable').forEach(el => {
el.classList.toggle('expanded', toolOutputsExpanded);
});
document.querySelectorAll('.compaction').forEach(el => {
el.classList.toggle('expanded', toolOutputsExpanded);
});
document.querySelectorAll('.skill-invocation').forEach(el => {
el.classList.toggle('expanded', toolOutputsExpanded);
});
};
const attachHeaderHandlers = () => {
document.querySelector('[data-action="toggle-thinking"]')?.addEventListener('click', toggleThinking);
document.querySelector('[data-action="toggle-tools"]')?.addEventListener('click', toggleToolOutputs);
};
const isEditableTarget = (element) => {
if (!element) return false;
const tagName = element.tagName;
if (tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT' || tagName === 'BUTTON') {
return true;
}
return element.isContentEditable || Boolean(element.closest?.('[contenteditable="true"]'));
};
// Keyboard shortcuts
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
searchInput.value = '';
searchQuery = '';
navigateTo(leafId, 'bottom');
}
if (isEditableTarget(document.activeElement)) {
return;
}
const key = e.key.toLowerCase();
if (key === 't') {
e.preventDefault();
toggleThinking();
} else if (key === 'o') {
e.preventDefault();
toggleToolOutputs();
}
});
// Initial render
// If URL has targetId, scroll to that specific message; otherwise stay at top
if (leafId) {
if (urlTargetId && byId.has(urlTargetId)) {
// Deep link: navigate to leaf and scroll to target message
navigateTo(leafId, 'target', urlTargetId);
} else {
navigateTo(leafId, 'none');
}
} else if (entries.length > 0) {
// Fallback: use last entry if no leafId
navigateTo(entries[entries.length - 1].id, 'none');
}
})();
</script>
</body>
</html>