Files
MH-DashBoard-organization/incoming-files/사업관리대장/MH 통합 대시보드_260320.html
2026-03-31 17:52:27 +09:00

2599 lines
381 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>total</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Pretendard:wght@400;600;700;900&display=swap');
:root {
--bg: #f1eadf;
--panel: #fffaf3;
--panel-soft: #f4e9d7;
--ink: #10251d;
--muted: #66756d;
--line: #d9c5a8;
--brand: #0f3a2f;
--brand-deep: #0a2a22;
--brand-soft: #1a5645;
--accent: #d68a3a;
--accent-soft: #f2c484;
--mint: #2f9973;
--shadow: 0 22px 54px rgba(15, 58, 47, 0.12);
--hero-shadow: 0 28px 60px rgba(15, 58, 47, 0.2);
}
html { font-size: 14px; }
body {
margin: 0;
font-family: 'Pretendard', sans-serif;
font-size: 1rem;
line-height: 1.45;
letter-spacing: -0.02em;
color: var(--ink);
background:
radial-gradient(circle at top left, rgba(214, 138, 58, 0.18), transparent 24%),
radial-gradient(circle at top right, rgba(47, 153, 115, 0.12), transparent 22%),
linear-gradient(180deg, #f6efe6 0%, var(--bg) 100%);
}
input, select, button, textarea { font: inherit; }
.top-wrap {
position: sticky;
top: 0;
z-index: 1000;
padding: 16px 22px 12px;
background: transparent;
}
.control-bar {
max-width: 1700px;
margin: 0 auto;
display: flex;
justify-content: space-between;
align-items: center;
gap: 14px;
min-height: 74px;
padding: 14px 18px;
border-radius: 28px;
background:
radial-gradient(circle at 12% 18%, rgba(242, 196, 132, 0.16), transparent 24%),
radial-gradient(circle at 88% 12%, rgba(255, 255, 255, 0.08), transparent 18%),
linear-gradient(145deg, var(--brand-deep) 0%, var(--brand) 52%, var(--brand-soft) 100%);
box-shadow: var(--hero-shadow);
border: 1px solid rgba(255,255,255,0.08);
}
.tab-btn {
font-size: 13px;
font-weight: 900;
padding: 10px 16px;
border-radius: 999px;
border: 1px solid rgba(242, 196, 132, 0.24);
color: rgba(244, 239, 230, 0.92);
background: rgba(255,255,255,0.08);
box-shadow: inset 0 1px 0 rgba(255,255,255,0.06);
transition: all .18s ease;
}
.tab-btn:hover { background: rgba(242, 196, 132, 0.14); border-color: rgba(242, 196, 132, 0.42); }
.tab-btn.active {
background: linear-gradient(180deg, #fff8ee 0%, #f2dec0 100%);
color: var(--brand-deep);
border-color: rgba(242, 196, 132, 0.54);
box-shadow: 0 10px 24px rgba(10, 42, 34, 0.16);
}
.tab-btn.uploaded {
background: rgba(255,255,255,0.14);
color: #fff8ee;
border-color: rgba(141, 209, 180, 0.34);
box-shadow: 0 8px 18px rgba(10, 42, 34, 0.14);
}
.tab-wrap { display: inline-flex; align-items: center; gap: 8px; }
.pane { display: none; padding: 0 22px 22px; }
.pane.active { display: block; }
.frame {
width: 100%;
height: calc(100vh - 124px);
border: 0;
background: var(--panel);
border-radius: 26px;
box-shadow: var(--shadow);
overflow: hidden;
}
.date-box {
display: inline-flex;
align-items: center;
gap: 8px;
font-size: 13px;
font-weight: 800;
padding: 9px 12px;
border: 1px solid rgba(242, 196, 132, 0.22);
border-radius: 18px;
background: rgba(255,255,255,0.12);
color: #f3eadb;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.06);
}
.date-input { border: none; outline: none; font-size: 13px; font-weight: 800; color: #fff8ee; background: transparent; }
.year-shortcuts { display: inline-flex; align-items: center; gap: 6px; margin-left: 6px; padding-left: 10px; border-left: 1px solid rgba(255,255,255,0.14); flex-wrap: wrap; }
.year-chip {
border: 1px solid rgba(255,255,255,0.14);
background: rgba(255,255,255,0.08);
color: #f0e7d7;
border-radius: 999px;
padding: 6px 11px;
font-size: 12px;
font-weight: 900;
line-height: 1;
transition: all .18s ease;
}
.year-chip:hover { border-color: rgba(242,196,132,0.42); color: #fff9ef; background: rgba(242,196,132,0.14); }
.year-chip.active {
background: linear-gradient(180deg, #fff8ee 0%, #f2dec0 100%);
color: var(--brand-deep);
border-color: rgba(242, 196, 132, 0.54);
box-shadow: 0 8px 18px rgba(10, 42, 34, 0.16);
}
@media (max-width: 1200px) {
.control-bar { flex-direction: column; align-items: stretch; }
.tab-wrap { flex-wrap: wrap; }
.date-box { width: 100%; justify-content: flex-start; flex-wrap: wrap; }
.year-shortcuts { width: 100%; margin-left: 0; padding-left: 0; border-left: 0; padding-top: 6px; }
.frame { height: calc(100vh - 180px); }
}
@media (max-width: 720px) {
.top-wrap { padding: 14px 14px 10px; }
.pane { padding: 0 14px 16px; }
.control-bar { padding: 14px; border-radius: 24px; }
}
</style>
</head>
<body>
<input id="upload-business" type="file" accept=".csv,.xlsx,.xls" class="hidden" />
<input id="upload-expense" type="file" accept=".csv" class="hidden" />
<input id="upload-work" type="file" accept=".csv,.xlsx,.xls" class="hidden" />
<div class="top-wrap">
<div class="control-bar">
<div class="tab-wrap">
<button id="btn-tab-business" class="tab-btn active" type="button">사업관리대장</button>
<button id="btn-tab-dash" class="tab-btn" type="button">프로젝트별 분석</button>
<button id="btn-tab-mh" class="tab-btn" type="button">팀/개인별 분석</button>
</div>
<div class="flex flex-wrap items-center gap-2">
<div id="date-controls" class="date-box hidden">
<span class="text-indigo-600">기간</span>
<input id="global-start-date" type="date" class="date-input" value="2026-01-01" />
<span class="text-slate-300">~</span>
<input id="global-end-date" type="date" class="date-input" value="2026-01-31" />
<div id="year-shortcuts" class="year-shortcuts"></div>
</div>
<button id="btn-upload-business" class="tab-btn" type="button">사업관리대장-1 업로드</button>
<button id="btn-upload-expense" class="tab-btn" type="button">전표 데이터 업로드</button>
<button id="btn-upload-work" class="tab-btn" type="button">MH 데이터 업로드</button>
</div>
</div>
</div>
<section id="pane-business" class="pane active">
<iframe id="frame-business" class="frame"></iframe>
</section>
<section id="pane-dash" class="pane">
<iframe id="frame-dash" class="frame"></iframe>
</section>
<section id="pane-mh" class="pane">
<iframe id="frame-mh" class="frame"></iframe>
</section>
<script>
const paneBusiness = document.getElementById('pane-business');
const paneDash = document.getElementById('pane-dash');
const paneMh = document.getElementById('pane-mh');
const btnTabBusiness = document.getElementById('btn-tab-business');
const btnTabDash = document.getElementById('btn-tab-dash');
const btnTabMh = document.getElementById('btn-tab-mh');
const frameBusiness = document.getElementById('frame-business');
const frameDash = document.getElementById('frame-dash');
const frameMh = document.getElementById('frame-mh');
const BUSINESS_HTML_B64='PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9ImtvIj4KPGhlYWQ+CiAgPG1ldGEgY2hhcnNldD0iVVRGLTgiIC8+CiAgPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xLjAiIC8+CiAgPHRpdGxlPuyCrOyXheq0gOumrOuMgOyepSBEYXNoYm9hcmQ8L3RpdGxlPgogIDxzdHlsZT4KICAgICp7Ym94LXNpemluZzpib3JkZXItYm94fWJvZHl7bWFyZ2luOjA7YmFja2dyb3VuZDojZjhmYWZjO2NvbG9yOiMwZjE3MmE7Zm9udC1mYW1pbHk6J1ByZXRlbmRhcmQnLCdOb3RvIFNhbnMgS1InLCdNYWxndW4gR290aGljJyxzYW5zLXNlcmlmfQogICAgLndyYXB7bWF4LXdpZHRoOjE2MDBweDttYXJnaW46MCBhdXRvO3BhZGRpbmc6MjBweH0KICAgIC50b3B7ZGlzcGxheTpncmlkO2dyaWQtdGVtcGxhdGUtY29sdW1uczoxZnIgbWlubWF4KDI2MHB4LDUyMHB4KTtnYXA6MTJweDthbGlnbi1pdGVtczplbmR9CiAgICAudGl0bGV7Zm9udC1zaXplOjM0cHg7Zm9udC13ZWlnaHQ6OTAwO2xldHRlci1zcGFjaW5nOi0uMDNlbTttYXJnaW46MH0KICAgIC5zdWJ7Zm9udC1zaXplOjEycHg7Y29sb3I6IzY0NzQ4Yjtmb250LXdlaWdodDo4MDA7bGV0dGVyLXNwYWNpbmc6LjA4ZW07dGV4dC10cmFuc2Zvcm06dXBwZXJjYXNlfQogICAgLmNvbnRyb2xze2Rpc3BsYXk6ZmxleDtnYXA6OHB4O2p1c3RpZnktY29udGVudDpmbGV4LWVuZDtmbGV4LXdyYXA6d3JhcH0KICAgIC5idG57Ym9yZGVyOjFweCBzb2xpZCAjMjU2M2ViO2JhY2tncm91bmQ6IzI1NjNlYjtjb2xvcjojZmZmO2JvcmRlci1yYWRpdXM6MTJweDtwYWRkaW5nOjEwcHggMTRweDtmb250LXNpemU6MTNweDtmb250LXdlaWdodDo4MDA7Y3Vyc29yOnBvaW50ZXJ9CiAgICAuc2VhcmNoe2ZsZXg6MTttaW4td2lkdGg6MjUwcHg7Ym9yZGVyOjFweCBzb2xpZCAjZTJlOGYwO2JvcmRlci1yYWRpdXM6MTJweDtwYWRkaW5nOjEwcHggMTJweDtmb250LXNpemU6MTNweDtmb250LXdlaWdodDo3MDB9CiAgICAuc3RhdHVze21hcmdpbjoxMHB4IDAgMTRweDtmb250LXNpemU6MTJweDtmb250LXdlaWdodDo3MDA7Y29sb3I6IzY0NzQ4Yn0KICAgIC5jYXJkc3tkaXNwbGF5OmdyaWQ7Z3JpZC10ZW1wbGF0ZS1jb2x1bW5zOnJlcGVhdCg1LG1pbm1heCgxNTBweCwxZnIpKTtnYXA6MTBweDttYXJnaW4tYm90dG9tOjEycHh9CiAgICAuY2FyZHtiYWNrZ3JvdW5kOiNmZmY7Ym9yZGVyOjFweCBzb2xpZCAjZTJlOGYwO2JvcmRlci1yYWRpdXM6MTRweDtwYWRkaW5nOjEwcHggMTJweH0KICAgIC5jYXJkIC5re2ZvbnQtc2l6ZToxMXB4O2ZvbnQtd2VpZ2h0OjgwMDtjb2xvcjojNjQ3NDhifQogICAgLmNhcmQgLnZ7Zm9udC1zaXplOjE5cHg7Zm9udC13ZWlnaHQ6OTAwO3doaXRlLXNwYWNlOm5vd3JhcH0KICAgIC5wYW5lbHtiYWNrZ3JvdW5kOiNmZmY7Ym9yZGVyOjFweCBzb2xpZCAjZTJlOGYwO2JvcmRlci1yYWRpdXM6MjBweDtvdmVyZmxvdzpoaWRkZW59CiAgICAudGFibGUtd3JhcHtvdmVyZmxvdzphdXRvfQogICAgdGFibGV7d2lkdGg6MTAwJTttaW4td2lkdGg6MTI1MHB4O2JvcmRlci1jb2xsYXBzZTpjb2xsYXBzZX0KICAgIHRoZWFkIHRoe2JhY2tncm91bmQ6IzBmMTcyYTtjb2xvcjojZmZmZmZmZDE7Zm9udC1zaXplOjExcHg7dGV4dC10cmFuc2Zvcm06dXBwZXJjYXNlO2xldHRlci1zcGFjaW5nOi4xMmVtO3BhZGRpbmc6MTJweCAxMHB4O3RleHQtYWxpZ246bGVmdDt3aGl0ZS1zcGFjZTpub3dyYXA7dmVydGljYWwtYWxpZ246bWlkZGxlfQogICAgLnRoLWhlYWR7cG9zaXRpb246cmVsYXRpdmU7ZGlzcGxheTpmbGV4O2FsaWduLWl0ZW1zOmNlbnRlcn0KICAgIC50aC1oZWFkLmVuZHtqdXN0aWZ5LWNvbnRlbnQ6ZmxleC1lbmR9CiAgICAudGgtdHJpZ2dlcntkaXNwbGF5OmlubGluZS1mbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtnYXA6NnB4O2JvcmRlcjowO2JhY2tncm91bmQ6bm9uZTtwYWRkaW5nOjA7Y29sb3I6I2ZmZmZmZmQxO2ZvbnQ6aW5oZXJpdDtmb250LXdlaWdodDo5MDA7bGV0dGVyLXNwYWNpbmc6aW5oZXJpdDt0ZXh0LXRyYW5zZm9ybTppbmhlcml0O2N1cnNvcjpwb2ludGVyfQogICAgLnRoLXRyaWdnZXI6aG92ZXIsLnRoLXRyaWdnZXIuYWN0aXZlLC50aC10cmlnZ2VyLm9wZW57Y29sb3I6I2ZmZn0KICAgIC50aC10aXRsZXtkaXNwbGF5OmlubGluZS1ibG9ja30KICAgIC50aC1tZXRhe2ZvbnQtc2l6ZToxMHB4O2NvbG9yOiM5M2M1ZmQ7Zm9udC13ZWlnaHQ6ODAwO2xldHRlci1zcGFjaW5nOjA7dGV4dC10cmFuc2Zvcm06bm9uZX0KICAgIC50aC1tYXJre2Rpc3BsYXk6aW5saW5lLWZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2p1c3RpZnktY29udGVudDpjZW50ZXI7bWluLXdpZHRoOjhweDtjb2xvcjojNjBhNWZhO2ZvbnQtc2l6ZToxMnB4O2xpbmUtaGVpZ2h0OjF9CiAgICAudGgtY2FyZXR7Zm9udC1zaXplOjEwcHg7Y29sb3I6IzkzYzVmZDt0cmFuc2l0aW9uOnRyYW5zZm9ybSAuMTVzIGVhc2V9CiAgICAudGgtdHJpZ2dlci5vcGVuIC50aC1jYXJldHt0cmFuc2Zvcm06cm90YXRlKDE4MGRlZyl9CiAgICAudGgtbWVudXtwb3NpdGlvbjphYnNvbHV0ZTt0b3A6Y2FsYygxMDAlICsgOHB4KTtsZWZ0OjA7ZGlzcGxheTpub25lO21pbi13aWR0aDoxODBweDttYXgtd2lkdGg6MzIwcHg7bWF4LWhlaWdodDoyODBweDtvdmVyZmxvdzphdXRvO3BhZGRpbmc6NnB4O2JhY2tncm91bmQ6I2ZmZjtib3JkZXI6MXB4IHNvbGlkICNjYmQ1ZTE7Ym9yZGVyLXJhZGl1czoxMnB4O2JveC1zaGFkb3c6MCAxNnB4IDQwcHggIzBmMTcyYTI2O3otaW5kZXg6MTV9CiAgICAudGgtaGVhZC5lbmQgLnRoLW1lbnV7bGVmdDphdXRvO3JpZ2h0OjB9CiAgICAudGgtbWVudS5vcGVue2Rpc3BsYXk6YmxvY2t9CiAgICAudGgtb3B0aW9ue2Rpc3BsYXk6YmxvY2s7d2lkdGg6MTAwJTtib3JkZXI6MDtiYWNrZ3JvdW5kOm5vbmU7Ym9yZGVyLXJhZGl1czo4cHg7cGFkZGluZzo5cHggMTBweDt0ZXh0LWFsaWduOmxlZnQ7Zm9udC1zaXplOjEycHg7Zm9udC13ZWlnaHQ6NzAwO2NvbG9yOiMwZjE3MmE7Y3Vyc29yOnBvaW50ZXI7d2hpdGUtc3BhY2U6bm9ybWFsO3dvcmQtYnJlYWs6YnJlYWstd29yZH0KICAgIC50aC1vcHRpb246aG92ZXJ7YmFja2dyb3VuZDojZWZmNmZmfQogICAgLnRoLW9wdGlvbi5hY3RpdmV7YmFja2dyb3VuZDojZGJlYWZlO2NvbG9yOiMxZDRlZDh9CiAgICB0Ym9keSB0ZHtwYWRkaW5nOjEycHg7Ym9yZGVyLWJvdHRvbToxcHggc29saWQgI2YxZjVmOTtmb250LXNpemU6MTNweDt3aGl0ZS1zcGFjZTpub3dyYXA7dmVydGljYWwtYWxpZ246bWlkZGxlfQogICAgdGJvZHkgdHI6aG92ZXJ7YmFja2dyb3VuZDojZWZmNmZmfQogICAgdGJvZHkgdHIuc2V0dGxlZHtiYWNrZ3JvdW5kOiNmOGZhZmM7Y29sb3I6Izk0YTNiOH0KICAgIHRib2R5IHRyLnNldHRsZWQ6aG92ZXJ7YmFja2dyb3VuZDojZjFmNWY5fQogICAgdGJvZHkgdHIuc2V0dGxlZCAubmFtZSx0Ym9keSB0ci5zZXR0bGVkIHN0cm9uZ3tjb2xvcjojNjQ3NDhifQogICAgdGJvZHkgdHIuc2V0dGxlZCAuYmFkZ2V7Ym9yZGVyLWNvbG9yOiNjYmQ1ZTE7YmFja2dyb3VuZDojZjhmYWZjO2NvbG9yOiM2NDc0OGJ9CiAgICAubnVte3RleHQtYWxpZ246cmlnaHQ7Zm9udC12YXJpYW50LW51bWVyaWM6dGFidWxhci1udW1zfQogICAgLm5hbWV7Zm9udC13ZWlnaHQ6ODAwO21heC13aWR0aDo0NjBweDtvdmVyZmxvdzpoaWRkZW47dGV4dC1vdmVyZmxvdzplbGxpcHNpc30KICAgIC5zdWJsaW5le2ZvbnQtc2l6ZToxMXB4O2NvbG9yOiM5NGEzYjg7Zm9udC13ZWlnaHQ6NzAwO21hcmdpbi10b3A6M3B4fQogICAgLmJhZGdle2Rpc3BsYXk6aW5saW5lLWZsZXg7cGFkZGluZzozcHggOXB4O2JvcmRlci1yYWRpdXM6OTk5cHg7Ym9yZGVyOjFweCBzb2xpZCAjYmZkYmZlO2JhY2tncm91bmQ6I2VmZjZmZjtjb2xvcjojMWQ0ZWQ4O2ZvbnQtc2l6ZToxMXB4O2ZvbnQtd2VpZ2h0OjkwMH0KICAgIC5iYWRnZS5va3tib3JkZXItY29sb3I6I2JiZjdkMDtiYWNrZ3JvdW5kOiNmMGZkZjQ7Y29sb3I6IzA0Nzg1N30KICAgIC5lbXB0eXtkaXNwbGF5Om5vbmU7cGFkZGluZzozMnB4O3RleHQtYWxpZ246Y2VudGVyO2NvbG9yOiM5NGEzYjg7Zm9udC13ZWlnaHQ6ODAwfQogICAgLmhpZGRlbntkaXNwbGF5Om5vbmV9CiAgICAubW9kYWx7cG9zaXRpb246Zml4ZWQ7aW5zZXQ6MDtiYWNrZ3JvdW5kOiMwMjA2MTdiZjtiYWNrZHJvcC1maWx0ZXI6Ymx1cig0cHgpO2Rpc3BsYXk6bm9uZTthbGlnbi1pdGVtczpjZW50ZXI7anVzdGlmeS1jb250ZW50OmNlbnRlcjtwYWRkaW5nOjE2cHg7ei1pbmRleDozMH0KICAgIC5tb2RhbC5zaG93e2Rpc3BsYXk6ZmxleH0KICAgIC5tb2RhbC1jYXJke3dpZHRoOm1pbigxMjAwcHgsMTAwJSk7bWF4LWhlaWdodDo5MHZoO292ZXJmbG93OmF1dG87YmFja2dyb3VuZDojZmZmO2JvcmRlci1yYWRpdXM6MjRweDtib3JkZXI6MXB4IHNvbGlkICNlMmU4ZjB9CiAgICAubS10b3B7cGFkZGluZzoyMHB4O2JvcmRlci1ib3R0b206MXB4IHNvbGlkICNmMWY1Zjk7YmFja2dyb3VuZDojZjhmYWZjO2Rpc3BsYXk6ZmxleDtqdXN0aWZ5LWNvbnRlbnQ6c3BhY2UtYmV0d2VlbjtnYXA6MTBweH0KICAgIC54e3dpZHRoOjQycHg7aGVpZ2h0OjQycHg7Ym9yZGVyOjFweCBzb2xpZCAjZTJlOGYwO2JvcmRlci1yYWRpdXM6MTJweDtiYWNrZ3JvdW5kOiNmZmY7Zm9udC1zaXplOjIycHg7Zm9udC13ZWlnaHQ6OTAwO2NvbG9yOiM2NDc0OGI7Y3Vyc29yOnBvaW50ZXJ9CiAgICAubS1ib2R5e3BhZGRpbmc6MThweDtkaXNwbGF5OmdyaWQ7Z3JpZC10ZW1wbGF0ZS1jb2x1bW5zOjEuNWZyIDFmcjtnYXA6MTJweH0KICAgIC5zZWN7Ym9yZGVyOjFweCBzb2xpZCAjZTJlOGYwO2JvcmRlci1yYWRpdXM6MTZweDtwYWRkaW5nOjEycHh9CiAgICAuc2VjLmRhcmt7YmFja2dyb3VuZDojMGYxNzJhO2NvbG9yOiNmZmY7Ym9yZGVyLWNvbG9yOiMwZjE3MmF9CiAgICAuZ3JpZDN7ZGlzcGxheTpncmlkO2dyaWQtdGVtcGxhdGUtY29sdW1uczpyZXBlYXQoMyxtaW5tYXgoMTAwcHgsMWZyKSk7Z2FwOjhweH0KICAgIC5ncmlkNHtkaXNwbGF5OmdyaWQ7Z3JpZC10ZW1wbGF0ZS1jb2x1bW5zOnJlcGVhdCg0LG1pbm1heCgxMDBweCwxZnIpKTtnYXA6OHB4fQogICAgLmt2e2JvcmRlcjoxcHggc29saWQgI2UyZThmMDtib3JkZXItcmFkaXVzOjEycHg7cGFkZGluZzo5cHh9CiAgICAua3Zre2ZvbnQtc2l6ZToxMHB4O2NvbG9yOiM5NGEzYjg7Zm9udC13ZWlnaHQ6OTAwO3RleHQtdHJhbnNmb3JtOnVwcGVyY2FzZX0KICAgIC5rdnZ7Zm9udC1zaXplOjEzcHg7Zm9udC13ZWlnaHQ6ODAwO21hcmdpbi10b3A6M3B4O3dvcmQtYnJlYWs6YnJlYWstd29yZH0KICAgIC5saW5le2Rpc3BsYXk6ZmxleDtqdXN0aWZ5LWNvbnRlbnQ6c3BhY2UtYmV0d2VlbjtnYXA6MTBweDtwYWRkaW5nOjVweCAwO2JvcmRlci1ib3R0b206MXB4IGRhc2hlZCAjZTJlOGYwO2ZvbnQtc2l6ZToxM3B4O2ZvbnQtd2VpZ2h0OjcwMH0KICAgIC5saW5lOmxhc3QtY2hpbGR7Ym9yZGVyLWJvdHRvbTowfQogICAgLm1vbmV5e2ZvbnQtc2l6ZToyOHB4O2ZvbnQtd2VpZ2h0OjkwMH0KICAgIC5wcm9ncmVzc3toZWlnaHQ6MTFweDtiYWNrZ3JvdW5kOiM5NGEzYjgzMztib3JkZXItcmFkaXVzOjk5OXB4O292ZXJmbG93OmhpZGRlbjttYXJnaW4tdG9wOjdweH0KICAgIC5iYXJ7aGVpZ2h0OjEwMCU7YmFja2dyb3VuZDojM2I4MmY2O3dpZHRoOjAlfQogICAgLnBheS1saXN0e2Rpc3BsYXk6ZmxleDtmbGV4LWRpcmVjdGlvbjpjb2x1bW47Z2FwOjhweDttYXJnaW4tdG9wOjEwcHh9CiAgICAucGF5LWl0ZW17Ym9yZGVyOjFweCBzb2xpZCAjZTJlOGYwO2JvcmRlci1yYWRpdXM6MTJweDtwYWRkaW5nOjEwcHggMTJweDtiYWNrZ3JvdW5kOiNmOGZhZmN9CiAgICAucGF5LWhlYWR7ZGlzcGxheTpmbGV4O2p1c3RpZnktY29udGVudDpzcGFjZS1iZXR3ZWVuO2dhcDoxMHB4O2FsaWduLWl0ZW1zOmZsZXgtc3RhcnR9CiAgICAucGF5LW5hbWV7Zm9udC1zaXplOjEzcHg7Zm9udC13ZWlnaHQ6OTAwO3dvcmQtYnJlYWs6YnJlYWstd29yZH0KICAgIC5wYXktbWV0YXttYXJnaW4tdG9wOjZweDtkaXNwbGF5OmdyaWQ7Z3JpZC10ZW1wbGF0ZS1jb2x1bW5zOnJlcGVhdCgyLG1pbm1heCgxMjBweCwxZnIpKTtnYXA6NnB4IDEwcHg7Zm9udC1zaXplOjEycHg7Y29sb3I6IzQ3NTU2OTtmb250LXdlaWdodDo3MDB9CiAgICAucGF5LWVtcHR5e21hcmdpbi10b3A6MTBweDtib3JkZXI6MXB4IGRhc2hlZCAjY2JkNWUxO2JvcmRlci1yYWRpdXM6MTJweDtwYWRkaW5nOjEycHg7Y29sb3I6Izk0YTNiODtmb250LXNpemU6MTJweDtmb250LXdlaWdodDo4MDA7dGV4dC1hbGlnbjpjZW50ZXJ9CiAgICAucGF5LW5vdGV7bWFyZ2luLXRvcDo4cHg7Ym9yZGVyLXRvcDoxcHggZGFzaGVkICNmZWNhY2E7cGFkZGluZy10b3A6OHB4O2ZvbnQtc2l6ZToxMnB4O2NvbG9yOiNiOTFjMWM7Zm9udC13ZWlnaHQ6ODAwO3doaXRlLXNwYWNlOnByZS13cmFwfQogICAgLm1ldHJpYy1idG57ZGlzcGxheTppbmxpbmUtZmxleDtmbGV4LWRpcmVjdGlvbjpjb2x1bW47YWxpZ24taXRlbXM6ZmxleC1lbmQ7Z2FwOjJweDtib3JkZXI6MDtiYWNrZ3JvdW5kOm5vbmU7cGFkZGluZzowO2NvbG9yOmluaGVyaXQ7Zm9udDppbmhlcml0O2N1cnNvcjpwb2ludGVyfQogICAgLm1ldHJpYy1idG4gc3Ryb25ne2NvbG9yOiMwZjE3MmE7dGV4dC1kZWNvcmF0aW9uOnVuZGVybGluZTt0ZXh0LWRlY29yYXRpb24tY29sb3I6I2JmZGJmZTt0ZXh0LXVuZGVybGluZS1vZmZzZXQ6M3B4fQogICAgdGJvZHkgdHIuc2V0dGxlZCAubWV0cmljLWJ0biBzdHJvbmd7Y29sb3I6IzY0NzQ4Yn0KICAgIC5tZXRyaWMtYnRuOmhvdmVyIHN0cm9uZ3tjb2xvcjojMWQ0ZWQ4O3RleHQtZGVjb3JhdGlvbi1jb2xvcjojMWQ0ZWQ4fQogICAgLmRldGFpbC1yb3cgdGR7cGFkZGluZzowO2JvcmRlci1ib3R0b206MXB4IHNvbGlkICNlMmU4ZjA7YmFja2dyb3VuZDojZjhmYWZjfQogICAgLmRldGFpbC1yb3c6aG92ZXJ7YmFja2dyb3VuZDojZjhmYWZjfQogICAgLmRldGFpbC1jZWxse3BhZGRpbmc6MH0KICAgIC5pbmxpbmUtcGFuZWx7cGFkZGluZzoxNnB4IDE4cHh9CiAgICAuaW5saW5lLWdyaWR7ZGlzcGxheTpncmlkO2dyaWQtdGVtcGxhdGUtY29sdW1uczoxLjM1ZnIgMWZyO2dhcDoxMnB4fQogICAgLmlubGluZS1zdGFja3tkaXNwbGF5OmZsZXg7ZmxleC1kaXJlY3Rpb246Y29sdW1uO2dhcDoxMHB4fQogICAgLmlubGluZS1jYXJke2JhY2tncm91bmQ6I2ZmZjtib3JkZXI6MXB4IHNvbGlkICNlMmU4ZjA7Ym9yZGVyLXJhZGl1czoxNnB4O3BhZGRpbmc6MTJweH0KICAgIC5pbmxpbmUtaGVyb3tiYWNrZ3JvdW5kOiMwZjE3MmE7Y29sb3I6I2ZmZjtib3JkZXItY29sb3I6IzBmMTcyYX0KICAgIC5pbmxpbmUtaGVyby1ub3Rle2ZvbnQtc2l6ZToxMnB4O2NvbG9yOiM5NGEzYjg7bWFyZ2luLXRvcDo2cHh9CiAgICAuaW5saW5lLWhlcm8tc3BsaXR7ZGlzcGxheTpncmlkO2dyaWQtdGVtcGxhdGUtY29sdW1uczoxZnIgMWZyO2dhcDoxNHB4O2FsaWduLWl0ZW1zOmVuZH0KICAgIC5pbmxpbmUtaGVyby1jb2x7bWluLXdpZHRoOjB9CiAgICAuaW5saW5lLWhlcm8tY29sLnJpZ2h0e3BhZGRpbmctbGVmdDoxNHB4O2JvcmRlci1sZWZ0OjFweCBzb2xpZCAjMzM0MTU1fQogICAgLm91dC1saXN0e2Rpc3BsYXk6ZmxleDtmbGV4LWRpcmVjdGlvbjpjb2x1bW47Z2FwOjhweDttYXJnaW4tdG9wOjEwcHh9CiAgICAub3V0LWl0ZW17Ym9yZGVyOjFweCBzb2xpZCAjZTJlOGYwO2JvcmRlci1yYWRpdXM6MTJweDtwYWRkaW5nOjEwcHggMTJweDtiYWNrZ3JvdW5kOiNmOGZhZmN9CiAgICAub3V0LWhlYWR7ZGlzcGxheTpmbGV4O2p1c3RpZnktY29udGVudDpzcGFjZS1iZXR3ZWVuO2dhcDoxMHB4O2FsaWduLWl0ZW1zOmZsZXgtc3RhcnR9CiAgICAub3V0LXZlbmRvcntmb250LXNpemU6MTNweDtmb250LXdlaWdodDo5MDB9CiAgICAub3V0LW5hbWV7bWFyZ2luLXRvcDo2cHg7Zm9udC1zaXplOjEzcHg7Zm9udC13ZWlnaHQ6ODAwO3dvcmQtYnJlYWs6YnJlYWstd29yZH0KICAgIC5vdXQtbWV0YXttYXJnaW4tdG9wOjhweDtkaXNwbGF5OmdyaWQ7Z3JpZC10ZW1wbGF0ZS1jb2x1bW5zOnJlcGVhdCgyLG1pbm1heCgxNDBweCwxZnIpKTtnYXA6NnB4IDEwcHg7Zm9udC1zaXplOjEycHg7Y29sb3I6IzQ3NTU2OTtmb250LXdlaWdodDo3MDB9CiAgICAub3V0LXBheW1lbnRze2Rpc3BsYXk6ZmxleDtmbGV4LWRpcmVjdGlvbjpjb2x1bW47Z2FwOjZweDttYXJnaW4tdG9wOjhweDtwYWRkaW5nLXRvcDo4cHg7Ym9yZGVyLXRvcDoxcHggZGFzaGVkICNjYmQ1ZTF9CiAgICAub3V0LXBheW1lbnR7YmFja2dyb3VuZDojZmZmO2JvcmRlcjoxcHggc29saWQgI2UyZThmMDtib3JkZXItcmFkaXVzOjEwcHg7cGFkZGluZzo4cHh9CiAgICAub3V0LXBheW1lbnQtaGVhZHtkaXNwbGF5OmZsZXg7anVzdGlmeS1jb250ZW50OnNwYWNlLWJldHdlZW47Z2FwOjEwcHg7YWxpZ24taXRlbXM6ZmxleC1zdGFydDtmb250LXNpemU6MTJweDtmb250LXdlaWdodDo4MDB9CiAgICAub3V0LXBheW1lbnQtbWV0YXttYXJnaW4tdG9wOjZweDtkaXNwbGF5OmdyaWQ7Z3JpZC10ZW1wbGF0ZS1jb2x1bW5zOnJlcGVhdCgzLG1pbm1heCgxMjBweCwxZnIpKTtnYXA6NHB4IDhweDtmb250LXNpemU6MTJweDtjb2xvcjojNDc1NTY5O2ZvbnQtd2VpZ2h0OjcwMH0KICAgIC5vdXQtbm90ZXttYXJnaW4tdG9wOjhweDtib3JkZXItdG9wOjFweCBkYXNoZWQgI2ZlY2FjYTtwYWRkaW5nLXRvcDo4cHg7Zm9udC1zaXplOjEycHg7Y29sb3I6I2I5MWMxYztmb250LXdlaWdodDo4MDA7d2hpdGUtc3BhY2U6cHJlLXdyYXB9CiAgICAucHJvamVjdC1oZWFke2Rpc3BsYXk6Z3JpZDtncmlkLXRlbXBsYXRlLWNvbHVtbnM6MS4yZnIgLjhmcjtnYXA6MTJweDttYXJnaW4tYm90dG9tOjEycHh9CiAgICAucHJvamVjdC1tZXRhLWdyaWR7ZGlzcGxheTpncmlkO2dyaWQtdGVtcGxhdGUtY29sdW1uczpyZXBlYXQoNCxtaW5tYXgoMTEwcHgsMWZyKSk7Z2FwOjhweH0KICAgIC5wcm9qZWN0LXNlY3Rpb25ze2Rpc3BsYXk6Z3JpZDtncmlkLXRlbXBsYXRlLWNvbHVtbnM6MWZyIDFmcjtnYXA6MTJweH0KICAgIC5zZWN0aW9uLWNhcmR7YmFja2dyb3VuZDojZmZmO2JvcmRlcjoxcHggc29saWQgI2UyZThmMDtib3JkZXItcmFkaXVzOjE2cHg7cGFkZGluZzoxNHB4fQogICAgLnNlY3Rpb24taGVhZHtkaXNwbGF5OmZsZXg7anVzdGlmeS1jb250ZW50OnNwYWNlLWJldHdlZW47Z2FwOjEycHg7YWxpZ24taXRlbXM6ZmxleC1zdGFydDttYXJnaW4tYm90dG9tOjEwcHh9CiAgICAuc2VjdGlvbi10aXRsZXtmb250LXNpemU6MTZweDtmb250LXdlaWdodDo5MDB9CiAgICAuc2VjdGlvbi1zdWJ7bWFyZ2luLXRvcDo0cHg7Zm9udC1zaXplOjEycHg7Y29sb3I6IzY0NzQ4Yjtmb250LXdlaWdodDo4MDB9CiAgICAuc2VjdGlvbi1jaGlwe2Rpc3BsYXk6aW5saW5lLWZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2dhcDo2cHg7Ym9yZGVyOjFweCBzb2xpZCAjYmZkYmZlO2JhY2tncm91bmQ6I2VmZjZmZjtjb2xvcjojMWQ0ZWQ4O2JvcmRlci1yYWRpdXM6OTk5cHg7cGFkZGluZzo1cHggMTBweDtmb250LXNpemU6MTFweDtmb250LXdlaWdodDo5MDA7d2hpdGUtc3BhY2U6bm93cmFwfQogICAgLnNlY3Rpb24tY2hpcC5vdXR7Ym9yZGVyLWNvbG9yOiNmZWNkZDM7YmFja2dyb3VuZDojZmZmMWYyO2NvbG9yOiNiZTEyM2N9CiAgICAuc3VtbWFyeS1ncmlke2Rpc3BsYXk6Z3JpZDtncmlkLXRlbXBsYXRlLWNvbHVtbnM6cmVwZWF0KGF1dG8tZml0LG1pbm1heCgxNDBweCwxZnIpKTtnYXA6OHB4fQogICAgLnN1bW1hcnktY2FyZHtiYWNrZ3JvdW5kOiNmOGZhZmM7Ym9yZGVyOjFweCBzb2xpZCAjZTJlOGYwO2JvcmRlci1yYWRpdXM6MTRweDtwYWRkaW5nOjEycHg7bWluLXdpZHRoOjB9CiAgICAuc3VtbWFyeS1sYWJlbHtmb250LXNpemU6MTFweDtjb2xvcjojNjQ3NDhiO2ZvbnQtd2VpZ2h0OjkwMDt0ZXh0LXRyYW5zZm9ybTp1cHBlcmNhc2V9CiAgICAuc3VtbWFyeS12YWx1ZXttYXJnaW4tdG9wOjZweDtmb250LXNpemU6Y2xhbXAoMTJweCwwLjk1dncsMjJweCk7Zm9udC13ZWlnaHQ6OTAwO2xpbmUtaGVpZ2h0OjEuMTU7d2hpdGUtc3BhY2U6bm93cmFwO21heC13aWR0aDoxMDAlO2xldHRlci1zcGFjaW5nOi0uMDNlbX0KICAgIC5zdW1tYXJ5LW5vdGV7bWFyZ2luLXRvcDo0cHg7Zm9udC1zaXplOjEycHg7Y29sb3I6Izk0YTNiODtmb250LXdlaWdodDo4MDB9CiAgICAubGVkZ2VyLXN0YWNre2Rpc3BsYXk6ZmxleDtmbGV4LWRpcmVjdGlvbjpjb2x1bW47Z2FwOjE0cHh9CiAgICAubGVkZ2VyLWJsb2Nre2JhY2tncm91bmQ6I2ZmZjtib3JkZXI6MXB4IHNvbGlkICNlMmU4ZjA7Ym9yZGVyLXJhZGl1czoxOHB4O292ZXJmbG93OmhpZGRlbn0KICAgIC5sZWRnZXItYmxvY2sub3V0c291cmNle2JvcmRlci1jb2xvcjojZmVjZGQzO2JhY2tncm91bmQ6I2ZmZn0KICAgIC5sZWRnZXItYmxvY2suY29sbGVjdHtib3JkZXItY29sb3I6I2M3ZDJmZTtiYWNrZ3JvdW5kOiNmZmZ9CiAgICAubGVkZ2VyLWhlYWR7ZGlzcGxheTpmbGV4O2p1c3RpZnktY29udGVudDpzcGFjZS1iZXR3ZWVuO2FsaWduLWl0ZW1zOmNlbnRlcjtnYXA6MTJweDtwYWRkaW5nOjEycHggMTRweH0KICAgIC5sZWRnZXItaGVhZC1sZWZ0e2Rpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpjZW50ZXI7Z2FwOjEwcHg7bWluLXdpZHRoOjB9CiAgICAubGVkZ2VyLWljb257d2lkdGg6MjBweDtoZWlnaHQ6MjBweDtib3JkZXItcmFkaXVzOjk5OXB4O2Rpc3BsYXk6aW5saW5lLWZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2p1c3RpZnktY29udGVudDpjZW50ZXI7Zm9udC1zaXplOjEycHg7Zm9udC13ZWlnaHQ6OTAwO2NvbG9yOiNmZmY7ZmxleDowIDAgYXV0b30KICAgIC5sZWRnZXItYmxvY2sub3V0c291cmNlIC5sZWRnZXItaWNvbntiYWNrZ3JvdW5kOiNmNDNmNWV9CiAgICAubGVkZ2VyLWJsb2NrLmNvbGxlY3QgLmxlZGdlci1pY29ue2JhY2tncm91bmQ6IzYzNjZmMX0KICAgIC5sZWRnZXItbmFtZXtmb250LXNpemU6MTNweDtmb250LXdlaWdodDo5MDB9CiAgICAubGVkZ2VyLXN1YnttYXJnaW4tdG9wOjJweDtmb250LXNpemU6MTFweDtjb2xvcjojNjQ3NDhiO2ZvbnQtd2VpZ2h0OjgwMH0KICAgIC5sZWRnZXItcGlsbHtkaXNwbGF5OmlubGluZS1mbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtwYWRkaW5nOjZweCAxMHB4O2JvcmRlci1yYWRpdXM6OTk5cHg7Zm9udC1zaXplOjExcHg7Zm9udC13ZWlnaHQ6OTAwO3doaXRlLXNwYWNlOm5vd3JhcH0KICAgIC5sZWRnZXItYmxvY2sub3V0c291cmNlIC5sZWRnZXItcGlsbHtib3JkZXI6MXB4IHNvbGlkICNmZWNkZDM7YmFja2dyb3VuZDojZmZmMWYyO2NvbG9yOiNlMTFkNDh9CiAgICAubGVkZ2VyLWJsb2NrLmNvbGxlY3QgLmxlZGdlci1waWxse2JvcmRlcjoxcHggc29saWQgI2M3ZDJmZTtiYWNrZ3JvdW5kOiNlZWYyZmY7Y29sb3I6IzRmNDZlNX0KICAgIC5sZWRnZXItdGFibGUtd3JhcHtwYWRkaW5nOjAgMTJweCAxMnB4fQogICAgLmxlZGdlci10YWJsZXt3aWR0aDoxMDAlO21pbi13aWR0aDowO2JvcmRlci1jb2xsYXBzZTpjb2xsYXBzZX0KICAgIC5sZWRnZXItdGFibGUgdGhlYWQgdGh7YmFja2dyb3VuZDp0cmFuc3BhcmVudDtjb2xvcjojOTRhM2I4O2ZvbnQtc2l6ZToxMXB4O2ZvbnQtd2VpZ2h0OjkwMDtsZXR0ZXItc3BhY2luZzowO3RleHQtdHJhbnNmb3JtOm5vbmU7cGFkZGluZzo4cHggMTBweDtib3JkZXItYm90dG9tOjFweCBzb2xpZCAjZTJlOGYwfQogICAgLmxlZGdlci10YWJsZSB0Ym9keSB0ZHtwYWRkaW5nOjEwcHg7Ym9yZGVyLWJvdHRvbToxcHggc29saWQgI2VlZjJmNztmb250LXNpemU6MTJweDtjb2xvcjojMzM0MTU1O3doaXRlLXNwYWNlOm5vcm1hbDtiYWNrZ3JvdW5kOiNmZmZ9CiAgICAubGVkZ2VyLXRhYmxlIHRib2R5IHRyOmxhc3QtY2hpbGQgdGR7Ym9yZGVyLWJvdHRvbTowfQogICAgLmxlZGdlci1tYWlue2ZvbnQtd2VpZ2h0OjgwMDtjb2xvcjojMGYxNzJhfQogICAgLmxlZGdlci1tdXRlZHtkaXNwbGF5OmJsb2NrO21hcmdpbi10b3A6M3B4O2ZvbnQtc2l6ZToxMXB4O2NvbG9yOiM5NGEzYjg7Zm9udC13ZWlnaHQ6NzAwfQogICAgLmxlZGdlci1hbW91bnR7Zm9udC13ZWlnaHQ6OTAwO3RleHQtYWxpZ246cmlnaHQ7Y29sb3I6IzBmMTcyYX0KICAgIC5sZWRnZXItbm90ZXtmb250LXNpemU6MTFweDtjb2xvcjojNjQ3NDhiO2ZvbnQtd2VpZ2h0OjcwMH0KICAgIC5sZWRnZXItZW1wdHl7cGFkZGluZzoxNHB4IDEycHg7Y29sb3I6Izk0YTNiODtmb250LXNpemU6MTJweDtmb250LXdlaWdodDo4MDA7dGV4dC1hbGlnbjpjZW50ZXJ9CiAgICAubGVkZ2VyLWJsb2NrLm91dHNvdXJjZSAubGVkZ2VyLWhlYWR7YmFja2dyb3VuZDojZmZmMWYyO2JvcmRlci1ib3R0b206MXB4IHNvbGlkICNmZWNkZDN9CiAgICAubGVkZ2VyLWJsb2NrLmNvbGxlY3QgLmxlZGdlci1oZWFke2JhY2tncm91bmQ6I2VlZjJmZjtib3JkZXItYm90dG9tOjFweCBzb2xpZCAjYzdkMmZlfQogICAgLmxlZGdlci1ibG9jay5vdXRzb3VyY2UgLmxlZGdlci10YWJsZSB0aGVhZCB0aHtiYWNrZ3JvdW5kOiNmZmY3Zjh9CiAgICAubGVkZ2VyLWJsb2NrLmNvbGxlY3QgLmxlZGdlci10YWJsZSB0aGVhZCB0aHtiYWNrZ3JvdW5kOiNmNWY3ZmZ9CiAgICBAbWVkaWEobWF4LXdpZHRoOjEyODBweCl7LnRvcHtncmlkLXRlbXBsYXRlLWNvbHVtbnM6MWZyfS5jb250cm9sc3tqdXN0aWZ5LWNvbnRlbnQ6ZmxleC1zdGFydH0uY2FyZHN7Z3JpZC10ZW1wbGF0ZS1jb2x1bW5zOnJlcGVhdCgyLG1pbm1heCgxNDBweCwxZnIpKX0ubS1ib2R5e2dyaWQtdGVtcGxhdGUtY29sdW1uczoxZnJ9LmlubGluZS1ncmlke2dyaWQtdGVtcGxhdGUtY29sdW1uczoxZnJ9LmdyaWQ0e2dyaWQtdGVtcGxhdGUtY29sdW1uczpyZXBlYXQoMixtaW5tYXgoMTAwcHgsMWZyKSl9LmlubGluZS1oZXJvLXNwbGl0e2dyaWQtdGVtcGxhdGUtY29sdW1uczoxZnJ9LmlubGluZS1oZXJvLWNvbC5yaWdodHtwYWRkaW5nLWxlZnQ6MDtib3JkZXItbGVmdDowO2JvcmRlci10b3A6MXB4IHNvbGlkICMzMzQxNTU7cGFkZGluZy10b3A6MTJweH0ucHJvamVjdC1oZWFke2dyaWQtdGVtcGxhdGUtY29sdW1uczoxZnJ9LnByb2plY3QtbWV0YS1ncmlke2dyaWQtdGVtcGxhdGUtY29sdW1uczpyZXBlYXQoMixtaW5tYXgoMTEwcHgsMWZyKSl9LnByb2plY3Qtc2VjdGlvbnN7Z3JpZC10ZW1wbGF0ZS1jb2x1bW5zOjFmcn0uc3VtbWFyeS1ncmlke2dyaWQtdGVtcGxhdGUtY29sdW1uczpyZXBlYXQoMixtaW5tYXgoMTIwcHgsMWZyKSl9LmxlZGdlci1oZWFke2FsaWduLWl0ZW1zOmZsZXgtc3RhcnQ7ZmxleC1kaXJlY3Rpb246Y29sdW1ufS5sZWRnZXItcGlsbHthbGlnbi1zZWxmOmZsZXgtc3RhcnR9fQogIDwvc3R5bGU+CjwvaGVhZD4KPGJvZHk+CiAgPGlucHV0IGlkPSJmaWxlIiB0eXBlPSJmaWxlIiBhY2NlcHQ9Ii5jc3YsLnhsc3gsLnhscyIgY2xhc3M9ImhpZGRlbiIgLz4KICA8ZGl2IGNsYXNzPSJ3cmFwIj4KICAgIDxkaXYgY2xhc3M9InRvcCI+CiAgICAgIDxkaXY+PGRpdiBjbGFzcz0ic3ViIj5MaXZlIE1hbmFnZW1lbnQ8L2Rpdj48aDEgY2xhc3M9InRpdGxlIj7sgqzsl4XqtIDrpqzrjIDsnqUgPHNwYW4gc3R5bGU9ImZvbnQtd2VpZ2h0OjMwMDtjb2xvcjojOTRhM2I4Ij58IERhc2hib2FyZDwvc3Bhbj48L2gxPjwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJjb250cm9scyI+PGJ1dHRvbiBpZD0iYnRuVXBsb2FkIiBjbGFzcz0iYnRuIiB0eXBlPSJidXR0b24iPu2MjOydvCDsl4XroZzrk5w8L2J1dHRvbj48aW5wdXQgaWQ9InNlYXJjaCIgY2xhc3M9InNlYXJjaCIgcGxhY2Vob2xkZXI9IuyghOyytCDqsoDsg4kiIC8+PC9kaXY+CiAgICA8L2Rpdj4KICAgIDxkaXYgaWQ9InN0YXR1cyIgY2xhc3M9InN0YXR1cyI+Q1NWL1hMU1gg7YyM7J287J2EIOyXheuhnOuTnO2VmOuptCDrjbDsnbTthLDqsIAg7ZGc7Iuc65Cp64uI64ukLjwvZGl2PgogICAgPGRpdiBpZD0iY2FyZHMiIGNsYXNzPSJjYXJkcyI+PC9kaXY+CiAgICA8ZGl2IGNsYXNzPSJwYW5lbCI+CiAgICAgIDxkaXYgY2xhc3M9InRhYmxlLXdyYXAiPgogICAgICAgIDx0YWJsZT4KICAgICAgICAgIDx0aGVhZD4KICAgICAgICAgICAgPHRyPgogICAgICAgICAgICAgIDx0aD4KICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9InRoLWhlYWQiPgogICAgICAgICAgICAgICAgICA8YnV0dG9uIHR5cGU9ImJ1dHRvbiIgY2xhc3M9InRoLXRyaWdnZXIiIGRhdGEtZmlsdGVyPSJjb2RlIiBkYXRhLWxhYmVsPSLqtazrtoQgLyDsvZTrk5wiPgogICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJ0aC10aXRsZSI+6rWs67aEIC8g7L2U65OcPC9zcGFuPjxzcGFuIGNsYXNzPSJ0aC1tYXJrIj48L3NwYW4+PHNwYW4gY2xhc3M9InRoLWNhcmV0Ij7ilrw8L3NwYW4+CiAgICAgICAgICAgICAgICAgIDwvYnV0dG9uPgogICAgICAgICAgICAgICAgICA8ZGl2IGlkPSJmaWx0ZXJDb2RlTWVudSIgY2xhc3M9InRoLW1lbnUiIGRhdGEtZmlsdGVyPSJjb2RlIj48L2Rpdj4KICAgICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICAgIDwvdGg+CiAgICAgICAgICAgICAgPHRoPgogICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0idGgtaGVhZCI+CiAgICAgICAgICAgICAgICAgIDxidXR0b24gdHlwZT0iYnV0dG9uIiBjbGFzcz0idGgtdHJpZ2dlciIgZGF0YS1maWx0ZXI9Im5hbWUiIGRhdGEtbGFiZWw9IuyCrOyXheuqhSI+CiAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InRoLXRpdGxlIj7sgqzsl4XrqoU8L3NwYW4+PHNwYW4gY2xhc3M9InRoLW1hcmsiPjwvc3Bhbj48c3BhbiBjbGFzcz0idGgtY2FyZXQiPuKWvDwvc3Bhbj4KICAgICAgICAgICAgICAgICAgPC9idXR0b24+CiAgICAgICAgICAgICAgICAgIDxkaXYgaWQ9ImZpbHRlck5hbWVNZW51IiBjbGFzcz0idGgtbWVudSIgZGF0YS1maWx0ZXI9Im5hbWUiPjwvZGl2PgogICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgICAgPC90aD4KICAgICAgICAgICAgICA8dGg+CiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJ0aC1oZWFkIj4KICAgICAgICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJ0aC10cmlnZ2VyIiBkYXRhLWZpbHRlcj0iY29ycCIgZGF0YS1sYWJlbD0i6rOE7JW967KV7J24Ij4KICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0idGgtdGl0bGUiPuqzhOyVveuyleyduDwvc3Bhbj48c3BhbiBjbGFzcz0idGgtbWFyayI+PC9zcGFuPjxzcGFuIGNsYXNzPSJ0aC1jYXJldCI+4pa8PC9zcGFuPgogICAgICAgICAgICAgICAgICA8L2J1dHRvbj4KICAgICAgICAgICAgICAgICAgPGRpdiBpZD0iZmlsdGVyQ29ycE1lbnUiIGNsYXNzPSJ0aC1tZW51IiBkYXRhLWZpbHRlcj0iY29ycCI+PC9kaXY+CiAgICAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgICA8L3RoPgogICAgICAgICAgICAgIDx0aD4KICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9InRoLWhlYWQiPgogICAgICAgICAgICAgICAgICA8YnV0dG9uIHR5cGU9ImJ1dHRvbiIgY2xhc3M9InRoLXRyaWdnZXIiIGRhdGEtZmlsdGVyPSJzdGF0dXMiIGRhdGEtbGFiZWw9IuynhO2WieyDge2DnCI+CiAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InRoLXRpdGxlIj7sp4Ttlonsg4Htg5w8L3NwYW4+PHNwYW4gY2xhc3M9InRoLW1hcmsiPjwvc3Bhbj48c3BhbiBjbGFzcz0idGgtY2FyZXQiPuKWvDwvc3Bhbj4KICAgICAgICAgICAgICAgICAgPC9idXR0b24+CiAgICAgICAgICAgICAgICAgIDxkaXYgaWQ9ImZpbHRlclN0YXR1c01lbnUiIGNsYXNzPSJ0aC1tZW51IiBkYXRhLWZpbHRlcj0ic3RhdHVzIj48L2Rpdj4KICAgICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICAgIDwvdGg+CiAgICAgICAgICAgICAgPHRoPgogICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0idGgtaGVhZCI+CiAgICAgICAgICAgICAgICAgIDxidXR0b24gdHlwZT0iYnV0dG9uIiBjbGFzcz0idGgtdHJpZ2dlciIgZGF0YS1maWx0ZXI9Im91dHNvdXJjZSIgZGF0YS1sYWJlbD0i7Jm47KO867mEIj4KICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0idGgtdGl0bGUiPuyZuOyjvOu5hDwvc3Bhbj48c3BhbiBjbGFzcz0idGgtbWV0YSI+KFZBVCDrs4Trj4QpPC9zcGFuPjxzcGFuIGNsYXNzPSJ0aC1tYXJrIj48L3NwYW4+PHNwYW4gY2xhc3M9InRoLWNhcmV0Ij7ilrw8L3NwYW4+CiAgICAgICAgICAgICAgICAgIDwvYnV0dG9uPgogICAgICAgICAgICAgICAgICA8ZGl2IGlkPSJmaWx0ZXJPdXRzb3VyY2VNZW51IiBjbGFzcz0idGgtbWVudSIgZGF0YS1maWx0ZXI9Im91dHNvdXJjZSI+PC9kaXY+CiAgICAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgICA8L3RoPgogICAgICAgICAgICAgIDx0aCBjbGFzcz0ibnVtIj4KICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9InRoLWhlYWQgZW5kIj4KICAgICAgICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJ0aC10cmlnZ2VyIiBkYXRhLWZpbHRlcj0iYW1vdW50IiBkYXRhLWxhYmVsPSLqs4Tslb3quIgiPgogICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJ0aC10aXRsZSI+6rOE7JW96riIPC9zcGFuPjxzcGFuIGNsYXNzPSJ0aC1tZXRhIj4oVkFUIOuzhOuPhCk8L3NwYW4+PHNwYW4gY2xhc3M9InRoLW1hcmsiPjwvc3Bhbj48c3BhbiBjbGFzcz0idGgtY2FyZXQiPuKWvDwvc3Bhbj4KICAgICAgICAgICAgICAgICAgPC9idXR0b24+CiAgICAgICAgICAgICAgICAgIDxkaXYgaWQ9ImZpbHRlckFtb3VudE1lbnUiIGNsYXNzPSJ0aC1tZW51IiBkYXRhLWZpbHRlcj0iYW1vdW50Ij48L2Rpdj4KICAgICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICAgIDwvdGg+CiAgICAgICAgICAgICAgPHRoIGNsYXNzPSJudW0iPgogICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0idGgtaGVhZCBlbmQiPgogICAgICAgICAgICAgICAgICA8YnV0dG9uIHR5cGU9ImJ1dHRvbiIgY2xhc3M9InRoLXRyaWdnZXIiIGRhdGEtZmlsdGVyPSJjb2xsZWN0ZWQiIGRhdGEtbGFiZWw9IuyImOq4iOyVoSI+CiAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InRoLXRpdGxlIj7siJjquIjslaE8L3NwYW4+PHNwYW4gY2xhc3M9InRoLW1ldGEiPihWQVQg67OE64+EKTwvc3Bhbj48c3BhbiBjbGFzcz0idGgtbWFyayI+PC9zcGFuPjxzcGFuIGNsYXNzPSJ0aC1jYXJldCI+4pa8PC9zcGFuPgogICAgICAgICAgICAgICAgICA8L2J1dHRvbj4KICAgICAgICAgICAgICAgICAgPGRpdiBpZD0iZmlsdGVyQ29sbGVjdGVkTWVudSIgY2xhc3M9InRoLW1lbnUiIGRhdGEtZmlsdGVyPSJjb2xsZWN0ZWQiPjwvZGl2PgogICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgICAgPC90aD4KICAgICAgICAgICAgICA8dGggY2xhc3M9Im51bSI+CiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJ0aC1oZWFkIGVuZCI+CiAgICAgICAgICAgICAgICAgIDxidXR0b24gdHlwZT0iYnV0dG9uIiBjbGFzcz0idGgtdHJpZ2dlciIgZGF0YS1maWx0ZXI9InJhdGUiIGRhdGEtbGFiZWw9IuyImOq4iOuloCI+CiAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InRoLXRpdGxlIj7siJjquIjrpaA8L3NwYW4+PHNwYW4gY2xhc3M9InRoLW1hcmsiPjwvc3Bhbj48c3BhbiBjbGFzcz0idGgtY2FyZXQiPuKWvDwvc3Bhbj4KICAgICAgICAgICAgICAgICAgPC9idXR0b24+CiAgICAgICAgICAgICAgICAgIDxkaXYgaWQ9ImZpbHRlclJhdGVNZW51IiBjbGFzcz0idGgtbWVudSIgZGF0YS1maWx0ZXI9InJhdGUiPjwvZGl2PgogICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgICAgPC90aD4KICAgICAgICAgICAgPC90cj4KICAgICAgICAgIDwvdGhlYWQ+CiAgICAgICAgICA8dGJvZHkgaWQ9InRib2R5Ij48L3Rib2R5PgogICAgICAgIDwvdGFibGU+CiAgICAgIDwvZGl2PgogICAgICA8ZGl2IGlkPSJlbXB0eSIgY2xhc3M9ImVtcHR5Ij7tkZzsi5ztlaAg642w7J207YSw6rCAIOyXhuyKteuLiOuLpC48L2Rpdj4KICAgIDwvZGl2PgogIDwvZGl2PgogIDxkaXYgaWQ9ImNvbGxlY3RNb2RhbCIgY2xhc3M9Im1vZGFsIj4KICAgIDxkaXYgY2xhc3M9Im1vZGFsLWNhcmQiPgogICAgICA8ZGl2IGNsYXNzPSJtLXRvcCI+PGRpdj48ZGl2IGlkPSJtQ2F0IiBjbGFzcz0iYmFkZ2UiPuuvuOu2hOulmDwvZGl2PjxkaXYgaWQ9Im1UaXRsZSIgc3R5bGU9ImZvbnQtc2l6ZToyOHB4O2ZvbnQtd2VpZ2h0OjkwMDttYXJnaW4tdG9wOjZweCI+PC9kaXY+PGRpdiBpZD0ibVN1YiIgc3R5bGU9ImZvbnQtc2l6ZToxM3B4O2NvbG9yOiM2NDc0OGI7Zm9udC13ZWlnaHQ6NzAwO21hcmdpbi10b3A6NHB4Ij48L2Rpdj48L2Rpdj48YnV0dG9uIGlkPSJidG5Db2xsZWN0Q2xvc2UiIGNsYXNzPSJ4IiB0eXBlPSJidXR0b24iPsOXPC9idXR0b24+PC9kaXY+CiAgICAgIDxkaXYgY2xhc3M9Im0tYm9keSI+CiAgICAgICAgPGRpdiBzdHlsZT0iZGlzcGxheTpmbGV4O2ZsZXgtZGlyZWN0aW9uOmNvbHVtbjtnYXA6MTBweCI+CiAgICAgICAgICA8ZGl2IGNsYXNzPSJzZWMiPjxkaXYgY2xhc3M9ImdyaWQzIj48ZGl2IGNsYXNzPSJrdiI+PGRpdiBjbGFzcz0ia3ZrIj7rsJzso7zsspg8L2Rpdj48ZGl2IGlkPSJtQ2xpZW50IiBjbGFzcz0ia3Z2Ij48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJrdiI+PGRpdiBjbGFzcz0ia3ZrIj7rsJzso7zrsKnrspU8L2Rpdj48ZGl2IGlkPSJtT3JkZXIiIGNsYXNzPSJrdnYiPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9Imt2Ij48ZGl2IGNsYXNzPSJrdmsiPuu2hOuLtOycqDwvZGl2PjxkaXYgaWQ9Im1TcGxpdCIgY2xhc3M9Imt2diI+PC9kaXY+PC9kaXY+PC9kaXY+PC9kaXY+CiAgICAgICAgICA8ZGl2IGNsYXNzPSJzZWMiPjxkaXYgY2xhc3M9ImxpbmUiPjxzcGFuPuywqeyImOydvDwvc3Bhbj48c3Ryb25nIGlkPSJtU3RhcnREYXRlIj48L3N0cm9uZz48L2Rpdj48ZGl2IGNsYXNzPSJsaW5lIj48c3Bhbj7spIDqs7Xsnbw8L3NwYW4+PHN0cm9uZyBpZD0ibUVuZERhdGUiPjwvc3Ryb25nPjwvZGl2PjxkaXYgY2xhc3M9ImxpbmUiPjxzcGFuPuuMgOq4iOq1rOu2hDwvc3Bhbj48c3Ryb25nIGlkPSJtUGF5VHlwZSI+PC9zdHJvbmc+PC9kaXY+PGRpdiBpZD0ibVBheUl0ZW1zIiBjbGFzcz0icGF5LWxpc3QiPjwvZGl2PjwvZGl2PgogICAgICAgICAgPGRpdiBjbGFzcz0ic2VjIGRhcmsiPjxkaXYgc3R5bGU9ImRpc3BsYXk6ZmxleDtqdXN0aWZ5LWNvbnRlbnQ6c3BhY2UtYmV0d2VlbjtnYXA6MTBweDthbGlnbi1pdGVtczpmbGV4LWVuZCI+PGRpdj48ZGl2IHN0eWxlPSJmb250LXNpemU6MTFweDtjb2xvcjojOTRhM2I4O2ZvbnQtd2VpZ2h0OjkwMCI+7LSdIOqzhOyVvSDtlanqs4QoVkFUIO2PrO2VqCk8L2Rpdj48ZGl2IGlkPSJtQ29udHJhY3RUb3RhbCIgY2xhc3M9Im1vbmV5Ij48L2Rpdj48ZGl2IGlkPSJtQ29udHJhY3RTdXBwbHkiIHN0eWxlPSJmb250LXNpemU6MTJweDtjb2xvcjojOTRhM2I4Ij48L2Rpdj48L2Rpdj48ZGl2IHN0eWxlPSJ0ZXh0LWFsaWduOnJpZ2h0Ij48ZGl2IHN0eWxlPSJmb250LXNpemU6MTFweDtjb2xvcjojNjBhNWZhO2ZvbnQtd2VpZ2h0OjkwMCI+7IiY6riI6riI7JWhPC9kaXY+PGRpdiBpZD0ibUNvbGxlY3RlZCIgY2xhc3M9Im1vbmV5IiBzdHlsZT0iY29sb3I6IzYwYTVmYSI+PC9kaXY+PGRpdiBpZD0ibUNvbGxlY3REYXRlIiBzdHlsZT0iZm9udC1zaXplOjEycHg7Y29sb3I6Izk0YTNiOCI+PC9kaXY+PC9kaXY+PC9kaXY+PGRpdiBzdHlsZT0ibWFyZ2luLXRvcDoxMHB4O2Rpc3BsYXk6ZmxleDtqdXN0aWZ5LWNvbnRlbnQ6c3BhY2UtYmV0d2VlbiI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMnB4O2NvbG9yOiM5NGEzYjg7Zm9udC13ZWlnaHQ6OTAwIj7siJjquIgg7KeE7ZaJ66WgPC9zcGFuPjxzdHJvbmcgaWQ9Im1SYXRlIiBzdHlsZT0iZm9udC1zaXplOjI4cHgiPjwvc3Ryb25nPjwvZGl2PjxkaXYgY2xhc3M9InByb2dyZXNzIj48ZGl2IGlkPSJtUmF0ZUJhciIgY2xhc3M9ImJhciI+PC9kaXY+PC9kaXY+PGRpdiBzdHlsZT0iZGlzcGxheTpmbGV4O2p1c3RpZnktY29udGVudDpzcGFjZS1iZXR3ZWVuO21hcmdpbi10b3A6N3B4Ij48c3BhbiBzdHlsZT0iY29sb3I6I2ZkYTRhZjtmb250LXNpemU6MTJweDtmb250LXdlaWdodDo5MDAiPuuvuOyImCDquIjslaE8L3NwYW4+PHN0cm9uZyBpZD0ibVJlY2VpdmFibGUiIHN0eWxlPSJjb2xvcjojZmI3MTg1Ij48L3N0cm9uZz48L2Rpdj48L2Rpdj4KICAgICAgICA8L2Rpdj4KICAgICAgICA8ZGl2IHN0eWxlPSJkaXNwbGF5OmZsZXg7ZmxleC1kaXJlY3Rpb246Y29sdW1uO2dhcDoxMHB4Ij4KICAgICAgICAgIDxkaXYgY2xhc3M9InNlYyI+PGRpdiBzdHlsZT0iZm9udC1zaXplOjExcHg7Y29sb3I6IzY0NzQ4Yjtmb250LXdlaWdodDo5MDA7bGV0dGVyLXNwYWNpbmc6LjFlbTt0ZXh0LXRyYW5zZm9ybTp1cHBlcmNhc2UiPuqzhOyVvSAvIOyyreq1rCDri7Tri7nsnpA8L2Rpdj48ZGl2IHN0eWxlPSJtYXJnaW4tdG9wOjhweCI+PGRpdiBpZD0ibUNtTmFtZSIgc3R5bGU9ImZvbnQtc2l6ZToyMHB4O2ZvbnQtd2VpZ2h0OjkwMCI+PC9kaXY+PGRpdiBpZD0ibUNtT3JnIiBzdHlsZT0iZm9udC1zaXplOjEzcHg7Y29sb3I6IzBmMTcyYTtmb250LXdlaWdodDo4MDA7bWFyZ2luLXRvcDo0cHgiPjwvZGl2PjxkaXYgaWQ9Im1DbVBob25lIiBzdHlsZT0iZm9udC1zaXplOjEzcHg7Zm9udC13ZWlnaHQ6NzAwO21hcmdpbi10b3A6OHB4Ij48L2Rpdj48ZGl2IGlkPSJtQ21FbWFpbCIgc3R5bGU9ImZvbnQtc2l6ZToxM3B4O2ZvbnQtd2VpZ2h0OjcwMDttYXJnaW4tdG9wOjRweCI+PC9kaXY+PC9kaXY+PC9kaXY+CiAgICAgICAgICA8ZGl2IGNsYXNzPSJzZWMiPjxkaXYgc3R5bGU9ImZvbnQtc2l6ZToxMXB4O2NvbG9yOiM2NDc0OGI7Zm9udC13ZWlnaHQ6OTAwO2xldHRlci1zcGFjaW5nOi4xZW07dGV4dC10cmFuc2Zvcm06dXBwZXJjYXNlIj7rtoDshJwg64u064u57J6QPC9kaXY+PGRpdiBzdHlsZT0ibWFyZ2luLXRvcDo4cHgiPjxkaXYgaWQ9Im1EbU5hbWUiIHN0eWxlPSJmb250LXNpemU6MjBweDtmb250LXdlaWdodDo5MDAiPjwvZGl2PjxkaXYgaWQ9Im1EbU9yZyIgc3R5bGU9ImZvbnQtc2l6ZToxM3B4O2NvbG9yOiMzMzQxNTU7Zm9udC13ZWlnaHQ6ODAwO21hcmdpbi10b3A6NHB4Ij48L2Rpdj48ZGl2IGlkPSJtRG1QaG9uZSIgc3R5bGU9ImZvbnQtc2l6ZToxM3B4O2ZvbnQtd2VpZ2h0OjcwMDttYXJnaW4tdG9wOjhweCI+PC9kaXY+PGRpdiBpZD0ibURtRW1haWwiIHN0eWxlPSJmb250LXNpemU6MTNweDtmb250LXdlaWdodDo3MDA7bWFyZ2luLXRvcDo0cHgiPjwvZGl2PjwvZGl2PjwvZGl2PgogICAgICAgIDwvZGl2PgogICAgICA8L2Rpdj4KICAgIDwvZGl2PgogIDwvZGl2PgogIDxkaXYgaWQ9Im91dHNvdXJjZU1vZGFsIiBjbGFzcz0ibW9kYWwiPgogICAgPGRpdiBjbGFzcz0ibW9kYWwtY2FyZCI+CiAgICAgIDxkaXYgY2xhc3M9Im0tdG9wIj48ZGl2PjxkaXYgY2xhc3M9ImJhZGdlIj7smbjso7zruYQg7IOB7IS4PC9kaXY+PGRpdiBpZD0ib1RpdGxlIiBzdHlsZT0iZm9udC1zaXplOjI4cHg7Zm9udC13ZWlnaHQ6OTAwO21hcmdpbi10b3A6NnB4Ij48L2Rpdj48ZGl2IGlkPSJvU3ViIiBzdHlsZT0iZm9udC1zaXplOjEzcHg7Y29sb3I6IzY0NzQ4Yjtmb250LXdlaWdodDo3MDA7bWFyZ2luLXRvcDo0cHgiPjwvZGl2PjwvZGl2PjxidXR0b24gaWQ9ImJ0bk91dHNvdXJjZUNsb3NlIiBjbGFzcz0ieCIgdHlwZT0iYnV0dG9uIj7DlzwvYnV0dG9uPjwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJtLWJvZHkiPgogICAgICAgIDxkaXYgc3R5bGU9ImRpc3BsYXk6ZmxleDtmbGV4LWRpcmVjdGlvbjpjb2x1bW47Z2FwOjEwcHgiPgogICAgICAgICAgPGRpdiBjbGFzcz0ic2VjIj4KICAgICAgICAgICAgPGRpdiBjbGFzcz0iZ3JpZDMiPgogICAgICAgICAgICAgIDxkaXYgY2xhc3M9Imt2Ij48ZGl2IGNsYXNzPSJrdmsiPuqzhOyVveuyleyduDwvZGl2PjxkaXYgaWQ9Im9Db3JwIiBjbGFzcz0ia3Z2Ij48L2Rpdj48L2Rpdj4KICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJrdiI+PGRpdiBjbGFzcz0ia3ZrIj7rsJzso7zsspg8L2Rpdj48ZGl2IGlkPSJvQ2xpZW50IiBjbGFzcz0ia3Z2Ij48L2Rpdj48L2Rpdj4KICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJrdiI+PGRpdiBjbGFzcz0ia3ZrIj7smbjso7zsspgg7JqU7JW9PC9kaXY+PGRpdiBpZD0ib1ZlbmRvcnMiIGNsYXNzPSJrdnYiPjwvZGl2PjwvZGl2PgogICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgIDwvZGl2PgogICAgICAgICAgPGRpdiBjbGFzcz0ic2VjIj4KICAgICAgICAgICAgPGRpdiBjbGFzcz0ibGluZSI+PHNwYW4+7Jm47KO8IOy0neyVoTwvc3Bhbj48c3Ryb25nIGlkPSJvVG90YWwiPjwvc3Ryb25nPjwvZGl2PgogICAgICAgICAgICA8ZGl2IGNsYXNzPSJsaW5lIj48c3Bhbj7smbjso7wg6rG07IiYPC9zcGFuPjxzdHJvbmcgaWQ9Im9Db3VudCI+PC9zdHJvbmc+PC9kaXY+CiAgICAgICAgICAgIDxkaXYgY2xhc3M9ImxpbmUiPjxzcGFuPuqzhOyVveq4sOqwhDwvc3Bhbj48c3Ryb25nIGlkPSJvUGVyaW9kIj48L3N0cm9uZz48L2Rpdj4KICAgICAgICAgICAgPGRpdiBpZD0ib0l0ZW1zIiBjbGFzcz0ib3V0LWxpc3QiPjwvZGl2PgogICAgICAgICAgPC9kaXY+CiAgICAgICAgPC9kaXY+CiAgICAgICAgPGRpdiBzdHlsZT0iZGlzcGxheTpmbGV4O2ZsZXgtZGlyZWN0aW9uOmNvbHVtbjtnYXA6MTBweCI+CiAgICAgICAgICA8ZGl2IGNsYXNzPSJzZWMgZGFyayI+CiAgICAgICAgICAgIDxkaXYgc3R5bGU9ImZvbnQtc2l6ZToxMXB4O2NvbG9yOiM5NGEzYjg7Zm9udC13ZWlnaHQ6OTAwIj7stJ0g7Jm47KO867mEKOqzteq4ieqwgOyVoSDquLDspIApPC9kaXY+CiAgICAgICAgICAgIDxkaXYgaWQ9Im9Ub3RhbEhlcm8iIGNsYXNzPSJtb25leSI+PC9kaXY+CiAgICAgICAgICAgIDxkaXYgaWQ9Im9Ub3RhbEhpbnQiIHN0eWxlPSJmb250LXNpemU6MTJweDtjb2xvcjojOTRhM2I4O21hcmdpbi10b3A6NnB4Ij48L2Rpdj4KICAgICAgICAgIDwvZGl2PgogICAgICAgIDwvZGl2PgogICAgICA8L2Rpdj4KICAgIDwvZGl2PgogIDwvZGl2PgogIDxzY3JpcHQgc3JjPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL3hsc3hAMC4xOC41L2Rpc3QveGxzeC5mdWxsLm1pbi5qcyI+PC9zY3JpcHQ+CiAgPHNjcmlwdD4KICAgIGNvbnN0IEZJTFRFUl9LRVlTPVsiY29kZSIsIm5hbWUiLCJjb3JwIiwic3RhdHVzIiwib3V0c291cmNlIiwiYW1vdW50IiwiY29sbGVjdGVkIiwicmF0ZSJdOwogICAgY29uc3QgUz17YWxsOltdLHJvd3M6W10sdmlld1Jvd3M6W10sZmlsZToiIixmaWx0ZXJzOnt9LHRvdGFsczpudWxsLGV4cGFuZGVkOntrZXk6IiJ9fTsKICAgIGNvbnN0IEU9e2ZpbGU6ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoImZpbGUiKSxidG5VcGxvYWQ6ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoImJ0blVwbG9hZCIpLHNlYXJjaDpkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgic2VhcmNoIiksc3RhdHVzOmRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCJzdGF0dXMiKSxjYXJkczpkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgiY2FyZHMiKSx0Ym9keTpkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgidGJvZHkiKSxlbXB0eTpkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgiZW1wdHkiKSxjb2xsZWN0TW9kYWw6ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoImNvbGxlY3RNb2RhbCIpLGJ0bkNvbGxlY3RDbG9zZTpkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgiYnRuQ29sbGVjdENsb3NlIiksb3V0c291cmNlTW9kYWw6ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoIm91dHNvdXJjZU1vZGFsIiksYnRuT3V0c291cmNlQ2xvc2U6ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoImJ0bk91dHNvdXJjZUNsb3NlIiksZmlsdGVyQnV0dG9uczpPYmplY3QuZnJvbUVudHJpZXMoQXJyYXkuZnJvbShkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCIudGgtdHJpZ2dlciIpKS5tYXAoZWw9PltlbC5kYXRhc2V0LmZpbHRlcixlbF0pKSxmaWx0ZXJNZW51czpPYmplY3QuZnJvbUVudHJpZXMoQXJyYXkuZnJvbShkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCIudGgtbWVudSIpKS5tYXAoZWw9PltlbC5kYXRhc2V0LmZpbHRlcixlbF0pKX07CiAgICBjb25zdCBHPWlkPT5kb2N1bWVudC5nZXRFbGVtZW50QnlJZChpZCk7CiAgICBjb25zdCBlc2M9dj0+U3RyaW5nKHZ8fCIiKS5yZXBsYWNlKC8mL2csIiZhbXA7IikucmVwbGFjZSgvPC9nLCImbHQ7IikucmVwbGFjZSgvPi9nLCImZ3Q7Iik7CiAgICBjb25zdCBlc2NBdHRyPXY9PmVzYyh2KS5yZXBsYWNlKC8iL2csIiZxdW90OyIpOwogICAgY29uc3Qgbj12PT5TdHJpbmcodnx8IiIpLnJlcGxhY2UoL1tcc1xyXG5dKy9nLCIiKS50b0xvd2VyQ2FzZSgpOwogICAgY29uc3QgbnVtPXY9Pnt2PVN0cmluZyh2fHwiIikudHJpbSgpO2lmKCF2fHx2LnN0YXJ0c1dpdGgoIj0iKSlyZXR1cm4gMDtyZXR1cm4gcGFyc2VGbG9hdCh2LnJlcGxhY2UoL1teMC05LlwtXS9nLCIiKSl8fDA7fTsKICAgIGNvbnN0IHdvbj12PT5NYXRoLnJvdW5kKHZ8fDApLnRvTG9jYWxlU3RyaW5nKCJrby1LUiIpKyIg7JuQIjsKICAgIGNvbnN0IGQ9dj0+e3Y9U3RyaW5nKHZ8fCIiKS50cmltKCk7cmV0dXJuICF2fHx2PT09In4iPyItIjp2O307CiAgICBjb25zdCByYXRlPShyYXcsY29sLHNhbGVzKT0+e2NvbnN0IHg9cGFyc2VGbG9hdChTdHJpbmcocmF3fHwiIikucmVwbGFjZSgvW14wLTkuXC1dL2csIiIpKTtpZihOdW1iZXIuaXNGaW5pdGUoeCkpcmV0dXJuIE1hdGgubWF4KDAsTWF0aC5taW4oMTAwLHgpKTtyZXR1cm4gc2FsZXM+MD9NYXRoLm1heCgwLE1hdGgubWluKDEwMCxjb2wvc2FsZXMqMTAwKSk6MDt9OwogICAgY29uc3Qgc2NvcmU9dD0+e3Q9U3RyaW5nKHR8fCIiKTtsZXQgcz0wLG09dC5yZXBsYWNlKC9ccysvZywiIik7aWYobS5pbmNsdWRlcygi7IKs7JeF6rSA66as64yA7J6lIikpcys9ODtpZihtLmluY2x1ZGVzKCLstJ3qtITsgqzsl4XsvZTrk5wiKSlzKz04O2lmKG0uaW5jbHVkZXMoIuyCrOyXheuqhSjqs4Tslb3rqoUpIikpcys9NztzKz0odC5tYXRjaCgvW+qwgC3tnqNdL2cpfHxbXSkubGVuZ3RoKjAuMDE7cy09KHQubWF0Y2goL++/vS9nKXx8W10pLmxlbmd0aCowLjU7cmV0dXJuIHM7fTsKICAgIGNvbnN0IHJvd0tleT1yPT5bci5jb2RlfHwiIixyLm5hbWV8fCIiLHIuY29ycHx8IiIsci5jbGllbnR8fCIiXS5qb2luKCJ8Iik7CiAgICBmdW5jdGlvbiBwYXJzZUNzdih0eHQpe2NvbnN0IG91dD1bXTtsZXQgcm93PVtdLGY9IiIscT1mYWxzZTtmb3IobGV0IGk9MDtpPHR4dC5sZW5ndGg7aSsrKXtjb25zdCBjPXR4dFtpXTtpZihjPT09JyInKXtpZihxJiZ0eHRbaSsxXT09PSciJyl7Zis9JyInO2krKzt9ZWxzZSBxPSFxO2NvbnRpbnVlO31pZihjPT09IiwiJiYhcSl7cm93LnB1c2goZik7Zj0iIjtjb250aW51ZTt9aWYoKGM9PT0iXG4ifHxjPT09IlxyIikmJiFxKXtpZihjPT09IlxyIiYmdHh0W2krMV09PT0iXG4iKWkrKztyb3cucHVzaChmKTtvdXQucHVzaChyb3cpO3Jvdz1bXTtmPSIiO2NvbnRpbnVlO31mKz1jO31yb3cucHVzaChmKTtvdXQucHVzaChyb3cpO2lmKG91dC5sZW5ndGgmJm91dFswXS5sZW5ndGgpb3V0WzBdWzBdPVN0cmluZyhvdXRbMF1bMF18fCIiKS5yZXBsYWNlKC9eXHVGRUZGLywiIik7cmV0dXJuIG91dDt9CiAgICBmdW5jdGlvbiBocyhyb3dzKXsKICAgICAgZm9yKGxldCBpPTA7aTxyb3dzLmxlbmd0aDtpKyspewogICAgICAgIGNvbnN0IGE9KHJvd3NbaV18fFtdKS5tYXAobik7CiAgICAgICAgY29uc3QgaGFzTmFtZT1hLnNvbWUodj0+di5pbmNsdWRlcygi7IKs7JeF66qFKOqzhOyVveuqhSkiKXx8dj09PSLsgqzsl4XrqoUifHx2LmluY2x1ZGVzKCLsgqzsl4XrqoUiKSk7CiAgICAgICAgY29uc3QgaGFzQ29kZT1hLnNvbWUodj0+di5pbmNsdWRlcygi7LSd6rSE7IKs7JeF7L2U65OcIil8fHYuaW5jbHVkZXMoIuyCrOyXhey9lOuTnCIpKTsKICAgICAgICBjb25zdCBoYXNDbGllbnQ9YS5zb21lKHY9PnYuaW5jbHVkZXMoIuuwnOyjvOyymCjrp6TstpzsspgpIil8fHYuaW5jbHVkZXMoIuuwnOyjvOyymCIpKTsKICAgICAgICBpZihoYXNOYW1lJiYoaGFzQ29kZXx8aGFzQ2xpZW50KSkgcmV0dXJuIGk7CiAgICAgIH0KICAgICAgcmV0dXJuIC0xOwogICAgfQogICAgZnVuY3Rpb24gY2goYSxiKXthPWF8fFtdO2I9Ynx8W107Y29uc3QgbT1NYXRoLm1heChhLmxlbmd0aCxiLmxlbmd0aCksbz1bXTtsZXQgY2Fycnk9IiI7Zm9yKGxldCBpPTA7aTxtO2krKyl7Y29uc3QgdD1TdHJpbmcoYVtpXXx8IiIpLnJlcGxhY2UoL1xzKy9nLCIgIikudHJpbSgpLHM9U3RyaW5nKGJbaV18fCIiKS5yZXBsYWNlKC9ccysvZywiICIpLnRyaW0oKTtpZih0KWNhcnJ5PXQ7Y29uc3QgdG9wPXR8fGNhcnJ5O28ucHVzaCh0b3AmJnM/KHRvcCsiICIrcykudHJpbSgpOih0b3B8fHN8fCIiKSk7fXJldHVybiBvO30KICAgIGZ1bmN0aW9uIGhpKGhlYWRlcnMsY2FuZHMpe2NvbnN0IEM9KGNhbmRzfHxbXSkubWFwKG4pLmZpbHRlcihCb29sZWFuKTtmb3IoY29uc3QgYyBvZiBDKXtmb3IobGV0IGk9MDtpPGhlYWRlcnMubGVuZ3RoO2krKylpZihuKGhlYWRlcnNbaV0pPT09YylyZXR1cm4gaTt9cmV0dXJuIC0xO30KICAgIGZ1bmN0aW9uIHBhcnNlTGVkZ2VyUm93cyhSKXsKICAgICAgaWYoUi5sZW5ndGgmJlJbMF0ubGVuZ3RoKVJbMF1bMF09U3RyaW5nKFJbMF1bMF18fCIiKS5yZXBsYWNlKC9eXHVGRUZGLywiIik7CiAgICAgIGNvbnN0IGg9aHMoUik7aWYoaDwwKXRocm93IG5ldyBFcnJvcigi7Zek642U66W8IOywvuyngCDrqrvtlojsirXri4jri6QuIik7CiAgICAgIGNvbnN0IEg9Y2goUltoXSxSW2grMV18fFtdKSxJPXtjYXQ6aGkoSCxbIuyCrOyXheq1rOu2hCIsIuyCrOyXhSDqtazrtoQiXSksY29ycDpoaShILFsi6rOE7JW967KV7J24Iiwi6rOE7JW9IOuyleyduCJdKSxjb2RlOmhpKEgsWyLstJ3qtITsgqzsl4XsvZTrk5wiLCLstJ3qtIQg7IKs7JeF7L2U65OcIiwi7IKs7JeF7L2U65OcIl0pLG5hbWU6aGkoSCxbIuyCrOyXheuqhSAo6rOE7JW966qFKSIsIuyCrOyXheuqhSjqs4Tslb3rqoUpIiwi7IKs7JeF66qFIl0pLHBheTpoaShILFsi64yA6riI6rWs67aEIiwi64yA6riIIOq1rOu2hCJdKSx5bjpoaShILFsi6rOE7JW97Jes67aAIl0pLG9yZGVyOmhpKEgsWyLrsJzso7zrsKnrspUiXSkscG06aGkoSCxbInBtIl0pLHN0YXR1czpoaShILFsi7KeE7ZaJ7IOB7YOcIl0pLGNsaWVudDpoaShILFsi67Cc7KO87LKYICjrp6TstpzsspgpIiwi67Cc7KO87LKYKOunpOy2nOyymCkiLCLrsJzso7zsspgiXSksc3BsaXQ6aGkoSCxbIuu2hOuLtOycqCJdKSxjRGF0ZTpoaShILFsi6rOE7JW96riw6rCEIOqzhOyVveydvCIsIuqzhOyVveydvCIsIuuwnO2WieydvCJdKSxzRGF0ZTpoaShILFsi6rOE7JW96riw6rCEIOywqeyImOydvCIsIuywqeyImOydvCJdKSxlRGF0ZTpoaShILFsi6rOE7JW96riw6rCEIOykgOqzteydvCIsIuykgOqzteydvCJdKSxjU3VwOmhpKEgsWyLqs4Tslb3quIgg6rO16riJ6rCA7JWhIiwi66ek7Lac6riI7JWhIOqzteq4ieqwgOyVoSIsIuqzteq4ieqwgOyVoSJdKSxjVmF0OmhpKEgsWyLqs4Tslb3quIgg67aA6rCA7IS4Iiwi66ek7Lac6riI7JWhIOu2gOqwgOyEuCIsIuu2gOqwgOyEuCJdKSxjVG90OmhpKEgsWyLqs4Tslb3quIgg7ZWp6rOEIiwi66ek7Lac6riI7JWhIO2VqeqzhCIsIu2VqeqzhCIsIuqzhOyVveq4iCIsIuunpOy2nOq4iOyVoSJdKSxjb2xEYXRlOmhpKEgsWyLrp6TstpzquIjslaEg7IiY6riI7J28Iiwi7IiY6riI7J28Il0pLHNTdXA6aGkoSCxbIuunpOy2nOq4iOyVoSDqs7XquInqsIDslaEiLCLqs7XquInqsIDslaEiXSksc1ZhdDpoaShILFsi66ek7Lac6riI7JWhIOu2gOqwgOyEuCIsIuu2gOqwgOyEuCJdKSxzVG90OmhpKEgsWyLrp6TstpzquIjslaEg7ZWp6rOEIiwi7ZWp6rOEIiwi66ek7Lac6riI7JWhIl0pLGNvbDpoaShILFsi66ek7Lac6riI7JWhIOyImOq4iOq4iOyVoSIsIuyImOq4iOq4iOyVoSIsIuyImOq4iOyVoSJdKSxyZWN2OmhpKEgsWyLrp6TstpzquIjslaEg66+47IiY6riI7JWhIiwi66+47IiY6riI7JWhIl0pLHI6aGkoSCxbIuunpOy2nOq4iOyVoSDsiJjquIjsnKgiLCLsiJjquIjsnKgiXSksbm90ZTpoaShILFsi67mE6rOgIl0pLGNtQ286aGkoSCxbIuqzhOyVvS/ssq3qtazri7Tri7nsnpAg7ZqM7IKsIl0pLGNtTm06aGkoSCxbIuqzhOyVvS/ssq3qtazri7Tri7nsnpAg7J2066aEIl0pLGNtRHA6aGkoSCxbIuqzhOyVvS/ssq3qtazri7Tri7nsnpAg67aA7IScIl0pLGNtUGg6aGkoSCxbIuqzhOyVvS/ssq3qtazri7Tri7nsnpAg7Jew65297LKYIl0pLGNtRW06aGkoSCxbIuqzhOyVvS/ssq3qtazri7Tri7nsnpAg7J2066mU7J28Il0pLGRtQ286aGkoSCxbIuu2gOyEnOuLtOuLueyekCDtmozsgqwiXSksZG1ObTpoaShILFsi67aA7ISc64u064u57J6QIOydtOumhCJdKSxkbURwOmhpKEgsWyLrtoDshJzri7Tri7nsnpAg67aA7IScIl0pLGRtUGg6aGkoSCxbIuu2gOyEnOuLtOuLueyekCDsl7Drnb3sspgiXSksZG1FbTpoaShILFsi67aA7ISc64u064u57J6QIOydtOuplOydvCJdKX07CiAgICAgIGNvbnN0IG91dD1bXTtmb3IoY29uc3Qgcm93IG9mIFIuc2xpY2UoaCsyKSl7Y29uc3QgeD17Y2F0OkkuY2F0Pj0wP1N0cmluZyhyb3dbSS5jYXRdfHwiIikudHJpbSgpOiIiLGNvcnA6SS5jb3JwPj0wP1N0cmluZyhyb3dbSS5jb3JwXXx8IiIpLnRyaW0oKToiIixjb2RlOkkuY29kZT49MD9TdHJpbmcocm93W0kuY29kZV18fCIiKS50cmltKCk6IiIsbmFtZTpJLm5hbWU+PTA/U3RyaW5nKHJvd1tJLm5hbWVdfHwiIikudHJpbSgpOiIiLHBheTpJLnBheT49MD9TdHJpbmcocm93W0kucGF5XXx8IiIpLnRyaW0oKToiIix5bjpJLnluPj0wP1N0cmluZyhyb3dbSS55bl18fCIiKS50cmltKCk6IiIsb3JkZXI6SS5vcmRlcj49MD9TdHJpbmcocm93W0kub3JkZXJdfHwiIikudHJpbSgpOiIiLHBtOkkucG0+PTA/U3RyaW5nKHJvd1tJLnBtXXx8IiIpLnRyaW0oKToiIixzdGF0dXM6SS5zdGF0dXM+PTA/U3RyaW5nKHJvd1tJLnN0YXR1c118fCIiKS50cmltKCk6IiIsY2xpZW50OkkuY2xpZW50Pj0wP1N0cmluZyhyb3dbSS5jbGllbnRdfHwiIikudHJpbSgpOiIiLHNwbGl0Okkuc3BsaXQ+PTA/U3RyaW5nKHJvd1tJLnNwbGl0XXx8IiIpLnRyaW0oKToiIixjRGF0ZTpJLmNEYXRlPj0wP1N0cmluZyhyb3dbSS5jRGF0ZV18fCIiKS50cmltKCk6IiIsc0RhdGU6SS5zRGF0ZT49MD9TdHJpbmcocm93W0kuc0RhdGVdfHwiIikudHJpbSgpOiIiLGVEYXRlOkkuZURhdGU+PTA/U3RyaW5nKHJvd1tJLmVEYXRlXXx8IiIpLnRyaW0oKToiIixjU3VwOkkuY1N1cD49MD9udW0ocm93W0kuY1N1cF0pOjAsY1ZhdDpJLmNWYXQ+PTA/bnVtKHJvd1tJLmNWYXRdKTowLGNUb3Q6SS5jVG90Pj0wP251bShyb3dbSS5jVG90XSk6MCxjb2xEYXRlOkkuY29sRGF0ZT49MD9TdHJpbmcocm93W0kuY29sRGF0ZV18fCIiKS50cmltKCk6IiIsc1N1cDpJLnNTdXA+PTA/bnVtKHJvd1tJLnNTdXBdKTowLHNWYXQ6SS5zVmF0Pj0wP251bShyb3dbSS5zVmF0XSk6MCxzVG90Okkuc1RvdD49MD9udW0ocm93W0kuc1RvdF0pOjAsY29sOkkuY29sPj0wP251bShyb3dbSS5jb2xdKTowLHJlY3Y6SS5yZWN2Pj0wP251bShyb3dbSS5yZWN2XSk6MCxyYXRlUmF3Okkucj49MD9TdHJpbmcocm93W0kucl18fCIiKS50cmltKCk6IiIsbm90ZTpJLm5vdGU+PTA/U3RyaW5nKHJvd1tJLm5vdGVdfHwiIikudHJpbSgpOiIiLGNtQ286SS5jbUNvPj0wP1N0cmluZyhyb3dbSS5jbUNvXXx8IiIpLnRyaW0oKToiIixjbU5tOkkuY21ObT49MD9TdHJpbmcocm93W0kuY21ObV18fCIiKS50cmltKCk6IiIsY21EcDpJLmNtRHA+PTA/U3RyaW5nKHJvd1tJLmNtRHBdfHwiIikudHJpbSgpOiIiLGNtUGg6SS5jbVBoPj0wP1N0cmluZyhyb3dbSS5jbVBoXXx8IiIpLnRyaW0oKToiIixjbUVtOkkuY21FbT49MD9TdHJpbmcocm93W0kuY21FbV18fCIiKS50cmltKCk6IiIsZG1DbzpJLmRtQ28+PTA/U3RyaW5nKHJvd1tJLmRtQ29dfHwiIikudHJpbSgpOiIiLGRtTm06SS5kbU5tPj0wP1N0cmluZyhyb3dbSS5kbU5tXXx8IiIpLnRyaW0oKToiIixkbURwOkkuZG1EcD49MD9TdHJpbmcocm93W0kuZG1EcF18fCIiKS50cmltKCk6IiIsZG1QaDpJLmRtUGg+PTA/U3RyaW5nKHJvd1tJLmRtUGhdfHwiIikudHJpbSgpOiIiLGRtRW06SS5kbUVtPj0wP1N0cmluZyhyb3dbSS5kbUVtXXx8IiIpLnRyaW0oKToiIn07CiAgICAgICAgaWYoIXgubmFtZSYmIXguY29kZSljb250aW51ZTtpZigheC5jb2RlJiYheC5jb3JwJiYheC5jbGllbnQmJiF4LnBtKWNvbnRpbnVlO2lmKCF4LmNUb3QpeC5jVG90PXguY1N1cCt4LmNWYXQ7aWYoIXguc1RvdCl4LnNUb3Q9eC5zU3VwK3guc1ZhdDtpZigheC5yZWN2KXgucmVjdj1NYXRoLm1heCgwLHguc1RvdC14LmNvbCk7eC5yYXRlPXJhdGUoeC5yYXRlUmF3LHguY29sLHguc1RvdCk7b3V0LnB1c2goeCk7fQogICAgICByZXR1cm4gb3V0OwogICAgfQogICAgY29uc3QgaGs9dj0+U3RyaW5nKHZ8fCIiKS5ub3JtYWxpemUoIk5GS0MiKS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1teMC05YS166rCALe2eo10rL2csIiIpOwogICAgZnVuY3Rpb24gZmluZEhlYWRlckluZGV4KGhlYWRlcnMsY2FuZHMpewogICAgICBjb25zdCBub3JtYWxpemVkPShoZWFkZXJzfHxbXSkubWFwKGhrKTsKICAgICAgY29uc3QgY2FuZGlkYXRlcz0oY2FuZHN8fFtdKS5tYXAoaGspLmZpbHRlcihCb29sZWFuKTsKICAgICAgZm9yKGNvbnN0IGMgb2YgY2FuZGlkYXRlcyl7CiAgICAgICAgZm9yKGxldCBpPTA7aTxub3JtYWxpemVkLmxlbmd0aDtpKyspewogICAgICAgICAgaWYoIW5vcm1hbGl6ZWRbaV0pIGNvbnRpbnVlOwogICAgICAgICAgaWYobm9ybWFsaXplZFtpXT09PWN8fG5vcm1hbGl6ZWRbaV0uaW5jbHVkZXMoYyl8fGMuaW5jbHVkZXMobm9ybWFsaXplZFtpXSkpIHJldHVybiBpOwogICAgICAgIH0KICAgICAgfQogICAgICByZXR1cm4gLTE7CiAgICB9CiAgICBmdW5jdGlvbiB0ZXh0QXQocm93LGlkeCl7cmV0dXJuIGlkeD49MD9TdHJpbmcocm93W2lkeF0/PyIiKS5yZXBsYWNlKC9cdTAwYTAvZywiICIpLnJlcGxhY2UoL1xzKy9nLCIgIikudHJpbSgpOiIiO30KICAgIGZ1bmN0aW9uIG1vbmV5QXQocm93LGlkeCl7cmV0dXJuIGlkeD49MD9udW0ocm93W2lkeF0pOjA7fQogICAgZnVuY3Rpb24gbGFzdFRleHQodmFsdWVzKXtmb3IobGV0IGk9dmFsdWVzLmxlbmd0aC0xO2k+PTA7aS0tKXtjb25zdCB2PWQodmFsdWVzW2ldKTtpZih2IT09Ii0iKXJldHVybiB2O31yZXR1cm4gIi0iO30KICAgIGZ1bmN0aW9uIHBheW1lbnRTdW1tYXJ5KHBheW1lbnRzKXsKICAgICAgY29uc3QgbGFiZWxzPVsuLi5uZXcgU2V0KChwYXltZW50c3x8W10pLm1hcChwPT5TdHJpbmcocC5wYXl8fCIiKS50cmltKCkpLmZpbHRlcihCb29sZWFuKSldOwogICAgICBpZighbGFiZWxzLmxlbmd0aCkgcmV0dXJuICItIjsKICAgICAgaWYobGFiZWxzLmxlbmd0aDw9MikgcmV0dXJuIGxhYmVscy5qb2luKCIsICIpOwogICAgICByZXR1cm4gYCR7bGFiZWxzLnNsaWNlKDAsMikuam9pbigiLCAiKX0g7Jm4ICR7bGFiZWxzLmxlbmd0aC0yfeqxtGA7CiAgICB9CiAgICBmdW5jdGlvbiBwYXltZW50UmVjb3JkKHgsZmFsbGJhY2tQYXkpewogICAgICBjb25zdCBzdXBwbHk9eC5zU3VwfHwwLHZhdD14LnNWYXR8fDAsdG90YWw9eC5zVG90fHxzdXBwbHkrdmF0LGNvbGxlY3RlZD14LmNvbHx8MDsKICAgICAgcmV0dXJuIHtwYXk6U3RyaW5nKHgucGF5fHx4Lm5hbWV8fGZhbGxiYWNrUGF5fHwi66+47J6F66ClIikudHJpbSgpLHN0YXR1czp4LnN0YXR1c3x8IiIsaXNzdWVEYXRlOnguaXNzdWVEYXRlfHx4LmNEYXRlfHwiIixjb2xsZWN0RGF0ZTp4LmNvbERhdGV8fCIiLHN1cHBseSx2YXQsdG90YWwsY29sbGVjdGVkLHJlY2VpdmFibGU6eC5yZWN2fHxNYXRoLm1heCgwLHRvdGFsLWNvbGxlY3RlZCkscmF0ZTpyYXRlKHgucmF0ZVJhdyxjb2xsZWN0ZWQsdG90YWwpLG5vdGU6U3RyaW5nKHgubm90ZXx8IiIpLnRyaW0oKX07CiAgICB9CiAgICBmdW5jdGlvbiBmaW5hbGl6ZVByb2plY3QocHJvamVjdCl7CiAgICAgIGNvbnN0IHBheW1lbnRzPShwcm9qZWN0LnBheW1lbnRzfHxbXSkuZmlsdGVyKHA9PnAucGF5fHxwLmlzc3VlRGF0ZXx8cC5jb2xsZWN0RGF0ZXx8cC50b3RhbHx8cC5jb2xsZWN0ZWR8fHAucmVjZWl2YWJsZSk7CiAgICAgIGlmKCFwYXltZW50cy5sZW5ndGgmJihwcm9qZWN0Lmlzc3VlRGF0ZXx8cHJvamVjdC5jb2xEYXRlfHxwcm9qZWN0LnNTdXB8fHByb2plY3Quc1ZhdHx8cHJvamVjdC5zVG90fHxwcm9qZWN0LmNvbHx8cHJvamVjdC5yZWN2KSkgcGF5bWVudHMucHVzaChwYXltZW50UmVjb3JkKHByb2plY3QscHJvamVjdC5wYXl8fCLsnbzqtIQiKSk7CiAgICAgIHByb2plY3QucGF5bWVudHM9cGF5bWVudHM7CiAgICAgIHByb2plY3QucGF5PXBheW1lbnRTdW1tYXJ5KHBheW1lbnRzKTsKICAgICAgcHJvamVjdC5wZXJpb2RUZXh0PShkKHByb2plY3Quc0RhdGUpPT09Ii0iJiZkKHByb2plY3QuZURhdGUpPT09Ii0iKT8iLSI6YCR7ZChwcm9qZWN0LnNEYXRlKX0gfiAke2QocHJvamVjdC5lRGF0ZSl9YDsKICAgICAgcHJvamVjdC5pc3N1ZURhdGVTdW1tYXJ5PWxhc3RUZXh0KHBheW1lbnRzLm1hcChwPT5wLmlzc3VlRGF0ZSkpOwogICAgICBwcm9qZWN0LmNvbGxlY3REYXRlU3VtbWFyeT1sYXN0VGV4dChwYXltZW50cy5tYXAocD0+cC5jb2xsZWN0RGF0ZSkpOwogICAgICByZXR1cm4gcHJvamVjdDsKICAgIH0KICAgIGZ1bmN0aW9uIG5vcm1hbGl6ZVByb2plY3RLZXkodil7cmV0dXJuIGhrKHYpO30KICAgIGZ1bmN0aW9uIG5vcm1hbGl6ZVByb2plY3RCYXNlKHYpewogICAgICByZXR1cm4gaGsoU3RyaW5nKHZ8fCIiKS5yZXBsYWNlKC9cKFteKV0qXCkvZywiICIpLnJlcGxhY2UoL1xbW15cXV0qXF0vZywiICIpKTsKICAgIH0KICAgIGZ1bmN0aW9uIHN1bW1hcml6ZU91dHNvdXJjZVZlbmRvcnModmVuZG9ycyl7CiAgICAgIGNvbnN0IGxpc3Q9KHZlbmRvcnN8fFtdKS5maWx0ZXIoQm9vbGVhbik7CiAgICAgIGlmKCFsaXN0Lmxlbmd0aCkgcmV0dXJuICIiOwogICAgICBpZihsaXN0Lmxlbmd0aDw9MikgcmV0dXJuIGxpc3Quam9pbigiLCAiKTsKICAgICAgcmV0dXJuIGAke2xpc3Quc2xpY2UoMCwyKS5qb2luKCIsICIpfSBcdUM2NzggJHtsaXN0Lmxlbmd0aC0yfVx1QUNGM2A7CiAgICB9CiAgICBmdW5jdGlvbiBjYWxjVmF0RXhjbHVkZWQodG90YWwpe3JldHVybiB0b3RhbD4wP01hdGgucm91bmQodG90YWwvMS4xKTowO30KICAgIGZ1bmN0aW9uIG91dHNvdXJjZVRvdGFsTGFiZWwoaXRlbSl7CiAgICAgIGNvbnN0IGV4PU1hdGgucm91bmQoaXRlbSYmaXRlbS5jb250cmFjdEV4fHwwKTsKICAgICAgY29uc3QgdG90YWw9TWF0aC5yb3VuZChpdGVtJiZpdGVtLmNvbnRyYWN0SW58fDApOwogICAgICBpZihleD4wKSByZXR1cm4gd29uKGV4KTsKICAgICAgaWYodG90YWw+MCkgcmV0dXJuIHdvbihjYWxjVmF0RXhjbHVkZWQodG90YWwpKTsKICAgICAgcmV0dXJuICItIjsKICAgIH0KICAgIGZ1bmN0aW9uIGNsZWFuVmVuZG9yTmFtZSh2YWx1ZSxzaGVldE5hbWUpewogICAgICBjb25zdCByYXc9U3RyaW5nKHZhbHVlfHxzaGVldE5hbWV8fCIiKS50cmltKCk7CiAgICAgIHJldHVybiByYXcucmVwbGFjZSgvXlwoXHVDOEZDXClccyovLCIiKS5yZXBsYWNlKC9eXHVDOEZDXHVDMkREXHVENjhDXHVDMEFDXHMqLywiIikucmVwbGFjZSgvXlx1QzY3OFx1QzhGQy8sIiIpLnRyaW0oKXx8U3RyaW5nKHNoZWV0TmFtZXx8Ilx1QzY3OFx1QzhGQyIpLnJlcGxhY2UoL15cdUM2NzhcdUM4RkMvLCIiKS50cmltKCl8fCJcdUM2NzhcdUM4RkMiOwogICAgfQogICAgZnVuY3Rpb24gZ2V0T3V0c291cmNlTGF5b3V0KHJvd3MpewogICAgICBjb25zdCBoZWFkZXI9cm93c1szXXx8W107CiAgICAgIGNvbnN0IGhhc1ZhdENvbnRyYWN0PVN0cmluZyhoZWFkZXJbOV0/PyIiKS5pbmNsdWRlcygiVkFUXHVEM0VDXHVENTY4Iik7CiAgICAgIGlmKGhhc1ZhdENvbnRyYWN0KXsKICAgICAgICByZXR1cm4ge2hhc1ZhdENvbnRyYWN0OnRydWUsY29udHJhY3RFeDo4LGNvbnRyYWN0SW46OSxpbnZvaWNlRGF0ZToxMCxwYXltZW50RGF0ZToxMSxwYXltZW50QW1vdW50OjEyLHJlbWFpbmluZ0Ftb3VudDoxMyxwcm9ncmVzczoxNCxsYWJlbDoxNSxub3RlOjE2fTsKICAgICAgfQogICAgICByZXR1cm4ge2hhc1ZhdENvbnRyYWN0OmZhbHNlLGNvbnRyYWN0RXg6OCxjb250cmFjdEluOi0xLGludm9pY2VEYXRlOjkscGF5bWVudERhdGU6MTAscGF5bWVudEFtb3VudDoxMSxyZW1haW5pbmdBbW91bnQ6MTIscHJvZ3Jlc3M6MTMsbGFiZWw6LTEsbm90ZToxNH07CiAgICB9CiAgICBmdW5jdGlvbiBzaG91bGRTdG9wT3V0c291cmNlUm93cyhyb3cpewogICAgICBjb25zdCBmaXJzdD1TdHJpbmcocm93WzBdPz8iIikudHJpbSgpOwogICAgICBjb25zdCBwcm9qZWN0PVN0cmluZyhyb3dbMl0/PyIiKS50cmltKCk7CiAgICAgIGNvbnN0IGRldGFpbD1TdHJpbmcocm93WzNdPz8iIikudHJpbSgpOwogICAgICBjb25zdCBqb2luZWQ9W3Jvd1swXSxyb3dbMl0scm93WzNdLHJvd1sxM10scm93WzE0XSxyb3dbMTVdLHJvd1sxNl1dLm1hcCh2PT5TdHJpbmcodj8/IiIpLnRyaW0oKSkuam9pbigiICIpOwogICAgICByZXR1cm4gZmlyc3Q9PT0iXHVCMEEwXHVDOURDInx8Zmlyc3Quc3RhcnRzV2l0aCgiKlx1Qzc5MFx1QjhDQ1x1Q0Q5Q1x1Q0M5OCIpfHxwcm9qZWN0PT09Ilx1QzgwMVx1QzY5NCJ8fGRldGFpbD09PSJcdUM4MDFcdUM2OTQifHxwcm9qZWN0LmluY2x1ZGVzKCJcdUM3OTBcdUI4Q0NcdUNEOUNcdUNDOTgiKXx8am9pbmVkLmluY2x1ZGVzKCJcdUM2RDBcdUFDQzRcdUM1N0RcdUFFMDgiKXx8am9pbmVkLmluY2x1ZGVzKCJcdUMyMThcdUFFMDgvXHVDOUMwXHVBRTA5XHVDQzk4Iik7CiAgICB9CiAgICBmdW5jdGlvbiBnZXRPdXRzb3VyY2VFbnRyeShtYXAsa2V5LG5hbWUpewogICAgICBjb25zdCBjdXJyZW50PW1hcC5nZXQoa2V5KTsKICAgICAgaWYoY3VycmVudCkgcmV0dXJuIGN1cnJlbnQ7CiAgICAgIGNvbnN0IG5leHQ9e25hbWUsa2V5LGJhc2VLZXk6bm9ybWFsaXplUHJvamVjdEJhc2UobmFtZSksdmVuZG9yczpuZXcgU2V0KCksaXRlbXM6W10sY29udHJhY3Q6MCxjb250cmFjdEluOjAscGFpZDowLHBhaWRJbjowLHJlbWFpbmluZzowLHJlbWFpbmluZ0luOjB9OwogICAgICBtYXAuc2V0KGtleSxuZXh0KTsKICAgICAgcmV0dXJuIG5leHQ7CiAgICB9CiAgICBmdW5jdGlvbiBjcmVhdGVPdXRzb3VyY2VJdGVtKGVudHJ5LHZlbmRvcixwcm9qZWN0TmFtZSxkZXRhaWwscm93LGxheW91dCl7CiAgICAgIGNvbnN0IGNvbnRyYWN0RXg9bnVtKHJvd1tsYXlvdXQuY29udHJhY3RFeF0pOwogICAgICBjb25zdCBjb250cmFjdEluPWxheW91dC5jb250cmFjdEluPj0wP251bShyb3dbbGF5b3V0LmNvbnRyYWN0SW5dKTowOwogICAgICBjb25zdCBuZXh0PXsKICAgICAgICB2ZW5kb3IsCiAgICAgICAgcHJvamVjdE5hbWUsCiAgICAgICAgZGV0YWlsOlN0cmluZyhkZXRhaWx8fCItIikudHJpbSgpfHwiLSIsCiAgICAgICAgY29udHJhY3REYXRlOlN0cmluZyhyb3dbNF0/PyIiKS50cmltKCksCiAgICAgICAgc3RhcnREYXRlOlN0cmluZyhyb3dbNV0/PyIiKS50cmltKCksCiAgICAgICAgZW5kRGF0ZTpTdHJpbmcocm93WzddPz8iIikudHJpbSgpLAogICAgICAgIGNvbnRyYWN0RXgsCiAgICAgICAgY29udHJhY3RJbiwKICAgICAgICBpbnZvaWNlRGF0ZTpTdHJpbmcocm93W2xheW91dC5pbnZvaWNlRGF0ZV0/PyIiKS50cmltKCksCiAgICAgICAgcHJvZ3Jlc3M6U3RyaW5nKHJvd1tsYXlvdXQucHJvZ3Jlc3NdPz8iIikudHJpbSgpLAogICAgICAgIG5vdGU6IiIsCiAgICAgICAgcGF5bWVudHM6W10KICAgICAgfTsKICAgICAgZW50cnkuaXRlbXMucHVzaChuZXh0KTsKICAgICAgcmV0dXJuIG5leHQ7CiAgICB9CiAgICBmdW5jdGlvbiBidWlsZE91dHNvdXJjZVBheW1lbnQoaXRlbSxyb3csbGF5b3V0KXsKICAgICAgY29uc3QgaW52b2ljZURhdGU9U3RyaW5nKHJvd1tsYXlvdXQuaW52b2ljZURhdGVdPz8iIikudHJpbSgpOwogICAgICBjb25zdCBwYXltZW50RGF0ZT1TdHJpbmcocm93W2xheW91dC5wYXltZW50RGF0ZV0/PyIiKS50cmltKCk7CiAgICAgIGNvbnN0IHBheW1lbnRDZWxsPVN0cmluZyhyb3dbbGF5b3V0LnBheW1lbnRBbW91bnRdPz8iIikudHJpbSgpOwogICAgICBjb25zdCByZW1haW5pbmdDZWxsPVN0cmluZyhyb3dbbGF5b3V0LnJlbWFpbmluZ0Ftb3VudF0/PyIiKS50cmltKCk7CiAgICAgIGNvbnN0IHBheW1lbnRSYXc9bnVtKHJvd1tsYXlvdXQucGF5bWVudEFtb3VudF0pOwogICAgICBjb25zdCByZW1haW5pbmdSYXc9bnVtKHJvd1tsYXlvdXQucmVtYWluaW5nQW1vdW50XSk7CiAgICAgIGNvbnN0IGxhYmVsPWxheW91dC5sYWJlbD49MD9TdHJpbmcocm93W2xheW91dC5sYWJlbF0/PyIiKS50cmltKCk6IiI7CiAgICAgIGNvbnN0IG5vdGU9bGF5b3V0Lm5vdGU+PTA/U3RyaW5nKHJvd1tsYXlvdXQubm90ZV0/PyIiKS50cmltKCk6U3RyaW5nKHJvd1sxNF0/PyIiKS50cmltKCk7CiAgICAgIGlmKCEoaW52b2ljZURhdGV8fHBheW1lbnREYXRlfHxwYXltZW50UmF3fHxyZW1haW5pbmdSYXd8fGxhYmVsfHxub3RlKSkgcmV0dXJuIG51bGw7CiAgICAgIGlmKG5vdGUmJiFsYWJlbCYmIXBheW1lbnREYXRlJiYhcGF5bWVudFJhdyYmIXJlbWFpbmluZ1JhdyYmIWludm9pY2VEYXRlKXsKICAgICAgICBpdGVtLm5vdGU9bm90ZTsKICAgICAgfQogICAgICByZXR1cm4gewogICAgICAgIGxhYmVsLAogICAgICAgIG5vdGUsCiAgICAgICAgaW52b2ljZURhdGUsCiAgICAgICAgcGF5bWVudERhdGUsCiAgICAgICAgcGF5bWVudEtub3duOnBheW1lbnRDZWxsIT09IiIsCiAgICAgICAgcmVtYWluaW5nS25vd246cmVtYWluaW5nQ2VsbCE9PSIiLAogICAgICAgIHBheW1lbnRFeDpwYXltZW50UmF3PyhsYXlvdXQuaGFzVmF0Q29udHJhY3Q/Y2FsY1ZhdEV4Y2x1ZGVkKHBheW1lbnRSYXcpOnBheW1lbnRSYXcpOjAsCiAgICAgICAgcGF5bWVudEluOmxheW91dC5oYXNWYXRDb250cmFjdD9wYXltZW50UmF3OjAsCiAgICAgICAgcmVtYWluaW5nRXg6cmVtYWluaW5nUmF3PyhsYXlvdXQuaGFzVmF0Q29udHJhY3Q/Y2FsY1ZhdEV4Y2x1ZGVkKHJlbWFpbmluZ1Jhdyk6cmVtYWluaW5nUmF3KTowLAogICAgICAgIHJlbWFpbmluZ0luOmxheW91dC5oYXNWYXRDb250cmFjdD9yZW1haW5pbmdSYXc6MAogICAgICB9OwogICAgfQogICAgZnVuY3Rpb24gZmluYWxpemVPdXRzb3VyY2VJdGVtKGl0ZW0pewogICAgICBjb25zdCBwYXltZW50cz1BcnJheS5pc0FycmF5KGl0ZW0ucGF5bWVudHMpP2l0ZW0ucGF5bWVudHMuZmlsdGVyKEJvb2xlYW4pOltdOwogICAgICBjb25zdCBwYWlkRXg9TWF0aC5yb3VuZChwYXltZW50cy5yZWR1Y2UoKHN1bSxwKT0+c3VtKyhwLnBheW1lbnRFeHx8MCksMCkpOwogICAgICBjb25zdCBwYWlkSW49TWF0aC5yb3VuZChwYXltZW50cy5yZWR1Y2UoKHN1bSxwKT0+c3VtKyhwLnBheW1lbnRJbnx8MCksMCkpOwogICAgICBsZXQgcmVtYWluaW5nRXg9MDsKICAgICAgbGV0IHJlbWFpbmluZ0luPTA7CiAgICAgIGZvcihsZXQgaT1wYXltZW50cy5sZW5ndGgtMTtpPj0wO2ktLSl7CiAgICAgICAgY29uc3QgcGF5bWVudD1wYXltZW50c1tpXTsKICAgICAgICBpZihwYXltZW50LnJlbWFpbmluZ0tub3duKXsKICAgICAgICAgIHJlbWFpbmluZ0V4PU1hdGgucm91bmQocGF5bWVudC5yZW1haW5pbmdFeHx8MCk7CiAgICAgICAgICByZW1haW5pbmdJbj1NYXRoLnJvdW5kKHBheW1lbnQucmVtYWluaW5nSW58fDApOwogICAgICAgICAgYnJlYWs7CiAgICAgICAgfQogICAgICB9CiAgICAgIGlmKCFyZW1haW5pbmdFeCYmaXRlbS5jb250cmFjdEV4PjApIHJlbWFpbmluZ0V4PU1hdGgubWF4KDAsTWF0aC5yb3VuZChpdGVtLmNvbnRyYWN0RXgtcGFpZEV4KSk7CiAgICAgIGlmKCFyZW1haW5pbmdJbiYmaXRlbS5jb250cmFjdEluPjApIHJlbWFpbmluZ0luPU1hdGgubWF4KDAsTWF0aC5yb3VuZChpdGVtLmNvbnRyYWN0SW4tcGFpZEluKSk7CiAgICAgIHJldHVybiB7Li4uaXRlbSxwYXltZW50cyxwYWlkRXgscGFpZEluLHJlbWFpbmluZ0V4LHJlbWFpbmluZ0lufTsKICAgIH0KICAgIGZ1bmN0aW9uIHBhcnNlT3V0c291cmNlUm93cyhyb3dzLHNoZWV0TmFtZSxtYXApewogICAgICBpZighcm93c3x8cm93cy5sZW5ndGg8NikgcmV0dXJuOwogICAgICBjb25zdCB2ZW5kb3I9Y2xlYW5WZW5kb3JOYW1lKChyb3dzWzFdfHxbXSlbMF0sc2hlZXROYW1lKTsKICAgICAgY29uc3QgbGF5b3V0PWdldE91dHNvdXJjZUxheW91dChyb3dzKTsKICAgICAgbGV0IGN1cnJlbnRLZXk9IiIsY3VycmVudE5hbWU9IiIsY3VycmVudEl0ZW09bnVsbDsKICAgICAgZm9yKGNvbnN0IHJvdyBvZiByb3dzLnNsaWNlKDUpKXsKICAgICAgICBpZihzaG91bGRTdG9wT3V0c291cmNlUm93cyhyb3cpKSBicmVhazsKICAgICAgICBjb25zdCBwcm9qZWN0TmFtZT1TdHJpbmcocm93WzJdPz8iIikudHJpbSgpOwogICAgICAgIGNvbnN0IHByb2plY3RLZXk9bm9ybWFsaXplUHJvamVjdEtleShwcm9qZWN0TmFtZSk7CiAgICAgICAgY29uc3QgZGV0YWlsPVN0cmluZyhyb3dbM10/PyIiKS50cmltKCk7CiAgICAgICAgY29uc3QgdmFsaWRQcm9qZWN0PXByb2plY3RLZXkmJnByb2plY3RLZXkhPT0icmVmIjsKICAgICAgICBpZih2YWxpZFByb2plY3QpewogICAgICAgICAgY3VycmVudEtleT1wcm9qZWN0S2V5OwogICAgICAgICAgY3VycmVudE5hbWU9cHJvamVjdE5hbWU7CiAgICAgICAgICBjb25zdCBlbnRyeT1nZXRPdXRzb3VyY2VFbnRyeShtYXAsY3VycmVudEtleSxjdXJyZW50TmFtZSk7CiAgICAgICAgICBlbnRyeS52ZW5kb3JzLmFkZCh2ZW5kb3IpOwogICAgICAgICAgY3VycmVudEl0ZW09Y3JlYXRlT3V0c291cmNlSXRlbShlbnRyeSx2ZW5kb3IsY3VycmVudE5hbWUsZGV0YWlsLHJvdyxsYXlvdXQpOwogICAgICAgICAgY29uc3QgZmlyc3RQYXltZW50PWJ1aWxkT3V0c291cmNlUGF5bWVudChjdXJyZW50SXRlbSxyb3csbGF5b3V0KTsKICAgICAgICAgIGlmKGZpcnN0UGF5bWVudCkgY3VycmVudEl0ZW0ucGF5bWVudHMucHVzaChmaXJzdFBheW1lbnQpOwogICAgICAgICAgY29udGludWU7CiAgICAgICAgfQogICAgICAgIGlmKCFjdXJyZW50S2V5KSBjb250aW51ZTsKICAgICAgICBjb25zdCBlbnRyeT1nZXRPdXRzb3VyY2VFbnRyeShtYXAsY3VycmVudEtleSxjdXJyZW50TmFtZSk7CiAgICAgICAgZW50cnkudmVuZG9ycy5hZGQodmVuZG9yKTsKICAgICAgICBjb25zdCBjb250cmFjdEV4PW51bShyb3dbbGF5b3V0LmNvbnRyYWN0RXhdKTsKICAgICAgICBjb25zdCBjb250cmFjdEluPWxheW91dC5jb250cmFjdEluPj0wP251bShyb3dbbGF5b3V0LmNvbnRyYWN0SW5dKTowOwogICAgICAgIGNvbnN0IGhhc0ZpbmFuY2lhbFJvdz0hIShjb250cmFjdEV4fHxjb250cmFjdElufHxudW0ocm93W2xheW91dC5wYXltZW50QW1vdW50XSl8fG51bShyb3dbbGF5b3V0LnJlbWFpbmluZ0Ftb3VudF0pKTsKICAgICAgICBjb25zdCBoYXNNZXRhUm93PSEhKFN0cmluZyhyb3dbbGF5b3V0Lmludm9pY2VEYXRlXT8/IiIpLnRyaW0oKXx8U3RyaW5nKHJvd1tsYXlvdXQucGF5bWVudERhdGVdPz8iIikudHJpbSgpfHxTdHJpbmcocm93W2xheW91dC5wcm9ncmVzc10/PyIiKS50cmltKCl8fGRldGFpbCk7CiAgICAgICAgaWYoZGV0YWlsJiZoYXNNZXRhUm93KXsKICAgICAgICAgIGN1cnJlbnRJdGVtPWNyZWF0ZU91dHNvdXJjZUl0ZW0oZW50cnksdmVuZG9yLGN1cnJlbnROYW1lLGRldGFpbCxyb3csbGF5b3V0KTsKICAgICAgICAgIGNvbnN0IHBheW1lbnQ9YnVpbGRPdXRzb3VyY2VQYXltZW50KGN1cnJlbnRJdGVtLHJvdyxsYXlvdXQpOwogICAgICAgICAgaWYocGF5bWVudCkgY3VycmVudEl0ZW0ucGF5bWVudHMucHVzaChwYXltZW50KTsKICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIH0KICAgICAgICBpZighY3VycmVudEl0ZW0pewogICAgICAgICAgaWYoIShoYXNGaW5hbmNpYWxSb3d8fGhhc01ldGFSb3cpKSBjb250aW51ZTsKICAgICAgICAgIGN1cnJlbnRJdGVtPWNyZWF0ZU91dHNvdXJjZUl0ZW0oZW50cnksdmVuZG9yLGN1cnJlbnROYW1lLGRldGFpbHx8Ilx1QzY3OFx1QzhGQyBcdUFDQzRcdUM1N0QiLHJvdyxsYXlvdXQpOwogICAgICAgIH1lbHNlewogICAgICAgICAgaWYoY29udHJhY3RFeD4wKSBjdXJyZW50SXRlbS5jb250cmFjdEV4Kz1jb250cmFjdEV4OwogICAgICAgICAgaWYoY29udHJhY3RJbj4wKSBjdXJyZW50SXRlbS5jb250cmFjdEluKz1jb250cmFjdEluOwogICAgICAgICAgaWYoIWN1cnJlbnRJdGVtLnByb2dyZXNzKSBjdXJyZW50SXRlbS5wcm9ncmVzcz1TdHJpbmcocm93W2xheW91dC5wcm9ncmVzc10/PyIiKS50cmltKCk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHBheW1lbnQ9YnVpbGRPdXRzb3VyY2VQYXltZW50KGN1cnJlbnRJdGVtLHJvdyxsYXlvdXQpOwogICAgICAgIGlmKHBheW1lbnQpIGN1cnJlbnRJdGVtLnBheW1lbnRzLnB1c2gocGF5bWVudCk7CiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIHBhcnNlT3V0c291cmNlU2hlZXRzKHdvcmtib29rKXsKICAgICAgY29uc3QgbWFwPW5ldyBNYXAoKTsKICAgICAgY29uc3QgbmFtZXM9KHdvcmtib29rJiZ3b3JrYm9vay5TaGVldE5hbWVzKXx8W107CiAgICAgIGZvcihjb25zdCBzaGVldE5hbWUgb2YgbmFtZXMpewogICAgICAgIGlmKCFTdHJpbmcoc2hlZXROYW1lfHwiIikuc3RhcnRzV2l0aCgiXHVDNjc4XHVDOEZDIikpIGNvbnRpbnVlOwogICAgICAgIGNvbnN0IHNoZWV0PXdvcmtib29rLlNoZWV0c1tzaGVldE5hbWVdOwogICAgICAgIGlmKCFzaGVldCkgY29udGludWU7CiAgICAgICAgY29uc3Qgcm93cz1YTFNYLnV0aWxzLnNoZWV0X3RvX2pzb24oc2hlZXQse2hlYWRlcjoxLHJhdzpmYWxzZSxkZWZ2YWw6IiJ9KTsKICAgICAgICBwYXJzZU91dHNvdXJjZVJvd3Mocm93cyxzaGVldE5hbWUsbWFwKTsKICAgICAgfQogICAgICBmb3IoY29uc3QgZW50cnkgb2YgbWFwLnZhbHVlcygpKXsKICAgICAgICBlbnRyeS5pdGVtcz1lbnRyeS5pdGVtcy5tYXAoZmluYWxpemVPdXRzb3VyY2VJdGVtKS5maWx0ZXIoaXRlbT0+aXRlbS5jb250cmFjdEV4fHxpdGVtLmNvbnRyYWN0SW58fGl0ZW0ucGFpZEV4fHxpdGVtLnBhaWRJbnx8aXRlbS5yZW1haW5pbmdFeHx8aXRlbS5yZW1haW5pbmdJbnx8aXRlbS5kZXRhaWx8fGl0ZW0ucGF5bWVudHMubGVuZ3RoKTsKICAgICAgICBlbnRyeS5jb250cmFjdD1NYXRoLnJvdW5kKGVudHJ5Lml0ZW1zLnJlZHVjZSgoc3VtLGl0ZW0pPT5zdW0rKGl0ZW0uY29udHJhY3RFeHx8MCksMCkpOwogICAgICAgIGVudHJ5LmNvbnRyYWN0SW49TWF0aC5yb3VuZChlbnRyeS5pdGVtcy5yZWR1Y2UoKHN1bSxpdGVtKT0+c3VtKyhpdGVtLmNvbnRyYWN0SW58fDApLDApKTsKICAgICAgICBlbnRyeS5wYWlkPU1hdGgucm91bmQoZW50cnkuaXRlbXMucmVkdWNlKChzdW0saXRlbSk9PnN1bSsoaXRlbS5wYWlkRXh8fDApLDApKTsKICAgICAgICBlbnRyeS5wYWlkSW49TWF0aC5yb3VuZChlbnRyeS5pdGVtcy5yZWR1Y2UoKHN1bSxpdGVtKT0+c3VtKyhpdGVtLnBhaWRJbnx8MCksMCkpOwogICAgICAgIGVudHJ5LnJlbWFpbmluZz1NYXRoLnJvdW5kKGVudHJ5Lml0ZW1zLnJlZHVjZSgoc3VtLGl0ZW0pPT5zdW0rKGl0ZW0ucmVtYWluaW5nRXh8fDApLDApKTsKICAgICAgICBlbnRyeS5yZW1haW5pbmdJbj1NYXRoLnJvdW5kKGVudHJ5Lml0ZW1zLnJlZHVjZSgoc3VtLGl0ZW0pPT5zdW0rKGl0ZW0ucmVtYWluaW5nSW58fDApLDApKTsKICAgICAgfQogICAgICByZXR1cm4gbWFwOwogICAgfQogICAgZnVuY3Rpb24gcmVzb2x2ZU91dHNvdXJjZUVudHJ5KHJlY29yZCxvdXRzb3VyY2VNYXApewogICAgICBjb25zdCBmdWxsS2V5PW5vcm1hbGl6ZVByb2plY3RLZXkocmVjb3JkLm5hbWV8fCIiKTsKICAgICAgY29uc3QgYmFzZUtleT1ub3JtYWxpemVQcm9qZWN0QmFzZShyZWNvcmQubmFtZXx8IiIpOwogICAgICBpZihmdWxsS2V5JiZvdXRzb3VyY2VNYXAuaGFzKGZ1bGxLZXkpKSByZXR1cm4gb3V0c291cmNlTWFwLmdldChmdWxsS2V5KTsKICAgICAgaWYoYmFzZUtleSYmb3V0c291cmNlTWFwLmhhcyhiYXNlS2V5KSkgcmV0dXJuIG91dHNvdXJjZU1hcC5nZXQoYmFzZUtleSk7CiAgICAgIGxldCBiZXN0PW51bGwsYmVzdFNjb3JlPTA7CiAgICAgIGZvcihjb25zdCBlbnRyeSBvZiBvdXRzb3VyY2VNYXAudmFsdWVzKCkpewogICAgICAgIGNvbnN0IGVudHJ5RnVsbD1TdHJpbmcoZW50cnkmJmVudHJ5LmtleXx8IiIpOwogICAgICAgIGNvbnN0IGVudHJ5QmFzZT1TdHJpbmcoZW50cnkmJmVudHJ5LmJhc2VLZXl8fG5vcm1hbGl6ZVByb2plY3RCYXNlKGVudHJ5JiZlbnRyeS5uYW1lfHwiIikpOwogICAgICAgIGZvcihjb25zdCBjYW5kaWRhdGUgb2YgW2VudHJ5RnVsbCxlbnRyeUJhc2VdKXsKICAgICAgICAgIGlmKCFjYW5kaWRhdGUpIGNvbnRpbnVlOwogICAgICAgICAgY29uc3QgbWF0Y2hlZD0oZnVsbEtleSYmZnVsbEtleS5pbmNsdWRlcyhjYW5kaWRhdGUpKXx8KGNhbmRpZGF0ZSYmZnVsbEtleSYmY2FuZGlkYXRlLmluY2x1ZGVzKGZ1bGxLZXkpKXx8KGJhc2VLZXkmJmJhc2VLZXkuaW5jbHVkZXMoY2FuZGlkYXRlKSl8fChjYW5kaWRhdGUmJmJhc2VLZXkmJmNhbmRpZGF0ZS5pbmNsdWRlcyhiYXNlS2V5KSk7CiAgICAgICAgICBpZihtYXRjaGVkJiZjYW5kaWRhdGUubGVuZ3RoPmJlc3RTY29yZSl7CiAgICAgICAgICAgIGJlc3Q9ZW50cnk7CiAgICAgICAgICAgIGJlc3RTY29yZT1jYW5kaWRhdGUubGVuZ3RoOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgICByZXR1cm4gYmVzdDsKICAgIH0KICAgIGZ1bmN0aW9uIGF0dGFjaE91dHNvdXJjZUNvc3RzKHJlY29yZHMsb3V0c291cmNlTWFwKXsKICAgICAgcmV0dXJuIChyZWNvcmRzfHxbXSkubWFwKHJlY29yZD0+ewogICAgICAgIGNvbnN0IGVudHJ5PXJlc29sdmVPdXRzb3VyY2VFbnRyeShyZWNvcmQsb3V0c291cmNlTWFwKTsKICAgICAgICBjb25zdCBvdXRzb3VyY2VDb3N0PWVudHJ5P01hdGgucm91bmQoZW50cnkuY29udHJhY3R8fDApOjA7CiAgICAgICAgY29uc3Qgb3V0c291cmNlUGFpZD1lbnRyeT9NYXRoLnJvdW5kKGVudHJ5LnBhaWR8fDApOjA7CiAgICAgICAgY29uc3Qgb3V0c291cmNlUmVtYWluaW5nPWVudHJ5P01hdGgucm91bmQoZW50cnkucmVtYWluaW5nfHwwKTowOwogICAgICAgIGNvbnN0IG91dHNvdXJjZUNvc3RJbj1lbnRyeT9NYXRoLnJvdW5kKGVudHJ5LmNvbnRyYWN0SW58fDApOjA7CiAgICAgICAgY29uc3Qgb3V0c291cmNlUGFpZEluPWVudHJ5P01hdGgucm91bmQoZW50cnkucGFpZElufHwwKTowOwogICAgICAgIGNvbnN0IG91dHNvdXJjZVJlbWFpbmluZ0luPWVudHJ5P01hdGgucm91bmQoZW50cnkucmVtYWluaW5nSW58fDApOjA7CiAgICAgICAgY29uc3Qgb3V0c291cmNlVmVuZG9ycz1lbnRyeT9BcnJheS5mcm9tKGVudHJ5LnZlbmRvcnMpOltdOwogICAgICAgIGNvbnN0IG91dHNvdXJjZUl0ZW1zPWVudHJ5JiZBcnJheS5pc0FycmF5KGVudHJ5Lml0ZW1zKT9lbnRyeS5pdGVtcy5zbGljZSgpOltdOwogICAgICAgIHJldHVybiB7CiAgICAgICAgICAuLi5yZWNvcmQsCiAgICAgICAgICBvdXRzb3VyY2VDb3N0LAogICAgICAgICAgb3V0c291cmNlUGFpZCwKICAgICAgICAgIG91dHNvdXJjZVJlbWFpbmluZywKICAgICAgICAgIG91dHNvdXJjZUNvc3RJbiwKICAgICAgICAgIG91dHNvdXJjZVBhaWRJbiwKICAgICAgICAgIG91dHNvdXJjZVJlbWFpbmluZ0luLAogICAgICAgICAgb3V0c291cmNlVmVuZG9ycywKICAgICAgICAgIG91dHNvdXJjZVZlbmRvclRleHQ6c3VtbWFyaXplT3V0c291cmNlVmVuZG9ycyhvdXRzb3VyY2VWZW5kb3JzKSwKICAgICAgICAgIG91dHNvdXJjZUl0ZW1zCiAgICAgICAgfTsKICAgICAgfSk7CiAgICB9CiAgICBmdW5jdGlvbiBwYXJzZUxlZGdlclJlY29yZHMoUil7CiAgICAgIGlmKFIubGVuZ3RoJiZSWzBdLmxlbmd0aClSWzBdWzBdPVN0cmluZyhSWzBdWzBdfHwiIikucmVwbGFjZSgvXlx1RkVGRi8sIiIpOwogICAgICBjb25zdCBoPWhzKFIpO2lmKGg8MCl0aHJvdyBuZXcgRXJyb3IoIu2XpOuNlOulvCDssL7sp4Ag66q77ZaI7Iq164uI64ukLiIpOwogICAgICBjaChSW2hdLFJbaCsxXXx8W10pOwogICAgICBjb25zdCBJPXtjYXQ6MSxjb3JwOjQsY29kZTo1LG5hbWU6NixwYXk6Nyx5bjo4LG9yZGVyOjkscG06MTAsc3RhdHVzOjExLGNsaWVudDoxMixzcGxpdDoxMyxjRGF0ZToxNCxzRGF0ZToxNSxlRGF0ZToxNyxjU3VwOjE4LGNWYXQ6MTksY1RvdDoyMCxpc3N1ZURhdGU6MjEsY29sRGF0ZToyMixzU3VwOjIzLHNWYXQ6MjQsc1RvdDoyNSxjb2w6MjYscmVjdjoyNyxyOjI4LG5vdGU6MjksY21DbzozMCxjbU5tOjMxLGNtRHA6MzIsY21QaDozMyxjbUVtOjM0LGRtQ286MzUsZG1ObTozNixkbURwOjM3LGRtUGg6MzgsZG1FbTozOX07CiAgICAgIGNvbnN0IG91dD1bXTtsZXQgY3VycmVudD1udWxsOwogICAgICBmb3IoY29uc3Qgcm93IG9mIFIuc2xpY2UoaCsyKSl7CiAgICAgICAgY29uc3QgeD17CiAgICAgICAgICBjYXQ6dGV4dEF0KHJvdyxJLmNhdCksY29ycDp0ZXh0QXQocm93LEkuY29ycCksY29kZTp0ZXh0QXQocm93LEkuY29kZSksbmFtZTp0ZXh0QXQocm93LEkubmFtZSkscGF5OnRleHRBdChyb3csSS5wYXkpLAogICAgICAgICAgeW46dGV4dEF0KHJvdyxJLnluKSxvcmRlcjp0ZXh0QXQocm93LEkub3JkZXIpLHBtOnRleHRBdChyb3csSS5wbSksc3RhdHVzOnRleHRBdChyb3csSS5zdGF0dXMpLGNsaWVudDp0ZXh0QXQocm93LEkuY2xpZW50KSwKICAgICAgICAgIHNwbGl0OnRleHRBdChyb3csSS5zcGxpdCksY0RhdGU6dGV4dEF0KHJvdyxJLmNEYXRlKSxzRGF0ZTp0ZXh0QXQocm93LEkuc0RhdGUpLGVEYXRlOnRleHRBdChyb3csSS5lRGF0ZSksCiAgICAgICAgICBjU3VwOm1vbmV5QXQocm93LEkuY1N1cCksY1ZhdDptb25leUF0KHJvdyxJLmNWYXQpLGNUb3Q6bW9uZXlBdChyb3csSS5jVG90KSxpc3N1ZURhdGU6dGV4dEF0KHJvdyxJLmlzc3VlRGF0ZSksY29sRGF0ZTp0ZXh0QXQocm93LEkuY29sRGF0ZSksCiAgICAgICAgICBzU3VwOm1vbmV5QXQocm93LEkuc1N1cCksc1ZhdDptb25leUF0KHJvdyxJLnNWYXQpLHNUb3Q6bW9uZXlBdChyb3csSS5zVG90KSxjb2w6bW9uZXlBdChyb3csSS5jb2wpLHJlY3Y6bW9uZXlBdChyb3csSS5yZWN2KSxyYXRlUmF3OnRleHRBdChyb3csSS5yKSwKICAgICAgICAgIG5vdGU6dGV4dEF0KHJvdyxJLm5vdGUpLGNtQ286dGV4dEF0KHJvdyxJLmNtQ28pLGNtTm06dGV4dEF0KHJvdyxJLmNtTm0pLGNtRHA6dGV4dEF0KHJvdyxJLmNtRHApLGNtUGg6dGV4dEF0KHJvdyxJLmNtUGgpLGNtRW06dGV4dEF0KHJvdyxJLmNtRW0pLAogICAgICAgICAgZG1Dbzp0ZXh0QXQocm93LEkuZG1DbyksZG1ObTp0ZXh0QXQocm93LEkuZG1ObSksZG1EcDp0ZXh0QXQocm93LEkuZG1EcCksZG1QaDp0ZXh0QXQocm93LEkuZG1QaCksZG1FbTp0ZXh0QXQocm93LEkuZG1FbSkKICAgICAgICB9OwogICAgICAgIGlmKCF4LmNUb3QpIHguY1RvdD14LmNTdXAreC5jVmF0OwogICAgICAgIGlmKCF4LnNUb3QpIHguc1RvdD14LnNTdXAreC5zVmF0OwogICAgICAgIGlmKCF4LnJlY3YpIHgucmVjdj1NYXRoLm1heCgwLHguc1RvdC14LmNvbCk7CiAgICAgICAgeC5yYXRlPXJhdGUoeC5yYXRlUmF3LHguY29sLHguc1RvdCk7CiAgICAgICAgY29uc3QgaXNQcm9qZWN0PSEhKHguY29kZXx8KHgubmFtZSYmKHguY2F0fHx4LmNvcnB8fHguY2xpZW50fHx4LnlufHx4Lm9yZGVyfHx4LnBtKSkpOwogICAgICAgIGNvbnN0IGlzUGF5bWVudD0haXNQcm9qZWN0JiYhISh4LnBheXx8eC5uYW1lfHx4Lmlzc3VlRGF0ZXx8eC5jb2xEYXRlfHx4LnNTdXB8fHguc1ZhdHx8eC5zVG90fHx4LmNvbHx8eC5yZWN2KTsKICAgICAgICBpZihpc1Byb2plY3QpewogICAgICAgICAgaWYoIXgubmFtZSYmIXguY29kZSkgY29udGludWU7CiAgICAgICAgICBpZihjdXJyZW50KSBvdXQucHVzaChmaW5hbGl6ZVByb2plY3QoY3VycmVudCkpOwogICAgICAgICAgY3VycmVudD17Li4ueCxwYXltZW50czpbXX07CiAgICAgICAgICBjb250aW51ZTsKICAgICAgICB9CiAgICAgICAgaWYoaXNQYXltZW50JiZjdXJyZW50KSBjdXJyZW50LnBheW1lbnRzLnB1c2gocGF5bWVudFJlY29yZCh4LHgucGF5KSk7CiAgICAgIH0KICAgICAgaWYoY3VycmVudCkgb3V0LnB1c2goZmluYWxpemVQcm9qZWN0KGN1cnJlbnQpKTsKICAgICAgcmV0dXJuIG91dDsKICAgIH0KICAgIGZ1bmN0aW9uIGV4dHJhY3RMZWRnZXJUb3RhbHMocm93cyl7CiAgICAgIGNvbnN0IGluZGV4ZXM9e2NvbnRyYWN0OjIwLGNvbGxlY3RlZDoyNixyZWNlaXZhYmxlOjI3LHJhdGU6Mjh9OwogICAgICBsZXQgc3VtbWFyeVJvdz1udWxsOwogICAgICBmb3IobGV0IGk9KHJvd3N8fFtdKS5sZW5ndGgtMTtpPj0wO2ktLSl7CiAgICAgICAgY29uc3Qgcm93PXJvd3NbaV18fFtdOwogICAgICAgIGNvbnN0IGhhc1N1bW1hcnlMYWJlbD1yb3cuc29tZShjZWxsPT5TdHJpbmcoY2VsbD8/IiIpLnJlcGxhY2UoL1xzKy9nLCIiKS5pbmNsdWRlcygi7ZWp6rOEIikpOwogICAgICAgIGlmKGhhc1N1bW1hcnlMYWJlbCl7c3VtbWFyeVJvdz1yb3c7YnJlYWs7fQogICAgICB9CiAgICAgIGlmKCFzdW1tYXJ5Um93KSByZXR1cm4gbnVsbDsKICAgICAgY29uc3QgY29udHJhY3Q9bnVtKHN1bW1hcnlSb3dbaW5kZXhlcy5jb250cmFjdF0pOwogICAgICBjb25zdCBjb2xsZWN0ZWQ9bnVtKHN1bW1hcnlSb3dbaW5kZXhlcy5jb2xsZWN0ZWRdKTsKICAgICAgY29uc3QgcmVjZWl2YWJsZT1udW0oc3VtbWFyeVJvd1tpbmRleGVzLnJlY2VpdmFibGVdKTsKICAgICAgY29uc3QgcmF0ZVJhdz1TdHJpbmcoc3VtbWFyeVJvd1tpbmRleGVzLnJhdGVdPz8iIikudHJpbSgpOwogICAgICBpZighKGNvbnRyYWN0fHxjb2xsZWN0ZWR8fHJlY2VpdmFibGV8fHJhdGVSYXcpKSByZXR1cm4gbnVsbDsKICAgICAgY29uc3QgdG90YWxCYXNlPWNvbGxlY3RlZCtyZWNlaXZhYmxlOwogICAgICByZXR1cm4ge2NvbnRyYWN0LGNvbGxlY3RlZCxyZWNlaXZhYmxlLHJhdGU6cmF0ZShyYXRlUmF3LGNvbGxlY3RlZCx0b3RhbEJhc2UpfTsKICAgIH0KICAgIGZ1bmN0aW9uIHBhcnNlTGVkZ2VyKHR4dCl7CiAgICAgIGNvbnN0IHJvd3M9cGFyc2VDc3YodHh0KTsKICAgICAgcmV0dXJuIHtyZWNvcmRzOnBhcnNlTGVkZ2VyUmVjb3Jkcyhyb3dzKSx0b3RhbHM6ZXh0cmFjdExlZGdlclRvdGFscyhyb3dzKX07CiAgICB9CiAgICBmdW5jdGlvbiBwYXJzZUxlZGdlckV4Y2VsKGJ1Zil7CiAgICAgIGlmKHR5cGVvZiBYTFNYPT09InVuZGVmaW5lZCIpdGhyb3cgbmV3IEVycm9yKCJYTFNYIOudvOydtOu4jOufrOumrOulvCDrtojrn6zsmKTsp4Ag66q77ZaI7Iq164uI64ukLiIpOwogICAgICBjb25zdCB3Yj1YTFNYLnJlYWQoYnVmLHt0eXBlOiJhcnJheSIsY2VsbERhdGVzOmZhbHNlfSk7CiAgICAgIGNvbnN0IG91dHNvdXJjZU1hcD1wYXJzZU91dHNvdXJjZVNoZWV0cyh3Yik7CiAgICAgIGNvbnN0IG5hbWVzPXdiLlNoZWV0TmFtZXN8fFtdOwogICAgICBjb25zdCBwcmVmZXJyZWROYW1lcz1uYW1lcy5maWx0ZXIobmFtZT0+U3RyaW5nKG5hbWV8fCIiKS5pbmNsdWRlcygi6rO17Jyg7IKs7JeF6rSA66as64yA7J6lIikpOwogICAgICBjb25zdCBjYW5kaWRhdGVOYW1lcz1wcmVmZXJyZWROYW1lcy5sZW5ndGg/cHJlZmVycmVkTmFtZXM6Wy4uLm5hbWVzXTsKICAgICAgbGV0IGJlc3RSZWNvcmRzPW51bGw7CiAgICAgIGxldCBiZXN0U2hlZXQ9IiI7CiAgICAgIGxldCBiZXN0U2NvcmU9LTE7CiAgICAgIGxldCBiZXN0VG90YWxzPW51bGw7CiAgICAgIGZvcihjb25zdCBuYW1lIG9mIGNhbmRpZGF0ZU5hbWVzKXsKICAgICAgICB0cnl7CiAgICAgICAgICBjb25zdCBzaGVldD13Yi5TaGVldHNbbmFtZV07CiAgICAgICAgICBjb25zdCByb3dzPVhMU1gudXRpbHMuc2hlZXRfdG9fanNvbihzaGVldCx7aGVhZGVyOjEscmF3OmZhbHNlLGRlZnZhbDoiIn0pOwogICAgICAgICAgY29uc3Qgbm9ybWFsaXplZD0ocm93c3x8W10pLm1hcChyPT5BcnJheS5pc0FycmF5KHIpP3IubWFwKHY9PlN0cmluZyh2Pz8iIikpOltdKTsKICAgICAgICAgIGNvbnN0IHJlY29yZHM9YXR0YWNoT3V0c291cmNlQ29zdHMocGFyc2VMZWRnZXJSZWNvcmRzKG5vcm1hbGl6ZWQpLG91dHNvdXJjZU1hcCk7CiAgICAgICAgICBpZighcmVjb3Jkcy5sZW5ndGgpIGNvbnRpbnVlOwogICAgICAgICAgY29uc3QgdG90YWxzPWV4dHJhY3RMZWRnZXJUb3RhbHMobm9ybWFsaXplZCk7CiAgICAgICAgICBjb25zdCBib251cz1TdHJpbmcobmFtZXx8IiIpLmluY2x1ZGVzKCLqs7XsnKDsgqzsl4XqtIDrpqzrjIDsnqUiKT8xMDAwMDAwOi/sgqzsl4XqtIDrpqzrjIDsnqUvaS50ZXN0KFN0cmluZyhuYW1lfHwiIikpPzEwMDAwOjA7CiAgICAgICAgICBjb25zdCBzY29yZT1yZWNvcmRzLmxlbmd0aCtib251czsKICAgICAgICAgIGlmKHNjb3JlPmJlc3RTY29yZSl7CiAgICAgICAgICAgIGJlc3RTY29yZT1zY29yZTsKICAgICAgICAgICAgYmVzdFJlY29yZHM9cmVjb3JkczsKICAgICAgICAgICAgYmVzdFNoZWV0PW5hbWU7CiAgICAgICAgICAgIGJlc3RUb3RhbHM9dG90YWxzOwogICAgICAgICAgfQogICAgICAgIH1jYXRjaChfKXsKICAgICAgICAgIC8vIHRyeSBuZXh0IHNoZWV0CiAgICAgICAgfQogICAgICB9CiAgICAgIGlmKCFiZXN0UmVjb3JkcykgdGhyb3cgbmV3IEVycm9yKCLsl5HshYDsl5DshJwg7IKs7JeF6rSA66as64yA7J6lIO2XpOuNlOulvCDssL7sp4Ag66q77ZaI7Iq164uI64ukLiIpOwogICAgICByZXR1cm4geyByZWNvcmRzOiBiZXN0UmVjb3Jkcywgc2hlZXROYW1lOiBiZXN0U2hlZXQsIHRvdGFsczogYmVzdFRvdGFscyB9OwogICAgfQogICAgZnVuY3Rpb24gZGVjb2RlKGJ1Zil7Y29uc3QgdT1uZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1Zik7bGV0IGU9IiI7dHJ5e2U9bmV3IFRleHREZWNvZGVyKCJldWMta3IiKS5kZWNvZGUoYnVmKTt9Y2F0Y2goXyl7ZT11O31yZXR1cm4gc2NvcmUoZSk+c2NvcmUodSk/ZTp1O30KICAgIGZ1bmN0aW9uIHN1bVJvd3Mocm93cyl7cmV0dXJuIHJvd3MucmVkdWNlKChhLHIpPT4oYS5jKz1yLmNUb3R8fDAsYS5zKz1yLnNUb3R8fDAsYS5jb2wrPXIuY29sfHwwLGEucmVjdis9ci5yZWN2fHwwLGEpLHtjOjAsczowLGNvbDowLHJlY3Y6MH0pO30KICAgIGZ1bmN0aW9uIGlzU2V0dGxlZFJvdyhyKXsKICAgICAgY29uc3Qgbm9TYWxlcz0oci5zVG90fHwwKTw9MCYmKHIuY29sfHwwKTw9MCYmKHIucmVjdnx8MCk8PTA7CiAgICAgIGNvbnN0IHN0YXR1c0RvbmU9U3RyaW5nKHIuc3RhdHVzfHwiIikuaW5jbHVkZXMoIuyZhOujjCIpOwogICAgICBjb25zdCBjb29wRG9uZT1TdHJpbmcoci55bnx8IiIpLmluY2x1ZGVzKCLsl4XrrLTtmJHsobAiKSYmc3RhdHVzRG9uZSYmbm9TYWxlczsKICAgICAgcmV0dXJuIGNvb3BEb25lfHwoc3RhdHVzRG9uZSYmTWF0aC5yb3VuZChyLnJlY3Z8fDApPD0wJiYoci5yYXRlfHwwKT49MTAwKTsKICAgIH0KICAgIGZ1bmN0aW9uIGhhc0FjdGl2ZURhc2hib2FyZEZpbHRlcnMoKXsKICAgICAgcmV0dXJuICEhU3RyaW5nKEUuc2VhcmNoLnZhbHVlfHwiIikudHJpbSgpfHxGSUxURVJfS0VZUy5zb21lKGtleT0+ISFTLmZpbHRlcnNba2V5XSk7CiAgICB9CiAgICBmdW5jdGlvbiBjb2RlRmlsdGVyTGFiZWwocil7cmV0dXJuIHIuY2F0fHwiLSI7fQogICAgZnVuY3Rpb24gcGVyaW9kRmlsdGVyTGFiZWwocil7cmV0dXJuIGAke2Qoci5zRGF0ZSl9IH4gJHtkKHIuZURhdGUpfWA7fQogICAgZnVuY3Rpb24gb3V0c291cmNlRmlsdGVyTGFiZWwocil7cmV0dXJuIHIub3V0c291cmNlQ29zdD93b24oci5vdXRzb3VyY2VDb3N0KToiLSI7fQogICAgZnVuY3Rpb24gYW1vdW50RmlsdGVyTGFiZWwocil7cmV0dXJuIHdvbihyLmNTdXApO30KICAgIGZ1bmN0aW9uIGNvbGxlY3RlZEZpbHRlckxhYmVsKHIpe3JldHVybiB3b24oci5jb2wpO30KICAgIGZ1bmN0aW9uIHJhdGVGaWx0ZXJMYWJlbChyKXtyZXR1cm4gci5yYXRlLnRvRml4ZWQoMikrIiUiO30KICAgIGZ1bmN0aW9uIHVuaXF1ZUZpbHRlclZhbHVlcyhyb3dzLG1hcEZuKXsKICAgICAgY29uc3Qgc2Vlbj1uZXcgU2V0KCksb3V0PVtdOwogICAgICBmb3IoY29uc3Qgcm93IG9mIHJvd3MpewogICAgICAgIGNvbnN0IHZhbHVlPVN0cmluZyhtYXBGbihyb3cpfHwiIikudHJpbSgpOwogICAgICAgIGlmKCF2YWx1ZXx8c2Vlbi5oYXModmFsdWUpKSBjb250aW51ZTsKICAgICAgICBzZWVuLmFkZCh2YWx1ZSk7CiAgICAgICAgb3V0LnB1c2godmFsdWUpOwogICAgICB9CiAgICAgIHJldHVybiBvdXQ7CiAgICB9CiAgICBmdW5jdGlvbiBmaWx0ZXJEZWZpbml0aW9ucygpewogICAgICByZXR1cm4gWwogICAgICAgIHtrZXk6ImNvZGUiLG1hcDpjb2RlRmlsdGVyTGFiZWx9LAogICAgICAgIHtrZXk6Im5hbWUiLG1hcDpyPT5yLm5hbWV8fCItIn0sCiAgICAgICAge2tleToiY29ycCIsbWFwOnI9PnIuY29ycHx8Ii0ifSwKICAgICAgICB7a2V5OiJzdGF0dXMiLG1hcDpyPT5yLnN0YXR1c3x8Ii0ifSwKICAgICAgICB7a2V5OiJvdXRzb3VyY2UiLG1hcDpvdXRzb3VyY2VGaWx0ZXJMYWJlbH0sCiAgICAgICAge2tleToiYW1vdW50IixtYXA6YW1vdW50RmlsdGVyTGFiZWx9LAogICAgICAgIHtrZXk6ImNvbGxlY3RlZCIsbWFwOmNvbGxlY3RlZEZpbHRlckxhYmVsfSwKICAgICAgICB7a2V5OiJyYXRlIixtYXA6cmF0ZUZpbHRlckxhYmVsfQogICAgICBdOwogICAgfQogICAgZnVuY3Rpb24gY2xvc2VGaWx0ZXJNZW51cygpewogICAgICBPYmplY3QudmFsdWVzKEUuZmlsdGVyTWVudXMpLmZvckVhY2gobWVudT0+bWVudS5jbGFzc0xpc3QucmVtb3ZlKCJvcGVuIikpOwogICAgICBPYmplY3QudmFsdWVzKEUuZmlsdGVyQnV0dG9ucykuZm9yRWFjaChidG49PmJ0bi5jbGFzc0xpc3QucmVtb3ZlKCJvcGVuIikpOwogICAgfQogICAgZnVuY3Rpb24gdXBkYXRlRmlsdGVyQnV0dG9ucygpewogICAgICBGSUxURVJfS0VZUy5mb3JFYWNoKGtleT0+ewogICAgICAgIGNvbnN0IGJ0bj1FLmZpbHRlckJ1dHRvbnNba2V5XTsKICAgICAgICBpZighYnRuKSByZXR1cm47CiAgICAgICAgY29uc3QgYWN0aXZlPSEhUy5maWx0ZXJzW2tleV07CiAgICAgICAgYnRuLmNsYXNzTGlzdC50b2dnbGUoImFjdGl2ZSIsYWN0aXZlKTsKICAgICAgICBidG4udGl0bGU9YWN0aXZlP2Ake2J0bi5kYXRhc2V0LmxhYmVsfTogJHtTLmZpbHRlcnNba2V5XX1gOmJ0bi5kYXRhc2V0LmxhYmVsfHwiIjsKICAgICAgICBjb25zdCBtYXJrPWJ0bi5xdWVyeVNlbGVjdG9yKCIudGgtbWFyayIpOwogICAgICAgIGlmKG1hcmspIG1hcmsudGV4dENvbnRlbnQ9YWN0aXZlPyLigKIiOiIiOwogICAgICB9KTsKICAgIH0KICAgIGZ1bmN0aW9uIHJlbmRlckZpbHRlck1lbnUoa2V5LHZhbHVlcyl7CiAgICAgIGNvbnN0IG1lbnU9RS5maWx0ZXJNZW51c1trZXldOwogICAgICBpZighbWVudSkgcmV0dXJuOwogICAgICBjb25zdCBjdXJyZW50PVN0cmluZyhTLmZpbHRlcnNba2V5XXx8IiIpOwogICAgICBtZW51LmlubmVySFRNTD1gPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJ0aC1vcHRpb24keyFjdXJyZW50PyIgYWN0aXZlIjoiIn0iIGRhdGEtZmlsdGVyLXZhbHVlPSIiPuyghOyytDwvYnV0dG9uPmArdmFsdWVzLm1hcCh2PT5gPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJ0aC1vcHRpb24ke2N1cnJlbnQ9PT12PyIgYWN0aXZlIjoiIn0iIGRhdGEtZmlsdGVyLXZhbHVlPSIke2VzY0F0dHIodil9Ij4ke2VzYyh2KX08L2J1dHRvbj5gKS5qb2luKCIiKTsKICAgIH0KICAgIGZ1bmN0aW9uIHN5bmNDb2x1bW5GaWx0ZXJzKHJvd3MpewogICAgICBmaWx0ZXJEZWZpbml0aW9ucygpLmZvckVhY2goZGVmPT57CiAgICAgICAgY29uc3QgdmFsdWVzPXVuaXF1ZUZpbHRlclZhbHVlcyhyb3dzLGRlZi5tYXApOwogICAgICAgIGlmKFMuZmlsdGVyc1tkZWYua2V5XSYmIXZhbHVlcy5pbmNsdWRlcyhTLmZpbHRlcnNbZGVmLmtleV0pKSBkZWxldGUgUy5maWx0ZXJzW2RlZi5rZXldOwogICAgICAgIHJlbmRlckZpbHRlck1lbnUoZGVmLmtleSx2YWx1ZXMpOwogICAgICB9KTsKICAgICAgdXBkYXRlRmlsdGVyQnV0dG9ucygpOwogICAgfQogICAgZnVuY3Rpb24gdG9nZ2xlRmlsdGVyTWVudShrZXkpewogICAgICBjb25zdCBtZW51PUUuZmlsdGVyTWVudXNba2V5XSxidG49RS5maWx0ZXJCdXR0b25zW2tleV07CiAgICAgIGlmKCFtZW51fHwhYnRuKSByZXR1cm47CiAgICAgIGNvbnN0IHdpbGxPcGVuPSFtZW51LmNsYXNzTGlzdC5jb250YWlucygib3BlbiIpOwogICAgICBjbG9zZUZpbHRlck1lbnVzKCk7CiAgICAgIGlmKHdpbGxPcGVuKXsKICAgICAgICBtZW51LmNsYXNzTGlzdC5hZGQoIm9wZW4iKTsKICAgICAgICBidG4uY2xhc3NMaXN0LmFkZCgib3BlbiIpOwogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBzZXRGaWx0ZXJWYWx1ZShrZXksdmFsdWUpewogICAgICBpZih2YWx1ZSkgUy5maWx0ZXJzW2tleV09dmFsdWU7CiAgICAgIGVsc2UgZGVsZXRlIFMuZmlsdGVyc1trZXldOwogICAgICBzeW5jQ29sdW1uRmlsdGVycyhTLmFsbCk7CiAgICAgIGNsb3NlRmlsdGVyTWVudXMoKTsKICAgICAgZmlsdGVyKCk7CiAgICB9CiAgICBmdW5jdGlvbiBtYXRjaGVzQ29sdW1uRmlsdGVycyhyKXsKICAgICAgaWYoUy5maWx0ZXJzLmNvZGUmJmNvZGVGaWx0ZXJMYWJlbChyKSE9PVMuZmlsdGVycy5jb2RlKSByZXR1cm4gZmFsc2U7CiAgICAgIGlmKFMuZmlsdGVycy5uYW1lJiYoci5uYW1lfHwiLSIpIT09Uy5maWx0ZXJzLm5hbWUpIHJldHVybiBmYWxzZTsKICAgICAgaWYoUy5maWx0ZXJzLmNvcnAmJihyLmNvcnB8fCItIikhPT1TLmZpbHRlcnMuY29ycCkgcmV0dXJuIGZhbHNlOwogICAgICBpZihTLmZpbHRlcnMuc3RhdHVzJiYoci5zdGF0dXN8fCItIikhPT1TLmZpbHRlcnMuc3RhdHVzKSByZXR1cm4gZmFsc2U7CiAgICAgIGlmKFMuZmlsdGVycy5vdXRzb3VyY2UmJm91dHNvdXJjZUZpbHRlckxhYmVsKHIpIT09Uy5maWx0ZXJzLm91dHNvdXJjZSkgcmV0dXJuIGZhbHNlOwogICAgICBpZihTLmZpbHRlcnMuYW1vdW50JiZhbW91bnRGaWx0ZXJMYWJlbChyKSE9PVMuZmlsdGVycy5hbW91bnQpIHJldHVybiBmYWxzZTsKICAgICAgaWYoUy5maWx0ZXJzLmNvbGxlY3RlZCYmY29sbGVjdGVkRmlsdGVyTGFiZWwocikhPT1TLmZpbHRlcnMuY29sbGVjdGVkKSByZXR1cm4gZmFsc2U7CiAgICAgIGlmKFMuZmlsdGVycy5yYXRlJiZyYXRlRmlsdGVyTGFiZWwocikhPT1TLmZpbHRlcnMucmF0ZSkgcmV0dXJuIGZhbHNlOwogICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KICAgIGZ1bmN0aW9uIHNldFRleHQoaWQsdil7Y29uc3QgZWw9RyhpZCk7aWYoZWwpZWwudGV4dENvbnRlbnQ9dnx8Ii0iO30KICAgIGZ1bmN0aW9uIHJlbmRlclBheW1lbnRzSHRtbChwYXltZW50cyl7CiAgICAgIGlmKCFwYXltZW50c3x8IXBheW1lbnRzLmxlbmd0aCkgcmV0dXJuICc8ZGl2IGNsYXNzPSJwYXktZW1wdHkiPuuMgOq4iCDssKjsiJgg7KCV67O06rCAIOyXhuyKteuLiOuLpC48L2Rpdj4nOwogICAgICByZXR1cm4gcGF5bWVudHMubWFwKHA9PmA8ZGl2IGNsYXNzPSJwYXktaXRlbSI+PGRpdiBjbGFzcz0icGF5LWhlYWQiPjxkaXYgY2xhc3M9InBheS1uYW1lIj4ke2VzYyhwLnBheXx8IuuvuOyeheugpSIpfTwvZGl2PjxkaXYgc3R5bGU9ImZvbnQtc2l6ZToxMXB4O2NvbG9yOiM2NDc0OGI7Zm9udC13ZWlnaHQ6ODAwO3doaXRlLXNwYWNlOm5vd3JhcCI+JHtlc2MocC5zdGF0dXN8fCItIil9PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0icGF5LW1ldGEiPjxzcGFuPuuwnO2WieydvCAke2VzYyhkKHAuaXNzdWVEYXRlKSl9PC9zcGFuPjxzcGFuPuyImOq4iOydvCAke2VzYyhkKHAuY29sbGVjdERhdGUpKX08L3NwYW4+PHNwYW4+6rO16riJ6rCA7JWhICR7ZXNjKHdvbihwLnN1cHBseSkpfTwvc3Bhbj48c3Bhbj7siJjquIjquIjslaEgJHtlc2Mod29uKHAuY29sbGVjdGVkKSl9PC9zcGFuPjwvZGl2PiR7cC5ub3RlP2A8ZGl2IGNsYXNzPSJwYXktbm90ZSI+67mE6rOgOiAke2VzYyhwLm5vdGUpfTwvZGl2PmA6IiJ9PC9kaXY+YCkuam9pbigiIik7CiAgICB9CiAgICBmdW5jdGlvbiByZW5kZXJPdXRzb3VyY2VQYXltZW50cyhwYXltZW50cyl7CiAgICAgIGNvbnN0IGxpc3Q9KHBheW1lbnRzfHxbXSkuZmlsdGVyKHBheW1lbnQ9PnBheW1lbnQmJihwYXltZW50LmxhYmVsfHxwYXltZW50Lm5vdGV8fHBheW1lbnQuaW52b2ljZURhdGV8fHBheW1lbnQucGF5bWVudERhdGV8fHBheW1lbnQucGF5bWVudEV4fHxwYXltZW50LnJlbWFpbmluZ0V4fHxwYXltZW50LnBheW1lbnRJbnx8cGF5bWVudC5yZW1haW5pbmdJbikpOwogICAgICBpZighbGlzdC5sZW5ndGgpIHJldHVybiAiIjsKICAgICAgcmV0dXJuIGA8ZGl2IGNsYXNzPSJvdXQtcGF5bWVudHMiPiR7bGlzdC5tYXAoKHBheW1lbnQsaW5kZXgpPT5gPGRpdiBjbGFzcz0ib3V0LXBheW1lbnQiPjxkaXYgY2xhc3M9Im91dC1wYXltZW50LWhlYWQiPjxzcGFuPiR7ZXNjKHBheW1lbnQubGFiZWx8fGBcdUM5QzBcdUFFMDkgJHtpbmRleCsxfWApfTwvc3Bhbj48c3Bhbj4ke2VzYyhwYXltZW50LnBheW1lbnREYXRlP2QocGF5bWVudC5wYXltZW50RGF0ZSk6Ii0iKX08L3NwYW4+PC9kaXY+PGRpdiBjbGFzcz0ib3V0LXBheW1lbnQtbWV0YSI+PHNwYW4+XHVBQ0M0XHVDMEIwXHVDMTFDXHVDNzdDXHVDNzkwICR7ZXNjKHBheW1lbnQuaW52b2ljZURhdGU/ZChwYXltZW50Lmludm9pY2VEYXRlKToiLSIpfTwvc3Bhbj48c3Bhbj5cdUM5QzBcdUFFMDlcdUFFMDhcdUM1NjEgJHtlc2MocGF5bWVudC5wYXltZW50RXg/d29uKHBheW1lbnQucGF5bWVudEV4KToiLSIpfTwvc3Bhbj48c3Bhbj5cdUM3OTRcdUM1RUNcdUFFMDhcdUM1NjEgJHtlc2MocGF5bWVudC5yZW1haW5pbmdFeHx8cGF5bWVudC5yZW1haW5pbmdFeD09PTA/d29uKHBheW1lbnQucmVtYWluaW5nRXgpOiItIil9PC9zcGFuPjwvZGl2PiR7cGF5bWVudC5ub3RlP2A8ZGl2IGNsYXNzPSJvdXQtbm90ZSI+XHVCRTQ0XHVBQ0UwOiAke2VzYyhwYXltZW50Lm5vdGUpfTwvZGl2PmA6IiJ9PC9kaXY+YCkuam9pbigiIil9PC9kaXY+YDsKICAgIH0KICAgIGZ1bmN0aW9uIGNvdW50T3V0c291cmNlU3RhZ2VzKHIpewogICAgICByZXR1cm4gKHIub3V0c291cmNlSXRlbXN8fFtdKS5yZWR1Y2UoKHN1bSxpdGVtKT0+ewogICAgICAgIGNvbnN0IHN0YWdlcz0oaXRlbS5wYXltZW50c3x8W10pLmZpbHRlcihwYXltZW50PT5wYXltZW50JiYocGF5bWVudC5sYWJlbHx8cGF5bWVudC5ub3RlfHxwYXltZW50Lmludm9pY2VEYXRlfHxwYXltZW50LnBheW1lbnREYXRlfHxwYXltZW50LnBheW1lbnRFeHx8cGF5bWVudC5yZW1haW5pbmdFeHx8cGF5bWVudC5wYXltZW50SW58fHBheW1lbnQucmVtYWluaW5nSW4pKTsKICAgICAgICByZXR1cm4gc3VtKyhzdGFnZXMubGVuZ3RofHwxKTsKICAgICAgfSwwKTsKICAgIH0KICAgIGZ1bmN0aW9uIHN1bW1hcml6ZU91dHNvdXJjZUNvdW50cyhyKXsKICAgICAgY29uc3QgdmVuZG9ycz0oci5vdXRzb3VyY2VWZW5kb3JzfHxbXSkubGVuZ3RoOwogICAgICBjb25zdCBjb250cmFjdHM9KHIub3V0c291cmNlSXRlbXN8fFtdKS5sZW5ndGg7CiAgICAgIGNvbnN0IHN0YWdlcz1jb3VudE91dHNvdXJjZVN0YWdlcyhyKTsKICAgICAgY29uc3QgcGFydHM9W107CiAgICAgIGlmKHZlbmRvcnMpIHBhcnRzLnB1c2goYOyZuOyjvOyymCAke3ZlbmRvcnMudG9Mb2NhbGVTdHJpbmcoImtvLUtSIil96rOzYCk7CiAgICAgIGlmKGNvbnRyYWN0cykgcGFydHMucHVzaChg6rOE7JW9ICR7Y29udHJhY3RzLnRvTG9jYWxlU3RyaW5nKCJrby1LUiIpfeqxtGApOwogICAgICBpZihzdGFnZXMpIHBhcnRzLnB1c2goYOyngOq4ieuLqOqzhCAke3N0YWdlcy50b0xvY2FsZVN0cmluZygia28tS1IiKX3qsbRgKTsKICAgICAgcmV0dXJuIHBhcnRzLmpvaW4oIiDCtyAiKXx8IuyZuOyjvCDrgrTsl60g7JeG7J2MIjsKICAgIH0KICAgIGZ1bmN0aW9uIHJlbmRlck91dHNvdXJjZUh0bWwoaXRlbXMpewogICAgICBpZighaXRlbXN8fCFpdGVtcy5sZW5ndGgpIHJldHVybiAnPGRpdiBjbGFzcz0icGF5LWVtcHR5Ij7smbjso7wg7IOB7IS4IOygleuztOqwgCDsl4bsirXri4jri6QuPC9kaXY+JzsKICAgICAgcmV0dXJuIGl0ZW1zLm1hcChpdGVtPT57CiAgICAgICAgY29uc3Qgc3RhZ2VDb3VudD0oaXRlbS5wYXltZW50c3x8W10pLmZpbHRlcihwYXltZW50PT5wYXltZW50JiYocGF5bWVudC5sYWJlbHx8cGF5bWVudC5ub3RlfHxwYXltZW50Lmludm9pY2VEYXRlfHxwYXltZW50LnBheW1lbnREYXRlfHxwYXltZW50LnBheW1lbnRFeHx8cGF5bWVudC5yZW1haW5pbmdFeHx8cGF5bWVudC5wYXltZW50SW58fHBheW1lbnQucmVtYWluaW5nSW4pKS5sZW5ndGg7CiAgICAgICAgY29uc3Qgc3RhZ2VUZXh0PXN0YWdlQ291bnQ/YOyngOq4ieuLqOqzhCAke3N0YWdlQ291bnQudG9Mb2NhbGVTdHJpbmcoImtvLUtSIil96rG0YDoi7KeA6riJ64K07JetIOyXhuydjCI7CiAgICAgICAgY29uc3QgcGVyaW9kVGV4dD0oZChpdGVtLnN0YXJ0RGF0ZSk9PT0iLSImJmQoaXRlbS5lbmREYXRlKT09PSItIik/Ii0iOmAke2QoaXRlbS5zdGFydERhdGUpfSB+ICR7ZChpdGVtLmVuZERhdGUpfWA7CiAgICAgICAgcmV0dXJuIGA8ZGl2IGNsYXNzPSJvdXQtaXRlbSI+PGRpdiBjbGFzcz0ib3V0LWhlYWQiPjxkaXY+PGRpdiBjbGFzcz0ib3V0LXZlbmRvciI+JHtlc2MoaXRlbS52ZW5kb3J8fCLsmbjso7wiKX08L2Rpdj48ZGl2IGNsYXNzPSJvdXQtbmFtZSI+JHtlc2MoaXRlbS5kZXRhaWx8fCItIil9PC9kaXY+PC9kaXY+PGRpdiBzdHlsZT0iZm9udC1zaXplOjExcHg7Y29sb3I6IzY0NzQ4Yjtmb250LXdlaWdodDo4MDA7d2hpdGUtc3BhY2U6bm93cmFwIj4ke2VzYyhpdGVtLnByb2dyZXNzfHxzdGFnZVRleHQpfTwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9Im91dC1tZXRhIj48c3Bhbj7qs4Tslb3quLDqsIQgJHtlc2MocGVyaW9kVGV4dCl9PC9zcGFuPjxzcGFuPuqzhOyVveq4iOyVoSAke2VzYyhpdGVtLmNvbnRyYWN0RXg/d29uKGl0ZW0uY29udHJhY3RFeCk6Ii0iKX08L3NwYW4+PHNwYW4+7KeA6riJ6riI7JWhICR7ZXNjKGl0ZW0ucGFpZEV4fHxpdGVtLnBhaWRFeD09PTA/d29uKGl0ZW0ucGFpZEV4KToiLSIpfTwvc3Bhbj48c3Bhbj7snpTsl6zquIjslaEgJHtlc2MoaXRlbS5yZW1haW5pbmdFeHx8aXRlbS5yZW1haW5pbmdFeD09PTA/d29uKGl0ZW0ucmVtYWluaW5nRXgpOiItIil9PC9zcGFuPjxzcGFuPuqzhOyCsOyEnOydvOyekCAke2VzYyhpdGVtLmludm9pY2VEYXRlP2QoaXRlbS5pbnZvaWNlRGF0ZSk6Ii0iKX08L3NwYW4+PHNwYW4+JHtlc2Moc3RhZ2VUZXh0KX08L3NwYW4+PC9kaXY+JHtpdGVtLm5vdGU/YDxkaXYgY2xhc3M9Im91dC1ub3RlIj7ruYTqs6A6ICR7ZXNjKGl0ZW0ubm90ZSl9PC9kaXY+YDoiIn0ke3JlbmRlck91dHNvdXJjZVBheW1lbnRzKGl0ZW0ucGF5bWVudHN8fFtdKX08L2Rpdj5gOwogICAgICB9KS5qb2luKCIiKTsKICAgIH0KICAgIGZ1bmN0aW9uIHJlbmRlckNvbnRhY3RDb21wYWN0KGxhYmVsLG5hbWUsY29tcGFueSxkZXB0LHBob25lLGVtYWlsKXsKICAgICAgcmV0dXJuIGA8ZGl2IGNsYXNzPSJzdW1tYXJ5LWNhcmQiPjxkaXYgY2xhc3M9InN1bW1hcnktbGFiZWwiPiR7ZXNjKGxhYmVsKX08L2Rpdj48ZGl2IHN0eWxlPSJtYXJnaW4tdG9wOjZweDtmb250LXNpemU6MTZweDtmb250LXdlaWdodDo5MDAiPiR7ZXNjKG5hbWV8fCItIil9PC9kaXY+PGRpdiBjbGFzcz0ic3VtbWFyeS1ub3RlIj4ke2VzYyhbY29tcGFueXx8Ii0iLGRlcHR8fCItIl0uam9pbigiIMK3ICIpKX08L2Rpdj48ZGl2IGNsYXNzPSJzdW1tYXJ5LW5vdGUiPiR7ZXNjKGDsoITtmZQgJHtwaG9uZXx8Ii0ifSAvIOuplOydvCAke2VtYWlsfHwiLSJ9YCl9PC9kaXY+PC9kaXY+YDsKICAgIH0KICAgIGZ1bmN0aW9uIHJlbmRlck91dHNvdXJjZUJvYXJkKHIpewogICAgICBjb25zdCBpdGVtcz1yLm91dHNvdXJjZUl0ZW1zfHxbXTsKICAgICAgaWYoIWl0ZW1zLmxlbmd0aCl7CiAgICAgICAgcmV0dXJuIGA8ZGl2IGNsYXNzPSJsZWRnZXItYmxvY2sgb3V0c291cmNlIj48ZGl2IGNsYXNzPSJsZWRnZXItaGVhZCI+PGRpdiBjbGFzcz0ibGVkZ2VyLWhlYWQtbGVmdCI+PGRpdiBjbGFzcz0ibGVkZ2VyLWljb24iPk88L2Rpdj48ZGl2PjxkaXYgY2xhc3M9ImxlZGdlci1uYW1lIj7smbjso7wg6rOE7JW9IC8g7KeA6riJIO2YhO2ZqTwvZGl2PjxkaXYgY2xhc3M9ImxlZGdlci1zdWIiPuuTseuhneuQnCDsmbjso7wg642w7J207YSwIOyXhuydjDwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImxlZGdlci1waWxsIj7stJ0g6rOE7JW9IDDsm5A8L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJsZWRnZXItZW1wdHkiPuyZuOyjvCDsg4HshLgg7KCV67O06rCAIOyXhuyKteuLiOuLpC48L2Rpdj48L2Rpdj5gOwogICAgICB9CiAgICAgIHJldHVybiBgPGRpdiBjbGFzcz0ibGVkZ2VyLWJsb2NrIG91dHNvdXJjZSI+PGRpdiBjbGFzcz0ibGVkZ2VyLWhlYWQiPjxkaXYgY2xhc3M9ImxlZGdlci1oZWFkLWxlZnQiPjxkaXYgY2xhc3M9ImxlZGdlci1pY29uIj5PPC9kaXY+PGRpdj48ZGl2IGNsYXNzPSJsZWRnZXItbmFtZSI+7Jm47KO8IOqzhOyVvSAvIOyngOq4iSDtmITtmak8L2Rpdj48ZGl2IGNsYXNzPSJsZWRnZXItc3ViIj5WQVQg67OE64+EPC9kaXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0ibGVkZ2VyLXBpbGwiPuy0nSDqs4Tslb0gJHtlc2Moci5vdXRzb3VyY2VDb3N0P3dvbihyLm91dHNvdXJjZUNvc3QpOiItIil9PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0ibGVkZ2VyLXRhYmxlLXdyYXAiPjx0YWJsZSBjbGFzcz0ibGVkZ2VyLXRhYmxlIj48dGhlYWQ+PHRyPjx0aD7smbjso7zsspggLyDqs4Tslb3rqoU8L3RoPjx0aD7qs4Tslb3quLDqsIQ8L3RoPjx0aCBzdHlsZT0idGV4dC1hbGlnbjpyaWdodCI+6rOE7JW96riI7JWhPC90aD48dGggc3R5bGU9InRleHQtYWxpZ246cmlnaHQiPuyngOq4ieq4iOyVoTwvdGg+PHRoIHN0eWxlPSJ0ZXh0LWFsaWduOnJpZ2h0Ij7snpTsl6zquIjslaE8L3RoPjx0aD7sp4TtlontmITtmak8L3RoPjx0aD7ruYTqs6A8L3RoPjwvdHI+PC90aGVhZD48dGJvZHk+JHtpdGVtcy5tYXAoaXRlbT0+e2NvbnN0IHBlcmlvZFRleHQ9KGQoaXRlbS5zdGFydERhdGUpPT09Ii0iJiZkKGl0ZW0uZW5kRGF0ZSk9PT0iLSIpPyItIjpgJHtkKGl0ZW0uc3RhcnREYXRlKX0gfiAke2QoaXRlbS5lbmREYXRlKX1gO2NvbnN0IG5vdGVMaW5lcz0oaXRlbS5wYXltZW50c3x8W10pLm1hcChwYXltZW50PT57Y29uc3QgbGFiZWw9U3RyaW5nKHBheW1lbnQubGFiZWx8fCIiKS50cmltKCk7Y29uc3Qgbm90ZT1TdHJpbmcocGF5bWVudC5ub3RlfHwiIikudHJpbSgpO2lmKCFsYWJlbCYmIW5vdGUpIHJldHVybiAiIjtpZihsYWJlbCYmbm90ZSkgcmV0dXJuIGAke2xhYmVsfTogJHtub3RlfWA7cmV0dXJuIGxhYmVsfHxub3RlO30pLmZpbHRlcihCb29sZWFuKTtpZihpdGVtLm5vdGUpIG5vdGVMaW5lcy51bnNoaWZ0KGl0ZW0ubm90ZSk7cmV0dXJuIGA8dHI+PHRkPjxzcGFuIGNsYXNzPSJsZWRnZXItbWFpbiI+JHtlc2MoaXRlbS52ZW5kb3J8fCLsmbjso7wiKX08L3NwYW4+PHNwYW4gY2xhc3M9ImxlZGdlci1tdXRlZCI+JHtlc2MoaXRlbS5kZXRhaWx8fCItIil9PC9zcGFuPjwvdGQ+PHRkPjxzcGFuIGNsYXNzPSJsZWRnZXItbWFpbiI+JHtlc2MocGVyaW9kVGV4dCl9PC9zcGFuPjwvdGQ+PHRkIGNsYXNzPSJsZWRnZXItYW1vdW50Ij4ke2VzYyhpdGVtLmNvbnRyYWN0RXg/d29uKGl0ZW0uY29udHJhY3RFeCk6Ii0iKX08L3RkPjx0ZCBjbGFzcz0ibGVkZ2VyLWFtb3VudCI+JHtlc2MoaXRlbS5wYWlkRXh8fGl0ZW0ucGFpZEV4PT09MD93b24oaXRlbS5wYWlkRXgpOiItIil9PC90ZD48dGQgY2xhc3M9ImxlZGdlci1hbW91bnQiPiR7ZXNjKGl0ZW0ucmVtYWluaW5nRXh8fGl0ZW0ucmVtYWluaW5nRXg9PT0wP3dvbihpdGVtLnJlbWFpbmluZ0V4KToiLSIpfTwvdGQ+PHRkPjxzcGFuIGNsYXNzPSJsZWRnZXItbm90ZSI+JHtlc2MoaXRlbS5wcm9ncmVzc3x8Ii0iKX08L3NwYW4+PC90ZD48dGQ+PHNwYW4gY2xhc3M9ImxlZGdlci1ub3RlIj4ke2VzYyhub3RlTGluZXMuam9pbigiIC8gIil8fCItIil9PC9zcGFuPjwvdGQ+PC90cj5gO30pLmpvaW4oIiIpfTwvdGJvZHk+PC90YWJsZT48L2Rpdj48L2Rpdj5gOwogICAgfQogICAgZnVuY3Rpb24gcmVuZGVyQ29sbGVjdGlvbkJvYXJkKHIpewogICAgICBjb25zdCBwYXltZW50cz1yLnBheW1lbnRzJiZyLnBheW1lbnRzLmxlbmd0aD9yLnBheW1lbnRzOlt7cGF5OnIucGF5fHwiLSIsaXNzdWVEYXRlOnIuaXNzdWVEYXRlfHwiIixjb2xsZWN0RGF0ZTpyLmNvbGxlY3REYXRlU3VtbWFyeXx8ci5jb2xEYXRlfHwiIixzdXBwbHk6ci5zU3VwfHwwLGNvbGxlY3RlZDpyLmNvbHx8MCxyZWNlaXZhYmxlOnIucmVjdnx8TWF0aC5tYXgoMCwoci5zVG90fHwwKS0oci5jb2x8fDApKSxyYXRlOnIucmF0ZXx8MCxub3RlOnIubm90ZXx8IiIsc3RhdHVzOnIuc3RhdHVzfHwiLSJ9XTsKICAgICAgcmV0dXJuIGA8ZGl2IGNsYXNzPSJsZWRnZXItYmxvY2sgY29sbGVjdCI+PGRpdiBjbGFzcz0ibGVkZ2VyLWhlYWQiPjxkaXYgY2xhc3M9ImxlZGdlci1oZWFkLWxlZnQiPjxkaXYgY2xhc3M9ImxlZGdlci1pY29uIj5DPC9kaXY+PGRpdj48ZGl2IGNsYXNzPSJsZWRnZXItbmFtZSI+7IiY6riIIOuwjyDquLDshLEg7ZiE7ZmpPC9kaXY+PGRpdiBjbGFzcz0ibGVkZ2VyLXN1YiI+VkFUIOuzhOuPhDwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImxlZGdlci1waWxsIj7stJ0g7IiY6riIICR7ZXNjKHdvbihyLmNvbCkpfTwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImxlZGdlci10YWJsZS13cmFwIj48dGFibGUgY2xhc3M9ImxlZGdlci10YWJsZSI+PHRoZWFkPjx0cj48dGg+67Cc7ZaJIC8g7IiY6riI7J28PC90aD48dGg+6rWs67aEPC90aD48dGggc3R5bGU9InRleHQtYWxpZ246cmlnaHQiPuqzteq4ieqwgOyVoTwvdGg+PHRoIHN0eWxlPSJ0ZXh0LWFsaWduOnJpZ2h0Ij7siJjquIjquIjslaE8L3RoPjx0aCBzdHlsZT0idGV4dC1hbGlnbjpyaWdodCI+66+47IiY6riI7JWhPC90aD48dGggc3R5bGU9InRleHQtYWxpZ246cmlnaHQiPuyImOq4iOycqDwvdGg+PHRoPuu5hOqzoDwvdGg+PC90cj48L3RoZWFkPjx0Ym9keT4ke3BheW1lbnRzLm1hcChwYXltZW50PT57Y29uc3QgZGF0ZVBhcnRzPVtwYXltZW50Lmlzc3VlRGF0ZT9g67Cc7ZaJICR7ZChwYXltZW50Lmlzc3VlRGF0ZSl9YDoiIixwYXltZW50LmNvbGxlY3REYXRlP2DsiJjquIggJHtkKHBheW1lbnQuY29sbGVjdERhdGUpfWA6IiJdLmZpbHRlcihCb29sZWFuKTtjb25zdCBub3RlUGFydHM9W107aWYocGF5bWVudC5zdGF0dXMpIG5vdGVQYXJ0cy5wdXNoKHBheW1lbnQuc3RhdHVzKTtpZihwYXltZW50Lm5vdGUpIG5vdGVQYXJ0cy5wdXNoKHBheW1lbnQubm90ZSk7cmV0dXJuIGA8dHI+PHRkPjxzcGFuIGNsYXNzPSJsZWRnZXItbWFpbiI+JHtlc2MoZGF0ZVBhcnRzWzBdfHwiLSIpfTwvc3Bhbj48c3BhbiBjbGFzcz0ibGVkZ2VyLW11dGVkIj4ke2VzYyhkYXRlUGFydHNbMV18fCLsiJjquIjsnbwg7JeG7J2MIil9PC9zcGFuPjwvdGQ+PHRkPjxzcGFuIGNsYXNzPSJsZWRnZXItbWFpbiI+JHtlc2MocGF5bWVudC5wYXl8fCLrr7jsnoXroKUiKX08L3NwYW4+PC90ZD48dGQgY2xhc3M9ImxlZGdlci1hbW91bnQiPiR7ZXNjKHdvbihwYXltZW50LnN1cHBseXx8MCkpfTwvdGQ+PHRkIGNsYXNzPSJsZWRnZXItYW1vdW50Ij4ke2VzYyh3b24ocGF5bWVudC5jb2xsZWN0ZWR8fDApKX08L3RkPjx0ZCBjbGFzcz0ibGVkZ2VyLWFtb3VudCI+JHtlc2Mod29uKHBheW1lbnQucmVjZWl2YWJsZXx8MCkpfTwvdGQ+PHRkIGNsYXNzPSJsZWRnZXItYW1vdW50Ij4ke2VzYygoKHBheW1lbnQucmF0ZXx8MCkudG9GaXhlZD9wYXltZW50LnJhdGUudG9GaXhlZCgyKTpOdW1iZXIocGF5bWVudC5yYXRlfHwwKS50b0ZpeGVkKDIpKSsiJSIpfTwvdGQ+PHRkPjxzcGFuIGNsYXNzPSJsZWRnZXItbm90ZSI+JHtlc2Mobm90ZVBhcnRzLmpvaW4oIiAvICIpfHwiLSIpfTwvc3Bhbj48L3RkPjwvdHI+YDt9KS5qb2luKCIiKX08L3Rib2R5PjwvdGFibGU+PC9kaXY+PC9kaXY+YDsKICAgIH0KICAgIGZ1bmN0aW9uIHJlbmRlclByb2plY3RJbmxpbmUocil7CiAgICAgIGNvbnN0IHBheW1lbnRzPXIucGF5bWVudHN8fFtdOwogICAgICBjb25zdCBsYXRlc3RDb2xsZWN0PWQoci5jb2xsZWN0RGF0ZVN1bW1hcnl8fHIuY29sRGF0ZSk7CiAgICAgIGNvbnN0IGNvbGxlY3RDb3VudFRleHQ9cGF5bWVudHMubGVuZ3RoP2DssKjsiJggJHtwYXltZW50cy5sZW5ndGgudG9Mb2NhbGVTdHJpbmcoImtvLUtSIil96rG0YDoi7IiY6riIIOuCtOyXrSDsl4bsnYwiOwogICAgICBjb25zdCBvdXRzb3VyY2VDb3VudFRleHQ9c3VtbWFyaXplT3V0c291cmNlQ291bnRzKHIpOwogICAgICBjb25zdCBoYXNPdXRzb3VyY2U9KHIub3V0c291cmNlSXRlbXN8fFtdKS5sZW5ndGg+MHx8KHIub3V0c291cmNlQ29zdHx8MCk+MHx8KHIub3V0c291cmNlUGFpZHx8MCk+MHx8KHIub3V0c291cmNlUmVtYWluaW5nfHwwKT4wOwogICAgICBjb25zdCBzdW1tYXJ5Q2FyZHM9WwogICAgICAgIGA8ZGl2IGNsYXNzPSJzdW1tYXJ5LWNhcmQiPjxkaXYgY2xhc3M9InN1bW1hcnktbGFiZWwiPuqzhOyVveq4iDwvZGl2PjxkaXYgY2xhc3M9InN1bW1hcnktdmFsdWUiPiR7ZXNjKHdvbihyLmNTdXApKX08L2Rpdj48ZGl2IGNsYXNzPSJzdW1tYXJ5LW5vdGUiPlZBVCDrs4Trj4Q8L2Rpdj48L2Rpdj5gLAogICAgICAgIGA8ZGl2IGNsYXNzPSJzdW1tYXJ5LWNhcmQiPjxkaXYgY2xhc3M9InN1bW1hcnktbGFiZWwiPuyImOq4iOyVoTwvZGl2PjxkaXYgY2xhc3M9InN1bW1hcnktdmFsdWUiPiR7ZXNjKHdvbihyLmNvbCkpfTwvZGl2PjxkaXYgY2xhc3M9InN1bW1hcnktbm90ZSI+JHtlc2MobGF0ZXN0Q29sbGVjdD09PSItIj8i7IiY6riI7J28IOyXhuydjCI6YOy1nOyihSDsiJjquIjsnbwgJHtsYXRlc3RDb2xsZWN0fWApfTwvZGl2PjwvZGl2PmAsCiAgICAgICAgYDxkaXYgY2xhc3M9InN1bW1hcnktY2FyZCI+PGRpdiBjbGFzcz0ic3VtbWFyeS1sYWJlbCI+7IiY6riI7JyoPC9kaXY+PGRpdiBjbGFzcz0ic3VtbWFyeS12YWx1ZSI+JHtlc2Moci5yYXRlLnRvRml4ZWQoMikrIiUiKX08L2Rpdj48ZGl2IGNsYXNzPSJzdW1tYXJ5LW5vdGUiPiR7ZXNjKGNvbGxlY3RDb3VudFRleHQpfTwvZGl2PjwvZGl2PmAKICAgICAgXS5maWx0ZXIoQm9vbGVhbikuam9pbigiIik7CiAgICAgIGNvbnN0IGJvdHRvbU5vdGVzPVsKICAgICAgICBgPGRpdiBjbGFzcz0ic3VtbWFyeS1ub3RlIj7rr7jsiJjquIjslaEgJHtlc2Mod29uKHIucmVjdikpfTwvZGl2PmAKICAgICAgXS5qb2luKCIiKTsKICAgICAgY29uc3QgYm9hcmRzPVsKICAgICAgICBoYXNPdXRzb3VyY2U/cmVuZGVyT3V0c291cmNlQm9hcmQocik6IiIsCiAgICAgICAgcmVuZGVyQ29sbGVjdGlvbkJvYXJkKHIpCiAgICAgIF0uZmlsdGVyKEJvb2xlYW4pLmpvaW4oIiIpOwogICAgICByZXR1cm4gYDxkaXYgY2xhc3M9ImlubGluZS1wYW5lbCI+PGRpdiBjbGFzcz0icHJvamVjdC1oZWFkIj48ZGl2IGNsYXNzPSJpbmxpbmUtY2FyZCI+PGRpdiBjbGFzcz0icHJvamVjdC1tZXRhLWdyaWQiPjxkaXYgY2xhc3M9Imt2Ij48ZGl2IGNsYXNzPSJrdmsiPuqzhOyVveuyleyduDwvZGl2PjxkaXYgY2xhc3M9Imt2diI+JHtlc2Moci5jb3JwfHwiLSIpfTwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9Imt2Ij48ZGl2IGNsYXNzPSJrdmsiPuuwnOyjvOyymDwvZGl2PjxkaXYgY2xhc3M9Imt2diI+JHtlc2Moci5jbGllbnR8fCItIil9PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0ia3YiPjxkaXYgY2xhc3M9Imt2ayI+67Cc7KO867Cp67KVPC9kaXY+PGRpdiBjbGFzcz0ia3Z2Ij4ke2VzYyhyLm9yZGVyfHwiLSIpfTwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9Imt2Ij48ZGl2IGNsYXNzPSJrdmsiPlBNPC9kaXY+PGRpdiBjbGFzcz0ia3Z2Ij4ke2VzYyhyLnBtfHwiLSIpfTwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgc3R5bGU9ImRpc3BsYXk6Z3JpZDtncmlkLXRlbXBsYXRlLWNvbHVtbnM6MWZyIDFmcjtnYXA6OHB4O21hcmdpbi10b3A6MTBweCI+JHtyZW5kZXJDb250YWN0Q29tcGFjdCgi6rOE7JW9IC8g7LKt6rWsIOuLtOuLueyekCIsci5jbU5tLHIuY21DbyxyLmNtRHAsci5jbVBoLHIuY21FbSl9JHtyZW5kZXJDb250YWN0Q29tcGFjdCgi67aA7IScIOuLtOuLueyekCIsci5kbU5tLHIuZG1DbyxyLmRtRHAsci5kbVBoLHIuZG1FbSl9PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iaW5saW5lLWNhcmQiPjxkaXYgY2xhc3M9InN1bW1hcnktZ3JpZCI+JHtzdW1tYXJ5Q2FyZHN9PC9kaXY+PGRpdiBzdHlsZT0ibWFyZ2luLXRvcDoxMHB4IiBjbGFzcz0icHJvZ3Jlc3MiPjxkaXYgY2xhc3M9ImJhciIgc3R5bGU9IndpZHRoOiR7TWF0aC5tYXgoMCxNYXRoLm1pbigxMDAsci5yYXRlfHwwKSl9JSI+PC9kaXY+PC9kaXY+PGRpdiBzdHlsZT0iZGlzcGxheTpmbGV4O2p1c3RpZnktY29udGVudDpzcGFjZS1iZXR3ZWVuO2dhcDoxMHB4O21hcmdpbi10b3A6MTBweCI+JHtib3R0b21Ob3Rlc308L2Rpdj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJsZWRnZXItc3RhY2siPiR7Ym9hcmRzfTwvZGl2PjwvZGl2PmA7CiAgICB9CiAgICBmdW5jdGlvbiBjbG9zZUFsbE1vZGFscygpewogICAgICBFLmNvbGxlY3RNb2RhbC5jbGFzc0xpc3QucmVtb3ZlKCJzaG93Iik7CiAgICAgIEUub3V0c291cmNlTW9kYWwuY2xhc3NMaXN0LnJlbW92ZSgic2hvdyIpOwogICAgfQogICAgZnVuY3Rpb24gdG9nZ2xlSW5saW5lRGV0YWlsKHIpewogICAgICBjb25zdCBrZXk9cm93S2V5KHIpOwogICAgICBTLmV4cGFuZGVkLmtleT1TLmV4cGFuZGVkLmtleT09PWtleT8iIjprZXk7CiAgICAgIHJlbmRlcigpOwogICAgfQogICAgZnVuY3Rpb24gb3BlbkNvbGxlY3Rpb25Nb2RhbChyKXsKICAgICAgc2V0VGV4dCgibUNhdCIsci5jYXR8fCLrr7jrtoTrpZgiKTtHKCJtQ2F0IikuY2xhc3NMaXN0LnRvZ2dsZSgib2siLChyLnN0YXR1c3x8IiIpLmluY2x1ZGVzKCLsmYTro4wiKSk7c2V0VGV4dCgibVRpdGxlIixyLm5hbWV8fCItIik7c2V0VGV4dCgibVN1YiIsIlByb2plY3QgQ29kZTogIisoci5jb2RlfHwiLSIpKyIgwrcg6rOE7JW967KV7J24OiAiKyhyLmNvcnB8fCItIikpOwogICAgICBzZXRUZXh0KCJtQ2xpZW50IixyLmNsaWVudHx8Ii0iKTtzZXRUZXh0KCJtT3JkZXIiLHIub3JkZXJ8fCItIik7c2V0VGV4dCgibVNwbGl0IixyLnNwbGl0fHwiLSIpO3NldFRleHQoIm1TdGFydERhdGUiLGQoci5zRGF0ZSkpO3NldFRleHQoIm1FbmREYXRlIixkKHIuZURhdGUpKTtzZXRUZXh0KCJtUGF5VHlwZSIsci5wYXl8fCItIik7RygibVBheUl0ZW1zIikuaW5uZXJIVE1MPXJlbmRlclBheW1lbnRzSHRtbChyLnBheW1lbnRzfHxbXSk7CiAgICAgIHNldFRleHQoIm1Db250cmFjdFRvdGFsIix3b24oci5jVG90KSk7c2V0VGV4dCgibUNvbnRyYWN0U3VwcGx5Iiwi6rO16riJ6rCA7JWhOiAiK3dvbihyLmNTdXApKTtzZXRUZXh0KCJtQ29sbGVjdGVkIix3b24oci5jb2wpKTtzZXRUZXh0KCJtQ29sbGVjdERhdGUiLChyLnBheW1lbnRzJiZyLnBheW1lbnRzLmxlbmd0aD4xPyLstZzqt7wg7IiY6riI7J28OiAiOiLsiJjquIjsnbw6ICIpK2Qoci5jb2xsZWN0RGF0ZVN1bW1hcnl8fHIuY29sRGF0ZSkpO3NldFRleHQoIm1SYXRlIixyLnJhdGUudG9GaXhlZCgyKSsiJSIpO3NldFRleHQoIm1SZWNlaXZhYmxlIix3b24oci5yZWN2KSk7RygibVJhdGVCYXIiKS5zdHlsZS53aWR0aD1NYXRoLm1heCgwLE1hdGgubWluKDEwMCxyLnJhdGV8fDApKSsiJSI7CiAgICAgIHNldFRleHQoIm1DbU5hbWUiLHIuY21ObXx8Ii0iKTtzZXRUZXh0KCJtQ21PcmciLChyLmNtQ298fCItIikrIiDCtyAiKyhyLmNtRHB8fCItIikpO3NldFRleHQoIm1DbVBob25lIiwi7KCE7ZmUOiAiKyhyLmNtUGh8fCItIikpO3NldFRleHQoIm1DbUVtYWlsIiwi66mU7J28OiAiKyhyLmNtRW18fCItIikpOwogICAgICBzZXRUZXh0KCJtRG1OYW1lIixyLmRtTm18fCItIik7c2V0VGV4dCgibURtT3JnIiwoci5kbUNvfHwiLSIpKyIgwrcgIisoci5kbURwfHwiLSIpKTtzZXRUZXh0KCJtRG1QaG9uZSIsIuyghO2ZlDogIisoci5kbVBofHwiLSIpKTtzZXRUZXh0KCJtRG1FbWFpbCIsIuuplOydvDogIisoci5kbUVtfHwiLSIpKTsKICAgICAgY2xvc2VBbGxNb2RhbHMoKTsKICAgICAgRS5jb2xsZWN0TW9kYWwuY2xhc3NMaXN0LmFkZCgic2hvdyIpOwogICAgfQogICAgZnVuY3Rpb24gb3Blbk91dHNvdXJjZU1vZGFsKHIpewogICAgICBzZXRUZXh0KCJvVGl0bGUiLHIubmFtZXx8Ii0iKTsKICAgICAgc2V0VGV4dCgib1N1YiIsIlByb2plY3QgQ29kZTogIisoci5jb2RlfHwiLSIpKyIgwrcgUE06ICIrKHIucG18fCItIikpOwogICAgICBzZXRUZXh0KCJvQ29ycCIsci5jb3JwfHwiLSIpOwogICAgICBzZXRUZXh0KCJvQ2xpZW50IixyLmNsaWVudHx8Ii0iKTsKICAgICAgc2V0VGV4dCgib1ZlbmRvcnMiLHIub3V0c291cmNlVmVuZG9yVGV4dHx8Ii0iKTsKICAgICAgc2V0VGV4dCgib1RvdGFsIixyLm91dHNvdXJjZUNvc3Q/d29uKHIub3V0c291cmNlQ29zdCk6Ii0iKTsKICAgICAgc2V0VGV4dCgib0NvdW50Iiwoci5vdXRzb3VyY2VJdGVtc3x8W10pLmxlbmd0aD9gJHsoci5vdXRzb3VyY2VJdGVtc3x8W10pLmxlbmd0aC50b0xvY2FsZVN0cmluZygia28tS1IiKX3qsbRgOiIw6rG0Iik7CiAgICAgIHNldFRleHQoIm9QZXJpb2QiLHIucGVyaW9kVGV4dHx8Ii0iKTsKICAgICAgc2V0VGV4dCgib1RvdGFsSGVybyIsci5vdXRzb3VyY2VDb3N0P3dvbihyLm91dHNvdXJjZUNvc3QpOiItIik7CiAgICAgIHNldFRleHQoIm9Ub3RhbEhpbnQiLChyLm91dHNvdXJjZUl0ZW1zfHxbXSkubGVuZ3RoPyLsi5ztirjrs4Qg7Jm47KO8IOyDgeyEuCDrgrTsl60g7ZWp7IKwIjoi7Jm47KO8IOyDgeyEuCDsoJXrs7TqsIAg7JeG7Iq164uI64ukLiIpOwogICAgICBHKCJvSXRlbXMiKS5pbm5lckhUTUw9cmVuZGVyT3V0c291cmNlSHRtbChyLm91dHNvdXJjZUl0ZW1zfHxbXSk7CiAgICAgIGNsb3NlQWxsTW9kYWxzKCk7CiAgICAgIEUub3V0c291cmNlTW9kYWwuY2xhc3NMaXN0LmFkZCgic2hvdyIpOwogICAgfQogICAgZnVuY3Rpb24gb3V0c291cmNlU3VtbWFyeVRleHQocil7CiAgICAgIGNvbnN0IGNvbnRyYWN0cz0oci5vdXRzb3VyY2VJdGVtc3x8W10pLmxlbmd0aDsKICAgICAgY29uc3Qgc3RhZ2VzPWNvdW50T3V0c291cmNlU3RhZ2VzKHIpOwogICAgICBjb25zdCBwYXJ0cz1bXTsKICAgICAgaWYoY29udHJhY3RzKSBwYXJ0cy5wdXNoKGDqs4Tslb0gJHtjb250cmFjdHMudG9Mb2NhbGVTdHJpbmcoImtvLUtSIil96rG0YCk7CiAgICAgIGlmKHN0YWdlcykgcGFydHMucHVzaChg7KeA6riJ64uo6rOEICR7c3RhZ2VzLnRvTG9jYWxlU3RyaW5nKCJrby1LUiIpfeqxtGApOwogICAgICBpZihwYXJ0cy5sZW5ndGgpIHJldHVybiBwYXJ0cy5qb2luKCIgwrcgIik7CiAgICAgIHJldHVybiAiLSI7CiAgICB9CiAgICBmdW5jdGlvbiByZW5kZXIoKXsKICAgICAgY29uc3Qgcm93cz1TLnJvd3MsdD1zdW1Sb3dzKHJvd3MpLHZpZXdSb3dzPXJvd3Muc2xpY2UoKS5zb3J0KChhLGIpPT57Y29uc3QgYXM9aXNTZXR0bGVkUm93KGEpLGJzPWlzU2V0dGxlZFJvdyhiKTtpZihhcyE9PWJzKXJldHVybiBhcz8xOi0xO3JldHVybiAoYi5yZWN2fHwwKS0oYS5yZWN2fHwwKTt9KTsKICAgICAgY29uc3QgdXNlU2hlZXRUb3RhbHM9ISEoUy50b3RhbHMmJiFoYXNBY3RpdmVEYXNoYm9hcmRGaWx0ZXJzKCkpOwogICAgICBjb25zdCB0b3RhbENvbnRyYWN0PXVzZVNoZWV0VG90YWxzP1MudG90YWxzLmNvbnRyYWN0OnQuYzsKICAgICAgY29uc3QgdG90YWxDb2xsZWN0ZWQ9dXNlU2hlZXRUb3RhbHM/Uy50b3RhbHMuY29sbGVjdGVkOnQuY29sOwogICAgICBjb25zdCB0b3RhbFJlY2VpdmFibGU9dXNlU2hlZXRUb3RhbHM/Uy50b3RhbHMucmVjZWl2YWJsZTp0LnJlY3Y7CiAgICAgIGNvbnN0IHRvdGFsUmF0ZT11c2VTaGVldFRvdGFscz9TLnRvdGFscy5yYXRlOnJhdGUoIiIsdG90YWxDb2xsZWN0ZWQsdG90YWxDb2xsZWN0ZWQrdG90YWxSZWNlaXZhYmxlKTsKICAgICAgUy52aWV3Um93cz12aWV3Um93czsKICAgICAgRS5jYXJkcy5pbm5lckhUTUw9W1si7LSdIO2UhOuhnOygne2KuOyImCIscm93cy5sZW5ndGgudG9Mb2NhbGVTdHJpbmcoImtvLUtSIikrIiDqsbQiXSxbIuy0nSDqs4Tslb3quIgiLHdvbih0b3RhbENvbnRyYWN0KV0sWyLstJ0g7IiY6riI6riI7JWhIix3b24odG90YWxDb2xsZWN0ZWQpXSxbIuy0nSDrr7jsiJjquIjslaEiLHdvbih0b3RhbFJlY2VpdmFibGUpXSxbIuy0nSDsiJjquIjsnKgiLHRvdGFsUmF0ZS50b0ZpeGVkKDIpKyIlIl1dLm1hcChjPT5gPGRpdiBjbGFzcz0iY2FyZCI+PGRpdiBjbGFzcz0iayI+JHtlc2MoY1swXSl9PC9kaXY+PGRpdiBjbGFzcz0idiI+JHtlc2MoY1sxXSl9PC9kaXY+PC9kaXY+YCkuam9pbigiIik7CiAgICAgIEUudGJvZHkuaW5uZXJIVE1MPXZpZXdSb3dzLm1hcCgocixpKT0+ewogICAgICAgIGNvbnN0IGtleT1yb3dLZXkocik7CiAgICAgICAgY29uc3QgZGV0YWlsT3Blbj1TLmV4cGFuZGVkLmtleT09PWtleTsKICAgICAgICBjb25zdCBkZXRhaWxIdG1sPWRldGFpbE9wZW4/cmVuZGVyUHJvamVjdElubGluZShyKToiIjsKICAgICAgICByZXR1cm4gYDx0ciBkYXRhLWk9IiR7aX0iIGNsYXNzPSIke2lzU2V0dGxlZFJvdyhyKT8ic2V0dGxlZCI6IiJ9Ij48dGQ+PGRpdiBjbGFzcz0iYmFkZ2UiPiR7ZXNjKHIuY2F0fHwiLSIpfTwvZGl2PjxkaXYgY2xhc3M9InN1YmxpbmUiPklEOiAke2VzYyhyLmNvZGV8fCItIil9PC9kaXY+PC90ZD48dGQ+PGRpdiBjbGFzcz0ibmFtZSI+JHtlc2Moci5uYW1lfHwiLSIpfTwvZGl2PjxkaXYgY2xhc3M9InN1YmxpbmUiPiR7ZXNjKHIucGVyaW9kVGV4dHx8Ii0iKX08L2Rpdj48L3RkPjx0ZD48ZGl2PiR7ZXNjKHIuY29ycHx8Ii0iKX08L2Rpdj48L3RkPjx0ZD48ZGl2IGNsYXNzPSJiYWRnZSAkeyhyLnN0YXR1c3x8IiIpLmluY2x1ZGVzKCLsmYTro4wiKT8ib2siOiIifSI+JHtlc2Moci5zdGF0dXN8fCItIil9PC9kaXY+PGRpdiBjbGFzcz0ic3VibGluZSI+JHtlc2Moci55bnx8Ii0iKX08L2Rpdj48L3RkPjx0ZCBjbGFzcz0ibnVtIj48c3Ryb25nPiR7ZXNjKHIub3V0c291cmNlQ29zdD93b24oci5vdXRzb3VyY2VDb3N0KToiLSIpfTwvc3Ryb25nPjwvdGQ+PHRkIGNsYXNzPSJudW0iPjxzdHJvbmc+JHtlc2Mod29uKHIuY1N1cCkpfTwvc3Ryb25nPjwvdGQ+PHRkIGNsYXNzPSJudW0iPjxzdHJvbmc+JHtlc2Mod29uKHIuY29sKSl9PC9zdHJvbmc+PC90ZD48dGQgY2xhc3M9Im51bSI+PHN0cm9uZyBzdHlsZT0iY29sb3I6JHtpc1NldHRsZWRSb3cocik/IiM5NGEzYjgiOiIjMjU2M2ViIn0iPiR7ZXNjKHIucmF0ZS50b0ZpeGVkKDIpKyIlIil9PC9zdHJvbmc+PC90ZD48L3RyPiR7ZGV0YWlsSHRtbD9gPHRyIGNsYXNzPSJkZXRhaWwtcm93Ij48dGQgY2xhc3M9ImRldGFpbC1jZWxsIiBjb2xzcGFuPSI4Ij4ke2RldGFpbEh0bWx9PC90ZD48L3RyPmA6IiJ9YDsKICAgICAgfSkuam9pbigiIik7CiAgICAgIEUuZW1wdHkuc3R5bGUuZGlzcGxheT1yb3dzLmxlbmd0aD8ibm9uZSI6ImJsb2NrIjsKICAgICAgY29uc3Qgc2V0dGxlZENvdW50PVMuYWxsLmZpbHRlcihpc1NldHRsZWRSb3cpLmxlbmd0aDsKICAgICAgRS5zdGF0dXMudGV4dENvbnRlbnQ9Uy5hbGwubGVuZ3RoP2DroZzrk5wg7JmE66OMOiAke1MuYWxsLmxlbmd0aC50b0xvY2FsZVN0cmluZygia28tS1IiKX3qsbQke1MuZmlsZT9gIMK3IO2MjOydvDogJHtTLmZpbGV9YDoiIn0ke3NldHRsZWRDb3VudD9gIMK3IOyZhOuCqSAke3NldHRsZWRDb3VudC50b0xvY2FsZVN0cmluZygia28tS1IiKX3qsbQg7ZWY64uoIOygleugrGA6IiJ9YDoiQ1NWL1hMU1gg7YyM7J287J2EIOyXheuhnOuTnO2VmOuptCDrjbDsnbTthLDqsIAg7ZGc7Iuc65Cp64uI64ukLiI7CiAgICB9CiAgICBmdW5jdGlvbiBmaWx0ZXIoKXtjb25zdCBxPVN0cmluZyhFLnNlYXJjaC52YWx1ZXx8IiIpLnRyaW0oKS50b0xvd2VyQ2FzZSgpO2NvbnN0IHNlYXJjaGVkPSFxP1MuYWxsLnNsaWNlKCk6Uy5hbGwuZmlsdGVyKHI9PltyLmNvZGUsci5uYW1lLHIuY2xpZW50LHIucG0sci5zdGF0dXMsci5jYXQsci5jb3JwLHIucGF5LChyLnBheW1lbnRzfHxbXSkubWFwKHA9PnAucGF5KS5qb2luKCIgIiksci5wZXJpb2RUZXh0LHIub3V0c291cmNlVmVuZG9yVGV4dCwoci5vdXRzb3VyY2VJdGVtc3x8W10pLm1hcChpdGVtPT5baXRlbS52ZW5kb3IsaXRlbS5kZXRhaWwsaXRlbS5wcm9ncmVzcyxpdGVtLm5vdGUsKGl0ZW0ucGF5bWVudHN8fFtdKS5tYXAocGF5bWVudD0+W3BheW1lbnQubGFiZWwscGF5bWVudC5ub3RlLHBheW1lbnQuaW52b2ljZURhdGUscGF5bWVudC5wYXltZW50RGF0ZV0uam9pbigiICIpKS5qb2luKCIgIildLmpvaW4oIiAiKSkuam9pbigiICIpLG91dHNvdXJjZUZpbHRlckxhYmVsKHIpLGFtb3VudEZpbHRlckxhYmVsKHIpLGNvbGxlY3RlZEZpbHRlckxhYmVsKHIpXS5qb2luKCIgIikudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhxKSk7Uy5yb3dzPXNlYXJjaGVkLmZpbHRlcihtYXRjaGVzQ29sdW1uRmlsdGVycyk7cmVuZGVyKCk7fQogICAgZnVuY3Rpb24gYXBwbHlQYXJzZWRMZWRnZXJSZXN1bHQoZmlsZU5hbWUscGFyc2VkLHNoZWV0TmFtZSl7CiAgICAgIFMuYWxsPXBhcnNlZC5yZWNvcmRzOwogICAgICBTLnRvdGFscz1wYXJzZWQudG90YWxzfHxudWxsOwogICAgICBTLmZpbGU9KGZpbGVOYW1lfHwiIikrKHNoZWV0TmFtZT9gIFske3NoZWV0TmFtZX1dYDoiIik7CiAgICAgIHN5bmNDb2x1bW5GaWx0ZXJzKFMuYWxsKTsKICAgICAgZmlsdGVyKCk7CiAgICB9CiAgICBhc3luYyBmdW5jdGlvbiBsb2FkTGVkZ2VyRmlsZShidWZmZXIsZmlsZU5hbWUpewogICAgICBjb25zdCBpc0V4Y2VsPS9cLih4bHN4fHhscykkL2kudGVzdChTdHJpbmcoZmlsZU5hbWV8fCIiKSk7CiAgICAgIGlmKGlzRXhjZWwpewogICAgICAgIGNvbnN0IHBhcnNlZD1wYXJzZUxlZGdlckV4Y2VsKGJ1ZmZlcik7CiAgICAgICAgYXBwbHlQYXJzZWRMZWRnZXJSZXN1bHQoZmlsZU5hbWUscGFyc2VkLHBhcnNlZC5zaGVldE5hbWV8fCIiKTsKICAgICAgICByZXR1cm47CiAgICAgIH0KICAgICAgY29uc3QgcGFyc2VkPXBhcnNlTGVkZ2VyKGRlY29kZShidWZmZXIpKTsKICAgICAgYXBwbHlQYXJzZWRMZWRnZXJSZXN1bHQoZmlsZU5hbWUscGFyc2VkLCIiKTsKICAgIH0KICAgIEUuYnRuVXBsb2FkLmFkZEV2ZW50TGlzdGVuZXIoImNsaWNrIiwoKT0+RS5maWxlLmNsaWNrKCkpOwogICAgRS5maWxlLmFkZEV2ZW50TGlzdGVuZXIoImNoYW5nZSIsYXN5bmMgZT0+ewogICAgICBjb25zdCBmPWUudGFyZ2V0LmZpbGVzJiZlLnRhcmdldC5maWxlc1swXTsKICAgICAgdHJ5ewogICAgICAgIGlmKGYpewogICAgICAgICAgY29uc3QgYnVmPWF3YWl0IGYuYXJyYXlCdWZmZXIoKTsKICAgICAgICAgIGF3YWl0IGxvYWRMZWRnZXJGaWxlKGJ1ZixmLm5hbWV8fCIiKTsKICAgICAgICB9CiAgICAgIH1jYXRjaChlcnIpewogICAgICAgIFMuYWxsPVtdO1Mucm93cz1bXTtTLnRvdGFscz1udWxsO3N5bmNDb2x1bW5GaWx0ZXJzKFtdKTtjbG9zZUFsbE1vZGFscygpO3JlbmRlcigpO0Uuc3RhdHVzLnRleHRDb250ZW50PSLsl4XroZzrk5wg7Iuk7YyoOiAiKyhlcnImJmVyci5tZXNzYWdlP2Vyci5tZXNzYWdlOlN0cmluZyhlcnIpKTsKICAgICAgfQogICAgICBlLnRhcmdldC52YWx1ZT0iIjsKICAgIH0pOwogICAgRS5zZWFyY2guYWRkRXZlbnRMaXN0ZW5lcigiaW5wdXQiLGZpbHRlcik7CiAgICBPYmplY3QudmFsdWVzKEUuZmlsdGVyQnV0dG9ucykuZm9yRWFjaChidG49PmJ0bi5hZGRFdmVudExpc3RlbmVyKCJjbGljayIsZT0+e2Uuc3RvcFByb3BhZ2F0aW9uKCk7dG9nZ2xlRmlsdGVyTWVudShidG4uZGF0YXNldC5maWx0ZXIpO30pKTsKICAgIE9iamVjdC52YWx1ZXMoRS5maWx0ZXJNZW51cykuZm9yRWFjaChtZW51PT5tZW51LmFkZEV2ZW50TGlzdGVuZXIoImNsaWNrIixlPT57CiAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7CiAgICAgIGNvbnN0IG9wdGlvbj1lLnRhcmdldCYmZS50YXJnZXQuY2xvc2VzdD9lLnRhcmdldC5jbG9zZXN0KCJidXR0b25bZGF0YS1maWx0ZXItdmFsdWVdIik6bnVsbDsKICAgICAgaWYoIW9wdGlvbikgcmV0dXJuOwogICAgICBzZXRGaWx0ZXJWYWx1ZShtZW51LmRhdGFzZXQuZmlsdGVyLG9wdGlvbi5nZXRBdHRyaWJ1dGUoImRhdGEtZmlsdGVyLXZhbHVlIil8fCIiKTsKICAgIH0pKTsKICAgIEUudGJvZHkuYWRkRXZlbnRMaXN0ZW5lcigiY2xpY2siLGU9PnsKICAgICAgY29uc3Qgcm93RWw9ZS50YXJnZXQmJmUudGFyZ2V0LmNsb3Nlc3Q/ZS50YXJnZXQuY2xvc2VzdCgidHJbZGF0YS1pXSIpOm51bGw7CiAgICAgIGlmKCFyb3dFbCkgcmV0dXJuOwogICAgICBjb25zdCByPVMudmlld1Jvd3NbcGFyc2VJbnQocm93RWwuZ2V0QXR0cmlidXRlKCJkYXRhLWkiKSwxMCldOwogICAgICBpZighcikgcmV0dXJuOwogICAgICB0b2dnbGVJbmxpbmVEZXRhaWwocik7CiAgICB9KTsKICAgIEUuYnRuQ29sbGVjdENsb3NlLmFkZEV2ZW50TGlzdGVuZXIoImNsaWNrIixjbG9zZUFsbE1vZGFscyk7CiAgICBFLmJ0bk91dHNvdXJjZUNsb3NlLmFkZEV2ZW50TGlzdGVuZXIoImNsaWNrIixjbG9zZUFsbE1vZGFscyk7CiAgICBFLmNvbGxlY3RNb2RhbC5hZGRFdmVudExpc3RlbmVyKCJjbGljayIsZT0+e2lmKGUudGFyZ2V0PT09RS5jb2xsZWN0TW9kYWwpY2xvc2VBbGxNb2RhbHMoKTt9KTsKICAgIEUub3V0c291cmNlTW9kYWwuYWRkRXZlbnRMaXN0ZW5lcigiY2xpY2siLGU9PntpZihlLnRhcmdldD09PUUub3V0c291cmNlTW9kYWwpY2xvc2VBbGxNb2RhbHMoKTt9KTsKICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoImNsaWNrIixlPT57aWYoIShlLnRhcmdldCYmZS50YXJnZXQuY2xvc2VzdCYmZS50YXJnZXQuY2xvc2VzdCgiLnRoLWhlYWQiKSkpY2xvc2VGaWx0ZXJNZW51cygpO30pOwogICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigia2V5ZG93biIsZT0+e2lmKGUua2V5PT09IkVzY2FwZSIpe2Nsb3NlRmlsdGVyTWVudXMoKTtjbG9zZUFsbE1vZGFscygpO319KTsKICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIixhc3luYyBlPT57CiAgICAgIGNvbnN0IGRhdGE9ZS5kYXRhfHx7fTsKICAgICAgaWYoZGF0YS5zb3VyY2U9PT0idG90YWwtY29udHJvbCImJmRhdGEudHlwZT09PSJlbWJlZGRlZC1ob3N0IikgRS5idG5VcGxvYWQuc3R5bGUuZGlzcGxheT0ibm9uZSI7CiAgICAgIGlmKGRhdGEuc291cmNlIT09InRvdGFsLXVwbG9hZCJ8fGRhdGEudHlwZSE9PSJidXNpbmVzcyIpIHJldHVybjsKICAgICAgdHJ5ewogICAgICAgIGNvbnN0IGJ1ZmZlcj1kYXRhLmJ1ZmZlciBpbnN0YW5jZW9mIEFycmF5QnVmZmVyP2RhdGEuYnVmZmVyOihkYXRhLmJ1ZmZlciYmZGF0YS5idWZmZXIuYnVmZmVyIGluc3RhbmNlb2YgQXJyYXlCdWZmZXI/ZGF0YS5idWZmZXIuYnVmZmVyOm51bGwpOwogICAgICAgIGlmKCFidWZmZXIpIHRocm93IG5ldyBFcnJvcigi7JeF66Gc65OcIOuNsOydtO2EsOqwgCDruYTslrQg7J6I7Iq164uI64ukLiIpOwogICAgICAgIGF3YWl0IGxvYWRMZWRnZXJGaWxlKGJ1ZmZlcixkYXRhLmZpbGVOYW1lfHwi7IKs7JeF6rSA66as64yA7J6lLnhsc3giKTsKICAgICAgfWNhdGNoKGVycil7CiAgICAgICAgUy5hbGw9W107Uy5yb3dzPVtdO1MudG90YWxzPW51bGw7c3luY0NvbHVtbkZpbHRlcnMoW10pO2Nsb3NlQWxsTW9kYWxzKCk7cmVuZGVyKCk7RS5zdGF0dXMudGV4dENvbnRlbnQ9IuyXheuhnOuTnCDsi6TtjKg6ICIrKGVyciYmZXJyLm1lc3NhZ2U/ZXJyLm1lc3NhZ2U6U3RyaW5nKGVycikpOwogICAgICB9CiAgICB9KTsKICAgIHN5bmNDb2x1bW5GaWx0ZXJzKFtdKTsKICAgIHJlbmRlcigpOwogIDwvc2NyaXB0Pgo8L2JvZHk+CjwvaHRtbD4K';
const DASH_HTML_B64='PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9ImtvIj4KPGhlYWQ+CiAgPG1ldGEgY2hhcnNldD0iVVRGLTgiIC8+CiAgPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xLjAiIC8+CiAgPHRpdGxlPu2UhOuhnOygne2KuCDrjIDsi5zrs7Trk5w8L3RpdGxlPgogIDxzY3JpcHQgc3JjPSJodHRwczovL3VucGtnLmNvbS9yZWFjdEAxOC91bWQvcmVhY3QucHJvZHVjdGlvbi5taW4uanMiPjwvc2NyaXB0PgogIDxzY3JpcHQgc3JjPSJodHRwczovL3VucGtnLmNvbS9yZWFjdC1kb21AMTgvdW1kL3JlYWN0LWRvbS5wcm9kdWN0aW9uLm1pbi5qcyI+PC9zY3JpcHQ+CiAgPHNjcmlwdCBzcmM9Imh0dHBzOi8vdW5wa2cuY29tL3JlYWN0LWlzL3VtZC9yZWFjdC1pcy5wcm9kdWN0aW9uLm1pbi5qcyI+PC9zY3JpcHQ+CiAgPHNjcmlwdCBzcmM9Imh0dHBzOi8vdW5wa2cuY29tL3JlY2hhcnRzL3VtZC9SZWNoYXJ0cy5taW4uanMiPjwvc2NyaXB0PgogIDxzY3JpcHQgc3JjPSJodHRwczovL3VucGtnLmNvbS9AYmFiZWwvc3RhbmRhbG9uZS9iYWJlbC5taW4uanMiPjwvc2NyaXB0PgogIDxzY3JpcHQgc3JjPSJodHRwczovL2Nkbi50YWlsd2luZGNzcy5jb20iPjwvc2NyaXB0Pgo8L2hlYWQ+Cjxib2R5PgogIDxkaXYgaWQ9InJvb3QiPjwvZGl2PgogIDxzY3JpcHQgdHlwZT0idGV4dC9iYWJlbCI+CmNvbnN0IHsgdXNlU3RhdGUsIHVzZU1lbW8sIHVzZUVmZmVjdCB9ID0gUmVhY3Q7CmNvbnN0IFJlY2hhcnRzTGliID0gd2luZG93LlJlY2hhcnRzIHx8IHt9OwoKY29uc3QgaWNvbiA9IChnbHlwaCkgPT4gKHsgc2l6ZSA9IDE0LCBjbGFzc05hbWUgPSAnJyB9KSA9PiAoCiAgPHNwYW4gY2xhc3NOYW1lPXtjbGFzc05hbWV9IHN0eWxlPXt7IGZvbnRTaXplOiBgJHtzaXplfXB4YCwgbGluZUhlaWdodDogMSB9fT57Z2x5cGh9PC9zcGFuPgopOwpjb25zdCBMYXlvdXREYXNoYm9hcmQgPSBpY29uKCfilqYnKTsKY29uc3QgQ2xvY2sgPSBpY29uKCfil7cnKTsKY29uc3QgQnJpZWZjYXNlID0gaWNvbign4pajJyk7CmNvbnN0IENhbGVuZGFyID0gaWNvbign4perJyk7CmNvbnN0IExpc3QgPSBpY29uKCfiiaEnKTsKY29uc3QgVGFyZ2V0ID0gaWNvbign4peOJyk7CmNvbnN0IFVzZXJzID0gaWNvbign8J+RpScpOwpjb25zdCBVcGxvYWQgPSBpY29uKCfih6onKTsKY29uc3QgQ2hlY2tDaXJjbGUyID0gaWNvbign4pePJyk7CmNvbnN0IEZpbGVUZXh0ID0gaWNvbign4pakJyk7CmNvbnN0IFJlZnJlc2hDdyA9IGljb24oJ+KGuycpOwpjb25zdCBNYXBQaW4gPSBpY29uKCfijJYnKTsKY29uc3QgQ29mZmVlID0gaWNvbign4piVJyk7CmNvbnN0IFBhY2thZ2UgPSBpY29uKCfilqcnKTsKY29uc3QgV2FsbGV0ID0gaWNvbign4pauJyk7CmNvbnN0IFVzZXJDaGVjayA9IGljb24oJ+KckycpOwpjb25zdCBJbmZvID0gaWNvbign4pOYJyk7Cgpjb25zdCBBcHAgPSAoKSA9PiB7CiAgY29uc3QgW2V4cGVuc2VSYXcsIHNldEV4cGVuc2VSYXddID0gdXNlU3RhdGUoW10pOwogIGNvbnN0IFt3b3JrUmF3LCBzZXRXb3JrUmF3XSA9IHVzZVN0YXRlKFtdKTsKICBjb25zdCBbZGF0YUxvYWRlZCwgc2V0RGF0YUxvYWRlZF0gPSB1c2VTdGF0ZSh7IGV4cGVuc2U6IGZhbHNlLCB3b3JrOiBmYWxzZSB9KTsKICBjb25zdCBbZXJyb3JNc2csIHNldEVycm9yTXNnXSA9IHVzZVN0YXRlKG51bGwpOwoKICBjb25zdCBbc2VsZWN0ZWRSZXYsIHNldFNlbGVjdGVkUmV2XSA9IHVzZVN0YXRlKCfsoITssrQnKTsKICBjb25zdCBbc2VsZWN0ZWREMSwgc2V0U2VsZWN0ZWREMV0gPSB1c2VTdGF0ZSgn7KCE7LK0Jyk7CiAgY29uc3QgW3NlbGVjdGVkRDIsIHNldFNlbGVjdGVkRDJdID0gdXNlU3RhdGUoJ+yghOyytCcpOwogIGNvbnN0IFtzZWxlY3RlZFByb2plY3QsIHNldFNlbGVjdGVkUHJvamVjdF0gPSB1c2VTdGF0ZSgn7KCE7LK0Jyk7CiAgY29uc3QgW3N0YXJ0RGF0ZSwgc2V0U3RhcnREYXRlXSA9IHVzZVN0YXRlKCcyMDI2LTAxLTAxJyk7CiAgY29uc3QgW2VuZERhdGUsIHNldEVuZERhdGVdID0gdXNlU3RhdGUoJzIwMjYtMDEtMzEnKTsKICBjb25zdCBbc2VsZWN0ZWRFeHBlbnNlRGV0YWlsQ2F0ZWdvcnksIHNldFNlbGVjdGVkRXhwZW5zZURldGFpbENhdGVnb3J5XSA9IHVzZVN0YXRlKCcnKTsKCiAgY29uc3QgZDFPcmRlciA9IHsgIuunpOy2nCI6IDEsICLruYTrp6TstpwiOiAyLCAi6rO17Ya1IjogMywgIuy0neq0hOq4sO2ajeyLpCI6IDQgfTsKICBjb25zdCBkMk9yZGVyID0geyAi67CU66Gg6rOE7JW9IjogMSwgIuqwgOyhseyCrCDtlITroZzsoJ3tirgiOiAyLCAiUy9XIOqwnOuwnCI6IDMsICLquLDtmo0v7KCc7JWIIjogNCwgIuy0neq0hOq4sO2ajeyLpCI6IDUsICLqs7XthrUiOiA2IH07CiAgY29uc3Qgbm9ybWFsaXplS2V5ID0gKHYpID0+IFN0cmluZyh2IHx8ICcnKS50cmltKCkucmVwbGFjZSgvXHMrL2csICcnKS50b0xvd2VyQ2FzZSgpOwogIGNvbnN0IG5vcm1hbGl6ZVByb2plY3RLZXkgPSAodikgPT4KICAgIFN0cmluZyh2IHx8ICcnKQogICAgICAubm9ybWFsaXplKCdORktDJykKICAgICAgLnRvTG93ZXJDYXNlKCkKICAgICAgLnJlcGxhY2UoL1tcdTIwMGItXHUyMDBkXHVmZWZmXS9nLCAnJykKICAgICAgLnJlcGxhY2UoL1teMC05YS166rCALe2eo10vZywgJycpOwogIGNvbnN0IGQzRGlzcGxheU9yZGVyID0gWwogICAgJ1MvV+2MkOunpCcsICfquLDsiKDsmqnsl63qs4Tslb0nLCAn7L2Y7YWQ7LigIOygnOyekScsICdSJkQnLCAn7Iuc6rO1JywgJ+uUlOyekOyduCcsICfrgrTrtoAgQklNIOyEpOqzhCDsp4Dsm5AnLCAn6riw7LSI7KGw7IKsIOuwjyBHSVMnLAogICAgJ+uPhOuhnCcsICfqtazsobAnLCAn6rWQ7Ya1JywgJ+yImOumrC/siJjrrLgnLCAn6re4656Y7ZS9JywgJ+q1rOyhsO2VtOyEnScsICfshpTro6jshZgnLCAn7Jq07JiBUy9XJywgJ+q4sO2ajSbqtIDrpqwnLCAn7LSd6rSE6riw7ZqN7IukJywgJ+qzte2GtScKICBdOwogIGNvbnN0IGQyT3JkZXJNYXAgPSBuZXcgTWFwKE9iamVjdC5rZXlzKGQyT3JkZXIpLm1hcCgobmFtZSkgPT4gW25vcm1hbGl6ZUtleShuYW1lKSwgZDJPcmRlcltuYW1lXV0pKTsKICBjb25zdCBkM09yZGVyTWFwID0gbmV3IE1hcChkM0Rpc3BsYXlPcmRlci5tYXAoKG5hbWUsIGlkeCkgPT4gW25vcm1hbGl6ZUtleShuYW1lKSwgaWR4ICsgMV0pKTsKICBjb25zdCBkM1ByaW9yaXR5QnlEMiA9IHsKICAgICdzL3fqsJzrsJwnOiB7ICfquLDstIjsobDsgqzrsI9naXMnOiAwIH0sCiAgICAn6riw7ZqNL+ygnOyViCc6IHsgJ+yatOyYgXMvdyc6IDAgfQogIH07CiAgY29uc3QgZ2V0RDJPcmRlciA9IChuYW1lKSA9PiB7CiAgICBjb25zdCBuayA9IG5vcm1hbGl6ZUtleShuYW1lKTsKICAgIHJldHVybiBkMk9yZGVyTWFwLmhhcyhuaykgPyBkMk9yZGVyTWFwLmdldChuaykgOiA5OTk5OwogIH07CiAgY29uc3QgZ2V0RDNPcmRlciA9IChuYW1lLCBkMikgPT4gewogICAgY29uc3QgbmsgPSBub3JtYWxpemVLZXkobmFtZSk7CiAgICBjb25zdCBvdmVycmlkZSA9IGQzUHJpb3JpdHlCeUQyW25vcm1hbGl6ZUtleShkMildPy5bbmtdOwogICAgaWYgKG92ZXJyaWRlICE9PSB1bmRlZmluZWQpIHJldHVybiBvdmVycmlkZTsKICAgIHJldHVybiBkM09yZGVyTWFwLmhhcyhuaykgPyBkM09yZGVyTWFwLmdldChuaykgKyAxMDAgOiA5OTk5OwogIH07CiAgY29uc3QgcHJvamVjdERpc3BsYXlPcmRlciA9IFsKICAgICdFRy1CSU0gKO2MjOydtO2UhO2Fjey9lOumrOyVhCknLCAnRVJQ7Iuc7Iqk7YWc6rWs7LaVKO2VnOyihSknLCAnR0FJQSDquLDriqUg6rCc7ISgIOqzhOyVvScsICfqs4TslpF+6rCV7ZmUIOqzoOyGjeuPhOuhnCg16rO16rWsKScsCiAgICAn6rWt64+ENDIg7JuQ7KO8fu2dpeyXhScsICfsnbjso7x+7Je87LmYKDHqs7Xqtawp67mF66O4JywgJ+yduOyjvH7sl7zsuZgoMuqzteq1rCnruYXro7gnLCAn64yA7IKwfuuLueynhCgx6rO16rWsKSDruYXro7gnLAogICAgJ+uMgOyCsH7ri7nsp4QoMuqzteq1rCkg67mF66O4JywgJ+uMgOyCsH7ri7nsp4QoM3406rO16rWsKSDruYXro7gnLCAn67O07J2A6rWt7Yag64+E66GcIOyCrOyXheq0gOumrCcsICftlZzqsJXqtZDrn4kg7IKs7JeF6rSA66asKDLqs7XqtawpJywKICAgICfsmIjsgrDqta3thqAg7KCcMuq2jOyXrScsICfqsIDtj4nqtbAg7ZWY7IiY6rSA66ed7Iuc7Iqk7YWcJywgJ1BRIOyLnOyKpO2FnCjsp4DsmKTrqZTsubTsnbTsl5Tsp4ApJywgJ+uUlOyngO2EuCDqta3thqDsoJXrs7QoMe2VteyLrCknLAogICAgJ+uUlOyngO2EuCDqta3thqDsoJXrs7QoMu2VteyLrCknLCAn7Iqk66eI7Yq46rG07ISk6riw7IigKDEw6rO87KCcKScsICdYUuq4sOuwmCDqsbTshKTshKTqs4Qg7ZiB7Iug7Iuc7Iqk7YWcJywgJ+yduOyynOuwnCBLVFgg7Iuc6rO1JywKICAgICfqsIDsobHsgqzrs7Tqs6DshJwg7YOs7ZSM66a/IOygnOyekScsICfrjIDsgrB+64u57KeEKDLqs7XqtawpIOyLnOqztUJJTScsICfshJzsgrB+66qF7LKcIOq4sOuzuCDrsI8g7Iuk7Iuc7ISk6rOEJywgJ+yauOyCsOyZuOqzveyInO2ZmCgx6rO16rWsKScsCiAgICAn7Lap64Ko7ZiVIOyKpOuniO2KuO2MnCDquLDrs7gv7Iuk7IucJywgJ+ybkO2aqOuMgOq1kOu2geuLqOuwj+q1reygnOyXheustOyngOq1rCcsICftlqXstIzsp4DqtazsmrDsiJjsnKDstpzsoIDqsJDsgqzsl4XqtIDrpqwnLCAnS05HSUwnLAogICAgJ0dJUyBNYXBwZXInLCAn7LKc7KeA7J24JywgJ1N1cnZleW9yJywgJ0dBSUEnLCAnV2F5UHJpbWFsJywgJ1dheUNvbmZpcm0nLCAnV2F5RHJhdycsICdXYXlTaG9wJywKICAgICdXYXRjaEJJTScsICdUd2luIEhpZ2h3YXknLCAnV2FsbFphaW5lcicsICdCcmlkZ2UgcGxhbm5lcicsICdBYnV0WmFpbmVyJywgJ0JyaVphaW5lci1EUicsCiAgICAnQnJpWmFpbmVyLU5vZHVsYXInLCAnVHVubmVsWmFpbmVyJywgJ1RPVkEnLCAnTGlmZUxpbmUtd2F0ZXInLCAn6rCV7Jqw6rCV64+E7IKw7KCVIO2UhOuhnOq3uOueqCcsICdIbUVHKEhtRHJhdyknLAogICAgJ0VHLUJJTSBNb2RlbGVyJywgJ0VHLUJJTSBEcmF3ZXInLCAnU3RyQW5hJywgJ+usuOyEnOq0gOumrOyLnOyKpO2FnChQTSknLCAnQ0NQJywgJ2JDTWYnLCAnR1NJTScsCiAgICAn64uo6rCAL+qzteyglSBzb2x1dGlvbicsICdEb21haW5lcicsICdFUlA67J6l7ZeM7IKw7JeFJywgJ0VSUDpQVEMnLCAnRVJQOu2VnOudvCcsICdFUlA67IK87JWIJywgJ0VSUDrtlZzrp6UnLAogICAgJ0VSUDrrsJTroaAnLCAnRVJQOuyepe2XjCcsICdFUlA67IKw7ZWY7KKF7ZWp6riw7IigJywgJ+yeheywsOygleuztCjsmqnsl60v6rO17IKsKeyhsO2ajOyLnOyKpO2FnCcsICdQUeyLnOyKpO2FnCcsICfsoITsgrDsmrTsmIHqtIDrpqwnLAogICAgJ0JFUHMnLCAn7IKs7KCE6riw7ZqNJywgJ+yyreyaqeyynOq1kCDsl4XrrLTsp4Dsm5AnLCAn7IiY7J6Q7JuQIO2VtOyZuOyCrOyXhScsICdBSScsICdDaXZpbEVuZ2luZWVyaW5nTGFiJywgJ0dJUyDsnqXruYTqsJzrsJwnLAogICAgJ+2UhOumrOy6kOyKpO2KuCDsobDrpr3si50g67CV7Iqk7ZiVIOq1kOufiScsICfsnbjrjZXsm5B+64+Z7YOEIOyKpOuniO2KuOyDge2ZqeyLpCcsICftlZzrp6XqsIDsobEg67Cw7JuA7YSwJywgJ+qyveyYgeq4sO2ajS/soITrnrUnLCAn7J247IKsL+q1kOycoScsCiAgICAn7Jq07JiB7KeA7JuQKOy0neustCknLCAn7JeF66y0L+yCrOyXheq0gOumrCcsICfqtZDsnKHtm4jroKgsIOywuOyEnScsICfqs7XthrUo6riw7YOAKScKICBdOwogIGNvbnN0IGRlZmF1bHRQcm9qZWN0T3JkZXJNYXAgPSBuZXcgTWFwKHByb2plY3REaXNwbGF5T3JkZXIubWFwKChuYW1lLCBpZHgpID0+IFtub3JtYWxpemVQcm9qZWN0S2V5KG5hbWUpLCBpZHhdKSk7CiAgY29uc3QgW2N1c3RvbVByb2plY3RPcmRlck1hcCwgc2V0Q3VzdG9tUHJvamVjdE9yZGVyTWFwXSA9IHVzZVN0YXRlKG51bGwpOwogIGNvbnN0IGdldFByb2plY3RPcmRlciA9IChuYW1lKSA9PiB7CiAgICBjb25zdCBrZXkgPSBub3JtYWxpemVQcm9qZWN0S2V5KG5hbWUpOwogICAgaWYgKCFrZXkpIHJldHVybiA5OTk5OwogICAgaWYgKGN1c3RvbVByb2plY3RPcmRlck1hcCAmJiBjdXN0b21Qcm9qZWN0T3JkZXJNYXAuaGFzKGtleSkpIHJldHVybiBjdXN0b21Qcm9qZWN0T3JkZXJNYXAuZ2V0KGtleSk7CiAgICByZXR1cm4gZGVmYXVsdFByb2plY3RPcmRlck1hcC5oYXMoa2V5KSA/IGRlZmF1bHRQcm9qZWN0T3JkZXJNYXAuZ2V0KGtleSkgOiA5OTk5OwogIH07CiAgCiAgY29uc3QgY29zdENhdGVnb3JpZXMgPSBbCiAgICB7IG5hbWU6ICfsnbjqsbTruYQnLCBjb2xvcjogJyM2MzY2ZjEnIH0sCiAgICB7IG5hbWU6ICfstpzsnqXruYQnLCBjb2xvcjogJyNmNDNmNWUnIH0sCiAgICB7IG5hbWU6ICfrs7Xrpqztm4Tsg53ruYQnLCBjb2xvcjogJyNmYmJmMjQnIH0sCiAgICB7IG5hbWU6ICfqtazrp6TruYQnLCBjb2xvcjogJyMwZWE1ZTknIH0sCiAgICB7IG5hbWU6ICfsmbjso7zruYQnLCBjb2xvcjogJyM5NGEzYjgnIH0KICBdOwoKICBjb25zdCBwb3NpdGlvblN0eWxlcyA9IHsKICAgICfsiJjshJ3sl7Dqtazsm5AnOiB7IGJnOiAnYmctcHVycGxlLTUwJywgdGV4dDogJ3RleHQtcHVycGxlLTYwMCcsIGJvcmRlcjogJ2JvcmRlci1wdXJwbGUtMTAwJywgaWNvbjogJ2JnLXB1cnBsZS02MDAnIH0sCiAgICAn7LGF7J6E7Jew6rWs7JuQJzogeyBiZzogJ2JnLWJsdWUtNTAnLCB0ZXh0OiAndGV4dC1ibHVlLTYwMCcsIGJvcmRlcjogJ2JvcmRlci1ibHVlLTEwMCcsIGljb246ICdiZy1ibHVlLTYwMCcgfSwKICAgICfshKDsnoTsl7Dqtazsm5AnOiB7IGJnOiAnYmctaW5kaWdvLTUwJywgdGV4dDogJ3RleHQtaW5kaWdvLTYwMCcsIGJvcmRlcjogJ2JvcmRlci1pbmRpZ28tMTAwJywgaWNvbjogJ2JnLWluZGlnby02MDAnIH0sCiAgICAn7KCE7J6E7Jew6rWs7JuQJzogeyBiZzogJ2JnLWVtZXJhbGQtNTAnLCB0ZXh0OiAndGV4dC1lbWVyYWxkLTYwMCcsIGJvcmRlcjogJ2JvcmRlci1lbWVyYWxkLTEwMCcsIGljb246ICdiZy1lbWVyYWxkLTYwMCcgfSwKICAgICfso7zsnoTsl7Dqtazsm5AnOiB7IGJnOiAnYmctc2xhdGUtNTAnLCB0ZXh0OiAndGV4dC1zbGF0ZS02MDAnLCBib3JkZXI6ICdib3JkZXItc2xhdGUtMTAwJywgaWNvbjogJ2JnLXNsYXRlLTYwMCcgfSwKICAgICfsl7Dqtazsm5AnOiB7IGJnOiAnYmctc2xhdGUtNTAnLCB0ZXh0OiAndGV4dC1zbGF0ZS01MDAnLCBib3JkZXI6ICdib3JkZXItc2xhdGUtMTAwJywgaWNvbjogJ2JnLXNsYXRlLTQwMCcgfSwKICAgICfrr7jsp4DsoJUnOiB7IGJnOiAnYmctZ3JheS01MCcsIHRleHQ6ICd0ZXh0LWdyYXktNDAwJywgYm9yZGVyOiAnYm9yZGVyLWdyYXktMTAwJywgaWNvbjogJ2JnLWdyYXktMzAwJyB9CiAgfTsKICBjb25zdCBwb3NpdGlvbk9yZGVyID0geyAn7IiY7ISd7Jew6rWs7JuQJzogMSwgJ+yxheyehOyXsOq1rOybkCc6IDIsICfshKDsnoTsl7Dqtazsm5AnOiAzLCAn7Jew6rWs7JuQJzogNCB9OwogIGNvbnN0IHBvc2l0aW9uQ29sb3JNYXAgPSB7CiAgICAn7IiY7ISd7Jew6rWs7JuQJzogJyM3YzNhZWQnLAogICAgJ+yxheyehOyXsOq1rOybkCc6ICcjMjU2M2ViJywKICAgICfshKDsnoTsl7Dqtazsm5AnOiAnIzRmNDZlNScsCiAgICAn7KCE7J6E7Jew6rWs7JuQJzogJyMwNTk2NjknLAogICAgJ+yjvOyehOyXsOq1rOybkCc6ICcjNDc1NTY5JywKICAgICfsl7Dqtazsm5AnOiAnIzY0NzQ4YicsCiAgICAn66+47KeA7KCVJzogJyM5Y2EzYWYnCiAgfTsKCiAgY29uc3QgZ2V0UG9zaXRpb25TdHlsZSA9IChwb3MpID0+IHBvc2l0aW9uU3R5bGVzW3Bvc10gfHwgcG9zaXRpb25TdHlsZXNbJ+uvuOyngOyglSddOwogIGNvbnN0IGdldENvc3RDb2xvciA9IChuYW1lKSA9PiBjb3N0Q2F0ZWdvcmllcy5maW5kKGMgPT4gYy5uYW1lID09PSBuYW1lKT8uY29sb3IgfHwgJyM5NGEzYjgnOwogIGNvbnN0IGdldFBvc2l0aW9uQ29sb3IgPSAobmFtZSkgPT4gcG9zaXRpb25Db2xvck1hcFtuYW1lXSB8fCBwb3NpdGlvbkNvbG9yTWFwWyfrr7jsp4DsoJUnXTsKCiAgY29uc3QgZm9ybWF0V29uID0gKHZhbHVlKSA9PiBg4oKpJHsodmFsdWUgfHwgMCkudG9Mb2NhbGVTdHJpbmcoKX1gOwogIGNvbnN0IGZvcm1hdFdvblJvdW5kZWQgPSAodmFsdWUpID0+IGDigqkke01hdGgucm91bmQodmFsdWUgfHwgMCkudG9Mb2NhbGVTdHJpbmcoKX1gOwoKICBjb25zdCBidWlsZERvbnV0R3JhZGllbnQgPSAoaXRlbXMpID0+IHsKICAgIGNvbnN0IHRvdGFsID0gaXRlbXMucmVkdWNlKChzdW0sIGl0ZW0pID0+IHN1bSArIChpdGVtLnZhbHVlIHx8IDApLCAwKTsKICAgIGlmICh0b3RhbCA8PSAwKSByZXR1cm4gJ2NvbmljLWdyYWRpZW50KCNlMmU4ZjAgMGRlZyAzNjBkZWcpJzsKICAgIGxldCBzdGFydCA9IDA7CiAgICBjb25zdCBzbGljZXMgPSBpdGVtcy5tYXAoKGl0ZW0pID0+IHsKICAgICAgY29uc3QgZGVnID0gKChpdGVtLnZhbHVlIHx8IDApIC8gdG90YWwpICogMzYwOwogICAgICBjb25zdCBlbmQgPSBzdGFydCArIGRlZzsKICAgICAgY29uc3Qgc2VnbWVudCA9IGAke2dldENvc3RDb2xvcihpdGVtLm5hbWUpfSAke3N0YXJ0fWRlZyAke2VuZH1kZWdgOwogICAgICBzdGFydCA9IGVuZDsKICAgICAgcmV0dXJuIHNlZ21lbnQ7CiAgICB9KTsKICAgIHJldHVybiBgY29uaWMtZ3JhZGllbnQoJHtzbGljZXMuam9pbignLCAnKX0pYDsKICB9OwoKICBjb25zdCByZW5kZXJCcmVha2Rvd25Ub29sdGlwID0gKGJyZWFrZG93biwgdG90YWwpID0+ICgKICAgIDxkaXYgY2xhc3NOYW1lPSJwb2ludGVyLWV2ZW50cy1ub25lIGFic29sdXRlIGxlZnQtMS8yIHRvcC0wIHotMjAgLXRyYW5zbGF0ZS14LTEvMiAtdHJhbnNsYXRlLXktWzExMCVdIHdoaXRlc3BhY2Utbm93cmFwIHJvdW5kZWQtbGcgYmctc2xhdGUtOTAwIHB4LTMgcHktMiB0ZXh0LVsxMnB4XSBmb250LWJvbGQgdGV4dC13aGl0ZSBvcGFjaXR5LTAgc2hhZG93LWxnIHRyYW5zaXRpb24tb3BhY2l0eSBncm91cC1ob3ZlcjpvcGFjaXR5LTEwMCI+CiAgICAgIHtjb3N0Q2F0ZWdvcmllcy5tYXAoKGNhdCkgPT4gewogICAgICAgIGNvbnN0IHZhbCA9IGJyZWFrZG93bj8uW2NhdC5uYW1lXSB8fCAwOwogICAgICAgIGNvbnN0IHJhdGlvID0gdG90YWwgPiAwID8gKCh2YWwgLyB0b3RhbCkgKiAxMDApLnRvRml4ZWQoMSkgOiAnMC4wJzsKICAgICAgICByZXR1cm4gKAogICAgICAgICAgPGRpdiBrZXk9e2NhdC5uYW1lfSBjbGFzc05hbWU9ImZsZXggaXRlbXMtY2VudGVyIGp1c3RpZnktYmV0d2VlbiBnYXAtMyI+CiAgICAgICAgICAgIDxzcGFuIGNsYXNzTmFtZT0iZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTEuNSI+CiAgICAgICAgICAgICAgPHNwYW4gY2xhc3NOYW1lPSJpbmxpbmUtYmxvY2sgaC0yIHctMiByb3VuZGVkLWZ1bGwiIHN0eWxlPXt7IGJhY2tncm91bmRDb2xvcjogZ2V0Q29zdENvbG9yKGNhdC5uYW1lKSB9fT48L3NwYW4+CiAgICAgICAgICAgICAge2NhdC5uYW1lfQogICAgICAgICAgICA8L3NwYW4+CiAgICAgICAgICAgIDxzcGFuPntmb3JtYXRXb24odmFsKX0gKHtyYXRpb30lKTwvc3Bhbj4KICAgICAgICAgIDwvZGl2PgogICAgICAgICk7CiAgICAgIH0pfQogICAgPC9kaXY+CiAgKTsKCiAgY29uc3QgcmVuZGVyUG9zaXRpb25CcmVha2Rvd25Ub29sdGlwID0gKGJyZWFrZG93biwgdG90YWxIcnMpID0+ICgKICAgIDxkaXYgY2xhc3NOYW1lPSJwb2ludGVyLWV2ZW50cy1ub25lIGFic29sdXRlIGxlZnQtMS8yIHRvcC0wIHotMjAgLXRyYW5zbGF0ZS14LTEvMiAtdHJhbnNsYXRlLXktWzExMCVdIHdoaXRlc3BhY2Utbm93cmFwIHJvdW5kZWQtbGcgYmctc2xhdGUtOTAwIHB4LTMgcHktMiB0ZXh0LVsxMnB4XSBmb250LWJvbGQgdGV4dC13aGl0ZSBvcGFjaXR5LTAgc2hhZG93LWxnIHRyYW5zaXRpb24tb3BhY2l0eSBncm91cC1ob3ZlcjpvcGFjaXR5LTEwMCI+CiAgICAgIHtPYmplY3QuZW50cmllcyhicmVha2Rvd24gfHwge30pCiAgICAgICAgLnNvcnQoKFthXSwgW2JdKSA9PiAocG9zaXRpb25PcmRlclthXSB8fCA5OSkgLSAocG9zaXRpb25PcmRlcltiXSB8fCA5OSkgfHwgYS5sb2NhbGVDb21wYXJlKGIpKQogICAgICAgIC5tYXAoKFtwb3MsIHZhbF0pID0+IHsKICAgICAgICAgIGNvbnN0IHJhdGlvID0gdG90YWxIcnMgPiAwID8gKCh2YWwgLyB0b3RhbEhycykgKiAxMDApLnRvRml4ZWQoMSkgOiAnMC4wJzsKICAgICAgICAgIHJldHVybiAoCiAgICAgICAgICAgIDxkaXYga2V5PXtwb3N9IGNsYXNzTmFtZT0iZmxleCBpdGVtcy1jZW50ZXIganVzdGlmeS1iZXR3ZWVuIGdhcC0zIj4KICAgICAgICAgICAgICA8c3BhbiBjbGFzc05hbWU9ImZsZXggaXRlbXMtY2VudGVyIGdhcC0xLjUiPgogICAgICAgICAgICAgICAgPHNwYW4gY2xhc3NOYW1lPSJpbmxpbmUtYmxvY2sgaC0yIHctMiByb3VuZGVkLWZ1bGwiIHN0eWxlPXt7IGJhY2tncm91bmRDb2xvcjogZ2V0UG9zaXRpb25Db2xvcihwb3MpIH19Pjwvc3Bhbj4KICAgICAgICAgICAgICAgIHtwb3N9CiAgICAgICAgICAgICAgPC9zcGFuPgogICAgICAgICAgICAgIDxzcGFuPnt2YWwudG9GaXhlZCgyKX1oICh7cmF0aW99JSk8L3NwYW4+CiAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgKTsKICAgICAgICB9KX0KICAgIDwvZGl2PgogICk7CgogIGNvbnN0IHJlbmRlckNvc3RCcmVha2Rvd25UYWJsZSA9IChicmVha2Rvd24pID0+IHsKICAgIGNvbnN0IGNlbGxzID0gWwogICAgICB7IGtleTogJ+yduOqxtOu5hCcsIGxhYmVsOiAn7J246rG067mEJyB9LAogICAgICB7IGtleTogJ+y2nOyepeu5hCcsIGxhYmVsOiAn7Lac7J6l67mEJyB9LAogICAgICB7IGtleTogJ+uzteumrO2bhOyDneu5hCcsIGxhYmVsOiAn67O166as7ZuE7IOd67mEJyB9LAogICAgICB7IGtleTogJ+q1rOunpOu5hCcsIGxhYmVsOiAn6rWs66ek67mEJyB9LAogICAgICB7IGtleTogJ+yZuOyjvOu5hCcsIGxhYmVsOiAn7Jm47KO867mEJyB9CiAgICBdOwogICAgcmV0dXJuICgKICAgICAgPHRhYmxlIGNsYXNzTmFtZT0idy1mdWxsIHRhYmxlLWZpeGVkIGJvcmRlci1zZXBhcmF0ZSBib3JkZXItc3BhY2luZy0wIHRleHQtY2VudGVyIHRleHQtWzExcHhdIGZvbnQtYmxhY2sgb3ZlcmZsb3ctaGlkZGVuIHJvdW5kZWQtbGciPgogICAgICAgIDx0Ym9keT4KICAgICAgICAgIDx0cj4KICAgICAgICAgICAge2NlbGxzLm1hcCgoY2VsbCkgPT4gKAogICAgICAgICAgICAgIDx0ZCBrZXk9e2Ake2NlbGwua2V5fS1oYH0gY2xhc3NOYW1lPSJ3LTEvNSBiZy1zbGF0ZS0zMDAvNzAgdGV4dC1zbGF0ZS03MDAgcHktMS41IGJvcmRlci1yIGJvcmRlci13aGl0ZSBsYXN0OmJvcmRlci1yLTAgd2hpdGVzcGFjZS1ub3dyYXAiPntjZWxsLmxhYmVsfTwvdGQ+CiAgICAgICAgICAgICkpfQogICAgICAgICAgPC90cj4KICAgICAgICAgIDx0cj4KICAgICAgICAgICAge2NlbGxzLm1hcCgoY2VsbCkgPT4gKAogICAgICAgICAgICAgIDx0ZCBrZXk9e2Ake2NlbGwua2V5fS12YH0gY2xhc3NOYW1lPSJ3LTEvNSBiZy1zbGF0ZS0xMDAgdGV4dC1zbGF0ZS03MDAgcHktMS41IGJvcmRlci1yIGJvcmRlci13aGl0ZSBsYXN0OmJvcmRlci1yLTAgd2hpdGVzcGFjZS1ub3dyYXAiPgogICAgICAgICAgICAgICAge01hdGgucm91bmQoYnJlYWtkb3duPy5bY2VsbC5rZXldIHx8IDApLnRvTG9jYWxlU3RyaW5nKCl9IOybkAogICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICkpfQogICAgICAgICAgPC90cj4KICAgICAgICA8L3Rib2R5PgogICAgICA8L3RhYmxlPgogICAgKTsKICB9OwoKICBjb25zdCBwYXJzZUNTViA9ICh0ZXh0KSA9PiB7CiAgICBpZiAoIXRleHQpIHJldHVybiBbXTsKICAgIGNvbnN0IGxpbmVzID0gU3RyaW5nKHRleHQpLnNwbGl0KC9ccj9cbi8pLmZpbHRlcihsaW5lID0+IGxpbmUudHJpbSgpKTsKICAgIGlmIChsaW5lcy5sZW5ndGggPT09IDApIHJldHVybiBbXTsKICAgIAogICAgY29uc3Qgc3BsaXRMaW5lID0gKGxpbmUpID0+IHsKICAgICAgY29uc3Qgb3V0ID0gW107CiAgICAgIGxldCBjdXIgPSAnJzsKICAgICAgbGV0IGluUSA9IGZhbHNlOwogICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxpbmUubGVuZ3RoOyBpKyspIHsKICAgICAgICBjb25zdCBjaCA9IGxpbmVbaV07CiAgICAgICAgaWYgKGNoID09PSAnIicpIGluUSA9ICFpblE7CiAgICAgICAgZWxzZSBpZiAoY2ggPT09ICcsJyAmJiAhaW5RKSB7CiAgICAgICAgICBvdXQucHVzaChjdXIpOwogICAgICAgICAgY3VyID0gJyc7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGN1ciArPSBjaDsKICAgICAgICB9CiAgICAgIH0KICAgICAgb3V0LnB1c2goY3VyKTsKICAgICAgcmV0dXJuIG91dC5tYXAodiA9PiBTdHJpbmcodiB8fCAnJykucmVwbGFjZSgvXiJ8IiQvZywgJycpLnJlcGxhY2UoL1tcdWZlZmZcdTIwMGJdL2csICcnKS50cmltKCkpOwogICAgfTsKCiAgICBjb25zdCBoZWFkZXJzID0gc3BsaXRMaW5lKGxpbmVzWzBdKTsKICAgIGNvbnN0IG5IZWFkZXJzID0gaGVhZGVycy5tYXAoaCA9PiBub3JtYWxpemVLZXkoaCkpOwogICAgcmV0dXJuIGxpbmVzLnNsaWNlKDEpLm1hcChsaW5lID0+IHsKICAgICAgY29uc3QgdmFsdWVzID0gc3BsaXRMaW5lKGxpbmUpOwogICAgICBjb25zdCBvYmogPSB7IF9fdmFsdWVzOiB2YWx1ZXMgfTsKICAgICAgaGVhZGVycy5mb3JFYWNoKChoZWFkZXIsIGkpID0+IHsKICAgICAgICBpZiAoIWhlYWRlcikgcmV0dXJuOwogICAgICAgIG9ialtoZWFkZXJdID0gdmFsdWVzW2ldIHx8ICcnOwogICAgICAgIGlmIChuSGVhZGVyc1tpXSkgb2JqW2BfX25fJHtuSGVhZGVyc1tpXX1gXSA9IHZhbHVlc1tpXSB8fCAnJzsKICAgICAgfSk7CiAgICAgIHJldHVybiBvYmo7CiAgICB9KTsKICB9OwoKICBjb25zdCBwYXJzZVByb2plY3RPcmRlck1hcEZyb21Dc3YgPSAodGV4dCkgPT4gewogICAgY29uc3Qgcm93cyA9IHBhcnNlQ1NWKHRleHQpOwogICAgaWYgKCFyb3dzLmxlbmd0aCkgcmV0dXJuIG51bGw7CiAgICBjb25zdCBtYXAgPSBuZXcgTWFwKCk7CiAgICByb3dzLmZvckVhY2goKHJvdykgPT4gewogICAgICBjb25zdCBjYW5kaWRhdGVzID0gWwogICAgICAgIGdldFZhbChyb3csIFsn7IKs7JeF66qFKOyduO2KuOudvOuEt+q4sOykgCknLCAn7IKs7JeF66m0KOyduO2KuOudvOuEt+q4sOykgCknLCAn7IKs7JeF66qFKOyduO2KuOudvOuEtyDquLDspIApJywgJ+yCrOyXheuptCjsnbjtirjrnbzrhLcg6riw7KSAKScsICdENCddLCA5KSwKICAgICAgICBnZXRWYWwocm93LCBbJ+2UhOuhnOygne2KuOuqhScsICftlITroZzsoJ3tirgnLCAn7ZSE66Gc7KCd7Yq466qFIOunpOy5rSddLCAwKQogICAgICBdOwogICAgICBjb25zdCBmaXJzdEZpbGxlZCA9IChyb3cuX192YWx1ZXMgfHwgW10pLmZpbmQoKHYpID0+IG5vcm0odikpOwogICAgICBjb25zdCBwcm9qZWN0TmFtZSA9IG5vcm0oY2FuZGlkYXRlcy5maW5kKCh2KSA9PiBub3JtKHYpKSB8fCBmaXJzdEZpbGxlZCB8fCAnJyk7CiAgICAgIGNvbnN0IGtleSA9IG5vcm1hbGl6ZVByb2plY3RLZXkocHJvamVjdE5hbWUpOwogICAgICBpZiAoIWtleSB8fCBtYXAuaGFzKGtleSkpIHJldHVybjsKICAgICAgbWFwLnNldChrZXksIG1hcC5zaXplKTsKICAgIH0pOwogICAgcmV0dXJuIG1hcC5zaXplID8gbWFwIDogbnVsbDsKICB9OwoKICBjb25zdCBnZXRWYWwgPSAocm93LCBjYW5kaWRhdGVzID0gW10sIGZhbGxiYWNrSWR4ID0gLTEpID0+IHsKICAgIGZvciAoY29uc3QgYyBvZiBjYW5kaWRhdGVzKSB7CiAgICAgIGlmIChyb3dbY10gIT09IHVuZGVmaW5lZCAmJiByb3dbY10gIT09ICcnKSByZXR1cm4gcm93W2NdOwogICAgICBjb25zdCBudiA9IHJvd1tgX19uXyR7bm9ybWFsaXplS2V5KGMpfWBdOwogICAgICBpZiAobnYgIT09IHVuZGVmaW5lZCAmJiBudiAhPT0gJycpIHJldHVybiBudjsKICAgIH0KICAgIGlmIChmYWxsYmFja0lkeCA+PSAwICYmIHJvdy5fX3ZhbHVlcyAmJiByb3cuX192YWx1ZXNbZmFsbGJhY2tJZHhdICE9PSB1bmRlZmluZWQpIHJldHVybiByb3cuX192YWx1ZXNbZmFsbGJhY2tJZHhdOwogICAgcmV0dXJuICcnOwogIH07CgogIGNvbnN0IG5vcm0gPSAodikgPT4gU3RyaW5nKHYgfHwgJycpLnJlcGxhY2UoL1tcdWZlZmZcdTIwMGJdL2csICcnKS50cmltKCk7CiAgY29uc3QgcG51bSA9ICh2KSA9PiBwYXJzZUZsb2F0KFN0cmluZyh2IHx8ICcnKS5yZXBsYWNlKC9bXjAtOS5cLV0vZywgJycpKSB8fCAwOwogIGNvbnN0IG5vcm1hbGl6ZUQxQ2F0ZWdvcnkgPSAodmFsdWUpID0+IHsKICAgIGNvbnN0IHRleHQgPSBub3JtKHZhbHVlKTsKICAgIGlmICghdGV4dCkgcmV0dXJuICcnOwogICAgaWYgKHRleHQgPT09ICfqs7XrsLEnIHx8IHRleHQgPT09ICctJyB8fCB0ZXh0ID09PSAn7JeG7J2MJyB8fCB0ZXh0ID09PSAnbmEnIHx8IHRleHQgPT09ICduL2EnKSByZXR1cm4gJyc7CiAgICByZXR1cm4gdGV4dDsKICB9OwogIGNvbnN0IHJlc2V0RmlsdGVycyA9ICgpID0+IHsKICAgIHNldFNlbGVjdGVkUmV2KCfsoITssrQnKTsKICAgIHNldFNlbGVjdGVkRDEoJ+yghOyytCcpOwogICAgc2V0U2VsZWN0ZWREMign7KCE7LK0Jyk7CiAgICBzZXRTZWxlY3RlZFByb2plY3QoJ+yghOyytCcpOwogIH07CgogIGNvbnN0IGhhbmRsZUZpbGVVcGxvYWQgPSAoZSwgdHlwZSkgPT4gewogICAgY29uc3QgZmlsZSA9IGUudGFyZ2V0LmZpbGVzWzBdOwogICAgaWYgKCFmaWxlKSByZXR1cm47CiAgICBjb25zdCByZWFkZXIgPSBuZXcgRmlsZVJlYWRlcigpOwogICAgcmVhZGVyLm9ubG9hZCA9IChldmVudCkgPT4gewogICAgICB0cnkgewogICAgICAgIGNvbnN0IGRhdGEgPSBwYXJzZUNTVihldmVudC50YXJnZXQucmVzdWx0KTsKICAgICAgICBpZiAodHlwZSA9PT0gJ2V4cGVuc2UnKSB7CiAgICAgICAgICBzZXRFeHBlbnNlUmF3KGRhdGEpOwogICAgICAgICAgc2V0RGF0YUxvYWRlZChwcmV2ID0+ICh7IC4uLnByZXYsIGV4cGVuc2U6IHRydWUgfSkpOwogICAgICAgICAgcmVzZXRGaWx0ZXJzKCk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHNldFdvcmtSYXcoZGF0YSk7CiAgICAgICAgICBzZXREYXRhTG9hZGVkKHByZXYgPT4gKHsgLi4ucHJldiwgd29yazogdHJ1ZSB9KSk7CiAgICAgICAgICByZXNldEZpbHRlcnMoKTsKICAgICAgICB9CiAgICAgIH0gY2F0Y2ggKGVycikgewogICAgICAgIHNldEVycm9yTXNnKGDsmKTrpZg6ICR7ZXJyLm1lc3NhZ2V9YCk7CiAgICAgIH0KICAgIH07CiAgICByZWFkZXIucmVhZEFzVGV4dChmaWxlLCAnZXVjLWtyJyk7CiAgfTsKCiAgdXNlRWZmZWN0KCgpID0+IHsKICAgIGNvbnN0IG9uUGFyZW50TWVzc2FnZSA9IChldmVudCkgPT4gewogICAgICBjb25zdCBwYXlsb2FkID0gZXZlbnQ/LmRhdGE7CiAgICAgIGlmICghcGF5bG9hZCkgcmV0dXJuOwoKICAgICAgaWYgKHBheWxvYWQuc291cmNlID09PSAndG90YWwtdXBsb2FkJykgewogICAgICAgIGlmIChwYXlsb2FkLnR5cGUgIT09ICdleHBlbnNlJyAmJiBwYXlsb2FkLnR5cGUgIT09ICd3b3JrJykgcmV0dXJuOwogICAgICAgIHRyeSB7CiAgICAgICAgICBjb25zdCBkYXRhID0gcGFyc2VDU1YocGF5bG9hZC50ZXh0IHx8ICcnKTsKICAgICAgICAgIGlmIChwYXlsb2FkLnR5cGUgPT09ICdleHBlbnNlJykgewogICAgICAgICAgICBzZXRFeHBlbnNlUmF3KGRhdGEpOwogICAgICAgICAgICBzZXREYXRhTG9hZGVkKHByZXYgPT4gKHsgLi4ucHJldiwgZXhwZW5zZTogdHJ1ZSB9KSk7CiAgICAgICAgICAgIHJlc2V0RmlsdGVycygpOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgc2V0V29ya1JhdyhkYXRhKTsKICAgICAgICAgICAgc2V0RGF0YUxvYWRlZChwcmV2ID0+ICh7IC4uLnByZXYsIHdvcms6IHRydWUgfSkpOwogICAgICAgICAgICByZXNldEZpbHRlcnMoKTsKICAgICAgICAgIH0KICAgICAgICB9IGNhdGNoIChlcnIpIHsKICAgICAgICAgIHNldEVycm9yTXNnKGDsmKTrpZg6ICR7ZXJyLm1lc3NhZ2V9YCk7CiAgICAgICAgfQogICAgICAgIHJldHVybjsKICAgICAgfQoKICAgICAgaWYgKHBheWxvYWQuc291cmNlID09PSAndG90YWwtY29udHJvbCcgJiYgcGF5bG9hZC50eXBlID09PSAnZGF0ZS1yYW5nZScpIHsKICAgICAgICBpZiAocGF5bG9hZC5zdGFydERhdGUpIHNldFN0YXJ0RGF0ZShwYXlsb2FkLnN0YXJ0RGF0ZSk7CiAgICAgICAgaWYgKHBheWxvYWQuZW5kRGF0ZSkgc2V0RW5kRGF0ZShwYXlsb2FkLmVuZERhdGUpOwogICAgICAgIHJldHVybjsKICAgICAgfQoKICAgICAgaWYgKHBheWxvYWQuc291cmNlID09PSAndG90YWwtY29udHJvbCcgJiYgcGF5bG9hZC50eXBlID09PSAncHJvamVjdC1vcmRlci1jc3YnKSB7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIGNvbnN0IHBhcnNlZE1hcCA9IHBhcnNlUHJvamVjdE9yZGVyTWFwRnJvbUNzdihwYXlsb2FkLnRleHQgfHwgJycpOwogICAgICAgICAgaWYgKHBhcnNlZE1hcCkgc2V0Q3VzdG9tUHJvamVjdE9yZGVyTWFwKHBhcnNlZE1hcCk7CiAgICAgICAgfSBjYXRjaCAoZXJyKSB7CiAgICAgICAgICBjb25zb2xlLmVycm9yKCftlITroZzsoJ3tirgg7ZGc7Lac7Iic7IScIENTViDsspjrpqwg7Iuk7YyoOicsIGVycik7CiAgICAgICAgfQogICAgICB9CiAgICB9OwoKICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgb25QYXJlbnRNZXNzYWdlKTsKICAgIHJldHVybiAoKSA9PiB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIG9uUGFyZW50TWVzc2FnZSk7CiAgfSwgW10pOwoKICBjb25zdCBmb3JtYXRXb3JrRGF0ZSA9IChkYXRlU3RyKSA9PiB7CiAgICBpZiAoIWRhdGVTdHIpIHJldHVybiAnJzsKICAgIGNvbnN0IGNsZWFuID0gZGF0ZVN0ci5yZXBsYWNlKC9ccy9nLCAnJykucmVwbGFjZSgvXC4vZywgJy0nKTsKICAgIGNvbnN0IHBhcnRzID0gY2xlYW4uc3BsaXQoJy0nKTsKICAgIGlmIChwYXJ0cy5sZW5ndGggPCAzKSByZXR1cm4gY2xlYW47CiAgICByZXR1cm4gYCR7cGFydHNbMF19LSR7cGFydHNbMV0ucGFkU3RhcnQoMiwgJzAnKX0tJHtwYXJ0c1syXS5wYWRTdGFydCgyLCAnMCcpfWA7CiAgfTsKCiAgY29uc3QgcHJvY2Vzc2VkRGF0YSA9IHVzZU1lbW8oKCkgPT4gewogICAgaWYgKCFkYXRhTG9hZGVkLmV4cGVuc2UgfHwgIWRhdGFMb2FkZWQud29yaykgcmV0dXJuIG51bGw7CgogICAgY29uc3Qgcm9sZUhvdXJseVJhdGUgPSB7CiAgICAgICfsiJjshJ0nOiA0NjYwMCwKICAgICAgJ+yxheyehCc6IDQwNTAwLAogICAgICAn7ISg7J6EJzogMzUzMDAsCiAgICAgICfsl7Dqtazsm5AnOiAyODkwMAogICAgfTsKICAgIGNvbnN0IGdldFJvbGVIb3VybHlSYXRlID0gKHBvc2l0aW9uKSA9PiB7CiAgICAgIGNvbnN0IHBvcyA9IG5vcm0ocG9zaXRpb24pOwogICAgICBpZiAoIXBvcykgcmV0dXJuIHJvbGVIb3VybHlSYXRlWyfsl7Dqtazsm5AnXTsKICAgICAgaWYgKHBvcy5pbmNsdWRlcygn7IiY7ISdJykpIHJldHVybiByb2xlSG91cmx5UmF0ZVsn7IiY7ISdJ107CiAgICAgIGlmIChwb3MuaW5jbHVkZXMoJ+yxheyehCcpKSByZXR1cm4gcm9sZUhvdXJseVJhdGVbJ+yxheyehCddOwogICAgICBpZiAocG9zLmluY2x1ZGVzKCfshKDsnoQnKSkgcmV0dXJuIHJvbGVIb3VybHlSYXRlWyfshKDsnoQnXTsKICAgICAgcmV0dXJuIHJvbGVIb3VybHlSYXRlWyfsl7Dqtazsm5AnXTsKICAgIH07CiAgICBjb25zdCBhbGxvY2F0ZVJvdW5kZWRMYWJvciA9ICh0b3RhbExhYm9yLCBzZWdtZW50cywgaXNXZWVrZW5kKSA9PiB7CiAgICAgIGNvbnN0IHRhcmdldExhYm9yID0gTWF0aC5yb3VuZChOdW1iZXIodG90YWxMYWJvcikgfHwgMCk7CiAgICAgIGlmICh0YXJnZXRMYWJvciA8PSAwIHx8ICFzZWdtZW50cy5sZW5ndGgpIHJldHVybiBzZWdtZW50cy5tYXAoKCkgPT4gMCk7CiAgICAgIGNvbnN0IHdlaWdodGVkID0gc2VnbWVudHMubWFwKChzZWcsIGlkeCkgPT4gewogICAgICAgIGNvbnN0IG11bCA9IChpc1dlZWtlbmQgfHwgc2VnLm92ZXJ0aW1lKSA/IDEuNSA6IDE7CiAgICAgICAgcmV0dXJuIHsgaWR4LCB3ZWlnaHQ6IE1hdGgubWF4KDAsIE51bWJlcihzZWcuaG91cnMpIHx8IDApICogbXVsIH07CiAgICAgIH0pOwogICAgICBjb25zdCB0b3RhbFdlaWdodCA9IHdlaWdodGVkLnJlZHVjZSgoc3VtLCBpdGVtKSA9PiBzdW0gKyBpdGVtLndlaWdodCwgMCk7CiAgICAgIGlmICh0b3RhbFdlaWdodCA8PSAwKSByZXR1cm4gc2VnbWVudHMubWFwKCgpID0+IDApOwoKICAgICAgY29uc3QgYWxsb2NhdGlvbnMgPSB3ZWlnaHRlZC5tYXAoKGl0ZW0pID0+IHsKICAgICAgICBjb25zdCByYXcgPSAodGFyZ2V0TGFib3IgKiBpdGVtLndlaWdodCkgLyB0b3RhbFdlaWdodDsKICAgICAgICBjb25zdCBiYXNlID0gTWF0aC5mbG9vcihyYXcpOwogICAgICAgIHJldHVybiB7IGlkeDogaXRlbS5pZHgsIGJhc2UsIGZyYWM6IHJhdyAtIGJhc2UgfTsKICAgICAgfSk7CiAgICAgIGxldCByZW1haW4gPSB0YXJnZXRMYWJvciAtIGFsbG9jYXRpb25zLnJlZHVjZSgoc3VtLCBwYXJ0KSA9PiBzdW0gKyBwYXJ0LmJhc2UsIDApOwogICAgICBpZiAocmVtYWluID4gMCkgewogICAgICAgIGFsbG9jYXRpb25zLnNvcnQoKGEsIGIpID0+IChiLmZyYWMgLSBhLmZyYWMpIHx8IChhLmlkeCAtIGIuaWR4KSk7CiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhbGxvY2F0aW9ucy5sZW5ndGggJiYgcmVtYWluID4gMDsgaSArPSAxLCByZW1haW4gLT0gMSkgYWxsb2NhdGlvbnNbaV0uYmFzZSArPSAxOwogICAgICB9IGVsc2UgaWYgKHJlbWFpbiA8IDApIHsKICAgICAgICBhbGxvY2F0aW9ucy5zb3J0KChhLCBiKSA9PiAoYS5mcmFjIC0gYi5mcmFjKSB8fCAoYS5pZHggLSBiLmlkeCkpOwogICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYWxsb2NhdGlvbnMubGVuZ3RoICYmIHJlbWFpbiA8IDA7IGkgKz0gMSwgcmVtYWluICs9IDEpIGFsbG9jYXRpb25zW2ldLmJhc2UgLT0gMTsKICAgICAgfQogICAgICBhbGxvY2F0aW9ucy5zb3J0KChhLCBiKSA9PiBhLmlkeCAtIGIuaWR4KTsKICAgICAgcmV0dXJuIGFsbG9jYXRpb25zLm1hcCgoaXRlbSkgPT4gaXRlbS5iYXNlKTsKICAgIH07CgogICAgY29uc3QgZ2V0RXhwZW5zZVByb2plY3ROYW1lID0gKHJvdykgPT4gewogICAgICAvLyBENCBpcyBmaXhlZCB0byBKIGNvbHVtbiBvZiBleHBlbnNlIENTViAo7IKs7JeF66qFKOyduO2KuOudvOuEt+q4sOykgCkpLgogICAgICBjb25zdCBqVmFsdWUgPSBub3JtKHJvdz8uX192YWx1ZXM/Lls5XSk7CiAgICAgIGlmIChqVmFsdWUpIHJldHVybiBqVmFsdWU7CiAgICAgIHJldHVybiBub3JtKGdldFZhbChyb3csIFsn7IKs7JeF66qFKOyduO2KuOudvOuEt+q4sOykgCknLCAn7IKs7JeF66m0KOyduO2KuOudvOuEt+q4sOykgCknLCAn7IKs7JeF66qFKOyduO2KuOudvOuEtyDquLDspIApJywgJ+yCrOyXheuptCjsnbjtirjrnbzrhLcg6riw7KSAKScsICdENCddLCA5KSk7CiAgICB9OwogICAgY29uc3QgZ2V0V29ya1Byb2plY3ROYW1lID0gKHJvdykgPT4gbm9ybShyb3c/LnByb2plY3ROYW1lIHx8IGdldFZhbChyb3csIFsn7ZSE66Gc7KCd7Yq466qFIOunpOy5rScsICftlITroZzsoJ3tirjrqoUnLCAn7IKs7JeF66qFKO2RnOy2nFBKVCknLCAnRDQnXSkpOwogICAgY29uc3QgZ2V0RXhwZW5zZVByb2plY3RLZXkgPSAocm93KSA9PiBub3JtYWxpemVQcm9qZWN0S2V5KGdldEV4cGVuc2VQcm9qZWN0TmFtZShyb3cpKTsKICAgIGNvbnN0IGdldFdvcmtQcm9qZWN0S2V5ID0gKHJvdykgPT4gbm9ybWFsaXplUHJvamVjdEtleShnZXRXb3JrUHJvamVjdE5hbWUocm93KSk7CiAgICBjb25zdCBoYXNOYW1lZEhlYWRlciA9IChyb3csIGhlYWRlcikgPT4gewogICAgICBpZiAoIXJvdyB8fCAhaGVhZGVyKSByZXR1cm4gZmFsc2U7CiAgICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocm93LCBoZWFkZXIpKSByZXR1cm4gdHJ1ZTsKICAgICAgY29uc3QgbmsgPSBgX19uXyR7bm9ybWFsaXplS2V5KGhlYWRlcil9YDsKICAgICAgcmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChyb3csIG5rKTsKICAgIH07CiAgICBjb25zdCB0b1dvcmtFbnRyeUxpc3QgPSAocm93KSA9PiB7CiAgICAgIGNvbnN0IHdvcmtEYXRlID0gZm9ybWF0V29ya0RhdGUoZ2V0VmFsKHJvdywgWyfqt7zrrLTsnbzsnpAnLCAn64Kg7KecJywgJ+ydvOyekCddKSk7CiAgICAgIGNvbnN0IHdvcmtlck5hbWUgPSBub3JtKGdldFZhbChyb3csIFsn7J2066aEJ10pKTsKICAgICAgY29uc3QgcG9zaXRpb24gPSBub3JtKGdldFZhbChyb3csIFsn7KeB7LGFJywgJ+yngeq4iSddKSk7CiAgICAgIGNvbnN0IHVzZXJTdGF0ZSA9IG5vcm0oZ2V0VmFsKHJvdywgWyd1c2VyX3N0YXRlJywgJ1VzZXIgU3RhdGUnLCAndXNlciBzdGF0ZScsICd1c2Vyc3RhdGUnLCAnVXNlcl9TdGF0ZSddKSk7CiAgICAgIGNvbnN0IGlzV2Vla2VuZCA9IHVzZXJTdGF0ZS5pbmNsdWRlcygn7KO866eQJyk7CiAgICAgIGNvbnN0IGlzTWhTY2hlbWEgPSBoYXNOYW1lZEhlYWRlcihyb3csICfrqZTsnbjsl4XrrLQg7ZSE66Gc7KCd7Yq466qFJykgfHwgaGFzTmFtZWRIZWFkZXIocm93LCAn7Jew7J6l6re866y0IO2UhOuhnOygne2KuOuqhScpIHx8IGhhc05hbWVkSGVhZGVyKHJvdywgJ+yXsOyepeq3vOustCDsi5zqsIQo6rCA6rO1KScpOwogICAgICBjb25zdCBpbXBvcnRlZExhYm9yID0gcG51bShnZXRWYWwocm93LCBbJ+yCsOygleq4iOyVoScsICfsnbjqsbTruYQnXSkpOwogICAgICBjb25zdCBvdmVydGltZUhvdXJzRnJvbVJvdyA9IGlzTWhTY2hlbWEKICAgICAgICA/IHBudW0oZ2V0VmFsKHJvdywgWyfsl7DsnqXqt7zrrLQg7Iuc6rCEKOqwgOqztSknLCAn7Jew7J6l6re866y07Iuc6rCEKOqwgOqztSknLCAn7Jew7J6l6re866y0IOyLnOqwhCcsICfsl7DsnqXqt7zrrLTsi5zqsIQnLCAn7LaU6rCA6re866y0J10sIDQ0KSkKICAgICAgICA6IHBudW0oZ2V0VmFsKHJvdywgWyfsl7DsnqXqt7zrrLQg7Iuc6rCEKOqwgOqztSknLCAn7Jew7J6l6re866y07Iuc6rCEKOqwgOqztSknLCAn7Jew7J6l6re866y0IOyLnOqwhCcsICfsl7DsnqXqt7zrrLTsi5zqsIQnLCAn7LaU6rCA6re866y0J10pKTsKICAgICAgY29uc3QgZDEgPSBub3JtYWxpemVEMUNhdGVnb3J5KGdldFZhbChyb3csIFsnRDEnLCAn66ek7LacL+u5hOunpOy2nCddKSk7CiAgICAgIGNvbnN0IGQyID0gbm9ybShnZXRWYWwocm93LCBbJ0QyJywgJ+yCrOyXheu2hOyVvCcsICfrtoTslbwnXSkpOwogICAgICBjb25zdCBkMyA9IG5vcm0oZ2V0VmFsKHJvdywgWydEMycsICfshLjrtoDrtoTslbwnXSkpOwogICAgICBjb25zdCByYXRlID0gZ2V0Um9sZUhvdXJseVJhdGUocG9zaXRpb24pOwoKICAgICAgY29uc3QgbWhQcm9qZWN0RmllbGRzID0gWwogICAgICAgIHsgbmFtZTogJ+uplOyduOyXheustCDtlITroZzsoJ3tirjrqoUnLCBob3VyOiAn66mU7J247JeF66y0IOq3vOustOyLnOqwhCcsIG92ZXJ0aW1lOiBmYWxzZSwgbmFtZUlkeDogMTAsIGhvdXJJZHg6IDEyIH0sCiAgICAgICAgeyBuYW1lOiAn7LaU6rCA7JeF66y0MSDtlITroZzsoJ3tirjrqoUnLCBob3VyOiAn7LaU6rCA7JeF66y0MSDqt7zrrLTsi5zqsIQnLCBvdmVydGltZTogZmFsc2UsIG5hbWVJZHg6IDE2LCBob3VySWR4OiAxOCB9LAogICAgICAgIHsgbmFtZTogJ+y2lOqwgOyXheustDIg7ZSE66Gc7KCd7Yq466qFJywgaG91cjogJ+y2lOqwgOyXheustDIg6re866y07Iuc6rCEJywgb3ZlcnRpbWU6IGZhbHNlLCBuYW1lSWR4OiAyMSwgaG91cklkeDogMjMgfSwKICAgICAgICB7IG5hbWU6ICfstpTqsIDsl4XrrLQzIO2UhOuhnOygne2KuOuqhScsIGhvdXI6ICfstpTqsIDsl4XrrLQzIOq3vOustOyLnOqwhCcsIG92ZXJ0aW1lOiBmYWxzZSwgbmFtZUlkeDogMjYsIGhvdXJJZHg6IDI4IH0sCiAgICAgICAgeyBuYW1lOiAn7LaU6rCA7JeF66y0NCDtlITroZzsoJ3tirjrqoUnLCBob3VyOiAn7LaU6rCA7JeF66y0NCDqt7zrrLTsi5zqsIQnLCBvdmVydGltZTogZmFsc2UsIG5hbWVJZHg6IDMxLCBob3VySWR4OiAzMyB9LAogICAgICAgIHsgbmFtZTogJ+y2lOqwgOyXheustDUg7ZSE66Gc7KCd7Yq466qFJywgaG91cjogJ+y2lOqwgOyXheustDUg6re866y07Iuc6rCEJywgb3ZlcnRpbWU6IGZhbHNlLCBuYW1lSWR4OiAzNiwgaG91cklkeDogMzggfSwKICAgICAgICB7IG5hbWU6ICfsl7DsnqXqt7zrrLQg7ZSE66Gc7KCd7Yq466qFJywgaG91cjogJ+yXsOyepeq3vOustCDsi5zqsIQo6rCA6rO1KScsIG92ZXJ0aW1lOiB0cnVlLCBuYW1lSWR4OiA0MSwgaG91cklkeDogNDQgfQogICAgICBdOwoKICAgICAgY29uc3QgaGFzTWhTaGFwZSA9IGlzTWhTY2hlbWEgJiYgbWhQcm9qZWN0RmllbGRzLnNvbWUoKGYpID0+CiAgICAgICAgbm9ybShnZXRWYWwocm93LCBbZi5uYW1lXSwgZi5uYW1lSWR4KSkgfHwgcG51bShnZXRWYWwocm93LCBbZi5ob3VyXSwgZi5ob3VySWR4KSkgPiAwCiAgICAgICk7CiAgICAgIGNvbnN0IHNlZ21lbnRzID0gW107CgogICAgICBpZiAoaGFzTWhTaGFwZSkgewogICAgICAgIG1oUHJvamVjdEZpZWxkcy5mb3JFYWNoKChmKSA9PiB7CiAgICAgICAgICBjb25zdCBwcm9qZWN0TmFtZSA9IG5vcm0oZ2V0VmFsKHJvdywgW2YubmFtZV0sIGYubmFtZUlkeCkpOwogICAgICAgICAgY29uc3QgaG91cnMgPSBwbnVtKGdldFZhbChyb3csIFtmLmhvdXJdLCBmLmhvdXJJZHgpKTsKICAgICAgICAgIGlmICghcHJvamVjdE5hbWUgfHwgaG91cnMgPD0gMCkgcmV0dXJuOwogICAgICAgICAgc2VnbWVudHMucHVzaCh7IHByb2plY3ROYW1lLCBob3Vycywgb3ZlcnRpbWU6IGYub3ZlcnRpbWUgfSk7CiAgICAgICAgfSk7CgogICAgICAgIGlmIChpc01oU2NoZW1hICYmIG92ZXJ0aW1lSG91cnNGcm9tUm93ID4gMCAmJiAhc2VnbWVudHMuc29tZSgocykgPT4gcy5vdmVydGltZSkpIHsKICAgICAgICAgIGNvbnN0IGZhbGxiYWNrUHJvamVjdCA9IG5vcm0oZ2V0VmFsKHJvdywgWyfrqZTsnbjsl4XrrLQg7ZSE66Gc7KCd7Yq466qFJywgJ+2UhOuhnOygne2KuOuqhScsICfsgqzsl4XrqoUo7ZGc7LacUEpUKScsICdENCddLCAxMCkpOwogICAgICAgICAgaWYgKGZhbGxiYWNrUHJvamVjdCkgewogICAgICAgICAgICBzZWdtZW50cy5wdXNoKHsgcHJvamVjdE5hbWU6IGZhbGxiYWNrUHJvamVjdCwgaG91cnM6IG92ZXJ0aW1lSG91cnNGcm9tUm93LCBvdmVydGltZTogdHJ1ZSB9KTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0gZWxzZSB7CiAgICAgICAgY29uc3QgcHJvamVjdE5hbWUgPSBnZXRXb3JrUHJvamVjdE5hbWUocm93KTsKICAgICAgICBjb25zdCBob3VycyA9IHBudW0oZ2V0VmFsKHJvdywgWyfsi5zqsIQnLCAn6re866y07Iuc6rCEJywgJ+2IrOyeheyLnOqwhCcsICfstJ3qt7zrrLTsi5zqsIQnLCAn7J2867CY6re866y0J10pKTsKICAgICAgICBpZiAocHJvamVjdE5hbWUgJiYgaG91cnMgPiAwKSB7CiAgICAgICAgICBjb25zdCBvdEhvdXJzID0gTWF0aC5tYXgoMCwgTWF0aC5taW4oaG91cnMsIG92ZXJ0aW1lSG91cnNGcm9tUm93KSk7CiAgICAgICAgICBjb25zdCBub3JtYWxIb3VycyA9IE1hdGgubWF4KDAsIGhvdXJzIC0gb3RIb3Vycyk7CiAgICAgICAgICBpZiAobm9ybWFsSG91cnMgPiAwKSBzZWdtZW50cy5wdXNoKHsgcHJvamVjdE5hbWUsIGhvdXJzOiBub3JtYWxIb3Vycywgb3ZlcnRpbWU6IGZhbHNlIH0pOwogICAgICAgICAgaWYgKG90SG91cnMgPiAwKSBzZWdtZW50cy5wdXNoKHsgcHJvamVjdE5hbWUsIGhvdXJzOiBvdEhvdXJzLCBvdmVydGltZTogdHJ1ZSB9KTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIGNvbnN0IGltcG9ydGVkTGFib3JBbGxvY2F0aW9ucyA9IGltcG9ydGVkTGFib3IgPiAwCiAgICAgICAgPyBhbGxvY2F0ZVJvdW5kZWRMYWJvcihpbXBvcnRlZExhYm9yLCBzZWdtZW50cywgaXNXZWVrZW5kKQogICAgICAgIDogbnVsbDsKCiAgICAgIHJldHVybiBzZWdtZW50cy5tYXAoKHNlZywgaWR4KSA9PiB7CiAgICAgICAgY29uc3QgbXVsID0gKGlzV2Vla2VuZCB8fCBzZWcub3ZlcnRpbWUpID8gMS41IDogMTsKICAgICAgICByZXR1cm4gewogICAgICAgICAgcHJvamVjdE5hbWU6IHNlZy5wcm9qZWN0TmFtZSwKICAgICAgICAgIHdvcmtEYXRlLAogICAgICAgICAgd29ya2VyTmFtZSwKICAgICAgICAgIHBvc2l0aW9uLAogICAgICAgICAgdXNlclN0YXRlLAogICAgICAgICAgaG91cnM6IHNlZy5ob3VycywKICAgICAgICAgIGxhYm9yOiBpbXBvcnRlZExhYm9yQWxsb2NhdGlvbnMKICAgICAgICAgICAgPyAoaW1wb3J0ZWRMYWJvckFsbG9jYXRpb25zW2lkeF0gfHwgMCkKICAgICAgICAgICAgOiBNYXRoLnJvdW5kKHNlZy5ob3VycyAqIHJhdGUgKiBtdWwpLAogICAgICAgICAgZDEsCiAgICAgICAgICBkMiwKICAgICAgICAgIGQzCiAgICAgICAgfTsKICAgICAgfSk7CiAgICB9OwogICAgY29uc3Qgd29ya0VudHJpZXMgPSB3b3JrUmF3LmZsYXRNYXAodG9Xb3JrRW50cnlMaXN0KTsKICAgIGNvbnN0IHVua25vd25EZXB0aCA9IHsgZDE6ICfrr7jrtoTrpZgnLCBkMjogJ+uvuOu2hOulmCcsIGQzOiAn66+467aE66WYJyB9OwogICAgY29uc3QgaXNVbmtub3duID0gKHYpID0+IG5vcm1hbGl6ZUtleSh2KSA9PT0gbm9ybWFsaXplS2V5KCfrr7jrtoTrpZgnKTsKICAgIGNvbnN0IGRlcHRoU2NvcmUgPSAoZCkgPT4gW2Q/LmQxLCBkPy5kMiwgZD8uZDNdLnJlZHVjZSgoYWNjLCB2KSA9PiBhY2MgKyAoaXNVbmtub3duKHYpID8gMCA6IDEpLCAwKTsKICAgIGNvbnN0IG1lcmdlRGVwdGggPSAoY3VycmVudCwgaW5jb21pbmcpID0+IHsKICAgICAgaWYgKCFjdXJyZW50KSByZXR1cm4gaW5jb21pbmc7CiAgICAgIGNvbnN0IGN1clNjb3JlID0gZGVwdGhTY29yZShjdXJyZW50KTsKICAgICAgY29uc3QgaW5TY29yZSA9IGRlcHRoU2NvcmUoaW5jb21pbmcpOwogICAgICBpZiAoaW5TY29yZSA+IGN1clNjb3JlKSByZXR1cm4gaW5jb21pbmc7CiAgICAgIGlmIChpblNjb3JlIDwgY3VyU2NvcmUpIHJldHVybiBjdXJyZW50OwogICAgICByZXR1cm4gewogICAgICAgIGQxOiBpc1Vua25vd24oY3VycmVudC5kMSkgJiYgIWlzVW5rbm93bihpbmNvbWluZy5kMSkgPyBpbmNvbWluZy5kMSA6IGN1cnJlbnQuZDEsCiAgICAgICAgZDI6IGlzVW5rbm93bihjdXJyZW50LmQyKSAmJiAhaXNVbmtub3duKGluY29taW5nLmQyKSA/IGluY29taW5nLmQyIDogY3VycmVudC5kMiwKICAgICAgICBkMzogaXNVbmtub3duKGN1cnJlbnQuZDMpICYmICFpc1Vua25vd24oaW5jb21pbmcuZDMpID8gaW5jb21pbmcuZDMgOiBjdXJyZW50LmQzCiAgICAgIH07CiAgICB9OwoKICAgIGNvbnN0IHByb2plY3RUb0RlcHRoID0ge307CiAgICBjb25zdCBwcm9qZWN0RGlzcGxheUJ5S2V5ID0ge307CiAgICBleHBlbnNlUmF3LmZvckVhY2goZSA9PiB7CiAgICAgIGNvbnN0IHBOYW1lID0gZ2V0RXhwZW5zZVByb2plY3ROYW1lKGUpOwogICAgICBjb25zdCBwS2V5ID0gbm9ybWFsaXplUHJvamVjdEtleShwTmFtZSk7CiAgICAgIGlmICghcEtleSkgcmV0dXJuOwogICAgICBjb25zdCBkMSA9IG5vcm1hbGl6ZUQxQ2F0ZWdvcnkoZ2V0VmFsKGUsIFsnRDEnLCAn66ek7LacL+u5hOunpOy2nCcsICfrp6TstpzruYTrp6TstpwnXSwgMTApKTsKICAgICAgaWYgKCFkMSkgcmV0dXJuOyAvLyBEMShLKSBlbXB0eSByb3dzIGFyZSBpZ25vcmVkLgogICAgICBpZiAoIXByb2plY3REaXNwbGF5QnlLZXlbcEtleV0pIHByb2plY3REaXNwbGF5QnlLZXlbcEtleV0gPSBwTmFtZTsKICAgICAgcHJvamVjdFRvRGVwdGhbcEtleV0gPSBtZXJnZURlcHRoKHByb2plY3RUb0RlcHRoW3BLZXldLCB7CiAgICAgICAgZDEsCiAgICAgICAgZDI6IG5vcm0oZ2V0VmFsKGUsIFsnRDInLCAn7IKs7JeF67aE7JW8JywgJ+u2hOyVvCddLCAxMSkpIHx8ICfrr7jrtoTrpZgnLAogICAgICAgIGQzOiBub3JtKGdldFZhbChlLCBbJ0QzJywgJ+yEuOu2gOu2hOyVvCddLCAxMikpIHx8ICfrr7jrtoTrpZgnCiAgICAgIH0pOwogICAgfSk7CiAgICB3b3JrRW50cmllcy5mb3JFYWNoKHcgPT4gewogICAgICBjb25zdCBwTmFtZSA9IGdldFdvcmtQcm9qZWN0TmFtZSh3KTsKICAgICAgY29uc3QgcEtleSA9IG5vcm1hbGl6ZVByb2plY3RLZXkocE5hbWUpOwogICAgICBpZiAoIXBLZXkpIHJldHVybjsKICAgICAgaWYgKCFwcm9qZWN0RGlzcGxheUJ5S2V5W3BLZXldKSBwcm9qZWN0RGlzcGxheUJ5S2V5W3BLZXldID0gcE5hbWU7CiAgICAgIGNvbnN0IGQxID0gbm9ybWFsaXplRDFDYXRlZ29yeShnZXRWYWwodywgWydEMScsICfrp6Tstpwv67mE66ek7LacJ10pKSB8fCBub3JtYWxpemVEMUNhdGVnb3J5KHcuZDEpOwogICAgICBwcm9qZWN0VG9EZXB0aFtwS2V5XSA9IG1lcmdlRGVwdGgocHJvamVjdFRvRGVwdGhbcEtleV0sIHsKICAgICAgICBkMTogZDEgfHwgJ+uvuOu2hOulmCcsCiAgICAgICAgZDI6IG5vcm0oZ2V0VmFsKHcsIFsnRDInLCAn7IKs7JeF67aE7JW8JywgJ+u2hOyVvCddKSkgfHwgbm9ybSh3LmQyKSB8fCAn66+467aE66WYJywKICAgICAgICBkMzogbm9ybShnZXRWYWwodywgWydEMycsICfshLjrtoDrtoTslbwnXSkpIHx8IG5vcm0ody5kMykgfHwgJ+uvuOu2hOulmCcKICAgICAgfSk7CiAgICB9KTsKCiAgICBjb25zdCBpc1dpdGhpblJhbmdlID0gKGRhdGVTdHIpID0+IHsKICAgICAgaWYgKCFkYXRlU3RyKSByZXR1cm4gZmFsc2U7CiAgICAgIGNvbnN0IGQgPSBuZXcgRGF0ZShTdHJpbmcoZGF0ZVN0cikucmVwbGFjZSgvXC4vZywgJy0nKSk7CiAgICAgIHJldHVybiBkID49IG5ldyBEYXRlKHN0YXJ0RGF0ZSkgJiYgZCA8PSBuZXcgRGF0ZShlbmREYXRlKTsKICAgIH07CgogICAgY29uc3QgZXhjbHVkZWRXb3JrZXJzID0gbmV3IFNldChbJ+ygle2DnOybkCcsICfslpHrs5HtmY0nLCAn7J6l6rOE7ISdJywgJ+yepeyiheywrCcsICfquYDsm5Dsi50nLCAn6rmA7ZiV7KSAJ10pOwogICAgY29uc3Qgc2VsZWN0ZWRQcm9qZWN0S2V5ID0gbm9ybWFsaXplUHJvamVjdEtleShzZWxlY3RlZFByb2plY3QgPT09ICfsoITssrQnID8gJycgOiBzZWxlY3RlZFByb2plY3QpOwoKICAgIGNvbnN0IGJhc2VGaWx0ZXJlZFdvcmsgPSB3b3JrRW50cmllcy5maWx0ZXIoaXRlbSA9PiB7CiAgICAgIGNvbnN0IHBOYW1lID0gZ2V0V29ya1Byb2plY3ROYW1lKGl0ZW0pOwogICAgICBjb25zdCBwS2V5ID0gZ2V0V29ya1Byb2plY3RLZXkoaXRlbSk7CiAgICAgIGNvbnN0IHdvcmtlck5hbWUgPSBub3JtKGl0ZW0ud29ya2VyTmFtZSB8fCBnZXRWYWwoaXRlbSwgWyfsnbTrpoQnXSkpOwogICAgICBpZiAod29ya2VyTmFtZSAmJiBleGNsdWRlZFdvcmtlcnMuaGFzKHdvcmtlck5hbWUpKSByZXR1cm4gZmFsc2U7CiAgICAgIGNvbnN0IGluZm8gPSBwcm9qZWN0VG9EZXB0aFtwS2V5XSB8fCB1bmtub3duRGVwdGg7CiAgICAgIGNvbnN0IGZEYXRlID0gZm9ybWF0V29ya0RhdGUoaXRlbS53b3JrRGF0ZSB8fCBnZXRWYWwoaXRlbSwgWyfrgqDsp5wnLCAn7J287J6QJywgJ+q3vOustOydvOyekCddKSk7CiAgICAgIHJldHVybiAoc2VsZWN0ZWRSZXYgPT09ICfsoITssrQnIHx8IGluZm8uZDEgPT09IHNlbGVjdGVkUmV2KSAmJgogICAgICAgICAgICAgKHNlbGVjdGVkRDEgPT09ICfsoITssrQnIHx8IGluZm8uZDIgPT09IHNlbGVjdGVkRDEpICYmCiAgICAgICAgICAgICAoc2VsZWN0ZWREMiA9PT0gJ+yghOyytCcgfHwgaW5mby5kMyA9PT0gc2VsZWN0ZWREMikgJiYKICAgICAgICAgICAgIChzZWxlY3RlZFByb2plY3QgPT09ICfsoITssrQnIHx8IHBLZXkgPT09IHNlbGVjdGVkUHJvamVjdEtleSkgJiYKICAgICAgICAgICAgIGlzV2l0aGluUmFuZ2UoZkRhdGUpOwogICAgfSk7CgogICAgY29uc3QgYmFzZUZpbHRlcmVkRXhwID0gZXhwZW5zZVJhdy5maWx0ZXIoaXRlbSA9PiB7CiAgICAgIGNvbnN0IHBLZXkgPSBnZXRFeHBlbnNlUHJvamVjdEtleShpdGVtKTsKICAgICAgY29uc3QgZDFGcm9tUm93ID0gbm9ybWFsaXplRDFDYXRlZ29yeShnZXRWYWwoaXRlbSwgWydEMScsICfrp6Tstpwv67mE66ek7LacJywgJ+unpOy2nOu5hOunpOy2nCddLCAxMCkpOwogICAgICBpZiAoIWQxRnJvbVJvdykgcmV0dXJuIGZhbHNlOyAvLyBEMShLKSBlbXB0eSByb3dzIGFyZSBpZ25vcmVkLgogICAgICBjb25zdCBpbmZvID0gcHJvamVjdFRvRGVwdGhbcEtleV0gfHwgdW5rbm93bkRlcHRoOwogICAgICBjb25zdCBpc3N1ZURhdGUgPSBnZXRWYWwoaXRlbSwgWyfrsJztlonsnbwnXSwgMik7CiAgICAgIHJldHVybiAoc2VsZWN0ZWRSZXYgPT09ICfsoITssrQnIHx8IGluZm8uZDEgPT09IHNlbGVjdGVkUmV2KSAmJgogICAgICAgICAgICAgKHNlbGVjdGVkRDEgPT09ICfsoITssrQnIHx8IGluZm8uZDIgPT09IHNlbGVjdGVkRDEpICYmCiAgICAgICAgICAgICAoc2VsZWN0ZWREMiA9PT0gJ+yghOyytCcgfHwgaW5mby5kMyA9PT0gc2VsZWN0ZWREMikgJiYKICAgICAgICAgICAgIChzZWxlY3RlZFByb2plY3QgPT09ICfsoITssrQnIHx8IHBLZXkgPT09IHNlbGVjdGVkUHJvamVjdEtleSkgJiYKICAgICAgICAgICAgIGlzV2l0aGluUmFuZ2UoaXNzdWVEYXRlKTsKICAgIH0pOwoKICAgIGNvbnN0IHBvc2l0aW9uR3JvdXBNb2RlID0gKHNlbGVjdGVkRDIgIT09ICfsoITssrQnIHx8IHNlbGVjdGVkUHJvamVjdCAhPT0gJ+yghOyytCcpCiAgICAgID8gJ0Q0JwogICAgICA6IChzZWxlY3RlZEQxICE9PSAn7KCE7LK0JyA/ICdEMycgOiAoc2VsZWN0ZWRSZXYgIT09ICfsoITssrQnID8gJ0QyJyA6ICdEMScpKTsKICAgIGNvbnN0IHBvc2l0aW9uQW5hbHlzaXMgPSB7fTsKICAgIGJhc2VGaWx0ZXJlZFdvcmsuZm9yRWFjaCh3ID0+IHsKICAgICAgY29uc3QgcE5hbWUgPSBnZXRXb3JrUHJvamVjdE5hbWUodyk7CiAgICAgIGNvbnN0IHBLZXkgPSBnZXRXb3JrUHJvamVjdEtleSh3KTsKICAgICAgY29uc3QgaW5mbyA9IHByb2plY3RUb0RlcHRoW3BLZXldIHx8IHVua25vd25EZXB0aDsKICAgICAgY29uc3QgZGlzcGxheU5hbWUgPSBwcm9qZWN0RGlzcGxheUJ5S2V5W3BLZXldIHx8IHBOYW1lIHx8ICfrr7jsp4DsoJUg7ZSE66Gc7KCd7Yq4JzsKICAgICAgY29uc3QgZ3JvdXBLZXkgPSBwb3NpdGlvbkdyb3VwTW9kZSA9PT0gJ0QxJyA/IGluZm8uZDEKICAgICAgICA6IChwb3NpdGlvbkdyb3VwTW9kZSA9PT0gJ0QyJyA/IGluZm8uZDIKICAgICAgICA6IChwb3NpdGlvbkdyb3VwTW9kZSA9PT0gJ0QzJyA/IGluZm8uZDMgOiBkaXNwbGF5TmFtZSkpOwogICAgICBjb25zdCBzYWZlR3JvdXBLZXkgPSAoZ3JvdXBLZXkgJiYgU3RyaW5nKGdyb3VwS2V5KS50cmltKCkpIHx8ICfrr7jsp4DsoJUg7ZSE66Gc7KCd7Yq4JzsKICAgICAgY29uc3QgcG9zID0gbm9ybShnZXRWYWwodywgWyfsp4HquIknXSkpIHx8IG5vcm0ody5wb3NpdGlvbikgfHwgJ+uvuOyngOyglSc7CiAgICAgIGNvbnN0IG5hbWUgPSBub3JtKGdldFZhbCh3LCBbJ+ydtOumhCddKSkgfHwgbm9ybSh3Lndvcmtlck5hbWUpIHx8ICfrrLTrqoUnOwogICAgICBjb25zdCB2YWwgPSBwbnVtKHcubGFib3IgfHwgZ2V0VmFsKHcsIFsn7IKw7KCV6riI7JWhJywgJ+yduOqxtOu5hCddKSk7CiAgICAgIGNvbnN0IGggPSBwbnVtKHcuaG91cnMgfHwgZ2V0VmFsKHcsIFsn7Iuc6rCEJywgJ+q3vOustOyLnOqwhCddKSk7CgogICAgICBpZiAoIXBvc2l0aW9uQW5hbHlzaXNbc2FmZUdyb3VwS2V5XSkgcG9zaXRpb25BbmFseXNpc1tzYWZlR3JvdXBLZXldID0ge307CiAgICAgIGlmICghcG9zaXRpb25BbmFseXNpc1tzYWZlR3JvdXBLZXldW3Bvc10pIHBvc2l0aW9uQW5hbHlzaXNbc2FmZUdyb3VwS2V5XVtwb3NdID0geyBsYWJvcjogMCwgaHJzOiAwLCBuYW1lczogbmV3IFNldCgpIH07CiAgICAgIHBvc2l0aW9uQW5hbHlzaXNbc2FmZUdyb3VwS2V5XVtwb3NdLmxhYm9yICs9IHZhbDsKICAgICAgcG9zaXRpb25BbmFseXNpc1tzYWZlR3JvdXBLZXldW3Bvc10uaHJzICs9IGg7CiAgICAgIHBvc2l0aW9uQW5hbHlzaXNbc2FmZUdyb3VwS2V5XVtwb3NdLm5hbWVzLmFkZChuYW1lKTsKICAgIH0pOwoKICAgIGNvbnN0IGFsbFByb2plY3RLZXlzID0gQXJyYXkuZnJvbShuZXcgU2V0KFsKICAgICAgLi4uYmFzZUZpbHRlcmVkRXhwLm1hcChlID0+IGdldEV4cGVuc2VQcm9qZWN0S2V5KGUpKSwKICAgICAgLi4uYmFzZUZpbHRlcmVkV29yay5tYXAodyA9PiBnZXRXb3JrUHJvamVjdEtleSh3KSkKICAgIF0pKS5maWx0ZXIoQm9vbGVhbik7CgogICAgbGV0IHN1bW1hcnlMaXN0ID0gYWxsUHJvamVjdEtleXMubWFwKHBLZXkgPT4gewogICAgICBjb25zdCBwRXhwID0gYmFzZUZpbHRlcmVkRXhwLmZpbHRlcihlID0+IGdldEV4cGVuc2VQcm9qZWN0S2V5KGUpID09PSBwS2V5KTsKICAgICAgY29uc3QgcFdvcmsgPSBiYXNlRmlsdGVyZWRXb3JrLmZpbHRlcih3ID0+IGdldFdvcmtQcm9qZWN0S2V5KHcpID09PSBwS2V5KTsKICAgICAgY29uc3QgcE5hbWUgPSBwcm9qZWN0RGlzcGxheUJ5S2V5W3BLZXldIHx8IGdldEV4cGVuc2VQcm9qZWN0TmFtZShwRXhwWzBdKSB8fCBnZXRXb3JrUHJvamVjdE5hbWUocFdvcmtbMF0pIHx8ICfrr7jsp4DsoJUg7ZSE66Gc7KCd7Yq4JzsKICAgICAgY29uc3QgbGFib3IgPSBwV29yay5yZWR1Y2UoKHMsIGMpID0+IHMgKyBwbnVtKGMubGFib3IgfHwgZ2V0VmFsKGMsIFsn7IKw7KCV6riI7JWhJywgJ+yduOqxtOu5hCddKSksIDApOwogICAgICBjb25zdCBocnMgPSBwV29yay5yZWR1Y2UoKHMsIGMpID0+IHMgKyBwbnVtKGMuaG91cnMgfHwgZ2V0VmFsKGMsIFsn7Iuc6rCEJywgJ+q3vOustOyLnOqwhCddKSksIDApOwogICAgICBjb25zdCBwb3NpdGlvbkJyZWFrZG93biA9IHt9OwogICAgICBwV29yay5mb3JFYWNoKHcgPT4gewogICAgICAgIGNvbnN0IHBvcyA9IG5vcm0oZ2V0VmFsKHcsIFsn7KeB6riJJ10pKSB8fCBub3JtKHcucG9zaXRpb24pIHx8ICfrr7jsp4DsoJUnOwogICAgICAgIGNvbnN0IGggPSBwbnVtKHcuaG91cnMgfHwgZ2V0VmFsKHcsIFsn7Iuc6rCEJywgJ+q3vOustOyLnOqwhCddKSk7CiAgICAgICAgcG9zaXRpb25CcmVha2Rvd25bcG9zXSA9IChwb3NpdGlvbkJyZWFrZG93bltwb3NdIHx8IDApICsgaDsKICAgICAgfSk7CiAgICAgIGNvbnN0IGluY29tZSA9IHBFeHAucmVkdWNlKChzLCBjKSA9PiBzICsgcG51bShnZXRWYWwoYywgWyfsiJjsnoUnXSwgMjApKSwgMCk7CiAgICAgIGNvbnN0IGNvc3RCcmVha2Rvd24gPSB7ICfsnbjqsbTruYQnOiBsYWJvciwgJ+y2nOyepeu5hCc6IDAsICfrs7Xrpqztm4Tsg53ruYQnOiAwLCAn6rWs66ek67mEJzogMCwgJ+yZuOyjvOu5hCc6IDAgfTsKICAgICAgcEV4cC5mb3JFYWNoKGUgPT4gewogICAgICAgIGNvbnN0IGRpdiA9IG5vcm0oZ2V0VmFsKGUsIFsn6rWs67aEJ10sIDIyKSk7CiAgICAgICAgY29uc3Qgc3BlbmQgPSBwbnVtKGdldFZhbChlLCBbJ+yngOy2nCddLCAxOSkpOwogICAgICAgIGlmIChkaXYgPT09ICfsoJzsmbgnIHx8ICFzcGVuZCkgcmV0dXJuOwogICAgICAgIGlmIChkaXYgPT09ICfstpzsnqXruYQnKSBjb3N0QnJlYWtkb3duWyfstpzsnqXruYQnXSArPSBzcGVuZDsKICAgICAgICBlbHNlIGlmIChkaXYgPT09ICfrs7Xrpqztm4Tsg53ruYQnKSBjb3N0QnJlYWtkb3duWyfrs7Xrpqztm4Tsg53ruYQnXSArPSBzcGVuZDsKICAgICAgICBlbHNlIGlmIChkaXYgPT09ICfsmbjso7zruYQnKSBjb3N0QnJlYWtkb3duWyfsmbjso7zruYQnXSArPSBzcGVuZDsKICAgICAgICBlbHNlIGNvc3RCcmVha2Rvd25bJ+q1rOunpOu5hCddICs9IHNwZW5kOwogICAgICB9KTsKICAgICAgY29uc3QgZGVwdGggPSBwcm9qZWN0VG9EZXB0aFtwS2V5XSB8fCB1bmtub3duRGVwdGg7CiAgICAgIGNvbnN0IHRvdGFsID0gT2JqZWN0LnZhbHVlcyhjb3N0QnJlYWtkb3duKS5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKTsKICAgICAgY29uc3Qgd29ya2VyTmFtZXMgPSBBcnJheS5mcm9tKG5ldyBTZXQocFdvcmsubWFwKHcgPT4gbm9ybShnZXRWYWwodywgWyfsnbTrpoQnXSkpIHx8IG5vcm0ody53b3JrZXJOYW1lKSkuZmlsdGVyKEJvb2xlYW4pKSk7CiAgICAgIHJldHVybiB7IAogICAgICAgIG5hbWU6IHBOYW1lLCBkMTogZGVwdGguZDEsIGQyOiBkZXB0aC5kMiwgZDM6IGRlcHRoLmQzLCBpbmNvbWUsIGxhYm9yLCB0b3RhbCwgY29zdEJyZWFrZG93biwgcG9zaXRpb25CcmVha2Rvd24sCiAgICAgICAgd29ya2Vyczogd29ya2VyTmFtZXMubGVuZ3RoLAogICAgICAgIHdvcmtlck5hbWVzLAogICAgICAgIGhycwogICAgICB9OwogICAgfSkuZmlsdGVyKHAgPT4gcC50b3RhbCA+IDAgfHwgcC5pbmNvbWUgPiAwIHx8IHAuaHJzID4gMCkKICAgIC5zb3J0KChhLCBiKSA9PgogICAgICAoZDFPcmRlclthLmQxXSB8fCA5OSkgLSAoZDFPcmRlcltiLmQxXSB8fCA5OSkgfHwKICAgICAgZ2V0RDJPcmRlcihhLmQyKSAtIGdldEQyT3JkZXIoYi5kMikgfHwKICAgICAgYS5kMi5sb2NhbGVDb21wYXJlKGIuZDIpIHx8CiAgICAgIGdldEQzT3JkZXIoYS5kMywgYS5kMikgLSBnZXREM09yZGVyKGIuZDMsIGIuZDIpIHx8CiAgICAgIGEuZDMubG9jYWxlQ29tcGFyZShiLmQzKSB8fAogICAgICBnZXRQcm9qZWN0T3JkZXIoYS5uYW1lKSAtIGdldFByb2plY3RPcmRlcihiLm5hbWUpIHx8CiAgICAgIGEubmFtZS5sb2NhbGVDb21wYXJlKGIubmFtZSkKICAgICk7CgogICAgY29uc3QgaXNBbGxGaWx0ZXJzT2ZmID0gc2VsZWN0ZWRSZXYgPT09ICfsoITssrQnICYmIHNlbGVjdGVkRDEgPT09ICfsoITssrQnICYmIHNlbGVjdGVkRDIgPT09ICfsoITssrQnICYmIHNlbGVjdGVkUHJvamVjdCA9PT0gJ+yghOyytCc7CgogICAgY29uc3QgYWdncmVnYXRlR3JvdXBTdW1tYXJ5ID0gKGl0ZW1zLCBsYWJlbCwgbGV2ZWwpID0+IHsKICAgICAgY29uc3QgY29zdEJyZWFrZG93biA9IHsgJ+yduOqxtOu5hCc6IDAsICfstpzsnqXruYQnOiAwLCAn67O166as7ZuE7IOd67mEJzogMCwgJ+q1rOunpOu5hCc6IDAsICfsmbjso7zruYQnOiAwIH07CiAgICAgIGNvbnN0IHBvc2l0aW9uQnJlYWtkb3duID0ge307CiAgICAgIGNvbnN0IHdvcmtlcnMgPSBuZXcgU2V0KCk7CiAgICAgIGl0ZW1zLmZvckVhY2goKGl0ZW0pID0+IHsKICAgICAgICBjb3N0QnJlYWtkb3duWyfsnbjqsbTruYQnXSArPSBpdGVtLmNvc3RCcmVha2Rvd24/Llsn7J246rG067mEJ10gfHwgMDsKICAgICAgICBjb3N0QnJlYWtkb3duWyfstpzsnqXruYQnXSArPSBpdGVtLmNvc3RCcmVha2Rvd24/Llsn7Lac7J6l67mEJ10gfHwgMDsKICAgICAgICBjb3N0QnJlYWtkb3duWyfrs7Xrpqztm4Tsg53ruYQnXSArPSBpdGVtLmNvc3RCcmVha2Rvd24/Llsn67O166as7ZuE7IOd67mEJ10gfHwgMDsKICAgICAgICBjb3N0QnJlYWtkb3duWyfqtazrp6TruYQnXSArPSBpdGVtLmNvc3RCcmVha2Rvd24/Llsn6rWs66ek67mEJ10gfHwgMDsKICAgICAgICBjb3N0QnJlYWtkb3duWyfsmbjso7zruYQnXSArPSBpdGVtLmNvc3RCcmVha2Rvd24/Llsn7Jm47KO867mEJ10gfHwgMDsKICAgICAgICBPYmplY3QuZW50cmllcyhpdGVtLnBvc2l0aW9uQnJlYWtkb3duIHx8IHt9KS5mb3JFYWNoKChbcG9zLCB2YWxdKSA9PiB7CiAgICAgICAgICBwb3NpdGlvbkJyZWFrZG93bltwb3NdID0gKHBvc2l0aW9uQnJlYWtkb3duW3Bvc10gfHwgMCkgKyAodmFsIHx8IDApOwogICAgICAgIH0pOwogICAgICAgIChpdGVtLndvcmtlck5hbWVzIHx8IFtdKS5mb3JFYWNoKChuYW1lKSA9PiB3b3JrZXJzLmFkZChuYW1lKSk7CiAgICAgIH0pOwogICAgICByZXR1cm4gewogICAgICAgIGlzU3VidG90YWw6IHRydWUsCiAgICAgICAgc3VidG90YWxMZXZlbDogbGV2ZWwsCiAgICAgICAgc3VidG90YWxMYWJlbDogbGFiZWwsCiAgICAgICAgbGFiZWxDb2xTcGFuOiBsZXZlbCA9PT0gJ2QxJyA/IChpc0FsbEZpbHRlcnNPZmYgPyAzIDogNCkgOiAoaXNBbGxGaWx0ZXJzT2ZmID8gMiA6IDMpLAogICAgICAgIGluY29tZTogaXRlbXMucmVkdWNlKChzLCBjKSA9PiBzICsgKGMuaW5jb21lIHx8IDApLCAwKSwKICAgICAgICB0b3RhbDogaXRlbXMucmVkdWNlKChzLCBjKSA9PiBzICsgKGMudG90YWwgfHwgMCksIDApLAogICAgICAgIGhyczogaXRlbXMucmVkdWNlKChzLCBjKSA9PiBzICsgKGMuaHJzIHx8IDApLCAwKSwKICAgICAgICB3b3JrZXJzOiB3b3JrZXJzLnNpemUsCiAgICAgICAgY29zdEJyZWFrZG93biwKICAgICAgICBwb3NpdGlvbkJyZWFrZG93bgogICAgICB9OwogICAgfTsKCiAgICBjb25zdCBidWlsZEQzU3VtbWFyeVJvdyA9IChpdGVtcywgZDEsIGQyLCBkMykgPT4gewogICAgICBjb25zdCBtZXJnZWQgPSBhZ2dyZWdhdGVHcm91cFN1bW1hcnkoaXRlbXMsIGAke2QzfSDshozqs4RgLCAnZDMnKTsKICAgICAgcmV0dXJuIHsKICAgICAgICAuLi5tZXJnZWQsCiAgICAgICAgaXNTdWJ0b3RhbDogZmFsc2UsCiAgICAgICAgaXNEM1N1bW1hcnlSb3c6IHRydWUsCiAgICAgICAgZDEsIGQyLCBkMywKICAgICAgICBuYW1lOiBgJHtkM30g7IaM6rOEYAogICAgICB9OwogICAgfTsKCiAgICBjb25zdCBmaW5hbERpc3BsYXlMaXN0ID0gW107CiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHN1bW1hcnlMaXN0Lmxlbmd0aDspIHsKICAgICAgY29uc3QgZDEgPSBzdW1tYXJ5TGlzdFtpXS5kMTsKICAgICAgbGV0IGQxRW5kID0gaTsKICAgICAgd2hpbGUgKGQxRW5kIDwgc3VtbWFyeUxpc3QubGVuZ3RoICYmIHN1bW1hcnlMaXN0W2QxRW5kXS5kMSA9PT0gZDEpIGQxRW5kKys7CgogICAgICBjb25zdCBkMlJhbmdlcyA9IFtdOwogICAgICBmb3IgKGxldCBqID0gaTsgaiA8IGQxRW5kOykgewogICAgICAgIGNvbnN0IGQyID0gc3VtbWFyeUxpc3Rbal0uZDI7CiAgICAgICAgbGV0IGQyRW5kID0gajsKICAgICAgICB3aGlsZSAoZDJFbmQgPCBkMUVuZCAmJiBzdW1tYXJ5TGlzdFtkMkVuZF0uZDIgPT09IGQyKSBkMkVuZCsrOwogICAgICAgIGQyUmFuZ2VzLnB1c2goeyBzdGFydDogaiwgZW5kOiBkMkVuZCwgbmFtZTogZDIgfSk7CiAgICAgICAgaiA9IGQyRW5kOwogICAgICB9CgogICAgICBjb25zdCBkMUQzQ291bnQgPSBpc0FsbEZpbHRlcnNPZmYKICAgICAgICA/IG5ldyBTZXQoc3VtbWFyeUxpc3Quc2xpY2UoaSwgZDFFbmQpLm1hcCgocm93KSA9PiBgJHtyb3cuZDJ9fHx8JHtyb3cuZDN9YCkpLnNpemUKICAgICAgICA6IDA7CiAgICAgIGNvbnN0IGQxU3BhblRvdGFsID0gKGlzQWxsRmlsdGVyc09mZiA/IGQxRDNDb3VudCA6IChkMUVuZCAtIGkpKSArIGQyUmFuZ2VzLmxlbmd0aDsKICAgICAgbGV0IGQxUGxhY2VkID0gZmFsc2U7CgogICAgICBkMlJhbmdlcy5mb3JFYWNoKChyYW5nZSkgPT4gewogICAgICAgIGNvbnN0IGogPSByYW5nZS5zdGFydDsKICAgICAgICBjb25zdCBkMkVuZCA9IHJhbmdlLmVuZDsKICAgICAgICBjb25zdCBkMiA9IHJhbmdlLm5hbWU7CgogICAgICAgIGNvbnN0IGQzU3VtbWFyeVJvd3MgPSBbXTsKICAgICAgICBmb3IgKGxldCBrID0gajsgayA8IGQyRW5kOykgewogICAgICAgICAgY29uc3QgZDMgPSBzdW1tYXJ5TGlzdFtrXS5kMzsKICAgICAgICAgIGxldCBkM0VuZCA9IGs7CiAgICAgICAgICB3aGlsZSAoZDNFbmQgPCBkMkVuZCAmJiBzdW1tYXJ5TGlzdFtkM0VuZF0uZDMgPT09IGQzKSBkM0VuZCsrOwoKICAgICAgICAgIGNvbnN0IGQzU2xpY2UgPSBzdW1tYXJ5TGlzdC5zbGljZShrLCBkM0VuZCk7CiAgICAgICAgICBpZiAoIWlzQWxsRmlsdGVyc09mZikgewogICAgICAgICAgICBmb3IgKGxldCByID0gazsgciA8IGQzRW5kOyByKyspIHsKICAgICAgICAgICAgICBmaW5hbERpc3BsYXlMaXN0LnB1c2goewogICAgICAgICAgICAgICAgLi4uc3VtbWFyeUxpc3Rbcl0sCiAgICAgICAgICAgICAgICBkMVNwYW46ICFkMVBsYWNlZCA/IGQxU3BhblRvdGFsIDogMCwKICAgICAgICAgICAgICAgIGQyU3BhbjogciA9PT0gaiA/IChkMkVuZCAtIGopIDogMCwKICAgICAgICAgICAgICAgIGQzU3BhbjogciA9PT0gayA/IChkM0VuZCAtIGspIDogMAogICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgIGlmICghZDFQbGFjZWQpIGQxUGxhY2VkID0gdHJ1ZTsKICAgICAgICAgICAgfQogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgZDNTdW1tYXJ5Um93cy5wdXNoKGJ1aWxkRDNTdW1tYXJ5Um93KGQzU2xpY2UsIGQxLCBkMiwgZDMpKTsKICAgICAgICAgIH0KICAgICAgICAgIGsgPSBkM0VuZDsKICAgICAgICB9CgogICAgICAgIGlmIChpc0FsbEZpbHRlcnNPZmYpIHsKICAgICAgICAgIGQzU3VtbWFyeVJvd3MuZm9yRWFjaCgocm93LCBpZHhXaXRoaW5EMikgPT4gewogICAgICAgICAgICBmaW5hbERpc3BsYXlMaXN0LnB1c2goewogICAgICAgICAgICAgIC4uLnJvdywKICAgICAgICAgICAgICBkMVNwYW46ICFkMVBsYWNlZCAmJiBpZHhXaXRoaW5EMiA9PT0gMCA/IGQxU3BhblRvdGFsIDogMCwKICAgICAgICAgICAgICBkMlNwYW46IGlkeFdpdGhpbkQyID09PSAwID8gZDNTdW1tYXJ5Um93cy5sZW5ndGggOiAwLAogICAgICAgICAgICAgIGQzU3BhbjogMQogICAgICAgICAgICB9KTsKICAgICAgICAgICAgaWYgKCFkMVBsYWNlZCAmJiBpZHhXaXRoaW5EMiA9PT0gMCkgZDFQbGFjZWQgPSB0cnVlOwogICAgICAgICAgfSk7CiAgICAgICAgfQoKICAgICAgICBjb25zdCBkMlNsaWNlID0gc3VtbWFyeUxpc3Quc2xpY2UoaiwgZDJFbmQpOwogICAgICAgIGZpbmFsRGlzcGxheUxpc3QucHVzaChhZ2dyZWdhdGVHcm91cFN1bW1hcnkoZDJTbGljZSwgYCR7ZDJ9IOyGjOqzhGAsICdkMicpKTsKICAgICAgfSk7CgogICAgICBjb25zdCBkMVNsaWNlID0gc3VtbWFyeUxpc3Quc2xpY2UoaSwgZDFFbmQpOwogICAgICBmaW5hbERpc3BsYXlMaXN0LnB1c2goYWdncmVnYXRlR3JvdXBTdW1tYXJ5KGQxU2xpY2UsIGAke2QxfSDtlanqs4RgLCAnZDEnKSk7CgogICAgICBpID0gZDFFbmQ7CiAgICB9CgogICAgY29uc3QgaGllcmFyY2h5ID0ge307CiAgICBPYmplY3QuZW50cmllcyhwcm9qZWN0VG9EZXB0aCkuZm9yRWFjaCgoW3BLZXksIGluZm9dKSA9PiB7CiAgICAgIGlmICghaGllcmFyY2h5W2luZm8uZDFdKSBoaWVyYXJjaHlbaW5mby5kMV0gPSB7fTsKICAgICAgaWYgKCFoaWVyYXJjaHlbaW5mby5kMV1baW5mby5kMl0pIGhpZXJhcmNoeVtpbmZvLmQxXVtpbmZvLmQyXSA9IHt9OwogICAgICBpZiAoIWhpZXJhcmNoeVtpbmZvLmQxXVtpbmZvLmQyXVtpbmZvLmQzXSkgaGllcmFyY2h5W2luZm8uZDFdW2luZm8uZDJdW2luZm8uZDNdID0gbmV3IFNldCgpOwogICAgICBoaWVyYXJjaHlbaW5mby5kMV1baW5mby5kMl1baW5mby5kM10uYWRkKHByb2plY3REaXNwbGF5QnlLZXlbcEtleV0gfHwgcEtleSk7CiAgICB9KTsKCiAgICBjb25zdCB0b3RhbEV4cCA9IHN1bW1hcnlMaXN0LnJlZHVjZSgocywgYykgPT4gcyArIGMudG90YWwsIDApOwoKICAgIGNvbnN0IGV4cGVuc2VEZXRhaWxCeUNhdGVnb3J5ID0geyAn7Lac7J6l67mEJzogW10sICfrs7Xrpqztm4Tsg53ruYQnOiBbXSwgJ+q1rOunpOu5hCc6IFtdLCAn7Jm47KO867mEJzogW10gfTsKICAgIGJhc2VGaWx0ZXJlZEV4cC5mb3JFYWNoKChlKSA9PiB7CiAgICAgIGNvbnN0IGRpdiA9IG5vcm0oZ2V0VmFsKGUsIFsn6rWs67aEJ10sIDIyKSk7CiAgICAgIGNvbnN0IGFtb3VudCA9IHBudW0oZ2V0VmFsKGUsIFsn7KeA7LacJ10sIDE5KSk7CiAgICAgIGlmICghYW1vdW50KSByZXR1cm47CgogICAgICBsZXQgY2F0ZWdvcnkgPSAn6rWs66ek67mEJzsKICAgICAgaWYgKGRpdiA9PT0gJ+y2nOyepeu5hCcpIGNhdGVnb3J5ID0gJ+y2nOyepeu5hCc7CiAgICAgIGVsc2UgaWYgKGRpdiA9PT0gJ+uzteumrO2bhOyDneu5hCcpIGNhdGVnb3J5ID0gJ+uzteumrO2bhOyDneu5hCc7CiAgICAgIGVsc2UgaWYgKGRpdiA9PT0gJ+yZuOyjvOu5hCcpIGNhdGVnb3J5ID0gJ+yZuOyjvOu5hCc7CiAgICAgIGVsc2UgaWYgKGRpdiA9PT0gJ+ygnOyZuCcpIHJldHVybjsKCiAgICAgIGV4cGVuc2VEZXRhaWxCeUNhdGVnb3J5W2NhdGVnb3J5XS5wdXNoKHsKICAgICAgICBpc3N1ZURhdGU6IG5vcm0oZ2V0VmFsKGUsIFsn67Cc7ZaJ7J28JywgJ+uwnO2WiSDsnbzsnpAnLCAn7J287J6QJ10sIDIpKSwKICAgICAgICBwcm9qZWN0TmFtZTogZ2V0RXhwZW5zZVByb2plY3ROYW1lKGUpIHx8ICfrr7jsp4DsoJUg7ZSE66Gc7KCd7Yq4JywKICAgICAgICBzdW1tYXJ5OiBub3JtKGdldFZhbChlLCBbJ+yggeyalCcsICfsoITtkZzsoIHsmpQnLCAn7KCE7ZGcIOyggeyalCcsICfrgrTsmqknLCAn67mE6rOgJ10sIDE3KSksCiAgICAgICAgYW1vdW50CiAgICAgIH0pOwogICAgfSk7CiAgICBPYmplY3Qua2V5cyhleHBlbnNlRGV0YWlsQnlDYXRlZ29yeSkuZm9yRWFjaCgoa2V5KSA9PiB7CiAgICAgIGV4cGVuc2VEZXRhaWxCeUNhdGVnb3J5W2tleV0uc29ydCgoYSwgYikgPT4gU3RyaW5nKGIuaXNzdWVEYXRlKS5sb2NhbGVDb21wYXJlKFN0cmluZyhhLmlzc3VlRGF0ZSkpKTsKICAgIH0pOwoKICAgIGNvbnN0IGNhdGVnb3J5RGF0YSA9IGNvc3RDYXRlZ29yaWVzLm1hcChjYXQgPT4gewogICAgICBjb25zdCB2YWwgPSBzdW1tYXJ5TGlzdC5yZWR1Y2UoKGFjYywgY3VyKSA9PiBhY2MgKyAoY3VyLmNvc3RCcmVha2Rvd25bY2F0Lm5hbWVdIHx8IDApLCAwKTsKICAgICAgcmV0dXJuIHsgbmFtZTogY2F0Lm5hbWUsIHZhbHVlOiB2YWwsIHJhdGlvOiB0b3RhbEV4cCA+IDAgPyAoKHZhbCAvIHRvdGFsRXhwKSAqIDEwMCkudG9GaXhlZCgxKSA6IDAgfTsKICAgIH0pLmZpbHRlcihkID0+IGQudmFsdWUgPiAwKTsKCiAgICByZXR1cm4geyAKICAgICAga3BpczogewogICAgICAgIGluY29tZTogc3VtbWFyeUxpc3QucmVkdWNlKChzLCBjKSA9PiBzICsgYy5pbmNvbWUsIDApLAogICAgICAgIGxhYm9yOiBzdW1tYXJ5TGlzdC5yZWR1Y2UoKHMsIGMpID0+IHMgKyBjLmxhYm9yLCAwKSwKICAgICAgICBob3Vyczogc3VtbWFyeUxpc3QucmVkdWNlKChzLCBjKSA9PiBzICsgYy5ocnMsIDApLAogICAgICAgIHdvcmtlcnM6IG5ldyBTZXQoYmFzZUZpbHRlcmVkV29yay5tYXAodyA9PiBub3JtKGdldFZhbCh3LCBbJ+ydtOumhCddKSkgfHwgbm9ybSh3Lndvcmtlck5hbWUpKS5maWx0ZXIoQm9vbGVhbikpLnNpemUsCiAgICAgICAgdHJhdmVsOiBiYXNlRmlsdGVyZWRFeHAuZmlsdGVyKGUgPT4gbm9ybShnZXRWYWwoZSwgWyfqtazrtoQnXSwgMjIpKSA9PT0gJ+y2nOyepeu5hCcpLnJlZHVjZSgocywgYykgPT4gcyArIHBudW0oZ2V0VmFsKGMsIFsn7KeA7LacJ10sIDE5KSksIDApLAogICAgICAgIHdlbGZhcmU6IGJhc2VGaWx0ZXJlZEV4cC5maWx0ZXIoZSA9PiBub3JtKGdldFZhbChlLCBbJ+q1rOu2hCddLCAyMikpID09PSAn67O166as7ZuE7IOd67mEJykucmVkdWNlKChzLCBjKSA9PiBzICsgcG51bShnZXRWYWwoYywgWyfsp4DstpwnXSwgMTkpKSwgMCksCiAgICAgICAgb3RoZXJzOiBiYXNlRmlsdGVyZWRFeHAuZmlsdGVyKGUgPT4gIVsn7Lac7J6l67mEJywgJ+uzteumrO2bhOyDneu5hCcsICfsoJzsmbgnXS5pbmNsdWRlcyhub3JtKGdldFZhbChlLCBbJ+q1rOu2hCddLCAyMikpKSkucmVkdWNlKChzLCBjKSA9PiBzICsgcG51bShnZXRWYWwoYywgWyfsp4DstpwnXSwgMTkpKSwgMCkKICAgICAgfSwKICAgICAgZmluYWxEaXNwbGF5TGlzdCwgcG9zaXRpb25BbmFseXNpcywgcG9zaXRpb25Hcm91cE1vZGUsIGhpZXJhcmNoeSwgY2F0ZWdvcnlEYXRhLCBleHBlbnNlRGV0YWlsQnlDYXRlZ29yeSwgaXNBbGxGaWx0ZXJzT2ZmCiAgICB9OwogIH0sIFtleHBlbnNlUmF3LCB3b3JrUmF3LCBkYXRhTG9hZGVkLCBzZWxlY3RlZFJldiwgc2VsZWN0ZWREMSwgc2VsZWN0ZWREMiwgc2VsZWN0ZWRQcm9qZWN0LCBzdGFydERhdGUsIGVuZERhdGUsIGN1c3RvbVByb2plY3RPcmRlck1hcF0pOwoKCiAgdXNlRWZmZWN0KCgpID0+IHsKICAgIGNvbnN0IGFsbEZpbHRlcnNPZmYgPSBwcm9jZXNzZWREYXRhID8gcHJvY2Vzc2VkRGF0YS5pc0FsbEZpbHRlcnNPZmYgOiBmYWxzZTsKICAgIGlmIChhbGxGaWx0ZXJzT2ZmICYmIHNlbGVjdGVkRXhwZW5zZURldGFpbENhdGVnb3J5KSB7CiAgICAgIHNldFNlbGVjdGVkRXhwZW5zZURldGFpbENhdGVnb3J5KCcnKTsKICAgIH0KICB9LCBbcHJvY2Vzc2VkRGF0YSwgc2VsZWN0ZWRFeHBlbnNlRGV0YWlsQ2F0ZWdvcnldKTsKCiAgY29uc3QgaGFuZGxlRDFDbGljayA9IChkMSkgPT4gewogICAgaWYgKHNlbGVjdGVkUmV2ID09PSBkMSAmJiBzZWxlY3RlZEQxID09PSAn7KCE7LK0JyAmJiBzZWxlY3RlZEQyID09PSAn7KCE7LK0JyAmJiBzZWxlY3RlZFByb2plY3QgPT09ICfsoITssrQnKSB7CiAgICAgIHNldFNlbGVjdGVkUmV2KCfsoITssrQnKTsKICAgICAgc2V0U2VsZWN0ZWREMSgn7KCE7LK0Jyk7CiAgICAgIHNldFNlbGVjdGVkRDIoJ+yghOyytCcpOwogICAgICBzZXRTZWxlY3RlZFByb2plY3QoJ+yghOyytCcpOwogICAgICByZXR1cm47CiAgICB9CiAgICBzZXRTZWxlY3RlZFJldihkMSk7CiAgICBzZXRTZWxlY3RlZEQxKCfsoITssrQnKTsKICAgIHNldFNlbGVjdGVkRDIoJ+yghOyytCcpOwogICAgc2V0U2VsZWN0ZWRQcm9qZWN0KCfsoITssrQnKTsKICB9OwoKICBjb25zdCBoYW5kbGVEMkNsaWNrID0gKGQxLCBkMikgPT4gewogICAgc2V0U2VsZWN0ZWRSZXYoZDEpOwogICAgc2V0U2VsZWN0ZWREMShkMik7CiAgICBzZXRTZWxlY3RlZEQyKCfsoITssrQnKTsKICAgIHNldFNlbGVjdGVkUHJvamVjdCgn7KCE7LK0Jyk7CiAgfTsKCiAgY29uc3QgaGFuZGxlRDNDbGljayA9IChkMSwgZDIsIGQzKSA9PiB7CiAgICBzZXRTZWxlY3RlZFJldihkMSk7CiAgICBzZXRTZWxlY3RlZEQxKGQyKTsKICAgIHNldFNlbGVjdGVkRDIoZDMpOwogICAgc2V0U2VsZWN0ZWRQcm9qZWN0KCfsoITssrQnKTsKICB9OwoKICBjb25zdCBoYW5kbGVENENsaWNrID0gKGQxLCBkMiwgZDMsIGQ0KSA9PiB7CiAgICBzZXRTZWxlY3RlZFJldihkMSk7CiAgICBzZXRTZWxlY3RlZEQxKGQyKTsKICAgIHNldFNlbGVjdGVkRDIoZDMpOwogICAgc2V0U2VsZWN0ZWRQcm9qZWN0KGQ0KTsKICB9OwoKICBjb25zdCB2aWV3RGF0YSA9IHByb2Nlc3NlZERhdGEgfHwgewogICAga3BpczogeyBpbmNvbWU6IDAsIGxhYm9yOiAwLCBob3VyczogMCwgd29ya2VyczogMCwgdHJhdmVsOiAwLCB3ZWxmYXJlOiAwLCBvdGhlcnM6IDAgfSwKICAgIGZpbmFsRGlzcGxheUxpc3Q6IFtdLAogICAgcG9zaXRpb25BbmFseXNpczoge30sCiAgICBwb3NpdGlvbkdyb3VwTW9kZTogJ0QxJywKICAgIGhpZXJhcmNoeToge30sCiAgICBjYXRlZ29yeURhdGE6IFtdLAogICAgZXhwZW5zZURldGFpbEJ5Q2F0ZWdvcnk6IHsgJ+y2nOyepeu5hCc6IFtdLCAn67O166as7ZuE7IOd67mEJzogW10sICfqtazrp6TruYQnOiBbXSwgJ+yZuOyjvOu5hCc6IFtdIH0sCiAgICBpc0FsbEZpbHRlcnNPZmY6IGZhbHNlCiAgfTsKCiAgcmV0dXJuICgKICAgIDxkaXYgY2xhc3NOYW1lPSJtaW4taC1zY3JlZW4gYmctWyNmOGZhZmNdIHAtNiBmb250LXNhbnMgdGV4dC1zbGF0ZS05MDAiPgogICAgICA8ZGl2IGNsYXNzTmFtZT0idy1mdWxsIG14LWF1dG8gc3BhY2UteS02Ij4KICAgICAgICAKICAgICAgICB7LyogSGVhZGVyICovfQogICAgICAgIDxoZWFkZXIgY2xhc3NOYW1lPSJiZy13aGl0ZSBwLTYgcm91bmRlZC1bMzVweF0gc2hhZG93LXNtIGJvcmRlciBib3JkZXItc2xhdGUtMTAwIGZsZXggaXRlbXMtc3RhcnQganVzdGlmeS1iZXR3ZWVuIGdhcC02Ij4KICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPSJmbGV4IGl0ZW1zLWNlbnRlciBnYXAtNCI+CiAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPSJ3LTEyIGgtMTIgYmctaW5kaWdvLTYwMCByb3VuZGVkLTJ4bCBmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciB0ZXh0LXdoaXRlIHNoYWRvdy1sZyI+PExheW91dERhc2hib2FyZCBzaXplPXsyNH0gLz48L2Rpdj4KICAgICAgICAgICAgPGRpdj4KICAgICAgICAgICAgICA8aDEgY2xhc3NOYW1lPSJ0ZXh0LTJ4bCBmb250LWJsYWNrIj4yMDI2IOumrOyGjOyKpCDthrXtlakg64yA7Iuc67O065OcPC9oMT4KICAgICAgICAgICAgICA8cCBjbGFzc05hbWU9InRleHQtWzEycHhdIHRleHQtc2xhdGUtNDAwIGZvbnQtYm9sZCB1cHBlcmNhc2UgdHJhY2tpbmctd2lkZXN0Ij5GaW5hbCBTdGFibGUgVmVyc2lvbjwvcD4KICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICA8L2Rpdj4KICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPSJmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWVuZCBnYXAtMiBmbGV4LXdyYXAgbWF4LXctWzExMDBweF0gZmxleC0xIj4KICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9ImZsZXggZ2FwLTIgYmctc2xhdGUtNTAvODAgcC0xLjUgcm91bmRlZC0yeGwgYm9yZGVyIGJvcmRlci1zbGF0ZS0xMDAgZmxleC1bMV8xXzcwMHB4XSBtaW4tdy1bNDIwcHhdIj4KICAgICAgICAgICAgICA8c2VsZWN0IHZhbHVlPXtzZWxlY3RlZFJldn0gb25DaGFuZ2U9e2UgPT4ge3NldFNlbGVjdGVkUmV2KGUudGFyZ2V0LnZhbHVlKTsgc2V0U2VsZWN0ZWREMSgn7KCE7LK0Jyk7IHNldFNlbGVjdGVkRDIoJ+yghOyytCcpOyBzZXRTZWxlY3RlZFByb2plY3QoJ+yghOyytCcpO319IGNsYXNzTmFtZT0iZmlsdGVyLXNlbGVjdCBmbGV4LTEiPgogICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT0i7KCE7LK0Ij7rjIDrtoTrpZgg7KCE7LK0PC9vcHRpb24+CiAgICAgICAgICAgICAgICB7T2JqZWN0LmtleXModmlld0RhdGEuaGllcmFyY2h5KQogICAgICAgICAgICAgICAgICAuZmlsdGVyKGQgPT4gZCAmJiBkICE9PSAn66+467aE66WYJykKICAgICAgICAgICAgICAgICAgLnNvcnQoKGEsYik9PihkMU9yZGVyW2FdfHw5OSktKGQxT3JkZXJbYl18fDk5KSB8fCBhLmxvY2FsZUNvbXBhcmUoYikpCiAgICAgICAgICAgICAgICAgIC5tYXAoZCA9PiA8b3B0aW9uIGtleT17ZH0gdmFsdWU9e2R9PntkfTwvb3B0aW9uPil9CiAgICAgICAgICAgICAgPC9zZWxlY3Q+CiAgICAgICAgICAgICAgPHNlbGVjdCB2YWx1ZT17c2VsZWN0ZWREMX0gb25DaGFuZ2U9e2UgPT4ge3NldFNlbGVjdGVkRDEoZS50YXJnZXQudmFsdWUpOyBzZXRTZWxlY3RlZEQyKCfsoITssrQnKTsgc2V0U2VsZWN0ZWRQcm9qZWN0KCfsoITssrQnKTt9fSBjbGFzc05hbWU9ImZpbHRlci1zZWxlY3QgZmxleC0xIj4KICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9IuyghOyytCI+7KSR67aE66WYIOyghOyytDwvb3B0aW9uPgogICAgICAgICAgICAgICAge3NlbGVjdGVkUmV2ICE9PSAn7KCE7LK0JyAmJiB2aWV3RGF0YS5oaWVyYXJjaHlbc2VsZWN0ZWRSZXZdICYmIE9iamVjdC5rZXlzKHZpZXdEYXRhLmhpZXJhcmNoeVtzZWxlY3RlZFJldl0pCiAgICAgICAgICAgICAgICAgIC5maWx0ZXIoZCA9PiBkICYmIGQgIT09ICfrr7jrtoTrpZgnKQogICAgICAgICAgICAgICAgICAuc29ydCgoYSxiKT0+Z2V0RDJPcmRlcihhKS1nZXREMk9yZGVyKGIpIHx8IGEubG9jYWxlQ29tcGFyZShiKSkKICAgICAgICAgICAgICAgICAgLm1hcChkID0+IDxvcHRpb24ga2V5PXtkfSB2YWx1ZT17ZH0+e2R9PC9vcHRpb24+KX0KICAgICAgICAgICAgICA8L3NlbGVjdD4KICAgICAgICAgICAgICA8c2VsZWN0IHZhbHVlPXtzZWxlY3RlZEQyfSBvbkNoYW5nZT17ZSA9PiB7c2V0U2VsZWN0ZWREMihlLnRhcmdldC52YWx1ZSk7IHNldFNlbGVjdGVkUHJvamVjdCgn7KCE7LK0Jyk7fX0gY2xhc3NOYW1lPSJmaWx0ZXItc2VsZWN0IGZsZXgtMSI+CiAgICAgICAgICAgICAgICA8b3B0aW9uIHZhbHVlPSLsoITssrQiPuyGjOu2hOulmCDsoITssrQ8L29wdGlvbj4KICAgICAgICAgICAgICAgIHtzZWxlY3RlZFJldiAhPT0gJ+yghOyytCcgJiYgc2VsZWN0ZWREMSAhPT0gJ+yghOyytCcgJiYgdmlld0RhdGEuaGllcmFyY2h5W3NlbGVjdGVkUmV2XT8uW3NlbGVjdGVkRDFdICYmIE9iamVjdC5rZXlzKHZpZXdEYXRhLmhpZXJhcmNoeVtzZWxlY3RlZFJldl1bc2VsZWN0ZWREMV0pCiAgICAgICAgICAgICAgICAgIC5maWx0ZXIoZCA9PiBkICYmIGQgIT09ICfrr7jrtoTrpZgnKQogICAgICAgICAgICAgICAgICAuc29ydCgoYSwgYikgPT4gZ2V0RDNPcmRlcihhLCBzZWxlY3RlZEQxKSAtIGdldEQzT3JkZXIoYiwgc2VsZWN0ZWREMSkgfHwgYS5sb2NhbGVDb21wYXJlKGIpKQogICAgICAgICAgICAgICAgICAubWFwKGQgPT4gPG9wdGlvbiBrZXk9e2R9IHZhbHVlPXtkfT57ZH08L29wdGlvbj4pfQogICAgICAgICAgICAgIDwvc2VsZWN0PgogICAgICAgICAgICAgIDxzZWxlY3QgdmFsdWU9e3NlbGVjdGVkUHJvamVjdH0gb25DaGFuZ2U9e2UgPT4gc2V0U2VsZWN0ZWRQcm9qZWN0KGUudGFyZ2V0LnZhbHVlKX0gY2xhc3NOYW1lPSJmaWx0ZXItc2VsZWN0IGZsZXgtWzEuNF0iPgogICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT0i7KCE7LK0Ij7tlITroZzsoJ3tirjrqoUg7KCE7LK0PC9vcHRpb24+CiAgICAgICAgICAgICAgICB7c2VsZWN0ZWRSZXYgIT09ICfsoITssrQnICYmIHNlbGVjdGVkRDEgIT09ICfsoITssrQnICYmIHNlbGVjdGVkRDIgIT09ICfsoITssrQnICYmIHZpZXdEYXRhLmhpZXJhcmNoeVtzZWxlY3RlZFJldl0/LltzZWxlY3RlZEQxXT8uW3NlbGVjdGVkRDJdICYmIEFycmF5LmZyb20odmlld0RhdGEuaGllcmFyY2h5W3NlbGVjdGVkUmV2XVtzZWxlY3RlZEQxXVtzZWxlY3RlZEQyXSkKICAgICAgICAgICAgICAgICAgLmZpbHRlcihwID0+IHAgJiYgcCAhPT0gJ+uvuOu2hOulmCcpCiAgICAgICAgICAgICAgICAgIC5zb3J0KChhLCBiKSA9PiBnZXRQcm9qZWN0T3JkZXIoYSkgLSBnZXRQcm9qZWN0T3JkZXIoYikgfHwgYS5sb2NhbGVDb21wYXJlKGIpKQogICAgICAgICAgICAgICAgICAubWFwKHAgPT4gPG9wdGlvbiBrZXk9e3B9IHZhbHVlPXtwfT57cH08L29wdGlvbj4pfQogICAgICAgICAgICAgIDwvc2VsZWN0PgogICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPSJmbGV4IGl0ZW1zLWNlbnRlciBnYXAtMSBweC0zIHB5LTEuNSBiZy1zbGF0ZS01MCByb3VuZGVkLXhsIHRleHQtWzEycHhdIGZvbnQtYm9sZCBib3JkZXIgYm9yZGVyLXNsYXRlLTEwMCBzaHJpbmstMCI+CiAgICAgICAgICAgICAgPENhbGVuZGFyIHNpemU9ezEzfSBjbGFzc05hbWU9InRleHQtaW5kaWdvLTUwMCIgLz4KICAgICAgICAgICAgICA8aW5wdXQgdHlwZT0iZGF0ZSIgdmFsdWU9e3N0YXJ0RGF0ZX0gb25DaGFuZ2U9e2UgPT4gc2V0U3RhcnREYXRlKGUudGFyZ2V0LnZhbHVlKX0gY2xhc3NOYW1lPSJiZy10cmFuc3BhcmVudCBvdXRsaW5lLW5vbmUiIC8+CiAgICAgICAgICAgICAgPHNwYW4gY2xhc3NOYW1lPSJteC0xIHRleHQtc2xhdGUtMzAwIj5+PC9zcGFuPgogICAgICAgICAgICAgIDxpbnB1dCB0eXBlPSJkYXRlIiB2YWx1ZT17ZW5kRGF0ZX0gb25DaGFuZ2U9e2UgPT4gc2V0RW5kRGF0ZShlLnRhcmdldC52YWx1ZSl9IGNsYXNzTmFtZT0iYmctdHJhbnNwYXJlbnQgb3V0bGluZS1ub25lIiAvPgogICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgIDxidXR0b24gb25DbGljaz17KCkgPT4ge3NldFNlbGVjdGVkUmV2KCfsoITssrQnKTsgc2V0U2VsZWN0ZWREMSgn7KCE7LK0Jyk7IHNldFNlbGVjdGVkRDIoJ+yghOyytCcpOyBzZXRTZWxlY3RlZFByb2plY3QoJ+yghOyytCcpO319IGNsYXNzTmFtZT0icC0xLjUgYmctd2hpdGUgcm91bmRlZC14bCBib3JkZXIgYm9yZGVyLXNsYXRlLTIwMCB0ZXh0LXNsYXRlLTQwMCBob3Zlcjp0ZXh0LWluZGlnby02MDAgdHJhbnNpdGlvbi1hbGwgc2hhZG93LXNtIHNocmluay0wIj48UmVmcmVzaEN3IHNpemU9ezE0fS8+PC9idXR0b24+CiAgICAgICAgICA8L2Rpdj4KICAgICAgICAgPC9oZWFkZXI+CgogICAgICAgIHsvKiBLUElzICovfQogICAgICAgIDxkaXYgY2xhc3NOYW1lPSJncmlkIGdyaWQtY29scy0yIG1kOmdyaWQtY29scy00IGxnOmdyaWQtY29scy03IGdhcC00Ij4KICAgICAgICAgIHtbCiAgICAgICAgICAgIHsgbGFiZWw6ICfstJ0g7IiY7J6FKOunpOy2nCknLCB2YWx1ZTogYOKCqSR7dmlld0RhdGEua3Bpcy5pbmNvbWUudG9Mb2NhbGVTdHJpbmcoKX1gLCBpY29uOiBXYWxsZXQsIGNvbG9yOiAndGV4dC1pbmRpZ28tNjAwJyB9LAogICAgICAgICAgICB7IGxhYmVsOiAn7J246rG067mEIO2VqeqzhCcsIHZhbHVlOiBg4oKpJHtNYXRoLnJvdW5kKHZpZXdEYXRhLmtwaXMubGFib3IpLnRvTG9jYWxlU3RyaW5nKCl9YCwgaWNvbjogQnJpZWZjYXNlLCBjb2xvcjogJ3RleHQtc2xhdGUtNjAwJyB9LAogICAgICAgICAgICB7IGxhYmVsOiAn7Lac7J6l67mEJywgdmFsdWU6IGDigqkke3ZpZXdEYXRhLmtwaXMudHJhdmVsLnRvTG9jYWxlU3RyaW5nKCl9YCwgaWNvbjogTWFwUGluLCBjb2xvcjogJ3RleHQtcm9zZS02MDAnIH0sCiAgICAgICAgICAgIHsgbGFiZWw6ICfrs7Xrpqztm4Tsg53ruYQnLCB2YWx1ZTogYOKCqSR7dmlld0RhdGEua3Bpcy53ZWxmYXJlLnRvTG9jYWxlU3RyaW5nKCl9YCwgaWNvbjogQ29mZmVlLCBjb2xvcjogJ3RleHQtYW1iZXItNjAwJyB9LAogICAgICAgICAgICB7IGxhYmVsOiAn6rWs66ekL+yZuOyjvOu5hCcsIHZhbHVlOiBg4oKpJHt2aWV3RGF0YS5rcGlzLm90aGVycy50b0xvY2FsZVN0cmluZygpfWAsIGljb246IFBhY2thZ2UsIGNvbG9yOiAndGV4dC1zbGF0ZS01MDAnIH0sCiAgICAgICAgICAgIHsgbGFiZWw6ICftiKzsnoXsi5zqsIQnLCB2YWx1ZTogYCR7dmlld0RhdGEua3Bpcy5ob3Vycy50b0xvY2FsZVN0cmluZygpfWhgLCBpY29uOiBDbG9jaywgY29sb3I6ICd0ZXh0LWluZGlnby02MDAnIH0sCiAgICAgICAgICAgIHsgbGFiZWw6ICfssLjsl6zsnbjsm5AnLCB2YWx1ZTogYCR7dmlld0RhdGEua3Bpcy53b3JrZXJzfeuqhWAsIGljb246IFVzZXJzLCBjb2xvcjogJ3RleHQtd2hpdGUnLCBiZzogJ2JnLXNsYXRlLTkwMCcgfSwKICAgICAgICAgIF0ubWFwKChrcGksIGkpID0+ICgKICAgICAgICAgICAgPGRpdiBrZXk9e2l9IGNsYXNzTmFtZT17YCR7a3BpLmJnIHx8ICdiZy13aGl0ZSd9ICR7a3BpLmNvbG9yfSBwLTQgcm91bmRlZC1bMjJweF0gYm9yZGVyIGJvcmRlci1zbGF0ZS0xMDAgc2hhZG93LXNtIGZsZXggZmxleC1jb2wganVzdGlmeS1iZXR3ZWVuIGgtMjRgfT4KICAgICAgICAgICAgICA8c3BhbiBjbGFzc05hbWU9InRleHQtWzExcHhdIGZvbnQtYmxhY2sgdXBwZXJjYXNlIG9wYWNpdHktNjAgZmxleCBqdXN0aWZ5LWJldHdlZW4iPntrcGkubGFiZWx9IDxrcGkuaWNvbiBzaXplPXsxMH0vPjwvc3Bhbj4KICAgICAgICAgICAgICA8c3BhbiBjbGFzc05hbWU9InRleHQtbGcgZm9udC1ibGFjayB0cnVuY2F0ZSI+e2twaS52YWx1ZX08L3NwYW4+CiAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgKSl9CiAgICAgICAgPC9kaXY+CgogICAgICAgIHsvKiDsg4HshLgg67aE7ISdIO2FjOydtOu4lCAqL30KICAgICAgICA8c2VjdGlvbiBjbGFzc05hbWU9ImJnLXdoaXRlIHJvdW5kZWQtWzM1cHhdIHNoYWRvdy1zbSBib3JkZXIgYm9yZGVyLXNsYXRlLTEwMCBvdmVyZmxvdy1oaWRkZW4iPgogICAgICAgICAgPGRpdiBjbGFzc05hbWU9InAtNiBib3JkZXItYiBib3JkZXItc2xhdGUtNTAgZmxleCBpdGVtcy1jZW50ZXIiPgogICAgICAgICAgICA8aDIgY2xhc3NOYW1lPSJ0ZXh0LWxnIGZvbnQtYmxhY2sgZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTMiPjxMaXN0IHNpemU9ezIwfSBjbGFzc05hbWU9InRleHQtaW5kaWdvLTYwMCIgLz4g67aE7JW867OEIO2UhOuhnOygne2KuCDsg4HshLgg67aE7ISdPC9oMj4KICAgICAgICAgIDwvZGl2PgogICAgICAgICAgPGRpdiBjbGFzc05hbWU9Im92ZXJmbG93LXgtYXV0byI+CiAgICAgICAgICAgIDx0YWJsZSBjbGFzc05hbWU9InctZnVsbCB0ZXh0LWxlZnQgYm9yZGVyLWNvbGxhcHNlIHRhYmxlLWZpeGVkIj4KICAgICAgICAgICAgICA8Y29sZ3JvdXA+CiAgICAgICAgICAgICAgICB7dmlld0RhdGEuaXNBbGxGaWx0ZXJzT2ZmID8gKAogICAgICAgICAgICAgICAgICA8PgogICAgICAgICAgICAgICAgICAgIDxjb2wgc3R5bGU9e3sgd2lkdGg6ICc5JScgfX0gLz4KICAgICAgICAgICAgICAgICAgICA8Y29sIHN0eWxlPXt7IHdpZHRoOiAnMTElJyB9fSAvPgogICAgICAgICAgICAgICAgICAgIDxjb2wgc3R5bGU9e3sgd2lkdGg6ICcxMyUnIH19IC8+CiAgICAgICAgICAgICAgICAgICAgPGNvbCBzdHlsZT17eyB3aWR0aDogJzExJScgfX0gLz4KICAgICAgICAgICAgICAgICAgICA8Y29sIHN0eWxlPXt7IHdpZHRoOiAnMTElJyB9fSAvPgogICAgICAgICAgICAgICAgICAgIDxjb2wgc3R5bGU9e3sgd2lkdGg6ICcyNiUnIH19IC8+CiAgICAgICAgICAgICAgICAgICAgPGNvbCBzdHlsZT17eyB3aWR0aDogJzEzJScgfX0gLz4KICAgICAgICAgICAgICAgICAgICA8Y29sIHN0eWxlPXt7IHdpZHRoOiAnNiUnIH19IC8+CiAgICAgICAgICAgICAgICAgIDwvPgogICAgICAgICAgICAgICAgKSA6ICgKICAgICAgICAgICAgICAgICAgPD4KICAgICAgICAgICAgICAgICAgICA8Y29sIHN0eWxlPXt7IHdpZHRoOiAnOCUnIH19IC8+CiAgICAgICAgICAgICAgICAgICAgPGNvbCBzdHlsZT17eyB3aWR0aDogJzEwJScgfX0gLz4KICAgICAgICAgICAgICAgICAgICA8Y29sIHN0eWxlPXt7IHdpZHRoOiAnMTIlJyB9fSAvPgogICAgICAgICAgICAgICAgICAgIDxjb2wgc3R5bGU9e3sgd2lkdGg6ICcxNiUnIH19IC8+CiAgICAgICAgICAgICAgICAgICAgPGNvbCBzdHlsZT17eyB3aWR0aDogJzEwJScgfX0gLz4KICAgICAgICAgICAgICAgICAgICA8Y29sIHN0eWxlPXt7IHdpZHRoOiAnMTAlJyB9fSAvPgogICAgICAgICAgICAgICAgICAgIDxjb2wgc3R5bGU9e3sgd2lkdGg6ICcyNSUnIH19IC8+CiAgICAgICAgICAgICAgICAgICAgPGNvbCBzdHlsZT17eyB3aWR0aDogJzEzJScgfX0gLz4KICAgICAgICAgICAgICAgICAgICA8Y29sIHN0eWxlPXt7IHdpZHRoOiAnNiUnIH19IC8+CiAgICAgICAgICAgICAgICAgIDwvPgogICAgICAgICAgICAgICAgKX0KICAgICAgICAgICAgICA8L2NvbGdyb3VwPgogICAgICAgICAgICAgIDx0aGVhZCBjbGFzc05hbWU9ImJnLXNsYXRlLTUwLzgwIj4KICAgICAgICAgICAgICAgIDx0ciBjbGFzc05hbWU9InRleHQtWzExcHhdIGZvbnQtYmxhY2sgdGV4dC1zbGF0ZS00MDAgdXBwZXJjYXNlIHRyYWNraW5nLXdpZGVzdCBib3JkZXItYiBib3JkZXItc2xhdGUtMTAwIj4KICAgICAgICAgICAgICAgICAgPHRoIGNsYXNzTmFtZT0icHgtNCBweS0zIHdoaXRlc3BhY2Utbm93cmFwIj7rjIDrtoTrpZg8L3RoPgogICAgICAgICAgICAgICAgICA8dGggY2xhc3NOYW1lPSJweC00IHB5LTMgd2hpdGVzcGFjZS1ub3dyYXAiPuykkeu2hOulmDwvdGg+CiAgICAgICAgICAgICAgICAgIDx0aCBjbGFzc05hbWU9InB4LTQgcHktMyB3aGl0ZXNwYWNlLW5vd3JhcCI+7IaM67aE66WYPC90aD4KICAgICAgICAgICAgICAgICAgeyF2aWV3RGF0YS5pc0FsbEZpbHRlcnNPZmYgJiYgPHRoIGNsYXNzTmFtZT0icHgtNCBweS0zIHdoaXRlc3BhY2Utbm93cmFwIj7tlITroZzsoJ3tirjrqoU8L3RoPn0KICAgICAgICAgICAgICAgICAgPHRoIGNsYXNzTmFtZT0icHgtNCBweS0zIHRleHQtcmlnaHQgd2hpdGVzcGFjZS1ub3dyYXAiPuyImOyehSjrp6TstpwpPC90aD4KICAgICAgICAgICAgICAgICAgPHRoIGNsYXNzTmFtZT0icHgtNCBweS0zIHRleHQtcmlnaHQgd2hpdGVzcGFjZS1ub3dyYXAiPuyngOy2nCDtlanqs4Q8L3RoPgogICAgICAgICAgICAgICAgICA8dGggY2xhc3NOYW1lPSJweC00IHB5LTMgd2hpdGVzcGFjZS1ub3dyYXAiPuyngOy2nCDqtazshLHruYQ8L3RoPgogICAgICAgICAgICAgICAgICA8dGggY2xhc3NOYW1lPSJweC00IHB5LTMgd2hpdGVzcGFjZS1ub3dyYXAiPuyngeq4ieuzhCDsnbjsm5DtiKzsnoU8L3RoPgogICAgICAgICAgICAgICAgICA8dGggY2xhc3NOYW1lPSJweC00IHB5LTMgdGV4dC1jZW50ZXIgd2hpdGVzcGFjZS1ub3dyYXAiPuywuOyXrOyduOybkDwvdGg+CiAgICAgICAgICAgICAgICA8L3RyPgogICAgICAgICAgICAgIDwvdGhlYWQ+CiAgICAgICAgICAgICAgPHRib2R5IGNsYXNzTmFtZT0idGV4dC1bMTNweF0gZm9udC1ib2xkIj4KICAgICAgICAgICAgICAgIHt2aWV3RGF0YS5maW5hbERpc3BsYXlMaXN0Lmxlbmd0aCA9PT0gMCAmJiAoCiAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICA8dGQgY29sU3Bhbj17dmlld0RhdGEuaXNBbGxGaWx0ZXJzT2ZmID8gOCA6IDl9IGNsYXNzTmFtZT0icHgtNCBweS0xMiB0ZXh0LWNlbnRlciB0ZXh0LXNsYXRlLTQwMCBmb250LWJvbGQiPu2RnOyLnO2VoCDrjbDsnbTthLDqsIAg7JeG7Iq164uI64ukLjwvdGQ+CiAgICAgICAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgICAgICApfQogICAgICAgICAgICAgICAge3ZpZXdEYXRhLmZpbmFsRGlzcGxheUxpc3QubWFwKChpdGVtLCBpZHgpID0+IHsKICAgICAgICAgICAgICAgICAgaWYgKGl0ZW0uaXNTdWJ0b3RhbCkgewogICAgICAgICAgICAgICAgICAgIGNvbnN0IGlzR3JhbmRUb3RhbCA9IGl0ZW0uc3VidG90YWxMZXZlbCA9PT0gJ2QxJzsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAgICAgICAgICAgPHRyCiAgICAgICAgICAgICAgICAgICAgICAgIGtleT17YHN1YnRvdGFsLSR7aWR4fWB9CiAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZT17YGgtMTIgYm9yZGVyLXkgJHtpc0dyYW5kVG90YWwgPyAnYmctaW5kaWdvLTEwMCBib3JkZXItaW5kaWdvLTMwMCBzaGFkb3ctW2luc2V0XzBfMXB4XzBfcmdiYSg5OSwxMDIsMjQxLDAuMzUpXScgOiAnYmctYW1iZXItNTAgYm9yZGVyLWFtYmVyLTIwMCd9YH0KICAgICAgICAgICAgICAgICAgICAgID4KICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGNvbFNwYW49e2l0ZW0ubGFiZWxDb2xTcGFuIHx8IDR9IGNsYXNzTmFtZT17YHB4LTQgcHktMyB3aGl0ZXNwYWNlLW5vd3JhcCAke2lzR3JhbmRUb3RhbCA/ICd0ZXh0LWluZGlnby05MDAgdGV4dC1bMTRweF0gZm9udC1leHRyYWJvbGQnIDogJ3RleHQtYW1iZXItOTAwIGZvbnQtYmxhY2snfWB9PgogICAgICAgICAgICAgICAgICAgICAgICAgIHtpdGVtLnN1YnRvdGFsTGFiZWx9CiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBjbGFzc05hbWU9e2BweC00IHB5LTMgdGV4dC1yaWdodCBmb250LWJsYWNrIHdoaXRlc3BhY2Utbm93cmFwICR7aXNHcmFuZFRvdGFsID8gJ3RleHQtaW5kaWdvLTgwMCB0ZXh0LVsxNHB4XScgOiAndGV4dC1hbWJlci04MDAnfWB9Pntmb3JtYXRXb24oaXRlbS5pbmNvbWUpfTwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBjbGFzc05hbWU9e2BweC00IHB5LTMgdGV4dC1yaWdodCBmb250LWJsYWNrIHdoaXRlc3BhY2Utbm93cmFwICR7aXNHcmFuZFRvdGFsID8gJ3RleHQtaW5kaWdvLTkwMCB0ZXh0LVsxNHB4XScgOiAndGV4dC1hbWJlci05MDAnfWB9Pntmb3JtYXRXb25Sb3VuZGVkKGl0ZW0udG90YWwpfTwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBjbGFzc05hbWU9InB4LTQgcHktMyI+e3JlbmRlckNvc3RCcmVha2Rvd25UYWJsZShpdGVtLmNvc3RCcmVha2Rvd24pfTwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBjbGFzc05hbWU9InB4LTQgcHktMyI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9e2Bncm91cCByZWxhdGl2ZSBoLTIuNSByb3VuZGVkLWZ1bGwgb3ZlcmZsb3ctdmlzaWJsZSBmbGV4IHNoYWRvdy1pbm5lciAke2lzR3JhbmRUb3RhbCA/ICdiZy1pbmRpZ28tMjAwLzgwJyA6ICdiZy1hbWJlci0xMDAnfWB9PgogICAgICAgICAgICAgICAgICAgICAgICAgICAge3JlbmRlclBvc2l0aW9uQnJlYWtkb3duVG9vbHRpcChpdGVtLnBvc2l0aW9uQnJlYWtkb3duLCBpdGVtLmhycyl9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7T2JqZWN0LmVudHJpZXMoaXRlbS5wb3NpdGlvbkJyZWFrZG93biB8fCB7fSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnNvcnQoKFthXSwgW2JdKSA9PiAocG9zaXRpb25PcmRlclthXSB8fCA5OSkgLSAocG9zaXRpb25PcmRlcltiXSB8fCA5OSkgfHwgYS5sb2NhbGVDb21wYXJlKGIpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAubWFwKChbcG9zLCB2YWxdKSA9PiB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcmF0aW8gPSAodmFsIC8gKGl0ZW0uaHJzIHx8IDEpKSAqIDEwMDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocmF0aW8gPCAwLjEpIHJldHVybiBudWxsOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiA8ZGl2IGtleT17cG9zfSBjbGFzc05hbWU9ImgtZnVsbCIgc3R5bGU9e3sgd2lkdGg6IGAke3JhdGlvfSVgLCBiYWNrZ3JvdW5kQ29sb3I6IGdldFBvc2l0aW9uQ29sb3IocG9zKSB9fT48L2Rpdj47CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pfQogICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgICA8dGQgY2xhc3NOYW1lPXtgcHgtNCBweS0zIHRleHQtY2VudGVyIHdoaXRlc3BhY2Utbm93cmFwIGZvbnQtYmxhY2sgJHtpc0dyYW5kVG90YWwgPyAndGV4dC1pbmRpZ28tOTAwIHRleHQtWzE0cHhdJyA6ICd0ZXh0LWFtYmVyLTkwMCd9YH0+e2l0ZW0ud29ya2Vyc33rqoU8L3RkPgogICAgICAgICAgICAgICAgICAgICAgPC90cj4KICAgICAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAgICAgICAgIDx0ciBrZXk9e2Byb3ctJHtpZHh9YH0gY2xhc3NOYW1lPSJoLTEyIGhvdmVyOmJnLWluZGlnby01MC8zMCB0cmFuc2l0aW9uLWFsbCBib3JkZXItYiBib3JkZXItc2xhdGUtNTAgZ3JvdXAiPgogICAgICAgICAgICAgICAgICAgICAge2l0ZW0uZDFTcGFuID4gMCAmJiAoCiAgICAgICAgICAgICAgICAgICAgICAgIDx0ZAogICAgICAgICAgICAgICAgICAgICAgICAgIHJvd1NwYW49e2l0ZW0uZDFTcGFufQogICAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2xpY2s9eygpID0+IGhhbmRsZUQxQ2xpY2soaXRlbS5kMSl9CiAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lPXtgcHgtMyBweS0zIGJvcmRlci1yIGJvcmRlci1zbGF0ZS0xMDAgYWxpZ24tbWlkZGxlIGZvbnQtYmxhY2sgY3Vyc29yLXBvaW50ZXIgdHJhbnNpdGlvbi1jb2xvcnMgd2hpdGVzcGFjZS1ub3dyYXAgJHtzZWxlY3RlZFJldiA9PT0gaXRlbS5kMSA/ICdiZy1pbmRpZ28tNjAwIHRleHQtd2hpdGUnIDogJ2JnLXdoaXRlIHRleHQtaW5kaWdvLTYwMCBob3ZlcjpiZy1pbmRpZ28tNTAgaG92ZXI6dGV4dC1pbmRpZ28tODAwJ31gfQogICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3NOYW1lPSJibG9jayB0cnVuY2F0ZSI+e2l0ZW0uZDF9PC9zcGFuPgogICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgKX0KICAgICAgICAgICAgICAgICAgICAgIHtpdGVtLmQyU3BhbiA+IDAgJiYgKAogICAgICAgICAgICAgICAgICAgICAgICA8dGQKICAgICAgICAgICAgICAgICAgICAgICAgICByb3dTcGFuPXtpdGVtLmQyU3Bhbn0KICAgICAgICAgICAgICAgICAgICAgICAgICBvbkNsaWNrPXsoKSA9PiBoYW5kbGVEMkNsaWNrKGl0ZW0uZDEsIGl0ZW0uZDIpfQogICAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZT17YHB4LTMgcHktMyBib3JkZXItciBib3JkZXItc2xhdGUtMTAwIGFsaWduLW1pZGRsZSBmb250LWJsYWNrIGN1cnNvci1wb2ludGVyIHRyYW5zaXRpb24tY29sb3JzIHdoaXRlc3BhY2Utbm93cmFwICR7c2VsZWN0ZWRSZXYgPT09IGl0ZW0uZDEgJiYgc2VsZWN0ZWREMSA9PT0gaXRlbS5kMiA/ICdiZy1pbmRpZ28tNjAwIHRleHQtd2hpdGUnIDogJ2JnLXdoaXRlIHRleHQtaW5kaWdvLTYwMCBob3ZlcjpiZy1pbmRpZ28tNTAgaG92ZXI6dGV4dC1pbmRpZ28tODAwJ31gfQogICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3NOYW1lPSJibG9jayB0cnVuY2F0ZSI+e2l0ZW0uZDJ9PC9zcGFuPgogICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgKX0KICAgICAgICAgICAgICAgICAgICAgIHtpdGVtLmQzU3BhbiA+IDAgJiYgKAogICAgICAgICAgICAgICAgICAgICAgICA8dGQKICAgICAgICAgICAgICAgICAgICAgICAgICByb3dTcGFuPXtpdGVtLmQzU3Bhbn0KICAgICAgICAgICAgICAgICAgICAgICAgICBvbkNsaWNrPXsoKSA9PiBoYW5kbGVEM0NsaWNrKGl0ZW0uZDEsIGl0ZW0uZDIsIGl0ZW0uZDMpfQogICAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZT17YHB4LTMgcHktMyBib3JkZXItciBib3JkZXItc2xhdGUtMTAwIGFsaWduLW1pZGRsZSBmb250LWJsYWNrIGN1cnNvci1wb2ludGVyIHRyYW5zaXRpb24tY29sb3JzIHdoaXRlc3BhY2Utbm93cmFwICR7c2VsZWN0ZWRSZXYgPT09IGl0ZW0uZDEgJiYgc2VsZWN0ZWREMSA9PT0gaXRlbS5kMiAmJiBzZWxlY3RlZEQyID09PSBpdGVtLmQzID8gJ2JnLWluZGlnby02MDAgdGV4dC13aGl0ZScgOiAnYmctd2hpdGUgdGV4dC1pbmRpZ28tNjAwIGhvdmVyOmJnLWluZGlnby01MCBob3Zlcjp0ZXh0LWluZGlnby04MDAnfWB9CiAgICAgICAgICAgICAgICAgICAgICAgID4KICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzc05hbWU9ImJsb2NrIHRydW5jYXRlIj57aXRlbS5kM308L3NwYW4+CiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICApfQogICAgICAgICAgICAgICAgICAgICAgeyF2aWV3RGF0YS5pc0FsbEZpbHRlcnNPZmYgJiYgKAogICAgICAgICAgICAgICAgICAgICAgICA8dGQKICAgICAgICAgICAgICAgICAgICAgICAgICBvbkNsaWNrPXsoKSA9PiBoYW5kbGVENENsaWNrKGl0ZW0uZDEsIGl0ZW0uZDIsIGl0ZW0uZDMsIGl0ZW0ubmFtZSl9CiAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lPSJweC00IHB5LTMgdHJ1bmNhdGUgdGV4dC1zbGF0ZS03MDAgY3Vyc29yLXBvaW50ZXIgaG92ZXI6YmctaW5kaWdvLTUwIGhvdmVyOnRleHQtaW5kaWdvLTgwMCB0cmFuc2l0aW9uLWNvbG9ycyIKICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgIHtpdGVtLm5hbWV9CiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICApfQogICAgICAgICAgICAgICAgICAgICAgPHRkIGNsYXNzTmFtZT0icHgtNCBweS0zIHRleHQtcmlnaHQgdGV4dC1pbmRpZ28tNjAwIGZvbnQtYmxhY2sgd2hpdGVzcGFjZS1ub3dyYXAiPntmb3JtYXRXb24oaXRlbS5pbmNvbWUpfTwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICA8dGQgY2xhc3NOYW1lPSJweC00IHB5LTMgdGV4dC1yaWdodCBmb250LWJsYWNrIHdoaXRlc3BhY2Utbm93cmFwIj57Zm9ybWF0V29uUm91bmRlZChpdGVtLnRvdGFsKX08L3RkPgogICAgICAgICAgICAgICAgICAgICAgPHRkIGNsYXNzTmFtZT0icHgtNCBweS0zIj57cmVuZGVyQ29zdEJyZWFrZG93blRhYmxlKGl0ZW0uY29zdEJyZWFrZG93bil9PC90ZD4KICAgICAgICAgICAgICAgICAgICAgIDx0ZCBjbGFzc05hbWU9InB4LTQgcHktMyI+CiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPSJncm91cCByZWxhdGl2ZSBoLTIuNSBiZy1zbGF0ZS0xMDAgcm91bmRlZC1mdWxsIG92ZXJmbG93LXZpc2libGUgZmxleCBzaGFkb3ctaW5uZXIiPgogICAgICAgICAgICAgICAgICAgICAgICAgIHtyZW5kZXJQb3NpdGlvbkJyZWFrZG93blRvb2x0aXAoaXRlbS5wb3NpdGlvbkJyZWFrZG93biwgaXRlbS5ocnMpfQogICAgICAgICAgICAgICAgICAgICAgICAgIHtPYmplY3QuZW50cmllcyhpdGVtLnBvc2l0aW9uQnJlYWtkb3duIHx8IHt9KQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLnNvcnQoKFthXSwgW2JdKSA9PiAocG9zaXRpb25PcmRlclthXSB8fCA5OSkgLSAocG9zaXRpb25PcmRlcltiXSB8fCA5OSkgfHwgYS5sb2NhbGVDb21wYXJlKGIpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLm1hcCgoW3BvcywgdmFsXSkgPT4gewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCByYXRpbyA9ICh2YWwgLyAoaXRlbS5ocnMgfHwgMSkpICogMTAwOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocmF0aW8gPCAwLjEpIHJldHVybiBudWxsOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gPGRpdiBrZXk9e3Bvc30gY2xhc3NOYW1lPSJoLWZ1bGwiIHN0eWxlPXt7IHdpZHRoOiBgJHtyYXRpb30lYCwgYmFja2dyb3VuZENvbG9yOiBnZXRQb3NpdGlvbkNvbG9yKHBvcykgfX0+PC9kaXY+OwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfSl9CiAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICAgICAgICAgICAgPC90ZD4KICAgICAgICAgICAgICAgICAgICAgIDx0ZCBjbGFzc05hbWU9InB4LTQgcHktMyB0ZXh0LWNlbnRlciB3aGl0ZXNwYWNlLW5vd3JhcCI+e2l0ZW0ud29ya2Vyc33rqoU8L3RkPgogICAgICAgICAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgICB9KX0KICAgICAgICAgICAgICA8L3Rib2R5PgogICAgICAgICAgICA8L3RhYmxlPgogICAgICAgICAgPC9kaXY+CiAgICAgICAgPC9zZWN0aW9uPgoKICAgICAgICB7Lyog7ZWY64uoIOyDgeyEuCDssKjtirggKi99CiAgICAgICAgPGRpdiBjbGFzc05hbWU9ImdyaWQgZ3JpZC1jb2xzLTEgbGc6Z3JpZC1jb2xzLTEyIGdhcC02IHBiLTEyIj4KICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPSJsZzpjb2wtc3Bhbi01IGJnLXdoaXRlIHAtOCByb3VuZGVkLVs0MHB4XSBzaGFkb3ctc20gYm9yZGVyIGJvcmRlci1zbGF0ZS0xMDAgbWluLWgtWzQ4MHB4XSBmbGV4IGZsZXgtY29sIj4KICAgICAgICAgICAgIDxoMyBjbGFzc05hbWU9InRleHQtbGcgZm9udC1ibGFjayBtYi02IGZsZXggaXRlbXMtY2VudGVyIGdhcC0zIj48VGFyZ2V0IGNsYXNzTmFtZT0idGV4dC1pbmRpZ28tNjAwIi8+IOyngOy2nCDqtazshLEg7IOB7IS4PC9oMz4KICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPSJmbGV4LTEiPgogICAgICAgICAgICAgICB7dmlld0RhdGEuY2F0ZWdvcnlEYXRhLmxlbmd0aCA+IDAgPyAoCiAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9ImgtZnVsbCBmbGV4IGZsZXgtY29sIGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciBnYXAtNiI+CiAgICAgICAgICAgICAgICAgICA8ZGl2CiAgICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZT0icmVsYXRpdmUgaC02NCB3LTY0IHJvdW5kZWQtZnVsbCIKICAgICAgICAgICAgICAgICAgICAgc3R5bGU9e3sgYmFja2dyb3VuZDogYnVpbGREb251dEdyYWRpZW50KHZpZXdEYXRhLmNhdGVnb3J5RGF0YSkgfX0KICAgICAgICAgICAgICAgICAgID4KICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9ImFic29sdXRlIGluc2V0LTEyIHJvdW5kZWQtZnVsbCBiZy13aGl0ZSBib3JkZXIgYm9yZGVyLXNsYXRlLTEwMCBmbGV4IGZsZXgtY29sIGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciI+CiAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3NOYW1lPSJ0ZXh0LVsxM3B4XSBmb250LWJsYWNrIHRleHQtc2xhdGUtNTAwIj7stJ0g7KeA7LacPC9zcGFuPgogICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzTmFtZT0idGV4dC1bMTZweF0gZm9udC1ibGFjayB0ZXh0LXNsYXRlLTkwMCI+CiAgICAgICAgICAgICAgICAgICAgICAgICB7Zm9ybWF0V29uKHZpZXdEYXRhLmNhdGVnb3J5RGF0YS5yZWR1Y2UoKHN1bSwgaXRlbSkgPT4gc3VtICsgKGl0ZW0udmFsdWUgfHwgMCksIDApKX0KICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4+CiAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT0idy1mdWxsIGdyaWQgZ3JpZC1jb2xzLTEgZ2FwLXktMiI+CiAgICAgICAgICAgICAgICAgICAgIHt2aWV3RGF0YS5jYXRlZ29yeURhdGEubWFwKChpdGVtKSA9PiB7CiAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgaXNTZWxlY3RhYmxlID0gaXRlbS5uYW1lICE9PSAn7J246rG067mEJzsKICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBpc1NlbGVjdGVkID0gc2VsZWN0ZWRFeHBlbnNlRGV0YWlsQ2F0ZWdvcnkgPT09IGl0ZW0ubmFtZTsKICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAgICAgICAgICAgICAgPGJ1dHRvbgogICAgICAgICAgICAgICAgICAgICAgICAgICBrZXk9e2l0ZW0ubmFtZX0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZT0iYnV0dG9uIgogICAgICAgICAgICAgICAgICAgICAgICAgICBvbkNsaWNrPXsoKSA9PiB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFpc1NlbGVjdGFibGUpIHJldHVybjsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXRTZWxlY3RlZEV4cGVuc2VEZXRhaWxDYXRlZ29yeSgocHJldikgPT4gKHByZXYgPT09IGl0ZW0ubmFtZSA/ICcnIDogaXRlbS5uYW1lKSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgIH19CiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZT17YGZsZXggaXRlbXMtY2VudGVyIGp1c3RpZnktYmV0d2VlbiBnYXAtMiB0ZXh0LVsxM3B4XSBmb250LWJvbGQgdGV4dC1sZWZ0IHJvdW5kZWQtbGcgcHgtMiBweS0xLjUgdHJhbnNpdGlvbi1jb2xvcnMgJHtpc1NlbGVjdGFibGUgPyAnaG92ZXI6Ymctc2xhdGUtNTAgY3Vyc29yLXBvaW50ZXInIDogJ2N1cnNvci1kZWZhdWx0J30gJHtpc1NlbGVjdGVkID8gJ2JnLWluZGlnby01MCcgOiAnJ31gfQogICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzc05hbWU9ImZsZXggaXRlbXMtY2VudGVyIGdhcC0yIHRleHQtc2xhdGUtNjAwIHRydW5jYXRlIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3NOYW1lPSJpbmxpbmUtYmxvY2sgdy0yLjUgaC0yLjUgcm91bmRlZC1mdWxsIHNocmluay0wIiBzdHlsZT17eyBiYWNrZ3JvdW5kQ29sb3I6IGdldENvc3RDb2xvcihpdGVtLm5hbWUpIH19Pjwvc3Bhbj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge2l0ZW0ubmFtZX0gKHtpdGVtLnJhdGlvfSUpCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3NOYW1lPSJ0ZXh0LXNsYXRlLTkwMCI+e2Zvcm1hdFdvbihpdGVtLnZhbHVlKX08L3NwYW4+CiAgICAgICAgICAgICAgICAgICAgICAgICA8L2J1dHRvbj4KICAgICAgICAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgICAgICAgICB9KX0KICAgICAgICAgICAgICAgICAgIDwvZGl2PgoKICAgICAgICAgICAgICAgICAgIHt2aWV3RGF0YS5pc0FsbEZpbHRlcnNPZmYgJiYgKAogICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT0idy1mdWxsIG10LTQgdGV4dC1bMTJweF0gdGV4dC1zbGF0ZS00MDAgZm9udC1ib2xkIHRleHQtY2VudGVyIj4KICAgICAgICAgICAgICAgICAgICAgICDsg4HshLgg64K07Jet7J2AIO2VhO2EsCDsoIHsmqkg7IucIO2RnOyLnOuQqeuLiOuLpC4KICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgICAgICAgICApfQoKICAgICAgICAgICAgICAgICAgIHshdmlld0RhdGEuaXNBbGxGaWx0ZXJzT2ZmICYmIHNlbGVjdGVkRXhwZW5zZURldGFpbENhdGVnb3J5ICYmIHNlbGVjdGVkRXhwZW5zZURldGFpbENhdGVnb3J5ICE9PSAn7J246rG067mEJyAmJiAoCiAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPSJ3LWZ1bGwgbXQtNSBwdC00IGJvcmRlci10IGJvcmRlci1zbGF0ZS0xMDAiPgogICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPSJ0ZXh0LVsxMnB4XSBmb250LWJsYWNrIHRleHQtc2xhdGUtNjAwIG1iLTIiPgogICAgICAgICAgICAgICAgICAgICAgICAge3NlbGVjdGVkRXhwZW5zZURldGFpbENhdGVnb3J5fSDsp4Dstpwg6rWs7ISxIOyDgeyEuCDrgrTsl60KICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgICAgICAgICAgICB7KHZpZXdEYXRhLmV4cGVuc2VEZXRhaWxCeUNhdGVnb3J5Py5bc2VsZWN0ZWRFeHBlbnNlRGV0YWlsQ2F0ZWdvcnldIHx8IFtdKS5sZW5ndGggPiAwID8gKAogICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9Im1heC1oLTU2IG92ZXJmbG93LXktYXV0byByb3VuZGVkLWxnIGJvcmRlciBib3JkZXItc2xhdGUtMTAwIGN1c3RvbS1zY3JvbGxiYXIiPgogICAgICAgICAgICAgICAgICAgICAgICAgICA8dGFibGUgY2xhc3NOYW1lPSJ3LWZ1bGwgdGV4dC1bMTJweF0gdGFibGUtZml4ZWQgYm9yZGVyLWNvbGxhcHNlIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGhlYWQgY2xhc3NOYW1lPSJiZy1zbGF0ZS01MCB0ZXh0LXNsYXRlLTUwMCBmb250LWJsYWNrIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRoIGNsYXNzTmFtZT0icHgtMiBweS0yIHRleHQtbGVmdCB3LVs4OHB4XSI+67Cc7ZaJ7J28PC90aD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRoIGNsYXNzTmFtZT0icHgtMiBweS0yIHRleHQtbGVmdCB3LVsxNzBweF0iPuyCrOyXheuqhTwvdGg+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0aCBjbGFzc05hbWU9InB4LTIgcHktMiB0ZXh0LWxlZnQiPuyggeyalDwvdGg+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0aCBjbGFzc05hbWU9InB4LTIgcHktMiB0ZXh0LXJpZ2h0IHctWzkwcHhdIj7quIjslaE8L3RoPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RoZWFkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsodmlld0RhdGEuZXhwZW5zZURldGFpbEJ5Q2F0ZWdvcnlbc2VsZWN0ZWRFeHBlbnNlRGV0YWlsQ2F0ZWdvcnldIHx8IFtdKS5tYXAoKHJvdywgaWR4KSA9PiAoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ciBrZXk9e2Ake3NlbGVjdGVkRXhwZW5zZURldGFpbENhdGVnb3J5fS0ke2lkeH1gfSBjbGFzc05hbWU9ImJvcmRlci10IGJvcmRlci1zbGF0ZS01MCB0ZXh0LXNsYXRlLTcwMCI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGNsYXNzTmFtZT0icHgtMiBweS0xLjUgd2hpdGVzcGFjZS1ub3dyYXAiPntyb3cuaXNzdWVEYXRlIHx8ICctJ308L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBjbGFzc05hbWU9InB4LTIgcHktMS41IHRydW5jYXRlIj57cm93LnByb2plY3ROYW1lIHx8ICctJ308L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBjbGFzc05hbWU9InB4LTIgcHktMS41IHRydW5jYXRlIj57cm93LnN1bW1hcnkgfHwgJy0nfTwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGNsYXNzTmFtZT0icHgtMiBweS0xLjUgdGV4dC1yaWdodCB3aGl0ZXNwYWNlLW5vd3JhcCI+e2Zvcm1hdFdvblJvdW5kZWQocm93LmFtb3VudCl9PC90ZD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk+CiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGFibGU+CiAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgICAgICAgICAgICApIDogKAogICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9InRleHQtWzEycHhdIHRleHQtc2xhdGUtNDAwIGZvbnQtYm9sZCI+7ZGc7Iuc7ZWgIOyghO2RnCDrjbDsnbTthLDqsIAg7JeG7Iq164uI64ukLjwvZGl2PgogICAgICAgICAgICAgICAgICAgICAgICl9CiAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICAgICAgICAgKX0KICAgICAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgICAgKSA6ICgKICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT0iaC1mdWxsIGZsZXggaXRlbXMtY2VudGVyIGp1c3RpZnktY2VudGVyIHRleHQtc2xhdGUtMzAwIHRleHQtc20gZm9udC1ib2xkIj7tkZzsi5ztlaAg7KeA7LacIOuNsOydtO2EsOqwgCDsl4bsirXri4jri6QuPC9kaXY+CiAgICAgICAgICAgICAgICl9CiAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9ImxnOmNvbC1zcGFuLTcgYmctd2hpdGUgcC04IHJvdW5kZWQtWzQwcHhdIHNoYWRvdy1zbSBib3JkZXIgYm9yZGVyLXNsYXRlLTEwMCBmbGV4IGZsZXgtY29sIGgtWzU2MHB4XSBvdmVyZmxvdy1oaWRkZW4iPgogICAgICAgICAgICAgPGgzIGNsYXNzTmFtZT0idGV4dC1sZyBmb250LWJsYWNrIG1iLTYgZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTMgc2hyaW5rLTAiPgogICAgICAgICAgICAgICA8VXNlckNoZWNrIGNsYXNzTmFtZT0idGV4dC1pbmRpZ28tNjAwIi8+IOyngeq4ieuzhCDsnbjsm5Ag7Yis7J6FIOyDgeyEuAogICAgICAgICAgICAgICA8c3BhbiBjbGFzc05hbWU9Im1sLTEgdGV4dC1bMTFweF0gZm9udC1ibGFjayB0ZXh0LWluZGlnby02MDAgYmctaW5kaWdvLTUwIGJvcmRlciBib3JkZXItaW5kaWdvLTEwMCBweC0yIHB5LTEgcm91bmRlZC1sZyI+CiAgICAgICAgICAgICAgICAg6riw7KSAOiB7dmlld0RhdGEucG9zaXRpb25Hcm91cE1vZGV9CiAgICAgICAgICAgICAgIDwvc3Bhbj4KICAgICAgICAgICAgIDwvaDM+CiAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9ImZsZXgtMSBvdmVyZmxvdy15LWF1dG8gcHItMiBjdXN0b20tc2Nyb2xsYmFyIj4KICAgICAgICAgICAgICAgIHtPYmplY3Qua2V5cyh2aWV3RGF0YS5wb3NpdGlvbkFuYWx5c2lzKS5sZW5ndGggPiAwID8gKAogICAgICAgICAgICAgICAgICBPYmplY3QuZW50cmllcyh2aWV3RGF0YS5wb3NpdGlvbkFuYWx5c2lzKQogICAgICAgICAgICAgICAgICAgIC5zb3J0KChbYV0sIFtiXSkgPT4gewogICAgICAgICAgICAgICAgICAgICAgaWYgKHZpZXdEYXRhLnBvc2l0aW9uR3JvdXBNb2RlID09PSAnRDEnKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAoKGQxT3JkZXJbYV0gfHwgOTkpIC0gKGQxT3JkZXJbYl0gfHwgOTkpKSB8fCBhLmxvY2FsZUNvbXBhcmUoYik7CiAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gYS5sb2NhbGVDb21wYXJlKGIpOwogICAgICAgICAgICAgICAgICAgIH0pCiAgICAgICAgICAgICAgICAgICAgLm1hcCgoW3BOYW1lLCBwb3NpdGlvbnNdKSA9PiAoCiAgICAgICAgICAgICAgICAgICAgPGRpdiBrZXk9e3BOYW1lfSBjbGFzc05hbWU9Im1iLTggbGFzdDptYi0wIj4KICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPSJiZy1zbGF0ZS05MDAgcHgtNCBweS0xLjUgcm91bmRlZC14bCB0ZXh0LVsxMnB4XSBmb250LWJsYWNrIHRleHQtd2hpdGUgbWItNCBzdGlja3kgdG9wLTAgei0xMCI+e3BOYW1lfTwvZGl2PgogICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9ImdyaWQgZ3JpZC1jb2xzLTEgZ2FwLTMiPgogICAgICAgICAgICAgICAgICAgICAgIHtPYmplY3QuZW50cmllcyhwb3NpdGlvbnMpCiAgICAgICAgICAgICAgICAgICAgICAgICAuc29ydCgoW2FdLCBbYl0pID0+IChwb3NpdGlvbk9yZGVyW2FdIHx8IDk5KSAtIChwb3NpdGlvbk9yZGVyW2JdIHx8IDk5KSB8fCBhLmxvY2FsZUNvbXBhcmUoYikpCiAgICAgICAgICAgICAgICAgICAgICAgICAubWFwKChbcG9zLCBkYXRhXSkgPT4gewogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHN0eWxlID0gZ2V0UG9zaXRpb25TdHlsZShwb3MpOwogICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYga2V5PXtwb3N9IGNsYXNzTmFtZT17YGJnLXdoaXRlIGJvcmRlciAke3N0eWxlLmJvcmRlcn0gcm91bmRlZC1bMjhweF0gcC01IGZsZXggaXRlbXMtY2VudGVyIGdhcC02IGhvdmVyOnNoYWRvdy1tZCB0cmFuc2l0aW9uLWFsbGB9PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT17YGZsZXggaXRlbXMtY2VudGVyIGdhcC0zIHctMS80IHNocmluay0wIHB4LTQgcHktMiByb3VuZGVkLTJ4bCAke3N0eWxlLmJnfSBib3JkZXIgJHtzdHlsZS5ib3JkZXJ9YH0+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPXtgdy0zIGgtMyByb3VuZGVkLWZ1bGwgJHtzdHlsZS5pY29ufSBzaGFkb3ctc21gfT48L2Rpdj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9e2B0ZXh0LVsxNHB4XSBmb250LWJsYWNrICR7c3R5bGUudGV4dH1gfT57cG9zfTwvZGl2PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9ImZsZXgtMSBncmlkIGdyaWQtY29scy0yIGdhcC04IGJvcmRlci1sIGJvcmRlci1zbGF0ZS0xMDAgcGwtOCI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXY+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9InRleHQtWzExcHhdIHRleHQtc2xhdGUtNDAwIGZvbnQtYmxhY2sgdXBwZXJjYXNlIG1iLTEiPkVzdGltYXRlZCBDb3N0PC9kaXY+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9InRleHQtWzE2cHhdIGZvbnQtYmxhY2sgdGV4dC1pbmRpZ28tNjAwIGZvbnQtbW9ubyI+4oKpe01hdGgucm91bmQoZGF0YS5sYWJvcikudG9Mb2NhbGVTdHJpbmcoKX08L2Rpdj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXY+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9InRleHQtWzExcHhdIHRleHQtc2xhdGUtNDAwIGZvbnQtYmxhY2sgdXBwZXJjYXNlIG1iLTEiPkhvdXJzICYgQ291bnQ8L2Rpdj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT0idGV4dC1bMTZweF0gZm9udC1ibGFjayB0ZXh0LXNsYXRlLTkwMCI+e2RhdGEuaHJzLnRvRml4ZWQoMil9aCA8c3BhbiBjbGFzc05hbWU9InRleHQtc2xhdGUtMzAwIG14LTEiPnw8L3NwYW4+IHtkYXRhLm5hbWVzLnNpemV966qFPC9kaXY+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9InctMS8zIG1pbi13LVsyNjBweF0gYm9yZGVyLWwgYm9yZGVyLXNsYXRlLTEwMCBwbC00Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT0ib3ZlcmZsb3cteC1hdXRvIG92ZXJmbG93LXktaGlkZGVuIGN1c3RvbS1zY3JvbGxiYXIiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9ImdyaWQgZ3JpZC1yb3dzLTIgZ3JpZC1mbG93LWNvbCBhdXRvLWNvbHMtbWF4IGdhcC14LTEuNSBnYXAteS0xLjUgbWluLXctbWF4IHBiLTEiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7QXJyYXkuZnJvbShkYXRhLm5hbWVzKS5tYXAobmFtZSA9PiAoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4ga2V5PXtuYW1lfSBjbGFzc05hbWU9InB4LTIgcHktMC41IGJnLXNsYXRlLTUwIHRleHQtc2xhdGUtNTAwIHJvdW5kZWQtbGcgdGV4dC1bMTFweF0gZm9udC1ib2xkIGJvcmRlciBib3JkZXItc2xhdGUtMTAwIHdoaXRlc3BhY2Utbm93cmFwIj57bmFtZX08L3NwYW4+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0pfQogICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICAgICAgICkpCiAgICAgICAgICAgICAgICkgOiAoCiAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9ImgtZnVsbCBmbGV4IGZsZXgtY29sIGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciB0ZXh0LXNsYXRlLTMwMCBnYXAtMyI+CiAgICAgICAgICAgICAgICAgICA8SW5mbyBzaXplPXs0MH0gLz4KICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzTmFtZT0idGV4dC1zbSBmb250LWJvbGQiPu2RnOyLnO2VoCDrjbDsnbTthLDqsIAg7JeG7Iq164uI64ukLjwvc3Bhbj4KICAgICAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgICAgKX0KICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgPC9kaXY+CiAgICAgICAgPC9kaXY+CiAgICAgIDwvZGl2PgoKICAgICAgPHN0eWxlPntgCiAgICAgICAgQGltcG9ydCB1cmwoJ2h0dHBzOi8vZm9udHMuZ29vZ2xlYXBpcy5jb20vY3NzMj9mYW1pbHk9UHJldGVuZGFyZDp3Z2h0QDQwMDs2MDA7NzAwOzkwMCZkaXNwbGF5PXN3YXAnKTsKICAgICAgICBib2R5IHsgZm9udC1mYW1pbHk6ICdQcmV0ZW5kYXJkJywgc2Fucy1zZXJpZjsgbGV0dGVyLXNwYWNpbmc6IC0wLjAyNWVtOyAtd2Via2l0LWZvbnQtc21vb3RoaW5nOiBhbnRpYWxpYXNlZDsgYmFja2dyb3VuZC1jb2xvcjogI2Y4ZmFmYzsgfQogICAgICAgIC5maWx0ZXItc2VsZWN0IHsKICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRyYW5zcGFyZW50OyBib3JkZXI6IG5vbmU7IHBhZGRpbmc6IDAuMzVyZW0gMS42cmVtIDAuMzVyZW0gMC41cmVtOyBmb250LXNpemU6IDEwcHg7IGZvbnQtd2VpZ2h0OiA4MDA7CiAgICAgICAgICBvdXRsaW5lOiBub25lOyBhcHBlYXJhbmNlOiBub25lOyBjdXJzb3I6IHBvaW50ZXI7IHRyYW5zaXRpb246IGFsbCAwLjJzOwogICAgICAgICAgYmFja2dyb3VuZC1pbWFnZTogdXJsKCJkYXRhOmltYWdlL3N2Zyt4bWwsJTNDc3ZnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZycgZmlsbD0nbm9uZScgdmlld0JveD0nMCAwIDI0IDI0JyBzdHJva2U9JyUyMzk0YTNiOCclM0UlM0NwYXRoIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCcgc3Ryb2tlLXdpZHRoPScyJyBkPSdNMTkgOWwtNyA3LTctNyclM0UlM0MvcGF0aCUzRSUzQy9zdmclM0UiKTsKICAgICAgICAgIGJhY2tncm91bmQtcmVwZWF0OiBuby1yZXBlYXQ7IGJhY2tncm91bmQtcG9zaXRpb246IHJpZ2h0IDAuNHJlbSBjZW50ZXI7IGJhY2tncm91bmQtc2l6ZTogMC42cmVtOwogICAgICAgIH0KICAgICAgICAuZmlsdGVyLXNlbGVjdDpob3ZlciB7IGNvbG9yOiAjNjM2NmYxOyBiYWNrZ3JvdW5kLWNvbG9yOiB3aGl0ZTsgYm9yZGVyLXJhZGl1czogOHB4OyB9CiAgICAgICAgLmN1c3RvbS1zY3JvbGxiYXI6Oi13ZWJraXQtc2Nyb2xsYmFyIHsgd2lkdGg6IDRweDsgaGVpZ2h0OiA0cHg7IH0KICAgICAgICAuY3VzdG9tLXNjcm9sbGJhcjo6LXdlYmtpdC1zY3JvbGxiYXItdGh1bWIgeyBiYWNrZ3JvdW5kOiAjZTJlOGYwOyBib3JkZXItcmFkaXVzOiAxMHB4OyB9CiAgICAgIGB9PC9zdHlsZT4KICAgIDwvZGl2PgogICk7Cn07Cgpjb25zdCBtb3VudE5vZGUgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncm9vdCcpOwppZiAoUmVhY3RET00uY3JlYXRlUm9vdCkgewogIFJlYWN0RE9NLmNyZWF0ZVJvb3QobW91bnROb2RlKS5yZW5kZXIoPEFwcCAvPik7Cn0gZWxzZSB7CiAgUmVhY3RET00ucmVuZGVyKDxBcHAgLz4sIG1vdW50Tm9kZSk7Cn0KICA8L3NjcmlwdD4KPC9ib2R5Pgo8L2h0bWw+CgoKCgoKCgoKCgoKDQo=';
const MH_HTML_B64 = 'PCFET0NUWVBFIGh0bWw+Cgo8aHRtbCBsYW5nPSJrbyI+Cgo8aGVhZD4KCiAgICA8bWV0YSBjaGFyc2V0PSJVVEYtOCI+CgogICAgPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xLjAiPgoKICAgIDx0aXRsZT5EZk1BIO2MgOuzhC/qsJzsnbjrs4Qg642w7J207YSwIOu2hOyEnSDsi5zsiqTthZw8L3RpdGxlPgoKICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2Nkbi50YWlsd2luZGNzcy5jb20iPjwvc2NyaXB0PgoKICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy94bHN4LzAuMTguNS94bHN4LmZ1bGwubWluLmpzIj48L3NjcmlwdD4KCiAgICA8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCIgc3JjPSJodHRwczovL3d3dy5nc3RhdGljLmNvbS9jaGFydHMvbG9hZGVyLmpzIj48L3NjcmlwdD4KCiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly91bnBrZy5jb20vbHVjaWRlQGxhdGVzdCI+PC9zY3JpcHQ+CgogICAgPHN0eWxlPgogICAgICAgIEBpbXBvcnQgdXJsKCdodHRwczovL2ZvbnRzLmdvb2dsZWFwaXMuY29tL2NzczI/ZmFtaWx5PVByZXRlbmRhcmQ6d2dodEA0MDA7NjAwOzcwMDs5MDAmZGlzcGxheT1zd2FwJyk7CiAgICAgICAgaHRtbCB7IGZvbnQtc2l6ZTogMTRweDsgfQogICAgICAgIGJvZHkgeyBmb250LWZhbWlseTogJ1ByZXRlbmRhcmQnLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDFyZW07IGxpbmUtaGVpZ2h0OiAxLjQ1OyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjhmYWZjOyBsZXR0ZXItc3BhY2luZzogLTAuMDJlbTsgfQogICAgICAgIGlucHV0LCBzZWxlY3QsIGJ1dHRvbiwgdGV4dGFyZWEgeyBmb250OiBpbmhlcml0OyB9CiAgICAgICAgLmdvb2dsZS12aXN1YWxpemF0aW9uLXRvb2x0aXAgewogICAgICAgICAgICBib3JkZXI6IG5vbmUgIWltcG9ydGFudDsKICAgICAgICAgICAgYm9yZGVyLXJhZGl1czogMXJlbSAhaW1wb3J0YW50OwogICAgICAgICAgICBib3gtc2hhZG93OiAwIDIwcHggMjVweCAtNXB4IHJnYigwIDAgMCAvIDAuMSkgIWltcG9ydGFudDsKCiAgICAgICAgICAgIHBhZGRpbmc6IDFyZW0gIWltcG9ydGFudDsKCiAgICAgICAgfQoKICAgICAgICAuY3VzdG9tLXNjcm9sbGJhcjo6LXdlYmtpdC1zY3JvbGxiYXIgeyB3aWR0aDogNnB4OyB9CgogICAgICAgIC5jdXN0b20tc2Nyb2xsYmFyOjotd2Via2l0LXNjcm9sbGJhci10cmFjayB7IGJhY2tncm91bmQ6ICNmMWY1Zjk7IH0KCiAgICAgICAgLmN1c3RvbS1zY3JvbGxiYXI6Oi13ZWJraXQtc2Nyb2xsYmFyLXRodW1iIHsgYmFja2dyb3VuZDogI2NiZDVlMTsgYm9yZGVyLXJhZGl1czogMTBweDsgfQoKCgogICAgICAgICNzZWFyY2gtZHJvcGRvd24gewoKICAgICAgICAgICAgbWF4LWhlaWdodDogMzAwcHg7CgogICAgICAgICAgICBvdmVyZmxvdy15OiBhdXRvOwoKICAgICAgICAgICAgei1pbmRleDogMTAwMDsKCiAgICAgICAgfQoKICAgIDwvc3R5bGU+Cgo8L2hlYWQ+Cgo8Ym9keSBjbGFzcz0icC0zIG1kOnAtNCI+CgoKICAgIDxpbnB1dCBpZD0iZmlsZS1pbnB1dCIgdHlwZT0iZmlsZSIgY2xhc3M9ImhpZGRlbiIgYWNjZXB0PSIueGxzeCwgLnhscyI+CgogICAgPGRpdiBpZD0icHJvamVjdC1tZW1iZXJzLW1vZGFsIiBjbGFzcz0iaGlkZGVuIGZpeGVkIGluc2V0LTAgei1bMTAwXSBmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciBwLTQiPgogICAgICAgIDxkaXYgY2xhc3M9ImFic29sdXRlIGluc2V0LTAgYmctc2xhdGUtOTAwLzYwIGJhY2tkcm9wLWJsdXItc20iIG9uY2xpY2s9ImNsb3NlUHJvamVjdE1vZGFsKCkiPjwvZGl2PgoKICAgICAgICA8ZGl2IGNsYXNzPSJiZy13aGl0ZSByb3VuZGVkLVsyLjVyZW1dIHNoYWRvdy0yeGwgdy1mdWxsIG1heC13LWxnIG92ZXJmbG93LWhpZGRlbiByZWxhdGl2ZSB6LTEwIGFuaW1hdGUtaW4gem9vbS1pbiBkdXJhdGlvbi0zMDAiPgoKICAgICAgICAgICAgPGRpdiBjbGFzcz0icC04IGJvcmRlci1iIGJnLXNsYXRlLTUwLzUwIGZsZXggaXRlbXMtY2VudGVyIGp1c3RpZnktYmV0d2VlbiI+CgogICAgICAgICAgICAgICAgPGRpdj4KCiAgICAgICAgICAgICAgICAgICAgPGgzIGlkPSJtb2RhbC1wcm9qZWN0LXRpdGxlIiBjbGFzcz0idGV4dC14bCBmb250LWJsYWNrIHRleHQtc2xhdGUtOTAwIGxlYWRpbmctdGlnaHQiPu2UhOuhnOygne2KuCDssLjsl6wg66qF64uoPC9oMz4KCiAgICAgICAgICAgICAgICAgICAgPHAgaWQ9Im1vZGFsLXByb2plY3QtY291bnQiIGNsYXNzPSJ0ZXh0LXNtIHRleHQtc2xhdGUtNDAwIGZvbnQtYm9sZCBtdC0xIj7stJ0gMOuqhSDssLjsl6wg7KSRPC9wPgoKICAgICAgICAgICAgICAgIDwvZGl2PgoKICAgICAgICAgICAgICAgIDxidXR0b24gb25jbGljaz0iY2xvc2VQcm9qZWN0TW9kYWwoKSIgY2xhc3M9InAtMiBob3ZlcjpiZy1zbGF0ZS0yMDAgcm91bmRlZC1mdWxsIHRyYW5zaXRpb24tY29sb3JzIHRleHQtc2xhdGUtNDAwIGhvdmVyOnRleHQtc2xhdGUtNjAwIj4KCiAgICAgICAgICAgICAgICAgICAgPGkgZGF0YS1sdWNpZGU9IngiIHNpemU9IjI0Ij48L2k+CgogICAgICAgICAgICAgICAgPC9idXR0b24+CgogICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgIDxkaXYgaWQ9Im1vZGFsLW1lbWJlcnMtbGlzdCIgY2xhc3M9InAtOCBtYXgtaC1bNjB2aF0gb3ZlcmZsb3cteS1hdXRvIGN1c3RvbS1zY3JvbGxiYXIgZmxleCBmbGV4LWNvbCBnYXAtMiI+CgogICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgIDxkaXYgY2xhc3M9InAtNiBiZy1zbGF0ZS01MC81MCBib3JkZXItdCBmbGV4IGp1c3RpZnktZW5kIj4KCiAgICAgICAgICAgICAgICA8YnV0dG9uIG9uY2xpY2s9ImNsb3NlUHJvamVjdE1vZGFsKCkiIGNsYXNzPSJweC02IHB5LTIuNSBiZy1zbGF0ZS05MDAgdGV4dC13aGl0ZSByb3VuZGVkLXhsIGZvbnQtYmxhY2sgdGV4dC1zbSBob3ZlcjpiZy1zbGF0ZS04MDAgdHJhbnNpdGlvbi1hbGwiPuuLq+q4sDwvYnV0dG9uPgoKICAgICAgICAgICAgPC9kaXY+CgogICAgICAgIDwvZGl2PgoKICAgIDwvZGl2PgoKCgogICAgPGRpdiBpZD0idGFiLXRlYW0tcGVyc29uYWwtcGFuZSIgY2xhc3M9InctZnVsbCBhbmltYXRlLWluIGZhZGUtaW4gZHVyYXRpb24tNzAwIj4KICAgICAgICA8ZGl2IGNsYXNzPSJiZy13aGl0ZSByb3VuZGVkLVsycmVtXSBzaGFkb3cteGwgYm9yZGVyIGJvcmRlci1zbGF0ZS0yMDAgcC00IG1iLTggc3RpY2t5IHRvcC0zIHotNTAgYmFja2Ryb3AtYmx1ci14bCBiZy13aGl0ZS85NSI+CiAgICAgICAgICAgIDxoMSBpZD0ibWFpbi10aXRsZSIgY2xhc3M9ImhpZGRlbiI+PC9oMT4KICAgICAgICAgICAgPGRpdiBjbGFzcz0iYmctc2xhdGUtNTAvODAgcC0yIHJvdW5kZWQtMnhsIGJvcmRlciBib3JkZXItc2xhdGUtMjAwIGdyaWQgZ3JpZC1jb2xzLTEgbGc6Z3JpZC1jb2xzLVsxLjJmcl8xZnJfMWZyX2F1dG9dIGdhcC0yIGl0ZW1zLWNlbnRlciI+CiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJyZWxhdGl2ZSI+CiAgICAgICAgICAgICAgICAgICAgPGlucHV0IHR5cGU9InRleHQiIGlkPSJtYWluLXNlYXJjaCIgYXV0b2NvbXBsZXRlPSJvZmYiIHBsYWNlaG9sZGVyPSLtjIAg65iQ64qUIOydtOumhCDqsoDsg4kiIGNsYXNzPSJ3LWZ1bGwgYmctd2hpdGUgYm9yZGVyIGJvcmRlci1zbGF0ZS0yMDAgcm91bmRlZC14bCBweC00IHB5LTIuNSB0ZXh0LXNtIGZvbnQtYm9sZCBvdXRsaW5lLW5vbmUgdGV4dC1zbGF0ZS03MDAgZm9jdXM6Ym9yZGVyLWluZGlnby0zMDAiPgogICAgICAgICAgICAgICAgICAgIDxkaXYgaWQ9InNlYXJjaC1kcm9wZG93biIgY2xhc3M9ImhpZGRlbiBhYnNvbHV0ZSB0b3AtZnVsbCBsZWZ0LTAgdy1mdWxsIG10LTIgYmctd2hpdGUgYm9yZGVyIGJvcmRlci1zbGF0ZS0yMDAgcm91bmRlZC0yeGwgc2hhZG93LTJ4bCBvdmVyZmxvdy1oaWRkZW4gY3VzdG9tLXNjcm9sbGJhciI+CiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgaWQ9InNlYXJjaC1yZXN1bHRzLWxpc3QiIGNsYXNzPSJweS0yIj48L2Rpdj4KICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICAgICAgPHNlbGVjdCBpZD0idGVhbS1zZWxlY3QiIGNsYXNzPSJiZy13aGl0ZSBib3JkZXIgYm9yZGVyLXNsYXRlLTIwMCByb3VuZGVkLXhsIHB4LTQgcHktMi41IHRleHQtc20gZm9udC1ibGFjayBvdXRsaW5lLW5vbmUgY3Vyc29yLXBvaW50ZXIgdGV4dC1zbGF0ZS03MDAgdy1mdWxsIj4KICAgICAgICAgICAgICAgICAgICA8b3B0aW9uIHZhbHVlPSIiPu2MgCDshKDtg508L29wdGlvbj4KICAgICAgICAgICAgICAgIDwvc2VsZWN0PgogICAgICAgICAgICAgICAgPHNlbGVjdCBpZD0icGVyc29uLXNlbGVjdCIgY2xhc3M9ImJnLXdoaXRlIGJvcmRlciBib3JkZXItc2xhdGUtMjAwIHJvdW5kZWQteGwgcHgtNCBweS0yLjUgdGV4dC1zbSBmb250LWJsYWNrIG91dGxpbmUtbm9uZSBjdXJzb3ItcG9pbnRlciB0ZXh0LWJsdWUtNjAwIHctZnVsbCI+CiAgICAgICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT0iIj7tjIDsm5DsnYQg7ISg7YOd7ZWY7IS47JqUPC9vcHRpb24+CiAgICAgICAgICAgICAgICA8L3NlbGVjdD4KICAgICAgICAgICAgICAgIDxidXR0b24gb25jbGljaz0icmVzZXRNaFZpZXcoKSIgY2xhc3M9InAtMi41IHRleHQtc2xhdGUtNDAwIGhvdmVyOnRleHQtaW5kaWdvLTYwMCBob3ZlcjpiZy13aGl0ZSByb3VuZGVkLXhsIHRyYW5zaXRpb24tYWxsIGJvcmRlciBib3JkZXItdHJhbnNwYXJlbnQgaG92ZXI6Ym9yZGVyLWluZGlnby0xMDAiPgogICAgICAgICAgICAgICAgICAgIDxpIGRhdGEtbHVjaWRlPSJyZWZyZXNoLWN3IiBzaXplPSIyMCI+PC9pPgogICAgICAgICAgICAgICAgPC9idXR0b24+CiAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICA8ZGl2IGlkPSJtaC1kYXRlLWZpbHRlci13cmFwIiBjbGFzcz0iaGlkZGVuIj4KICAgICAgICAgICAgICAgIDxpbnB1dCB0eXBlPSJkYXRlIiBpZD0ic3RhcnQtZGF0ZSI+CiAgICAgICAgICAgICAgICA8aW5wdXQgdHlwZT0iZGF0ZSIgaWQ9ImVuZC1kYXRlIj4KICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgPC9kaXY+CgoKICAgICAgICA8ZGl2IGNsYXNzPSJncmlkIGdyaWQtY29scy0xIG1kOmdyaWQtY29scy0yIGxnOmdyaWQtY29scy00IGdhcC02IG1iLTEwIiBpZD0ia3BpLWNvbnRhaW5lciI+CgogICAgICAgICAgICA8ZGl2IGNsYXNzPSJiZy13aGl0ZSBwLTcgcm91bmRlZC1bMnJlbV0gc2hhZG93LXhsIGJvcmRlciBib3JkZXItc2xhdGUtMjAwIGFuaW1hdGUtcHVsc2UgaC0zMiI+PC9kaXY+CgogICAgICAgICAgICA8ZGl2IGNsYXNzPSJiZy13aGl0ZSBwLTcgcm91bmRlZC1bMnJlbV0gc2hhZG93LXhsIGJvcmRlciBib3JkZXItc2xhdGUtMjAwIGFuaW1hdGUtcHVsc2UgaC0zMiI+PC9kaXY+CgogICAgICAgICAgICA8ZGl2IGNsYXNzPSJiZy13aGl0ZSBwLTcgcm91bmRlZC1bMnJlbV0gc2hhZG93LXhsIGJvcmRlciBib3JkZXItc2xhdGUtMjAwIGFuaW1hdGUtcHVsc2UgaC0zMiI+PC9kaXY+CgogICAgICAgICAgICA8ZGl2IGNsYXNzPSJiZy13aGl0ZSBwLTcgcm91bmRlZC1bMnJlbV0gc2hhZG93LXhsIGJvcmRlciBib3JkZXItc2xhdGUtMjAwIGFuaW1hdGUtcHVsc2UgaC0zMiI+PC9kaXY+CgogICAgICAgIDwvZGl2PgoKCgogICAgICAgIDxkaXYgY2xhc3M9ImJnLXdoaXRlIHJvdW5kZWQtWzNyZW1dIHNoYWRvdy0yeGwgc2hhZG93LXNsYXRlLTIwMC81MCBib3JkZXIgYm9yZGVyLXNsYXRlLTEwMCBvdmVyZmxvdy1oaWRkZW4gbWItMTAiPgoKICAgICAgICAgICAgPGRpdiBjbGFzcz0icC0xMCBib3JkZXItYiBiZy1zbGF0ZS01MC81MCBmbGV4IGZsZXgtd3JhcCBpdGVtcy1jZW50ZXIganVzdGlmeS1iZXR3ZWVuIGdhcC02Ij4KCiAgICAgICAgICAgICAgICA8aDMgY2xhc3M9ImZvbnQtYmxhY2sgdGV4dC0zeGwgZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTQgdHJhY2tpbmctdGlnaHRlciB0ZXh0LXNsYXRlLTkwMCI+CgogICAgICAgICAgICAgICAgICAgIDxpIGRhdGEtbHVjaWRlPSJmaWxlLXRleHQiIHNpemU9IjM2IiBjbGFzcz0idGV4dC1lbWVyYWxkLTUwMCI+PC9pPiDtjIDrs4Qg7ZiE7ZmpCgogICAgICAgICAgICAgICAgPC9oMz4KCiAgICAgICAgICAgICAgICA8ZGl2IGlkPSJtYXRyaXgtZm9vdGVyLXZpc3VhbCIgY2xhc3M9ImZsZXggaXRlbXMtY2VudGVyIGdhcC00Ij48L2Rpdj4KCiAgICAgICAgICAgIDwvZGl2PgoKICAgICAgICAgICAgCgogICAgICAgICAgICA8ZGl2IGNsYXNzPSJwLTEwIj4KCiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJmbGV4IGZsZXgtY29sIGxnOmZsZXgtcm93IGdhcC0xMCI+CgogICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9ImxnOnctMS8zIGJnLXNsYXRlLTUwLzUwIHJvdW5kZWQtWzJyZW1dIHAtNiBib3JkZXIgYm9yZGVyLXNsYXRlLTEwMCBmbGV4IGZsZXgtY29sIGl0ZW1zLWNlbnRlciBzZWxmLXN0YXJ0Ij4KCiAgICAgICAgICAgICAgICAgICAgICAgIDxoNCBjbGFzcz0idGV4dC1zbSBmb250LWJsYWNrIHRleHQtc2xhdGUtNDAwIHVwcGVyY2FzZSB0cmFja2luZy13aWRlc3QgbWItNCI+7IKs7JeFIOyiheulmOuzhCDtiKzsnoUg67mE7KSRPC9oND4KCiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgaWQ9ImJpel9waWVfY2hhcnQiIGNsYXNzPSJ3LWZ1bGwgaC1bMzUwcHhdIGZsZXggaXRlbXMtY2VudGVyIGp1c3RpZnktY2VudGVyIHRleHQtc2xhdGUtMzAwIGZvbnQtYm9sZCBpdGFsaWMiPuuNsOydtO2EsCDrjIDquLAg7KSRPC9kaXY+CgogICAgICAgICAgICAgICAgICAgIDwvZGl2PgoKCgogICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9ImxnOnctMi8zIj4KCiAgICAgICAgICAgICAgICAgICAgICAgIDxoNCBjbGFzcz0idGV4dC1zbSBmb250LWJsYWNrIHRleHQtc2xhdGUtNDAwIHVwcGVyY2FzZSB0cmFja2luZy13aWRlc3QgbWItNCBtbC0yIj7tlITroZzsoJ3tirgg7ZiE7ZmpPC9oND4KCiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgaWQ9Im1hdHJpeC12aXN1YWwtY29udGFpbmVyIiBjbGFzcz0iY29sdW1ucy0xIG1kOmNvbHVtbnMtMiBnYXAtNCBtYXgtaC1bNjAwcHhdIG92ZXJmbG93LXktYXV0byBwci0yIGN1c3RvbS1zY3JvbGxiYXIiPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9InRleHQtc2xhdGUtMzAwIGZvbnQtYm9sZCBpdGFsaWMgcC0xMCB0ZXh0LWNlbnRlciB3LWZ1bGwiPu2MjOydvOydhCDsl4XroZzrk5ztlZjrqbQg7ZSE66Gc7KCd7Yq4IO2YhO2ZqeydtCDtkZzsi5zrkKnri4jri6QuPC9kaXY+CgogICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgICAgICAgICAgPC9kaXY+CgogICAgICAgICAgICAgICAgPC9kaXY+CgogICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgPC9kaXY+CgoKCiAgICAgICAgPGRpdiBjbGFzcz0iYmctd2hpdGUgcC0xMCByb3VuZGVkLVszcmVtXSBzaGFkb3ctMnhsIHNoYWRvdy1zbGF0ZS0yMDAvNTAgYm9yZGVyIGJvcmRlci1zbGF0ZS0xMDAgbWItMjAiPgoKICAgICAgICAgICAgPGRpdiBjbGFzcz0iZmxleCBmbGV4LWNvbCBsZzpmbGV4LXJvdyBsZzppdGVtcy1jZW50ZXIganVzdGlmeS1iZXR3ZWVuIG1iLTEyIGdhcC02Ij4KCiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJmbGV4IGl0ZW1zLWNlbnRlciBnYXAtNSI+CgogICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9InAtNCBiZy1zbGF0ZS01MCByb3VuZGVkLVsxLjVyZW1dIGJvcmRlciBib3JkZXItc2xhdGUtMTAwIj4KCiAgICAgICAgICAgICAgICAgICAgICAgIDxpIGlkPSJjaGFydC1pY29uIiBkYXRhLWx1Y2lkZT0iYmFyLWNoYXJ0LTIiIGNsYXNzPSJ0ZXh0LWJsdWUtNjAwIiBzaXplPSIzMiI+PC9pPgoKICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgICAgICAgICAgPGRpdj4KCiAgICAgICAgICAgICAgICAgICAgICAgIDxoMyBpZD0iY2hhcnQtdGl0bGUiIGNsYXNzPSJ0ZXh0LTN4bCBmb250LWJsYWNrIHRleHQtc2xhdGUtOTAwIHRyYWNraW5nLXRpZ2h0ZXIiPuu2hOyEnSDrjbDsnbTthLDrpbwg6riw64uk66as64qUIOykkS4uLjwvaDM+CgogICAgICAgICAgICAgICAgICAgICAgICA8cCBpZD0iY2hhcnQtZGVzYyIgY2xhc3M9ImhpZGRlbiB0ZXh0LXNsYXRlLTQwMCBmb250LWJvbGQgbXQtMSI+PC9wPgoKICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgICAgICA8ZGl2IGlkPSJ0YXJnZXQtYmFkZ2UiIGNsYXNzPSJoaWRkZW4gZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTQgYmctcmVkLTUwLzUwIHAtNSByb3VuZGVkLVsycmVtXSBib3JkZXIgYm9yZGVyLXJlZC0xMDAvNTAiPgoKICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJ0ZXh0LXJpZ2h0Ij4KCiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJ0ZXh0LVsxMHB4XSBmb250LWJsYWNrIHRleHQtcmVkLTQwMCB1cHBlcmNhc2UgdHJhY2tpbmctd2lkZXN0IGJsb2NrIG1iLTEiPlRhcmdldCBMaW1pdDwvc3Bhbj4KCiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgaWQ9InRhcmdldC12YWx1ZSIgY2xhc3M9InRleHQtM3hsIGZvbnQtYmxhY2sgdGV4dC1yZWQtNjAwIGxlYWRpbmctbm9uZSI+MC4wMGg8L2Rpdj4KCiAgICAgICAgICAgICAgICAgICAgPC9kaXY+CgogICAgICAgICAgICAgICAgPC9kaXY+CgogICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgIDxkaXYgaWQ9ImNoYXJ0X2RpdiIgY2xhc3M9InctZnVsbCBtaW4taC1bNTAwcHhdIGZsZXggaXRlbXMtY2VudGVyIGp1c3RpZnktY2VudGVyIHRleHQtc2xhdGUtMjAwIj4KCiAgICAgICAgICAgICAgICA8aSBkYXRhLWx1Y2lkZT0iYmFyLWNoYXJ0IiBzaXplPSI2NCI+PC9pPgoKICAgICAgICAgICAgPC9kaXY+CgogICAgICAgIDwvZGl2PgoKICAgIDwvZGl2PgoKICAgIDxzY3JpcHQ+CiAgICAgICAgLy8gLS0tIENvbmZpZ3VyYXRpb24gLS0tCgogICAgICAgIGNvbnN0IEhPTElEQVlTID0gWyIyMDI2LTAxLTAxIiwgIjIwMjYtMDMtMDEiLCAiMjAyNi0wNS0wNSIsICIyMDI2LTA2LTA2IiwgIjIwMjYtMDgtMTUiLCAiMjAyNi0xMC0wMyIsICIyMDI2LTEwLTA5IiwgIjIwMjYtMTItMjUiXTsKCiAgICAgICAgY29uc3QgUkFOS19XRUlHSFRTID0geyAn7IiY7ISdJzogMSwgJ+yxheyehCc6IDIsICfshKDsnoQnOiAzLCAn7Jew6rWs7JuQJzogNCB9OwogICAgICAgIAogICAgICAgIGxldCB0ZWFtRGF0YSA9IFtdOwogICAgICAgIGxldCBhbGxUZWFtcyA9IFtdOwogICAgICAgIGxldCBhbGxQZW9wbGVEYXRhID0gW107CiAgICAgICAgY29uc3QgREVGQVVMVF9DT0xVTU5fTUFQID0gewogICAgICAgICAgICBkYXRlOiAwLAogICAgICAgICAgICB0ZWFtOiAyLAogICAgICAgICAgICBuYW1lOiA0LAogICAgICAgICAgICByYW5rOiA1LAogICAgICAgICAgICB1c2VyU3RhdGU6IDYsCiAgICAgICAgICAgIG5vcm1hbENvc3Q6IC0xLAogICAgICAgICAgICBleHRyYUNvc3Q6IC0xLAogICAgICAgICAgICBzbG90czogWwogICAgICAgICAgICAgICAgeyBiaXo6IDgsIHByb2o6IDEwLCB0aW1lOiAxMiwgZXh0cmE6IGZhbHNlIH0sCiAgICAgICAgICAgICAgICB7IGJpejogMTQsIHByb2o6IDE2LCB0aW1lOiAxOCwgZXh0cmE6IGZhbHNlIH0sCiAgICAgICAgICAgICAgICB7IGJpejogMTksIHByb2o6IDIxLCB0aW1lOiAyMywgZXh0cmE6IGZhbHNlIH0sCiAgICAgICAgICAgICAgICB7IGJpejogMjQsIHByb2o6IDI2LCB0aW1lOiAyOCwgZXh0cmE6IGZhbHNlIH0sCiAgICAgICAgICAgICAgICB7IGJpejogMjksIHByb2o6IDMxLCB0aW1lOiAzMywgZXh0cmE6IGZhbHNlIH0sCiAgICAgICAgICAgICAgICB7IGJpejogMzQsIHByb2o6IDM2LCB0aW1lOiAzOCwgZXh0cmE6IGZhbHNlIH0sCiAgICAgICAgICAgICAgICB7IGJpejogMzksIHByb2o6IDQxLCB0aW1lOiA0NCwgZXh0cmE6IHRydWUgfQogICAgICAgICAgICBdCiAgICAgICAgfTsKICAgICAgICBjb25zdCBjbG9uZURlZmF1bHRDb2x1bW5NYXAgPSAoKSA9PiAoewogICAgICAgICAgICAuLi5ERUZBVUxUX0NPTFVNTl9NQVAsCiAgICAgICAgICAgIHNsb3RzOiBERUZBVUxUX0NPTFVNTl9NQVAuc2xvdHMubWFwKHMgPT4gKHsgLi4ucyB9KSkKICAgICAgICB9KTsKICAgICAgICBsZXQgY29sdW1uTWFwID0gY2xvbmVEZWZhdWx0Q29sdW1uTWFwKCk7CgogICAgICAgIC8vIC0tLSBVdGlscyAtLS0KICAgICAgICBjb25zdCBmb3JtYXROdW0gPSAodikgPT4gTnVtYmVyKHYgfHwgMCkudG9Mb2NhbGVTdHJpbmcoJ2tvLUtSJywgeyBtaW5pbXVtRnJhY3Rpb25EaWdpdHM6IDIsIG1heGltdW1GcmFjdGlvbkRpZ2l0czogMiB9KTsKICAgICAgICBjb25zdCBub3JtYWxpemVIZWFkZXIgPSAodikgPT4gU3RyaW5nKHYgfHwgJycpLnJlcGxhY2UoL1xzKy9nLCAnJykudG9Mb3dlckNhc2UoKTsKICAgICAgICBjb25zdCBwYXJzZU51bWJlciA9ICh2KSA9PiBwYXJzZUZsb2F0KFN0cmluZyh2IHx8ICcnKS5yZXBsYWNlKC9bXjAtOS5dL2csICcnKSkgfHwgMDsKICAgICAgICBjb25zdCBMRUdBTF9XRUVLTFlfTElNSVRfSE9VUlMgPSA1MjsKICAgICAgICBjb25zdCBEQUlMWV9TVEFOREFSRF9IT1VSUyA9IDg7CiAgICAgICAgY29uc3QgZFN0ciA9ICh2KSA9PiB7CiAgICAgICAgICAgIGlmICghdikgcmV0dXJuICIiOwogICAgICAgICAgICBsZXQgZCA9ICh0eXBlb2YgdiA9PT0gJ251bWJlcicpID8gbmV3IERhdGUoTWF0aC5yb3VuZCgodiAtIDI1NTY5KSAqIDg2NDAwICogMTAwMCkpIDogbmV3IERhdGUodik7CiAgICAgICAgICAgIGlmIChpc05hTihkLmdldFRpbWUoKSkpIHJldHVybiAiIjsKICAgICAgICAgICAgcmV0dXJuIGAke2QuZ2V0RnVsbFllYXIoKX0tJHsoIjAiICsgKGQuZ2V0TW9udGgoKSArIDEpKS5zbGljZSgtMil9LSR7KCIwIiArIGQuZ2V0RGF0ZSgpKS5zbGljZSgtMil9YDsKICAgICAgICB9OwogICAgICAgIGNvbnN0IGNhbGN1bGF0ZVRhcmdldEhvdXJzID0gKHN0YXJ0U3RyLCBlbmRTdHIpID0+IHsKICAgICAgICAgICAgY29uc3Qgc3RhcnQgPSBuZXcgRGF0ZShzdGFydFN0cik7CiAgICAgICAgICAgIGNvbnN0IGVuZCA9IG5ldyBEYXRlKGVuZFN0cik7CiAgICAgICAgICAgIGlmIChpc05hTihzdGFydC5nZXRUaW1lKCkpIHx8IGlzTmFOKGVuZC5nZXRUaW1lKCkpIHx8IGVuZCA8IHN0YXJ0KSByZXR1cm4gMjA4OwogICAgICAgICAgICBjb25zdCBzdGFydFV0YyA9IERhdGUuVVRDKHN0YXJ0LmdldEZ1bGxZZWFyKCksIHN0YXJ0LmdldE1vbnRoKCksIHN0YXJ0LmdldERhdGUoKSk7CiAgICAgICAgICAgIGNvbnN0IGVuZFV0YyA9IERhdGUuVVRDKGVuZC5nZXRGdWxsWWVhcigpLCBlbmQuZ2V0TW9udGgoKSwgZW5kLmdldERhdGUoKSk7CiAgICAgICAgICAgIGNvbnN0IG9uZURheSA9IDg2NDAwMDAwOwoKICAgICAgICAgICAgLy8gRnVsbCBjYWxlbmRhciBtb250aCBzZWxlY3Rpb24gKGUuZy4gMjAyNi0wMS0wMSB+IDIwMjYtMDEtMzEpOiB1c2UgZGF5LWNvdW50ICogOGguCiAgICAgICAgICAgIGNvbnN0IGlzU2FtZU1vbnRoID0gc3RhcnQuZ2V0RnVsbFllYXIoKSA9PT0gZW5kLmdldEZ1bGxZZWFyKCkgJiYgc3RhcnQuZ2V0TW9udGgoKSA9PT0gZW5kLmdldE1vbnRoKCk7CiAgICAgICAgICAgIGNvbnN0IGxhc3REYXlPZk1vbnRoID0gbmV3IERhdGUoc3RhcnQuZ2V0RnVsbFllYXIoKSwgc3RhcnQuZ2V0TW9udGgoKSArIDEsIDApLmdldERhdGUoKTsKICAgICAgICAgICAgY29uc3QgaXNGdWxsQ2FsZW5kYXJNb250aCA9IGlzU2FtZU1vbnRoICYmIHN0YXJ0LmdldERhdGUoKSA9PT0gMSAmJiBlbmQuZ2V0RGF0ZSgpID09PSBsYXN0RGF5T2ZNb250aDsKICAgICAgICAgICAgaWYgKGlzRnVsbENhbGVuZGFyTW9udGgpIHsKICAgICAgICAgICAgICAgIGNvbnN0IGRheXNJblJhbmdlID0gTWF0aC5mbG9vcigoZW5kVXRjIC0gc3RhcnRVdGMpIC8gb25lRGF5KSArIDE7CiAgICAgICAgICAgICAgICByZXR1cm4gTWF0aC5yb3VuZChkYXlzSW5SYW5nZSAqIERBSUxZX1NUQU5EQVJEX0hPVVJTKTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGV0IHRvdGFsVGFyZ2V0ID0gMDsKCiAgICAgICAgICAgIC8vIE1vbmRheS1zdGFydCB3ZWVrIGJvdW5kYXJ5IChNb25+U3VuKQogICAgICAgICAgICBjb25zdCBnZXRXZWVrU3RhcnRVdGMgPSAodXRjTXMpID0+IHsKICAgICAgICAgICAgICAgIGNvbnN0IGRvdyA9IG5ldyBEYXRlKHV0Y01zKS5nZXRVVENEYXkoKTsgLy8gU3VuOjAgLi4uIFNhdDo2CiAgICAgICAgICAgICAgICBjb25zdCBtb25kYXlPZmZzZXQgPSAoZG93ICsgNikgJSA3OyAvLyBNb246MCAuLi4gU3VuOjYKICAgICAgICAgICAgICAgIHJldHVybiB1dGNNcyAtIG1vbmRheU9mZnNldCAqIG9uZURheTsKICAgICAgICAgICAgfTsKCiAgICAgICAgICAgIGZvciAobGV0IHdlZWtTdGFydCA9IGdldFdlZWtTdGFydFV0YyhzdGFydFV0Yyk7IHdlZWtTdGFydCA8PSBlbmRVdGM7IHdlZWtTdGFydCArPSA3ICogb25lRGF5KSB7CiAgICAgICAgICAgICAgICBjb25zdCB3ZWVrRW5kID0gd2Vla1N0YXJ0ICsgNiAqIG9uZURheTsKICAgICAgICAgICAgICAgIGNvbnN0IHNlZ1N0YXJ0ID0gTWF0aC5tYXgoc3RhcnRVdGMsIHdlZWtTdGFydCk7CiAgICAgICAgICAgICAgICBjb25zdCBzZWdFbmQgPSBNYXRoLm1pbihlbmRVdGMsIHdlZWtFbmQpOwogICAgICAgICAgICAgICAgaWYgKHNlZ1N0YXJ0ID4gc2VnRW5kKSBjb250aW51ZTsKCiAgICAgICAgICAgICAgICBjb25zdCBzZWxlY3RlZERheXMgPSBNYXRoLmZsb29yKChzZWdFbmQgLSBzZWdTdGFydCkgLyBvbmVEYXkpICsgMTsKICAgICAgICAgICAgICAgIGNvbnN0IGlzRnVsbE1vblN1bldlZWtTZWxlY3RlZCA9IChzZWdTdGFydCA9PT0gd2Vla1N0YXJ0KSAmJiAoc2VnRW5kID09PSB3ZWVrRW5kKTsKCiAgICAgICAgICAgICAgICB0b3RhbFRhcmdldCArPSBpc0Z1bGxNb25TdW5XZWVrU2VsZWN0ZWQKICAgICAgICAgICAgICAgICAgICA/IExFR0FMX1dFRUtMWV9MSU1JVF9IT1VSUwogICAgICAgICAgICAgICAgICAgIDogc2VsZWN0ZWREYXlzICogREFJTFlfU1RBTkRBUkRfSE9VUlM7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIHJldHVybiBNYXRoLnJvdW5kKHRvdGFsVGFyZ2V0KTsKICAgICAgICB9OwogICAgICAgIGNvbnN0IGZpbmRIZWFkZXJJbmRleCA9IChub3JtYWxpemVkSGVhZGVycywgY2FuZGlkYXRlcykgPT4gewogICAgICAgICAgICBjb25zdCB0YXJnZXRzID0gY2FuZGlkYXRlcy5tYXAobm9ybWFsaXplSGVhZGVyKTsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBub3JtYWxpemVkSGVhZGVycy5sZW5ndGg7IGkrKykgewogICAgICAgICAgICAgICAgaWYgKHRhcmdldHMuaW5jbHVkZXMobm9ybWFsaXplZEhlYWRlcnNbaV0pKSByZXR1cm4gaTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gLTE7CiAgICAgICAgfTsKICAgICAgICBjb25zdCBmaW5kQml6SW5kZXhCeVByb2plY3QgPSAobm9ybWFsaXplZEhlYWRlcnMsIHByb2pJZHgpID0+IHsKICAgICAgICAgICAgY29uc3QgYml6S2V5ID0gbm9ybWFsaXplSGVhZGVyKCfsgqzsl4Ug7KKF66WYJyk7CiAgICAgICAgICAgIGZvciAobGV0IGkgPSBwcm9qSWR4IC0gMTsgaSA+PSAwOyBpLS0pIHsKICAgICAgICAgICAgICAgIGlmIChub3JtYWxpemVkSGVhZGVyc1tpXSA9PT0gYml6S2V5KSByZXR1cm4gaTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gLTE7CiAgICAgICAgfTsKICAgICAgICBmdW5jdGlvbiBidWlsZENvbHVtbk1hcCgpIHsKICAgICAgICAgICAgY29sdW1uTWFwID0gY2xvbmVEZWZhdWx0Q29sdW1uTWFwKCk7CiAgICAgICAgICAgIGlmICh0ZWFtRGF0YS5sZW5ndGggPT09IDAgfHwgIUFycmF5LmlzQXJyYXkodGVhbURhdGFbMF0pKSByZXR1cm47CgogICAgICAgICAgICBjb25zdCBub3JtYWxpemVkSGVhZGVycyA9IHRlYW1EYXRhWzBdLm1hcChub3JtYWxpemVIZWFkZXIpOwogICAgICAgICAgICBpZiAobm9ybWFsaXplZEhlYWRlcnMubGVuZ3RoID09PSAwKSByZXR1cm47CgogICAgICAgICAgICBjb25zdCBkYXRlSWR4ID0gZmluZEhlYWRlckluZGV4KG5vcm1hbGl6ZWRIZWFkZXJzLCBbJ+q3vOustOydvOyekCddKTsKICAgICAgICAgICAgY29uc3QgdGVhbUlkeCA9IGZpbmRIZWFkZXJJbmRleChub3JtYWxpemVkSGVhZGVycywgWyftjIAnXSk7CiAgICAgICAgICAgIGNvbnN0IG5hbWVJZHggPSBmaW5kSGVhZGVySW5kZXgobm9ybWFsaXplZEhlYWRlcnMsIFsn7J2066aEJ10pOwogICAgICAgICAgICBjb25zdCByYW5rSWR4ID0gZmluZEhlYWRlckluZGV4KG5vcm1hbGl6ZWRIZWFkZXJzLCBbJ+yngeyxhSddKTsKICAgICAgICAgICAgY29uc3Qgc3RhdGVJZHggPSBmaW5kSGVhZGVySW5kZXgobm9ybWFsaXplZEhlYWRlcnMsIFsndXNlcl9zdGF0ZSddKTsKICAgICAgICAgICAgY29uc3Qgbm9ybWFsQ29zdElkeCA9IGZpbmRIZWFkZXJJbmRleChub3JtYWxpemVkSGVhZGVycywgWyfsnbzrsJjqt7zrrLQnXSk7CiAgICAgICAgICAgIGNvbnN0IGV4dHJhQ29zdElkeCA9IGZpbmRIZWFkZXJJbmRleChub3JtYWxpemVkSGVhZGVycywgWyfstpTqsIDqt7zrrLQnXSk7CgogICAgICAgICAgICBpZiAoZGF0ZUlkeCA+PSAwKSBjb2x1bW5NYXAuZGF0ZSA9IGRhdGVJZHg7CiAgICAgICAgICAgIGlmICh0ZWFtSWR4ID49IDApIGNvbHVtbk1hcC50ZWFtID0gdGVhbUlkeDsKICAgICAgICAgICAgaWYgKG5hbWVJZHggPj0gMCkgY29sdW1uTWFwLm5hbWUgPSBuYW1lSWR4OwogICAgICAgICAgICBpZiAocmFua0lkeCA+PSAwKSBjb2x1bW5NYXAucmFuayA9IHJhbmtJZHg7CiAgICAgICAgICAgIGlmIChzdGF0ZUlkeCA+PSAwKSBjb2x1bW5NYXAudXNlclN0YXRlID0gc3RhdGVJZHg7CiAgICAgICAgICAgIGlmIChub3JtYWxDb3N0SWR4ID49IDApIGNvbHVtbk1hcC5ub3JtYWxDb3N0ID0gbm9ybWFsQ29zdElkeDsKICAgICAgICAgICAgaWYgKGV4dHJhQ29zdElkeCA+PSAwKSBjb2x1bW5NYXAuZXh0cmFDb3N0ID0gZXh0cmFDb3N0SWR4OwoKICAgICAgICAgICAgY29uc3Qgc2xvdERlZnMgPSBbCiAgICAgICAgICAgICAgICB7IHByb2pIZWFkZXJzOiBbJ+uplOyduOyXheustCDtlITroZzsoJ3tirjrqoUnXSwgdGltZUhlYWRlcnM6IFsn66mU7J247JeF66y0IOq3vOustOyLnOqwhCddLCBleHRyYTogZmFsc2UgfSwKICAgICAgICAgICAgICAgIHsgcHJvakhlYWRlcnM6IFsn7LaU6rCA7JeF66y0MSDtlITroZzsoJ3tirjrqoUnXSwgdGltZUhlYWRlcnM6IFsn7LaU6rCA7JeF66y0MSDqt7zrrLTsi5zqsIQnXSwgZXh0cmE6IGZhbHNlIH0sCiAgICAgICAgICAgICAgICB7IHByb2pIZWFkZXJzOiBbJ+y2lOqwgOyXheustDIg7ZSE66Gc7KCd7Yq466qFJ10sIHRpbWVIZWFkZXJzOiBbJ+y2lOqwgOyXheustDIg6re866y07Iuc6rCEJ10sIGV4dHJhOiBmYWxzZSB9LAogICAgICAgICAgICAgICAgeyBwcm9qSGVhZGVyczogWyfstpTqsIDsl4XrrLQzIO2UhOuhnOygne2KuOuqhSddLCB0aW1lSGVhZGVyczogWyfstpTqsIDsl4XrrLQzIOq3vOustOyLnOqwhCddLCBleHRyYTogZmFsc2UgfSwKICAgICAgICAgICAgICAgIHsgcHJvakhlYWRlcnM6IFsn7LaU6rCA7JeF66y0NCDtlITroZzsoJ3tirjrqoUnXSwgdGltZUhlYWRlcnM6IFsn7LaU6rCA7JeF66y0NCDqt7zrrLTsi5zqsIQnXSwgZXh0cmE6IGZhbHNlIH0sCiAgICAgICAgICAgICAgICB7IHByb2pIZWFkZXJzOiBbJ+y2lOqwgOyXheustDUg7ZSE66Gc7KCd7Yq466qFJ10sIHRpbWVIZWFkZXJzOiBbJ+y2lOqwgOyXheustDUg6re866y07Iuc6rCEJ10sIGV4dHJhOiBmYWxzZSB9LAogICAgICAgICAgICAgICAgeyBwcm9qSGVhZGVyczogWyfsl7DsnqXqt7zrrLQg7ZSE66Gc7KCd7Yq466qFJ10sIHRpbWVIZWFkZXJzOiBbJ+yXsOyepeq3vOustCDsi5zqsIQo6rCA6rO1KScsICfsl7DsnqXqt7zrrLTsi5zqsIQo6rCA6rO1KSddLCBleHRyYTogdHJ1ZSB9CiAgICAgICAgICAgIF07CiAgICAgICAgICAgIGNvbnN0IG1hcHBlZFNsb3RzID0gc2xvdERlZnMubWFwKGRlZiA9PiB7CiAgICAgICAgICAgICAgICBjb25zdCBwcm9qID0gZmluZEhlYWRlckluZGV4KG5vcm1hbGl6ZWRIZWFkZXJzLCBkZWYucHJvakhlYWRlcnMpOwogICAgICAgICAgICAgICAgY29uc3QgdGltZSA9IGZpbmRIZWFkZXJJbmRleChub3JtYWxpemVkSGVhZGVycywgZGVmLnRpbWVIZWFkZXJzKTsKICAgICAgICAgICAgICAgIGlmIChwcm9qIDwgMCB8fCB0aW1lIDwgMCkgcmV0dXJuIG51bGw7CiAgICAgICAgICAgICAgICByZXR1cm4geyBiaXo6IGZpbmRCaXpJbmRleEJ5UHJvamVjdChub3JtYWxpemVkSGVhZGVycywgcHJvaiksIHByb2osIHRpbWUsIGV4dHJhOiBkZWYuZXh0cmEgfTsKICAgICAgICAgICAgfSkuZmlsdGVyKEJvb2xlYW4pOwogICAgICAgICAgICBpZiAobWFwcGVkU2xvdHMubGVuZ3RoID4gMCkgY29sdW1uTWFwLnNsb3RzID0gbWFwcGVkU2xvdHM7CiAgICAgICAgfQoKICAgICAgICBnb29nbGUuY2hhcnRzLmxvYWQoJ2N1cnJlbnQnLCB7J3BhY2thZ2VzJzpbJ2NvcmVjaGFydCddfSk7CgoKICAgICAgICAvLyAtLS0gUG9wdXAgRnVuY3Rpb25zIC0tLQoKICAgICAgICBmdW5jdGlvbiBzaG93UHJvamVjdE1lbWJlcnMocE5hbWUpIHsKCiAgICAgICAgICAgIGNvbnN0IG1vZGFsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3Byb2plY3QtbWVtYmVycy1tb2RhbCcpOwoKICAgICAgICAgICAgY29uc3QgdGl0bGVFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdtb2RhbC1wcm9qZWN0LXRpdGxlJyk7CgogICAgICAgICAgICBjb25zdCBjb3VudEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ21vZGFsLXByb2plY3QtY291bnQnKTsKCiAgICAgICAgICAgIGNvbnN0IGxpc3RFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdtb2RhbC1tZW1iZXJzLWxpc3QnKTsKCiAgICAgICAgICAgIAoKICAgICAgICAgICAgY29uc3Qgc3RhcnRTdHIgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnc3RhcnQtZGF0ZScpLnZhbHVlOwogICAgICAgICAgICBjb25zdCBlbmRTdHIgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZW5kLWRhdGUnKS52YWx1ZTsKICAgICAgICAgICAgCiAgICAgICAgICAgIGxldCBtZW1iZXJNYXAgPSB7fTsKICAgICAgICAgICAgY29uc3Qgc2xvdHMgPSBjb2x1bW5NYXAuc2xvdHMgfHwgW107CgogICAgICAgICAgICB0ZWFtRGF0YS5zbGljZSgxKS5mb3JFYWNoKHJvdyA9PiB7CiAgICAgICAgICAgICAgICBjb25zdCBkID0gZFN0cihyb3dbY29sdW1uTWFwLmRhdGVdKTsKICAgICAgICAgICAgICAgIGlmICghZCB8fCBkIDwgc3RhcnRTdHIgfHwgZCA+IGVuZFN0cikgcmV0dXJuOwogICAgICAgICAgICAgICAgY29uc3QgdGVhbSA9IFN0cmluZyhyb3dbY29sdW1uTWFwLnRlYW1dIHx8ICcnKS50cmltKCk7CiAgICAgICAgICAgICAgICBjb25zdCBuYW1lID0gU3RyaW5nKHJvd1tjb2x1bW5NYXAubmFtZV0gfHwgJycpLnRyaW0oKTsKICAgICAgICAgICAgICAgIGNvbnN0IHJhbmsgPSBTdHJpbmcocm93W2NvbHVtbk1hcC5yYW5rXSB8fCAn7Jew6rWs7JuQJykudHJpbSgpOwoKICAgICAgICAgICAgICAgIHNsb3RzLmZvckVhY2gocyA9PiB7CiAgICAgICAgICAgICAgICAgICAgY29uc3Qgcm93UE5hbWUgPSBTdHJpbmcocm93W3MucHJval0gfHwgJycpLnRyaW0oKTsKICAgICAgICAgICAgICAgICAgICBjb25zdCB2YWwgPSBwYXJzZU51bWJlcihyb3dbcy50aW1lXSk7CiAgICAgICAgICAgICAgICAgICAgaWYgKHJvd1BOYW1lID09PSBwTmFtZSAmJiB2YWwgPiAwKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGtleSA9IGAke25hbWV9fCR7dGVhbX18JHtyYW5rfWA7CiAgICAgICAgICAgICAgICAgICAgICAgIG1lbWJlck1hcFtrZXldID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICB9KTsKCgoKICAgICAgICAgICAgY29uc3QgbWVtYmVycyA9IE9iamVjdC5rZXlzKG1lbWJlck1hcCkubWFwKGsgPT4gewoKICAgICAgICAgICAgICAgIGNvbnN0IFtuLCB0LCByXSA9IGsuc3BsaXQoJ3wnKTsKCiAgICAgICAgICAgICAgICByZXR1cm4geyBuYW1lOiBuLCB0ZWFtOiB0LCByYW5rOiByIH07CgogICAgICAgICAgICB9KS5zb3J0KChhLGIpID0+IGEubmFtZS5sb2NhbGVDb21wYXJlKGIubmFtZSwgJ2tvJykpOwoKCgogICAgICAgICAgICB0aXRsZUVsLmlubmVyVGV4dCA9IHBOYW1lOwoKICAgICAgICAgICAgY291bnRFbC5pbm5lclRleHQgPSBg7LSdICR7bWVtYmVycy5sZW5ndGh966qFIOywuOyXrCDspJEgKOyghOyytCDtjIAg6riw7KSAKWA7CgogICAgICAgICAgICAKCiAgICAgICAgICAgIGxpc3RFbC5pbm5lckhUTUwgPSBtZW1iZXJzLm1hcChtID0+IGAKCiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWJldHdlZW4gcC00IGJnLXNsYXRlLTUwLzUwIGJvcmRlciBib3JkZXItc2xhdGUtMTAwIHJvdW5kZWQtMnhsIGdyb3VwIGhvdmVyOmJnLWJsdWUtNTAgdHJhbnNpdGlvbi1hbGwiPgoKICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJmbGV4LTEiPgoKICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0iZmxleCBpdGVtcy1iYXNlbGluZSBnYXAtMiI+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InRleHQtYmFzZSBmb250LWJsYWNrIHRleHQtc2xhdGUtODAwIj4ke20ubmFtZX08L3NwYW4+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InRleHQtWzExcHhdIGZvbnQtYmxhY2sgdGV4dC1ibHVlLTYwMCBiZy1ibHVlLTUwIHB4LTIgcHktMC41IHJvdW5kZWQtbGcgYm9yZGVyIGJvcmRlci1ibHVlLTEwMCI+JHttLnJhbmt9PC9zcGFuPgoKICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CgogICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJ0ZXh0LVsxMXB4XSB0ZXh0LXNsYXRlLTQwMCBmb250LWJvbGQgbXQtMSI+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgJHttLnRlYW19CgogICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgICAgICAgICAgPC9kaXY+CgogICAgICAgICAgICAgICAgICAgIDxidXR0b24gb25jbGljaz0iZ29Ub01lbWJlckFuYWx5c2lzKCcke20udGVhbX0nLCAnJHttLm5hbWV9JykiIGNsYXNzPSJwLTIuNSBiZy13aGl0ZSByb3VuZGVkLWZ1bGwgc2hhZG93LXNtIGJvcmRlciBib3JkZXItc2xhdGUtMTAwIGhvdmVyOmJvcmRlci1ibHVlLTMwMCBob3ZlcjpzY2FsZS0xMTAgdHJhbnNpdGlvbi1hbGwgdGV4dC1zbGF0ZS0zMDAgaG92ZXI6dGV4dC1ibHVlLTUwMCI+CgogICAgICAgICAgICAgICAgICAgICAgICA8aSBkYXRhLWx1Y2lkZT0iY2hldnJvbi1yaWdodCIgc2l6ZT0iMTgiPjwvaT4KCiAgICAgICAgICAgICAgICAgICAgPC9idXR0b24+CgogICAgICAgICAgICAgICAgPC9kaXY+CgogICAgICAgICAgICBgKS5qb2luKCcnKTsKCiAgICAgICAgICAgIAoKICAgICAgICAgICAgbW9kYWwuY2xhc3NMaXN0LnJlbW92ZSgnaGlkZGVuJyk7CgogICAgICAgICAgICBsdWNpZGUuY3JlYXRlSWNvbnMoKTsKCiAgICAgICAgfQoKCgogICAgICAgIGZ1bmN0aW9uIGNsb3NlUHJvamVjdE1vZGFsKCkgewoKICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3Byb2plY3QtbWVtYmVycy1tb2RhbCcpLmNsYXNzTGlzdC5hZGQoJ2hpZGRlbicpOwoKICAgICAgICB9CgoKCiAgICAgICAgZnVuY3Rpb24gZ29Ub01lbWJlckFuYWx5c2lzKHRlYW0sIG5hbWUpIHsKCiAgICAgICAgICAgIGNsb3NlUHJvamVjdE1vZGFsKCk7CgogICAgICAgICAgICBjb25zdCB0ZWFtU2VsZWN0ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3RlYW0tc2VsZWN0Jyk7CgogICAgICAgICAgICBjb25zdCBwZXJzb25TZWxlY3QgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncGVyc29uLXNlbGVjdCcpOwoKICAgICAgICAgICAgdGVhbVNlbGVjdC52YWx1ZSA9IHRlYW07CgogICAgICAgICAgICB1cGRhdGVGaWx0ZXJzKCk7CgogICAgICAgICAgICBwZXJzb25TZWxlY3QudmFsdWUgPSBuYW1lOwoKICAgICAgICAgICAgcmVuZGVyKCk7CgogICAgICAgICAgICB3aW5kb3cuc2Nyb2xsVG8oeyB0b3A6IDAsIGJlaGF2aW9yOiAnc21vb3RoJyB9KTsKCiAgICAgICAgfQoKCgogICAgICAgIC8vIC0tLSBIYW5kbGVycyAtLS0KICAgICAgICBmdW5jdGlvbiBsb2FkV29ya2Jvb2tCaW5hcnkoYmluYXJ5U3RyKSB7CiAgICAgICAgICAgIGlmICghYmluYXJ5U3RyKSByZXR1cm47CiAgICAgICAgICAgIGNvbnN0IHdvcmtib29rID0gWExTWC5yZWFkKGJpbmFyeVN0ciwge3R5cGU6ICdiaW5hcnknLCBjZWxsRGF0ZXM6IHRydWUsIGRhdGVORjogJ3l5eXktbW0tZGQnfSk7CiAgICAgICAgICAgIHRlYW1EYXRhID0gWExTWC51dGlscy5zaGVldF90b19qc29uKHdvcmtib29rLlNoZWV0c1t3b3JrYm9vay5TaGVldE5hbWVzWzBdXSwge2hlYWRlcjogMSwgZGVmdmFsOiAiIn0pOwogICAgICAgICAgICBidWlsZENvbHVtbk1hcCgpOwogICAgICAgICAgICBpbml0VGVhbVRhYkFmdGVyVXBsb2FkKCk7CiAgICAgICAgfQoKICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZmlsZS1pbnB1dCcpLmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIGZ1bmN0aW9uKGUpIHsKICAgICAgICAgICAgY29uc3QgZmlsZSA9IGUudGFyZ2V0LmZpbGVzWzBdOwogICAgICAgICAgICBpZiAoIWZpbGUpIHJldHVybjsKCiAgICAgICAgICAgIGNvbnN0IHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKCk7CiAgICAgICAgICAgIHJlYWRlci5vbmxvYWQgPSBmdW5jdGlvbihldnQpIHsKICAgICAgICAgICAgICAgIGxvYWRXb3JrYm9va0JpbmFyeShldnQudGFyZ2V0LnJlc3VsdCk7CiAgICAgICAgICAgIH07CiAgICAgICAgICAgIHJlYWRlci5yZWFkQXNCaW5hcnlTdHJpbmcoZmlsZSk7CiAgICAgICAgfSk7CgogICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgZnVuY3Rpb24oZXZlbnQpIHsKICAgICAgICAgICAgY29uc3QgcGF5bG9hZCA9IGV2ZW50Py5kYXRhOwogICAgICAgICAgICBpZiAoIXBheWxvYWQgfHwgcGF5bG9hZC5zb3VyY2UgIT09ICd0b3RhbC11cGxvYWQnIHx8IHBheWxvYWQudHlwZSAhPT0gJ21oJykgcmV0dXJuOwogICAgICAgICAgICB0cnkgewogICAgICAgICAgICAgICAgbG9hZFdvcmtib29rQmluYXJ5KHBheWxvYWQuYmluYXJ5IHx8ICcnKTsKICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7CiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGVycik7CiAgICAgICAgICAgIH0KICAgICAgICB9KTsKCiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCBmdW5jdGlvbihldmVudCkgewogICAgICAgICAgICBjb25zdCBwYXlsb2FkID0gZXZlbnQ/LmRhdGE7CiAgICAgICAgICAgIGlmICghcGF5bG9hZCB8fCBwYXlsb2FkLnNvdXJjZSAhPT0gJ3RvdGFsLWNvbnRyb2wnKSByZXR1cm47CiAgICAgICAgICAgIGlmIChwYXlsb2FkLnR5cGUgPT09ICd0YWItYWN0aXZhdGVkJyAmJiBwYXlsb2FkLnRhYiA9PT0gJ21oJykgewogICAgICAgICAgICAgICAgLy8gSGlkZGVuIHN0YXRl7JeQ7IScIOuovOyggCDqt7jroKTsp4Qg7LCo7Yq4IOugiOydtOyVhOybgyDrs7TsoJUKICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4gcmVuZGVyKCksIDApOwogICAgICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiByZW5kZXIoKSwgMTIwKTsKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAocGF5bG9hZC50eXBlICE9PSAnZGF0ZS1yYW5nZScpIHJldHVybjsKICAgICAgICAgICAgY29uc3Qgc3RhcnRJbnB1dCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdzdGFydC1kYXRlJyk7CiAgICAgICAgICAgIGNvbnN0IGVuZElucHV0ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2VuZC1kYXRlJyk7CiAgICAgICAgICAgIGlmIChwYXlsb2FkLnN0YXJ0RGF0ZSkgc3RhcnRJbnB1dC52YWx1ZSA9IHBheWxvYWQuc3RhcnREYXRlOwogICAgICAgICAgICBpZiAocGF5bG9hZC5lbmREYXRlKSBlbmRJbnB1dC52YWx1ZSA9IHBheWxvYWQuZW5kRGF0ZTsKICAgICAgICAgICAgcmVuZGVyKCk7CiAgICAgICAgfSk7CgoKICAgICAgICBmdW5jdGlvbiBpbml0VGVhbVRhYkFmdGVyVXBsb2FkKCkgewogICAgICAgICAgICBpZiAodGVhbURhdGEubGVuZ3RoIDwgMikgcmV0dXJuOwogICAgICAgICAgICBjb25zdCBkYXRlcyA9IHRlYW1EYXRhLnNsaWNlKDEpLm1hcChyID0+IGRTdHIocltjb2x1bW5NYXAuZGF0ZV0pKS5maWx0ZXIoQm9vbGVhbikuc29ydCgpOwogICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnc3RhcnQtZGF0ZScpLnZhbHVlID0gZGF0ZXNbMF07CiAgICAgICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdlbmQtZGF0ZScpLnZhbHVlID0gZGF0ZXNbZGF0ZXMubGVuZ3RoIC0gMV07CgogICAgICAgICAgICBhbGxUZWFtcyA9IFsuLi5uZXcgU2V0KHRlYW1EYXRhLnNsaWNlKDEpLm1hcChyID0+IFN0cmluZyhyW2NvbHVtbk1hcC50ZWFtXSB8fCAnJykudHJpbSgpKSldLmZpbHRlcihCb29sZWFuKS5zb3J0KCk7CiAgICAgICAgICAgIGFsbFBlb3BsZURhdGEgPSB0ZWFtRGF0YS5zbGljZSgxKS5tYXAociA9PiAoewogICAgICAgICAgICAgICAgbmFtZTogU3RyaW5nKHJbY29sdW1uTWFwLm5hbWVdIHx8ICcnKS50cmltKCksCiAgICAgICAgICAgICAgICB0ZWFtOiBTdHJpbmcocltjb2x1bW5NYXAudGVhbV0gfHwgJycpLnRyaW0oKQogICAgICAgICAgICB9KSkuZmlsdGVyKHAgPT4gcC5uYW1lICYmIHAudGVhbSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY29uc3Qgc2VlbiA9IG5ldyBTZXQoKTsKCiAgICAgICAgICAgIGFsbFBlb3BsZURhdGEgPSBhbGxQZW9wbGVEYXRhLmZpbHRlcihwID0+IHsKCiAgICAgICAgICAgICAgICBjb25zdCBrZXkgPSBgJHtwLm5hbWV9LSR7cC50ZWFtfWA7CgogICAgICAgICAgICAgICAgaWYgKHNlZW4uaGFzKGtleSkpIHJldHVybiBmYWxzZTsKCiAgICAgICAgICAgICAgICBzZWVuLmFkZChrZXkpOwoKICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwoKICAgICAgICAgICAgfSk7CgoKCiAgICAgICAgICAgIGNvbnN0IHRlYW1TZWxlY3QgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndGVhbS1zZWxlY3QnKTsKCiAgICAgICAgICAgIHRlYW1TZWxlY3QuaW5uZXJIVE1MID0gYWxsVGVhbXMubWFwKHQgPT4gYDxvcHRpb24gdmFsdWU9IiR7dH0iPiR7dH08L29wdGlvbj5gKS5qb2luKCcnKTsKCiAgICAgICAgICAgIHVwZGF0ZUZpbHRlcnMoKTsKCiAgICAgICAgICAgIHJlbmRlcigpOwoKICAgICAgICAgICAgbHVjaWRlLmNyZWF0ZUljb25zKCk7CgogICAgICAgIH0KCgoKICAgICAgICAvLyAtLS0gRGFzaGJvYXJkIFNlYXJjaCAmIEZpbHRlcnMgLS0tCgogICAgICAgIGNvbnN0IG1haW5TZWFyY2hJbnB1dCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdtYWluLXNlYXJjaCcpOwoKICAgICAgICBjb25zdCBzZWFyY2hEcm9wZG93biA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdzZWFyY2gtZHJvcGRvd24nKTsKCiAgICAgICAgY29uc3Qgc2VhcmNoUmVzdWx0c0xpc3QgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnc2VhcmNoLXJlc3VsdHMtbGlzdCcpOwoKCgogICAgICAgIG1haW5TZWFyY2hJbnB1dC5hZGRFdmVudExpc3RlbmVyKCdpbnB1dCcsIGZ1bmN0aW9uKGUpIHsKCiAgICAgICAgICAgIGNvbnN0IHZhbCA9IGUudGFyZ2V0LnZhbHVlLnRyaW0oKS50b0xvd2VyQ2FzZSgpOwoKICAgICAgICAgICAgaWYgKCF2YWwgfHwgdGVhbURhdGEubGVuZ3RoID09PSAwKSB7CgogICAgICAgICAgICAgICAgc2VhcmNoRHJvcGRvd24uY2xhc3NMaXN0LmFkZCgnaGlkZGVuJyk7CgogICAgICAgICAgICAgICAgcmV0dXJuOwoKICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29uc3QgbWF0Y2hlZFRlYW1zID0gYWxsVGVhbXMuZmlsdGVyKHQgPT4gdC50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKHZhbCkpOwoKICAgICAgICAgICAgY29uc3QgbWF0Y2hlZFBlb3BsZSA9IGFsbFBlb3BsZURhdGEuZmlsdGVyKHAgPT4gcC5uYW1lLnRvTG93ZXJDYXNlKCkuaW5jbHVkZXModmFsKSk7CgoKCiAgICAgICAgICAgIGlmIChtYXRjaGVkVGVhbXMubGVuZ3RoID09PSAwICYmIG1hdGNoZWRQZW9wbGUubGVuZ3RoID09PSAwKSB7CgogICAgICAgICAgICAgICAgc2VhcmNoUmVzdWx0c0xpc3QuaW5uZXJIVE1MID0gYDxkaXYgY2xhc3M9InB4LTQgcHktMyB0ZXh0LXNsYXRlLTQwMCB0ZXh0LXNtIGl0YWxpYyB0ZXh0LWNlbnRlciI+6rKA7IOJIOqysOqzvOqwgCDsl4bsirXri4jri6Q8L2Rpdj5gOwoKICAgICAgICAgICAgfSBlbHNlIHsKCiAgICAgICAgICAgICAgICBsZXQgaHRtbCA9ICIiOwoKICAgICAgICAgICAgICAgIGlmIChtYXRjaGVkVGVhbXMubGVuZ3RoID4gMCkgewoKICAgICAgICAgICAgICAgICAgICBodG1sICs9IGA8ZGl2IGNsYXNzPSJweC00IHB5LTEgdGV4dC1bMTBweF0gZm9udC1ibGFjayB0ZXh0LWJsdWUtNTAwIHVwcGVyY2FzZSB0cmFja2luZy13aWRlc3QgYmctYmx1ZS01MC81MCI+VGVhbXM8L2Rpdj5gOwoKICAgICAgICAgICAgICAgICAgICBtYXRjaGVkVGVhbXMuZm9yRWFjaCh0ID0+IHsKCiAgICAgICAgICAgICAgICAgICAgICAgIGh0bWwgKz0gYDxkaXYgY2xhc3M9InNlYXJjaC1pdGVtIHB4LTQgcHktMiBob3ZlcjpiZy1zbGF0ZS01MCBjdXJzb3ItcG9pbnRlciB0ZXh0LXNtIGZvbnQtYm9sZCB0ZXh0LXNsYXRlLTcwMCIgZGF0YS10eXBlPSJ0ZWFtIiBkYXRhLXZhbHVlPSIke3R9Ij4ke3R9PC9kaXY+YDsKCiAgICAgICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIGlmIChtYXRjaGVkUGVvcGxlLmxlbmd0aCA+IDApIHsKCiAgICAgICAgICAgICAgICAgICAgaHRtbCArPSBgPGRpdiBjbGFzcz0icHgtNCBweS0xIHRleHQtWzEwcHhdIGZvbnQtYmxhY2sgdGV4dC1lbWVyYWxkLTUwMCB1cHBlcmNhc2UgdHJhY2tpbmctd2lkZXN0IGJnLWVtZXJhbGQtNTAvNTAgbXQtMSI+UGVvcGxlPC9kaXY+YDsKCiAgICAgICAgICAgICAgICAgICAgbWF0Y2hlZFBlb3BsZS5mb3JFYWNoKHAgPT4gewoKICAgICAgICAgICAgICAgICAgICAgICAgaHRtbCArPSBgPGRpdiBjbGFzcz0ic2VhcmNoLWl0ZW0gcHgtNCBweS0yIGhvdmVyOmJnLXNsYXRlLTUwIGN1cnNvci1wb2ludGVyIHRleHQtc20gZmxleCBpdGVtcy1jZW50ZXIganVzdGlmeS1iZXR3ZWVuIiBkYXRhLXR5cGU9InBlcnNvbiIgZGF0YS1uYW1lPSIke3AubmFtZX0iIGRhdGEtdGVhbT0iJHtwLnRlYW19Ij4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJmb250LWJvbGQgdGV4dC1zbGF0ZS03MDAiPiR7cC5uYW1lfTwvc3Bhbj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJ0ZXh0LVsxMHB4XSB0ZXh0LXNsYXRlLTQwMCBmb250LW1lZGl1bSI+JHtwLnRlYW19PC9zcGFuPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+YDsKCiAgICAgICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHNlYXJjaFJlc3VsdHNMaXN0LmlubmVySFRNTCA9IGh0bWw7CgogICAgICAgICAgICB9CgogICAgICAgICAgICBzZWFyY2hEcm9wZG93bi5jbGFzc0xpc3QucmVtb3ZlKCdoaWRkZW4nKTsKCiAgICAgICAgfSk7CgoKCiAgICAgICAgc2VhcmNoUmVzdWx0c0xpc3QuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbihlKSB7CgogICAgICAgICAgICBjb25zdCBpdGVtID0gZS50YXJnZXQuY2xvc2VzdCgnLnNlYXJjaC1pdGVtJyk7CgogICAgICAgICAgICBpZiAoIWl0ZW0pIHJldHVybjsKCiAgICAgICAgICAgIGNvbnN0IHR5cGUgPSBpdGVtLmRhdGFzZXQudHlwZTsKCiAgICAgICAgICAgIGNvbnN0IHRlYW1TZWxlY3QgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndGVhbS1zZWxlY3QnKTsKCiAgICAgICAgICAgIGNvbnN0IHBlcnNvblNlbGVjdCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdwZXJzb24tc2VsZWN0Jyk7CgoKCiAgICAgICAgICAgIGlmICh0eXBlID09PSAndGVhbScpIHsKCiAgICAgICAgICAgICAgICB0ZWFtU2VsZWN0LnZhbHVlID0gaXRlbS5kYXRhc2V0LnZhbHVlOwoKICAgICAgICAgICAgICAgIHVwZGF0ZUZpbHRlcnMoKTsKCiAgICAgICAgICAgICAgICBwZXJzb25TZWxlY3QudmFsdWUgPSAiIjsKCiAgICAgICAgICAgIH0gZWxzZSB7CgogICAgICAgICAgICAgICAgdGVhbVNlbGVjdC52YWx1ZSA9IGl0ZW0uZGF0YXNldC50ZWFtOwoKICAgICAgICAgICAgICAgIHVwZGF0ZUZpbHRlcnMoKTsKCiAgICAgICAgICAgICAgICBwZXJzb25TZWxlY3QudmFsdWUgPSBpdGVtLmRhdGFzZXQubmFtZTsKCiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIG1haW5TZWFyY2hJbnB1dC52YWx1ZSA9ICIiOwoKICAgICAgICAgICAgc2VhcmNoRHJvcGRvd24uY2xhc3NMaXN0LmFkZCgnaGlkZGVuJyk7CgogICAgICAgICAgICByZW5kZXIoKTsKCiAgICAgICAgfSk7CgoKCiAgICAgICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbihlKSB7CgogICAgICAgICAgICBpZiAoIW1haW5TZWFyY2hJbnB1dC5jb250YWlucyhlLnRhcmdldCkgJiYgIXNlYXJjaERyb3Bkb3duLmNvbnRhaW5zKGUudGFyZ2V0KSkgewoKICAgICAgICAgICAgICAgIHNlYXJjaERyb3Bkb3duLmNsYXNzTGlzdC5hZGQoJ2hpZGRlbicpOwoKICAgICAgICAgICAgfQoKICAgICAgICB9KTsKCgoKICAgICAgICBmdW5jdGlvbiB1cGRhdGVGaWx0ZXJzKCkgewogICAgICAgICAgICBpZiAodGVhbURhdGEubGVuZ3RoID09PSAwKSByZXR1cm47CiAgICAgICAgICAgIGNvbnN0IHRlYW0gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndGVhbS1zZWxlY3QnKS52YWx1ZTsKICAgICAgICAgICAgaWYgKCF0ZWFtKSByZXR1cm47CiAgICAgICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdtYWluLXRpdGxlJykuaW5uZXJUZXh0ID0gdGVhbTsKICAgICAgICAgICAgY29uc3QgdGVhbVBlb3BsZSA9IFsuLi5uZXcgU2V0KHRlYW1EYXRhLnNsaWNlKDEpLmZpbHRlcihyID0+IFN0cmluZyhyW2NvbHVtbk1hcC50ZWFtXSB8fCAnJykudHJpbSgpID09PSB0ZWFtKS5tYXAociA9PiBTdHJpbmcocltjb2x1bW5NYXAubmFtZV0gfHwgJycpLnRyaW0oKSkpXS5zb3J0KCk7CiAgICAgICAgICAgIGNvbnN0IHBlcnNvblNlbGVjdCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdwZXJzb24tc2VsZWN0Jyk7CiAgICAgICAgICAgIHBlcnNvblNlbGVjdC5pbm5lckhUTUwgPSAnPG9wdGlvbiB2YWx1ZT0iIj7soITssrQg7J247JuQPC9vcHRpb24+JyArIHRlYW1QZW9wbGUubWFwKHAgPT4gYDxvcHRpb24gdmFsdWU9IiR7cH0iPiR7cH08L29wdGlvbj5gKS5qb2luKCcnKTsKICAgICAgICB9CgogICAgICAgIGZ1bmN0aW9uIHJlc2V0TWhWaWV3KCkgewogICAgICAgICAgICBpZiAodGVhbURhdGEubGVuZ3RoIDwgMikgcmV0dXJuOwogICAgICAgICAgICBjb25zdCB0ZWFtU2VsZWN0ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3RlYW0tc2VsZWN0Jyk7CiAgICAgICAgICAgIGNvbnN0IHBlcnNvblNlbGVjdCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdwZXJzb24tc2VsZWN0Jyk7CiAgICAgICAgICAgIGNvbnN0IG1haW5TZWFyY2ggPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbWFpbi1zZWFyY2gnKTsKICAgICAgICAgICAgY29uc3Qgc2VhcmNoRHJvcGRvd24gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnc2VhcmNoLWRyb3Bkb3duJyk7CiAgICAgICAgICAgIGNvbnN0IHN0YXJ0SW5wdXQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnc3RhcnQtZGF0ZScpOwogICAgICAgICAgICBjb25zdCBlbmRJbnB1dCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdlbmQtZGF0ZScpOwoKICAgICAgICAgICAgaWYgKG1haW5TZWFyY2gpIG1haW5TZWFyY2gudmFsdWUgPSAnJzsKICAgICAgICAgICAgaWYgKHNlYXJjaERyb3Bkb3duKSBzZWFyY2hEcm9wZG93bi5jbGFzc0xpc3QuYWRkKCdoaWRkZW4nKTsKCiAgICAgICAgICAgIGlmICh0ZWFtU2VsZWN0ICYmIHRlYW1TZWxlY3Qub3B0aW9ucy5sZW5ndGggPiAwKSB7CiAgICAgICAgICAgICAgICB0ZWFtU2VsZWN0LnNlbGVjdGVkSW5kZXggPSAwOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHVwZGF0ZUZpbHRlcnMoKTsKICAgICAgICAgICAgaWYgKHBlcnNvblNlbGVjdCkgcGVyc29uU2VsZWN0LnZhbHVlID0gJyc7CgogICAgICAgICAgICBjb25zdCBkYXRlcyA9IHRlYW1EYXRhLnNsaWNlKDEpLm1hcChyID0+IGRTdHIocltjb2x1bW5NYXAuZGF0ZV0pKS5maWx0ZXIoQm9vbGVhbikuc29ydCgpOwogICAgICAgICAgICBpZiAoZGF0ZXMubGVuZ3RoID4gMCkgewogICAgICAgICAgICAgICAgc3RhcnRJbnB1dC52YWx1ZSA9IGRhdGVzWzBdOwogICAgICAgICAgICAgICAgZW5kSW5wdXQudmFsdWUgPSBkYXRlc1tkYXRlcy5sZW5ndGggLSAxXTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgcmVuZGVyKCk7CiAgICAgICAgfQoKCiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3RlYW0tc2VsZWN0JykuYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgKCkgPT4geyB1cGRhdGVGaWx0ZXJzKCk7IHJlbmRlcigpOyB9KTsKCiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3BlcnNvbi1zZWxlY3QnKS5hZGRFdmVudExpc3RlbmVyKCdjaGFuZ2UnLCByZW5kZXIpOwoKICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnc3RhcnQtZGF0ZScpLmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIHJlbmRlcik7CgogICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdlbmQtZGF0ZScpLmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIHJlbmRlcik7CgoKCiAgICAgICAgLy8gLS0tIENvcmUgUmVuZGVyaW5nOiBEYXNoYm9hcmQgLS0tCgogICAgICAgIGZ1bmN0aW9uIHJlbmRlcigpIHsKCiAgICAgICAgICAgIGlmICh0ZWFtRGF0YS5sZW5ndGggPT09IDApIHJldHVybjsKCiAgICAgICAgICAgIGNvbnN0IHRlYW0gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndGVhbS1zZWxlY3QnKS52YWx1ZTsKCiAgICAgICAgICAgIGlmICghdGVhbSkgcmV0dXJuOwoKICAgICAgICAgICAgY29uc3QgcGVyc29uID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3BlcnNvbi1zZWxlY3QnKS52YWx1ZTsKCiAgICAgICAgICAgIGNvbnN0IHN0YXJ0ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3N0YXJ0LWRhdGUnKS52YWx1ZTsKCiAgICAgICAgICAgIGNvbnN0IGVuZCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdlbmQtZGF0ZScpLnZhbHVlOwoKCgogICAgICAgICAgICBjb25zdCB0YXJnZXRIID0gY2FsY3VsYXRlVGFyZ2V0SG91cnMoc3RhcnQsIGVuZCk7CgogICAgICAgICAgICBjb25zdCByZXN1bHRzID0gcHJvY2Vzc0RhdGEodGVhbSwgcGVyc29uLCBzdGFydCwgZW5kLCB0YXJnZXRIKTsKCiAgICAgICAgICAgIHJlbmRlcktQSXMocmVzdWx0cy5zdGF0cyk7CgogICAgICAgICAgICByZW5kZXJNYXRyaXgocmVzdWx0cy5tYXRyaXgpOwoKICAgICAgICAgICAgZHJhd0NoYXJ0KHJlc3VsdHMucGVyc29uUm93cywgdGFyZ2V0SCwgcGVyc29uLCBzdGFydCwgZW5kKTsKCiAgICAgICAgICAgIGx1Y2lkZS5jcmVhdGVJY29ucygpOwoKICAgICAgICB9CgoKCiAgICAgICAgZnVuY3Rpb24gcHJvY2Vzc0RhdGEodGVhbUYsIHBlcnNvbkYsIHN0YXJ0U3RyLCBlbmRTdHIsIHRhcmdldEgpIHsKICAgICAgICAgICAgbGV0IHBNYXAgPSB7fTsgbGV0IG1NYXAgPSB7fTsKICAgICAgICAgICAgbGV0IHN0YXRzID0geyB0b3RhbE1IOiAwLCBwZXJzb25Db3VudDogMCwgZXh0cmFIb2xNSDogMCwgb3ZlckNvdW50OiAwLCBsYWJvckNvc3Q6IDAsIGhhc0xhYm9yQ29zdENvbHM6IChjb2x1bW5NYXAubm9ybWFsQ29zdCA+PSAwIHx8IGNvbHVtbk1hcC5leHRyYUNvc3QgPj0gMCkgfTsKICAgICAgICAgICAgY29uc3Qgc2xvdHMgPSBjb2x1bW5NYXAuc2xvdHMgfHwgW107CgogICAgICAgICAgICB0ZWFtRGF0YS5zbGljZSgxKS5mb3JFYWNoKHJvdyA9PiB7CiAgICAgICAgICAgICAgICBjb25zdCBkID0gZFN0cihyb3dbY29sdW1uTWFwLmRhdGVdKTsKICAgICAgICAgICAgICAgIGlmICghZCB8fCBkIDwgc3RhcnRTdHIgfHwgZCA+IGVuZFN0ciB8fCBTdHJpbmcocm93W2NvbHVtbk1hcC50ZWFtXSB8fCAnJykudHJpbSgpICE9PSB0ZWFtRikgcmV0dXJuOwogICAgICAgICAgICAgICAgY29uc3QgaXNXZWVrZW5kID0gU3RyaW5nKHJvd1tjb2x1bW5NYXAudXNlclN0YXRlXSB8fCAnJykuaW5jbHVkZXMoIuyjvOunkCIpOwogICAgICAgICAgICAgICAgY29uc3QgbmFtZSA9IFN0cmluZyhyb3dbY29sdW1uTWFwLm5hbWVdIHx8ICcnKS50cmltKCk7CiAgICAgICAgICAgICAgICBjb25zdCByYW5rID0gU3RyaW5nKHJvd1tjb2x1bW5NYXAucmFua10gfHwgJ+yXsOq1rOybkCcpLnRyaW0oKTsKICAgICAgICAgICAgICAgIGlmICghbmFtZSkgcmV0dXJuOwogICAgICAgICAgICAgICAgc3RhdHMubGFib3JDb3N0ICs9IHBhcnNlTnVtYmVyKHJvd1tjb2x1bW5NYXAubm9ybWFsQ29zdF0pICsgcGFyc2VOdW1iZXIocm93W2NvbHVtbk1hcC5leHRyYUNvc3RdKTsKICAgICAgICAgICAgICAgIGlmICghcE1hcFtuYW1lXSkgcE1hcFtuYW1lXSA9IHsgbmFtZSwgcmFuaywgbm9ybWFsOiAwLCBleHRyYTogMCwgaG9saWRheTogMCwgdG90YWw6IDAsIHByb2plY3RzOiB7fSB9OwogICAgICAgICAgICAgICAgc2xvdHMuZm9yRWFjaChzID0+IHsKICAgICAgICAgICAgICAgICAgICBjb25zdCB2YWwgPSBwYXJzZU51bWJlcihyb3dbcy50aW1lXSk7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgcE5hbWUgPSBTdHJpbmcocm93W3MucHJval0gfHwgJycpLnRyaW0oKTsKICAgICAgICAgICAgICAgICAgICBjb25zdCBiaXogPSAocy5iaXogPj0gMCA/IFN0cmluZyhyb3dbcy5iaXpdIHx8ICcnKSA6ICcnKS50cmltKCkgfHwgJ+qzte2GtSc7CiAgICAgICAgICAgICAgICAgICAgaWYgKHZhbCA+IDAgJiYgcE5hbWUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHMudG90YWxNSCArPSB2YWw7IHBNYXBbbmFtZV0udG90YWwgKz0gdmFsOwogICAgICAgICAgICAgICAgICAgICAgICBsZXQgdHlwZSA9ICdub3JtYWwnOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNXZWVrZW5kKSB7IHR5cGUgPSAnaG9saWRheSc7IHBNYXBbbmFtZV0uaG9saWRheSArPSB2YWw7IHN0YXRzLmV4dHJhSG9sTUggKz0gdmFsOyB9CgogICAgICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChzLmV4dHJhKSB7IHR5cGUgPSAnZXh0cmEnOyBwTWFwW25hbWVdLmV4dHJhICs9IHZhbDsgc3RhdHMuZXh0cmFIb2xNSCArPSB2YWw7IH0KCiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgeyBwTWFwW25hbWVdLm5vcm1hbCArPSB2YWw7IH0KCiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghcE1hcFtuYW1lXS5wcm9qZWN0c1twTmFtZV0pIHBNYXBbbmFtZV0ucHJvamVjdHNbcE5hbWVdID0geyBub3JtYWw6IDAsIGV4dHJhOiAwLCBob2xpZGF5OiAwLCB0b3RhbDogMCB9OwoKICAgICAgICAgICAgICAgICAgICAgICAgcE1hcFtuYW1lXS5wcm9qZWN0c1twTmFtZV0udG90YWwgKz0gdmFsOyBwTWFwW25hbWVdLnByb2plY3RzW3BOYW1lXVt0eXBlXSArPSB2YWw7CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoIW1NYXBbYml6XSkgbU1hcFtiaXpdID0ge307CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoIW1NYXBbYml6XVtwTmFtZV0pIHsKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtTWFwW2Jpel1bcE5hbWVdID0geyB0b3RhbDogMCwgcHM6IG5ldyBTZXQoKSwgcmFua0RldGFpbHM6IHsgIuyImOyEnSI6IHsgbWg6IDAsIHBzOiBuZXcgU2V0KCkgfSwgIuyxheyehCI6IHsgbWg6IDAsIHBzOiBuZXcgU2V0KCkgfSwgIuyEoOyehCI6IHsgbWg6IDAsIHBzOiBuZXcgU2V0KCkgfSwgIuyXsOq1rOybkCI6IHsgbWg6IDAsIHBzOiBuZXcgU2V0KCkgfSB9IH07CgogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICBtTWFwW2Jpel1bcE5hbWVdLnRvdGFsICs9IHZhbDsgbU1hcFtiaXpdW3BOYW1lXS5wcy5hZGQobmFtZSk7CgogICAgICAgICAgICAgICAgICAgICAgICBjb25zdCByS2V5ID0gcmFuay5pbmNsdWRlcygi7IiY7ISdIikgPyAi7IiY7ISdIiA6IHJhbmsuaW5jbHVkZXMoIuyxheyehCIpID8gIuyxheyehCIgOiByYW5rLmluY2x1ZGVzKCLshKDsnoQiKSA/ICLshKDsnoQiIDogIuyXsOq1rOybkCI7CgogICAgICAgICAgICAgICAgICAgICAgICBtTWFwW2Jpel1bcE5hbWVdLnJhbmtEZXRhaWxzW3JLZXldLm1oICs9IHZhbDsgbU1hcFtiaXpdW3BOYW1lXS5yYW5rRGV0YWlsc1tyS2V5XS5wcy5hZGQobmFtZSk7CgogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgIH0pOwoKCgogICAgICAgICAgICBjb25zdCB0ZWFtTGlzdCA9IE9iamVjdC52YWx1ZXMocE1hcCkuc29ydCgoYSwgYikgPT4gewoKICAgICAgICAgICAgICAgIGNvbnN0IHdhID0gUkFOS19XRUlHSFRTW2EucmFuay5pbmNsdWRlcygn7IiY7ISdJykgPyAn7IiY7ISdJyA6IGEucmFuay5pbmNsdWRlcygn7LGF7J6EJykgPyAn7LGF7J6EJyA6IGEucmFuay5pbmNsdWRlcygn7ISg7J6EJykgPyAn7ISg7J6EJyA6ICfsl7Dqtazsm5AnXSB8fCA5OTsKCiAgICAgICAgICAgICAgICBjb25zdCB3YiA9IFJBTktfV0VJR0hUU1tiLnJhbmsuaW5jbHVkZXMoJ+yImOyEnScpID8gJ+yImOyEnScgOiBiLnJhbmsuaW5jbHVkZXMoJ+yxheyehCcpID8gJ+yxheyehCcgOiBiLnJhbmsuaW5jbHVkZXMoJ+yEoOyehCcpID8gJ+yEoOyehCcgOiAn7Jew6rWs7JuQJ10gfHwgOTk7CgogICAgICAgICAgICAgICAgcmV0dXJuICh3YSAhPT0gd2IpID8gd2EgLSB3YiA6IGEubmFtZS5sb2NhbGVDb21wYXJlKGIubmFtZSwgJ2tvJyk7CgogICAgICAgICAgICB9KTsKCiAgICAgICAgICAgIHN0YXRzLnBlcnNvbkNvdW50ID0gdGVhbUxpc3QubGVuZ3RoOwoKICAgICAgICAgICAgdGVhbUxpc3QuZm9yRWFjaChwID0+IHsgaWYgKHAudG90YWwgPiB0YXJnZXRIKSBzdGF0cy5vdmVyQ291bnQrKzsgfSk7CgoKCiAgICAgICAgICAgIGNvbnN0IHBlcnNvblJvd3MgPSB0ZWFtTGlzdC5tYXAocCA9PiAoewogICAgICAgICAgICAgICAgbmFtZTogcC5uYW1lLAogICAgICAgICAgICAgICAgcmFuazogcC5yYW5rLAogICAgICAgICAgICAgICAgbm9ybWFsOiBwLm5vcm1hbCwKICAgICAgICAgICAgICAgIGV4dHJhOiBwLmV4dHJhLAogICAgICAgICAgICAgICAgaG9saWRheTogcC5ob2xpZGF5LAogICAgICAgICAgICAgICAgdG90YWw6IHAudG90YWwsCiAgICAgICAgICAgICAgICBwcm9qZWN0czogT2JqZWN0LmVudHJpZXMocC5wcm9qZWN0cykKICAgICAgICAgICAgICAgICAgICAubWFwKChbcHJvamVjdE5hbWUsIGRdKSA9PiAoeyBwcm9qZWN0TmFtZSwgLi4uZCB9KSkKICAgICAgICAgICAgICAgICAgICAuc29ydCgoYSwgYikgPT4gYi50b3RhbCAtIGEudG90YWwpCiAgICAgICAgICAgIH0pKTsKCiAgICAgICAgICAgIHJldHVybiB7IHN0YXRzLCBtYXRyaXg6IG1NYXAsIHBlcnNvblJvd3MgfTsKCiAgICAgICAgfQoKCgogICAgICAgIGZ1bmN0aW9uIHJlbmRlcktQSXMocykgewogICAgICAgICAgICBjb25zdCBjb250YWluZXIgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgna3BpLWNvbnRhaW5lcicpOwogICAgICAgICAgICBjb25zdCBsYWJvckNvc3RUZXh0ID0gcy5oYXNMYWJvckNvc3RDb2xzCiAgICAgICAgICAgICAgICA/ICgn4oKpJyArIE51bWJlcihzLmxhYm9yQ29zdCB8fCAwKS50b0xvY2FsZVN0cmluZygna28tS1InKSkKICAgICAgICAgICAgICAgIDogKHMub3ZlckNvdW50ICsgJ+uqhScpOwogICAgICAgICAgICBjb25zdCBjYXJkcyA9IFsKICAgICAgICAgICAgICAgIHsgdGl0bGU6ICLstJ0g7Yis7J6FIOyLnOqwhCIsIHZhbDogZm9ybWF0TnVtKHMudG90YWxNSCkgKyAnaCcsIGljb246ICJjbG9jayIsIGNvbG9yOiAidGV4dC1ibHVlLTYwMCIsIGJnOiAiYmctYmx1ZS01MCIsIGljb25Cb3JkZXI6ICJib3JkZXItYmx1ZS0xMDAiLCByaW5nOiAicmluZy1ibHVlLTUwMC8xMCIsIHN1YjogIlRlYW0gVG90YWwiIH0sCiAgICAgICAgICAgICAgICB7IHRpdGxlOiAi7LC47JesIOyLpOustOyekCIsIHZhbDogcy5wZXJzb25Db3VudCArICfrqoUnLCBpY29uOiAidXNlcnMiLCBjb2xvcjogInRleHQtZW1lcmFsZC02MDAiLCBiZzogImJnLWVtZXJhbGQtNTAiLCBpY29uQm9yZGVyOiAiYm9yZGVyLWVtZXJhbGQtMTAwIiwgcmluZzogInJpbmctZW1lcmFsZC01MDAvMTAiLCBzdWI6ICJBY3RpdmUgTWVtYmVycyIgfSwKICAgICAgICAgICAgICAgIHsgdGl0bGU6ICLstJ0g7Jew7J6lL+2ctOydvCIsIHZhbDogZm9ybWF0TnVtKHMuZXh0cmFIb2xNSCkgKyAnaCcsIGljb246ICJhbGVydC1jaXJjbGUiLCBjb2xvcjogInRleHQtYW1iZXItNjAwIiwgYmc6ICJiZy1hbWJlci01MCIsIGljb25Cb3JkZXI6ICJib3JkZXItYW1iZXItMTAwIiwgcmluZzogInJpbmctYW1iZXItNTAwLzEwIiwgc3ViOiAiT3ZlcnRpbWUgJiBXZWVrZW5kIiB9LAogICAgICAgICAgICAgICAgeyB0aXRsZTogIuyduOqxtOu5hCIsIHZhbDogbGFib3JDb3N0VGV4dCwgaWNvbjogIndhbGxldCIsIGNvbG9yOiAidGV4dC1yZWQtNjAwIiwgYmc6ICJiZy1yZWQtNTAiLCBpY29uQm9yZGVyOiAiYm9yZGVyLXJlZC0xMDAiLCByaW5nOiAicmluZy1yZWQtNTAwLzEwIiwgc3ViOiAocy5oYXNMYWJvckNvc3RDb2xzID8gIkxhYm9yIENvc3QiIDogIk92ZXJsaW1pdCIpIH0KICAgICAgICAgICAgXTsKICAgICAgICAgICAgY29udGFpbmVyLmlubmVySFRNTCA9IGNhcmRzLm1hcChjID0+IGAKCiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJiZy13aGl0ZSBwLTcgcm91bmRlZC1bMnJlbV0gc2hhZG93LXhsIGJvcmRlciBib3JkZXItc2xhdGUtMjAwIHRyYW5zaXRpb24tYWxsIGhvdmVyOi10cmFuc2xhdGUteS0xIHJpbmctNCAke2MucmluZ30iPgoKICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJmbGV4IGp1c3RpZnktYmV0d2VlbiBpdGVtcy1zdGFydCBtYi00Ij4KCiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9InAtMyAke2MuYmd9ICR7Yy5jb2xvcn0gcm91bmRlZC0yeGwgYm9yZGVyICR7Yy5pY29uQm9yZGVyfSBzaGFkb3ctc20iPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxpIGRhdGEtbHVjaWRlPSIke2MuaWNvbn0iPjwvaT4KCiAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgoKICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InRleHQtWzEwcHhdIGZvbnQtYmxhY2sgdGV4dC1zbGF0ZS0zMDAgdXBwZXJjYXNlIHRyYWNraW5nLXdpZGVzdCI+JHtjLnN1Yn08L3NwYW4+CgogICAgICAgICAgICAgICAgICAgIDwvZGl2PgoKICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJ0ZXh0LTN4bCBmb250LWJsYWNrIHRleHQtc2xhdGUtODAwIG1iLTIgdHJhY2tpbmctdGlnaHRlciBsZWFkaW5nLW5vbmUiPiR7Yy52YWx9PC9kaXY+CgogICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9InRleHQtWzExcHhdIGZvbnQtYmxhY2sgdGV4dC1zbGF0ZS00MDAgdXBwZXJjYXNlIHRyYWNraW5nLVswLjJlbV0iPiR7Yy50aXRsZX08L2Rpdj4KCiAgICAgICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgIGApLmpvaW4oJycpOwoKICAgICAgICB9CgoKCiAgICAgICAgZnVuY3Rpb24gcmVuZGVyTWF0cml4KG0pIHsKCiAgICAgICAgICAgIGNvbnN0IHZpc3VhbENvbnRhaW5lciA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdtYXRyaXgtdmlzdWFsLWNvbnRhaW5lcicpOwoKICAgICAgICAgICAgY29uc3QgZm9vdGVyVmlzdWFsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ21hdHJpeC1mb290ZXItdmlzdWFsJyk7CgogICAgICAgICAgICBsZXQgYml6RGF0YSA9IFtdOyBsZXQgY2FyZHNIdG1sID0gIiI7IGxldCBncmFuZFRvdGFsID0gMDsgbGV0IGdyYW5kUGVvcGxlID0gbmV3IFNldCgpOwoKICAgICAgICAgICAgbGV0IHRvdGFsUHJvamVjdHNDb3VudCA9IDA7CgoKCiAgICAgICAgICAgIE9iamVjdC5lbnRyaWVzKG0pLmZvckVhY2goKFtiaXosIHByb2pzXSkgPT4gewoKICAgICAgICAgICAgICAgIGxldCBiaXpUb3RhbCA9IDA7IGxldCBiaXpQcm9qcyA9IFtdOwoKICAgICAgICAgICAgICAgIE9iamVjdC5lbnRyaWVzKHByb2pzKS5mb3JFYWNoKChbcHJvak5hbWUsIGRdKSA9PiB7CgogICAgICAgICAgICAgICAgICAgIGJpelRvdGFsICs9IGQudG90YWw7IGdyYW5kVG90YWwgKz0gZC50b3RhbDsgZC5wcy5mb3JFYWNoKHAgPT4gZ3JhbmRQZW9wbGUuYWRkKHApKTsKCiAgICAgICAgICAgICAgICAgICAgYml6UHJvanMucHVzaCh7IAoKICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTogcHJvak5hbWUsIAoKICAgICAgICAgICAgICAgICAgICAgICAgdG90YWw6IGQudG90YWwsIAoKICAgICAgICAgICAgICAgICAgICAgICAgcGVvcGxlQ291bnQ6IGQucHMuc2l6ZSwgCgogICAgICAgICAgICAgICAgICAgICAgICByYW5rRGV0YWlsczogZC5yYW5rRGV0YWlscwoKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgdG90YWxQcm9qZWN0c0NvdW50Kys7CgogICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgYml6RGF0YS5wdXNoKFtiaXosIGJpelRvdGFsXSk7CgogICAgICAgICAgICAgICAgY2FyZHNIdG1sICs9IGAKCiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0iYmctd2hpdGUgYm9yZGVyIGJvcmRlci1zbGF0ZS0xMDAgcm91bmRlZC1bMS41cmVtXSBwLTUgc2hhZG93LXNtIGhvdmVyOnNoYWRvdy1tZCB0cmFuc2l0aW9uLXNoYWRvdyBicmVhay1pbnNpZGUtYXZvaWQtY29sdW1uIG1iLTQiPgoKICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0iZmxleCBqdXN0aWZ5LWJldHdlZW4gaXRlbXMtc3RhcnQgbWItNCI+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPGg1IGNsYXNzPSJmb250LWJsYWNrIHRleHQtc2xhdGUtOTAwIHRleHQtbGcgdHJhY2tpbmctdGlnaHQgbXItMiI+JHtiaXp9PC9oNT4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0iYmctYmx1ZS01MCB0ZXh0LWJsdWUtNjAwIHB4LTMgcHktMSByb3VuZGVkLWZ1bGwgdGV4dC1bMTFweF0gZm9udC1ibGFjayBzaHJpbmstMCI+JHtmb3JtYXROdW0oYml6VG90YWwpfWg8L3NwYW4+CgogICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9InNwYWNlLXktNCI+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgJHtiaXpQcm9qcy5tYXAocCA9PiBgCgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9ImJvcmRlci1iIGJvcmRlci1zbGF0ZS01MCBsYXN0OmJvcmRlci0wIHBiLTMgbGFzdDpwYi0wIGdyb3VwIGJyZWFrLWluc2lkZS1hdm9pZCI+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWJldHdlZW4gbWItMSI+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gb25jbGljaz0ic2hvd1Byb2plY3RNZW1iZXJzKCcke3AubmFtZS5yZXBsYWNlKC8nL2csICJcXCciKX0nKSIgY2xhc3M9InRleHQtc2xhdGUtNzAwIGZvbnQtYm9sZCBob3Zlcjp0ZXh0LWJsdWUtNjAwIGhvdmVyOnVuZGVybGluZSBjdXJzb3ItcG9pbnRlciB0cmFuc2l0aW9uLWNvbG9ycyBmbGV4LTEgcHItMiI+JHtwLm5hbWV9PC9zcGFuPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9ImZsZXggaXRlbXMtY2VudGVyIGdhcC0xIHNocmluay0wIj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InRleHQtc2xhdGUtOTAwIGZvbnQtYmxhY2siPiR7Zm9ybWF0TnVtKHAudG90YWwpfWg8L3NwYW4+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJ0ZXh0LVsxMHB4XSB0ZXh0LXNsYXRlLTQwMCBmb250LWJvbGQiPigke3AucGVvcGxlQ291bnR966qFKTwvc3Bhbj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0ic3BhY2UteS0yIG10LTIiPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICR7T2JqZWN0LmVudHJpZXMocC5yYW5rRGV0YWlscykuZmlsdGVyKChbciwgaW5mb10pID0+IGluZm8ubWggPiAwKS5tYXAoKFtyYW5rLCBpbmZvXSkgPT4gYAoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJ0ZXh0LVsxMXB4XSBiZy1zbGF0ZS01MC84MCBweC0yLjUgcHktMiByb3VuZGVkLXhsIGJvcmRlciBib3JkZXItc2xhdGUtMTAwIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0iZmxleCBqdXN0aWZ5LWJldHdlZW4gaXRlbXMtY2VudGVyIG1iLTEiPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJ0ZXh0LVsxMXB4XSB0ZXh0LXNsYXRlLTUwMCBmb250LWJsYWNrIj4ke3Jhbmt9PC9zcGFuPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InRleHQtWzExcHhdIHRleHQtc2xhdGUtOTAwIGZvbnQtYmxhY2siPiR7Zm9ybWF0TnVtKGluZm8ubWgpfWggPHNtYWxsIGNsYXNzPSJ0ZXh0LVsxMHB4XSB0ZXh0LXNsYXRlLTQwMCI+KCR7aW5mby5wcy5zaXplfeuqhSk8L3NtYWxsPjwvc3Bhbj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJ0ZXh0LVsxMXB4XSB0ZXh0LXNsYXRlLTQwMCBmb250LWJvbGQgbGVhZGluZy1yZWxheGVkIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICR7QXJyYXkuZnJvbShpbmZvLnBzKS5qb2luKCcsICcpfQoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGApLmpvaW4oJycpfQoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGApLmpvaW4oJycpfQoKICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CgogICAgICAgICAgICAgICAgICAgIDwvZGl2PgoKICAgICAgICAgICAgICAgIGA7CgogICAgICAgICAgICB9KTsKCiAgICAgICAgICAgIHZpc3VhbENvbnRhaW5lci5pbm5lckhUTUwgPSBjYXJkc0h0bWw7CgogICAgICAgICAgICAKCiAgICAgICAgICAgIGZvb3RlclZpc3VhbC5pbm5lckhUTUwgPSBgCgogICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0iZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTQiPgoKICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJ0ZXh0LXJpZ2h0Ij4KCiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJ0ZXh0LVsxMHB4XSBmb250LWJsYWNrIHRleHQtc2xhdGUtNDAwIHVwcGVyY2FzZSB0cmFja2luZy13aWRlc3QgYmxvY2siPuynhO2WiSDtlITroZzsoJ3tirg8L3NwYW4+CgogICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJ0ZXh0LXhsIGZvbnQtYmxhY2sgdGV4dC1ibHVlLTYwMCBsZWFkaW5nLW5vbmUiPiR7dG90YWxQcm9qZWN0c0NvdW50feqwnDwvZGl2PgoKICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgIGA7CgogICAgICAgICAgICAKCiAgICAgICAgICAgIGNvbnN0IGR0ID0gbmV3IGdvb2dsZS52aXN1YWxpemF0aW9uLkRhdGFUYWJsZSgpOyBkdC5hZGRDb2x1bW4oJ3N0cmluZycsICdCdXNpbmVzcyBVbml0Jyk7IGR0LmFkZENvbHVtbignbnVtYmVyJywgJ1RvdGFsIE1IJyk7IGR0LmFkZFJvd3MoYml6RGF0YSk7CgogICAgICAgICAgICBjb25zdCBjaGFydCA9IG5ldyBnb29nbGUudmlzdWFsaXphdGlvbi5QaWVDaGFydChkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYml6X3BpZV9jaGFydCcpKTsKCiAgICAgICAgICAgIGNoYXJ0LmRyYXcoZHQsIHsgcGllSG9sZTogMC41LCBjb2xvcnM6IFsnIzNiODJmNicsICcjMTBiOTgxJywgJyNmNTllMGInLCAnI2Y0M2Y1ZScsICcjOGI1Y2Y2JywgJyM2NDc0OGInXSwgbGVnZW5kOiB7IHBvc2l0aW9uOiAnYm90dG9tJywgdGV4dFN0eWxlOiB7IGZvbnRTaXplOiAxMSwgZm9udE5hbWU6ICdOb3RvIFNhbnMgS1InLCBib2xkOiB0cnVlLCBjb2xvcjogJyM2NDc0OGInIH0gfSwgY2hhcnRBcmVhOiB7IHdpZHRoOiAnOTAlJywgaGVpZ2h0OiAnODAlJyB9LCBwaWVTbGljZVRleHQ6ICdub25lJywgYmFja2dyb3VuZENvbG9yOiAndHJhbnNwYXJlbnQnLCB0b29sdGlwOiB7IGlzSHRtbDogdHJ1ZSB9IH0pOwoKICAgICAgICB9CgoKCiAgICAgICAgZnVuY3Rpb24gZHJhd0NoYXJ0KHBlcnNvblJvd3MsIHRhcmdldEgsIHBlcnNvbkYsIHN0YXJ0U3RyLCBlbmRTdHIpIHsKICAgICAgICAgICAgY29uc3QgY29udGFpbmVyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2NoYXJ0X2RpdicpOwogICAgICAgICAgICBjb25zdCB0aXRsZUVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2NoYXJ0LXRpdGxlJyk7CiAgICAgICAgICAgIGNvbnN0IGljb25FbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdjaGFydC1pY29uJyk7CiAgICAgICAgICAgIGNvbnN0IHRhcmdldEJhZGdlID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3RhcmdldC1iYWRnZScpOwogICAgICAgICAgICBjb25zdCBjaGFydERlc2MgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnY2hhcnQtZGVzYycpOwogICAgICAgICAgICBjb250YWluZXIuY2xhc3NMaXN0LnJlbW92ZSgnZmxleCcsICdpdGVtcy1jZW50ZXInLCAnanVzdGlmeS1jZW50ZXInKTsKICAgICAgICAgICAgY29udGFpbmVyLmNsYXNzTGlzdC5hZGQoJ2Jsb2NrJyk7CgogICAgICAgICAgICB0aXRsZUVsLmlubmVyVGV4dCA9ICfqsJzsnbjrs4Qg7ZiE7ZmpJzsKICAgICAgICAgICAgY2hhcnREZXNjLmlubmVyVGV4dCA9ICcnOwogICAgICAgICAgICBjaGFydERlc2MuY2xhc3NMaXN0LmFkZCgnaGlkZGVuJyk7CiAgICAgICAgICAgIHRhcmdldEJhZGdlLmNsYXNzTGlzdC5hZGQoJ2hpZGRlbicpOwogICAgICAgICAgICBpY29uRWwuc2V0QXR0cmlidXRlKCdkYXRhLWx1Y2lkZScsICdsYXlvdXQtZ3JpZCcpOwoKICAgICAgICAgICAgY29uc3Qgcm93cyA9IChwZXJzb25GID8gcGVyc29uUm93cy5maWx0ZXIocCA9PiBwLm5hbWUgPT09IHBlcnNvbkYpIDogcGVyc29uUm93cykgfHwgW107CiAgICAgICAgICAgIGlmICghcm93cy5sZW5ndGgpIHsKICAgICAgICAgICAgICAgIGNvbnRhaW5lci5pbm5lckhUTUwgPSAnPGRpdiBjbGFzcz0idGV4dC1zbGF0ZS0zMDAgZm9udC1ib2xkIGl0YWxpYyBwLTEwIHRleHQtY2VudGVyIHctZnVsbCI+7ZGc7Iuc7ZWgIOuNsOydtO2EsOqwgCDsl4bsirXri4jri6QuPC9kaXY+JzsKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29uc3QgZm9ybWF0SG91ciA9ICh2KSA9PiB7CiAgICAgICAgICAgICAgICBjb25zdCBuID0gTnVtYmVyKHYgfHwgMCk7CiAgICAgICAgICAgICAgICBpZiAoIU51bWJlci5pc0Zpbml0ZShuKSkgcmV0dXJuICcwJzsKICAgICAgICAgICAgICAgIHJldHVybiBOdW1iZXIuaXNJbnRlZ2VyKG4pID8gU3RyaW5nKG4pIDogbi50b0ZpeGVkKDEpLnJlcGxhY2UoL1wuMCQvLCAnJyk7CiAgICAgICAgICAgIH07CiAgICAgICAgICAgIGNvbnN0IHRvU2hvcnREYXRlID0gKHMpID0+IHsKICAgICAgICAgICAgICAgIGNvbnN0IGQgPSBuZXcgRGF0ZShzKTsKICAgICAgICAgICAgICAgIGlmIChpc05hTihkLmdldFRpbWUoKSkpIHJldHVybiBzIHx8ICctJzsKICAgICAgICAgICAgICAgIGNvbnN0IHl5ID0gU3RyaW5nKGQuZ2V0RnVsbFllYXIoKSkuc2xpY2UoMik7CiAgICAgICAgICAgICAgICBjb25zdCBtbSA9IFN0cmluZyhkLmdldE1vbnRoKCkgKyAxKS5wYWRTdGFydCgyLCAnMCcpOwogICAgICAgICAgICAgICAgY29uc3QgZGQgPSBTdHJpbmcoZC5nZXREYXRlKCkpLnBhZFN0YXJ0KDIsICcwJyk7CiAgICAgICAgICAgICAgICByZXR1cm4gYCR7eXl9LiR7bW19LiR7ZGR9YDsKICAgICAgICAgICAgfTsKICAgICAgICAgICAgY29uc3QgZGF0ZVJhbmdlVGV4dCA9IGAke3RvU2hvcnREYXRlKHN0YXJ0U3RyKX0gfiAke3RvU2hvcnREYXRlKGVuZFN0cil9YDsKICAgICAgICAgICAgY29uc3QgbWFya2VyID0gewogICAgICAgICAgICAgICAgbm9ybWFsOiB7IGJhcjogJyM2MzY2ZjEnLCB0ZXh0OiAndGV4dC1pbmRpZ28tNjAwJywgZG90OiAnYmctaW5kaWdvLTUwMCcgfSwKICAgICAgICAgICAgICAgIGV4dHJhOiB7IGJhcjogJyNmNTllMGInLCB0ZXh0OiAndGV4dC1hbWJlci02MDAnLCBkb3Q6ICdiZy1hbWJlci01MDAnIH0sCiAgICAgICAgICAgICAgICBob2xpZGF5OiB7IGJhcjogJyNlZjQ0NDQnLCB0ZXh0OiAndGV4dC1yZWQtNTAwJywgZG90OiAnYmctcmVkLTUwMCcgfQogICAgICAgICAgICB9OwogICAgICAgICAgICBjb25zdCBwcm9qZWN0VG9uZVR5cGUgPSAocCkgPT4gewogICAgICAgICAgICAgICAgaWYgKE51bWJlcihwLmhvbGlkYXkgfHwgMCkgPiAwKSByZXR1cm4gJ2hvbGlkYXknOwogICAgICAgICAgICAgICAgaWYgKE51bWJlcihwLmV4dHJhIHx8IDApID4gMCkgcmV0dXJuICdleHRyYSc7CiAgICAgICAgICAgICAgICByZXR1cm4gJ25vcm1hbCc7CiAgICAgICAgICAgIH07CiAgICAgICAgICAgIGNvbnN0IHByb2plY3RUaW1lSHRtbCA9IChwLCB0b25lVHlwZSkgPT4gewogICAgICAgICAgICAgICAgY29uc3QgcGFydHMgPSBbXTsKICAgICAgICAgICAgICAgIGlmIChOdW1iZXIocC5ub3JtYWwgfHwgMCkgPiAwKSBwYXJ0cy5wdXNoKGA8c3BhbiBjbGFzcz0idGV4dC1zbGF0ZS03MDAiPiR7Zm9ybWF0SG91cihwLm5vcm1hbCl9PC9zcGFuPmApOwogICAgICAgICAgICAgICAgaWYgKE51bWJlcihwLmV4dHJhIHx8IDApID4gMCkgcGFydHMucHVzaChgPHNwYW4gY2xhc3M9IiR7bWFya2VyLmV4dHJhLnRleHR9Ij4rJHtmb3JtYXRIb3VyKHAuZXh0cmEpfTwvc3Bhbj5gKTsKICAgICAgICAgICAgICAgIGlmIChOdW1iZXIocC5ob2xpZGF5IHx8IDApID4gMCkgcGFydHMucHVzaChgPHNwYW4gY2xhc3M9IiR7bWFya2VyLmhvbGlkYXkudGV4dH0iPiske2Zvcm1hdEhvdXIocC5ob2xpZGF5KX08L3NwYW4+YCk7CiAgICAgICAgICAgICAgICBpZiAoIXBhcnRzLmxlbmd0aCkgcGFydHMucHVzaCgnPHNwYW4gY2xhc3M9InRleHQtc2xhdGUtNzAwIj4wPC9zcGFuPicpOwogICAgICAgICAgICAgICAgcmV0dXJuIGAke3BhcnRzLmpvaW4oJyAnKX08c3BhbiBjbGFzcz0ibWwtMSAke21hcmtlclt0b25lVHlwZV0udGV4dH0iPuyLnOqwhDwvc3Bhbj5gOwogICAgICAgICAgICB9OwoKICAgICAgICAgICAgY29udGFpbmVyLmlubmVySFRNTCA9IGAKICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9InNwYWNlLXktNCB3LWZ1bGwiPgogICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9ImZsZXggaXRlbXMtY2VudGVyIGdhcC01IHB4LTEiPgogICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJmbGV4IGl0ZW1zLWNlbnRlciBnYXAtMiB0ZXh0LVsxMnB4XSBmb250LWJsYWNrIHRleHQtc2xhdGUtNTAwIj48c3BhbiBjbGFzcz0iaW5saW5lLWJsb2NrIHctMiBoLTIgcm91bmRlZC1mdWxsICR7bWFya2VyLm5vcm1hbC5kb3R9Ij48L3NwYW4+7KCV6recPC9kaXY+CiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9ImZsZXggaXRlbXMtY2VudGVyIGdhcC0yIHRleHQtWzEycHhdIGZvbnQtYmxhY2sgdGV4dC1zbGF0ZS01MDAiPjxzcGFuIGNsYXNzPSJpbmxpbmUtYmxvY2sgdy0yIGgtMiByb3VuZGVkLWZ1bGwgJHttYXJrZXIuZXh0cmEuZG90fSI+PC9zcGFuPuyXsOyepTwvZGl2PgogICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJmbGV4IGl0ZW1zLWNlbnRlciBnYXAtMiB0ZXh0LVsxMnB4XSBmb250LWJsYWNrIHRleHQtc2xhdGUtNTAwIj48c3BhbiBjbGFzcz0iaW5saW5lLWJsb2NrIHctMiBoLTIgcm91bmRlZC1mdWxsICR7bWFya2VyLmhvbGlkYXkuZG90fSI+PC9zcGFuPu2ctOydvDwvZGl2PgogICAgICAgICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9ImhpZGRlbiBsZzpncmlkIGdyaWQtY29scy1bMjAwcHhfMWZyXSBiZy1zbGF0ZS0xMDAvODAgcm91bmRlZC14bCB0ZXh0LXNsYXRlLTcwMCBmb250LWJsYWNrIHRleHQtWzEycHhdIj4KICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0icHgtNCBweS0yLjUgYm9yZGVyLXIgYm9yZGVyLXNsYXRlLTIwMCI+7J2066aEPC9kaXY+CiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9InB4LTQgcHktMi41Ij7tiKzsnoUg7ZSE66Gc7KCd7Yq4PC9kaXY+CiAgICAgICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgICAgICAgICAgJHtyb3dzLm1hcChwZXJzb24gPT4gewogICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB0b3RhbCA9IE51bWJlcihwZXJzb24udG90YWwgfHwgMCk7CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG92ZXIgPSB0b3RhbCA+IHRhcmdldEg7CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG92ZXJIb3VyID0gTWF0aC5tYXgoMCwgdG90YWwgLSB0YXJnZXRIKTsKICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcHJvamVjdHMgPSBwZXJzb24ucHJvamVjdHMgfHwgW107CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJncmlkIGdyaWQtY29scy0xIGxnOmdyaWQtY29scy1bMjAwcHhfMWZyXSBnYXAtMyBib3JkZXIgYm9yZGVyLXNsYXRlLTIwMCByb3VuZGVkLTJ4bCBwLTMiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9ImxnOnByLTMgbGc6Ym9yZGVyLXIgYm9yZGVyLXNsYXRlLTEwMCI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9InRleHQtWzE4cHhdIGZvbnQtYmxhY2sgdGV4dC1zbGF0ZS05MDAgbGVhZGluZy10aWdodCI+JHtwZXJzb24ubmFtZX0gPHNwYW4gY2xhc3M9InRleHQtc2xhdGUtNTAwIj4ke3BlcnNvbi5yYW5rfTwvc3Bhbj48L2Rpdj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0ibXQtMi41IHRleHQtWzMycHhdIGZvbnQtYmxhY2sgbGVhZGluZy1ub25lIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJ0ZXh0LWluZGlnby02MDAiPiR7Zm9ybWF0SG91cih0b3RhbCl9PC9zcGFuPjxzcGFuIGNsYXNzPSJ0ZXh0LXNsYXRlLTQwMCI+LyR7Zm9ybWF0SG91cih0YXJnZXRIKX1oPC9zcGFuPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHtvdmVyID8gYAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0ibXQtMi41IGZsZXggaXRlbXMtY2VudGVyIGdhcC0xLjUgdGV4dC1yZWQtNTAwIHRleHQtWzEwcHhdIGZvbnQtYmxhY2siPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxpIGRhdGEtbHVjaWRlPSJhbGVydC1jaXJjbGUiIHNpemU9IjEyIj48L2k+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4+7LSI6rO86re866y0ICR7Zm9ybWF0SG91cihvdmVySG91cil97Iuc6rCEPC9zcGFuPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGAgOiAnJ30KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJ3LWZ1bGwgb3ZlcmZsb3cteC1hdXRvIHBiLTEgY3VzdG9tLXNjcm9sbGJhciI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9ImZsZXggZ2FwLTMgbWluLXctbWF4Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHtwcm9qZWN0cy5sZW5ndGggPyBwcm9qZWN0cy5tYXAocHJvamVjdCA9PiB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB0b25lVHlwZSA9IHByb2plY3RUb25lVHlwZShwcm9qZWN0KTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHRvbmUgPSBtYXJrZXJbdG9uZVR5cGVdOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdG90YWxQcm9qZWN0ID0gTnVtYmVyKHByb2plY3QudG90YWwgfHwgMCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBub3JtYWxQY3QgPSB0b3RhbFByb2plY3QgPiAwID8gKE51bWJlcihwcm9qZWN0Lm5vcm1hbCB8fCAwKSAvIHRvdGFsUHJvamVjdCkgKiAxMDAgOiAwOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZXh0cmFQY3QgPSB0b3RhbFByb2plY3QgPiAwID8gKE51bWJlcihwcm9qZWN0LmV4dHJhIHx8IDApIC8gdG90YWxQcm9qZWN0KSAqIDEwMCA6IDA7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBob2xpZGF5UGN0ID0gdG90YWxQcm9qZWN0ID4gMCA/IChOdW1iZXIocHJvamVjdC5ob2xpZGF5IHx8IDApIC8gdG90YWxQcm9qZWN0KSAqIDEwMCA6IDA7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gYAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9InctWzI4MHB4XSBzaHJpbmstMCBiZy1zbGF0ZS01MC82MCBib3JkZXIgYm9yZGVyLXNsYXRlLTIwMCByb3VuZGVkLTJ4bCBwLTMuNSByZWxhdGl2ZSBvdmVyZmxvdy1oaWRkZW4iPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJhYnNvbHV0ZSBsZWZ0LTAgdG9wLTAgYm90dG9tLTAgdy0xIiBzdHlsZT0iYmFja2dyb3VuZDoke3RvbmUuYmFyfTsiPjwvZGl2PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJwbC0yIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9InRleHQtWzE3cHhdIGZvbnQtYmxhY2sgdGV4dC1zbGF0ZS04MDAgbGVhZGluZy10aWdodCBtYi0xLjUiPiR7cHJvamVjdC5wcm9qZWN0TmFtZX08L2Rpdj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9ImZsZXggaXRlbXMtY2VudGVyIGdhcC0xLjUgdGV4dC1bMTFweF0gdGV4dC1zbGF0ZS01MDAgZm9udC1ib2xkIG1iLTEiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxpIGRhdGEtbHVjaWRlPSJjYWxlbmRhciIgc2l6ZT0iMTMiPjwvaT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj4ke2RhdGVSYW5nZVRleHR9PC9zcGFuPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJmbGV4IGl0ZW1zLWNlbnRlciBnYXAtMS41IHRleHQtWzEycHhdIGZvbnQtYmxhY2sgbWItMi41Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8aSBkYXRhLWx1Y2lkZT0iY2xvY2siIHNpemU9IjEyIiBjbGFzcz0iJHt0b25lLnRleHR9Ij48L2k+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4+JHtwcm9qZWN0VGltZUh0bWwocHJvamVjdCwgdG9uZVR5cGUpfTwvc3Bhbj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0iaC0yIGJnLXNsYXRlLTIwMCByb3VuZGVkLWZ1bGwgb3ZlcmZsb3ctaGlkZGVuIGZsZXgiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICR7bm9ybWFsUGN0ID4gMCA/IGA8c3BhbiBjbGFzcz0iaC1mdWxsIGJnLWluZGlnby01MDAiIHN0eWxlPSJ3aWR0aDoke25vcm1hbFBjdH0lOyI+PC9zcGFuPmAgOiAnJ30KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAke2V4dHJhUGN0ID4gMCA/IGA8c3BhbiBjbGFzcz0iaC1mdWxsIGJnLWFtYmVyLTUwMCIgc3R5bGU9IndpZHRoOiR7ZXh0cmFQY3R9JTsiPjwvc3Bhbj5gIDogJyd9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHtob2xpZGF5UGN0ID4gMCA/IGA8c3BhbiBjbGFzcz0iaC1mdWxsIGJnLXJlZC01MDAiIHN0eWxlPSJ3aWR0aDoke2hvbGlkYXlQY3R9JTsiPjwvc3Bhbj5gIDogJyd9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KS5qb2luKCcnKSA6ICc8ZGl2IGNsYXNzPSJ0ZXh0LXNsYXRlLTMwMCBmb250LWJvbGQgaXRhbGljIHAtOCI+7ZSE66Gc7KCd7Yq4IOuNsOydtO2EsOqwgCDsl4bsirXri4jri6QuPC9kaXY+J30KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgICAgICAgICAgICAgYDsKICAgICAgICAgICAgICAgICAgICB9KS5qb2luKCcnKX0KICAgICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICBgOwogICAgICAgIH0KCgoKICAgICAgICB3aW5kb3cub25sb2FkID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIGx1Y2lkZS5jcmVhdGVJY29ucygpOwogICAgICAgIH0KICAgIDwvc2NyaXB0Pgo8L2JvZHk+CjwvaHRtbD4KCgo=';
function decodeBase64ToBytes(b64) {
const bin = atob(b64);
const bytes = new Uint8Array(bin.length);
for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
return bytes;
}
function decodeBase64Utf8(b64) {
return new TextDecoder('utf-8').decode(decodeBase64ToBytes(b64));
}
function arrayBufferToBinaryString(buffer) {
const bytes = new Uint8Array(buffer);
const chunk = 0x8000;
let out = '';
for (let i = 0; i < bytes.length; i += chunk) {
const slice = bytes.subarray(i, i + chunk);
out += String.fromCharCode(...slice);
}
return out;
}
function arrayBufferToBase64(buffer) {
return btoa(arrayBufferToBinaryString(buffer));
}
function decodeBufferText(buffer, encodings = ['euc-kr', 'utf-8']) {
for (const enc of encodings) {
try {
return new TextDecoder(enc).decode(buffer);
} catch (_) {
// Try next encoding.
}
}
return new TextDecoder('utf-8').decode(buffer);
}
function syncBusinessTodayDate() {
const doc = frameBusiness.contentDocument;
if (!doc) return;
if (doc.documentElement) doc.documentElement.classList.add('mh-business-html');
if (doc.body) doc.body.classList.add('mh-business-theme');
let themeLink = doc.getElementById('mh-business-theme-css');
if (!themeLink) {
themeLink = doc.createElement('link');
themeLink.id = 'mh-business-theme-css';
themeLink.rel = 'stylesheet';
themeLink.href = encodeURI('./MH 통합 대시보드_260320.css');
doc.head.appendChild(themeLink);
}
let style = doc.getElementById('business-today-style');
if (!style) {
style = doc.createElement('style');
style.id = 'business-today-style';
style.textContent = `
body {
color: #0a2114;
background:
radial-gradient(circle at top left, rgba(249, 115, 22, 0.10), transparent 24%),
radial-gradient(circle at top right, rgba(19, 149, 101, 0.08), transparent 20%),
#f6efe4;
font-family: "Pretendard", "Malgun Gothic", sans-serif;
overflow-x: hidden;
}
.wrap {
width: calc(100vw - 60px);
max-width: calc(100vw - 60px);
margin: 0 auto;
padding: 15px 15px 14px;
}
.top {
position: relative;
overflow: hidden;
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 18px 24px;
align-items: start;
background:
radial-gradient(circle at 10% 15%, rgba(242, 196, 132, 0.18), transparent 24%),
radial-gradient(circle at 88% 12%, rgba(255, 255, 255, 0.10), transparent 18%),
linear-gradient(145deg, #0a2a22 0%, #0f3a2f 52%, #1a5645 100%);
border: 1px solid rgba(255,255,255,0.08);
border-radius: 30px;
padding: 28px 30px 26px;
box-shadow: 0 28px 70px rgba(15, 58, 47, 0.22);
margin-bottom: 14px;
}
.top::before {
content: "";
position: absolute;
inset: auto -6% -46% auto;
width: 320px;
height: 320px;
border-radius: 50%;
background: radial-gradient(circle, rgba(242, 196, 132, 0.22), transparent 68%);
pointer-events: none;
}
.top::after {
content: "";
position: absolute;
top: -88px;
right: 76px;
width: 220px;
height: 220px;
border-radius: 50%;
border: 1px solid rgba(242, 196, 132, 0.16);
pointer-events: none;
}
.top > div:first-child { min-width: 0; }
.sub { display: none !important; }
.brand-head {
display: flex;
align-items: center;
gap: 18px;
min-width: 0;
position: relative;
z-index: 1;
}
.brand-copy {
min-width: 0;
}
.brand-kicker { display: none !important; }
.brand-title {
min-width: 0;
color: #f4efe6;
font-size: clamp(34px, 3vw, 54px);
font-weight: 900;
letter-spacing: -0.04em;
line-height: 1.1;
word-break: keep-all;
}
.brand-subtitle {
display: inline;
color: rgba(244, 239, 230, 0.82);
font-size: 0.72em;
font-weight: 500;
letter-spacing: 0.01em;
margin-left: 8px;
}
.brand-description { display: none !important; }
.title { display: none !important; }
.controls {
display: flex;
flex-direction: column;
align-items: stretch;
justify-self: end;
gap: 12px;
min-width: min(100%, 420px);
position: relative;
z-index: 1;
}
.controls-top-row {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 10px;
flex-wrap: wrap;
}
.controls-top-actions {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 10px;
flex-wrap: wrap;
}
.controls .btn {
padding: 12px 16px;
border-radius: 999px;
border: 1px solid rgba(242, 196, 132, 0.34);
background: rgba(255, 255, 255, 0.08);
color: #f4efe6;
font-size: 14px;
font-weight: 900;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.06);
}
.controls .btn:hover {
background: rgba(242, 196, 132, 0.16);
border-color: rgba(242, 196, 132, 0.52);
}
.search {
width: min(520px, 100%);
align-self: flex-end;
min-height: 52px;
border-radius: 18px;
border: 1px solid rgba(255, 255, 255, 0.18);
background: rgba(255, 255, 255, 0.14);
color: #fff7eb;
padding: 14px 18px;
font-size: 15px;
font-weight: 800;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.06);
}
.search::placeholder { color: rgba(247, 240, 228, 0.66); }
.status {
display: none !important;
}
.cards {
grid-column: 1 / -1;
grid-template-columns: repeat(6, minmax(0, 1fr));
gap: 14px;
margin-top: 6px;
margin-bottom: 0;
position: relative;
z-index: 1;
}
.cards-summary {
grid-column: 1 / -1;
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
margin-bottom: 6px;
}
.cards-summary-chip {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 9px 14px;
border-radius: 999px;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.14);
box-shadow: inset 0 1px 0 rgba(255,255,255,0.04);
color: #f4efe6;
font-size: 12px;
font-weight: 900;
white-space: nowrap;
}
.cards-summary-chip strong {
color: #f2c484;
font-weight: 900;
}
.table-top-note {
display: flex;
justify-content: flex-end;
margin: 0 2px 10px;
}
.table-vat-note {
display: inline-flex;
align-items: center;
padding: 6px 10px;
border-radius: 999px;
background: #fffdfa;
border: 1px solid #dfcfb8;
color: #64748b;
font-size: 11px;
font-weight: 900;
letter-spacing: -0.01em;
}
.panel {
background: #fffdfa;
border: 1px solid #dfcfb8;
box-shadow: 0 18px 44px rgba(10, 33, 20, 0.08);
}
.cards .card {
padding: 16px 16px 14px;
border-radius: 22px;
background: linear-gradient(180deg, rgba(255,255,255,0.12) 0%, rgba(255,255,255,0.07) 100%);
border: 1px solid rgba(255,255,255,0.14);
color: #f7f0e4;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.04);
backdrop-filter: blur(8px);
}
.cards .card.management {
background: linear-gradient(180deg, rgba(242, 196, 132, 0.15) 0%, rgba(255,255,255,0.08) 100%);
border-color: rgba(242, 196, 132, 0.42);
}
.cards .card .k {
color: rgba(255, 244, 230, 0.68);
font-size: 11px;
font-weight: 900;
letter-spacing: 0.04em;
}
.cards .card .v {
margin-top: 7px;
color: #fff7eb;
font-size: clamp(19px, 1.55vw, 27px);
font-weight: 900;
letter-spacing: -0.03em;
white-space: nowrap;
}
.cards .card .n {
margin-top: 5px;
color: rgba(247, 240, 228, 0.80);
font-size: 12px;
font-weight: 700;
line-height: 1.4;
}
.badge.badge-baron {
border-color: #fdba74;
background: #fff7ed;
color: #c2410c;
}
.badge.badge-family {
border-color: #93c5fd;
background: #eff6ff;
color: #1d4ed8;
}
.summary-card.receivable {
background: linear-gradient(180deg, #fff1f2 0%, #ffe4e6 100%);
border-color: #fda4af;
}
.summary-card.receivable .summary-label,
.summary-card.receivable .summary-value,
.summary-card.receivable .summary-note {
color: #be123c;
}
.collect-stage-list {
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 12px;
}
.collect-stage-item {
border: 1px solid #dbe7f3;
border-radius: 14px;
background: #f8fbff;
padding: 10px 12px;
}
.collect-stage-head {
display: flex;
justify-content: space-between;
align-items: center;
gap: 10px;
font-size: 12px;
font-weight: 900;
color: #0f172a;
}
.collect-stage-badge {
display: inline-flex;
align-items: center;
padding: 4px 8px;
border-radius: 999px;
background: #e0ecff;
color: #1d4ed8;
font-size: 11px;
font-weight: 900;
white-space: nowrap;
}
.collect-stage-grid {
margin-top: 8px;
display: grid;
grid-template-columns: repeat(4, minmax(120px, 1fr));
gap: 6px 10px;
}
.collect-stage-cell {
font-size: 12px;
color: #475569;
font-weight: 700;
}
.collect-stage-cell strong {
display: block;
margin-top: 3px;
color: #0f172a;
font-size: 13px;
font-weight: 900;
}
.ledger-table {
width: 100% !important;
table-layout: fixed !important;
}
.ledger-table th,
.ledger-table td {
width: 16.666% !important;
}
.ledger-table th:nth-child(1),
.ledger-table td:nth-child(1),
.ledger-table th:nth-child(2),
.ledger-table td:nth-child(2),
.ledger-table th:nth-child(3),
.ledger-table td:nth-child(3),
.ledger-table th:nth-child(4),
.ledger-table td:nth-child(4),
.ledger-table th:nth-child(5),
.ledger-table td:nth-child(5),
.ledger-table th:nth-child(6),
.ledger-table td:nth-child(6) {
width: 16.666% !important;
}
.ledger-table th:last-child,
.ledger-table td:last-child,
.ledger-table td:last-child .ledger-note {
white-space: nowrap !important;
word-break: keep-all !important;
}
.today-date-label {
display: inline-flex;
align-items: center;
padding: 10px 14px;
border-radius: 999px;
border: 1px solid rgba(242, 196, 132, 0.28);
background: rgba(255,255,255,0.08);
color: #f4efe6;
font-size: 12px;
font-weight: 900;
letter-spacing: -0.01em;
white-space: nowrap;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
}
.table-wrap {
overflow-x: hidden !important;
}
table {
width: 100% !important;
min-width: 0 !important;
table-layout: fixed;
}
thead th {
padding: 11px 8px;
font-size: 11px;
letter-spacing: -0.02em;
}
tbody td {
padding: 11px 8px;
font-size: 13px;
white-space: normal;
word-break: break-word;
}
tbody tr.selected td {
background: #eef4ff;
}
tbody tr.selected:hover td {
background: #e6efff;
}
tbody tr.selected + .detail-row td {
border-top-color: #bfd3ff;
}
tbody tr.selected .name,
tbody tr.selected td strong {
color: #0b2f6b;
}
.detail-row td {
background: linear-gradient(180deg, #eef4ff 0%, #f8fbff 100%);
border-top: 1px solid #bfd3ff;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.65);
}
.detail-row .inline-panel {
background: linear-gradient(180deg, rgba(222, 235, 255, 0.72) 0%, rgba(248, 251, 255, 0.96) 100%);
border-left: 3px solid #7aa2ff;
}
.detail-row .inline-card,
.detail-row .ledger-block {
box-shadow: 0 10px 24px rgba(59, 130, 246, 0.08);
}
.group-row td {
padding: 12px 14px 10px;
background: linear-gradient(180deg, #f8fbff 0%, #eef4ff 100%);
border-top: 1px solid #c7d7f8;
border-bottom: 1px solid #dbe7f3;
}
.group-chip {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 6px 12px;
border-radius: 999px;
background: #ffffff;
border: 1px solid #bfd3ff;
color: #1e3a8a;
font-size: 12px;
font-weight: 900;
box-shadow: 0 8px 18px rgba(59, 130, 246, 0.08);
cursor: pointer;
}
.group-chip .group-toggle {
margin-left: 4px;
width: 22px;
height: 22px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 999px;
background: #eef4ff;
color: #1d4ed8;
font-size: 14px;
font-weight: 900;
line-height: 1;
}
th:nth-child(1), td:nth-child(1) { width: 5%; }
th:nth-child(2), td:nth-child(2) { width: 6%; }
th:nth-child(3), td:nth-child(3) { width: 31%; }
th:nth-child(4), td:nth-child(4) { width: 12%; }
th:nth-child(5), td:nth-child(5) { width: 7%; }
th:nth-child(6), td:nth-child(6) { width: 6%; }
th:nth-child(7), td:nth-child(7) { width: 9%; }
th:nth-child(8), td:nth-child(8) { width: 8%; }
th:nth-child(9), td:nth-child(9) { width: 8%; }
th:nth-child(10), td:nth-child(10) { width: 8%; }
th:nth-child(11), td:nth-child(11) { width: 5%; }
.name {
max-width: none;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 14px;
font-weight: 900;
}
.subline {
font-size: 12px;
line-height: 1.35;
}
.client-main {
font-size: 13px;
font-weight: 900;
}
td:nth-child(2) .subline,
td:nth-child(5),
td:nth-child(6) {
white-space: nowrap;
}
td:nth-child(4) {
white-space: normal;
word-break: keep-all;
overflow-wrap: anywhere;
}
.client-main {
display: block;
font-weight: 800;
color: #0f172a;
}
th.num, td.num, td.num strong,
td:nth-child(7), td:nth-child(8), td:nth-child(9), td:nth-child(10), td:nth-child(11) {
text-align: right;
white-space: nowrap;
}
@media (max-width: 720px) {
.wrap { width: calc(100vw - 30px); max-width: calc(100vw - 30px); padding: 10px 10px 10px; }
.top {
grid-template-columns: 1fr;
padding: 18px 14px 16px;
gap: 14px;
}
.brand-head { gap: 12px; align-items: flex-start; }
.brand-title { font-size: 30px; }
.brand-subtitle { display: block; margin-left: 0; margin-top: 4px; }
.controls { min-width: 0; justify-self: stretch; }
.controls-top-row,
.controls-top-actions { justify-content: flex-start; }
.search { width: 100%; align-self: stretch; }
.cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.collect-stage-grid { grid-template-columns: repeat(2, minmax(120px, 1fr)); }
}
`;
doc.head.appendChild(style);
}
const controls = doc.querySelector('.controls');
const search = doc.getElementById('search');
const titleWrap = doc.querySelector('.top > div:first-child');
const top = doc.querySelector('.top');
const cards = doc.querySelector('.cards');
const panel = doc.querySelector('.panel');
if (!controls || !search) return;
if (titleWrap && !doc.getElementById('business-brand-head')) {
titleWrap.innerHTML = `
<div id="business-brand-head" class="brand-head">
<div class="brand-copy">
<div class="brand-title">사업관리대장<span class="brand-subtitle">Dashboard</span></div>
<div class="brand-description">연도별 프로젝트 현황과 계약, 수금, 경영지원서비스 흐름을 한 화면에서 확인합니다.</div>
</div>
</div>
`;
}
let topRow = doc.getElementById('controls-top-row');
let actionWrap = doc.getElementById('controls-top-actions');
let dateLabel = doc.getElementById('business-today-date');
if (!topRow) {
topRow = doc.createElement('div');
topRow.id = 'controls-top-row';
topRow.className = 'controls-top-row';
actionWrap = doc.createElement('div');
actionWrap.id = 'controls-top-actions';
actionWrap.className = 'controls-top-actions';
dateLabel = doc.createElement('div');
dateLabel.id = 'business-today-date';
dateLabel.className = 'today-date-label';
const uploadBtn = doc.getElementById('btnUpload');
if (uploadBtn) actionWrap.appendChild(uploadBtn);
topRow.appendChild(actionWrap);
topRow.appendChild(dateLabel);
controls.insertBefore(topRow, search);
}
if (top && cards && cards.parentNode !== top) {
top.appendChild(cards);
}
if (dateLabel) {
const parts = new Intl.DateTimeFormat('ko-KR', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
}).formatToParts(new Date());
const year = parts.find((part) => part.type === 'year')?.value ?? '';
const month = parts.find((part) => part.type === 'month')?.value ?? '';
const day = parts.find((part) => part.type === 'day')?.value ?? '';
dateLabel.textContent = `${year}${month}${day}`;
}
if (panel && !doc.getElementById('business-table-top-note')) {
const noteWrap = doc.createElement('div');
noteWrap.id = 'business-table-top-note';
noteWrap.className = 'table-top-note';
noteWrap.innerHTML = '<div class="table-vat-note">(VAT 별도)</div>';
panel.parentNode.insertBefore(noteWrap, panel);
}
}
function buildBusinessSrcdoc() {
return decodeBase64Utf8(BUSINESS_HTML_B64)
.replace('</head>', '<link rel="stylesheet" href="MH 통합 대시보드_260320.css" /></head>')
.replace('<body>', '<body class="mh-business-theme">')
.replace('</style>', `
.cards-toolbar {
grid-column: 1 / -1;
display: flex;
flex-direction: column;
gap: 10px;
margin-bottom: 6px;
}
.cards-toolbar-row {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
}
.cards-toolbar-metrics {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
}
.summary-filter-chip {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-between;
gap: 6px;
width: 100%;
min-height: 96px;
padding: 16px 18px;
border-radius: 22px;
border: 1px solid rgba(255,255,255,0.14);
background:
linear-gradient(180deg, rgba(255,255,255,0.12) 0%, rgba(255,255,255,0.08) 100%);
color: #f4efe6;
font-size: 12px;
font-weight: 900;
cursor: pointer;
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.04),
0 14px 28px rgba(7, 28, 22, 0.12);
transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease, background .18s ease;
}
.summary-filter-chip:hover {
transform: translateY(-2px);
border-color: rgba(242, 196, 132, 0.4);
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.05),
0 18px 34px rgba(7, 28, 22, 0.18);
}
.summary-filter-chip .label {
color: rgba(244, 239, 230, 0.78);
letter-spacing: 0.02em;
}
.summary-filter-chip .count {
color: #fff7e6;
font-size: 28px;
line-height: 1;
letter-spacing: -0.03em;
}
.summary-filter-chip .meta {
color: #f2c484;
font-size: 11px;
font-weight: 800;
}
.summary-filter-chip.active {
background: linear-gradient(180deg, #fff8ee 0%, #f2dec0 100%);
color: #0a2a22;
border-color: rgba(242, 196, 132, 0.58);
box-shadow: 0 12px 28px rgba(10, 42, 34, 0.18);
}
.summary-filter-chip.active .label {
color: rgba(10, 42, 34, 0.72);
}
.summary-filter-chip.active .count {
color: #b86b1f;
}
.summary-filter-chip.active .meta {
color: #7c5a20;
}
.summary-year-chip {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 58px;
padding: 9px 14px;
border-radius: 999px;
border: 1px solid rgba(255,255,255,0.14);
background: rgba(255,255,255,0.08);
color: #f4efe6;
font-size: 12px;
font-weight: 900;
cursor: pointer;
}
.summary-year-chip.active {
background: linear-gradient(180deg, #fff8ee 0%, #f2dec0 100%);
color: #0a2a22;
border-color: rgba(242, 196, 132, 0.58);
box-shadow: 0 12px 28px rgba(10, 42, 34, 0.18);
}
@media (max-width: 980px) {
.cards-toolbar-metrics {
grid-template-columns: 1fr;
}
.summary-filter-chip {
min-height: 84px;
}
.summary-filter-chip .count {
font-size: 24px;
}
}
</style>`)
.replace('table{width:100%;min-width:1250px;border-collapse:collapse}', 'table{width:100%;min-width:0;border-collapse:collapse;table-layout:fixed}')
.replace(/<thead>[\s\S]*?<\/thead>\s*<tbody id="tbody"><\/tbody>/, `<thead>
<tr>
<th>
<div class="th-head">
<button type="button" class="th-trigger" data-filter="cat" data-label="구분">
<span class="th-title">구분</span><span class="th-mark"></span><span class="th-caret">▼</span>
</button>
<div id="filterCatMenu" class="th-menu" data-filter="cat"></div>
</div>
</th>
<th>
<div class="th-head">
<button type="button" class="th-trigger" data-filter="code" data-label="사업코드">
<span class="th-title">사업코드</span><span class="th-mark"></span><span class="th-caret">▼</span>
</button>
<div id="filterCodeMenu" class="th-menu" data-filter="code"></div>
</div>
</th>
<th>
<div class="th-head">
<button type="button" class="th-trigger" data-filter="name" data-label="사업명(계약명)">
<span class="th-title">사업명(계약명)</span><span class="th-mark"></span><span class="th-caret">▼</span>
</button>
<div id="filterNameMenu" class="th-menu" data-filter="name"></div>
</div>
</th>
<th>
<div class="th-head">
<button type="button" class="th-trigger" data-filter="client" data-label="발주처(계약처)">
<span class="th-title">발주처(계약처)</span><span class="th-mark"></span><span class="th-caret">▼</span>
</button>
<div id="filterClientMenu" class="th-menu" data-filter="client"></div>
</div>
</th>
<th>
<div class="th-head">
<button type="button" class="th-trigger" data-filter="order" data-label="발주방법">
<span class="th-title">발주방법</span><span class="th-mark"></span><span class="th-caret">▼</span>
</button>
<div id="filterOrderMenu" class="th-menu" data-filter="order"></div>
</div>
</th>
<th>
<div class="th-head">
<button type="button" class="th-trigger" data-filter="status" data-label="진행상태">
<span class="th-title">진행상태</span><span class="th-mark"></span><span class="th-caret">▼</span>
</button>
<div id="filterStatusMenu" class="th-menu" data-filter="status"></div>
</div>
</th>
<th class="num">
<div class="th-head end">
<button type="button" class="th-trigger" data-filter="amount" data-label="계약금">
<span class="th-title">계약금</span><span class="th-mark"></span><span class="th-caret">▼</span>
</button>
<div id="filterAmountMenu" class="th-menu" data-filter="amount"></div>
</div>
</th>
<th class="num">
<div class="th-head end">
<button type="button" class="th-trigger" data-filter="outsource" data-label="외주비">
<span class="th-title">외주비</span><span class="th-mark"></span><span class="th-caret">▼</span>
</button>
<div id="filterOutsourceMenu" class="th-menu" data-filter="outsource"></div>
</div>
</th>
<th class="num">
<div class="th-head end">
<button type="button" class="th-trigger" data-filter="receivable" data-label="미수금">
<span class="th-title">미수금</span><span class="th-mark"></span><span class="th-caret">▼</span>
</button>
<div id="filterReceivableMenu" class="th-menu" data-filter="receivable"></div>
</div>
</th>
<th class="num">
<div class="th-head end">
<button type="button" class="th-trigger" data-filter="collected" data-label="수금액">
<span class="th-title">수금액</span><span class="th-mark"></span><span class="th-caret">▼</span>
</button>
<div id="filterCollectedMenu" class="th-menu" data-filter="collected"></div>
</div>
</th>
<th class="num">
<div class="th-head end">
<button type="button" class="th-trigger" data-filter="rate" data-label="수금률">
<span class="th-title">수금률</span><span class="th-mark"></span><span class="th-caret">▼</span>
</button>
<div id="filterRateMenu" class="th-menu" data-filter="rate"></div>
</div>
</th>
</tr>
</thead>
<tbody id="tbody"></tbody>`)
.replace('const FILTER_KEYS=["code","name","corp","status","outsource","amount","collected","rate"];', 'const FILTER_KEYS=["cat","code","name","client","order","status","amount","outsource","receivable","collected","rate"];')
.replace('function codeFilterLabel(r){return r.cat||"-";}', 'function catFilterLabel(r){return r.cat||"-";}\n function codeFilterLabel(r){return r.code||"-";}\n function clientFilterLabel(r){return r.client||"-";}\n function orderFilterLabel(r){return r.order||"-";}\n function receivableFilterLabel(r){return won(r.recv||0);}\n function statusFilterLabel(r){const value=String(r&&r.status||"").trim();if(!value) return "-";if(value.includes("대기")) return "계약대기";if(value.includes("중지")) return "과업중지";if(value.includes("완료")||value.includes("준공")) return "준공";if(value.includes("진행")) return "과업 진행중";return value;}')
.replace(' ch(R[h],R[h+1]||[]);\n const I={cat:1,corp:4,code:5,name:6,pay:7,yn:8,order:9,pm:10,status:11,client:12,split:13,cDate:14,sDate:15,eDate:17,cSup:18,cVat:19,cTot:20,issueDate:21,colDate:22,sSup:23,sVat:24,sTot:25,col:26,recv:27,r:28,note:29,cmCo:30,cmNm:31,cmDp:32,cmPh:33,cmEm:34,dmCo:35,dmNm:36,dmDp:37,dmPh:38,dmEm:39};', ' const H=ch(R[h],R[h+1]||[]);\n const I={cat:findHeaderIndex(H,["사업구분"]),corp:findHeaderIndex(H,["계약 법인","계약법인"]),code:findHeaderIndex(H,["총괄 사업코드","총괄사업코드","사업코드"]),name:findHeaderIndex(H,["사업명 (계약명)","사업명(계약명)","사업명"]),pay:findHeaderIndex(H,["대금 구분","구분"]),yn:findHeaderIndex(H,["계약여부"]),order:findHeaderIndex(H,["발주방법"]),pm:findHeaderIndex(H,["pm"]),status:findHeaderIndex(H,["진행상태"]),client:findHeaderIndex(H,["발주처 (매출처)","발주처(매출처)","발주처"]),split:findHeaderIndex(H,["분담율"]),cDate:findHeaderIndex(H,["계약기간 계약일","계약일"]),sDate:findHeaderIndex(H,["계약기간 착수일","착수일","시작일","개시일"]),eDate:findHeaderIndex(H,["계약기간 준공일","준공일","종료일","완료일","계약기간 종료일"]),cSup:findHeaderIndex(H,["계약금 공급가액"]),cVat:findHeaderIndex(H,["계약금 부가세"]),cTot:findHeaderIndex(H,["계약금 합계"]),issueDate:findHeaderIndex(H,["매출금액 발행일","발행일"]),colDate:findHeaderIndex(H,["매출금액 수금일","수금일"]),sSup:findHeaderIndex(H,["매출금액 공급가액"]),sVat:findHeaderIndex(H,["매출금액 부가세"]),sTot:findHeaderIndex(H,["매출금액 합계"]),col:findHeaderIndex(H,["매출금액 수금금액","수금금액"]),recv:findHeaderIndex(H,["매출금액 미수금액","미수금액"]),r:findHeaderIndex(H,["매출금액 수금율","수금율"]),note:findHeaderIndex(H,["비고"]),cmCo:findHeaderIndex(H,["계약/청구담당자 회사","계약 / 청구 담당자 회사"]),cmNm:findHeaderIndex(H,["계약/청구담당자 이름","계약 / 청구 담당자 이름"]),cmDp:findHeaderIndex(H,["계약/청구담당자 부서","계약 / 청구 담당자 부서"]),cmPh:findHeaderIndex(H,["계약/청구담당자 연락처","계약 / 청구 담당자 연락처"]),cmEm:findHeaderIndex(H,["계약/청구담당자 이메일","계약 / 청구 담당자 이메일"]),dmCo:findHeaderIndex(H,["부서담당자 회사","부서 담당자 회사"]),dmNm:findHeaderIndex(H,["부서담당자 이름","부서 담당자 이름"]),dmDp:findHeaderIndex(H,["부서담당자 부서","부서 담당자 부서"]),dmPh:findHeaderIndex(H,["부서담당자 연락처","부서 담당자 연락처"]),dmEm:findHeaderIndex(H,["부서담당자 이메일","부서 담당자 이메일"])};')
.replace(' const indexes={contract:20,collected:26,receivable:27,rate:28};', ' if(rows.length&&rows[0].length)rows[0][0]=String(rows[0][0]||"").replace(/^\\uFEFF/,"");\n const h=hs(rows);\n if(h<0) return null;\n const H=ch(rows[h],rows[h+1]||[]);\n const indexes={contract:findHeaderIndex(H,["계약금 합계"]),collected:findHeaderIndex(H,["매출금액 수금금액","수금금액"]),receivable:findHeaderIndex(H,["매출금액 미수금액","미수금액"]),rate:findHeaderIndex(H,["매출금액 수금율","수금율"])};')
.replace('function textAt(row,idx){return idx>=0?String(row[idx]??"").replace(/\\u00a0/g," ").replace(/\\s+/g," ").trim():"";}', 'function textAt(row,idx){return idx>=0?String(row[idx]??"").replace(/\\u00a0/g," ").replace(/\\s+/g," ").trim():"";}\n function dateTextAt(row,primaryIdx,...fallbackIdxs){for(const idx of [primaryIdx,...fallbackIdxs]){if(!(idx>=0)) continue;const value=textAt(row,idx);if(value&&value!=="~") return value;}return "";}')
.replace('split:textAt(row,I.split),cDate:textAt(row,I.cDate),sDate:textAt(row,I.sDate),eDate:textAt(row,I.eDate),', 'split:textAt(row,I.split),cDate:textAt(row,I.cDate),sDate:dateTextAt(row,I.sDate,I.cDate>=0?I.cDate+1:-1),eDate:dateTextAt(row,I.eDate,I.sDate>=0?I.sDate+2:-1,I.cDate>=0?I.cDate+3:-1),')
.replace(' const preferredNames=names.filter(name=>String(name||"").includes("공유사업관리대장"));', ' const preferredNames=[...names.filter(name=>String(name||"").includes("바론계약건만")),...names.filter(name=>String(name||"").includes("공유사업관리대장"))];')
.replace(' const bonus=String(name||"").includes("공유사업관리대장")?1000000:/사업관리대장/i.test(String(name||""))?10000:0;', ' const bonus=String(name||"").includes("바론계약건만")?2000000:String(name||"").includes("공유사업관리대장")?1000000:/사업관리대장/i.test(String(name||""))?10000:0;')
.replace(`function matchesColumnFilters(r){
if(S.filters.code&&codeFilterLabel(r)!==S.filters.code) return false;
if(S.filters.name&&(r.name||"-")!==S.filters.name) return false;
if(S.filters.corp&&(r.corp||"-")!==S.filters.corp) return false;
if(S.filters.status&&statusFilterLabel(r)!==S.filters.status) return false;
if(S.filters.outsource&&outsourceFilterLabel(r)!==S.filters.outsource) return false;
if(S.filters.amount&&amountFilterLabel(r)!==S.filters.amount) return false;
if(S.filters.receivable&&receivableFilterLabel(r)!==S.filters.receivable) return false;
if(S.filters.collected&&collectedFilterLabel(r)!==S.filters.collected) return false;
if(S.filters.rate&&rateFilterLabel(r)!==S.filters.rate) return false;
return true;
}`, `function matchesColumnFilters(r){
if(S.filters.cat&&catFilterLabel(r)!==S.filters.cat) return false;
if(S.filters.code&&codeFilterLabel(r)!==S.filters.code) return false;
if(S.filters.name&&(r.name||"-")!==S.filters.name) return false;
if(S.filters.client&&clientFilterLabel(r)!==S.filters.client) return false;
if(S.filters.order&&orderFilterLabel(r)!==S.filters.order) return false;
if(S.filters.status&&statusFilterLabel(r)!==S.filters.status) return false;
if(S.filters.amount&&amountFilterLabel(r)!==S.filters.amount) return false;
if(S.filters.outsource&&outsourceFilterLabel(r)!==S.filters.outsource) return false;
if(S.filters.receivable&&receivableFilterLabel(r)!==S.filters.receivable) return false;
if(S.filters.collected&&collectedFilterLabel(r)!==S.filters.collected) return false;
if(S.filters.rate&&rateFilterLabel(r)!==S.filters.rate) return false;
return true;
}`)
.replace(`function filterDefinitions(){
return [
{key:"code",map:codeFilterLabel},
{key:"name",map:r=>r.name||"-"},
{key:"corp",map:r=>r.corp||"-"},
{key:"status",map:statusFilterLabel},
{key:"outsource",map:outsourceFilterLabel},
{key:"amount",map:amountFilterLabel},
{key:"receivable",map:receivableFilterLabel},
{key:"collected",map:collectedFilterLabel},
{key:"rate",map:rateFilterLabel}
];
}`, `function filterDefinitions(){
return [
{key:"cat",map:catFilterLabel},
{key:"code",map:codeFilterLabel},
{key:"name",map:r=>r.name||"-"},
{key:"client",map:clientFilterLabel},
{key:"order",map:orderFilterLabel},
{key:"status",map:statusFilterLabel},
{key:"amount",map:amountFilterLabel},
{key:"outsource",map:outsourceFilterLabel},
{key:"receivable",map:receivableFilterLabel},
{key:"collected",map:collectedFilterLabel},
{key:"rate",map:rateFilterLabel}
];
}`)
.replace('const rowKey=r=>[r.code||"",r.name||"",r.corp||"",r.client||""].join("|");', `const rowKey=r=>[r.code||"",r.name||"",r.corp||"",r.client||""].join("|");
function isSupportServiceRow(r){
const normalizedName=String(r&&r.name||"").replace(/\\s+/g,"");
return normalizedName.includes("경영및기술지원서비스")||normalizedName.includes("경영지원서비스")||normalizedName.includes("기술지원서비스");
}
function isProgramRow(r){
return String(r&&r.name||"").includes("프로그램");
}
function baronGroupRank(r){
if(isSupportServiceRow(r)) return 2;
if(isProgramRow(r)) return 1;
return 0;
}
function groupSortRank(r){
const cat=String(r&&r.cat||"").trim();
const selectedYear=Number((typeof S!=="undefined"&&S.dashboard&&S.dashboard.year)||projectYear(r)||0);
if(typeof bgCompletedInYear==="function"&&bgCompletedInYear(r,String(selectedYear))) return 5;
const startYear=Number(projectYear(r)||0);
const isCarryOver=startYear>0&&selectedYear>startYear;
if(cat.includes("바론")) return isCarryOver?-1:baronGroupRank(r);
if(cat.includes("가족사")) return isCarryOver?2:3;
return 4;
}
function projectYear(r){
const start=String(r&&r.sDate||"").trim();
const startMatch=start.match(/(20\\d{2})/);
if(startMatch) return startMatch[1];
const name=String(r&&r.name||"").trim();
const nameMatch=name.match(/^(20\\d{2})/);
if(nameMatch) return nameMatch[1];
const end=String(r&&r.eDate||"").trim();
const endMatch=end.match(/(20\\d{2})/);
if(endMatch) return endMatch[1];
return "미지정";
}
function projectYearShort(r){
const year=projectYear(r);
return /^20\\d{2}$/.test(year)?year.slice(2):"";
}
function sectionLabel(r){
const selectedYear=String((typeof S!=="undefined"&&S.dashboard&&S.dashboard.year)||projectYear(r)||"");
if(typeof bgCompletedInYear==="function"&&bgCompletedInYear(r,selectedYear)) return selectedYear+"년 완료과업";
if(typeof bgStartedInYear==="function"&&bgStartedInYear(r,selectedYear)) return selectedYear+"년 신규프로젝트";
return selectedYear+"년 진행과업";
}
function tableGroupLabel(r){
const cat=String(r&&r.cat||"").trim();
const selectedYear=String((typeof S!=="undefined"&&S.dashboard&&S.dashboard.year)||projectYear(r)||"");
const startYear=projectYear(r);
const isCompleted=typeof bgCompletedInYear==="function"&&bgCompletedInYear(r,selectedYear);
const isCarryOver=/^20\\d{2}$/.test(selectedYear)&&/^20\\d{2}$/.test(startYear)&&selectedYear!==startYear&&!isCompleted;
if(isCompleted) return selectedYear+"년 완료과업";
if(cat.includes("바론")){
if(isCarryOver) return "바론-"+projectYearShort(r)+"년도";
if(isSupportServiceRow(r)) return "바론 · 경영 및 기술지원 서비스";
if(isProgramRow(r)) return "바론 · 프로그램 사업";
return "바론-프로젝트";
}
if(cat.includes("가족사")){
if(isCarryOver) return "가족사-"+projectYearShort(r)+"년도";
return "가족사-프로젝트";
}
return "기타 과업";
}
function formatSplitDisplay(split){
const value=String(split||"").trim();
if(!value) return "";
if(value.includes("%")) return value;
const numeric=value.replace(/[^0-9.]/g,"");
return numeric?numeric+"%":value;
}
function normalizeClientDisplay(client){
const value=String(client||"").trim();
if(value === "장헌산업 주식회사 장헌산업") return "장헌산업";
return value || "-";
}
function categoryBadgeClass(cat){
const value=String(cat||"").trim();
if(value.includes("바론")) return "badge-baron";
if(value.includes("가족사")) return "badge-family";
return "";
}`)
.replace(/function renderCollectionBoard\(r\)\{[\s\S]*?\n function renderProjectInline\(r\)\{/, `function renderCollectionBoard(r){
const payments=r.payments&&r.payments.length?r.payments:[{pay:r.pay||"-",issueDate:r.issueDate||"",collectDate:r.collectDateSummary||r.colDate||"",supply:r.sSup||0,collected:r.col||0,receivable:r.recv||Math.max(0,(r.sTot||0)-(r.col||0)),rate:r.rate||0,note:r.note||"",status:r.status||"-"}];
return \`<div class="ledger-block collect"><div class="ledger-head"><div class="ledger-head-left"><div class="ledger-icon">C</div><div><div class="ledger-name">수금 및 기성 현황</div><div class="ledger-sub">기성 차수별 세금계산서 발행 및 수금 내역</div></div></div><div class="ledger-pill">총 수금 \${esc(won(r.col))}</div></div><div class="ledger-table-wrap"><table class="ledger-table"><thead><tr><th>기성 차수</th><th>세금계산서 발행일</th><th>수금일</th><th style="text-align:right">수금금액</th><th style="text-align:right">미수금액</th><th>비고</th></tr></thead><tbody>\${payments.map((payment,index)=>{const noteParts=[];if(payment.status) noteParts.push(payment.status);if(payment.note) noteParts.push(payment.note);const stageLabel=\`\${index+1}차\`;return \`<tr><td><span class="ledger-main">\${esc(stageLabel)}</span><span class="ledger-muted">\${esc(payment.pay||"-")}</span></td><td><span class="ledger-main">\${esc(payment.issueDate?d(payment.issueDate):"-")}</span></td><td><span class="ledger-main">\${esc(payment.collectDate?d(payment.collectDate):"-")}</span></td><td class="ledger-amount">\${esc(won(payment.collected||0))}</td><td class="ledger-amount" style="color:#be123c">\${esc(won(payment.receivable||0))}</td><td><span class="ledger-note">\${esc(noteParts.join(" / ")||"-")}</span></td></tr>\`;}).join("")}</tbody></table></div></div>\`;
}
function renderProjectInline(r){`)
.replace(/function renderProjectInline\(r\)\{[\s\S]*?\n function closeAllModals\(\)\{/, `function renderProjectInline(r){
const payments=r.payments||[];
const latestCollect=d(r.collectDateSummary||r.colDate);
const hasOutsource=(r.outsourceItems||[]).length>0||(r.outsourceCost||0)>0||(r.outsourcePaid||0)>0||(r.outsourceRemaining||0)>0;
const summaryCards=[
\`<div class="summary-card"><div class="summary-label">계약금</div><div class="summary-value">\${esc(won(r.cSup))}</div><div class="summary-note">VAT 별도</div></div>\`,
\`<div class="summary-card"><div class="summary-label">수금액</div><div class="summary-value">\${esc(won(r.col))}</div><div class="summary-note">\${esc(latestCollect==="-"?"수금일 없음":\`최종 수금일 \${latestCollect}\`)}</div></div>\`,
\`<div class="summary-card"><div class="summary-label">수금률</div><div class="summary-value">\${esc(r.rate.toFixed(2)+"%")}</div><div class="summary-note">\${esc(payments.length?\`기성 \${payments.length}차까지 반영\`:"차수 정보 없음")}</div></div>\`,
\`<div class="summary-card receivable"><div class="summary-label">미수금액</div><div class="summary-value">\${esc(won(r.recv))}</div><div class="summary-note">잔여 수금 필요 금액</div></div>\`
].join("");
const boards=[
hasOutsource?renderOutsourceBoard(r):"",
renderCollectionBoard(r)
].filter(Boolean).join("");
return \`<div class="inline-panel"><div class="project-head" style="display:grid;grid-template-columns:minmax(0,1.95fr) minmax(280px,0.72fr);gap:10px;align-items:start"><div style="display:flex;flex-direction:column;gap:10px;min-width:0"><div class="inline-card"><div class="project-meta-grid"><div class="kv"><div class="kvk">계약법인</div><div class="kvv">\${esc(r.corp||"-")}</div></div><div class="kv"><div class="kvk">발주처</div><div class="kvv">\${esc(normalizeClientDisplay(r.client))}</div><div class="summary-note">\${esc(formatSplitDisplay(r.split)?\`계약비율 \${formatSplitDisplay(r.split)}\`:"계약비율 -")}</div></div><div class="kv"><div class="kvk">발주방법</div><div class="kvv">\${esc(r.order||"-")}</div></div><div class="kv"><div class="kvk">PM</div><div class="kvv">\${esc(r.pm||"-")}</div></div></div></div><div class="inline-card"><div class="summary-grid">\${summaryCards}</div><div style="margin-top:10px" class="progress"><div class="bar" style="width:\${Math.max(0,Math.min(100,r.rate||0))}%"></div></div></div></div><div style="display:grid;grid-template-columns:1fr;gap:8px;width:100%">\${renderContactCompact("계약 / 청구 담당자",r.cmNm,r.cmCo,r.cmDp,r.cmPh,r.cmEm)}\${renderContactCompact("부서 담당자",r.dmNm,r.dmCo,r.dmDp,r.dmPh,r.dmEm)}</div></div><div class="ledger-stack">\${boards}</div></div>\`;
}
function openProjectWindow(r){
const popup=window.open("","business_project_"+rowKey(r).replace(/[^0-9a-zA-Z]/g,"_"),"width=1600,height=980,resizable=yes,scrollbars=yes");
if(!popup) return;
const styleText=Array.from(document.querySelectorAll("style")).map(el=>el.textContent||"").join("\\n");
const detailHtml=renderProjectInline(r);
popup.document.open();
popup.document.write(\`<!DOCTYPE html><html lang="ko"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>\${esc(r.name||"사업 상세")}</title><style>\${styleText}
body{margin:0;background:#eef4ff;color:#0f172a;font-family:'Pretendard','Noto Sans KR','Malgun Gothic',sans-serif}
.popup-wrap{max-width:1680px;margin:0 auto;padding:20px}
.popup-head{margin-bottom:14px;padding:18px 20px;border:1px solid #dbe7f3;border-radius:20px;background:linear-gradient(180deg,#f8fbff 0%,#eef4ff 100%)}
.popup-title{font-size:28px;font-weight:900;line-height:1.2}
.popup-sub{margin-top:6px;font-size:13px;font-weight:800;color:#64748b}
.inline-panel{padding:0}
</style></head><body><div class="popup-wrap"><div class="popup-head"><div class="popup-title">\${esc(r.name||"-")}</div><div class="popup-sub">사업코드 \${esc(r.code||"-")} · 계약법인 \${esc(r.corp||"-")}</div></div>\${detailHtml}</div></body></html>\`);
popup.document.close();
popup.focus();
}
function closeAllModals(){`)
.replace(/function toggleInlineDetail\(r\)\{[\s\S]*?\n function openCollectionModal\(r\)\{/, `function toggleInlineDetail(r){
openProjectWindow(r);
}
function openCollectionModal(r){`)
.replace('const rows=S.rows,t=sumRows(rows),viewRows=rows.slice().sort((a,b)=>{const as=isSettledRow(a),bs=isSettledRow(b);if(as!==bs)return as?1:-1;return (b.recv||0)-(a.recv||0);});', 'const rows=S.rows,t=sumRows(rows),viewRows=rows.slice().sort((a,b)=>{const ar=groupSortRank(a),br=groupSortRank(b);if(ar!==br)return ar-br;return (b.recv||0)-(a.recv||0);});')
.replace(`<tr data-i="\${i}" class="\${isSettledRow(r)?"settled":""}"><td><div class="badge">\${esc(r.cat||"-")}</div><div class="subline">ID: \${esc(r.code||"-")}</div></td><td><div class="name">\${esc(r.name||"-")}</div><div class="subline">\${esc(r.periodText||"-")}</div></td><td><div>\${esc(r.corp||"-")}</div></td><td><div class="badge \${(r.status||"").includes("완료")?"ok":""}">\${esc(r.status||"-")}</div><div class="subline">\${esc(r.yn||"-")}</div></td><td class="num"><strong>\${esc(r.outsourceCost?won(r.outsourceCost):"-")}</strong></td><td class="num"><strong>\${esc(won(r.cSup))}</strong></td><td class="num"><strong>\${esc(won(r.col))}</strong></td><td class="num"><strong style="color:\${isSettledRow(r)?"#94a3b8":"#2563eb"}">\${esc(r.rate.toFixed(2)+"%")}</strong></td></tr>\${detailHtml?\`<tr class="detail-row"><td class="detail-cell" colspan="8">\${detailHtml}</td></tr>\`:""}`, `<tr data-i="\${i}" class="\${[isSettledRow(r)?"settled":"",detailOpen?"selected":""].filter(Boolean).join(" ")}"><td><div class="badge \${categoryBadgeClass(r.cat)}">\${esc(r.cat||"-")}</div></td><td><div class="subline" style="margin-top:0;font-size:12px;color:#475569">\${esc(r.code||"-")}</div></td><td><div class="name">\${esc(r.name||"-")}</div><div class="subline">\${esc(r.periodText||"-")}</div></td><td><div class="client-main">\${esc(normalizeClientDisplay(r.client))}</div><div class="subline">\${esc(formatSplitDisplay(r.split)?\`계약비율 \${formatSplitDisplay(r.split)}\`:"계약비율 -")}</div></td><td><div>\${esc(r.order||"-")}</div></td><td><div class="badge \${(r.status||"").includes("완료")?"ok":""}">\${esc(r.status||"-")}</div></td><td class="num"><strong>\${esc(won(r.cSup))}</strong></td><td class="num"><strong>\${esc(r.outsourceCost?won(r.outsourceCost):"-")}</strong></td><td class="num"><strong>\${esc(won(r.recv))}</strong></td><td class="num"><strong>\${esc(won(r.col))}</strong></td><td class="num"><strong style="color:\${isSettledRow(r)?"#94a3b8":"#2563eb"}">\${esc(r.rate.toFixed(2)+"%")}</strong></td></tr>\${detailHtml?\`<tr class="detail-row"><td class="detail-cell" colspan="11">\${detailHtml}</td></tr>\`:""}`)
.replace('setText("mCat",r.cat||"미분류");G("mCat").classList.toggle("ok",(r.status||"").includes("완료"));', 'setText("mCat",r.cat||"미분류");G("mCat").className=`badge ${categoryBadgeClass(r.cat)} ${(r.status||"").includes("완료")?"ok":""}`.trim();')
.replace('const S={all:[],rows:[],viewRows:[],file:"",filters:{},totals:null,expanded:{key:""}};', 'const S={all:[],rows:[],viewRows:[],file:"",filters:{},totals:null,expanded:{key:""},collapsedGroups:{}};')
.replace(/E\.tbody\.innerHTML=viewRows\.map\(\(r,i\)=>\{[\s\S]*?\}\)\.join\(""\);/, `let lastGroupLabel="";E.tbody.innerHTML=viewRows.map((r,i)=>{const groupLabel=tableGroupLabel(r);const isCollapsed=!!S.collapsedGroups[groupLabel];const groupRow=groupLabel!==lastGroupLabel?\`<tr class="group-row"><td colspan="11"><button type="button" class="group-chip" data-group-label="\${escAttr(groupLabel)}"><span>\${esc(groupLabel)}</span><span class="group-toggle" aria-hidden="true">\${isCollapsed?"":""}</span></button></td></tr>\`:"";lastGroupLabel=groupLabel;if(isCollapsed)return groupRow;return \`\${groupRow}<tr data-i="\${i}" class="\${isSettledRow(r)?"settled":""}"><td><div class="badge \${categoryBadgeClass(r.cat)}">\${esc(r.cat||"-")}</div></td><td><div class="subline" style="margin-top:0;font-size:12px;color:#475569">\${esc(r.code||"-")}</div></td><td><div class="name">\${esc(r.name||"-")}</div><div class="subline">\${esc(r.periodText||"-")}</div></td><td><div class="client-main">\${esc(normalizeClientDisplay(r.client))}</div><div class="subline">\${esc(formatSplitDisplay(r.split)?\`분담율 \${formatSplitDisplay(r.split)}\`:"분담율 -")}</div></td><td><div>\${esc(r.order||"-")}</div></td><td><div class="badge \${(r.status||"").includes("완료")?"ok":""}">\${esc(r.status||"-")}</div></td><td class="num"><strong>\${esc(won(r.cSup))}</strong></td><td class="num"><strong>\${esc(r.outsourceCost?won(r.outsourceCost):"-")}</strong></td><td class="num"><strong>\${esc(won(r.recv))}</strong></td><td class="num"><strong>\${esc(won(r.col))}</strong></td><td class="num"><strong style="color:\${isSettledRow(r)?"#94a3b8":"#2563eb"}">\${esc(r.rate.toFixed(2)+"%")}</strong></td></tr>\`;}).join("");`)
.replace(/E\.tbody\.addEventListener\("click",e=>\{[\s\S]*?\}\);/, `E.tbody.addEventListener("click",e=>{const groupButton=e.target&&e.target.closest?e.target.closest("button[data-group-label]"):null;if(groupButton){const label=groupButton.getAttribute("data-group-label")||"";if(label){S.collapsedGroups[label]=!S.collapsedGroups[label];render();}return;}const rowEl=e.target&&e.target.closest?e.target.closest("tr[data-i]"):null;if(!rowEl)return;const r=S.viewRows[parseInt(rowEl.getAttribute("data-i"),10)];if(!r)return;toggleInlineDetail(r);});`)
.replace('window.addEventListener("message",async e=>{\n const data=e.data||{};\n if(data.source==="total-control"&&data.type==="embedded-host") E.btnUpload.style.display="none";\n if(data.source!=="total-upload"||data.type!=="business") return;\n try{\n const buffer=data.buffer instanceof ArrayBuffer?data.buffer:(data.buffer&&data.buffer.buffer instanceof ArrayBuffer?data.buffer.buffer:null);\n if(!buffer) throw new Error("업로드 데이터가 비어 있습니다.");\n await loadLedgerFile(buffer,data.fileName||"사업관리대장.xlsx");\n }catch(err){\n S.all=[];S.rows=[];S.totals=null;syncColumnFilters([]);closeAllModals();render();E.status.textContent="업로드 실패: "+(err&&err.message?err.message:String(err));\n }\n });', 'window.addEventListener("message",async e=>{\n const data=e.data||{};\n if(data.source==="total-control"&&data.type==="embedded-host") E.btnUpload.style.display="none";\n if(data.source!=="total-upload"||data.type!=="business") return;\n try{\n let buffer=data.buffer instanceof ArrayBuffer?data.buffer:(data.buffer&&data.buffer.buffer instanceof ArrayBuffer?data.buffer.buffer:null);\n if(!buffer&&data.base64){\n const binary=atob(String(data.base64||""));\n const bytes=new Uint8Array(binary.length);\n for(let i=0;i<binary.length;i++) bytes[i]=binary.charCodeAt(i);\n buffer=bytes.buffer;\n }\n if(!buffer) throw new Error("업로드 데이터가 비어 있습니다.");\n await loadLedgerFile(buffer,data.fileName||"사업관리대장.xlsx");\n }catch(err){\n S.all=[];S.rows=[];S.totals=null;syncColumnFilters([]);closeAllModals();render();E.status.textContent="업로드 실패: "+(err&&err.message?err.message:String(err));\n }\n });')
.replace(/<\/body>\s*<\/html>\s*$/, `<script>
(function(){
if(typeof XLSX==="undefined"&&window.parent&&window.parent.XLSX){
window.XLSX=window.parent.XLSX;
}
if(typeof S==="undefined"||typeof E==="undefined") return;
if(!S.dashboard) S.dashboard={year:"",section:"active"};
function stableNorm(value){
return String(value||"").replace(/[\s\r\n]+/g,"").toLowerCase();
}
function stableHeaderRow(rows){
for(var i=0;i<rows.length;i++){
var row=(rows[i]||[]).map(stableNorm);
var hasName=row.some(function(v){return v.indexOf("사업명(계약명)")>=0||v==="사업명"||v.indexOf("사업명")>=0;});
var hasCode=row.some(function(v){return v.indexOf("총괄사업코드")>=0||v.indexOf("사업코드")>=0;});
var hasClient=row.some(function(v){return v.indexOf("발주처(매출처)")>=0||v.indexOf("발주처")>=0;});
if(hasName&&(hasCode||hasClient)) return i;
}
return -1;
}
function stableCombinedHeaders(top,bottom){
top=top||[];
bottom=bottom||[];
var max=Math.max(top.length,bottom.length),out=[],carry="";
for(var i=0;i<max;i++){
var topText=String(top[i]||"").replace(/\s+/g," ").trim();
var bottomText=String(bottom[i]||"").replace(/\s+/g," ").trim();
if(topText) carry=topText;
var head=topText||carry;
out.push(head&&bottomText?(head+" "+bottomText).trim():(head||bottomText||""));
}
return out;
}
function stableHeaderIndex(headers,candidates){
var normalized=(headers||[]).map(function(v){
return String(v||"").normalize("NFKC").toLowerCase().replace(/[^0-9a-z가-힣]+/g,"");
});
var targets=(candidates||[]).map(function(v){
return String(v||"").normalize("NFKC").toLowerCase().replace(/[^0-9a-z가-힣]+/g,"");
}).filter(Boolean);
for(var c=0;c<targets.length;c++){
var target=targets[c];
for(var i=0;i<normalized.length;i++){
if(!normalized[i]) continue;
if(normalized[i]===target||normalized[i].indexOf(target)>=0||target.indexOf(normalized[i])>=0) return i;
}
}
return -1;
}
function stableText(row,idx){
return idx>=0?String(row[idx]??"").replace(/\u00a0/g," ").replace(/\s+/g," ").trim():"";
}
function stableMoney(row,idx){
var raw=idx>=0?String(row[idx]??"").trim():"";
if(!raw||raw.indexOf("=")===0) return 0;
return parseFloat(raw.replace(/[^0-9.\-]/g,""))||0;
}
function stableRate(raw,collected,total){
var parsed=parseFloat(String(raw||"").replace(/[^0-9.\-]/g,""));
if(Number.isFinite(parsed)) return Math.max(0,Math.min(100,parsed));
return total>0?Math.max(0,Math.min(100,collected/total*100)):0;
}
function stableExtractTotals(rows){
if(rows.length&&rows[0].length) rows[0][0]=String(rows[0][0]||"").replace(/^\uFEFF/,"");
var h=stableHeaderRow(rows);
if(h<0) return null;
var headers=stableCombinedHeaders(rows[h],rows[h+1]||[]);
var indexes={
contract:stableHeaderIndex(headers,["계약금 합계","매출금액 합계","합계"]),
collected:stableHeaderIndex(headers,["매출금액 수금금액","수금금액","수금액"]),
receivable:stableHeaderIndex(headers,["매출금액 미수금액","미수금액"]),
rate:stableHeaderIndex(headers,["매출금액 수금율","수금율"])
};
var totals={contract:0,collected:0,receivable:0,rate:0};
for(var i=h+2;i<rows.length;i++){
var row=rows[i]||[];
var name=stableText(row,stableHeaderIndex(headers,["사업명 (계약명)","사업명(계약명)","사업명"]));
var code=stableText(row,stableHeaderIndex(headers,["총괄 사업코드","총괄사업코드","사업코드"]));
if(!name&&!code) continue;
totals.contract+=stableMoney(row,indexes.contract);
totals.collected+=stableMoney(row,indexes.collected);
totals.receivable+=stableMoney(row,indexes.receivable);
}
totals.rate=totals.contract>0?(totals.collected/totals.contract*100):0;
return totals;
}
window.parseLedgerExcel=function(buf){
if(typeof XLSX==="undefined") throw new Error("XLSX 라이브러리를 불러오지 못했습니다.");
var workbook=XLSX.read(buf,{type:"array",cellDates:false});
var sheetNames=workbook.SheetNames||[];
var preferredNames=sheetNames.filter(function(name){return String(name||"").indexOf("공유사업관리대장")>=0;});
var candidateNames=preferredNames.length?preferredNames:[sheetNames[1]].filter(Boolean).concat(sheetNames);
var bestRecords=null;
var bestSheet="";
var bestScore=-1;
var bestTotals=null;
candidateNames.forEach(function(name){
if(!name) return;
try{
var sheet=workbook.Sheets[name];
var rows=XLSX.utils.sheet_to_json(sheet,{header:1,raw:false,defval:""});
if(rows.length&&rows[0].length) rows[0][0]=String(rows[0][0]||"").replace(/^\uFEFF/,"");
var h=stableHeaderRow(rows);
if(h<0) return;
var headers=stableCombinedHeaders(rows[h],rows[h+1]||[]);
var indexes={
cat:stableHeaderIndex(headers,["사업구분","사업 구분"]),
corp:stableHeaderIndex(headers,["계약법인","계약 법인"]),
code:stableHeaderIndex(headers,["총괄사업코드","총괄 사업코드","사업코드"]),
name:stableHeaderIndex(headers,["사업명 (계약명)","사업명(계약명)","사업명"]),
pay:stableHeaderIndex(headers,["대금구분","대금 구분"]),
yn:stableHeaderIndex(headers,["계약여부"]),
order:stableHeaderIndex(headers,["발주방법"]),
pm:stableHeaderIndex(headers,["pm"]),
status:stableHeaderIndex(headers,["진행상태"]),
client:stableHeaderIndex(headers,["발주처 (매출처)","발주처(매출처)","발주처"]),
split:stableHeaderIndex(headers,["분담율"]),
cDate:stableHeaderIndex(headers,["계약기간 계약일","계약일"]),
sDate:stableHeaderIndex(headers,["계약기간 착수일","착수일","시작일","개시일"]),
eDate:stableHeaderIndex(headers,["계약기간 준공일","준공일","종료일","완료일"]),
cSup:stableHeaderIndex(headers,["계약금 공급가액","공급가액"]),
cVat:stableHeaderIndex(headers,["계약금 부가세","부가세"]),
cTot:stableHeaderIndex(headers,["계약금 합계","합계"]),
colDate:stableHeaderIndex(headers,["매출금액 수금일","수금일"]),
sSup:stableHeaderIndex(headers,["매출금액 공급가액","공급가액"]),
sVat:stableHeaderIndex(headers,["매출금액 부가세","부가세"]),
sTot:stableHeaderIndex(headers,["매출금액 합계","합계","매출금액"]),
col:stableHeaderIndex(headers,["매출금액 수금금액","수금금액","수금액"]),
recv:stableHeaderIndex(headers,["매출금액 미수금액","미수금액"]),
r:stableHeaderIndex(headers,["매출금액 수금율","수금율"]),
note:stableHeaderIndex(headers,["비고"])
};
var records=[];
for(var i=h+2;i<rows.length;i++){
var row=rows[i]||[];
var record={
cat:stableText(row,indexes.cat),
corp:stableText(row,indexes.corp),
code:stableText(row,indexes.code),
name:stableText(row,indexes.name),
pay:stableText(row,indexes.pay),
yn:stableText(row,indexes.yn),
order:stableText(row,indexes.order),
pm:stableText(row,indexes.pm),
status:stableText(row,indexes.status),
client:stableText(row,indexes.client),
split:stableText(row,indexes.split),
cDate:stableText(row,indexes.cDate),
sDate:stableText(row,indexes.sDate),
eDate:stableText(row,indexes.eDate),
cSup:stableMoney(row,indexes.cSup),
cVat:stableMoney(row,indexes.cVat),
cTot:stableMoney(row,indexes.cTot),
colDate:stableText(row,indexes.colDate),
sSup:stableMoney(row,indexes.sSup),
sVat:stableMoney(row,indexes.sVat),
sTot:stableMoney(row,indexes.sTot),
col:stableMoney(row,indexes.col),
recv:stableMoney(row,indexes.recv),
rateRaw:stableText(row,indexes.r),
note:stableText(row,indexes.note),
outsourceCost:0,
outsourceItems:[]
};
if(!record.name&&!record.code) continue;
if(!record.code&&!record.corp&&!record.client&&!record.pm) continue;
if(!record.cTot) record.cTot=record.cSup+record.cVat;
if(!record.sTot) record.sTot=record.sSup+record.sVat;
if(!record.recv) record.recv=Math.max(0,record.sTot-record.col);
record.rate=stableRate(record.rateRaw,record.col,record.sTot);
records.push(record);
}
if(!records.length) return;
var score=records.length+(String(name||"").indexOf("공유사업관리대장")>=0?1000000:0);
if(score>bestScore){
bestScore=score;
bestRecords=records;
bestSheet=name;
bestTotals=stableExtractTotals(rows);
}
}catch(_){}
});
if(!bestRecords) throw new Error("엑셀에서 사업관리대장 헤더를 찾지 못했습니다.");
return {records:bestRecords,sheetName:bestSheet,totals:bestTotals};
};
try{ parseLedgerExcel=window.parseLedgerExcel; }catch(_){}
function bgToday(){
var now=new Date();
return new Date(now.getFullYear(),now.getMonth(),now.getDate());
}
function bgParseDate(value){
var text=String(value||"").trim();
if(!text) return null;
var match=text.match(/(20\\d{2})\\D?(\\d{1,2})\\D?(\\d{1,2})/);
if(match){
var parsed=new Date(Number(match[1]),Number(match[2])-1,Number(match[3]));
return isNaN(parsed.getTime())?null:parsed;
}
var fallback=new Date(text);
if(isNaN(fallback.getTime())) return null;
return new Date(fallback.getFullYear(),fallback.getMonth(),fallback.getDate());
}
function bgDateOrYearStart(row){
return bgParseDate(row&&row.sDate)||bgParseDate(row&&row.cDate)||(/^20\\d{2}$/.test(bgDisplayYear(row))?new Date(Number(bgDisplayYear(row)),0,1):null);
}
function bgDateOrYearEnd(row){
return bgParseDate(row&&row.eDate)||(/^20\\d{2}$/.test(bgCompletionYear(row))?new Date(Number(bgCompletionYear(row)),11,31):null);
}
function bgYearCutoff(year){
var targetYear=Number(year||0);
if(!targetYear) return null;
var today=bgToday();
if(targetYear < today.getFullYear()) return new Date(targetYear,11,31);
if(targetYear === today.getFullYear()) return today;
return null;
}
function bgYearStartDate(year){
var targetYear=Number(year||0);
return targetYear?new Date(targetYear,0,1):null;
}
function bgYearFromText(value){
var match=String(value||"").trim().match(/(20\\d{2})/);
return match?match[1]:"";
}
function bgStartYear(row){
return bgYearFromText(row&&row.sDate);
}
function bgEndYear(row){
return bgYearFromText(row&&row.eDate);
}
function bgDisplayYear(row){
var start=bgStartYear(row);
if(start) return start;
var contractMatch=String(row&&row.cDate||"").trim().match(/(20\\d{2})/);
if(contractMatch) return contractMatch[1];
var nameMatch=String(row&&row.name||"").trim().match(/^(20\\d{2})/);
if(nameMatch) return nameMatch[1];
return bgEndYear(row)||"미지정";
}
function bgCompletionYear(row){
return bgEndYear(row)||bgDisplayYear(row);
}
function bgLastActiveYear(row){
var startYear=Number(bgDisplayYear(row)||0);
var endDate=bgDateOrYearEnd(row);
var today=bgToday();
if(endDate) return String(Math.min(endDate.getFullYear(),today.getFullYear()));
if(startYear>0) return String(Math.max(startYear,today.getFullYear()));
return "";
}
function bgActiveInYear(row,year){
var cutoff=bgYearCutoff(year);
var yearStart=bgYearStartDate(year);
var startDate=bgDateOrYearStart(row);
var endDate=bgDateOrYearEnd(row);
if(!(cutoff&&yearStart&&startDate)) return false;
if(startDate>cutoff) return false;
if(endDate&&endDate<yearStart) return false;
return !(endDate&&endDate<=cutoff);
}
function bgStartedInYear(row,year){
var cutoff=bgYearCutoff(year);
var startDate=bgDateOrYearStart(row);
if(!(cutoff&&startDate)) return false;
return startDate.getFullYear()===Number(year||0)&&startDate<=cutoff;
}
function bgCompletedInYear(row,year){
var cutoff=bgYearCutoff(year);
var endDate=bgDateOrYearEnd(row);
if(!(cutoff&&endDate)) return false;
return endDate.getFullYear()===Number(year||0)&&endDate<=cutoff;
}
function bgYearRange(row){
var years=[];
var startYear=Number(bgDisplayYear(row)||0);
var lastYear=Number(isSettledRow(row)?bgCompletionYear(row):bgLastActiveYear(row));
if(startYear&&lastYear&&lastYear>=startYear){
for(var year=startYear;year<=lastYear;year++) years.push(String(year));
}else if(startYear){
years.push(String(startYear));
}
if(isSettledRow(row)){
var completionYear=bgCompletionYear(row);
if(/^20\\d{2}$/.test(completionYear)&&years.indexOf(completionYear)<0) years.push(completionYear);
}
return years;
}
function bgYears(rows){
var years=Array.from(new Set((Array.isArray(rows)?rows:[]).flatMap(function(row){
return bgYearRange(row);
}).filter(function(year){
return /^20\\d{2}$/.test(year);
}))).sort(function(a,b){
return Number(b)-Number(a);
});
return years.length?years:[String(new Date().getFullYear())];
}
function bgEnsureYear(rows){
var years=bgYears(rows);
if(!years.includes(S.dashboard.year)) S.dashboard.year=years[0];
return years;
}
function bgSummarize(rows,selectedYear){
var items=Array.isArray(rows)?rows:[];
var targetYear=selectedYear||bgEnsureYear(items)[0];
var projectRows=items.filter(function(row){ return bgActiveInYear(row,targetYear)||bgStartedInYear(row,targetYear)||bgCompletedInYear(row,targetYear); });
function bgTotals(targetRows){
return (Array.isArray(targetRows)?targetRows:[]).reduce(function(acc,row){
acc.c += Number(row&&row.cSup||0);
acc.col += Number(row&&row.col||0);
acc.recv += Number(row&&row.recv||0);
return acc;
},{c:0,col:0,recv:0});
}
function isBaronProjectRow(row){
var category=String(row&&row.cat||"").trim();
if(!category.includes("바론")) return false;
if(typeof isSupportServiceRow==="function"&&isSupportServiceRow(row)) return false;
if(typeof isProgramRow==="function"&&isProgramRow(row)) return false;
return true;
}
var baronProjectRows=projectRows.filter(isBaronProjectRow);
var activeRows=items.filter(function(row){ return bgActiveInYear(row,targetYear); });
var newProjectRows=items.filter(function(row){ return bgStartedInYear(row,targetYear); });
var completedRows=items.filter(function(row){ return bgCompletedInYear(row,targetYear); });
var managementRows=newProjectRows.filter(function(row){ return typeof isSupportServiceRow==="function"&&isSupportServiceRow(row); });
var coreRows=projectRows.filter(function(row){ return !(typeof isSupportServiceRow==="function"&&isSupportServiceRow(row)); });
var projectBreakdown=newProjectRows.reduce(function(acc,row){
var category=String(row&&row.cat||"").trim();
if(category==="바론") acc.baron++;
else if(category==="가족사") acc.family++;
return acc;
},{baron:0,family:0});
return {
targetYear:targetYear,
projectRows:projectRows,
baronProjectRows:baronProjectRows,
baronProjectTotals:bgTotals(baronProjectRows),
isBaronProjectRow:isBaronProjectRow,
managementRows:managementRows,
coreTotals:bgTotals(coreRows),
managementTotals:bgTotals(managementRows),
activeRows:activeRows,
newProjectRows:newProjectRows,
completedRows:completedRows,
projectBreakdown:projectBreakdown
};
}
function bgMatches(row){
var section=S.dashboard.section||"active";
var selectedYear=S.dashboard.year||bgEnsureYear(S.all)[0];
if(section==="new") return bgStartedInYear(row,selectedYear);
if(section==="completed") return bgCompletedInYear(row,selectedYear);
return bgActiveInYear(row,selectedYear);
}
filter=function(){
bgEnsureYear(S.all);
var q=String(E.search.value||"").trim().toLowerCase();
var searched=!q?S.all.slice():S.all.filter(function(r){
return [r.code,r.name,r.client,r.pm,r.status,r.cat,r.corp,r.pay,(r.payments||[]).map(function(p){return p.pay;}).join(" "),r.periodText,r.outsourceVendorText,(r.outsourceItems||[]).map(function(item){return [item.vendor,item.detail,item.progress,item.note,(item.payments||[]).map(function(payment){return [payment.label,payment.note,payment.invoiceDate,payment.paymentDate].join(" ");}).join(" ")].join(" ");}).join(" "),outsourceFilterLabel(r),amountFilterLabel(r),collectedFilterLabel(r)].join(" ").toLowerCase().includes(q);
});
S.rows=searched.filter(function(r){ return bgMatches(r)&&matchesColumnFilters(r); });
render();
};
render=function(){
var rows=S.rows;
var viewRows=rows.slice().sort(function(a,b){
var ar=groupSortRank(a),br=groupSortRank(b);
if(ar!==br) return ar-br;
return (b.recv||0)-(a.recv||0);
});
var years=bgEnsureYear(S.all);
var summary=bgSummarize(S.all,S.dashboard.year);
var visibleBaronProjectRows=rows.filter(function(row){
return typeof summary.isBaronProjectRow==="function"&&summary.isBaronProjectRow(row);
});
var baseCoreTotals=visibleBaronProjectRows.reduce(function(acc,row){
acc.c += Number(row&&row.cSup||0);
acc.col += Number(row&&row.col||0);
acc.recv += Number(row&&row.recv||0);
return acc;
},{c:0,col:0,recv:0});
var totalContract=baseCoreTotals.c;
var totalCollected=baseCoreTotals.col;
var totalReceivable=baseCoreTotals.recv;
var totalRate=rate("",totalCollected,totalCollected+totalReceivable);
S.viewRows=viewRows;
var projectNote='계약기간 시작년도 기준 · 진행과업은 전년도 이월 포함';
var toolbarHtml='<div class="cards-toolbar">'
+'<div class="cards-toolbar-row">'+years.map(function(year){
return '<button type="button" class="summary-year-chip '+(S.dashboard.year===year?'active':'')+'" data-dashboard-year="'+escAttr(year)+'">'+esc(year)+'</button>';
}).join('')+'</div>'
+'<div class="cards-toolbar-metrics">'
+'<button type="button" class="summary-filter-chip '+(S.dashboard.section==='active'?'active':'')+'" data-dashboard-section="active"><span class="label">'+esc(summary.targetYear)+'년 진행과업</span><span class="count">'+summary.activeRows.length.toLocaleString("ko-KR")+'건</span><span class="meta">전년도 이월 사업 포함</span></button>'
+'<button type="button" class="summary-filter-chip '+(S.dashboard.section==='new'?'active':'')+'" data-dashboard-section="new"><span class="label">'+esc(summary.targetYear)+'년 신규프로젝트</span><span class="count">'+summary.newProjectRows.length.toLocaleString("ko-KR")+'건</span><span class="meta">계약기간 시작년도 기준</span></button>'
+'<button type="button" class="summary-filter-chip '+(S.dashboard.section==='completed'?'active':'')+'" data-dashboard-section="completed"><span class="label">'+esc(summary.targetYear)+'년 완료과업</span><span class="count">'+summary.completedRows.length.toLocaleString("ko-KR")+'건</span><span class="meta">해당년도 종료 사업 기준</span></button>'
+'</div></div>';
var cards=[
{label:summary.targetYear+'년 바론 프로젝트수',value:visibleBaronProjectRows.length.toLocaleString("ko-KR")+' 건',note:projectNote},
{label:'바론 프로젝트 계약금',value:won(totalContract),note:'현재 표 기준 바론 일반프로젝트 합계'},
{label:'바론 프로젝트 수금금액',value:won(totalCollected),note:'현재 표 기준 바론 일반프로젝트 합계'},
{label:'바론 프로젝트 미수금액',value:won(totalReceivable),note:'현재 표 기준 바론 일반프로젝트 합계'},
{label:'바론 프로젝트 수금율',value:totalRate.toFixed(2)+'%',note:'현재 표 기준 바론 일반프로젝트 합계'},
{label:'경영지원서비스 금액',value:won(summary.managementTotals.c),note:(summary.managementRows.length?'시작년도 '+summary.targetYear+' 기준 '+summary.managementRows.length.toLocaleString("ko-KR")+'건':'시작년도 '+summary.targetYear+' 대상 없음'),className:'management'}
];
E.cards.innerHTML=toolbarHtml+cards.map(function(card){
return '<div class="card '+esc(card.className||'')+'"><div class="k">'+esc(card.label)+'</div><div class="v">'+esc(card.value)+'</div>'+(card.note?'<div class="n">'+esc(card.note)+'</div>':'')+'</div>';
}).join('');
var lastGroupLabel='';
E.tbody.innerHTML=viewRows.map(function(r,i){
var groupLabel=tableGroupLabel(r);
var isCollapsed=!!S.collapsedGroups[groupLabel];
var groupRow=groupLabel!==lastGroupLabel?'<tr class="group-row"><td colspan="11"><button type="button" class="group-chip" data-group-label="'+escAttr(groupLabel)+'"><span>'+esc(groupLabel)+'</span><span class="group-toggle" aria-hidden="true">'+(isCollapsed?'':'')+'</span></button></td></tr>':'';
lastGroupLabel=groupLabel;
if(isCollapsed) return groupRow;
return groupRow+'<tr data-i="'+i+'" class="'+(isSettledRow(r)?'settled':'')+'"><td><div class="badge '+categoryBadgeClass(r.cat)+'">'+esc(r.cat||'-')+'</div></td><td><div class="subline" style="margin-top:0;font-size:12px;color:#475569">'+esc(r.code||'-')+'</div></td><td><div class="name">'+esc(r.name||'-')+'</div><div class="subline">'+esc(r.periodText||'-')+'</div></td><td><div class="client-main">'+esc(normalizeClientDisplay(r.client))+'</div><div class="subline">'+esc(formatSplitDisplay(r.split)?'분담율 '+formatSplitDisplay(r.split):'분담율 -')+'</div></td><td><div>'+esc(r.order||'-')+'</div></td><td><div class="badge '+((r.status||'').includes('완료')?'ok':'')+'">'+esc(r.status||'-')+'</div></td><td class="num"><strong>'+esc(won(r.cSup))+'</strong></td><td class="num"><strong>'+esc(r.outsourceCost?won(r.outsourceCost):'-')+'</strong></td><td class="num"><strong>'+esc(won(r.recv))+'</strong></td><td class="num"><strong>'+esc(won(r.col))+'</strong></td><td class="num"><strong style="color:'+(isSettledRow(r)?'#94a3b8':'#2563eb')+'">'+esc(r.rate.toFixed(2)+'%')+'</strong></td></tr>';
}).join('');
E.empty.style.display=rows.length?'none':'block';
var settledCount=S.all.filter(isSettledRow).length;
E.status.textContent=S.all.length?'로드 완료: '+S.all.length.toLocaleString("ko-KR")+'건'+(S.file?' · 파일: '+S.file:'')+(settledCount?' · 완료 '+settledCount.toLocaleString("ko-KR")+'건 포함':''):'사업관리대장-1.xlsx를 업로드하면 데이터를 불러옵니다.';
};
if(E.cards&&!E.cards.dataset.dashboardBound){
E.cards.dataset.dashboardBound='true';
E.cards.addEventListener("click",function(e){
var yearBtn=e.target&&e.target.closest?e.target.closest("[data-dashboard-year]"):null;
if(yearBtn){
S.dashboard.year=yearBtn.getAttribute("data-dashboard-year")||S.dashboard.year;
filter();
return;
}
var sectionBtn=e.target&&e.target.closest?e.target.closest("[data-dashboard-section]"):null;
if(sectionBtn){
S.dashboard.section=sectionBtn.getAttribute("data-dashboard-section")||"active";
filter();
}
});
}
filter();
})();
<\/script></body></html>`);
}
frameBusiness.addEventListener('load', () => {
businessReady = true;
syncBusinessTodayDate();
if (frameBusiness.contentWindow) {
frameBusiness.contentWindow.postMessage({ source: 'total-control', type: 'embedded-host' }, '*');
}
flushPending().catch(console.error);
});
frameBusiness.srcdoc = buildBusinessSrcdoc();
frameDash.srcdoc = decodeBase64Utf8(DASH_HTML_B64)
.replace(/<div className="flex items-center gap-4">[\s\S]*?<\/div>\s*<div className="flex items-center justify-end gap-2 flex-wrap max-w-\[1100px\] flex-1">/, '<div className="flex items-center justify-start gap-2 flex-wrap w-full">')
.replace('<h1 className="text-2xl font-black">2026 리소스 통합 대시보드</h1>', '')
.replace('<p className="text-[12px] text-slate-400 font-bold uppercase tracking-widest">Final Stable Version</p>', '');
frameMh.srcdoc = decodeBase64Utf8(MH_HTML_B64);
const uploadBusiness = document.getElementById('upload-business');
const uploadExpense = document.getElementById('upload-expense');
const uploadWork = document.getElementById('upload-work');
const btnUploadBusiness = document.getElementById('btn-upload-business');
const btnUploadExpense = document.getElementById('btn-upload-expense');
const btnUploadWork = document.getElementById('btn-upload-work');
const dateControls = document.getElementById('date-controls');
const yearShortcuts = document.getElementById('year-shortcuts');
const globalStartDate = document.getElementById('global-start-date');
const globalEndDate = document.getElementById('global-end-date');
const RECENT_YEAR = new Date().getFullYear();
let availableYears = Array.from({ length: 5 }, (_, i) => RECENT_YEAR - 4 + i);
let activeYearShortcut = String(RECENT_YEAR);
let businessReady = false;
let dashReady = false;
let mhReady = false;
let expenseUploaded = false;
let workUploaded = false;
const pending = { business: null, expense: null, work: null, mh: null, projectOrder: null };
let autoProjectOrderCsvText = '';
let autoDefaultDataLoaded = false;
const EMBEDDED_PROJECT_ORDER_CSV_B64 = '66ek7LacL+u5hOunpOy2nCzrtoTslbws7IS467aA67aE7JW8LO2UhOuhnOygne2KuOuqhQ0K66ek7LacLOuwlOuhoOqzhOyVvSztjJDrp6QsRUctQklNICjtjIzsnbTtlITthY3svZTrpqzslYQpDQrrp6Tstpws67CU66Gg6rOE7JW9LO2MkOunpCxFUlDsi5zsiqTthZwg6rCc67CcIOuwjyDsnKDsp4Drs7TsiJgo7ZWc6rWt7KKF7ZWp7JeU7KeA64uI7Ja066eBKQ0K66ek7LacLOuwlOuhoOqzhOyVvSztjJDrp6QsR0FJQSDquLDriqUg6rCc7ISgIOqzhOyVvQ0K66ek7LacLOuwlOuhoOqzhOyVvSzquLDsiKDsmqnsl60s6rOE7JaRLeqwle2ZlCDqs6Dsho3rj4TroZwg6rG07ISkIOq4sOuzuCDrsI8g7Iuk7IucKDXqs7XqtawpDQrrp6Tstpws67CU66Gg6rOE7JW9LOq4sOyIoOyaqeyXrSzqta3rj4Q0Mu2YuOyEoCDsm5Dso7wg7Z2l7JeFIOyCrOygnCDsmbggMeqwnOyGjCDqtZDssKjroZwg6rCc7ISg6rO17IKsIOyLpOyLnOyEpOqzhOyaqeyXrSjsgrzslYgpDQrrp6Tstpws67CU66Gg6rOE7JW9LOq4sOyIoOyaqeyXrSzsnbjso7wt7Je87LmYKOygnDHqs7XqtawpIO2ajOydmCDsi5zsiqTthZwg7ISk7LmYDQrrp6Tstpws67CU66Gg6rOE7JW9LOq4sOyIoOyaqeyXrSzqs6Dsho3qta3rj4Qg7KCcMzLtmLgg64u57KeEfuyyreyjvOyEoCDsnbjso7x+7Je87LmY6rCEIOqxtOyEpOqzteyCrCjsoJwy6rO16rWsKSDthrXtlakg7Iqk66eI7Yq47IOB7Zmp7IukIOq1rOy2lSDrsI8g7Jq07JiBDQrrp6Tstpws67CU66Gg6rOE7JW9LOq4sOyIoOyaqeyXrSzrjIDsgrAt64u57KeEIDHqs7XqtawgQ29uZmVyZW5jZSBQbGF0Zm9ybShCaWdSb29tKeq1rOy2lQ0K66ek7LacLOuwlOuhoOqzhOyVvSzquLDsiKDsmqnsl60s64yA7IKwLeuLueynhCAy6rO16rWsIENvbmZlcmVuY2UgUGxhdGZvcm0oQmlnUm9vbSnqtazstpUNCuunpOy2nCzrsJTroaDqs4Tslb0s6riw7Iig7Jqp7JetLOuMgOyCsC3ri7nsp4QgMy006rO16rWsIENvbmZlcmVuY2UgUGxhdGZvcm0oQmlnUm9vbSnqtazstpUNCuunpOy2nCzrsJTroaDqs4Tslb0s7L2Y7YWQ7LigIOygnOyekSzrs7TsnYDqta3thqDrj4TroZwg7IKs7JeF6rSA66asDQrrp6Tstpws67CU66Gg6rOE7JW9LOy9mO2FkOy4oCDsoJzsnpEs7ZWc6rCV6rWQ65+JIOyCrOyXheq0gOumrCgy6rO16rWsKQ0K66ek7LacLOuwlOuhoOqzhOyVvSzsvZjthZDsuKAg7KCc7J6RLOyYiOyCsOq1re2GoCDsoJwy6raM7JetDQrrp6Tstpws67CU66Gg6rOE7JW9LOy9mO2FkOy4oCDsoJzsnpEs6rCA7Y+J6rWwIO2VmOyImOq0gOunnSDqs4TsuKHsi5zsiqTthZwg7Jyg7KeA6rSA66asIOyaqeyXrQ0K66ek7LacLOuwlOuhoOqzhOyVvSzsvZjthZDsuKAg7KCc7J6RLFBRKOyngOyYpOuplOy5tOydtOyXlOyngCkNCuunpOy2nCzqsIDsobHsgqwg7ZSE66Gc7KCd7Yq4LEJJTSDshKTqs4Qs64yA7IKwfuuLueynhCDsi5zqs7Uy6rO16rWsIOyLnOqztUJJTSDsiJjtlokNCuunpOy2nCzqsIDsobHsgqwg7ZSE66Gc7KCd7Yq4LEJJTSDshKTqs4Qs7ISc7IKwfuuqheyynCDquLDrs7gg67CPIOyLpOyLnOyEpOqzhA0K66ek7LacLOqwgOyhseyCrCDtlITroZzsoJ3tirgsQklNIOyEpOqzhCzsmrjsgrB+7Jm46rO97Iic7ZmYIOqzoOyGjeuPhOuhnCgx6rO16rWsKQ0K66ek7LacLOqwgOyhseyCrCDtlITroZzsoJ3tirgsQklNIOyEpOqzhCzstqnrgqjrhbzsgrDsiqTrp4jtirjtjJwg7KGw6rCQ64+EDQrrp6Tstpws6rCA7KGx7IKsIO2UhOuhnOygne2KuCxCSU0g7ISk6rOELOybkO2aqOuMgOq1kOu2geuLqCDsobDqsJDrj4QNCuunpOy2nCzqsIDsobHsgqwg7ZSE66Gc7KCd7Yq4LEJJTSDshKTqs4Qs7IKs7LKc7IucIO2Wpey0jOyngOq1rCDsmrDsiJjsnKDstpzsoIDqsJDsi5zshKQgUFEg66y47ISc7Y647KeRDQrrp6Tstpws6rCA7KGx7IKsIO2UhOuhnOygne2KuCzsi5zqs7Us7J247LKc67CcIEtUWCDsp4HqsrDqtZDrn4kg7Iuc6rO1DQrrp6Tstpws6rCA7KGx7IKsIO2UhOuhnOygne2KuCzrlJTsnpDsnbgs6rCA7KGx7IKsIOuztOqzoOyEnCDthZztlIzrpr8g7KCc7J6RX1BRDQrrp6Tstpws6rCA7KGx7IKsIO2UhOuhnOygne2KuCxSJkQs65SU7KeA7YS4IOq1re2GoOygleuztCDquLDsiKDqsJzrsJzsgqzsl4UNCuunpOy2nCzqsIDsobHsgqwg7ZSE66Gc7KCd7Yq4LFImRCzqta3thqDsoJXrs7QgMu2VteyLrA0K66ek7LacLOqwgOyhseyCrCDtlITroZzsoJ3tirgsUiZELOyKpOuniO2KuOqxtOyEpCgxMOqzvOygnCkNCuunpOy2nCzqsIDsobHsgqwg7ZSE66Gc7KCd7Yq4LFImRCxYUuq4sOuwmCDqsbTshKTshKTqs4Qg7ZiB7Iug7Iuc7Iqk7YWcDQrruYTrp6TstpwsUy9XIOqwnOuwnCzquLDstIjsobDsgqwg67CPIEdJUyxLTkdJTA0K67mE66ek7LacLFMvVyDqsJzrsJws6riw7LSI7KGw7IKsIOuwjyBHSVMsR0lTIE1hcHBlcg0K67mE66ek7LacLFMvVyDqsJzrsJws6riw7LSI7KGw7IKsIOuwjyBHSVMs7LKc7KeA7J24DQrruYTrp6TstpwsUy9XIOqwnOuwnCzquLDstIjsobDsgqwg67CPIEdJUyxTdXJ2ZXlvcg0K67mE66ek7LacLFMvVyDqsJzrsJws6riw7LSI7KGw7IKsIOuwjyBHSVMsR0FJQQ0K67mE66ek7LacLFMvVyDqsJzrsJws64+E66GcLFdheVByaW1hbA0K67mE66ek7LacLFMvVyDqsJzrsJws64+E66GcLFdheUNvbmZpcm0NCuu5hOunpOy2nCxTL1cg6rCc67CcLOuPhOuhnCxXYXlEcmF3DQrruYTrp6TstpwsUy9XIOqwnOuwnCzrj4TroZwsV2F5U2hvcA0K67mE66ek7LacLFMvVyDqsJzrsJws6rWs7KGw66y8LFdhbGxaYWluZXINCuu5hOunpOy2nCxTL1cg6rCc67CcLOq1rOyhsOusvCxCcmlkZ2UgcGxhbm5lcg0K67mE66ek7LacLFMvVyDqsJzrsJws6rWs7KGw66y8LEFidXRaYWluZXINCuu5hOunpOy2nCxTL1cg6rCc67CcLOq1rOyhsOusvCxCcmlaYWluZXItRFINCuu5hOunpOy2nCxTL1cg6rCc67CcLOq1rOyhsOusvCxCcmlaYWluZXItTm9kdWxhcg0K67mE66ek7LacLFMvVyDqsJzrsJws6rWs7KGw66y8LFR1bm5lbFphaW5lcg0K67mE66ek7LacLFMvVyDqsJzrsJws6rWQ7Ya1LFRPVkENCuu5hOunpOy2nCxTL1cg6rCc67CcLOyImOumrC/siJjrrLgsTGlmZUxpbmUtV2F0ZXINCuu5hOunpOy2nCxTL1cg6rCc67CcLOyImOumrC/siJjrrLgs6rCV7Jqw6rCV64+E7IKw7KCVIO2UhOuhnOq3uOueqA0K67mE66ek7LacLFMvVyDqsJzrsJws6re4656Y7ZS9Juq1rOyhsO2VtOyEnSxIbUVHKEhtRHJhdykNCuu5hOunpOy2nCxTL1cg6rCc67CcLOq3uOuemO2UvSbqtazsobDtlbTshJ0sRUctQklNIE1vZGVsZXINCuu5hOunpOy2nCxTL1cg6rCc67CcLOq3uOuemO2UvSbqtazsobDtlbTshJ0sRUctQklNIERyYXdlcg0K67mE66ek7LacLFMvVyDqsJzrsJws6re4656Y7ZS9Juq1rOyhsO2VtOyEnSxTdHJBbmENCuu5hOunpOy2nCxTL1cg6rCc67CcLOyGlOujqOyFmCzrrLjshJzqtIDrpqzsi5zsiqTthZwoUE0pDQrruYTrp6TstpwsUy9XIOqwnOuwnCzshpTro6jshZgsYkNNZg0K67mE66ek7LacLFMvVyDqsJzrsJws7IaU66Oo7IWYLEdTSU0NCuu5hOunpOy2nCxTL1cg6rCc67CcLOyGlOujqOyFmCxDQ1ANCuu5hOunpOy2nCxTL1cg6rCc67CcLOyGlOujqOyFmCzri6jqsIAv6rO17KCVIHNvbHV0aW9uDQrruYTrp6TstpwsUy9XIOqwnOuwnCzshpTro6jshZgsV2F0Y2hCSU0NCuu5hOunpOy2nCxTL1cg6rCc67CcLOyGlOujqOyFmCxUd2luIEhpZ2h3YXkNCuu5hOunpOy2nCxTL1cg6rCc67CcLOyGlOujqOyFmCxEb21haW5lcg0K67mE66ek7LacLFMvVyDqsJzrsJws7Jq07JiBUy9XLOyeheywsOygleuztCjsmqnsl60v6rO17IKsKSDsobDtmowg7Iuc7Iqk7YWcDQrruYTrp6TstpwsUy9XIOqwnOuwnCzsmrTsmIFTL1csRVJQOiDsnqXtl4zsgrDsl4UNCuu5hOunpOy2nCxTL1cg6rCc67CcLOyatOyYgVMvVyxFUlA6IFBUQw0K67mE66ek7LacLFMvVyDqsJzrsJws7Jq07JiBUy9XLEVSUDog7ZWc6528DQrruYTrp6TstpwsUy9XIOqwnOuwnCzsmrTsmIFTL1csRVJQOiDsgrzslYgNCuu5hOunpOy2nCxTL1cg6rCc67CcLOyatOyYgVMvVyxFUlA6IO2VnOunpQ0K67mE66ek7LacLFMvVyDqsJzrsJws7Jq07JiBUy9XLEVSUDog67CU66GgDQrruYTrp6TstpwsUy9XIOqwnOuwnCzsmrTsmIFTL1csRVJQOiAo7KO8Keyepe2XjA0K67mE66ek7LacLFMvVyDqsJzrsJws7Jq07JiBUy9XLEVSUDog7IKw7ZWY7KKF7ZWp6riw7IigDQrruYTrp6TstpwsUy9XIOqwnOuwnCzsmrTsmIFTL1csQ2l2aWxFbmdpbmVlcmluZ0xhYg0K67mE66ek7LacLFMvVyDqsJzrsJws7Jq07JiBUy9XLFBR7Iuc7Iqk7YWcDQrruYTrp6TstpwsUy9XIOqwnOuwnCzsmrTsmIFTL1csQkVQcw0K67mE66ek7LacLFMvVyDqsJzrsJws7Jq07JiBUy9XLOyghOyCsOyatOyYgeq0gOumrA0K67mE66ek7LacLFMvVyDqsJzrsJws7Jq07JiBUy9XLO2VnOunpeqwgOyhsSDrsLDsm4DthLANCuu5hOunpOy2nCzquLDtmo0v7KCc7JWILOq4sO2ajSzsgqzsoITquLDtmo0NCuu5hOunpOy2nCzquLDtmo0v7KCc7JWILOq4sO2ajSzssq3smqnsspzqtZAg7JeF66y07KeA7JuQDQrruYTrp6Tstpws6riw7ZqNL+ygnOyViCzquLDtmo0s7IiY7J6Q7JuQIO2VtOyZuOyCrOyXhQ0K67mE66ek7LacLOq4sO2ajS/soJzslYgs6riw7ZqNLEFJDQrruYTrp6Tstpws6riw7ZqNL+ygnOyViCzquLDtmo0sR0lT7J6l67mEIOqwnOuwnA0K67mE66ek7LacLOq4sO2ajS/soJzslYgs6riw7ZqNLO2UhOumrOy6kOyKpO2KuCDsobDrpr3si50g67CV7IqkIOq1kOufiQ0K67mE66ek7LacLOq4sO2ajS/soJzslYgs6riw7ZqNLOyduOuNleybkH7rj5ntg4Qg67O17ISg7KCE7LKgIOyKpOuniO2KuOyDge2ZqeyLpCDqtazstpUg67CPIOyatOyYgeyViA0K7LSd6rSE6riw7ZqN7IukLOy0neq0hOq4sO2ajeyLpCzstJ3qtITquLDtmo3si6Qs6rK97JiB6riw7ZqNL+yghOuetQ0K7LSd6rSE6riw7ZqN7IukLOy0neq0hOq4sO2ajeyLpCzstJ3qtITquLDtmo3si6Qs7J247IKsL+q1kOycoQ0K7LSd6rSE6riw7ZqN7IukLOy0neq0hOq4sO2ajeyLpCzstJ3qtITquLDtmo3si6Qs7Jq07JiB7KeA7JuQKOy0neustCkNCuy0neq0hOq4sO2ajeyLpCzstJ3qtITquLDtmo3si6Qs7LSd6rSE6riw7ZqN7IukLOyXheustC/sgqzsl4XqtIDrpqwNCuqzte2GtSzqs7XthrUs6rO17Ya1LCLqtZDsnKHtm4jroKgs7LC47ISdIg0K6rO17Ya1LOqzte2GtSzqs7XthrUs6rO17Ya1DQo=';
function hasAnalysisInputs() {
return expenseUploaded && workUploaded;
}
function setTab(tab) {
if ((tab === 'dash' || tab === 'mh') && !hasAnalysisInputs()) {
alert('전표 데이터와 MH 데이터를 모두 업로드해야 분석 탭을 볼 수 있습니다.');
tab = 'business';
}
const isBusiness = tab === 'business';
const isMh = tab === 'mh';
const isDash = !isBusiness && !isMh;
paneBusiness.classList.toggle('active', isBusiness);
paneDash.classList.toggle('active', isDash);
paneMh.classList.toggle('active', isMh);
btnTabBusiness.classList.toggle('active', isBusiness);
btnTabDash.classList.toggle('active', isDash);
btnTabMh.classList.toggle('active', isMh);
dateControls.classList.toggle('hidden', isBusiness);
if (isBusiness) {
syncBusinessTodayDate();
if (frameBusiness.contentWindow) {
frameBusiness.contentWindow.postMessage({ source: 'total-control', type: 'tab-activated', tab: 'business' }, '*');
}
return;
}
if (isMh) {
if (frameMh.contentWindow) {
frameMh.contentWindow.postMessage({ source: 'total-control', type: 'tab-activated', tab: 'mh' }, '*');
}
return;
}
if (frameDash.contentWindow) {
frameDash.contentWindow.postMessage({ source: 'total-control', type: 'tab-activated', tab: 'dash' }, '*');
}
}
let businessRequestSeq = 0;
const businessUploadAcks = new Map();
function waitForBusinessUploadAck(requestId) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
businessUploadAcks.delete(requestId);
reject(new Error('사업관리대장 업로드 응답이 없습니다.'));
}, 8000);
businessUploadAcks.set(requestId, { resolve, reject, timer });
});
}
async function ensureBusinessReady(timeoutMs = 8000) {
const startedAt = Date.now();
while ((!businessReady || !frameBusiness.contentWindow) && (Date.now() - startedAt) < timeoutMs) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
if (!businessReady || !frameBusiness.contentWindow) {
throw new Error('사업관리대장 화면이 아직 준비되지 않았습니다.');
}
}
async function deliverBusinessPayload(payload) {
if (!frameBusiness.contentWindow) return false;
try {
frameBusiness.contentWindow.postMessage(payload, '*');
return true;
} catch (_) {
return false;
}
}
async function postToBusiness(buffer, fileName) {
await ensureBusinessReady();
const requestId = `business-${Date.now()}-${++businessRequestSeq}`;
const payload = {
source: 'total-upload',
type: 'business',
fileName,
requestId,
buffer,
base64: arrayBufferToBase64(buffer)
};
if (!businessReady || !frameBusiness.contentWindow) {
pending.business = payload;
return;
}
if (!await deliverBusinessPayload(payload)) {
businessUploadAcks.delete(requestId);
pending.business = payload;
return;
}
pending.business = null;
}
function postToDash(type, text) {
const payload = { source: 'total-upload', type, text };
if (!dashReady || !frameDash.contentWindow) {
pending[type] = payload;
return;
}
frameDash.contentWindow.postMessage(payload, '*');
}
function postToMh(binary, fileName) {
const payload = { source: 'total-upload', type: 'mh', binary, fileName };
if (!mhReady || !frameMh.contentWindow) {
pending.mh = payload;
return;
}
frameMh.contentWindow.postMessage(payload, '*');
}
function postProjectOrderCsv(text) {
const payload = { source: 'total-control', type: 'project-order-csv', text };
if (!dashReady || !frameDash.contentWindow) {
pending.projectOrder = payload;
return;
}
frameDash.contentWindow.postMessage(payload, '*');
}
function inferYearsFromText(text) {
const matches = String(text || '').match(/\b20\d{2}\b/g) || [];
return Array.from(new Set(matches.map(Number).filter(year => year >= 2010 && year <= 2099))).sort((a, b) => a - b);
}
function getFallbackYears() {
return Array.from({ length: 5 }, (_, i) => RECENT_YEAR - 4 + i);
}
function getCurrentAllRange() {
const years = availableYears.length ? availableYears : getFallbackYears();
return {
startDate: `${years[0]}-01-01`,
endDate: `${years[years.length - 1]}-12-31`
};
}
function getDefaultYearShortcut() {
const years = availableYears.length ? availableYears : getFallbackYears();
return years.includes(RECENT_YEAR) ? String(RECENT_YEAR) : String(years[years.length - 1]);
}
function renderYearShortcutButtons() {
if (!yearShortcuts) return;
const years = availableYears.length ? availableYears : getFallbackYears();
yearShortcuts.innerHTML = [`<button type="button" class="year-chip${activeYearShortcut === 'ALL' ? ' active' : ''}" data-year-shortcut="ALL">전체</button>`]
.concat(years.map(year => `<button type="button" class="year-chip${activeYearShortcut === String(year) ? ' active' : ''}" data-year-shortcut="${year}">${year}</button>`))
.join('');
}
function syncYearShortcutStateFromDates() {
const start = String(globalStartDate.value || '').trim();
const end = String(globalEndDate.value || '').trim();
const years = availableYears.length ? availableYears : getFallbackYears();
const allRange = getCurrentAllRange();
if (start === allRange.startDate && end === allRange.endDate) {
activeYearShortcut = 'ALL';
renderYearShortcutButtons();
return;
}
const fullYearMatch = start.match(/^(\d{4})-01-01$/);
if (fullYearMatch && end === `${fullYearMatch[1]}-12-31` && years.includes(Number(fullYearMatch[1]))) {
activeYearShortcut = fullYearMatch[1];
} else {
activeYearShortcut = '';
}
renderYearShortcutButtons();
}
function applyYearShortcut(value, options = {}) {
const sync = options.sync !== false;
const years = availableYears.length ? availableYears : getFallbackYears();
if (value === 'ALL') {
const allRange = getCurrentAllRange();
activeYearShortcut = 'ALL';
globalStartDate.value = allRange.startDate;
globalEndDate.value = allRange.endDate;
} else {
const year = Number(value);
const safeYear = years.includes(year) ? year : Number(getDefaultYearShortcut());
activeYearShortcut = String(safeYear);
globalStartDate.value = `${safeYear}-01-01`;
globalEndDate.value = `${safeYear}-12-31`;
}
renderYearShortcutButtons();
if (sync) syncDateRange();
}
function updateAvailableYears(nextYears = []) {
const normalized = Array.from(new Set((nextYears || []).map(Number).filter(year => year >= 2010 && year <= 2099))).sort((a, b) => a - b);
availableYears = normalized.length ? normalized : getFallbackYears();
if (activeYearShortcut === 'ALL') {
applyYearShortcut('ALL');
return;
}
if (!availableYears.includes(Number(activeYearShortcut))) {
applyYearShortcut(getDefaultYearShortcut());
return;
}
syncYearShortcutStateFromDates();
}
function applyMhWorkbookBinary(binary, fileName = 'MH 데이터_260303.xlsx', activateDash = true) {
const workCsv = convertMhBinaryToDashWorkCsv(binary);
postToDash('work', workCsv);
postToMh(binary, fileName);
updateAvailableYears(workCsv ? [...availableYears, ...inferYearsFromText(workCsv)] : availableYears);
workUploaded = true;
btnUploadWork.classList.add('uploaded');
if (activateDash && hasAnalysisInputs()) setTab('dash');
}
async function tryLoadAutoProjectOrderCsv() {
const candidates = [
'./로우데이터/프로젝트표출순서_인트라넷 기준.csv',
'./프로젝트표출순서_인트라넷 기준.csv'
];
for (const url of candidates) {
try {
const response = await fetch(url, { cache: 'no-store' });
if (!response.ok) continue;
const buffer = await response.arrayBuffer();
let text = '';
try {
text = new TextDecoder('euc-kr').decode(buffer);
} catch (_) {
text = new TextDecoder('utf-8').decode(buffer);
}
if (String(text || '').trim()) {
autoProjectOrderCsvText = text;
postProjectOrderCsv(text);
return;
}
} catch (_) {
// Ignore and try next candidate.
}
}
if (!String(autoProjectOrderCsvText || '').trim()) {
const embedded = decodeBase64Utf8(EMBEDDED_PROJECT_ORDER_CSV_B64);
if (String(embedded || '').trim()) {
autoProjectOrderCsvText = embedded;
postProjectOrderCsv(embedded);
}
}
}
async function fetchFirstAvailableBuffer(candidates = []) {
for (const url of candidates) {
try {
const response = await fetch(url, { cache: 'no-store' });
if (!response.ok) continue;
const buffer = await response.arrayBuffer();
if (buffer && buffer.byteLength > 0) return { url, buffer };
} catch (_) {
// Ignore and try next candidate.
}
}
return null;
}
async function tryLoadAutoDefaultData() {
if (autoDefaultDataLoaded) return;
autoDefaultDataLoaded = true;
if (!String(autoProjectOrderCsvText || '').trim()) {
await tryLoadAutoProjectOrderCsv();
}
const businessCandidates = [
'./로우데이터/사업관리 대장-1.xlsx',
'./로우데이터/사업관리대장-1.xlsx',
'./사업관리 대장-1.xlsx',
'./사업관리대장-1.xlsx',
'./로우데이터/사업관리 대장.xlsx',
'./로우데이터/사업관리대장.xlsx',
'./사업관리 대장.xlsx',
'./사업관리대장.xlsx'
];
const expenseCandidates = [
'./로우데이터/전표정리_1월_전표_인트라넷기준.csv',
'./전표정리_1월_전표_인트라넷기준.csv'
];
const mhCandidates = [
'./로우데이터/MH 데이터_260303.xlsx',
'./MH 데이터_260303.xlsx'
];
let loadedSomething = false;
const businessResult = await fetchFirstAvailableBuffer(businessCandidates);
if (businessResult) {
const businessFileName = String(businessResult.url || '').split('/').pop() || '사업관리대장-1.xlsx';
await postToBusiness(businessResult.buffer, businessFileName);
btnUploadBusiness.classList.add('uploaded');
loadedSomething = true;
}
const expenseResult = await fetchFirstAvailableBuffer(expenseCandidates);
if (expenseResult) {
const expenseText = decodeBufferText(expenseResult.buffer, ['euc-kr', 'utf-8']);
if (String(expenseText || '').trim()) {
updateAvailableYears([...availableYears, ...inferYearsFromText(expenseText)]);
postToDash('expense', normalizeExpenseHierarchyCsv(expenseText));
expenseUploaded = true;
btnUploadExpense.classList.add('uploaded');
loadedSomething = true;
}
}
const mhResult = await fetchFirstAvailableBuffer(mhCandidates);
if (mhResult) {
try {
const binary = arrayBufferToBinaryString(mhResult.buffer);
applyMhWorkbookBinary(binary, 'MH 데이터_260303.xlsx', false);
workUploaded = true;
loadedSomething = true;
} catch (err) {
console.error(err);
}
}
if (loadedSomething) setTab('business');
}
function normalizeHeader(value) {
return String(value || '').replace(/\s+/g, '').toLowerCase();
}
function findHeaderIndex(normalizedHeaders, candidates) {
const targetSet = new Set(candidates.map(normalizeHeader));
for (let i = 0; i < normalizedHeaders.length; i++) {
if (targetSet.has(normalizedHeaders[i])) return i;
}
return -1;
}
function parseNumber(value) {
return parseFloat(String(value || '').replace(/[^0-9.\-]/g, '')) || 0;
}
function formatWorkDate(value) {
if (value === null || value === undefined || value === '') return '';
const toDotDate = (d) => {
const yyyy = d.getFullYear();
const mm = String(d.getMonth() + 1).padStart(2, '0');
const dd = String(d.getDate()).padStart(2, '0');
return `${yyyy}.${mm}.${dd}`;
};
if (value instanceof Date && !isNaN(value.getTime())) return toDotDate(value);
if (typeof value === 'number') {
const d = new Date(Math.round((value - 25569) * 86400 * 1000));
if (!isNaN(d.getTime())) return toDotDate(d);
}
const text = String(value).trim();
const m = text.match(/(\d{4})\D+(\d{1,2})\D+(\d{1,2})/);
if (m) {
return `${m[1]}.${String(m[2]).padStart(2, '0')}.${String(m[3]).padStart(2, '0')}`;
}
const d = new Date(text);
if (!isNaN(d.getTime())) return toDotDate(d);
return text;
}
function csvEscape(value) {
const s = String(value ?? '');
if (/[",\r\n]/.test(s)) return `"${s.replace(/"/g, '""')}"`;
return s;
}
function parseCsvRows(text) {
const rows = [];
let row = [];
let field = '';
let inQuotes = false;
const src = String(text || '');
for (let i = 0; i < src.length; i++) {
const ch = src[i];
if (ch === '"') {
if (inQuotes && src[i + 1] === '"') {
field += '"';
i++;
} else {
inQuotes = !inQuotes;
}
continue;
}
if (ch === ',' && !inQuotes) {
row.push(field);
field = '';
continue;
}
if ((ch === '\n' || ch === '\r') && !inQuotes) {
if (ch === '\r' && src[i + 1] === '\n') i++;
row.push(field);
rows.push(row);
row = [];
field = '';
continue;
}
field += ch;
}
row.push(field);
rows.push(row);
if (rows.length && rows[0].length) {
rows[0][0] = String(rows[0][0] || '').replace(/^\uFEFF/, '');
}
return rows.filter((r) => r.some((cell) => String(cell || '').trim() !== ''));
}
function stringifyCsvRows(rows) {
return (rows || []).map((row) => (row || []).map(csvEscape).join(',')).join('\n');
}
function normalizeLooseHeader(value) {
return String(value || '').toLowerCase().replace(/[\s_./()\-]/g, '');
}
function findHeaderIndexLoose(headers, candidates) {
const target = new Set((candidates || []).map(normalizeLooseHeader));
for (let i = 0; i < headers.length; i++) {
if (target.has(normalizeLooseHeader(headers[i]))) return i;
}
return -1;
}
function detectExpenseHierarchyIndexes(headers) {
const d1 = findHeaderIndexLoose(headers, ['D1', 'D1(K)', '대분류', 'K']);
const d2 = findHeaderIndexLoose(headers, ['D2', 'D2(L)', '중분류', 'L']);
const d3 = findHeaderIndexLoose(headers, ['D3', 'D3(M)', '소분류', 'M']);
const d4 = findHeaderIndexLoose(headers, ['D4', 'D4(J)', '프로젝트명', '사업명(인트라넷기준)', 'J']);
const byLetter = (idx) => (headers.length > idx ? idx : -1);
return {
d1: d1 >= 0 ? d1 : byLetter(10),
d2: d2 >= 0 ? d2 : byLetter(11),
d3: d3 >= 0 ? d3 : byLetter(12),
d4: d4 >= 0 ? d4 : byLetter(9)
};
}
function isUnclassified(value) {
const txt = String(value || '').trim();
if (!txt) return true;
return normalizeHeader(txt) === normalizeHeader('미분류');
}
function normalizeProjectKey(value) {
return String(value || '')
.normalize('NFKC')
.toLowerCase()
.replace(/[\u200b-\u200d\ufeff]/g, '')
.replace(/[^0-9a-z가-힣]/g, '');
}
function normalizeCodeKey(value) {
return String(value || '')
.normalize('NFKC')
.toUpperCase()
.replace(/[\u200b-\u200d\ufeff]/g, '')
.replace(/[^0-9A-Z가-힣]/g, '');
}
function normalizeExpenseHierarchyCsv(text) {
const rows = parseCsvRows(text);
if (rows.length < 2) return text;
const headers = rows[0];
const idx = detectExpenseHierarchyIndexes(headers);
if (idx.d1 < 0 || idx.d4 < 0) return text;
const bestByProject = new Map();
const scoreOf = (d1, d2, d3) => [d1, d2, d3].reduce((acc, v) => acc + (isUnclassified(v) ? 0 : 1), 0);
for (let r = 1; r < rows.length; r++) {
const row = rows[r];
const key = normalizeProjectKey(row[idx.d4]);
if (!key) continue;
const d1 = String(row[idx.d1] || '').trim();
const d2 = idx.d2 >= 0 ? String(row[idx.d2] || '').trim() : '';
const d3 = idx.d3 >= 0 ? String(row[idx.d3] || '').trim() : '';
const score = scoreOf(d1, d2, d3);
const prev = bestByProject.get(key);
if (!prev || score > prev.score) {
bestByProject.set(key, { d1, d2, d3, score });
continue;
}
if (prev && score === prev.score && score > 0) {
bestByProject.set(key, {
d1: isUnclassified(prev.d1) ? d1 : prev.d1,
d2: isUnclassified(prev.d2) ? d2 : prev.d2,
d3: isUnclassified(prev.d3) ? d3 : prev.d3,
score
});
}
}
for (let r = 1; r < rows.length; r++) {
const row = rows[r];
const key = normalizeProjectKey(row[idx.d4]);
if (!key) continue;
const best = bestByProject.get(key);
if (!best || best.score <= 0) continue;
if (idx.d1 >= 0 && isUnclassified(row[idx.d1]) && !isUnclassified(best.d1)) row[idx.d1] = best.d1;
if (idx.d2 >= 0 && isUnclassified(row[idx.d2]) && !isUnclassified(best.d2)) row[idx.d2] = best.d2;
if (idx.d3 >= 0 && isUnclassified(row[idx.d3]) && !isUnclassified(best.d3)) row[idx.d3] = best.d3;
}
return stringifyCsvRows(rows);
}
function mergeClassInfo(current, incoming) {
const clean = {
d1: String(incoming?.d1 || '').trim(),
d2: String(incoming?.d2 || '').trim(),
d3: String(incoming?.d3 || '').trim()
};
if (!current) return clean;
const pick = (oldVal, newVal) => {
const oldTxt = String(oldVal || '').trim();
const newTxt = String(newVal || '').trim();
if (oldTxt && normalizeHeader(oldTxt) !== normalizeHeader('미분류')) return oldTxt;
if (newTxt && normalizeHeader(newTxt) !== normalizeHeader('미분류')) return newTxt;
return oldTxt || newTxt || '';
};
return {
d1: pick(current.d1, clean.d1),
d2: pick(current.d2, clean.d2),
d3: pick(current.d3, clean.d3)
};
}
function buildProjectOrderClassificationMapsFromCsv(text) {
const byName = new Map();
const rows = parseCsvRows(text);
if (rows.length < 2) return byName;
const headers = rows[0] || [];
const normalized = headers.map(normalizeHeader);
const nameIdx = findHeaderIndex(normalized, ['사업명(인트라넷기준)', '사업명(인트라넷 기준)', '프로젝트명', '사업명', 'd4']);
const d1Idx = findHeaderIndex(normalized, ['대분류', 'd1', '매출/비매출', '매출비매출']);
const d2Idx = findHeaderIndex(normalized, ['중분류', 'd2', '사업분야', '분야']);
const d3Idx = findHeaderIndex(normalized, ['소분류', 'd3', '세부분야']);
if (nameIdx < 0 || (d1Idx < 0 && d2Idx < 0 && d3Idx < 0)) return byName;
rows.slice(1).forEach((row) => {
const classInfo = {
d1: d1Idx >= 0 ? String(row[d1Idx] || '').trim() : '',
d2: d2Idx >= 0 ? String(row[d2Idx] || '').trim() : '',
d3: d3Idx >= 0 ? String(row[d3Idx] || '').trim() : ''
};
if (!classInfo.d1 && !classInfo.d2 && !classInfo.d3) return;
const nameKey = normalizeProjectKey(row[nameIdx]);
if (nameKey) byName.set(nameKey, mergeClassInfo(byName.get(nameKey), classInfo));
});
return byName;
}
function findMhWorkSheetName(workbook) {
const names = workbook?.SheetNames || [];
for (const sheetName of names) {
const sheet = workbook.Sheets[sheetName];
if (!sheet) continue;
const rows = XLSX.utils.sheet_to_json(sheet, { header: 1, defval: '', range: 0 });
const header = rows?.[0] || [];
const normalized = header.map(normalizeHeader);
const hasDate = findHeaderIndex(normalized, ['근무일자']) >= 0;
const hasName = findHeaderIndex(normalized, ['이름']) >= 0;
const hasProject = (
findHeaderIndex(normalized, ['메인업무 프로젝트명']) >= 0 ||
findHeaderIndex(normalized, ['추가업무1 프로젝트명']) >= 0 ||
findHeaderIndex(normalized, ['연장근무 프로젝트명']) >= 0
);
if (hasDate && hasName && hasProject) return sheetName;
}
return names[0] || '';
}
function buildMhClassificationMaps(_workbook, _workSheetName, projectOrderCsvText = '') {
return buildProjectOrderClassificationMapsFromCsv(projectOrderCsvText);
}
function buildWorkMapFromMhHeader(headerRow) {
const normalizedHeaders = (headerRow || []).map(normalizeHeader);
const hasNoColumn = normalizedHeaders[0] === normalizeHeader('No');
const fallbackShift = hasNoColumn ? 1 : 0;
const dateIdx = findHeaderIndex(normalizedHeaders, ['근무일자']);
const nameIdx = findHeaderIndex(normalizedHeaders, ['이름']);
const rankIdx = findHeaderIndex(normalizedHeaders, ['직책']);
const userStateIdx = findHeaderIndex(normalizedHeaders, ['user_state', 'user state', 'userstate', 'user-state', 'userstate(주말/평일)']);
const normalCostIdx = findHeaderIndex(normalizedHeaders, ['일반근무']);
const extraCostIdx = findHeaderIndex(normalizedHeaders, ['추가근무']);
const slotDefs = [
{ codeHeaders: ['메인업무 프로젝트 코드', '메인업무 프로젝트코드'], projHeaders: ['메인업무 프로젝트명'], timeHeaders: ['메인업무 근무시간'], overtime: false },
{ codeHeaders: ['추가업무1 프로젝트 코드', '추가업무1 프로젝트코드'], projHeaders: ['추가업무1 프로젝트명'], timeHeaders: ['추가업무1 근무시간'], overtime: false },
{ codeHeaders: ['추가업무2 프로젝트 코드', '추가업무2 프로젝트코드'], projHeaders: ['추가업무2 프로젝트명'], timeHeaders: ['추가업무2 근무시간'], overtime: false },
{ codeHeaders: ['추가업무3 프로젝트 코드', '추가업무3 프로젝트코드'], projHeaders: ['추가업무3 프로젝트명'], timeHeaders: ['추가업무3 근무시간'], overtime: false },
{ codeHeaders: ['추가업무4 프로젝트 코드', '추가업무4 프로젝트코드'], projHeaders: ['추가업무4 프로젝트명'], timeHeaders: ['추가업무4 근무시간'], overtime: false },
{ codeHeaders: ['추가업무5 프로젝트 코드', '추가업무5 프로젝트코드'], projHeaders: ['추가업무5 프로젝트명'], timeHeaders: ['추가업무5 근무시간'], overtime: false },
{ codeHeaders: ['연장근무 프로젝트 코드', '연장근무 프로젝트코드'], projHeaders: ['연장근무 프로젝트명'], timeHeaders: ['연장근무 시간(가공)', '연장근무시간(가공)'], overtime: true }
];
const bizHeader = normalizeHeader('사업 종류');
const slots = slotDefs.map((def, idx) => {
const code = findHeaderIndex(normalizedHeaders, def.codeHeaders || []);
const proj = findHeaderIndex(normalizedHeaders, def.projHeaders);
const time = findHeaderIndex(normalizedHeaders, def.timeHeaders);
if (proj < 0 || time < 0) {
// Fallback index map compatible with old/new MH formats.
const fallbackProj = [10, 16, 21, 26, 31, 36, 41][idx] + fallbackShift;
const fallbackTime = [12, 18, 23, 28, 33, 38, 44][idx] + fallbackShift;
return { code: fallbackProj - 1, proj: fallbackProj, time: fallbackTime, biz: fallbackProj - 2, overtime: !!def.overtime };
}
let biz = -1;
for (let i = proj - 1; i >= 0; i--) {
if (normalizedHeaders[i] === bizHeader) {
biz = i;
break;
}
}
return { code, proj, time, biz, overtime: !!def.overtime };
});
return {
dateIdx: dateIdx >= 0 ? dateIdx : 0 + fallbackShift,
nameIdx: nameIdx >= 0 ? nameIdx : 4 + fallbackShift,
rankIdx: rankIdx >= 0 ? rankIdx : 5 + fallbackShift,
userStateIdx: userStateIdx,
normalCostIdx: normalCostIdx,
extraCostIdx: extraCostIdx,
slots
};
}
function convertMhBinaryToDashWorkCsv(binaryStr) {
if (typeof XLSX === 'undefined') {
throw new Error('XLSX 라이브러리를 찾을 수 없습니다.');
}
const workbook = XLSX.read(binaryStr, { type: 'binary', cellDates: true, dateNF: 'yyyy-mm-dd' });
const workSheetName = findMhWorkSheetName(workbook);
const workSheet = workbook.Sheets[workSheetName];
const rows = XLSX.utils.sheet_to_json(workSheet, { header: 1, defval: '' });
if (rows.length < 2) return '';
const classMapByProjectName = buildMhClassificationMaps(workbook, workSheetName, autoProjectOrderCsvText);
const map = buildWorkMapFromMhHeader(rows[0]);
const output = [[
'날짜', '일자', '이름', '직급', 'user_state',
'사업명(표출PJT)', '프로젝트명', '프로젝트명 매칭',
'D1', 'D2', 'D3',
'사업분야', '세부분야',
'시간', '근무시간',
'추가근무',
'인건비', '산정금액'
]];
rows.slice(1).forEach((row) => {
const date = formatWorkDate(row[map.dateIdx]);
const name = String(row[map.nameIdx] || '').trim();
const rank = String(row[map.rankIdx] || '').trim() || '연구원';
const userState = String(map.userStateIdx >= 0 ? (row[map.userStateIdx] || '') : '').trim();
const isWeekend = userState.includes('주말');
if (!date || !name) return;
const rowLabor = parseNumber(row[map.normalCostIdx]) + parseNumber(row[map.extraCostIdx]);
const slotRows = map.slots.map((slot) => {
const project = String(row[slot.proj] || '').trim();
const hours = parseNumber(row[slot.time]);
const biz = (slot.biz >= 0 ? String(row[slot.biz] || '').trim() : '') || '미분류';
const mapped = classMapByProjectName.get(normalizeProjectKey(project)) || null;
const d1 = String(mapped?.d1 || '').trim();
const d2 = String(mapped?.d2 || '').trim() || biz;
const d3 = String(mapped?.d3 || '').trim() || '미분류';
return { project, hours, overtime: !!slot.overtime, d1, d2, d3 };
}).filter((slot) => slot.project && slot.hours > 0);
if (!slotRows.length) return;
const totalHours = slotRows.reduce((sum, slot) => sum + slot.hours, 0);
const targetLabor = Math.round(rowLabor);
const allocations = slotRows.map((slot, idx) => {
const raw = totalHours > 0 ? (targetLabor * slot.hours) / totalHours : 0;
const base = Math.floor(raw);
return { idx, base, frac: raw - base };
});
let remain = targetLabor - allocations.reduce((sum, part) => sum + part.base, 0);
if (remain > 0) {
allocations.sort((a, b) => (b.frac - a.frac) || (a.idx - b.idx));
for (let i = 0; i < allocations.length && remain > 0; i++, remain--) allocations[i].base += 1;
} else if (remain < 0) {
allocations.sort((a, b) => (a.frac - b.frac) || (a.idx - b.idx));
for (let i = 0; i < allocations.length && remain < 0; i++, remain++) allocations[i].base -= 1;
}
allocations.sort((a, b) => a.idx - b.idx);
slotRows.forEach((slot, idx) => {
const roundedHours = Math.round(slot.hours * 1000) / 1000;
const roundedLabor = allocations[idx]?.base || 0;
output.push([
date, date, name, rank, userState,
slot.project, slot.project, slot.project,
slot.d1 || '미분류', slot.d2 || '미분류', slot.d3 || '미분류',
slot.d2 || '미분류', slot.d3 || '미분류',
roundedHours, roundedHours,
slot.overtime ? roundedHours : 0,
roundedLabor, roundedLabor
]);
});
});
return output.map((row) => row.map(csvEscape).join(',')).join('\n');
}
function syncDateRange() {
syncYearShortcutStateFromDates();
const payload = {
source: 'total-control',
type: 'date-range',
startDate: globalStartDate.value,
endDate: globalEndDate.value
};
if (frameDash.contentWindow) frameDash.contentWindow.postMessage(payload, '*');
if (frameMh.contentWindow) frameMh.contentWindow.postMessage(payload, '*');
}
async function flushPending() {
if (businessReady && frameBusiness.contentWindow && pending.business) {
if (await deliverBusinessPayload(pending.business)) pending.business = null;
}
if (dashReady && frameDash.contentWindow) {
if (pending.expense) frameDash.contentWindow.postMessage(pending.expense, '*');
if (pending.work) frameDash.contentWindow.postMessage(pending.work, '*');
if (pending.projectOrder) frameDash.contentWindow.postMessage(pending.projectOrder, '*');
pending.expense = null;
pending.work = null;
pending.projectOrder = null;
}
if (mhReady && frameMh.contentWindow && pending.mh) {
frameMh.contentWindow.postMessage(pending.mh, '*');
pending.mh = null;
}
}
window.addEventListener('message', (e) => {
const data = e.data || {};
if (data.source !== 'business-upload-result') return;
const pendingAck = businessUploadAcks.get(data.requestId);
if (!pendingAck) return;
clearTimeout(pendingAck.timer);
businessUploadAcks.delete(data.requestId);
if (data.ok) {
pendingAck.resolve(data);
return;
}
pendingAck.reject(new Error(data.message || '사업관리대장 업로드에 실패했습니다.'));
});
frameDash.addEventListener('load', () => {
dashReady = true;
flushPending().catch(console.error);
syncDateRange();
if (autoProjectOrderCsvText) {
setTimeout(() => postProjectOrderCsv(autoProjectOrderCsvText), 250);
}
});
frameMh.addEventListener('load', () => { mhReady = true; flushPending().catch(console.error); syncDateRange(); });
tryLoadAutoProjectOrderCsv();
tryLoadAutoDefaultData();
btnTabBusiness.addEventListener('click', () => setTab('business'));
btnTabDash.addEventListener('click', () => setTab('dash'));
btnTabMh.addEventListener('click', () => setTab('mh'));
globalStartDate.addEventListener('change', syncDateRange);
globalEndDate.addEventListener('change', syncDateRange);
yearShortcuts.addEventListener('click', (e) => {
const button = e.target && e.target.closest ? e.target.closest('button[data-year-shortcut]') : null;
if (!button) return;
applyYearShortcut(button.getAttribute('data-year-shortcut') || getDefaultYearShortcut());
});
document.getElementById('btn-upload-business').addEventListener('click', () => uploadBusiness.click());
document.getElementById('btn-upload-expense').addEventListener('click', () => uploadExpense.click());
document.getElementById('btn-upload-work').addEventListener('click', () => uploadWork.click());
uploadBusiness.addEventListener('change', async (e) => {
const file = e.target.files?.[0];
if (!file) return;
try {
const buffer = await file.arrayBuffer();
await postToBusiness(buffer, file.name || '사업관리대장-1.xlsx');
btnUploadBusiness.classList.add('uploaded');
setTab('business');
} catch (err) {
console.error(err);
alert(`사업관리대장-1 업로드 중 오류가 발생했습니다: ${err.message}`);
}
e.target.value = '';
});
uploadExpense.addEventListener('change', (e) => {
const file = e.target.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (evt) => {
const rawExpense = evt.target?.result || '';
updateAvailableYears([...availableYears, ...inferYearsFromText(rawExpense)]);
postToDash('expense', normalizeExpenseHierarchyCsv(rawExpense));
expenseUploaded = true;
btnUploadExpense.classList.add('uploaded');
if (hasAnalysisInputs()) setTab('dash');
};
reader.readAsText(file, 'euc-kr');
e.target.value = '';
});
uploadWork.addEventListener('change', (e) => {
const file = e.target.files?.[0];
if (!file) return;
const isWorkbook = /\.(xlsx|xls)$/i.test(file.name || '');
const reader = new FileReader();
reader.onload = async (evt) => {
const result = evt.target?.result || '';
if (isWorkbook) {
try {
if (!String(autoProjectOrderCsvText || '').trim()) {
await tryLoadAutoProjectOrderCsv();
}
applyMhWorkbookBinary(result, file.name, true);
} catch (err) {
console.error(err);
alert(`통합 파일 처리 중 오류가 발생했습니다: ${err.message}`);
}
return;
}
postToDash('work', result);
workUploaded = true;
btnUploadWork.classList.add('uploaded');
if (hasAnalysisInputs()) setTab('dash');
};
if (isWorkbook) reader.readAsBinaryString(file);
else reader.readAsText(file, 'euc-kr');
e.target.value = '';
});
applyYearShortcut(getDefaultYearShortcut(), { sync: false });
setTab('business');
</script>
</body>
</html>