Homepage / downloads /index.html
CompactAI's picture
Update downloads/index.html
6f85936 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Download | CompactAI Studio</title>
<link rel="stylesheet" href="bluesheet.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=Geist+Mono&display=swap" rel="stylesheet">
<style>
:root {
--blue-900: #000000;
--blue-800: #0a0a0a;
--blue-700: #111111;
--blue-600: #1a1a1a;
--blue-500: #333333;
--blue-400: #555555;
--blue-300: #777777;
--blue-200: #888888;
--blue-100: #aaaaaa;
--white: #ffffff;
--white-soft: #f5f5f5;
--white-muted: #e0e0e0;
--grid-line: rgba(255, 255, 255, 0.03);
--grid-line-major: rgba(255, 255, 255, 0.06);
--accent: #ededed;
--accent-muted: #888888;
--font-sans: 'Geist', -apple-system, BlinkMacSystemFont, sans-serif;
--font-mono: 'Geist Mono', 'SF Mono', 'Fira Code', monospace;
--container-max: 1100px;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-size: 16px;
scroll-behavior: smooth;
}
body {
font-family: var(--font-sans);
background: var(--blue-900);
color: var(--white-muted);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
color: var(--white);
text-decoration: none;
transition: color 0.15s ease;
}
a:hover {
color: var(--accent);
}
.container {
max-width: var(--container-max);
margin: 0 auto;
padding: 0 24px;
}
nav {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
background: rgba(0, 0, 0, 0.85);
backdrop-filter: blur(12px);
border-bottom: 1px solid var(--blue-600);
padding: 16px 0;
}
nav .container {
display: flex;
justify-content: space-between;
align-items: center;
}
.nav-brand {
font-size: 18px;
font-weight: 600;
color: var(--white);
display: flex;
align-items: center;
gap: 8px;
}
.nav-brand span {
color: var(--accent);
}
.nav-links {
display: flex;
gap: 24px;
}
.nav-links a {
color: var(--white-muted);
font-size: 14px;
font-weight: 500;
}
.nav-links a:hover {
color: var(--white);
}
main {
padding-top: 100px;
padding-bottom: 80px;
min-height: 100vh;
}
h1 {
font-size: 48px;
font-weight: 700;
color: var(--white);
margin-bottom: 16px;
letter-spacing: -0.02em;
}
.subtitle {
font-size: 20px;
color: var(--blue-200);
margin-bottom: 48px;
}
.download-grid {
display: grid;
gap: 24px;
}
.download-card {
background: var(--blue-800);
border: 1px solid var(--blue-600);
border-radius: 12px;
padding: 32px;
display: flex;
align-items: center;
justify-content: space-between;
transition: border-color 0.2s ease;
}
.download-card:hover {
border-color: var(--blue-500);
}
.download-info h3 {
font-size: 20px;
font-weight: 600;
color: var(--white);
margin-bottom: 8px;
}
.download-info p {
color: var(--blue-200);
font-size: 14px;
}
.download-info .version {
display: inline-block;
background: var(--blue-600);
color: var(--blue-200);
font-size: 12px;
padding: 2px 8px;
border-radius: 4px;
margin-left: 8px;
}
.download-btn {
display: inline-flex;
align-items: center;
gap: 8px;
background: var(--white);
color: var(--blue-900);
padding: 12px 24px;
border-radius: 8px;
font-weight: 500;
transition: all 0.15s ease;
}
.download-btn:hover {
background: var(--white-muted);
color: var(--blue-900);
}
.platform-icon {
width: 40px;
height: 40px;
background: var(--blue-600);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 16px;
}
.platform-icon svg {
width: 24px;
height: 24px;
color: var(--blue-200);
}
.download-card-left {
display: flex;
align-items: center;
}
.browser-alt {
margin-top: 40px;
padding: 28px 32px;
background: var(--blue-800);
border: 1px solid var(--blue-600);
border-radius: 12px;
}
.browser-alt h2 {
font-size: 22px;
font-weight: 600;
color: var(--white);
margin-bottom: 12px;
}
.browser-alt > p {
color: var(--blue-200);
font-size: 15px;
margin-bottom: 16px;
max-width: 52ch;
}
.code-block {
font-family: var(--font-mono);
font-size: 13px;
line-height: 1.5;
background: var(--blue-800);
border: 1px solid var(--blue-600);
border-radius: 8px;
padding: 16px 20px;
color: var(--white-muted);
overflow-x: auto;
white-space: pre;
}
.note {
margin-top: 32px;
padding: 16px;
background: var(--blue-800);
border: 1px solid var(--blue-600);
border-radius: 8px;
color: var(--blue-200);
font-size: 14px;
}
.note strong {
color: var(--white-muted);
}
/* Background Scribbles */
.scribbles {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
pointer-events: none;
opacity: 0.25;
}
/* Deprecation Notice */
.deprecation-notice {
background: rgba(255, 180, 0, 0.08);
border: 1px solid rgba(255, 180, 0, 0.25);
color: #e6b800;
padding: 16px 20px;
border-radius: 8px;
margin-bottom: 32px;
font-size: 14px;
line-height: 1.5;
}
.deprecation-notice strong {
color: #ffd633;
}
.deprecation-notice a {
color: #ffd633;
text-decoration: underline;
}
</style>
</head>
<body>
<svg class="scribbles" viewBox="0 0 1440 900" preserveAspectRatio="xMidYMid slice">
<path d="M100,50 Q150,30 200,60 T300,40 T400,70" fill="none" stroke="white" stroke-width="1"/>
<path d="M800,200 Q850,180 900,210 T1000,190 T1100,220" fill="none" stroke="white" stroke-width="0.8"/>
<path d="M200,700 Q250,680 300,710 T400,690 T500,720" fill="none" stroke="white" stroke-width="0.6"/>
<path d="M1200,400 Q1250,380 1300,410 T1400,390" fill="none" stroke="white" stroke-width="0.7"/>
<path d="M50,400 Q100,380 150,420 T250,400" fill="none" stroke="white" stroke-width="0.5"/>
<circle cx="350" cy="150" r="30" fill="none" stroke="white" stroke-width="0.6"/>
<circle cx="1100" cy="600" r="25" fill="none" stroke="white" stroke-width="0.5"/>
<path d="M600,100 L620,80 L640,100 L660,80" fill="none" stroke="white" stroke-width="0.7"/>
<path d="M1300,750 Q1320,730 1340,760 T1380,740" fill="none" stroke="white" stroke-width="0.5"/>
<path d="M100,800 Q120,780 140,810 T180,790 T220,820" fill="none" stroke="white" stroke-width="0.6"/>
<path d="M700,500 Q720,480 740,510 T780,490 T820,520" fill="none" stroke="white" stroke-width="0.4"/>
<path d="M400,300 C420,280 440,320 460,300 C480,280 500,320 520,300" fill="none" stroke="white" stroke-width="0.5"/>
<path d="M900,700 C920,680 940,720 960,700 C980,680 1000,720 1020,700" fill="none" stroke="white" stroke-width="0.6"/>
<path d="M150,250 Q170,230 190,260 Q210,240 230,270" fill="none" stroke="white" stroke-width="0.4"/>
<path d="M1050,100 Q1070,80 1090,110 Q1110,90 1130,120" fill="none" stroke="white" stroke-width="0.5"/>
<path d="M500,850 C520,830 540,860 560,840 C580,820 600,860 620,840" fill="none" stroke="white" stroke-width="0.4"/>
<path d="M1350,50 Q1370,30 1390,60 T1430,40" fill="none" stroke="white" stroke-width="0.5"/>
<path d="M30,600 Q50,580 70,610 T110,590" fill="none" stroke="white" stroke-width="0.4"/>
</svg>
<nav>
<div class="container">
<a href="../index.html" class="nav-brand">
<span>/</span>TinyMemoryLM
</a>
<div class="nav-links">
<a href="../index.html">Home</a>
<a href="../blog.html">Blog</a>
<a href="../status.html">Status</a>
<a href="#">GitHub</a>
</div>
</div>
</nav>
<main>
<div class="container">
<h1>CompactAI Studio</h1>
<p class="subtitle">Run AI models locally on your machine</p>
<div class="deprecation-notice">
<strong>Deprecation Notice:</strong> This utility is deprecated and only operates correctly up to Glint-1. It is advised to use the updated interface at <a href="https://huggingface.co/spaces/CompactAI-O/CompactAIModelRunner" target="_blank">https://huggingface.co/spaces/CompactAI-O/CompactAIModelRunner</a>.
</div>
<section class="browser-alt">
<h2>Run the browser version</h2>
<p>Pull checkpoints from <a href="https://huggingface.co/CompactAI">huggingface.co/CompactAI</a> and chat locally without installing anything. Install dependencies with <code>pip install -r requirements.txt</code> before launching.</p>
<div style="display:flex; gap:12px; flex-wrap:wrap; margin-bottom:16px;">
<a href="interactive.py" download="interactive.py" class="download-btn">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M6 9l6 6 6-6" />
<path d="M12 15V3" />
</svg>
Download browser launcher
</a>
</div>
<pre class="code-block">python3 interactive.py</pre>
</section>
<div class="note">
<strong>Note:</strong> The launcher downloads model files from Hugging Face and caches them locally.
</div>
</div>
</main>
<script>
(function() {
var b64 = "IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwoiIiJQdWJsaWMtZmFjaW5nIFRNTE0tSGFpa3UgaW50ZXJhY3RpdmUgQ0xJLgoKUHVsbHMgbW9kZWxzIGZyb20gdGhlIENvbXBhY3RBSS1PIEh1Z2dpbmdGYWNlIGNvbGxlY3Rpb246CiAgaHR0cHM6Ly9odWdnaW5nZmFjZS5jby9jb2xsZWN0aW9ucy9Db21wYWN0QUktTy90bWxtLWhhaWt1LXNlcmllcwoiIiIKZnJvbSBfX2Z1dHVyZV9fIGltcG9ydCBhbm5vdGF0aW9ucwoKCiMhL3Vzci9iaW4vZW52IHB5dGhvbjMKZnJvbSBfX2Z1dHVyZV9fIGltcG9ydCBhbm5vdGF0aW9ucwoKaW1wb3J0IGhhc2hsaWIKaW1wb3J0IGpzb24KaW1wb3J0IG1hdGgKaW1wb3J0IG9zCmltcG9ydCBzdHJpbmcKaW1wb3J0IHN5cwpmcm9tIGRhdGFjbGFzc2VzIGltcG9ydCBkYXRhY2xhc3MKZnJvbSBwYXRobGliIGltcG9ydCBQYXRoCmZyb20gdHlwaW5nIGltcG9ydCBEaWN0LCBJdGVyYXRvciwgTGlzdCwgT3B0aW9uYWwsIFNlcXVlbmNlLCBUdXBsZQoKaW1wb3J0IHRvcmNoCmltcG9ydCB0b3JjaC5ubiBhcyBubgppbXBvcnQgdG9yY2gubm4uZnVuY3Rpb25hbCBhcyBGCmZyb20gdG9yY2gudXRpbHMuY2hlY2twb2ludCBpbXBvcnQgY2hlY2twb2ludAoKSFVHR0lOR0ZBQ0VfTU9ERUxTID0gewogICAgIlRNTE0tSGFpa3UtMSI6ICJDb21wYWN0QUktTy9UTUxNLUhhaWt1LTEiLAogICAgIlRNTE0tSGFpa3UtMS4zIjogIkNvbXBhY3RBSS1PL1RNTE0tSGFpa3UtMS4zIiwKICAgICJUTUxNLUhhaWt1LTIiOiAiQ29tcGFjdEFJLU8vVE1MTS1IYWlrdS0yIiwKfQoKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgQ29uZmlnCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgoKQGRhdGFjbGFzcwpjbGFzcyBNb2RlbENvbmZpZzoKICAgIGRpbTogaW50ID0gMTI4CiAgICBuX3VuaXF1ZV9sYXllcnM6IGludCA9IDgKICAgIG5fbG9naWNhbF9sYXllcnM6IGludCA9IDE2CiAgICBuX2hlYWRzOiBpbnQgPSA0CiAgICBuX2t2X2hlYWRzOiBpbnQgPSAyCiAgICBmZm5fZGltOiBpbnQgPSAyMjQKICAgIGRyb3BvdXQ6IGZsb2F0ID0gMC4wCiAgICBzZXFfbGVuOiBpbnQgPSAyMDQ4CiAgICBzbGlkaW5nX3dpbmRvd19zaXplOiBpbnQgPSA1MTIKICAgIG10cF9ob3Jpem9uczogVHVwbGVbaW50LCAuLi5dID0gKDIsIDMsIDQpCiAgICByb3BlX2ZyYWN0aW9uOiBmbG9hdCA9IDAuNQogICAgZW1iZWRfc2NhbGU6IGJvb2wgPSBUcnVlCiAgICBsb2dpdF9zb2Z0X2NhcDogZmxvYXQgPSAtMS4wCiAgICBxdWFudGl6YXRpb246IHN0ciA9ICJudmZwNCIKCiAgICBAcHJvcGVydHkKICAgIGRlZiBoZWFkX2RpbShzZWxmKSAtPiBpbnQ6CiAgICAgICAgcmV0dXJuIHNlbGYuZGltIC8vIHNlbGYubl9oZWFkcwoKCm1vZGVsX2NvbmZpZyA9IE1vZGVsQ29uZmlnKCkKCk1PREVMX1NFUklFUyA9IHsKICAgICJoYWlrdSI6IHsKICAgICAgICAiZGltIjogNjQsCiAgICAgICAgIm5fdW5pcXVlX2xheWVycyI6IDEyLAogICAgICAgICJuX2xvZ2ljYWxfbGF5ZXJzIjogMjQsCiAgICAgICAgIm5faGVhZHMiOiA0LAogICAgICAgICJuX2t2X2hlYWRzIjogMiwKICAgICAgICAiZmZuX2RpbSI6IDM4NCwKICAgICAgICAiZHJvcG91dCI6IDAuMCwKICAgICAgICAic2VxX2xlbiI6IDIwNDgsCiAgICAgICAgInNsaWRpbmdfd2luZG93X3NpemUiOiAyMDQ4LAogICAgICAgICJtdHBfaG9yaXpvbnMiOiAoKSwKICAgICAgICAicm9wZV9mcmFjdGlvbiI6IDAuNSwKICAgICAgICAiZW5ncmFtX2RpbSI6IDgsCiAgICAgICAgImVuZ3JhbV9oZWFkcyI6IDIsCiAgICAgICAgImVuZ3JhbV90YWJsZV9zaXplIjogNjQsCiAgICAgICAgImVuZ3JhbV9tYXhfbmdyYW0iOiAyLAogICAgICAgICJtaGNfZXhwYW5zaW9uIjogMiwKICAgIH0sCiAgICAic29ubmV0IjogewogICAgICAgICJkaW0iOiAxMDI0LAogICAgICAgICJuX3VuaXF1ZV9sYXllcnMiOiAyMCwKICAgICAgICAibl9sb2dpY2FsX2xheWVycyI6IDQwLAogICAgICAgICJuX2hlYWRzIjogMTYsCiAgICAgICAgIm5fa3ZfaGVhZHMiOiA0LAogICAgICAgICJmZm5fZGltIjogNDA5NiwKICAgICAgICAiZHJvcG91dCI6IDAuMCwKICAgICAgICAic2VxX2xlbiI6IDIwNDgsCiAgICAgICAgIm10cF9ob3Jpem9ucyI6ICgyLCksCiAgICAgICAgImVuZ3JhbV9kaW0iOiAzMiwKICAgICAgICAiZW5ncmFtX2hlYWRzIjogOCwKICAgICAgICAiZW5ncmFtX3RhYmxlX3NpemUiOiA0MDk2LAogICAgICAgICJlbmdyYW1fbWF4X25ncmFtIjogMiwKICAgICAgICAibWhjX2V4cGFuc2lvbiI6IDIsCiAgICB9LAogICAgIm9wdXMiOiB7CiAgICAgICAgImRpbSI6IDE1MzYsCiAgICAgICAgIm5fdW5pcXVlX2xheWVycyI6IDE4LAogICAgICAgICJuX2xvZ2ljYWxfbGF5ZXJzIjogMzYsCiAgICAgICAgIm5faGVhZHMiOiAxNiwKICAgICAgICAibl9rdl9oZWFkcyI6IDQsCiAgICAgICAgImZmbl9kaW0iOiA1ODg4LAogICAgICAgICJkcm9wb3V0IjogMC4wLAogICAgICAgICJzZXFfbGVuIjogMjA0OCwKICAgICAgICAibXRwX2hvcml6b25zIjogKDIsKSwKICAgICAgICAiZW5ncmFtX2RpbSI6IDY0LAogICAgICAgICJlbmdyYW1faGVhZHMiOiA4LAogICAgICAgICJlbmdyYW1fdGFibGVfc2l6ZSI6IDgxOTIsCiAgICAgICAgImVuZ3JhbV9tYXhfbmdyYW0iOiAyLAogICAgICAgICJtaGNfZXhwYW5zaW9uIjogNCwKICAgIH0sCn0KCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFRva2VuaXplcgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKRk9STUFUX1RPS0VOUyA9IFsKICAgICI8fHVzZXJ8PiIsCiAgICAiPHxhc3Npc3RhbnR8PiIsCiAgICAiPHxzeXN0ZW18PiIsCiAgICAiPHxzdGFydF9oZWFkZXJfaWR8PiIsCiAgICAiPHxlbmRfaGVhZGVyX2lkfD4iLAogICAgIjx8YmVnaW5fb2ZfdGhvdWdodHw+IiwKICAgICI8fGVuZF9vZl90aG91Z2h0fD4iLAogICAgIjx8YmVnaW5fb2Zfc29sdXRpb258PiIsCiAgICAiPHxlbmRfb2Zfc29sdXRpb258PiIsCl0KCgpjbGFzcyBXb3JkVG9rZW5pemVyOgogICAgZGVmIF9faW5pdF9fKAogICAgICAgIHNlbGYsIGV4dHJhX2NoYXJzOiBzdHIgPSAiIiwgZm9ybWF0X3Rva2VuczogT3B0aW9uYWxbTGlzdFtzdHJdXSA9IE5vbmUKICAgICkgLT4gTm9uZToKICAgICAgICBiYXNlID0gc3RyaW5nLmFzY2lpX2xldHRlcnMgKyBzdHJpbmcuZGlnaXRzICsgc3RyaW5nLnB1bmN0dWF0aW9uICsgIiBcblx0XHIiCiAgICAgICAgZmFsbGJhY2tfY2hhcnMgPSBzb3J0ZWQoc2V0KGJhc2UgKyBleHRyYV9jaGFycykpCiAgICAgICAgc2VsZi5jb3JlX3NwZWNpYWwgPSBbIjxQQUQ+IiwgIjxCT1M+IiwgIjxFT1M+IiwgIjxVTks+Il0KICAgICAgICBzZWxmLmZvcm1hdF90b2tlbnMgPSAoCiAgICAgICAgICAgIGxpc3QoZm9ybWF0X3Rva2VucykgaWYgZm9ybWF0X3Rva2VucyBlbHNlIGxpc3QoRk9STUFUX1RPS0VOUykKICAgICAgICApCiAgICAgICAgc2VsZi5zcGVjaWFsID0gbGlzdChzZWxmLmNvcmVfc3BlY2lhbCkgKyBsaXN0KHNlbGYuZm9ybWF0X3Rva2VucykKICAgICAgICBzZWxmLmlkX3RvX3Rva2VuOiBMaXN0W3N0cl0gPSAoCiAgICAgICAgICAgIGxpc3Qoc2VsZi5jb3JlX3NwZWNpYWwpICsgc2VsZi5mb3JtYXRfdG9rZW5zICsgZmFsbGJhY2tfY2hhcnMKICAgICAgICApCiAgICAgICAgc2VsZi50b2tlbl90b19pZDogRGljdFtzdHIsIGludF0gPSB7CiAgICAgICAgICAgIHQ6IGkgZm9yIGksIHQgaW4gZW51bWVyYXRlKHNlbGYuaWRfdG9fdG9rZW4pCiAgICAgICAgfQogICAgICAgIHNlbGYuc3BlY2lhbF9tdWx0aV90b2tlbnMgPSBzb3J0ZWQoCiAgICAgICAgICAgIFt0IGZvciB0IGluIHNlbGYuc3BlY2lhbCBpZiBsZW4odCkgPiAxXSwga2V5PWxlbiwgcmV2ZXJzZT1UcnVlCiAgICAgICAgKQogICAgICAgIHNlbGYubXVsdGlfY2hhcl90b2tlbnMgPSBzZWxmLnNwZWNpYWxfbXVsdGlfdG9rZW5zCiAgICAgICAgc2VsZi5keW5hbWljX2FkZGl0aW9ucyA9IDAKCiAgICBAcHJvcGVydHkKICAgIGRlZiBwYWRfaWQoc2VsZikgLT4gaW50OgogICAgICAgIHJldHVybiBzZWxmLnRva2VuX3RvX2lkWyI8UEFEPiJdCgogICAgQHByb3BlcnR5CiAgICBkZWYgYm9zX2lkKHNlbGYpIC0+IGludDoKICAgICAgICByZXR1cm4gc2VsZi50b2tlbl90b19pZFsiPEJPUz4iXQoKICAgIEBwcm9wZXJ0eQogICAgZGVmIGVvc19pZChzZWxmKSAtPiBpbnQ6CiAgICAgICAgcmV0dXJuIHNlbGYudG9rZW5fdG9faWRbIjxFT1M+Il0KCiAgICBAcHJvcGVydHkKICAgIGRlZiB1bmtfaWQoc2VsZikgLT4gaW50OgogICAgICAgIHJldHVybiBzZWxmLnRva2VuX3RvX2lkWyI8VU5LPiJdCgogICAgQHByb3BlcnR5CiAgICBkZWYgdm9jYWJfc2l6ZShzZWxmKSAtPiBpbnQ6CiAgICAgICAgcmV0dXJuIGxlbihzZWxmLmlkX3RvX3Rva2VuKQoKICAgIGRlZiBtYXliZV9hZGRfY2hhcihzZWxmLCBjaDogc3RyKSAtPiBib29sOgogICAgICAgIGlmIGNoIGluIHNlbGYudG9rZW5fdG9faWQ6CiAgICAgICAgICAgIHJldHVybiBGYWxzZQogICAgICAgIHNlbGYudG9rZW5fdG9faWRbY2hdID0gbGVuKHNlbGYuaWRfdG9fdG9rZW4pCiAgICAgICAgc2VsZi5pZF90b190b2tlbi5hcHBlbmQoY2gpCiAgICAgICAgc2VsZi5keW5hbWljX2FkZGl0aW9ucyArPSAxCiAgICAgICAgcmV0dXJuIFRydWUKCiAgICBkZWYgaXRlcl9sZXhpY2FsX3Rva2VucyhzZWxmLCB0ZXh0OiBzdHIpIC0+IEl0ZXJhdG9yW3N0cl06CiAgICAgICAgaSA9IDAKICAgICAgICBuID0gbGVuKHRleHQpCiAgICAgICAgd2hpbGUgaSA8IG46CiAgICAgICAgICAgIG1hdGNoZWRfc3BlY2lhbCA9IEZhbHNlCiAgICAgICAgICAgIGZvciB0b2tlbiBpbiBzZWxmLnNwZWNpYWxfbXVsdGlfdG9rZW5zOgogICAgICAgICAgICAgICAgaWYgdGV4dC5zdGFydHN3aXRoKHRva2VuLCBpKToKICAgICAgICAgICAgICAgICAgICB5aWVsZCB0b2tlbgogICAgICAgICAgICAgICAgICAgIGkgKz0gbGVuKHRva2VuKQogICAgICAgICAgICAgICAgICAgIG1hdGNoZWRfc3BlY2lhbCA9IFRydWUKICAgICAgICAgICAgICAgICAgICBicmVhawogICAgICAgICAgICBpZiBtYXRjaGVkX3NwZWNpYWw6CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICB5aWVsZCB0ZXh0W2ldCiAgICAgICAgICAgIGkgKz0gMQoKICAgIGRlZiBlbmNvZGUoCiAgICAgICAgc2VsZiwgdGV4dDogc3RyLCBhZGRfYm9zOiBib29sID0gRmFsc2UsIGFkZF9lb3M6IGJvb2wgPSBGYWxzZQogICAgKSAtPiBMaXN0W2ludF06CiAgICAgICAgb3V0OiBMaXN0W2ludF0gPSBbXQogICAgICAgIGlmIGFkZF9ib3M6CiAgICAgICAgICAgIG91dC5hcHBlbmQoc2VsZi5ib3NfaWQpCiAgICAgICAgdW5rID0gc2VsZi51bmtfaWQKICAgICAgICB0MmkgPSBzZWxmLnRva2VuX3RvX2lkCiAgICAgICAgZm9yIHRvayBpbiBzZWxmLml0ZXJfbGV4aWNhbF90b2tlbnModGV4dCk6CiAgICAgICAgICAgIG91dC5hcHBlbmQodDJpLmdldCh0b2ssIHVuaykpCiAgICAgICAgaWYgYWRkX2VvczoKICAgICAgICAgICAgb3V0LmFwcGVuZChzZWxmLmVvc19pZCkKICAgICAgICByZXR1cm4gb3V0CgogICAgZGVmIGRlY29kZShzZWxmLCBpZHM6IFNlcXVlbmNlW2ludF0sIHNraXBfc3BlY2lhbDogYm9vbCA9IFRydWUpIC0+IHN0cjoKICAgICAgICBwaWVjZXM6IExpc3Rbc3RyXSA9IFtdCiAgICAgICAgZm9yIGlkeCBpbiBpZHM6CiAgICAgICAgICAgIGlmIGludChpZHgpIDwgMCBvciBpbnQoaWR4KSA+PSBsZW4oc2VsZi5pZF90b190b2tlbik6CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICB0b2sgPSBzZWxmLmlkX3RvX3Rva2VuW2ludChpZHgpXQogICAgICAgICAgICBpZiBza2lwX3NwZWNpYWwgYW5kIHRvayBpbiBzZWxmLnNwZWNpYWw6CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICBwaWVjZXMuYXBwZW5kKHRvaykKICAgICAgICByZXR1cm4gIiIuam9pbihwaWVjZXMpCgogICAgQGNsYXNzbWV0aG9kCiAgICBkZWYgbG9hZChjbHMsIHBhdGg6IFBhdGgpIC0+IFdvcmRUb2tlbml6ZXI6CiAgICAgICAgd2l0aCBwYXRoLm9wZW4oInIiLCBlbmNvZGluZz0idXRmLTgiKSBhcyBmOgogICAgICAgICAgICBkYXRhID0ganNvbi5sb2FkKGYpCiAgICAgICAgZm9ybWF0X3Rva2VucyA9IGRhdGEuZ2V0KCJmb3JtYXRfdG9rZW5zIiwgRk9STUFUX1RPS0VOUykKICAgICAgICB0b2tlbml6ZXIgPSBjbHMoZXh0cmFfY2hhcnM9IiIsIGZvcm1hdF90b2tlbnM9Zm9ybWF0X3Rva2VucykKICAgICAgICB0b2tlbml6ZXIuaWRfdG9fdG9rZW4gPSBkYXRhWyJpZF90b190b2tlbiJdCiAgICAgICAgdG9rZW5pemVyLnRva2VuX3RvX2lkID0ge3Q6IGkgZm9yIGksIHQgaW4gZW51bWVyYXRlKHRva2VuaXplci5pZF90b190b2tlbil9CiAgICAgICAgdG9rZW5pemVyLnNwZWNpYWwgPSBsaXN0KHRva2VuaXplci5jb3JlX3NwZWNpYWwpICsgbGlzdCh0b2tlbml6ZXIuZm9ybWF0X3Rva2VucykKICAgICAgICB0b2tlbml6ZXIuc3BlY2lhbF9tdWx0aV90b2tlbnMgPSBzb3J0ZWQoCiAgICAgICAgICAgIFt0IGZvciB0IGluIHRva2VuaXplci5zcGVjaWFsIGlmIGxlbih0KSA+IDFdLCBrZXk9bGVuLCByZXZlcnNlPVRydWUKICAgICAgICApCiAgICAgICAgdG9rZW5pemVyLm11bHRpX2NoYXJfdG9rZW5zID0gdG9rZW5pemVyLnNwZWNpYWxfbXVsdGlfdG9rZW5zCiAgICAgICAgcmV0dXJuIHRva2VuaXplcgoKCkxldHRlclRva2VuaXplciA9IFdvcmRUb2tlbml6ZXIKCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIE1vZGVsCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgoKY2xhc3MgUk1TTm9ybShubi5Nb2R1bGUpOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIGRpbTogaW50LCBlcHM6IGZsb2F0ID0gMWUtNikgLT4gTm9uZToKICAgICAgICBzdXBlcigpLl9faW5pdF9fKCkKICAgICAgICBzZWxmLndlaWdodCA9IG5uLlBhcmFtZXRlcih0b3JjaC5vbmVzKGRpbSkpCiAgICAgICAgc2VsZi5lcHMgPSBlcHMKCiAgICBkZWYgZm9yd2FyZChzZWxmLCB4OiB0b3JjaC5UZW5zb3IpIC0+IHRvcmNoLlRlbnNvcjoKICAgICAgICBpZiBoYXNhdHRyKHRvcmNoLm5uLmZ1bmN0aW9uYWwsICJybXNfbm9ybSIpOgogICAgICAgICAgICByZXR1cm4gdG9yY2gubm4uZnVuY3Rpb25hbC5ybXNfbm9ybSgKICAgICAgICAgICAgICAgIHgsIHNlbGYud2VpZ2h0LnNoYXBlLCBzZWxmLndlaWdodCwgc2VsZi5lcHMKICAgICAgICAgICAgKQogICAgICAgIHhfZnAgPSB4LmZsb2F0KCkKICAgICAgICBybXMgPSB0b3JjaC5yc3FydCh4X2ZwLnBvdygyKS5tZWFuKGRpbT0tMSwga2VlcGRpbT1UcnVlKSArIHNlbGYuZXBzKQogICAgICAgIHJldHVybiAoeF9mcCAqIHJtcykudG8oZHR5cGU9eC5kdHlwZSkgKiBzZWxmLndlaWdodAoKCmNsYXNzIFJvdGFyeUVtYmVkZGluZyhubi5Nb2R1bGUpOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIGRpbTogaW50LCBiYXNlOiBmbG9hdCA9IDEwMDAwLjApIC0+IE5vbmU6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygpCiAgICAgICAgaW52ID0gMS4wIC8gKGJhc2UgKiogKHRvcmNoLmFyYW5nZSgwLCBkaW0sIDIpLmZsb2F0KCkgLyBkaW0pKQogICAgICAgIHNlbGYucmVnaXN0ZXJfYnVmZmVyKCJpbnZfZnJlcSIsIGludiwgcGVyc2lzdGVudD1GYWxzZSkKCiAgICBkZWYgY29zX3NpbigKICAgICAgICBzZWxmLCBzZXFfbGVuOiBpbnQsIGRldmljZTogdG9yY2guZGV2aWNlLCBkdHlwZTogdG9yY2guZHR5cGUKICAgICkgLT4gVHVwbGVbdG9yY2guVGVuc29yLCB0b3JjaC5UZW5zb3JdOgogICAgICAgIHQgPSB0b3JjaC5hcmFuZ2Uoc2VxX2xlbiwgZGV2aWNlPWRldmljZSwgZHR5cGU9c2VsZi5pbnZfZnJlcS5kdHlwZSkKICAgICAgICBmcmVxcyA9IHRvcmNoLm91dGVyKHQsIHNlbGYuaW52X2ZyZXEpCiAgICAgICAgZW1iID0gdG9yY2guY2F0KFtmcmVxcywgZnJlcXNdLCBkaW09LTEpCiAgICAgICAgY29zID0gZW1iLmNvcygpW05vbmUsIE5vbmUsIDosIDpdLnRvKGR0eXBlPWR0eXBlKQogICAgICAgIHNpbiA9IGVtYi5zaW4oKVtOb25lLCBOb25lLCA6LCA6XS50byhkdHlwZT1kdHlwZSkKICAgICAgICByZXR1cm4gY29zLCBzaW4KCgpkZWYgX3JvdGF0ZV9oYWxmKHg6IHRvcmNoLlRlbnNvcikgLT4gdG9yY2guVGVuc29yOgogICAgeDEgPSB4Wy4uLiwgOiB4LnNoYXBlWy0xXSAvLyAyXQogICAgeDIgPSB4Wy4uLiwgeC5zaGFwZVstMV0gLy8gMiA6XQogICAgcmV0dXJuIHRvcmNoLmNhdCgoLXgyLCB4MSksIGRpbT0tMSkKCgpjbGFzcyBDYXVzYWxTZWxmQXR0ZW50aW9uKG5uLk1vZHVsZSk6CiAgICBkZWYgX19pbml0X18oCiAgICAgICAgc2VsZiwKICAgICAgICBkaW06IGludCwKICAgICAgICBuX2hlYWRzOiBpbnQsCiAgICAgICAgbl9rdl9oZWFkczogaW50LAogICAgICAgIGhlYWRfZGltOiBpbnQsCiAgICAgICAgZHJvcG91dDogZmxvYXQsCiAgICAgICAgc2xpZGluZ193aW5kb3c6IGludCwKICAgICAgICByb3BlX2ZyYWN0aW9uOiBmbG9hdCwKICAgICkgLT4gTm9uZToKICAgICAgICBzdXBlcigpLl9faW5pdF9fKCkKICAgICAgICBzZWxmLmRpbSA9IGRpbQogICAgICAgIHNlbGYubl9oZWFkcyA9IG5faGVhZHMKICAgICAgICBzZWxmLm5fa3ZfaGVhZHMgPSBuX2t2X2hlYWRzCiAgICAgICAgc2VsZi5oZWFkX2RpbSA9IGhlYWRfZGltCiAgICAgICAgc2VsZi5uX3JlcCA9IG5faGVhZHMgLy8gbl9rdl9oZWFkcwogICAgICAgIHNlbGYuZHJvcG91dCA9IGRyb3BvdXQKICAgICAgICBzZWxmLnNsaWRpbmdfd2luZG93ID0gc2xpZGluZ193aW5kb3cKCiAgICAgICAgc2VsZi53cSA9IG5uLkxpbmVhcihkaW0sIG5faGVhZHMgKiBoZWFkX2RpbSwgYmlhcz1GYWxzZSkKICAgICAgICBzZWxmLndrID0gbm4uTGluZWFyKGRpbSwgbl9rdl9oZWFkcyAqIGhlYWRfZGltLCBiaWFzPUZhbHNlKQogICAgICAgIHNlbGYud3YgPSBubi5MaW5lYXIoZGltLCBuX2t2X2hlYWRzICogaGVhZF9kaW0sIGJpYXM9RmFsc2UpCiAgICAgICAgc2VsZi53byA9IG5uLkxpbmVhcihuX2hlYWRzICogaGVhZF9kaW0sIGRpbSwgYmlhcz1GYWxzZSkKCiAgICAgICAgc2VsZi5yb3BlX2RpbSA9IG1heCgyLCBpbnQoaGVhZF9kaW0gKiByb3BlX2ZyYWN0aW9uKSAvLyAyICogMikKICAgICAgICBzZWxmLnJvcGUgPSBSb3RhcnlFbWJlZGRpbmcoc2VsZi5yb3BlX2RpbSkKCiAgICAgICAgc2VsZi5xX25vcm0gPSBSTVNOb3JtKGhlYWRfZGltKQogICAgICAgIHNlbGYua19ub3JtID0gUk1TTm9ybShoZWFkX2RpbSkKCiAgICAgICAgc2VsZi5vdXRwdXRfZ2F0ZSA9IG5uLlBhcmFtZXRlcih0b3JjaC5vbmVzKG5faGVhZHMpKQoKICAgIGRlZiBmb3J3YXJkKAogICAgICAgIHNlbGYsCiAgICAgICAgeDogdG9yY2guVGVuc29yLAogICAgICAgIGlzX2dsb2JhbDogYm9vbCwKICAgICAgICBwYXN0X2t2OiBPcHRpb25hbFtUdXBsZVt0b3JjaC5UZW5zb3IsIHRvcmNoLlRlbnNvcl1dID0gTm9uZSwKICAgICAgICB1c2VfY2FjaGU6IGJvb2wgPSBGYWxzZSwKICAgICkgLT4gVHVwbGVbdG9yY2guVGVuc29yLCBPcHRpb25hbFtUdXBsZVt0b3JjaC5UZW5zb3IsIHRvcmNoLlRlbnNvcl1dXToKICAgICAgICBCLCBULCBfID0geC5zaGFwZQoKICAgICAgICBxID0gc2VsZi53cSh4KS52aWV3KEIsIFQsIHNlbGYubl9oZWFkcywgc2VsZi5oZWFkX2RpbSkKICAgICAgICBrID0gc2VsZi53ayh4KS52aWV3KEIsIFQsIHNlbGYubl9rdl9oZWFkcywgc2VsZi5oZWFkX2RpbSkKICAgICAgICB2ID0gc2VsZi53dih4KS52aWV3KEIsIFQsIHNlbGYubl9rdl9oZWFkcywgc2VsZi5oZWFkX2RpbSkKCiAgICAgICAgcSA9IHNlbGYucV9ub3JtKHEpCiAgICAgICAgayA9IHNlbGYua19ub3JtKGspCgogICAgICAgIHEgPSBxLnRyYW5zcG9zZSgxLCAyKQogICAgICAgIGsgPSBrLnRyYW5zcG9zZSgxLCAyKQogICAgICAgIHYgPSB2LnRyYW5zcG9zZSgxLCAyKQoKICAgICAgICBwYXN0X2xlbiA9IHBhc3Rfa3ZbMF0uc2hhcGVbMl0gaWYgcGFzdF9rdiBpcyBub3QgTm9uZSBlbHNlIDAKICAgICAgICBjb3MsIHNpbiA9IHNlbGYucm9wZS5jb3Nfc2luKFQgKyBwYXN0X2xlbiwgeC5kZXZpY2UsIHEuZHR5cGUpCiAgICAgICAgY29zX3NsaWNlID0gY29zWzosIDosIHBhc3RfbGVuIDogcGFzdF9sZW4gKyBULCA6XQogICAgICAgIHNpbl9zbGljZSA9IHNpbls6LCA6LCBwYXN0X2xlbiA6IHBhc3RfbGVuICsgVCwgOl0KCiAgICAgICAgcV9yb3BlID0gcVsuLi4sIDogc2VsZi5yb3BlX2RpbV0KICAgICAgICBxX3Bhc3MgPSBxWy4uLiwgc2VsZi5yb3BlX2RpbSA6XQogICAgICAgIGtfcm9wZSA9IGtbLi4uLCA6IHNlbGYucm9wZV9kaW1dCiAgICAgICAga19wYXNzID0ga1suLi4sIHNlbGYucm9wZV9kaW0gOl0KCiAgICAgICAgcV9yb3BlID0gKHFfcm9wZSAqIGNvc19zbGljZSkgKyAoX3JvdGF0ZV9oYWxmKHFfcm9wZSkgKiBzaW5fc2xpY2UpCiAgICAgICAga19yb3BlID0gKGtfcm9wZSAqIGNvc19zbGljZSkgKyAoX3JvdGF0ZV9oYWxmKGtfcm9wZSkgKiBzaW5fc2xpY2UpCgogICAgICAgIHEgPSB0b3JjaC5jYXQoW3Ffcm9wZSwgcV9wYXNzXSwgZGltPS0xKQogICAgICAgIGsgPSB0b3JjaC5jYXQoW2tfcm9wZSwga19wYXNzXSwgZGltPS0xKQoKICAgICAgICBpZiBwYXN0X2t2IGlzIG5vdCBOb25lOgogICAgICAgICAgICBrID0gdG9yY2guY2F0KFtwYXN0X2t2WzBdLCBrXSwgZGltPTIpCiAgICAgICAgICAgIHYgPSB0b3JjaC5jYXQoW3Bhc3Rfa3ZbMV0sIHZdLCBkaW09MikKCiAgICAgICAgbmV3X2t2ID0gKGssIHYpIGlmIHVzZV9jYWNoZSBlbHNlIE5vbmUKCiAgICAgICAgUyA9IGsuc2hhcGVbMl0KICAgICAgICBpZiBzZWxmLm5fcmVwID4gMToKICAgICAgICAgICAgayA9ICgKICAgICAgICAgICAgICAgIGtbOiwgOiwgTm9uZSwgOiwgOl0KICAgICAgICAgICAgICAgIC5leHBhbmQoQiwgc2VsZi5uX2t2X2hlYWRzLCBzZWxmLm5fcmVwLCBTLCBzZWxmLmhlYWRfZGltKQogICAgICAgICAgICAgICAgLnJlc2hhcGUoQiwgc2VsZi5uX2hlYWRzLCBTLCBzZWxmLmhlYWRfZGltKQogICAgICAgICAgICApCiAgICAgICAgICAgIHYgPSAoCiAgICAgICAgICAgICAgICB2WzosIDosIE5vbmUsIDosIDpdCiAgICAgICAgICAgICAgICAuZXhwYW5kKEIsIHNlbGYubl9rdl9oZWFkcywgc2VsZi5uX3JlcCwgUywgc2VsZi5oZWFkX2RpbSkKICAgICAgICAgICAgICAgIC5yZXNoYXBlKEIsIHNlbGYubl9oZWFkcywgUywgc2VsZi5oZWFkX2RpbSkKICAgICAgICAgICAgKQoKICAgICAgICBkcm9wX3AgPSBzZWxmLmRyb3BvdXQgaWYgKHNlbGYudHJhaW5pbmcgYW5kIHRvcmNoLmlzX2dyYWRfZW5hYmxlZCgpKSBlbHNlIDAuMAoKICAgICAgICBpZiBpc19nbG9iYWw6CiAgICAgICAgICAgIGlmIHBhc3Rfa3YgaXMgTm9uZSBhbmQgVCA+IDE6CiAgICAgICAgICAgICAgICBvdXQgPSBGLnNjYWxlZF9kb3RfcHJvZHVjdF9hdHRlbnRpb24oCiAgICAgICAgICAgICAgICAgICAgcSwgaywgdiwgaXNfY2F1c2FsPVRydWUsIGRyb3BvdXRfcD1kcm9wX3AKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgIG91dCA9IEYuc2NhbGVkX2RvdF9wcm9kdWN0X2F0dGVudGlvbihxLCBrLCB2LCBkcm9wb3V0X3A9ZHJvcF9wKQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIFRfcSA9IHEuc2hhcGVbMl0KICAgICAgICAgICAgcV9wb3MgPSB0b3JjaC5hcmFuZ2UocGFzdF9sZW4sIHBhc3RfbGVuICsgVF9xLCBkZXZpY2U9cS5kZXZpY2UpLnVuc3F1ZWV6ZSgxKQogICAgICAgICAgICBrX3BvcyA9IHRvcmNoLmFyYW5nZShTLCBkZXZpY2U9cS5kZXZpY2UpLnVuc3F1ZWV6ZSgwKQogICAgICAgICAgICBtYXNrID0gKHFfcG9zID49IGtfcG9zKSAmICgocV9wb3MgLSBrX3BvcykgPCBzZWxmLnNsaWRpbmdfd2luZG93KQogICAgICAgICAgICBvdXQgPSBGLnNjYWxlZF9kb3RfcHJvZHVjdF9hdHRlbnRpb24oCiAgICAgICAgICAgICAgICBxLCBrLCB2LCBhdHRuX21hc2s9bWFzay51bnNxdWVlemUoMCkudW5zcXVlZXplKDApLCBkcm9wb3V0X3A9ZHJvcF9wCiAgICAgICAgICAgICkKCiAgICAgICAgZ2F0ZSA9IHRvcmNoLnNpZ21vaWQoc2VsZi5vdXRwdXRfZ2F0ZSkudmlldygxLCBzZWxmLm5faGVhZHMsIDEsIDEpCiAgICAgICAgb3V0ID0gb3V0ICogZ2F0ZQoKICAgICAgICBvdXQgPSBvdXQudHJhbnNwb3NlKDEsIDIpLmNvbnRpZ3VvdXMoKS52aWV3KEIsIFQsIHNlbGYubl9oZWFkcyAqIHNlbGYuaGVhZF9kaW0pCiAgICAgICAgb3V0ID0gc2VsZi53byhvdXQpCgogICAgICAgIHJldHVybiBvdXQsIG5ld19rdgoKCmNsYXNzIFN3aUdMVShubi5Nb2R1bGUpOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIGRpbTogaW50LCBoaWRkZW5fZGltOiBpbnQsIGRyb3BvdXQ6IGZsb2F0KSAtPiBOb25lOgogICAgICAgIHN1cGVyKCkuX19pbml0X18oKQogICAgICAgIHNlbGYuZ2F0ZSA9IG5uLkxpbmVhcihkaW0sIGhpZGRlbl9kaW0sIGJpYXM9RmFsc2UpCiAgICAgICAgc2VsZi51cCA9IG5uLkxpbmVhcihkaW0sIGhpZGRlbl9kaW0sIGJpYXM9RmFsc2UpCiAgICAgICAgc2VsZi5kb3duID0gbm4uTGluZWFyKGhpZGRlbl9kaW0sIGRpbSwgYmlhcz1GYWxzZSkKICAgICAgICBzZWxmLmRyb3AgPSBubi5Ecm9wb3V0KGRyb3BvdXQpCgogICAgICAgIG5uLmluaXQubm9ybWFsXyhzZWxmLmdhdGUud2VpZ2h0LCBzdGQ9ZGltKiotMC41KQogICAgICAgIG5uLmluaXQubm9ybWFsXyhzZWxmLnVwLndlaWdodCwgc3RkPWRpbSoqLTAuNSkKICAgICAgICBubi5pbml0Lm5vcm1hbF8oc2VsZi5kb3duLndlaWdodCwgc3RkPWhpZGRlbl9kaW0qKi0wLjUpCgogICAgZGVmIGZvcndhcmQoc2VsZiwgeDogdG9yY2guVGVuc29yKSAtPiB0b3JjaC5UZW5zb3I6CiAgICAgICAgaCA9IEYuc2lsdShzZWxmLmdhdGUoeCkpICogc2VsZi51cCh4KQogICAgICAgIG91dCA9IHNlbGYuZG93bihoKQogICAgICAgIGlmIHNlbGYudHJhaW5pbmcgYW5kIHRvcmNoLmlzX2dyYWRfZW5hYmxlZCgpOgogICAgICAgICAgICBvdXQgPSBzZWxmLmRyb3Aob3V0KQogICAgICAgIHJldHVybiBvdXQKCgpjbGFzcyBFbmdyYW1CbG9jayhubi5Nb2R1bGUpOgogICAgIiIiRGVlcFNlZWsgRW5ncmFtOiBjb25kaXRpb25hbCBtZW1vcnkgdmlhIE8oMSkgaGFzaGVkIE4tZ3JhbSBsb29rdXAuCgogICAgU3RvcmVzIGNvbW1vbiB0b2tlbi1wYWlyL3RyaXBsZXQgcGF0dGVybnMgaW4gYW4gZW1iZWRkaW5nIHRhYmxlIGFuZAogICAgcmV0cmlldmVzIHRoZW0gd2l0aCBtdWx0aS1oZWFkIGhhc2hpbmcuICBBIGNvbnRleHQtYXdhcmUgZ2F0ZSAodXNpbmcgdGhlCiAgICBjdXJyZW50IGhpZGRlbiBzdGF0ZSBhcyBxdWVyeSkgZGVjaWRlcyBob3cgbXVjaCBvZiB0aGUgcmV0cmlldmVkIG1lbW9yeQogICAgdG8gaW5qZWN0IGludG8gdGhlIHJlc2lkdWFsIHN0cmVhbS4KCiAgICBSZWZlcmVuY2U6IERlZXBTZWVrLUFJLCAiQ29uZGl0aW9uYWwgTWVtb3J5IHZpYSBTY2FsYWJsZSBMb29rdXAiICgyMDI1KS4KICAgICIiIgoKICAgIGRlZiBfX2luaXRfXygKICAgICAgICBzZWxmLAogICAgICAgIGRpbTogaW50LAogICAgICAgIGVuZ3JhbV9kaW06IGludCwKICAgICAgICBuX2hlYWRzOiBpbnQgPSA0LAogICAgICAgIHRhYmxlX3NpemU6IGludCA9IDgxOTIsCiAgICAgICAgbWF4X25ncmFtOiBpbnQgPSAzLAogICAgKSAtPiBOb25lOgogICAgICAgIHN1cGVyKCkuX19pbml0X18oKQogICAgICAgIHNlbGYuZGltID0gZGltCiAgICAgICAgc2VsZi5lbmdyYW1fZGltID0gZW5ncmFtX2RpbQogICAgICAgIHNlbGYubl9oZWFkcyA9IG5faGVhZHMKICAgICAgICBzZWxmLnRhYmxlX3NpemUgPSB0YWJsZV9zaXplCiAgICAgICAgc2VsZi5tYXhfbmdyYW0gPSBtYXhfbmdyYW0KCiAgICAgICAgIyBPbmUgZW1iZWRkaW5nIHRhYmxlIHBlciAobmdyYW1fb3JkZXIsIGhhc2hfaGVhZCkKICAgICAgICBzZWxmLmVtYmVkZGluZ3MgPSBubi5QYXJhbWV0ZXJEaWN0KCkKICAgICAgICBmb3IgbiBpbiByYW5nZSgyLCBtYXhfbmdyYW0gKyAxKToKICAgICAgICAgICAgZm9yIGsgaW4gcmFuZ2Uobl9oZWFkcyk6CiAgICAgICAgICAgICAgICBzZWxmLmVtYmVkZGluZ3NbZiJ7bn1fe2t9Il0gPSBubi5QYXJhbWV0ZXIoCiAgICAgICAgICAgICAgICAgICAgdG9yY2gucmFuZG4odGFibGVfc2l6ZSwgZW5ncmFtX2RpbSkgKiAoZW5ncmFtX2RpbSoqLTAuNSkKICAgICAgICAgICAgICAgICkKCiAgICAgICAgIyBGaXhlZCBoYXNoIHBhcmFtZXRlcnMgKG5vbi1sZWFybmFibGUsIGRldGVybWluaXN0aWMpCiAgICAgICAgZm9yIG4gaW4gcmFuZ2UoMiwgbWF4X25ncmFtICsgMSk6CiAgICAgICAgICAgIGZvciBrIGluIHJhbmdlKG5faGVhZHMpOgogICAgICAgICAgICAgICAgc2VlZCA9IGludChoYXNobGliLm1kNShmImVuZ3JhbV97bn1fe2t9Ii5lbmNvZGUoKSkuaGV4ZGlnZXN0KClbOjhdLCAxNikKICAgICAgICAgICAgICAgIHJuZyA9IHRvcmNoLkdlbmVyYXRvcigpLm1hbnVhbF9zZWVkKHNlZWQpCiAgICAgICAgICAgICAgICBhID0gdG9yY2gucmFuZGludCgxLCAyKiozMSwgKDEsKSwgZ2VuZXJhdG9yPXJuZykuaXRlbSgpCiAgICAgICAgICAgICAgICBiID0gdG9yY2gucmFuZGludCgwLCAyKiozMSwgKDEsKSwgZ2VuZXJhdG9yPXJuZykuaXRlbSgpCiAgICAgICAgICAgICAgICBzZWxmLnJlZ2lzdGVyX2J1ZmZlcigKICAgICAgICAgICAgICAgICAgICBmImhhc2hfYV97bn1fe2t9IiwgdG9yY2gudGVuc29yKGEpLCBwZXJzaXN0ZW50PUZhbHNlCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICBzZWxmLnJlZ2lzdGVyX2J1ZmZlcigKICAgICAgICAgICAgICAgICAgICBmImhhc2hfYl97bn1fe2t9IiwgdG9yY2gudGVuc29yKGIpLCBwZXJzaXN0ZW50PUZhbHNlCiAgICAgICAgICAgICAgICApCgogICAgICAgICMgQ2F1c2FsIGNvbnZvbHV0aW9uIG92ZXIgTi1ncmFtIGJyYW5jaCBvdXRwdXRzIChrZXJuZWw9NCwgZGlsYXRpb249bWF4X25ncmFtKQogICAgICAgIHRvdGFsX2JyYW5jaF9kaW0gPSBlbmdyYW1fZGltICogbl9oZWFkcyAqIChtYXhfbmdyYW0gLSAxKQogICAgICAgIHNlbGYuYnJhbmNoX2NvbnYgPSBubi5Db252MWQoCiAgICAgICAgICAgIHRvdGFsX2JyYW5jaF9kaW0sCiAgICAgICAgICAgIHRvdGFsX2JyYW5jaF9kaW0sCiAgICAgICAgICAgIGtlcm5lbF9zaXplPTQsCiAgICAgICAgICAgIGRpbGF0aW9uPW1heF9uZ3JhbSwKICAgICAgICAgICAgcGFkZGluZz0wLAogICAgICAgICAgICBncm91cHM9dG90YWxfYnJhbmNoX2RpbSwKICAgICAgICAgICAgYmlhcz1UcnVlLAogICAgICAgICkKICAgICAgICBubi5pbml0Lnplcm9zXyhzZWxmLmJyYW5jaF9jb252LndlaWdodCkKICAgICAgICBubi5pbml0Lnplcm9zXyhzZWxmLmJyYW5jaF9jb252LmJpYXMpCgogICAgICAgICMgQ29udGV4dC1hd2FyZSBnYXRpbmc6IGhpZGRlbiBzdGF0ZSBhcyBxdWVyeSwgbWVtb3J5IGFzIGtleS92YWx1ZQogICAgICAgIHNlbGYuZ2F0ZV9xdWVyeSA9IG5uLkxpbmVhcihkaW0sIGVuZ3JhbV9kaW0sIGJpYXM9RmFsc2UpCiAgICAgICAgc2VsZi5nYXRlX2tleSA9IG5uLkxpbmVhcih0b3RhbF9icmFuY2hfZGltLCBlbmdyYW1fZGltLCBiaWFzPUZhbHNlKQogICAgICAgIHNlbGYuZ2F0ZV92YWx1ZSA9IG5uLkxpbmVhcih0b3RhbF9icmFuY2hfZGltLCBkaW0sIGJpYXM9RmFsc2UpCiAgICAgICAgc2VsZi5nYXRlX3NjYWxlID0gZW5ncmFtX2RpbSoqLTAuNQoKICAgIGRlZiBfaGFzaF9uZ3JhbShzZWxmLCB0b2tlbl9pZHM6IHRvcmNoLlRlbnNvciwgbjogaW50LCBrOiBpbnQpIC0+IHRvcmNoLlRlbnNvcjoKICAgICAgICAiIiJIYXNoIG4tZ3JhbSB0b2tlbiBzZXF1ZW5jZXMgaW50byB0YWJsZSBpbmRpY2VzLgoKICAgICAgICBBcmdzOgogICAgICAgICAgICB0b2tlbl9pZHM6IChCLCBUKSB0b2tlbiBJRHMKICAgICAgICAgICAgbjogbi1ncmFtIG9yZGVyICgyID0gYmlncmFtLCAzID0gdHJpZ3JhbSkKICAgICAgICAgICAgazogaGFzaCBoZWFkIGluZGV4CiAgICAgICAgUmV0dXJuczoKICAgICAgICAgICAgaW5kaWNlczogKEIsIFQpIGludGVnZXIgaW5kaWNlcyBpbnRvIGVtYmVkZGluZyB0YWJsZQogICAgICAgICIiIgogICAgICAgIGEgPSBnZXRhdHRyKHNlbGYsIGYiaGFzaF9hX3tufV97a30iKQogICAgICAgIGIgPSBnZXRhdHRyKHNlbGYsIGYiaGFzaF9iX3tufV97a30iKQogICAgICAgIEIsIFQgPSB0b2tlbl9pZHMuc2hhcGUKCiAgICAgICAgIyBQYWQgbGVmdCB3aXRoIHplcm9zIHNvIGV2ZXJ5IHBvc2l0aW9uIGhhcyBhIHZhbGlkIG4tZ3JhbQogICAgICAgIHBhZGRlZCA9IEYucGFkKHRva2VuX2lkcywgKG4gLSAxLCAwKSwgdmFsdWU9MCkgICMgKEIsIFQrbi0xKQoKICAgICAgICAjIFBvbHlub21pYWwgcm9sbGluZyBoYXNoCiAgICAgICAgY29tYmluZWQgPSB0b3JjaC56ZXJvcyhCLCBULCBkdHlwZT10b3JjaC5sb25nLCBkZXZpY2U9dG9rZW5faWRzLmRldmljZSkKICAgICAgICBmb3IgaSBpbiByYW5nZShuKToKICAgICAgICAgICAgY29tYmluZWQgPSBjb21iaW5lZCAqIDMxICsgcGFkZGVkWzosIGkgOiBpICsgVF0ubG9uZygpCgogICAgICAgIGluZGljZXMgPSAoKGEgKiBjb21iaW5lZCkgXiBiKSAlIHNlbGYudGFibGVfc2l6ZQogICAgICAgIHJldHVybiBpbmRpY2VzCgogICAgZGVmIGZvcndhcmQoCiAgICAgICAgc2VsZiwgaGlkZGVuOiB0b3JjaC5UZW5zb3IsIHRva2VuX2lkczogT3B0aW9uYWxbdG9yY2guVGVuc29yXSA9IE5vbmUKICAgICkgLT4gdG9yY2guVGVuc29yOgogICAgICAgICIiIkZvcndhcmQgcGFzcy4KCiAgICAgICAgQXJnczoKICAgICAgICAgICAgaGlkZGVuOiAoQiwgVCwgZGltKSBjdXJyZW50IGhpZGRlbiBzdGF0ZQogICAgICAgICAgICB0b2tlbl9pZHM6IChCLCBUKSBpbnB1dCB0b2tlbiBJRHMgZm9yIG4tZ3JhbSBoYXNoaW5nLgogICAgICAgICAgICAgICAgICAgICAgIElmIE5vbmUsIHVzZXMgYXJnbWF4IG9mIGhpZGRlbiBwcm9qZWN0aW9ucyBhcyBwcm94eS4KICAgICAgICBSZXR1cm5zOgogICAgICAgICAgICBvdXRwdXQ6IChCLCBULCBkaW0pIG1lbW9yeSBpbmplY3Rpb24gZm9yIHJlc2lkdWFsIHN0cmVhbQogICAgICAgICIiIgogICAgICAgIEIsIFQsIF8gPSBoaWRkZW4uc2hhcGUKCiAgICAgICAgaWYgdG9rZW5faWRzIGlzIE5vbmU6CiAgICAgICAgICAgICMgRmFsbGJhY2s6IGRlcml2ZSBwc2V1ZG8tdG9rZW4taWRzIGZyb20gaGlkZGVuIHN0YXRlCiAgICAgICAgICAgIHRva2VuX2lkcyA9IGhpZGRlbi5tZWFuKGRpbT0tMSkubG9uZygpICUgc2VsZi50YWJsZV9zaXplCgogICAgICAgICMgUmV0cmlldmUgYW5kIGNvbmNhdGVuYXRlIGFjcm9zcyBuLWdyYW0gb3JkZXJzIGFuZCBoYXNoIGhlYWRzCiAgICAgICAgYnJhbmNoX291dHB1dHMgPSBbXQogICAgICAgIGZvciBuIGluIHJhbmdlKDIsIHNlbGYubWF4X25ncmFtICsgMSk6CiAgICAgICAgICAgIGZvciBrIGluIHJhbmdlKHNlbGYubl9oZWFkcyk6CiAgICAgICAgICAgICAgICBpbmRpY2VzID0gc2VsZi5faGFzaF9uZ3JhbSh0b2tlbl9pZHMsIG4sIGspICAjIChCLCBUKQogICAgICAgICAgICAgICAgdGFibGUgPSBzZWxmLmVtYmVkZGluZ3NbZiJ7bn1fe2t9Il0gICMgKHRhYmxlX3NpemUsIGVuZ3JhbV9kaW0pCiAgICAgICAgICAgICAgICByZXRyaWV2ZWQgPSB0YWJsZVtpbmRpY2VzXSAgIyAoQiwgVCwgZW5ncmFtX2RpbSkKICAgICAgICAgICAgICAgIGJyYW5jaF9vdXRwdXRzLmFwcGVuZChyZXRyaWV2ZWQpCgogICAgICAgICMgKEIsIFQsIGVuZ3JhbV9kaW0gKiBuX2hlYWRzICogKG1heF9uZ3JhbSAtIDEpKQogICAgICAgIG1lbW9yeSA9IHRvcmNoLmNhdChicmFuY2hfb3V0cHV0cywgZGltPS0xKQoKICAgICAgICAjIENhdXNhbCBjb252b2x1dGlvbiBvdmVyIHNlcXVlbmNlIGRpbWVuc2lvbgogICAgICAgICMgUGFkIGxlZnQgZm9yIGNhdXNhbGl0eSAoa2VybmVsX3NpemUgLSAxID0gMykKICAgICAgICBjb252X2luID0gbWVtb3J5LnRyYW5zcG9zZSgxLCAyKSAgIyAoQiwgQywgVCkKICAgICAgICBjb252X2luID0gRi5wYWQoCiAgICAgICAgICAgIGNvbnZfaW4sCiAgICAgICAgICAgICgoc2VsZi5icmFuY2hfY29udi5rZXJuZWxfc2l6ZVswXSAtIDEpICogc2VsZi5icmFuY2hfY29udi5kaWxhdGlvblswXSwgMCksCiAgICAgICAgKQogICAgICAgIGNvbnZfb3V0ID0gc2VsZi5icmFuY2hfY29udihjb252X2luKSAgIyAoQiwgQywgVCkKICAgICAgICBtZW1vcnkgPSBjb252X291dC50cmFuc3Bvc2UoMSwgMikgICMgKEIsIFQsIEMpCgogICAgICAgICMgQ29udGV4dC1hd2FyZSBnYXRpbmcKICAgICAgICBxdWVyeSA9IHNlbGYuZ2F0ZV9xdWVyeShoaWRkZW4pICAjIChCLCBULCBlbmdyYW1fZGltKQogICAgICAgIGtleSA9IHNlbGYuZ2F0ZV9rZXkobWVtb3J5KSAgIyAoQiwgVCwgZW5ncmFtX2RpbSkKICAgICAgICBnYXRlID0gdG9yY2guc2lnbW9pZCgKICAgICAgICAgICAgKHF1ZXJ5ICoga2V5KS5zdW0oZGltPS0xLCBrZWVwZGltPVRydWUpICogc2VsZi5nYXRlX3NjYWxlCiAgICAgICAgKSAgIyAoQiwgVCwgMSkKICAgICAgICB2YWx1ZSA9IHNlbGYuZ2F0ZV92YWx1ZShtZW1vcnkpICAjIChCLCBULCBkaW0pCgogICAgICAgIHJldHVybiBnYXRlICogdmFsdWUKCgpkZWYgX3Npbmtob3JuX2tub3BwKGxvZ2l0czogdG9yY2guVGVuc29yLCBuX2l0ZXJzOiBpbnQgPSA3KSAtPiB0b3JjaC5UZW5zb3I6CiAgICBNID0gdG9yY2guZXhwKGxvZ2l0cy5jbGFtcCgtMTAsIDEwKSkKICAgIGZvciBfIGluIHJhbmdlKG5faXRlcnMpOgogICAgICAgIE0gPSBNIC8gTS5zdW0oZGltPS0xLCBrZWVwZGltPVRydWUpLmNsYW1wKG1pbj0xZS0xMCkKICAgICAgICBNID0gTSAvIE0uc3VtKGRpbT0tMiwga2VlcGRpbT1UcnVlKS5jbGFtcChtaW49MWUtMTApCiAgICByZXR1cm4gTQoKCmNsYXNzIE1hbmlmb2xkSHlwZXJDb25uZWN0aW9uKG5uLk1vZHVsZSk6CiAgICBkZWYgX19pbml0X18oc2VsZiwgZGltOiBpbnQsIGV4cGFuc2lvbjogaW50ID0gMikgLT4gTm9uZToKICAgICAgICBzdXBlcigpLl9faW5pdF9fKCkKICAgICAgICBzZWxmLmRpbSA9IGRpbQogICAgICAgIHNlbGYuZXhwYW5zaW9uID0gZXhwYW5zaW9uCiAgICAgICAgbiA9IGV4cGFuc2lvbgoKICAgICAgICBzZWxmLmV4cGFuZF9mbiA9ICJkdXBsaWNhdGUiCiAgICAgICAgc2VsZi5jb2xsYXBzZV9mbiA9ICJtZWFuIgoKICAgICAgICBzZWxmLmJpYXNfcHJlID0gbm4uUGFyYW1ldGVyKHRvcmNoLnplcm9zKDEsIG4pKQogICAgICAgIHNlbGYuYmlhc19wb3N0ID0gbm4uUGFyYW1ldGVyKHRvcmNoLnplcm9zKDEsIG4pKQogICAgICAgIHNlbGYuYmlhc19yZXMgPSBubi5QYXJhbWV0ZXIodG9yY2guemVyb3MobiwgbikpCgogICAgICAgIHNlbGYudGhldGFfcHJlID0gbm4uTGluZWFyKG4gKiBkaW0sIG4sIGJpYXM9RmFsc2UpCiAgICAgICAgc2VsZi50aGV0YV9wb3N0ID0gbm4uTGluZWFyKG4gKiBkaW0sIG4sIGJpYXM9RmFsc2UpCiAgICAgICAgc2VsZi50aGV0YV9yZXMgPSBubi5MaW5lYXIobiAqIGRpbSwgbiAqIG4sIGJpYXM9RmFsc2UpCgogICAgICAgIHNlbGYuYWxwaGFfcHJlID0gbm4uUGFyYW1ldGVyKHRvcmNoLnRlbnNvcigwLjApKQogICAgICAgIHNlbGYuYWxwaGFfcG9zdCA9IG5uLlBhcmFtZXRlcih0b3JjaC50ZW5zb3IoMC4wKSkKICAgICAgICBzZWxmLmFscGhhX3JlcyA9IG5uLlBhcmFtZXRlcih0b3JjaC50ZW5zb3IoMC4wKSkKCiAgICBkZWYgX2NvbXB1dGVfbWFwcGluZ3MoCiAgICAgICAgc2VsZiwgeF9leHBhbmRlZDogdG9yY2guVGVuc29yCiAgICApIC0+IFR1cGxlW3RvcmNoLlRlbnNvciwgdG9yY2guVGVuc29yLCB0b3JjaC5UZW5zb3JdOgogICAgICAgIEIsIFQsIF8gPSB4X2V4cGFuZGVkLnNoYXBlCiAgICAgICAgbiA9IHNlbGYuZXhwYW5zaW9uCgogICAgICAgIHhfbm9ybSA9IEYucm1zX25vcm0oeF9leHBhbmRlZCwgW3hfZXhwYW5kZWQuc2hhcGVbLTFdXSkKCiAgICAgICAgZF9wcmUgPSB0b3JjaC50YW5oKHNlbGYudGhldGFfcHJlKHhfbm9ybSkpCiAgICAgICAgZF9wb3N0ID0gdG9yY2gudGFuaChzZWxmLnRoZXRhX3Bvc3QoeF9ub3JtKSkKICAgICAgICBkX3JlcyA9IHNlbGYudGhldGFfcmVzKHhfbm9ybSkKCiAgICAgICAgSF9wcmVfcmF3ID0gdG9yY2guc2lnbW9pZChzZWxmLmFscGhhX3ByZSAqIGRfcHJlICsgc2VsZi5iaWFzX3ByZSkKICAgICAgICBIX3Bvc3RfcmF3ID0gMi4wICogdG9yY2guc2lnbW9pZChzZWxmLmFscGhhX3Bvc3QgKiBkX3Bvc3QgKyBzZWxmLmJpYXNfcG9zdCkKICAgICAgICBIX3Jlc19yYXcgPSAoc2VsZi5hbHBoYV9yZXMgKiBkX3JlcyArIHNlbGYuYmlhc19yZXMucmVzaGFwZSgxLCAxLCAtMSkpLnJlc2hhcGUoCiAgICAgICAgICAgIEIsIFQsIG4sIG4KICAgICAgICApCgogICAgICAgIEhfcmVzID0gX3Npbmtob3JuX2tub3BwKEhfcmVzX3JhdykKCiAgICAgICAgcmV0dXJuIEhfcHJlX3Jhdy51bnNxdWVlemUoLTIpLCBIX3Bvc3RfcmF3LnVuc3F1ZWV6ZSgtMiksIEhfcmVzCgogICAgZGVmIGV4cGFuZF9zdHJlYW0oc2VsZiwgeDogdG9yY2guVGVuc29yKSAtPiB0b3JjaC5UZW5zb3I6CiAgICAgICAgcmV0dXJuIHgucmVwZWF0KDEsIDEsIHNlbGYuZXhwYW5zaW9uKQoKICAgIGRlZiBjb2xsYXBzZV9zdHJlYW0oc2VsZiwgeF9leHBhbmRlZDogdG9yY2guVGVuc29yKSAtPiB0b3JjaC5UZW5zb3I6CiAgICAgICAgQiwgVCwgXyA9IHhfZXhwYW5kZWQuc2hhcGUKICAgICAgICBuID0gc2VsZi5leHBhbnNpb24KICAgICAgICBDID0gc2VsZi5kaW0KICAgICAgICByZXR1cm4geF9leHBhbmRlZC52aWV3KEIsIFQsIG4sIEMpLm1lYW4oZGltPS0yKQoKICAgIGRlZiBwcmVfbWl4KHNlbGYsIHhfZXhwYW5kZWQ6IHRvcmNoLlRlbnNvciwgSF9wcmU6IHRvcmNoLlRlbnNvcikgLT4gdG9yY2guVGVuc29yOgogICAgICAgIEIsIFQsIF8gPSB4X2V4cGFuZGVkLnNoYXBlCiAgICAgICAgbiA9IHNlbGYuZXhwYW5zaW9uCiAgICAgICAgeF9zdHJlYW1zID0geF9leHBhbmRlZC52aWV3KEIsIFQsIG4sIHNlbGYuZGltKQogICAgICAgIHJldHVybiAoSF9wcmUgQCB4X3N0cmVhbXMpLnNxdWVlemUoLTIpCgogICAgZGVmIHBvc3RfcmVzX21peCgKICAgICAgICBzZWxmLAogICAgICAgIGxheWVyX291dHB1dDogdG9yY2guVGVuc29yLAogICAgICAgIHhfZXhwYW5kZWQ6IHRvcmNoLlRlbnNvciwKICAgICAgICBIX3Bvc3Q6IHRvcmNoLlRlbnNvciwKICAgICAgICBIX3JlczogdG9yY2guVGVuc29yLAogICAgKSAtPiB0b3JjaC5UZW5zb3I6CiAgICAgICAgQiwgVCwgXyA9IHhfZXhwYW5kZWQuc2hhcGUKICAgICAgICBuID0gc2VsZi5leHBhbnNpb24KICAgICAgICBDID0gc2VsZi5kaW0KCiAgICAgICAgeF9zdHJlYW1zID0geF9leHBhbmRlZC52aWV3KEIsIFQsIG4sIEMpCiAgICAgICAgbWl4ZWQgPSB0b3JjaC5tYXRtdWwoSF9yZXMsIHhfc3RyZWFtcykKICAgICAgICBwb3N0X291dCA9IHRvcmNoLm1hdG11bChIX3Bvc3QudHJhbnNwb3NlKC0yLCAtMSksIGxheWVyX291dHB1dC51bnNxdWVlemUoLTIpKQoKICAgICAgICByZXN1bHQgPSBtaXhlZCArIHBvc3Rfb3V0CiAgICAgICAgcmV0dXJuIHJlc3VsdC5yZXNoYXBlKEIsIFQsIG4gKiBDKQoKCmNsYXNzIFRyYW5zZm9ybWVyQmxvY2sobm4uTW9kdWxlKToKICAgIGRlZiBfX2luaXRfXygKICAgICAgICBzZWxmLAogICAgICAgIGRpbTogaW50LAogICAgICAgIG5faGVhZHM6IGludCwKICAgICAgICBuX2t2X2hlYWRzOiBpbnQsCiAgICAgICAgaGVhZF9kaW06IGludCwKICAgICAgICBmZm5fZGltOiBpbnQsCiAgICAgICAgZHJvcG91dDogZmxvYXQsCiAgICAgICAgc2xpZGluZ193aW5kb3c6IGludCwKICAgICAgICByb3BlX2ZyYWN0aW9uOiBmbG9hdCwKICAgICAgICBlbmdyYW1fZGltOiBpbnQgPSAwLAogICAgICAgIGVuZ3JhbV9oZWFkczogaW50ID0gNCwKICAgICAgICBlbmdyYW1fdGFibGVfc2l6ZTogaW50ID0gODE5MiwKICAgICAgICBlbmdyYW1fbWF4X25ncmFtOiBpbnQgPSAzLAogICAgICAgIG1oY19leHBhbnNpb246IGludCA9IDEsCiAgICApIC0+IE5vbmU6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygpCiAgICAgICAgc2VsZi5ub3JtMSA9IFJNU05vcm0oZGltKQogICAgICAgIHNlbGYuYXR0biA9IENhdXNhbFNlbGZBdHRlbnRpb24oCiAgICAgICAgICAgIGRpbT1kaW0sCiAgICAgICAgICAgIG5faGVhZHM9bl9oZWFkcywKICAgICAgICAgICAgbl9rdl9oZWFkcz1uX2t2X2hlYWRzLAogICAgICAgICAgICBoZWFkX2RpbT1oZWFkX2RpbSwKICAgICAgICAgICAgZHJvcG91dD1kcm9wb3V0LAogICAgICAgICAgICBzbGlkaW5nX3dpbmRvdz1zbGlkaW5nX3dpbmRvdywKICAgICAgICAgICAgcm9wZV9mcmFjdGlvbj1yb3BlX2ZyYWN0aW9uLAogICAgICAgICkKICAgICAgICBzZWxmLm5vcm0yID0gUk1TTm9ybShkaW0pCiAgICAgICAgc2VsZi5mZm4gPSBTd2lHTFUoZGltLCBmZm5fZGltLCBkcm9wb3V0KQogICAgICAgIHNlbGYudXNlX2VuZ3JhbSA9IGVuZ3JhbV9kaW0gPiAwCiAgICAgICAgaWYgc2VsZi51c2VfZW5ncmFtOgogICAgICAgICAgICBzZWxmLmVuZ3JhbSA9IEVuZ3JhbUJsb2NrKAogICAgICAgICAgICAgICAgZGltPWRpbSwKICAgICAgICAgICAgICAgIGVuZ3JhbV9kaW09ZW5ncmFtX2RpbSwKICAgICAgICAgICAgICAgIG5faGVhZHM9ZW5ncmFtX2hlYWRzLAogICAgICAgICAgICAgICAgdGFibGVfc2l6ZT1lbmdyYW1fdGFibGVfc2l6ZSwKICAgICAgICAgICAgICAgIG1heF9uZ3JhbT1lbmdyYW1fbWF4X25ncmFtLAogICAgICAgICAgICApCiAgICAgICAgICAgIHNlbGYuZW5ncmFtX25vcm0gPSBSTVNOb3JtKGRpbSkKICAgICAgICBzZWxmLnVzZV9taGMgPSBtaGNfZXhwYW5zaW9uID4gMQogICAgICAgIGlmIHNlbGYudXNlX21oYzoKICAgICAgICAgICAgc2VsZi5taGNfYXR0biA9IE1hbmlmb2xkSHlwZXJDb25uZWN0aW9uKGRpbSwgZXhwYW5zaW9uPW1oY19leHBhbnNpb24pCiAgICAgICAgICAgIHNlbGYubWhjX2ZmbiA9IE1hbmlmb2xkSHlwZXJDb25uZWN0aW9uKGRpbSwgZXhwYW5zaW9uPW1oY19leHBhbnNpb24pCgogICAgZGVmIGZvcndhcmQoCiAgICAgICAgc2VsZiwKICAgICAgICB4OiB0b3JjaC5UZW5zb3IsCiAgICAgICAgaXNfZ2xvYmFsOiBib29sLAogICAgICAgIHBhc3Rfa3Y6IE9wdGlvbmFsW1R1cGxlW3RvcmNoLlRlbnNvciwgdG9yY2guVGVuc29yXV0gPSBOb25lLAogICAgICAgIHVzZV9jYWNoZTogYm9vbCA9IEZhbHNlLAogICAgICAgIHRva2VuX2lkczogT3B0aW9uYWxbdG9yY2guVGVuc29yXSA9IE5vbmUsCiAgICApIC0+IFR1cGxlW3RvcmNoLlRlbnNvciwgT3B0aW9uYWxbVHVwbGVbdG9yY2guVGVuc29yLCB0b3JjaC5UZW5zb3JdXV06CiAgICAgICAgaWYgc2VsZi51c2VfbWhjOgogICAgICAgICAgICB4X2V4cCA9IHNlbGYubWhjX2F0dG4uZXhwYW5kX3N0cmVhbSh4KQogICAgICAgICAgICBIX3ByZSwgSF9wb3N0LCBIX3JlcyA9IHNlbGYubWhjX2F0dG4uX2NvbXB1dGVfbWFwcGluZ3MoeF9leHApCiAgICAgICAgICAgIGF0dG5faW4gPSBzZWxmLm1oY19hdHRuLnByZV9taXgoeF9leHAsIEhfcHJlKQogICAgICAgICAgICBhdHRuX291dCwgbmV3X2t2ID0gc2VsZi5hdHRuKAogICAgICAgICAgICAgICAgc2VsZi5ub3JtMShhdHRuX2luKSwgaXNfZ2xvYmFsLCBwYXN0X2t2LCB1c2VfY2FjaGUKICAgICAgICAgICAgKQogICAgICAgICAgICB4X2V4cCA9IHNlbGYubWhjX2F0dG4ucG9zdF9yZXNfbWl4KGF0dG5fb3V0LCB4X2V4cCwgSF9wb3N0LCBIX3JlcykKICAgICAgICAgICAgaWYgc2VsZi51c2VfZW5ncmFtOgogICAgICAgICAgICAgICAgY29sbGFwc2VkID0gc2VsZi5taGNfYXR0bi5jb2xsYXBzZV9zdHJlYW0oeF9leHApCiAgICAgICAgICAgICAgICBjb2xsYXBzZWQgPSBjb2xsYXBzZWQgKyBzZWxmLmVuZ3JhbSgKICAgICAgICAgICAgICAgICAgICBzZWxmLmVuZ3JhbV9ub3JtKGNvbGxhcHNlZCksIHRva2VuX2lkcz10b2tlbl9pZHMKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIHhfZXhwID0gc2VsZi5taGNfYXR0bi5leHBhbmRfc3RyZWFtKGNvbGxhcHNlZCkKICAgICAgICAgICAgSF9wcmUyLCBIX3Bvc3QyLCBIX3JlczIgPSBzZWxmLm1oY19mZm4uX2NvbXB1dGVfbWFwcGluZ3MoeF9leHApCiAgICAgICAgICAgIGZmbl9pbiA9IHNlbGYubWhjX2Zmbi5wcmVfbWl4KHhfZXhwLCBIX3ByZTIpCiAgICAgICAgICAgIGZmbl9vdXQgPSBzZWxmLmZmbihzZWxmLm5vcm0yKGZmbl9pbikpCiAgICAgICAgICAgIHhfZXhwID0gc2VsZi5taGNfZmZuLnBvc3RfcmVzX21peChmZm5fb3V0LCB4X2V4cCwgSF9wb3N0MiwgSF9yZXMyKQogICAgICAgICAgICB4ID0gc2VsZi5taGNfYXR0bi5jb2xsYXBzZV9zdHJlYW0oeF9leHApCiAgICAgICAgZWxzZToKICAgICAgICAgICAgYXR0bl9vdXQsIG5ld19rdiA9IHNlbGYuYXR0bihzZWxmLm5vcm0xKHgpLCBpc19nbG9iYWwsIHBhc3Rfa3YsIHVzZV9jYWNoZSkKICAgICAgICAgICAgeCA9IHggKyBhdHRuX291dAogICAgICAgICAgICBpZiBzZWxmLnVzZV9lbmdyYW06CiAgICAgICAgICAgICAgICB4ID0geCArIHNlbGYuZW5ncmFtKHNlbGYuZW5ncmFtX25vcm0oeCksIHRva2VuX2lkcz10b2tlbl9pZHMpCiAgICAgICAgICAgIHggPSB4ICsgc2VsZi5mZm4oc2VsZi5ub3JtMih4KSkKICAgICAgICByZXR1cm4geCwgbmV3X2t2CgoKY2xhc3MgVGlueU1lbW9yeUxNKG5uLk1vZHVsZSk6CiAgICBkZWYgX19pbml0X18oCiAgICAgICAgc2VsZiwKICAgICAgICB2b2NhYl9zaXplOiBpbnQsCiAgICAgICAgZGltOiBpbnQsCiAgICAgICAgbl91bmlxdWVfbGF5ZXJzOiBpbnQsCiAgICAgICAgbl9sb2dpY2FsX2xheWVyczogaW50LAogICAgICAgIG5faGVhZHM6IGludCwKICAgICAgICBuX2t2X2hlYWRzOiBpbnQsCiAgICAgICAgZmZuX2RpbTogaW50LAogICAgICAgIGRyb3BvdXQ6IGZsb2F0LAogICAgICAgIG10cF9ob3Jpem9uczogU2VxdWVuY2VbaW50XSwKICAgICAgICBncmFkX2NoZWNrcG9pbnQ6IGJvb2wsCiAgICAgICAgc2xpZGluZ193aW5kb3c6IGludCA9IDUxMiwKICAgICAgICByb3BlX2ZyYWN0aW9uOiBmbG9hdCA9IDAuNSwKICAgICAgICBlbWJlZF9zY2FsZTogYm9vbCA9IFRydWUsCiAgICAgICAgZW5ncmFtX2RpbTogaW50ID0gMCwKICAgICAgICBlbmdyYW1faGVhZHM6IGludCA9IDQsCiAgICAgICAgZW5ncmFtX3RhYmxlX3NpemU6IGludCA9IDgxOTIsCiAgICAgICAgZW5ncmFtX21heF9uZ3JhbTogaW50ID0gMywKICAgICAgICBtaGNfZXhwYW5zaW9uOiBpbnQgPSAxLAogICAgKSAtPiBOb25lOgogICAgICAgIHN1cGVyKCkuX19pbml0X18oKQogICAgICAgIHNlbGYuZGltID0gZGltCiAgICAgICAgc2VsZi5uX3VuaXF1ZV9sYXllcnMgPSBuX3VuaXF1ZV9sYXllcnMKICAgICAgICBzZWxmLm5fbG9naWNhbF9sYXllcnMgPSBuX2xvZ2ljYWxfbGF5ZXJzCiAgICAgICAgc2VsZi5ncmFkX2NoZWNrcG9pbnQgPSBncmFkX2NoZWNrcG9pbnQKICAgICAgICBzZWxmLmVtYmVkX3NjYWxlX2ZhY3RvciA9IG1hdGguc3FydChkaW0pIGlmIGVtYmVkX3NjYWxlIGVsc2UgMS4wCiAgICAgICAgaGVhZF9kaW0gPSBkaW0gLy8gbl9oZWFkcwoKICAgICAgICBzZWxmLmVtYmVkX3Rva2VucyA9IG5uLkVtYmVkZGluZyh2b2NhYl9zaXplLCBkaW0pCiAgICAgICAgc2VsZi5oZWFkID0gbm4uTGluZWFyKGRpbSwgdm9jYWJfc2l6ZSwgYmlhcz1GYWxzZSkKICAgICAgICBzZWxmLmhlYWQud2VpZ2h0ID0gc2VsZi5lbWJlZF90b2tlbnMud2VpZ2h0CgogICAgICAgIHNlbGYub3V0cHV0X2JpYXMgPSBubi5QYXJhbWV0ZXIodG9yY2guemVyb3Modm9jYWJfc2l6ZSkpCgogICAgICAgIHNlbGYuYmxvY2tzID0gbm4uTW9kdWxlTGlzdCgKICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgVHJhbnNmb3JtZXJCbG9jaygKICAgICAgICAgICAgICAgICAgICBkaW09ZGltLAogICAgICAgICAgICAgICAgICAgIG5faGVhZHM9bl9oZWFkcywKICAgICAgICAgICAgICAgICAgICBuX2t2X2hlYWRzPW5fa3ZfaGVhZHMsCiAgICAgICAgICAgICAgICAgICAgaGVhZF9kaW09aGVhZF9kaW0sCiAgICAgICAgICAgICAgICAgICAgZmZuX2RpbT1mZm5fZGltLAogICAgICAgICAgICAgICAgICAgIGRyb3BvdXQ9ZHJvcG91dCwKICAgICAgICAgICAgICAgICAgICBzbGlkaW5nX3dpbmRvdz1zbGlkaW5nX3dpbmRvdywKICAgICAgICAgICAgICAgICAgICByb3BlX2ZyYWN0aW9uPXJvcGVfZnJhY3Rpb24sCiAgICAgICAgICAgICAgICAgICAgZW5ncmFtX2RpbT1lbmdyYW1fZGltLAogICAgICAgICAgICAgICAgICAgIGVuZ3JhbV9oZWFkcz1lbmdyYW1faGVhZHMsCiAgICAgICAgICAgICAgICAgICAgZW5ncmFtX3RhYmxlX3NpemU9ZW5ncmFtX3RhYmxlX3NpemUsCiAgICAgICAgICAgICAgICAgICAgZW5ncmFtX21heF9uZ3JhbT1lbmdyYW1fbWF4X25ncmFtLAogICAgICAgICAgICAgICAgICAgIG1oY19leHBhbnNpb249bWhjX2V4cGFuc2lvbiwKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIGZvciBfIGluIHJhbmdlKG5fdW5pcXVlX2xheWVycykKICAgICAgICAgICAgXQogICAgICAgICkKICAgICAgICBzZWxmLm5vcm0gPSBSTVNOb3JtKGRpbSkKCiAgICAgICAgc2VsZi5tdHBfaG9yaXpvbnMgPSBzb3J0ZWQoe2ludChoKSBmb3IgaCBpbiBtdHBfaG9yaXpvbnMgaWYgaW50KGgpID4gMX0pCiAgICAgICAgc2VsZi5tdHBfYWRhcHRlcnMgPSBubi5Nb2R1bGVEaWN0KAogICAgICAgICAgICB7c3RyKGgpOiBubi5MaW5lYXIoZGltLCBkaW0sIGJpYXM9RmFsc2UpIGZvciBoIGluIHNlbGYubXRwX2hvcml6b25zfQogICAgICAgICkKICAgICAgICBzZWxmLm10cF9ub3JtcyA9IG5uLk1vZHVsZURpY3QoCiAgICAgICAgICAgIHtzdHIoaCk6IFJNU05vcm0oZGltKSBmb3IgaCBpbiBzZWxmLm10cF9ob3Jpem9uc30KICAgICAgICApCgogICAgICAgIHJlc19zY2FsZSA9ICgyICogbl91bmlxdWVfbGF5ZXJzKSAqKiAtMC41CiAgICAgICAgZm9yIGJsb2NrIGluIHNlbGYuYmxvY2tzOgogICAgICAgICAgICBibG9jay5hdHRuLndvLndlaWdodC5kYXRhLm11bF8ocmVzX3NjYWxlKQogICAgICAgICAgICBibG9jay5mZm4uZG93bi53ZWlnaHQuZGF0YS5tdWxfKHJlc19zY2FsZSkKCiAgICBkZWYgcmVzaXplX3Rva2VuX2VtYmVkZGluZ3Moc2VsZiwgbmV3X3ZvY2FiX3NpemU6IGludCkgLT4gTm9uZToKICAgICAgICBvbGRfdm9jYWJfc2l6ZSA9IHNlbGYuZW1iZWRfdG9rZW5zLm51bV9lbWJlZGRpbmdzCiAgICAgICAgaWYgbmV3X3ZvY2FiX3NpemUgPT0gb2xkX3ZvY2FiX3NpemU6CiAgICAgICAgICAgIHJldHVybgogICAgICAgIGRldmljZSA9IHNlbGYuZW1iZWRfdG9rZW5zLndlaWdodC5kZXZpY2UKICAgICAgICBvbGRfZW1iZWRfd2VpZ2h0ID0gc2VsZi5lbWJlZF90b2tlbnMud2VpZ2h0LmRhdGEuY2xvbmUoKQogICAgICAgIHNlbGYuZW1iZWRfdG9rZW5zID0gbm4uRW1iZWRkaW5nKAogICAgICAgICAgICBuZXdfdm9jYWJfc2l6ZSwgc2VsZi5lbWJlZF90b2tlbnMuZW1iZWRkaW5nX2RpbQogICAgICAgICkudG8oZGV2aWNlKQogICAgICAgIHNlbGYuaGVhZCA9IG5uLkxpbmVhcigKICAgICAgICAgICAgc2VsZi5lbWJlZF90b2tlbnMuZW1iZWRkaW5nX2RpbSwgbmV3X3ZvY2FiX3NpemUsIGJpYXM9RmFsc2UKICAgICAgICApLnRvKGRldmljZSkKICAgICAgICBzZWxmLmhlYWQud2VpZ2h0ID0gc2VsZi5lbWJlZF90b2tlbnMud2VpZ2h0CiAgICAgICAgb2xkX2JpYXMgPSBzZWxmLm91dHB1dF9iaWFzLmRhdGEuY2xvbmUoKQogICAgICAgIHNlbGYub3V0cHV0X2JpYXMgPSBubi5QYXJhbWV0ZXIodG9yY2guemVyb3MobmV3X3ZvY2FiX3NpemUsIGRldmljZT1kZXZpY2UpKQogICAgICAgIGNvcHlfc2l6ZSA9IG1pbihvbGRfdm9jYWJfc2l6ZSwgbmV3X3ZvY2FiX3NpemUpCiAgICAgICAgc2VsZi5vdXRwdXRfYmlhcy5kYXRhWzpjb3B5X3NpemVdID0gb2xkX2JpYXNbOmNvcHlfc2l6ZV0KICAgICAgICBzZWxmLmVtYmVkX3Rva2Vucy53ZWlnaHQuZGF0YVs6Y29weV9zaXplXSA9IG9sZF9lbWJlZF93ZWlnaHRbOmNvcHlfc2l6ZV0KCiAgICBkZWYgX2J1aWxkX2xvZ2ljYWxfbGF5ZXJzKHNlbGYpIC0+IExpc3RbVHVwbGVbbm4uTW9kdWxlLCBpbnRdXToKICAgICAgICBsb2dpY2FsID0gW10KICAgICAgICBibG9ja3NfbGlzdCA9IGxpc3Qoc2VsZi5ibG9ja3MpCiAgICAgICAgZnVsbF9zZXF1ZW5jZSA9IGJsb2Nrc19saXN0ICsgYmxvY2tzX2xpc3QKICAgICAgICBmb3IgbG9naWNhbF9pZHgsIGJsb2NrIGluIGVudW1lcmF0ZShmdWxsX3NlcXVlbmNlWzogc2VsZi5uX2xvZ2ljYWxfbGF5ZXJzXSk6CiAgICAgICAgICAgIGxvZ2ljYWwuYXBwZW5kKChibG9jaywgbG9naWNhbF9pZHgpKQogICAgICAgIHJldHVybiBsb2dpY2FsCgogICAgZGVmIGZvcndhcmQoCiAgICAgICAgc2VsZiwKICAgICAgICBpZHM6IHRvcmNoLlRlbnNvciwKICAgICAgICB1c2VfY2FjaGU6IGJvb2wgPSBGYWxzZSwKICAgICAgICBwYXN0X2tleV92YWx1ZXM6IE9wdGlvbmFsWwogICAgICAgICAgICBMaXN0W09wdGlvbmFsW1R1cGxlW3RvcmNoLlRlbnNvciwgdG9yY2guVGVuc29yXV1dCiAgICAgICAgXSA9IE5vbmUsCiAgICAgICAgcmV0dXJuX2hpZGRlbjogYm9vbCA9IEZhbHNlLAogICAgKSAtPiBUdXBsZVsKICAgICAgICB0b3JjaC5UZW5zb3IsCiAgICAgICAgRGljdFtpbnQsIHRvcmNoLlRlbnNvcl0sCiAgICAgICAgT3B0aW9uYWxbdG9yY2guVGVuc29yXSwKICAgICAgICBPcHRpb25hbFtMaXN0W1R1cGxlW3RvcmNoLlRlbnNvciwgdG9yY2guVGVuc29yXV1dLAogICAgXToKICAgICAgICBCLCBUID0gaWRzLnNoYXBlCiAgICAgICAgeCA9IHNlbGYuZW1iZWRfdG9rZW5zKGlkcykgKiBzZWxmLmVtYmVkX3NjYWxlX2ZhY3RvcgogICAgICAgIHRva2VuX2lkcyA9IGlkcwoKICAgICAgICBsb2dpY2FsX2xheWVycyA9IHNlbGYuX2J1aWxkX2xvZ2ljYWxfbGF5ZXJzKCkKICAgICAgICBuZXdfcGFzdF9rZXlfdmFsdWVzOiBPcHRpb25hbFtMaXN0W1R1cGxlW3RvcmNoLlRlbnNvciwgdG9yY2guVGVuc29yXV1dID0gKAogICAgICAgICAgICBbXSBpZiB1c2VfY2FjaGUgZWxzZSBOb25lCiAgICAgICAgKQoKICAgICAgICBsYXN0X2xvZ2ljYWxfaWR4ID0gbGVuKGxvZ2ljYWxfbGF5ZXJzKSAtIDEKICAgICAgICBmb3IgbGF5ZXJfaWR4LCAoYmxvY2ssIGxvZ2ljYWxfaWR4KSBpbiBlbnVtZXJhdGUobG9naWNhbF9sYXllcnMpOgogICAgICAgICAgICBpc19nbG9iYWwgPSBsb2dpY2FsX2lkeCAlIDIgPT0gMCBvciBsYXllcl9pZHggPT0gbGFzdF9sb2dpY2FsX2lkeAogICAgICAgICAgICBwYXN0X2t2ID0gKAogICAgICAgICAgICAgICAgcGFzdF9rZXlfdmFsdWVzW2xheWVyX2lkeF0KICAgICAgICAgICAgICAgIGlmIHBhc3Rfa2V5X3ZhbHVlcyBpcyBub3QgTm9uZSBhbmQgbGF5ZXJfaWR4IDwgbGVuKHBhc3Rfa2V5X3ZhbHVlcykKICAgICAgICAgICAgICAgIGVsc2UgTm9uZQogICAgICAgICAgICApCgogICAgICAgICAgICBpZiBzZWxmLmdyYWRfY2hlY2twb2ludCBhbmQgc2VsZi50cmFpbmluZyBhbmQgbm90IHVzZV9jYWNoZToKICAgICAgICAgICAgICAgIHgsIGxheWVyX2t2ID0gY2hlY2twb2ludCgKICAgICAgICAgICAgICAgICAgICBibG9jaywKICAgICAgICAgICAgICAgICAgICB4LAogICAgICAgICAgICAgICAgICAgIGlzX2dsb2JhbCwKICAgICAgICAgICAgICAgICAgICBwYXN0X2t2LAogICAgICAgICAgICAgICAgICAgIHVzZV9jYWNoZSwKICAgICAgICAgICAgICAgICAgICB0b2tlbl9pZHMsCiAgICAgICAgICAgICAgICAgICAgdXNlX3JlZW50cmFudD1UcnVlLAogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgeCwgbGF5ZXJfa3YgPSBibG9jayh4LCBpc19nbG9iYWwsIHBhc3Rfa3YsIHVzZV9jYWNoZSwgdG9rZW5faWRzKQoKICAgICAgICAgICAgaWYgbmV3X3Bhc3Rfa2V5X3ZhbHVlcyBpcyBub3QgTm9uZToKICAgICAgICAgICAgICAgIG5ld19wYXN0X2tleV92YWx1ZXMuYXBwZW5kKGxheWVyX2t2KQoKICAgICAgICB4ID0gc2VsZi5ub3JtKHgpCiAgICAgICAgaF9vdXQgPSB4IGlmIHJldHVybl9oaWRkZW4gZWxzZSBOb25lCiAgICAgICAgbG9naXRzID0gc2VsZi5oZWFkKHgpCiAgICAgICAgaWYgc2VsZi5lbWJlZF9zY2FsZV9mYWN0b3IgIT0gMS4wOgogICAgICAgICAgICBsb2dpdHMgPSBsb2dpdHMgLyBzZWxmLmVtYmVkX3NjYWxlX2ZhY3RvcgogICAgICAgIGxvZ2l0cyA9IGxvZ2l0cyArIHNlbGYub3V0cHV0X2JpYXMKCiAgICAgICAgbXRwOiBEaWN0W2ludCwgdG9yY2guVGVuc29yXSA9IHt9CiAgICAgICAgaWYgc2VsZi5tdHBfaG9yaXpvbnMgYW5kIHNlbGYudHJhaW5pbmc6CiAgICAgICAgICAgIGZvciBob3Jpem9uIGluIHNlbGYubXRwX2hvcml6b25zOgogICAgICAgICAgICAgICAgaWYgaG9yaXpvbiA+IDEgYW5kIGhvcml6b24gPD0gVCAtIDE6CiAgICAgICAgICAgICAgICAgICAgc2hpZnRlZF9oID0geFs6LCA6LWhvcml6b24sIDpdCiAgICAgICAgICAgICAgICAgICAgYWRhcHRlZF9oID0gc2VsZi5tdHBfYWRhcHRlcnNbc3RyKGhvcml6b24pXShzaGlmdGVkX2gpCiAgICAgICAgICAgICAgICAgICAgYWRhcHRlZF9oID0gc2VsZi5tdHBfbm9ybXNbc3RyKGhvcml6b24pXShhZGFwdGVkX2gpCiAgICAgICAgICAgICAgICAgICAgbXRwX2xvZ2l0cyA9IHNlbGYuaGVhZChhZGFwdGVkX2gpCiAgICAgICAgICAgICAgICAgICAgaWYgc2VsZi5lbWJlZF9zY2FsZV9mYWN0b3IgIT0gMS4wOgogICAgICAgICAgICAgICAgICAgICAgICBtdHBfbG9naXRzID0gbXRwX2xvZ2l0cyAvIHNlbGYuZW1iZWRfc2NhbGVfZmFjdG9yCiAgICAgICAgICAgICAgICAgICAgbXRwX2xvZ2l0cyA9IG10cF9sb2dpdHMgKyBzZWxmLm91dHB1dF9iaWFzCiAgICAgICAgICAgICAgICAgICAgbXRwW2hvcml6b25dID0gbXRwX2xvZ2l0cwoKICAgICAgICByZXR1cm4gbG9naXRzLCBtdHAsIGhfb3V0LCBuZXdfcGFzdF9rZXlfdmFsdWVzCgoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBHZW5lcmF0aW9uCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgoKZGVmIGJ1aWxkX3N0b3BfdG9rZW5faWRzKHRva2VuaXplcjogV29yZFRva2VuaXplcikgLT4gc2V0OgogICAgc3RvcF90b2tlbnMgPSB7dG9rZW5pemVyLmVvc19pZH0KICAgIGZvciB0b2sgaW4gKCI8fHVzZXJ8PiIsICI8fHN5c3RlbXw+IiwgIjx8YXNzaXN0YW50fD4iKToKICAgICAgICB0aWQgPSB0b2tlbml6ZXIudG9rZW5fdG9faWQuZ2V0KHRvaykKICAgICAgICBpZiB0aWQgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIHN0b3BfdG9rZW5zLmFkZChpbnQodGlkKSkKICAgIHJldHVybiBzdG9wX3Rva2VucwoKCmRlZiBhcHBseV9ub19yZXBlYXRfbmdyYW0oCiAgICBsb2dpdHM6IHRvcmNoLlRlbnNvciwKICAgIHRva2VuX2hpc3Rvcnk6IFNlcXVlbmNlW2ludF0sCiAgICBuZ3JhbV9zaXplOiBpbnQsCikgLT4gdG9yY2guVGVuc29yOgogICAgaWYgbmdyYW1fc2l6ZSA8PSAxIG9yIGxlbih0b2tlbl9oaXN0b3J5KSA8IG1heCgwLCBuZ3JhbV9zaXplIC0gMSk6CiAgICAgICAgcmV0dXJuIGxvZ2l0cwogICAgcHJlZml4ID0gdHVwbGUodG9rZW5faGlzdG9yeVstKG5ncmFtX3NpemUgLSAxKSA6XSkgaWYgbmdyYW1fc2l6ZSA+IDEgZWxzZSB0dXBsZSgpCiAgICBiYW5uZWQ6IHNldCA9IHNldCgpCiAgICBmb3IgaSBpbiByYW5nZShsZW4odG9rZW5faGlzdG9yeSkgLSBuZ3JhbV9zaXplICsgMSk6CiAgICAgICAgaWYgdHVwbGUodG9rZW5faGlzdG9yeVtpIDogaSArIG5ncmFtX3NpemUgLSAxXSkgPT0gcHJlZml4OgogICAgICAgICAgICBiYW5uZWQuYWRkKGludCh0b2tlbl9oaXN0b3J5W2kgKyBuZ3JhbV9zaXplIC0gMV0pKQogICAgaWYgbm90IGJhbm5lZDoKICAgICAgICByZXR1cm4gbG9naXRzCiAgICBvdXQgPSBsb2dpdHMuY2xvbmUoKQogICAgYmFubmVkX2lkcyA9IHRvcmNoLnRlbnNvcihzb3J0ZWQoYmFubmVkKSwgZGV2aWNlPWxvZ2l0cy5kZXZpY2UsIGR0eXBlPXRvcmNoLmxvbmcpCiAgICBvdXRbYmFubmVkX2lkc10gPSBmbG9hdCgiLWluZiIpCiAgICByZXR1cm4gb3V0CgoKZGVmIGFwcGx5X2xvb3BfcGVuYWx0eSgKICAgIGxvZ2l0czogdG9yY2guVGVuc29yLAogICAgdG9rZW5pemVyOiBXb3JkVG9rZW5pemVyLAogICAgZ2VuZXJhdGVkX3RleHQ6IHN0ciwKICAgIHBlbmFsdHk6IGZsb2F0ID0gNS4wLAopIC0+IHRvcmNoLlRlbnNvcjoKICAgICIiIkRldGVjdCByZXBlYXRlZCBzdWJzdHJpbmcgbG9vcHMgYW5kIHBlbmFsaXNlIGNvbnRpbnVhdGlvbiB0b2tlbnMuIiIiCiAgICBpZiBsZW4oZ2VuZXJhdGVkX3RleHQpIDwgMTY6CiAgICAgICAgcmV0dXJuIGxvZ2l0cwogICAgb3V0ID0gbG9naXRzLmNsb25lKCkKICAgIGZvciBzcGFuX2xlbiBpbiBbMjQsIDE2LCAxMiwgOF06CiAgICAgICAgaWYgbGVuKGdlbmVyYXRlZF90ZXh0KSA8IHNwYW5fbGVuICogMjoKICAgICAgICAgICAgY29udGludWUKICAgICAgICBzdWZmaXggPSBnZW5lcmF0ZWRfdGV4dFstc3Bhbl9sZW46XQogICAgICAgIHByZXYgPSBnZW5lcmF0ZWRfdGV4dFs6LXNwYW5fbGVuXS5yZmluZChzdWZmaXgpCiAgICAgICAgaWYgcHJldiA9PSAtMToKICAgICAgICAgICAgY29udGludWUKICAgICAgICBuZXh0X3BvcyA9IHByZXYgKyBzcGFuX2xlbgogICAgICAgIGlmIG5leHRfcG9zIDwgbGVuKGdlbmVyYXRlZF90ZXh0KToKICAgICAgICAgICAgbmV4dF9jaGFyID0gZ2VuZXJhdGVkX3RleHRbbmV4dF9wb3NdCiAgICAgICAgICAgIHRpZCA9IHRva2VuaXplci50b2tlbl90b19pZC5nZXQobmV4dF9jaGFyKQogICAgICAgICAgICBpZiB0aWQgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICBvdXRbdGlkXSAtPSBwZW5hbHR5CiAgICAgICAgYnJlYWsKICAgIHJldHVybiBvdXQKCgpkZWYgYXBwbHlfbWluX3AobG9naXRzOiB0b3JjaC5UZW5zb3IsIG1pbl9wOiBmbG9hdCkgLT4gdG9yY2guVGVuc29yOgogICAgIiIiRmlsdGVyIHRva2VucyBiZWxvdyBtaW5fcCBmcmFjdGlvbiBvZiB0aGUgdG9wIHRva2VuIHByb2JhYmlsaXR5LiIiIgogICAgaWYgbWluX3AgPD0gMC4wOgogICAgICAgIHJldHVybiBsb2dpdHMKICAgIHByb2JzID0gdG9yY2guc29mdG1heChsb2dpdHMsIGRpbT0tMSkKICAgIHRocmVzaG9sZCA9IHByb2JzLm1heCgpICogbWluX3AKICAgIG91dCA9IGxvZ2l0cy5jbG9uZSgpCiAgICBvdXRbcHJvYnMgPCB0aHJlc2hvbGRdID0gZmxvYXQoIi1pbmYiKQogICAgcmV0dXJuIG91dAoKCmRlZiBnZW5lcmF0ZSgKICAgIG1vZGVsOiBUaW55TWVtb3J5TE0sCiAgICB0b2tlbml6ZXI6IFdvcmRUb2tlbml6ZXIsCiAgICBwcm9tcHQ6IHN0ciwKICAgIG1heF9uZXdfdG9rZW5zOiBpbnQgPSAyNTYsCiAgICB0ZW1wZXJhdHVyZTogZmxvYXQgPSAwLjgsCiAgICB0b3BfazogaW50ID0gMTYsCiAgICB0b3BfcDogZmxvYXQgPSAwLjk1LAogICAgcmVwZXRpdGlvbl9wZW5hbHR5OiBmbG9hdCA9IDEuMCwKICAgIGRldmljZTogc3RyID0gImN1ZGEiLAogICAgc2Z0X21vZGU6IGJvb2wgPSBUcnVlLAogICAgc3RyZWFtOiBib29sID0gVHJ1ZSwKICAgIG5vX3JlcGVhdF9uZ3JhbV9zaXplOiBpbnQgPSAwLAogICAgY29udGV4dF93aW5kb3c6IGludCA9IDIwNDgsCiAgICBsb2dpdF9zb2Z0X2NhcDogZmxvYXQgPSAxNS4wLAogICAgbWluX3A6IGZsb2F0ID0gMC4wNSwKICAgIGxvb3BfcGVuYWx0eTogZmxvYXQgPSA1LjAsCikgLT4gc3RyOgogICAgaWYgc2Z0X21vZGU6CiAgICAgICAgZnVsbF9wcm9tcHQgPSBmIjx8dXNlcnw+XG57cHJvbXB0fVxuPHxhc3Npc3RhbnR8PlxuIgogICAgZWxzZToKICAgICAgICBmdWxsX3Byb21wdCA9IHByb21wdAogICAgaW5wdXRfaWRzID0gdG9rZW5pemVyLmVuY29kZShmdWxsX3Byb21wdCwgYWRkX2Jvcz1UcnVlLCBhZGRfZW9zPUZhbHNlKQogICAgaW5wdXRfaWRzX3QgPSB0b3JjaC50ZW5zb3IoW2lucHV0X2lkc10sIGR0eXBlPXRvcmNoLmxvbmcsIGRldmljZT1kZXZpY2UpCiAgICB2aXNpYmxlX3Rva2VuczogTGlzdFtzdHJdID0gW10KICAgIHN0b3BfdG9rZW5faWRzID0gYnVpbGRfc3RvcF90b2tlbl9pZHModG9rZW5pemVyKQogICAgZ2VuZXJhdGVkX3RleHQgPSAiIgoKICAgIGdlbmVyYXRlZF9pZHM6IExpc3RbaW50XSA9IFtdCiAgICAjIEZ1bGwgaGlzdG9yeSAocHJvbXB0ICsgZ2VuZXJhdGVkKSBmb3IgbmdyYW0gYmxvY2tpbmcg4oCUIHByZXZlbnRzIGVjaG9pbmcgcHJvbXB0CiAgICBmdWxsX2lkc19oaXN0b3J5OiBMaXN0W2ludF0gPSBsaXN0KGlucHV0X2lkcykKCiAgICB3aXRoIHRvcmNoLm5vX2dyYWQoKToKICAgICAgICBmb3IgXyBpbiByYW5nZShtYXhfbmV3X3Rva2Vucyk6CiAgICAgICAgICAgIGN0eF9pZHMgPSAoCiAgICAgICAgICAgICAgICBpbnB1dF9pZHNfdFs6LCAtY29udGV4dF93aW5kb3c6XSBpZiBjb250ZXh0X3dpbmRvdyA+IDAgZWxzZSBpbnB1dF9pZHNfdAogICAgICAgICAgICApCiAgICAgICAgICAgIGxvZ2l0cywgXywgXywgXyA9IG1vZGVsKGN0eF9pZHMpCiAgICAgICAgICAgIG5leHRfbG9naXRzID0gbG9naXRzWzAsIC0xLCA6XS5jbG9uZSgpCgogICAgICAgICAgICAjIExvZ2l0IHNvZnQtY2FwcGluZyAoR2VtbWEtc3R5bGUpIOKAlCBwcmV2ZW50cyBvdmVyY29uZmlkZW50IGNvbGxhcHNlCiAgICAgICAgICAgIGlmIGxvZ2l0X3NvZnRfY2FwID4gMDoKICAgICAgICAgICAgICAgIG5leHRfbG9naXRzID0gbG9naXRfc29mdF9jYXAgKiB0b3JjaC50YW5oKG5leHRfbG9naXRzIC8gbG9naXRfc29mdF9jYXApCgogICAgICAgICAgICByYXdfbmV4dF9sb2dpdHMgPSBuZXh0X2xvZ2l0cy5jbG9uZSgpCgogICAgICAgICAgICAjIFJlcGV0aXRpb24gcGVuYWx0eSBvbiBwcmV2aW91c2x5IGdlbmVyYXRlZCB0b2tlbnMKICAgICAgICAgICAgaWYgcmVwZXRpdGlvbl9wZW5hbHR5ICE9IDEuMCBhbmQgZ2VuZXJhdGVkX2lkczoKICAgICAgICAgICAgICAgIGZvciB0b2tfaWQgaW4gc2V0KGdlbmVyYXRlZF9pZHMpOgogICAgICAgICAgICAgICAgICAgIGlmIG5leHRfbG9naXRzW3Rva19pZF0gPiAwOgogICAgICAgICAgICAgICAgICAgICAgICBuZXh0X2xvZ2l0c1t0b2tfaWRdIC89IHJlcGV0aXRpb25fcGVuYWx0eQogICAgICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAgICAgICAgIG5leHRfbG9naXRzW3Rva19pZF0gKj0gcmVwZXRpdGlvbl9wZW5hbHR5CgogICAgICAgICAgICAjIE5vLXJlcGVhdCBuLWdyYW0gYmxvY2tpbmcgb24gZ2VuZXJhdGVkIHRva2VucyBvbmx5CiAgICAgICAgICAgIGlmIG5vX3JlcGVhdF9uZ3JhbV9zaXplID4gMCBhbmQgZ2VuZXJhdGVkX2lkczoKICAgICAgICAgICAgICAgIG5leHRfbG9naXRzID0gYXBwbHlfbm9fcmVwZWF0X25ncmFtKG5leHRfbG9naXRzLCBnZW5lcmF0ZWRfaWRzLCBub19yZXBlYXRfbmdyYW1fc2l6ZSkKCiAgICAgICAgICAgICMgU3Vic3RyaW5nIGxvb3AgZGV0ZWN0aW9uCiAgICAgICAgICAgIG5leHRfbG9naXRzID0gYXBwbHlfbG9vcF9wZW5hbHR5KG5leHRfbG9naXRzLCB0b2tlbml6ZXIsIGdlbmVyYXRlZF90ZXh0LCBwZW5hbHR5PWxvb3BfcGVuYWx0eSkKCiAgICAgICAgICAgICMgVGVtcGVyYXR1cmUgc2NhbGluZwogICAgICAgICAgICBpZiB0ZW1wZXJhdHVyZSAhPSAxLjA6CiAgICAgICAgICAgICAgICBuZXh0X2xvZ2l0cyA9IG5leHRfbG9naXRzIC8gbWF4KHRlbXBlcmF0dXJlLCAxZS02KQoKICAgICAgICAgICAgIyBNaW4tcCBmaWx0ZXJpbmcg4oCUIHJlbW92ZSB0b2tlbnMgYmVsb3cgbWluX3AgKiBtYXhfcHJvYgogICAgICAgICAgICBpZiBtaW5fcCA+IDA6CiAgICAgICAgICAgICAgICBuZXh0X2xvZ2l0cyA9IGFwcGx5X21pbl9wKG5leHRfbG9naXRzLCBtaW5fcCkKCiAgICAgICAgICAgICMgVG9wLWsgZmlsdGVyaW5nCiAgICAgICAgICAgIGlmIHRvcF9rID4gMDoKICAgICAgICAgICAgICAgIHYsIF8gPSB0b3JjaC50b3BrKG5leHRfbG9naXRzLCBtaW4odG9wX2ssIG5leHRfbG9naXRzLnNpemUoMCkpKQogICAgICAgICAgICAgICAgbmV4dF9sb2dpdHNbbmV4dF9sb2dpdHMgPCB2Wy0xXV0gPSBmbG9hdCgiLWluZiIpCgogICAgICAgICAgICAjIFRvcC1wIChudWNsZXVzKSBmaWx0ZXJpbmcKICAgICAgICAgICAgaWYgMC4wIDwgdG9wX3AgPCAxLjA6CiAgICAgICAgICAgICAgICBzb3J0ZWRfbG9naXRzLCBzb3J0ZWRfaW5kaWNlcyA9IHRvcmNoLnNvcnQobmV4dF9sb2dpdHMsIGRlc2NlbmRpbmc9VHJ1ZSkKICAgICAgICAgICAgICAgIHNvcnRlZF9wcm9icyA9IHRvcmNoLnNvZnRtYXgoc29ydGVkX2xvZ2l0cywgZGltPS0xKQogICAgICAgICAgICAgICAgY3VtdWxhdGl2ZV9wcm9icyA9IHRvcmNoLmN1bXN1bShzb3J0ZWRfcHJvYnMsIGRpbT0tMSkKICAgICAgICAgICAgICAgIHJlbW92ZV9tYXNrID0gY3VtdWxhdGl2ZV9wcm9icyA+IHRvcF9wCiAgICAgICAgICAgICAgICByZW1vdmVfbWFza1swXSA9IEZhbHNlCiAgICAgICAgICAgICAgICBpbmRpY2VzX3RvX3JlbW92ZSA9IHNvcnRlZF9pbmRpY2VzW3JlbW92ZV9tYXNrXQogICAgICAgICAgICAgICAgbmV4dF9sb2dpdHNbaW5kaWNlc190b19yZW1vdmVdID0gZmxvYXQoIi1pbmYiKQoKICAgICAgICAgICAgIyBGYWxsYmFjayBpZiBhbGwgdG9rZW5zIG1hc2tlZAogICAgICAgICAgICBpZiBub3QgdG9yY2guaXNmaW5pdGUobmV4dF9sb2dpdHMpLmFueSgpOgogICAgICAgICAgICAgICAgbmV4dF9sb2dpdHMgPSByYXdfbmV4dF9sb2dpdHMKICAgICAgICAgICAgICAgIGlmIHRlbXBlcmF0dXJlICE9IDEuMDoKICAgICAgICAgICAgICAgICAgICBuZXh0X2xvZ2l0cyA9IG5leHRfbG9naXRzIC8gbWF4KHRlbXBlcmF0dXJlLCAxZS02KQoKICAgICAgICAgICAgaWYgdGVtcGVyYXR1cmUgPT0gMDoKICAgICAgICAgICAgICAgIG5leHRfaWQgPSB0b3JjaC5hcmdtYXgobmV4dF9sb2dpdHMpLml0ZW0oKQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgcHJvYnMgPSB0b3JjaC5zb2Z0bWF4KG5leHRfbG9naXRzLCBkaW09LTEpCiAgICAgICAgICAgICAgICBuZXh0X2lkID0gdG9yY2gubXVsdGlub21pYWwocHJvYnMsIG51bV9zYW1wbGVzPTEpLml0ZW0oKQogICAgICAgICAgICBpZiBuZXh0X2lkIGluIHN0b3BfdG9rZW5faWRzOgogICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgdG9rZW5fc3RyID0gKAogICAgICAgICAgICAgICAgdG9rZW5pemVyLmlkX3RvX3Rva2VuW25leHRfaWRdCiAgICAgICAgICAgICAgICBpZiBuZXh0X2lkIDwgbGVuKHRva2VuaXplci5pZF90b190b2tlbikKICAgICAgICAgICAgICAgIGVsc2UgIiIKICAgICAgICAgICAgKQogICAgICAgICAgICBnZW5lcmF0ZWRfaWRzLmFwcGVuZChuZXh0X2lkKQogICAgICAgICAgICBmdWxsX2lkc19oaXN0b3J5LmFwcGVuZChuZXh0X2lkKQogICAgICAgICAgICBpZiB0b2tlbl9zdHIgbm90IGluIHRva2VuaXplci5zcGVjaWFsOgogICAgICAgICAgICAgICAgdmlzaWJsZV90b2tlbnMuYXBwZW5kKHRva2VuX3N0cikKICAgICAgICAgICAgICAgIGdlbmVyYXRlZF90ZXh0ICs9IHRva2VuX3N0cgogICAgICAgICAgICAgICAgaWYgc3RyZWFtOgogICAgICAgICAgICAgICAgICAgIHByaW50KHRva2VuX3N0ciwgZW5kPSIiLCBmbHVzaD1UcnVlKQogICAgICAgICAgICBpbnB1dF9pZHNfdCA9IHRvcmNoLmNhdCgKICAgICAgICAgICAgICAgIFtpbnB1dF9pZHNfdCwgdG9yY2gudGVuc29yKFtbbmV4dF9pZF1dLCBkZXZpY2U9ZGV2aWNlKV0sIGRpbT0xCiAgICAgICAgICAgICkKICAgIGlmIHN0cmVhbToKICAgICAgICBwcmludCgpCiAgICByZXR1cm4gIiIuam9pbih2aXNpYmxlX3Rva2VucykKCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIExvY2FsIG1vZGVsIGxvYWRpbmcKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCgpkZWYgc2VyaWVzX2Zyb21fbmFtZShuYW1lOiBzdHIpIC0+IHN0ciB8IE5vbmU6CiAgICBsb3dlciA9IChuYW1lIG9yICIiKS5sb3dlcigpCiAgICBpZiAiaGFpa3UiIGluIGxvd2VyOgogICAgICAgIHJldHVybiAiSGFpa3UiCiAgICBpZiAic29ubmV0IiBpbiBsb3dlcjoKICAgICAgICByZXR1cm4gIlNvbm5ldCIKICAgIGlmICJvcHVzIiBpbiBsb3dlcjoKICAgICAgICByZXR1cm4gIk9wdXMiCiAgICByZXR1cm4gTm9uZQoKCmRlZiBzZXJpZXNfY29uZmlnKHNlcmllczogc3RyKSAtPiBkaWN0W3N0ciwgb2JqZWN0XToKICAgIHJldHVybiBNT0RFTF9TRVJJRVMuZ2V0KHNlcmllcy5sb3dlcigpLCBNT0RFTF9TRVJJRVNbInNvbm5ldCJdKQoKCmRlZiBkaXNjb3Zlcl9tb2RlbHMocnVuc19kaXI6IFBhdGgpIC0+IExpc3RbZGljdF06CiAgICBtb2RlbHMgPSBbXQogICAgaWYgbm90IHJ1bnNfZGlyLmlzX2RpcigpOgogICAgICAgIHJldHVybiBtb2RlbHMKICAgIGZvciBjaGlsZCBpbiBzb3J0ZWQocnVuc19kaXIuaXRlcmRpcigpKToKICAgICAgICBpZiBub3QgY2hpbGQuaXNfZGlyKCk6CiAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgdG9rZW5pemVyX3BhdGggPSBjaGlsZCAvICJ0b2tlbml6ZXIuanNvbiIKICAgICAgICBpZiBub3QgdG9rZW5pemVyX3BhdGguZXhpc3RzKCk6CiAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgbmFtZSA9IGNoaWxkLm5hbWUKICAgICAgICBzZXJpZXMgPSBzZXJpZXNfZnJvbV9uYW1lKG5hbWUpIG9yICJTb25uZXQiCiAgICAgICAgZm9yIGNrcHRfbmFtZSBpbiAoIm1vZGVsLnB0IiwgInByZXRyYWluLnB0Iik6CiAgICAgICAgICAgIGNrcHRfcGF0aCA9IGNoaWxkIC8gY2twdF9uYW1lCiAgICAgICAgICAgIGlmIGNrcHRfcGF0aC5leGlzdHMoKToKICAgICAgICAgICAgICAgIG1vZGVscy5hcHBlbmQoCiAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICAibmFtZSI6IG5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICJjaGVja3BvaW50IjogY2twdF9uYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAic2VyaWVzIjogc2VyaWVzLAogICAgICAgICAgICAgICAgICAgICAgICAibW9kZWxfcGF0aCI6IGNrcHRfcGF0aCwKICAgICAgICAgICAgICAgICAgICAgICAgInRva2VuaXplcl9wYXRoIjogdG9rZW5pemVyX3BhdGgsCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgcmV0dXJuIG1vZGVscwoKCmRlZiBfZGV0ZWN0X2VuZ3JhbShzdGF0ZV9kaWN0KToKICAgIGZvciBrZXkgaW4gc3RhdGVfZGljdDoKICAgICAgICBpZiAiLmVuZ3JhbS4iIGluIGtleToKICAgICAgICAgICAgaWYgIi5lbWJlZGRpbmdzLiIgaW4ga2V5OgogICAgICAgICAgICAgICAgcmV0dXJuIHN0YXRlX2RpY3Rba2V5XS5zaGFwZVstMV0KICAgIHJldHVybiAwCgoKZGVmIF9kZXRlY3RfbWhjKHN0YXRlX2RpY3QpOgogICAgZm9yIGtleSwgdmFsIGluIHN0YXRlX2RpY3QuaXRlbXMoKToKICAgICAgICBpZiAiLm1oY19hdHRuLmJpYXNfcHJlIiBpbiBrZXkgYW5kIHZhbC5kaW0oKSA9PSAyOgogICAgICAgICAgICByZXR1cm4gdmFsLnNoYXBlWy0xXSAgIyAoMSwgZXhwYW5zaW9uKQogICAgcmV0dXJuIDEKCgpkZWYgX2luZmVyX2FyY2hfZnJvbV9zdGF0ZV9kaWN0KHN0YXRlX2RpY3QsIGNmZyk6CiAgICAiIiJJbmZlciBhcmNoaXRlY3R1cmUgaHlwZXItcGFyYW1ldGVycyBkaXJlY3RseSBmcm9tIGNoZWNrcG9pbnQgd2VpZ2h0cywKICAgIGZhbGxpbmcgYmFjayB0byAqY2ZnKiAoc2VyaWVzIGNvbmZpZykgd2hlbiBhIGtleSBpcyBub3QgZm91bmQuIiIiCiAgICBvdmVycmlkZXMgPSB7fQoKICAgICMgZGltIGZyb20gZW1iZWRfdG9rZW5zLndlaWdodCBbdm9jYWIsIGRpbV0KICAgIGlmICJlbWJlZF90b2tlbnMud2VpZ2h0IiBpbiBzdGF0ZV9kaWN0OgogICAgICAgIG92ZXJyaWRlc1siZGltIl0gPSBzdGF0ZV9kaWN0WyJlbWJlZF90b2tlbnMud2VpZ2h0Il0uc2hhcGVbMV0KCiAgICAjIGZmbl9kaW0gZnJvbSBibG9ja3MuMC5mZm4uZ2F0ZS53ZWlnaHQgW2Zmbl9kaW0sIGRpbV0KICAgIGlmICJibG9ja3MuMC5mZm4uZ2F0ZS53ZWlnaHQiIGluIHN0YXRlX2RpY3Q6CiAgICAgICAgb3ZlcnJpZGVzWyJmZm5fZGltIl0gPSBzdGF0ZV9kaWN0WyJibG9ja3MuMC5mZm4uZ2F0ZS53ZWlnaHQiXS5zaGFwZVswXQoKICAgICMgbl91bmlxdWVfbGF5ZXJzIOKAkyBjb3VudCBibG9jayBpbmRpY2VzCiAgICBibG9ja19pZHMgPSB7CiAgICAgICAgaW50KGsuc3BsaXQoIi4iKVsxXSkKICAgICAgICBmb3IgayBpbiBzdGF0ZV9kaWN0CiAgICAgICAgaWYgay5zdGFydHN3aXRoKCJibG9ja3MuIikgYW5kIGsuc3BsaXQoIi4iKVsxXS5pc2RpZ2l0KCkKICAgIH0KICAgIGlmIGJsb2NrX2lkczoKICAgICAgICBvdmVycmlkZXNbIm5fdW5pcXVlX2xheWVycyJdID0gbWF4KGJsb2NrX2lkcykgKyAxCgogICAgIyBuX2hlYWRzIGZyb20gd3EgW25faGVhZHMqaGVhZF9kaW0sIGRpbV0gYW5kIHdrIFtuX2t2KmhlYWRfZGltLCBkaW1dCiAgICBkaW0gPSBvdmVycmlkZXMuZ2V0KCJkaW0iLCBpbnQoY2ZnLmdldCgiZGltIiwgbW9kZWxfY29uZmlnLmRpbSkpKQogICAgaWYgImJsb2Nrcy4wLmF0dG4ud3Eud2VpZ2h0IiBpbiBzdGF0ZV9kaWN0OgogICAgICAgIHdxX3Jvd3MgPSBzdGF0ZV9kaWN0WyJibG9ja3MuMC5hdHRuLndxLndlaWdodCJdLnNoYXBlWzBdICAjIG5faGVhZHMgKiBoZWFkX2RpbQogICAgICAgIGlmICJibG9ja3MuMC5hdHRuLnFfbm9ybS53ZWlnaHQiIGluIHN0YXRlX2RpY3Q6CiAgICAgICAgICAgIGhlYWRfZGltID0gc3RhdGVfZGljdFsiYmxvY2tzLjAuYXR0bi5xX25vcm0ud2VpZ2h0Il0uc2hhcGVbMF0KICAgICAgICAgICAgb3ZlcnJpZGVzWyJuX2hlYWRzIl0gPSB3cV9yb3dzIC8vIGhlYWRfZGltCiAgICBpZiAiYmxvY2tzLjAuYXR0bi53ay53ZWlnaHQiIGluIHN0YXRlX2RpY3Q6CiAgICAgICAgd2tfcm93cyA9IHN0YXRlX2RpY3RbImJsb2Nrcy4wLmF0dG4ud2sud2VpZ2h0Il0uc2hhcGVbMF0KICAgICAgICBpZiAiYmxvY2tzLjAuYXR0bi5rX25vcm0ud2VpZ2h0IiBpbiBzdGF0ZV9kaWN0OgogICAgICAgICAgICBoZWFkX2RpbSA9IHN0YXRlX2RpY3RbImJsb2Nrcy4wLmF0dG4ua19ub3JtLndlaWdodCJdLnNoYXBlWzBdCiAgICAgICAgICAgIG92ZXJyaWRlc1sibl9rdl9oZWFkcyJdID0gd2tfcm93cyAvLyBoZWFkX2RpbQoKICAgICMgZW5ncmFtIHBhcmFtcyBmcm9tIGJsb2Nrcy4wLmVuZ3JhbS5lbWJlZGRpbmdzLipfMCBbdGFibGVfc2l6ZSwgZW5ncmFtX2RpbV0KICAgIGZvciBrZXksIHZhbCBpbiBzdGF0ZV9kaWN0Lml0ZW1zKCk6CiAgICAgICAgaWYgIi5lbmdyYW0uZW1iZWRkaW5ncy4iIGluIGtleSBhbmQga2V5LmVuZHN3aXRoKCJfMCIpIGFuZCB2YWwuZGltKCkgPT0gMjoKICAgICAgICAgICAgb3ZlcnJpZGVzWyJlbmdyYW1fdGFibGVfc2l6ZSJdID0gdmFsLnNoYXBlWzBdCiAgICAgICAgICAgIG92ZXJyaWRlc1siZW5ncmFtX2RpbSJdID0gdmFsLnNoYXBlWzFdCiAgICAgICAgICAgIGJyZWFrCiAgICAjIGVuZ3JhbV9oZWFkcyBmcm9tIGJyYW5jaF9jb252IFt0b3RhbF9icmFuY2hfZGltLCAxLCA0XQogICAgIyB0b3RhbF9icmFuY2hfZGltID0gZW5ncmFtX2RpbSAqIG5faGVhZHMgKiAobWF4X25ncmFtIC0gMSkKICAgIGVuZ3JhbV9kaW0gPSBvdmVycmlkZXMuZ2V0KCJlbmdyYW1fZGltIiwgaW50KGNmZy5nZXQoImVuZ3JhbV9kaW0iLCAwKSkpCiAgICBlbmdyYW1fbWF4X25ncmFtID0gaW50KGNmZy5nZXQoImVuZ3JhbV9tYXhfbmdyYW0iLCAyKSkKICAgIGlmIGVuZ3JhbV9kaW0gPiAwOgogICAgICAgIGZvciBrZXksIHZhbCBpbiBzdGF0ZV9kaWN0Lml0ZW1zKCk6CiAgICAgICAgICAgIGlmICIuZW5ncmFtLmJyYW5jaF9jb252LndlaWdodCIgaW4ga2V5IGFuZCB2YWwuZGltKCkgPT0gMzoKICAgICAgICAgICAgICAgIHRvdGFsX2JyYW5jaF9kaW0gPSB2YWwuc2hhcGVbMF0KICAgICAgICAgICAgICAgIGRlbm9tID0gZW5ncmFtX2RpbSAqIChlbmdyYW1fbWF4X25ncmFtIC0gMSkKICAgICAgICAgICAgICAgIGlmIGRlbm9tID4gMCBhbmQgdG90YWxfYnJhbmNoX2RpbSAlIGRlbm9tID09IDA6CiAgICAgICAgICAgICAgICAgICAgb3ZlcnJpZGVzWyJlbmdyYW1faGVhZHMiXSA9IHRvdGFsX2JyYW5jaF9kaW0gLy8gZGVub20KICAgICAgICAgICAgICAgIGJyZWFrCgogICAgIyBtZXJnZTogY2hlY2twb2ludCB2YWx1ZXMgdGFrZSBwcmlvcml0eSBvdmVyIHNlcmllcyBjb25maWcKICAgIG1lcmdlZCA9IGRpY3QoY2ZnKQogICAgbWVyZ2VkLnVwZGF0ZShvdmVycmlkZXMpCiAgICByZXR1cm4gbWVyZ2VkCgoKZGVmIGxvYWRfbG9jYWxfbW9kZWwobW9kZWxfcGF0aDogUGF0aCwgdG9rZW5pemVyX3BhdGg6IFBhdGgsIHNlcmllczogc3RyKSAtPiBkaWN0OgogICAgdG9rZW5pemVyID0gV29yZFRva2VuaXplci5sb2FkKHRva2VuaXplcl9wYXRoKQogICAgY2twdCA9IHRvcmNoLmxvYWQoc3RyKG1vZGVsX3BhdGgpLCBtYXBfbG9jYXRpb249ImNwdSIsIHdlaWdodHNfb25seT1GYWxzZSkKICAgIGNmZyA9IHNlcmllc19jb25maWcoc2VyaWVzKQogICAgdm9jYWJfc2l6ZSA9IGludChja3B0LmdldCgidm9jYWJfc2l6ZSIsIHRva2VuaXplci52b2NhYl9zaXplKSkKCiAgICBzdGF0ZV9kaWN0ID0gY2twdC5nZXQoIm1vZGVsX3N0YXRlIikgb3IgY2twdC5nZXQoInN0YXRlX2RpY3QiKSBvciBja3B0CgogICAgIyBJbmZlciBhcmNoaXRlY3R1cmUgZnJvbSBjaGVja3BvaW50IHdlaWdodHMgc28gY29uZmlnIG1pc21hdGNoZXMgYXJlCiAgICAjIGhhbmRsZWQgYXV0b21hdGljYWxseS4KICAgIGNmZyA9IF9pbmZlcl9hcmNoX2Zyb21fc3RhdGVfZGljdChzdGF0ZV9kaWN0LCBjZmcpCgogICAgZW5ncmFtX2RpbSA9IGludChjZmcuZ2V0KCJlbmdyYW1fZGltIiwgMCkpCiAgICBpZiBfZGV0ZWN0X2VuZ3JhbShzdGF0ZV9kaWN0KSA9PSAwOgogICAgICAgIGVuZ3JhbV9kaW0gPSAwCgogICAgbWhjX2V4cGFuc2lvbiA9IF9kZXRlY3RfbWhjKHN0YXRlX2RpY3QpCiAgICBpZiBtaGNfZXhwYW5zaW9uID09IDE6CiAgICAgICAgbWhjX2V4cGFuc2lvbiA9IGludChjZmcuZ2V0KCJtaGNfZXhwYW5zaW9uIiwgMSkpCgogICAgbW9kZWwgPSBUaW55TWVtb3J5TE0oCiAgICAgICAgdm9jYWJfc2l6ZT12b2NhYl9zaXplLAogICAgICAgIGRpbT1pbnQoY2ZnLmdldCgiZGltIiwgbW9kZWxfY29uZmlnLmRpbSkpLAogICAgICAgIG5fdW5pcXVlX2xheWVycz1pbnQoY2ZnLmdldCgibl91bmlxdWVfbGF5ZXJzIiwgbW9kZWxfY29uZmlnLm5fdW5pcXVlX2xheWVycykpLAogICAgICAgIG5fbG9naWNhbF9sYXllcnM9aW50KAogICAgICAgICAgICBjZmcuZ2V0KCJuX2xvZ2ljYWxfbGF5ZXJzIiwgbW9kZWxfY29uZmlnLm5fbG9naWNhbF9sYXllcnMpCiAgICAgICAgKSwKICAgICAgICBuX2hlYWRzPWludChjZmcuZ2V0KCJuX2hlYWRzIiwgbW9kZWxfY29uZmlnLm5faGVhZHMpKSwKICAgICAgICBuX2t2X2hlYWRzPWludChjZmcuZ2V0KCJuX2t2X2hlYWRzIiwgbW9kZWxfY29uZmlnLm5fa3ZfaGVhZHMpKSwKICAgICAgICBmZm5fZGltPWludChjZmcuZ2V0KCJmZm5fZGltIiwgbW9kZWxfY29uZmlnLmZmbl9kaW0pKSwKICAgICAgICBkcm9wb3V0PWZsb2F0KGNmZy5nZXQoImRyb3BvdXQiLCBtb2RlbF9jb25maWcuZHJvcG91dCkpLAogICAgICAgIG10cF9ob3Jpem9ucz10dXBsZSgKICAgICAgICAgICAgaW50KHYpIGZvciB2IGluIGNmZy5nZXQoIm10cF9ob3Jpem9ucyIsIG1vZGVsX2NvbmZpZy5tdHBfaG9yaXpvbnMpCiAgICAgICAgKSwKICAgICAgICBncmFkX2NoZWNrcG9pbnQ9RmFsc2UsCiAgICAgICAgc2xpZGluZ193aW5kb3c9aW50KAogICAgICAgICAgICBjZmcuZ2V0KAogICAgICAgICAgICAgICAgInNsaWRpbmdfd2luZG93X3NpemUiLAogICAgICAgICAgICAgICAgZ2V0YXR0cihtb2RlbF9jb25maWcsICJzbGlkaW5nX3dpbmRvd19zaXplIiwgNTEyKSwKICAgICAgICAgICAgKQogICAgICAgICksCiAgICAgICAgcm9wZV9mcmFjdGlvbj1mbG9hdCgKICAgICAgICAgICAgY2ZnLmdldCgicm9wZV9mcmFjdGlvbiIsIGdldGF0dHIobW9kZWxfY29uZmlnLCAicm9wZV9mcmFjdGlvbiIsIDAuMjUpKQogICAgICAgICksCiAgICAgICAgZW1iZWRfc2NhbGU9Ym9vbCgKICAgICAgICAgICAgY2ZnLmdldCgiZW1iZWRfc2NhbGUiLCBnZXRhdHRyKG1vZGVsX2NvbmZpZywgImVtYmVkX3NjYWxlIiwgVHJ1ZSkpCiAgICAgICAgKSwKICAgICAgICBlbmdyYW1fZGltPWVuZ3JhbV9kaW0sCiAgICAgICAgZW5ncmFtX2hlYWRzPWludChjZmcuZ2V0KCJlbmdyYW1faGVhZHMiLCA0KSksCiAgICAgICAgZW5ncmFtX3RhYmxlX3NpemU9aW50KGNmZy5nZXQoImVuZ3JhbV90YWJsZV9zaXplIiwgODE5MikpLAogICAgICAgIGVuZ3JhbV9tYXhfbmdyYW09aW50KGNmZy5nZXQoImVuZ3JhbV9tYXhfbmdyYW0iLCAzKSksCiAgICAgICAgbWhjX2V4cGFuc2lvbj1taGNfZXhwYW5zaW9uLAogICAgKQogICAgbW9kZWwubG9hZF9zdGF0ZV9kaWN0KHN0YXRlX2RpY3QsIHN0cmljdD1GYWxzZSkKICAgIG1vZGVsLmV2YWwoKQogICAgaWYgdG9rZW5pemVyLnZvY2FiX3NpemUgPiB2b2NhYl9zaXplOgogICAgICAgIG1vZGVsLnJlc2l6ZV90b2tlbl9lbWJlZGRpbmdzKHRva2VuaXplci52b2NhYl9zaXplKQogICAgZGV2aWNlID0gImN1ZGEiIGlmIHRvcmNoLmN1ZGEuaXNfYXZhaWxhYmxlKCkgZWxzZSAiY3B1IgogICAgbW9kZWwgPSBtb2RlbC50byhkZXZpY2UpCiAgICByZXR1cm4gewogICAgICAgICJtb2RlbCI6IG1vZGVsLAogICAgICAgICJ0b2tlbml6ZXIiOiB0b2tlbml6ZXIsCiAgICAgICAgImRldmljZSI6IGRldmljZSwKICAgICAgICAic2VyaWVzIjogc2VyaWVzLAogICAgfQoKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgSHVnZ2luZ0ZhY2UgTW9kZWwgRG93bmxvYWQgJiBMb2FkaW5nCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpkZWYgZG93bmxvYWRfaHVnZ2luZ2ZhY2VfbW9kZWwoaGZfaWQ6IHN0ciwgY2FjaGVfZGlyOiBQYXRoKSAtPiBkaWN0OgogICAgdHJ5OgogICAgICAgIGZyb20gaHVnZ2luZ2ZhY2VfaHViIGltcG9ydCBzbmFwc2hvdF9kb3dubG9hZAogICAgZXhjZXB0IEltcG9ydEVycm9yOgogICAgICAgIHByaW50KCJodWdnaW5nZmFjZV9odWIgbm90IGluc3RhbGxlZC4gSW5zdGFsbCB3aXRoOiBwaXAgaW5zdGFsbCBodWdnaW5nZmFjZV9odWIiKQogICAgICAgIHN5cy5leGl0KDEpCgogICAgcHJpbnQoZiJEb3dubG9hZGluZyB7aGZfaWR9Li4uIikKICAgIHRyeToKICAgICAgICBsb2NhbF9kaXIgPSBQYXRoKHNuYXBzaG90X2Rvd25sb2FkKHJlcG9faWQ9aGZfaWQsIGNhY2hlX2Rpcj1zdHIoY2FjaGVfZGlyKSkpCiAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgcHJpbnQoZiJGYWlsZWQgdG8gZG93bmxvYWQge2hmX2lkfToge2V9IikKICAgICAgICByZXR1cm4gTm9uZQoKICAgIHByaW50KGYiVXNpbmcgY2FjaGVkIHtoZl9pZH0gZnJvbSB7bG9jYWxfZGlyfSIpCgogICAgbW9kZWxfZGlyID0gbG9jYWxfZGlyIC8gIm1vZGVsIiBpZiAobG9jYWxfZGlyIC8gIm1vZGVsIikuZXhpc3RzKCkgZWxzZSBsb2NhbF9kaXIKICAgIG1vZGVsX3BhdGggPSBtb2RlbF9kaXIgLyAibW9kZWwucHQiCiAgICBwcmV0cmFpbl9wYXRoID0gbW9kZWxfZGlyIC8gInByZXRyYWluLnB0IgogICAgdG9rZW5pemVyX3BhdGggPSBtb2RlbF9kaXIgLyAidG9rZW5pemVyLmpzb24iCgogICAgY2twdF9wYXRoID0gTm9uZQogICAgZm9yIHAgaW4gW21vZGVsX3BhdGgsIHByZXRyYWluX3BhdGhdOgogICAgICAgIGlmIHAuZXhpc3RzKCk6CiAgICAgICAgICAgIGNrcHRfcGF0aCA9IHAKICAgICAgICAgICAgYnJlYWsKCiAgICBpZiBja3B0X3BhdGggaXMgTm9uZSBvciBub3QgdG9rZW5pemVyX3BhdGguZXhpc3RzKCk6CiAgICAgICAgcHJpbnQoZiJNaXNzaW5nIG1vZGVsIGZpbGVzIGluIHttb2RlbF9kaXJ9IikKICAgICAgICBwcmludChmIiAgbW9kZWwucHQgZXhpc3RzOiB7bW9kZWxfcGF0aC5leGlzdHMoKX0iKQogICAgICAgIHByaW50KGYiICBwcmV0cmFpbi5wdCBleGlzdHM6IHtwcmV0cmFpbl9wYXRoLmV4aXN0cygpfSIpCiAgICAgICAgcHJpbnQoZiIgIHRva2VuaXplci5qc29uIGV4aXN0czoge3Rva2VuaXplcl9wYXRoLmV4aXN0cygpfSIpCiAgICAgICAgcmV0dXJuIE5vbmUKCiAgICByZXR1cm4gewogICAgICAgICJtb2RlbF9wYXRoIjogY2twdF9wYXRoLAogICAgICAgICJ0b2tlbml6ZXJfcGF0aCI6IHRva2VuaXplcl9wYXRoLAogICAgICAgICJtb2RlbF9uYW1lIjogY2twdF9wYXRoLnN0ZW0sCiAgICB9CgoKZGVmIGxvYWRfaHVnZ2luZ2ZhY2VfbW9kZWwoaGZfaWQ6IHN0ciwgY2FjaGVfZGlyOiBQYXRoKSAtPiBkaWN0OgogICAgZmlsZXMgPSBkb3dubG9hZF9odWdnaW5nZmFjZV9tb2RlbChoZl9pZCwgY2FjaGVfZGlyKQogICAgaWYgZmlsZXMgaXMgTm9uZToKICAgICAgICByZXR1cm4gTm9uZQoKICAgIHJldHVybiBsb2FkX2xvY2FsX21vZGVsKGZpbGVzWyJtb2RlbF9wYXRoIl0sIGZpbGVzWyJ0b2tlbml6ZXJfcGF0aCJdLCAiSGFpa3UiKQoKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgQ29tcGFyZSBBbGwgTW9kZWxzCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpfaGZfbW9kZWxfY2FjaGU6IERpY3Rbc3RyLCBkaWN0XSA9IHt9CgoKZGVmIHByZWZldGNoX2h1Z2dpbmdmYWNlX21vZGVscygpIC0+IE5vbmU6CiAgICByb290ID0gUGF0aChfX2ZpbGVfXykucmVzb2x2ZSgpLnBhcmVudAogICAgY2FjaGVfZGlyID0gcm9vdCAvICJjYWNoZSIgLyAiaHVnZ2luZ2ZhY2UiCiAgICBjYWNoZV9kaXIubWtkaXIocGFyZW50cz1UcnVlLCBleGlzdF9vaz1UcnVlKQoKICAgIHByaW50KCJEb3dubG9hZGluZy9wcmVwYXJpbmcgSHVnZ2luZ0ZhY2UgbW9kZWxzLi4uIikKICAgIGZvciBuYW1lLCBoZl9pZCBpbiBIVUdHSU5HRkFDRV9NT0RFTFMuaXRlbXMoKToKICAgICAgICBwcmludChmIiAge25hbWV9Li4uIikKICAgICAgICBidW5kbGUgPSBsb2FkX2h1Z2dpbmdmYWNlX21vZGVsKGhmX2lkLCBjYWNoZV9kaXIpCiAgICAgICAgaWYgYnVuZGxlOgogICAgICAgICAgICBfaGZfbW9kZWxfY2FjaGVbbmFtZV0gPSBidW5kbGUKICAgIHByaW50KGYiUHJlcGFyZWQge2xlbihfaGZfbW9kZWxfY2FjaGUpfSBIdWdnaW5nRmFjZSBtb2RlbHMiKQoKCmRlZiBjb21wYXJlX2FsbF9tb2RlbHMocHJvbXB0OiBzdHIsIGNmZzogZGljdCkgLT4gTm9uZToKICAgIHJvb3QgPSBQYXRoKF9fZmlsZV9fKS5yZXNvbHZlKCkucGFyZW50CiAgICBydW5zX2RpciA9IHJvb3QgLyAicnVucyIKICAgIGFsbF9tb2RlbHMgPSBkaXNjb3Zlcl9tb2RlbHMocnVuc19kaXIpCgogICAgaXNfcHJldHJhaW4gPSBub3QgY2ZnLmdldCgic2Z0X21vZGUiLCBUcnVlKQogICAgbG9jYWxfbW9kZWxzID0gWwogICAgICAgIG0gZm9yIG0gaW4gYWxsX21vZGVscwogICAgICAgIGlmICgicHJldHJhaW4iIGluIG1bImNoZWNrcG9pbnQiXSkgPT0gaXNfcHJldHJhaW4KICAgIF0KCiAgICBpZiBub3QgbG9jYWxfbW9kZWxzOgogICAgICAgIHByaW50KCJObyBtb2RlbHMgZm91bmQgbWF0Y2hpbmcgbW9kZS4iKQogICAgICAgIHJldHVybgoKICAgIHJlc3VsdHM6IExpc3RbZGljdF0gPSBbXQoKICAgIGZvciBtIGluIGxvY2FsX21vZGVsczoKICAgICAgICBwcmludChmIlxueyc9Jyo2MH0iKQogICAgICAgIHByaW50KGYiTG9hZGluZyBsb2NhbCB7bVsnbmFtZSddfS97bVsnY2hlY2twb2ludCddfS4uLiIpCiAgICAgICAgdHJ5OgogICAgICAgICAgICBidW5kbGUgPSBsb2FkX2xvY2FsX21vZGVsKG1bIm1vZGVsX3BhdGgiXSwgbVsidG9rZW5pemVyX3BhdGgiXSwgbVsic2VyaWVzIl0pCiAgICAgICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlOgogICAgICAgICAgICBwcmludChmIkZhaWxlZCB0byBsb2FkIHttWyduYW1lJ119OiB7ZX0iKQogICAgICAgICAgICBjb250aW51ZQoKICAgICAgICBtb2RlbCA9IGJ1bmRsZVsibW9kZWwiXQogICAgICAgIHRva2VuaXplciA9IGJ1bmRsZVsidG9rZW5pemVyIl0KICAgICAgICBkZXZpY2UgPSBidW5kbGVbImRldmljZSJdCgogICAgICAgIHByaW50KGYiR2VuZXJhdGluZyBvbiAne3Byb21wdH0nLi4uIikKICAgICAgICBvdXRwdXQgPSBnZW5lcmF0ZSgKICAgICAgICAgICAgbW9kZWw9bW9kZWwsCiAgICAgICAgICAgIHRva2VuaXplcj10b2tlbml6ZXIsCiAgICAgICAgICAgIHByb21wdD1wcm9tcHQsCiAgICAgICAgICAgIG1heF9uZXdfdG9rZW5zPWNmZ1sibWF4X25ld190b2tlbnMiXSwKICAgICAgICAgICAgdGVtcGVyYXR1cmU9Y2ZnWyJ0ZW1wZXJhdHVyZSJdLAogICAgICAgICAgICB0b3Bfaz1jZmdbInRvcF9rIl0sCiAgICAgICAgICAgIHRvcF9wPWNmZ1sidG9wX3AiXSwKICAgICAgICAgICAgbWluX3A9Y2ZnWyJtaW5fcCJdLAogICAgICAgICAgICBub19yZXBlYXRfbmdyYW1fc2l6ZT1jZmdbIm5vX3JlcGVhdF9uZ3JhbV9zaXplIl0sCiAgICAgICAgICAgIHJlcGV0aXRpb25fcGVuYWx0eT1jZmdbInJlcGV0aXRpb25fcGVuYWx0eSJdLAogICAgICAgICAgICBsb2dpdF9zb2Z0X2NhcD1jZmdbImxvZ2l0X3NvZnRfY2FwIl0sCiAgICAgICAgICAgIGxvb3BfcGVuYWx0eT1jZmdbImxvb3BfcGVuYWx0eSJdLAogICAgICAgICAgICBkZXZpY2U9c3RyKGRldmljZSksCiAgICAgICAgICAgIHNmdF9tb2RlPWNmZ1sic2Z0X21vZGUiXSwKICAgICAgICAgICAgc3RyZWFtPVRydWUsCiAgICAgICAgICAgIGNvbnRleHRfd2luZG93PWNmZ1siY29udGV4dF93aW5kb3ciXSwKICAgICAgICApCgogICAgICAgIHJlc3VsdHMuYXBwZW5kKHsKICAgICAgICAgICAgIm5hbWUiOiBmIltMT0NBTF0ge21bJ25hbWUnXX0ve21bJ2NoZWNrcG9pbnQnXX0iLAogICAgICAgICAgICAib3V0cHV0Ijogb3V0cHV0LAogICAgICAgICAgICAiZGV2aWNlIjogZGV2aWNlLAogICAgICAgIH0pCgogICAgZm9yIG5hbWUsIGJ1bmRsZSBpbiBfaGZfbW9kZWxfY2FjaGUuaXRlbXMoKToKICAgICAgICBwcmludChmIlxueyc9Jyo2MH0iKQogICAgICAgIHByaW50KGYiTG9hZGluZyB7bmFtZX0gKGNhY2hlZCkuLi4iKQoKICAgICAgICBtb2RlbCA9IGJ1bmRsZVsibW9kZWwiXQogICAgICAgIHRva2VuaXplciA9IGJ1bmRsZVsidG9rZW5pemVyIl0KICAgICAgICBkZXZpY2UgPSBidW5kbGVbImRldmljZSJdCgogICAgICAgIHByaW50KGYiR2VuZXJhdGluZyBvbiAne3Byb21wdH0nLi4uIikKICAgICAgICBvdXRwdXQgPSBnZW5lcmF0ZSgKICAgICAgICAgICAgbW9kZWw9bW9kZWwsCiAgICAgICAgICAgIHRva2VuaXplcj10b2tlbml6ZXIsCiAgICAgICAgICAgIHByb21wdD1wcm9tcHQsCiAgICAgICAgICAgIG1heF9uZXdfdG9rZW5zPWNmZ1sibWF4X25ld190b2tlbnMiXSwKICAgICAgICAgICAgdGVtcGVyYXR1cmU9Y2ZnWyJ0ZW1wZXJhdHVyZSJdLAogICAgICAgICAgICB0b3Bfaz1jZmdbInRvcF9rIl0sCiAgICAgICAgICAgIHRvcF9wPWNmZ1sidG9wX3AiXSwKICAgICAgICAgICAgbWluX3A9Y2ZnWyJtaW5fcCJdLAogICAgICAgICAgICBub19yZXBlYXRfbmdyYW1fc2l6ZT1jZmdbIm5vX3JlcGVhdF9uZ3JhbV9zaXplIl0sCiAgICAgICAgICAgIHJlcGV0aXRpb25fcGVuYWx0eT1jZmdbInJlcGV0aXRpb25fcGVuYWx0eSJdLAogICAgICAgICAgICBsb2dpdF9zb2Z0X2NhcD1jZmdbImxvZ2l0X3NvZnRfY2FwIl0sCiAgICAgICAgICAgIGxvb3BfcGVuYWx0eT1jZmdbImxvb3BfcGVuYWx0eSJdLAogICAgICAgICAgICBkZXZpY2U9c3RyKGRldmljZSksCiAgICAgICAgICAgIHNmdF9tb2RlPWNmZ1sic2Z0X21vZGUiXSwKICAgICAgICAgICAgc3RyZWFtPVRydWUsCiAgICAgICAgICAgIGNvbnRleHRfd2luZG93PWNmZ1siY29udGV4dF93aW5kb3ciXSwKICAgICAgICApCgogICAgICAgIHJlc3VsdHMuYXBwZW5kKHsKICAgICAgICAgICAgIm5hbWUiOiBuYW1lLAogICAgICAgICAgICAib3V0cHV0Ijogb3V0cHV0LAogICAgICAgICAgICAiZGV2aWNlIjogZGV2aWNlLAogICAgICAgIH0pCgogICAgcHJpbnQoZiJcbnsnPScqNjB9IikKICAgIHByaW50KCI9IiAqIDYwKQogICAgcHJpbnQoIlNJREUtQlktU0lERSBDT01QQVJJU09OIikKICAgIHByaW50KCI9IiAqIDYwKQogICAgZm9yIHIgaW4gcmVzdWx0czoKICAgICAgICBwcmludChmIlxuLS0tIHtyWyduYW1lJ119IC0tLSIpCiAgICAgICAgcHJpbnQoclsib3V0cHV0Il0pCiAgICBwcmludChmIlxueyc9Jyo2MH0iKQoKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgSW50ZXJhY3RpdmUgQ0xJCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgoKZGVmIF9waWNrX3NlcmllcyhkZXRlY3RlZDogc3RyKSAtPiBzdHI6CiAgICBzZXJpZXNfbGlzdCA9IGxpc3QoTU9ERUxfU0VSSUVTLmtleXMoKSkKICAgIGRldGVjdGVkX2xvd2VyID0gZGV0ZWN0ZWQubG93ZXIoKQogICAgZGVmYXVsdF9pZHggPSBuZXh0KAogICAgICAgIChpICsgMSBmb3IgaSwgcyBpbiBlbnVtZXJhdGUoc2VyaWVzX2xpc3QpIGlmIHMgPT0gZGV0ZWN0ZWRfbG93ZXIpLCAxCiAgICApCgogICAgIyBTa2lwIHNlbGVjdGlvbiBpZiBvbmx5IG9uZSBzZXJpZXMgYXZhaWxhYmxlCiAgICBpZiBsZW4oc2VyaWVzX2xpc3QpID09IDE6CiAgICAgICAgcmV0dXJuIHNlcmllc19saXN0WzBdLmNhcGl0YWxpemUoKQoKICAgIHByaW50KCJTZXJpZXM6IikKICAgIGZvciBpLCBzIGluIGVudW1lcmF0ZShzZXJpZXNfbGlzdCk6CiAgICAgICAgbWFya2VyID0gIiAoZGV0ZWN0ZWQpIiBpZiBzID09IGRldGVjdGVkX2xvd2VyIGVsc2UgIiIKICAgICAgICBwcmludChmIiAgW3tpICsgMX1dIHtzLmNhcGl0YWxpemUoKX17bWFya2VyfSIpCiAgICB3aGlsZSBUcnVlOgogICAgICAgIHRyeToKICAgICAgICAgICAgY2hvaWNlID0gaW5wdXQoZiJTZWxlY3Qgc2VyaWVzIFt7ZGVmYXVsdF9pZHh9XTogIikuc3RyaXAoKQogICAgICAgIGV4Y2VwdCAoRU9GRXJyb3IsIEtleWJvYXJkSW50ZXJydXB0KToKICAgICAgICAgICAgcHJpbnQoKQogICAgICAgICAgICBzeXMuZXhpdCgwKQogICAgICAgIGlmIG5vdCBjaG9pY2U6CiAgICAgICAgICAgIGNob2ljZSA9IHN0cihkZWZhdWx0X2lkeCkKICAgICAgICBpZiBjaG9pY2UuaXNkaWdpdCgpIGFuZCAxIDw9IGludChjaG9pY2UpIDw9IGxlbihzZXJpZXNfbGlzdCk6CiAgICAgICAgICAgIHJldHVybiBzZXJpZXNfbGlzdFtpbnQoY2hvaWNlKSAtIDFdLmNhcGl0YWxpemUoKQogICAgICAgIHByaW50KGYiRW50ZXIgYSBudW1iZXIgMS17bGVuKHNlcmllc19saXN0KX0iKQoKCmRlZiBwaWNrX21vZGVsKHJ1bnNfZGlyOiBQYXRoKSAtPiB0dXBsZVtkaWN0LCBzdHJdOgogICAgbW9kZWxzID0gZGlzY292ZXJfbW9kZWxzKHJ1bnNfZGlyKQogICAgaWYgbm90IG1vZGVsczoKICAgICAgICBwcmludChmIk5vIG1vZGVscyBmb3VuZCBpbiB7cnVuc19kaXJ9IikKICAgICAgICBwcmludCgiRXhwZWN0ZWQgbGF5b3V0OiBydW5zLzxuYW1lPi9tb2RlbC5wdCAob3IgcHJldHJhaW4ucHQpICsgdG9rZW5pemVyLmpzb24iKQogICAgICAgIHN5cy5leGl0KDEpCgogICAgaWYgbGVuKG1vZGVscykgPT0gMToKICAgICAgICBtID0gbW9kZWxzWzBdCiAgICAgICAgcHJpbnQoZiJMb2FkaW5nIHttWyduYW1lJ119L3ttWydjaGVja3BvaW50J119ICh7bVsnc2VyaWVzJ119KS4uLiIpCiAgICAgICAgYnVuZGxlID0gbG9hZF9sb2NhbF9tb2RlbChtWyJtb2RlbF9wYXRoIl0sIG1bInRva2VuaXplcl9wYXRoIl0sIG1bInNlcmllcyJdKQogICAgICAgIHJldHVybiBidW5kbGUsIG1bImNoZWNrcG9pbnQiXQoKICAgIHByaW50KCJBdmFpbGFibGUgbW9kZWxzOiIpCiAgICBmb3IgaSwgbSBpbiBlbnVtZXJhdGUobW9kZWxzKToKICAgICAgICBwcmludChmIiAgW3tpICsgMX1dIHttWyduYW1lJ119L3ttWydjaGVja3BvaW50J119ICh7bVsnc2VyaWVzJ119KSIpCiAgICB3aGlsZSBUcnVlOgogICAgICAgIHRyeToKICAgICAgICAgICAgY2hvaWNlID0gaW5wdXQoIlNlbGVjdCBtb2RlbCBbMV06ICIpLnN0cmlwKCkKICAgICAgICBleGNlcHQgKEVPRkVycm9yLCBLZXlib2FyZEludGVycnVwdCk6CiAgICAgICAgICAgIHByaW50KCkKICAgICAgICAgICAgc3lzLmV4aXQoMCkKICAgICAgICBpZiBub3QgY2hvaWNlOgogICAgICAgICAgICBjaG9pY2UgPSAiMSIKICAgICAgICBpZiBjaG9pY2UuaXNkaWdpdCgpIGFuZCAxIDw9IGludChjaG9pY2UpIDw9IGxlbihtb2RlbHMpOgogICAgICAgICAgICBtID0gbW9kZWxzW2ludChjaG9pY2UpIC0gMV0KICAgICAgICAgICAgcHJpbnQoZiJMb2FkaW5nIHttWyduYW1lJ119L3ttWydjaGVja3BvaW50J119ICh7bVsnc2VyaWVzJ119KS4uLiIpCiAgICAgICAgICAgIGJ1bmRsZSA9IGxvYWRfbG9jYWxfbW9kZWwobVsibW9kZWxfcGF0aCJdLCBtWyJ0b2tlbml6ZXJfcGF0aCJdLCBtWyJzZXJpZXMiXSkKICAgICAgICAgICAgcmV0dXJuIGJ1bmRsZSwgbVsiY2hlY2twb2ludCJdCiAgICAgICAgcHJpbnQoZiJFbnRlciBhIG51bWJlciAxLXtsZW4obW9kZWxzKX0iKQoKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgR2VuZXJhdGlvbiBtb2RlIGNvbmZpZ3MKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCk1PREVTID0gewogICAgIyBDaGF0IOKAlCB0d28gZmxhdm91cnMKICAgICJjaGF0LWNvaGVyZW50IjogewogICAgICAgICJsYWJlbCI6ICJDaGF0IOKAlCBDb2hlcmVudCIsCiAgICAgICAgImRlc2MiOiAic3RydWN0dXJlZCwgY29uc2lzdGVudCwgc3Ryb25nIHJlcGV0aXRpb24gY29udHJvbCIsCiAgICAgICAgInNmdF9tb2RlIjogImNoYXQiLAogICAgICAgICJ0ZW1wZXJhdHVyZSI6IDAuNSwKICAgICAgICAidG9wX2siOiA0MCwKICAgICAgICAidG9wX3AiOiAwLjksCiAgICAgICAgIm1pbl9wIjogMC4wNiwKICAgICAgICAibm9fcmVwZWF0X25ncmFtX3NpemUiOiA1LAogICAgICAgICJyZXBldGl0aW9uX3BlbmFsdHkiOiAxLjE1LAogICAgICAgICJsb2dpdF9zb2Z0X2NhcCI6IDI1LjAsCiAgICAgICAgImxvb3BfcGVuYWx0eSI6IDE1LjAsCiAgICAgICAgIm1heF9uZXdfdG9rZW5zIjogMjU2LAogICAgICAgICJjb250ZXh0X3dpbmRvdyI6IDIwNDgsCiAgICB9LAogICAgImNoYXQtdmFyaWFudHMiOiB7CiAgICAgICAgImxhYmVsIjogIkNoYXQg4oCUIFZhcmlhbnRzIiwKICAgICAgICAiZGVzYyI6ICJjcmVhdGl2ZSwgZGl2ZXJzZSwgbW9yZSBzdXJwcmlzaW5nIG91dHB1dHMiLAogICAgICAgICJzZnRfbW9kZSI6ICJjaGF0IiwKICAgICAgICAidGVtcGVyYXR1cmUiOiAwLjcyLAogICAgICAgICJ0b3BfayI6IDUwLAogICAgICAgICJ0b3BfcCI6IDAuOTMsCiAgICAgICAgIm1pbl9wIjogMC4wNCwKICAgICAgICAibm9fcmVwZWF0X25ncmFtX3NpemUiOiA1LAogICAgICAgICJyZXBldGl0aW9uX3BlbmFsdHkiOiAxLjEsCiAgICAgICAgImxvZ2l0X3NvZnRfY2FwIjogMjUuMCwKICAgICAgICAibG9vcF9wZW5hbHR5IjogMTUuMCwKICAgICAgICAibWF4X25ld190b2tlbnMiOiAyNTYsCiAgICAgICAgImNvbnRleHRfd2luZG93IjogMjA0OCwKICAgIH0sCiAgICAjIFByZXRyYWluIOKAlCB0d28gZmxhdm91cnMKICAgICJwcmV0cmFpbi1jb2hlcmVudCI6IHsKICAgICAgICAibGFiZWwiOiAiUHJldHJhaW4g4oCUIENvaGVyZW50IiwKICAgICAgICAiZGVzYyI6ICJncm91bmRlZCBjb250aW51YXRpb24sIGxvdyB0ZW1wZXJhdHVyZSwgdGlnaHQgc2FtcGxpbmciLAogICAgICAgICJzZnRfbW9kZSI6IEZhbHNlLAogICAgICAgICJ0ZW1wZXJhdHVyZSI6IDAuMjUsCiAgICAgICAgInRvcF9rIjogMjAsCiAgICAgICAgInRvcF9wIjogMC44NSwKICAgICAgICAibWluX3AiOiAwLjEwLAogICAgICAgICJub19yZXBlYXRfbmdyYW1fc2l6ZSI6IDUsCiAgICAgICAgInJlcGV0aXRpb25fcGVuYWx0eSI6IDEuMiwKICAgICAgICAibG9naXRfc29mdF9jYXAiOiAyNS4wLAogICAgICAgICJsb29wX3BlbmFsdHkiOiAxNS4wLAogICAgICAgICJtYXhfbmV3X3Rva2VucyI6IDI1NiwKICAgICAgICAiY29udGV4dF93aW5kb3ciOiAyMDQ4LAogICAgfSwKICAgICJwcmV0cmFpbi12YXJpYW50cyI6IHsKICAgICAgICAibGFiZWwiOiAiUHJldHJhaW4g4oCUIFZhcmlhbnRzIiwKICAgICAgICAiZGVzYyI6ICJmcmVlLWZvcm0gY29udGludWF0aW9uLCBoaWdoZXIgdGVtcGVyYXR1cmUsIG1vcmUgZXhwbG9yYXRpb24iLAogICAgICAgICJzZnRfbW9kZSI6IEZhbHNlLAogICAgICAgICJ0ZW1wZXJhdHVyZSI6IDAuNzIsCiAgICAgICAgInRvcF9rIjogNjAsCiAgICAgICAgInRvcF9wIjogMC45NSwKICAgICAgICAibWluX3AiOiAwLjAzLAogICAgICAgICJub19yZXBlYXRfbmdyYW1fc2l6ZSI6IDQsCiAgICAgICAgInJlcGV0aXRpb25fcGVuYWx0eSI6IDEuMSwKICAgICAgICAibG9naXRfc29mdF9jYXAiOiAyNS4wLAogICAgICAgICJsb29wX3BlbmFsdHkiOiAxMi4wLAogICAgICAgICJtYXhfbmV3X3Rva2VucyI6IDI1NiwKICAgICAgICAiY29udGV4dF93aW5kb3ciOiAyMDQ4LAogICAgfSwKfQoKX01PREVfTElTVCA9IGxpc3QoTU9ERVMua2V5cygpKQoKCmRlZiBwaWNrX21vZGUoaXNfcHJldHJhaW46IGJvb2wpIC0+IGRpY3Q6CiAgICAiIiJQcm9tcHQgdGhlIHVzZXIgdG8gY2hvb3NlIGEgZ2VuZXJhdGlvbiBtb2RlLiBSZXR1cm5zIGEgY29uZmlnIGRpY3QuIiIiCiAgICAjIEZpbHRlciB0byByZWxldmFudCBtb2RlcyBiYXNlZCBvbiBjaGVja3BvaW50IHR5cGUKICAgIGNhbmRpZGF0ZXMgPSBbayBmb3IgayBpbiBfTU9ERV9MSVNUIGlmICgicHJldHJhaW4iIGluIGspID09IGlzX3ByZXRyYWluXQogICAgcHJpbnQoIlxuR2VuZXJhdGlvbiBtb2RlOiIpCiAgICBmb3IgaSwga2V5IGluIGVudW1lcmF0ZShjYW5kaWRhdGVzKToKICAgICAgICBjZmcgPSBNT0RFU1trZXldCiAgICAgICAgcHJpbnQoZiIgIFt7aSArIDF9XSB7Y2ZnWydsYWJlbCddfSAg4oCUIHtjZmdbJ2Rlc2MnXX0iKQogICAgd2hpbGUgVHJ1ZToKICAgICAgICB0cnk6CiAgICAgICAgICAgIGNob2ljZSA9IGlucHV0KCJTZWxlY3QgbW9kZSBbMV06ICIpLnN0cmlwKCkKICAgICAgICBleGNlcHQgKEVPRkVycm9yLCBLZXlib2FyZEludGVycnVwdCk6CiAgICAgICAgICAgIHByaW50KCkKICAgICAgICAgICAgc3lzLmV4aXQoMCkKICAgICAgICBpZiBub3QgY2hvaWNlOgogICAgICAgICAgICBjaG9pY2UgPSAiMSIKICAgICAgICBpZiBjaG9pY2UuaXNkaWdpdCgpIGFuZCAxIDw9IGludChjaG9pY2UpIDw9IGxlbihjYW5kaWRhdGVzKToKICAgICAgICAgICAga2V5ID0gY2FuZGlkYXRlc1tpbnQoY2hvaWNlKSAtIDFdCiAgICAgICAgICAgIGNmZyA9IE1PREVTW2tleV0KICAgICAgICAgICAgcHJpbnQoZiJNb2RlOiB7Y2ZnWydsYWJlbCddfSIpCiAgICAgICAgICAgIHJldHVybiBjZmcKICAgICAgICBwcmludChmIkVudGVyIGEgbnVtYmVyIDEte2xlbihjYW5kaWRhdGVzKX0iKQoKCmRlZiBfcnVuX2xvb3AoYnVuZGxlOiBkaWN0LCBjZmc6IGRpY3QpIC0+IE5vbmU6CiAgICBtb2RlbCA9IGJ1bmRsZVsibW9kZWwiXQogICAgdG9rZW5pemVyID0gYnVuZGxlWyJ0b2tlbml6ZXIiXQogICAgZGV2aWNlID0gYnVuZGxlWyJkZXZpY2UiXQogICAgc2Z0ID0gY2ZnWyJzZnRfbW9kZSJdCiAgICBwcm9tcHRfbGFiZWwgPSAiWW91IiBpZiBzZnQgZWxzZSAiUHJvbXB0IgogICAgcHJpbnQoZiJcbk1vZGVsIHJlYWR5IG9uIHtkZXZpY2V9LiBUeXBlIHlvdXIgbWVzc2FnZSwgb3IgL3F1aXQgdG8gZXhpdC4iKQogICAgcHJpbnQoZiIgIHRlbXA9e2NmZ1sndGVtcGVyYXR1cmUnXX0gIHRvcF9rPXtjZmdbJ3RvcF9rJ119ICB0b3BfcD17Y2ZnWyd0b3BfcCddfSIpCiAgICBwcmludChmIiAgbWluX3A9e2NmZ1snbWluX3AnXX0gIG5nPXtjZmdbJ25vX3JlcGVhdF9uZ3JhbV9zaXplJ119ICBycD17Y2ZnWydyZXBldGl0aW9uX3BlbmFsdHknXX0iKQogICAgcHJpbnQoZiIgIGNhcD17Y2ZnWydsb2dpdF9zb2Z0X2NhcCddfSAgbG9vcF9wZW5hbHR5PXtjZmdbJ2xvb3BfcGVuYWx0eSddfVxuIikKICAgIHdoaWxlIFRydWU6CiAgICAgICAgdHJ5OgogICAgICAgICAgICBwcm9tcHQgPSBpbnB1dChmIntwcm9tcHRfbGFiZWx9OiAiKS5zdHJpcCgpCiAgICAgICAgZXhjZXB0IChFT0ZFcnJvciwgS2V5Ym9hcmRJbnRlcnJ1cHQpOgogICAgICAgICAgICBwcmludCgpCiAgICAgICAgICAgIGJyZWFrCiAgICAgICAgaWYgbm90IHByb21wdDoKICAgICAgICAgICAgY29udGludWUKICAgICAgICBpZiBwcm9tcHQgaW4gKCIvcXVpdCIsICIvZXhpdCIsICIvcSIpOgogICAgICAgICAgICBicmVhawogICAgICAgIGlmIHByb21wdCA9PSAiL2hlbHAiOgogICAgICAgICAgICBwcmludCgiQ29tbWFuZHM6IC9xdWl0ICAvZXhpdCAgL3EgIC9oZWxwICAvbW9kZSIpCiAgICAgICAgICAgIGlmIHNmdDoKICAgICAgICAgICAgICAgIHByaW50KCJBbnl0aGluZyBlbHNlIGlzIHNlbnQgYXMgYSBjaGF0IHByb21wdC4iKQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgcHJpbnQoIkFueXRoaW5nIGVsc2UgaXMgc2VudCBhcyBhIHJhdyBjb250aW51YXRpb24gcHJvbXB0LiIpCiAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgaWYgcHJvbXB0ID09ICIvbW9kZSI6CiAgICAgICAgICAgIHByaW50KGYiQ3VycmVudDoge2NmZ1snbGFiZWwnXX0g4oCUIHtjZmdbJ2Rlc2MnXX0iKQogICAgICAgICAgICBjb250aW51ZQogICAgICAgIHByaW50KCJBSTogIiwgZW5kPSIiLCBmbHVzaD1UcnVlKQogICAgICAgIGdlbmVyYXRlKAogICAgICAgICAgICBtb2RlbD1tb2RlbCwKICAgICAgICAgICAgdG9rZW5pemVyPXRva2VuaXplciwKICAgICAgICAgICAgcHJvbXB0PXByb21wdCwKICAgICAgICAgICAgbWF4X25ld190b2tlbnM9Y2ZnWyJtYXhfbmV3X3Rva2VucyJdLAogICAgICAgICAgICB0ZW1wZXJhdHVyZT1jZmdbInRlbXBlcmF0dXJlIl0sCiAgICAgICAgICAgIHRvcF9rPWNmZ1sidG9wX2siXSwKICAgICAgICAgICAgdG9wX3A9Y2ZnWyJ0b3BfcCJdLAogICAgICAgICAgICBtaW5fcD1jZmdbIm1pbl9wIl0sCiAgICAgICAgICAgIG5vX3JlcGVhdF9uZ3JhbV9zaXplPWNmZ1sibm9fcmVwZWF0X25ncmFtX3NpemUiXSwKICAgICAgICAgICAgcmVwZXRpdGlvbl9wZW5hbHR5PWNmZ1sicmVwZXRpdGlvbl9wZW5hbHR5Il0sCiAgICAgICAgICAgIGxvZ2l0X3NvZnRfY2FwPWNmZ1sibG9naXRfc29mdF9jYXAiXSwKICAgICAgICAgICAgbG9vcF9wZW5hbHR5PWNmZ1sibG9vcF9wZW5hbHR5Il0sCiAgICAgICAgICAgIGRldmljZT1zdHIoZGV2aWNlKSwKICAgICAgICAgICAgc2Z0X21vZGU9Y2ZnWyJzZnRfbW9kZSJdLAogICAgICAgICAgICBzdHJlYW09VHJ1ZSwKICAgICAgICAgICAgY29udGV4dF93aW5kb3c9Y2ZnWyJjb250ZXh0X3dpbmRvdyJdLAogICAgICAgICkKCgoKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgRHluYW1pYyBjb2xsZWN0aW9uIGRpc2NvdmVyeQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKX0NPTExFQ1RJT05fU0xVRyA9ICJDb21wYWN0QUktTy90bWxtLWhhaWt1LXNlcmllcyIKX0FVVEhPUiA9ICJDb21wYWN0QUktTyIKX1NFQVJDSCA9ICJUTUxNLUhhaWt1IgoKX0ZBTExCQUNLX0NPTExFQ1RJT04gPSBbCiAgICB7InZlcnNpb24iOiAiVE1MTS1IYWlrdS0yLjMiLCAiaGZfaWQiOiAiQ29tcGFjdEFJLU8vVE1MTS1IYWlrdS0yLjMifSwKICAgIHsidmVyc2lvbiI6ICJUTUxNLUhhaWt1LTIiLCAgICJoZl9pZCI6ICJDb21wYWN0QUktTy9UTUxNLUhhaWt1LTIifSwKICAgIHsidmVyc2lvbiI6ICJUTUxNLUhhaWt1LTEuMyIsICJoZl9pZCI6ICJDb21wYWN0QUktTy9UTUxNLUhhaWt1LTEuMyJ9LAogICAgeyJ2ZXJzaW9uIjogIlRNTE0tSGFpa3UtMSIsICAgImhmX2lkIjogIkNvbXBhY3RBSS1PL1RNTE0tSGFpa3UtMSJ9LApdCgoKZGVmIF9wcm9iZV9yZXBvKGhmX2lkOiBzdHIpIC0+IGRpY3QgfCBOb25lOgogICAgIiIiUmV0dXJuIGVudHJ5IGRpY3QgZm9yIG9uZSByZXBvLCBvciBOb25lIGlmIG5vIHVzYWJsZSBjaGVja3BvaW50cyBmb3VuZC4iIiIKICAgIGZyb20gaHVnZ2luZ2ZhY2VfaHViIGltcG9ydCBsaXN0X3JlcG9fZmlsZXMKCiAgICB0cnk6CiAgICAgICAgZmlsZXMgPSBzZXQobGlzdF9yZXBvX2ZpbGVzKGhmX2lkKSkKICAgIGV4Y2VwdCBFeGNlcHRpb246CiAgICAgICAgcmV0dXJuIE5vbmUKCiAgICAjIERldGVjdCB3aGljaCBzdWJkaXJlY3RvcnkgaG9sZHMgdGhlIGNoZWNrcG9pbnRzCiAgICBzdWJkaXI6IHN0ciB8IE5vbmUgPSBOb25lCiAgICBmb3IgY2FuZGlkYXRlIGluICgibW9kZWxzIiwgIm1vZGVsIik6CiAgICAgICAgaWYgYW55KGYuc3RhcnRzd2l0aChmIntjYW5kaWRhdGV9LyIpIGZvciBmIGluIGZpbGVzKToKICAgICAgICAgICAgc3ViZGlyID0gY2FuZGlkYXRlCiAgICAgICAgICAgIGJyZWFrCgogICAgcHJlZml4ID0gZiJ7c3ViZGlyfS8iIGlmIHN1YmRpciBlbHNlICIiCgogICAgIyBDb2xsZWN0IGFsbCAucHQgZmlsZXMgaW4gdGhlIGNoZWNrcG9pbnQgZGlyZWN0b3J5CiAgICBwdF9maWxlcyA9IHNvcnRlZCgKICAgICAgICBmW2xlbihwcmVmaXgpOl0gZm9yIGYgaW4gZmlsZXMKICAgICAgICBpZiBmLnN0YXJ0c3dpdGgocHJlZml4KSBhbmQgZi5lbmRzd2l0aCgiLnB0IikKICAgICkKCiAgICBfTEFCRUxTID0gewogICAgICAgICJtb2RlbC5wdCI6ICgiQ2hhdCAoU0ZUKSIsIEZhbHNlKSwKICAgICAgICAicHJldHJhaW4ucHQiOiAoIlByZXRyYWluIChiYXNlKSIsIFRydWUpLAogICAgfQoKICAgIGNoZWNrcG9pbnRzID0gW10KICAgIGZvciBmbmFtZSBpbiBwdF9maWxlczoKICAgICAgICBsYWJlbCwgaXNfcHJldHJhaW4gPSBfTEFCRUxTLmdldChmbmFtZSwgKGZuYW1lLnJlbW92ZXN1ZmZpeCgiLnB0IiksICJwcmV0cmFpbiIgaW4gZm5hbWUpKQogICAgICAgIGNoZWNrcG9pbnRzLmFwcGVuZCgobGFiZWwsIGZuYW1lLCBpc19wcmV0cmFpbikpCgogICAgaWYgbm90IGNoZWNrcG9pbnRzOgogICAgICAgIHJldHVybiBOb25lCgogICAgcmV0dXJuIHsKICAgICAgICAidmVyc2lvbiI6IGhmX2lkLnNwbGl0KCIvIilbLTFdLAogICAgICAgICJoZl9pZCI6IGhmX2lkLAogICAgICAgICJzdWJkaXIiOiBzdWJkaXIsCiAgICAgICAgImNoZWNrcG9pbnRzIjogY2hlY2twb2ludHMsCiAgICAgICAgImRlc2MiOiAiIiwKICAgIH0KCgpkZWYgZmV0Y2hfY29sbGVjdGlvbigpIC0+IGxpc3RbZGljdF06CiAgICAiIiJRdWVyeSBIRiBmb3IgYWxsIENvbXBhY3RBSS1PIFRNTE0tSGFpa3UgbW9kZWxzLCBuZXdlc3QgZmlyc3QuIiIiCiAgICBmcm9tIGh1Z2dpbmdmYWNlX2h1YiBpbXBvcnQgSGZBcGkKCiAgICBwcmludCgiQ2hlY2tpbmcgSHVnZ2luZ0ZhY2UgY29sbGVjdGlvbiBmb3IgYXZhaWxhYmxlIG1vZGVscy4uLiIpCiAgICB0cnk6CiAgICAgICAgYXBpID0gSGZBcGkoKQogICAgICAgIGluZm9zID0gbGlzdCgKICAgICAgICAgICAgYXBpLmxpc3RfbW9kZWxzKAogICAgICAgICAgICAgICAgYXV0aG9yPV9BVVRIT1IsCiAgICAgICAgICAgICAgICBzZWFyY2g9X1NFQVJDSCwKICAgICAgICAgICAgICAgIHNvcnQ9Imxhc3RNb2RpZmllZCIsCiAgICAgICAgICAgICkKICAgICAgICApCiAgICAgICAgaW5mb3Muc29ydChrZXk9bGFtYmRhIG06IGdldGF0dHIobSwgImxhc3RNb2RpZmllZCIsICIiKSwgcmV2ZXJzZT1UcnVlKQogICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBleGM6CiAgICAgICAgcHJpbnQoZiIgIENvdWxkIG5vdCByZWFjaCBIdWdnaW5nRmFjZSAoe2V4Y30pOyB1c2luZyBmYWxsYmFjayBsaXN0LiIpCiAgICAgICAgaW5mb3MgPSBbdHlwZSgiTSIsICgpLCB7ImlkIjogZVsiaGZfaWQiXX0pKCkgZm9yIGUgaW4gX0ZBTExCQUNLX0NPTExFQ1RJT05dCgogICAgZW50cmllcyA9IFtdCiAgICBmb3IgaW5mbyBpbiBpbmZvczoKICAgICAgICByZXBvX2lkID0gaW5mby5pZAogICAgICAgIGlmIF9TRUFSQ0gubG93ZXIoKSBub3QgaW4gcmVwb19pZC5sb3dlcigpOgogICAgICAgICAgICBjb250aW51ZQogICAgICAgIGVudHJ5ID0gX3Byb2JlX3JlcG8ocmVwb19pZCkKICAgICAgICBpZiBlbnRyeToKICAgICAgICAgICAgZW50cmllcy5hcHBlbmQoZW50cnkpCgogICAgaWYgbm90IGVudHJpZXM6CiAgICAgICAgcHJpbnQoIiAgTm8gbW9kZWxzIGZvdW5kOyB1c2luZyBmYWxsYmFjayBsaXN0LiIpCiAgICAgICAgZW50cmllcyA9IFtdCiAgICAgICAgZm9yIGZiIGluIF9GQUxMQkFDS19DT0xMRUNUSU9OOgogICAgICAgICAgICBlID0gX3Byb2JlX3JlcG8oZmJbImhmX2lkIl0pCiAgICAgICAgICAgIGlmIGU6CiAgICAgICAgICAgICAgICBlbnRyaWVzLmFwcGVuZChlKQoKICAgIHJldHVybiBlbnRyaWVzCgoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBEb3dubG9hZCBoZWxwZXIKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCgpkZWYgX2Rvd25sb2FkX3ZlcnNpb24oZW50cnk6IGRpY3QsIGNhY2hlX2RpcjogUGF0aCkgLT4gUGF0aDoKICAgICIiIkRvd25sb2FkIGZ1bGwgcmVwbyBzbmFwc2hvdDsgcmV0dXJuIHRoZSBkaXJlY3RvcnkgY29udGFpbmluZyBtb2RlbCBmaWxlcy4iIiIKICAgIHRyeToKICAgICAgICBmcm9tIGh1Z2dpbmdmYWNlX2h1YiBpbXBvcnQgc25hcHNob3RfZG93bmxvYWQKICAgIGV4Y2VwdCBJbXBvcnRFcnJvcjoKICAgICAgICBwcmludCgiaHVnZ2luZ2ZhY2VfaHViIG5vdCBpbnN0YWxsZWQuIFJ1bjogcGlwIGluc3RhbGwgaHVnZ2luZ2ZhY2VfaHViIikKICAgICAgICBzeXMuZXhpdCgxKQoKICAgIGhmX2lkID0gZW50cnlbImhmX2lkIl0KICAgIHByaW50KGYiRmV0Y2hpbmcge2hmX2lkfSAuLi4iKQogICAgdHJ5OgogICAgICAgIGxvY2FsX2RpciA9IFBhdGgoc25hcHNob3RfZG93bmxvYWQocmVwb19pZD1oZl9pZCwgY2FjaGVfZGlyPXN0cihjYWNoZV9kaXIpKSkKICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZXhjOgogICAgICAgIHByaW50KGYiRG93bmxvYWQgZmFpbGVkOiB7ZXhjfSIpCiAgICAgICAgc3lzLmV4aXQoMSkKCiAgICBzdWJkaXIgPSBlbnRyeS5nZXQoInN1YmRpciIpCiAgICBtb2RlbF9kaXIgPSAobG9jYWxfZGlyIC8gc3ViZGlyKSBpZiBzdWJkaXIgZWxzZSBsb2NhbF9kaXIKICAgIGlmIG5vdCBtb2RlbF9kaXIuZXhpc3RzKCk6CiAgICAgICAgIyBGYWxsYmFjayB0byByb290CiAgICAgICAgbW9kZWxfZGlyID0gbG9jYWxfZGlyCiAgICByZXR1cm4gbW9kZWxfZGlyCgoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBTZWxlY3Rpb24gcHJvbXB0cwojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKCmRlZiBfcHJvbXB0X2ludChwcm9tcHQ6IHN0ciwgbG86IGludCwgaGk6IGludCwgZGVmYXVsdDogaW50ID0gMSkgLT4gaW50OgogICAgd2hpbGUgVHJ1ZToKICAgICAgICB0cnk6CiAgICAgICAgICAgIHJhdyA9IGlucHV0KGYie3Byb21wdH0gW3tkZWZhdWx0fV06ICIpLnN0cmlwKCkKICAgICAgICBleGNlcHQgKEVPRkVycm9yLCBLZXlib2FyZEludGVycnVwdCk6CiAgICAgICAgICAgIHByaW50KCkKICAgICAgICAgICAgc3lzLmV4aXQoMCkKICAgICAgICBpZiBub3QgcmF3OgogICAgICAgICAgICByZXR1cm4gZGVmYXVsdAogICAgICAgIGlmIHJhdy5pc2RpZ2l0KCkgYW5kIGxvIDw9IGludChyYXcpIDw9IGhpOgogICAgICAgICAgICByZXR1cm4gaW50KHJhdykKICAgICAgICBwcmludChmIiAgRW50ZXIgYSBudW1iZXIge2xvfeKAk3toaX0uIikKCgpkZWYgcGlja192ZXJzaW9uKGNvbGxlY3Rpb246IGxpc3RbZGljdF0pIC0+IGRpY3Q6CiAgICBwcmludCgiXG5UTUxNLUhhaWt1IHNlcmllcyAgKENvbXBhY3RBSS1PKVxuIikKICAgIGZvciBpLCBlbnRyeSBpbiBlbnVtZXJhdGUoY29sbGVjdGlvbik6CiAgICAgICAgZGVzYyA9IGYiICDigJQge2VudHJ5WydkZXNjJ119IiBpZiBlbnRyeVsiZGVzYyJdIGVsc2UgIiIKICAgICAgICBwcmludChmIiAgW3tpICsgMX1dIHtlbnRyeVsndmVyc2lvbiddfXtkZXNjfSIpCiAgICBpZHggPSBfcHJvbXB0X2ludCgiU2VsZWN0IHZlcnNpb24iLCAxLCBsZW4oY29sbGVjdGlvbikpCiAgICByZXR1cm4gY29sbGVjdGlvbltpZHggLSAxXQoKCmRlZiBwaWNrX2NoZWNrcG9pbnQoZW50cnk6IGRpY3QpIC0+IHR1cGxlW3N0ciwgYm9vbF06CiAgICAiIiJSZXR1cm4gKGZpbGVuYW1lLCBpc19wcmV0cmFpbikuIiIiCiAgICBja3B0cyA9IGVudHJ5WyJjaGVja3BvaW50cyJdCiAgICBpZiBsZW4oY2twdHMpID09IDE6CiAgICAgICAgbGFiZWwsIGZuYW1lLCBpc19wcmV0cmFpbiA9IGNrcHRzWzBdCiAgICAgICAgcHJpbnQoZiIgIFVzaW5nOiB7bGFiZWx9ICh7Zm5hbWV9KSIpCiAgICAgICAgcmV0dXJuIGZuYW1lLCBpc19wcmV0cmFpbgoKICAgIHByaW50KGYiXG5DaGVja3BvaW50cyBmb3Ige2VudHJ5Wyd2ZXJzaW9uJ119OiIpCiAgICBmb3IgaSwgKGxhYmVsLCBmbmFtZSwgXykgaW4gZW51bWVyYXRlKGNrcHRzKToKICAgICAgICBwcmludChmIiAgW3tpICsgMX1dIHtsYWJlbH0gICh7Zm5hbWV9KSIpCiAgICBpZHggPSBfcHJvbXB0X2ludCgiU2VsZWN0IGNoZWNrcG9pbnQiLCAxLCBsZW4oY2twdHMpKQogICAgbGFiZWwsIGZuYW1lLCBpc19wcmV0cmFpbiA9IGNrcHRzW2lkeCAtIDFdCiAgICByZXR1cm4gZm5hbWUsIGlzX3ByZXRyYWluCgoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBNYWluCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgoKZGVmIG1haW4oKSAtPiBOb25lOgogICAgcHJpbnQoIj0iICogNTYpCiAgICBwcmludCgiICBUTUxNLUhhaWt1IEludGVyYWN0aXZlIENoYXQiKQogICAgcHJpbnQoIiAgTW9kZWxzOiBodWdnaW5nZmFjZS5jby9Db21wYWN0QUktTyIpCiAgICBwcmludCgiPSIgKiA1NikKCiAgICBjb2xsZWN0aW9uID0gZmV0Y2hfY29sbGVjdGlvbigpCiAgICBpZiBub3QgY29sbGVjdGlvbjoKICAgICAgICBwcmludCgiTm8gbW9kZWxzIGZvdW5kLiBDaGVjayB5b3VyIGludGVybmV0IGNvbm5lY3Rpb24uIikKICAgICAgICBzeXMuZXhpdCgxKQoKICAgIGVudHJ5ID0gcGlja192ZXJzaW9uKGNvbGxlY3Rpb24pCiAgICBmbmFtZSwgaXNfcHJldHJhaW4gPSBwaWNrX2NoZWNrcG9pbnQoZW50cnkpCgogICAgcm9vdCA9IFBhdGgoX19maWxlX18pLnJlc29sdmUoKS5wYXJlbnQKICAgIGNhY2hlX2RpciA9IHJvb3QgLyAiY2FjaGUiIC8gImh1Z2dpbmdmYWNlIgogICAgY2FjaGVfZGlyLm1rZGlyKHBhcmVudHM9VHJ1ZSwgZXhpc3Rfb2s9VHJ1ZSkKCiAgICBtb2RlbF9kaXIgPSBfZG93bmxvYWRfdmVyc2lvbihlbnRyeSwgY2FjaGVfZGlyKQoKICAgIG1vZGVsX3BhdGggPSBtb2RlbF9kaXIgLyBmbmFtZQogICAgdG9rZW5pemVyX3BhdGggPSBtb2RlbF9kaXIgLyAidG9rZW5pemVyLmpzb24iCgogICAgaWYgbm90IG1vZGVsX3BhdGguZXhpc3RzKCk6CiAgICAgICAgcHJpbnQoZiJGaWxlIG5vdCBmb3VuZDoge21vZGVsX3BhdGh9IikKICAgICAgICBzeXMuZXhpdCgxKQogICAgaWYgbm90IHRva2VuaXplcl9wYXRoLmV4aXN0cygpOgogICAgICAgIHByaW50KGYiVG9rZW5pemVyIG5vdCBmb3VuZDoge3Rva2VuaXplcl9wYXRofSIpCiAgICAgICAgc3lzLmV4aXQoMSkKCiAgICBwcmludChmIkxvYWRpbmcge2VudHJ5Wyd2ZXJzaW9uJ119IC8ge2ZuYW1lfSAuLi4iKQogICAgYnVuZGxlID0gbG9hZF9sb2NhbF9tb2RlbChtb2RlbF9wYXRoLCB0b2tlbml6ZXJfcGF0aCwgIkhhaWt1IikKCiAgICBjZmcgPSBwaWNrX21vZGUoaXNfcHJldHJhaW4pCiAgICBfcnVuX2xvb3AoYnVuZGxlLCBjZmcpCgoKaWYgX19uYW1lX18gPT0gIl9fbWFpbl9fIjoKICAgIG1haW4oKQo=";
var btn = document.getElementById('browser-launcher-download');
if (btn) {
btn.addEventListener('click', function() {
var bin = atob(b64);
var bytes = new Uint8Array(bin.length);
for (var i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
var blob = new Blob([bytes], { type: 'application/x-python' });
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'interactive.py';
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
var reqs = new Blob(['torch>=2.0.0\n'], { type: 'text/plain' });
var reqsUrl = URL.createObjectURL(reqs);
var b = document.createElement('a');
b.href = reqsUrl;
b.download = 'requirements.txt';
document.body.appendChild(b);
b.click();
b.remove();
URL.revokeObjectURL(reqsUrl);
});
}
})();
</script>
</body>
</html>