Homepage / downloads /index.html
CompactAI's picture
Upload 88 files
093ccf9 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: #0a1628;
--blue-800: #0f2240;
--blue-700: #142d54;
--blue-600: #1a3a6b;
--blue-500: #2250a0;
--blue-400: #3a7bd5;
--blue-300: #6ba3f0;
--blue-200: #a8c8f5;
--blue-100: #d4e4fa;
--white: #ffffff;
--white-soft: #f0f4fa;
--white-muted: #c8d8ec;
--grid-line: rgba(255, 255, 255, 0.08);
--grid-line-major: rgba(255, 255, 255, 0.18);
--accent: #6ba3f0;
--accent-muted: #3a7bd5;
--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(10, 22, 40, 0.92);
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);
}
</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>
<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;">
<button id="browser-launcher-download" type="button" 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
</button>
</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 = "IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwpmcm9tIF9fZnV0dXJlX18gaW1wb3J0IGFubm90YXRpb25zCgppbXBvcnQganNvbgppbXBvcnQgbWF0aAppbXBvcnQgb3MKaW1wb3J0IHJlCmltcG9ydCBzaHV0aWwKaW1wb3J0IHNvY2tldAppbXBvcnQgc3RyaW5nCmltcG9ydCBzeXMKaW1wb3J0IHRocmVhZGluZwppbXBvcnQgd2ViYnJvd3Nlcgpmcm9tIGRhdGFjbGFzc2VzIGltcG9ydCBkYXRhY2xhc3MKZnJvbSBodHRwLnNlcnZlciBpbXBvcnQgQmFzZUhUVFBSZXF1ZXN0SGFuZGxlciwgVGhyZWFkaW5nSFRUUFNlcnZlcgpmcm9tIHBhdGhsaWIgaW1wb3J0IFBhdGgKZnJvbSB0eXBpbmcgaW1wb3J0IEFueSwgRGljdCwgSXRlcmF0b3IsIExpc3QsIE9wdGlvbmFsLCBTZXF1ZW5jZSwgVHVwbGUKZnJvbSB1cmxsaWIucGFyc2UgaW1wb3J0IHF1b3RlLCB1bnF1b3RlLCB1cmxwYXJzZQpmcm9tIHVybGxpYi5yZXF1ZXN0IGltcG9ydCBSZXF1ZXN0LCB1cmxvcGVuCgppbXBvcnQgaGFzaGxpYgoKaW1wb3J0IHRvcmNoCmltcG9ydCB0b3JjaC5ubiBhcyBubgppbXBvcnQgdG9yY2gubm4uZnVuY3Rpb25hbCBhcyBGCmZyb20gdG9yY2gudXRpbHMuY2hlY2twb2ludCBpbXBvcnQgY2hlY2twb2ludAoKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgQ29uZmlnIChmcm9tIGFpbGF5LmNvbmZpZykKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCgpAZGF0YWNsYXNzCmNsYXNzIE1vZGVsQ29uZmlnOgogICAgZGltOiBpbnQgPSAxMjgKICAgIG5fdW5pcXVlX2xheWVyczogaW50ID0gOAogICAgbl9sb2dpY2FsX2xheWVyczogaW50ID0gMTYKICAgIG5faGVhZHM6IGludCA9IDQKICAgIG5fa3ZfaGVhZHM6IGludCA9IDIKICAgIGZmbl9kaW06IGludCA9IDIyNAogICAgZHJvcG91dDogZmxvYXQgPSAwLjAKICAgIHNlcV9sZW46IGludCA9IDIwNDgKICAgIHNsaWRpbmdfd2luZG93X3NpemU6IGludCA9IDUxMgogICAgbXRwX2hvcml6b25zOiBUdXBsZVtpbnQsIC4uLl0gPSAoMiwgMywgNCkKICAgIHJvcGVfZnJhY3Rpb246IGZsb2F0ID0gMC41CiAgICBlbWJlZF9zY2FsZTogYm9vbCA9IFRydWUKICAgIGxvZ2l0X3NvZnRfY2FwOiBmbG9hdCA9IC0xLjAKICAgIHF1YW50aXphdGlvbjogc3RyID0gIm52ZnA0IgogICAgIyBFbmdyYW0gKGNvbmRpdGlvbmFsIG1lbW9yeSkgY29uZmlnCiAgICBlbmdyYW1fZGltOiBpbnQgPSAwCiAgICBlbmdyYW1faGVhZHM6IGludCA9IDQKICAgIGVuZ3JhbV90YWJsZV9zaXplOiBpbnQgPSA4MTkyCiAgICBlbmdyYW1fbWF4X25ncmFtOiBpbnQgPSAzCiAgICAjIG1IQyAoTWFuaWZvbGQtQ29uc3RyYWluZWQgSHlwZXItQ29ubmVjdGlvbnMpIGNvbmZpZwogICAgbWhjX2V4cGFuc2lvbjogaW50ID0gMQoKICAgIEBwcm9wZXJ0eQogICAgZGVmIGhlYWRfZGltKHNlbGYpIC0+IGludDoKICAgICAgICByZXR1cm4gc2VsZi5kaW0gLy8gc2VsZi5uX2hlYWRzCgoKbW9kZWxfY29uZmlnID0gTW9kZWxDb25maWcoKQoKTU9ERUxfU0VSSUVTID0gewogICAgImhhaWt1IjogewogICAgICAgICJkaW0iOiA2NCwKICAgICAgICAibl91bmlxdWVfbGF5ZXJzIjogMTIsCiAgICAgICAgIm5fbG9naWNhbF9sYXllcnMiOiAyNCwKICAgICAgICAibl9oZWFkcyI6IDQsCiAgICAgICAgIm5fa3ZfaGVhZHMiOiAyLAogICAgICAgICJmZm5fZGltIjogMzg0LAogICAgICAgICJkcm9wb3V0IjogMC4wLAogICAgICAgICJzZXFfbGVuIjogMjA0OCwKICAgICAgICAibXRwX2hvcml6b25zIjogKDIsIDMsIDQpLAogICAgICAgICJyb3BlX2ZyYWN0aW9uIjogMC41LAogICAgICAgICJiYXRjaF9zaXplIjogODAsCiAgICAgICAgImdyYWRfYWNjdW0iOiAxLAogICAgICAgICJsciI6IDhlLTQsCiAgICAgICAgIm1pbl9sciI6IDFlLTUsCiAgICAgICAgInNmdF9sciI6IDJlLTQsCiAgICAgICAgInNmdF9taW5fbHIiOiAxZS01LAogICAgICAgICJ3YXJtdXBfc3RlcHMiOiAzMDAsCiAgICAgICAgIndlaWdodF9kZWNheSI6IDAuMDIsCiAgICAgICAgInByZXRyYWluX3Bhc3NlcyI6IDIsCiAgICAgICAgInNmdF9wYXNzZXMiOiAzLAogICAgICAgICJtYXhfc2Z0X3RhcmdldF9jaGFycyI6IDAsCiAgICAgICAgInVzZV9ncmFkX2NoZWNrcG9pbnQiOiBUcnVlLAogICAgICAgICJudW1fd29ya2VycyI6IDI0LAogICAgICAgICJwcmVmZXRjaF9mYWN0b3IiOiA2NCwKICAgICAgICAic2h1ZmZsZV9idWZmZXIiOiA4MTkyLAogICAgICAgICJtYXhfcHJldHJhaW5fdG9rZW5zIjogMCwKICAgICAgICAibWluX3ByZXRyYWluX3Rva2VucyI6IDEwMF8wMDBfMDAwLAogICAgICAgICJxdWFudGl6YXRpb24iOiAibnZmcDQiLAogICAgICAgICJlbmdyYW1fZGltIjogOCwKICAgICAgICAiZW5ncmFtX2hlYWRzIjogMiwKICAgICAgICAiZW5ncmFtX3RhYmxlX3NpemUiOiA2NCwKICAgICAgICAiZW5ncmFtX21heF9uZ3JhbSI6IDIsCiAgICAgICAgIm1oY19leHBhbnNpb24iOiAyLAogICAgfSwKICAgICJzb25uZXQiOiB7CiAgICAgICAgImRpbSI6IDEwMjQsCiAgICAgICAgIm5fdW5pcXVlX2xheWVycyI6IDIwLAogICAgICAgICJuX2xvZ2ljYWxfbGF5ZXJzIjogNDAsCiAgICAgICAgIm5faGVhZHMiOiAxNiwKICAgICAgICAibl9rdl9oZWFkcyI6IDQsCiAgICAgICAgImZmbl9kaW0iOiA0MDk2LAogICAgICAgICJkcm9wb3V0IjogMC4wLAogICAgICAgICJzZXFfbGVuIjogMjA0OCwKICAgICAgICAibXRwX2hvcml6b25zIjogKDIsKSwKICAgICAgICAicm9wZV9mcmFjdGlvbiI6IDAuNSwKICAgICAgICAiYmF0Y2hfc2l6ZSI6IDI0LAogICAgICAgICJncmFkX2FjY3VtIjogMSwKICAgICAgICAibHIiOiAxZS00LAogICAgICAgICJtaW5fbHIiOiAyZS01LAogICAgICAgICJzZnRfbHIiOiA1ZS01LAogICAgICAgICJzZnRfbWluX2xyIjogNWUtNiwKICAgICAgICAid2FybXVwX3N0ZXBzIjogMjUwLAogICAgICAgICJ3ZWlnaHRfZGVjYXkiOiAwLjEsCiAgICAgICAgInByZXRyYWluX3Bhc3NlcyI6IDEsCiAgICAgICAgInNmdF9wYXNzZXMiOiAxLAogICAgICAgICJtYXhfc2Z0X3RhcmdldF9jaGFycyI6IDAsCiAgICAgICAgInVzZV9ncmFkX2NoZWNrcG9pbnQiOiBUcnVlLAogICAgICAgICJudW1fd29ya2VycyI6IDMyLAogICAgICAgICJwcmVmZXRjaF9mYWN0b3IiOiA2NCwKICAgICAgICAic2h1ZmZsZV9idWZmZXIiOiAxNjM4NCwKICAgICAgICAibWF4X3ByZXRyYWluX3Rva2VucyI6IDAsCiAgICAgICAgIm1pbl9wcmV0cmFpbl90b2tlbnMiOiAxMDBfMDAwXzAwMCwKICAgICAgICAicXVhbnRpemF0aW9uIjogIm52ZnA0IiwKICAgICAgICAiZW5ncmFtX2RpbSI6IDMyLAogICAgICAgICJlbmdyYW1faGVhZHMiOiA4LAogICAgICAgICJlbmdyYW1fdGFibGVfc2l6ZSI6IDQwOTYsCiAgICAgICAgImVuZ3JhbV9tYXhfbmdyYW0iOiAyLAogICAgICAgICJtaGNfZXhwYW5zaW9uIjogMiwKICAgIH0sCiAgICAib3B1cyI6IHsKICAgICAgICAiZGltIjogMTUzNiwKICAgICAgICAibl91bmlxdWVfbGF5ZXJzIjogMTgsCiAgICAgICAgIm5fbG9naWNhbF9sYXllcnMiOiAzNiwKICAgICAgICAibl9oZWFkcyI6IDE2LAogICAgICAgICJuX2t2X2hlYWRzIjogNCwKICAgICAgICAiZmZuX2RpbSI6IDU4ODgsCiAgICAgICAgImRyb3BvdXQiOiAwLjAsCiAgICAgICAgInNlcV9sZW4iOiAyMDQ4LAogICAgICAgICJtdHBfaG9yaXpvbnMiOiAoMiwpLAogICAgICAgICJyb3BlX2ZyYWN0aW9uIjogMC41LAogICAgICAgICJiYXRjaF9zaXplIjogMjQsCiAgICAgICAgImdyYWRfYWNjdW0iOiAxLAogICAgICAgICJsciI6IDEuNmUtNCwKICAgICAgICAibWluX2xyIjogMS42ZS01LAogICAgICAgICJzZnRfbHIiOiAzZS01LAogICAgICAgICJzZnRfbWluX2xyIjogM2UtNiwKICAgICAgICAid2FybXVwX3N0ZXBzIjogMjAwLAogICAgICAgICJ3ZWlnaHRfZGVjYXkiOiAwLjEsCiAgICAgICAgInByZXRyYWluX3Bhc3NlcyI6IDEsCiAgICAgICAgInNmdF9wYXNzZXMiOiAxLAogICAgICAgICJtYXhfc2Z0X3RhcmdldF9jaGFycyI6IDAsCiAgICAgICAgInVzZV9ncmFkX2NoZWNrcG9pbnQiOiBUcnVlLAogICAgICAgICJudW1fd29ya2VycyI6IDQ4LAogICAgICAgICJwcmVmZXRjaF9mYWN0b3IiOiA2NCwKICAgICAgICAic2h1ZmZsZV9idWZmZXIiOiAxNjM4NCwKICAgICAgICAibWF4X3ByZXRyYWluX3Rva2VucyI6IDAsCiAgICAgICAgIm1pbl9wcmV0cmFpbl90b2tlbnMiOiAxMDBfMDAwXzAwMCwKICAgICAgICAicXVhbnRpemF0aW9uIjogIm52ZnA0IiwKICAgICAgICAiZW5ncmFtX2RpbSI6IDY0LAogICAgICAgICJlbmdyYW1faGVhZHMiOiA4LAogICAgICAgICJlbmdyYW1fdGFibGVfc2l6ZSI6IDgxOTIsCiAgICAgICAgImVuZ3JhbV9tYXhfbmdyYW0iOiAyLAogICAgICAgICJtaGNfZXhwYW5zaW9uIjogNCwKICAgIH0sCn0KCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFRva2VuaXplciAoZnJvbSBhaWxheS50b2tlbml6ZXIpCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpGT1JNQVRfVE9LRU5TID0gWwogICAgIjx8dXNlcnw+IiwKICAgICI8fGFzc2lzdGFudHw+IiwKICAgICI8fHN5c3RlbXw+IiwKICAgICI8fHN0YXJ0X2hlYWRlcl9pZHw+IiwKICAgICI8fGVuZF9oZWFkZXJfaWR8PiIsCiAgICAiPHxiZWdpbl9vZl90aG91Z2h0fD4iLAogICAgIjx8ZW5kX29mX3Rob3VnaHR8PiIsCiAgICAiPHxiZWdpbl9vZl9zb2x1dGlvbnw+IiwKICAgICI8fGVuZF9vZl9zb2x1dGlvbnw+IiwKXQoKCmNsYXNzIFdvcmRUb2tlbml6ZXI6CiAgICBXT1JEX1JFID0gcmUuY29tcGlsZSgKICAgICAgICByIlxzK3xbXlxXXGRfXSsoPzpbJ1x1MjAxOV1bXlxXXGRfXSspP3xcZCt8W15cd1xzXSsiLCByZS5VTklDT0RFCiAgICApCgogICAgZGVmIF9faW5pdF9fKAogICAgICAgIHNlbGYsIGV4dHJhX2NoYXJzOiBzdHIgPSAiIiwgZm9ybWF0X3Rva2VuczogT3B0aW9uYWxbTGlzdFtzdHJdXSA9IE5vbmUKICAgICkgLT4gTm9uZToKICAgICAgICBiYXNlID0gc3RyaW5nLmFzY2lpX2xldHRlcnMgKyBzdHJpbmcuZGlnaXRzICsgc3RyaW5nLnB1bmN0dWF0aW9uICsgIiBcblx0XHIiCiAgICAgICAgZmFsbGJhY2tfY2hhcnMgPSBzb3J0ZWQoc2V0KGJhc2UgKyBleHRyYV9jaGFycykpCiAgICAgICAgc2VsZi5jb3JlX3NwZWNpYWwgPSBbIjxQQUQ+IiwgIjxCT1M+IiwgIjxFT1M+IiwgIjxVTks+Il0KICAgICAgICBzZWxmLmZvcm1hdF90b2tlbnMgPSAoCiAgICAgICAgICAgIGxpc3QoZm9ybWF0X3Rva2VucykgaWYgZm9ybWF0X3Rva2VucyBlbHNlIGxpc3QoRk9STUFUX1RPS0VOUykKICAgICAgICApCiAgICAgICAgc2VsZi5zcGVjaWFsID0gbGlzdChzZWxmLmNvcmVfc3BlY2lhbCkgKyBsaXN0KHNlbGYuZm9ybWF0X3Rva2VucykKICAgICAgICBzZWxmLmlkX3RvX3Rva2VuOiBMaXN0W3N0cl0gPSAoCiAgICAgICAgICAgIGxpc3Qoc2VsZi5jb3JlX3NwZWNpYWwpICsgc2VsZi5mb3JtYXRfdG9rZW5zICsgZmFsbGJhY2tfY2hhcnMKICAgICAgICApCiAgICAgICAgc2VsZi50b2tlbl90b19pZDogRGljdFtzdHIsIGludF0gPSB7CiAgICAgICAgICAgIHQ6IGkgZm9yIGksIHQgaW4gZW51bWVyYXRlKHNlbGYuaWRfdG9fdG9rZW4pCiAgICAgICAgfQogICAgICAgIHNlbGYuc3BlY2lhbF9tdWx0aV90b2tlbnMgPSBzb3J0ZWQoCiAgICAgICAgICAgIFt0IGZvciB0IGluIHNlbGYuc3BlY2lhbCBpZiBsZW4odCkgPiAxXSwga2V5PWxlbiwgcmV2ZXJzZT1UcnVlCiAgICAgICAgKQogICAgICAgIHNlbGYubXVsdGlfY2hhcl90b2tlbnMgPSBzZWxmLnNwZWNpYWxfbXVsdGlfdG9rZW5zCiAgICAgICAgc2VsZi5keW5hbWljX2FkZGl0aW9ucyA9IDAKCiAgICBAcHJvcGVydHkKICAgIGRlZiBwYWRfaWQoc2VsZikgLT4gaW50OgogICAgICAgIHJldHVybiBzZWxmLnRva2VuX3RvX2lkWyI8UEFEPiJdCgogICAgQHByb3BlcnR5CiAgICBkZWYgYm9zX2lkKHNlbGYpIC0+IGludDoKICAgICAgICByZXR1cm4gc2VsZi50b2tlbl90b19pZFsiPEJPUz4iXQoKICAgIEBwcm9wZXJ0eQogICAgZGVmIGVvc19pZChzZWxmKSAtPiBpbnQ6CiAgICAgICAgcmV0dXJuIHNlbGYudG9rZW5fdG9faWRbIjxFT1M+Il0KCiAgICBAcHJvcGVydHkKICAgIGRlZiB1bmtfaWQoc2VsZikgLT4gaW50OgogICAgICAgIHJldHVybiBzZWxmLnRva2VuX3RvX2lkWyI8VU5LPiJdCgogICAgQHByb3BlcnR5CiAgICBkZWYgdm9jYWJfc2l6ZShzZWxmKSAtPiBpbnQ6CiAgICAgICAgcmV0dXJuIGxlbihzZWxmLmlkX3RvX3Rva2VuKQoKICAgIGRlZiBtYXliZV9hZGRfY2hhcihzZWxmLCBjaDogc3RyKSAtPiBib29sOgogICAgICAgIGlmIGNoIGluIHNlbGYudG9rZW5fdG9faWQ6CiAgICAgICAgICAgIHJldHVybiBGYWxzZQogICAgICAgIHNlbGYudG9rZW5fdG9faWRbY2hdID0gbGVuKHNlbGYuaWRfdG9fdG9rZW4pCiAgICAgICAgc2VsZi5pZF90b190b2tlbi5hcHBlbmQoY2gpCiAgICAgICAgc2VsZi5keW5hbWljX2FkZGl0aW9ucyArPSAxCiAgICAgICAgcmV0dXJuIFRydWUKCiAgICBkZWYgbWF5YmVfYWRkX3Rva2VuKHNlbGYsIHRva2VuOiBzdHIpIC0+IGJvb2w6CiAgICAgICAgaWYgdG9rZW4gaW4gc2VsZi50b2tlbl90b19pZDoKICAgICAgICAgICAgcmV0dXJuIEZhbHNlCiAgICAgICAgc2VsZi50b2tlbl90b19pZFt0b2tlbl0gPSBsZW4oc2VsZi5pZF90b190b2tlbikKICAgICAgICBzZWxmLmlkX3RvX3Rva2VuLmFwcGVuZCh0b2tlbikKICAgICAgICBzZWxmLmR5bmFtaWNfYWRkaXRpb25zICs9IDEKICAgICAgICByZXR1cm4gVHJ1ZQoKICAgIGRlZiBpdGVyX2xleGljYWxfdG9rZW5zKHNlbGYsIHRleHQ6IHN0cikgLT4gSXRlcmF0b3Jbc3RyXToKICAgICAgICBpID0gMAogICAgICAgIG4gPSBsZW4odGV4dCkKICAgICAgICB3aGlsZSBpIDwgbjoKICAgICAgICAgICAgbWF0Y2hlZF9zcGVjaWFsID0gRmFsc2UKICAgICAgICAgICAgZm9yIHRva2VuIGluIHNlbGYuc3BlY2lhbF9tdWx0aV90b2tlbnM6CiAgICAgICAgICAgICAgICBpZiB0ZXh0LnN0YXJ0c3dpdGgodG9rZW4sIGkpOgogICAgICAgICAgICAgICAgICAgIHlpZWxkIHRva2VuCiAgICAgICAgICAgICAgICAgICAgaSArPSBsZW4odG9rZW4pCiAgICAgICAgICAgICAgICAgICAgbWF0Y2hlZF9zcGVjaWFsID0gVHJ1ZQogICAgICAgICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICAgIGlmIG1hdGNoZWRfc3BlY2lhbDoKICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgIG0gPSBzZWxmLldPUkRfUkUubWF0Y2godGV4dCwgaSkKICAgICAgICAgICAgaWYgbSBpcyBOb25lOgogICAgICAgICAgICAgICAgeWllbGQgdGV4dFtpXQogICAgICAgICAgICAgICAgaSArPSAxCiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICB0b2sgPSBtLmdyb3VwKDApCiAgICAgICAgICAgIHlpZWxkIHRvawogICAgICAgICAgICBpID0gbS5lbmQoKQoKICAgIGRlZiBlbmNvZGUoCiAgICAgICAgc2VsZiwgdGV4dDogc3RyLCBhZGRfYm9zOiBib29sID0gRmFsc2UsIGFkZF9lb3M6IGJvb2wgPSBGYWxzZQogICAgKSAtPiBMaXN0W2ludF06CiAgICAgICAgb3V0OiBMaXN0W2ludF0gPSBbXQogICAgICAgIGlmIGFkZF9ib3M6CiAgICAgICAgICAgIG91dC5hcHBlbmQoc2VsZi5ib3NfaWQpCiAgICAgICAgdW5rID0gc2VsZi51bmtfaWQKICAgICAgICB0MmkgPSBzZWxmLnRva2VuX3RvX2lkCiAgICAgICAgZm9yIHRvayBpbiBzZWxmLml0ZXJfbGV4aWNhbF90b2tlbnModGV4dCk6CiAgICAgICAgICAgIHRpZCA9IHQyaS5nZXQodG9rKQogICAgICAgICAgICBpZiB0aWQgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICBvdXQuYXBwZW5kKHRpZCkKICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgIGZvciBjaCBpbiB0b2s6CiAgICAgICAgICAgICAgICBvdXQuYXBwZW5kKHQyaS5nZXQoY2gsIHVuaykpCiAgICAgICAgaWYgYWRkX2VvczoKICAgICAgICAgICAgb3V0LmFwcGVuZChzZWxmLmVvc19pZCkKICAgICAgICByZXR1cm4gb3V0CgogICAgZGVmIGRlY29kZShzZWxmLCBpZHM6IFNlcXVlbmNlW2ludF0sIHNraXBfc3BlY2lhbDogYm9vbCA9IFRydWUpIC0+IHN0cjoKICAgICAgICBwaWVjZXM6IExpc3Rbc3RyXSA9IFtdCiAgICAgICAgZm9yIGlkeCBpbiBpZHM6CiAgICAgICAgICAgIGlmIGludChpZHgpIDwgMCBvciBpbnQoaWR4KSA+PSBsZW4oc2VsZi5pZF90b190b2tlbik6CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICB0b2sgPSBzZWxmLmlkX3RvX3Rva2VuW2ludChpZHgpXQogICAgICAgICAgICBpZiBza2lwX3NwZWNpYWwgYW5kIHRvayBpbiBzZWxmLnNwZWNpYWw6CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICBwaWVjZXMuYXBwZW5kKHRvaykKICAgICAgICByZXR1cm4gIiIuam9pbihwaWVjZXMpCgogICAgZGVmIHNhdmUoc2VsZiwgcGF0aDogUGF0aCkgLT4gTm9uZToKICAgICAgICB3aXRoIHBhdGgub3BlbigidyIsIGVuY29kaW5nPSJ1dGYtOCIpIGFzIGY6CiAgICAgICAgICAgIGpzb24uZHVtcCgKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAiaWRfdG9fdG9rZW4iOiBzZWxmLmlkX3RvX3Rva2VuLAogICAgICAgICAgICAgICAgICAgICJmb3JtYXRfdG9rZW5zIjogc2VsZi5mb3JtYXRfdG9rZW5zLAogICAgICAgICAgICAgICAgICAgICJjb3JlX3NwZWNpYWwiOiBzZWxmLmNvcmVfc3BlY2lhbCwKICAgICAgICAgICAgICAgICAgICAidG9rZW5pemVyX3R5cGUiOiAid29yZF9sZXZlbF92MSIsCiAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgZiwKICAgICAgICAgICAgICAgIGVuc3VyZV9hc2NpaT1GYWxzZSwKICAgICAgICAgICAgICAgIGluZGVudD0yLAogICAgICAgICAgICApCgogICAgQGNsYXNzbWV0aG9kCiAgICBkZWYgbG9hZChjbHMsIHBhdGg6IFBhdGgpIC0+IFdvcmRUb2tlbml6ZXI6CiAgICAgICAgd2l0aCBwYXRoLm9wZW4oInIiLCBlbmNvZGluZz0idXRmLTgiKSBhcyBmOgogICAgICAgICAgICBkYXRhID0ganNvbi5sb2FkKGYpCiAgICAgICAgZm9ybWF0X3Rva2VucyA9IGRhdGEuZ2V0KCJmb3JtYXRfdG9rZW5zIiwgRk9STUFUX1RPS0VOUykKICAgICAgICB0b2tlbml6ZXIgPSBjbHMoZXh0cmFfY2hhcnM9IiIsIGZvcm1hdF90b2tlbnM9Zm9ybWF0X3Rva2VucykKICAgICAgICB0b2tlbml6ZXIuaWRfdG9fdG9rZW4gPSBkYXRhWyJpZF90b190b2tlbiJdCiAgICAgICAgdG9rZW5pemVyLnRva2VuX3RvX2lkID0ge3Q6IGkgZm9yIGksIHQgaW4gZW51bWVyYXRlKHRva2VuaXplci5pZF90b190b2tlbil9CiAgICAgICAgdG9rZW5pemVyLnNwZWNpYWwgPSBsaXN0KHRva2VuaXplci5jb3JlX3NwZWNpYWwpICsgbGlzdCh0b2tlbml6ZXIuZm9ybWF0X3Rva2VucykKICAgICAgICB0b2tlbml6ZXIuc3BlY2lhbF9tdWx0aV90b2tlbnMgPSBzb3J0ZWQoCiAgICAgICAgICAgIFt0IGZvciB0IGluIHRva2VuaXplci5zcGVjaWFsIGlmIGxlbih0KSA+IDFdLCBrZXk9bGVuLCByZXZlcnNlPVRydWUKICAgICAgICApCiAgICAgICAgdG9rZW5pemVyLm11bHRpX2NoYXJfdG9rZW5zID0gdG9rZW5pemVyLnNwZWNpYWxfbXVsdGlfdG9rZW5zCiAgICAgICAgcmV0dXJuIHRva2VuaXplcgoKCkxldHRlclRva2VuaXplciA9IFdvcmRUb2tlbml6ZXIKCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIE1vZGVsIChmcm9tIGFpbGF5Lm1vZGVsKQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKCmNsYXNzIFJNU05vcm0obm4uTW9kdWxlKToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBkaW06IGludCwgZXBzOiBmbG9hdCA9IDFlLTYpIC0+IE5vbmU6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygpCiAgICAgICAgc2VsZi53ZWlnaHQgPSBubi5QYXJhbWV0ZXIodG9yY2gub25lcyhkaW0pKQogICAgICAgIHNlbGYuZXBzID0gZXBzCgogICAgZGVmIGZvcndhcmQoc2VsZiwgeDogdG9yY2guVGVuc29yKSAtPiB0b3JjaC5UZW5zb3I6CiAgICAgICAgaWYgaGFzYXR0cih0b3JjaC5ubi5mdW5jdGlvbmFsLCAicm1zX25vcm0iKToKICAgICAgICAgICAgcmV0dXJuIHRvcmNoLm5uLmZ1bmN0aW9uYWwucm1zX25vcm0oCiAgICAgICAgICAgICAgICB4LCBzZWxmLndlaWdodC5zaGFwZSwgc2VsZi53ZWlnaHQsIHNlbGYuZXBzCiAgICAgICAgICAgICkKICAgICAgICB4X2ZwID0geC5mbG9hdCgpCiAgICAgICAgcm1zID0gdG9yY2gucnNxcnQoeF9mcC5wb3coMikubWVhbihkaW09LTEsIGtlZXBkaW09VHJ1ZSkgKyBzZWxmLmVwcykKICAgICAgICByZXR1cm4gKHhfZnAgKiBybXMpLnRvKGR0eXBlPXguZHR5cGUpICogc2VsZi53ZWlnaHQKCgpjbGFzcyBSb3RhcnlFbWJlZGRpbmcobm4uTW9kdWxlKToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBkaW06IGludCwgYmFzZTogZmxvYXQgPSAxMDAwMC4wKSAtPiBOb25lOgogICAgICAgIHN1cGVyKCkuX19pbml0X18oKQogICAgICAgIGludiA9IDEuMCAvIChiYXNlICoqICh0b3JjaC5hcmFuZ2UoMCwgZGltLCAyKS5mbG9hdCgpIC8gZGltKSkKICAgICAgICBzZWxmLnJlZ2lzdGVyX2J1ZmZlcigiaW52X2ZyZXEiLCBpbnYsIHBlcnNpc3RlbnQ9RmFsc2UpCgogICAgZGVmIGNvc19zaW4oCiAgICAgICAgc2VsZiwgc2VxX2xlbjogaW50LCBkZXZpY2U6IHRvcmNoLmRldmljZSwgZHR5cGU6IHRvcmNoLmR0eXBlCiAgICApIC0+IFR1cGxlW3RvcmNoLlRlbnNvciwgdG9yY2guVGVuc29yXToKICAgICAgICB0ID0gdG9yY2guYXJhbmdlKHNlcV9sZW4sIGRldmljZT1kZXZpY2UsIGR0eXBlPXNlbGYuaW52X2ZyZXEuZHR5cGUpCiAgICAgICAgZnJlcXMgPSB0b3JjaC5vdXRlcih0LCBzZWxmLmludl9mcmVxKQogICAgICAgIGVtYiA9IHRvcmNoLmNhdChbZnJlcXMsIGZyZXFzXSwgZGltPS0xKQogICAgICAgIGNvcyA9IGVtYi5jb3MoKVtOb25lLCBOb25lLCA6LCA6XS50byhkdHlwZT1kdHlwZSkKICAgICAgICBzaW4gPSBlbWIuc2luKClbTm9uZSwgTm9uZSwgOiwgOl0udG8oZHR5cGU9ZHR5cGUpCiAgICAgICAgcmV0dXJuIGNvcywgc2luCgoKZGVmIF9yb3RhdGVfaGFsZih4OiB0b3JjaC5UZW5zb3IpIC0+IHRvcmNoLlRlbnNvcjoKICAgIHgxID0geFsuLi4sIDogeC5zaGFwZVstMV0gLy8gMl0KICAgIHgyID0geFsuLi4sIHguc2hhcGVbLTFdIC8vIDIgOl0KICAgIHJldHVybiB0b3JjaC5jYXQoKC14MiwgeDEpLCBkaW09LTEpCgoKY2xhc3MgQ2F1c2FsU2VsZkF0dGVudGlvbihubi5Nb2R1bGUpOgogICAgZGVmIF9faW5pdF9fKAogICAgICAgIHNlbGYsCiAgICAgICAgZGltOiBpbnQsCiAgICAgICAgbl9oZWFkczogaW50LAogICAgICAgIG5fa3ZfaGVhZHM6IGludCwKICAgICAgICBoZWFkX2RpbTogaW50LAogICAgICAgIGRyb3BvdXQ6IGZsb2F0LAogICAgICAgIHNsaWRpbmdfd2luZG93OiBpbnQsCiAgICAgICAgcm9wZV9mcmFjdGlvbjogZmxvYXQsCiAgICApIC0+IE5vbmU6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygpCiAgICAgICAgc2VsZi5kaW0gPSBkaW0KICAgICAgICBzZWxmLm5faGVhZHMgPSBuX2hlYWRzCiAgICAgICAgc2VsZi5uX2t2X2hlYWRzID0gbl9rdl9oZWFkcwogICAgICAgIHNlbGYuaGVhZF9kaW0gPSBoZWFkX2RpbQogICAgICAgIHNlbGYubl9yZXAgPSBuX2hlYWRzIC8vIG5fa3ZfaGVhZHMKICAgICAgICBzZWxmLmRyb3BvdXQgPSBkcm9wb3V0CiAgICAgICAgc2VsZi5zbGlkaW5nX3dpbmRvdyA9IHNsaWRpbmdfd2luZG93CgogICAgICAgIHNlbGYud3EgPSBubi5MaW5lYXIoZGltLCBuX2hlYWRzICogaGVhZF9kaW0sIGJpYXM9RmFsc2UpCiAgICAgICAgc2VsZi53ayA9IG5uLkxpbmVhcihkaW0sIG5fa3ZfaGVhZHMgKiBoZWFkX2RpbSwgYmlhcz1GYWxzZSkKICAgICAgICBzZWxmLnd2ID0gbm4uTGluZWFyKGRpbSwgbl9rdl9oZWFkcyAqIGhlYWRfZGltLCBiaWFzPUZhbHNlKQogICAgICAgIHNlbGYud28gPSBubi5MaW5lYXIobl9oZWFkcyAqIGhlYWRfZGltLCBkaW0sIGJpYXM9RmFsc2UpCgogICAgICAgIGZvciBsaW4gaW4gKHNlbGYud3EsIHNlbGYud2ssIHNlbGYud3YpOgogICAgICAgICAgICBubi5pbml0Lm5vcm1hbF8obGluLndlaWdodCwgc3RkPWRpbSAqKiAtMC41KQogICAgICAgIG5uLmluaXQubm9ybWFsXyhzZWxmLndvLndlaWdodCwgc3RkPShuX2hlYWRzICogaGVhZF9kaW0pICoqIC0wLjUpCgogICAgICAgIHNlbGYucm9wZV9kaW0gPSBtYXgoMiwgaW50KGhlYWRfZGltICogcm9wZV9mcmFjdGlvbikgLy8gMiAqIDIpCiAgICAgICAgc2VsZi5yb3BlID0gUm90YXJ5RW1iZWRkaW5nKHNlbGYucm9wZV9kaW0pCgogICAgICAgIHNlbGYucV9ub3JtID0gUk1TTm9ybShoZWFkX2RpbSkKICAgICAgICBzZWxmLmtfbm9ybSA9IFJNU05vcm0oaGVhZF9kaW0pCgogICAgICAgIHNlbGYub3V0cHV0X2dhdGUgPSBubi5QYXJhbWV0ZXIodG9yY2guemVyb3Mobl9oZWFkcykpCgogICAgZGVmIGZvcndhcmQoCiAgICAgICAgc2VsZiwKICAgICAgICB4OiB0b3JjaC5UZW5zb3IsCiAgICAgICAgaXNfZ2xvYmFsOiBib29sLAogICAgICAgIHBhc3Rfa3Y6IE9wdGlvbmFsW1R1cGxlW3RvcmNoLlRlbnNvciwgdG9yY2guVGVuc29yXV0gPSBOb25lLAogICAgICAgIHVzZV9jYWNoZTogYm9vbCA9IEZhbHNlLAogICAgKSAtPiBUdXBsZVt0b3JjaC5UZW5zb3IsIE9wdGlvbmFsW1R1cGxlW3RvcmNoLlRlbnNvciwgdG9yY2guVGVuc29yXV1dOgogICAgICAgIEIsIFQsIF8gPSB4LnNoYXBlCgogICAgICAgIHEgPSBzZWxmLndxKHgpLnZpZXcoQiwgVCwgc2VsZi5uX2hlYWRzLCBzZWxmLmhlYWRfZGltKQogICAgICAgIGsgPSBzZWxmLndrKHgpLnZpZXcoQiwgVCwgc2VsZi5uX2t2X2hlYWRzLCBzZWxmLmhlYWRfZGltKQogICAgICAgIHYgPSBzZWxmLnd2KHgpLnZpZXcoQiwgVCwgc2VsZi5uX2t2X2hlYWRzLCBzZWxmLmhlYWRfZGltKQoKICAgICAgICBxID0gc2VsZi5xX25vcm0ocSkKICAgICAgICBrID0gc2VsZi5rX25vcm0oaykKCiAgICAgICAgcSA9IHEudHJhbnNwb3NlKDEsIDIpCiAgICAgICAgayA9IGsudHJhbnNwb3NlKDEsIDIpCiAgICAgICAgdiA9IHYudHJhbnNwb3NlKDEsIDIpCgogICAgICAgIHBhc3RfbGVuID0gcGFzdF9rdlswXS5zaGFwZVsyXSBpZiBwYXN0X2t2IGlzIG5vdCBOb25lIGVsc2UgMAogICAgICAgIGNvcywgc2luID0gc2VsZi5yb3BlLmNvc19zaW4oVCArIHBhc3RfbGVuLCB4LmRldmljZSwgcS5kdHlwZSkKICAgICAgICBjb3Nfc2xpY2UgPSBjb3NbOiwgOiwgcGFzdF9sZW4gOiBwYXN0X2xlbiArIFQsIDpdCiAgICAgICAgc2luX3NsaWNlID0gc2luWzosIDosIHBhc3RfbGVuIDogcGFzdF9sZW4gKyBULCA6XQoKICAgICAgICBxX3JvcGUgPSBxWy4uLiwgOiBzZWxmLnJvcGVfZGltXQogICAgICAgIHFfcGFzcyA9IHFbLi4uLCBzZWxmLnJvcGVfZGltIDpdCiAgICAgICAga19yb3BlID0ga1suLi4sIDogc2VsZi5yb3BlX2RpbV0KICAgICAgICBrX3Bhc3MgPSBrWy4uLiwgc2VsZi5yb3BlX2RpbSA6XQoKICAgICAgICBxX3JvcGUgPSAocV9yb3BlICogY29zX3NsaWNlKSArIChfcm90YXRlX2hhbGYocV9yb3BlKSAqIHNpbl9zbGljZSkKICAgICAgICBrX3JvcGUgPSAoa19yb3BlICogY29zX3NsaWNlKSArIChfcm90YXRlX2hhbGYoa19yb3BlKSAqIHNpbl9zbGljZSkKCiAgICAgICAgcSA9IHRvcmNoLmNhdChbcV9yb3BlLCBxX3Bhc3NdLCBkaW09LTEpCiAgICAgICAgayA9IHRvcmNoLmNhdChba19yb3BlLCBrX3Bhc3NdLCBkaW09LTEpCgogICAgICAgIGlmIHBhc3Rfa3YgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIGsgPSB0b3JjaC5jYXQoW3Bhc3Rfa3ZbMF0sIGtdLCBkaW09MikKICAgICAgICAgICAgdiA9IHRvcmNoLmNhdChbcGFzdF9rdlsxXSwgdl0sIGRpbT0yKQoKICAgICAgICBuZXdfa3YgPSAoaywgdikgaWYgdXNlX2NhY2hlIGVsc2UgTm9uZQoKICAgICAgICBTID0gay5zaGFwZVsyXQogICAgICAgIGlmIHNlbGYubl9yZXAgPiAxOgogICAgICAgICAgICBrID0gKAogICAgICAgICAgICAgICAga1s6LCA6LCBOb25lLCA6LCA6XQogICAgICAgICAgICAgICAgLmV4cGFuZChCLCBzZWxmLm5fa3ZfaGVhZHMsIHNlbGYubl9yZXAsIFMsIHNlbGYuaGVhZF9kaW0pCiAgICAgICAgICAgICAgICAucmVzaGFwZShCLCBzZWxmLm5faGVhZHMsIFMsIHNlbGYuaGVhZF9kaW0pCiAgICAgICAgICAgICkKICAgICAgICAgICAgdiA9ICgKICAgICAgICAgICAgICAgIHZbOiwgOiwgTm9uZSwgOiwgOl0KICAgICAgICAgICAgICAgIC5leHBhbmQoQiwgc2VsZi5uX2t2X2hlYWRzLCBzZWxmLm5fcmVwLCBTLCBzZWxmLmhlYWRfZGltKQogICAgICAgICAgICAgICAgLnJlc2hhcGUoQiwgc2VsZi5uX2hlYWRzLCBTLCBzZWxmLmhlYWRfZGltKQogICAgICAgICAgICApCgogICAgICAgIGRyb3BfcCA9IHNlbGYuZHJvcG91dCBpZiAoc2VsZi50cmFpbmluZyBhbmQgdG9yY2guaXNfZ3JhZF9lbmFibGVkKCkpIGVsc2UgMC4wCgogICAgICAgIGlmIGlzX2dsb2JhbDoKICAgICAgICAgICAgaWYgcGFzdF9rdiBpcyBOb25lIGFuZCBUID4gMToKICAgICAgICAgICAgICAgIG91dCA9IEYuc2NhbGVkX2RvdF9wcm9kdWN0X2F0dGVudGlvbigKICAgICAgICAgICAgICAgICAgICBxLCBrLCB2LCBpc19jYXVzYWw9VHJ1ZSwgZHJvcG91dF9wPWRyb3BfcAogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgb3V0ID0gRi5zY2FsZWRfZG90X3Byb2R1Y3RfYXR0ZW50aW9uKHEsIGssIHYsIGRyb3BvdXRfcD1kcm9wX3ApCiAgICAgICAgZWxzZToKICAgICAgICAgICAgVF9xID0gcS5zaGFwZVsyXQogICAgICAgICAgICBxX3BvcyA9IHRvcmNoLmFyYW5nZShwYXN0X2xlbiwgcGFzdF9sZW4gKyBUX3EsIGRldmljZT1xLmRldmljZSkudW5zcXVlZXplKDEpCiAgICAgICAgICAgIGtfcG9zID0gdG9yY2guYXJhbmdlKFMsIGRldmljZT1xLmRldmljZSkudW5zcXVlZXplKDApCiAgICAgICAgICAgIG1hc2sgPSAocV9wb3MgPj0ga19wb3MpICYgKChxX3BvcyAtIGtfcG9zKSA8IHNlbGYuc2xpZGluZ193aW5kb3cpCiAgICAgICAgICAgIG91dCA9IEYuc2NhbGVkX2RvdF9wcm9kdWN0X2F0dGVudGlvbigKICAgICAgICAgICAgICAgIHEsIGssIHYsIGF0dG5fbWFzaz1tYXNrLnVuc3F1ZWV6ZSgwKS51bnNxdWVlemUoMCksIGRyb3BvdXRfcD1kcm9wX3AKICAgICAgICAgICAgKQoKICAgICAgICBnYXRlID0gdG9yY2guc2lnbW9pZChzZWxmLm91dHB1dF9nYXRlKS52aWV3KDEsIHNlbGYubl9oZWFkcywgMSwgMSkKICAgICAgICBvdXQgPSBvdXQgKiBnYXRlCgogICAgICAgIG91dCA9IG91dC50cmFuc3Bvc2UoMSwgMikuY29udGlndW91cygpLnZpZXcoQiwgVCwgc2VsZi5uX2hlYWRzICogc2VsZi5oZWFkX2RpbSkKICAgICAgICBvdXQgPSBzZWxmLndvKG91dCkKCiAgICAgICAgcmV0dXJuIG91dCwgbmV3X2t2CgoKY2xhc3MgU3dpR0xVKG5uLk1vZHVsZSk6CiAgICBkZWYgX19pbml0X18oc2VsZiwgZGltOiBpbnQsIGhpZGRlbl9kaW06IGludCwgZHJvcG91dDogZmxvYXQpIC0+IE5vbmU6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygpCiAgICAgICAgc2VsZi5nYXRlID0gbm4uTGluZWFyKGRpbSwgaGlkZGVuX2RpbSwgYmlhcz1GYWxzZSkKICAgICAgICBzZWxmLnVwID0gbm4uTGluZWFyKGRpbSwgaGlkZGVuX2RpbSwgYmlhcz1GYWxzZSkKICAgICAgICBzZWxmLmRvd24gPSBubi5MaW5lYXIoaGlkZGVuX2RpbSwgZGltLCBiaWFzPUZhbHNlKQogICAgICAgIHNlbGYuZHJvcCA9IG5uLkRyb3BvdXQoZHJvcG91dCkKCiAgICAgICAgbm4uaW5pdC5ub3JtYWxfKHNlbGYuZ2F0ZS53ZWlnaHQsIHN0ZD1kaW0gKiogLTAuNSkKICAgICAgICBubi5pbml0Lm5vcm1hbF8oc2VsZi51cC53ZWlnaHQsIHN0ZD1kaW0gKiogLTAuNSkKICAgICAgICBubi5pbml0Lm5vcm1hbF8oc2VsZi5kb3duLndlaWdodCwgc3RkPWhpZGRlbl9kaW0gKiogLTAuNSkKCiAgICBkZWYgZm9yd2FyZChzZWxmLCB4OiB0b3JjaC5UZW5zb3IpIC0+IHRvcmNoLlRlbnNvcjoKICAgICAgICBoID0gRi5zaWx1KHNlbGYuZ2F0ZSh4KSkgKiBzZWxmLnVwKHgpCiAgICAgICAgb3V0ID0gc2VsZi5kb3duKGgpCiAgICAgICAgaWYgc2VsZi50cmFpbmluZyBhbmQgdG9yY2guaXNfZ3JhZF9lbmFibGVkKCk6CiAgICAgICAgICAgIG91dCA9IHNlbGYuZHJvcChvdXQpCiAgICAgICAgcmV0dXJuIG91dAoKCmNsYXNzIEVuZ3JhbUJsb2NrKG5uLk1vZHVsZSk6CiAgICAiIiJDb25kaXRpb25hbCBtZW1vcnkgdmlhIE8oMSkgaGFzaGVkIE4tZ3JhbSBsb29rdXAgKERlZXBTZWVrIEVuZ3JhbSkuIiIiCgogICAgZGVmIF9faW5pdF9fKAogICAgICAgIHNlbGYsCiAgICAgICAgZGltOiBpbnQsCiAgICAgICAgZW5ncmFtX2RpbTogaW50LAogICAgICAgIG5faGVhZHM6IGludCA9IDQsCiAgICAgICAgdGFibGVfc2l6ZTogaW50ID0gODE5MiwKICAgICAgICBtYXhfbmdyYW06IGludCA9IDMsCiAgICApIC0+IE5vbmU6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygpCiAgICAgICAgc2VsZi5kaW0gPSBkaW0KICAgICAgICBzZWxmLmVuZ3JhbV9kaW0gPSBlbmdyYW1fZGltCiAgICAgICAgc2VsZi5uX2hlYWRzID0gbl9oZWFkcwogICAgICAgIHNlbGYudGFibGVfc2l6ZSA9IHRhYmxlX3NpemUKICAgICAgICBzZWxmLm1heF9uZ3JhbSA9IG1heF9uZ3JhbQoKICAgICAgICBzZWxmLmVtYmVkZGluZ3MgPSBubi5QYXJhbWV0ZXJEaWN0KCkKICAgICAgICBmb3IgbiBpbiByYW5nZSgyLCBtYXhfbmdyYW0gKyAxKToKICAgICAgICAgICAgZm9yIGsgaW4gcmFuZ2Uobl9oZWFkcyk6CiAgICAgICAgICAgICAgICBzZWxmLmVtYmVkZGluZ3NbZiJ7bn1fe2t9Il0gPSBubi5QYXJhbWV0ZXIoCiAgICAgICAgICAgICAgICAgICAgdG9yY2gucmFuZG4odGFibGVfc2l6ZSwgZW5ncmFtX2RpbSkgKiAoZW5ncmFtX2RpbSoqLTAuNSkKICAgICAgICAgICAgICAgICkKCiAgICAgICAgZm9yIG4gaW4gcmFuZ2UoMiwgbWF4X25ncmFtICsgMSk6CiAgICAgICAgICAgIGZvciBrIGluIHJhbmdlKG5faGVhZHMpOgogICAgICAgICAgICAgICAgc2VlZCA9IGludChoYXNobGliLm1kNShmImVuZ3JhbV97bn1fe2t9Ii5lbmNvZGUoKSkuaGV4ZGlnZXN0KClbOjhdLCAxNikKICAgICAgICAgICAgICAgIHJuZyA9IHRvcmNoLkdlbmVyYXRvcigpLm1hbnVhbF9zZWVkKHNlZWQpCiAgICAgICAgICAgICAgICBhID0gdG9yY2gucmFuZGludCgxLCAyKiozMSwgKDEsKSwgZ2VuZXJhdG9yPXJuZykuaXRlbSgpCiAgICAgICAgICAgICAgICBiID0gdG9yY2gucmFuZGludCgwLCAyKiozMSwgKDEsKSwgZ2VuZXJhdG9yPXJuZykuaXRlbSgpCiAgICAgICAgICAgICAgICBzZWxmLnJlZ2lzdGVyX2J1ZmZlcigKICAgICAgICAgICAgICAgICAgICBmImhhc2hfYV97bn1fe2t9IiwgdG9yY2gudGVuc29yKGEpLCBwZXJzaXN0ZW50PUZhbHNlCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICBzZWxmLnJlZ2lzdGVyX2J1ZmZlcigKICAgICAgICAgICAgICAgICAgICBmImhhc2hfYl97bn1fe2t9IiwgdG9yY2gudGVuc29yKGIpLCBwZXJzaXN0ZW50PUZhbHNlCiAgICAgICAgICAgICAgICApCgogICAgICAgIHRvdGFsX2JyYW5jaF9kaW0gPSBlbmdyYW1fZGltICogbl9oZWFkcyAqIChtYXhfbmdyYW0gLSAxKQogICAgICAgIHNlbGYuYnJhbmNoX2NvbnYgPSBubi5Db252MWQoCiAgICAgICAgICAgIHRvdGFsX2JyYW5jaF9kaW0sCiAgICAgICAgICAgIHRvdGFsX2JyYW5jaF9kaW0sCiAgICAgICAgICAgIGtlcm5lbF9zaXplPTQsCiAgICAgICAgICAgIGRpbGF0aW9uPW1heF9uZ3JhbSwKICAgICAgICAgICAgcGFkZGluZz0wLAogICAgICAgICAgICBncm91cHM9dG90YWxfYnJhbmNoX2RpbSwKICAgICAgICAgICAgYmlhcz1UcnVlLAogICAgICAgICkKICAgICAgICBubi5pbml0Lnplcm9zXyhzZWxmLmJyYW5jaF9jb252LndlaWdodCkKICAgICAgICBubi5pbml0Lnplcm9zXyhzZWxmLmJyYW5jaF9jb252LmJpYXMpCgogICAgICAgIHNlbGYuZ2F0ZV9xdWVyeSA9IG5uLkxpbmVhcihkaW0sIGVuZ3JhbV9kaW0sIGJpYXM9RmFsc2UpCiAgICAgICAgc2VsZi5nYXRlX2tleSA9IG5uLkxpbmVhcih0b3RhbF9icmFuY2hfZGltLCBlbmdyYW1fZGltLCBiaWFzPUZhbHNlKQogICAgICAgIHNlbGYuZ2F0ZV92YWx1ZSA9IG5uLkxpbmVhcih0b3RhbF9icmFuY2hfZGltLCBkaW0sIGJpYXM9RmFsc2UpCiAgICAgICAgc2VsZi5nYXRlX3NjYWxlID0gZW5ncmFtX2RpbSoqLTAuNQoKICAgIGRlZiBfaGFzaF9uZ3JhbShzZWxmLCB0b2tlbl9pZHM6IHRvcmNoLlRlbnNvciwgbjogaW50LCBrOiBpbnQpIC0+IHRvcmNoLlRlbnNvcjoKICAgICAgICBhID0gZ2V0YXR0cihzZWxmLCBmImhhc2hfYV97bn1fe2t9IikKICAgICAgICBiID0gZ2V0YXR0cihzZWxmLCBmImhhc2hfYl97bn1fe2t9IikKICAgICAgICBCLCBUID0gdG9rZW5faWRzLnNoYXBlCiAgICAgICAgcGFkZGVkID0gRi5wYWQodG9rZW5faWRzLCAobiAtIDEsIDApLCB2YWx1ZT0wKQogICAgICAgIGNvbWJpbmVkID0gdG9yY2guemVyb3MoQiwgVCwgZHR5cGU9dG9yY2gubG9uZywgZGV2aWNlPXRva2VuX2lkcy5kZXZpY2UpCiAgICAgICAgZm9yIGkgaW4gcmFuZ2Uobik6CiAgICAgICAgICAgIGNvbWJpbmVkID0gKGNvbWJpbmVkICogMzEgKyBwYWRkZWRbOiwgaSA6IGkgKyBUXS5sb25nKCkpICUgc2VsZi50YWJsZV9zaXplCiAgICAgICAgcmV0dXJuICgoYSAqIGNvbWJpbmVkKSBeIGIpICUgc2VsZi50YWJsZV9zaXplCgogICAgZGVmIGZvcndhcmQoCiAgICAgICAgc2VsZiwgaGlkZGVuOiB0b3JjaC5UZW5zb3IsIHRva2VuX2lkczogT3B0aW9uYWxbdG9yY2guVGVuc29yXSA9IE5vbmUKICAgICkgLT4gdG9yY2guVGVuc29yOgogICAgICAgIEIsIFQsIF8gPSBoaWRkZW4uc2hhcGUKICAgICAgICBpZiB0b2tlbl9pZHMgaXMgTm9uZToKICAgICAgICAgICAgdG9rZW5faWRzID0gaGlkZGVuLm1lYW4oZGltPS0xKS5sb25nKCkgJSBzZWxmLnRhYmxlX3NpemUKICAgICAgICBhbGxfaW5kaWNlcyA9IFtdCiAgICAgICAgYWxsX3RhYmxlcyA9IFtdCiAgICAgICAgZm9yIG4gaW4gcmFuZ2UoMiwgc2VsZi5tYXhfbmdyYW0gKyAxKToKICAgICAgICAgICAgZm9yIGsgaW4gcmFuZ2Uoc2VsZi5uX2hlYWRzKToKICAgICAgICAgICAgICAgIGFsbF9pbmRpY2VzLmFwcGVuZChzZWxmLl9oYXNoX25ncmFtKHRva2VuX2lkcywgbiwgaykpCiAgICAgICAgICAgICAgICBhbGxfdGFibGVzLmFwcGVuZChzZWxmLmVtYmVkZGluZ3NbZiJ7bn1fe2t9Il0pCiAgICAgICAgYnJhbmNoX291dHB1dHMgPSBbdGJsW2lkeF0gZm9yIGlkeCwgdGJsIGluIHppcChhbGxfaW5kaWNlcywgYWxsX3RhYmxlcyldCiAgICAgICAgbWVtb3J5ID0gdG9yY2guY2F0KGJyYW5jaF9vdXRwdXRzLCBkaW09LTEpCiAgICAgICAgY29udl9pbiA9IG1lbW9yeS50cmFuc3Bvc2UoMSwgMikKICAgICAgICBjb252X2luID0gRi5wYWQoCiAgICAgICAgICAgIGNvbnZfaW4sCiAgICAgICAgICAgIChzZWxmLmJyYW5jaF9jb252LmRpbGF0aW9uWzBdICogKHNlbGYuYnJhbmNoX2NvbnYua2VybmVsX3NpemVbMF0gLSAxKSwgMCksCiAgICAgICAgKQogICAgICAgIGNvbnZfb3V0ID0gc2VsZi5icmFuY2hfY29udihjb252X2luKQogICAgICAgIG1lbW9yeSA9IGNvbnZfb3V0LnRyYW5zcG9zZSgxLCAyKQogICAgICAgIHF1ZXJ5ID0gc2VsZi5nYXRlX3F1ZXJ5KGhpZGRlbikKICAgICAgICBrZXkgPSBzZWxmLmdhdGVfa2V5KG1lbW9yeSkKICAgICAgICBnYXRlID0gdG9yY2guc2lnbW9pZCgKICAgICAgICAgICAgKHF1ZXJ5ICoga2V5KS5zdW0oZGltPS0xLCBrZWVwZGltPVRydWUpICogc2VsZi5nYXRlX3NjYWxlCiAgICAgICAgKQogICAgICAgIHZhbHVlID0gc2VsZi5nYXRlX3ZhbHVlKG1lbW9yeSkKICAgICAgICByZXR1cm4gZ2F0ZSAqIHZhbHVlCgoKZGVmIF9zaW5raG9ybl9rbm9wcChsb2dpdHM6IHRvcmNoLlRlbnNvciwgbl9pdGVyczogaW50ID0gNykgLT4gdG9yY2guVGVuc29yOgogICAgTSA9IHRvcmNoLmV4cChsb2dpdHMuY2xhbXAoLTEwLCAxMCkpCiAgICBmb3IgXyBpbiByYW5nZShuX2l0ZXJzKToKICAgICAgICBNID0gTSAvIE0uc3VtKGRpbT0tMSwga2VlcGRpbT1UcnVlKS5jbGFtcChtaW49MWUtMTApCiAgICAgICAgTSA9IE0gLyBNLnN1bShkaW09LTIsIGtlZXBkaW09VHJ1ZSkuY2xhbXAobWluPTFlLTEwKQogICAgcmV0dXJuIE0KCgpjbGFzcyBNYW5pZm9sZEh5cGVyQ29ubmVjdGlvbihubi5Nb2R1bGUpOgogICAgIiIiTWFuaWZvbGQtQ29uc3RyYWluZWQgSHlwZXItQ29ubmVjdGlvbnMgKG1IQykgcmVzaWR1YWwgd3JhcHBlci4iIiIKCiAgICBkZWYgX19pbml0X18oc2VsZiwgZGltOiBpbnQsIGV4cGFuc2lvbjogaW50ID0gMikgLT4gTm9uZToKICAgICAgICBzdXBlcigpLl9faW5pdF9fKCkKICAgICAgICBzZWxmLmRpbSA9IGRpbQogICAgICAgIHNlbGYuZXhwYW5zaW9uID0gZXhwYW5zaW9uCiAgICAgICAgbiA9IGV4cGFuc2lvbgoKICAgICAgICBzZWxmLmJpYXNfcHJlID0gbm4uUGFyYW1ldGVyKHRvcmNoLnplcm9zKDEsIG4pKQogICAgICAgIHNlbGYuYmlhc19wb3N0ID0gbm4uUGFyYW1ldGVyKHRvcmNoLnplcm9zKDEsIG4pKQogICAgICAgIHNlbGYuYmlhc19yZXMgPSBubi5QYXJhbWV0ZXIodG9yY2guemVyb3MobiwgbikpCgogICAgICAgIHNlbGYudGhldGFfcHJlID0gbm4uTGluZWFyKG4gKiBkaW0sIG4sIGJpYXM9RmFsc2UpCiAgICAgICAgc2VsZi50aGV0YV9wb3N0ID0gbm4uTGluZWFyKG4gKiBkaW0sIG4sIGJpYXM9RmFsc2UpCiAgICAgICAgc2VsZi50aGV0YV9yZXMgPSBubi5MaW5lYXIobiAqIGRpbSwgbiAqIG4sIGJpYXM9RmFsc2UpCgogICAgICAgIHNlbGYuYWxwaGFfcHJlID0gbm4uUGFyYW1ldGVyKHRvcmNoLnRlbnNvcigwLjApKQogICAgICAgIHNlbGYuYWxwaGFfcG9zdCA9IG5uLlBhcmFtZXRlcih0b3JjaC50ZW5zb3IoMC4wKSkKICAgICAgICBzZWxmLmFscGhhX3JlcyA9IG5uLlBhcmFtZXRlcih0b3JjaC50ZW5zb3IoMC4wKSkKCiAgICBkZWYgX2NvbXB1dGVfbWFwcGluZ3MoCiAgICAgICAgc2VsZiwgeF9leHBhbmRlZDogdG9yY2guVGVuc29yCiAgICApIC0+IFR1cGxlW3RvcmNoLlRlbnNvciwgdG9yY2guVGVuc29yLCB0b3JjaC5UZW5zb3JdOgogICAgICAgIEIsIFQsIF8gPSB4X2V4cGFuZGVkLnNoYXBlCiAgICAgICAgbiA9IHNlbGYuZXhwYW5zaW9uCiAgICAgICAgeF9ub3JtID0gRi5ybXNfbm9ybSh4X2V4cGFuZGVkLCBbeF9leHBhbmRlZC5zaGFwZVstMV1dKQogICAgICAgIGRfcHJlID0gdG9yY2gudGFuaChzZWxmLnRoZXRhX3ByZSh4X25vcm0pKQogICAgICAgIGRfcG9zdCA9IHRvcmNoLnRhbmgoc2VsZi50aGV0YV9wb3N0KHhfbm9ybSkpCiAgICAgICAgZF9yZXMgPSBzZWxmLnRoZXRhX3Jlcyh4X25vcm0pCiAgICAgICAgSF9wcmVfcmF3ID0gdG9yY2guc2lnbW9pZChzZWxmLmFscGhhX3ByZSAqIGRfcHJlICsgc2VsZi5iaWFzX3ByZSkKICAgICAgICBIX3Bvc3RfcmF3ID0gMi4wICogdG9yY2guc2lnbW9pZChzZWxmLmFscGhhX3Bvc3QgKiBkX3Bvc3QgKyBzZWxmLmJpYXNfcG9zdCkKICAgICAgICBIX3Jlc19yYXcgPSAoc2VsZi5hbHBoYV9yZXMgKiBkX3JlcyArIHNlbGYuYmlhc19yZXMucmVzaGFwZSgxLCAxLCAtMSkpLnJlc2hhcGUoCiAgICAgICAgICAgIEIsIFQsIG4sIG4KICAgICAgICApCiAgICAgICAgSF9yZXMgPSBfc2lua2hvcm5fa25vcHAoSF9yZXNfcmF3KQogICAgICAgIHJldHVybiBIX3ByZV9yYXcudW5zcXVlZXplKC0yKSwgSF9wb3N0X3Jhdy51bnNxdWVlemUoLTIpLCBIX3JlcwoKICAgIGRlZiBleHBhbmRfc3RyZWFtKHNlbGYsIHg6IHRvcmNoLlRlbnNvcikgLT4gdG9yY2guVGVuc29yOgogICAgICAgIHJldHVybiB4LnJlcGVhdCgxLCAxLCBzZWxmLmV4cGFuc2lvbikKCiAgICBkZWYgY29sbGFwc2Vfc3RyZWFtKHNlbGYsIHhfZXhwYW5kZWQ6IHRvcmNoLlRlbnNvcikgLT4gdG9yY2guVGVuc29yOgogICAgICAgIEIsIFQsIF8gPSB4X2V4cGFuZGVkLnNoYXBlCiAgICAgICAgcmV0dXJuIHhfZXhwYW5kZWQudmlldyhCLCBULCBzZWxmLmV4cGFuc2lvbiwgc2VsZi5kaW0pLm1lYW4oZGltPS0yKQoKICAgIGRlZiBwcmVfbWl4KHNlbGYsIHhfZXhwYW5kZWQ6IHRvcmNoLlRlbnNvciwgSF9wcmU6IHRvcmNoLlRlbnNvcikgLT4gdG9yY2guVGVuc29yOgogICAgICAgIEIsIFQsIF8gPSB4X2V4cGFuZGVkLnNoYXBlCiAgICAgICAgeF9zdHJlYW1zID0geF9leHBhbmRlZC52aWV3KEIsIFQsIHNlbGYuZXhwYW5zaW9uLCBzZWxmLmRpbSkKICAgICAgICByZXR1cm4gKEhfcHJlIEAgeF9zdHJlYW1zKS5zcXVlZXplKC0yKQoKICAgIGRlZiBwb3N0X3Jlc19taXgoCiAgICAgICAgc2VsZiwKICAgICAgICBsYXllcl9vdXRwdXQ6IHRvcmNoLlRlbnNvciwKICAgICAgICB4X2V4cGFuZGVkOiB0b3JjaC5UZW5zb3IsCiAgICAgICAgSF9wb3N0OiB0b3JjaC5UZW5zb3IsCiAgICAgICAgSF9yZXM6IHRvcmNoLlRlbnNvciwKICAgICkgLT4gdG9yY2guVGVuc29yOgogICAgICAgIEIsIFQsIF8gPSB4X2V4cGFuZGVkLnNoYXBlCiAgICAgICAgeF9zdHJlYW1zID0geF9leHBhbmRlZC52aWV3KEIsIFQsIHNlbGYuZXhwYW5zaW9uLCBzZWxmLmRpbSkKICAgICAgICBtaXhlZCA9IHRvcmNoLm1hdG11bChIX3JlcywgeF9zdHJlYW1zKQogICAgICAgIHBvc3Rfb3V0ID0gdG9yY2gubWF0bXVsKEhfcG9zdC50cmFuc3Bvc2UoLTIsIC0xKSwgbGF5ZXJfb3V0cHV0LnVuc3F1ZWV6ZSgtMikpCiAgICAgICAgcmV0dXJuIChtaXhlZCArIHBvc3Rfb3V0KS5yZXNoYXBlKEIsIFQsIHNlbGYuZXhwYW5zaW9uICogc2VsZi5kaW0pCgoKY2xhc3MgVHJhbnNmb3JtZXJCbG9jayhubi5Nb2R1bGUpOgogICAgZGVmIF9faW5pdF9fKAogICAgICAgIHNlbGYsCiAgICAgICAgZGltOiBpbnQsCiAgICAgICAgbl9oZWFkczogaW50LAogICAgICAgIG5fa3ZfaGVhZHM6IGludCwKICAgICAgICBoZWFkX2RpbTogaW50LAogICAgICAgIGZmbl9kaW06IGludCwKICAgICAgICBkcm9wb3V0OiBmbG9hdCwKICAgICAgICBzbGlkaW5nX3dpbmRvdzogaW50LAogICAgICAgIHJvcGVfZnJhY3Rpb246IGZsb2F0LAogICAgICAgIGVuZ3JhbV9kaW06IGludCA9IDAsCiAgICAgICAgZW5ncmFtX2hlYWRzOiBpbnQgPSA0LAogICAgICAgIGVuZ3JhbV90YWJsZV9zaXplOiBpbnQgPSA4MTkyLAogICAgICAgIGVuZ3JhbV9tYXhfbmdyYW06IGludCA9IDMsCiAgICAgICAgbWhjX2V4cGFuc2lvbjogaW50ID0gMSwKICAgICkgLT4gTm9uZToKICAgICAgICBzdXBlcigpLl9faW5pdF9fKCkKICAgICAgICBzZWxmLmRpbSA9IGRpbQogICAgICAgIHNlbGYubm9ybTEgPSBSTVNOb3JtKGRpbSkKICAgICAgICBzZWxmLmF0dG4gPSBDYXVzYWxTZWxmQXR0ZW50aW9uKAogICAgICAgICAgICBkaW09ZGltLAogICAgICAgICAgICBuX2hlYWRzPW5faGVhZHMsCiAgICAgICAgICAgIG5fa3ZfaGVhZHM9bl9rdl9oZWFkcywKICAgICAgICAgICAgaGVhZF9kaW09aGVhZF9kaW0sCiAgICAgICAgICAgIGRyb3BvdXQ9ZHJvcG91dCwKICAgICAgICAgICAgc2xpZGluZ193aW5kb3c9c2xpZGluZ193aW5kb3csCiAgICAgICAgICAgIHJvcGVfZnJhY3Rpb249cm9wZV9mcmFjdGlvbiwKICAgICAgICApCiAgICAgICAgc2VsZi5ub3JtMiA9IFJNU05vcm0oZGltKQogICAgICAgIHNlbGYuZmZuID0gU3dpR0xVKGRpbSwgZmZuX2RpbSwgZHJvcG91dCkKICAgICAgICBzZWxmLnVzZV9lbmdyYW0gPSBlbmdyYW1fZGltID4gMAogICAgICAgIGlmIHNlbGYudXNlX2VuZ3JhbToKICAgICAgICAgICAgc2VsZi5lbmdyYW0gPSBFbmdyYW1CbG9jaygKICAgICAgICAgICAgICAgIGRpbT1kaW0sCiAgICAgICAgICAgICAgICBlbmdyYW1fZGltPWVuZ3JhbV9kaW0sCiAgICAgICAgICAgICAgICBuX2hlYWRzPWVuZ3JhbV9oZWFkcywKICAgICAgICAgICAgICAgIHRhYmxlX3NpemU9ZW5ncmFtX3RhYmxlX3NpemUsCiAgICAgICAgICAgICAgICBtYXhfbmdyYW09ZW5ncmFtX21heF9uZ3JhbSwKICAgICAgICAgICAgKQogICAgICAgICAgICBzZWxmLmVuZ3JhbV9ub3JtID0gUk1TTm9ybShkaW0pCiAgICAgICAgc2VsZi51c2VfbWhjID0gbWhjX2V4cGFuc2lvbiA+IDEKICAgICAgICBpZiBzZWxmLnVzZV9taGM6CiAgICAgICAgICAgIHNlbGYubWhjX2F0dG4gPSBNYW5pZm9sZEh5cGVyQ29ubmVjdGlvbihkaW0sIGV4cGFuc2lvbj1taGNfZXhwYW5zaW9uKQogICAgICAgICAgICBzZWxmLm1oY19mZm4gPSBNYW5pZm9sZEh5cGVyQ29ubmVjdGlvbihkaW0sIGV4cGFuc2lvbj1taGNfZXhwYW5zaW9uKQoKICAgIGRlZiBmb3J3YXJkKAogICAgICAgIHNlbGYsCiAgICAgICAgeDogdG9yY2guVGVuc29yLAogICAgICAgIGlzX2dsb2JhbDogYm9vbCwKICAgICAgICBwYXN0X2t2OiBPcHRpb25hbFtUdXBsZVt0b3JjaC5UZW5zb3IsIHRvcmNoLlRlbnNvcl1dID0gTm9uZSwKICAgICAgICB1c2VfY2FjaGU6IGJvb2wgPSBGYWxzZSwKICAgICAgICB0b2tlbl9pZHM6IE9wdGlvbmFsW3RvcmNoLlRlbnNvcl0gPSBOb25lLAogICAgKSAtPiBUdXBsZVt0b3JjaC5UZW5zb3IsIE9wdGlvbmFsW1R1cGxlW3RvcmNoLlRlbnNvciwgdG9yY2guVGVuc29yXV1dOgogICAgICAgIGlmIHNlbGYudXNlX21oYzoKICAgICAgICAgICAgeF9leHAgPSBzZWxmLm1oY19hdHRuLmV4cGFuZF9zdHJlYW0oeCkKICAgICAgICAgICAgSF9wcmUsIEhfcG9zdCwgSF9yZXMgPSBzZWxmLm1oY19hdHRuLl9jb21wdXRlX21hcHBpbmdzKHhfZXhwKQogICAgICAgICAgICBhdHRuX2luID0gc2VsZi5taGNfYXR0bi5wcmVfbWl4KHhfZXhwLCBIX3ByZSkKICAgICAgICAgICAgYXR0bl9vdXQsIG5ld19rdiA9IHNlbGYuYXR0bigKICAgICAgICAgICAgICAgIHNlbGYubm9ybTEoYXR0bl9pbiksIGlzX2dsb2JhbCwgcGFzdF9rdiwgdXNlX2NhY2hlCiAgICAgICAgICAgICkKICAgICAgICAgICAgeF9leHAgPSBzZWxmLm1oY19hdHRuLnBvc3RfcmVzX21peChhdHRuX291dCwgeF9leHAsIEhfcG9zdCwgSF9yZXMpCiAgICAgICAgICAgIGlmIHNlbGYudXNlX2VuZ3JhbToKICAgICAgICAgICAgICAgIGNvbGxhcHNlZCA9IHNlbGYubWhjX2F0dG4uY29sbGFwc2Vfc3RyZWFtKHhfZXhwKQogICAgICAgICAgICAgICAgY29sbGFwc2VkID0gY29sbGFwc2VkICsgc2VsZi5lbmdyYW0oCiAgICAgICAgICAgICAgICAgICAgc2VsZi5lbmdyYW1fbm9ybShjb2xsYXBzZWQpLCB0b2tlbl9pZHM9dG9rZW5faWRzCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICB4X2V4cCA9IHNlbGYubWhjX2F0dG4uZXhwYW5kX3N0cmVhbShjb2xsYXBzZWQpCiAgICAgICAgICAgIEhfcHJlMiwgSF9wb3N0MiwgSF9yZXMyID0gc2VsZi5taGNfZmZuLl9jb21wdXRlX21hcHBpbmdzKHhfZXhwKQogICAgICAgICAgICBmZm5faW4gPSBzZWxmLm1oY19mZm4ucHJlX21peCh4X2V4cCwgSF9wcmUyKQogICAgICAgICAgICBmZm5fb3V0ID0gc2VsZi5mZm4oc2VsZi5ub3JtMihmZm5faW4pKQogICAgICAgICAgICB4X2V4cCA9IHNlbGYubWhjX2Zmbi5wb3N0X3Jlc19taXgoZmZuX291dCwgeF9leHAsIEhfcG9zdDIsIEhfcmVzMikKICAgICAgICAgICAgeCA9IHNlbGYubWhjX2F0dG4uY29sbGFwc2Vfc3RyZWFtKHhfZXhwKQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIGF0dG5fb3V0LCBuZXdfa3YgPSBzZWxmLmF0dG4oc2VsZi5ub3JtMSh4KSwgaXNfZ2xvYmFsLCBwYXN0X2t2LCB1c2VfY2FjaGUpCiAgICAgICAgICAgIHggPSB4ICsgYXR0bl9vdXQKICAgICAgICAgICAgaWYgc2VsZi51c2VfZW5ncmFtOgogICAgICAgICAgICAgICAgeCA9IHggKyBzZWxmLmVuZ3JhbShzZWxmLmVuZ3JhbV9ub3JtKHgpLCB0b2tlbl9pZHM9dG9rZW5faWRzKQogICAgICAgICAgICB4ID0geCArIHNlbGYuZmZuKHNlbGYubm9ybTIoeCkpCiAgICAgICAgcmV0dXJuIHgsIG5ld19rdgoKCmRlZiBfZGV0ZWN0X2VuZ3JhbV9kaW0oc3RhdGVfZGljdDogZGljdCkgLT4gaW50OgogICAgZm9yIGtleSBpbiBzdGF0ZV9kaWN0OgogICAgICAgIGlmICIuZW5ncmFtLiIgaW4ga2V5IGFuZCAiLmVtYmVkZGluZ3MuIiBpbiBrZXk6CiAgICAgICAgICAgIHJldHVybiBzdGF0ZV9kaWN0W2tleV0uc2hhcGVbLTFdCiAgICByZXR1cm4gMAoKCmRlZiBfZGV0ZWN0X21oY19leHBhbnNpb24oc3RhdGVfZGljdDogZGljdCkgLT4gaW50OgogICAgZm9yIGtleSwgdmFsIGluIHN0YXRlX2RpY3QuaXRlbXMoKToKICAgICAgICBpZiAiLm1oY19hdHRuLmJpYXNfcHJlIiBpbiBrZXkgYW5kIHZhbC5kaW0oKSA9PSAyOgogICAgICAgICAgICByZXR1cm4gdmFsLnNoYXBlWy0xXQogICAgcmV0dXJuIDEKCgpjbGFzcyBUaW55TWVtb3J5TE0obm4uTW9kdWxlKToKICAgIGRlZiBfX2luaXRfXygKICAgICAgICBzZWxmLAogICAgICAgIHZvY2FiX3NpemU6IGludCwKICAgICAgICBkaW06IGludCwKICAgICAgICBuX3VuaXF1ZV9sYXllcnM6IGludCwKICAgICAgICBuX2xvZ2ljYWxfbGF5ZXJzOiBpbnQsCiAgICAgICAgbl9oZWFkczogaW50LAogICAgICAgIG5fa3ZfaGVhZHM6IGludCwKICAgICAgICBmZm5fZGltOiBpbnQsCiAgICAgICAgZHJvcG91dDogZmxvYXQsCiAgICAgICAgbXRwX2hvcml6b25zOiBTZXF1ZW5jZVtpbnRdLAogICAgICAgIGdyYWRfY2hlY2twb2ludDogYm9vbCwKICAgICAgICBzbGlkaW5nX3dpbmRvdzogaW50ID0gNTEyLAogICAgICAgIHJvcGVfZnJhY3Rpb246IGZsb2F0ID0gMC41LAogICAgICAgIGVtYmVkX3NjYWxlOiBib29sID0gVHJ1ZSwKICAgICAgICBlbmdyYW1fZGltOiBpbnQgPSAwLAogICAgICAgIGVuZ3JhbV9oZWFkczogaW50ID0gNCwKICAgICAgICBlbmdyYW1fdGFibGVfc2l6ZTogaW50ID0gODE5MiwKICAgICAgICBlbmdyYW1fbWF4X25ncmFtOiBpbnQgPSAzLAogICAgICAgIG1oY19leHBhbnNpb246IGludCA9IDEsCiAgICApIC0+IE5vbmU6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygpCiAgICAgICAgc2VsZi5kaW0gPSBkaW0KICAgICAgICBzZWxmLm5fdW5pcXVlX2xheWVycyA9IG5fdW5pcXVlX2xheWVycwogICAgICAgIHNlbGYubl9sb2dpY2FsX2xheWVycyA9IG5fbG9naWNhbF9sYXllcnMKICAgICAgICBzZWxmLmdyYWRfY2hlY2twb2ludCA9IGdyYWRfY2hlY2twb2ludAogICAgICAgIHNlbGYuZW1iZWRfc2NhbGVfZmFjdG9yID0gbWF0aC5zcXJ0KGRpbSkgaWYgZW1iZWRfc2NhbGUgZWxzZSAxLjAKICAgICAgICBoZWFkX2RpbSA9IGRpbSAvLyBuX2hlYWRzCgogICAgICAgIHNlbGYuZW1iZWRfdG9rZW5zID0gbm4uRW1iZWRkaW5nKHZvY2FiX3NpemUsIGRpbSkKICAgICAgICBzZWxmLmhlYWQgPSBubi5MaW5lYXIoZGltLCB2b2NhYl9zaXplLCBiaWFzPUZhbHNlKQogICAgICAgIHNlbGYuaGVhZC53ZWlnaHQgPSBzZWxmLmVtYmVkX3Rva2Vucy53ZWlnaHQKCiAgICAgICAgc2VsZi5vdXRwdXRfYmlhcyA9IG5uLlBhcmFtZXRlcih0b3JjaC56ZXJvcyh2b2NhYl9zaXplKSkKCiAgICAgICAgc2VsZi5ibG9ja3MgPSBubi5Nb2R1bGVMaXN0KAogICAgICAgICAgICBbCiAgICAgICAgICAgICAgICBUcmFuc2Zvcm1lckJsb2NrKAogICAgICAgICAgICAgICAgICAgIGRpbT1kaW0sCiAgICAgICAgICAgICAgICAgICAgbl9oZWFkcz1uX2hlYWRzLAogICAgICAgICAgICAgICAgICAgIG5fa3ZfaGVhZHM9bl9rdl9oZWFkcywKICAgICAgICAgICAgICAgICAgICBoZWFkX2RpbT1oZWFkX2RpbSwKICAgICAgICAgICAgICAgICAgICBmZm5fZGltPWZmbl9kaW0sCiAgICAgICAgICAgICAgICAgICAgZHJvcG91dD1kcm9wb3V0LAogICAgICAgICAgICAgICAgICAgIHNsaWRpbmdfd2luZG93PXNsaWRpbmdfd2luZG93LAogICAgICAgICAgICAgICAgICAgIHJvcGVfZnJhY3Rpb249cm9wZV9mcmFjdGlvbiwKICAgICAgICAgICAgICAgICAgICBlbmdyYW1fZGltPWVuZ3JhbV9kaW0sCiAgICAgICAgICAgICAgICAgICAgZW5ncmFtX2hlYWRzPWVuZ3JhbV9oZWFkcywKICAgICAgICAgICAgICAgICAgICBlbmdyYW1fdGFibGVfc2l6ZT1lbmdyYW1fdGFibGVfc2l6ZSwKICAgICAgICAgICAgICAgICAgICBlbmdyYW1fbWF4X25ncmFtPWVuZ3JhbV9tYXhfbmdyYW0sCiAgICAgICAgICAgICAgICAgICAgbWhjX2V4cGFuc2lvbj1taGNfZXhwYW5zaW9uLAogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgZm9yIF8gaW4gcmFuZ2Uobl91bmlxdWVfbGF5ZXJzKQogICAgICAgICAgICBdCiAgICAgICAgKQogICAgICAgIHNlbGYubm9ybSA9IFJNU05vcm0oZGltKQoKICAgICAgICBzZWxmLm10cF9ob3Jpem9ucyA9IHNvcnRlZCh7aW50KGgpIGZvciBoIGluIG10cF9ob3Jpem9ucyBpZiBpbnQoaCkgPiAxfSkKICAgICAgICBzZWxmLm10cF9hZGFwdGVycyA9IG5uLk1vZHVsZURpY3QoCiAgICAgICAgICAgIHtzdHIoaCk6IG5uLkxpbmVhcihkaW0sIGRpbSwgYmlhcz1GYWxzZSkgZm9yIGggaW4gc2VsZi5tdHBfaG9yaXpvbnN9CiAgICAgICAgKQogICAgICAgIHNlbGYubXRwX25vcm1zID0gbm4uTW9kdWxlRGljdCgKICAgICAgICAgICAge3N0cihoKTogUk1TTm9ybShkaW0pIGZvciBoIGluIHNlbGYubXRwX2hvcml6b25zfQogICAgICAgICkKCiAgICAgICAgcmVzX3NjYWxlID0gKDIgKiBuX2xvZ2ljYWxfbGF5ZXJzKSAqKiAtMC41CiAgICAgICAgZm9yIGJsb2NrIGluIHNlbGYuYmxvY2tzOgogICAgICAgICAgICBibG9jay5hdHRuLndvLndlaWdodC5kYXRhLm11bF8ocmVzX3NjYWxlKQogICAgICAgICAgICBibG9jay5mZm4uZG93bi53ZWlnaHQuZGF0YS5tdWxfKHJlc19zY2FsZSkKCiAgICBkZWYgcmVzaXplX3Rva2VuX2VtYmVkZGluZ3Moc2VsZiwgbmV3X3ZvY2FiX3NpemU6IGludCkgLT4gTm9uZToKICAgICAgICBvbGRfdm9jYWJfc2l6ZSA9IHNlbGYuZW1iZWRfdG9rZW5zLm51bV9lbWJlZGRpbmdzCiAgICAgICAgaWYgbmV3X3ZvY2FiX3NpemUgPT0gb2xkX3ZvY2FiX3NpemU6CiAgICAgICAgICAgIHJldHVybgogICAgICAgIGRldmljZSA9IHNlbGYuZW1iZWRfdG9rZW5zLndlaWdodC5kZXZpY2UKICAgICAgICBvbGRfZW1iZWRfd2VpZ2h0ID0gc2VsZi5lbWJlZF90b2tlbnMud2VpZ2h0LmRhdGEuY2xvbmUoKQogICAgICAgIHNlbGYuZW1iZWRfdG9rZW5zID0gbm4uRW1iZWRkaW5nKAogICAgICAgICAgICBuZXdfdm9jYWJfc2l6ZSwgc2VsZi5lbWJlZF90b2tlbnMuZW1iZWRkaW5nX2RpbQogICAgICAgICkudG8oZGV2aWNlKQogICAgICAgIHNlbGYuaGVhZCA9IG5uLkxpbmVhcigKICAgICAgICAgICAgc2VsZi5lbWJlZF90b2tlbnMuZW1iZWRkaW5nX2RpbSwgbmV3X3ZvY2FiX3NpemUsIGJpYXM9RmFsc2UKICAgICAgICApLnRvKGRldmljZSkKICAgICAgICBzZWxmLmhlYWQud2VpZ2h0ID0gc2VsZi5lbWJlZF90b2tlbnMud2VpZ2h0CiAgICAgICAgb2xkX2JpYXMgPSBzZWxmLm91dHB1dF9iaWFzLmRhdGEuY2xvbmUoKQogICAgICAgIHNlbGYub3V0cHV0X2JpYXMgPSBubi5QYXJhbWV0ZXIodG9yY2guemVyb3MobmV3X3ZvY2FiX3NpemUsIGRldmljZT1kZXZpY2UpKQogICAgICAgIGNvcHlfc2l6ZSA9IG1pbihvbGRfdm9jYWJfc2l6ZSwgbmV3X3ZvY2FiX3NpemUpCiAgICAgICAgc2VsZi5vdXRwdXRfYmlhcy5kYXRhWzpjb3B5X3NpemVdID0gb2xkX2JpYXNbOmNvcHlfc2l6ZV0KICAgICAgICBzZWxmLmVtYmVkX3Rva2Vucy53ZWlnaHQuZGF0YVs6Y29weV9zaXplXSA9IG9sZF9lbWJlZF93ZWlnaHRbOmNvcHlfc2l6ZV0KCiAgICBkZWYgX2J1aWxkX2xvZ2ljYWxfbGF5ZXJzKHNlbGYpIC0+IExpc3RbVHVwbGVbbm4uTW9kdWxlLCBpbnRdXToKICAgICAgICBsb2dpY2FsID0gW10KICAgICAgICBibG9ja3NfbGlzdCA9IGxpc3Qoc2VsZi5ibG9ja3MpCiAgICAgICAgZnVsbF9zZXF1ZW5jZSA9IGJsb2Nrc19saXN0ICsgYmxvY2tzX2xpc3QKICAgICAgICBmb3IgbG9naWNhbF9pZHgsIGJsb2NrIGluIGVudW1lcmF0ZShmdWxsX3NlcXVlbmNlWzogc2VsZi5uX2xvZ2ljYWxfbGF5ZXJzXSk6CiAgICAgICAgICAgIGxvZ2ljYWwuYXBwZW5kKChibG9jaywgbG9naWNhbF9pZHgpKQogICAgICAgIHJldHVybiBsb2dpY2FsCgogICAgZGVmIGZvcndhcmQoCiAgICAgICAgc2VsZiwKICAgICAgICBpZHM6IHRvcmNoLlRlbnNvciwKICAgICAgICB1c2VfY2FjaGU6IGJvb2wgPSBGYWxzZSwKICAgICAgICBwYXN0X2tleV92YWx1ZXM6IE9wdGlvbmFsWwogICAgICAgICAgICBMaXN0W09wdGlvbmFsW1R1cGxlW3RvcmNoLlRlbnNvciwgdG9yY2guVGVuc29yXV1dCiAgICAgICAgXSA9IE5vbmUsCiAgICAgICAgcmV0dXJuX2hpZGRlbjogYm9vbCA9IEZhbHNlLAogICAgKSAtPiBUdXBsZVsKICAgICAgICB0b3JjaC5UZW5zb3IsCiAgICAgICAgRGljdFtpbnQsIHRvcmNoLlRlbnNvcl0sCiAgICAgICAgT3B0aW9uYWxbdG9yY2guVGVuc29yXSwKICAgICAgICBPcHRpb25hbFtMaXN0W1R1cGxlW3RvcmNoLlRlbnNvciwgdG9yY2guVGVuc29yXV1dLAogICAgXToKICAgICAgICBCLCBUID0gaWRzLnNoYXBlCiAgICAgICAgeCA9IHNlbGYuZW1iZWRfdG9rZW5zKGlkcykgKiBzZWxmLmVtYmVkX3NjYWxlX2ZhY3RvcgoKICAgICAgICBsb2dpY2FsX2xheWVycyA9IHNlbGYuX2J1aWxkX2xvZ2ljYWxfbGF5ZXJzKCkKICAgICAgICBuZXdfcGFzdF9rZXlfdmFsdWVzOiBPcHRpb25hbFtMaXN0W1R1cGxlW3RvcmNoLlRlbnNvciwgdG9yY2guVGVuc29yXV1dID0gKAogICAgICAgICAgICBbXSBpZiB1c2VfY2FjaGUgZWxzZSBOb25lCiAgICAgICAgKQoKICAgICAgICBmb3IgbGF5ZXJfaWR4LCAoYmxvY2ssIGxvZ2ljYWxfaWR4KSBpbiBlbnVtZXJhdGUobG9naWNhbF9sYXllcnMpOgogICAgICAgICAgICBpc19nbG9iYWwgPSBsb2dpY2FsX2lkeCAlIDIgPT0gMAogICAgICAgICAgICBwYXN0X2t2ID0gKAogICAgICAgICAgICAgICAgcGFzdF9rZXlfdmFsdWVzW2xheWVyX2lkeF0KICAgICAgICAgICAgICAgIGlmIHBhc3Rfa2V5X3ZhbHVlcyBpcyBub3QgTm9uZSBhbmQgbGF5ZXJfaWR4IDwgbGVuKHBhc3Rfa2V5X3ZhbHVlcykKICAgICAgICAgICAgICAgIGVsc2UgTm9uZQogICAgICAgICAgICApCgogICAgICAgICAgICBpZiBzZWxmLmdyYWRfY2hlY2twb2ludCBhbmQgc2VsZi50cmFpbmluZyBhbmQgbm90IHVzZV9jYWNoZToKICAgICAgICAgICAgICAgIHgsIGxheWVyX2t2ID0gY2hlY2twb2ludCgKICAgICAgICAgICAgICAgICAgICBibG9jaywgeCwgaXNfZ2xvYmFsLCBwYXN0X2t2LCB1c2VfY2FjaGUsIGlkcywgdXNlX3JlZW50cmFudD1UcnVlCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICB4LCBsYXllcl9rdiA9IGJsb2NrKHgsIGlzX2dsb2JhbCwgcGFzdF9rdiwgdXNlX2NhY2hlLCBpZHMpCgogICAgICAgICAgICBpZiBuZXdfcGFzdF9rZXlfdmFsdWVzIGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgbmV3X3Bhc3Rfa2V5X3ZhbHVlcy5hcHBlbmQobGF5ZXJfa3YpCgogICAgICAgIHggPSBzZWxmLm5vcm0oeCkKICAgICAgICBoX291dCA9IHggaWYgcmV0dXJuX2hpZGRlbiBlbHNlIE5vbmUKICAgICAgICBsb2dpdHMgPSBzZWxmLmhlYWQoeCkKICAgICAgICBpZiBzZWxmLmVtYmVkX3NjYWxlX2ZhY3RvciAhPSAxLjA6CiAgICAgICAgICAgIGxvZ2l0cyA9IGxvZ2l0cyAvIHNlbGYuZW1iZWRfc2NhbGVfZmFjdG9yCiAgICAgICAgbG9naXRzID0gbG9naXRzICsgc2VsZi5vdXRwdXRfYmlhcwoKICAgICAgICBtdHA6IERpY3RbaW50LCB0b3JjaC5UZW5zb3JdID0ge30KICAgICAgICBpZiBzZWxmLm10cF9ob3Jpem9ucyBhbmQgc2VsZi50cmFpbmluZzoKICAgICAgICAgICAgZm9yIGhvcml6b24gaW4gc2VsZi5tdHBfaG9yaXpvbnM6CiAgICAgICAgICAgICAgICBpZiBob3Jpem9uID4gMSBhbmQgaG9yaXpvbiA8PSBUIC0gMToKICAgICAgICAgICAgICAgICAgICBzaGlmdGVkX2ggPSB4WzosIDotaG9yaXpvbiwgOl0KICAgICAgICAgICAgICAgICAgICBhZGFwdGVkX2ggPSBzZWxmLm10cF9hZGFwdGVyc1tzdHIoaG9yaXpvbildKHNoaWZ0ZWRfaCkKICAgICAgICAgICAgICAgICAgICBhZGFwdGVkX2ggPSBzZWxmLm10cF9ub3Jtc1tzdHIoaG9yaXpvbildKGFkYXB0ZWRfaCkKICAgICAgICAgICAgICAgICAgICBtdHBfbG9naXRzID0gc2VsZi5oZWFkKGFkYXB0ZWRfaCkKICAgICAgICAgICAgICAgICAgICBpZiBzZWxmLmVtYmVkX3NjYWxlX2ZhY3RvciAhPSAxLjA6CiAgICAgICAgICAgICAgICAgICAgICAgIG10cF9sb2dpdHMgPSBtdHBfbG9naXRzIC8gc2VsZi5lbWJlZF9zY2FsZV9mYWN0b3IKICAgICAgICAgICAgICAgICAgICBtdHBfbG9naXRzID0gbXRwX2xvZ2l0cyArIHNlbGYub3V0cHV0X2JpYXMKICAgICAgICAgICAgICAgICAgICBtdHBbaG9yaXpvbl0gPSBtdHBfbG9naXRzCgogICAgICAgIHJldHVybiBsb2dpdHMsIG10cCwgaF9vdXQsIG5ld19wYXN0X2tleV92YWx1ZXMKCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIEdlbmVyYXRpb24gKGZyb20gYWlsYXkuZ2VuZXJhdGlvbikKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCgpkZWYgc2FtcGxlX3RleHQoCiAgICBtb2RlbDogVGlueU1lbW9yeUxNLAogICAgdG9rZW5pemVyOiBXb3JkVG9rZW5pemVyLAogICAgcHJvbXB0OiBzdHIsCiAgICBtYXhfbmV3X3Rva2VuczogaW50LAogICAgdGVtcGVyYXR1cmU6IGZsb2F0LAogICAgdG9wX2s6IGludCwKICAgIGJyYW5jaGVzOiBpbnQsCiAgICBicmFuY2hfbGVuOiBpbnQsCiAgICBkZXZpY2U6IHRvcmNoLmRldmljZSwKICAgIHNlcV9sZW46IGludCwKKSAtPiBzdHI6CiAgICBkZWYgX3NhbXBsZV9pZChsb2dpdHM6IHRvcmNoLlRlbnNvcikgLT4gdG9yY2guVGVuc29yOgogICAgICAgIGlmIG5vdCB0b3JjaC5pc2Zpbml0ZShsb2dpdHMpLmFueSgpOgogICAgICAgICAgICBsb2dpdHMgPSB0b3JjaC56ZXJvc19saWtlKGxvZ2l0cykKICAgICAgICBsb2dpdHMgPSB0b3JjaC53aGVyZSgKICAgICAgICAgICAgdG9yY2guaXNmaW5pdGUobG9naXRzKSwgbG9naXRzLCB0b3JjaC5mdWxsX2xpa2UobG9naXRzLCAtMWU5KQogICAgICAgICkKICAgICAgICBpZiB0b3BfayA+IDA6CiAgICAgICAgICAgIHYsIGlkeCA9IHRvcmNoLnRvcGsobG9naXRzLCBrPW1pbih0b3BfaywgbG9naXRzLnNoYXBlWy0xXSkpCiAgICAgICAgICAgIHAgPSB0b3JjaC5zb2Z0bWF4KHYsIGRpbT0tMSkKICAgICAgICAgICAgcmV0dXJuIGlkeC5nYXRoZXIoLTEsIHRvcmNoLm11bHRpbm9taWFsKHAsIDEpKQogICAgICAgIHAgPSB0b3JjaC5zb2Z0bWF4KGxvZ2l0cywgZGltPS0xKQogICAgICAgIHJldHVybiB0b3JjaC5tdWx0aW5vbWlhbChwLCAxKQoKICAgIG1vZGVsLmV2YWwoKQogICAgaWRzID0gdG9rZW5pemVyLmVuY29kZShwcm9tcHQsIGFkZF9ib3M9VHJ1ZSwgYWRkX2Vvcz1GYWxzZSkKICAgIHByb21wdF9sZW4gPSBsZW4oaWRzKQogICAgeCA9IHRvcmNoLnRlbnNvcihpZHMsIGR0eXBlPXRvcmNoLmxvbmcsIGRldmljZT1kZXZpY2UpLnVuc3F1ZWV6ZSgwKQoKICAgIHdpdGggdG9yY2gubm9fZ3JhZCgpOgogICAgICAgIGdlbmVyYXRlZCA9IDAKICAgICAgICB3aGlsZSBnZW5lcmF0ZWQgPCBtYXhfbmV3X3Rva2VuczoKICAgICAgICAgICAgaWYgYnJhbmNoZXMgPD0gMToKICAgICAgICAgICAgICAgIGN0eCA9IHhbOiwgLXNlcV9sZW46XQogICAgICAgICAgICAgICAgbG9naXRzLCBfLCBfLCBfID0gbW9kZWwoY3R4KQogICAgICAgICAgICAgICAgbmxvZ2l0cyA9IGxvZ2l0c1s6LCAtMSwgOl0gLyBtYXgodGVtcGVyYXR1cmUsIDFlLTYpCiAgICAgICAgICAgICAgICBuaWQgPSBfc2FtcGxlX2lkKG5sb2dpdHMpCiAgICAgICAgICAgICAgICB4ID0gdG9yY2guY2F0KFt4LCBuaWRdLCBkaW09MSkKICAgICAgICAgICAgICAgIGdlbmVyYXRlZCArPSAxCiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICByb2xsb3V0ID0gbWluKGJyYW5jaF9sZW4sIG1heF9uZXdfdG9rZW5zIC0gZ2VuZXJhdGVkKQogICAgICAgICAgICBiZXN0X25sbDogT3B0aW9uYWxbZmxvYXRdID0gTm9uZQogICAgICAgICAgICBiZXN0X3Rva2VuczogT3B0aW9uYWxbTGlzdFt0b3JjaC5UZW5zb3JdXSA9IE5vbmUKICAgICAgICAgICAgZm9yIF8gaW4gcmFuZ2UoYnJhbmNoZXMpOgogICAgICAgICAgICAgICAgY2FuZCA9IHgKICAgICAgICAgICAgICAgIGNhbmRfdG9rZW5zOiBMaXN0W3RvcmNoLlRlbnNvcl0gPSBbXQogICAgICAgICAgICAgICAgbmxsID0gMC4wCiAgICAgICAgICAgICAgICBmb3IgXyBpbiByYW5nZShyb2xsb3V0KToKICAgICAgICAgICAgICAgICAgICBjdHggPSBjYW5kWzosIC1zZXFfbGVuOl0KICAgICAgICAgICAgICAgICAgICBsb2dpdHMsIF8sIF8sIF8gPSBtb2RlbChjdHgpCiAgICAgICAgICAgICAgICAgICAgbmxvZ2l0cyA9IGxvZ2l0c1s6LCAtMSwgOl0gLyBtYXgodGVtcGVyYXR1cmUsIDFlLTYpCiAgICAgICAgICAgICAgICAgICAgbmlkID0gX3NhbXBsZV9pZChubG9naXRzKQogICAgICAgICAgICAgICAgICAgIGxwID0gRi5sb2dfc29mdG1heChubG9naXRzLmZsb2F0KCksIGRpbT0tMSkKICAgICAgICAgICAgICAgICAgICBubGwgKz0gZmxvYXQoLWxwLmdhdGhlcigtMSwgbmlkKS5pdGVtKCkpCiAgICAgICAgICAgICAgICAgICAgY2FuZCA9IHRvcmNoLmNhdChbY2FuZCwgbmlkXSwgZGltPTEpCiAgICAgICAgICAgICAgICAgICAgY2FuZF90b2tlbnMuYXBwZW5kKG5pZCkKICAgICAgICAgICAgICAgIGlmIGJlc3RfbmxsIGlzIE5vbmUgb3IgbmxsIDwgYmVzdF9ubGw6CiAgICAgICAgICAgICAgICAgICAgYmVzdF9ubGwgPSBubGwKICAgICAgICAgICAgICAgICAgICBiZXN0X3Rva2VucyA9IGNhbmRfdG9rZW5zCiAgICAgICAgICAgIGFzc2VydCBiZXN0X3Rva2VucyBpcyBub3QgTm9uZQogICAgICAgICAgICBmb3IgdCBpbiBiZXN0X3Rva2VuczoKICAgICAgICAgICAgICAgIHggPSB0b3JjaC5jYXQoW3gsIHRdLCBkaW09MSkKICAgICAgICAgICAgICAgIGdlbmVyYXRlZCArPSAxCgogICAgZ2VuZXJhdGVkX2lkcyA9IHhbMCwgcHJvbXB0X2xlbjpdLnRvbGlzdCgpCiAgICByZXR1cm4gdG9rZW5pemVyLmRlY29kZShnZW5lcmF0ZWRfaWRzLCBza2lwX3NwZWNpYWw9VHJ1ZSkKCgpkZWYgc2FtcGxlX3RleHRfY2FjaGVkKAogICAgbW9kZWw6IFRpbnlNZW1vcnlMTSwKICAgIHRva2VuaXplcjogV29yZFRva2VuaXplciwKICAgIHByb21wdDogc3RyLAogICAgbWF4X25ld190b2tlbnM6IGludCwKICAgIHRlbXBlcmF0dXJlOiBmbG9hdCwKICAgIHRvcF9rOiBpbnQsCiAgICBkZXZpY2U6IHRvcmNoLmRldmljZSwKICAgIHNlcV9sZW46IGludCwKKSAtPiBzdHI6CiAgICBtb2RlbC5ldmFsKCkKICAgIGlkcyA9IHRva2VuaXplci5lbmNvZGUocHJvbXB0LCBhZGRfYm9zPVRydWUsIGFkZF9lb3M9RmFsc2UpCiAgICBwcm9tcHRfbGVuID0gbGVuKGlkcykKICAgIHggPSB0b3JjaC50ZW5zb3IoaWRzLCBkdHlwZT10b3JjaC5sb25nLCBkZXZpY2U9ZGV2aWNlKS51bnNxdWVlemUoMCkKCiAgICB3aXRoIHRvcmNoLm5vX2dyYWQoKToKICAgICAgICBsb2dpdHMsIF8sIF8sIHBhc3Rfa3YgPSBtb2RlbCh4LCB1c2VfY2FjaGU9VHJ1ZSkKICAgICAgICBubG9naXRzID0gbG9naXRzWzosIC0xLCA6XSAvIG1heCh0ZW1wZXJhdHVyZSwgMWUtNikKICAgICAgICBpZiB0b3BfayA+IDA6CiAgICAgICAgICAgIHYsIGlkeCA9IHRvcmNoLnRvcGsobmxvZ2l0cywgaz1taW4odG9wX2ssIG5sb2dpdHMuc2hhcGVbLTFdKSkKICAgICAgICAgICAgcCA9IHRvcmNoLnNvZnRtYXgodiwgZGltPS0xKQogICAgICAgICAgICBuaWQgPSBpZHguZ2F0aGVyKC0xLCB0b3JjaC5tdWx0aW5vbWlhbChwLCAxKSkKICAgICAgICBlbHNlOgogICAgICAgICAgICBwID0gdG9yY2guc29mdG1heChubG9naXRzLCBkaW09LTEpCiAgICAgICAgICAgIG5pZCA9IHRvcmNoLm11bHRpbm9taWFsKHAsIDEpCiAgICAgICAgYWxsX2lkcyA9IFtpbnQobmlkLml0ZW0oKSldCgogICAgICAgIGZvciBfIGluIHJhbmdlKG1heF9uZXdfdG9rZW5zIC0gMSk6CiAgICAgICAgICAgIGxvZ2l0cywgXywgXywgcGFzdF9rdiA9IG1vZGVsKG5pZCwgdXNlX2NhY2hlPVRydWUsIHBhc3Rfa2V5X3ZhbHVlcz1wYXN0X2t2KQogICAgICAgICAgICBubG9naXRzID0gbG9naXRzWzosIC0xLCA6XSAvIG1heCh0ZW1wZXJhdHVyZSwgMWUtNikKICAgICAgICAgICAgaWYgdG9wX2sgPiAwOgogICAgICAgICAgICAgICAgdiwgaWR4ID0gdG9yY2gudG9wayhubG9naXRzLCBrPW1pbih0b3BfaywgbmxvZ2l0cy5zaGFwZVstMV0pKQogICAgICAgICAgICAgICAgcCA9IHRvcmNoLnNvZnRtYXgodiwgZGltPS0xKQogICAgICAgICAgICAgICAgbmlkID0gaWR4LmdhdGhlcigtMSwgdG9yY2gubXVsdGlub21pYWwocCwgMSkpCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICBwID0gdG9yY2guc29mdG1heChubG9naXRzLCBkaW09LTEpCiAgICAgICAgICAgICAgICBuaWQgPSB0b3JjaC5tdWx0aW5vbWlhbChwLCAxKQogICAgICAgICAgICB0aWQgPSBpbnQobmlkLml0ZW0oKSkKICAgICAgICAgICAgYWxsX2lkcy5hcHBlbmQodGlkKQogICAgICAgICAgICBpZiB0aWQgPT0gdG9rZW5pemVyLmVvc19pZDoKICAgICAgICAgICAgICAgIGJyZWFrCgogICAgcmV0dXJuIHRva2VuaXplci5kZWNvZGUoYWxsX2lkcywgc2tpcF9zcGVjaWFsPVRydWUpCgoKZGVmIHNwZWN1bGF0aXZlX2RlY29kZSgKICAgIG1vZGVsOiBUaW55TWVtb3J5TE0sCiAgICB0b2tlbml6ZXI6IFdvcmRUb2tlbml6ZXIsCiAgICBwcm9tcHQ6IHN0ciwKICAgIG1heF9uZXdfdG9rZW5zOiBpbnQsCiAgICB0ZW1wZXJhdHVyZTogZmxvYXQsCiAgICB0b3BfazogaW50LAogICAgZGV2aWNlOiB0b3JjaC5kZXZpY2UsCiAgICBzZXFfbGVuOiBpbnQsCikgLT4gc3RyOgogICAgbW9kZWwuZXZhbCgpCiAgICBpZHMgPSB0b2tlbml6ZXIuZW5jb2RlKHByb21wdCwgYWRkX2Jvcz1UcnVlLCBhZGRfZW9zPUZhbHNlKQogICAgeCA9IHRvcmNoLnRlbnNvcihpZHMsIGR0eXBlPXRvcmNoLmxvbmcsIGRldmljZT1kZXZpY2UpLnVuc3F1ZWV6ZSgwKQogICAgYWxsX2dlbmVyYXRlZDogTGlzdFtpbnRdID0gW10KCiAgICB3aXRoIHRvcmNoLm5vX2dyYWQoKToKICAgICAgICBsb2dpdHMsIF8sIGhfb3V0LCBwYXN0X2t2ID0gbW9kZWwoeCwgdXNlX2NhY2hlPVRydWUsIHJldHVybl9oaWRkZW49VHJ1ZSkKCiAgICAgICAgZGVmIF9zYW1wbGVfZnJvbShsZzogdG9yY2guVGVuc29yKSAtPiBpbnQ6CiAgICAgICAgICAgIGxnID0gbGcgLyBtYXgodGVtcGVyYXR1cmUsIDFlLTYpCiAgICAgICAgICAgIGlmIHRvcF9rID4gMDoKICAgICAgICAgICAgICAgIHYsIGlkeCA9IHRvcmNoLnRvcGsobGcsIGs9bWluKHRvcF9rLCBsZy5zaGFwZVstMV0pKQogICAgICAgICAgICAgICAgcCA9IHRvcmNoLnNvZnRtYXgodiwgZGltPS0xKQogICAgICAgICAgICAgICAgcmV0dXJuIGludChpZHhbdG9yY2gubXVsdGlub21pYWwocCwgMSldLml0ZW0oKSkKICAgICAgICAgICAgcCA9IHRvcmNoLnNvZnRtYXgobGcsIGRpbT0tMSkKICAgICAgICAgICAgcmV0dXJuIGludCh0b3JjaC5tdWx0aW5vbWlhbChwLCAxKS5pdGVtKCkpCgogICAgICAgIG1haW5fdG9rZW4gPSBfc2FtcGxlX2Zyb20obG9naXRzWzAsIC0xLCA6XSkKICAgICAgICBhbGxfZ2VuZXJhdGVkLmFwcGVuZChtYWluX3Rva2VuKQoKICAgICAgICB3aGlsZSBsZW4oYWxsX2dlbmVyYXRlZCkgPCBtYXhfbmV3X3Rva2VuczoKICAgICAgICAgICAgaWYgbWFpbl90b2tlbiA9PSB0b2tlbml6ZXIuZW9zX2lkOgogICAgICAgICAgICAgICAgYnJlYWsKCiAgICAgICAgICAgIGRyYWZ0X3Rva2VucyA9IFtdCiAgICAgICAgICAgIGlmIGhfb3V0IGlzIG5vdCBOb25lIGFuZCBtb2RlbC5tdHBfaG9yaXpvbnM6CiAgICAgICAgICAgICAgICBsYXN0X2hpZGRlbiA9IGhfb3V0WzosIC0xOiwgOl0KICAgICAgICAgICAgICAgIGZvciBoIGluIG1vZGVsLm10cF9ob3Jpem9uczoKICAgICAgICAgICAgICAgICAgICBhZGFwdGVyID0gbW9kZWwubXRwX2FkYXB0ZXJzW3N0cihoKV0KICAgICAgICAgICAgICAgICAgICBub3JtID0gbW9kZWwubXRwX25vcm1zW3N0cihoKV0KICAgICAgICAgICAgICAgICAgICBhZGFwdGVkID0gbm9ybShhZGFwdGVyKGxhc3RfaGlkZGVuKSkKICAgICAgICAgICAgICAgICAgICBkcmFmdF9sb2dpdHMgPSBtb2RlbC5oZWFkKGFkYXB0ZWQpICsgbW9kZWwub3V0cHV0X2JpYXMKICAgICAgICAgICAgICAgICAgICBkcmFmdF90b2sgPSBfc2FtcGxlX2Zyb20oZHJhZnRfbG9naXRzWzAsIDAsIDpdKQogICAgICAgICAgICAgICAgICAgIGRyYWZ0X3Rva2Vucy5hcHBlbmQoZHJhZnRfdG9rKQoKICAgICAgICAgICAgaWYgbm90IGRyYWZ0X3Rva2VuczoKICAgICAgICAgICAgICAgIG5pZCA9IHRvcmNoLnRlbnNvcihbW21haW5fdG9rZW5dXSwgZHR5cGU9dG9yY2gubG9uZywgZGV2aWNlPWRldmljZSkKICAgICAgICAgICAgICAgIGxvZ2l0cywgXywgaF9vdXQsIHBhc3Rfa3YgPSBtb2RlbCgKICAgICAgICAgICAgICAgICAgICBuaWQsIHVzZV9jYWNoZT1UcnVlLCBwYXN0X2tleV92YWx1ZXM9cGFzdF9rdiwgcmV0dXJuX2hpZGRlbj1UcnVlCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICBtYWluX3Rva2VuID0gX3NhbXBsZV9mcm9tKGxvZ2l0c1swLCAtMSwgOl0pCiAgICAgICAgICAgICAgICBhbGxfZ2VuZXJhdGVkLmFwcGVuZChtYWluX3Rva2VuKQogICAgICAgICAgICAgICAgY29udGludWUKCiAgICAgICAgICAgIHZlcmlmeV9pbnB1dCA9IHRvcmNoLnRlbnNvcigKICAgICAgICAgICAgICAgIFtbbWFpbl90b2tlbl0gKyBkcmFmdF90b2tlbnNdLCBkdHlwZT10b3JjaC5sb25nLCBkZXZpY2U9ZGV2aWNlCiAgICAgICAgICAgICkKICAgICAgICAgICAgdmVyaWZ5X2xvZ2l0cywgXywgaF9vdXQsIHBhc3Rfa3YgPSBtb2RlbCgKICAgICAgICAgICAgICAgIHZlcmlmeV9pbnB1dCwKICAgICAgICAgICAgICAgIHVzZV9jYWNoZT1UcnVlLAogICAgICAgICAgICAgICAgcGFzdF9rZXlfdmFsdWVzPXBhc3Rfa3YsCiAgICAgICAgICAgICAgICByZXR1cm5faGlkZGVuPVRydWUsCiAgICAgICAgICAgICkKCiAgICAgICAgICAgIGFjY2VwdGVkID0gMAogICAgICAgICAgICBhbGxfZ2VuZXJhdGVkLmFwcGVuZChtYWluX3Rva2VuKSBpZiBtYWluX3Rva2VuIG5vdCBpbiBhbGxfZ2VuZXJhdGVkWwogICAgICAgICAgICAgICAgLTE6CiAgICAgICAgICAgIF0gZWxzZSBOb25lCiAgICAgICAgICAgIGZvciBpLCBkcmFmdF90b2sgaW4gZW51bWVyYXRlKGRyYWZ0X3Rva2Vucyk6CiAgICAgICAgICAgICAgICB2ZXJpZmllZF90b2sgPSBfc2FtcGxlX2Zyb20odmVyaWZ5X2xvZ2l0c1swLCBpLCA6XSkKICAgICAgICAgICAgICAgIGlmIHZlcmlmaWVkX3RvayA9PSBkcmFmdF90b2s6CiAgICAgICAgICAgICAgICAgICAgYWxsX2dlbmVyYXRlZC5hcHBlbmQoZHJhZnRfdG9rKQogICAgICAgICAgICAgICAgICAgIGFjY2VwdGVkICs9IDEKICAgICAgICAgICAgICAgICAgICBpZiBkcmFmdF90b2sgPT0gdG9rZW5pemVyLmVvc19pZDoKICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAgICAgYWxsX2dlbmVyYXRlZC5hcHBlbmQodmVyaWZpZWRfdG9rKQogICAgICAgICAgICAgICAgICAgIGJyZWFrCgogICAgICAgICAgICBpZiBhY2NlcHRlZCA8IGxlbihkcmFmdF90b2tlbnMpOgogICAgICAgICAgICAgICAgdHJpbV9sZW4gPSBsZW4oZHJhZnRfdG9rZW5zKSAtIGFjY2VwdGVkIC0gMQogICAgICAgICAgICAgICAgaWYgdHJpbV9sZW4gPiAwIGFuZCBwYXN0X2t2IGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgICAgIHBhc3Rfa3YgPSBbCiAgICAgICAgICAgICAgICAgICAgICAgIChrWzosIDosIDotdHJpbV9sZW4sIDpdLCB2WzosIDosIDotdHJpbV9sZW4sIDpdKQogICAgICAgICAgICAgICAgICAgICAgICBpZiBrIGlzIG5vdCBOb25lCiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgTm9uZQogICAgICAgICAgICAgICAgICAgICAgICBmb3IgaywgdiBpbiBwYXN0X2t2CiAgICAgICAgICAgICAgICAgICAgXQoKICAgICAgICAgICAgbWFpbl90b2tlbiA9IGFsbF9nZW5lcmF0ZWRbLTFdCgogICAgcmV0dXJuIHRva2VuaXplci5kZWNvZGUoYWxsX2dlbmVyYXRlZCwgc2tpcF9zcGVjaWFsPVRydWUpCgoKZGVmIGJ1aWxkX3N0b3BfdG9rZW5faWRzKHRva2VuaXplcjogV29yZFRva2VuaXplcikgLT4gc2V0OgogICAgc3RvcF90b2tlbnMgPSB7dG9rZW5pemVyLmVvc19pZH0KICAgIGZvciB0b2sgaW4gKCI8fHVzZXJ8PiIsICI8fHN5c3RlbXw+IiwgIjx8YXNzaXN0YW50fD4iKToKICAgICAgICB0aWQgPSB0b2tlbml6ZXIudG9rZW5fdG9faWQuZ2V0KHRvaykKICAgICAgICBpZiB0aWQgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIHN0b3BfdG9rZW5zLmFkZChpbnQodGlkKSkKICAgIHJldHVybiBzdG9wX3Rva2VucwoKCmRlZiBhcHBseV9ub19yZXBlYXRfbmdyYW0oCiAgICBsb2dpdHM6IHRvcmNoLlRlbnNvciwKICAgIHRva2VuX2hpc3Rvcnk6IFNlcXVlbmNlW2ludF0sCiAgICBuZ3JhbV9zaXplOiBpbnQsCikgLT4gdG9yY2guVGVuc29yOgogICAgaWYgbmdyYW1fc2l6ZSA8PSAxIG9yIGxlbih0b2tlbl9oaXN0b3J5KSA8IG1heCgwLCBuZ3JhbV9zaXplIC0gMSk6CiAgICAgICAgcmV0dXJuIGxvZ2l0cwogICAgcHJlZml4ID0gdHVwbGUodG9rZW5faGlzdG9yeVstKG5ncmFtX3NpemUgLSAxKSA6XSkgaWYgbmdyYW1fc2l6ZSA+IDEgZWxzZSB0dXBsZSgpCiAgICBiYW5uZWQ6IHNldCA9IHNldCgpCiAgICBmb3IgaSBpbiByYW5nZShsZW4odG9rZW5faGlzdG9yeSkgLSBuZ3JhbV9zaXplICsgMSk6CiAgICAgICAgaWYgdHVwbGUodG9rZW5faGlzdG9yeVtpIDogaSArIG5ncmFtX3NpemUgLSAxXSkgPT0gcHJlZml4OgogICAgICAgICAgICBiYW5uZWQuYWRkKGludCh0b2tlbl9oaXN0b3J5W2kgKyBuZ3JhbV9zaXplIC0gMV0pKQogICAgaWYgbm90IGJhbm5lZDoKICAgICAgICByZXR1cm4gbG9naXRzCiAgICBvdXQgPSBsb2dpdHMuY2xvbmUoKQogICAgYmFubmVkX2lkcyA9IHRvcmNoLnRlbnNvcihzb3J0ZWQoYmFubmVkKSwgZGV2aWNlPWxvZ2l0cy5kZXZpY2UsIGR0eXBlPXRvcmNoLmxvbmcpCiAgICBvdXRbYmFubmVkX2lkc10gPSBmbG9hdCgiLWluZiIpCiAgICByZXR1cm4gb3V0CgoKZGVmIHNjb3JlX2NhbmRpZGF0ZSgKICAgIHByb21wdDogc3RyLAogICAgcmF3X3RleHQ6IHN0ciwKICAgIHZpc2libGVfdGV4dDogc3RyLAogICAgYXZnX2xvZ3Byb2I6IGZsb2F0LAopIC0+IGZsb2F0OgogICAgY2xlYW4gPSB2aXNpYmxlX3RleHQuc3RyaXAoKQogICAgaWYgbm90IGNsZWFuOgogICAgICAgIHJldHVybiAtMWU5CiAgICBzY29yZSA9IGF2Z19sb2dwcm9iCiAgICB3b3JkcyA9IGNsZWFuLmxvd2VyKCkuc3BsaXQoKQogICAgcHJvbXB0X3dvcmRzID0gcmUuZmluZGFsbChyIltBLVphLXpdW0EtWmEteictXXsyLH0iLCBwcm9tcHQubG93ZXIoKSkKICAgIHByb21wdF9zdG9wID0gewogICAgICAgICJ3aGF0IiwKICAgICAgICAid2hpY2giLAogICAgICAgICJ3aGVuIiwKICAgICAgICAid2hlcmUiLAogICAgICAgICJ3aHkiLAogICAgICAgICJob3ciLAogICAgICAgICJhcmUiLAogICAgICAgICJpcyIsCiAgICAgICAgInRoZSIsCiAgICAgICAgImFuZCIsCiAgICAgICAgImZvciIsCiAgICAgICAgIndpdGgiLAogICAgICAgICJ0aGF0IiwKICAgICAgICAidGhpcyIsCiAgICAgICAgImZyb20iLAogICAgICAgICJpbnRvIiwKICAgICAgICAiYWJvdXQiLAogICAgICAgICJleHBsYWluIiwKICAgICAgICAidGVsbCIsCiAgICAgICAgImdpdmUiLAogICAgICAgICJsaXN0IiwKICAgICAgICAic2hvdyIsCiAgICAgICAgIndyaXRlIiwKICAgICAgICAidGhlaXIiLAogICAgICAgICJ0aGVyZSIsCiAgICAgICAgInlvdXIiLAogICAgfQogICAgcHJvbXB0X2tleXdvcmRzID0ge3cgZm9yIHcgaW4gcHJvbXB0X3dvcmRzIGlmIHcgbm90IGluIHByb21wdF9zdG9wfQogICAgY2FuZGlkYXRlX2tleXdvcmRzID0gc2V0KHJlLmZpbmRhbGwociJbQS1aYS16XVtBLVphLXonLV17Mix9IiwgY2xlYW4ubG93ZXIoKSkpCiAgICBpZiBsZW4od29yZHMpIDwgNjoKICAgICAgICBzY29yZSAtPSAyLjAKICAgIGVsc2U6CiAgICAgICAgc2NvcmUgKz0gbWluKDIuMCwgbGVuKHdvcmRzKSAqIDAuMDMpCiAgICBpZiBjbGVhblstMTpdIGluICIuIT8iOgogICAgICAgIHNjb3JlICs9IDAuNQogICAgaWYgIjx8dXNlcnw+IiBpbiByYXdfdGV4dCBvciAiPHxzeXN0ZW18PiIgaW4gcmF3X3RleHQ6CiAgICAgICAgc2NvcmUgLT0gNC4wCiAgICBpZiByYXdfdGV4dC5jb3VudCgiPHxhc3Npc3RhbnR8PiIpID4gMToKICAgICAgICBzY29yZSAtPSAyLjAKICAgIGlmIHByb21wdF9rZXl3b3JkczoKICAgICAgICBvdmVybGFwID0gbGVuKHByb21wdF9rZXl3b3JkcyAmIGNhbmRpZGF0ZV9rZXl3b3JkcykgLyBsZW4ocHJvbXB0X2tleXdvcmRzKQogICAgICAgIGlmIG92ZXJsYXAgPT0gMC4wOgogICAgICAgICAgICBzY29yZSAtPSAyLjUKICAgICAgICBlbHNlOgogICAgICAgICAgICBzY29yZSArPSBtaW4oMy41LCBvdmVybGFwICogNC4wKQogICAgZm9yIG9wZW5fdG9rLCBjbG9zZV90b2sgaW4gWwogICAgICAgICgiPHxiZWdpbl9vZl90aG91Z2h0fD4iLCAiPHxlbmRfb2ZfdGhvdWdodHw+IiksCiAgICAgICAgKCI8fGJlZ2luX29mX3NvbHV0aW9ufD4iLCAiPHxlbmRfb2Zfc29sdXRpb258PiIpLAogICAgXToKICAgICAgICBpZiAob3Blbl90b2sgaW4gcmF3X3RleHQpICE9IChjbG9zZV90b2sgaW4gcmF3X3RleHQpOgogICAgICAgICAgICBzY29yZSAtPSAxLjAKICAgIGlmIGxlbih3b3JkcykgPj0gMzoKICAgICAgICB0cmlncmFtcyA9IFt0dXBsZSh3b3Jkc1tpIDogaSArIDNdKSBmb3IgaSBpbiByYW5nZShsZW4od29yZHMpIC0gMildCiAgICAgICAgaWYgdHJpZ3JhbXM6CiAgICAgICAgICAgIHVuaXF1ZV9yYXRpbyA9IGxlbihzZXQodHJpZ3JhbXMpKSAvIGxlbih0cmlncmFtcykKICAgICAgICAgICAgaWYgdW5pcXVlX3JhdGlvIDwgMC4zNToKICAgICAgICAgICAgICAgIHNjb3JlIC09IDQuMAogICAgICAgICAgICBlbGlmIHVuaXF1ZV9yYXRpbyA8IDAuNTU6CiAgICAgICAgICAgICAgICBzY29yZSAtPSAyLjAKICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgIHNjb3JlICs9IG1pbigxLjAsICh1bmlxdWVfcmF0aW8gLSAwLjU1KSAqIDIuMCkKICAgIGFscGhhX3dvcmRzID0gWwogICAgICAgIHcKICAgICAgICBmb3IgdyBpbiB3b3JkcwogICAgICAgIGlmIGxlbih3KSA8PSAxOCBhbmQgKHN1bShjaC5pc2FscGhhKCkgZm9yIGNoIGluIHcpIC8gbWF4KGxlbih3KSwgMSkpID4gMC43CiAgICBdCiAgICBhbHBoYV9yYXRpbyA9IGxlbihhbHBoYV93b3JkcykgLyBtYXgobGVuKHdvcmRzKSwgMSkKICAgIGlmIGFscGhhX3JhdGlvIDwgMC40NToKICAgICAgICBzY29yZSAtPSAzLjAKICAgIGVsaWYgYWxwaGFfcmF0aW8gPCAwLjY1OgogICAgICAgIHNjb3JlIC09IDEuMAogICAgcmV0dXJuIHNjb3JlCgoKZGVmIGdlbmVyYXRlX2NhbmRpZGF0ZSgKICAgIG1vZGVsOiBUaW55TWVtb3J5TE0sCiAgICB0b2tlbml6ZXI6IFdvcmRUb2tlbml6ZXIsCiAgICBwcm9tcHQ6IHN0ciwKICAgIG1heF9uZXdfdG9rZW5zOiBpbnQsCiAgICB0ZW1wZXJhdHVyZTogZmxvYXQsCiAgICB0b3BfazogaW50LAogICAgcmVwZXRpdGlvbl9wZW5hbHR5OiBmbG9hdCwKICAgIG5vX3JlcGVhdF9uZ3JhbV9zaXplOiBpbnQsCiAgICBkZXZpY2U6IHN0ciwKICAgIHNmdF9tb2RlOiBib29sLAogICAgZm9yY2VfdGhvdWdodDogYm9vbCwKICAgIHN0cmVhbTogYm9vbCwKICAgIGNvbnRleHRfd2luZG93OiBpbnQsCikgLT4gVHVwbGVbc3RyLCBzdHIsIGZsb2F0LCBpbnRdOgogICAgaWYgc2Z0X21vZGU6CiAgICAgICAgZnVsbF9wcm9tcHQgPSBmIjx8dXNlcnw+XG57cHJvbXB0fVxuPHxhc3Npc3RhbnR8PlxuIgogICAgZWxzZToKICAgICAgICBmdWxsX3Byb21wdCA9IHByb21wdAogICAgaWYgZm9yY2VfdGhvdWdodDoKICAgICAgICBmdWxsX3Byb21wdCA9IGYie2Z1bGxfcHJvbXB0fTx8YmVnaW5fb2ZfdGhvdWdodHw+ICIKICAgIGlucHV0X2lkcyA9IHRva2VuaXplci5lbmNvZGUoZnVsbF9wcm9tcHQsIGFkZF9ib3M9VHJ1ZSwgYWRkX2Vvcz1GYWxzZSkKICAgIGlucHV0X2lkc190ID0gdG9yY2gudGVuc29yKFtpbnB1dF9pZHNdLCBkdHlwZT10b3JjaC5sb25nLCBkZXZpY2U9ZGV2aWNlKQogICAgdmlzaWJsZV90b2tlbnM6IExpc3Rbc3RyXSA9IFtdCiAgICByYXdfdG9rZW5zOiBMaXN0W3N0cl0gPSBbXQogICAgc3RvcF90b2tlbl9pZHMgPSBidWlsZF9zdG9wX3Rva2VuX2lkcyh0b2tlbml6ZXIpCiAgICB0b3RhbF9sb2dwcm9iID0gMC4wCiAgICBzYW1wbGVkX3Rva2VucyA9IDAKICAgIHdpdGggdG9yY2gubm9fZ3JhZCgpOgogICAgICAgIGZvciBfIGluIHJhbmdlKG1heF9uZXdfdG9rZW5zKToKICAgICAgICAgICAgY3R4X2lkcyA9ICgKICAgICAgICAgICAgICAgIGlucHV0X2lkc190WzosIC1jb250ZXh0X3dpbmRvdzpdIGlmIGNvbnRleHRfd2luZG93ID4gMCBlbHNlIGlucHV0X2lkc190CiAgICAgICAgICAgICkKICAgICAgICAgICAgbG9naXRzLCBfLCBfLCBfID0gbW9kZWwoY3R4X2lkcykKICAgICAgICAgICAgbmV4dF9sb2dpdHMgPSBsb2dpdHNbMCwgLTEsIDpdLmNsb25lKCkKICAgICAgICAgICAgcmF3X25leHRfbG9naXRzID0gbmV4dF9sb2dpdHMuY2xvbmUoKQogICAgICAgICAgICBpZiByZXBldGl0aW9uX3BlbmFsdHkgIT0gMS4wOgogICAgICAgICAgICAgICAgc2VlbiA9IHNldChpbnB1dF9pZHNfdFswXS50b2xpc3QoKSkKICAgICAgICAgICAgICAgIGZvciB0b2tlbl9pZCBpbiBzZWVuOgogICAgICAgICAgICAgICAgICAgIGlmIG5leHRfbG9naXRzW3Rva2VuX2lkXSA+IDA6CiAgICAgICAgICAgICAgICAgICAgICAgIG5leHRfbG9naXRzW3Rva2VuX2lkXSAvPSByZXBldGl0aW9uX3BlbmFsdHkKICAgICAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgICAgICBuZXh0X2xvZ2l0c1t0b2tlbl9pZF0gKj0gcmVwZXRpdGlvbl9wZW5hbHR5CiAgICAgICAgICAgIGlmIHRlbXBlcmF0dXJlICE9IDEuMDoKICAgICAgICAgICAgICAgIG5leHRfbG9naXRzID0gbmV4dF9sb2dpdHMgLyBtYXgodGVtcGVyYXR1cmUsIDFlLTYpCiAgICAgICAgICAgIGlmIG5vX3JlcGVhdF9uZ3JhbV9zaXplID4gMToKICAgICAgICAgICAgICAgIG5leHRfbG9naXRzID0gYXBwbHlfbm9fcmVwZWF0X25ncmFtKAogICAgICAgICAgICAgICAgICAgIG5leHRfbG9naXRzLAogICAgICAgICAgICAgICAgICAgIGlucHV0X2lkc190WzBdLnRvbGlzdCgpLAogICAgICAgICAgICAgICAgICAgIG5vX3JlcGVhdF9uZ3JhbV9zaXplLAogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBpZiB0b3BfayA+IDA6CiAgICAgICAgICAgICAgICB2LCBfID0gdG9yY2gudG9wayhuZXh0X2xvZ2l0cywgbWluKHRvcF9rLCBuZXh0X2xvZ2l0cy5zaXplKDApKSkKICAgICAgICAgICAgICAgIG5leHRfbG9naXRzW25leHRfbG9naXRzIDwgdlstMV1dID0gZmxvYXQoIi1pbmYiKQogICAgICAgICAgICB0b3BfcCA9IDAuOQogICAgICAgICAgICBpZiB0b3BfcCA8IDEuMDoKICAgICAgICAgICAgICAgIHNvcnRlZF9sb2dpdHMsIHNvcnRlZF9pbmRpY2VzID0gdG9yY2guc29ydChuZXh0X2xvZ2l0cywgZGVzY2VuZGluZz1UcnVlKQogICAgICAgICAgICAgICAgY3VtX3Byb2JzID0gdG9yY2guY3Vtc3VtKHRvcmNoLnNvZnRtYXgoc29ydGVkX2xvZ2l0cywgZGltPS0xKSwgZGltPS0xKQogICAgICAgICAgICAgICAgcmVtb3ZlX21hc2sgPSBjdW1fcHJvYnMgLSB0b3JjaC5zb2Z0bWF4KHNvcnRlZF9sb2dpdHMsIGRpbT0tMSkgPj0gdG9wX3AKICAgICAgICAgICAgICAgIHNvcnRlZF9sb2dpdHNbcmVtb3ZlX21hc2tdID0gZmxvYXQoIi1pbmYiKQogICAgICAgICAgICAgICAgbmV4dF9sb2dpdHMgPSBzb3J0ZWRfbG9naXRzLnNjYXR0ZXIoMCwgc29ydGVkX2luZGljZXMsIHNvcnRlZF9sb2dpdHMpCiAgICAgICAgICAgIGlmIG5vdCB0b3JjaC5pc2Zpbml0ZShuZXh0X2xvZ2l0cykuYW55KCk6CiAgICAgICAgICAgICAgICBuZXh0X2xvZ2l0cyA9IHJhd19uZXh0X2xvZ2l0cwogICAgICAgICAgICAgICAgaWYgdGVtcGVyYXR1cmUgIT0gMS4wOgogICAgICAgICAgICAgICAgICAgIG5leHRfbG9naXRzID0gbmV4dF9sb2dpdHMgLyBtYXgodGVtcGVyYXR1cmUsIDFlLTYpCiAgICAgICAgICAgIHByb2JzID0gdG9yY2guc29mdG1heChuZXh0X2xvZ2l0cywgZGltPS0xKQogICAgICAgICAgICBuZXh0X2lkID0gdG9yY2gubXVsdGlub21pYWwocHJvYnMsIG51bV9zYW1wbGVzPTEpLml0ZW0oKQogICAgICAgICAgICB0b3RhbF9sb2dwcm9iICs9IGZsb2F0KHRvcmNoLmxvZyhwcm9ic1tuZXh0X2lkXSArIDFlLTEyKS5pdGVtKCkpCiAgICAgICAgICAgIHNhbXBsZWRfdG9rZW5zICs9IDEKICAgICAgICAgICAgaWYgbmV4dF9pZCBpbiBzdG9wX3Rva2VuX2lkczoKICAgICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICAgIHRva2VuX3N0ciA9ICgKICAgICAgICAgICAgICAgIHRva2VuaXplci5pZF90b190b2tlbltuZXh0X2lkXQogICAgICAgICAgICAgICAgaWYgbmV4dF9pZCA8IGxlbih0b2tlbml6ZXIuaWRfdG9fdG9rZW4pCiAgICAgICAgICAgICAgICBlbHNlICIiCiAgICAgICAgICAgICkKICAgICAgICAgICAgcmF3X3Rva2Vucy5hcHBlbmQodG9rZW5fc3RyKQogICAgICAgICAgICBpZiB0b2tlbl9zdHIgbm90IGluIHRva2VuaXplci5zcGVjaWFsOgogICAgICAgICAgICAgICAgdmlzaWJsZV90b2tlbnMuYXBwZW5kKHRva2VuX3N0cikKICAgICAgICAgICAgICAgIGlmIHN0cmVhbToKICAgICAgICAgICAgICAgICAgICBwcmludCh0b2tlbl9zdHIsIGVuZD0iIiwgZmx1c2g9VHJ1ZSkKICAgICAgICAgICAgaW5wdXRfaWRzX3QgPSB0b3JjaC5jYXQoCiAgICAgICAgICAgICAgICBbaW5wdXRfaWRzX3QsIHRvcmNoLnRlbnNvcihbW25leHRfaWRdXSwgZGV2aWNlPWRldmljZSldLCBkaW09MQogICAgICAgICAgICApCiAgICBpZiBzdHJlYW06CiAgICAgICAgcHJpbnQoKQogICAgYXZnX2xvZ3Byb2IgPSB0b3RhbF9sb2dwcm9iIC8gbWF4KDEsIHNhbXBsZWRfdG9rZW5zKQogICAgcmV0dXJuICIiLmpvaW4odmlzaWJsZV90b2tlbnMpLCAiIi5qb2luKHJhd190b2tlbnMpLCBhdmdfbG9ncHJvYiwgMAoKCmRlZiBnZW5lcmF0ZV9iZWFtX3NlYXJjaCgKICAgIG1vZGVsOiBUaW55TWVtb3J5TE0sCiAgICB0b2tlbml6ZXI6IFdvcmRUb2tlbml6ZXIsCiAgICBwcm9tcHQ6IHN0ciwKICAgIG1heF9uZXdfdG9rZW5zOiBpbnQgPSA2MCwKICAgIGJlYW1fd2lkdGg6IGludCA9IDgsCiAgICBsZW5ndGhfcGVuYWx0eTogZmxvYXQgPSAwLjcsCiAgICBub19yZXBlYXRfbmdyYW1fc2l6ZTogaW50ID0gMywKICAgIGRldmljZTogc3RyID0gImN1ZGEiLAogICAgc2Z0X21vZGU6IGJvb2wgPSBGYWxzZSwKICAgIGNvbnRleHRfd2luZG93OiBpbnQgPSAyMDQ4LAopIC0+IHN0cjoKICAgIGlmIHNmdF9tb2RlOgogICAgICAgIGZ1bGxfcHJvbXB0ID0gZiI8fHVzZXJ8Plxue3Byb21wdH1cbjx8YXNzaXN0YW50fD5cbiIKICAgIGVsc2U6CiAgICAgICAgZnVsbF9wcm9tcHQgPSBwcm9tcHQKICAgIHByb21wdF9pZHMgPSB0b2tlbml6ZXIuZW5jb2RlKGZ1bGxfcHJvbXB0LCBhZGRfYm9zPVRydWUsIGFkZF9lb3M9RmFsc2UpCiAgICBwcm9tcHRfbGVuID0gbGVuKHByb21wdF9pZHMpCiAgICBzdG9wX2lkcyA9IGJ1aWxkX3N0b3BfdG9rZW5faWRzKHRva2VuaXplcikKICAgIGJlYW1zOiBMaXN0W1R1cGxlW2Zsb2F0LCBMaXN0W2ludF1dXSA9IFsoMC4wLCBsaXN0KHByb21wdF9pZHMpKV0KICAgIGNvbXBsZXRlZDogTGlzdFtUdXBsZVtmbG9hdCwgTGlzdFtpbnRdXV0gPSBbXQogICAgZm9yIF9zdGVwIGluIHJhbmdlKG1heF9uZXdfdG9rZW5zKToKICAgICAgICBpZiBub3QgYmVhbXM6CiAgICAgICAgICAgIGJyZWFrCiAgICAgICAgY2FuZGlkYXRlczogTGlzdFtUdXBsZVtmbG9hdCwgTGlzdFtpbnRdXV0gPSBbXQogICAgICAgIGZvciBiZWFtX3Njb3JlLCBiZWFtX2lkcyBpbiBiZWFtczoKICAgICAgICAgICAgeCA9IHRvcmNoLnRlbnNvcigKICAgICAgICAgICAgICAgIFtiZWFtX2lkc1stY29udGV4dF93aW5kb3c6XV0sIGR0eXBlPXRvcmNoLmxvbmcsIGRldmljZT1kZXZpY2UKICAgICAgICAgICAgKQogICAgICAgICAgICB3aXRoIHRvcmNoLm5vX2dyYWQoKToKICAgICAgICAgICAgICAgIGxvZ2l0cywgXywgXywgXyA9IG1vZGVsKHgpCiAgICAgICAgICAgIG5sID0gbG9naXRzWzAsIC0xLCA6XQogICAgICAgICAgICBsb2dfcHJvYnMgPSBGLmxvZ19zb2Z0bWF4KG5sLCBkaW09LTEpCiAgICAgICAgICAgIGdlbl9pZHMgPSBiZWFtX2lkc1twcm9tcHRfbGVuOl0KICAgICAgICAgICAgaWYgbm9fcmVwZWF0X25ncmFtX3NpemUgPiAxIGFuZCBsZW4oZ2VuX2lkcykgPj0gbm9fcmVwZWF0X25ncmFtX3NpemUgLSAxOgogICAgICAgICAgICAgICAgcHJlZml4ID0gdHVwbGUoZ2VuX2lkc1stKG5vX3JlcGVhdF9uZ3JhbV9zaXplIC0gMSkgOl0pCiAgICAgICAgICAgICAgICBmb3IgaSBpbiByYW5nZShsZW4oZ2VuX2lkcykgLSBub19yZXBlYXRfbmdyYW1fc2l6ZSArIDEpOgogICAgICAgICAgICAgICAgICAgIGlmIHR1cGxlKGdlbl9pZHNbaSA6IGkgKyBub19yZXBlYXRfbmdyYW1fc2l6ZSAtIDFdKSA9PSBwcmVmaXg6CiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ19wcm9ic1tnZW5faWRzW2kgKyBub19yZXBlYXRfbmdyYW1fc2l6ZSAtIDFdXSA9IGZsb2F0KCItaW5mIikKICAgICAgICAgICAgdG9wa19scCwgdG9wa19pZHMgPSB0b3JjaC50b3BrKGxvZ19wcm9icywgYmVhbV93aWR0aCkKICAgICAgICAgICAgZm9yIGkgaW4gcmFuZ2UoYmVhbV93aWR0aCk6CiAgICAgICAgICAgICAgICB0aWQgPSB0b3BrX2lkc1tpXS5pdGVtKCkKICAgICAgICAgICAgICAgIG5ld19zY29yZSA9IGJlYW1fc2NvcmUgKyB0b3BrX2xwW2ldLml0ZW0oKQogICAgICAgICAgICAgICAgbmV3X2lkcyA9IGJlYW1faWRzICsgW3RpZF0KICAgICAgICAgICAgICAgIGlmIHRpZCBpbiBzdG9wX2lkczoKICAgICAgICAgICAgICAgICAgICBjb21wbGV0ZWQuYXBwZW5kKChuZXdfc2NvcmUsIG5ld19pZHMpKQogICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICAgICBjYW5kaWRhdGVzLmFwcGVuZCgobmV3X3Njb3JlLCBuZXdfaWRzKSkKCiAgICAgICAgZGVmIF9ub3JtX3Njb3JlKHBhaXIpOgogICAgICAgICAgICBnZW5fbGVuID0gbWF4KDEsIGxlbihwYWlyWzFdKSAtIHByb21wdF9sZW4pCiAgICAgICAgICAgIHJldHVybiBwYWlyWzBdIC8gKGdlbl9sZW4qKmxlbmd0aF9wZW5hbHR5KQoKICAgICAgICBjYW5kaWRhdGVzLnNvcnQoa2V5PV9ub3JtX3Njb3JlLCByZXZlcnNlPVRydWUpCiAgICAgICAgYmVhbXMgPSBjYW5kaWRhdGVzWzpiZWFtX3dpZHRoXQoKICAgIHBvb2wgPSBjb21wbGV0ZWQgKyBiZWFtcwogICAgaWYgbm90IHBvb2w6CiAgICAgICAgcmV0dXJuICIiCgogICAgZGVmIF9ub3JtX3Njb3JlX2ZpbmFsKHBhaXIpOgogICAgICAgIGdlbl9sZW4gPSBtYXgoMSwgbGVuKHBhaXJbMV0pIC0gcHJvbXB0X2xlbikKICAgICAgICByZXR1cm4gcGFpclswXSAvIChnZW5fbGVuKipsZW5ndGhfcGVuYWx0eSkKCiAgICBwb29sLnNvcnQoa2V5PV9ub3JtX3Njb3JlX2ZpbmFsLCByZXZlcnNlPVRydWUpCiAgICBiZXN0X2lkcyA9IHBvb2xbMF1bMV1bcHJvbXB0X2xlbjpdCiAgICB0ZXh0ID0gdG9rZW5pemVyLmRlY29kZShiZXN0X2lkcywgc2tpcF9zcGVjaWFsPVRydWUpCiAgICBubF9wb3MgPSB0ZXh0LmZpbmQoIlxuIikKICAgIGlmIG5sX3BvcyA+IDU6CiAgICAgICAgdGV4dCA9IHRleHRbOm5sX3Bvc10KICAgIHJldHVybiB0ZXh0LnN0cmlwKCkKCgpkZWYgZ2VuZXJhdGUoCiAgICBtb2RlbDogVGlueU1lbW9yeUxNLAogICAgdG9rZW5pemVyOiBXb3JkVG9rZW5pemVyLAogICAgcHJvbXB0OiBzdHIsCiAgICBtYXhfbmV3X3Rva2VuczogaW50ID0gMjU2LAogICAgdGVtcGVyYXR1cmU6IGZsb2F0ID0gMC44LAogICAgdG9wX2s6IGludCA9IDQwLAogICAgcmVwZXRpdGlvbl9wZW5hbHR5OiBmbG9hdCA9IDEuMCwKICAgIGRldmljZTogc3RyID0gImN1ZGEiLAogICAgc2Z0X21vZGU6IGJvb2wgPSBGYWxzZSwKICAgIGZvcmNlX3Rob3VnaHQ6IGJvb2wgPSBGYWxzZSwKICAgIHN0cmVhbTogYm9vbCA9IFRydWUsCiAgICBkZWNvZGVfbW9kZTogc3RyID0gImxlZ2FjeSIsCiAgICBiZXN0X29mOiBpbnQgPSAzLAogICAgbm9fcmVwZWF0X25ncmFtX3NpemU6IGludCA9IDMsCiAgICBjb250ZXh0X3dpbmRvdzogaW50ID0gMjA0OCwKICAgIGJlYW1fd2lkdGg6IGludCA9IDgsCiAgICBsZW5ndGhfcGVuYWx0eTogZmxvYXQgPSAwLjcsCikgLT4gc3RyOgogICAgaWYgZGVjb2RlX21vZGUgPT0gImJlYW0iOgogICAgICAgIHRleHQgPSBnZW5lcmF0ZV9iZWFtX3NlYXJjaCgKICAgICAgICAgICAgbW9kZWw9bW9kZWwsCiAgICAgICAgICAgIHRva2VuaXplcj10b2tlbml6ZXIsCiAgICAgICAgICAgIHByb21wdD1wcm9tcHQsCiAgICAgICAgICAgIG1heF9uZXdfdG9rZW5zPW1heF9uZXdfdG9rZW5zLAogICAgICAgICAgICBiZWFtX3dpZHRoPWJlYW1fd2lkdGgsCiAgICAgICAgICAgIGxlbmd0aF9wZW5hbHR5PWxlbmd0aF9wZW5hbHR5LAogICAgICAgICAgICBub19yZXBlYXRfbmdyYW1fc2l6ZT1ub19yZXBlYXRfbmdyYW1fc2l6ZSwKICAgICAgICAgICAgZGV2aWNlPWRldmljZSwKICAgICAgICAgICAgc2Z0X21vZGU9c2Z0X21vZGUsCiAgICAgICAgICAgIGNvbnRleHRfd2luZG93PWNvbnRleHRfd2luZG93LAogICAgICAgICkKICAgICAgICBpZiBzdHJlYW06CiAgICAgICAgICAgIHByaW50KHRleHQpCiAgICAgICAgcmV0dXJuIHRleHQKICAgIGlmIGRlY29kZV9tb2RlID09ICJsZWdhY3kiOgogICAgICAgIHRleHQsIF8sIF8sIF8gPSBnZW5lcmF0ZV9jYW5kaWRhdGUoCiAgICAgICAgICAgIG1vZGVsPW1vZGVsLAogICAgICAgICAgICB0b2tlbml6ZXI9dG9rZW5pemVyLAogICAgICAgICAgICBwcm9tcHQ9cHJvbXB0LAogICAgICAgICAgICBtYXhfbmV3X3Rva2Vucz1tYXhfbmV3X3Rva2VucywKICAgICAgICAgICAgdGVtcGVyYXR1cmU9dGVtcGVyYXR1cmUsCiAgICAgICAgICAgIHRvcF9rPXRvcF9rLAogICAgICAgICAgICByZXBldGl0aW9uX3BlbmFsdHk9cmVwZXRpdGlvbl9wZW5hbHR5LAogICAgICAgICAgICBub19yZXBlYXRfbmdyYW1fc2l6ZT1ub19yZXBlYXRfbmdyYW1fc2l6ZSwKICAgICAgICAgICAgZGV2aWNlPWRldmljZSwKICAgICAgICAgICAgc2Z0X21vZGU9c2Z0X21vZGUsCiAgICAgICAgICAgIGZvcmNlX3Rob3VnaHQ9Zm9yY2VfdGhvdWdodCwKICAgICAgICAgICAgc3RyZWFtPXN0cmVhbSwKICAgICAgICAgICAgY29udGV4dF93aW5kb3c9Y29udGV4dF93aW5kb3csCiAgICAgICAgKQogICAgICAgIHJldHVybiB0ZXh0CiAgICBjYW5kaWRhdGVzOiBMaXN0W1R1cGxlW2Zsb2F0LCBzdHIsIHN0ciwgZmxvYXRdXSA9IFtdCiAgICBmb3IgXyBpbiByYW5nZShtYXgoMSwgYmVzdF9vZikpOgogICAgICAgIGNhbmRpZGF0ZV90ZXh0LCByYXdfdGV4dCwgYXZnX2xvZ3Byb2IsIF8gPSBnZW5lcmF0ZV9jYW5kaWRhdGUoCiAgICAgICAgICAgIG1vZGVsPW1vZGVsLAogICAgICAgICAgICB0b2tlbml6ZXI9dG9rZW5pemVyLAogICAgICAgICAgICBwcm9tcHQ9cHJvbXB0LAogICAgICAgICAgICBtYXhfbmV3X3Rva2Vucz1tYXhfbmV3X3Rva2VucywKICAgICAgICAgICAgdGVtcGVyYXR1cmU9dGVtcGVyYXR1cmUsCiAgICAgICAgICAgIHRvcF9rPXRvcF9rLAogICAgICAgICAgICByZXBldGl0aW9uX3BlbmFsdHk9cmVwZXRpdGlvbl9wZW5hbHR5LAogICAgICAgICAgICBub19yZXBlYXRfbmdyYW1fc2l6ZT1ub19yZXBlYXRfbmdyYW1fc2l6ZSwKICAgICAgICAgICAgZGV2aWNlPWRldmljZSwKICAgICAgICAgICAgc2Z0X21vZGU9c2Z0X21vZGUsCiAgICAgICAgICAgIGZvcmNlX3Rob3VnaHQ9Zm9yY2VfdGhvdWdodCwKICAgICAgICAgICAgc3RyZWFtPUZhbHNlLAogICAgICAgICAgICBjb250ZXh0X3dpbmRvdz1jb250ZXh0X3dpbmRvdywKICAgICAgICApCiAgICAgICAgc2NvcmUgPSBzY29yZV9jYW5kaWRhdGUocHJvbXB0LCByYXdfdGV4dCwgY2FuZGlkYXRlX3RleHQsIGF2Z19sb2dwcm9iKQogICAgICAgIGNhbmRpZGF0ZXMuYXBwZW5kKChzY29yZSwgY2FuZGlkYXRlX3RleHQsIHJhd190ZXh0LCBhdmdfbG9ncHJvYikpCiAgICBiZXN0X3Njb3JlLCBiZXN0X3RleHQsIF8sIF8gPSBtYXgoY2FuZGlkYXRlcywga2V5PWxhbWJkYSBpdGVtOiBpdGVtWzBdKQogICAgaWYgc3RyZWFtOgogICAgICAgIHByaW50KGJlc3RfdGV4dCwgZW5kPSIiLCBmbHVzaD1UcnVlKQogICAgICAgIHByaW50KCkKICAgIHJldHVybiBiZXN0X3RleHQKCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFdlYiBzZXJ2ZXIgKGZyb20gaW50ZXJhY3RpdmUucHkpCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpST09UID0gUGF0aChfX2ZpbGVfXykucmVzb2x2ZSgpLnBhcmVudAppZiBzdHIoUk9PVCkgbm90IGluIHN5cy5wYXRoOgogICAgc3lzLnBhdGguaW5zZXJ0KDAsIHN0cihST09UKSkKCgpIRl9PUkcgPSAiQ29tcGFjdEFJIgpIRl9BUEkgPSAiaHR0cHM6Ly9odWdnaW5nZmFjZS5jby9hcGkiCkNBQ0hFX1JPT1QgPSBQYXRoLmhvbWUoKSAvICIuY2FjaGUiIC8gImNvbXBhY3RhaV93ZWIiClVTRVJfQUdFTlQgPSAiTW96aWxsYS81LjAgQ29tcGFjdEFJLVdlYiIKTU9ERUxfQ0FDSEU6IGRpY3RbdHVwbGVbc3RyLCBzdHJdLCBkaWN0W3N0ciwgb2JqZWN0XV0gPSB7fQpNT0RFTF9DQUNIRV9MT0NLID0gdGhyZWFkaW5nLlJMb2NrKCkKR0VORVJBVElPTl9MT0NLID0gdGhyZWFkaW5nLkxvY2soKQoKCmRlZiByZXF1ZXN0X2pzb24odXJsOiBzdHIpOgogICAgcmVxID0gUmVxdWVzdCh1cmwsIGhlYWRlcnM9eyJVc2VyLUFnZW50IjogVVNFUl9BR0VOVH0pCiAgICB3aXRoIHVybG9wZW4ocmVxLCB0aW1lb3V0PTYwKSBhcyByZXNwb25zZToKICAgICAgICByZXR1cm4ganNvbi5sb2FkcyhyZXNwb25zZS5yZWFkKCkuZGVjb2RlKCJ1dGYtOCIpKQoKCmRlZiByZXF1ZXN0X3RleHQodXJsOiBzdHIpIC0+IHN0cjoKICAgIHJlcSA9IFJlcXVlc3QodXJsLCBoZWFkZXJzPXsiVXNlci1BZ2VudCI6IFVTRVJfQUdFTlR9KQogICAgd2l0aCB1cmxvcGVuKHJlcSwgdGltZW91dD02MCkgYXMgcmVzcG9uc2U6CiAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnJlYWQoKS5kZWNvZGUoInV0Zi04IiwgZXJyb3JzPSJyZXBsYWNlIikKCgpkZWYgZG93bmxvYWRfZmlsZSh1cmw6IHN0ciwgZGVzdGluYXRpb246IFBhdGgpIC0+IE5vbmU6CiAgICBkZXN0aW5hdGlvbi5wYXJlbnQubWtkaXIocGFyZW50cz1UcnVlLCBleGlzdF9vaz1UcnVlKQogICAgdGVtcF9wYXRoID0gZGVzdGluYXRpb24ud2l0aF9zdWZmaXgoZGVzdGluYXRpb24uc3VmZml4ICsgIi50bXAiKQogICAgcmVxID0gUmVxdWVzdCh1cmwsIGhlYWRlcnM9eyJVc2VyLUFnZW50IjogVVNFUl9BR0VOVH0pCiAgICB3aXRoIHVybG9wZW4ocmVxLCB0aW1lb3V0PTEyMCkgYXMgcmVzcG9uc2UsIHRlbXBfcGF0aC5vcGVuKCJ3YiIpIGFzIGhhbmRsZToKICAgICAgICBzaHV0aWwuY29weWZpbGVvYmoocmVzcG9uc2UsIGhhbmRsZSkKICAgIHRlbXBfcGF0aC5yZXBsYWNlKGRlc3RpbmF0aW9uKQoKCmRlZiBub3JtYWxpemVfcmVwb19pZChyYXdfcmVwb19pZDogc3RyKSAtPiBzdHI6CiAgICBpZiBub3QgaXNpbnN0YW5jZShyYXdfcmVwb19pZCwgc3RyKToKICAgICAgICByZXR1cm4gIiIKICAgIHJlcG9faWQgPSByYXdfcmVwb19pZC5zdHJpcCgpCiAgICBpZiBub3QgcmVwb19pZDoKICAgICAgICByZXR1cm4gIiIKICAgIHRyeToKICAgICAgICByZXBvX2lkID0gdW5xdW90ZShyZXBvX2lkKQogICAgZXhjZXB0IEV4Y2VwdGlvbjoKICAgICAgICBwYXNzCiAgICByZXR1cm4gKAogICAgICAgIHJlcG9faWQucmVwbGFjZSgiaHR0cHM6Ly9odWdnaW5nZmFjZS5jby8iLCAiIikKICAgICAgICAucmVwbGFjZSgiaHR0cDovL2h1Z2dpbmdmYWNlLmNvLyIsICIiKQogICAgICAgIC5yZXBsYWNlKCJhcGkvbW9kZWxzLyIsICIiKQogICAgICAgIC5yZXBsYWNlKCJtb2RlbHMvIiwgIiIpCiAgICAgICAgLnNwbGl0KCI/IiwgMSlbMF0KICAgICAgICAuc3BsaXQoIiMiLCAxKVswXQogICAgICAgIC5zdHJpcCgiLyIpCiAgICApCgoKZGVmIHNlcmllc19mcm9tX25hbWUobmFtZTogc3RyKSAtPiBzdHIgfCBOb25lOgogICAgbG93ZXIgPSAobmFtZSBvciAiIikubG93ZXIoKQogICAgaWYgImhhaWt1IiBpbiBsb3dlcjoKICAgICAgICByZXR1cm4gIkhhaWt1IgogICAgaWYgInNvbm5ldCIgaW4gbG93ZXI6CiAgICAgICAgcmV0dXJuICJTb25uZXQiCiAgICBpZiAib3B1cyIgaW4gbG93ZXI6CiAgICAgICAgcmV0dXJuICJPcHVzIgogICAgcmV0dXJuIE5vbmUKCgpkZWYgZW5jb2RlZF9yZXBvX2lkKHJlcG9faWQ6IHN0cikgLT4gc3RyOgogICAgcmV0dXJuICIvIi5qb2luKAogICAgICAgIHF1b3RlKHBhcnQsIHNhZmU9IiIpIGZvciBwYXJ0IGluIG5vcm1hbGl6ZV9yZXBvX2lkKHJlcG9faWQpLnNwbGl0KCIvIikgaWYgcGFydAogICAgKQoKCmRlZiBoZl9maWxlX3VybChyZXBvX2lkOiBzdHIsIGZpbGVuYW1lOiBzdHIpIC0+IHN0cjoKICAgIGVuY29kZWRfbmFtZSA9ICIvIi5qb2luKAogICAgICAgIHF1b3RlKHBhcnQsIHNhZmU9IiIpIGZvciBwYXJ0IGluIGZpbGVuYW1lLnNwbGl0KCIvIikgaWYgcGFydAogICAgKQogICAgcmV0dXJuICgKICAgICAgICBmImh0dHBzOi8vaHVnZ2luZ2ZhY2UuY28ve2VuY29kZWRfcmVwb19pZChyZXBvX2lkKX0vcmVzb2x2ZS9tYWluL3tlbmNvZGVkX25hbWV9IgogICAgKQoKCmRlZiBtb2RlbF9saXN0KCkgLT4gbGlzdFtkaWN0W3N0ciwgb2JqZWN0XV06CiAgICBkYXRhID0gcmVxdWVzdF9qc29uKGYie0hGX0FQSX0vbW9kZWxzP2F1dGhvcj17cXVvdGUoSEZfT1JHKX0mZnVsbD10cnVlJmxpbWl0PTIwMCIpCiAgICBtb2RlbHM6IGxpc3RbZGljdFtzdHIsIG9iamVjdF1dID0gW10KICAgIGZvciBpdGVtIGluIGRhdGE6CiAgICAgICAgc2libGluZ3MgPSBpdGVtLmdldCgic2libGluZ3MiKSBvciBbXQogICAgICAgIGZpbGVuYW1lcyA9IFtzLmdldCgicmZpbGVuYW1lIiwgIiIpIGZvciBzIGluIHNpYmxpbmdzIGlmIGlzaW5zdGFuY2UocywgZGljdCldCiAgICAgICAgaGFzX21vZGVsID0gIm1vZGVsLnB0IiBpbiBmaWxlbmFtZXMgb3IgIm1vZGVsL21vZGVsLnB0IiBpbiBmaWxlbmFtZXMKICAgICAgICBoYXNfcHJldHJhaW4gPSAicHJldHJhaW4ucHQiIGluIGZpbGVuYW1lcyBvciAibW9kZWwvcHJldHJhaW4ucHQiIGluIGZpbGVuYW1lcwogICAgICAgIGhhc190b2tlbml6ZXIgPSAoCiAgICAgICAgICAgICJ0b2tlbml6ZXIuanNvbiIgaW4gZmlsZW5hbWVzIG9yICJtb2RlbC90b2tlbml6ZXIuanNvbiIgaW4gZmlsZW5hbWVzCiAgICAgICAgKQogICAgICAgIGlmIG5vdCBoYXNfbW9kZWwgYW5kIG5vdCBoYXNfcHJldHJhaW46CiAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgbmFtZSA9IChpdGVtLmdldCgiaWQiKSBvciAiIikuc3BsaXQoIi8iKVstMV0KICAgICAgICBzZXJpZXMgPSBzZXJpZXNfZnJvbV9uYW1lKG5hbWUpCiAgICAgICAgaWYgbm90IHNlcmllczoKICAgICAgICAgICAgY29udGludWUKICAgICAgICBtb2RlbHMuYXBwZW5kKAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiBpdGVtLmdldCgiaWQiLCAiIiksCiAgICAgICAgICAgICAgICAibmFtZSI6IG5hbWUsCiAgICAgICAgICAgICAgICAic2VyaWVzIjogc2VyaWVzLAogICAgICAgICAgICAgICAgImRvd25sb2FkcyI6IGl0ZW0uZ2V0KCJkb3dubG9hZHMiLCAwKSBvciAwLAogICAgICAgICAgICAgICAgImxpa2VzIjogaXRlbS5nZXQoImxpa2VzIiwgMCkgb3IgMCwKICAgICAgICAgICAgICAgICJoYXNfbW9kZWwiOiBoYXNfbW9kZWwsCiAgICAgICAgICAgICAgICAiaGFzX3ByZXRyYWluIjogaGFzX3ByZXRyYWluLAogICAgICAgICAgICAgICAgImhhc190b2tlbml6ZXIiOiBoYXNfdG9rZW5pemVyLAogICAgICAgICAgICB9CiAgICAgICAgKQogICAgcmV0dXJuIHNvcnRlZChtb2RlbHMsIGtleT1sYW1iZGEgZW50cnk6IGVudHJ5WyJkb3dubG9hZHMiXSwgcmV2ZXJzZT1UcnVlKQoKCmRlZiBtb2RlbF9kZXRhaWxzKHJlcG9faWQ6IHN0cikgLT4gZGljdFtzdHIsIG9iamVjdF0gfCBOb25lOgogICAgbm9ybWFsaXplZCA9IG5vcm1hbGl6ZV9yZXBvX2lkKHJlcG9faWQpCiAgICBpZiBub3Qgbm9ybWFsaXplZDoKICAgICAgICByZXR1cm4gTm9uZQogICAgZGF0YSA9IHJlcXVlc3RfanNvbihmIntIRl9BUEl9L21vZGVscy97ZW5jb2RlZF9yZXBvX2lkKG5vcm1hbGl6ZWQpfSIpCiAgICBzaWJsaW5ncyA9IGRhdGEuZ2V0KCJzaWJsaW5ncyIpIG9yIFtdCiAgICBmaWxlczogZGljdFtzdHIsIGRpY3Rbc3RyLCBmbG9hdF1dID0ge30KICAgIGhhc19tb2RlbCA9IEZhbHNlCiAgICBoYXNfcHJldHJhaW4gPSBGYWxzZQogICAgZm9yIHNpYmxpbmcgaW4gc2libGluZ3M6CiAgICAgICAgaWYgbm90IGlzaW5zdGFuY2Uoc2libGluZywgZGljdCk6CiAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgZmlsZW5hbWUgPSBzaWJsaW5nLmdldCgicmZpbGVuYW1lIikgb3IgIiIKICAgICAgICBpZiBub3QgZmlsZW5hbWU6CiAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgc2l6ZV9tYiA9IHJvdW5kKChzaWJsaW5nLmdldCgic2l6ZSIpIG9yIDApIC8gKDEwMjQgKiAxMDI0KSwgMikKICAgICAgICBmaWxlc1tmaWxlbmFtZV0gPSB7InNpemVfbWIiOiBzaXplX21ifQogICAgICAgIGlmIGZpbGVuYW1lLnN0YXJ0c3dpdGgoIm1vZGVsLyIpOgogICAgICAgICAgICBmaWxlc1tmaWxlbmFtZS5yZW1vdmVwcmVmaXgoIm1vZGVsLyIpXSA9IHsic2l6ZV9tYiI6IHNpemVfbWJ9CiAgICAgICAgaWYgZmlsZW5hbWUgaW4geyJtb2RlbC5wdCIsICJtb2RlbC9tb2RlbC5wdCJ9OgogICAgICAgICAgICBoYXNfbW9kZWwgPSBUcnVlCiAgICAgICAgaWYgZmlsZW5hbWUgaW4geyJwcmV0cmFpbi5wdCIsICJtb2RlbC9wcmV0cmFpbi5wdCJ9OgogICAgICAgICAgICBoYXNfcHJldHJhaW4gPSBUcnVlCiAgICByZWFkbWVfcmF3ID0gIiIKICAgIHRyeToKICAgICAgICByZWFkbWVfcmF3ID0gcmVxdWVzdF90ZXh0KAogICAgICAgICAgICBmImh0dHBzOi8vaHVnZ2luZ2ZhY2UuY28ve2VuY29kZWRfcmVwb19pZChub3JtYWxpemVkKX0vcmF3L21haW4vUkVBRE1FLm1kIgogICAgICAgICkKICAgIGV4Y2VwdCBFeGNlcHRpb246CiAgICAgICAgcmVhZG1lX3JhdyA9ICIiCiAgICBuYW1lID0gKGRhdGEuZ2V0KCJpZCIpIG9yIG5vcm1hbGl6ZWQpLnNwbGl0KCIvIilbLTFdCiAgICByZXR1cm4gewogICAgICAgICJpZCI6IG5vcm1hbGl6ZWQsCiAgICAgICAgIm5hbWUiOiBuYW1lLAogICAgICAgICJzZXJpZXMiOiBzZXJpZXNfZnJvbV9uYW1lKG5hbWUpIG9yICJTb25uZXQiLAogICAgICAgICJkb3dubG9hZHMiOiBkYXRhLmdldCgiZG93bmxvYWRzIiwgMCkgb3IgMCwKICAgICAgICAiZmlsZXMiOiBmaWxlcywKICAgICAgICAicmVhZG1lX3JhdyI6IHJlYWRtZV9yYXcsCiAgICAgICAgImhmX21vZGVsX2lkIjogbm9ybWFsaXplZCwKICAgICAgICAiaGFzX21vZGVsIjogaGFzX21vZGVsLAogICAgICAgICJoYXNfcHJldHJhaW4iOiBoYXNfcHJldHJhaW4sCiAgICB9CgoKZGVmIGNhY2hlX2RpcihyZXBvX2lkOiBzdHIsIG1vZGVsX3R5cGU6IHN0cikgLT4gUGF0aDoKICAgIHJldHVybiBDQUNIRV9ST09UIC8gbm9ybWFsaXplX3JlcG9faWQocmVwb19pZCkucmVwbGFjZSgiLyIsICJfXyIpIC8gbW9kZWxfdHlwZQoKCmRlZiBhcnRpZmFjdF9jYW5kaWRhdGVzKG1vZGVsX3R5cGU6IHN0cikgLT4gbGlzdFtzdHJdOgogICAgcmV0dXJuICgKICAgICAgICBbIm1vZGVsL3ByZXRyYWluLnB0IiwgInByZXRyYWluLnB0Il0KICAgICAgICBpZiBtb2RlbF90eXBlID09ICJwcmV0cmFpbiIKICAgICAgICBlbHNlIFsibW9kZWwvbW9kZWwucHQiLCAibW9kZWwucHQiXQogICAgKQoKCmRlZiBlbnN1cmVfYXJ0aWZhY3QocmVwb19pZDogc3RyLCBtb2RlbF90eXBlOiBzdHIsIGRlc3RpbmF0aW9uX25hbWU6IHN0cikgLT4gUGF0aDoKICAgIG5vcm1hbGl6ZWQgPSBub3JtYWxpemVfcmVwb19pZChyZXBvX2lkKQogICAgdGFyZ2V0ID0gY2FjaGVfZGlyKG5vcm1hbGl6ZWQsIG1vZGVsX3R5cGUpIC8gZGVzdGluYXRpb25fbmFtZQogICAgaWYgdGFyZ2V0LmV4aXN0cygpOgogICAgICAgIHJldHVybiB0YXJnZXQKICAgIGxhc3RfZXJyb3I6IEV4Y2VwdGlvbiB8IE5vbmUgPSBOb25lCiAgICBmb3IgY2FuZGlkYXRlIGluICgKICAgICAgICBhcnRpZmFjdF9jYW5kaWRhdGVzKG1vZGVsX3R5cGUpCiAgICAgICAgaWYgZGVzdGluYXRpb25fbmFtZS5lbmRzd2l0aCgiLnB0IikKICAgICAgICBlbHNlIFsibW9kZWwvdG9rZW5pemVyLmpzb24iLCAidG9rZW5pemVyLmpzb24iXQogICAgKToKICAgICAgICB0cnk6CiAgICAgICAgICAgIGRvd25sb2FkX2ZpbGUoaGZfZmlsZV91cmwobm9ybWFsaXplZCwgY2FuZGlkYXRlKSwgdGFyZ2V0KQogICAgICAgICAgICByZXR1cm4gdGFyZ2V0CiAgICAgICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBleGM6CiAgICAgICAgICAgIGxhc3RfZXJyb3IgPSBleGMKICAgIHJhaXNlIFJ1bnRpbWVFcnJvcigKICAgICAgICBmIlVuYWJsZSB0byBkb3dubG9hZCB7ZGVzdGluYXRpb25fbmFtZX0gZm9yIHtub3JtYWxpemVkfToge2xhc3RfZXJyb3J9IgogICAgKQoKCmRlZiBzZXJpZXNfY29uZmlnKHNlcmllczogc3RyKSAtPiBkaWN0W3N0ciwgb2JqZWN0XToKICAgIHJldHVybiBNT0RFTF9TRVJJRVMuZ2V0KHNlcmllcy5sb3dlcigpLCBNT0RFTF9TRVJJRVNbInNvbm5ldCJdKQoKCmRlZiBsb2FkX2J1bmRsZShyZXBvX2lkOiBzdHIsIG1vZGVsX3R5cGU6IHN0cikgLT4gZGljdFtzdHIsIG9iamVjdF06CiAgICBub3JtYWxpemVkID0gbm9ybWFsaXplX3JlcG9faWQocmVwb19pZCkKICAgIGRldGFpbHMgPSBtb2RlbF9kZXRhaWxzKG5vcm1hbGl6ZWQpCiAgICBpZiBub3QgZGV0YWlsczoKICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoIk1vZGVsIGRldGFpbHMgYXJlIHVuYXZhaWxhYmxlLiIpCiAgICBzZXJpZXMgPSBzdHIoZGV0YWlsc1sic2VyaWVzIl0pCiAgICBrZXkgPSAobm9ybWFsaXplZCwgbW9kZWxfdHlwZSkKICAgIHdpdGggTU9ERUxfQ0FDSEVfTE9DSzoKICAgICAgICBjYWNoZWQgPSBNT0RFTF9DQUNIRS5nZXQoa2V5KQogICAgICAgIGlmIGNhY2hlZDoKICAgICAgICAgICAgcmV0dXJuIGNhY2hlZAogICAgICAgIGJ1bmRsZV9kaXIgPSBjYWNoZV9kaXIobm9ybWFsaXplZCwgbW9kZWxfdHlwZSkKICAgICAgICBidW5kbGVfZGlyLm1rZGlyKHBhcmVudHM9VHJ1ZSwgZXhpc3Rfb2s9VHJ1ZSkKICAgICAgICBtb2RlbF9wYXRoID0gYnVuZGxlX2RpciAvICgKICAgICAgICAgICAgInByZXRyYWluLnB0IiBpZiBtb2RlbF90eXBlID09ICJwcmV0cmFpbiIgZWxzZSAibW9kZWwucHQiCiAgICAgICAgKQogICAgICAgIHRva2VuaXplcl9wYXRoID0gYnVuZGxlX2RpciAvICJ0b2tlbml6ZXIuanNvbiIKICAgICAgICBpZiBub3QgbW9kZWxfcGF0aC5leGlzdHMoKToKICAgICAgICAgICAgZW5zdXJlX2FydGlmYWN0KG5vcm1hbGl6ZWQsIG1vZGVsX3R5cGUsIG1vZGVsX3BhdGgubmFtZSkKICAgICAgICBpZiBub3QgdG9rZW5pemVyX3BhdGguZXhpc3RzKCk6CiAgICAgICAgICAgIGVuc3VyZV9hcnRpZmFjdChub3JtYWxpemVkLCBtb2RlbF90eXBlLCB0b2tlbml6ZXJfcGF0aC5uYW1lKQogICAgICAgIHRva2VuaXplciA9IFdvcmRUb2tlbml6ZXIubG9hZCh0b2tlbml6ZXJfcGF0aCkKICAgICAgICBja3B0ID0gdG9yY2gubG9hZChzdHIobW9kZWxfcGF0aCksIG1hcF9sb2NhdGlvbj0iY3B1Iiwgd2VpZ2h0c19vbmx5PUZhbHNlKQogICAgICAgIGNmZyA9IHNlcmllc19jb25maWcoc2VyaWVzKQogICAgICAgIHZvY2FiX3NpemUgPSBpbnQoY2twdC5nZXQoInZvY2FiX3NpemUiLCB0b2tlbml6ZXIudm9jYWJfc2l6ZSkpCiAgICAgICAgc3RhdGVfZGljdCA9IGNrcHQuZ2V0KCJtb2RlbF9zdGF0ZSIpIG9yIGNrcHQuZ2V0KCJzdGF0ZV9kaWN0Iikgb3IgY2twdAogICAgICAgICMgQXV0by1kZXRlY3QgbmV3IGFyY2ggZmVhdHVyZXMgZnJvbSBjaGVja3BvaW50IHdlaWdodHMKICAgICAgICBlbmdyYW1fZGltID0gX2RldGVjdF9lbmdyYW1fZGltKHN0YXRlX2RpY3QpIG9yIGludCgKICAgICAgICAgICAgY2ZnLmdldCgiZW5ncmFtX2RpbSIsIG1vZGVsX2NvbmZpZy5lbmdyYW1fZGltKQogICAgICAgICkKICAgICAgICBtaGNfZXhwYW5zaW9uID0gX2RldGVjdF9taGNfZXhwYW5zaW9uKHN0YXRlX2RpY3QpIG9yIGludCgKICAgICAgICAgICAgY2ZnLmdldCgibWhjX2V4cGFuc2lvbiIsIG1vZGVsX2NvbmZpZy5taGNfZXhwYW5zaW9uKQogICAgICAgICkKICAgICAgICBtb2RlbCA9IFRpbnlNZW1vcnlMTSgKICAgICAgICAgICAgdm9jYWJfc2l6ZT12b2NhYl9zaXplLAogICAgICAgICAgICBkaW09aW50KGNmZy5nZXQoImRpbSIsIG1vZGVsX2NvbmZpZy5kaW0pKSwKICAgICAgICAgICAgbl91bmlxdWVfbGF5ZXJzPWludCgKICAgICAgICAgICAgICAgIGNmZy5nZXQoIm5fdW5pcXVlX2xheWVycyIsIG1vZGVsX2NvbmZpZy5uX3VuaXF1ZV9sYXllcnMpCiAgICAgICAgICAgICksCiAgICAgICAgICAgIG5fbG9naWNhbF9sYXllcnM9aW50KAogICAgICAgICAgICAgICAgY2ZnLmdldCgibl9sb2dpY2FsX2xheWVycyIsIG1vZGVsX2NvbmZpZy5uX2xvZ2ljYWxfbGF5ZXJzKQogICAgICAgICAgICApLAogICAgICAgICAgICBuX2hlYWRzPWludChjZmcuZ2V0KCJuX2hlYWRzIiwgbW9kZWxfY29uZmlnLm5faGVhZHMpKSwKICAgICAgICAgICAgbl9rdl9oZWFkcz1pbnQoY2ZnLmdldCgibl9rdl9oZWFkcyIsIG1vZGVsX2NvbmZpZy5uX2t2X2hlYWRzKSksCiAgICAgICAgICAgIGZmbl9kaW09aW50KGNmZy5nZXQoImZmbl9kaW0iLCBtb2RlbF9jb25maWcuZmZuX2RpbSkpLAogICAgICAgICAgICBkcm9wb3V0PWZsb2F0KGNmZy5nZXQoImRyb3BvdXQiLCBtb2RlbF9jb25maWcuZHJvcG91dCkpLAogICAgICAgICAgICBtdHBfaG9yaXpvbnM9dHVwbGUoCiAgICAgICAgICAgICAgICBpbnQodikgZm9yIHYgaW4gY2ZnLmdldCgibXRwX2hvcml6b25zIiwgbW9kZWxfY29uZmlnLm10cF9ob3Jpem9ucykKICAgICAgICAgICAgKSwKICAgICAgICAgICAgZ3JhZF9jaGVja3BvaW50PUZhbHNlLAogICAgICAgICAgICBzbGlkaW5nX3dpbmRvdz1pbnQoCiAgICAgICAgICAgICAgICBjZmcuZ2V0KCJzbGlkaW5nX3dpbmRvd19zaXplIiwgbW9kZWxfY29uZmlnLnNsaWRpbmdfd2luZG93X3NpemUpCiAgICAgICAgICAgICksCiAgICAgICAgICAgIHJvcGVfZnJhY3Rpb249ZmxvYXQoCiAgICAgICAgICAgICAgICBjZmcuZ2V0KCJyb3BlX2ZyYWN0aW9uIiwgbW9kZWxfY29uZmlnLnJvcGVfZnJhY3Rpb24pCiAgICAgICAgICAgICksCiAgICAgICAgICAgIGVtYmVkX3NjYWxlPWJvb2woCiAgICAgICAgICAgICAgICBjZmcuZ2V0KCJlbWJlZF9zY2FsZSIsIG1vZGVsX2NvbmZpZy5lbWJlZF9zY2FsZSkKICAgICAgICAgICAgKSwKICAgICAgICAgICAgZW5ncmFtX2RpbT1lbmdyYW1fZGltLAogICAgICAgICAgICBlbmdyYW1faGVhZHM9aW50KGNmZy5nZXQoImVuZ3JhbV9oZWFkcyIsIG1vZGVsX2NvbmZpZy5lbmdyYW1faGVhZHMpKSwKICAgICAgICAgICAgZW5ncmFtX3RhYmxlX3NpemU9aW50KAogICAgICAgICAgICAgICAgY2ZnLmdldCgiZW5ncmFtX3RhYmxlX3NpemUiLCBtb2RlbF9jb25maWcuZW5ncmFtX3RhYmxlX3NpemUpCiAgICAgICAgICAgICksCiAgICAgICAgICAgIGVuZ3JhbV9tYXhfbmdyYW09aW50KAogICAgICAgICAgICAgICAgY2ZnLmdldCgiZW5ncmFtX21heF9uZ3JhbSIsIG1vZGVsX2NvbmZpZy5lbmdyYW1fbWF4X25ncmFtKQogICAgICAgICAgICApLAogICAgICAgICAgICBtaGNfZXhwYW5zaW9uPW1oY19leHBhbnNpb24sCiAgICAgICAgKQogICAgICAgIG1vZGVsLmxvYWRfc3RhdGVfZGljdChzdGF0ZV9kaWN0LCBzdHJpY3Q9RmFsc2UpCiAgICAgICAgbW9kZWwuZXZhbCgpCiAgICAgICAgaWYgdG9rZW5pemVyLnZvY2FiX3NpemUgPiB2b2NhYl9zaXplOgogICAgICAgICAgICBtb2RlbC5yZXNpemVfdG9rZW5fZW1iZWRkaW5ncyh0b2tlbml6ZXIudm9jYWJfc2l6ZSkKICAgICAgICBkZXZpY2UgPSAiY3VkYSIgaWYgdG9yY2guY3VkYS5pc19hdmFpbGFibGUoKSBlbHNlICJjcHUiCiAgICAgICAgbW9kZWwgPSBtb2RlbC50byhkZXZpY2UpCiAgICAgICAgYnVuZGxlID0gewogICAgICAgICAgICAicmVwb19pZCI6IG5vcm1hbGl6ZWQsCiAgICAgICAgICAgICJuYW1lIjogZGV0YWlsc1sibmFtZSJdLAogICAgICAgICAgICAic2VyaWVzIjogc2VyaWVzLAogICAgICAgICAgICAidHlwZSI6IG1vZGVsX3R5cGUsCiAgICAgICAgICAgICJtb2RlbCI6IG1vZGVsLAogICAgICAgICAgICAidG9rZW5pemVyIjogdG9rZW5pemVyLAogICAgICAgICAgICAiZGV2aWNlIjogZGV2aWNlLAogICAgICAgICAgICAibW9kZWxfcGF0aCI6IHN0cihtb2RlbF9wYXRoKSwKICAgICAgICAgICAgInRva2VuaXplcl9wYXRoIjogc3RyKHRva2VuaXplcl9wYXRoKSwKICAgICAgICAgICAgImRvd25sb2FkcyI6IGRldGFpbHNbImRvd25sb2FkcyJdLAogICAgICAgIH0KICAgICAgICBNT0RFTF9DQUNIRVtrZXldID0gYnVuZGxlCiAgICAgICAgcmV0dXJuIGJ1bmRsZQoKCmRlZiBlbnN1cmVfcG9ydChzdGFydF9wb3J0OiBpbnQpIC0+IGludDoKICAgIGZvciBwb3J0IGluIHJhbmdlKHN0YXJ0X3BvcnQsIHN0YXJ0X3BvcnQgKyA1MCk6CiAgICAgICAgd2l0aCBzb2NrZXQuc29ja2V0KHNvY2tldC5BRl9JTkVULCBzb2NrZXQuU09DS19TVFJFQU0pIGFzIHNvY2s6CiAgICAgICAgICAgIHRyeToKICAgICAgICAgICAgICAgIHNvY2suYmluZCgoIjEyNy4wLjAuMSIsIHBvcnQpKQogICAgICAgICAgICBleGNlcHQgT1NFcnJvcjoKICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgIHJldHVybiBwb3J0CiAgICB3aXRoIHNvY2tldC5zb2NrZXQoc29ja2V0LkFGX0lORVQsIHNvY2tldC5TT0NLX1NUUkVBTSkgYXMgc29jazoKICAgICAgICBzb2NrLmJpbmQoKCIxMjcuMC4wLjEiLCAwKSkKICAgICAgICByZXR1cm4gc29jay5nZXRzb2NrbmFtZSgpWzFdCgoKZGVmIHBhZ2VfaHRtbCgpIC0+IHN0cjoKICAgIHJldHVybiBmIiIiPCFkb2N0eXBlIGh0bWw+CjxodG1sIGxhbmc9ImVuIj4KPGhlYWQ+CiAgPG1ldGEgY2hhcnNldD0idXRmLTgiPgogIDxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsIGluaXRpYWwtc2NhbGU9MSI+CiAgPHRpdGxlPkNvbXBhY3RBSSBXZWI8L3RpdGxlPgogIDxzdHlsZT4KICAgIDpyb290IHt7CiAgICAgIGNvbG9yLXNjaGVtZTogZGFyazsKICAgICAgLS1iZzogIzA1MDUwNTsKICAgICAgLS1wYW5lbDogIzExMTExMTsKICAgICAgLS1wYW5lbC0yOiAjMTYxNjE2OwogICAgICAtLWxpbmU6ICMyNjI2MjY7CiAgICAgIC0tdGV4dDogI2Y1ZjVmNTsKICAgICAgLS1tdXRlZDogI2EzYTNhMzsKICAgICAgLS1hY2NlbnQ6ICNkOTc3MDY7CiAgICAgIC0tYWNjZW50LTI6ICNiNDUzMDk7CiAgICAgIC0tc29mdDogIzFmMWYxZjsKICAgIH19CiAgICAqIHt7IGJveC1zaXppbmc6IGJvcmRlci1ib3g7IH19CiAgICBib2R5IHt7CiAgICAgIG1hcmdpbjogMDsKICAgICAgZm9udC1mYW1pbHk6IEdlaXN0LCAtYXBwbGUtc3lzdGVtLCBCbGlua01hY1N5c3RlbUZvbnQsIHNhbnMtc2VyaWY7CiAgICAgIGJhY2tncm91bmQ6IHZhcigtLWJnKTsKICAgICAgY29sb3I6IHZhcigtLXRleHQpOwogICAgICBsaW5lLWhlaWdodDogMS41OwogICAgfX0KICAgIGEge3sgY29sb3I6IGluaGVyaXQ7IH19CiAgICAud3JhcCB7eyBtYXgtd2lkdGg6IDExMjBweDsgbWFyZ2luOiAwIGF1dG87IHBhZGRpbmc6IDI4cHggMjBweCA0MHB4OyB9fQogICAgLmhlcm8ge3sKICAgICAgZGlzcGxheTogZmxleDsKICAgICAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuOwogICAgICBhbGlnbi1pdGVtczogZW5kOwogICAgICBnYXA6IDE2cHg7CiAgICAgIHBhZGRpbmc6IDIycHggMCAyOHB4OwogICAgICBib3JkZXItYm90dG9tOiAxcHggc29saWQgdmFyKC0tbGluZSk7CiAgICAgIG1hcmdpbi1ib3R0b206IDIycHg7CiAgICB9fQogICAgaDEge3sgbWFyZ2luOiAwOyBmb250LXNpemU6IGNsYW1wKDJyZW0sIDV2dywgMy41cmVtKTsgbGV0dGVyLXNwYWNpbmc6IC0wLjA0ZW07IH19CiAgICAuc3VidGl0bGUge3sgbWFyZ2luOiAxMHB4IDAgMDsgY29sb3I6IHZhcigtLW11dGVkKTsgbWF4LXdpZHRoOiA1OGNoOyB9fQogICAgLmdyaWQge3sKICAgICAgZGlzcGxheTogZ3JpZDsKICAgICAgZ3JpZC10ZW1wbGF0ZS1jb2x1bW5zOiAxLjFmciAxZnI7CiAgICAgIGdhcDogMThweDsKICAgIH19CiAgICAucGFuZWwge3sKICAgICAgYmFja2dyb3VuZDogdmFyKC0tcGFuZWwpOwogICAgICBib3JkZXI6IDFweCBzb2xpZCB2YXIoLS1saW5lKTsKICAgICAgYm9yZGVyLXJhZGl1czogMThweDsKICAgICAgcGFkZGluZzogMThweDsKICAgIH19CiAgICAucGFuZWwgaDIge3sgbWFyZ2luOiAwIDAgMTJweDsgZm9udC1zaXplOiAxNXB4OyBsZXR0ZXItc3BhY2luZzogMC4wMmVtOyB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlOyBjb2xvcjogdmFyKC0tbXV0ZWQpOyB9fQogICAgLnJvdyB7eyBkaXNwbGF5OiBmbGV4OyBnYXA6IDEwcHg7IGZsZXgtd3JhcDogd3JhcDsgfX0KICAgIHNlbGVjdCwgdGV4dGFyZWEsIGlucHV0IHt7CiAgICAgIHdpZHRoOiAxMDAlOwogICAgICBiYWNrZ3JvdW5kOiB2YXIoLS1wYW5lbC0yKTsKICAgICAgY29sb3I6IHZhcigtLXRleHQpOwogICAgICBib3JkZXI6IDFweCBzb2xpZCB2YXIoLS1saW5lKTsKICAgICAgYm9yZGVyLXJhZGl1czogMTJweDsKICAgICAgcGFkZGluZzogMTJweCAxNHB4OwogICAgICBmb250OiBpbmhlcml0OwogICAgICBvdXRsaW5lOiBub25lOwogICAgfX0KICAgIHRleHRhcmVhIHt7IG1pbi1oZWlnaHQ6IDE3MHB4OyByZXNpemU6IHZlcnRpY2FsOyB9fQogICAgc2VsZWN0IHt7IGFwcGVhcmFuY2U6IG5vbmU7IH19CiAgICAuY2hvaWNlIHt7CiAgICAgIGZsZXg6IDEgMSAxNTBweDsKICAgICAgZGlzcGxheTogZmxleDsKICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICAgICAgZ2FwOiAxMHB4OwogICAgICBwYWRkaW5nOiAxMHB4IDEycHg7CiAgICAgIGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWxpbmUpOwogICAgICBib3JkZXItcmFkaXVzOiAxMnB4OwogICAgICBiYWNrZ3JvdW5kOiB2YXIoLS1wYW5lbC0yKTsKICAgICAgY3Vyc29yOiBwb2ludGVyOwogICAgfX0KICAgIC5jaG9pY2UgaW5wdXQge3sgd2lkdGg6IGF1dG87IH19CiAgICAuYnRucyB7eyBkaXNwbGF5OiBmbGV4OyBmbGV4LXdyYXA6IHdyYXA7IGdhcDogMTBweDsgfX0KICAgIGJ1dHRvbiB7ewogICAgICBib3JkZXI6IDFweCBzb2xpZCB2YXIoLS1saW5lKTsKICAgICAgYm9yZGVyLXJhZGl1czogMTJweDsKICAgICAgcGFkZGluZzogMTFweCAxNHB4OwogICAgICBiYWNrZ3JvdW5kOiB2YXIoLS1zb2Z0KTsKICAgICAgY29sb3I6IHZhcigtLXRleHQpOwogICAgICBmb250OiBpbmhlcml0OwogICAgICBjdXJzb3I6IHBvaW50ZXI7CiAgICAgIHRyYW5zaXRpb246IHRyYW5zZm9ybSAwLjE1cyBlYXNlLCBib3JkZXItY29sb3IgMC4xNXMgZWFzZSwgYmFja2dyb3VuZCAwLjE1cyBlYXNlOwogICAgfX0KICAgIGJ1dHRvbjpob3ZlciB7eyB0cmFuc2Zvcm06IHRyYW5zbGF0ZVkoLTFweCk7IGJvcmRlci1jb2xvcjogIzNhM2EzYTsgfX0KICAgIC5wcmltYXJ5IHt7IGJhY2tncm91bmQ6IHZhcigtLWFjY2VudCk7IGJvcmRlci1jb2xvcjogdmFyKC0tYWNjZW50KTsgY29sb3I6ICNmZmY7IH19CiAgICAucHJpbWFyeTpob3ZlciB7eyBiYWNrZ3JvdW5kOiB2YXIoLS1hY2NlbnQtMik7IGJvcmRlci1jb2xvcjogdmFyKC0tYWNjZW50LTIpOyB9fQogICAgLnN0YXR1cyB7ewogICAgICBtYXJnaW4tdG9wOiAxMnB4OwogICAgICBjb2xvcjogdmFyKC0tbXV0ZWQpOwogICAgICBmb250LXNpemU6IDEzcHg7CiAgICAgIG1pbi1oZWlnaHQ6IDEuNGVtOwogICAgfX0KICAgIC5vdXRwdXQge3sKICAgICAgd2hpdGUtc3BhY2U6IHByZS13cmFwOwogICAgICBiYWNrZ3JvdW5kOiAjMGIwYjBiOwogICAgICBib3JkZXI6IDFweCBzb2xpZCB2YXIoLS1saW5lKTsKICAgICAgYm9yZGVyLXJhZGl1czogMTZweDsKICAgICAgbWluLWhlaWdodDogMjgwcHg7CiAgICAgIHBhZGRpbmc6IDE2cHg7CiAgICAgIGNvbG9yOiAjZTdlNWU0OwogICAgICBvdmVyZmxvdzogYXV0bzsKICAgIH19CiAgICAubWV0YSB7ewogICAgICBkaXNwbGF5OiBmbGV4OwogICAgICBmbGV4LXdyYXA6IHdyYXA7CiAgICAgIGdhcDogOHB4OwogICAgICBtYXJnaW4tdG9wOiA4cHg7CiAgICB9fQogICAgLmNoaXAge3sKICAgICAgZGlzcGxheTogaW5saW5lLWZsZXg7CiAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgICAgIGdhcDogNnB4OwogICAgICBwYWRkaW5nOiA2cHggMTBweDsKICAgICAgYm9yZGVyLXJhZGl1czogOTk5cHg7CiAgICAgIGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWxpbmUpOwogICAgICBiYWNrZ3JvdW5kOiB2YXIoLS1wYW5lbC0yKTsKICAgICAgZm9udC1zaXplOiAxMnB4OwogICAgICBjb2xvcjogdmFyKC0tbXV0ZWQpOwogICAgfX0KICAgIC5jb2RlIHt7CiAgICAgIG1hcmdpbi10b3A6IDE0cHg7CiAgICAgIHBhZGRpbmc6IDEycHggMTRweDsKICAgICAgYm9yZGVyLXJhZGl1czogMTJweDsKICAgICAgYm9yZGVyOiAxcHggc29saWQgdmFyKC0tbGluZSk7CiAgICAgIGJhY2tncm91bmQ6ICMwYjBiMGI7CiAgICAgIGZvbnQtZmFtaWx5OiB1aS1tb25vc3BhY2UsIFNGTW9uby1SZWd1bGFyLCBNZW5sbywgTW9uYWNvLCBDb25zb2xhcywgbW9ub3NwYWNlOwogICAgICBmb250LXNpemU6IDEzcHg7CiAgICAgIG92ZXJmbG93LXg6IGF1dG87CiAgICB9fQogICAgQG1lZGlhIChtYXgtd2lkdGg6IDkwMHB4KSB7ewogICAgICAuZ3JpZCB7eyBncmlkLXRlbXBsYXRlLWNvbHVtbnM6IDFmcjsgfX0KICAgICAgLmhlcm8ge3sgYWxpZ24taXRlbXM6IHN0YXJ0OyBmbGV4LWRpcmVjdGlvbjogY29sdW1uOyB9fQogICAgfX0KICA8L3N0eWxlPgo8L2hlYWQ+Cjxib2R5PgogIDxkaXYgY2xhc3M9IndyYXAiPgogICAgPGRpdiBjbGFzcz0iaGVybyI+CiAgICAgIDxkaXY+CiAgICAgICAgPGgxPkNvbXBhY3RBSSBXZWI8L2gxPgogICAgICAgIDxwIGNsYXNzPSJzdWJ0aXRsZSI+UHVsbCBhIG1vZGVsIGZyb20gSHVnZ2luZyBGYWNlLCBrZWVwIGl0IGNhY2hlZCBsb2NhbGx5LCBhbmQgY2hhdCBpbiB0aGUgYnJvd3Nlci48L3A+CiAgICAgIDwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJtZXRhIj4KICAgICAgICA8c3BhbiBjbGFzcz0iY2hpcCI+SHVnZ2luZyBGYWNlOiBDb21wYWN0QUk8L3NwYW4+CiAgICAgICAgPHNwYW4gY2xhc3M9ImNoaXAiPnBpcCBpbnN0YWxsIC1yIHJlcXVpcmVtZW50cy50eHQ8L3NwYW4+CiAgICAgICAgPHNwYW4gY2xhc3M9ImNoaXAiPkxvY2FsIGluZmVyZW5jZTwvc3Bhbj4KICAgICAgPC9kaXY+CiAgICA8L2Rpdj4KCiAgICA8ZGl2IGNsYXNzPSJncmlkIj4KICAgICAgPHNlY3Rpb24gY2xhc3M9InBhbmVsIj4KICAgICAgICA8aDI+TW9kZWw8L2gyPgogICAgICAgIDxzZWxlY3QgaWQ9Im1vZGVsU2VsZWN0Ij48L3NlbGVjdD4KICAgICAgICA8ZGl2IGNsYXNzPSJyb3ciIHN0eWxlPSJtYXJnaW4tdG9wOiAxMHB4OyI+CiAgICAgICAgICA8bGFiZWwgY2xhc3M9ImNob2ljZSI+PGlucHV0IHR5cGU9InJhZGlvIiBuYW1lPSJ0eXBlIiB2YWx1ZT0ibW9kZWwiIGNoZWNrZWQ+IEluc3RydWN0IC8gZmluYWw8L2xhYmVsPgogICAgICAgICAgPGxhYmVsIGNsYXNzPSJjaG9pY2UiPjxpbnB1dCB0eXBlPSJyYWRpbyIgbmFtZT0idHlwZSIgdmFsdWU9InByZXRyYWluIj4gUHJldHJhaW48L2xhYmVsPgogICAgICAgIDwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImJ0bnMiIHN0eWxlPSJtYXJnaW4tdG9wOiAxMnB4OyI+CiAgICAgICAgICA8YnV0dG9uIGlkPSJkb3dubG9hZEJ0biI+RG93bmxvYWQ8L2J1dHRvbj4KICAgICAgICAgIDxidXR0b24gaWQ9InJlZnJlc2hCdG4iPlJlZnJlc2ggbW9kZWxzPC9idXR0b24+CiAgICAgICAgPC9kaXY+CiAgICAgICAgPGRpdiBjbGFzcz0ic3RhdHVzIiBpZD0ibW9kZWxTdGF0dXMiPkxvYWRpbmcgbW9kZWwgbGlzdOKApjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImNvZGUiPnB5dGhvbjMgaW50ZXJhY3RpdmVfd2ViLnB5PC9kaXY+CiAgICAgIDwvc2VjdGlvbj4KCiAgICAgIDxzZWN0aW9uIGNsYXNzPSJwYW5lbCI+CiAgICAgICAgPGgyPlByb21wdDwvaDI+CiAgICAgICAgPHRleHRhcmVhIGlkPSJwcm9tcHQiIHBsYWNlaG9sZGVyPSJBc2sgc29tZXRoaW5n4oCmIj48L3RleHRhcmVhPgogICAgICAgIDxkaXYgY2xhc3M9InJvdyIgc3R5bGU9Im1hcmdpbi10b3A6IDEwcHg7Ij4KICAgICAgICAgIDxpbnB1dCBpZD0idGVtcGVyYXR1cmUiIHR5cGU9Im51bWJlciIgbWluPSIwLjEiIG1heD0iMiIgc3RlcD0iMC4wNSIgdmFsdWU9IjAuOCIgc3R5bGU9ImZsZXg6IDEgMSAxMjBweDsiPgogICAgICAgICAgPGlucHV0IGlkPSJ0b3BLIiB0eXBlPSJudW1iZXIiIG1pbj0iMSIgbWF4PSIxMDAiIHN0ZXA9IjEiIHZhbHVlPSI0MCIgc3R5bGU9ImZsZXg6IDEgMSAxMjBweDsiPgogICAgICAgICAgPGlucHV0IGlkPSJtYXhUb2tlbnMiIHR5cGU9Im51bWJlciIgbWluPSIxNiIgbWF4PSIyMDQ4IiBzdGVwPSIxNiIgdmFsdWU9IjI1NiIgc3R5bGU9ImZsZXg6IDEgMSAxMjBweDsiPgogICAgICAgIDwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImJ0bnMiIHN0eWxlPSJtYXJnaW4tdG9wOiAxMnB4OyI+CiAgICAgICAgICA8YnV0dG9uIGlkPSJnZW5lcmF0ZUJ0biIgY2xhc3M9InByaW1hcnkiPkdlbmVyYXRlPC9idXR0b24+CiAgICAgICAgPC9kaXY+CiAgICAgICAgPGRpdiBjbGFzcz0ic3RhdHVzIiBpZD0iZ2VuU3RhdHVzIj48L2Rpdj4KICAgICAgPC9zZWN0aW9uPgogICAgPC9kaXY+CgogICAgPHNlY3Rpb24gY2xhc3M9InBhbmVsIiBzdHlsZT0ibWFyZ2luLXRvcDogMThweDsiPgogICAgICA8aDI+UmVzcG9uc2U8L2gyPgogICAgICA8ZGl2IGlkPSJvdXRwdXQiIGNsYXNzPSJvdXRwdXQiPjwvZGl2PgogICAgPC9zZWN0aW9uPgogIDwvZGl2PgoKICA8c2NyaXB0PgogICAgY29uc3QgbW9kZWxTZWxlY3QgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbW9kZWxTZWxlY3QnKTsKICAgIGNvbnN0IG1vZGVsU3RhdHVzID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ21vZGVsU3RhdHVzJyk7CiAgICBjb25zdCBnZW5TdGF0dXMgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ2VuU3RhdHVzJyk7CiAgICBjb25zdCBvdXRwdXQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnb3V0cHV0Jyk7CiAgICBjb25zdCBwcm9tcHRCb3ggPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncHJvbXB0Jyk7CgogICAgYXN5bmMgZnVuY3Rpb24gYXBpKHBhdGgsIGJvZHkpIHt7CiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2gocGF0aCwge3sKICAgICAgICBtZXRob2Q6IGJvZHkgPyAnUE9TVCcgOiAnR0VUJywKICAgICAgICBoZWFkZXJzOiBib2R5ID8ge3sgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyB9fSA6IHVuZGVmaW5lZCwKICAgICAgICBib2R5OiBib2R5ID8gSlNPTi5zdHJpbmdpZnkoYm9keSkgOiB1bmRlZmluZWQsCiAgICAgIH19KTsKICAgICAgcmV0dXJuIHJlc3BvbnNlLmpzb24oKTsKICAgIH19CgogICAgZnVuY3Rpb24gY3VycmVudFR5cGUoKSB7ewogICAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignaW5wdXRbbmFtZT0idHlwZSJdOmNoZWNrZWQnKS52YWx1ZTsKICAgIH19CgogICAgZnVuY3Rpb24gY3VycmVudE1vZGVsSWQoKSB7ewogICAgICByZXR1cm4gbW9kZWxTZWxlY3QudmFsdWU7CiAgICB9fQoKICAgIGZ1bmN0aW9uIHNldE1vZGVscyhtb2RlbHMpIHt7CiAgICAgIG1vZGVsU2VsZWN0LmlubmVySFRNTCA9ICcnOwogICAgICBmb3IgKGNvbnN0IG1vZGVsIG9mIG1vZGVscykge3sKICAgICAgICBjb25zdCBvcHRpb24gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdvcHRpb24nKTsKICAgICAgICBvcHRpb24udmFsdWUgPSBtb2RlbC5pZDsKICAgICAgICBvcHRpb24udGV4dENvbnRlbnQgPSBgJHt7bW9kZWwubmFtZX19IOKAoiAke3ttb2RlbC5zZXJpZXN9fWA7CiAgICAgICAgbW9kZWxTZWxlY3QuYXBwZW5kQ2hpbGQob3B0aW9uKTsKICAgICAgfX0KICAgICAgaWYgKG1vZGVscy5sZW5ndGggPT09IDApIHt7CiAgICAgICAgY29uc3Qgb3B0aW9uID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnb3B0aW9uJyk7CiAgICAgICAgb3B0aW9uLnZhbHVlID0gJyc7CiAgICAgICAgb3B0aW9uLnRleHRDb250ZW50ID0gJ05vIENvbXBhY3RBSSBtb2RlbHMgZm91bmQnOwogICAgICAgIG1vZGVsU2VsZWN0LmFwcGVuZENoaWxkKG9wdGlvbik7CiAgICAgIH19CiAgICB9fQoKICAgIGFzeW5jIGZ1bmN0aW9uIHJlZnJlc2hNb2RlbHMoKSB7ewogICAgICBtb2RlbFN0YXR1cy50ZXh0Q29udGVudCA9ICdMb2FkaW5nIG1vZGVsIGxpc3TigKYnOwogICAgICB0cnkge3sKICAgICAgICBjb25zdCBtb2RlbHMgPSBhd2FpdCBhcGkoJy9hcGkvbW9kZWxzJyk7CiAgICAgICAgc2V0TW9kZWxzKG1vZGVscyk7CiAgICAgICAgbW9kZWxTdGF0dXMudGV4dENvbnRlbnQgPSBtb2RlbHMubGVuZ3RoID8gYCR7e21vZGVscy5sZW5ndGh9fSBtb2RlbHMgYXZhaWxhYmxlIGZyb20gQ29tcGFjdEFJYCA6ICdObyBjb21wYXRpYmxlIG1vZGVscyBmb3VuZC4nOwogICAgICB9fSBjYXRjaCAoZXJyb3IpIHt7CiAgICAgICAgbW9kZWxTdGF0dXMudGV4dENvbnRlbnQgPSAnRmFpbGVkIHRvIGxvYWQgbW9kZWwgbGlzdC4nOwogICAgICB9fQogICAgfX0KCiAgICBhc3luYyBmdW5jdGlvbiBlbnN1cmVNb2RlbCgpIHt7CiAgICAgIGNvbnN0IG1vZGVsSWQgPSBjdXJyZW50TW9kZWxJZCgpOwogICAgICBpZiAoIW1vZGVsSWQpIHt7CiAgICAgICAgbW9kZWxTdGF0dXMudGV4dENvbnRlbnQgPSAnUGljayBhIG1vZGVsIGZpcnN0Lic7CiAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgIH19CiAgICAgIG1vZGVsU3RhdHVzLnRleHRDb250ZW50ID0gJ0Rvd25sb2FkaW5nIG1vZGVsIGZpbGVz4oCmJzsKICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYXBpKCcvYXBpL2Vuc3VyZScsIHt7IG1vZGVsSWQsIHR5cGU6IGN1cnJlbnRUeXBlKCkgfX0pOwogICAgICBpZiAoIXJlc3VsdC5zdWNjZXNzKSB7ewogICAgICAgIG1vZGVsU3RhdHVzLnRleHRDb250ZW50ID0gcmVzdWx0LmVycm9yIHx8ICdEb3dubG9hZCBmYWlsZWQuJzsKICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgfX0KICAgICAgbW9kZWxTdGF0dXMudGV4dENvbnRlbnQgPSBgJHt7cmVzdWx0Lm5hbWV9fSByZWFkeSBvbiAke3tyZXN1bHQuc2VyaWVzfX1gOwogICAgICByZXR1cm4gcmVzdWx0OwogICAgfX0KCiAgICBhc3luYyBmdW5jdGlvbiBnZW5lcmF0ZSgpIHt7CiAgICAgIG91dHB1dC50ZXh0Q29udGVudCA9ICcnOwogICAgICBnZW5TdGF0dXMudGV4dENvbnRlbnQgPSAnJzsKICAgICAgY29uc3QgbW9kZWxJZCA9IGN1cnJlbnRNb2RlbElkKCk7CiAgICAgIGNvbnN0IHByb21wdCA9IHByb21wdEJveC52YWx1ZS50cmltKCk7CiAgICAgIGlmICghbW9kZWxJZCkge3sKICAgICAgICBnZW5TdGF0dXMudGV4dENvbnRlbnQgPSAnUGljayBhIG1vZGVsIGZpcnN0Lic7CiAgICAgICAgcmV0dXJuOwogICAgICB9fQogICAgICBpZiAoIXByb21wdCkge3sKICAgICAgICBnZW5TdGF0dXMudGV4dENvbnRlbnQgPSAnRW50ZXIgYSBwcm9tcHQgZmlyc3QuJzsKICAgICAgICByZXR1cm47CiAgICAgIH19CiAgICAgIGdlblN0YXR1cy50ZXh0Q29udGVudCA9ICdQcmVwYXJpbmcgbW9kZWzigKYnOwogICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBhcGkoJy9hcGkvZ2VuZXJhdGUnLCB7ewogICAgICAgIG1vZGVsSWQsCiAgICAgICAgdHlwZTogY3VycmVudFR5cGUoKSwKICAgICAgICBwcm9tcHQsCiAgICAgICAgdGVtcGVyYXR1cmU6IE51bWJlcihkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndGVtcGVyYXR1cmUnKS52YWx1ZSB8fCAwLjgpLAogICAgICAgIHRvcF9rOiBOdW1iZXIoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3RvcEsnKS52YWx1ZSB8fCA0MCksCiAgICAgICAgbWF4X25ld190b2tlbnM6IE51bWJlcihkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbWF4VG9rZW5zJykudmFsdWUgfHwgMjU2KSwKICAgICAgfX0pOwogICAgICBpZiAoIXJlc3VsdC5zdWNjZXNzKSB7ewogICAgICAgIGdlblN0YXR1cy50ZXh0Q29udGVudCA9IHJlc3VsdC5lcnJvciB8fCAnR2VuZXJhdGlvbiBmYWlsZWQuJzsKICAgICAgICByZXR1cm47CiAgICAgIH19CiAgICAgIG91dHB1dC50ZXh0Q29udGVudCA9IHJlc3VsdC50ZXh0IHx8ICcnOwogICAgICBnZW5TdGF0dXMudGV4dENvbnRlbnQgPSAnRG9uZS4nOwogICAgfX0KCiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncmVmcmVzaEJ0bicpLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgcmVmcmVzaE1vZGVscyk7CiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZG93bmxvYWRCdG4nKS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGVuc3VyZU1vZGVsKTsKICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdnZW5lcmF0ZUJ0bicpLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZ2VuZXJhdGUpOwogICAgcHJvbXB0Qm94LmFkZEV2ZW50TGlzdGVuZXIoJ2tleWRvd24nLCAoZXZlbnQpID0+IHt7CiAgICAgIGlmIChldmVudC5rZXkgPT09ICdFbnRlcicgJiYgKGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleSkpIHt7CiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTsKICAgICAgICBnZW5lcmF0ZSgpOwogICAgICB9fQogICAgfX0pOwoKICAgIHJlZnJlc2hNb2RlbHMoKTsKICA8L3NjcmlwdD4KPC9ib2R5Pgo8L2h0bWw+IiIiCgoKY2xhc3MgSGFuZGxlcihCYXNlSFRUUFJlcXVlc3RIYW5kbGVyKToKICAgIGRlZiBfc2VuZF9qc29uKHNlbGYsIHBheWxvYWQsIHN0YXR1cz0yMDApOgogICAgICAgIGJvZHkgPSBqc29uLmR1bXBzKHBheWxvYWQpLmVuY29kZSgidXRmLTgiKQogICAgICAgIHNlbGYuc2VuZF9yZXNwb25zZShzdGF0dXMpCiAgICAgICAgc2VsZi5zZW5kX2hlYWRlcigiQ29udGVudC1UeXBlIiwgImFwcGxpY2F0aW9uL2pzb247IGNoYXJzZXQ9dXRmLTgiKQogICAgICAgIHNlbGYuc2VuZF9oZWFkZXIoIkNvbnRlbnQtTGVuZ3RoIiwgc3RyKGxlbihib2R5KSkpCiAgICAgICAgc2VsZi5zZW5kX2hlYWRlcigiQ2FjaGUtQ29udHJvbCIsICJuby1zdG9yZSIpCiAgICAgICAgc2VsZi5lbmRfaGVhZGVycygpCiAgICAgICAgc2VsZi53ZmlsZS53cml0ZShib2R5KQoKICAgIGRlZiBfc2VuZF9odG1sKHNlbGYsIHBheWxvYWQ6IHN0ciwgc3RhdHVzPTIwMCk6CiAgICAgICAgYm9keSA9IHBheWxvYWQuZW5jb2RlKCJ1dGYtOCIpCiAgICAgICAgc2VsZi5zZW5kX3Jlc3BvbnNlKHN0YXR1cykKICAgICAgICBzZWxmLnNlbmRfaGVhZGVyKCJDb250ZW50LVR5cGUiLCAidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04IikKICAgICAgICBzZWxmLnNlbmRfaGVhZGVyKCJDb250ZW50LUxlbmd0aCIsIHN0cihsZW4oYm9keSkpKQogICAgICAgIHNlbGYuc2VuZF9oZWFkZXIoIkNhY2hlLUNvbnRyb2wiLCAibm8tc3RvcmUiKQogICAgICAgIHNlbGYuZW5kX2hlYWRlcnMoKQogICAgICAgIHNlbGYud2ZpbGUud3JpdGUoYm9keSkKCiAgICBkZWYgZG9fR0VUKHNlbGYpOgogICAgICAgIHBhcnNlZCA9IHVybHBhcnNlKHNlbGYucGF0aCkKICAgICAgICBpZiBwYXJzZWQucGF0aCBpbiB7Ii8iLCAiL2luZGV4Lmh0bWwifToKICAgICAgICAgICAgc2VsZi5fc2VuZF9odG1sKHBhZ2VfaHRtbCgpKQogICAgICAgICAgICByZXR1cm4KICAgICAgICBpZiBwYXJzZWQucGF0aCA9PSAiL2FwaS9tb2RlbHMiOgogICAgICAgICAgICB0cnk6CiAgICAgICAgICAgICAgICBzZWxmLl9zZW5kX2pzb24obW9kZWxfbGlzdCgpKQogICAgICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGV4YzoKICAgICAgICAgICAgICAgIHNlbGYuX3NlbmRfanNvbih7InN1Y2Nlc3MiOiBGYWxzZSwgImVycm9yIjogc3RyKGV4Yyl9LCA1MDApCiAgICAgICAgICAgIHJldHVybgogICAgICAgIGlmIHBhcnNlZC5wYXRoLnN0YXJ0c3dpdGgoIi9hcGkvbW9kZWxzLyIpOgogICAgICAgICAgICByZXBvX2lkID0gbm9ybWFsaXplX3JlcG9faWQocGFyc2VkLnBhdGgucmVtb3ZlcHJlZml4KCIvYXBpL21vZGVscy8iKSkKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgZGV0YWlscyA9IG1vZGVsX2RldGFpbHMocmVwb19pZCkKICAgICAgICAgICAgICAgIGlmIG5vdCBkZXRhaWxzOgogICAgICAgICAgICAgICAgICAgIHNlbGYuX3NlbmRfanNvbigKICAgICAgICAgICAgICAgICAgICAgICAgeyJzdWNjZXNzIjogRmFsc2UsICJlcnJvciI6ICJNb2RlbCBub3QgZm91bmQuIn0sIDQwNAogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAgICAgc2VsZi5fc2VuZF9qc29uKGRldGFpbHMpCiAgICAgICAgICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZXhjOgogICAgICAgICAgICAgICAgc2VsZi5fc2VuZF9qc29uKHsic3VjY2VzcyI6IEZhbHNlLCAiZXJyb3IiOiBzdHIoZXhjKX0sIDUwMCkKICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgc2VsZi5fc2VuZF9qc29uKHsic3VjY2VzcyI6IEZhbHNlLCAiZXJyb3IiOiAiTm90IGZvdW5kLiJ9LCA0MDQpCgogICAgZGVmIGRvX1BPU1Qoc2VsZik6CiAgICAgICAgcGFyc2VkID0gdXJscGFyc2Uoc2VsZi5wYXRoKQogICAgICAgIGxlbmd0aCA9IGludChzZWxmLmhlYWRlcnMuZ2V0KCJDb250ZW50LUxlbmd0aCIsICIwIikgb3IgIjAiKQogICAgICAgIHJhdyA9IHNlbGYucmZpbGUucmVhZChsZW5ndGgpLmRlY29kZSgidXRmLTgiKSBpZiBsZW5ndGggZWxzZSAie30iCiAgICAgICAgdHJ5OgogICAgICAgICAgICBwYXlsb2FkID0ganNvbi5sb2FkcyhyYXcgb3IgInt9IikKICAgICAgICBleGNlcHQgRXhjZXB0aW9uOgogICAgICAgICAgICBwYXlsb2FkID0ge30KICAgICAgICBpZiBwYXJzZWQucGF0aCA9PSAiL2FwaS9lbnN1cmUiOgogICAgICAgICAgICB0cnk6CiAgICAgICAgICAgICAgICByZXBvX2lkID0gbm9ybWFsaXplX3JlcG9faWQocGF5bG9hZC5nZXQoIm1vZGVsSWQiLCAiIikpCiAgICAgICAgICAgICAgICBtb2RlbF90eXBlID0gcGF5bG9hZC5nZXQoInR5cGUiLCAibW9kZWwiKQogICAgICAgICAgICAgICAgaWYgbm90IHJlcG9faWQ6CiAgICAgICAgICAgICAgICAgICAgc2VsZi5fc2VuZF9qc29uKAogICAgICAgICAgICAgICAgICAgICAgICB7InN1Y2Nlc3MiOiBGYWxzZSwgImVycm9yIjogIk1pc3NpbmcgbW9kZWwgSUQuIn0sIDQwMAogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICByZXR1cm4KICAgICAgICAgICAgICAgIGRldGFpbHMgPSBtb2RlbF9kZXRhaWxzKHJlcG9faWQpCiAgICAgICAgICAgICAgICBpZiBub3QgZGV0YWlsczoKICAgICAgICAgICAgICAgICAgICBzZWxmLl9zZW5kX2pzb24oCiAgICAgICAgICAgICAgICAgICAgICAgIHsic3VjY2VzcyI6IEZhbHNlLCAiZXJyb3IiOiAiTW9kZWwgbm90IGZvdW5kLiJ9LCA0MDQKICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgICAgICAgICBidW5kbGUgPSBsb2FkX2J1bmRsZShyZXBvX2lkLCBtb2RlbF90eXBlKQogICAgICAgICAgICAgICAgc2VsZi5fc2VuZF9qc29uKAogICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgInN1Y2Nlc3MiOiBUcnVlLAogICAgICAgICAgICAgICAgICAgICAgICAiaWQiOiBidW5kbGVbInJlcG9faWQiXSwKICAgICAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiBidW5kbGVbIm5hbWUiXSwKICAgICAgICAgICAgICAgICAgICAgICAgInNlcmllcyI6IGJ1bmRsZVsic2VyaWVzIl0sCiAgICAgICAgICAgICAgICAgICAgICAgICJ0eXBlIjogYnVuZGxlWyJ0eXBlIl0sCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGV4YzoKICAgICAgICAgICAgICAgIHNlbGYuX3NlbmRfanNvbih7InN1Y2Nlc3MiOiBGYWxzZSwgImVycm9yIjogc3RyKGV4Yyl9LCA1MDApCiAgICAgICAgICAgIHJldHVybgogICAgICAgIGlmIHBhcnNlZC5wYXRoID09ICIvYXBpL2dlbmVyYXRlIjoKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgcmVwb19pZCA9IG5vcm1hbGl6ZV9yZXBvX2lkKHBheWxvYWQuZ2V0KCJtb2RlbElkIiwgIiIpKQogICAgICAgICAgICAgICAgbW9kZWxfdHlwZSA9IHBheWxvYWQuZ2V0KCJ0eXBlIiwgIm1vZGVsIikKICAgICAgICAgICAgICAgIHByb21wdCA9IHN0cihwYXlsb2FkLmdldCgicHJvbXB0IiwgIiIpKQogICAgICAgICAgICAgICAgaWYgbm90IHJlcG9faWQ6CiAgICAgICAgICAgICAgICAgICAgc2VsZi5fc2VuZF9qc29uKAogICAgICAgICAgICAgICAgICAgICAgICB7InN1Y2Nlc3MiOiBGYWxzZSwgImVycm9yIjogIk1pc3NpbmcgbW9kZWwgSUQuIn0sIDQwMAogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICByZXR1cm4KICAgICAgICAgICAgICAgIGJ1bmRsZSA9IGxvYWRfYnVuZGxlKHJlcG9faWQsIG1vZGVsX3R5cGUpCiAgICAgICAgICAgICAgICB3aXRoIEdFTkVSQVRJT05fTE9DSzoKICAgICAgICAgICAgICAgICAgICB0ZXh0ID0gZ2VuZXJhdGUoCiAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsPWJ1bmRsZVsibW9kZWwiXSwKICAgICAgICAgICAgICAgICAgICAgICAgdG9rZW5pemVyPWJ1bmRsZVsidG9rZW5pemVyIl0sCiAgICAgICAgICAgICAgICAgICAgICAgIHByb21wdD1wcm9tcHQsCiAgICAgICAgICAgICAgICAgICAgICAgIG1heF9uZXdfdG9rZW5zPWludChwYXlsb2FkLmdldCgibWF4X25ld190b2tlbnMiLCAyNTYpKSwKICAgICAgICAgICAgICAgICAgICAgICAgdGVtcGVyYXR1cmU9ZmxvYXQocGF5bG9hZC5nZXQoInRlbXBlcmF0dXJlIiwgMC44KSksCiAgICAgICAgICAgICAgICAgICAgICAgIHRvcF9rPWludChwYXlsb2FkLmdldCgidG9wX2siLCA0MCkpLAogICAgICAgICAgICAgICAgICAgICAgICByZXBldGl0aW9uX3BlbmFsdHk9ZmxvYXQoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXlsb2FkLmdldCgicmVwZXRpdGlvbl9wZW5hbHR5IiwgMS4wKQogICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICBkZXZpY2U9c3RyKGJ1bmRsZVsiZGV2aWNlIl0pLAogICAgICAgICAgICAgICAgICAgICAgICBzZnRfbW9kZT1tb2RlbF90eXBlICE9ICJwcmV0cmFpbiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGZvcmNlX3Rob3VnaHQ9Ym9vbChwYXlsb2FkLmdldCgiZm9yY2VfdGhvdWdodCIsIEZhbHNlKSksCiAgICAgICAgICAgICAgICAgICAgICAgIHN0cmVhbT1GYWxzZSwKICAgICAgICAgICAgICAgICAgICAgICAgZGVjb2RlX21vZGU9c3RyKHBheWxvYWQuZ2V0KCJkZWNvZGVfbW9kZSIsICJsZWdhY3kiKSksCiAgICAgICAgICAgICAgICAgICAgICAgIGJlc3Rfb2Y9aW50KHBheWxvYWQuZ2V0KCJiZXN0X29mIiwgMykpLAogICAgICAgICAgICAgICAgICAgICAgICBub19yZXBlYXRfbmdyYW1fc2l6ZT1pbnQoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXlsb2FkLmdldCgibm9fcmVwZWF0X25ncmFtX3NpemUiLCAzKQogICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0X3dpbmRvdz1pbnQocGF5bG9hZC5nZXQoImNvbnRleHRfd2luZG93IiwgMjA0OCkpLAogICAgICAgICAgICAgICAgICAgICAgICBiZWFtX3dpZHRoPWludChwYXlsb2FkLmdldCgiYmVhbV93aWR0aCIsIDgpKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoX3BlbmFsdHk9ZmxvYXQocGF5bG9hZC5nZXQoImxlbmd0aF9wZW5hbHR5IiwgMC43KSksCiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgc2VsZi5fc2VuZF9qc29uKAogICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgInN1Y2Nlc3MiOiBUcnVlLAogICAgICAgICAgICAgICAgICAgICAgICAidGV4dCI6IHRleHQsCiAgICAgICAgICAgICAgICAgICAgICAgICJuYW1lIjogYnVuZGxlWyJuYW1lIl0sCiAgICAgICAgICAgICAgICAgICAgICAgICJzZXJpZXMiOiBidW5kbGVbInNlcmllcyJdLAogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBleGM6CiAgICAgICAgICAgICAgICBzZWxmLl9zZW5kX2pzb24oeyJzdWNjZXNzIjogRmFsc2UsICJlcnJvciI6IHN0cihleGMpfSwgNTAwKQogICAgICAgICAgICByZXR1cm4KICAgICAgICBzZWxmLl9zZW5kX2pzb24oeyJzdWNjZXNzIjogRmFsc2UsICJlcnJvciI6ICJOb3QgZm91bmQuIn0sIDQwNCkKCiAgICBkZWYgbG9nX21lc3NhZ2Uoc2VsZiwgZm9ybWF0LCAqYXJncyk6CiAgICAgICAgcmV0dXJuCgoKZGVmIG1haW4oKToKICAgIENBQ0hFX1JPT1QubWtkaXIocGFyZW50cz1UcnVlLCBleGlzdF9vaz1UcnVlKQogICAgcG9ydCA9IGVuc3VyZV9wb3J0KGludChvcy5lbnZpcm9uLmdldCgiUE9SVCIsICI3ODYwIikpKQogICAgc2VydmVyID0gVGhyZWFkaW5nSFRUUFNlcnZlcigoIjEyNy4wLjAuMSIsIHBvcnQpLCBIYW5kbGVyKQogICAgdXJsID0gZiJodHRwOi8vMTI3LjAuMC4xOntwb3J0fSIKICAgIHByaW50KHVybCwgZmx1c2g9VHJ1ZSkKICAgIHRyeToKICAgICAgICB3ZWJicm93c2VyLm9wZW4odXJsKQogICAgZXhjZXB0IEV4Y2VwdGlvbjoKICAgICAgICBwYXNzCiAgICB0cnk6CiAgICAgICAgc2VydmVyLnNlcnZlX2ZvcmV2ZXIoKQogICAgZXhjZXB0IEtleWJvYXJkSW50ZXJydXB0OgogICAgICAgIHBhc3MKICAgIGZpbmFsbHk6CiAgICAgICAgc2VydmVyLnNlcnZlcl9jbG9zZSgpCgoKaWYgX19uYW1lX18gPT0gIl9fbWFpbl9fIjoKICAgIG1haW4oKQo=";
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>