Search this site
Embedded Files
iLetGo
  • v1
  • 002
  • SongwriterStijn
  • ⌘
  • LoveLifeLaugh
  • NOW
  • ERROR
  • Design
  • LLL
iLetGo
  • v1
  • 002
  • SongwriterStijn
  • ⌘
  • LoveLifeLaugh
  • NOW
  • ERROR
  • Design
  • LLL
  • More
    • v1
    • 002
    • SongwriterStijn
    • ⌘
    • LoveLifeLaugh
    • NOW
    • ERROR
    • Design
    • LLL

ERROR

Fix in index

<!doctype html>

<!--

 BESTAND: index.html

 APP: i Let Go v2 LLL GODOGOOD Script

 VERSIE: v2 · codebasis V7.1

 DATUM:TIJD: 2026-10-06 09:24:01 Europe/Amsterdam

 PROJECT: i Let Go v2 LLL GODOGOOD Script

 SET: ⌘  by Gabeler.eu GODOGOOD.eu ⌘

 KOPPELFILE: Code.gs

 BASIS: LLL Quotes System V7 · alle sheet-tabbladen, kolomlezer en random sets

 FIX: Geen nulmelding tijdens opstart; random wordt beschikbaar na het laden van zinnen.

-->

<html lang="nl">

<head>

<meta charset="utf-8">

<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">

<meta name="theme-color" content="#4b1838">

<meta name="description" content="LoveLifeLaugh message board: zoek, kies, randomiseer en deel liefdevolle vragen, antwoorden, quotes en relatieberichten.">

<title>LLL Quotes System · Alle tabbladen · Stijn Gabeler</title>

<style>

:root{

  --ink:#2e1728;--paper:#fff7f2;--cream:#fffdf9;--rose:#ff8fa3;--pink:#ffd2dc;--red:#ee5a67;

  --gold:#ffd56a;--mint:#cceee0;--blue:#cde5ff;--purple:#d8c9ff;--line:#3d1a2b22;--muted:#755d6d;

  --shadow:0 15px 40px #4b183817;--radius:20px;--font-scale:1;

}

*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:linear-gradient(180deg,#fff8f4,#fff2f5 55%,#fff9f0);color:var(--ink);font-family:Arial,Helvetica,sans-serif;font-size:calc(15px * var(--font-scale));line-height:1.5}

button,input,select{font:inherit}button{cursor:pointer}button:focus-visible,input:focus-visible,select:focus-visible{outline:3px solid #5a61ff;outline-offset:2px}

.topbar{position:sticky;top:0;z-index:100;background:#4b1838f4;color:#fff;backdrop-filter:blur(14px);box-shadow:0 6px 24px #30102244}

.barInner{max-width:1920px;margin:auto;padding:9px clamp(9px,2vw,24px);display:grid;gap:8px}.row{display:flex;gap:7px;align-items:center;overflow-x:auto;scrollbar-width:thin;padding-bottom:2px}

.brand{display:flex;align-items:center;gap:9px;min-width:max-content;background:#fff;color:var(--ink);border-radius:13px;padding:7px 12px;font-weight:950;letter-spacing:.02em}.brandMark{display:grid;place-items:center;width:30px;height:30px;background:var(--rose);border-radius:10px}.brand small{display:block;color:var(--muted);font-size:.67em;font-weight:800}

.topbar button,.topbar select{min-height:40px;border:1px solid #ffffff38;border-radius:11px;padding:6px 11px;font-weight:850;white-space:nowrap}.topbar button{background:#ffffff14;color:#fff}.topbar button:hover{background:#ffffff27}.topbar .primary{background:var(--gold);color:var(--ink);border-color:transparent}.topbar .wa{background:#25d366;color:#07321b;border-color:transparent}.topbar .soft{background:#fff;color:var(--ink)}.spacer{flex:1}

.hero{max-width:1920px;margin:auto;padding:clamp(24px,4vw,52px) clamp(12px,2vw,28px) 18px}.heroGrid{display:grid;grid-template-columns:minmax(0,1.45fr) minmax(340px,.85fr);gap:22px;align-items:end}.eyebrow{display:inline-flex;align-items:center;gap:8px;padding:6px 11px;border-radius:999px;background:var(--pink);font-size:.79em;font-weight:950;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,5.7vw,6rem);line-height:.91;letter-spacing:-.055em;margin:17px 0 14px;max-width:1150px}.hero p{margin:0;max-width:930px;color:var(--muted);font-size:clamp(1rem,1.5vw,1.22rem)}.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}.stat{background:#fff;border:1px solid var(--line);border-radius:16px;padding:13px;box-shadow:var(--shadow)}.stat strong{display:block;font-size:clamp(1.35rem,2.8vw,2.35rem);line-height:1}.stat span{display:block;margin-top:7px;color:var(--muted);font-size:.72em;font-weight:800}

.workspace{max-width:1920px;margin:auto;padding:0 clamp(10px,2vw,28px) 80px}.controls{position:sticky;top:102px;z-index:70;background:#fff;border:1px solid var(--line);border-radius:18px;padding:12px;margin-bottom:14px;box-shadow:var(--shadow);display:grid;gap:9px}.searchRow{display:grid;grid-template-columns:minmax(260px,1fr) auto auto auto;gap:8px}.searchWrap{position:relative}.searchWrap span{position:absolute;left:13px;top:50%;transform:translateY(-50%)}.searchWrap input{width:100%;min-height:44px;border:1px solid var(--line);border-radius:11px;padding:10px 12px 10px 40px;background:#fffaf7;color:var(--ink)}.controls button,.controls select{min-height:44px;border:1px solid var(--line);border-radius:11px;background:#fffaf7;color:var(--ink);padding:8px 11px;font-weight:850}.controls button.primary{background:var(--gold)}.selector{display:flex;gap:7px;overflow-x:auto;padding-bottom:2px}.chip{flex:0 0 auto;border:1px solid var(--line)!important;background:#fff!important}.chip[aria-pressed="true"]{background:var(--pink)!important;box-shadow:inset 0 0 0 1px #db7388}.resultLine{display:flex;justify-content:space-between;gap:12px;align-items:center;color:var(--muted);font-size:.84em}.resultLine strong{color:var(--ink)}

.boardWrap{overflow-x:auto;padding-bottom:15px;scrollbar-width:thin}.board{display:flex;gap:14px;align-items:stretch;min-height:410px}.sourceCol{flex:0 0 min(410px,86vw);display:flex;flex-direction:column;background:#eee5e2;border:1px solid var(--line);border-radius:21px;padding:10px;min-width:0}.sourceHead{border-radius:15px;padding:13px 14px;margin-bottom:10px;box-shadow:0 8px 24px #4b183818}.sourceHead h2{font-size:1.04rem;line-height:1.15;margin:0}.sourceHead p{margin:5px 0 0;font-size:.74em;opacity:.78}.tone0{background:var(--gold)}.tone1{background:var(--blue)}.tone2{background:var(--rose)}.tone3{background:var(--mint)}.tone4{background:var(--purple)}.messageCard{background:#fff;border:1px solid var(--line);border-radius:17px;padding:16px;box-shadow:0 4px 18px #4b18380d;display:flex;flex-direction:column;gap:12px;min-height:290px;flex:1}.messageText{margin:0;white-space:pre-wrap;font-size:1.05em;line-height:1.62;overflow-wrap:anywhere}.messageMeta{margin-top:auto;color:var(--muted);font-size:.72em;border-top:1px dashed var(--line);padding-top:9px}.actions{display:grid;grid-template-columns:repeat(4,1fr);gap:6px}.actions button{border:0;border-radius:9px;min-height:38px;background:#f5f0ed;color:var(--ink);font-size:.76em;font-weight:850}.actions button:hover{background:var(--pink)}.sourceFooter{display:flex;justify-content:space-between;align-items:center;gap:8px;margin-top:9px;font-size:.74em;color:var(--muted)}

.searchPanel{display:none;background:#fff;border:1px solid var(--line);border-radius:19px;padding:12px;margin:0 0 14px;box-shadow:var(--shadow)}.searchPanel.show{display:block}.searchPanel h2{font-size:1rem;margin:0 0 10px}.searchGrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(290px,1fr));gap:9px;max-height:54vh;overflow:auto}.searchItem{border:1px solid var(--line);border-radius:13px;padding:11px;background:#fffaf7;display:grid;gap:8px}.searchItem strong{font-size:.77em}.searchItem p{margin:0;line-height:1.45}.searchItem button{justify-self:start;border:0;border-radius:8px;background:var(--pink);padding:7px 9px;font-weight:850}.empty{border:1px dashed #9a7d8d;border-radius:13px;padding:18px;text-align:center;color:var(--muted)}

.about{margin-top:18px;background:#fff;border:1px solid var(--line);border-radius:18px;padding:15px;box-shadow:var(--shadow)}.about h2{margin:0 0 7px;font-size:1rem}.about p{margin:4px 0;color:var(--muted)}.siteLink{font-weight:900;color:#7b214d}.toast{position:fixed;z-index:999;left:50%;bottom:22px;transform:translate(-50%,28px);opacity:0;pointer-events:none;background:var(--ink);color:#fff;padding:11px 16px;border-radius:12px;box-shadow:0 12px 40px #0005;transition:.2s ease;max-width:min(92vw,720px);text-align:center}.toast.show{transform:translate(-50%,0);opacity:1}

#printRoot{display:none}

@media(max-width:1000px){.heroGrid{grid-template-columns:1fr}.controls{top:100px}.searchRow{grid-template-columns:1fr 1fr}.searchWrap{grid-column:1/-1}.stats{grid-template-columns:repeat(2,1fr)}}

@media(max-width:620px){.brandText{display:none}.searchRow{grid-template-columns:1fr}.searchWrap{grid-column:auto}.controls{position:relative;top:auto}.sourceCol{flex-basis:88vw}.actions{grid-template-columns:repeat(2,1fr)}}

@media print{body>*:not(#printRoot){display:none!important}#printRoot{display:block!important;background:#fff;color:#000;padding:18mm;font-family:Arial,sans-serif}#printRoot h1{font-size:22pt;letter-spacing:0;line-height:1.1}#printRoot article{page-break-inside:avoid;border:1px solid #bbb;padding:12px;margin-bottom:12px;border-radius:8px}#printRoot h2{font-size:12pt;margin:0 0 7px}#printRoot p{white-space:pre-wrap}}

#quoteTools{margin:0 0 14px}.qfilters{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}.qfilters label{display:grid;gap:4px;font-size:.8rem;font-weight:bold}.qfilters input,.qfilters select,.qfilters textarea{width:100%;min-width:0;padding:10px;border:1px solid var(--line);border-radius:10px;font:inherit}.qbuttons{display:flex;flex-wrap:wrap;gap:7px;margin:10px 0}#quoteTools button,.qbuttons a{border:1px solid var(--line);border-radius:10px;padding:9px;background:var(--pink);color:var(--ink);font:inherit}#qTopics{max-height:180px;overflow:auto}details{margin-top:10px}#qStatus{font-size:.85rem}.qbuttons a{overflow-wrap:anywhere}body{overscroll-behavior-y:contain}.heroGrid{grid-template-columns:1fr}.hero h1{font-size:clamp(2.1rem,6vw,4rem)}@media(max-width:800px){.qfilters{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:460px){.qfilters{grid-template-columns:1fr}.searchRow{min-width:0}.searchWrap{min-width:0}.controls{min-width:0}}

.connection{margin:0 0 14px}.connection label{display:flex;gap:6px;align-items:center;font-size:.83rem}.connection input{min-height:20px;min-width:20px}.controls{position:relative;top:auto}.selector{flex-wrap:wrap;overflow:visible;margin-top:10px}.selector .chip{min-height:34px;font-size:.8rem;padding:6px 9px}.selector .chip.emptySource{opacity:.65}.tabPicker summary{font-weight:850;cursor:pointer}.board.gridLayout{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,320px),1fr));align-items:stretch}.gridLayout .sourceCol{width:100%;flex:initial}.gridLayout .messageCard{min-height:260px}#boardLayout{max-width:100%;font:inherit;border:1px solid var(--line);border-radius:8px;min-height:38px}.qbuttons label{max-width:100%;overflow-wrap:anywhere}#liveStatus[data-state="live"]{color:#145d30}#liveStatus[data-state="error"]{color:#922b38}#liveStatus[data-state="loading"]{color:#745208}

.readerScroll{max-height:65vh;overflow:auto} .readerScroll table{width:100%;border-collapse:collapse;background:#fff}.readerScroll th,.readerScroll td{text-align:left;vertical-align:top;border:1px solid var(--line);padding:9px;min-width:140px;white-space:pre-wrap;overflow-wrap:anywhere}.readerScroll th{position:sticky;top:0;background:var(--pink)}.readerScroll button{border:1px solid var(--line);border-radius:8px;padding:8px;background:var(--gold);font:inherit}#sourceReader[hidden]{display:none}

</style>

</head>

<body>

<header class="topbar">

  <div class="barInner">

    <div class="row">

      <div class="brand"><span class="brandMark">♥</span><span class="brandText">LOVELIFELAUGH<small>QUOTES SYSTEM · STIJN GABELER</small></span></div>

      <button class="primary" id="randomAll">↻ Nieuwe random set</button>

      <button id="chooseAll">Alle kolommen</button><button id="chooseNone">Geen kolommen</button>

      <span class="spacer"></span>

      <button class="soft" id="copySet">📋 Kopieer set</button><button class="wa" id="waSet">💬 WhatsApp</button>

    </div>

    <div class="row">

      <select id="exportScope"><option value="current">Huidige random set</option><option value="search">Zoekresultaten</option><option value="allSelected">Alle berichten uit gekozen kolommen</option></select>

      <button id="expTxt">TXT</button><button id="expCsv">CSV</button><button id="expJson">JSON</button><button id="expDoc">DOC</button><button id="expPdf">PDF / print</button>

    </div>

  </div>

</header>

<section class="hero">

  <div class="heroGrid">

    <div><span class="eyebrow">Love · Life · Laugh · Share</span><h1>One quote. A new perspective.</h1><p>Ontdek quotes op categorie, auteur en trefwoord. Mix bronnen, bewaar favorieten en deel jouw selectie. Alle tabbladen uit de ontwikkelsheet zijn bronnen. Kies tabbladen, maak een willekeurige set en deel die. In de Apps Script-webapp worden de bronnen rechtstreeks uit Google Sheets geladen.</p></div>

    <div class="stats"><div class="stat"><strong id="statSources">0</strong><span>tabbladen / bronnen</span></div><div class="stat"><strong id="statMessages">0</strong><span>berichten totaal</span></div><div class="stat"><strong id="statSelected">0</strong><span>kolommen gekozen</span></div><div class="stat"><strong id="statSearch">0</strong><span>zoekresultaten</span></div></div>

  </div>

</section>

<main class="workspace">

  <section class="about connection"><h2>Alle tabbladen uit Google Sheets · V7.1</h2><p id="liveStatus" role="status" aria-live="polite">V7.1 pagina geopend · verbinding met de ontwikkelsheet wordt gestart…</p><div class="qbuttons"><button id="reloadSheet">↻ Sheet opnieuw inlezen</button><label><input id="autoSync" type="checkbox"> Vernieuw elke 2 minuten</label><label><input id="uniqueSet" type="checkbox" checked> Vermijd dubbele zinnen in een random set</label></div><details id="liveHelp"><summary>Live koppeling activeren</summary><p>Gebruik deze volledige HTML als bestand <strong>index</strong> in hetzelfde Apps Script-project als de meegeleverde <strong>Code.gs</strong>. Publiceer dat project als webapp en open de webapp-link. Dan worden alle tabbladen automatisch uit de sheet gelezen. Een los HTML-bestand kan de sheet niet lezen. Open de gepubliceerde Apps Script-webapp; deze index bevat geen ingebouwde zinnen.</p><p>De koppeling leest alleen; wijzigingen in de sheet zie je na opnieuw inlezen. Nieuwe tabbladen worden automatisch meegenomen.</p></details></section>

<section class="about" id="quoteTools"><h2>⌘ Quotes System · Stijn Gabeler</h2><div class="qfilters"><label>Categorie<select id="qCategory"><option value="">Alle categorieën</option></select></label><label>Auteur<input id="qAuthor" placeholder="Zoek auteur"></label><label>Trefwoord<input id="qTag" placeholder="Bijv. ambition, balance"></label><label>Bibliotheek<select id="qMode"><option value="all" selected>Alle tabbladen uit de sheet</option><option value="quotes">Alleen quoteverzamelingen</option><option value="favorites">Favorieten</option><option value="legacy">Sheet + eigen import</option></select></label></div><div class="qbuttons"><button id="qReset">Wis filters</button><button id="qImport">Importeer CSV / JSON</button><input id="qFile" type="file" accept=".csv,.json" hidden><button id="qBackup">Back-up bibliotheek JSON</button><a href="https://docs.google.com/spreadsheets/d/1zDJSqXXv9LjDsvEbkJJ0U-Hu_NOsAVR1QDGEBUKc5aA/edit" target="_blank" rel="noopener">Open ontwikkelsheet ↗</a></div><p id="qStatus"></p><details><summary>Trefwoordenindex A–Z</summary><div id="qLetters" class="qbuttons"></div><div id="qTopics" class="qbuttons"></div></details><details><summary>Nieuwe quote toevoegen & bronnen</summary><div class="qfilters"><label>Quote<textarea id="qText" rows="3"></textarea></label><label>Auteur<input id="qNewAuthor"></label><label>Categorieën / trefwoorden<input id="qNewTags" placeholder="Love, Wisdom, balance"></label><label>Bronlink<input id="qNewUrl" type="url" placeholder="https://…"></label></div><button id="qAdd">Voeg quote toe</button><p>Ontdek quotes bij <a href="https://www.brainyquote.com/topics" target="_blank" rel="noopener">BrainyQuote</a> en <a href="https://en.wikiquote.org/wiki/Main_Page" target="_blank" rel="noopener">Wikiquote</a>. Websitequotes tonen de toeschrijving van de bron; die is geen verificatie van het oorspronkelijke werk.</p><p>CSV-kolommen: quote, author, category, source_url. Download in de sheet het tabblad Quotes via Bestand → Downloaden → CSV en importeer het hier. Toevoegingen en favorieten worden lokaal bewaard waar je browser dat toestaat. Bewaar een JSON-back-up om ze mee te nemen. De webapp leest alle tabbladen uit de sheet; eigen toevoegingen en imports blijven lokaal. Quotes van websites kun je via de sheet of een eigen import toevoegen.</p></details></section>

<section class="controls">

    <div class="searchRow"><div class="searchWrap"><span>⌕</span><input id="search" type="search" placeholder="Zoek op woord of zin in alle berichten…" autocomplete="off"></div><button class="primary" id="randomVisible">↻ Random gekozen kolommen</button><button id="clearSearch">Wis zoeken</button><button id="scrollBoard">Naar message board</button></div>

    <details class="tabPicker" open><summary id="tabCountLabel">Alle tabbladen kiezen</summary><div class="selector" id="selector"></div></details><div class="qbuttons"><label>Weergave <select id="boardLayout"><option value="swipe">Kolommen naast elkaar · swipe</option><option value="grid">Alle kaarten onder elkaar / in een raster</option></select></label></div>

    <div class="resultLine"><span><strong id="activeLabel">0</strong> gekozen kolommen · klik op een tabnaam om aan/uit te zetten</span><span id="searchLabel">Typ hierboven om alle bronnen te doorzoeken.</span></div>

  </section>

  <section class="about" id="sourceReader" hidden><div class="qbuttons"><h2 id="readerTitle"></h2><button id="readerClose">Sluit kolom</button><a id="readerSheet" target="_blank" rel="noopener">Open dit tabblad in de sheet ↗</a></div><p>Kies een rij om de zin in je random set te gebruiken. Alle ingevulde kolommen staan hieronder.</p><div class="readerScroll" id="readerRows"></div></section>

  <section class="searchPanel" id="searchPanel"><h2>Zoekresultaten</h2><div class="searchGrid" id="searchGrid"></div></section>

  <div class="boardWrap" id="boardAnchor"><div class="board" id="board"></div></div>

  <section class="about"><h2>LoveLifeLaugh · I Love You</h2><p>Bron: <strong>LLL Quotes System · ontwikkelkopie · Stijn Gabeler / GODOGOOD.eu</strong>.</p><p>Bij kopiëren, exporteren en WhatsApp wordt de verwijzing toegevoegd: <span class="siteLink">https://sites.google.com/view/lovelifelaugh ( i love you )</span></p></section>

</main>

<div class="toast" id="toast" role="status" aria-live="polite"></div><section id="printRoot" aria-hidden="true"></section>

<script>

window.addEventListener('error',function(event){var status=document.getElementById('liveStatus');if(status){status.textContent='De app kon niet starten: '+(event.message||'JavaScript-fout')+'. Controleer of Code.gs en index uit hetzelfde pakket zijn gepubliceerd.';status.setAttribute('data-state','error');}});

</script>

<script>

(function(){

  var status = document.getElementById('liveStatus');

  try {

    status.textContent = 'V7.1 client gestart · alle tabbladen worden ingelezen…';

    var encoded = 'CigoKT0+eyd1c2Ugc3RyaWN0JzsKbGV0IFNPVVJDRVM9W107CmNvbnN0IFNJVEU9J2h0dHBzOi8vc2l0ZXMuZ29vZ2xlLmNvbS92aWV3L2xvdmVsaWZlbGF1Z2gnOwpjb25zdCBGT09URVI9YExvdmVMaWZlTGF1Z2ggwrcgSSBMb3ZlIFlvdVxuJHtTSVRFfVxuKCBpIGxvdmUgeW91IClgOwpjb25zdCBzdGF0ZT17c2VsZWN0ZWQ6bmV3IFNldChTT1VSQ0VTLm1hcCgoXyxpKT0+aSkpLGN1cnJlbnQ6bmV3IE1hcCgpLHNlYXJjaFJlc3VsdHM6W119Owpjb25zdCAkPWlkPT5kb2N1bWVudC5nZXRFbGVtZW50QnlJZChpZCk7IGxldCB0b2FzdFRpbWVyOwpmdW5jdGlvbiBub3RpZnkobXNnKXtjbGVhclRpbWVvdXQodG9hc3RUaW1lcik7JCgndG9hc3QnKS50ZXh0Q29udGVudD1tc2c7JCgndG9hc3QnKS5jbGFzc0xpc3QuYWRkKCdzaG93Jyk7dG9hc3RUaW1lcj1zZXRUaW1lb3V0KCgpPT4kKCd0b2FzdCcpLmNsYXNzTGlzdC5yZW1vdmUoJ3Nob3cnKSwyNjAwKX0KZnVuY3Rpb24gcm5kKG4pe2lmKCFuKXJldHVybiAtMTtyZXR1cm4gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpKm4pfQpmdW5jdGlvbiBjdXJyZW50Rm9yKGkpe2NvbnN0IHNyYz1TT1VSQ0VTW2ldO2lmKCFzcmMuaXRlbXMubGVuZ3RoKXJldHVybiBudWxsO2xldCBpZHg9c3RhdGUuY3VycmVudC5nZXQoaSk7aWYoaWR4PT09dW5kZWZpbmVkfHxpZHg8MHx8aWR4Pj1zcmMuaXRlbXMubGVuZ3RoKXtpZHg9cm5kKHNyYy5pdGVtcy5sZW5ndGgpO3N0YXRlLmN1cnJlbnQuc2V0KGksaWR4KX1yZXR1cm4ge3NvdXJjZUluZGV4OmksaW5kZXg6aWR4LC4uLnNyYy5pdGVtc1tpZHhdfX0KZnVuY3Rpb24gcmFuZG9tT25lKGksdXNlZCl7Y29uc3Qgc3JjPVNPVVJDRVNbaV07aWYoIXNyYy5pdGVtcy5sZW5ndGgpcmV0dXJuO2NvbnN0IG9sZD1zdGF0ZS5jdXJyZW50LmdldChpKTtsZXQgcG9vbD1zcmMuaXRlbXMubWFwKChfLGopPT5qKTtpZih1c2VkKXtjb25zdCB1bmlxdWU9cG9vbC5maWx0ZXIoaj0+IXVzZWQuaGFzKG5vcm1hbGl6ZShzcmMuaXRlbXNbal0udGV4dCkudHJpbSgpKSk7aWYodW5pcXVlLmxlbmd0aClwb29sPXVuaXF1ZX1pZihwb29sLmxlbmd0aD4xJiZwb29sLmluY2x1ZGVzKG9sZCkpcG9vbD1wb29sLmZpbHRlcihqPT5qIT09b2xkKTtjb25zdCBuZXh0PXBvb2xbcm5kKHBvb2wubGVuZ3RoKV07c3RhdGUuY3VycmVudC5zZXQoaSxuZXh0KTtpZih1c2VkKXVzZWQuYWRkKG5vcm1hbGl6ZShzcmMuaXRlbXNbbmV4dF0udGV4dCkudHJpbSgpKX0KZnVuY3Rpb24gcmFuZG9tU2VsZWN0ZWQoKXtpZighWy4uLnN0YXRlLnNlbGVjdGVkXS5zb21lKGk9PlNPVVJDRVNbaV0/Lml0ZW1zLmxlbmd0aCkpcmV0dXJuO2NvbnN0IHVzZWQ9JCgndW5pcXVlU2V0JykuY2hlY2tlZD9uZXcgU2V0KCk6bnVsbDtbLi4uc3RhdGUuc2VsZWN0ZWRdLnNvcnQoKGEsYik9PmEtYikuZm9yRWFjaChpPT5yYW5kb21PbmUoaSx1c2VkKSk7cmVuZGVyQm9hcmQoKTtub3RpZnkoJ05pZXV3ZSByYW5kb20gc2V0OiAnK3NlbGVjdGVkQ3VycmVudCgpLmxlbmd0aCsnIHppbm5lbiB1aXQgZ2Vrb3plbiBicm9ubmVuLicpfQpmdW5jdGlvbiByZW5kZXJTZWxlY3Rvcigpe2NvbnN0IGJveD0kKCdzZWxlY3RvcicpO2JveC5yZXBsYWNlQ2hpbGRyZW4oKTtTT1VSQ0VTLmZvckVhY2goKHMsaSk9Pntjb25zdCBiPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2J1dHRvbicpO2IuY2xhc3NOYW1lPSdjaGlwJysoIXMuaXRlbXMubGVuZ3RoPycgZW1wdHlTb3VyY2UnOicnKTtiLnR5cGU9J2J1dHRvbic7Yi50ZXh0Q29udGVudD1gJHtzLm5hbWV9IMK3ICR7cy5pdGVtcy5sZW5ndGh9YDtiLnNldEF0dHJpYnV0ZSgndGl0bGUnLGAke3MubmFtZX06ICR7cy5pdGVtcy5sZW5ndGh9IHppbm5lbmApO2Iuc2V0QXR0cmlidXRlKCdhcmlhLXByZXNzZWQnLHN0YXRlLnNlbGVjdGVkLmhhcyhpKSk7Yi5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsKCk9PntzdGF0ZS5zZWxlY3RlZC5oYXMoaSk/c3RhdGUuc2VsZWN0ZWQuZGVsZXRlKGkpOnN0YXRlLnNlbGVjdGVkLmFkZChpKTtyZW5kZXJTZWxlY3RvcigpO3JlbmRlckJvYXJkKCk7dXBkYXRlU3RhdHMoKX0pO2JveC5hcHBlbmQoYil9KX0KZnVuY3Rpb24gY2FyZEFjdGlvbnMoY29sLGksaXRlbSl7Y29uc3QgYT1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTthLmNsYXNzTmFtZT0nYWN0aW9ucyc7Y29uc3Qgc3BlY3M9W1sn4oa7IE5pZXV3ZScsKCk9PntyYW5kb21PbmUoaSk7cmVuZGVyQm9hcmQoKX1dLFsn8J+TiyBLb3BpZWVyJywoKT0+Y29weVRleHQoZm9ybWF0U2luZ2xlKGksY3VycmVudEZvcihpKSkpXSxbJ/CfkqwgV2hhdHNBcHAnLCgpPT5zaGFyZVdBKGZvcm1hdFNpbmdsZShpLGN1cnJlbnRGb3IoaSkpKV0sWyfinJMgS2llcyBlbmtlbCcsKCk9PntzdGF0ZS5zZWxlY3RlZD1uZXcgU2V0KFtpXSk7cmVuZGVyU2VsZWN0b3IoKTtyZW5kZXJCb2FyZCgpO3VwZGF0ZVN0YXRzKCl9XV07c3BlY3MuZm9yRWFjaCgoW2xhYmVsLGZuXSk9Pntjb25zdCBiPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2J1dHRvbicpO2IudHlwZT0nYnV0dG9uJztiLnRleHRDb250ZW50PWxhYmVsO2IuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLGZuKTthLmFwcGVuZChiKX0pO3JldHVybiBhfQpmdW5jdGlvbiByZW5kZXJCb2FyZCgpe2NvbnN0IGJvYXJkPSQoJ2JvYXJkJyk7Ym9hcmQucmVwbGFjZUNoaWxkcmVuKCk7Wy4uLnN0YXRlLnNlbGVjdGVkXS5zb3J0KChhLGIpPT5hLWIpLmZvckVhY2goKGksb3JkZXIpPT57Y29uc3Qgc3JjPVNPVVJDRVNbaV0saXRlbT1jdXJyZW50Rm9yKGkpLGNvbD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzZWN0aW9uJyk7Y29sLmNsYXNzTmFtZT0nc291cmNlQ29sJztjb25zdCBoZWFkPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO2hlYWQuY2xhc3NOYW1lPWBzb3VyY2VIZWFkIHRvbmUke29yZGVyJTV9YDtjb25zdCBoPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2gyJyk7aC50ZXh0Q29udGVudD1zcmMubmFtZTtjb25zdCBwPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3AnKTtwLnRleHRDb250ZW50PWAke3NyYy5pdGVtcy5sZW5ndGgudG9Mb2NhbGVTdHJpbmcoJ25sLU5MJyl9IGJlcmljaHRlbiDCtyAxIHdpbGxla2V1cmlnIGJlcmljaHQgYWN0aWVmYDtoZWFkLmFwcGVuZChoLHApO2NvbnN0IGNhcmQ9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYXJ0aWNsZScpO2NhcmQuY2xhc3NOYW1lPSdtZXNzYWdlQ2FyZCc7Y29uc3QgdHh0PWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3AnKTt0eHQuY2xhc3NOYW1lPSdtZXNzYWdlVGV4dCc7dHh0LnRleHRDb250ZW50PWl0ZW0/aXRlbS50ZXh0OidHZWVuIGJlcmljaHRlbic7Y2FyZC5hcHBlbmQodHh0KTtpZihpdGVtPy5tZXRhKXtjb25zdCBtPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO20uY2xhc3NOYW1lPSdtZXNzYWdlTWV0YSc7bS50ZXh0Q29udGVudD1pdGVtLm1ldGE7Y2FyZC5hcHBlbmQobSl9aWYoaXRlbSl7Y2FyZC5hcHBlbmQoY2FyZEFjdGlvbnMoY29sLGksaXRlbSkpO2NvbnN0IHRvb2xzPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO3Rvb2xzLmNsYXNzTmFtZT0ncWJ1dHRvbnMnO2NvbnN0IHJlYWQ9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYnV0dG9uJyk7cmVhZC50ZXh0Q29udGVudD0nTGVlcyBhbGxlIHppbm5lbiAvIGtvbG9tbWVuJztyZWFkLm9uY2xpY2s9KCk9Pm9wZW5Tb3VyY2VSZWFkZXIoaSk7dG9vbHMuYXBwZW5kKHJlYWQpO2NvbnN0IGZhdj1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdidXR0b24nKTtmYXYudGV4dENvbnRlbnQ9ZmF2b3JpdGVzLmhhcyhxdW90ZUtleShpdGVtKSk/J+KYhSBGYXZvcmlldCc6J+KYhiBCZXdhYXInO2Zhdi5vbmNsaWNrPSgpPT57Y29uc3Qgaz1xdW90ZUtleShpdGVtKTtmYXZvcml0ZXMuaGFzKGspP2Zhdm9yaXRlcy5kZWxldGUoayk6ZmF2b3JpdGVzLmFkZChrKTtzYXZlTG9jYWwoKTtpZigkKCdxTW9kZScpLnZhbHVlPT09J2Zhdm9yaXRlcycpYXBwbHlRdW90ZUZpbHRlcnMoKTtlbHNlIHJlbmRlckJvYXJkKCl9O3Rvb2xzLmFwcGVuZChmYXYpO2lmKGl0ZW0udXJsJiYvXmh0dHBzPzpcL1wvL2kudGVzdChpdGVtLnVybCkpe2NvbnN0IGxpbms9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYScpO2xpbmsuaHJlZj1pdGVtLnVybDtsaW5rLnRhcmdldD0nX2JsYW5rJztsaW5rLnJlbD0nbm9vcGVuZXInO2xpbmsudGV4dENvbnRlbnQ9J0Jyb24g4oaXJzt0b29scy5hcHBlbmQobGluayl9Y2FyZC5hcHBlbmQodG9vbHMpfWNvbnN0IGZvb3Q9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7Zm9vdC5jbGFzc05hbWU9J3NvdXJjZUZvb3Rlcic7Zm9vdC5pbm5lckhUTUw9YDxzcGFuPmJlcmljaHQgJHsoaXRlbT8uaW5kZXg/PzApKzF9IC8gJHtzcmMuaXRlbXMubGVuZ3RofTwvc3Bhbj48c3Bhbj7imaUgTG92ZUxpZmVMYXVnaDwvc3Bhbj5gO2NvbC5hcHBlbmQoaGVhZCxjYXJkLGZvb3QpO2JvYXJkLmFwcGVuZChjb2wpfSk7aWYoIXN0YXRlLnNlbGVjdGVkLnNpemUpe2NvbnN0IGU9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgncCcpO2UuY2xhc3NOYW1lPSdlbXB0eSc7ZS50ZXh0Q29udGVudD0nS2llcyBoaWVyYm92ZW4gw6nDqW4gb2YgbWVlciB0YWJibGFkZW4gb20gaGV0IG1lc3NhZ2UgYm9hcmQgdGUgdnVsbGVuLic7Ym9hcmQuYXBwZW5kKGUpfXVwZGF0ZVN0YXRzKCl9CgpmdW5jdGlvbiBvcGVuU291cmNlUmVhZGVyKGkpe2NvbnN0IHNyYz1TT1VSQ0VTW2ldOyQoJ3JlYWRlclRpdGxlJykudGV4dENvbnRlbnQ9c3JjLm5hbWUrJyDCtyAnK3NyYy5pdGVtcy5sZW5ndGgrJyB6aW5uZW4nOyQoJ3JlYWRlclNoZWV0JykuaGlkZGVuPXNyYy5zaGVldElkPT1udWxsOyQoJ3JlYWRlclNoZWV0JykuaHJlZj0naHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMXpESlNxWFh2OUxqRHN2RWJrSkowVS1IdV9OT3NBVlIxUURHRUJVS2M1YUEvZWRpdCNnaWQ9JytlbmNvZGVVUklDb21wb25lbnQoc3JjLnNoZWV0SWQ/PycnKTtjb25zdCBib3g9JCgncmVhZGVyUm93cycpO2JveC5yZXBsYWNlQ2hpbGRyZW4oKTtjb25zdCB0YWJsZT1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCd0YWJsZScpLGhlYWQ9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndGhlYWQnKSxocj1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCd0cicpO2NvbnN0IGNvbHVtbnM9c3JjLmNvbHVtbnM/Lmxlbmd0aD9zcmMuY29sdW1uczpbJ1ppbicsJ1RvZWxpY2h0aW5nJ107WydSaWonLC4uLmNvbHVtbnMsJ0luIHNldCddLmZvckVhY2gobGFiZWw9Pntjb25zdCB0aD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCd0aCcpO3RoLnRleHRDb250ZW50PWxhYmVsO2hyLmFwcGVuZCh0aCl9KTtoZWFkLmFwcGVuZChocik7dGFibGUuYXBwZW5kKGhlYWQpO2NvbnN0IGJvZHk9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndGJvZHknKTtjb25zdCByb3dzPXNyYy5yb3dzfHxzcmMuaXRlbXMubWFwKChpdGVtLGluZGV4KT0+KHtyb3c6aXRlbS5yb3c/P2luZGV4KzEsY2VsbHM6W2l0ZW0udGV4dCxpdGVtLm1ldGF8fCcnXX0pKTtyb3dzLmZvckVhY2gocm93PT57Y29uc3QgaXRlbUluZGV4PXNyYy5pdGVtcy5maW5kSW5kZXgoaXRlbT0+aXRlbS5yb3c9PT1yb3cucm93KTtjb25zdCB0cj1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCd0cicpO1tyb3cucm93LC4uLnJvdy5jZWxsc10uZm9yRWFjaCh2YWx1ZT0+e2NvbnN0IHRkPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3RkJyk7dGQudGV4dENvbnRlbnQ9U3RyaW5nKHZhbHVlPz8nJyk7dHIuYXBwZW5kKHRkKX0pO2NvbnN0IGFjdGlvbj1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCd0ZCcpO2lmKGl0ZW1JbmRleD49MHx8IXNyYy5yb3dzKXtjb25zdCBpbmRleD1pdGVtSW5kZXg+PTA/aXRlbUluZGV4OnJvd3MuaW5kZXhPZihyb3cpO2lmKHNyYy5pdGVtc1tpbmRleF0pe2NvbnN0IGJ1dHRvbj1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdidXR0b24nKTtidXR0b24udGV4dENvbnRlbnQ9J0dlYnJ1aWsgemluJztidXR0b24ub25jbGljaz0oKT0+e3N0YXRlLnNlbGVjdGVkLmFkZChpKTtzdGF0ZS5jdXJyZW50LnNldChpLGluZGV4KTtyZW5kZXJTZWxlY3RvcigpO3JlbmRlckJvYXJkKCk7bm90aWZ5KCdaaW4gdWl0ICcrc3JjLm5hbWUrJyBnZWtvemVuLicpfTthY3Rpb24uYXBwZW5kKGJ1dHRvbil9fXRyLmFwcGVuZChhY3Rpb24pO2JvZHkuYXBwZW5kKHRyKX0pO3RhYmxlLmFwcGVuZChib2R5KTtib3guYXBwZW5kKHRhYmxlKTskKCdzb3VyY2VSZWFkZXInKS5oaWRkZW49ZmFsc2U7JCgnc291cmNlUmVhZGVyJykuc2Nyb2xsSW50b1ZpZXcoe2JlaGF2aW9yOidzbW9vdGgnLGJsb2NrOidzdGFydCd9KX0KJCgncmVhZGVyQ2xvc2UnKS5vbmNsaWNrPSgpPT57JCgnc291cmNlUmVhZGVyJykuaGlkZGVuPXRydWV9OwpmdW5jdGlvbiB1cGRhdGVTdGF0cygpe2NvbnN0IHJlYWR5PVsuLi5zdGF0ZS5zZWxlY3RlZF0uc29tZShpPT5TT1VSQ0VTW2ldPy5pdGVtcy5sZW5ndGgpOyQoJ3JhbmRvbUFsbCcpLmRpc2FibGVkPSFyZWFkeTskKCdyYW5kb21WaXNpYmxlJykuZGlzYWJsZWQ9IXJlYWR5OyQoJ3RhYkNvdW50TGFiZWwnKS50ZXh0Q29udGVudD1gJHtTT1VSQ0VTLmxlbmd0aH0gYnJvbm5lbiBraWV6ZW4gwrcgJHtPUklHSU5BTC5sZW5ndGh9IHRhYmJsYWRlbiBpbiBkZSBzaGVldGA7JCgnc3RhdFNvdXJjZXMnKS50ZXh0Q29udGVudD1TT1VSQ0VTLmxlbmd0aC50b0xvY2FsZVN0cmluZygnbmwtTkwnKTskKCdzdGF0TWVzc2FnZXMnKS50ZXh0Q29udGVudD1TT1VSQ0VTLnJlZHVjZSgobixzKT0+bitzLml0ZW1zLmxlbmd0aCwwKS50b0xvY2FsZVN0cmluZygnbmwtTkwnKTskKCdzdGF0U2VsZWN0ZWQnKS50ZXh0Q29udGVudD1zdGF0ZS5zZWxlY3RlZC5zaXplOyQoJ2FjdGl2ZUxhYmVsJykudGV4dENvbnRlbnQ9c3RhdGUuc2VsZWN0ZWQuc2l6ZTskKCdzdGF0U2VhcmNoJykudGV4dENvbnRlbnQ9c3RhdGUuc2VhcmNoUmVzdWx0cy5sZW5ndGgudG9Mb2NhbGVTdHJpbmcoJ25sLU5MJyl9CmZ1bmN0aW9uIG5vcm1hbGl6ZShzKXtyZXR1cm4gU3RyaW5nKHN8fCcnKS50b0xvY2FsZUxvd2VyQ2FzZSgnbmwtTkwnKS5ub3JtYWxpemUoJ05GRCcpLnJlcGxhY2UoL1tcdTAzMDAtXHUwMzZmXS9nLCcnKX0KZnVuY3Rpb24gZG9TZWFyY2goKXtjb25zdCBxPSQoJ3NlYXJjaCcpLnZhbHVlLnRyaW0oKSxwYW5lbD0kKCdzZWFyY2hQYW5lbCcpLGdyaWQ9JCgnc2VhcmNoR3JpZCcpO3N0YXRlLnNlYXJjaFJlc3VsdHM9W107Z3JpZC5yZXBsYWNlQ2hpbGRyZW4oKTtpZighcSl7cGFuZWwuY2xhc3NMaXN0LnJlbW92ZSgnc2hvdycpOyQoJ3NlYXJjaExhYmVsJykudGV4dENvbnRlbnQ9J1R5cCBoaWVyYm92ZW4gb20gYWxsZSBicm9ubmVuIHRlIGRvb3J6b2VrZW4uJzt1cGRhdGVTdGF0cygpO3JldHVybn1jb25zdCBucT1ub3JtYWxpemUocSk7U09VUkNFUy5mb3JFYWNoKChzLHNpKT0+cy5pdGVtcy5mb3JFYWNoKChpdCxpZHgpPT57aWYobm9ybWFsaXplKGl0LnRleHQrJyAnKyhpdC5tZXRhfHwnJykpLmluY2x1ZGVzKG5xKSlzdGF0ZS5zZWFyY2hSZXN1bHRzLnB1c2goe3NvdXJjZUluZGV4OnNpLGluZGV4OmlkeCwuLi5pdH0pfSkpO3BhbmVsLmNsYXNzTGlzdC5hZGQoJ3Nob3cnKTskKCdzZWFyY2hMYWJlbCcpLnRleHRDb250ZW50PWAke3N0YXRlLnNlYXJjaFJlc3VsdHMubGVuZ3RoLnRvTG9jYWxlU3RyaW5nKCdubC1OTCcpfSByZXN1bHRhdGVuIHZvb3Ig4oCcJHtxfeKAnWA7Y29uc3QgbGltaXQ9MjUwO3N0YXRlLnNlYXJjaFJlc3VsdHMuc2xpY2UoMCxsaW1pdCkuZm9yRWFjaChyPT57Y29uc3QgYm94PWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2FydGljbGUnKTtib3guY2xhc3NOYW1lPSdzZWFyY2hJdGVtJztjb25zdCBzdHJvbmc9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3Ryb25nJyk7c3Ryb25nLnRleHRDb250ZW50PVNPVVJDRVNbci5zb3VyY2VJbmRleF0ubmFtZTtjb25zdCBwPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3AnKTtwLnRleHRDb250ZW50PXIudGV4dDtjb25zdCBiPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2J1dHRvbicpO2IudHlwZT0nYnV0dG9uJztiLnRleHRDb250ZW50PSdHZWJydWlrIGRpdCBiZXJpY2h0JztiLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywoKT0+e3N0YXRlLnNlbGVjdGVkLmFkZChyLnNvdXJjZUluZGV4KTtzdGF0ZS5jdXJyZW50LnNldChyLnNvdXJjZUluZGV4LHIuaW5kZXgpO3JlbmRlclNlbGVjdG9yKCk7cmVuZGVyQm9hcmQoKTskKCdib2FyZEFuY2hvcicpLnNjcm9sbEludG9WaWV3KHtiZWhhdmlvcjonc21vb3RoJ30pO25vdGlmeSgnQmVyaWNodCBhbHMgaHVpZGlnZSBrYWFydCBpbmdlc3RlbGQuJyl9KTtib3guYXBwZW5kKHN0cm9uZyxwLGIpO2dyaWQuYXBwZW5kKGJveCl9KTtpZighc3RhdGUuc2VhcmNoUmVzdWx0cy5sZW5ndGgpe2NvbnN0IGU9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgncCcpO2UuY2xhc3NOYW1lPSdlbXB0eSc7ZS50ZXh0Q29udGVudD0nR2VlbiBiZXJpY2h0ZW4gZ2V2b25kZW4uJztncmlkLmFwcGVuZChlKX1lbHNlIGlmKHN0YXRlLnNlYXJjaFJlc3VsdHMubGVuZ3RoPmxpbWl0KXtjb25zdCBlPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3AnKTtlLmNsYXNzTmFtZT0nZW1wdHknO2UudGV4dENvbnRlbnQ9YEVlcnN0ZSAke2xpbWl0fSByZXN1bHRhdGVuIGdldG9vbmQuIFZlcmZpam4gamUgem9la3Rlcm0gdm9vciBlZW4ga29ydGVyZSBsaWpzdC5gO2dyaWQuYXBwZW5kKGUpfXVwZGF0ZVN0YXRzKCl9CmZ1bmN0aW9uIHNlbGVjdGVkQ3VycmVudCgpe3JldHVybiBbLi4uc3RhdGUuc2VsZWN0ZWRdLnNvcnQoKGEsYik9PmEtYikubWFwKGk9Pntjb25zdCBjPWN1cnJlbnRGb3IoaSk7cmV0dXJuIGM/e3NvdXJjZTpTT1VSQ0VTW2ldLm5hbWUsLi4uY306bnVsbH0pLmZpbHRlcihCb29sZWFuKX0KZnVuY3Rpb24gYWxsU2VsZWN0ZWQoKXtjb25zdCBhcnI9W107Wy4uLnN0YXRlLnNlbGVjdGVkXS5zb3J0KChhLGIpPT5hLWIpLmZvckVhY2goaT0+U09VUkNFU1tpXS5pdGVtcy5mb3JFYWNoKChpdCxpbmRleCk9PmFyci5wdXNoKHtzb3VyY2U6U09VUkNFU1tpXS5uYW1lLHNvdXJjZUluZGV4OmksaW5kZXgsLi4uaXR9KSkpO3JldHVybiBhcnJ9CmZ1bmN0aW9uIHNjb3BlSXRlbXMoKXtjb25zdCBzY29wZT0kKCdleHBvcnRTY29wZScpLnZhbHVlO2lmKHNjb3BlPT09J3NlYXJjaCcpcmV0dXJuIHN0YXRlLnNlYXJjaFJlc3VsdHMubWFwKHI9Pih7c291cmNlOlNPVVJDRVNbci5zb3VyY2VJbmRleF0ubmFtZSwuLi5yfSkpO2lmKHNjb3BlPT09J2FsbFNlbGVjdGVkJylyZXR1cm4gYWxsU2VsZWN0ZWQoKTtyZXR1cm4gc2VsZWN0ZWRDdXJyZW50KCl9CmZ1bmN0aW9uIGZvcm1hdFNpbmdsZShpLGl0ZW0pe3JldHVybiBgJHtpdGVtLnRleHR9JHtpdGVtLm1ldGE/YFxuXG4ke2l0ZW0ubWV0YX1gOicnfVxuXG4ke0ZPT1RFUn1gfQpmdW5jdGlvbiBleHBvcnRUZXh0KGl0ZW1zKXtyZXR1cm4gaXRlbXMubWFwKCh4LG4pPT5gJHtuKzF9LiBbJHt4LnNvdXJjZX1dXG4ke3gudGV4dH0ke3gubWV0YT9gXG4ke3gubWV0YX1gOicnfWApLmpvaW4oJ1xuXG4tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuJykrYFxuXG49PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiR7Rk9PVEVSfWB9CmZ1bmN0aW9uIGNzdkNlbGwodil7cmV0dXJuIGAiJHtTdHJpbmcodj8/JycpLnJlcGxhY2VBbGwoJyInLCciIicpfSJgfQpmdW5jdGlvbiBleHBvcnRDc3YoaXRlbXMpe3JldHVybiAnXHVmZWZmJytbWydicm9uJywncXVvdGUnLCdhdXRob3InLCdjYXRlZ29yeScsJ3NvdXJjZV91cmwnLCdtZXRhZGF0YScsJ251bW1lciddLC4uLml0ZW1zLm1hcCh4PT5beC5zb3VyY2UseC50ZXh0LHguYXV0aG9yfHwnJyx4LnRhZ3N8fCcnLHgudXJsfHwnJyx4Lm1ldGF8fCcnLCh4LmluZGV4Pz8wKSsxXSldLm1hcChyPT5yLm1hcChjc3ZDZWxsKS5qb2luKCc7JykpLmpvaW4oJ1xyXG4nKStgXHJcblxyXG4ke2NzdkNlbGwoJ0xvdmVMaWZlTGF1Z2gnKX07JHtjc3ZDZWxsKFNJVEUpfTske2NzdkNlbGwoJyggaSBsb3ZlIHlvdSApJyl9O2B9CmZ1bmN0aW9uIGV4cG9ydEpzb24oaXRlbXMpe3JldHVybiBKU09OLnN0cmluZ2lmeSh7YXBwOidMb3ZlTGlmZUxhdWdoIE1lc3NhZ2UgQm9hcmQnLHNpdGU6U0lURSx0YWdsaW5lOidpIGxvdmUgeW91JyxleHBvcnRlZEF0Om5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxjb3VudDppdGVtcy5sZW5ndGgsbWVzc2FnZXM6aXRlbXMubWFwKHg9Pih7c291cmNlOnguc291cmNlLG1lc3NhZ2U6eC50ZXh0LG1ldGE6eC5tZXRhfHwnJyxhdXRob3I6eC5hdXRob3J8fCcnLGNhdGVnb3J5OngudGFnc3x8Jycsc291cmNlX3VybDp4LnVybHx8JycsbnVtYmVyOih4LmluZGV4Pz8wKSsxfSkpfSxudWxsLDIpfQpmdW5jdGlvbiBlc2NhcGVIdG1sKHYpe3JldHVybiBTdHJpbmcodj8/JycpLnJlcGxhY2VBbGwoJyYnLCcmYW1wOycpLnJlcGxhY2VBbGwoJzwnLCcmbHQ7JykucmVwbGFjZUFsbCgnPicsJyZndDsnKS5yZXBsYWNlQWxsKCciJywnJnF1b3Q7Jyl9CmZ1bmN0aW9uIHdvcmREb2MoaXRlbXMpe3JldHVybiBgPCFkb2N0eXBlIGh0bWw+PGh0bWw+PGhlYWQ+PG1ldGEgY2hhcnNldD0idXRmLTgiPjx0aXRsZT5Mb3ZlTGlmZUxhdWdoPC90aXRsZT48c3R5bGU+Ym9keXtmb250LWZhbWlseTpBcmlhbCxzYW5zLXNlcmlmO2xpbmUtaGVpZ2h0OjEuNTU7Y29sb3I6IzJlMTcyOH1hcnRpY2xle3BhZGRpbmc6MTJweDttYXJnaW46MCAwIDE0cHg7Ym9yZGVyOjFweCBzb2xpZCAjY2NjO3BhZ2UtYnJlYWstaW5zaWRlOmF2b2lkfWgxe2ZvbnQtc2l6ZToyMnB0fWgye2ZvbnQtc2l6ZToxM3B0O2NvbG9yOiM3YjIxNGR9LmZvb3RlcnttYXJnaW4tdG9wOjMwcHg7Zm9udC13ZWlnaHQ6Ym9sZH0ucmVhZGVyU2Nyb2xse21heC1oZWlnaHQ6NjV2aDtvdmVyZmxvdzphdXRvfSAucmVhZGVyU2Nyb2xsIHRhYmxle3dpZHRoOjEwMCU7Ym9yZGVyLWNvbGxhcHNlOmNvbGxhcHNlO2JhY2tncm91bmQ6I2ZmZn0ucmVhZGVyU2Nyb2xsIHRoLC5yZWFkZXJTY3JvbGwgdGR7dGV4dC1hbGlnbjpsZWZ0O3ZlcnRpY2FsLWFsaWduOnRvcDtib3JkZXI6MXB4IHNvbGlkIHZhcigtLWxpbmUpO3BhZGRpbmc6OXB4O21pbi13aWR0aDoxNDBweDt3aGl0ZS1zcGFjZTpwcmUtd3JhcDtvdmVyZmxvdy13cmFwOmFueXdoZXJlfS5yZWFkZXJTY3JvbGwgdGh7cG9zaXRpb246c3RpY2t5O3RvcDowO2JhY2tncm91bmQ6dmFyKC0tcGluayl9LnJlYWRlclNjcm9sbCBidXR0b257Ym9yZGVyOjFweCBzb2xpZCB2YXIoLS1saW5lKTtib3JkZXItcmFkaXVzOjhweDtwYWRkaW5nOjhweDtiYWNrZ3JvdW5kOnZhcigtLWdvbGQpO2ZvbnQ6aW5oZXJpdH0jc291cmNlUmVhZGVyW2hpZGRlbl17ZGlzcGxheTpub25lfQo8L3N0eWxlPjwvaGVhZD48Ym9keT48aDE+TG92ZUxpZmVMYXVnaCDCtyBJIExvdmUgWW91PC9oMT4ke2l0ZW1zLm1hcCh4PT5gPGFydGljbGU+PGgyPiR7ZXNjYXBlSHRtbCh4LnNvdXJjZSl9PC9oMj48cD4ke2VzY2FwZUh0bWwoeC50ZXh0KX08L3A+JHt4Lm1ldGE/YDxwPjxlbT4ke2VzY2FwZUh0bWwoeC5tZXRhKX08L2VtPjwvcD5gOicnfTwvYXJ0aWNsZT5gKS5qb2luKCcnKX08cCBjbGFzcz0iZm9vdGVyIj4ke2VzY2FwZUh0bWwoU0lURSl9PGJyPiggaSBsb3ZlIHlvdSApPC9wPjwvYm9keT48L2h0bWw+YH0KZnVuY3Rpb24gZG93bmxvYWQoY29udGVudCxuYW1lLHR5cGUpe2NvbnN0IGJsb2I9bmV3IEJsb2IoW2NvbnRlbnRdLHt0eXBlfSksdXJsPVVSTC5jcmVhdGVPYmplY3RVUkwoYmxvYiksYT1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7YS5ocmVmPXVybDthLmRvd25sb2FkPW5hbWU7ZG9jdW1lbnQuYm9keS5hcHBlbmQoYSk7YS5jbGljaygpO2EucmVtb3ZlKCk7c2V0VGltZW91dCgoKT0+VVJMLnJldm9rZU9iamVjdFVSTCh1cmwpLDEyMDApfQphc3luYyBmdW5jdGlvbiBjb3B5VGV4dCh0ZXh0KXt0cnl7YXdhaXQgbmF2aWdhdG9yLmNsaXBib2FyZC53cml0ZVRleHQodGV4dCk7bm90aWZ5KCdHZWtvcGllZXJkIG5hYXIga2xlbWJvcmQuJyl9Y2F0Y2h7Y29uc3QgdGE9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndGV4dGFyZWEnKTt0YS52YWx1ZT10ZXh0O3RhLnN0eWxlLnBvc2l0aW9uPSdmaXhlZCc7dGEuc3R5bGUub3BhY2l0eT0nMCc7ZG9jdW1lbnQuYm9keS5hcHBlbmQodGEpO3RhLnNlbGVjdCgpO2RvY3VtZW50LmV4ZWNDb21tYW5kKCdjb3B5Jyk7dGEucmVtb3ZlKCk7bm90aWZ5KCdHZWtvcGllZXJkLicpfX0KZnVuY3Rpb24gc2hhcmVXQSh0ZXh0KXt3aW5kb3cub3BlbihgaHR0cHM6Ly93YS5tZS8/dGV4dD0ke2VuY29kZVVSSUNvbXBvbmVudCh0ZXh0KX1gLCdfYmxhbmsnLCdub29wZW5lcixub3JlZmVycmVyJyl9CmZ1bmN0aW9uIHByZXBhcmVQcmludChpdGVtcyl7Y29uc3Qgcm9vdD0kKCdwcmludFJvb3QnKTtyb290LnJlcGxhY2VDaGlsZHJlbigpO2NvbnN0IGg9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaDEnKTtoLnRleHRDb250ZW50PSdMb3ZlTGlmZUxhdWdoIMK3IEkgTG92ZSBZb3UnO3Jvb3QuYXBwZW5kKGgpO2l0ZW1zLmZvckVhY2goeD0+e2NvbnN0IGE9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYXJ0aWNsZScpLGgyPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2gyJykscD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdwJyk7aDIudGV4dENvbnRlbnQ9eC5zb3VyY2U7cC50ZXh0Q29udGVudD14LnRleHQrKHgubWV0YT9gXG5cbiR7eC5tZXRhfWA6JycpO2EuYXBwZW5kKGgyLHApO3Jvb3QuYXBwZW5kKGEpfSk7Y29uc3QgZj1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdwJyk7Zi50ZXh0Q29udGVudD1GT09URVI7cm9vdC5hcHBlbmQoZik7cm9vdC5zZXRBdHRyaWJ1dGUoJ2FyaWEtaGlkZGVuJywnZmFsc2UnKTt3aW5kb3cucHJpbnQoKX0KJCgncmFuZG9tQWxsJykuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLHJhbmRvbVNlbGVjdGVkKTskKCdyYW5kb21WaXNpYmxlJykuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLHJhbmRvbVNlbGVjdGVkKTskKCdjaG9vc2VBbGwnKS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsKCk9PntzdGF0ZS5zZWxlY3RlZD1uZXcgU2V0KFNPVVJDRVMubWFwKChfLGkpPT5pKSk7cmVuZGVyU2VsZWN0b3IoKTtyYW5kb21TZWxlY3RlZCgpfSk7JCgnY2hvb3NlTm9uZScpLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywoKT0+e3N0YXRlLnNlbGVjdGVkLmNsZWFyKCk7cmVuZGVyU2VsZWN0b3IoKTtyZW5kZXJCb2FyZCgpO3VwZGF0ZVN0YXRzKCl9KTskKCdzZWFyY2gnKS5hZGRFdmVudExpc3RlbmVyKCdpbnB1dCcsZG9TZWFyY2gpOyQoJ2NsZWFyU2VhcmNoJykuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCgpPT57JCgnc2VhcmNoJykudmFsdWU9Jyc7ZG9TZWFyY2goKX0pOyQoJ3Njcm9sbEJvYXJkJykuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCgpPT4kKCdib2FyZEFuY2hvcicpLnNjcm9sbEludG9WaWV3KHtiZWhhdmlvcjonc21vb3RoJ30pKTskKCdjb3B5U2V0JykuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCgpPT5jb3B5VGV4dChleHBvcnRUZXh0KHNlbGVjdGVkQ3VycmVudCgpKSkpOyQoJ3dhU2V0JykuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCgpPT5zaGFyZVdBKGV4cG9ydFRleHQoc2VsZWN0ZWRDdXJyZW50KCkpKSk7CiQoJ2V4cFR4dCcpLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywoKT0+e2NvbnN0IGk9c2NvcGVJdGVtcygpO2lmKCFpLmxlbmd0aClyZXR1cm4gbm90aWZ5KCdHZWVuIGJlcmljaHRlbiBpbiBkZXplIGV4cG9ydGtldXplLicpO2Rvd25sb2FkKGV4cG9ydFRleHQoaSksJ2xvdmVsaWZlbGF1Z2hfbWVzc2FnZXMudHh0JywndGV4dC9wbGFpbjtjaGFyc2V0PXV0Zi04Jyl9KTskKCdleHBDc3YnKS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsKCk9Pntjb25zdCBpPXNjb3BlSXRlbXMoKTtpZighaS5sZW5ndGgpcmV0dXJuIG5vdGlmeSgnR2VlbiBiZXJpY2h0ZW4gaW4gZGV6ZSBleHBvcnRrZXV6ZS4nKTtkb3dubG9hZChleHBvcnRDc3YoaSksJ2xvdmVsaWZlbGF1Z2hfbWVzc2FnZXMuY3N2JywndGV4dC9jc3Y7Y2hhcnNldD11dGYtOCcpfSk7JCgnZXhwSnNvbicpLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywoKT0+e2NvbnN0IGk9c2NvcGVJdGVtcygpO2lmKCFpLmxlbmd0aClyZXR1cm4gbm90aWZ5KCdHZWVuIGJlcmljaHRlbiBpbiBkZXplIGV4cG9ydGtldXplLicpO2Rvd25sb2FkKGV4cG9ydEpzb24oaSksJ2xvdmVsaWZlbGF1Z2hfbWVzc2FnZXMuanNvbicsJ2FwcGxpY2F0aW9uL2pzb247Y2hhcnNldD11dGYtOCcpfSk7JCgnZXhwRG9jJykuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCgpPT57Y29uc3QgaT1zY29wZUl0ZW1zKCk7aWYoIWkubGVuZ3RoKXJldHVybiBub3RpZnkoJ0dlZW4gYmVyaWNodGVuIGluIGRlemUgZXhwb3J0a2V1emUuJyk7ZG93bmxvYWQod29yZERvYyhpKSwnbG92ZWxpZmVsYXVnaF9tZXNzYWdlcy5kb2MnLCdhcHBsaWNhdGlvbi9tc3dvcmQ7Y2hhcnNldD11dGYtOCcpfSk7JCgnZXhwUGRmJykuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCgpPT57Y29uc3QgaT1zY29wZUl0ZW1zKCk7aWYoIWkubGVuZ3RoKXJldHVybiBub3RpZnkoJ0dlZW4gYmVyaWNodGVuIGluIGRlemUgZXhwb3J0a2V1emUuJyk7cHJlcGFyZVByaW50KGkpfSk7d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ2FmdGVycHJpbnQnLCgpPT57JCgncHJpbnRSb290Jykuc2V0QXR0cmlidXRlKCdhcmlhLWhpZGRlbicsJ3RydWUnKTskKCdwcmludFJvb3QnKS5yZXBsYWNlQ2hpbGRyZW4oKX0pOwoKY29uc3QgQ0FURUdPUklFUz1bIkFnZSIsICJBbG9uZSIsICJBbWF6aW5nIiwgIkFuZ2VyIiwgIkFubml2ZXJzYXJ5IiwgIkFyY2hpdGVjdHVyZSIsICJBcnQiLCAiQXR0aXR1ZGUiLCAiQmVhdXR5IiwgIkJlc3QiLCAiQmlydGhkYXkiLCAiQnJhaW55IiwgIkJ1c2luZXNzIiwgIkNhciIsICJDaGFuY2UiLCAiQ2hhbmdlIiwgIkNocmlzdG1hcyIsICJDb21tdW5pY2F0aW9uIiwgIkNvbXB1dGVycyIsICJDb29sIiwgIkNvdXJhZ2UiLCAiRGFkIiwgIkRhdGluZyIsICJEZWF0aCIsICJEZXNpZ24iLCAiRGlldCIsICJEcmVhbXMiLCAiRWFzdGVyIiwgIkVkdWNhdGlvbiIsICJFbnZpcm9ubWVudGFsIiwgIkVxdWFsaXR5IiwgIkV4cGVyaWVuY2UiLCAiRmFpbHVyZSIsICJGYWl0aCIsICJGYW1pbHkiLCAiRmFtb3VzIiwgIkZhdGhlcidzIERheSIsICJGZWFyIiwgIkZpbmFuY2UiLCAiRml0bmVzcyIsICJGb29kIiwgIkZvcmdpdmVuZXNzIiwgIkZyZWVkb20iLCAiRnJpZW5kc2hpcCIsICJGdW5ueSIsICJGdXR1cmUiLCAiR2FyZGVuaW5nIiwgIkdvZCIsICJHb29kIiwgIkdvdmVybm1lbnQiLCAiR3JhZHVhdGlvbiIsICJHcmVhdCIsICJIYXBwaW5lc3MiLCAiSGVhbHRoIiwgIkhpc3RvcnkiLCAiSG9tZSIsICJIb3BlIiwgIkh1bW9yIiwgIkltYWdpbmF0aW9uIiwgIkluZGVwZW5kZW5jZSIsICJJbnNwaXJhdGlvbmFsIiwgIkludGVsbGlnZW5jZSIsICJKZWFsb3VzeSIsICJLbm93bGVkZ2UiLCAiTGVhZGVyc2hpcCIsICJMZWFybmluZyIsICJMZWdhbCIsICJMaWZlIiwgIkxvdmUiLCAiTWFycmlhZ2UiLCAiTWVkaWNhbCIsICJNZW1vcmlhbCBEYXkiLCAiTWVuIiwgIk1vbSIsICJNb25leSIsICJNb3JuaW5nIiwgIk1vdGhlcidzIERheSIsICJNb3RpdmF0aW9uYWwiLCAiTW92aWVzIiwgIk1vdmluZyBPbiIsICJNdXNpYyIsICJOYXR1cmUiLCAiTmV3IFllYXIncyIsICJQYXJlbnRpbmciLCAiUGF0aWVuY2UiLCAiUGF0cmlvdGlzbSIsICJQZWFjZSIsICJQZXQiLCAiUG9ldHJ5IiwgIlBvbGl0aWNzIiwgIlBvc2l0aXZlIiwgIlBvd2VyIiwgIlJlbGF0aW9uc2hpcCIsICJSZWxpZ2lvbiIsICJSZXNwZWN0IiwgIlJvbWFudGljIiwgIlNhZCIsICJTYWludCBQYXRyaWNrJ3MgRGF5IiwgIlNjaWVuY2UiLCAiU21pbGUiLCAiU29jaWV0eSIsICJTcGFjZSIsICJTcG9ydHMiLCAiU3RyZW5ndGgiLCAiU3VjY2VzcyIsICJTeW1wYXRoeSIsICJUZWFjaGVyIiwgIlRlY2hub2xvZ3kiLCAiVGVlbiIsICJUaGFua2Z1bCIsICJUaGFua3NnaXZpbmciLCAiVGltZSIsICJUcmF2ZWwiLCAiVHJ1c3QiLCAiVHJ1dGgiLCAiVmFsZW50aW5lJ3MgRGF5IiwgIlZldGVyYW5zIERheSIsICJXYXIiLCAiV2VkZGluZyIsICJXaXNkb20iLCAiV29tZW4iLCAiV29yayJdOwpsZXQgT1JJR0lOQUw9U09VUkNFUzsKY29uc3QgV0VCU0lURV9TT1VSQ0VTPVtdOwpjb25zdCBMT0NBTF9LRVk9J2xsbC1xdW90ZXMtc3lzdGVtLXYyJzsKbGV0IGV4dHJhUXVvdGVzPVtdLGZhdm9yaXRlcz1uZXcgU2V0KCk7CnRyeXtjb25zdCBzdG9yZWQ9SlNPTi5wYXJzZShsb2NhbFN0b3JhZ2UuZ2V0SXRlbShMT0NBTF9LRVkpfHwne30nKTtleHRyYVF1b3Rlcz1BcnJheS5pc0FycmF5KHN0b3JlZC5xdW90ZXMpP3N0b3JlZC5xdW90ZXM6W107ZmF2b3JpdGVzPW5ldyBTZXQoc3RvcmVkLmZhdm9yaXRlc3x8W10pfWNhdGNoe30KZnVuY3Rpb24gcXVvdGVLZXkoeCl7cmV0dXJuIG5vcm1hbGl6ZSh4LnRleHQpLnRyaW0oKSsnfCcrbm9ybWFsaXplKHguYXV0aG9yfHwnJykudHJpbSgpfQpmdW5jdGlvbiBzYXZlTG9jYWwoKXt0cnl7bG9jYWxTdG9yYWdlLnNldEl0ZW0oTE9DQUxfS0VZLEpTT04uc3RyaW5naWZ5KHtxdW90ZXM6ZXh0cmFRdW90ZXMsZmF2b3JpdGVzOlsuLi5mYXZvcml0ZXNdfSkpfWNhdGNoe25vdGlmeSgnTG9rYWxlIG9wc2xhZyBuaWV0IGJlc2NoaWtiYWFyLiBHZWJydWlrIEpTT04tYmFjay11cC4nKX19CmZ1bmN0aW9uIHJhd1F1b3RlKHgpe2lmKCF4fHx0eXBlb2YgeCE9PSdvYmplY3QnKXRocm93IEVycm9yKCdPbmdlbGRpZyBxdW90ZXJlY29yZCcpO2NvbnN0IHRleHQ9U3RyaW5nKHgucXVvdGU/P3gubWVzc2FnZT8/eC50ZXh0Pz8nJykudHJpbSgpO2lmKCF0ZXh0KXJldHVybiBudWxsO2NvbnN0IGF1dGhvcj1TdHJpbmcoeC5hdXRob3J8fCcnKTtjb25zdCB0YWdzPVN0cmluZyh4LmNhdGVnb3J5Pz94LnRhZ3M/PycnKTtjb25zdCB1cmw9U3RyaW5nKHguc291cmNlX3VybD8/eC51cmw/PycnKTtyZXR1cm4ge3RleHQsYXV0aG9yLHRhZ3MsdXJsOi9eaHR0cHM/OlwvXC8vaS50ZXN0KHVybCk/dXJsOicnLG9yaWdpbjpTdHJpbmcoeC5vcmlnaW58fCdFaWdlbiBpbXBvcnQnKSxtZXRhOlN0cmluZyh4Lm1ldGF8fFthdXRob3IsdGFncyx1cmxdLmZpbHRlcihCb29sZWFuKS5qb2luKCcgwrcgJykpLGxhbmd1YWdlOlN0cmluZyh4Lmxhbmd1YWdlfHwnJyl9fQpmdW5jdGlvbiBsaWJyYXJpZXMoKXtyZXR1cm4gWy4uLk9SSUdJTkFMLC4uLldFQlNJVEVfU09VUkNFUywuLi4oZXh0cmFRdW90ZXMubGVuZ3RoP1t7bmFtZTonRWlnZW4gcXVvdGVzICYgaW1wb3J0JyxpZDonbG9jYWwtaW1wb3J0JyxvcmlnaW46J0VpZ2VuIGltcG9ydCcsaXRlbXM6ZXh0cmFRdW90ZXN9XTpbXSldfQpmdW5jdGlvbiBzb3VyY2VLZXkocyl7cmV0dXJuIFN0cmluZyhzLmlkPz9zLnNoZWV0SWQ/P3MubmFtZSl9CmZ1bmN0aW9uIGNhcHR1cmVWaWV3KCl7cmV0dXJuIHtzZWxlY3RlZDpbLi4uc3RhdGUuc2VsZWN0ZWRdLm1hcChpPT5zb3VyY2VLZXkoU09VUkNFU1tpXSkpLGN1cnJlbnQ6U09VUkNFUy5tYXAoKHNyYyxpKT0+KHtrZXk6c291cmNlS2V5KHNyYyksdGV4dDpjdXJyZW50Rm9yKGkpPy50ZXh0LGF1dGhvcjpjdXJyZW50Rm9yKGkpPy5hdXRob3J8fCcnfSkpfX0KZnVuY3Rpb24gYXBwbHlRdW90ZUZpbHRlcnMocHJlc2VydmUpe2NvbnN0IHByZXZpb3VzPXByZXNlcnZlPT09dHJ1ZT9jYXB0dXJlVmlldygpOm51bGw7Y29uc3QgY2F0ZWdvcnk9bm9ybWFsaXplKCQoJ3FDYXRlZ29yeScpLnZhbHVlKSxhdXRob3I9bm9ybWFsaXplKCQoJ3FBdXRob3InKS52YWx1ZSksdGFnPW5vcm1hbGl6ZSgkKCdxVGFnJykudmFsdWUpLG1vZGU9JCgncU1vZGUnKS52YWx1ZTtjb25zdCBhbGxNb2RlPW1vZGU9PT0nYWxsJ3x8bW9kZT09PSdsZWdhY3knfHxtb2RlPT09J2Zhdm9yaXRlcyc7U09VUkNFUz1saWJyYXJpZXMoKS5maWx0ZXIoc3JjPT57aWYobW9kZT09PSdhbGwnKXJldHVybiBPUklHSU5BTC5pbmNsdWRlcyhzcmMpfHxzcmMub3JpZ2luPT09J0VpZ2VuIGltcG9ydCc7aWYobW9kZT09PSduZXcnKXJldHVybiBXRUJTSVRFX1NPVVJDRVMuaW5jbHVkZXMoc3JjKTtyZXR1cm4gYWxsTW9kZXx8WydRdW90ZXMnLCdBIHRvIFonXS5pbmNsdWRlcyhzcmMubmFtZSl8fFdFQlNJVEVfU09VUkNFUy5pbmNsdWRlcyhzcmMpfHxzcmMub3JpZ2luPT09J0VpZ2VuIGltcG9ydCd9KS5tYXAoc3JjPT4oey4uLnNyYyxpdGVtczpzcmMuaXRlbXMuZmlsdGVyKHg9PighY2F0ZWdvcnl8fFN0cmluZyh4LnRhZ3N8fCcnKS5zcGxpdCgvWyw7fF0vKS5zb21lKHQ9Pm5vcm1hbGl6ZSh0LnRyaW0oKSk9PT1jYXRlZ29yeSkpJiYoIWF1dGhvcnx8bm9ybWFsaXplKHguYXV0aG9yfHx4Lm1ldGEpLmluY2x1ZGVzKGF1dGhvcikpJiYoIXRhZ3x8bm9ybWFsaXplKCh4LnRhZ3N8fCcnKSsnICcreC50ZXh0KycgJysoeC5tZXRhfHwnJykpLmluY2x1ZGVzKHRhZykpJiYobW9kZSE9PSdmYXZvcml0ZXMnfHxmYXZvcml0ZXMuaGFzKHF1b3RlS2V5KHgpKSkpfSkpLmZpbHRlcihzcmM9PnNyYy5pdGVtcy5sZW5ndGh8fChtb2RlPT09J2FsbCcmJiFjYXRlZ29yeSYmIWF1dGhvciYmIXRhZykpO3N0YXRlLnNlbGVjdGVkPW5ldyBTZXQoKTtzdGF0ZS5jdXJyZW50LmNsZWFyKCk7U09VUkNFUy5mb3JFYWNoKChzcmMsaSk9PntpZighcHJldmlvdXN8fHByZXZpb3VzLnNlbGVjdGVkLmluY2x1ZGVzKHNvdXJjZUtleShzcmMpKXx8IXByZXZpb3VzLmN1cnJlbnQuc29tZSh4PT54LmtleT09PXNvdXJjZUtleShzcmMpKSlzdGF0ZS5zZWxlY3RlZC5hZGQoaSk7aWYocHJldmlvdXMpe2NvbnN0IG9sZD1wcmV2aW91cy5jdXJyZW50LmZpbmQoeD0+eC5rZXk9PT1zb3VyY2VLZXkoc3JjKSk7aWYob2xkKXtjb25zdCBpbmRleD1zcmMuaXRlbXMuZmluZEluZGV4KHg9PngudGV4dD09PW9sZC50ZXh0JiYoeC5hdXRob3J8fCcnKT09PW9sZC5hdXRob3IpO2lmKGluZGV4Pj0wKXN0YXRlLmN1cnJlbnQuc2V0KGksaW5kZXgpfX19KTtzdGF0ZS5zZWFyY2hSZXN1bHRzPVtdO3JlbmRlclNlbGVjdG9yKCk7cmVuZGVyQm9hcmQoKTtkb1NlYXJjaCgpOyQoJ3FTdGF0dXMnKS50ZXh0Q29udGVudD1TT1VSQ0VTLnJlZHVjZSgobixzcmMpPT5uK3NyYy5pdGVtcy5sZW5ndGgsMCkudG9Mb2NhbGVTdHJpbmcoJ25sLU5MJykrJyB6aW5uZW4gYmlubmVuIGZpbHRlcnMgwrcgJytTT1VSQ0VTLmxlbmd0aCsnIGJyb25uZW4gwrcgJytmYXZvcml0ZXMuc2l6ZSsnIGZhdm9yaWV0ZW4nO2lmKCFTT1VSQ0VTLmxlbmd0aCkkKCdib2FyZCcpLnRleHRDb250ZW50PSdHZWVuIHppbm5lbiB2b29yIGRlemUgZmlsdGVycy4gS2llcyBBbGxlIHRhYmJsYWRlbiBlbiB3aXMgZGUgZmlsdGVycy4nfQoKQ0FURUdPUklFUy5mb3JFYWNoKGM9Pntjb25zdCBvPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ29wdGlvbicpO28udmFsdWU9YztvLnRleHRDb250ZW50PWM7JCgncUNhdGVnb3J5JykuYXBwZW5kKG8pfSk7ClsncUNhdGVnb3J5JywncU1vZGUnXS5mb3JFYWNoKGlkPT4kKGlkKS5hZGRFdmVudExpc3RlbmVyKCdjaGFuZ2UnLGFwcGx5UXVvdGVGaWx0ZXJzKSk7WydxQXV0aG9yJywncVRhZyddLmZvckVhY2goaWQ9PiQoaWQpLmFkZEV2ZW50TGlzdGVuZXIoJ2lucHV0JyxhcHBseVF1b3RlRmlsdGVycykpOwokKCdxUmVzZXQnKS5vbmNsaWNrPSgpPT57JCgncUNhdGVnb3J5JykudmFsdWU9Jyc7JCgncUF1dGhvcicpLnZhbHVlPScnOyQoJ3FUYWcnKS52YWx1ZT0nJzskKCdxTW9kZScpLnZhbHVlPSdhbGwnOyQoJ3NlYXJjaCcpLnZhbHVlPScnO2FwcGx5UXVvdGVGaWx0ZXJzKCl9OwpmdW5jdGlvbiBzaG93VG9waWNzKGxldHRlcil7Y29uc3QgdGFncz1bLi4ubmV3IFNldChsaWJyYXJpZXMoKS5mbGF0TWFwKHM9PnMuaXRlbXMuZmxhdE1hcCh4PT5TdHJpbmcoeC50YWdzfHwnJykuc3BsaXQoL1ssO3xdLykubWFwKHQ9PnQudHJpbSgpKS5maWx0ZXIoQm9vbGVhbikpKSldLnNvcnQoKGEsYik9PmEubG9jYWxlQ29tcGFyZShiKSk7JCgncVRvcGljcycpLnJlcGxhY2VDaGlsZHJlbigpO3RhZ3MuZmlsdGVyKHQ9Pm5vcm1hbGl6ZSh0KS5zdGFydHNXaXRoKGxldHRlci50b0xvd2VyQ2FzZSgpKSkuc2xpY2UoMCwyMDApLmZvckVhY2godD0+e2NvbnN0IGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYnV0dG9uJyk7Yi50ZXh0Q29udGVudD10O2Iub25jbGljaz0oKT0+eyQoJ3FUYWcnKS52YWx1ZT10O2FwcGx5UXVvdGVGaWx0ZXJzKCl9OyQoJ3FUb3BpY3MnKS5hcHBlbmQoYil9KX0KJ0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaJy5zcGxpdCgnJykuZm9yRWFjaChsPT57Y29uc3QgYj1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdidXR0b24nKTtiLnRleHRDb250ZW50PWw7Yi5vbmNsaWNrPSgpPT5zaG93VG9waWNzKGwpOyQoJ3FMZXR0ZXJzJykuYXBwZW5kKGIpfSk7c2hvd1RvcGljcygnQScpOwpmdW5jdGlvbiBhZGRJbXBvcnRzKHJvd3Mpe2NvbnN0IHNlZW49bmV3IFNldChsaWJyYXJpZXMoKS5mbGF0TWFwKHM9PnMuaXRlbXMubWFwKHF1b3RlS2V5KSkpO2xldCBhZGRlZD0wO2Zvcihjb25zdCByb3cgb2Ygcm93cyl7Y29uc3QgcT1yYXdRdW90ZShyb3cpO2lmKHEmJiFzZWVuLmhhcyhxdW90ZUtleShxKSkpe2V4dHJhUXVvdGVzLnB1c2gocSk7c2Vlbi5hZGQocXVvdGVLZXkocSkpO2FkZGVkKyt9fXNhdmVMb2NhbCgpOyQoJ3FNb2RlJykudmFsdWU9J2FsbCc7JCgncUNhdGVnb3J5JykudmFsdWU9Jyc7JCgncUF1dGhvcicpLnZhbHVlPScnOyQoJ3FUYWcnKS52YWx1ZT0nJzthcHBseVF1b3RlRmlsdGVycygpO25vdGlmeShhZGRlZCsnIHF1b3RlcyB0b2VnZXZvZWdkOyBkdWJiZWxlIHJlY29yZHMgb3Zlcmdlc2xhZ2VuLicpfQokKCdxQWRkJykub25jbGljaz0oKT0+e2lmKCEkKCdxVGV4dCcpLnZhbHVlLnRyaW0oKSlyZXR1cm4gbm90aWZ5KCdWdWwgZWVuIHF1b3RlIGluLicpO2lmKCQoJ3FOZXdVcmwnKS52YWx1ZSYmIS9eaHR0cHM/OlwvXC8vaS50ZXN0KCQoJ3FOZXdVcmwnKS52YWx1ZSkpcmV0dXJuIG5vdGlmeSgnR2VicnVpayBlZW4gaHR0cHM6Ly8gYnJvbmxpbmsuJyk7YWRkSW1wb3J0cyhbe3F1b3RlOiQoJ3FUZXh0JykudmFsdWUsYXV0aG9yOiQoJ3FOZXdBdXRob3InKS52YWx1ZSxjYXRlZ29yeTokKCdxTmV3VGFncycpLnZhbHVlLHNvdXJjZV91cmw6JCgncU5ld1VybCcpLnZhbHVlfV0pO1sncVRleHQnLCdxTmV3QXV0aG9yJywncU5ld1RhZ3MnLCdxTmV3VXJsJ10uZm9yRWFjaChpZD0+JChpZCkudmFsdWU9JycpfTsKZnVuY3Rpb24gcGFyc2VDc3YodGV4dCl7dGV4dD10ZXh0LnJlcGxhY2UoL15cdUZFRkYvLCcnKTtjb25zdCBmaXJzdD10ZXh0LnNwbGl0KC9ccj9cbi8pWzBdLHNlcD1maXJzdC5zcGxpdCgnOycpLmxlbmd0aD5maXJzdC5zcGxpdCgnLCcpLmxlbmd0aD8nOyc6JywnO2xldCByb3dzPVtdLHJvdz1bXSxjZWxsPScnLHF1b3RlZD1mYWxzZTtmb3IobGV0IGk9MDtpPHRleHQubGVuZ3RoO2krKyl7Y29uc3QgYz10ZXh0W2ldO2lmKGM9PT0nIicpe2lmKHF1b3RlZCYmdGV4dFtpKzFdPT09JyInKXtjZWxsKz0nIic7aSsrfWVsc2UgcXVvdGVkPSFxdW90ZWR9ZWxzZSBpZihjPT09c2VwJiYhcXVvdGVkKXtyb3cucHVzaChjZWxsKTtjZWxsPScnfWVsc2UgaWYoKGM9PT0nXG4nfHxjPT09J1xyJykmJiFxdW90ZWQpe2lmKGM9PT0nXHInJiZ0ZXh0W2krMV09PT0nXG4nKWkrKztyb3cucHVzaChjZWxsKTtpZihyb3cuc29tZShCb29sZWFuKSlyb3dzLnB1c2gocm93KTtyb3c9W107Y2VsbD0nJ31lbHNlIGNlbGwrPWN9aWYocXVvdGVkKXRocm93IEVycm9yKCdOaWV0IGFmZ2VzbG90ZW4gQ1NWLWFhbmhhbGluZ3N0ZWtlbicpO3Jvdy5wdXNoKGNlbGwpO2lmKHJvdy5zb21lKEJvb2xlYW4pKXJvd3MucHVzaChyb3cpO2NvbnN0IGhlYWRlcnM9KHJvd3Muc2hpZnQoKXx8W10pLm1hcCh4PT54LnRyaW0oKS50b0xvd2VyQ2FzZSgpKTtpZighaGVhZGVycy5zb21lKHg9PlsncXVvdGUnLCd0ZXh0JywnbWVzc2FnZSddLmluY2x1ZGVzKHgpKSl0aHJvdyBFcnJvcignQ1NWIG1pc3QgcXVvdGUta29sb20nKTtyZXR1cm4gcm93cy5tYXAocj0+T2JqZWN0LmZyb21FbnRyaWVzKGhlYWRlcnMubWFwKChoLGkpPT5baCxyW2ldfHwnJ10pKSl9CiQoJ3FJbXBvcnQnKS5vbmNsaWNrPSgpPT4kKCdxRmlsZScpLmNsaWNrKCk7JCgncUZpbGUnKS5vbmNoYW5nZT1hc3luYyBlPT57dHJ5e2NvbnN0IGY9ZS50YXJnZXQuZmlsZXNbMF07aWYoIWYpcmV0dXJuO2lmKGYuc2l6ZT4yMDAwMDAwMCl0aHJvdyBFcnJvcignQmVzdGFuZCBncm90ZXIgZGFuIDIwIE1CJyk7Y29uc3QgdGV4dD1hd2FpdCBmLnRleHQoKTtsZXQgcm93cztpZihmLm5hbWUudG9Mb3dlckNhc2UoKS5lbmRzV2l0aCgnLmpzb24nKSl7Y29uc3Qgb2JqPUpTT04ucGFyc2UodGV4dCk7cm93cz1BcnJheS5pc0FycmF5KG9iaik/b2JqOihvYmoucXVvdGVzfHxvYmoubWVzc2FnZXN8fG9iai5zb3VyY2VzPy5mbGF0TWFwKHNyYz0+c3JjLml0ZW1zLm1hcChpdGVtPT4oey4uLml0ZW0sc291cmNlOnNyYy5uYW1lfSkpKSk7aWYoIUFycmF5LmlzQXJyYXkocm93cykpdGhyb3cgRXJyb3IoJ0pTT04gbWlzdCBxdW90ZXMvbWVzc2FnZXMtYXJyYXknKTtpZihBcnJheS5pc0FycmF5KG9iai5mYXZvcml0ZXMpKW9iai5mYXZvcml0ZXMuZmlsdGVyKHg9PnR5cGVvZiB4PT09J3N0cmluZycpLmZvckVhY2goeD0+ZmF2b3JpdGVzLmFkZCh4KSl9ZWxzZSByb3dzPXBhcnNlQ3N2KHRleHQpO2FkZEltcG9ydHMocm93cyl9Y2F0Y2goZXJyKXtub3RpZnkoJ0ltcG9ydCBtaXNsdWt0OiAnK2Vyci5tZXNzYWdlKX1maW5hbGx5e2UudGFyZ2V0LnZhbHVlPScnfX07CiQoJ3FCYWNrdXAnKS5vbmNsaWNrPSgpPT5kb3dubG9hZChKU09OLnN0cmluZ2lmeSh7YXBwOidMTEwgUXVvdGVzIFN5c3RlbScsdmVyc2lvbjo2LGV4cG9ydGVkQXQ6bmV3IERhdGUoKS50b0lTT1N0cmluZygpLHNvdXJjZXM6bGlicmFyaWVzKCkscXVvdGVzOmxpYnJhcmllcygpLmZsYXRNYXAoc3JjPT5zcmMuaXRlbXMubWFwKGl0ZW09Pih7Li4uaXRlbSxzb3VyY2U6c3JjLm5hbWV9KSkpLGZhdm9yaXRlczpbLi4uZmF2b3JpdGVzXX0sbnVsbCwyKSwnTExMX1F1b3Rlc19TeXN0ZW1fQmFja3VwLmpzb24nLCdhcHBsaWNhdGlvbi9qc29uJyk7CgpsZXQgbGl2ZUJ1c3k9ZmFsc2U7CmxldCBzeW5jVGltZXI9bnVsbDsKY29uc3QgaGFzU2hlZXRCcmlkZ2U9dHlwZW9mIGdvb2dsZSE9PSd1bmRlZmluZWQnJiZCb29sZWFuKGdvb2dsZS5zY3JpcHQ/LnJ1bik7CmZ1bmN0aW9uIHNldExpdmVTdGF0dXMobWVzc2FnZSxraW5kKXskKCdsaXZlU3RhdHVzJykudGV4dENvbnRlbnQ9bWVzc2FnZTskKCdsaXZlU3RhdHVzJykuc2V0QXR0cmlidXRlKCdkYXRhLXN0YXRlJyxraW5kfHwnc25hcHNob3QnKX0KZnVuY3Rpb24gcmVmcmVzaENhdGVnb3J5T3B0aW9ucygpe2NvbnN0IGNob3Nlbj0kKCdxQ2F0ZWdvcnknKS52YWx1ZTtjb25zdCB0YWdzPVsuLi5uZXcgU2V0KFsuLi5DQVRFR09SSUVTLC4uLk9SSUdJTkFMLm1hcChzcmM9PnNyYy5uYW1lKSwuLi5saWJyYXJpZXMoKS5mbGF0TWFwKHNyYz0+c3JjLml0ZW1zLmZsYXRNYXAoaXRlbT0+U3RyaW5nKGl0ZW0udGFnc3x8JycpLnNwbGl0KC9bLDt8XS8pLm1hcCh2PT52LnRyaW0oKSkuZmlsdGVyKEJvb2xlYW4pKSldKV0uc29ydCgoYSxiKT0+YS5sb2NhbGVDb21wYXJlKGIsJ25sJykpOyQoJ3FDYXRlZ29yeScpLnJlcGxhY2VDaGlsZHJlbigpO2NvbnN0IGZpcnN0PWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ29wdGlvbicpO2ZpcnN0LnZhbHVlPScnO2ZpcnN0LnRleHRDb250ZW50PSdBbGxlIGNhdGVnb3JpZcOrbiAvIHJ1YnJpZWtlbic7JCgncUNhdGVnb3J5JykuYXBwZW5kKGZpcnN0KTt0YWdzLmZvckVhY2godGFnPT57Y29uc3Qgb3B0aW9uPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ29wdGlvbicpO29wdGlvbi52YWx1ZT10YWc7b3B0aW9uLnRleHRDb250ZW50PXRhZzskKCdxQ2F0ZWdvcnknKS5hcHBlbmQob3B0aW9uKX0pOyQoJ3FDYXRlZ29yeScpLnZhbHVlPXRhZ3MuaW5jbHVkZXMoY2hvc2VuKT9jaG9zZW46Jyd9CmZ1bmN0aW9uIHZhbGlkYXRlU2hlZXREYXRhKGRhdGEpe2lmKCFkYXRhfHxkYXRhLm9rIT09dHJ1ZXx8ZGF0YS5zcHJlYWRzaGVldElkIT09JzF6REpTcVhYdjlMakRzdkVia0pKMFUtSHVfTk9zQVZSMVFER0VCVUtjNWFBJ3x8IUFycmF5LmlzQXJyYXkoZGF0YS5zb3VyY2VzKSl0aHJvdyBFcnJvcignRGUgc2VydmVyIGdhZiBnZWVuIGdlbGRpZ2UgZ2VnZXZlbnMgdmFuIGRlemUgb250d2lra2Vsc2hlZXQgdGVydWcuJyk7Y29uc3QgaWRzPW5ldyBTZXQoKTtmb3IoY29uc3Qgc3JjIG9mIGRhdGEuc291cmNlcyl7aWYodHlwZW9mIHNyYy5uYW1lIT09J3N0cmluZyd8fCFBcnJheS5pc0FycmF5KHNyYy5pdGVtcykpdGhyb3cgRXJyb3IoJ0VlbiB0YWJibGFkIG1pc3QgZWVuIG5hYW0gb2YgemlubmVuLicpO2NvbnN0IGlkPXNvdXJjZUtleShzcmMpO2lmKGlkcy5oYXMoaWQpKXRocm93IEVycm9yKCdEdWJiZWwgdGFiYmxhZC1pZCBvbnR2YW5nZW4uJyk7aWRzLmFkZChpZCk7Zm9yKGNvbnN0IGl0ZW0gb2Ygc3JjLml0ZW1zKXtpZighaXRlbXx8dHlwZW9mIGl0ZW0udGV4dCE9PSdzdHJpbmcnfHwhaXRlbS50ZXh0LnRyaW0oKSl0aHJvdyBFcnJvcignRWVuIHRhYmJsYWQgYmV2YXQgZWVuIG9uZ2VsZGlnIHppbnJlY29yZC4nKX19cmV0dXJuIGRhdGF9CmZ1bmN0aW9uIGFkb3B0U2hlZXREYXRhKGRhdGEpe3ZhbGlkYXRlU2hlZXREYXRhKGRhdGEpO2NvbnN0IHByZXZpb3VzPWNhcHR1cmVWaWV3KCk7T1JJR0lOQUw9ZGF0YS5zb3VyY2VzO3JlZnJlc2hDYXRlZ29yeU9wdGlvbnMoKTskKCdzb3VyY2VSZWFkZXInKS5oaWRkZW49dHJ1ZTtTT1VSQ0VTPWxpYnJhcmllcygpLmZpbHRlcihzcmM9PiFXRUJTSVRFX1NPVVJDRVMuaW5jbHVkZXMoc3JjKSk7c3RhdGUuc2VsZWN0ZWQ9bmV3IFNldCgpO3N0YXRlLmN1cnJlbnQuY2xlYXIoKTtTT1VSQ0VTLmZvckVhY2goKHNyYyxpKT0+e2lmKHByZXZpb3VzLnNlbGVjdGVkLmluY2x1ZGVzKHNvdXJjZUtleShzcmMpKXx8IXByZXZpb3VzLmN1cnJlbnQuc29tZSh4PT54LmtleT09PXNvdXJjZUtleShzcmMpKSlzdGF0ZS5zZWxlY3RlZC5hZGQoaSk7Y29uc3Qgb2xkPXByZXZpb3VzLmN1cnJlbnQuZmluZCh4PT54LmtleT09PXNvdXJjZUtleShzcmMpKTtpZihvbGQpe2NvbnN0IGZvdW5kPXNyYy5pdGVtcy5maW5kSW5kZXgoaXRlbT0+aXRlbS50ZXh0PT09b2xkLnRleHQmJihpdGVtLmF1dGhvcnx8JycpPT09b2xkLmF1dGhvcik7aWYoZm91bmQ+PTApc3RhdGUuY3VycmVudC5zZXQoaSxmb3VuZCl9fSk7YXBwbHlRdW90ZUZpbHRlcnModHJ1ZSk7c2hvd1RvcGljcygnQScpO2NvbnN0IHdoZW49bmV3IERhdGUoZGF0YS5mZXRjaGVkQXQpO2NvbnN0IGRhdGU9TnVtYmVyLmlzTmFOKHdoZW4uZ2V0VGltZSgpKT8nem9qdWlzdCc6d2hlbi50b0xvY2FsZVN0cmluZygnbmwtTkwnLHt0aW1lWm9uZTonRXVyb3BlL0Ftc3RlcmRhbSd9KTtzZXRMaXZlU3RhdHVzKCdWNy4xIMK3IExpdmUgdWl0IEdvb2dsZSBTaGVldHM6ICcrT1JJR0lOQUwubGVuZ3RoKycgdGFiYmxhZGVuIMK3ICcrT1JJR0lOQUwucmVkdWNlKChuLHNyYyk9Pm4rc3JjLml0ZW1zLmxlbmd0aCwwKS50b0xvY2FsZVN0cmluZygnbmwtTkwnKSsnIHppbm5lbiDCtyBpbmdlbGV6ZW4gJytkYXRlLCdsaXZlJyl9CmZ1bmN0aW9uIHJlZnJlc2hTaGVldChzaWxlbnQpe2lmKGxpdmVCdXN5KXJldHVybjtpZighaGFzU2hlZXRCcmlkZ2Upe3NldExpdmVTdGF0dXMoJ0dlZW4gdmVyYmluZGluZzogb3BlbiBkZSBBcHBzIFNjcmlwdC13ZWJhcHAgbWV0IENvZGUuZ3MgZW4gaW5kZXguIERlemUgSFRNTCBiZXZhdCBnZWVuIGluZ2Vib3V3ZGUgc2hlZXRkYXRhLicsJ2Vycm9yJyk7JCgnbGl2ZUhlbHAnKS5vcGVuPXRydWU7cmV0dXJufWxpdmVCdXN5PXRydWU7JCgncmVsb2FkU2hlZXQnKS5kaXNhYmxlZD10cnVlO3NldExpdmVTdGF0dXMoJ0FsbGUgdGFiYmxhZGVuIGVuIGluZ2V2dWxkZSB6aW5uZW4gdWl0IGRlIHNoZWV0IHdvcmRlbiBpbmdlbGV6ZW7igKYnLCdsb2FkaW5nJyk7Y29uc3QgdGltZW91dD1zZXRUaW1lb3V0KCgpPT5mYWlsKEVycm9yKCdIZXQgbGV6ZW4gZHV1cnQgdGUgbGFuZy4gUHJvYmVlciBvcG5pZXV3OyBqZSBodWlkaWdlIGJyb25uZW4gYmxpanZlbiBzdGFhbi4nKSksOTAwMDApO2xldCBzZXR0bGVkPWZhbHNlO2Z1bmN0aW9uIGRvbmUoKXtpZihzZXR0bGVkKXJldHVybiBmYWxzZTtzZXR0bGVkPXRydWU7Y2xlYXJUaW1lb3V0KHRpbWVvdXQpO2xpdmVCdXN5PWZhbHNlOyQoJ3JlbG9hZFNoZWV0JykuZGlzYWJsZWQ9ZmFsc2U7cmV0dXJuIHRydWV9ZnVuY3Rpb24gZmFpbChlcnJvcil7aWYoIWRvbmUoKSlyZXR1cm47c2V0TGl2ZVN0YXR1cygnU2hlZXQgbmlldCB2ZXJuaWV1d2Q6ICcrU3RyaW5nKGVycm9yPy5tZXNzYWdlfHxlcnJvcikrJy4gRGUgbGFhdHN0IGdlbGFkZW4gYnJvbm5lbiBibGlqdmVuIGJlc2NoaWtiYWFyLicsJ2Vycm9yJyk7aWYoIXNpbGVudClub3RpZnkoJ0tvcHBlbGluZyBuaWV0IHZlcm5pZXV3ZC4gQmVraWprIGRlIG1lbGRpbmcgYmlqIEdvb2dsZSBTaGVldHMuJyl9dHJ5e2dvb2dsZS5zY3JpcHQucnVuLndpdGhTdWNjZXNzSGFuZGxlcihkYXRhPT57aWYoc2V0dGxlZClyZXR1cm47dHJ5e2Fkb3B0U2hlZXREYXRhKGRhdGEpO2RvbmUoKTtpZighc2lsZW50KW5vdGlmeSgnQWxsZSAnK09SSUdJTkFMLmxlbmd0aCsnIHRhYmJsYWRlbiB1aXQgZGUgc2hlZXQgaW5nZWxlemVuLicpfWNhdGNoKGVycm9yKXtmYWlsKGVycm9yKX19KS53aXRoRmFpbHVyZUhhbmRsZXIoZmFpbCkuZ2V0TExMRGF0YSgpfWNhdGNoKGVycm9yKXtmYWlsKGVycm9yKX19CiQoJ3JlbG9hZFNoZWV0Jykub25jbGljaz0oKT0+cmVmcmVzaFNoZWV0KGZhbHNlKTsKJCgnYXV0b1N5bmMnKS5kaXNhYmxlZD0haGFzU2hlZXRCcmlkZ2U7CiQoJ2F1dG9TeW5jJykub25jaGFuZ2U9KCk9PntpZihzeW5jVGltZXIpY2xlYXJJbnRlcnZhbChzeW5jVGltZXIpO3N5bmNUaW1lcj0kKCdhdXRvU3luYycpLmNoZWNrZWQmJmhhc1NoZWV0QnJpZGdlP3NldEludGVydmFsKCgpPT57aWYoIWRvY3VtZW50LmhpZGRlbilyZWZyZXNoU2hlZXQodHJ1ZSl9LDEyMDAwMCk6bnVsbH07CiQoJ2JvYXJkTGF5b3V0Jykub25jaGFuZ2U9KCk9PnskKCdib2FyZCcpLmNsYXNzTGlzdC50b2dnbGUoJ2dyaWRMYXlvdXQnLCQoJ2JvYXJkTGF5b3V0JykudmFsdWU9PT0nZ3JpZCcpfTsKcmVmcmVzaENhdGVnb3J5T3B0aW9ucygpOwokKCdxTW9kZScpLnZhbHVlPSdhbGwnOwphcHBseVF1b3RlRmlsdGVycygpOwpyZWZyZXNoU2hlZXQodHJ1ZSk7Cgp9KSgpOwo=';

    var binary = atob(encoded);

    var bytes = new Uint8Array(binary.length);

    for (var i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);

    var source = new TextDecoder('utf-8', {fatal: true}).decode(bytes);

    var client = document.createElement('script');

    client.textContent = source;

    document.body.appendChild(client);

  } catch (error) {

    status.textContent = 'De client kon niet worden geladen: ' + String(error.message || error);

    status.setAttribute('data-state', 'error');

  }

})();

</script>

</body></html>


Code gs

/*

BESTAND: Code.gs

APP: i Let Go v2 LLL GODOGOOD Script

VERSIE: v2 · codebasis V7

DATUM:TIJD: 2026-10-06 09:05:55 Europe/Amsterdam

PROJECT: i Let Go v2 LLL GODOGOOD Script

SET: ⌘  by Gabeler.eu GODOGOOD.eu ⌘

KOPPELFILE: index.html

BASIS: LLL Quotes System V7 · directe HTML-uitvoer en live sheetlezer

FIX: Index blijft direct openen; V7-client leest de volledige ontwikkelsheet asynchroon.

*/

const LLL_SHEET_CONFIG = Object.freeze({

 spreadsheetId: '1zDJSqXXv9LjDsvEbkJJ0U-Hu_NOsAVR1QDGEBUKc5aA',

 htmlFile: 'index',

 title: 'LLL Quotes System · Stijn Gabeler',

 version: '7.0-safe-client'

});


function doGet() {

 // Render the page first; read all sheet tabs asynchronously from the browser.

 try {

   return HtmlService.createHtmlOutputFromFile('index')

     .setTitle(LLL_SHEET_CONFIG.title)

     .addMetaTag('viewport', 'width=device-width, initial-scale=1, viewport-fit=cover')

     .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);

 } catch (error) {

   const message = String(error.message || error).replace(/&/g, '&amp;')

     .replace(/</g, '&lt;').replace(/>/g, '&gt;');

   return HtmlService.createHtmlOutput('<!doctype html><html lang="nl"><meta charset="utf-8"><title>LLL laden mislukt</title><body style="font-family:Arial;padding:24px"><h1>LLL Quotes System</h1><p>Het HTML-bestand kon niet worden geopend.</p><pre>' + message + '</pre><p>Gebruik de volledige V7 Code.gs en het HTML-bestand met exact de naam index.</p></body></html>');

 }

}


/** Wordt door index.html aangeroepen via google.script.run. Geen cache. */

function getLLLData() {

 const book = SpreadsheetApp.openById(LLL_SHEET_CONFIG.spreadsheetId);

 const sources = book.getSheets().map(function(sheet) {

   const rowCount = sheet.getLastRow();

   const columnCount = sheet.getLastColumn();

   const rows = rowCount && columnCount

     ? sheet.getRange(1, 1, rowCount, columnCount).getDisplayValues()

     : [];

   return lllReadSource_(sheet.getName(), sheet.getSheetId(), rows);

 });

 return {

   ok: true,

   version: LLL_SHEET_CONFIG.version,

   spreadsheetId: book.getId(),

   spreadsheetUrl: book.getUrl(),

   title: book.getName(),

   fetchedAt: new Date().toISOString(),

   sheetCount: sources.length,

   totalItems: sources.reduce(function(n, s) { return n + s.items.length; }, 0),

   sources: sources

 };

}


/** Houd de eerste zin van een tab zonder kopregel altijd intact. */

function lllReadSource_(name, sheetId, rows) {

 const aliases = {

   text: ['quote', 'quotes', 'text', 'tekst', 'zin', 'zinnen', 'bericht', 'message', 'sentence', 'vraag', 'antwoord'],

   author: ['author', 'auteur', 'schrijver'],

   tags: ['category', 'categorie', 'categories', 'tags', 'trefwoorden', 'rubriek'],

   url: ['source_url', 'sourceurl', 'bronlink', 'url', 'link'],

   language: ['language', 'taal'],

   metadata: ['metadata', 'meta', 'toelichting', 'notitie']

 };

 const first = (rows[0] || []).map(lllHeader_);

 const columns = {};

 Object.keys(aliases).forEach(function(key) {

   columns[key] = first.findIndex(function(label) { return aliases[key].indexOf(label) !== -1; });

 });

 const hasHeader = columns.text !== -1;

 const items = [];

 rows.forEach(function(row, index) {

   if (hasHeader && index === 0) return;

   const raw = row.map(function(v) { return String(v == null ? '' : v).trim(); });

   let text;

   let author = '';

   let tags = name;

   let url = '';

   let language = '';

   let extraMeta = '';

   if (hasHeader) {

     text = raw[columns.text] || '';

     author = columns.author < 0 ? '' : raw[columns.author] || '';

     const category = columns.tags < 0 ? '' : raw[columns.tags] || '';

     tags = [category, name].filter(Boolean).join(', ');

     url = columns.url < 0 ? '' : raw[columns.url] || '';

     language = columns.language < 0 ? '' : raw[columns.language] || '';

     const used = Object.keys(columns).map(function(key) { return columns[key]; });

     extraMeta = raw.filter(function(value, ci) { return value && used.indexOf(ci) === -1; }).join(' · ');

     if (columns.metadata >= 0 && raw[columns.metadata]) {

       extraMeta = [raw[columns.metadata], extraMeta].filter(Boolean).join(' · ');

     }

   } else {

     text = raw.find(function(v) { return Boolean(v); }) || '';

     const ci = raw.indexOf(text);

     extraMeta = raw.filter(function(v, index) { return v && index !== ci; }).join(' · ');

   }

   if (!text) return;

   if (!/^https?:\/\//i.test(url)) url = '';

   const meta = [author, tags, extraMeta, url ? 'Bron: ' + url : ''].filter(Boolean).join(' · ');

   items.push({

     text: text, author: author, tags: tags, url: url, language: language,

     meta: meta, origin: 'Google Sheets', sheetId: sheetId, row: index + 1,

     id: String(sheetId) + ':' + String(index + 1)

   });

 });

 const width = rows.reduce(function(n, row) { return Math.max(n, row.length); }, 0);

 const labels = Array.from({length: width}, function(_, i) {

   return hasHeader ? String(rows[0][i] || 'Kolom ' + (i + 1)) : 'Kolom ' + (i + 1);

 });

 const displayRows = rows.map(function(row, i) {

   return {row: i + 1, cells: Array.from({length: width}, function(_, ci) { return String(row[ci] == null ? '' : row[ci]); })};

 }).filter(function(row, i) { return (!hasHeader || i > 0) && row.cells.some(function(cell) { return cell.trim(); }); });

 return {name: name, id: String(sheetId), sheetId: sheetId, origin: 'Google Sheets', columns: labels, rows: displayRows, items: items};

}


function lllHeader_(value) {

 return String(value == null ? '' : value).trim().toLowerCase()

   .normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/\s+/g, '_');

}



v1 Site, Sheet, Script

002 Site, Sheet, Script

Google Sites
Report abuse
Page details
Page updated
Google Sites
Report abuse