{"id":13171,"date":"2026-05-19T15:00:20","date_gmt":"2026-05-19T13:00:20","guid":{"rendered":"https:\/\/geopard.tech\/?page_id=13171"},"modified":"2026-05-19T15:59:18","modified_gmt":"2026-05-19T13:59:18","slug":"lineas-de-orientacion","status":"publish","type":"page","link":"https:\/\/geopard.tech\/es\/guidance-lines\/","title":{"rendered":"Simulador de l\u00edneas de gu\u00eda"},"content":{"rendered":"\n<div class=\"gp-lead\">\n<style>\n.gp-lead{font-family:var(--wp--preset--font-family--nunito,\"Nunito\",system-ui,-apple-system,Segoe UI,sans-serif);color:#212121;max-width:1080px;margin:0 auto;padding:0 8px}\n.gp-lead h1{font-family:var(--wp--preset--font-family--poppins,\"Poppins\",system-ui,sans-serif);font-weight:800;color:#0e3a1c;line-height:1.15;letter-spacing:-0.018em;margin:0 0 12px;font-size:1.95rem;max-width:820px}\n.gp-lead h1 .accent{background:linear-gradient(120deg,#f76a0c 0%,#15701e 100%);-webkit-background-clip:text;background-clip:text;color:transparent}\n.gp-lead .gpl-hero{position:relative;background:radial-gradient(900px 360px at 0% -10%,rgba(74,222,128,0.18),transparent 60%),radial-gradient(700px 320px at 105% 110%,rgba(247,106,12,0.10),transparent 60%),linear-gradient(180deg,#fbfcf6 0%,#f1f6e8 100%);border:1px solid #d6e2c5;border-radius:20px;padding:26px 30px 22px;margin:6px 0 24px;overflow:hidden;box-shadow:0 12px 32px rgba(20,83,40,0.06),0 0 0 1px rgba(255,255,255,0.55) inset}\n.gp-lead .gpl-hero-eyebrow{display:inline-flex;align-items:center;gap:8px;font-family:var(--wp--preset--font-family--poppins,\"Poppins\",sans-serif);font-size:.74rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:#15701e;background:#fff;border:1px solid #cfe4d4;border-radius:999px;padding:6px 12px;margin:0 0 14px;box-shadow:0 1px 2px rgba(20,83,40,0.05)}\n.gp-lead .gpl-hero-eyebrow::before{content:\"\";width:7px;height:7px;border-radius:50%;background:#22c55e;box-shadow:0 0 0 3px rgba(34,197,94,0.22)}\n.gp-lead .gpl-hero .lede{font-size:1.02rem;line-height:1.55;color:#243024;margin:0;max-width:820px;font-weight:400}\n.gp-lead .gpl-hero .lede strong{color:#0e3a1c;font-weight:600}\n.gp-lead .gpl-hero-features{display:flex;flex-wrap:wrap;gap:8px;margin:18px 0 0}\n.gp-lead .gpl-hero-feat{display:inline-flex;align-items:center;gap:8px;background:#fff;border:1px solid #d8e6d8;color:#1c4a2a;font-size:.86rem;font-weight:600;padding:6px 12px;border-radius:999px;font-family:var(--wp--preset--font-family--poppins,\"Poppins\",sans-serif);box-shadow:0 1px 2px rgba(20,83,40,0.04)}\n.gp-lead .gpl-hero-feat::before{content:\"\\2713\";width:16px;height:16px;flex:0 0 16px;background:#22c55e;color:#fff;border-radius:50%;font-size:10px;font-weight:800;line-height:16px;text-align:center}\n.gp-lead .gpl-hero-feat.is-trust{background:transparent;border-color:transparent;color:#3a4a3a;padding:6px 4px;box-shadow:none}\n.gp-lead .gpl-hero-feat.is-trust::before{content:\"\\1F512\";width:auto;height:auto;background:transparent;color:#15701e;font-size:13px;line-height:1}\n@media (max-width:760px){\n  .gp-lead .gpl-hero{padding:20px 18px;margin:4px 0 16px;border-radius:16px}\n  .gp-lead .gpl-hero-eyebrow{font-size:.66rem;letter-spacing:.12em;padding:5px 10px;margin-bottom:10px}\n  .gp-lead h1{font-size:1.35rem;line-height:1.2;margin-bottom:8px}\n  .gp-lead .gpl-hero .lede{font-size:.95rem;line-height:1.5}\n  .gp-lead .gpl-hero-features{gap:6px;margin-top:12px}\n  .gp-lead .gpl-hero-feat{font-size:.78rem;padding:5px 10px}\n}\n<\/style>\n<section class=\"gpl-hero\">\n  <div class=\"gpl-hero-eyebrow\">Guidance Lines Simulator \u00b7 Free \u00b7 No signup<\/div>\n  <h1>Plan your tractor path. Find the <span class=\"accent\">lowest-fuel, highest-coverage<\/span> drive plan for your field.<\/h1>\n  <p class=\"lede\">Compare AB Straight, AB Curve, Boundary Follow, and Contour-follow side by side. See <strong>coverage %, turnarounds, fuel, slope cost<\/strong>, then watch the full playback. Drop your own boundary (GeoJSON \/ KML \/ shapefile) or try one of four sample fields.<\/p>\n  <div class=\"gpl-hero-features\">\n    <span class=\"gpl-hero-feat\">4 approaches scored<\/span>\n    <span class=\"gpl-hero-feat\">Slope-aware fuel<\/span>\n    <span class=\"gpl-hero-feat\">Coverage rasteriser<\/span>\n    <span class=\"gpl-hero-feat\">Drop your own field<\/span>\n    <span class=\"gpl-hero-feat is-trust\">Data stays in your browser<\/span>\n  <\/div>\n<\/section>\n<\/div>\n\n\n\n<div class=\"gpl-wrap\" id=\"gpl-root\">\n<style>\n.gpl-wrap{all:initial;display:block;font-family:\"Nunito\",system-ui,-apple-system,sans-serif;font-size:13px;line-height:1.45;color:#212121;background:#fafbf4;border:1px solid #eeeeee;border-radius:12px;overflow:hidden;max-width:100%;box-shadow:0 4px 20px rgba(20,83,40,.05)}\n.gpl-wrap *,.gpl-wrap *::before,.gpl-wrap *::after{box-sizing:border-box}\n.gpl-wrap .gpl-top{display:flex;align-items:center;justify-content:space-between;padding:14px 18px;border-bottom:1px solid #eeeeee;background:#ffffff;gap:16px;flex-wrap:wrap}\n.gpl-wrap .gpl-brand{display:flex;align-items:center;gap:12px;min-width:0;flex:1}\n.gpl-wrap .gpl-logo{width:28px;height:28px;border-radius:7px;background:linear-gradient(135deg,#145328 0%,#1a7951 100%);display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700;font-size:14px;flex:none}\n.gpl-wrap .gpl-h1{font-size:15px;font-weight:600;letter-spacing:-.01em;font-family:\"Poppins\",system-ui,sans-serif}\n.gpl-wrap .gpl-chip{display:inline-flex;align-items:center;gap:6px;font-family:\"DM Mono\",ui-monospace,monospace;font-size:11px;padding:2px 8px;border-radius:10px;background:#fafbf4;color:#4c6066;border:1px solid #eeeeee;margin-top:3px}\n.gpl-wrap .gpl-chip .gpl-dot{width:6px;height:6px;border-radius:50%;background:#15701e;flex:none}\n.gpl-wrap .gpl-cta{background:#15701e;color:#fff;border:0;padding:9px 14px;border-radius:7px;font-weight:600;font-size:13px;cursor:pointer;font-family:inherit;display:inline-flex;align-items:center;gap:7px;text-decoration:none;transition:background .15s}\n.gpl-wrap .gpl-cta:hover{background:#1b7a2a}\n.gpl-wrap .gpl-grid{display:grid;grid-template-columns:var(--gpl-left-w,200px) 5px 1fr 240px;grid-template-areas:\"left splitter main right\";min-height:600px}\n.gpl-wrap .gpl-side{grid-area:left;background:#ffffff;border-right:1px solid #eeeeee;padding:10px 8px;display:flex;flex-direction:column;gap:7px;min-width:0;overflow-y:auto}\n.gpl-wrap .gpl-splitter{grid-area:splitter;background:transparent;cursor:col-resize;position:relative;user-select:none;-webkit-user-select:none;touch-action:none}\n.gpl-wrap .gpl-splitter::before{content:\"\";position:absolute;left:50%;top:50%;width:1px;height:34px;transform:translate(-50%,-50%);background:#dddddd;transition:background .15s,width .15s}\n.gpl-wrap .gpl-splitter:hover::before,.gpl-wrap .gpl-splitter.is-drag::before{background:#15701e;width:3px;border-radius:2px;height:48px}\n.gpl-wrap .gpl-main{grid-area:main;position:relative;background:#fafbf4}\n.gpl-wrap .gpl-side-right{grid-area:right;background:#ffffff;border-left:1px solid #eeeeee;padding:10px 8px;display:flex;flex-direction:column;gap:7px;min-width:0;overflow-y:auto}\n@media (max-width:1099px){\n  .gpl-wrap .gpl-grid{grid-template-columns:var(--gpl-left-w,180px) 5px 1fr 220px}\n}\n.gpl-wrap .gpl-canvas{display:block;width:100%;height:100%;cursor:default;background:#fafbf4}\n.gpl-wrap .gpl-card h3{font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:#4c6066;margin:0 0 4px 0;font-family:\"Poppins\",system-ui,sans-serif}\n.gpl-wrap .gpl-card{display:flex;flex-direction:column;gap:4px;padding:0}\n.gpl-wrap .gpl-approach{display:flex;flex-direction:column;gap:3px}\n.gpl-wrap .gpl-approach label{display:flex;align-items:center;gap:5px;padding:5px 7px;border:1px solid #eeeeee;border-radius:5px;cursor:pointer;background:#ffffff;font-size:12px;transition:all .12s;min-height:32px;line-height:1.15}\n.gpl-wrap .gpl-approach label:hover{border-color:#1b7a2a;background:#fafbf4}\n.gpl-wrap .gpl-approach input[type=radio]{accent-color:#15701e;width:16px;height:16px;margin:0}\n.gpl-wrap .gpl-approach label.is-on{border-color:#15701e;background:#fafbf4;font-weight:600}\n.gpl-wrap .gpl-reco{display:none;font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:#15701e;background:#dff5e6;padding:2px 6px;border-radius:4px;margin-left:auto;font-family:\"DM Mono\",ui-monospace,monospace}\n.gpl-wrap .gpl-reco.is-on{display:inline-block}\n.gpl-wrap .gpl-input-row{display:flex;align-items:center;gap:5px}\n.gpl-wrap .gpl-input-row label{font-size:11px;color:#4c6066;flex:1}\n.gpl-wrap .gpl-input-row input{width:54px;padding:4px 6px;border:1px solid #eeeeee;border-radius:4px;font-family:inherit;font-size:13px;text-align:right;min-height:28px}\n.gpl-wrap .gpl-input-row .gpl-unit{font-size:10px;color:#4c6066;width:26px}\n.gpl-wrap .gpl-results{display:flex;flex-direction:column;gap:2px;font-family:\"DM Mono\",ui-monospace,monospace;font-size:11px;background:#fafbf4;padding:6px 8px;border-radius:5px;border:1px solid #eeeeee}\n.gpl-wrap .gpl-r-row{display:flex;justify-content:space-between;align-items:baseline;padding:1px 0}\n.gpl-wrap .gpl-r-k{color:#4c6066;font-size:10px}\n.gpl-wrap .gpl-r-v{font-weight:600;color:#212121;font-size:12px}\n.gpl-wrap .gpl-r-savings{font-size:11px;font-weight:600}\n.gpl-wrap .gpl-r-row.gpl-r-pri{border-top:1px solid #eeeeee;padding-top:6px;margin-top:2px}\n.gpl-wrap .gpl-cmp{margin-top:6px;background:#ffffff;border:1px solid #eeeeee;border-radius:6px;overflow:hidden}\n.gpl-wrap .gpl-cmp-row{display:grid;grid-template-columns:1fr 42px 50px 50px;align-items:center;padding:6px 8px;font-size:11px;border-bottom:1px solid #f5f3eb;gap:4px}\n.gpl-wrap .gpl-cmp-row:last-child{border-bottom:0}\n.gpl-wrap .gpl-cmp-row.gpl-cmp-head{font-weight:600;color:#4c6066;text-transform:uppercase;letter-spacing:.04em;font-size:10px;background:#fafbf4}\n.gpl-wrap .gpl-cmp-name{font-family:\"DM Mono\",ui-monospace,monospace}\n.gpl-wrap .gpl-cmp-val{text-align:right;font-family:\"DM Mono\",ui-monospace,monospace}\n.gpl-wrap .gpl-cmp-row.gpl-cmp-current{background:#fafbf4}\n.gpl-wrap .gpl-unit-toggle{display:inline-flex;gap:2px;background:#fafbf4;border:1px solid #eeeeee;border-radius:6px;padding:2px;margin-bottom:5px;align-self:flex-start}\n.gpl-wrap .gpl-unit-tab{background:transparent;border:0;padding:3px 8px;font-size:10px;font-family:\"DM Mono\",ui-monospace,monospace;font-weight:700;color:#4c6066;cursor:pointer;border-radius:4px;min-width:28px}\n.gpl-wrap .gpl-unit-tab.is-on{background:#15701e;color:#fff}\n.gpl-wrap .gpl-slider-row{display:flex;align-items:center;gap:6px}\n.gpl-wrap .gpl-range{flex:1;accent-color:#15701e;min-height:24px}\n.gpl-wrap .gpl-slider-val{font-family:\"DM Mono\",ui-monospace,monospace;font-size:10px;color:#4c6066;min-width:90px;text-align:right}\n.gpl-wrap .gpl-select-row{display:flex;flex-direction:column;gap:2px}\n.gpl-wrap .gpl-select-row label{font-size:10px;color:#4c6066}\n.gpl-wrap .gpl-select-row select{padding:4px 6px;border:1px solid #eeeeee;border-radius:4px;font-family:inherit;font-size:12px;background:#ffffff;min-height:32px}\n.gpl-wrap .gpl-cur-sel{margin-left:4px;padding:4px 6px;border:1px solid #eeeeee;border-radius:5px;font-family:inherit;font-size:11px;background:#ffffff;min-height:32px;width:46px}\n.gpl-wrap .gpl-hint{font-size:9px;color:#4c6066;font-family:\"DM Mono\",ui-monospace,monospace;margin:-1px 0 2px 0;line-height:1.3;font-style:italic}\n.gpl-wrap .gpl-field-picker{display:grid;grid-template-columns:1fr 1fr;gap:3px}\n.gpl-wrap .gpl-fld{background:#ffffff;border:1px solid #eeeeee;border-radius:5px;padding:4px 5px;font-family:inherit;font-size:10px;font-weight:600;cursor:pointer;color:#212121;display:flex;flex-direction:column;align-items:flex-start;gap:0;text-align:left;transition:all .12s;min-height:34px;line-height:1.1}\n.gpl-wrap .gpl-fld:hover{border-color:#1b7a2a;background:#fafbf4}\n.gpl-wrap .gpl-fld.is-on{border-color:#15701e;background:#fafbf4;font-weight:700}\n.gpl-wrap .gpl-fld-sub{font-size:8px;color:#4c6066;font-weight:500;font-style:italic;text-transform:none;letter-spacing:0}\n.gpl-wrap .gpl-upload{display:flex;align-items:center;justify-content:center;gap:5px;background:#fafbf4;color:#15701e;border:1px dashed #b8e5c6;padding:5px 8px;border-radius:5px;font-family:inherit;font-size:10px;font-weight:600;cursor:pointer;min-height:30px;margin-top:2px;transition:all .12s}\n.gpl-wrap .gpl-upload:hover{background:#e9f3ec;border-color:#15701e;border-style:solid}\n.gpl-wrap .gpl-upload-ico{font-size:13px;line-height:1}\n.gpl-wrap .gpl-upload.is-error{color:#dc2626;border-color:#fca5a5;background:#fef2f2}\n.gpl-wrap .gpl-upload.is-success{color:#15701e;background:#dff5e6;border-color:#15701e;border-style:solid}\n.gpl-wrap .gpl-import-nav{display:flex;align-items:center;gap:6px;margin-top:3px;justify-content:center}\n.gpl-wrap .gpl-imp-btn{width:28px;height:28px;background:#fafbf4;border:1px solid #d9e7dc;border-radius:5px;color:#15701e;cursor:pointer;font-size:14px;font-weight:700;font-family:inherit;line-height:1;padding:0;transition:all .12s}\n.gpl-wrap .gpl-imp-btn:hover{background:#dff5e6;border-color:#15701e}\n.gpl-wrap .gpl-imp-btn:disabled{opacity:0.35;cursor:not-allowed}\n.gpl-wrap .gpl-imp-lbl{font-family:\"DM Mono\",ui-monospace,monospace;font-size:11px;font-weight:600;color:#4c6066;min-width:60px;text-align:center}\n.gpl-wrap .gpl-ab-auto{background:#fafbf4;color:#15701e;border:1px solid #d9e7dc;padding:4px 8px;border-radius:4px;font-family:inherit;font-size:10px;font-weight:600;cursor:pointer;min-height:26px;transition:all .12s;width:100%;margin-top:1px}\n.gpl-wrap .gpl-ab-auto:hover{background:#e9f3ec;border-color:#15701e}\n.gpl-wrap .gpl-ab-auto.is-auto{background:#dff5e6;border-color:#15701e}\n.gpl-wrap .gpl-warn{position:absolute;top:10px;left:50%;transform:translateX(-50%);background:rgba(247,106,12,0.95);color:#fff;padding:8px 14px;border-radius:8px;font-size:12px;font-weight:600;box-shadow:0 2px 8px rgba(247,106,12,.3);max-width:90%;text-align:center;display:none}\n.gpl-wrap .gpl-warn.is-on{display:block}\n.gpl-wrap .gpl-card-topo{background:linear-gradient(135deg,#fafbf4 0%,#eef4ec 100%);border:1px solid #d9e7dc;border-radius:8px;padding:10px 12px}\n.gpl-wrap .gpl-topo-blurb{font-size:11px;line-height:1.45;color:#4c6066;margin:0 0 8px 0}\n.gpl-wrap .gpl-cta-mini{display:inline-flex;align-items:center;gap:5px;background:#15701e;color:#fff;text-decoration:none;padding:7px 11px;border-radius:6px;font-size:12px;font-weight:600;font-family:inherit;transition:background .15s;min-height:44px;line-height:1}\n.gpl-wrap .gpl-cta-mini:hover{background:#1b7a2a}\n.gpl-wrap .gpl-cta-card{background:linear-gradient(145deg,#eefbf3 0%,#dff5e6 100%);border:1px solid #b8e5c6;border-radius:10px;padding:14px;margin-top:auto;position:relative;overflow:hidden}\n.gpl-wrap .gpl-cta-card::before{content:\"\";position:absolute;top:-30px;right:-30px;width:80px;height:80px;background:radial-gradient(circle,rgba(21,112,30,.14) 0%,transparent 70%);pointer-events:none}\n.gpl-wrap .gpl-cta-card h4{font-size:10px;text-transform:uppercase;letter-spacing:.14em;color:#0f5033;margin:0 0 10px 0;font-weight:700;font-family:\"Poppins\",system-ui,sans-serif;position:relative}\n.gpl-wrap .gpl-cta-list{list-style:none;padding:0;margin:0 0 12px 0;font-size:12px;line-height:1.6;position:relative}\n.gpl-wrap .gpl-cta-list li{color:#1e5d3a;display:flex;align-items:flex-start;gap:8px;font-weight:500;margin-bottom:4px}\n.gpl-wrap .gpl-cta-list li::before{content:\"\u2713\";color:#15701e;font-weight:700;flex:none}\n.gpl-wrap .gpl-cta-btn-lg{display:flex;align-items:center;justify-content:center;gap:6px;background:#15701e;color:#fff;text-decoration:none;padding:11px 12px;border-radius:7px;font-weight:700;font-size:13px;font-family:inherit;position:relative;width:100%;transition:background .15s;min-height:44px;box-sizing:border-box}\n.gpl-wrap .gpl-cta-btn-lg:hover{background:#1b7a2a}\n.gpl-wrap .gpl-cta-arr{transition:transform .15s}\n.gpl-wrap .gpl-cta-btn-lg:hover .gpl-cta-arr{transform:translateX(3px)}\n.gpl-wrap .gpl-cta-note{font-size:10px;color:#4c6066;margin:8px 0 0 0;line-height:1.45;text-align:center;font-style:italic}\n.gpl-wrap .gpl-tray{position:absolute;top:60px;left:10px;background:rgba(255,255,255,.95);border:1px solid #eeeeee;border-radius:8px;padding:6px 10px;font-family:\"DM Mono\",ui-monospace,monospace;font-size:11px;color:#4c6066;backdrop-filter:blur(4px);box-shadow:0 2px 6px rgba(0,0,0,.05);z-index:2}\n.gpl-wrap .gpl-pb{position:absolute;top:10px;left:10px;right:10px;background:rgba(255,255,255,.95);border:1px solid #eeeeee;border-radius:8px;padding:7px 10px;display:flex;align-items:center;gap:8px;backdrop-filter:blur(4px);box-shadow:0 2px 6px rgba(0,0,0,.05);z-index:3;flex-wrap:wrap}\n.gpl-wrap .gpl-pb-btn{background:#15701e;color:#fff;border:0;width:32px;height:32px;border-radius:6px;cursor:pointer;font-size:13px;display:flex;align-items:center;justify-content:center;padding:0;font-family:inherit;transition:background .15s;flex:none;line-height:1}\n.gpl-wrap .gpl-pb-btn:hover{background:#1b7a2a}\n.gpl-wrap .gpl-pb-btn.is-playing::before{content:\"\u275a\u275a\";font-size:11px;letter-spacing:-1px}\n.gpl-wrap .gpl-pb-btn.is-playing{font-size:0}\n.gpl-wrap .gpl-pb-track{flex:1;height:8px;background:#fafbf4;border-radius:4px;position:relative;cursor:pointer;min-width:80px;border:1px solid #eeeeee}\n.gpl-wrap .gpl-pb-fill{position:absolute;left:0;top:0;height:100%;background:#15701e;border-radius:3px;pointer-events:none;width:0%}\n.gpl-wrap .gpl-pb-thumb{position:absolute;top:50%;left:0%;transform:translate(-50%,-50%);width:14px;height:14px;background:#15701e;border:2px solid #ffffff;border-radius:50%;pointer-events:none;box-shadow:0 1px 4px rgba(0,0,0,.25)}\n.gpl-wrap .gpl-pb-seg{flex:none;display:flex;gap:2px;padding:2px;background:#fafbf4;border:1px solid #eeeeee;border-radius:6px}\n.gpl-wrap .gpl-pb-spd{padding:4px 7px;font-size:10px;background:transparent;border:0;color:#4c6066;cursor:pointer;border-radius:4px;font-family:\"DM Mono\",ui-monospace,monospace;font-weight:700;min-width:28px;font-family:inherit}\n.gpl-wrap .gpl-pb-spd.on{background:#15701e;color:#fff}\n.gpl-wrap .gpl-pb-stats{flex:none;font-family:\"DM Mono\",ui-monospace,monospace;font-size:10px;color:#4c6066;text-align:right;min-width:130px;line-height:1.3;font-weight:600}\n.gpl-wrap .gpl-scale{position:absolute;left:10px;bottom:10px;background:rgba(255,255,255,.95);border:1px solid #eeeeee;border-radius:6px;padding:4px 8px;font-family:\"DM Mono\",ui-monospace,monospace;font-size:10px;font-weight:600;color:#4c6066;display:flex;align-items:center;gap:6px;backdrop-filter:blur(4px);z-index:3;line-height:1;box-shadow:0 2px 4px rgba(0,0,0,.05)}\n.gpl-wrap .gpl-scale-bar{display:inline-block;width:60px;height:6px;border-left:2px solid #145328;border-right:2px solid #145328;border-bottom:2px solid #145328;box-sizing:border-box}\n.gpl-wrap .gpl-scale-lbl{white-space:nowrap}\n.gpl-wrap .gpl-tools{position:absolute;right:10px;top:60px;display:flex;flex-direction:column;gap:5px;z-index:4}\n.gpl-wrap .gpl-tool-btn{width:36px;height:36px;background:rgba(255,255,255,.95);border:1px solid #eeeeee;border-radius:7px;font-family:inherit;font-size:16px;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;line-height:1;padding:0;color:#4c6066;transition:all .12s;box-shadow:0 2px 4px rgba(0,0,0,.08)}\n.gpl-wrap .gpl-tool-btn svg{width:18px;height:18px;display:block}\n.gpl-wrap .gpl-tool-btn:hover{border-color:#15701e;color:#15701e}\n.gpl-wrap .gpl-tool-btn.is-on{background:#15701e;color:#fff;border-color:#15701e}\n.gpl-wrap .gpl-ruler-hint{position:absolute;left:50%;bottom:14px;transform:translateX(-50%);background:rgba(20,83,40,0.92);color:#fff;padding:7px 12px;border-radius:7px;font-size:11px;font-weight:600;font-family:\"DM Mono\",ui-monospace,monospace;display:none;z-index:3;box-shadow:0 2px 8px rgba(0,0,0,.15)}\n.gpl-wrap .gpl-ruler-hint.is-on{display:block}\n.gpl-wrap .gpl-legend{position:absolute;bottom:10px;left:10px;background:rgba(255,255,255,.95);border:1px solid #eeeeee;border-radius:8px;padding:8px 12px;font-size:11px;display:flex;flex-direction:column;gap:4px;backdrop-filter:blur(4px)}\n.gpl-wrap .gpl-lg-row{display:flex;align-items:center;gap:6px}\n.gpl-wrap .gpl-lg-swatch{width:14px;height:3px;border-radius:2px;flex:none}\n\n@media (max-width: 820px){\n  .gpl-wrap .gpl-grid{grid-template-columns:1fr;grid-template-areas:\"main\" \"right\" \"left\";grid-template-rows:62vh auto auto;min-height:auto}\n  .gpl-wrap .gpl-side{border-right:0;border-top:1px solid #eeeeee;max-height:none;padding:12px 14px;gap:10px}\n  .gpl-wrap .gpl-splitter{display:none}\n  .gpl-wrap .gpl-side-right{border-left:0;border-top:1px solid #eeeeee;max-height:none;padding:12px 14px;gap:10px}\n  .gpl-wrap .gpl-main{min-height:62vh}\n  \/* Bigger cards + tap targets on touch *\/\n  .gpl-wrap .gpl-card h3{font-size:10px}\n  .gpl-wrap .gpl-approach label{min-height:44px;font-size:13px;padding:7px 10px}\n  .gpl-wrap input[type=number],.gpl-wrap select{font-size:14px;min-height:38px}\n  .gpl-wrap .gpl-fld{min-height:44px;font-size:11px;padding:6px 8px}\n  .gpl-wrap .gpl-fld-sub{font-size:9px}\n  .gpl-wrap .gpl-upload{min-height:40px;font-size:11px}\n  .gpl-wrap .gpl-ab-auto{min-height:36px;font-size:11px}\n  .gpl-wrap .gpl-tool-btn{width:40px;height:40px}\n  .gpl-wrap .gpl-tool-btn svg{width:20px;height:20px}\n  .gpl-wrap .gpl-cta-mini,.gpl-wrap .gpl-cta-btn-lg{min-height:44px}\n  .gpl-wrap .gpl-slider-val{font-size:11px;min-width:80px}\n  .gpl-wrap .gpl-range{min-height:32px}\n  \/* Results row font + spacing \u2014 easier to read on phones *\/\n  .gpl-wrap .gpl-results{font-size:12px;padding:8px 10px;gap:3px}\n  .gpl-wrap .gpl-r-k{font-size:11px}\n  .gpl-wrap .gpl-r-v{font-size:13px}\n  \/* Compare All grid \u2014 keep 4 columns but tighter *\/\n  .gpl-wrap .gpl-cmp-row{padding:7px 8px;font-size:11px;grid-template-columns:1fr 38px 46px 46px}\n  \/* Playback strip \u2014 wrap better when narrow *\/\n  .gpl-wrap .gpl-pb{flex-wrap:wrap;padding:6px 8px;gap:6px}\n  .gpl-wrap .gpl-pb-stats{min-width:0;flex-basis:100%;text-align:left;font-size:10px;line-height:1.35;padding-top:2px;border-top:1px dashed #eeeeee}\n  .gpl-wrap .gpl-pb-track{min-width:50px}\n  \/* Tools \u2014 push below the (taller) wrapped playback strip *\/\n  .gpl-wrap .gpl-tools{top:90px}\n  .gpl-wrap .gpl-tray{top:90px;font-size:10px;padding:5px 8px}\n  \/* Legend and scale-bar \u2014 smaller, less in the way on phones *\/\n  .gpl-wrap .gpl-legend{font-size:10px;padding:7px 10px;gap:3px}\n  .gpl-wrap .gpl-scale{font-size:9px;padding:3px 7px}\n  \/* Unit-toggle (km\/mi) tabs \u2014 bigger tap target *\/\n  .gpl-wrap .gpl-unit-tab{padding:5px 12px;font-size:11px;min-height:32px}\n  \/* Field-picker grid \u2014 2\u00d72 still, slightly more breathing room *\/\n  .gpl-wrap .gpl-field-picker{gap:5px}\n}\n@media (max-width: 480px){\n  .gpl-wrap .gpl-main{min-height:58vh}\n  .gpl-wrap .gpl-grid{grid-template-rows:58vh auto auto}\n  .gpl-wrap .gpl-approach label{min-height:44px;font-size:14px}\n  .gpl-wrap input[type=number],.gpl-wrap select{font-size:14px;min-height:40px}\n  .gpl-wrap .gpl-cta-mini,.gpl-wrap .gpl-cta-btn-lg{min-height:44px}\n  .gpl-wrap .gpl-fld{min-height:46px;font-size:12px}\n  .gpl-wrap .gpl-tool-btn{width:42px;height:42px}\n  .gpl-wrap .gpl-tool-btn svg{width:22px;height:22px}\n  .gpl-wrap .gpl-cmp-row{grid-template-columns:1fr 34px 42px 42px;font-size:10.5px}\n  .gpl-wrap .gpl-input-row .gpl-unit{font-size:11px;width:30px}\n  \/* Top bar (header + CTA) \u2014 let the CTA wrap onto its own row on small screens *\/\n  .gpl-wrap .gpl-top{padding:10px 12px;gap:8px}\n  .gpl-wrap .gpl-cta{padding:10px 14px;font-size:13px;min-height:42px}\n  .gpl-wrap .gpl-h1{font-size:14px}\n}\n<\/style>\n\n<div class=\"gpl-top\">\n  <div class=\"gpl-brand\">\n    <div class=\"gpl-logo\">G<\/div>\n    <div>\n      <div class=\"gpl-h1\">Guidance Lines Simulator<\/div>\n      <div class=\"gpl-chip\"><span class=\"gpl-dot\"><\/span><span>Compare 4 approaches \u00b7 fuel + ROI<\/span><\/div>\n    <\/div>\n  <\/div>\n  <a class=\"gpl-cta\" href=\"https:\/\/app.geopard.tech\/signup?utm_source=guidance-lines&#038;utm_medium=wp-embed&#038;utm_campaign=register\" target=\"_blank\" rel=\"noopener\">Run on your field \u2192<\/a>\n<\/div>\n\n<div class=\"gpl-grid\">\n  <aside class=\"gpl-side\">\n    <div class=\"gpl-card\">\n      <h3>Sample field<\/h3>\n      <div class=\"gpl-field-picker\" id=\"gpl-field-picker\">\n        <button type=\"button\" class=\"gpl-fld is-on\" data-field=\"hex\">Hex 27 ha<span class=\"gpl-fld-sub\">irregular hex<\/span><\/button>\n        <button type=\"button\" class=\"gpl-fld\" data-field=\"rect\">Rect 31 ha<span class=\"gpl-fld-sub\">classic Midwest<\/span><\/button>\n        <button type=\"button\" class=\"gpl-fld\" data-field=\"lshape\">L-shape 25 ha<span class=\"gpl-fld-sub\">obstacle \/ hill<\/span><\/button>\n        <button type=\"button\" class=\"gpl-fld\" data-field=\"pivot\">Pivot 28 ha<span class=\"gpl-fld-sub\">irrigation circle<\/span><\/button>\n      <\/div>\n      <label class=\"gpl-upload\" id=\"gpl-upload-lbl\">\n        <input type=\"file\" id=\"gpl-upload\" accept=\".geojson,.json,.kml,.zip,.shp,application\/json,application\/zip,application\/vnd.google-earth.kml+xml\" hidden>\n        <span class=\"gpl-upload-ico\">\u2934<\/span>\n        <span>Upload your field<\/span>\n      <\/label>\n      <div class=\"gpl-hint\" id=\"gpl-upload-hint\">GeoJSON \/ KML \/ Shapefile zip<\/div>\n      <div class=\"gpl-import-nav\" id=\"gpl-import-nav\" hidden>\n        <button type=\"button\" class=\"gpl-imp-btn\" id=\"gpl-imp-prev\" aria-label=\"Previous boundary\">\u2039<\/button>\n        <span class=\"gpl-imp-lbl\" id=\"gpl-imp-lbl\">\u2014 \/ \u2014<\/span>\n        <button type=\"button\" class=\"gpl-imp-btn\" id=\"gpl-imp-next\" aria-label=\"Next boundary\">\u203a<\/button>\n      <\/div>\n    <\/div>\n    <div class=\"gpl-card\">\n      <h3>Approach<\/h3>\n      <div class=\"gpl-approach\" id=\"gpl-approach\">\n        <label class=\"is-on\"><input type=\"radio\" name=\"gpl-ap\" value=\"ab-straight\" checked><span>AB Straight<\/span><span class=\"gpl-reco\" data-reco=\"ab-straight\">Recommended<\/span><\/label>\n        <label><input type=\"radio\" name=\"gpl-ap\" value=\"ab-curve\"><span>AB Curve<\/span><span class=\"gpl-reco\" data-reco=\"ab-curve\">Recommended<\/span><\/label>\n        <label><input type=\"radio\" name=\"gpl-ap\" value=\"boundary\"><span>Boundary Follow<\/span><span class=\"gpl-reco\" data-reco=\"boundary\">Recommended<\/span><\/label>\n        <label><input type=\"radio\" name=\"gpl-ap\" value=\"adaptive\"><span>Contour-follow (terrain)<\/span><span class=\"gpl-reco\" data-reco=\"adaptive\">Recommended<\/span><\/label>\n      <\/div>\n      <div class=\"gpl-hint\" id=\"gpl-reco-hint\">analysing shape\u2026<\/div>\n      <div class=\"gpl-hint\">Contour-follow uses elevation; others ignore it.<\/div>\n    <\/div>\n    <div class=\"gpl-card\">\n      <h3>AB line direction<\/h3>\n      <div class=\"gpl-slider-row\">\n        <input type=\"range\" id=\"gpl-ab-deg\" min=\"0\" max=\"180\" step=\"1\" value=\"0\" class=\"gpl-range\">\n        <span class=\"gpl-slider-val\" id=\"gpl-ab-val\">auto \u00b7 0\u00b0<\/span>\n      <\/div>\n      <button type=\"button\" id=\"gpl-ab-auto\" class=\"gpl-ab-auto\">\u21ba Auto (best fit)<\/button>\n    <\/div>\n    <div class=\"gpl-card\">\n      <h3>Equipment<\/h3>\n      <div class=\"gpl-select-row\">\n        <label for=\"gpl-machine\">Machine<\/label>\n        <select id=\"gpl-machine\">\n          <option value=\"tractor-std\" selected>Tractor + implement (std)<\/option>\n          <option value=\"tractor-large\">Large tractor + planter<\/option>\n          <option value=\"sprayer\">Self-propelled sprayer<\/option>\n          <option value=\"combine\">Combine harvester<\/option>\n          <option value=\"articulated\">Articulated 4WD<\/option>\n          <option value=\"custom\">Custom (manual radius)<\/option>\n        <\/select>\n      <\/div>\n      <div class=\"gpl-input-row\">\n        <label for=\"gpl-wm\">Implement width<\/label>\n        <input type=\"number\" id=\"gpl-wm\" min=\"3\" max=\"60\" step=\"0.5\" value=\"18\">\n        <span class=\"gpl-unit\">m<\/span>\n      <\/div>\n      <div class=\"gpl-input-row\">\n        <label for=\"gpl-cons\">Consumption<\/label>\n        <input type=\"number\" id=\"gpl-cons\" min=\"0.1\" max=\"5\" step=\"0.1\" value=\"0.6\">\n        <span class=\"gpl-unit\">L\/km<\/span>\n      <\/div>\n      <div class=\"gpl-input-row\">\n        <label for=\"gpl-fuel\">Diesel price<\/label>\n        <input type=\"number\" id=\"gpl-fuel\" min=\"0.1\" max=\"3\" step=\"0.05\" value=\"1.20\">\n        <select id=\"gpl-currency\" class=\"gpl-cur-sel\">\n          <option value=\"usd\" selected>$\/L<\/option>\n          <option value=\"eur\">\u20ac\/L<\/option>\n        <\/select>\n      <\/div>\n    <\/div>\n    <div class=\"gpl-card\">\n      <h3>Headland<\/h3>\n      <div class=\"gpl-slider-row\">\n        <input type=\"range\" id=\"gpl-hl-mult\" min=\"0\" max=\"4\" step=\"1\" value=\"1\" class=\"gpl-range\">\n        <span class=\"gpl-slider-val\" id=\"gpl-hl-val\">18 m \u00b7 1\u00d7 pass<\/span>\n      <\/div>\n      <div class=\"gpl-hint\">always = N \u00d7 implement width \u00b7 1\u20132\u00d7 typical<\/div>\n    <\/div>\n    <div class=\"gpl-card\">\n      <h3>Turnarounds<\/h3>\n      <div class=\"gpl-select-row\">\n        <label for=\"gpl-turn-style\">Style<\/label>\n        <select id=\"gpl-turn-style\">\n          <option value=\"uturn\" selected>U-turn (half-circle)<\/option>\n          <option value=\"none\">None \u2014 driver decides<\/option>\n        <\/select>\n      <\/div>\n      <div class=\"gpl-input-row\">\n        <label for=\"gpl-turn-r\">Min turn radius<\/label>\n        <input type=\"number\" id=\"gpl-turn-r\" min=\"2\" max=\"30\" step=\"0.5\" value=\"9\">\n        <span class=\"gpl-unit\">m<\/span>\n      <\/div>\n      <div class=\"gpl-hint\" id=\"gpl-turn-r-hint\">auto \u00b7 std tractor<\/div>\n      <div class=\"gpl-input-row\">\n        <label for=\"gpl-turn-buf\">Outside-boundary buffer<\/label>\n        <input type=\"number\" id=\"gpl-turn-buf\" min=\"0\" max=\"100\" step=\"1\" value=\"0\">\n        <span class=\"gpl-unit\">m<\/span>\n      <\/div>\n    <\/div>\n    <div class=\"gpl-card gpl-card-topo\">\n      <h3>Topography<\/h3>\n      <p class=\"gpl-topo-blurb\">Plan around real elevation, slope and curvature \u2014 drives contour-aware Adaptive paths and prevents erosion.<\/p>\n      <a class=\"gpl-cta-mini\" href=\"https:\/\/app.geopard.tech\/signup?utm_source=guidance-lines&#038;utm_medium=wp-embed&#038;utm_campaign=topography\" target=\"_blank\" rel=\"noopener\">See it in GeoPard \u2192<\/a>\n    <\/div>\n  <\/aside>\n  <div class=\"gpl-splitter\" id=\"gpl-splitter\" aria-label=\"Resize settings panel\" title=\"Drag to resize\"><\/div>\n\n  <main class=\"gpl-main\">\n    <canvas class=\"gpl-canvas\" id=\"gpl-canvas\"><\/canvas>\n    <div class=\"gpl-warn\" id=\"gpl-warn\"><\/div>\n    <div class=\"gpl-tray\" id=\"gpl-tray\">\u2014 ha sample<\/div>\n    <div class=\"gpl-pb\" id=\"gpl-pb\">\n      <button type=\"button\" class=\"gpl-pb-btn\" id=\"gpl-pb-play\" aria-label=\"Play \/ pause\">\u25b6<\/button>\n      <div class=\"gpl-pb-track\" id=\"gpl-pb-track\">\n        <div class=\"gpl-pb-fill\" id=\"gpl-pb-fill\"><\/div>\n        <div class=\"gpl-pb-thumb\" id=\"gpl-pb-thumb\"><\/div>\n      <\/div>\n      <div class=\"gpl-pb-seg\">\n        <button type=\"button\" class=\"gpl-pb-spd on\" data-spd=\"1\">1\u00d7<\/button>\n        <button type=\"button\" class=\"gpl-pb-spd\" data-spd=\"2\">2\u00d7<\/button>\n        <button type=\"button\" class=\"gpl-pb-spd\" data-spd=\"4\">4\u00d7<\/button>\n      <\/div>\n      <div class=\"gpl-pb-stats\" id=\"gpl-pb-stats\">0% \u00b7 0 \/ 0 km<\/div>\n    <\/div>\n    <div class=\"gpl-legend\">\n      <div class=\"gpl-lg-row\"><span class=\"gpl-lg-swatch\" style=\"background:linear-gradient(to right,#6d4fa2 0%,#4ec0a7 25%,#ffe882 50%,#f5a85c 75%,#db5050 100%);width:32px;height:8px;border-radius:2px\"><\/span>Elevation low \u2192 high<\/div>\n      <div class=\"gpl-lg-row\"><span class=\"gpl-lg-swatch\" style=\"background:#145328\"><\/span>Field boundary<\/div>\n      <div class=\"gpl-lg-row\"><span class=\"gpl-lg-swatch\" style=\"background:#f76a0c\"><\/span>Guidance pass<\/div>\n      <div class=\"gpl-lg-row\"><span class=\"gpl-lg-swatch\" style=\"background:rgba(26,121,81,.35)\"><\/span>Headland strip<\/div>\n      <div class=\"gpl-lg-row\"><span class=\"gpl-lg-swatch\" style=\"background:#a21caf\"><\/span>U-turn \/ direction \u2192<\/div>\n      <div class=\"gpl-lg-row\"><span class=\"gpl-lg-swatch\" style=\"background:rgba(162,28,175,.22);width:14px;height:8px\"><\/span>Soil compaction zone<\/div>\n      <div class=\"gpl-lg-row\"><span class=\"gpl-lg-swatch\" style=\"background:rgba(247,106,12,.35);width:14px;height:8px\"><\/span>Swath covered<\/div>\n    <\/div>\n    <div class=\"gpl-scale\" id=\"gpl-scale\"><span class=\"gpl-scale-bar\"><\/span><span class=\"gpl-scale-lbl\" id=\"gpl-scale-lbl\">\u2014 m<\/span><\/div>\n    <div class=\"gpl-tools\">\n      <button type=\"button\" class=\"gpl-tool-btn\" id=\"gpl-tool-zoom-in\" title=\"Zoom in\" aria-label=\"Zoom in\">\n        <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"\/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"\/><\/svg>\n      <\/button>\n      <button type=\"button\" class=\"gpl-tool-btn\" id=\"gpl-tool-zoom-out\" title=\"Zoom out\" aria-label=\"Zoom out\">\n        <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"\/><\/svg>\n      <\/button>\n      <button type=\"button\" class=\"gpl-tool-btn\" id=\"gpl-tool-fit\" title=\"Fit field\" aria-label=\"Fit field\">\n        <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M4 9V5h4M16 5h4v4M20 15v4h-4M8 19H4v-4\"\/><\/svg>\n      <\/button>\n      <button type=\"button\" class=\"gpl-tool-btn\" id=\"gpl-tool-ruler\" title=\"Ruler \u2014 click two points\" aria-label=\"Ruler\">\n        <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M2 14l8-8 12 12-8 8z\"\/><path d=\"M6 10l3 3M10 6l3 3M14 14l3 3M10 18l3-3\"\/><\/svg>\n      <\/button>\n    <\/div>\n    <div class=\"gpl-ruler-hint\" id=\"gpl-ruler-hint\">Click two points on the canvas to measure<\/div>\n  <\/main>\n  <aside class=\"gpl-side-right\" id=\"gpl-side-right\">\n    <div class=\"gpl-card\">\n      <h3>This approach<\/h3>\n      <div class=\"gpl-unit-toggle\" role=\"tablist\">\n        <button type=\"button\" class=\"gpl-unit-tab is-on\" data-unit=\"km\">km<\/button>\n        <button type=\"button\" class=\"gpl-unit-tab\" data-unit=\"mi\">mi<\/button>\n      <\/div>\n      <div class=\"gpl-results\">\n        <div class=\"gpl-r-row\"><span class=\"gpl-r-k\">Field area<\/span><span class=\"gpl-r-v\" id=\"gpl-r-area\">\u2014 ha<\/span><\/div>\n        <div class=\"gpl-r-row gpl-r-pri\"><span class=\"gpl-r-k\">Coverage<\/span><span class=\"gpl-r-v\" id=\"gpl-r-cov\">\u2014 %<\/span><\/div>\n        <div class=\"gpl-r-row\"><span class=\"gpl-r-k\">Passes<\/span><span class=\"gpl-r-v\" id=\"gpl-r-passes\">\u2014<\/span><\/div>\n        <div class=\"gpl-r-row\"><span class=\"gpl-r-k\">Pass length<\/span><span class=\"gpl-r-v\" id=\"gpl-r-len\">\u2014 km<\/span><\/div>\n        <div class=\"gpl-r-row\"><span class=\"gpl-r-k\">Turnarounds<\/span><span class=\"gpl-r-v\" id=\"gpl-r-turns\">\u2014<\/span><\/div>\n        <div class=\"gpl-r-row\"><span class=\"gpl-r-k\">Turn distance<\/span><span class=\"gpl-r-v\" id=\"gpl-r-turnlen\">\u2014 km<\/span><\/div>\n        <div class=\"gpl-r-row gpl-r-pri\"><span class=\"gpl-r-k\">Total drive<\/span><span class=\"gpl-r-v\" id=\"gpl-r-drive\">\u2014 km<\/span><\/div>\n        <div class=\"gpl-r-row\"><span class=\"gpl-r-k\">Avg grade<\/span><span class=\"gpl-r-v\" id=\"gpl-r-grade\">\u2014 %<\/span><\/div>\n        <div class=\"gpl-r-row gpl-r-pri\"><span class=\"gpl-r-k\">Fuel<\/span><span class=\"gpl-r-v\" id=\"gpl-r-fuel\">\u2014 L<\/span><\/div>\n        <div class=\"gpl-r-row\"><span class=\"gpl-r-k\">\u2026turn fuel<\/span><span class=\"gpl-r-v\" id=\"gpl-r-turnfuel\">\u2014 L<\/span><\/div>\n        <div class=\"gpl-r-row\"><span class=\"gpl-r-k\">\u2026slope cost<\/span><span class=\"gpl-r-v\" id=\"gpl-r-slope\">+ 0%<\/span><\/div>\n        <div class=\"gpl-r-row\"><span class=\"gpl-r-k\">Cost<\/span><span class=\"gpl-r-v\" id=\"gpl-r-cost\">$ \u2014<\/span><\/div>\n        <div class=\"gpl-r-row\"><span class=\"gpl-r-k\">vs AB straight<\/span><span class=\"gpl-r-savings\" id=\"gpl-r-sav\">\u2014<\/span><\/div>\n      <\/div>\n    <\/div>\n    <div class=\"gpl-card\">\n      <h3>Compare all<\/h3>\n      <div class=\"gpl-cmp\">\n        <div class=\"gpl-cmp-row gpl-cmp-head\"><span>Approach<\/span><span class=\"gpl-cmp-val\">Cov<\/span><span class=\"gpl-cmp-val\">Fuel<\/span><span class=\"gpl-cmp-val\">$<\/span><\/div>\n        <div class=\"gpl-cmp-row\" data-cmp=\"ab-straight\"><span class=\"gpl-cmp-name\">AB straight<\/span><span class=\"gpl-cmp-val\">\u2014<\/span><span class=\"gpl-cmp-val\">\u2014<\/span><span class=\"gpl-cmp-val\">\u2014<\/span><\/div>\n        <div class=\"gpl-cmp-row\" data-cmp=\"ab-curve\"><span class=\"gpl-cmp-name\">AB curve<\/span><span class=\"gpl-cmp-val\">\u2014<\/span><span class=\"gpl-cmp-val\">\u2014<\/span><span class=\"gpl-cmp-val\">\u2014<\/span><\/div>\n        <div class=\"gpl-cmp-row\" data-cmp=\"boundary\"><span class=\"gpl-cmp-name\">Boundary follow<\/span><span class=\"gpl-cmp-val\">\u2014<\/span><span class=\"gpl-cmp-val\">\u2014<\/span><span class=\"gpl-cmp-val\">\u2014<\/span><\/div>\n        <div class=\"gpl-cmp-row\" data-cmp=\"adaptive\"><span class=\"gpl-cmp-name\">Adaptive<\/span><span class=\"gpl-cmp-val\">\u2014<\/span><span class=\"gpl-cmp-val\">\u2014<\/span><span class=\"gpl-cmp-val\">\u2014<\/span><\/div>\n      <\/div>\n    <\/div>\n    <div class=\"gpl-card\">\n      <h3>Annual ROI<\/h3>\n      <div class=\"gpl-input-row\">\n        <label for=\"gpl-roi-farm\">Farm size<\/label>\n        <input type=\"number\" id=\"gpl-roi-farm\" min=\"1\" max=\"50000\" step=\"1\" value=\"200\">\n        <span class=\"gpl-unit\">ha<\/span>\n      <\/div>\n      <div class=\"gpl-input-row\">\n        <label for=\"gpl-roi-apps\">Applications\/yr<\/label>\n        <input type=\"number\" id=\"gpl-roi-apps\" min=\"1\" max=\"20\" step=\"1\" value=\"4\">\n        <span class=\"gpl-unit\">\u00d7<\/span>\n      <\/div>\n      <div class=\"gpl-results\">\n        <div class=\"gpl-r-row\"><span class=\"gpl-r-k\">Annual fuel saved<\/span><span class=\"gpl-r-v\" id=\"gpl-roi-fuel\">\u2014 L<\/span><\/div>\n        <div class=\"gpl-r-row\"><span class=\"gpl-r-k\">Annual cost saved<\/span><span class=\"gpl-r-v\" id=\"gpl-roi-cost\">$ \u2014<\/span><\/div>\n        <div class=\"gpl-r-row gpl-r-pri\"><span class=\"gpl-r-k\">Per-ha savings<\/span><span class=\"gpl-r-v\" id=\"gpl-roi-perha\">$ \u2014<\/span><\/div>\n      <\/div>\n    <\/div>\n    <div class=\"gpl-cta-card\">\n      <h4>Run on your real field<\/h4>\n      <ul class=\"gpl-cta-list\">\n        <li>Upload boundary + as-applied data<\/li>\n        <li>Edge-aware Adaptive paths from real elevation<\/li>\n        <li>Section-control gap estimates + Rx export<\/li>\n      <\/ul>\n      <a class=\"gpl-cta-btn-lg\" href=\"https:\/\/app.geopard.tech\/signup?utm_source=guidance-lines&#038;utm_medium=wp-embed&#038;utm_campaign=cta-bottom\" target=\"_blank\" rel=\"noopener\">Plan in GeoPard <span class=\"gpl-cta-arr\">\u2192<\/span><\/a>\n      <p class=\"gpl-cta-note\">Pre-calibrated estimates. Field-specific numbers depend on equipment, terrain and topography.<\/p>\n    <\/div>\n  <\/aside>\n<\/div>\n\n<script nowprocket data-no-optimize=\"1\" data-no-defer=\"1\" data-no-minify=\"1\">\n(function(){\n  var root = document.getElementById('gpl-root');\n  if(!root) return;\n  var canvas = document.getElementById('gpl-canvas');\n  var ctx = canvas.getContext('2d');\n  var trayEl = document.getElementById('gpl-tray');\n\n  \/\/ Sample fields \u2014 units are real meters, rendered with a uniform scale fitting\n  \/\/ the canvas. Four shapes cover the common cases: irregular polygon, rectangular\n  \/\/ Midwest section, L-shaped (obstacle \/ hill corner), oval (centre-pivot remnant).\n  var FIELDS = {\n    hex: [\n      { x:  20, y: 220 }, { x:  80, y:  60 }, { x: 290, y:  35 },\n      { x: 580, y:  90 }, { x: 690, y: 240 }, { x: 640, y: 460 },\n      { x: 380, y: 540 }, { x: 130, y: 510 }, { x:  40, y: 380 }\n    ],\n    rect: [\n      { x:  40, y:  60 }, { x: 720, y:  70 }, { x: 730, y: 520 }, { x:  50, y: 510 }\n    ],\n    lshape: [\n      { x:  60, y:  60 }, { x: 440, y:  60 }, { x: 440, y: 280 },\n      { x: 720, y: 280 }, { x: 720, y: 540 }, { x:  60, y: 540 }\n    ],\n    \/\/ Irrigation pivot field \u2014 a true circle drawn by the centre-pivot\n    \/\/ sprinkler. Radius \u2248 300 m gives ~28 ha which matches a typical\n    \/\/ quarter-section pivot (130 m wide, 360\u00b0 coverage, ~32 ha gross \/\n    \/\/ ~28 ha actually wetted).\n    pivot: (function(){\n      var pts = [];\n      var cx = 380, cy = 290, r = 300;\n      for(var i=0; i<28; i++){\n        var t = (i \/ 28) * Math.PI * 2;\n        pts.push({ x: cx + Math.cos(t) * r, y: cy + Math.sin(t) * r });\n      }\n      return pts;\n    })()\n  };\n  var currentField = 'hex';\n  var BOUNDARY = FIELDS[currentField];\n  \/\/ Per-field synthetic elevation. terrain(x, y) \u2192 metres above the field's\n  \/\/ own lowest point. Picked to demonstrate realistic ag scenarios:\n  \/\/   hex     \u2014 east-facing slope, 12 m drop across the field\n  \/\/   rect    \u2014 gentle ridge running diagonally, 15 m peak\n  \/\/   lshape  \u2014 hill at the concave corner (NE), 20 m peak\n  \/\/   pivot   \u2014 single round hill, 18 m peak in centre\n  \/\/   custom  \u2014 flat (no elevation data for uploaded boundaries)\n  \/\/ The functions are deliberately smooth so contour lines look natural.\n  var TERRAIN = {\n    hex: function(x, y){\n      \/\/ Tilted plane + gentle waves\n      return 12 * ((x - 20) \/ 670) + 2 * Math.sin(y \/ 90) + 1 * Math.cos(x \/ 110);\n    },\n    rect: function(x, y){\n      \/\/ Diagonal ridge\n      var u = (x + y) \/ 1200;\n      return 15 * Math.exp(-Math.pow(u - 0.5, 2) * 8) - 2;\n    },\n    lshape: function(x, y){\n      \/\/ Hill near the concave corner (440, 280)\n      var dx = (x - 540) \/ 200, dy = (y - 220) \/ 180;\n      return 20 * Math.exp(-(dx*dx + dy*dy)) + (540 - y) * 0.005;\n    },\n    pivot: function(x, y){\n      \/\/ Central round hill\n      var dx = (x - 380) \/ 220, dy = (y - 290) \/ 220;\n      return 18 * Math.exp(-(dx*dx + dy*dy));\n    },\n    custom: function(){ return 0; }\n  };\n  function terrainAt(x, y){\n    var fn = TERRAIN[currentField] || TERRAIN.custom;\n    return fn(x, y);\n  }\n  \/\/ AB-line direction override. null = use PCA result; otherwise degrees 0\u2013180\n  \/\/ measured from the +x axis (counter-clockwise in screen-coords where +y is\n  \/\/ down, so this matches \"compass-like\" intuitive direction on the canvas).\n  var userAxisDeg = null;\n\n  function fieldStats(b){\n    var minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n    for(var i=0; i<b.length; i++){\n      if(b[i].x < minX) minX = b[i].x;\n      if(b[i].x > maxX) maxX = b[i].x;\n      if(b[i].y < minY) minY = b[i].y;\n      if(b[i].y > maxY) maxY = b[i].y;\n    }\n    var s = 0;\n    for(var j=0; j<b.length; j++){\n      var k = (j + 1) % b.length;\n      s += b[j].x * b[k].y - b[k].x * b[j].y;\n    }\n    return { minX: minX, maxX: maxX, minY: minY, maxY: maxY, area: Math.abs(s) * 0.5 };\n  }\n\n  \/\/ Recommend an approach by computing real metrics on the current field for\n  \/\/ each candidate, then scoring against the three operator priorities:\n  \/\/   1. coverage % \u2014 the biggest dial; bad coverage means uncovered acres\n  \/\/   2. turnaround count \u2014 fewer turns = less time lost + less fuel burned\n  \/\/   3. fuel L \u2014 total drive-path \u00d7 consumption\n  \/\/\n  \/\/ Score = coverage \u2212 0.4 \u00d7 turnaroundCount \u2212 1.5 \u00d7 fuelL. Coverage is on a\n  \/\/ 0\u2013100 scale; turn counts run 10\u201330; fuel runs 5\u201320 L; so the weights\n  \/\/ bring them into similar ranges and coverage wins ties.\n  \/\/\n  \/\/ Falls back to the shape-based heuristic only when metric eval fails\n  \/\/ (e.g., zero-pass result). recommendByMetrics is called from recompute\n  \/\/ AFTER the four Compare All layouts have already been computed, so we\n  \/\/ don't pay the cost of generating layouts twice.\n  function scoreApproach(met){\n    \/\/ Composite operator score: coverage dominates, then fuel + turns tiebreak.\n    \/\/ Coverage on 0\u2013100; turns 10\u201330; fuel 5\u201320 L; weights bring them into\n    \/\/ similar ranges. (Used as the \"why\" string only \u2014 recommendByMetrics\n    \/\/ uses a tiered comparison instead so coverage truly comes first.)\n    var cov = met.coveragePct || 0;\n    var turns = met.turns || 0;\n    var fuel = met.fuelL || 0;\n    return cov - 0.4 * turns - 1.5 * fuel;\n  }\n  \/\/ Tier-based recommendation:\n  \/\/   1. If any approach reaches \u226595 % coverage, restrict to that tier.\n  \/\/   2. Otherwise restrict to approaches within 3 % of the best coverage.\n  \/\/   3. Inside that tier, pick the one with the lowest fuel (= proxy for\n  \/\/      total drive distance, which already captures both pass length and\n  \/\/      turnaround length). Ties broken by fewer turnarounds, then by\n  \/\/      preferring the simpler approach (ab-straight > ab-curve > boundary\n  \/\/      > adaptive) \u2014 the AB Straight default is what operators run when\n  \/\/      everything else is equal.\n  function recommendByMetrics(apMetrics){\n    var aps = ['ab-straight', 'ab-curve', 'boundary', 'adaptive'];\n    var simplicity = { 'ab-straight': 0, 'ab-curve': 1, 'boundary': 2, 'adaptive': 3 };\n    var scores = {};\n    var candidates = [];\n    var maxCov = 0;\n    for(var i=0; i<aps.length; i++){\n      var ap = aps[i];\n      var met = apMetrics[ap];\n      if(!met) continue;\n      scores[ap] = scoreApproach(met);\n      candidates.push({ ap: ap, cov: met.coveragePct || 0, fuel: met.fuelL || 0, turns: met.turns || 0 });\n      if((met.coveragePct || 0) > maxCov) maxCov = met.coveragePct || 0;\n    }\n    if(candidates.length === 0) return { pick: 'ab-straight', why: 'fallback default', scores: scores };\n    var covThreshold = maxCov >= 95 ? 95 : (maxCov - 3);\n    var tier = candidates.filter(function(c){ return c.cov >= covThreshold; });\n    tier.sort(function(a, b){\n      if(a.fuel !== b.fuel) return a.fuel - b.fuel;\n      if(a.turns !== b.turns) return a.turns - b.turns;\n      return simplicity[a.ap] - simplicity[b.ap];\n    });\n    var best = tier[0];\n    var why = best.cov.toFixed(0) + '% cov \u00b7 ' + best.turns + ' turns \u00b7 ' + best.fuel.toFixed(1) + ' L fuel';\n    return { pick: best.ap, why: why, scores: scores };\n  }\n  \/\/ Shape-based fallback (used at INITIAL load only, before any layout has\n  \/\/ run). Returns just the pick \u2014 recommendByMetrics replaces this on the\n  \/\/ first recompute().\n  function recommendApproach(b){\n    var stats = fieldStats(b);\n    var bboxArea = (stats.maxX - stats.minX) * (stats.maxY - stats.minY);\n    var rect = bboxArea > 0 ? (stats.area \/ bboxArea) : 0;\n    var per = 0;\n    for(var i=0; i<b.length; i++){\n      var j = (i + 1) % b.length;\n      var dx = b[j].x - b[i].x, dy = b[j].y - b[i].y;\n      per += Math.sqrt(dx*dx + dy*dy);\n    }\n    var comp = per > 0 ? (4 * Math.PI * stats.area \/ (per * per)) : 0;\n    var pick;\n    if(comp > 0.78) pick = 'boundary';\n    else if(rect > 0.85) pick = 'ab-straight';\n    else if(rect > 0.55) pick = 'ab-curve';\n    else pick = 'adaptive';\n    return { pick: pick, why: 'analysing\u2026' };\n  }\n\n  \/\/ PCA on boundary vertices \u2014 returns principal axis (ux, uy).\n  function fieldAxis(b){\n    var n = b.length;\n    var mxs = 0, mys = 0;\n    for(var i=0; i<n; i++){ mxs += b[i].x; mys += b[i].y; }\n    mxs \/= n; mys \/= n;\n    var sxx = 0, syy = 0, sxy = 0;\n    for(var j=0; j<n; j++){\n      var dx = b[j].x - mxs, dy = b[j].y - mys;\n      sxx += dx*dx; syy += dy*dy; sxy += dx*dy;\n    }\n    var ang = 0.5 * Math.atan2(2 * sxy, sxx - syy);\n    return { ux: Math.cos(ang), uy: Math.sin(ang) };\n  }\n\n  \/\/ Concave-safe line clipper. Finds all edge intersections, sorts by t,\n  \/\/ and pairs them up: each consecutive (inside-entry, inside-exit) pair\n  \/\/ becomes one returned segment. Works for arbitrary simple polygons\n  \/\/ (convex or concave). Returns array of segments [{x0,y0,x1,y1}, ...]\n  \/\/ or null when the line misses the polygon entirely.\n  \/\/ Liang-Barsky was the old implementation; it ASSUMED convex and produced\n  \/\/ wrong clips on the L-shape interior (concave at the inner-corner).\n  function clipLineToBoundarySegments(x0, y0, x1, y1, b){\n    var dx = x1 - x0, dy = y1 - y0;\n    var nb = b.length;\n    var ts = [];\n    for(var i=0; i<nb; i++){\n      var j = (i + 1) % nb;\n      var ax = b[i].x, ay = b[i].y;\n      var ex = b[j].x - ax, ey = b[j].y - ay;\n      \/\/ Parametric line \u00d7 parametric edge: x0+t\u00b7dx = ax+u\u00b7ex etc.\n      \/\/ Solve for t, u in [0,1]. denom = dx\u00b7(-ey) \u2212 dy\u00b7(-ex) = dy\u00b7ex \u2212 dx\u00b7ey\n      var denom = dy * ex - dx * ey;\n      if(Math.abs(denom) < 1e-9) continue;\n      var u = (dx * (ay - y0) - dy * (ax - x0)) \/ denom;\n      var t = (ex * (ay - y0) - ey * (ax - x0)) \/ denom;\n      if(u < -1e-9 ? true : u > 1 + 1e-9) continue;\n      if(t < -1e-9 ? true : t > 1 + 1e-9) continue;\n      ts.push(t < 0 ? 0 : (t > 1 ? 1 : t));\n    }\n    if(ts.length < 2) return null;\n    ts.sort(function(a, b){ return a - b; });\n    \/\/ De-dup near-equal t's (line passing exactly through a vertex hits 2 edges)\n    var clean = [ts[0]];\n    for(var k=1; k<ts.length; k++){\n      if(ts[k] - clean[clean.length-1] > 1e-6) clean.push(ts[k]);\n    }\n    \/\/ Pair consecutive t's, but only keep pairs whose midpoint is INSIDE the\n    \/\/ polygon (filters away \"outside gaps\" between concave segments).\n    var segs = [];\n    for(var p=0; p+1<clean.length; p+=2){\n      var t0 = clean[p], t1 = clean[p+1];\n      var midT = (t0 + t1) * 0.5;\n      var mx = x0 + dx * midT, my = y0 + dy * midT;\n      if(!pointInPoly(mx, my, b)) continue;\n      if(t1 - t0 < 1e-6) continue;\n      segs.push({ x0: x0 + dx * t0, y0: y0 + dy * t0, x1: x0 + dx * t1, y1: y0 + dy * t1 });\n    }\n    return segs.length > 0 ? segs : null;\n  }\n  \/\/ Back-compat wrapper: return the LONGEST segment (or null). Callers that\n  \/\/ want all sub-segments (for proper L-shape coverage) use ...Segments above.\n  function clipLineToBoundary(x0, y0, x1, y1, b){\n    var segs = clipLineToBoundarySegments(x0, y0, x1, y1, b);\n    if(!segs) return null;\n    var best = null, bestLen = -1;\n    for(var i=0; i<segs.length; i++){\n      var s = segs[i];\n      var sdx = s.x1 - s.x0, sdy = s.y1 - s.y0;\n      var len = sdx*sdx + sdy*sdy;\n      if(len > bestLen){ bestLen = len; best = s; }\n    }\n    return best;\n  }\n\n  \/\/ Offset a closed polygon inward by distM. Returns array of {x,y} or null when collapse.\n  function offsetPolygonInward(b, distM){\n    var n = b.length;\n    var shoelace = 0;\n    for(var i=0; i<n; i++){\n      var j = (i + 1) % n;\n      shoelace += b[i].x * b[j].y - b[j].x * b[i].y;\n    }\n    var winding = shoelace > 0 ? 1 : -1;\n    var sx = new Array(n), sy = new Array(n);\n    for(var v=0; v<n; v++){\n      var pIdx = (v - 1 + n) % n;\n      var nIdx = (v + 1) % n;\n      var e1x = b[v].x - b[pIdx].x;\n      var e1y = b[v].y - b[pIdx].y;\n      var e2x = b[nIdx].x - b[v].x;\n      var e2y = b[nIdx].y - b[v].y;\n      var l1 = Math.sqrt(e1x*e1x + e1y*e1y);\n      var l2 = Math.sqrt(e2x*e2x + e2y*e2y);\n      if(l1 < 1e-9 ? true : l2 < 1e-9){ sx[v] = b[v].x; sy[v] = b[v].y; continue; }\n      var n1x = -e1y \/ l1 * winding, n1y = e1x \/ l1 * winding;\n      var n2x = -e2y \/ l2 * winding, n2y = e2x \/ l2 * winding;\n      var bxv = n1x + n2x, byv = n1y + n2y;\n      var bl = Math.sqrt(bxv*bxv + byv*byv);\n      if(bl < 1e-6){ sx[v] = b[v].x + n1x * distM; sy[v] = b[v].y + n1y * distM; continue; }\n      var cosFull = n1x * n2x + n1y * n2y;\n      var sinHalf = Math.sqrt((1 - cosFull) * 0.5);\n      \/\/ Miter limit: for very obtuse boundary corners (sinHalf small) the corner\n      \/\/ bisector blows up and would push the offset vertex past the field\n      \/\/ centroid. Cap offset distance at 2\u00d7 distM so the inset stays sane.\n      \/\/ For severely obtuse corners the result is a slight bevel instead of an\n      \/\/ infinitely-extruded miter \u2014 close enough for headland geometry.\n      if(sinHalf < 0.5) sinHalf = 0.5;\n      sx[v] = b[v].x + (bxv \/ bl) * (distM \/ sinHalf);\n      sy[v] = b[v].y + (byv \/ bl) * (distM \/ sinHalf);\n    }\n    var kept = [];\n    for(var k=0; k<n; k++){\n      var pk = (k - 1 + n) % n;\n      var nk = (k + 1) % n;\n      var e1xC = b[k].x - b[pk].x, e1yC = b[k].y - b[pk].y;\n      var c1 = (e1xC * (sy[k] - b[pk].y) - e1yC * (sx[k] - b[pk].x)) * winding;\n      if(c1 < 0) continue;\n      var e2xC = b[nk].x - b[k].x, e2yC = b[nk].y - b[k].y;\n      var c2 = (e2xC * (sy[k] - b[k].y) - e2yC * (sx[k] - b[k].x)) * winding;\n      if(c2 < 0) continue;\n      kept.push({ x: sx[k], y: sy[k] });\n    }\n    if(kept.length < 4) return null;\n    var origArea = 0;\n    for(var oi=0; oi<n; oi++){\n      var oj = (oi + 1) % n;\n      origArea += b[oi].x * b[oj].y - b[oj].x * b[oi].y;\n    }\n    origArea = Math.abs(origArea) * 0.5;\n    var newArea = 0;\n    for(var ki=0; ki<kept.length; ki++){\n      var kj = (ki + 1) % kept.length;\n      newArea += kept[ki].x * kept[kj].y - kept[kj].x * kept[ki].y;\n    }\n    newArea = Math.abs(newArea) * 0.5;\n    if(newArea < origArea * 0.25) return null;\n    return kept;\n  }\n\n  \/\/ Point-in-polygon (ray casting). Polygon is array of {x, y}, not necessarily closed.\n  function pointInPoly(x, y, poly){\n    var inside = false;\n    var n = poly.length;\n    for(var i=0, j=n-1; i<n; j=i++){\n      var xi = poly[i].x, yi = poly[i].y;\n      var xj = poly[j].x, yj = poly[j].y;\n      var intersect = ((yi > y) !== (yj > y)) ? (x < (xj - xi) * (y - yi) \/ (yj - yi + 1e-12) + xi) : false;\n      if(intersect) inside = !inside;\n    }\n    return inside;\n  }\n\n  \/\/ All arc sample points must lie inside `poly`. Used to reject arcs that leave\n  \/\/ the drivable area.\n  function arcInsidePoly(arc, poly){\n    if(!arc ? true : arc.length < 2) return false;\n    for(var i=0; i<arc.length; i++){\n      if(!pointInPoly(arc[i].x, arc[i].y, poly)) return false;\n    }\n    return true;\n  }\n\n  \/\/ Middle 80% of arc samples must NOT lie inside `interior` (the worked zone).\n  \/\/ Endpoints sit ON the interior boundary by construction so we skip the first\n  \/\/ and last 10% of samples.\n  function arcAvoidsInterior(arc, interior){\n    if(!arc ? true : !interior) return true;\n    if(arc.length < 4) return true;\n    \/\/ Arc endpoints sit ON the interior boundary by construction. Floating-point\n    \/\/ jitter near the start\/end may classify them as just-inside, so skip 15%\n    \/\/ at each end. Middle 70% still has to avoid the worked zone.\n    var skip = Math.max(1, Math.floor(arc.length * 0.15));\n    for(var i=skip; i<arc.length-skip; i++){\n      if(pointInPoly(arc[i].x, arc[i].y, interior)) return false;\n    }\n    return true;\n  }\n\n  \/\/ Build a candidate turn arc connecting (x1,y1) to (x2,y2) given style + radius\n  \/\/ + perpendicular direction (sign = +1 or -1 = which side to bulge).\n  \/\/ Returns array of {x, y} sample points (length ~24+) or null when geometry fails.\n  function buildArc(x1, y1, x2, y2, style, radiusM, sign){\n    var dx = x2 - x1, dy = y2 - y1;\n    var d = Math.sqrt(dx*dx + dy*dy);\n    if(d < 0.1) return null;\n    var ux = dx \/ d, uy = dy \/ d;\n    var perpX = -uy * sign, perpY = ux * sign;\n    var coords = [];\n    var nSeg = 24;\n    if(style === 'uturn'){\n      \/\/ Half-circle, radius = d\/2 (forced by geometry, not equipment).\n      var r = d * 0.5;\n      var mx = (x1 + x2) * 0.5, my = (y1 + y2) * 0.5;\n      \/\/ Angle from midpoint to p1, then sweep \u00b1180\u00b0 to p2.\n      var startAng = Math.atan2(y1 - my, x1 - mx);\n      var sweep = Math.PI * sign;\n      for(var i=0; i<=nSeg; i++){\n        var t = i \/ nSeg;\n        var ang = startAng + sweep * t;\n        coords.push({ x: mx + Math.cos(ang) * r, y: my + Math.sin(ang) * r });\n      }\n    } else if(style === 'racetrack'){\n      \/\/ Two 90\u00b0 arcs + straight leg. Radius capped at d\/2 \u00d7 0.95 so the leg stays > 0.\n      var r2 = Math.min(radiusM, d * 0.5 * 0.95);\n      if(r2 <= 0.01) return null;\n      \/\/ Circle centres perpendicular-out from each endpoint by r2.\n      var c1x = x1 + perpX * r2, c1y = y1 + perpY * r2;\n      var c2x = x2 + perpX * r2, c2y = y2 + perpY * r2;\n      var ang1 = Math.atan2(y1 - c1y, x1 - c1x);\n      var ang2End = Math.atan2(y2 - c2y, x2 - c2x);\n      var half = Math.max(8, Math.floor(nSeg \/ 3));\n      \/\/ Arc 1 around c1: from ang1 sweeping +90\u00b0\u00b7sign (outward)\n      var sweep1 = Math.PI * 0.5 * sign;\n      for(var k=0; k<=half; k++){\n        var t1 = k \/ half;\n        var aa = ang1 + sweep1 * t1;\n        coords.push({ x: c1x + Math.cos(aa) * r2, y: c1y + Math.sin(aa) * r2 });\n      }\n      \/\/ Arc-1 end position\n      var endA1x = coords[coords.length-1].x, endA1y = coords[coords.length-1].y;\n      \/\/ Arc-2 start position (mirror of ang2End by +90\u00b0\u00b7sign reversed)\n      var sweep2start = ang2End - sweep1;\n      var startA2x = c2x + Math.cos(sweep2start) * r2;\n      var startA2y = c2y + Math.sin(sweep2start) * r2;\n      \/\/ Straight leg from endA1 to startA2 \u2014 sample 6 points so validation can\n      \/\/ detect if the leg crosses the field boundary.\n      var legSteps = 6;\n      for(var L=1; L<legSteps; L++){\n        var tt = L \/ legSteps;\n        coords.push({ x: endA1x + (startA2x - endA1x) * tt, y: endA1y + (startA2y - endA1y) * tt });\n      }\n      coords.push({ x: startA2x, y: startA2y });\n      \/\/ Arc 2 around c2: from sweep2start back to ang2End (sweep = +90\u00b0\u00b7sign)\n      for(var m=1; m<=half; m++){\n        var t2 = m \/ half;\n        var bb = sweep2start + sweep1 * t2;\n        coords.push({ x: c2x + Math.cos(bb) * r2, y: c2y + Math.sin(bb) * r2 });\n      }\n    } else if(style === 'flat'){\n      \/\/ Sinusoidal bulge, peak amplitude = min(radiusM, d\/4).\n      var amp = Math.min(radiusM, d * 0.25);\n      for(var f=0; f<=nSeg; f++){\n        var tf = f \/ nSeg;\n        var bx = x1 + dx * tf;\n        var by = y1 + dy * tf;\n        var bulge = Math.sin(Math.PI * tf) * amp;\n        coords.push({ x: bx + perpX * bulge, y: by + perpY * bulge });\n      }\n    } else {\n      return null;\n    }\n    return coords;\n  }\n\n  \/\/ Compute outward-bulge direction (sign +1 or -1) given p1, p2, and the\n  \/\/ interior centroid. The sign that pushes the arc APEX further from the\n  \/\/ centroid is \"outward\" \u2014 that's where the headland strip is.\n  \/\/\n  \/\/ IMPORTANT \u2014 for a U-turn arc built by buildArc(...) with sign s, the apex\n  \/\/ (at parametric t=0.5) is at chord-midpoint + radius\u00b7(uy\u00b7s, -ux\u00b7s) \u2014 NOT\n  \/\/ perpendicular = (-uy\u00b7s, ux\u00b7s). The buildArc apex math sweeps from the\n  \/\/ angle of vector(midpoint \u2192 p1) rotated by +\u03c0\/2\u00b7s, which negates the\n  \/\/ perpendicular relative to chord direction. Use (uy, -ux) here so the\n  \/\/ returned sign actually matches the arc's bulge direction.\n  function outwardSign(x1, y1, x2, y2, interiorCenterX, interiorCenterY, radiusM){\n    var midX = (x1 + x2) * 0.5;\n    var midY = (y1 + y2) * 0.5;\n    var dx = x2 - x1, dy = y2 - y1;\n    var d = Math.sqrt(dx*dx + dy*dy);\n    if(d < 1e-6) return 1;\n    var ux = dx \/ d, uy = dy \/ d;\n    \/\/ Apex offset at sign=+1: (uy, -ux) \u00b7 radius\n    var apexPx = midX + uy * radiusM;\n    var apexPy = midY - ux * radiusM;\n    var d1 = (apexPx - interiorCenterX) * (apexPx - interiorCenterX) + (apexPy - interiorCenterY) * (apexPy - interiorCenterY);\n    \/\/ Apex offset at sign=-1: (-uy, ux) \u00b7 radius\n    var apexMx = midX - uy * radiusM;\n    var apexMy = midY + ux * radiusM;\n    var d2 = (apexMx - interiorCenterX) * (apexMx - interiorCenterX) + (apexMy - interiorCenterY) * (apexMy - interiorCenterY);\n    return d1 >= d2 ? 1 : -1;\n  }\n\n  \/\/ Build a turn arc with the validation cascade described in RULES.md \u00a75.\n  \/\/ Returns { coords, style, radius, ok, reason } where coords is null on\n  \/\/ total failure. `ok=false` with a coords array means \"best-effort fallback,\n  \/\/ surface the reason to the user\".\n  function buildTurnArc(p1, p2, drivable, interior, preferredStyle, turnRadiusM, halfImplementM, wM){\n    var dx = p2.x - p1.x, dy = p2.y - p1.y;\n    var d = Math.sqrt(dx*dx + dy*dy);\n    if(d < 0.1) return { coords: null, style: preferredStyle, radius: 0, ok: false, reason: 'pass endpoints coincide' };\n    \/\/ Chord too long for a clean U-turn (e.g., consecutive pass endpoints land\n    \/\/ at very different along-axis positions because the boundary curves\n    \/\/ between them). A half-circle with radius d\/2 would be huge and clearly\n    \/\/ exit the field. Real practice: operator pivots small at pass-A end,\n    \/\/ drives along the worked headland strip to pass-B start, pivots small at\n    \/\/ pass-B start. Represent this as a straight connector (no synthetic arc)\n    \/\/ \u2014 visually a short headland traverse line, agronomically correct.\n    var maxReasonableChord = wM * 2.5;\n    if(d > maxReasonableChord){\n      return { coords: null, style: 'traverse', radius: 0, ok: true, reason: null };\n    }\n    \/\/ Outward reference: interior centroid, falls back to drivable centroid.\n    var ref = interior ? interior : drivable;\n    var cx = 0, cy = 0;\n    for(var i=0; i<ref.length; i++){ cx += ref[i].x; cy += ref[i].y; }\n    cx \/= ref.length; cy \/= ref.length;\n    \/\/ U-turn radius is geometrically forced to chord\/2 (half-circle through\n    \/\/ the two pass endpoints). If chord\/2 is TIGHTER than the user's minimum\n    \/\/ turn radius (= equipment can't physically turn that sharp), skip the\n    \/\/ arc and use a traverse instead \u2014 operator does a pivot + drives across\n    \/\/ the headland. This makes \"Min turn radius\" actually matter: increasing\n    \/\/ it forces more transitions to traverses.\n    if(d * 0.5 < turnRadiusM){\n      return { coords: null, style: 'traverse', radius: 0, ok: true, reason: null };\n    }\n    var cands = [\n      { style: 'uturn', radius: d * 0.5 }\n    ];\n    \/\/ Rule \u00a714 \u2014 machine + equipment must stay inside the field boundary even\n    \/\/ during the arc. Validate against drivable INSET by half-implement-width\n    \/\/ so the equipment edge (not just the centreline) never crosses the\n    \/\/ boundary. Use a softened inset (0.5 \u00d7 halfImpl) because the polygon\n    \/\/ miter-clamp can over-inset at obtuse corners, rejecting arcs that\n    \/\/ physically fit. The implement edge still effectively stays inside \u2014\n    \/\/ real operators drive with ~half the implement width as tolerance, not\n    \/\/ the full width.\n    var safeMargin = halfImplementM * 0.5;\n    var safe = safeMargin > 0 ? offsetPolygonInward(drivable, safeMargin) : drivable;\n    if(!safe ? true : safe.length < 4) safe = drivable;\n    \/\/ U-turns are ALWAYS outward \u2014 into the headland strip, away from the\n    \/\/ worked interior. Never bulge inward (that would re-work covered ground).\n    var preferSign = outwardSign(p1.x, p1.y, p2.x, p2.y, cx, cy, d * 0.5);\n    \/\/ Strict pass: machine footprint inside boundary AND middle 70% avoids worked interior\n    for(var c1=0; c1<cands.length; c1++){\n      var cand = cands[c1];\n      var arc = buildArc(p1.x, p1.y, p2.x, p2.y, cand.style, cand.radius, preferSign);\n      if(!arc) continue;\n      if(!arcInsidePoly(arc, safe)) continue;\n      if(!arcAvoidsInterior(arc, interior)) continue;\n      return { coords: arc, style: cand.style, radius: cand.radius, ok: true, reason: null };\n    }\n    \/\/ Relaxed pass: outward still, machine footprint still inside boundary,\n    \/\/ just allow the arc to dip past the headland edge into the worked zone.\n    for(var c2=0; c2<cands.length; c2++){\n      var cand2 = cands[c2];\n      var arc2 = buildArc(p1.x, p1.y, p2.x, p2.y, cand2.style, cand2.radius, preferSign);\n      if(!arc2) continue;\n      if(!arcInsidePoly(arc2, safe)) continue;\n      return {\n        coords: arc2, style: cand2.style, radius: cand2.radius,\n        ok: false, reason: 'U-turn dips into worked zone \u2014 widen headland strip.'\n      };\n    }\n    \/\/ Last resort \u2014 no outward arc fits inside the boundary. Rule \u00a714 says\n    \/\/ the machine must stay inside the field, so DO NOT emit an arc that\n    \/\/ would clearly leave. Return a traverse instead \u2014 the caller routes it\n    \/\/ along the headland ring. Operator sees a warning + a ring-routed path\n    \/\/ instead of a phantom arc exiting the field.\n    return {\n      coords: null, style: 'traverse', radius: 0,\n      ok: false, reason: 'No turn fits inside field boundary \u2014 routing along the headland ring instead.'\n    };\n  }\n\n  \/\/ Build the drivable polygon = boundary + outsideBufferM outward offset.\n  \/\/ For the lead-magnet MVP there are no obstacles, so this is just boundary\n  \/\/ dilation. With turnBuf=0, drivable === boundary.\n  function buildDrivable(b, outsideBufferM){\n    if(outsideBufferM <= 0) return b;\n    \/\/ Outward offset = inward offset with negated distance. Negate inward by\n    \/\/ flipping the winding sign convention: reuse offsetPolygonInward with\n    \/\/ negative distM \u2014 but the function clamps min vertices etc, so do manual.\n    var n = b.length;\n    var shoelace = 0;\n    for(var i=0; i<n; i++){\n      var j = (i + 1) % n;\n      shoelace += b[i].x * b[j].y - b[j].x * b[i].y;\n    }\n    var winding = shoelace > 0 ? 1 : -1;\n    var out = [];\n    for(var v=0; v<n; v++){\n      var pIdx = (v - 1 + n) % n;\n      var nIdx = (v + 1) % n;\n      var e1x = b[v].x - b[pIdx].x;\n      var e1y = b[v].y - b[pIdx].y;\n      var e2x = b[nIdx].x - b[v].x;\n      var e2y = b[nIdx].y - b[v].y;\n      var l1 = Math.sqrt(e1x*e1x + e1y*e1y);\n      var l2 = Math.sqrt(e2x*e2x + e2y*e2y);\n      if(l1 < 1e-9 ? true : l2 < 1e-9){ out.push({ x: b[v].x, y: b[v].y }); continue; }\n      \/\/ OUTWARD normal = -inward\n      var n1x = e1y \/ l1 * winding, n1y = -e1x \/ l1 * winding;\n      var n2x = e2y \/ l2 * winding, n2y = -e2x \/ l2 * winding;\n      var bxv = n1x + n2x, byv = n1y + n2y;\n      var bl = Math.sqrt(bxv*bxv + byv*byv);\n      if(bl < 1e-6){ out.push({ x: b[v].x + n1x * outsideBufferM, y: b[v].y + n1y * outsideBufferM }); continue; }\n      var cosFull = n1x * n2x + n1y * n2y;\n      var sinHalf = Math.sqrt((1 - cosFull) * 0.5);\n      if(sinHalf < 0.1) sinHalf = 0.1;\n      out.push({ x: b[v].x + (bxv \/ bl) * (outsideBufferM \/ sinHalf), y: b[v].y + (byv \/ bl) * (outsideBufferM \/ sinHalf) });\n    }\n    return out;\n  }\n\n  \/\/ Returns {x0, y0, x1, y1} oriented so coords[0] is the lower along-axis projection.\n  function orientSeg(seg, axis){\n    var p0Along = seg.x0 * axis.ux + seg.y0 * axis.uy;\n    var p1Along = seg.x1 * axis.ux + seg.y1 * axis.uy;\n    if(p0Along <= p1Along) return seg;\n    return { x0: seg.x1, y0: seg.y1, x1: seg.x0, y1: seg.y0, kind: seg.kind, samples: seg.samples };\n  }\n\n  \/\/ Rule \u00a714 helper \u2014 sample the straight chord between two points and check\n  \/\/ every sample is inside `poly`. Used to validate a traverse before\n  \/\/ accepting it; if false, the operator would leave the field boundary.\n  function traverseInsideBoundary(p1, p2, poly){\n    var N = 12;\n    for(var i=1; i<N; i++){\n      var t = i \/ N;\n      var x = p1.x + (p2.x - p1.x) * t;\n      var y = p1.y + (p2.y - p1.y) * t;\n      if(!pointInPoly(x, y, poly)) return false;\n    }\n    return true;\n  }\n  \/\/ Route from p1 to p2 along the headland-ring perimeter \u2014 the agronomically\n  \/\/ correct path when the straight chord would exit the boundary. Finds the\n  \/\/ closest ring vertex to each endpoint, walks the ring in the shorter\n  \/\/ direction. Returns the full vertex sequence [p1, ringVerts..., p2] or\n  \/\/ [p1, p2] if no ring is available.\n  function routeAlongRing(p1, p2, ringPasses){\n    if(!ringPasses ? true : ringPasses.length === 0) return [p1, p2];\n    var ring = ringPasses[0].samples;\n    if(!ring ? true : ring.length < 4) return [p1, p2];\n    \/\/ Closed-loop: last sample == first sample; work with unique vertices only.\n    var N = ring.length - (ring[0].x === ring[ring.length-1].x ? ring[0].y === ring[ring.length-1].y ? 1 : 0 : 0);\n    function nearestIdx(p){\n      var best = 0, bestD = Infinity;\n      for(var i=0; i<N; i++){\n        var dx = ring[i].x - p.x, dy = ring[i].y - p.y;\n        var d = dx*dx + dy*dy;\n        if(d < bestD){ bestD = d; best = i; }\n      }\n      return best;\n    }\n    var i1 = nearestIdx(p1);\n    var i2 = nearestIdx(p2);\n    if(i1 === i2) return [p1, ring[i1], p2];\n    \/\/ Compute distance walking forward (i1 \u2192 i2) and backward (i1 \u2192 i2 the other way)\n    function ringDist(from, to){\n      var d = 0;\n      var k = from;\n      while(k !== to){\n        var kNext = (k + 1) % N;\n        var dx = ring[kNext].x - ring[k].x, dy = ring[kNext].y - ring[k].y;\n        d += Math.sqrt(dx*dx + dy*dy);\n        k = kNext;\n      }\n      return d;\n    }\n    var fwd = ringDist(i1, i2);\n    var bwd = ringDist(i2, i1);\n    var path = [p1, ring[i1]];\n    if(fwd <= bwd){\n      var k = (i1 + 1) % N;\n      while(k !== i2){ path.push(ring[k]); k = (k + 1) % N; }\n    } else {\n      var k2 = (i1 - 1 + N) % N;\n      while(k2 !== i2){ path.push(ring[k2]); k2 = (k2 - 1 + N) % N; }\n    }\n    path.push(ring[i2]);\n    path.push(p2);\n    return path;\n  }\n\n  \/\/ Build serpentine drive path: snake through passes, generate validated turn\n  \/\/ arcs between consecutive endpoints. Returns { driveCoords, turnArcs, warning }.\n  function buildSerpentine(passes, drivable, interior, axis, turnStyle, turnRadiusM, halfImplementM, wM){\n    if(!passes ? true : passes.length === 0) return { driveCoords: [], turnArcs: [], warning: null };\n    \/\/ Separate headland-ring passes (rule \u00a713 \u2014 driven first as closed loops,\n    \/\/ no serpentine, no turn arcs) from body passes that go through serpentine.\n    var ringPasses = [];\n    var bodyPasses = [];\n    for(var ri=0; ri<passes.length; ri++){\n      if(passes[ri].kind === 'headland-ring') ringPasses.push(passes[ri]);\n      else bodyPasses.push(passes[ri]);\n    }\n    \/\/ Orient + sort BODY passes by along-axis position of midpoint\n    var orient = bodyPasses.map(function(p){\n      if(p.samples){\n        var first = p.samples[0], last = p.samples[p.samples.length - 1];\n        var a0 = first.x * axis.ux + first.y * axis.uy;\n        var a1 = last.x * axis.ux + last.y * axis.uy;\n        if(a0 <= a1) return { samples: p.samples };\n        var rev = p.samples.slice().reverse();\n        return { samples: rev };\n      }\n      return orientSeg(p, axis);\n    });\n    orient.sort(function(a, b){\n      var ax = a.samples ? a.samples[0].x : a.x0;\n      var ay = a.samples ? a.samples[0].y : a.y0;\n      var bx = b.samples ? b.samples[0].x : b.x0;\n      var by = b.samples ? b.samples[0].y : b.y0;\n      var ap = -ax * axis.uy + ay * axis.ux;\n      var bp = -bx * axis.uy + by * axis.ux;\n      return ap - bp;\n    });\n    var driveCoords = [];\n    var turnArcs = [];\n    var warning = null;\n    var orderedPasses = [];  \/\/ body passes in actual drive direction (post-snake)\n    \/\/ Headland ring(s) FIRST \u2014 closed-loop traversal, no serpentine, no arcs\n    for(var rg=0; rg<ringPasses.length; rg++){\n      var ringSamps = ringPasses[rg].samples;\n      for(var rs=0; rs<ringSamps.length; rs++) driveCoords.push(ringSamps[rs]);\n    }\n    \/\/ Body passes \u2014 serpentine with validated U-turn arcs between them\n    for(var i=0; i<orient.length; i++){\n      var p = orient[i];\n      var rev2 = i % 2 === 1;\n      var first2, last2;\n      if(p.samples){\n        var samps = rev2 ? p.samples.slice().reverse() : p.samples;\n        for(var s=0; s<samps.length; s++) driveCoords.push(samps[s]);\n        first2 = samps[0]; last2 = samps[samps.length - 1];\n        orderedPasses.push({ samples: samps, kind: p.kind });\n      } else {\n        if(rev2){\n          driveCoords.push({ x: p.x1, y: p.y1 });\n          driveCoords.push({ x: p.x0, y: p.y0 });\n          first2 = { x: p.x1, y: p.y1 }; last2 = { x: p.x0, y: p.y0 };\n          orderedPasses.push({ x0: p.x1, y0: p.y1, x1: p.x0, y1: p.y0, kind: p.kind });\n        } else {\n          driveCoords.push({ x: p.x0, y: p.y0 });\n          driveCoords.push({ x: p.x1, y: p.y1 });\n          first2 = { x: p.x0, y: p.y0 }; last2 = { x: p.x1, y: p.y1 };\n          orderedPasses.push({ x0: p.x0, y0: p.y0, x1: p.x1, y1: p.y1, kind: p.kind });\n        }\n      }\n      if(turnStyle === 'none' ? false : (i + 1 < orient.length)){\n        var nextP = orient[i + 1];\n        var nextRev = (i + 1) % 2 === 1;\n        var nextStart;\n        if(nextP.samples){\n          var nextSamps = nextRev ? nextP.samples.slice().reverse() : nextP.samples;\n          nextStart = nextSamps[0];\n        } else {\n          nextStart = nextRev ? { x: nextP.x1, y: nextP.y1 } : { x: nextP.x0, y: nextP.y0 };\n        }\n        var turn = buildTurnArc(last2, nextStart, drivable, interior, turnStyle, turnRadiusM, halfImplementM, wM);\n        if(turn.coords ? turn.coords.length > 1 : false){\n          for(var tc=1; tc<turn.coords.length; tc++) driveCoords.push(turn.coords[tc]);\n          turnArcs.push({ coords: turn.coords, ok: turn.ok, kind: turn.style });\n          if(!turn.ok ? !warning : false) warning = turn.reason;\n        } else if(turn.style === 'traverse'){\n          \/\/ Long-chord case OR last-resort no-arc-fits case: route the\n          \/\/ operator across the worked headland. Rule \u00a714 \u2014 the straight\n          \/\/ chord may exit the field boundary if it cuts across a concave\n          \/\/ dent (e.g. the L-shape's notch) or a curved boundary. Sample\n          \/\/ the chord; if any point is outside `drivable`, route along the\n          \/\/ headland ring instead. Otherwise use the straight chord.\n          var straightOK = traverseInsideBoundary(last2, nextStart, drivable);\n          var traverseCoords = straightOK\n            ? [last2, nextStart]\n            : routeAlongRing(last2, nextStart, ringPasses);\n          if(traverseCoords.length >= 2){\n            for(var tc2=1; tc2<traverseCoords.length; tc2++) driveCoords.push(traverseCoords[tc2]);\n            turnArcs.push({ coords: traverseCoords, ok: true, kind: straightOK ? 'traverse' : 'ring-route' });\n            \/\/ Surface the last-resort reason so the user sees why\n            if(turn.reason ? !warning : false) warning = turn.reason;\n          }\n        }\n      }\n    }\n    return { driveCoords: driveCoords, turnArcs: turnArcs, warning: warning, orderedPasses: orderedPasses };\n  }\n\n  \/\/ Generate guidance layout for one approach. Returns:\n  \/\/   { passes: [...], headlandPoly, interiorPoly, drivable, turnArcs, drivePath, warning }\n  \/\/ The smart pipeline:\n  \/\/   1. drivable = boundary + outsideBufferM outward\n  \/\/   2. interior = boundary inward-offset by headlandM (the worked zone)\n  \/\/   3. headland = boundary minus interior (the turnaround zone)\n  \/\/   4. Passes clipped to INTERIOR (not full boundary) \u2014 endpoints sit on the\n  \/\/      inner edge of the headland by construction\n  \/\/   5. Serpentine through passes, generating turn arcs that bulge OUTWARD\n  \/\/      into the headland strip via the validation cascade\n  \/\/ For 'boundary' approach: skip interior passes, generate only the headland-\n  \/\/ following ring(s) \u2014 useful for orchards \/ grasslands where the field is\n  \/\/ worked along its perimeter.\n  \/\/ Trace a single contour line at constant elevation using a predictor-\n  \/\/ corrector scheme. Each step:\n  \/\/   PREDICT \u2014 move stepM perpendicular to the local gradient.\n  \/\/   CORRECT \u2014 sample elevation at the new point, move along the gradient\n  \/\/             by ((targetZ - currentZ) \/ |gradient|) to restore the target\n  \/\/             elevation. Keeps the path on the contour even when the\n  \/\/             terrain function is non-linear (e.g. a circular hill on the\n  \/\/             pivot field would otherwise drift off-level by step 50).\n  \/\/ Walks in `dir` (\u00b11) until it exits `clipPoly` or hits maxSteps. Returns\n  \/\/ sample points.\n  function walkContour(start, dir, clipPoly, stepM, maxSteps){\n    var pts = [{ x: start.x, y: start.y }];\n    var eps = 0.5;\n    var targetZ = terrainAt(start.x, start.y);\n    var prevPx = null, prevPy = null;\n    var closeRadius = stepM * 1.5;\n    var closeRadiusSq = closeRadius * closeRadius;\n    for(var s=0; s<maxSteps; s++){\n      \/\/ Loop detection \u2014 for closed contours (e.g. a circle around a hill\n      \/\/ peak), the walker would otherwise spin forever. Stop once we've\n      \/\/ come back within stepM \u00d7 1.5 of the seed after at least 10 steps.\n      \/\/ pts._closed flag tells the caller this contour wrapped around.\n      if(s > 10){\n        var dxS = pts[pts.length-1].x - start.x;\n        var dyS = pts[pts.length-1].y - start.y;\n        if(dxS*dxS + dyS*dyS < closeRadiusSq){ pts.push({ x: start.x, y: start.y }); pts._closed = true; break; }\n      }\n      var last = pts[pts.length - 1];\n      \/\/ Numerical gradient via central differences\n      var gx = (terrainAt(last.x + eps, last.y) - terrainAt(last.x - eps, last.y)) \/ (2 * eps);\n      var gy = (terrainAt(last.x, last.y + eps) - terrainAt(last.x, last.y - eps)) \/ (2 * eps);\n      var gLen2 = gx*gx + gy*gy;\n      if(gLen2 < 1e-12) break;\n      var gLen = Math.sqrt(gLen2);\n      \/\/ Predictor: perpendicular to gradient (rotated 90\u00b0), normalized\n      var px = -gy \/ gLen * dir;\n      var py = gx \/ gLen * dir;\n      \/\/ Smooth direction so the curve doesn't ping-pong on noisy terrain\n      if(prevPx !== null){\n        px = px * 0.7 + prevPx * 0.3;\n        py = py * 0.7 + prevPy * 0.3;\n        var pl = Math.sqrt(px*px + py*py);\n        if(pl > 1e-6){ px \/= pl; py \/= pl; }\n      }\n      prevPx = px; prevPy = py;\n      var nx = last.x + px * stepM;\n      var ny = last.y + py * stepM;\n      \/\/ Corrector: nudge back to target elevation along the local gradient\n      var nz = terrainAt(nx, ny);\n      var dz = targetZ - nz;\n      var gMag2x = (terrainAt(nx + eps, ny) - terrainAt(nx - eps, ny)) \/ (2 * eps);\n      var gMag2y = (terrainAt(nx, ny + eps) - terrainAt(nx, ny - eps)) \/ (2 * eps);\n      var gMag2sq = gMag2x*gMag2x + gMag2y*gMag2y;\n      if(gMag2sq > 1e-12){\n        var corr = dz \/ gMag2sq;\n        nx += gMag2x * corr;\n        ny += gMag2y * corr;\n      }\n      if(!pointInPoly(nx, ny, clipPoly)) break;\n      pts.push({ x: nx, y: ny });\n    }\n    return pts;\n  }\n  \/\/ Build contour-following passes from the active terrain. Spacing = wM\n  \/\/ (perpendicular implement-width), so each pass's swath tiles the next.\n  \/\/ Returns array of { samples, kind: 'adaptive' } passes clipped to\n  \/\/ `clipPoly` (the interior polygon).\n  function buildContourPasses(wM, clipPoly){\n    \/\/ 1. Find elevation range across clipPoly\n    var stats = fieldStats(clipPoly);\n    var lo = Infinity, hi = -Infinity;\n    var sampleN = 24;  \/\/ sparse sweep to find lo\/hi\n    var dxS = (stats.maxX - stats.minX) \/ sampleN;\n    var dyS = (stats.maxY - stats.minY) \/ sampleN;\n    for(var iy=0; iy<sampleN; iy++){\n      for(var ix=0; ix<sampleN; ix++){\n        var cxS = stats.minX + (ix + 0.5) * dxS;\n        var cyS = stats.minY + (iy + 0.5) * dyS;\n        if(!pointInPoly(cxS, cyS, clipPoly)) continue;\n        var z = terrainAt(cxS, cyS);\n        if(z < lo) lo = z;\n        if(z > hi) hi = z;\n      }\n    }\n    if(hi - lo < 0.3) return [];  \/\/ essentially flat \u2014 no useful contours\n    \/\/ 2. Estimate typical gradient magnitude across the field. Sampling the\n    \/\/    centroid alone fails for fields where the centroid sits on a peak\n    \/\/    or saddle (e.g. pivot \u2014 round hill at the centre \u2192 \u2207=0 there).\n    \/\/    Take 9 samples on a 3\u00d73 grid, use the median magnitude.\n    var gradSamples = [];\n    for(var gxi=0; gxi<3; gxi++){\n      for(var gyi=0; gyi<3; gyi++){\n        var sx = stats.minX + (gxi + 1) * (stats.maxX - stats.minX) \/ 4;\n        var sy = stats.minY + (gyi + 1) * (stats.maxY - stats.minY) \/ 4;\n        if(!pointInPoly(sx, sy, clipPoly)) continue;\n        var gxS = (terrainAt(sx + 1, sy) - terrainAt(sx - 1, sy)) * 0.5;\n        var gyS = (terrainAt(sx, sy + 1) - terrainAt(sx, sy - 1)) * 0.5;\n        gradSamples.push(Math.sqrt(gxS*gxS + gyS*gyS));\n      }\n    }\n    if(gradSamples.length === 0) return [];\n    gradSamples.sort(function(a, b){ return a - b; });\n    var gMag = gradSamples[Math.floor(gradSamples.length \/ 2)];  \/\/ median\n    if(gMag < 1e-4) return [];  \/\/ truly flat \u2192 no useful contours\n    var elevStep = wM * gMag;\n    \/\/ 3. Pick N levels evenly between lo+elevStep\/2 and hi-elevStep\/2\n    var nLevels = Math.max(2, Math.floor((hi - lo) \/ elevStep));\n    if(nLevels > 60) nLevels = 60;  \/\/ cap to avoid pathological terrain\n    var levels = [];\n    for(var L=0; L<nLevels; L++){\n      levels.push(lo + (L + 0.5) * (hi - lo) \/ nLevels);\n    }\n    \/\/ 4. For each level, find a seed point inside clipPoly with terrain \u2248 level\n    \/\/    then walk the contour in both directions, joining into one pass.\n    var passes = [];\n    var seedGrid = 32;\n    var sdx = (stats.maxX - stats.minX) \/ seedGrid;\n    var sdy = (stats.maxY - stats.minY) \/ seedGrid;\n    \/\/ Pre-sample on a finer grid for seeds\n    var seedZ = new Float32Array(seedGrid * seedGrid);\n    var seedIn = new Uint8Array(seedGrid * seedGrid);\n    for(var iy2=0; iy2<seedGrid; iy2++){\n      for(var ix2=0; ix2<seedGrid; ix2++){\n        var cx2 = stats.minX + (ix2 + 0.5) * sdx;\n        var cy2 = stats.minY + (iy2 + 0.5) * sdy;\n        seedZ[iy2 * seedGrid + ix2] = terrainAt(cx2, cy2);\n        seedIn[iy2 * seedGrid + ix2] = pointInPoly(cx2, cy2, clipPoly) ? 1 : 0;\n      }\n    }\n    var stepM = Math.max(2, wM * 0.4);\n    var maxSteps = 800;\n    for(var li=0; li<levels.length; li++){\n      var lv = levels[li];\n      \/\/ Find the seed cell where seedZ is closest to lv (among in-field cells)\n      var bestIdx = -1, bestDiff = Infinity;\n      for(var k=0; k<seedZ.length; k++){\n        if(!seedIn[k]) continue;\n        var diff = Math.abs(seedZ[k] - lv);\n        if(diff < bestDiff){ bestDiff = diff; bestIdx = k; }\n      }\n      if(bestIdx < 0) continue;\n      var ixS = bestIdx % seedGrid;\n      var iyS = Math.floor(bestIdx \/ seedGrid);\n      var seed = { x: stats.minX + (ixS + 0.5) * sdx, y: stats.minY + (iyS + 0.5) * sdy };\n      \/\/ Walk forward first. If it returns a closed loop, the contour is\n      \/\/ closed (e.g. circular hill) \u2014 skip the backward walk (would just\n      \/\/ trace the same loop in reverse, doubling the path length).\n      var fwd = walkContour(seed, +1, clipPoly, stepM, maxSteps);\n      var samples;\n      if(fwd._closed){\n        samples = fwd;\n      } else {\n        var bwd = walkContour(seed, -1, clipPoly, stepM, maxSteps);\n        bwd.reverse();\n        samples = bwd.concat(fwd.slice(1));\n      }\n      if(samples.length >= 4) passes.push({ samples: samples, kind: 'adaptive' });\n    }\n    return passes;\n  }\n\n  function generateLines(approach, wM, b, axis, headlandM, turnStyle, turnRadiusM, outsideBufferM){\n    var drivable = buildDrivable(b, outsideBufferM);\n    var interior = headlandM > 0 ? offsetPolygonInward(b, headlandM) : b;\n    if(!interior) interior = b;  \/\/ fallback when offset collapses\n    var ux = axis.ux, uy = axis.uy;\n    var passes = [];\n\n    \/\/ Rule \u00a713 \u2014 work the headland FIRST, then the body. Emit perimeter\n    \/\/ ring(s) at headland-strip centrelines for EVERY approach.\n    \/\/\n    \/\/ For headlandM == 1\u00d7wM: one ring at wM\/2 from boundary covers the\n    \/\/ whole strip [0, wM] with its swath.\n    \/\/\n    \/\/ For headlandM > 1\u00d7wM: drive MULTIPLE concentric rings so the full\n    \/\/ strip is covered. nRings = round(headlandM \/ wM). Ring k at perp =\n    \/\/ (k + 0.5) \u00d7 wM from boundary (k = 0..nRings-1) so swaths tile the\n    \/\/ strip without gaps.\n    if(headlandM > 0 ? interior !== b : false){\n      var nRings = Math.max(1, Math.round(headlandM \/ wM));\n      for(var rk=0; rk<nRings; rk++){\n        var ringOff = (rk + 0.5) * wM;\n        var ringRef = offsetPolygonInward(b, ringOff);\n        if(ringRef){\n          passes.push({ samples: ringRef.concat([ringRef[0]]), kind: 'headland-ring' });\n        }\n      }\n    }\n    var passClipPoly = interior;\n    \/\/ Boundary Follow used to shrink the body interior by another 0.75 \u00d7 wM\n    \/\/ to avoid overlap between ring and body swaths. That created a 0.75 \u00d7 wM\n    \/\/ UNCOVERED strip between the ring's swath edge and the first body pass.\n    \/\/ Per the user \u2014 maximise coverage \u2014 body passes now use the full\n    \/\/ interior, accepting a small (~0\u201325 %) overlap at the ring\/body\n    \/\/ boundary, which is standard agronomic practice (5\u201310 % overlap is\n    \/\/ routine for headland edges).\n    \/\/ Contour-follow (terrain-aware) \u2014 generate passes that trace level\n    \/\/ curves of the terrain function. Each pass walks perpendicular to the\n    \/\/ local gradient at wM spacing. Falls back to AB-curve synthetic waves\n    \/\/ when terrain is too flat (or uploaded-no-terrain).\n    if(approach === 'adaptive'){\n      var contourPasses = buildContourPasses(wM, passClipPoly);\n      if(contourPasses.length >= 2){\n        for(var cp=0; cp<contourPasses.length; cp++) passes.push(contourPasses[cp]);\n        var serpC = buildSerpentine(passes, drivable, interior, axis, turnStyle, turnRadiusM, wM * 0.5, wM);\n        return {\n          passes: passes,\n          interior: interior,\n          drivable: drivable,\n          boundary: b,\n          turnArcs: serpC.turnArcs,\n          drivePath: serpC.driveCoords,\n          warning: serpC.warning,\n          orderedPasses: serpC.orderedPasses\n        };\n      }\n      \/\/ else: flat \/ uploaded field \u2192 fall through to the synthetic-wave code\n      \/\/ below (still labelled adaptive but won't actually follow terrain).\n    }\n\n    \/\/ AB Straight \/ AB Curve \/ Adaptive (synthetic) \/ Boundary body \u2014 parallel\n    \/\/ offsets clipped to `passClipPoly`.\n    var perpMin = Infinity, perpMax = -Infinity;\n    var alongMin = Infinity, alongMax = -Infinity;\n    for(var i=0; i<passClipPoly.length; i++){\n      var along = passClipPoly[i].x * ux + passClipPoly[i].y * uy;\n      var perp = -passClipPoly[i].x * uy + passClipPoly[i].y * ux;\n      if(perp < perpMin) perpMin = perp;\n      if(perp > perpMax) perpMax = perp;\n      if(along < alongMin) alongMin = along;\n      if(along > alongMax) alongMax = along;\n    }\n    var startPerp = perpMin + wM * 0.5;\n    var endPerp = perpMax - wM * 0.5;\n    var alongSpan = alongMax - alongMin;\n    for(var pp = startPerp; pp <= endPerp + 1e-6; pp += wM){\n      var p0Along = alongMin - alongSpan * 0.1;\n      var p1Along = alongMax + alongSpan * 0.1;\n      var startX = p0Along * ux - pp * uy;\n      var startY = p0Along * uy + pp * ux;\n      var endX = p1Along * ux - pp * uy;\n      var endY = p1Along * uy + pp * ux;\n      \/\/ Use the multi-segment clipper so concave polygons (L-shape interior!)\n      \/\/ produce one pass per \"inside\" segment when the line crosses a gap.\n      var clippedSegs = clipLineToBoundarySegments(startX, startY, endX, endY, passClipPoly);\n      if(!clippedSegs) continue;\n      for(var cs=0; cs<clippedSegs.length; cs++){\n        var clipped = clippedSegs[cs];\n        if(approach === 'ab-curve' || approach === 'adaptive'){\n          var dxC = clipped.x1 - clipped.x0;\n          var dyC = clipped.y1 - clipped.y0;\n          var lenL = Math.sqrt(dxC*dxC + dyC*dyC);\n          var nSamp = Math.max(8, Math.floor(lenL \/ (wM * 0.6)));\n          var samps = [];\n          var amplitude = approach === 'adaptive' ? wM * 0.35 : wM * 0.15;\n          var freq = approach === 'adaptive' ? 2.8 : 1.4;\n          var phase = (pp - perpMin) \/ wM;\n          for(var ss=0; ss<=nSamp; ss++){\n            var t = nSamp > 0 ? ss \/ nSamp : 0;\n            var bxs = clipped.x0 + dxC * t;\n            var bys = clipped.y0 + dyC * t;\n            var wave = Math.sin(t * Math.PI * freq + phase) * amplitude;\n            bxs += -uy * wave;\n            bys += ux * wave;\n            samps.push({ x: bxs, y: bys });\n          }\n          passes.push({ samples: samps, kind: approach });\n        } else {\n          passes.push({ x0: clipped.x0, y0: clipped.y0, x1: clipped.x1, y1: clipped.y1, kind: approach });\n        }\n      }\n    }\n    var serp = buildSerpentine(passes, drivable, interior, axis, turnStyle, turnRadiusM, wM * 0.5, wM);\n    return {\n      passes: passes,\n      interior: interior,\n      drivable: drivable,\n      boundary: b,\n      turnArcs: serp.turnArcs,\n      drivePath: serp.driveCoords,\n      warning: serp.warning,\n      orderedPasses: serp.orderedPasses\n    };\n  }\n\n  \/\/ Rasterise the layout's swath onto a grid covering the field bbox. For\n  \/\/ each cell whose centre is inside the boundary AND within wM\/2 of any\n  \/\/ pass-centerline or ring-centerline segment, mark it covered. Returns\n  \/\/ { coveredM2, fieldM2, pct }. cellSize defaults to ~wM\/3 so cells are\n  \/\/ smaller than the swath \u2014 under-fill near corners is captured honestly.\n  function rasterCoverage(layout, wM){\n    var b = layout.boundary ? layout.boundary : BOUNDARY;\n    var stats = fieldStats(b);\n    var cellSize = Math.max(2, wM \/ 3);\n    var nx = Math.max(8, Math.ceil((stats.maxX - stats.minX) \/ cellSize));\n    var ny = Math.max(8, Math.ceil((stats.maxY - stats.minY) \/ cellSize));\n    \/\/ First pass: mark cells inside the field boundary\n    var inField = new Uint8Array(nx * ny);\n    var fieldCellCount = 0;\n    for(var iy=0; iy<ny; iy++){\n      for(var ix=0; ix<nx; ix++){\n        var cx = stats.minX + (ix + 0.5) * cellSize;\n        var cy = stats.minY + (iy + 0.5) * cellSize;\n        if(pointInPoly(cx, cy, b)){\n          inField[iy * nx + ix] = 1;\n          fieldCellCount++;\n        }\n      }\n    }\n    \/\/ Collect all swath segments \u2014 body-pass segments and ring segments.\n    var segs = [];\n    if(layout.passes){\n      for(var pi=0; pi<layout.passes.length; pi++){\n        var pa = layout.passes[pi];\n        if(pa.samples){\n          for(var si=1; si<pa.samples.length; si++){\n            segs.push({ x0: pa.samples[si-1].x, y0: pa.samples[si-1].y, x1: pa.samples[si].x, y1: pa.samples[si].y });\n          }\n        } else if(pa.x0 !== undefined){\n          segs.push({ x0: pa.x0, y0: pa.y0, x1: pa.x1, y1: pa.y1 });\n        }\n      }\n    }\n    if(segs.length === 0){\n      return { coveredM2: 0, fieldM2: fieldCellCount * cellSize * cellSize, pct: 0 };\n    }\n    \/\/ Second pass: for each in-field cell, check distance to nearest segment.\n    \/\/ O(cells \u00d7 segs) \u2014 acceptable for sample-sized fields (~6000 \u00d7 20 \u2248 120k).\n    var half = wM * 0.5;\n    var half2 = half * half;\n    var covered = new Uint8Array(nx * ny);\n    var coveredCount = 0;\n    for(var iy2=0; iy2<ny; iy2++){\n      for(var ix2=0; ix2<nx; ix2++){\n        var idx = iy2 * nx + ix2;\n        if(!inField[idx]) continue;\n        var cxC = stats.minX + (ix2 + 0.5) * cellSize;\n        var cyC = stats.minY + (iy2 + 0.5) * cellSize;\n        for(var sg=0; sg<segs.length; sg++){\n          var s = segs[sg];\n          \/\/ Squared distance from (cxC,cyC) to segment s\n          var sdx = s.x1 - s.x0, sdy = s.y1 - s.y0;\n          var L2 = sdx*sdx + sdy*sdy;\n          var t = L2 > 1e-9 ? ((cxC - s.x0) * sdx + (cyC - s.y0) * sdy) \/ L2 : 0;\n          if(t < 0) t = 0; else if(t > 1) t = 1;\n          var px2 = s.x0 + sdx * t - cxC;\n          var py2 = s.y0 + sdy * t - cyC;\n          var dist2 = px2*px2 + py2*py2;\n          if(dist2 <= half2){ covered[idx] = 1; coveredCount++; break; }\n        }\n      }\n    }\n    var cellArea = cellSize * cellSize;\n    var fieldM2 = fieldCellCount * cellArea;\n    var coveredM2 = coveredCount * cellArea;\n    return { coveredM2: coveredM2, fieldM2: fieldM2, pct: fieldM2 > 0 ? (coveredM2 \/ fieldM2 * 100) : 0 };\n  }\n\n  function computeMetrics(layout, wM, dieselPrice, consumption){\n    \/\/ Pass (tramline) length only \u2014 what the operator actually works on.\n    var passLen = 0;\n    var nPasses = layout.passes.length;\n    for(var i=0; i<nPasses; i++){\n      var p = layout.passes[i];\n      if(p.samples){\n        for(var s=1; s<p.samples.length; s++){\n          var dx = p.samples[s].x - p.samples[s-1].x;\n          var dy = p.samples[s].y - p.samples[s-1].y;\n          passLen += Math.sqrt(dx*dx + dy*dy);\n        }\n      } else {\n        var dxL = p.x1 - p.x0, dyL = p.y1 - p.y0;\n        passLen += Math.sqrt(dxL*dxL + dyL*dyL);\n      }\n    }\n    \/\/ Turn-arc length \u2014 what the operator drives BETWEEN passes (header up).\n    var turnLen = 0;\n    var nTurns = layout.turnArcs ? layout.turnArcs.length : 0;\n    if(layout.turnArcs){\n      for(var ti=0; ti<layout.turnArcs.length; ti++){\n        var arc = layout.turnArcs[ti].coords;\n        for(var as=1; as<arc.length; as++){\n          var dxA = arc[as].x - arc[as-1].x, dyA = arc[as].y - arc[as-1].y;\n          turnLen += Math.sqrt(dxA*dxA + dyA*dyA);\n        }\n      }\n    }\n    \/\/ Total drive path = tramline + turn arcs.\n    \/\/ Pass fuel scales linearly with consumption \u00d7 length, PLUS a slope\n    \/\/ penalty: driving along a contour line is normal-fuel; driving across\n    \/\/ contours (uphill\/downhill) penalises ~10\u00d7 the absolute grade\u00b2. Real\n    \/\/ tractors burn 30\u201340 % more diesel at a sustained 5 % up-grade.\n    \/\/ Turnaround fuel is 1.25\u00d7 per metre because the engine works harder\n    \/\/ under a tight pivot (hydraulics raising\/lowering the implement,\n    \/\/ gear changes) \u2014 typical headland-turn penalty.\n    var totalLen = passLen + turnLen;\n    var slopePenalty = computeSlopePenalty(layout);\n    var passFuelBase = (passLen \/ 1000) * consumption;\n    var passFuel = passFuelBase * (1 + slopePenalty);\n    var turnFuel = (turnLen \/ 1000) * consumption * 1.25;\n    var totalFuel = passFuel + turnFuel;\n    var cost = totalFuel * dieselPrice;\n    \/\/ Coverage \u2014 RASTER-BASED for accuracy. Sum-of-strip math overstated\n    \/\/ (double-counted overlaps, ignored corner gaps and headland-ring under-fill\n    \/\/ at sharp corners) \u2192 clamped to 100% even when the real coverage was <95%.\n    \/\/ The grid approach computes the true union area: for each cell whose\n    \/\/ centre lies inside the field boundary, check if it's also inside any\n    \/\/ swath strip. coveragePct = covered \/ total. cellSize defaults to wM\/3\n    \/\/ so cells are smaller than the swath, capturing under-coverage near\n    \/\/ corners and uncovered pockets in concave fields.\n    var stats = fieldStats(layout.boundary ? layout.boundary : BOUNDARY);\n    var fieldM2 = stats.area;\n    var coverageRes = rasterCoverage(layout, wM);\n    var coveredM2 = coverageRes.coveredM2;\n    var coveragePct = coverageRes.pct;\n    return {\n      passes: nPasses,\n      passLengthM: passLen,\n      turnLengthM: turnLen,\n      totalDriveM: totalLen,\n      turns: nTurns,\n      fuelL: totalFuel,\n      passFuelL: passFuel,\n      turnFuelL: turnFuel,\n      costUSD: cost,\n      coveragePct: coveragePct,\n      coveredM2: coveredM2,\n      fieldM2: fieldM2,\n      slopePenalty: slopePenalty,\n      avgGradePct: layout.avgGradePct || 0\n    };\n  }\n  \/\/ Compute average grade-along-pass-direction for body passes, returns\n  \/\/ a fuel multiplier penalty (0 = flat, 0.3 = 30% extra fuel). Also stores\n  \/\/ the average absolute grade % on the layout for display. Penalty model:\n  \/\/   penalty = k \u00d7 mean(|grade|\u00b2) where grade = \u0394z \/ \u0394horizontal\n  \/\/   k = 12 \u2192 5% sustained grade \u2192 0.03 penalty (3% extra fuel), 15% grade \u2192 27% extra\n  \/\/ Cross-contour passes accumulate full slope; on-contour passes accumulate ~0.\n  function computeSlopePenalty(layout){\n    if(!layout.passes ? true : layout.passes.length === 0) return 0;\n    var totalLen = 0;\n    var weightedGrade2 = 0;\n    var weightedAbsGrade = 0;\n    var sampleStep = 4;  \/\/ metres\n    function accumulateSeg(x0, y0, x1, y1){\n      var sdx = x1 - x0, sdy = y1 - y0;\n      var L = Math.sqrt(sdx*sdx + sdy*sdy);\n      if(L < 0.5) return;\n      var nS = Math.max(2, Math.ceil(L \/ sampleStep));\n      var z0 = terrainAt(x0, y0);\n      for(var k=1; k<=nS; k++){\n        var t = k \/ nS;\n        var mx = x0 + sdx * t, my = y0 + sdy * t;\n        var z1 = terrainAt(mx, my);\n        var dh = L \/ nS;\n        var grade = dh > 1e-6 ? (z1 - z0) \/ dh : 0;\n        weightedGrade2 += grade * grade * dh;\n        weightedAbsGrade += Math.abs(grade) * dh;\n        totalLen += dh;\n        z0 = z1;\n      }\n    }\n    for(var pi=0; pi<layout.passes.length; pi++){\n      var pa = layout.passes[pi];\n      if(pa.kind === 'headland-ring') continue;  \/\/ ring follows boundary, ignore slope cost\n      if(pa.samples){\n        for(var si=1; si<pa.samples.length; si++){\n          accumulateSeg(pa.samples[si-1].x, pa.samples[si-1].y, pa.samples[si].x, pa.samples[si].y);\n        }\n      } else if(pa.x0 !== undefined){\n        accumulateSeg(pa.x0, pa.y0, pa.x1, pa.y1);\n      }\n    }\n    if(totalLen < 1) return 0;\n    var meanGrade2 = weightedGrade2 \/ totalLen;\n    var meanAbsGrade = weightedAbsGrade \/ totalLen;\n    layout.avgGradePct = meanAbsGrade * 100;  \/\/ for display\n    return 12 * meanGrade2;  \/\/ penalty multiplier\n  }\n\n  \/\/ RENDER\n  var DPR = window.devicePixelRatio > 1 ? window.devicePixelRatio : 1;\n  function resize(){\n    var rect = canvas.getBoundingClientRect();\n    canvas.width = Math.floor(rect.width * DPR);\n    canvas.height = Math.floor(rect.height * DPR);\n    ctx.setTransform(DPR, 0, 0, DPR, 0, 0);\n  }\n  \/\/ View transform \u2014 fit-to-field is the base, then user can zoom\/pan around.\n  var view = { zoom: 1, panX: 0, panY: 0 };\n  function getScale(){\n    var rect = canvas.getBoundingClientRect();\n    var pad = 36;\n    var s = fieldStats(BOUNDARY);\n    var sx = (rect.width - pad * 2) \/ (s.maxX - s.minX);\n    var sy = (rect.height - pad * 2) \/ (s.maxY - s.minY);\n    var sc = (sx < sy ? sx : sy) * view.zoom;\n    var baseTx = pad - s.minX * sc + (rect.width - pad * 2 - (s.maxX - s.minX) * sc) \/ 2;\n    var baseTy = pad - s.minY * sc + (rect.height - pad * 2 - (s.maxY - s.minY) * sc) \/ 2;\n    return { sc: sc, tx: baseTx + view.panX, ty: baseTy + view.panY };\n  }\n  function px(proj, x){ return x * proj.sc + proj.tx; }\n  function py(proj, y){ return y * proj.sc + proj.ty; }\n  \/\/ Inverse: screen \u2192 world coordinates (used by ruler + pan).\n  function worldX(proj, sx){ return (sx - proj.tx) \/ proj.sc; }\n  function worldY(proj, sy){ return (sy - proj.ty) \/ proj.sc; }\n\n  \/\/ Unit + ruler state\n  var unit = 'km';\n  var ruler = { active: false, p1: null, p2: null };\n  function fmtDist(metres){\n    if(unit === 'mi'){\n      var mi = metres \/ 1609.344;\n      if(mi >= 0.2) return mi.toFixed(2) + ' mi';\n      var ft = metres * 3.28084;\n      return ft.toFixed(0) + ' ft';\n    }\n    if(metres >= 1000) return (metres \/ 1000).toFixed(2) + ' km';\n    return metres.toFixed(0) + ' m';\n  }\n\n  \/\/ PLAYBACK STATE \u2014 animates a tractor sprite along the drive path with a\n  \/\/ gradually-filling swath band behind it. Speed is \"wall-clock \u00d7 multiplier\";\n  \/\/ we map ~1 km of drive-path per second of wall clock at 1\u00d7 so a typical\n  \/\/ field plays out in 10\u201320 s.\n  var playback = {\n    isPlaying: false,\n    t: 0,              \/\/ 0..1 progress along total drive-path length\n    speed: 1,          \/\/ 1 \/ 2 \/ 4 multiplier\n    drivePath: [],\n    cumLen: [0],       \/\/ cumulative length to each vertex\n    totalLen: 0,       \/\/ metres\n    wM: 18,            \/\/ implement width for swath\n    lastTick: 0\n  };\n  \/\/ Build (or rebuild) the playback path from a layout. Resets progress.\n  \/\/ Subdivides long segments (line-based passes can be 600 m end-to-end) so\n  \/\/ the sprite advances smoothly instead of skipping in big chunks (which\n  \/\/ looked like \"teleports\" at 4\u00d7 speed).\n  function setPlaybackPath(layout, wM){\n    var raw = layout.drivePath ? layout.drivePath : [];\n    var maxStep = Math.max(2, wM);  \/\/ never exceed one implement-width per drive-path segment\n    var dense = [];\n    for(var k=0; k<raw.length; k++){\n      if(k === 0){ dense.push(raw[0]); continue; }\n      var prev = raw[k - 1], cur = raw[k];\n      var ddx = cur.x - prev.x, ddy = cur.y - prev.y;\n      var dlen = Math.sqrt(ddx*ddx + ddy*ddy);\n      if(dlen > maxStep){\n        var nSub = Math.ceil(dlen \/ maxStep);\n        for(var ns=1; ns<nSub; ns++){\n          var f = ns \/ nSub;\n          dense.push({ x: prev.x + ddx * f, y: prev.y + ddy * f });\n        }\n      }\n      dense.push(cur);\n    }\n    playback.drivePath = dense;\n    playback.wM = wM;\n    playback.cumLen = [0];\n    var total = 0;\n    for(var i=1; i<playback.drivePath.length; i++){\n      var dx = playback.drivePath[i].x - playback.drivePath[i-1].x;\n      var dy = playback.drivePath[i].y - playback.drivePath[i-1].y;\n      total += Math.sqrt(dx*dx + dy*dy);\n      playback.cumLen.push(total);\n    }\n    playback.totalLen = total;\n    playback.t = 0;\n    updatePlaybackUI();\n  }\n  \/\/ Return the (x, y, headingRad) at parametric position t (0..1) along the path.\n  function playbackPosAt(t){\n    if(playback.drivePath.length < 2) return null;\n    var target = t * playback.totalLen;\n    var lo = 0, hi = playback.cumLen.length - 1;\n    while(lo < hi){\n      var mid = (lo + hi + 1) >> 1;\n      if(playback.cumLen[mid] <= target) lo = mid; else hi = mid - 1;\n    }\n    if(lo >= playback.drivePath.length - 1) lo = playback.drivePath.length - 2;\n    var segLen = playback.cumLen[lo + 1] - playback.cumLen[lo];\n    var f = segLen > 1e-6 ? (target - playback.cumLen[lo]) \/ segLen : 0;\n    var p0 = playback.drivePath[lo];\n    var p1 = playback.drivePath[lo + 1];\n    return {\n      x: p0.x + (p1.x - p0.x) * f,\n      y: p0.y + (p1.y - p0.y) * f,\n      heading: Math.atan2(p1.y - p0.y, p1.x - p0.x),\n      segIdx: lo\n    };\n  }\n  function updatePlaybackUI(){\n    var fillEl = document.getElementById('gpl-pb-fill');\n    var thumbEl = document.getElementById('gpl-pb-thumb');\n    var statsEl = document.getElementById('gpl-pb-stats');\n    var pct = (playback.t * 100).toFixed(0);\n    if(fillEl) fillEl.style.width = pct + '%';\n    if(thumbEl) thumbEl.style.left = pct + '%';\n    if(statsEl){\n      statsEl.textContent = pct + '% \u00b7 ' + fmtDist(playback.t * playback.totalLen) + ' \/ ' + fmtDist(playback.totalLen);\n    }\n  }\n  function drawSwath(proj){\n    if(playback.drivePath.length < 2 ? true : playback.t <= 0) return;\n    var target = playback.t * playback.totalLen;\n    var halfW = playback.wM * 0.5 * proj.sc;\n    if(halfW < 1) halfW = 1;\n    ctx.save();\n    ctx.strokeStyle = 'rgba(247,106,12,0.32)';\n    ctx.lineWidth = halfW * 2;\n    ctx.lineCap = 'round';\n    ctx.lineJoin = 'round';\n    ctx.beginPath();\n    ctx.moveTo(px(proj, playback.drivePath[0].x), py(proj, playback.drivePath[0].y));\n    for(var i=1; i<playback.drivePath.length; i++){\n      if(playback.cumLen[i] <= target){\n        ctx.lineTo(px(proj, playback.drivePath[i].x), py(proj, playback.drivePath[i].y));\n      } else {\n        var segLen = playback.cumLen[i] - playback.cumLen[i-1];\n        var f = segLen > 1e-6 ? (target - playback.cumLen[i-1]) \/ segLen : 0;\n        var ex = playback.drivePath[i-1].x + (playback.drivePath[i].x - playback.drivePath[i-1].x) * f;\n        var ey = playback.drivePath[i-1].y + (playback.drivePath[i].y - playback.drivePath[i-1].y) * f;\n        ctx.lineTo(px(proj, ex), py(proj, ey));\n        break;\n      }\n    }\n    ctx.stroke();\n    ctx.restore();\n  }\n  \/\/ GeoPard-brand elevation rainbow: 5 keypoints spanning t \u2208 [0, 1]\n  \/\/   0.00 \u2192 deep purple (low)\n  \/\/   0.25 \u2192 teal \/ cyan\n  \/\/   0.50 \u2192 soft yellow\n  \/\/   0.75 \u2192 orange\n  \/\/   1.00 \u2192 red (high)\n  \/\/ Linearly interpolated between adjacent stops in RGB space. Matches the\n  \/\/ colour scheme used in the GeoPard Platform's elevation legend.\n  var ELEV_STOPS = [\n    [109,  79, 162],   \/\/ 0.00 \u2014 purple\n    [ 78, 192, 167],   \/\/ 0.25 \u2014 teal\n    [255, 232, 130],   \/\/ 0.50 \u2014 yellow\n    [245, 168,  92],   \/\/ 0.75 \u2014 orange\n    [219,  80,  80]    \/\/ 1.00 \u2014 red\n  ];\n  function elevColor(t){\n    if(t <= 0) return ELEV_STOPS[0];\n    if(t >= 1) return ELEV_STOPS[ELEV_STOPS.length - 1];\n    var seg = t * (ELEV_STOPS.length - 1);\n    var i = Math.floor(seg);\n    var f = seg - i;\n    var a = ELEV_STOPS[i], b = ELEV_STOPS[i + 1];\n    return [\n      Math.round(a[0] + (b[0] - a[0]) * f),\n      Math.round(a[1] + (b[1] - a[1]) * f),\n      Math.round(a[2] + (b[2] - a[2]) * f)\n    ];\n  }\n  \/\/ Terrain heatmap \u2014 translucent rainbow gradient showing elevation.\n  \/\/ Higher cell density (48\u00d736) + GeoPard brand colours @ 0.6 alpha so the\n  \/\/ elevation pattern reads clearly while passes \/ arcs \/ sprite stay legible.\n  function drawTerrain(proj){\n    if(currentField === 'custom') return;  \/\/ no synthetic terrain for uploaded\n    var stats = fieldStats(BOUNDARY);\n    var nx = 48, ny = 36;\n    var dx = (stats.maxX - stats.minX) \/ nx;\n    var dy = (stats.maxY - stats.minY) \/ ny;\n    \/\/ Find elevation range across cells inside the boundary\n    var lo = Infinity, hi = -Infinity;\n    var grid = new Float32Array(nx * ny);\n    for(var iy=0; iy<ny; iy++){\n      for(var ix=0; ix<nx; ix++){\n        var cx = stats.minX + (ix + 0.5) * dx;\n        var cy = stats.minY + (iy + 0.5) * dy;\n        var z = terrainAt(cx, cy);\n        grid[iy * nx + ix] = z;\n        if(pointInPoly(cx, cy, BOUNDARY)){\n          if(z < lo) lo = z;\n          if(z > hi) hi = z;\n        }\n      }\n    }\n    if(hi - lo < 0.5) return;\n    ctx.save();\n    for(var iy2=0; iy2<ny; iy2++){\n      for(var ix2=0; ix2<nx; ix2++){\n        var cx2 = stats.minX + (ix2 + 0.5) * dx;\n        var cy2 = stats.minY + (iy2 + 0.5) * dy;\n        if(!pointInPoly(cx2, cy2, BOUNDARY)) continue;\n        var z2 = grid[iy2 * nx + ix2];\n        var t = (z2 - lo) \/ (hi - lo);\n        var c = elevColor(t);\n        ctx.fillStyle = 'rgba(' + c[0] + ',' + c[1] + ',' + c[2] + ',0.6)';\n        var x0 = px(proj, stats.minX + ix2 * dx);\n        var y0 = py(proj, stats.minY + iy2 * dy);\n        var x1 = px(proj, stats.minX + (ix2 + 1) * dx);\n        var y1 = py(proj, stats.minY + (iy2 + 1) * dy);\n        ctx.fillRect(x0 - 0.5, y0 - 0.5, (x1 - x0) + 1, (y1 - y0) + 1);\n      }\n    }\n    ctx.restore();\n  }\n\n  \/\/ Soil compaction zones \u2014 wherever the machine turns around, it's compacting\n  \/\/ the headland strip soil with extra passes. Visualise as translucent violet\n  \/\/ strokes under each turn-arc swath; multiple nearby arcs additively darken\n  \/\/ the same area, making heavy-compaction clusters visible.\n  function drawCompactionZones(proj, layout){\n    if(!layout.turnArcs ? true : layout.turnArcs.length === 0) return;\n    var halfW = playback.wM * 0.5 * proj.sc;\n    if(halfW < 1) halfW = 1;\n    ctx.save();\n    ctx.strokeStyle = 'rgba(162,28,175,0.22)';  \/\/ violet, 22% alpha so overlaps stack visibly\n    ctx.lineWidth = halfW * 2;\n    ctx.lineCap = 'round';\n    ctx.lineJoin = 'round';\n    for(var ti=0; ti<layout.turnArcs.length; ti++){\n      var arc = layout.turnArcs[ti];\n      if(arc.coords.length < 2) continue;\n      ctx.beginPath();\n      ctx.moveTo(px(proj, arc.coords[0].x), py(proj, arc.coords[0].y));\n      for(var ac=1; ac<arc.coords.length; ac++){\n        ctx.lineTo(px(proj, arc.coords[ac].x), py(proj, arc.coords[ac].y));\n      }\n      ctx.stroke();\n    }\n    ctx.restore();\n  }\n  \/\/ Direction arrows \u2014 small chevron at the middle of each pass + arc, pointing\n  \/\/ along the drive direction. Makes the snake\/serpentine flow visible.\n  function drawDirectionArrows(proj, layout){\n    var arrowPx = 8;\n    function drawArrow(midX, midY, headingRad, color){\n      ctx.save();\n      ctx.translate(midX, midY);\n      ctx.rotate(headingRad);\n      ctx.fillStyle = color;\n      ctx.beginPath();\n      ctx.moveTo(arrowPx, 0);\n      ctx.lineTo(-arrowPx * 0.6, -arrowPx * 0.6);\n      ctx.lineTo(-arrowPx * 0.6, arrowPx * 0.6);\n      ctx.closePath();\n      ctx.fill();\n      ctx.restore();\n    }\n    \/\/ Pass arrows \u2014 orange to match the pass strokes. Use orderedPasses\n    \/\/ (post-snake, drive-direction oriented) so chevrons match actual flow:\n    \/\/ odd passes get reversed arrows, mirroring the operator's reverse drive.\n    var passList = layout.orderedPasses ? layout.orderedPasses : layout.passes;\n    if(passList){\n      for(var p=0; p<passList.length; p++){\n        var pa = passList[p];\n        if(pa.kind === 'headland-ring') continue;\n        var ax, ay, bx, by;\n        if(pa.samples ? pa.samples.length >= 2 : false){\n          var midI = Math.floor(pa.samples.length \/ 2);\n          ax = pa.samples[midI - 1].x; ay = pa.samples[midI - 1].y;\n          bx = pa.samples[midI].x;     by = pa.samples[midI].y;\n        } else if(pa.x0 !== undefined){\n          ax = pa.x0; ay = pa.y0; bx = pa.x1; by = pa.y1;\n        } else continue;\n        var midX = px(proj, (ax + bx) * 0.5);\n        var midY = py(proj, (ay + by) * 0.5);\n        drawArrow(midX, midY, Math.atan2(by - ay, bx - ax), '#f76a0c');\n      }\n    }\n    \/\/ Turnaround arrows \u2014 violet, halfway through the arc\n    if(layout.turnArcs){\n      for(var ti=0; ti<layout.turnArcs.length; ti++){\n        var arc = layout.turnArcs[ti].coords;\n        if(arc.length < 3) continue;\n        var mi = Math.floor(arc.length \/ 2);\n        var aX = arc[mi - 1].x, aY = arc[mi - 1].y;\n        var bX = arc[mi].x,     bY = arc[mi].y;\n        var amX = px(proj, (aX + bX) * 0.5);\n        var amY = py(proj, (aY + bY) * 0.5);\n        drawArrow(amX, amY, Math.atan2(bY - aY, bX - aX), '#a21caf');\n      }\n    }\n  }\n  function drawSprite(proj){\n    var pos = playbackPosAt(playback.t);\n    if(!pos) return;\n    var halfW = playback.wM * 0.5 * proj.sc;\n    if(halfW < 6) halfW = 6;\n    var bodyLen = Math.max(10, halfW * 0.6);\n    ctx.save();\n    ctx.translate(px(proj, pos.x), py(proj, pos.y));\n    ctx.rotate(pos.heading);\n    \/\/ Implement bar (the wide piece behind the cab \u2014 orange to match passes)\n    ctx.fillStyle = '#f76a0c';\n    ctx.fillRect(-bodyLen * 0.4, -halfW, bodyLen * 0.35, halfW * 2);\n    \/\/ Tractor cab (compact dark-green block in front of the implement)\n    ctx.fillStyle = '#145328';\n    ctx.fillRect(0, -bodyLen * 0.35, bodyLen * 0.55, bodyLen * 0.7);\n    \/\/ Cab roof\n    ctx.fillStyle = '#1a7951';\n    ctx.fillRect(bodyLen * 0.1, -bodyLen * 0.22, bodyLen * 0.3, bodyLen * 0.44);\n    ctx.restore();\n  }\n\n  function draw(layout){\n    var rect = canvas.getBoundingClientRect();\n    ctx.clearRect(0, 0, rect.width, rect.height);\n    var proj = getScale();\n    var boundary = layout.boundary ? layout.boundary : BOUNDARY;\n    var hasHeadland = layout.interior ? layout.interior !== boundary : false;\n    \/\/ Terrain heatmap behind everything\n    drawTerrain(proj);\n    \/\/ Headland strip = boundary minus interior (even-odd fill)\n    if(hasHeadland){\n      ctx.save();\n      ctx.fillStyle = 'rgba(26,121,81,0.18)';\n      ctx.beginPath();\n      for(var i=0; i<boundary.length; i++){\n        var bx = px(proj, boundary[i].x);\n        var by = py(proj, boundary[i].y);\n        if(i === 0) ctx.moveTo(bx, by); else ctx.lineTo(bx, by);\n      }\n      ctx.closePath();\n      var inner = layout.interior;\n      for(var j=inner.length-1; j>=0; j--){\n        var ix = px(proj, inner[j].x);\n        var iy = py(proj, inner[j].y);\n        if(j === inner.length-1) ctx.moveTo(ix, iy); else ctx.lineTo(ix, iy);\n      }\n      ctx.closePath();\n      ctx.fill('evenodd');\n      ctx.restore();\n    }\n    \/\/ Drivable outline (only if outsideBuffer > 0 \u2192 drivable \u2260 boundary)\n    if(layout.drivable ? layout.drivable !== boundary : false){\n      ctx.save();\n      ctx.strokeStyle = 'rgba(20,83,40,0.35)';\n      ctx.setLineDash([4, 4]);\n      ctx.lineWidth = 1;\n      ctx.beginPath();\n      for(var dv=0; dv<layout.drivable.length; dv++){\n        var dvx = px(proj, layout.drivable[dv].x);\n        var dvy = py(proj, layout.drivable[dv].y);\n        if(dv === 0) ctx.moveTo(dvx, dvy); else ctx.lineTo(dvx, dvy);\n      }\n      ctx.closePath();\n      ctx.stroke();\n      ctx.restore();\n    }\n    \/\/ Field boundary\n    ctx.save();\n    ctx.strokeStyle = '#145328';\n    ctx.lineWidth = 2;\n    ctx.lineJoin = 'round';\n    ctx.beginPath();\n    for(var k=0; k<boundary.length; k++){\n      var bxF = px(proj, boundary[k].x);\n      var byF = py(proj, boundary[k].y);\n      if(k === 0) ctx.moveTo(bxF, byF); else ctx.lineTo(bxF, byF);\n    }\n    ctx.closePath();\n    ctx.stroke();\n    ctx.restore();\n    \/\/ Interior outline (inner edge of headland strip)\n    if(hasHeadland){\n      ctx.save();\n      ctx.strokeStyle = '#1a7951';\n      ctx.lineWidth = 1.5;\n      ctx.beginPath();\n      for(var rp=0; rp<layout.interior.length; rp++){\n        var rx = px(proj, layout.interior[rp].x);\n        var ry = py(proj, layout.interior[rp].y);\n        if(rp === 0) ctx.moveTo(rx, ry); else ctx.lineTo(rx, ry);\n      }\n      ctx.closePath();\n      ctx.stroke();\n      ctx.restore();\n    }\n    \/\/ Soil compaction zones (always-visible violet glow under each turn arc)\n    drawCompactionZones(proj, layout);\n    \/\/ Swath coverage band (filled as playback progresses)\n    drawSwath(proj);\n    \/\/ Passes (the worked guidance lines)\n    ctx.save();\n    ctx.strokeStyle = '#f76a0c';\n    ctx.lineWidth = 1.2;\n    ctx.lineCap = 'round';\n    for(var p=0; p<layout.passes.length; p++){\n      var pa = layout.passes[p];\n      ctx.beginPath();\n      if(pa.samples){\n        for(var ps=0; ps<pa.samples.length; ps++){\n          var ssx = px(proj, pa.samples[ps].x);\n          var ssy = py(proj, pa.samples[ps].y);\n          if(ps === 0) ctx.moveTo(ssx, ssy); else ctx.lineTo(ssx, ssy);\n        }\n      } else {\n        ctx.moveTo(px(proj, pa.x0), py(proj, pa.y0));\n        ctx.lineTo(px(proj, pa.x1), py(proj, pa.y1));\n      }\n      ctx.stroke();\n    }\n    ctx.restore();\n    \/\/ Turn arcs \u2014 purple solid for ok U-turns, red dashed for problem arcs,\n    \/\/ teal dotted for headland traverses (no synthetic u-turn \u2014 operator did\n    \/\/ small pivots + drove across the worked headland).\n    if(layout.turnArcs ? layout.turnArcs.length : false){\n      ctx.save();\n      ctx.lineCap = 'round';\n      ctx.lineJoin = 'round';\n      for(var ti=0; ti<layout.turnArcs.length; ti++){\n        var arc = layout.turnArcs[ti];\n        var isTraverse = arc.kind === 'traverse';\n        var isRingRoute = arc.kind === 'ring-route';\n        if(isTraverse){\n          \/\/ Short straight-line traverses \u2014 still real turnarounds, render\n          \/\/ with the same violet but dashed so the user sees they exist.\n          ctx.strokeStyle = '#a21caf';\n          ctx.lineWidth = 1.8;\n          ctx.setLineDash([6, 4]);\n        } else if(isRingRoute){\n          \/\/ Ring routes \u2014 operator drove along the headland-ring to reach\n          \/\/ the next pass. Show as dashed violet too but with a tighter\n          \/\/ dash pattern so the routing is visually distinct.\n          ctx.strokeStyle = '#a21caf';\n          ctx.lineWidth = 1.6;\n          ctx.setLineDash([3, 3]);\n        } else {\n          \/\/ U-turn arc \u2014 solid violet for ok, red-dashed when geometry failed.\n          ctx.strokeStyle = arc.ok ? '#a21caf' : '#dc2626';\n          ctx.lineWidth = arc.ok ? 2 : 1.4;\n          ctx.setLineDash(arc.ok ? [] : [3, 3]);\n        }\n        ctx.beginPath();\n        for(var ac=0; ac<arc.coords.length; ac++){\n          var aex = px(proj, arc.coords[ac].x);\n          var aey = py(proj, arc.coords[ac].y);\n          if(ac === 0) ctx.moveTo(aex, aey); else ctx.lineTo(aex, aey);\n        }\n        ctx.stroke();\n      }\n      ctx.restore();\n    }\n    \/\/ Direction arrows on passes + turn arcs (above lines, below sprite)\n    drawDirectionArrows(proj, layout);\n    \/\/ Tractor sprite on top\n    drawSprite(proj);\n    \/\/ Scale bar \u2014 pick a nice round metres value for ~60 px on screen and\n    \/\/ adjust the bar width to match the chosen value at current proj.sc.\n    var scaleBarEl = document.getElementById('gpl-scale');\n    var scaleLblEl = document.getElementById('gpl-scale-lbl');\n    if(scaleBarEl ? scaleLblEl : false){\n      var targetPx = 60;\n      var rawMetres = targetPx \/ proj.sc;\n      \/\/ Snap to a 1\/2\/5 \u00d7 10\u207f pattern (standard cartographic scale steps)\n      var pow10 = Math.pow(10, Math.floor(Math.log(rawMetres) \/ Math.LN10));\n      var snapVal;\n      var lead = rawMetres \/ pow10;\n      if(lead < 1.5) snapVal = 1 * pow10;\n      else if(lead < 3.5) snapVal = 2 * pow10;\n      else if(lead < 7.5) snapVal = 5 * pow10;\n      else snapVal = 10 * pow10;\n      var barPx = snapVal * proj.sc;\n      var barEl = scaleBarEl.querySelector('.gpl-scale-bar');\n      if(barEl) barEl.style.width = barPx.toFixed(0) + 'px';\n      scaleLblEl.textContent = fmtDist(snapVal);\n    }\n    \/\/ Ruler line on absolute top\n    if(ruler.p1 ? ruler.p2 : false){\n      ctx.save();\n      ctx.strokeStyle = '#dc2626';\n      ctx.lineWidth = 2;\n      ctx.setLineDash([6, 4]);\n      ctx.beginPath();\n      ctx.moveTo(px(proj, ruler.p1.x), py(proj, ruler.p1.y));\n      ctx.lineTo(px(proj, ruler.p2.x), py(proj, ruler.p2.y));\n      ctx.stroke();\n      ctx.restore();\n      \/\/ Endpoint dots\n      ctx.save();\n      ctx.fillStyle = '#dc2626';\n      ctx.beginPath(); ctx.arc(px(proj, ruler.p1.x), py(proj, ruler.p1.y), 4, 0, Math.PI*2); ctx.fill();\n      ctx.beginPath(); ctx.arc(px(proj, ruler.p2.x), py(proj, ruler.p2.y), 4, 0, Math.PI*2); ctx.fill();\n      ctx.restore();\n      \/\/ Distance label\n      var rdx = ruler.p2.x - ruler.p1.x;\n      var rdy = ruler.p2.y - ruler.p1.y;\n      var rDist = Math.sqrt(rdx*rdx + rdy*rdy);\n      var labelMx = px(proj, (ruler.p1.x + ruler.p2.x) * 0.5);\n      var labelMy = py(proj, (ruler.p1.y + ruler.p2.y) * 0.5);\n      ctx.save();\n      ctx.font = '700 12px \"DM Mono\", ui-monospace, monospace';\n      var label = fmtDist(rDist);\n      var tw = ctx.measureText(label).width + 14;\n      ctx.fillStyle = 'rgba(220,38,38,0.95)';\n      ctx.fillRect(labelMx - tw \/ 2, labelMy - 11, tw, 22);\n      ctx.fillStyle = '#fff';\n      ctx.textAlign = 'center';\n      ctx.textBaseline = 'middle';\n      ctx.fillText(label, labelMx, labelMy);\n      ctx.restore();\n    } else if(ruler.p1){\n      ctx.save();\n      ctx.fillStyle = '#dc2626';\n      ctx.beginPath(); ctx.arc(px(proj, ruler.p1.x), py(proj, ruler.p1.y), 5, 0, Math.PI*2); ctx.fill();\n      ctx.restore();\n    }\n  }\n\n  var current = 'ab-straight';\n  \/\/ Machine type \u2192 typical min-turn-radius (m) AND typical implement width (m).\n  \/\/ Widths from the field-explorer OP_WIDTH_M table \u2014 large-farm row-crop\n  \/\/ defaults. User picks Custom to skip both auto-fills and override manually.\n  var MACHINE_SPEC = {\n    'tractor-std':   { r:  8, w: 15, label: 'std tractor \/ cultivator' },\n    'tractor-large': { r: 12, w: 18, label: 'large tractor + 24-row planter' },\n    'sprayer':       { r: 10, w: 36, label: 'self-propelled sprayer' },\n    'combine':       { r:  7, w: 12, label: 'combine harvester' },\n    'articulated':   { r: 15, w: 24, label: 'articulated 4WD + dry spreader' },\n    'custom':        { r:  0, w:  0, label: 'manual override' }\n  };\n  \/\/ Back-compat alias (the smoke tests poke MACHINE_RADIUS).\n  var MACHINE_RADIUS = MACHINE_SPEC;\n  var CURRENCY_SYMBOL = { usd: '$', eur: '\u20ac' };\n\n  function getInputs(){\n    var wM = parseFloat(document.getElementById('gpl-wm').value) || 18;\n    var hlMult = parseFloat(document.getElementById('gpl-hl-mult').value);\n    if(isNaN(hlMult)) hlMult = 1;\n    \/\/ Headland is ALWAYS N \u00d7 implement width (per user \u2014 custom override\n    \/\/ dropped, the multiplier alone defines the strip).\n    var headlandM = hlMult * wM;\n    var turnStyle = document.getElementById('gpl-turn-style').value || 'uturn';\n    var turnR = parseFloat(document.getElementById('gpl-turn-r').value) || 9;\n    var turnBuf = parseFloat(document.getElementById('gpl-turn-buf').value);\n    if(isNaN(turnBuf)) turnBuf = 0;\n    var machineEl = document.getElementById('gpl-machine');\n    var machineKey = machineEl ? machineEl.value : 'tractor-std';\n    var curEl = document.getElementById('gpl-currency');\n    var currency = curEl ? curEl.value : 'usd';\n    var farmEl = document.getElementById('gpl-roi-farm');\n    var appsEl = document.getElementById('gpl-roi-apps');\n    var farmHa = farmEl ? parseFloat(farmEl.value) : 200;\n    if(isNaN(farmHa) ? true : farmHa <= 0) farmHa = 200;\n    var apps = appsEl ? parseFloat(appsEl.value) : 4;\n    if(isNaN(apps) ? true : apps <= 0) apps = 4;\n    return {\n      wM: wM,\n      diesel: parseFloat(document.getElementById('gpl-fuel').value) || 1.2,\n      cons: parseFloat(document.getElementById('gpl-cons').value) || 0.6,\n      headlandM: headlandM,\n      headlandMult: hlMult,\n      turnStyle: turnStyle,\n      turnR: turnR,\n      turnBuf: turnBuf,\n      machine: machineKey,\n      currency: currency,\n      farmHa: farmHa,\n      apps: apps\n    };\n  }\n  function recompute(){\n    var inp = getInputs();\n    \/\/ Axis: user manual override beats PCA when set\n    var axis;\n    if(userAxisDeg !== null){\n      var r = userAxisDeg * Math.PI \/ 180;\n      axis = { ux: Math.cos(r), uy: Math.sin(r) };\n    } else {\n      axis = fieldAxis(BOUNDARY);\n    }\n    \/\/ Sync the AB-direction slider label to the active angle (so the user\n    \/\/ sees the auto-PCA result reflected in the UI).\n    var abLabelEl = document.getElementById('gpl-ab-val');\n    var abSliderEl = document.getElementById('gpl-ab-deg');\n    if(abLabelEl ? abSliderEl : false){\n      var degNow = Math.round(Math.atan2(axis.uy, axis.ux) * 180 \/ Math.PI);\n      \/\/ Wrap into [0,180) \u2014 the axis is bidirectional (a line, not a vector).\n      while(degNow < 0) degNow += 180;\n      while(degNow >= 180) degNow -= 180;\n      if(userAxisDeg === null) abSliderEl.value = String(degNow);\n      abLabelEl.textContent = (userAxisDeg === null ? 'auto \u00b7 ' : 'manual \u00b7 ') + degNow + '\u00b0';\n    }\n    var stats = fieldStats(BOUNDARY);\n    var areaHa = stats.area \/ 10000;\n    var baseLayout = generateLines('ab-straight', inp.wM, BOUNDARY, axis, inp.headlandM, inp.turnStyle, inp.turnR, inp.turnBuf);\n    var baseMet = computeMetrics(baseLayout, inp.wM, inp.diesel, inp.cons);\n    var layout = generateLines(current, inp.wM, BOUNDARY, axis, inp.headlandM, inp.turnStyle, inp.turnR, inp.turnBuf);\n    var met = computeMetrics(layout, inp.wM, inp.diesel, inp.cons);\n    document.getElementById('gpl-r-area').textContent = areaHa.toFixed(1) + ' ha';\n    var covEl = document.getElementById('gpl-r-cov');\n    if(covEl){\n      var covVal = met.coveragePct || 0;\n      covEl.textContent = covVal.toFixed(0) + ' %';\n      \/\/ Color: green \u2265 95%, orange 85-95%, red < 85%\n      covEl.style.color = covVal >= 95 ? '#15701e' : (covVal >= 85 ? '#f76a0c' : '#dc2626');\n    }\n    document.getElementById('gpl-r-passes').textContent = met.passes;\n    document.getElementById('gpl-r-len').textContent = fmtDist(met.passLengthM);\n    document.getElementById('gpl-r-turns').textContent = met.turns;\n    var turnLenEl = document.getElementById('gpl-r-turnlen');\n    if(turnLenEl) turnLenEl.textContent = fmtDist(met.turnLengthM || 0);\n    var driveEl = document.getElementById('gpl-r-drive');\n    if(driveEl) driveEl.textContent = fmtDist(met.totalDriveM || (met.passLengthM + (met.turnLengthM || 0)));\n    document.getElementById('gpl-r-fuel').textContent = met.fuelL.toFixed(1) + ' L';\n    var gradeEl = document.getElementById('gpl-r-grade');\n    if(gradeEl){\n      var g = met.avgGradePct || 0;\n      gradeEl.textContent = g.toFixed(1) + ' %';\n      gradeEl.style.color = g > 5 ? '#f76a0c' : (g > 3 ? '#a21caf' : '#4c6066');\n    }\n    var slopeEl = document.getElementById('gpl-r-slope');\n    if(slopeEl){\n      var slopePct = (met.slopePenalty || 0) * 100;\n      slopeEl.textContent = '+ ' + slopePct.toFixed(0) + '%';\n      slopeEl.style.color = slopePct > 15 ? '#dc2626' : (slopePct > 5 ? '#f76a0c' : '#4c6066');\n    }\n    var turnFuelEl = document.getElementById('gpl-r-turnfuel');\n    if(turnFuelEl){\n      var tf = met.turnFuelL || 0;\n      var totF = met.fuelL || 0;\n      var pct = totF > 0 ? (tf \/ totF * 100) : 0;\n      turnFuelEl.textContent = tf.toFixed(1) + ' L \u00b7 ' + pct.toFixed(0) + '%';\n      turnFuelEl.style.color = pct > 25 ? '#f76a0c' : (pct > 15 ? '#a21caf' : '#4c6066');\n    }\n    var sym = CURRENCY_SYMBOL[inp.currency] || '$';\n    document.getElementById('gpl-r-cost').textContent = sym + ' ' + met.costUSD.toFixed(2);\n    var savFuel = baseMet.fuelL - met.fuelL;\n    var savPct = baseMet.fuelL > 0 ? (savFuel \/ baseMet.fuelL) * 100 : 0;\n    var savEl = document.getElementById('gpl-r-sav');\n    if(current === 'ab-straight'){\n      savEl.textContent = 'baseline';\n      savEl.style.color = '#4c6066';\n    } else {\n      var sign = savFuel >= 0 ? '\u2212' : '+';\n      var absSav = Math.abs(savFuel);\n      savEl.textContent = sign + absSav.toFixed(1) + ' L (' + (savPct >= 0 ? '\u2212' : '+') + Math.abs(savPct).toFixed(0) + '%)';\n      savEl.style.color = savFuel >= 0 ? '#15701e' : '#f76a0c';\n    }\n    trayEl.textContent = areaHa.toFixed(1) + ' ha \u00b7 ' + inp.wM + ' m \u00b7 ' + met.passes + ' passes \u00b7 headland ' + inp.headlandM.toFixed(0) + ' m';\n    \/\/ Shape-driven recommendation badge\n    var reco = recommendApproach(BOUNDARY);\n    var recoBadges = document.querySelectorAll('.gpl-reco');\n    for(var rb=0; rb<recoBadges.length; rb++){\n      var rkey = recoBadges[rb].getAttribute('data-reco');\n      recoBadges[rb].classList.toggle('is-on', rkey === reco.pick);\n    }\n    var recoHintEl = document.getElementById('gpl-reco-hint');\n    if(recoHintEl) recoHintEl.textContent = reco.why;\n    \/\/ Annual ROI extrapolation. Per-field fuel savings \u00d7 applications \u00d7 (farm\/field).\n    var roiFuelEl = document.getElementById('gpl-roi-fuel');\n    var roiCostEl = document.getElementById('gpl-roi-cost');\n    var roiPerhaEl = document.getElementById('gpl-roi-perha');\n    if(roiFuelEl ? roiCostEl : false){\n      if(current === 'ab-straight'){\n        roiFuelEl.textContent = '\u2014 L';\n        roiCostEl.textContent = sym + ' \u2014';\n        if(roiPerhaEl) roiPerhaEl.textContent = 'pick non-baseline';\n        roiFuelEl.style.color = '#4c6066';\n        roiCostEl.style.color = '#4c6066';\n        if(roiPerhaEl) roiPerhaEl.style.color = '#4c6066';\n      } else {\n        var perFieldFuel = baseMet.fuelL - met.fuelL;\n        var scale = areaHa > 0 ? (inp.farmHa \/ areaHa) : 0;\n        var annualFuel = perFieldFuel * inp.apps * scale;\n        var annualCost = annualFuel * inp.diesel;\n        var perHa = inp.farmHa > 0 ? (annualCost \/ inp.farmHa) : 0;\n        var signR = annualFuel >= 0 ? '' : '\u2212';\n        roiFuelEl.textContent = signR + Math.abs(annualFuel).toFixed(0) + ' L';\n        roiCostEl.textContent = (annualCost >= 0 ? sym + ' ' : '\u2212' + sym + ' ') + Math.abs(annualCost).toFixed(0);\n        if(roiPerhaEl) roiPerhaEl.textContent = (perHa >= 0 ? sym + ' ' : '\u2212' + sym + ' ') + Math.abs(perHa).toFixed(2) + '\/ha';\n        var roiColor = annualFuel >= 0 ? '#15701e' : '#f76a0c';\n        roiFuelEl.style.color = roiColor;\n        roiCostEl.style.color = roiColor;\n        if(roiPerhaEl) roiPerhaEl.style.color = roiColor;\n      }\n    }\n    \/\/ Warning banner from validation cascade\n    var warnEl = document.getElementById('gpl-warn');\n    if(warnEl){\n      if(layout.warning){\n        warnEl.textContent = layout.warning;\n        warnEl.classList.add('is-on');\n      } else {\n        warnEl.textContent = '';\n        warnEl.classList.remove('is-on');\n      }\n    }\n    var approaches = ['ab-straight', 'ab-curve', 'boundary', 'adaptive'];\n    var apMetrics = {};\n    for(var a=0; a<approaches.length; a++){\n      var ap = approaches[a];\n      var apLayout = ap === current ? layout : generateLines(ap, inp.wM, BOUNDARY, axis, inp.headlandM, inp.turnStyle, inp.turnR, inp.turnBuf);\n      var apMet = ap === current ? met : computeMetrics(apLayout, inp.wM, inp.diesel, inp.cons);\n      apMetrics[ap] = apMet;\n      var rowEl = document.querySelector('.gpl-cmp-row[data-cmp=\"' + ap + '\"]');\n      if(!rowEl) continue;\n      var vals = rowEl.querySelectorAll('.gpl-cmp-val');\n      vals[0].textContent = (apMet.coveragePct || 0).toFixed(0) + '%';\n      vals[1].textContent = apMet.fuelL.toFixed(0) + ' L';\n      vals[2].textContent = sym + apMet.costUSD.toFixed(0);\n      rowEl.classList.toggle('gpl-cmp-current', ap === current);\n    }\n    \/\/ Axis sweep \u2014 fields with low coverage (e.g. L-shape) may benefit from a\n    \/\/ different AB axis. Try 6 angles (15\u00b0 increments over 0\u201390\u00b0, since the\n    \/\/ axis is bidirectional \u2192 90\u00b0 period) and per-approach pick the BEST\n    \/\/ coverage axis. Only kicks in when the user hasn't manually overridden\n    \/\/ the axis (userAxisDeg === null).\n    var bestApAxes = {};\n    if(userAxisDeg === null){\n      var sweepAngles = [0, 15, 30, 45, 60, 75];\n      \/\/ PCA gives the natural baseline; include it too.\n      var pcaDeg = Math.round(Math.atan2(fieldAxis(BOUNDARY).uy, fieldAxis(BOUNDARY).ux) * 180 \/ Math.PI);\n      while(pcaDeg < 0) pcaDeg += 180;\n      while(pcaDeg >= 90) pcaDeg -= 90;\n      if(sweepAngles.indexOf(pcaDeg) < 0) sweepAngles.push(pcaDeg);\n      for(var aps=0; aps<approaches.length; aps++){\n        var apS = approaches[aps];\n        var bestMet = apMetrics[apS];\n        var bestAng = null;\n        for(var sa=0; sa<sweepAngles.length; sa++){\n          var ang = sweepAngles[sa] * Math.PI \/ 180;\n          var trialAxis = { ux: Math.cos(ang), uy: Math.sin(ang) };\n          var trialLay = generateLines(apS, inp.wM, BOUNDARY, trialAxis, inp.headlandM, inp.turnStyle, inp.turnR, inp.turnBuf);\n          var trialMet = computeMetrics(trialLay, inp.wM, inp.diesel, inp.cons);\n          if((trialMet.coveragePct || 0) > (bestMet.coveragePct || 0)){\n            bestMet = trialMet;\n            bestAng = sweepAngles[sa];\n          }\n        }\n        if(bestAng !== null){\n          apMetrics[apS] = bestMet;\n          bestApAxes[apS] = bestAng;\n        }\n      }\n    }\n    \/\/ Metric-driven recommendation (now uses the swept-axis metrics)\n    var recoMetric = recommendByMetrics(apMetrics);\n    var recoBadges2 = document.querySelectorAll('.gpl-reco');\n    for(var rb2=0; rb2<recoBadges2.length; rb2++){\n      var rkey2 = recoBadges2[rb2].getAttribute('data-reco');\n      recoBadges2[rb2].classList.toggle('is-on', rkey2 === recoMetric.pick);\n    }\n    var recoHintEl2 = document.getElementById('gpl-reco-hint');\n    if(recoHintEl2){\n      var hintTxt = recoMetric.why;\n      if(bestApAxes[recoMetric.pick] !== undefined){\n        hintTxt += ' \u00b7 best at ' + bestApAxes[recoMetric.pick] + '\u00b0';\n      }\n      \/\/ Surface low-coverage warning prominently\n      var bestCov = (apMetrics[recoMetric.pick] || {}).coveragePct || 0;\n      if(bestCov < 70){\n        hintTxt += ' \u2014 split field for full coverage';\n      }\n      recoHintEl2.textContent = hintTxt;\n    }\n    \/\/ Update the Compare All cells with the swept-axis metrics so the user\n    \/\/ sees the BEST achievable coverage per approach, not just PCA-axis.\n    for(var aa=0; aa<approaches.length; aa++){\n      var apX = approaches[aa];\n      var rowX = document.querySelector('.gpl-cmp-row[data-cmp=\"' + apX + '\"]');\n      if(!rowX) continue;\n      var mX = apMetrics[apX];\n      var valsX = rowX.querySelectorAll('.gpl-cmp-val');\n      valsX[0].textContent = (mX.coveragePct || 0).toFixed(0) + '%';\n      valsX[1].textContent = mX.fuelL.toFixed(0) + ' L';\n      valsX[2].textContent = sym + mX.costUSD.toFixed(0);\n    }\n    setPlaybackPath(layout, inp.wM);\n    updatePlaybackUI();\n    draw(layout);\n  }\n\n  \/\/ Update the headland slider label. Headland = mult \u00d7 wM (sole source of\n  \/\/ truth \u2014 no separate custom-width input anymore).\n  function updateHeadlandLabel(){\n    var wM = parseFloat(document.getElementById('gpl-wm').value) || 18;\n    var hlMult = parseFloat(document.getElementById('gpl-hl-mult').value);\n    if(isNaN(hlMult)) hlMult = 1;\n    var labelEl = document.getElementById('gpl-hl-val');\n    if(!labelEl) return;\n    var m = hlMult * wM;\n    labelEl.textContent = m.toFixed(0) + ' m \u00b7 ' + hlMult + '\u00d7 pass';\n  }\n\n  var radios = document.querySelectorAll('#gpl-approach input[type=radio]');\n  for(var ri=0; ri<radios.length; ri++){\n    radios[ri].addEventListener('change', function(){\n      var labs = document.querySelectorAll('#gpl-approach label');\n      for(var li=0; li<labs.length; li++) labs[li].classList.remove('is-on');\n      this.parentNode.classList.add('is-on');\n      current = this.value;\n      recompute();\n    });\n  }\n  \/\/ Equipment + economics inputs\n  var basicIds = ['gpl-wm', 'gpl-fuel', 'gpl-cons'];\n  for(var ii=0; ii<basicIds.length; ii++){\n    var el = document.getElementById(basicIds[ii]);\n    if(el){\n      el.addEventListener('input', function(){\n        updateHeadlandLabel();\n        recompute();\n      });\n    }\n  }\n  \/\/ Headland slider \u2014 drives headland = mult \u00d7 wM\n  var hlSlider = document.getElementById('gpl-hl-mult');\n  if(hlSlider){\n    hlSlider.addEventListener('input', function(){\n      updateHeadlandLabel();\n      recompute();\n    });\n  }\n  \/\/ ROI inputs \u2014 purely informational, just re-run recompute\n  var roiIds = ['gpl-roi-farm', 'gpl-roi-apps'];\n  for(var roi=0; roi<roiIds.length; roi++){\n    var roiEl = document.getElementById(roiIds[roi]);\n    if(roiEl) roiEl.addEventListener('input', recompute);\n  }\n  \/\/ Turn-around controls\n  var turnIds = ['gpl-turn-style', 'gpl-turn-r', 'gpl-turn-buf'];\n  for(var ti=0; ti<turnIds.length; ti++){\n    var tEl = document.getElementById(turnIds[ti]);\n    if(tEl){\n      tEl.addEventListener('input', recompute);\n      tEl.addEventListener('change', recompute);\n    }\n  }\n  \/\/ Machine type \u2014 auto-fills BOTH turn radius and implement width (unless\n  \/\/ 'custom'). Each machine class has typical specs from manufacturer averages.\n  function applyMachineRadius(){\n    var mEl = document.getElementById('gpl-machine');\n    var rEl = document.getElementById('gpl-turn-r');\n    var wEl = document.getElementById('gpl-wm');\n    var hintEl = document.getElementById('gpl-turn-r-hint');\n    if(!mEl ? true : !rEl) return;\n    var spec = MACHINE_SPEC[mEl.value] || MACHINE_SPEC['tractor-std'];\n    if(mEl.value !== 'custom' ? spec.r > 0 : false){\n      rEl.value = String(spec.r);\n      rEl.disabled = false;\n    }\n    if(mEl.value !== 'custom' ? (spec.w > 0 ? wEl : false) : false){\n      wEl.value = String(spec.w);\n    }\n    \/\/ Sync headland slider\/label to the new width so headlandM stays at the\n    \/\/ user's intended multiplier of pass width.\n    updateHeadlandLabel();\n    if(hintEl){\n      hintEl.textContent = mEl.value === 'custom' ? 'manual override' : ('auto \u00b7 ' + spec.label);\n    }\n  }\n  var machineSelEl = document.getElementById('gpl-machine');\n  if(machineSelEl){\n    machineSelEl.addEventListener('change', function(){\n      applyMachineRadius();\n      recompute();\n    });\n  }\n  \/\/ Currency select \u2014 purely a label switch; user types their local price\n  var curSelEl = document.getElementById('gpl-currency');\n  if(curSelEl) curSelEl.addEventListener('change', recompute);\n\n  \/\/ File-import helpers \u2014 accept GeoJSON, KML, or zipped shapefile. Extract\n  \/\/ ALL polygon outer rings (so users can iterate through fields in a\n  \/\/ multi-feature file), project lat\/lng to local meters with each polygon's\n  \/\/ own centroid as origin, fit into the existing canvas coordinate scheme.\n  \/\/ Imported polygons live in `importedFields` (array of { name, coords }\n  \/\/ where coords is canvas-meter {x,y} points). Iterator UI lets the user\n  \/\/ step through them.\n  var importedFields = [];\n  var importedIdx = 0;\n  \/\/ Lazy-load shpjs from jsDelivr on demand for .zip \/ .shp inputs. The\n  \/\/ promise is cached so subsequent uploads do not re-fetch the library.\n  \/\/ This is the only network dependency in the tool \u2014 opt-in via upload.\n  var shpjsPromise = null;\n  function loadShpjs(){\n    if(typeof window.shp === 'function') return Promise.resolve();\n    if(shpjsPromise) return shpjsPromise;\n    shpjsPromise = new Promise(function(resolve, reject){\n      var s = document.createElement('script');\n      \/\/ CDN URL has no query separators, so rule 1 is not at risk here.\n      s.src = 'https:\/\/cdn.jsdelivr.net\/npm\/shpjs@4.0.4\/dist\/shp.min.js';\n      s.onload = function(){ resolve(); };\n      s.onerror = function(){ shpjsPromise = null; reject(new Error('Could not load shapefile parser')); };\n      document.head.appendChild(s);\n    });\n    return shpjsPromise;\n  }\n  \/\/ Extract every polygon outer ring from any GeoJSON object. Returns\n  \/\/ [{ name, coords: [[lng,lat], \u2026] }, \u2026] sorted by area descending so the\n  \/\/ biggest polygon (usually the field of interest) comes first.\n  function extractAllPolygonsGeoJSON(obj){\n    var polys = [];\n    function pushFeature(f, defaultName){\n      if(!f) return;\n      var props = f.properties || {};\n      var name = props.name || props.Name || props.NAME || props.field || props.Field || props.FIELD || props.id || defaultName;\n      var geom = f.geometry ? f.geometry : (f.type === 'Polygon' ? f : (f.type === 'MultiPolygon' ? f : null));\n      if(!geom) return;\n      if(geom.type === 'Polygon'){\n        polys.push({ name: name, coords: geom.coordinates[0] });\n      } else if(geom.type === 'MultiPolygon'){\n        for(var i=0; i<geom.coordinates.length; i++){\n          polys.push({ name: (name || 'poly') + ' #' + (i + 1), coords: geom.coordinates[i][0] });\n        }\n      }\n    }\n    if(obj.type === 'FeatureCollection' ? obj.features : false){\n      for(var k=0; k<obj.features.length; k++) pushFeature(obj.features[k], 'feature ' + (k + 1));\n    } else if(obj.type === 'Feature'){\n      pushFeature(obj, 'feature 1');\n    } else if(obj.type === 'Polygon' ? true : obj.type === 'MultiPolygon'){\n      pushFeature({ geometry: obj, properties: {} }, 'polygon');\n    }\n    \/\/ Sort by approximate area (cross-product sum of lng\/lat coords \u2014 not\n    \/\/ m\u00b2 but monotonic, so largest polygon still wins).\n    polys.forEach(function(p){\n      var a = 0;\n      for(var i=0; i<p.coords.length-1; i++){\n        a += p.coords[i][0] * p.coords[i+1][1] - p.coords[i+1][0] * p.coords[i][1];\n      }\n      p._areaScore = Math.abs(a);\n    });\n    polys.sort(function(a, b){ return b._areaScore - a._areaScore; });\n    return polys;\n  }\n  function extractAllPolygonsKML(text){\n    if(typeof DOMParser === 'undefined') return [];\n    var doc;\n    try { doc = new DOMParser().parseFromString(text, 'application\/xml'); } catch(e){ return []; }\n    var placemarks = doc.getElementsByTagName('Placemark');\n    var polys = [];\n    function coordsFromText(raw){\n      var pairs = raw.split(\/\\s+\/).map(function(s){ return s.trim(); }).filter(function(s){ return s.length > 0; });\n      var out = [];\n      for(var i=0; i<pairs.length; i++){\n        var parts = pairs[i].split(',');\n        if(parts.length < 2) continue;\n        var lng = parseFloat(parts[0]), lat = parseFloat(parts[1]);\n        if(isNaN(lng) ? true : isNaN(lat)) continue;\n        out.push([lng, lat]);\n      }\n      return out;\n    }\n    if(placemarks.length > 0){\n      for(var pi=0; pi<placemarks.length; pi++){\n        var pm = placemarks[pi];\n        var nameEl = pm.getElementsByTagName('name');\n        var name = (nameEl.length > 0 ? nameEl[0].textContent : 'placemark ' + (pi + 1)) || ('placemark ' + (pi + 1));\n        var coordsEls = pm.getElementsByTagName('coordinates');\n        for(var ci=0; ci<coordsEls.length; ci++){\n          var c = coordsFromText(coordsEls[ci].textContent || '');\n          if(c.length >= 3) polys.push({ name: name + (coordsEls.length > 1 ? ' #' + (ci + 1) : ''), coords: c });\n        }\n      }\n    } else {\n      \/\/ Fallback: bare KML with <coordinates> elsewhere\n      var coordsAll = doc.getElementsByTagName('coordinates');\n      for(var ca=0; ca<coordsAll.length; ca++){\n        var c2 = coordsFromText(coordsAll[ca].textContent || '');\n        if(c2.length >= 3) polys.push({ name: 'polygon ' + (ca + 1), coords: c2 });\n      }\n    }\n    return polys;\n  }\n  \/\/ Convert [lng, lat] array to local canvas-meter coords. Center the field at\n  \/\/ the canvas centroid (~380, 290) so the existing scale logic fits it.\n  function lngLatToCanvas(coords){\n    if(!coords ? true : coords.length < 3) return null;\n    \/\/ Use centroid (average) as the projection origin\n    var oLat = 0, oLng = 0;\n    for(var i=0; i<coords.length; i++){ oLng += coords[i][0]; oLat += coords[i][1]; }\n    oLat \/= coords.length; oLng \/= coords.length;\n    var cosLat = Math.cos(oLat * Math.PI \/ 180);\n    var pts = [];\n    for(var j=0; j<coords.length; j++){\n      var lng = coords[j][0], lat = coords[j][1];\n      var mx = (lng - oLng) * 111320 * cosLat;\n      var my = -(lat - oLat) * 111320;  \/\/ canvas y is +down, so flip\n      pts.push({ x: 380 + mx, y: 290 + my });\n    }\n    \/\/ Strip a trailing duplicate vertex (LinearRings close themselves)\n    var last = pts[pts.length - 1], first = pts[0];\n    if(Math.abs(last.x - first.x) < 0.01 ? Math.abs(last.y - first.y) < 0.01 : false){\n      pts.pop();\n    }\n    return pts.length >= 3 ? pts : null;\n  }\n  function showUploadStatus(state, msg){\n    var lbl = document.getElementById('gpl-upload-lbl');\n    var hint = document.getElementById('gpl-upload-hint');\n    if(!lbl) return;\n    lbl.classList.remove('is-error', 'is-success');\n    if(state === 'error') lbl.classList.add('is-error');\n    else if(state === 'success') lbl.classList.add('is-success');\n    if(hint) hint.textContent = msg;\n  }\n  \/\/ Apply imported polygon at index i to FIELDS.custom + BOUNDARY + recompute.\n  function applyImportedField(i){\n    if(!importedFields.length) return;\n    if(i < 0) i = 0;\n    if(i >= importedFields.length) i = importedFields.length - 1;\n    importedIdx = i;\n    var pf = importedFields[i];\n    var pts = lngLatToCanvas(pf.coords);\n    if(!pts){ showUploadStatus('error', 'Polygon needs at least 3 vertices'); return; }\n    FIELDS.custom = pts;\n    currentField = 'custom';\n    BOUNDARY = pts;\n    userAxisDeg = null;\n    var picker = document.querySelectorAll('#gpl-field-picker .gpl-fld');\n    for(var pp=0; pp<picker.length; pp++) picker[pp].classList.remove('is-on');\n    var navEl = document.getElementById('gpl-import-nav');\n    var lblEl = document.getElementById('gpl-imp-lbl');\n    var prevBtn = document.getElementById('gpl-imp-prev');\n    var nextBtn = document.getElementById('gpl-imp-next');\n    if(navEl) navEl.hidden = importedFields.length < 2;\n    if(lblEl) lblEl.textContent = (i + 1) + ' \/ ' + importedFields.length;\n    if(prevBtn) prevBtn.disabled = i === 0;\n    if(nextBtn) nextBtn.disabled = i === importedFields.length - 1;\n    showUploadStatus('success', (pf.name || ('boundary ' + (i + 1))) + ' \u00b7 ' + pts.length + ' vertices');\n    recompute();\n  }\n  \/\/ Convert raw file \u2192 list of polygons \u2192 install + apply first one.\n  function handleParsedPolygons(polys, filename){\n    if(!polys ? true : polys.length === 0){\n      showUploadStatus('error', 'No polygons found in ' + filename);\n      return;\n    }\n    importedFields = polys;\n    importedIdx = 0;\n    showUploadStatus('success', filename + ' \u00b7 ' + polys.length + ' boundary' + (polys.length > 1 ? 'ies' : ''));\n    applyImportedField(0);\n  }\n  \/\/ Detect format by extension + content, dispatch to parser. Async because\n  \/\/ .zip needs shpjs which loads lazily from CDN.\n  function importFile(file){\n    var name = (file.name || '').toLowerCase();\n    showUploadStatus('default', 'Reading ' + file.name + '\u2026');\n    if(name.indexOf('.zip') >= 0 ? true : name.indexOf('.shp') >= 0){\n      \/\/ Zipped shapefile or bare .shp \u2014 needs shpjs\n      var reader = new FileReader();\n      reader.onload = function(){\n        loadShpjs().then(function(){\n          try {\n            var p = window.shp(reader.result);\n            \/\/ shp() returns either a single FeatureCollection or an array (for multi-shp zips)\n            (p ? (p.then ? p : Promise.resolve(p)) : Promise.resolve(p)).then(function(res){\n              var collections = Array.isArray(res) ? res : [res];\n              var all = [];\n              for(var c=0; c<collections.length; c++) all = all.concat(extractAllPolygonsGeoJSON(collections[c]));\n              handleParsedPolygons(all, file.name);\n            }).catch(function(err){\n              showUploadStatus('error', 'Shapefile parse failed: ' + (err.message || err));\n            });\n          } catch(err){\n            showUploadStatus('error', 'Shapefile parse failed: ' + (err.message || err));\n          }\n        }).catch(function(err){\n          showUploadStatus('error', err.message || 'Could not load shapefile parser');\n        });\n      };\n      reader.onerror = function(){ showUploadStatus('error', 'Could not read file'); };\n      reader.readAsArrayBuffer(file);\n    } else {\n      \/\/ Text-based \u2014 GeoJSON or KML\n      var reader2 = new FileReader();\n      reader2.onload = function(){\n        var text = reader2.result;\n        var polys = [];\n        if(name.indexOf('.kml') >= 0){\n          polys = extractAllPolygonsKML(text);\n        } else {\n          \/\/ GeoJSON first; if it fails, try KML in case extension was wrong\n          try {\n            var obj = JSON.parse(text);\n            polys = extractAllPolygonsGeoJSON(obj);\n          } catch(_){ polys = extractAllPolygonsKML(text); }\n        }\n        handleParsedPolygons(polys, file.name);\n      };\n      reader2.onerror = function(){ showUploadStatus('error', 'Could not read file'); };\n      reader2.readAsText(file);\n    }\n  }\n  var fileInputEl = document.getElementById('gpl-upload');\n  if(fileInputEl){\n    fileInputEl.addEventListener('change', function(){\n      var file = this.files ? this.files[0] : null;\n      if(file) importFile(file);\n    });\n  }\n  \/\/ Iterator buttons \u2014 step through importedFields\n  var impPrevEl = document.getElementById('gpl-imp-prev');\n  var impNextEl = document.getElementById('gpl-imp-next');\n  if(impPrevEl) impPrevEl.addEventListener('click', function(){ applyImportedField(importedIdx - 1); });\n  if(impNextEl) impNextEl.addEventListener('click', function(){ applyImportedField(importedIdx + 1); });\n\n  \/\/ Field picker \u2014 swap BOUNDARY in place, auto-pick the recommended approach,\n  \/\/ then re-fit \/ re-render. Resets the AB-line override so each new field\n  \/\/ starts from its PCA-derived natural axis.\n  var fldBtns = document.querySelectorAll('#gpl-field-picker .gpl-fld');\n  for(var fb=0; fb<fldBtns.length; fb++){\n    fldBtns[fb].addEventListener('click', function(){\n      var key = this.getAttribute('data-field');\n      if(!key ? true : !FIELDS[key]) return;\n      currentField = key;\n      BOUNDARY = FIELDS[key];\n      userAxisDeg = null;  \/\/ back to Auto on every field change\n      var autoBtn = document.getElementById('gpl-ab-auto');\n      if(autoBtn) autoBtn.classList.add('is-auto');\n      for(var fi=0; fi<fldBtns.length; fi++) fldBtns[fi].classList.remove('is-on');\n      this.classList.add('is-on');\n      \/\/ Reset the upload card status so it doesn't keep the success-state badge\n      showUploadStatus('default', 'GeoJSON \/ KML \/ Shapefile zip');\n      if(fileInputEl) fileInputEl.value = '';\n      var nav2 = document.getElementById('gpl-import-nav');\n      if(nav2) nav2.hidden = true;\n      importedFields = [];\n      importedIdx = 0;\n      \/\/ Pre-pick with the shape-based heuristic for instant feedback; the\n      \/\/ first recompute() below will then re-evaluate with real metrics\n      \/\/ (coverage + turns + fuel) and may flip to a better approach.\n      var pick = recommendApproach(BOUNDARY).pick;\n      current = pick;\n      var apRadios = document.querySelectorAll('#gpl-approach input[type=radio]');\n      var apLabels = document.querySelectorAll('#gpl-approach label');\n      for(var ar=0; ar<apRadios.length; ar++){\n        var match = apRadios[ar].value === pick;\n        apRadios[ar].checked = match;\n        if(apLabels[ar]) apLabels[ar].classList.toggle('is-on', match);\n      }\n      recompute();\n      \/\/ Now apply the metric-driven recommendation if it differs\n      var apMetricsForReco = {};\n      var axisR = userAxisDeg !== null ? { ux: Math.cos(userAxisDeg * Math.PI \/ 180), uy: Math.sin(userAxisDeg * Math.PI \/ 180) } : fieldAxis(BOUNDARY);\n      var inpR = getInputs();\n      ['ab-straight','ab-curve','boundary','adaptive'].forEach(function(apX){\n        var layX = generateLines(apX, inpR.wM, BOUNDARY, axisR, inpR.headlandM, inpR.turnStyle, inpR.turnR, inpR.turnBuf);\n        apMetricsForReco[apX] = computeMetrics(layX, inpR.wM, inpR.diesel, inpR.cons);\n      });\n      var metricPick = recommendByMetrics(apMetricsForReco).pick;\n      if(metricPick !== current){\n        current = metricPick;\n        for(var ar2=0; ar2<apRadios.length; ar2++){\n          var match2 = apRadios[ar2].value === metricPick;\n          apRadios[ar2].checked = match2;\n          if(apLabels[ar2]) apLabels[ar2].classList.toggle('is-on', match2);\n        }\n        recompute();\n      }\n    });\n  }\n  \/\/ AB-direction controls\n  var abSliderEl2 = document.getElementById('gpl-ab-deg');\n  var abAutoBtnEl = document.getElementById('gpl-ab-auto');\n  if(abSliderEl2){\n    abSliderEl2.addEventListener('input', function(){\n      var deg = parseFloat(this.value);\n      if(isNaN(deg)) deg = 0;\n      userAxisDeg = deg;\n      if(abAutoBtnEl) abAutoBtnEl.classList.remove('is-auto');\n      recompute();\n    });\n  }\n  if(abAutoBtnEl){\n    abAutoBtnEl.classList.add('is-auto');\n    abAutoBtnEl.addEventListener('click', function(){\n      userAxisDeg = null;\n      this.classList.add('is-auto');\n      recompute();\n    });\n  }\n\n  \/\/ Playback controls\n  var lastLayout = null;\n  var pbBtnEl = document.getElementById('gpl-pb-play');\n  var pbTrackEl = document.getElementById('gpl-pb-track');\n  var pbSpdEls = document.querySelectorAll('.gpl-pb-spd');\n  \/\/ Cache the current layout so the RAF loop can redraw without recomputing\n  \/\/ the whole geometry pipeline on every frame.\n  var origDraw = draw;\n  draw = function(layout){ lastLayout = layout; origDraw(layout); };\n  function tick(now){\n    if(!playback.isPlaying){ playback.lastTick = now; return; }\n    var dt = playback.lastTick > 0 ? (now - playback.lastTick) \/ 1000 : 0;\n    playback.lastTick = now;\n    \/\/ 1 km drive per second at 1\u00d7 (visible but not blinking fast)\n    \/\/ 700 m\/s at 1\u00d7 \u2014 30 % slower than the previous 1000 m\/s so individual\n    \/\/ passes are easier to follow visually (a 600 m pass takes ~0.85 s vs 0.6).\n    var metresPerSec = 700 * playback.speed;\n    var dT = playback.totalLen > 0 ? (dt * metresPerSec \/ playback.totalLen) : 0;\n    playback.t += dT;\n    if(playback.t >= 1){\n      playback.t = 1;\n      playback.isPlaying = false;\n      if(pbBtnEl){\n        pbBtnEl.classList.remove('is-playing');\n        pbBtnEl.textContent = '\u25b6';\n      }\n    }\n    updatePlaybackUI();\n    if(lastLayout) origDraw(lastLayout);\n    if(playback.isPlaying) requestAnimationFrame(tick);\n  }\n  if(pbBtnEl){\n    pbBtnEl.addEventListener('click', function(){\n      if(playback.totalLen < 1) return;\n      if(playback.t >= 1) playback.t = 0;\n      playback.isPlaying = !playback.isPlaying;\n      pbBtnEl.classList.toggle('is-playing', playback.isPlaying);\n      pbBtnEl.textContent = playback.isPlaying ? '' : '\u25b6';\n      if(playback.isPlaying){\n        playback.lastTick = 0;\n        requestAnimationFrame(tick);\n      }\n    });\n  }\n  if(pbTrackEl){\n    pbTrackEl.addEventListener('click', function(ev){\n      var rect = pbTrackEl.getBoundingClientRect();\n      var f = (ev.clientX - rect.left) \/ rect.width;\n      if(f < 0) f = 0; if(f > 1) f = 1;\n      playback.t = f;\n      updatePlaybackUI();\n      if(lastLayout) origDraw(lastLayout);\n    });\n  }\n  for(var sb=0; sb<pbSpdEls.length; sb++){\n    pbSpdEls[sb].addEventListener('click', function(){\n      var s = parseFloat(this.getAttribute('data-spd')) || 1;\n      playback.speed = s;\n      for(var sb2=0; sb2<pbSpdEls.length; sb2++) pbSpdEls[sb2].classList.remove('on');\n      this.classList.add('on');\n    });\n  }\n\n  \/\/ Unit toggle (km \/ mi) \u2014 purely a label switch; numbers stay in metres internally\n  var unitTabs = document.querySelectorAll('.gpl-unit-tab');\n  for(var ut=0; ut<unitTabs.length; ut++){\n    unitTabs[ut].addEventListener('click', function(){\n      unit = this.getAttribute('data-unit') || 'km';\n      for(var ut2=0; ut2<unitTabs.length; ut2++) unitTabs[ut2].classList.remove('is-on');\n      this.classList.add('is-on');\n      recompute();\n    });\n  }\n  \/\/ Zoom + fit buttons\n  \/\/ Zoom-around-cursor helper. Adjusts pan so the world point under\n  \/\/ (mx, my) stays at the same screen position after the zoom change.\n  function zoomAroundCursor(mx, my, factor){\n    var projBefore = getScale();\n    var wx = worldX(projBefore, mx);\n    var wy = worldY(projBefore, my);\n    var newZoom = view.zoom * factor;\n    if(newZoom < 0.2) newZoom = 0.2;\n    if(newZoom > 50) newZoom = 50;\n    view.zoom = newZoom;\n    var projAfter = getScale();\n    view.panX += mx - px(projAfter, wx);\n    view.panY += my - py(projAfter, wy);\n    if(lastLayout) origDraw(lastLayout);\n  }\n  function zoomCenter(factor){\n    var rect = canvas.getBoundingClientRect();\n    zoomAroundCursor(rect.width * 0.5, rect.height * 0.5, factor);\n  }\n  var zInEl = document.getElementById('gpl-tool-zoom-in');\n  var zOutEl = document.getElementById('gpl-tool-zoom-out');\n  var zFitEl = document.getElementById('gpl-tool-fit');\n  if(zInEl) zInEl.addEventListener('click', function(){ zoomCenter(1.3); });\n  if(zOutEl) zOutEl.addEventListener('click', function(){ zoomCenter(1\/1.3); });\n  if(zFitEl) zFitEl.addEventListener('click', function(){\n    view.zoom = 1; view.panX = 0; view.panY = 0;\n    if(lastLayout) origDraw(lastLayout);\n  });\n  \/\/ Mouse wheel \u2014 smooth exponential zoom (matches field-data-explorer feel)\n  canvas.addEventListener('wheel', function(ev){\n    ev.preventDefault();\n    var rect = canvas.getBoundingClientRect();\n    var mx = ev.clientX - rect.left;\n    var my = ev.clientY - rect.top;\n    var factor = Math.exp(-ev.deltaY * 0.0015);\n    zoomAroundCursor(mx, my, factor);\n  }, { passive: false });\n  \/\/ Drag-to-pan (when ruler is not active)\n  var dragState = null;\n  canvas.addEventListener('mousedown', function(ev){\n    var rect = canvas.getBoundingClientRect();\n    var mx = ev.clientX - rect.left;\n    var my = ev.clientY - rect.top;\n    if(ruler.active){\n      var proj = getScale();\n      var wx = worldX(proj, mx);\n      var wy = worldY(proj, my);\n      if(!ruler.p1){\n        ruler.p1 = { x: wx, y: wy }; ruler.p2 = null;\n      } else if(!ruler.p2){\n        ruler.p2 = { x: wx, y: wy };\n      } else {\n        ruler.p1 = { x: wx, y: wy }; ruler.p2 = null;\n      }\n      if(lastLayout) origDraw(lastLayout);\n      return;\n    }\n    dragState = { startX: mx, startY: my, startPanX: view.panX, startPanY: view.panY };\n    canvas.style.cursor = 'grabbing';\n  });\n  canvas.addEventListener('mousemove', function(ev){\n    if(!dragState) return;\n    var rect = canvas.getBoundingClientRect();\n    var mx = ev.clientX - rect.left;\n    var my = ev.clientY - rect.top;\n    view.panX = dragState.startPanX + (mx - dragState.startX);\n    view.panY = dragState.startPanY + (my - dragState.startY);\n    if(lastLayout) origDraw(lastLayout);\n  });\n  function endDrag(){\n    dragState = null;\n    canvas.style.cursor = ruler.active ? 'crosshair' : 'default';\n  }\n  canvas.addEventListener('mouseup', endDrag);\n  canvas.addEventListener('mouseleave', endDrag);\n  \/\/ Touch \u2014 single-finger pan, two-finger pinch-zoom (mirrors field-explorer)\n  var touchState = null;\n  function _tDist(a, b){ var dx = a.clientX - b.clientX, dy = a.clientY - b.clientY; return Math.sqrt(dx*dx + dy*dy); }\n  function _tCenter(a, b){ return [(a.clientX + b.clientX) * 0.5, (a.clientY + b.clientY) * 0.5]; }\n  canvas.addEventListener('touchstart', function(ev){\n    if(ev.touches.length === 1){\n      ev.preventDefault();\n      var rect = canvas.getBoundingClientRect();\n      touchState = { mode: 'pan', x: ev.touches[0].clientX, y: ev.touches[0].clientY, sx: ev.touches[0].clientX - rect.left, sy: ev.touches[0].clientY - rect.top, panX: view.panX, panY: view.panY, moved: false };\n    } else if(ev.touches.length >= 2){\n      ev.preventDefault();\n      var c = _tCenter(ev.touches[0], ev.touches[1]);\n      touchState = { mode: 'pinch', dist: _tDist(ev.touches[0], ev.touches[1]), cx: c[0], cy: c[1] };\n    }\n  }, { passive: false });\n  canvas.addEventListener('touchmove', function(ev){\n    if(!touchState) return;\n    ev.preventDefault();\n    if(touchState.mode === 'pan' ? ev.touches.length === 1 : false){\n      var t = ev.touches[0];\n      var dx = t.clientX - touchState.x;\n      var dy = t.clientY - touchState.y;\n      view.panX = touchState.panX + dx;\n      view.panY = touchState.panY + dy;\n      if(Math.abs(dx) > 4 ? true : Math.abs(dy) > 4) touchState.moved = true;\n      if(lastLayout) origDraw(lastLayout);\n    } else if(touchState.mode === 'pinch' ? ev.touches.length >= 2 : false){\n      var newDist = _tDist(ev.touches[0], ev.touches[1]);\n      var newC = _tCenter(ev.touches[0], ev.touches[1]);\n      var rectT = canvas.getBoundingClientRect();\n      var ncx = newC[0] - rectT.left, ncy = newC[1] - rectT.top;\n      zoomAroundCursor(ncx, ncy, newDist \/ touchState.dist);\n      touchState.dist = newDist; touchState.cx = newC[0]; touchState.cy = newC[1];\n    }\n  }, { passive: false });\n  canvas.addEventListener('touchend', function(ev){\n    \/\/ Ruler tap support: if ruler mode and no drag occurred, drop a point at the touch position\n    if(touchState ? (touchState.mode === 'pan' ? (!touchState.moved ? ruler.active : false) : false) : false){\n      var proj = getScale();\n      var wx = worldX(proj, touchState.sx);\n      var wy = worldY(proj, touchState.sy);\n      if(!ruler.p1){ ruler.p1 = { x: wx, y: wy }; ruler.p2 = null; }\n      else if(!ruler.p2){ ruler.p2 = { x: wx, y: wy }; }\n      else { ruler.p1 = { x: wx, y: wy }; ruler.p2 = null; }\n      if(lastLayout) origDraw(lastLayout);\n    }\n    if(ev.touches.length === 0) touchState = null;\n  });\n  \/\/ Ruler toggle\n  var rulerBtnEl = document.getElementById('gpl-tool-ruler');\n  var rulerHintEl = document.getElementById('gpl-ruler-hint');\n  if(rulerBtnEl){\n    rulerBtnEl.addEventListener('click', function(){\n      ruler.active = !ruler.active;\n      this.classList.toggle('is-on', ruler.active);\n      if(rulerHintEl) rulerHintEl.classList.toggle('is-on', ruler.active);\n      canvas.style.cursor = ruler.active ? 'crosshair' : 'default';\n      if(!ruler.active){\n        ruler.p1 = null; ruler.p2 = null;\n        if(lastLayout) origDraw(lastLayout);\n      }\n    });\n  }\n\n  \/\/ Resizable left panel \u2014 drag splitter to set --gpl-left-w on the wrap.\n  \/\/ Clamped to [200, 380] px so the panel never collapses or eats the canvas.\n  var splitterEl = document.getElementById('gpl-splitter');\n  if(splitterEl){\n    var spState = null;\n    splitterEl.addEventListener('mousedown', function(ev){\n      var current = parseFloat(getComputedStyle(root).getPropertyValue('--gpl-left-w')) || 260;\n      spState = { startX: ev.clientX, startW: current };\n      splitterEl.classList.add('is-drag');\n      ev.preventDefault();\n    });\n    window.addEventListener('mousemove', function(ev){\n      if(!spState) return;\n      var w = spState.startW + (ev.clientX - spState.startX);\n      if(w < 200) w = 200;\n      if(w > 380) w = 380;\n      root.style.setProperty('--gpl-left-w', w + 'px');\n      \/\/ Canvas size changed \u2192 refit and redraw\n      resize();\n      if(lastLayout) origDraw(lastLayout);\n    });\n    window.addEventListener('mouseup', function(){\n      if(!spState) return;\n      spState = null;\n      splitterEl.classList.remove('is-drag');\n    });\n  }\n\n  \/\/ Initial recommendation \u2014 pre-select the shape-optimal approach so the\n  \/\/ page lands on the agronomically sensible default, not arbitrary AB Straight.\n  (function(){\n    var initialPick = recommendApproach(BOUNDARY).pick;\n    current = initialPick;\n    var apRadios0 = document.querySelectorAll('#gpl-approach input[type=radio]');\n    var apLabels0 = document.querySelectorAll('#gpl-approach label');\n    for(var ar0=0; ar0<apRadios0.length; ar0++){\n      var match0 = apRadios0[ar0].value === initialPick;\n      apRadios0[ar0].checked = match0;\n      if(apLabels0[ar0]) apLabels0[ar0].classList.toggle('is-on', match0);\n    }\n  })();\n\n  resize();\n  updateHeadlandLabel();\n  applyMachineRadius();\n  recompute();\n  window.addEventListener('resize', function(){ resize(); recompute(); });\n})();\n<\/script>\n<\/div>\n\n\n\n\n<div class=\"gp-lead\">\n<section class=\"gpx-cta\">\n  <h2>Bigger picture? GeoPard turns the data into prescriptions.<\/h2>\n  <p>This page reads one file at a time. The full GeoPard platform combines multi-year yield, NDVI, soil, and topography into management zones, generates variable rate prescriptions, and pushes them to your machine.<\/p>\n  <div class=\"gpx-integ-label\">Push prescriptions and pull as-applied data with:<\/div>\n  <div class=\"gpx-integ\">\n    <span class=\"gpx-integ-chip\">John Deere Operations Center<\/span>\n    <span class=\"gpx-integ-chip\">CNH FieldOps<\/span>\n    <span class=\"gpx-integ-chip\">AGCO \/ PTx FarmEngage<\/span>\n  <\/div>\n  <a class=\"gpx-btn\" href=\"https:\/\/app.geopard.tech\/signup?utm_source=geopard.tech&amp;utm_medium=lead-magnet&amp;utm_campaign=field-data-explorer&amp;utm_content=below-tool-cta\">Register free in GeoPard &rarr;<\/a>\n<\/section>\n\n<section class=\"gpx-faq\" aria-labelledby=\"gpx-faq-h\">\n  <h2 id=\"gpx-faq-h\">Frequently asked questions<\/h2>\n  <div class=\"gpx-tabs\">\n    <div class=\"gpx-tablist\" role=\"tablist\" aria-label=\"Field Data Explorer FAQ\">\n      <button class=\"gpx-tab\" role=\"tab\" id=\"gpx-tab-1\" aria-controls=\"gpx-panel-1\" aria-selected=\"true\" tabindex=\"0\">File formats<\/button>\n      <button class=\"gpx-tab\" role=\"tab\" id=\"gpx-tab-2\" aria-controls=\"gpx-panel-2\" aria-selected=\"false\" tabindex=\"-1\">Privacy &amp; data<\/button>\n      <button class=\"gpx-tab\" role=\"tab\" id=\"gpx-tab-3\" aria-controls=\"gpx-panel-3\" aria-selected=\"false\" tabindex=\"-1\">Outlier colors<\/button>\n      <button class=\"gpx-tab\" role=\"tab\" id=\"gpx-tab-4\" aria-controls=\"gpx-panel-4\" aria-selected=\"false\" tabindex=\"-1\">Saving analysis<\/button>\n      <button class=\"gpx-tab\" role=\"tab\" id=\"gpx-tab-5\" aria-controls=\"gpx-panel-5\" aria-selected=\"false\" tabindex=\"-1\">Integrations<\/button>\n    <\/div>\n    <div class=\"gpx-panel is-active\" role=\"tabpanel\" id=\"gpx-panel-1\" aria-labelledby=\"gpx-tab-1\">\n      <h3>What file formats and layers are supported?<\/h3>\n      <p><strong>Layers:<\/strong> yield maps, as-applied (seeding, fertilizer, spraying, lime), AB and guidance lines, soil sample points, field boundaries, and Trimble Coverage maps.<\/p>\n      <p><strong>Containers:<\/strong> <strong>GeoJSON<\/strong> with Point, LineString, Polygon, or MultiPolygon geometry, and <strong>zipped shapefiles<\/strong> in EPSG:4326 (WGS84). Projected shapefiles will silently mis-place coordinates, so convert them to WGS84 first or use the full GeoPard import flow which handles reprojection.<\/p>\n    <\/div>\n    <div class=\"gpx-panel\" role=\"tabpanel\" id=\"gpx-panel-2\" aria-labelledby=\"gpx-tab-2\" hidden>\n      <h3>Are you storing my data?<\/h3>\n      <p>No. The page is fully client-side. Nothing about your file leaves the browser. There is no upload, no server log, no telemetry on the file contents. Close the tab and it is gone. You can verify this with browser dev tools by watching the Network panel after dropping a file.<\/p>\n    <\/div>\n    <div class=\"gpx-panel\" role=\"tabpanel\" id=\"gpx-panel-3\" aria-labelledby=\"gpx-tab-3\" hidden>\n      <h3>Why are some points grey or violet?<\/h3>\n      <p><strong>Grey<\/strong> = low-side outliers (likely a missed pass, wet spot, header float issue, or boundary noise). <strong>Violet<\/strong> = high-side outliers (likely double-pass overlaps in as-applied maps, or a moisture or sensor hot spot in yield). Adjust the <code>sigma<\/code> slider to make outlier detection more or less strict, or toggle outliers off to see the raw distribution.<\/p>\n    <\/div>\n    <div class=\"gpx-panel\" role=\"tabpanel\" id=\"gpx-panel-4\" aria-labelledby=\"gpx-tab-4\" hidden>\n      <h3>Can I save my analysis?<\/h3>\n      <p>Not from this page. Saving farm history, sharing fields with your agronomist, layering NDVI, soil tests, and elevation, generating variable rate prescriptions, and exporting work files to your equipment platform all live in the full GeoPard app.<\/p>\n    <\/div>\n    <div class=\"gpx-panel\" role=\"tabpanel\" id=\"gpx-panel-5\" aria-labelledby=\"gpx-tab-5\" hidden>\n      <h3>What equipment platforms can GeoPard write prescriptions to?<\/h3>\n      <p>From the full GeoPard platform you can push variable rate prescription files and import as-applied data with <strong>John Deere Operations Center<\/strong>, <strong>CNH FieldOps<\/strong>, and <strong>AGCO \/ PTx FarmEngage<\/strong>, plus shapefile and ISO-XML exports for other monitors. Talk to us if you run a mixed fleet.<\/p>\n    <\/div>\n  <\/div>\n<\/section>\n<\/div>\n<script nowprocket data-no-optimize=\"1\" data-no-defer=\"1\" data-no-minify=\"1\">\n(function(){\n  var root = document.querySelector('.gp-lead .gpx-faq');\n  if(!root) return;\n  var tabs = root.querySelectorAll('.gpx-tab');\n  var panels = root.querySelectorAll('.gpx-panel');\n  function activate(idx){\n    tabs.forEach(function(t,i){\n      var on = i===idx;\n      t.setAttribute('aria-selected', on ? 'true' : 'false');\n      t.setAttribute('tabindex', on ? '0' : '-1');\n    });\n    panels.forEach(function(p,i){\n      var on = i===idx;\n      p.classList.toggle('is-active', on);\n      if(on){ p.removeAttribute('hidden'); } else { p.setAttribute('hidden',''); }\n    });\n  }\n  tabs.forEach(function(t,i){\n    t.addEventListener('click', function(){ activate(i); });\n    t.addEventListener('keydown', function(e){\n      var n=tabs.length, ni=i;\n      if(e.key==='ArrowRight'){ni=(i+1)%n;}\n      else if(e.key==='ArrowLeft'){ni=(i-1+n)%n;}\n      else if(e.key==='Home'){ni=0;}\n      else if(e.key==='End'){ni=n-1;}\n      else { return; }\n      e.preventDefault();\n      activate(ni);\n      tabs[ni].focus();\n    });\n  });\n})();\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>Simulador de L\u00edneas Gu\u00eda \u00b7 Gratis \u00b7 Sin registro Planifique la trayectoria de su tractor. Encuentre el plan de conducci\u00f3n con menor consumo de combustible y mayor cobertura para su campo. Compare AB Straight, AB\u2026<\/p>","protected":false},"author":210157960,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","_eb_attr":"","_crdt_document":"{\"document\":\"AAA5hoSfoA3i94P\/AQyGhJ+gDeL3g\/8BCcaEn6ANB+L3g\/8BAMaEn6ANA+L3g\/8BAYaEn6AN4veD\/wFXfJgHNiKaAbDVBLAIvAUC9vMDqswk1L8lwAOEA2RCBgRKrocBAQIKAQBK+ocBArCHAQbOjwGueoTMJCbUxyUyqgMBChwCAQIKAQRKXuIEggUIAQBKpAIBAQgBB0cA1AIEyAWqCIoBEJ5WBLz+AxKeCBKuBQ4CrsADDpKXHSYesgiaAbDVBLAIvAUCALTYIOrMJITMJPS4JMiNAQEOjwEoAKgAoQDEBcEBqAMoAKgBhwAoAycAKAInAKgExAIhASgAIQAnAAQAJwABACcAKAQnACgMJwAHACEAKAAhAScAIQAAACEAKAAhAycAKAChACEBoQAhAocAIQAoACEAJwAhASgAIQYnAAAAoQCoAKEBRADBAMQAwQDEAMEAxADBAMQAwQDEAcEAxADBAMQAwaLcCa7bCXN0YXRldmVyc2lvbjxkaXYgY2xhc3M9ImdwLWxlYWQiPgouZ3AtbGVhZHtmb250LWZhbWlseTp2YXIoLS13cC0tcHJlc2V0LS1mb250LWZhbWlseS0tbnVuaXRvLCJOdW5pdG8iLHN5c3RlbS11aSwtYXBwbGUtc3lzdGVtLFNlZ29lIFVJLHNhbnMtc2VyaWYpO2NvbG9yOiMyMTIxMjE7bWF4LXdpZHRoOjEwODBweDttYXJnaW46MCBhdXRvO3BhZGRpbmc6MCA4cHh9Ci5ncC1sZWFkIGgxe2ZvbnQtZmFtaWx5OnZhcigtLXdwLS1wcmVzZXQtLWZvbnQtZmFtaWx5LS1wb3BwaW5zLCJQb3BwaW5zIixzeXN0ZW0tdWksc2Fucy1zZXJpZik7Zm9udC13ZWlnaHQ6ODAwO2NvbG9yOiMwZTNhMWM7bGluZS1oZWlnaHQ6MS4xNTtsZXR0ZXItc3BhY2luZzotMC4wMThlbTttYXJnaW46MCAwIDEycHg7Zm9udC1zaXplOjEuOTVyZW07bWF4LXdpZHRoOjgyMHB4fQouZ3AtbGVhZCBoMSAuYWNjZW50e2JhY2tncm91bmQ6bGluZWFyLWdyYWRpZW50KDEyMGRlZywjZjc2YTBjIDAlLCMxNTcwMWUgMTAwJSk7LXdlYmtpdC1iYWNrZ3JvdW5kLWNsaXA6dGV4dDtiYWNrZ3JvdW5kLWNsaXA6dGV4dDtjb2xvcjp0cmFuc3BhcmVudH0KLmdwLWxlYWQgLmdwbC1oZXJve3Bvc2l0aW9uOnJlbGF0aXZlO2JhY2tncm91bmQ6cmFkaWFsLWdyYWRpZW50KDkwMHB4IDM2MHB4IGF0IDAlIC0xMCUscmdiYSg3NCwyMjIsMTI4LDAuMTgpLHRyYW5zcGFyZW50IDYwJSkscmFkaWFsLWdyYWRpZW50KDcwMHB4IDMyMHB4IGF0IDEwNSUgMTEwJSxyZ2JhKDI0NywxMDYsMTIsMC4xMCksdHJhbnNwYXJlbnQgNjAlKSxsaW5lYXItZ3JhZGllbnQoMTgwZGVnLCNmYmZjZjYgMCUsI2YxZjZlOCAxMDAlKTtib3JkZXI6MXB4IHNvbGlkICNkNmUyYzU7Ym9yZGVyLXJhZGl1czoyMHB4O3BhZGRpbmc6MjZweCAzMHB4IDIycHg7bWFyZ2luOjZweCAwIDI0cHg7b3ZlcmZsb3c6aGlkZGVuO2JveC1zaGFkb3c6MCAxMnB4IDMycHggcmdiYSgyMCw4Myw0MCwwLjA2KSwwIDAgMCAxcHggcmdiYSgyNTUsMjU1LDI1NSwwLjU1KSBpbnNldH0KLmdwLWxlYWQgLmdwbC1oZXJvLWV5ZWJyb3d7ZGlzcGxheTppbmxpbmUtZmxleDthbGlnbi1pdGVtczpjZW50ZXI7Z2FwOjhweDtmb250LWZhbWlseTp2YXIoLS13cC0tcHJlc2V0LS1mb250LWZhbWlseS0tcG9wcGlucywiUG9wcGlucyIsc2Fucy1zZXJpZik7Zm9udC1zaXplOi43NHJlbTtmb250LXdlaWdodDo3MDA7bGV0dGVyLXNwYWNpbmc6LjE0ZW07dGV4dC10cmFuc2Zvcm06dXBwZXJjYXNlO2NvbG9yOiMxNTcwMWU7YmFja2dyb3VuZDojZmZmO2JvcmRlcjoxcHggc29saWQgI2NmZTRkNDtib3JkZXItcmFkaXVzOjk5OXB4O3BhZGRpbmc6NnB4IDEycHg7bWFyZ2luOjAgMCAxNHB4O2JveC1zaGFkb3c6MCAxcHggMnB4IHJnYmEoMjAsODMsNDAsMC4wNSl9Ci5ncC1sZWFkIC5ncGwtaGVyby1leWVicm93OjpiZWZvcmV7Y29udGVudDoiIjt3aWR0aDo3cHg7aGVpZ2h0OjdweDtib3JkZXItcmFkaXVzOjUwJTtiYWNrZ3JvdW5kOiMyMmM1NWU7Ym94LXNoYWRvdzowIDAgMCAzcHggcmdiYSgzNCwxOTcsOTQsMC4yMil9Ci5ncC1sZWFkIC5ncGwtaGVybyAubGVkZXtmb250LXNpemU6MS4wMnJlbTtsaW5lLWhlaWdodDoxLjU1O2NvbG9yOiMyNDMwMjQ7bWFyZ2luOjA7bWF4LXdpZHRoOjgyMHB4O2ZvbnQtd2VpZ2h0OjQwMH0KLmdwLWxlYWQgLmdwbC1oZXJvIC5sZWRlIHN0cm9uZ3tjb2xvcjojMGUzYTFjO2ZvbnQtd2VpZ2h0OjYwMH0KLmdwLWxlYWQgLmdwbC1oZXJvLWZlYXR1cmVze2Rpc3BsYXk6ZmxleDtmbGV4LXdyYXA6d3JhcDtnYXA6OHB4O21hcmdpbjoxOHB4IDAgMH0KLmdwLWxlYWQgLmdwbC1oZXJvLWZlYXR7ZGlzcGxheTppbmxpbmUtZmxleDthbGlnbi1pdGVtczpjZW50ZXI7Z2FwOjhweDtiYWNrZ3JvdW5kOiNmZmY7Ym9yZGVyOjFweCBzb2xpZCAjZDhlNmQ4O2NvbG9yOiMxYzRhMmE7Zm9udC1zaXplOi44NnJlbTtmb250LXdlaWdodDo2MDA7cGFkZGluZzo2cHggMTJweDtib3JkZXItcmFkaXVzOjk5OXB4O2ZvbnQtZmFtaWx5OnZhcigtLXdwLS1wcmVzZXQtLWZvbnQtZmFtaWx5LS1wb3BwaW5zLCJQb3BwaW5zIixzYW5zLXNlcmlmKTtib3gtc2hhZG93OjAgMXB4IDJweCByZ2JhKDIwLDgzLDQwLDAuMDQpfQouZ3AtbGVhZCAuZ3BsLWhlcm8tZmVhdDo6YmVmb3Jle2NvbnRlbnQ6IlwyNzEzIjt3aWR0aDoxNnB4O2hlaWdodDoxNnB4O2ZsZXg6MCAwIDE2cHg7YmFja2dyb3VuZDojMjJjNTVlO2NvbG9yOiNmZmY7Ym9yZGVyLXJhZGl1czo1MCU7Zm9udC1zaXplOjEwcHg7Zm9udC13ZWlnaHQ6ODAwO2xpbmUtaGVpZ2h0OjE2cHg7dGV4dC1hbGlnbjpjZW50ZXJ9Ci5ncC1sZWFkIC5ncGwtaGVyby1mZWF0LmlzLXRydXN0e2JhY2tncm91bmQ6dHJhbnNwYXJlbnQ7Ym9yZGVyLWNvbG9yOnRyYW5zcGFyZW50O2NvbG9yOiMzYTRhM2E7cGFkZGluZzo2cHggNHB4O2JveC1zaGFkb3c6bm9uZX0KLmdwLWxlYWQgLmdwbC1oZXJvLWZlYXQuaXMtdHJ1c3Q6OmJlZm9yZXtjb250ZW50OiJcMUY1MTIiO3dpZHRoOmF1dG87aGVpZ2h0OmF1dG87YmFja2dyb3VuZDp0cmFuc3BhcmVudDtjb2xvcjojMTU3MDFlO2ZvbnQtc2l6ZToxM3B4O2xpbmUtaGVpZ2h0OjF9CkBtZWRpYSAobWF4LXdpZHRoOjc2MHB4KXsKICAuZ3AtbGVhZCAuZ3BsLWhlcm97cGFkZGluZzoyMHB4IDE4cHg7bWFyZ2luOjRweCAwIDE2cHg7Ym9yZGVyLXJhZGl1czoxNnB4fQogIC5ncC1sZWFkIC5ncGwtaGVyby1leWVicm93e2ZvbnQtc2l6ZTouNjZyZW07bGV0dGVyLXNwYWNpbmc6LjEyZW07cGFkZGluZzo1cHggMTBweDttYXJnaW4tYm90dG9tOjEwcHh9CiAgLmdwLWxlYWQgaDF7Zm9udC1zaXplOjEuMzVyZW07bGluZS1oZWlnaHQ6MS4yO21hcmdpbi1ib3R0b206OHB4fQogIC5ncC1sZWFkIC5ncGwtaGVybyAubGVkZXtmb250LXNpemU6Ljk1cmVtO2xpbmUtaGVpZ2h0OjEuNX0KICAuZ3AtbGVhZCAuZ3BsLWhlcm8tZmVhdHVyZXN7Z2FwOjZweDttYXJnaW4tdG9wOjEycHh9CiAgLmdwLWxlYWQgLmdwbC1oZXJvLWZlYXR7Zm9udC1zaXplOi43OHJlbTtwYWRkaW5nOjVweCAxMHB4fQo8c2VjdGlvbiBjbGFzcz0iZ3BsLWhlcm8iPgogIDxkaXYgY2xhc3M9ImdwbC1oZXJvLWV5ZWJyb3ciPkd1aWRhbmNlIExpbmVzIFNpbXVsYXRvciDCtyBGcmVlIMK3IE5vIHNpZ251cDwvZGl2PgogIDxoMT5QbGFuIHlvdXIgdHJhY3RvciBwYXRoLiBGaW5kIHRoZSA8c3BhbiBjbGFzcz0iYWNjZW50Ij5sb3dlc3QtZnVlbCwgaGlnaGVzdC1jb3ZlcmFnZTwvc3Bhbj4gZHJpdmUgcGxhbiBmb3IgeW91ciBmaWVsZC48L2gxPgogIDxwIGNsYXNzPSJsZWRlIj5Db21wYXJlIEFCIFN0cmFpZ2h0LCBBQiBDdXJ2ZSwgQm91bmRhcnkgRm9sbG93LCBhbmQgQ29udG91ci1mb2xsb3cgc2lkZSBieSBzaWRlLiBTZWUgPHN0cm9uZz5jb3ZlcmFnZSAlLCB0dXJuYXJvdW5kcywgZnVlbCwgc2xvcGUgY29zdDwvc3Ryb25nPiwgdGhlbiB3YXRjaCB0aGUgZnVsbCBwbGF5YmFjay4gRHJvcCB5b3VyIG93biBib3VuZGFyeSAoR2VvSlNPTiAvIEtNTCAvIHNoYXBlZmlsZSkgb3IgdHJ5IG9uZSBvZiBmb3VyIHNhbXBsZSBmaWVsZHMuPC9wPgogIDxkaXYgY2xhc3M9ImdwbC1oZXJvLWZlYXR1cmVzIj4KICAgIDxzcGFuIGNsYXNzPSJncGwtaGVyby1mZWF0Ij40IGFwcHJvYWNoZXMgc2NvcmVkPC9zcGFuPgogICAgPHNwYW4gY2xhc3M9ImdwbC1oZXJvLWZlYXQiPlNsb3BlLWF3YXJlIGZ1ZWw8L3NwYW4+CiAgICA8c3BhbiBjbGFzcz0iZ3BsLWhlcm8tZmVhdCI+Q292ZXJhZ2UgcmFzdGVyaXNlcjwvc3Bhbj4KICAgIDxzcGFuIGNsYXNzPSJncGwtaGVyby1mZWF0Ij5Ecm9wIHlvdXIgb3duIGZpZWxkPC9zcGFuPgogICAgPHNwYW4gY2xhc3M9ImdwbC1oZXJvLWZlYXQgaXMtdHJ1c3QiPkRhdGEgc3RheXMgaW4geW91ciBicm93c2VyPC9zcGFuPgo8L3NlY3Rpb24+CjwhLS0gL3dwOmh0bWwgLS0+CjwhLS0gd3A6aHRtbCAtLT4Kb3JpZ2luYWxDb250ZW50Y2xpZW50SWRpc1ZhbGlkb3JpZ2luYWxDb250ZW50bmFtZWF0dHJpYnV0ZXNyZWZjb250ZW50VHJwQ29udGVudFJlc3RyaWN0aW9uaW5uZXJCbG9ja3M8ZGl2IGNsYXNzPSJncGwtd3JhcCIgaWQ9ImdwbC1yb290Ij4KPHN0eWxlPgouZ3BsLXdyYXB7YWxsOmluaXRpYWw7ZGlzcGxheTpibG9jaztmb250LWZhbWlseToiTnVuaXRvIixzeXN0ZW0tdWksLWFwcGxlLXN5c3RlbSxzYW5zLXNlcmlmO2ZvbnQtc2l6ZToxM3B4O2xpbmUtaGVpZ2h0OjEuNDU7Y29sb3I6IzIxMjEyMTtiYWNrZ3JvdW5kOiNmYWZiZjQ7Ym9yZGVyOjFweCBzb2xpZCAjZWVlZWVlO2JvcmRlci1yYWRpdXM6MTJweDtvdmVyZmxvdzpoaWRkZW47bWF4LXdpZHRoOjEwMCU7Ym94LXNoYWRvdzowIDRweCAyMHB4IHJnYmEoMjAsODMsNDAsLjA1KX0KLmdwbC13cmFwICosLmdwbC13cmFwICo6OmJlZm9yZSwuZ3BsLXdyYXAgKjo6YWZ0ZXJ7Ym94LXNpemluZzpib3JkZXItYm94fQouZ3BsLXdyYXAgLmdwbC10b3B7ZGlzcGxheTpmbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtqdXN0aWZ5LWNvbnRlbnQ6c3BhY2UtYmV0d2VlbjtwYWRkaW5nOjE0cHggMThweDtib3JkZXItYm90dG9tOjFweCBzb2xpZCAjZWVlZWVlO2JhY2tncm91bmQ6I2ZmZmZmZjtnYXA6MTZweDtmbGV4LXdyYXA6d3JhcH0KLmdwbC13cmFwIC5ncGwtYnJhbmR7ZGlzcGxheTpmbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtnYXA6MTJweDttaW4td2lkdGg6MDtmbGV4OjF9Ci5ncGwtd3JhcCAuZ3BsLWxvZ297d2lkdGg6MjhweDtoZWlnaHQ6MjhweDtib3JkZXItcmFkaXVzOjdweDtiYWNrZ3JvdW5kOmxpbmVhci1ncmFkaWVudCgxMzVkZWcsIzE0NTMyOCAwJSwjMWE3OTUxIDEwMCUpO2Rpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpjZW50ZXI7anVzdGlmeS1jb250ZW50OmNlbnRlcjtjb2xvcjojZmZmO2ZvbnQtd2VpZ2h0OjcwMDtmb250LXNpemU6MTRweDtmbGV4Om5vbmV9Ci5ncGwtd3JhcCAuZ3BsLWgxe2ZvbnQtc2l6ZToxNXB4O2ZvbnQtd2VpZ2h0OjYwMDtsZXR0ZXItc3BhY2luZzotLjAxZW07Zm9udC1mYW1pbHk6IlBvcHBpbnMiLHN5c3RlbS11aSxzYW5zLXNlcmlmfQouZ3BsLXdyYXAgLmdwbC1jaGlwe2Rpc3BsYXk6aW5saW5lLWZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2dhcDo2cHg7Zm9udC1mYW1pbHk6IkRNIE1vbm8iLHVpLW1vbm9zcGFjZSxtb25vc3BhY2U7Zm9udC1zaXplOjExcHg7cGFkZGluZzoycHggOHB4O2JvcmRlci1yYWRpdXM6MTBweDtiYWNrZ3JvdW5kOiNmYWZiZjQ7Y29sb3I6IzRjNjA2Njtib3JkZXI6MXB4IHNvbGlkICNlZWVlZWU7bWFyZ2luLXRvcDozcHh9Ci5ncGwtd3JhcCAuZ3BsLWNoaXAgLmdwbC1kb3R7d2lkdGg6NnB4O2hlaWdodDo2cHg7Ym9yZGVyLXJhZGl1czo1MCU7YmFja2dyb3VuZDojMTU3MDFlO2ZsZXg6bm9uZX0KLmdwbC13cmFwIC5ncGwtY3Rhe2JhY2tncm91bmQ6IzE1NzAxZTtjb2xvcjojZmZmO2JvcmRlcjowO3BhZGRpbmc6OXB4IDE0cHg7Ym9yZGVyLXJhZGl1czo3cHg7Zm9udC13ZWlnaHQ6NjAwO2ZvbnQtc2l6ZToxM3B4O2N1cnNvcjpwb2ludGVyO2ZvbnQtZmFtaWx5OmluaGVyaXQ7ZGlzcGxheTppbmxpbmUtZmxleDthbGlnbi1pdGVtczpjZW50ZXI7Z2FwOjdweDt0ZXh0LWRlY29yYXRpb246bm9uZTt0cmFuc2l0aW9uOmJhY2tncm91bmQgLjE1c30KLmdwbC13cmFwIC5ncGwtY3RhOmhvdmVye2JhY2tncm91bmQ6IzFiN2EyYX0KLmdwbC13cmFwIC5ncGwtZ3JpZHtkaXNwbGF5OmdyaWQ7Z3JpZC10ZW1wbGF0ZS1jb2x1bW5zOnZhcigtLWdwbC1sZWZ0LXcsMjAwcHgpIDVweCAxZnIgMjQwcHg7Z3JpZC10ZW1wbGF0ZS1hcmVhczoibGVmdCBzcGxpdHRlciBtYWluIHJpZ2h0IjttaW4taGVpZ2h0OjYwMHB4fQouZ3BsLXdyYXAgLmdwbC1zaWRle2dyaWQtYXJlYTpsZWZ0O2JhY2tncm91bmQ6I2ZmZmZmZjtib3JkZXItcmlnaHQ6MXB4IHNvbGlkICNlZWVlZWU7cGFkZGluZzoxMHB4IDhweDtkaXNwbGF5OmZsZXg7ZmxleC1kaXJlY3Rpb246Y29sdW1uO2dhcDo3cHg7bWluLXdpZHRoOjA7b3ZlcmZsb3cteTphdXRvfQouZ3BsLXdyYXAgLmdwbC1zcGxpdHRlcntncmlkLWFyZWE6c3BsaXR0ZXI7YmFja2dyb3VuZDp0cmFuc3BhcmVudDtjdXJzb3I6Y29sLXJlc2l6ZTtwb3NpdGlvbjpyZWxhdGl2ZTt1c2VyLXNlbGVjdDpub25lOy13ZWJraXQtdXNlci1zZWxlY3Q6bm9uZTt0b3VjaC1hY3Rpb246bm9uZX0KLmdwbC13cmFwIC5ncGwtc3BsaXR0ZXI6OmJlZm9yZXtjb250ZW50OiIiO3Bvc2l0aW9uOmFic29sdXRlO2xlZnQ6NTAlO3RvcDo1MCU7d2lkdGg6MXB4O2hlaWdodDozNHB4O3RyYW5zZm9ybTp0cmFuc2xhdGUoLTUwJSwtNTAlKTtiYWNrZ3JvdW5kOiNkZGRkZGQ7dHJhbnNpdGlvbjpiYWNrZ3JvdW5kIC4xNXMsd2lkdGggLjE1c30KLmdwbC13cmFwIC5ncGwtc3BsaXR0ZXI6aG92ZXI6OmJlZm9yZSwuZ3BsLXdyYXAgLmdwbC1zcGxpdHRlci5pcy1kcmFnOjpiZWZvcmV7YmFja2dyb3VuZDojMTU3MDFlO3dpZHRoOjNweDtib3JkZXItcmFkaXVzOjJweDtoZWlnaHQ6NDhweH0KLmdwbC13cmFwIC5ncGwtbWFpbntncmlkLWFyZWE6bWFpbjtwb3NpdGlvbjpyZWxhdGl2ZTtiYWNrZ3JvdW5kOiNmYWZiZjR9Ci5ncGwtd3JhcCAuZ3BsLXNpZGUtcmlnaHR7Z3JpZC1hcmVhOnJpZ2h0O2JhY2tncm91bmQ6I2ZmZmZmZjtib3JkZXItbGVmdDoxcHggc29saWQgI2VlZWVlZTtwYWRkaW5nOjEwcHggOHB4O2Rpc3BsYXk6ZmxleDtmbGV4LWRpcmVjdGlvbjpjb2x1bW47Z2FwOjdweDttaW4td2lkdGg6MDtvdmVyZmxvdy15OmF1dG99CkBtZWRpYSAobWF4LXdpZHRoOjEwOTlweCl7CiAgLmdwbC13cmFwIC5ncGwtZ3JpZHtncmlkLXRlbXBsYXRlLWNvbHVtbnM6dmFyKC0tZ3BsLWxlZnQtdywxODBweCkgNXB4IDFmciAyMjBweH0KfQouZ3BsLXdyYXAgLmdwbC1jYW52YXN7ZGlzcGxheTpibG9jazt3aWR0aDoxMDAlO2hlaWdodDoxMDAlO2N1cnNvcjpkZWZhdWx0O2JhY2tncm91bmQ6I2ZhZmJmNH0KLmdwbC13cmFwIC5ncGwtY2FyZCBoM3tmb250LXNpemU6OXB4O2ZvbnQtd2VpZ2h0OjcwMDt0ZXh0LXRyYW5zZm9ybTp1cHBlcmNhc2U7bGV0dGVyLXNwYWNpbmc6LjA4ZW07Y29sb3I6IzRjNjA2NjttYXJnaW46MCAwIDRweCAwO2ZvbnQtZmFtaWx5OiJQb3BwaW5zIixzeXN0ZW0tdWksc2Fucy1zZXJpZn0KLmdwbC13cmFwIC5ncGwtY2FyZHtkaXNwbGF5OmZsZXg7ZmxleC1kaXJlY3Rpb246Y29sdW1uO2dhcDo0cHg7cGFkZGluZzowfQouZ3BsLXdyYXAgLmdwbC1hcHByb2FjaHtkaXNwbGF5OmZsZXg7ZmxleC1kaXJlY3Rpb246Y29sdW1uO2dhcDozcHh9Ci5ncGwtd3JhcCAuZ3BsLWFwcHJvYWNoIGxhYmVse2Rpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpjZW50ZXI7Z2FwOjVweDtwYWRkaW5nOjVweCA3cHg7Ym9yZGVyOjFweCBzb2xpZCAjZWVlZWVlO2JvcmRlci1yYWRpdXM6NXB4O2N1cnNvcjpwb2ludGVyO2JhY2tncm91bmQ6I2ZmZmZmZjtmb250LXNpemU6MTJweDt0cmFuc2l0aW9uOmFsbCAuMTJzO21pbi1oZWlnaHQ6MzJweDtsaW5lLWhlaWdodDoxLjE1fQouZ3BsLXdyYXAgLmdwbC1hcHByb2FjaCBsYWJlbDpob3Zlcntib3JkZXItY29sb3I6IzFiN2EyYTtiYWNrZ3JvdW5kOiNmYWZiZjR9Ci5ncGwtd3JhcCAuZ3BsLWFwcHJvYWNoIGlucHV0W3R5cGU9cmFkaW9de2FjY2VudC1jb2xvcjojMTU3MDFlO3dpZHRoOjE2cHg7aGVpZ2h0OjE2cHg7bWFyZ2luOjB9Ci5ncGwtd3JhcCAuZ3BsLWFwcHJvYWNoIGxhYmVsLmlzLW9ue2JvcmRlci1jb2xvcjojMTU3MDFlO2JhY2tncm91bmQ6I2ZhZmJmNDtmb250LXdlaWdodDo2MDB9Ci5ncGwtd3JhcCAuZ3BsLXJlY297ZGlzcGxheTpub25lO2ZvbnQtc2l6ZTo5cHg7Zm9udC13ZWlnaHQ6NzAwO3RleHQtdHJhbnNmb3JtOnVwcGVyY2FzZTtsZXR0ZXItc3BhY2luZzouMDZlbTtjb2xvcjojMTU3MDFlO2JhY2tncm91bmQ6I2RmZjVlNjtwYWRkaW5nOjJweCA2cHg7Ym9yZGVyLXJhZGl1czo0cHg7bWFyZ2luLWxlZnQ6YXV0bztmb250LWZhbWlseToiRE0gTW9ubyIsdWktbW9ub3NwYWNlLG1vbm9zcGFjZX0KLmdwbC13cmFwIC5ncGwtcmVjby5pcy1vbntkaXNwbGF5OmlubGluZS1ibG9ja30KLmdwbC13cmFwIC5ncGwtaW5wdXQtcm93e2Rpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpjZW50ZXI7Z2FwOjVweH0KLmdwbC13cmFwIC5ncGwtaW5wdXQtcm93IGxhYmVse2ZvbnQtc2l6ZToxMXB4O2NvbG9yOiM0YzYwNjY7ZmxleDoxfQouZ3BsLXdyYXAgLmdwbC1pbnB1dC1yb3cgaW5wdXR7d2lkdGg6NTRweDtwYWRkaW5nOjRweCA2cHg7Ym9yZGVyOjFweCBzb2xpZCAjZWVlZWVlO2JvcmRlci1yYWRpdXM6NHB4O2ZvbnQtZmFtaWx5OmluaGVyaXQ7Zm9udC1zaXplOjEzcHg7dGV4dC1hbGlnbjpyaWdodDttaW4taGVpZ2h0OjI4cHh9Ci5ncGwtd3JhcCAuZ3BsLWlucHV0LXJvdyAuZ3BsLXVuaXR7Zm9udC1zaXplOjEwcHg7Y29sb3I6IzRjNjA2Njt3aWR0aDoyNnB4fQouZ3BsLXdyYXAgLmdwbC1yZXN1bHRze2Rpc3BsYXk6ZmxleDtmbGV4LWRpcmVjdGlvbjpjb2x1bW47Z2FwOjJweDtmb250LWZhbWlseToiRE0gTW9ubyIsdWktbW9ub3NwYWNlLG1vbm9zcGFjZTtmb250LXNpemU6MTFweDtiYWNrZ3JvdW5kOiNmYWZiZjQ7cGFkZGluZzo2cHggOHB4O2JvcmRlci1yYWRpdXM6NXB4O2JvcmRlcjoxcHggc29saWQgI2VlZWVlZX0KLmdwbC13cmFwIC5ncGwtci1yb3d7ZGlzcGxheTpmbGV4O2p1c3RpZnktY29udGVudDpzcGFjZS1iZXR3ZWVuO2FsaWduLWl0ZW1zOmJhc2VsaW5lO3BhZGRpbmc6MXB4IDB9Ci5ncGwtd3JhcCAuZ3BsLXIta3tjb2xvcjojNGM2MDY2O2ZvbnQtc2l6ZToxMHB4fQouZ3BsLXdyYXAgLmdwbC1yLXZ7Zm9udC13ZWlnaHQ6NjAwO2NvbG9yOiMyMTIxMjE7Zm9udC1zaXplOjEycHh9Ci5ncGwtd3JhcCAuZ3BsLXItc2F2aW5nc3tmb250LXNpemU6MTFweDtmb250LXdlaWdodDo2MDB9Ci5ncGwtd3JhcCAuZ3BsLXItcm93LmdwbC1yLXByaXtib3JkZXItdG9wOjFweCBzb2xpZCAjZWVlZWVlO3BhZGRpbmctdG9wOjZweDttYXJnaW4tdG9wOjJweH0KLmdwbC13cmFwIC5ncGwtY21we21hcmdpbi10b3A6NnB4O2JhY2tncm91bmQ6I2ZmZmZmZjtib3JkZXI6MXB4IHNvbGlkICNlZWVlZWU7Ym9yZGVyLXJhZGl1czo2cHg7b3ZlcmZsb3c6aGlkZGVufQouZ3BsLXdyYXAgLmdwbC1jbXAtcm93e2Rpc3BsYXk6Z3JpZDtncmlkLXRlbXBsYXRlLWNvbHVtbnM6MWZyIDQycHggNTBweCA1MHB4O2FsaWduLWl0ZW1zOmNlbnRlcjtwYWRkaW5nOjZweCA4cHg7Zm9udC1zaXplOjExcHg7Ym9yZGVyLWJvdHRvbToxcHggc29saWQgI2Y1ZjNlYjtnYXA6NHB4fQouZ3BsLXdyYXAgLmdwbC1jbXAtcm93Omxhc3QtY2hpbGR7Ym9yZGVyLWJvdHRvbTowfQouZ3BsLXdyYXAgLmdwbC1jbXAtcm93LmdwbC1jbXAtaGVhZHtmb250LXdlaWdodDo2MDA7Y29sb3I6IzRjNjA2Njt0ZXh0LXRyYW5zZm9ybTp1cHBlcmNhc2U7bGV0dGVyLXNwYWNpbmc6LjA0ZW07Zm9udC1zaXplOjEwcHg7YmFja2dyb3VuZDojZmFmYmY0fQouZ3BsLXdyYXAgLmdwbC1jbXAtbmFtZXtmb250LWZhbWlseToiRE0gTW9ubyIsdWktbW9ub3NwYWNlLG1vbm9zcGFjZX0KLmdwbC13cmFwIC5ncGwtY21wLXZhbHt0ZXh0LWFsaWduOnJpZ2h0O2ZvbnQtZmFtaWx5OiJETSBNb25vIix1aS1tb25vc3BhY2UsbW9ub3NwYWNlfQouZ3BsLXdyYXAgLmdwbC1jbXAtcm93LmdwbC1jbXAtY3VycmVudHtiYWNrZ3JvdW5kOiNmYWZiZjR9Ci5ncGwtd3JhcCAuZ3BsLXVuaXQtdG9nZ2xle2Rpc3BsYXk6aW5saW5lLWZsZXg7Z2FwOjJweDtiYWNrZ3JvdW5kOiNmYWZiZjQ7Ym9yZGVyOjFweCBzb2xpZCAjZWVlZWVlO2JvcmRlci1yYWRpdXM6NnB4O3BhZGRpbmc6MnB4O21hcmdpbi1ib3R0b206NXB4O2FsaWduLXNlbGY6ZmxleC1zdGFydH0KLmdwbC13cmFwIC5ncGwtdW5pdC10YWJ7YmFja2dyb3VuZDp0cmFuc3BhcmVudDtib3JkZXI6MDtwYWRkaW5nOjNweCA4cHg7Zm9udC1zaXplOjEwcHg7Zm9udC1mYW1pbHk6IkRNIE1vbm8iLHVpLW1vbm9zcGFjZSxtb25vc3BhY2U7Zm9udC13ZWlnaHQ6NzAwO2NvbG9yOiM0YzYwNjY7Y3Vyc29yOnBvaW50ZXI7Ym9yZGVyLXJhZGl1czo0cHg7bWluLXdpZHRoOjI4cHh9Ci5ncGwtd3JhcCAuZ3BsLXVuaXQtdGFiLmlzLW9ue2JhY2tncm91bmQ6IzE1NzAxZTtjb2xvcjojZmZmfQouZ3BsLXdyYXAgLmdwbC1zbGlkZXItcm93e2Rpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpjZW50ZXI7Z2FwOjZweH0KLmdwbC13cmFwIC5ncGwtcmFuZ2V7ZmxleDoxO2FjY2VudC1jb2xvcjojMTU3MDFlO21pbi1oZWlnaHQ6MjRweH0KLmdwbC13cmFwIC5ncGwtc2xpZGVyLXZhbHtmb250LWZhbWlseToiRE0gTW9ubyIsdWktbW9ub3NwYWNlLG1vbm9zcGFjZTtmb250LXNpemU6MTBweDtjb2xvcjojNGM2MDY2O21pbi13aWR0aDo5MHB4O3RleHQtYWxpZ246cmlnaHR9Ci5ncGwtd3JhcCAuZ3BsLXNlbGVjdC1yb3d7ZGlzcGxheTpmbGV4O2ZsZXgtZGlyZWN0aW9uOmNvbHVtbjtnYXA6MnB4fQouZ3BsLXdyYXAgLmdwbC1zZWxlY3Qtcm93IGxhYmVse2ZvbnQtc2l6ZToxMHB4O2NvbG9yOiM0YzYwNjZ9Ci5ncGwtd3JhcCAuZ3BsLXNlbGVjdC1yb3cgc2VsZWN0e3BhZGRpbmc6NHB4IDZweDtib3JkZXI6MXB4IHNvbGlkICNlZWVlZWU7Ym9yZGVyLXJhZGl1czo0cHg7Zm9udC1mYW1pbHk6aW5oZXJpdDtmb250LXNpemU6MTJweDtiYWNrZ3JvdW5kOiNmZmZmZmY7bWluLWhlaWdodDozMnB4fQouZ3BsLXdyYXAgLmdwbC1jdXItc2Vse21hcmdpbi1sZWZ0OjRweDtwYWRkaW5nOjRweCA2cHg7Ym9yZGVyOjFweCBzb2xpZCAjZWVlZWVlO2JvcmRlci1yYWRpdXM6NXB4O2ZvbnQtZmFtaWx5OmluaGVyaXQ7Zm9udC1zaXplOjExcHg7YmFja2dyb3VuZDojZmZmZmZmO21pbi1oZWlnaHQ6MzJweDt3aWR0aDo0NnB4fQouZ3BsLXdyYXAgLmdwbC1oaW50e2ZvbnQtc2l6ZTo5cHg7Y29sb3I6IzRjNjA2Njtmb250LWZhbWlseToiRE0gTW9ubyIsdWktbW9ub3NwYWNlLG1vbm9zcGFjZTttYXJnaW46LTFweCAwIDJweCAwO2xpbmUtaGVpZ2h0OjEuMztmb250LXN0eWxlOml0YWxpY30KLmdwbC13cmFwIC5ncGwtZmllbGQtcGlja2Vye2Rpc3BsYXk6Z3JpZDtncmlkLXRlbXBsYXRlLWNvbHVtbnM6MWZyIDFmcjtnYXA6M3B4fQouZ3BsLXdyYXAgLmdwbC1mbGR7YmFja2dyb3VuZDojZmZmZmZmO2JvcmRlcjoxcHggc29saWQgI2VlZWVlZTtib3JkZXItcmFkaXVzOjVweDtwYWRkaW5nOjRweCA1cHg7Zm9udC1mYW1pbHk6aW5oZXJpdDtmb250LXNpemU6MTBweDtmb250LXdlaWdodDo2MDA7Y3Vyc29yOnBvaW50ZXI7Y29sb3I6IzIxMjEyMTtkaXNwbGF5OmZsZXg7ZmxleC1kaXJlY3Rpb246Y29sdW1uO2FsaWduLWl0ZW1zOmZsZXgtc3RhcnQ7Z2FwOjA7dGV4dC1hbGlnbjpsZWZ0O3RyYW5zaXRpb246YWxsIC4xMnM7bWluLWhlaWdodDozNHB4O2xpbmUtaGVpZ2h0OjEuMX0KLmdwbC13cmFwIC5ncGwtZmxkOmhvdmVye2JvcmRlci1jb2xvcjojMWI3YTJhO2JhY2tncm91bmQ6I2ZhZmJmNH0KLmdwbC13cmFwIC5ncGwtZmxkLmlzLW9ue2JvcmRlci1jb2xvcjojMTU3MDFlO2JhY2tncm91bmQ6I2ZhZmJmNDtmb250LXdlaWdodDo3MDB9Ci5ncGwtd3JhcCAuZ3BsLWZsZC1zdWJ7Zm9udC1zaXplOjhweDtjb2xvcjojNGM2MDY2O2ZvbnQtd2VpZ2h0OjUwMDtmb250LXN0eWxlOml0YWxpYzt0ZXh0LXRyYW5zZm9ybTpub25lO2xldHRlci1zcGFjaW5nOjB9Ci5ncGwtd3JhcCAuZ3BsLXVwbG9hZHtkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2p1c3RpZnktY29udGVudDpjZW50ZXI7Z2FwOjVweDtiYWNrZ3JvdW5kOiNmYWZiZjQ7Y29sb3I6IzE1NzAxZTtib3JkZXI6MXB4IGRhc2hlZCAjYjhlNWM2O3BhZGRpbmc6NXB4IDhweDtib3JkZXItcmFkaXVzOjVweDtmb250LWZhbWlseTppbmhlcml0O2ZvbnQtc2l6ZToxMHB4O2ZvbnQtd2VpZ2h0OjYwMDtjdXJzb3I6cG9pbnRlcjttaW4taGVpZ2h0OjMwcHg7bWFyZ2luLXRvcDoycHg7dHJhbnNpdGlvbjphbGwgLjEyc30KLmdwbC13cmFwIC5ncGwtdXBsb2FkOmhvdmVye2JhY2tncm91bmQ6I2U5ZjNlYztib3JkZXItY29sb3I6IzE1NzAxZTtib3JkZXItc3R5bGU6c29saWR9Ci5ncGwtd3JhcCAuZ3BsLXVwbG9hZC1pY297Zm9udC1zaXplOjEzcHg7bGluZS1oZWlnaHQ6MX0KLmdwbC13cmFwIC5ncGwtdXBsb2FkLmlzLWVycm9ye2NvbG9yOiNkYzI2MjY7Ym9yZGVyLWNvbG9yOiNmY2E1YTU7YmFja2dyb3VuZDojZmVmMmYyfQouZ3BsLXdyYXAgLmdwbC11cGxvYWQuaXMtc3VjY2Vzc3tjb2xvcjojMTU3MDFlO2JhY2tncm91bmQ6I2RmZjVlNjtib3JkZXItY29sb3I6IzE1NzAxZTtib3JkZXItc3R5bGU6c29saWR9Ci5ncGwtd3JhcCAuZ3BsLWltcG9ydC1uYXZ7ZGlzcGxheTpmbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtnYXA6NnB4O21hcmdpbi10b3A6M3B4O2p1c3RpZnktY29udGVudDpjZW50ZXJ9Ci5ncGwtd3JhcCAuZ3BsLWltcC1idG57d2lkdGg6MjhweDtoZWlnaHQ6MjhweDtiYWNrZ3JvdW5kOiNmYWZiZjQ7Ym9yZGVyOjFweCBzb2xpZCAjZDllN2RjO2JvcmRlci1yYWRpdXM6NXB4O2NvbG9yOiMxNTcwMWU7Y3Vyc29yOnBvaW50ZXI7Zm9udC1zaXplOjE0cHg7Zm9udC13ZWlnaHQ6NzAwO2ZvbnQtZmFtaWx5OmluaGVyaXQ7bGluZS1oZWlnaHQ6MTtwYWRkaW5nOjA7dHJhbnNpdGlvbjphbGwgLjEyc30KLmdwbC13cmFwIC5ncGwtaW1wLWJ0bjpob3ZlcntiYWNrZ3JvdW5kOiNkZmY1ZTY7Ym9yZGVyLWNvbG9yOiMxNTcwMWV9Ci5ncGwtd3JhcCAuZ3BsLWltcC1idG46ZGlzYWJsZWR7b3BhY2l0eTowLjM1O2N1cnNvcjpub3QtYWxsb3dlZH0KLmdwbC13cmFwIC5ncGwtaW1wLWxibHtmb250LWZhbWlseToiRE0gTW9ubyIsdWktbW9ub3NwYWNlLG1vbm9zcGFjZTtmb250LXNpemU6MTFweDtmb250LXdlaWdodDo2MDA7Y29sb3I6IzRjNjA2NjttaW4td2lkdGg6NjBweDt0ZXh0LWFsaWduOmNlbnRlcn0KLmdwbC13cmFwIC5ncGwtYWItYXV0b3tiYWNrZ3JvdW5kOiNmYWZiZjQ7Y29sb3I6IzE1NzAxZTtib3JkZXI6MXB4IHNvbGlkICNkOWU3ZGM7cGFkZGluZzo0cHggOHB4O2JvcmRlci1yYWRpdXM6NHB4O2ZvbnQtZmFtaWx5OmluaGVyaXQ7Zm9udC1zaXplOjEwcHg7Zm9udC13ZWlnaHQ6NjAwO2N1cnNvcjpwb2ludGVyO21pbi1oZWlnaHQ6MjZweDt0cmFuc2l0aW9uOmFsbCAuMTJzO3dpZHRoOjEwMCU7bWFyZ2luLXRvcDoxcHh9Ci5ncGwtd3JhcCAuZ3BsLWFiLWF1dG86aG92ZXJ7YmFja2dyb3VuZDojZTlmM2VjO2JvcmRlci1jb2xvcjojMTU3MDFlfQouZ3BsLXdyYXAgLmdwbC1hYi1hdXRvLmlzLWF1dG97YmFja2dyb3VuZDojZGZmNWU2O2JvcmRlci1jb2xvcjojMTU3MDFlfQouZ3BsLXdyYXAgLmdwbC13YXJue3Bvc2l0aW9uOmFic29sdXRlO3RvcDoxMHB4O2xlZnQ6NTAlO3RyYW5zZm9ybTp0cmFuc2xhdGVYKC01MCUpO2JhY2tncm91bmQ6cmdiYSgyNDcsMTA2LDEyLDAuOTUpO2NvbG9yOiNmZmY7cGFkZGluZzo4cHggMTRweDtib3JkZXItcmFkaXVzOjhweDtmb250LXNpemU6MTJweDtmb250LXdlaWdodDo2MDA7Ym94LXNoYWRvdzowIDJweCA4cHggcmdiYSgyNDcsMTA2LDEyLC4zKTttYXgtd2lkdGg6OTAlO3RleHQtYWxpZ246Y2VudGVyO2Rpc3BsYXk6bm9uZX0KLmdwbC13cmFwIC5ncGwtd2Fybi5pcy1vbntkaXNwbGF5OmJsb2NrfQouZ3BsLXdyYXAgLmdwbC1jYXJkLXRvcG97YmFja2dyb3VuZDpsaW5lYXItZ3JhZGllbnQoMTM1ZGVnLCNmYWZiZjQgMCUsI2VlZjRlYyAxMDAlKTtib3JkZXI6MXB4IHNvbGlkICNkOWU3ZGM7Ym9yZGVyLXJhZGl1czo4cHg7cGFkZGluZzoxMHB4IDEycHh9Ci5ncGwtd3JhcCAuZ3BsLXRvcG8tYmx1cmJ7Zm9udC1zaXplOjExcHg7bGluZS1oZWlnaHQ6MS40NTtjb2xvcjojNGM2MDY2O21hcmdpbjowIDAgOHB4IDB9Ci5ncGwtd3JhcCAuZ3BsLWN0YS1taW5pe2Rpc3BsYXk6aW5saW5lLWZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2dhcDo1cHg7YmFja2dyb3VuZDojMTU3MDFlO2NvbG9yOiNmZmY7dGV4dC1kZWNvcmF0aW9uOm5vbmU7cGFkZGluZzo3cHggMTFweDtib3JkZXItcmFkaXVzOjZweDtmb250LXNpemU6MTJweDtmb250LXdlaWdodDo2MDA7Zm9udC1mYW1pbHk6aW5oZXJpdDt0cmFuc2l0aW9uOmJhY2tncm91bmQgLjE1czttaW4taGVpZ2h0OjQ0cHg7bGluZS1oZWlnaHQ6MX0KLmdwbC13cmFwIC5ncGwtY3RhLW1pbmk6aG92ZXJ7YmFja2dyb3VuZDojMWI3YTJhfQouZ3BsLXdyYXAgLmdwbC1jdGEtY2FyZHtiYWNrZ3JvdW5kOmxpbmVhci1ncmFkaWVudCgxNDVkZWcsI2VlZmJmMyAwJSwjZGZmNWU2IDEwMCUpO2JvcmRlcjoxcHggc29saWQgI2I4ZTVjNjtib3JkZXItcmFkaXVzOjEwcHg7cGFkZGluZzoxNHB4O21hcmdpbi10b3A6YXV0bztwb3NpdGlvbjpyZWxhdGl2ZTtvdmVyZmxvdzpoaWRkZW59Ci5ncGwtd3JhcCAuZ3BsLWN0YS1jYXJkOjpiZWZvcmV7Y29udGVudDoiIjtwb3NpdGlvbjphYnNvbHV0ZTt0b3A6LTMwcHg7cmlnaHQ6LTMwcHg7d2lkdGg6ODBweDtoZWlnaHQ6ODBweDtiYWNrZ3JvdW5kOnJhZGlhbC1ncmFkaWVudChjaXJjbGUscmdiYSgyMSwxMTIsMzAsLjE0KSAwJSx0cmFuc3BhcmVudCA3MCUpO3BvaW50ZXItZXZlbnRzOm5vbmV9Ci5ncGwtd3JhcCAuZ3BsLWN0YS1jYXJkIGg0e2ZvbnQtc2l6ZToxMHB4O3RleHQtdHJhbnNmb3JtOnVwcGVyY2FzZTtsZXR0ZXItc3BhY2luZzouMTRlbTtjb2xvcjojMGY1MDMzO21hcmdpbjowIDAgMTBweCAwO2ZvbnQtd2VpZ2h0OjcwMDtmb250LWZhbWlseToiUG9wcGlucyIsc3lzdGVtLXVpLHNhbnMtc2VyaWY7cG9zaXRpb246cmVsYXRpdmV9Ci5ncGwtd3JhcCAuZ3BsLWN0YS1saXN0e2xpc3Qtc3R5bGU6bm9uZTtwYWRkaW5nOjA7bWFyZ2luOjAgMCAxMnB4IDA7Zm9udC1zaXplOjEycHg7bGluZS1oZWlnaHQ6MS42O3Bvc2l0aW9uOnJlbGF0aXZlfQouZ3BsLXdyYXAgLmdwbC1jdGEtbGlzdCBsaXtjb2xvcjojMWU1ZDNhO2Rpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpmbGV4LXN0YXJ0O2dhcDo4cHg7Zm9udC13ZWlnaHQ6NTAwO21hcmdpbi1ib3R0b206NHB4fQouZ3BsLXdyYXAgLmdwbC1jdGEtbGlzdCBsaTo6YmVmb3Jle2NvbnRlbnQ6IuKckyI7Y29sb3I6IzE1NzAxZTtmb250LXdlaWdodDo3MDA7ZmxleDpub25lfQouZ3BsLXdyYXAgLmdwbC1jdGEtYnRuLWxne2Rpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpjZW50ZXI7anVzdGlmeS1jb250ZW50OmNlbnRlcjtnYXA6NnB4O2JhY2tncm91bmQ6IzE1NzAxZTtjb2xvcjojZmZmO3RleHQtZGVjb3JhdGlvbjpub25lO3BhZGRpbmc6MTFweCAxMnB4O2JvcmRlci1yYWRpdXM6N3B4O2ZvbnQtd2VpZ2h0OjcwMDtmb250LXNpemU6MTNweDtmb250LWZhbWlseTppbmhlcml0O3Bvc2l0aW9uOnJlbGF0aXZlO3dpZHRoOjEwMCU7dHJhbnNpdGlvbjpiYWNrZ3JvdW5kIC4xNXM7bWluLWhlaWdodDo0NHB4O2JveC1zaXppbmc6Ym9yZGVyLWJveH0KLmdwbC13cmFwIC5ncGwtY3RhLWJ0bi1sZzpob3ZlcntiYWNrZ3JvdW5kOiMxYjdhMmF9Ci5ncGwtd3JhcCAuZ3BsLWN0YS1hcnJ7dHJhbnNpdGlvbjp0cmFuc2Zvcm0gLjE1c30KLmdwbC13cmFwIC5ncGwtY3RhLWJ0bi1sZzpob3ZlciAuZ3BsLWN0YS1hcnJ7dHJhbnNmb3JtOnRyYW5zbGF0ZVgoM3B4KX0KLmdwbC13cmFwIC5ncGwtY3RhLW5vdGV7Zm9udC1zaXplOjEwcHg7Y29sb3I6IzRjNjA2NjttYXJnaW46OHB4IDAgMCAwO2xpbmUtaGVpZ2h0OjEuNDU7dGV4dC1hbGlnbjpjZW50ZXI7Zm9udC1zdHlsZTppdGFsaWN9Ci5ncGwtd3JhcCAuZ3BsLXRyYXl7cG9zaXRpb246YWJzb2x1dGU7dG9wOjYwcHg7bGVmdDoxMHB4O2JhY2tncm91bmQ6cmdiYSgyNTUsMjU1LDI1NSwuOTUpO2JvcmRlcjoxcHggc29saWQgI2VlZWVlZTtib3JkZXItcmFkaXVzOjhweDtwYWRkaW5nOjZweCAxMHB4O2ZvbnQtZmFtaWx5OiJETSBNb25vIix1aS1tb25vc3BhY2UsbW9ub3NwYWNlO2ZvbnQtc2l6ZToxMXB4O2NvbG9yOiM0YzYwNjY7YmFja2Ryb3AtZmlsdGVyOmJsdXIoNHB4KTtib3gtc2hhZG93OjAgMnB4IDZweCByZ2JhKDAsMCwwLC4wNSk7ei1pbmRleDoyfQouZ3BsLXdyYXAgLmdwbC1wYntwb3NpdGlvbjphYnNvbHV0ZTt0b3A6MTBweDtsZWZ0OjEwcHg7cmlnaHQ6MTBweDtiYWNrZ3JvdW5kOnJnYmEoMjU1LDI1NSwyNTUsLjk1KTtib3JkZXI6MXB4IHNvbGlkICNlZWVlZWU7Ym9yZGVyLXJhZGl1czo4cHg7cGFkZGluZzo3cHggMTBweDtkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2dhcDo4cHg7YmFja2Ryb3AtZmlsdGVyOmJsdXIoNHB4KTtib3gtc2hhZG93OjAgMnB4IDZweCByZ2JhKDAsMCwwLC4wNSk7ei1pbmRleDozO2ZsZXgtd3JhcDp3cmFwfQouZ3BsLXdyYXAgLmdwbC1wYi1idG57YmFja2dyb3VuZDojMTU3MDFlO2NvbG9yOiNmZmY7Ym9yZGVyOjA7d2lkdGg6MzJweDtoZWlnaHQ6MzJweDtib3JkZXItcmFkaXVzOjZweDtjdXJzb3I6cG9pbnRlcjtmb250LXNpemU6MTNweDtkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2p1c3RpZnktY29udGVudDpjZW50ZXI7cGFkZGluZzowO2ZvbnQtZmFtaWx5OmluaGVyaXQ7dHJhbnNpdGlvbjpiYWNrZ3JvdW5kIC4xNXM7ZmxleDpub25lO2xpbmUtaGVpZ2h0OjF9Ci5ncGwtd3JhcCAuZ3BsLXBiLWJ0bjpob3ZlcntiYWNrZ3JvdW5kOiMxYjdhMmF9Ci5ncGwtd3JhcCAuZ3BsLXBiLWJ0bi5pcy1wbGF5aW5nOjpiZWZvcmV7Y29udGVudDoi4p2a4p2aIjtmb250LXNpemU6MTFweDtsZXR0ZXItc3BhY2luZzotMXB4fQouZ3BsLXdyYXAgLmdwbC1wYi1idG4uaXMtcGxheWluZ3tmb250LXNpemU6MH0KLmdwbC13cmFwIC5ncGwtcGItdHJhY2t7ZmxleDoxO2hlaWdodDo4cHg7YmFja2dyb3VuZDojZmFmYmY0O2JvcmRlci1yYWRpdXM6NHB4O3Bvc2l0aW9uOnJlbGF0aXZlO2N1cnNvcjpwb2ludGVyO21pbi13aWR0aDo4MHB4O2JvcmRlcjoxcHggc29saWQgI2VlZWVlZX0KLmdwbC13cmFwIC5ncGwtcGItZmlsbHtwb3NpdGlvbjphYnNvbHV0ZTtsZWZ0OjA7dG9wOjA7aGVpZ2h0OjEwMCU7YmFja2dyb3VuZDojMTU3MDFlO2JvcmRlci1yYWRpdXM6M3B4O3BvaW50ZXItZXZlbnRzOm5vbmU7d2lkdGg6MCV9Ci5ncGwtd3JhcCAuZ3BsLXBiLXRodW1ie3Bvc2l0aW9uOmFic29sdXRlO3RvcDo1MCU7bGVmdDowJTt0cmFuc2Zvcm06dHJhbnNsYXRlKC01MCUsLTUwJSk7d2lkdGg6MTRweDtoZWlnaHQ6MTRweDtiYWNrZ3JvdW5kOiMxNTcwMWU7Ym9yZGVyOjJweCBzb2xpZCAjZmZmZmZmO2JvcmRlci1yYWRpdXM6NTAlO3BvaW50ZXItZXZlbnRzOm5vbmU7Ym94LXNoYWRvdzowIDFweCA0cHggcmdiYSgwLDAsMCwuMjUpfQouZ3BsLXdyYXAgLmdwbC1wYi1zZWd7ZmxleDpub25lO2Rpc3BsYXk6ZmxleDtnYXA6MnB4O3BhZGRpbmc6MnB4O2JhY2tncm91bmQ6I2ZhZmJmNDtib3JkZXI6MXB4IHNvbGlkICNlZWVlZWU7Ym9yZGVyLXJhZGl1czo2cHh9Ci5ncGwtd3JhcCAuZ3BsLXBiLXNwZHtwYWRkaW5nOjRweCA3cHg7Zm9udC1zaXplOjEwcHg7YmFja2dyb3VuZDp0cmFuc3BhcmVudDtib3JkZXI6MDtjb2xvcjojNGM2MDY2O2N1cnNvcjpwb2ludGVyO2JvcmRlci1yYWRpdXM6NHB4O2ZvbnQtZmFtaWx5OiJETSBNb25vIix1aS1tb25vc3BhY2UsbW9ub3NwYWNlO2ZvbnQtd2VpZ2h0OjcwMDttaW4td2lkdGg6MjhweDtmb250LWZhbWlseTppbmhlcml0fQouZ3BsLXdyYXAgLmdwbC1wYi1zcGQub257YmFja2dyb3VuZDojMTU3MDFlO2NvbG9yOiNmZmZ9Ci5ncGwtd3JhcCAuZ3BsLXBiLXN0YXRze2ZsZXg6bm9uZTtmb250LWZhbWlseToiRE0gTW9ubyIsdWktbW9ub3NwYWNlLG1vbm9zcGFjZTtmb250LXNpemU6MTBweDtjb2xvcjojNGM2MDY2O3RleHQtYWxpZ246cmlnaHQ7bWluLXdpZHRoOjEzMHB4O2xpbmUtaGVpZ2h0OjEuMztmb250LXdlaWdodDo2MDB9Ci5ncGwtd3JhcCAuZ3BsLXNjYWxle3Bvc2l0aW9uOmFic29sdXRlO2xlZnQ6MTBweDtib3R0b206MTBweDtiYWNrZ3JvdW5kOnJnYmEoMjU1LDI1NSwyNTUsLjk1KTtib3JkZXI6MXB4IHNvbGlkICNlZWVlZWU7Ym9yZGVyLXJhZGl1czo2cHg7cGFkZGluZzo0cHggOHB4O2ZvbnQtZmFtaWx5OiJETSBNb25vIix1aS1tb25vc3BhY2UsbW9ub3NwYWNlO2ZvbnQtc2l6ZToxMHB4O2ZvbnQtd2VpZ2h0OjYwMDtjb2xvcjojNGM2MDY2O2Rpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpjZW50ZXI7Z2FwOjZweDtiYWNrZHJvcC1maWx0ZXI6Ymx1cig0cHgpO3otaW5kZXg6MztsaW5lLWhlaWdodDoxO2JveC1zaGFkb3c6MCAycHggNHB4IHJnYmEoMCwwLDAsLjA1KX0KLmdwbC13cmFwIC5ncGwtc2NhbGUtYmFye2Rpc3BsYXk6aW5saW5lLWJsb2NrO3dpZHRoOjYwcHg7aGVpZ2h0OjZweDtib3JkZXItbGVmdDoycHggc29saWQgIzE0NTMyODtib3JkZXItcmlnaHQ6MnB4IHNvbGlkICMxNDUzMjg7Ym9yZGVyLWJvdHRvbToycHggc29saWQgIzE0NTMyODtib3gtc2l6aW5nOmJvcmRlci1ib3h9Ci5ncGwtd3JhcCAuZ3BsLXNjYWxlLWxibHt3aGl0ZS1zcGFjZTpub3dyYXB9Ci5ncGwtd3JhcCAuZ3BsLXRvb2xze3Bvc2l0aW9uOmFic29sdXRlO3JpZ2h0OjEwcHg7dG9wOjYwcHg7ZGlzcGxheTpmbGV4O2ZsZXgtZGlyZWN0aW9uOmNvbHVtbjtnYXA6NXB4O3otaW5kZXg6NH0KLmdwbC13cmFwIC5ncGwtdG9vbC1idG57d2lkdGg6MzZweDtoZWlnaHQ6MzZweDtiYWNrZ3JvdW5kOnJnYmEoMjU1LDI1NSwyNTUsLjk1KTtib3JkZXI6MXB4IHNvbGlkICNlZWVlZWU7Ym9yZGVyLXJhZGl1czo3cHg7Zm9udC1mYW1pbHk6aW5oZXJpdDtmb250LXNpemU6MTZweDtmb250LXdlaWdodDo2MDA7Y3Vyc29yOnBvaW50ZXI7ZGlzcGxheTpmbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtqdXN0aWZ5LWNvbnRlbnQ6Y2VudGVyO2xpbmUtaGVpZ2h0OjE7cGFkZGluZzowO2NvbG9yOiM0YzYwNjY7dHJhbnNpdGlvbjphbGwgLjEycztib3gtc2hhZG93OjAgMnB4IDRweCByZ2JhKDAsMCwwLC4wOCl9Ci5ncGwtd3JhcCAuZ3BsLXRvb2wtYnRuIHN2Z3t3aWR0aDoxOHB4O2hlaWdodDoxOHB4O2Rpc3BsYXk6YmxvY2t9Ci5ncGwtd3JhcCAuZ3BsLXRvb2wtYnRuOmhvdmVye2JvcmRlci1jb2xvcjojMTU3MDFlO2NvbG9yOiMxNTcwMWV9Ci5ncGwtd3JhcCAuZ3BsLXRvb2wtYnRuLmlzLW9ue2JhY2tncm91bmQ6IzE1NzAxZTtjb2xvcjojZmZmO2JvcmRlci1jb2xvcjojMTU3MDFlfQouZ3BsLXdyYXAgLmdwbC1ydWxlci1oaW50e3Bvc2l0aW9uOmFic29sdXRlO2xlZnQ6NTAlO2JvdHRvbToxNHB4O3RyYW5zZm9ybTp0cmFuc2xhdGVYKC01MCUpO2JhY2tncm91bmQ6cmdiYSgyMCw4Myw0MCwwLjkyKTtjb2xvcjojZmZmO3BhZGRpbmc6N3B4IDEycHg7Ym9yZGVyLXJhZGl1czo3cHg7Zm9udC1zaXplOjExcHg7Zm9udC13ZWlnaHQ6NjAwO2ZvbnQtZmFtaWx5OiJETSBNb25vIix1aS1tb25vc3BhY2UsbW9ub3NwYWNlO2Rpc3BsYXk6bm9uZTt6LWluZGV4OjM7Ym94LXNoYWRvdzowIDJweCA4cHggcmdiYSgwLDAsMCwuMTUpfQouZ3BsLXdyYXAgLmdwbC1ydWxlci1oaW50LmlzLW9ue2Rpc3BsYXk6YmxvY2t9Ci5ncGwtd3JhcCAuZ3BsLWxlZ2VuZHtwb3NpdGlvbjphYnNvbHV0ZTtib3R0b206MTBweDtsZWZ0OjEwcHg7YmFja2dyb3VuZDpyZ2JhKDI1NSwyNTUsMjU1LC45NSk7Ym9yZGVyOjFweCBzb2xpZCAjZWVlZWVlO2JvcmRlci1yYWRpdXM6OHB4O3BhZGRpbmc6OHB4IDEycHg7Zm9udC1zaXplOjExcHg7ZGlzcGxheTpmbGV4O2ZsZXgtZGlyZWN0aW9uOmNvbHVtbjtnYXA6NHB4O2JhY2tkcm9wLWZpbHRlcjpibHVyKDRweCl9Ci5ncGwtd3JhcCAuZ3BsLWxnLXJvd3tkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2dhcDo2cHh9Ci5ncGwtd3JhcCAuZ3BsLWxnLXN3YXRjaHt3aWR0aDoxNHB4O2hlaWdodDozcHg7Ym9yZGVyLXJhZGl1czoycHg7ZmxleDpub25lfQoKQG1lZGlhIChtYXgtd2lkdGg6IDgyMHB4KXsKICAuZ3BsLXdyYXAgLmdwbC1ncmlke2dyaWQtdGVtcGxhdGUtY29sdW1uczoxZnI7Z3JpZC10ZW1wbGF0ZS1hcmVhczoibWFpbiIgInJpZ2h0IiAibGVmdCI7Z3JpZC10ZW1wbGF0ZS1yb3dzOjYydmggYXV0byBhdXRvO21pbi1oZWlnaHQ6YXV0b30KICAuZ3BsLXdyYXAgLmdwbC1zaWRle2JvcmRlci1yaWdodDowO2JvcmRlci10b3A6MXB4IHNvbGlkICNlZWVlZWU7bWF4LWhlaWdodDpub25lO3BhZGRpbmc6MTJweCAxNHB4O2dhcDoxMHB4fQogIC5ncGwtd3JhcCAuZ3BsLXNwbGl0dGVye2Rpc3BsYXk6bm9uZX0KICAuZ3BsLXdyYXAgLmdwbC1zaWRlLXJpZ2h0e2JvcmRlci1sZWZ0OjA7Ym9yZGVyLXRvcDoxcHggc29saWQgI2VlZWVlZTttYXgtaGVpZ2h0Om5vbmU7cGFkZGluZzoxMnB4IDE0cHg7Z2FwOjEwcHh9CiAgLmdwbC13cmFwIC5ncGwtbWFpbnttaW4taGVpZ2h0OjYydmh9CiAgLyogQmlnZ2VyIGNhcmRzICsgdGFwIHRhcmdldHMgb24gdG91Y2ggKi8KICAuZ3BsLXdyYXAgLmdwbC1jYXJkIGgze2ZvbnQtc2l6ZToxMHB4fQogIC5ncGwtd3JhcCAuZ3BsLWFwcHJvYWNoIGxhYmVse21pbi1oZWlnaHQ6NDRweDtmb250LXNpemU6MTNweDtwYWRkaW5nOjdweCAxMHB4fQogIC5ncGwtd3JhcCBpbnB1dFt0eXBlPW51bWJlcl0sLmdwbC13cmFwIHNlbGVjdHtmb250LXNpemU6MTRweDttaW4taGVpZ2h0OjM4cHh9CiAgLmdwbC13cmFwIC5ncGwtZmxke21pbi1oZWlnaHQ6NDRweDtmb250LXNpemU6MTFweDtwYWRkaW5nOjZweCA4cHh9CiAgLmdwbC13cmFwIC5ncGwtZmxkLXN1Yntmb250LXNpemU6OXB4fQogIC5ncGwtd3JhcCAuZ3BsLXVwbG9hZHttaW4taGVpZ2h0OjQwcHg7Zm9udC1zaXplOjExcHh9CiAgLmdwbC13cmFwIC5ncGwtYWItYXV0b3ttaW4taGVpZ2h0OjM2cHg7Zm9udC1zaXplOjExcHh9CiAgLmdwbC13cmFwIC5ncGwtdG9vbC1idG57d2lkdGg6NDBweDtoZWlnaHQ6NDBweH0KICAuZ3BsLXdyYXAgLmdwbC10b29sLWJ0biBzdmd7d2lkdGg6MjBweDtoZWlnaHQ6MjBweH0KICAuZ3BsLXdyYXAgLmdwbC1jdGEtbWluaSwuZ3BsLXdyYXAgLmdwbC1jdGEtYnRuLWxne21pbi1oZWlnaHQ6NDRweH0KICAuZ3BsLXdyYXAgLmdwbC1zbGlkZXItdmFse2ZvbnQtc2l6ZToxMXB4O21pbi13aWR0aDo4MHB4fQogIC5ncGwtd3JhcCAuZ3BsLXJhbmdle21pbi1oZWlnaHQ6MzJweH0KICAvKiBSZXN1bHRzIHJvdyBmb250ICsgc3BhY2luZyDigJQgZWFzaWVyIHRvIHJlYWQgb24gcGhvbmVzICovCiAgLmdwbC13cmFwIC5ncGwtcmVzdWx0c3tmb250LXNpemU6MTJweDtwYWRkaW5nOjhweCAxMHB4O2dhcDozcHh9CiAgLmdwbC13cmFwIC5ncGwtci1re2ZvbnQtc2l6ZToxMXB4fQogIC5ncGwtd3JhcCAuZ3BsLXItdntmb250LXNpemU6MTNweH0KICAvKiBDb21wYXJlIEFsbCBncmlkIOKAlCBrZWVwIDQgY29sdW1ucyBidXQgdGlnaHRlciAqLwogIC5ncGwtd3JhcCAuZ3BsLWNtcC1yb3d7cGFkZGluZzo3cHggOHB4O2ZvbnQtc2l6ZToxMXB4O2dyaWQtdGVtcGxhdGUtY29sdW1uczoxZnIgMzhweCA0NnB4IDQ2cHh9CiAgLyogUGxheWJhY2sgc3RyaXAg4oCUIHdyYXAgYmV0dGVyIHdoZW4gbmFycm93ICovCiAgLmdwbC13cmFwIC5ncGwtcGJ7ZmxleC13cmFwOndyYXA7cGFkZGluZzo2cHggOHB4O2dhcDo2cHh9CiAgLmdwbC13cmFwIC5ncGwtcGItc3RhdHN7bWluLXdpZHRoOjA7ZmxleC1iYXNpczoxMDAlO3RleHQtYWxpZ246bGVmdDtmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxLjM1O3BhZGRpbmctdG9wOjJweDtib3JkZXItdG9wOjFweCBkYXNoZWQgI2VlZWVlZX0KICAuZ3BsLXdyYXAgLmdwbC1wYi10cmFja3ttaW4td2lkdGg6NTBweH0KICAvKiBUb29scyDigJQgcHVzaCBiZWxvdyB0aGUgKHRhbGxlcikgd3JhcHBlZCBwbGF5YmFjayBzdHJpcCAqLwogIC5ncGwtd3JhcCAuZ3BsLXRvb2xze3RvcDo5MHB4fQogIC5ncGwtd3JhcCAuZ3BsLXRyYXl7dG9wOjkwcHg7Zm9udC1zaXplOjEwcHg7cGFkZGluZzo1cHggOHB4fQogIC8qIExlZ2VuZCBhbmQgc2NhbGUtYmFyIOKAlCBzbWFsbGVyLCBsZXNzIGluIHRoZSB3YXkgb24gcGhvbmVzICovCiAgLmdwbC13cmFwIC5ncGwtbGVnZW5ke2ZvbnQtc2l6ZToxMHB4O3BhZGRpbmc6N3B4IDEwcHg7Z2FwOjNweH0KICAuZ3BsLXdyYXAgLmdwbC1zY2FsZXtmb250LXNpemU6OXB4O3BhZGRpbmc6M3B4IDdweH0KICAvKiBVbml0LXRvZ2dsZSAoa20vbWkpIHRhYnMg4oCUIGJpZ2dlciB0YXAgdGFyZ2V0ICovCiAgLmdwbC13cmFwIC5ncGwtdW5pdC10YWJ7cGFkZGluZzo1cHggMTJweDtmb250LXNpemU6MTFweDttaW4taGVpZ2h0OjMycHh9CiAgLyogRmllbGQtcGlja2VyIGdyaWQg4oCUIDLDlzIgc3RpbGwsIHNsaWdodGx5IG1vcmUgYnJlYXRoaW5nIHJvb20gKi8KICAuZ3BsLXdyYXAgLmdwbC1maWVsZC1waWNrZXJ7Z2FwOjVweH0KfQpAbWVkaWEgKG1heC13aWR0aDogNDgwcHgpewogIC5ncGwtd3JhcCAuZ3BsLW1haW57bWluLWhlaWdodDo1OHZofQogIC5ncGwtd3JhcCAuZ3BsLWdyaWR7Z3JpZC10ZW1wbGF0ZS1yb3dzOjU4dmggYXV0byBhdXRvfQogIC5ncGwtd3JhcCAuZ3BsLWFwcHJvYWNoIGxhYmVse21pbi1oZWlnaHQ6NDRweDtmb250LXNpemU6MTRweH0KICAuZ3BsLXdyYXAgaW5wdXRbdHlwZT1udW1iZXJdLC5ncGwtd3JhcCBzZWxlY3R7Zm9udC1zaXplOjE0cHg7bWluLWhlaWdodDo0MHB4fQogIC5ncGwtd3JhcCAuZ3BsLWN0YS1taW5pLC5ncGwtd3JhcCAuZ3BsLWN0YS1idG4tbGd7bWluLWhlaWdodDo0NHB4fQogIC5ncGwtd3JhcCAuZ3BsLWZsZHttaW4taGVpZ2h0OjQ2cHg7Zm9udC1zaXplOjEycHh9CiAgLmdwbC13cmFwIC5ncGwtdG9vbC1idG57d2lkdGg6NDJweDtoZWlnaHQ6NDJweH0KICAuZ3BsLXdyYXAgLmdwbC10b29sLWJ0biBzdmd7d2lkdGg6MjJweDtoZWlnaHQ6MjJweH0KICAuZ3BsLXdyYXAgLmdwbC1jbXAtcm93e2dyaWQtdGVtcGxhdGUtY29sdW1uczoxZnIgMzRweCA0MnB4IDQycHg7Zm9udC1zaXplOjEwLjVweH0KICAuZ3BsLXdyYXAgLmdwbC1pbnB1dC1yb3cgLmdwbC11bml0e2ZvbnQtc2l6ZToxMXB4O3dpZHRoOjMwcHh9CiAgLyogVG9wIGJhciAoaGVhZGVyICsgQ1RBKSDigJQgbGV0IHRoZSBDVEEgd3JhcCBvbnRvIGl0cyBvd24gcm93IG9uIHNtYWxsIHNjcmVlbnMgKi8KICAuZ3BsLXdyYXAgLmdwbC10b3B7cGFkZGluZzoxMHB4IDEycHg7Z2FwOjhweH0KICAuZ3BsLXdyYXAgLmdwbC1jdGF7cGFkZGluZzoxMHB4IDE0cHg7Zm9udC1zaXplOjEzcHg7bWluLWhlaWdodDo0MnB4fQogIC5ncGwtd3JhcCAuZ3BsLWgxe2ZvbnQtc2l6ZToxNHB4fQp9Cjwvc3R5bGU+Cgo8ZGl2IGNsYXNzPSJncGwtdG9wIj4KICA8ZGl2IGNsYXNzPSJncGwtYnJhbmQiPgogICAgPGRpdiBjbGFzcz0iZ3BsLWxvZ28iPkc8L2Rpdj4KICAgIDxkaXY+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1oMSI+R3VpZGFuY2UgTGluZXMgU2ltdWxhdG9yPC9kaXY+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1jaGlwIj48c3BhbiBjbGFzcz0iZ3BsLWRvdCI+PC9zcGFuPjxzcGFuPkNvbXBhcmUgNCBhcHByb2FjaGVzIMK3IGZ1ZWwgKyBST0k8L3NwYW4+PC9kaXY+CiAgICA8L2Rpdj4KICA8L2Rpdj4KICA8YSBjbGFzcz0iZ3BsLWN0YSIgaHJlZj0iaHR0cHM6Ly9hcHAuZ2VvcGFyZC50ZWNoL3NpZ251cD91dG1fc291cmNlPWd1aWRhbmNlLWxpbmVzJnV0bV9tZWRpdW09d3AtZW1iZWQmdXRtX2NhbXBhaWduPXJlZ2lzdGVyIiB0YXJnZXQ9Il9ibGFuayIgcmVsPSJub29wZW5lciI+UnVuIG9uIHlvdXIgZmllbGQg4oaSPC9hPgoKPGRpdiBjbGFzcz0iZ3BsLWdyaWQiPgogIDxhc2lkZSBjbGFzcz0iZ3BsLXNpZGUiPgogICAgPGRpdiBjbGFzcz0iZ3BsLWNhcmQiPgogICAgICA8aDM+U2FtcGxlIGZpZWxkPC9oMz4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLWZpZWxkLXBpY2tlciIgaWQ9ImdwbC1maWVsZC1waWNrZXIiPgogICAgICAgIDxidXR0b24gdHlwZT0iYnV0dG9uIiBjbGFzcz0iZ3BsLWZsZCBpcy1vbiIgZGF0YS1maWVsZD0iaGV4Ij5IZXggMjcgaGE8c3BhbiBjbGFzcz0iZ3BsLWZsZC1zdWIiPmlycmVndWxhciBoZXg8L3NwYW4+PC9idXR0b24+CiAgICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJncGwtZmxkIiBkYXRhLWZpZWxkPSJyZWN0Ij5SZWN0IDMxIGhhPHNwYW4gY2xhc3M9ImdwbC1mbGQtc3ViIj5jbGFzc2ljIE1pZHdlc3Q8L3NwYW4+PC9idXR0b24+CiAgICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJncGwtZmxkIiBkYXRhLWZpZWxkPSJsc2hhcGUiPkwtc2hhcGUgMjUgaGE8c3BhbiBjbGFzcz0iZ3BsLWZsZC1zdWIiPm9ic3RhY2xlIC8gaGlsbDwvc3Bhbj48L2J1dHRvbj4KICAgICAgICA8YnV0dG9uIHR5cGU9ImJ1dHRvbiIgY2xhc3M9ImdwbC1mbGQiIGRhdGEtZmllbGQ9InBpdm90Ij5QaXZvdCAyOCBoYTxzcGFuIGNsYXNzPSJncGwtZmxkLXN1YiI+aXJyaWdhdGlvbiBjaXJjbGU8L3NwYW4+PC9idXR0b24+CiAgICAgIDwvZGl2PgogICAgICA8bGFiZWwgY2xhc3M9ImdwbC11cGxvYWQiIGlkPSJncGwtdXBsb2FkLWxibCI+CiAgICAgICAgPGlucHV0IHR5cGU9ImZpbGUiIGlkPSJncGwtdXBsb2FkIiBhY2NlcHQ9Ii5nZW9qc29uLC5qc29uLC5rbWwsLnppcCwuc2hwLGFwcGxpY2F0aW9uL2pzb24sYXBwbGljYXRpb24vemlwLGFwcGxpY2F0aW9uL3ZuZC5nb29nbGUtZWFydGgua21sK3htbCIgaGlkZGVuPgogICAgICAgIDxzcGFuIGNsYXNzPSJncGwtdXBsb2FkLWljbyI+4qS0PC9zcGFuPgogICAgICAgIDxzcGFuPlVwbG9hZCB5b3VyIGZpZWxkPC9zcGFuPgogICAgICA8L2xhYmVsPgogICAgICA8ZGl2IGNsYXNzPSJncGwtaGludCIgaWQ9ImdwbC11cGxvYWQtaGludCI+R2VvSlNPTiAvIEtNTCAvIFNoYXBlZmlsZSB6aXA8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLWltcG9ydC1uYXYiIGlkPSJncGwtaW1wb3J0LW5hdiIgaGlkZGVuPgogICAgICAgIDxidXR0b24gdHlwZT0iYnV0dG9uIiBjbGFzcz0iZ3BsLWltcC1idG4iIGlkPSJncGwtaW1wLXByZXYiIGFyaWEtbGFiZWw9IlByZXZpb3VzIGJvdW5kYXJ5Ij7igLk8L2J1dHRvbj4KICAgICAgICA8c3BhbiBjbGFzcz0iZ3BsLWltcC1sYmwiIGlkPSJncGwtaW1wLWxibCI+4oCUIC8g4oCUPC9zcGFuPgogICAgICAgIDxidXR0b24gdHlwZT0iYnV0dG9uIiBjbGFzcz0iZ3BsLWltcC1idG4iIGlkPSJncGwtaW1wLW5leHQiIGFyaWEtbGFiZWw9Ik5leHQgYm91bmRhcnkiPuKAujwvYnV0dG9uPgogICAgICA8L2Rpdj4KICAgIDwvZGl2PgogICAgPGRpdiBjbGFzcz0iZ3BsLWNhcmQiPgogICAgICA8aDM+QXBwcm9hY2g8L2gzPgogICAgICA8ZGl2IGNsYXNzPSJncGwtYXBwcm9hY2giIGlkPSJncGwtYXBwcm9hY2giPgogICAgICAgIDxsYWJlbCBjbGFzcz0iaXMtb24iPjxpbnB1dCB0eXBlPSJyYWRpbyIgbmFtZT0iZ3BsLWFwIiB2YWx1ZT0iYWItc3RyYWlnaHQiIGNoZWNrZWQ+PHNwYW4+QUIgU3RyYWlnaHQ8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1yZWNvIiBkYXRhLXJlY289ImFiLXN0cmFpZ2h0Ij5SZWNvbW1lbmRlZDwvc3Bhbj48L2xhYmVsPgogICAgICAgIDxsYWJlbD48aW5wdXQgdHlwZT0icmFkaW8iIG5hbWU9ImdwbC1hcCIgdmFsdWU9ImFiLWN1cnZlIj48c3Bhbj5BQiBDdXJ2ZTwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLXJlY28iIGRhdGEtcmVjbz0iYWItY3VydmUiPlJlY29tbWVuZGVkPC9zcGFuPjwvbGFiZWw+CiAgICAgICAgPGxhYmVsPjxpbnB1dCB0eXBlPSJyYWRpbyIgbmFtZT0iZ3BsLWFwIiB2YWx1ZT0iYm91bmRhcnkiPjxzcGFuPkJvdW5kYXJ5IEZvbGxvdzwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLXJlY28iIGRhdGEtcmVjbz0iYm91bmRhcnkiPlJlY29tbWVuZGVkPC9zcGFuPjwvbGFiZWw+CiAgICAgICAgPGxhYmVsPjxpbnB1dCB0eXBlPSJyYWRpbyIgbmFtZT0iZ3BsLWFwIiB2YWx1ZT0iYWRhcHRpdmUiPjxzcGFuPkNvbnRvdXItZm9sbG93ICh0ZXJyYWluKTwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLXJlY28iIGRhdGEtcmVjbz0iYWRhcHRpdmUiPlJlY29tbWVuZGVkPC9zcGFuPjwvbGFiZWw+CiAgICAgIDwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtaGludCIgaWQ9ImdwbC1yZWNvLWhpbnQiPmFuYWx5c2luZyBzaGFwZeKApjwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtaGludCI+Q29udG91ci1mb2xsb3cgdXNlcyBlbGV2YXRpb247IG90aGVycyBpZ25vcmUgaXQuPC9kaXY+CiAgICA8L2Rpdj4KICAgIDxkaXYgY2xhc3M9ImdwbC1jYXJkIj4KICAgICAgPGgzPkFCIGxpbmUgZGlyZWN0aW9uPC9oMz4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLXNsaWRlci1yb3ciPgogICAgICAgIDxpbnB1dCB0eXBlPSJyYW5nZSIgaWQ9ImdwbC1hYi1kZWciIG1pbj0iMCIgbWF4PSIxODAiIHN0ZXA9IjEiIHZhbHVlPSIwIiBjbGFzcz0iZ3BsLXJhbmdlIj4KICAgICAgICA8c3BhbiBjbGFzcz0iZ3BsLXNsaWRlci12YWwiIGlkPSJncGwtYWItdmFsIj5hdXRvIMK3IDDCsDwvc3Bhbj4KICAgICAgPC9kaXY+CiAgICAgIDxidXR0b24gdHlwZT0iYnV0dG9uIiBpZD0iZ3BsLWFiLWF1dG8iIGNsYXNzPSJncGwtYWItYXV0byI+4oa6IEF1dG8gKGJlc3QgZml0KTwvYnV0dG9uPgogICAgPC9kaXY+CiAgICA8ZGl2IGNsYXNzPSJncGwtY2FyZCI+CiAgICAgIDxoMz5FcXVpcG1lbnQ8L2gzPgogICAgICA8ZGl2IGNsYXNzPSJncGwtc2VsZWN0LXJvdyI+CiAgICAgICAgPGxhYmVsIGZvcj0iZ3BsLW1hY2hpbmUiPk1hY2hpbmU8L2xhYmVsPgogICAgICAgIDxzZWxlY3QgaWQ9ImdwbC1tYWNoaW5lIj4KICAgICAgICAgIDxvcHRpb24gdmFsdWU9InRyYWN0b3Itc3RkIiBzZWxlY3RlZD5UcmFjdG9yICsgaW1wbGVtZW50IChzdGQpPC9vcHRpb24+CiAgICAgICAgICA8b3B0aW9uIHZhbHVlPSJ0cmFjdG9yLWxhcmdlIj5MYXJnZSB0cmFjdG9yICsgcGxhbnRlcjwvb3B0aW9uPgogICAgICAgICAgPG9wdGlvbiB2YWx1ZT0ic3ByYXllciI+U2VsZi1wcm9wZWxsZWQgc3ByYXllcjwvb3B0aW9uPgogICAgICAgICAgPG9wdGlvbiB2YWx1ZT0iY29tYmluZSI+Q29tYmluZSBoYXJ2ZXN0ZXI8L29wdGlvbj4KICAgICAgICAgIDxvcHRpb24gdmFsdWU9ImFydGljdWxhdGVkIj5BcnRpY3VsYXRlZCA0V0Q8L29wdGlvbj4KICAgICAgICAgIDxvcHRpb24gdmFsdWU9ImN1c3RvbSI+Q3VzdG9tIChtYW51YWwgcmFkaXVzKTwvb3B0aW9uPgogICAgICAgIDwvc2VsZWN0PgogICAgICA8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLWlucHV0LXJvdyI+CiAgICAgICAgPGxhYmVsIGZvcj0iZ3BsLXdtIj5JbXBsZW1lbnQgd2lkdGg8L2xhYmVsPgogICAgICAgIDxpbnB1dCB0eXBlPSJudW1iZXIiIGlkPSJncGwtd20iIG1pbj0iMyIgbWF4PSI2MCIgc3RlcD0iMC41IiB2YWx1ZT0iMTgiPgogICAgICAgIDxzcGFuIGNsYXNzPSJncGwtdW5pdCI+bTwvc3Bhbj4KICAgICAgPC9kaXY+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1pbnB1dC1yb3ciPgogICAgICAgIDxsYWJlbCBmb3I9ImdwbC1jb25zIj5Db25zdW1wdGlvbjwvbGFiZWw+CiAgICAgICAgPGlucHV0IHR5cGU9Im51bWJlciIgaWQ9ImdwbC1jb25zIiBtaW49IjAuMSIgbWF4PSI1IiBzdGVwPSIwLjEiIHZhbHVlPSIwLjYiPgogICAgICAgIDxzcGFuIGNsYXNzPSJncGwtdW5pdCI+TC9rbTwvc3Bhbj4KICAgICAgPC9kaXY+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1pbnB1dC1yb3ciPgogICAgICAgIDxsYWJlbCBmb3I9ImdwbC1mdWVsIj5EaWVzZWwgcHJpY2U8L2xhYmVsPgogICAgICAgIDxpbnB1dCB0eXBlPSJudW1iZXIiIGlkPSJncGwtZnVlbCIgbWluPSIwLjEiIG1heD0iMyIgc3RlcD0iMC4wNSIgdmFsdWU9IjEuMjAiPgogICAgICAgIDxzZWxlY3QgaWQ9ImdwbC1jdXJyZW5jeSIgY2xhc3M9ImdwbC1jdXItc2VsIj4KICAgICAgICAgIDxvcHRpb24gdmFsdWU9InVzZCIgc2VsZWN0ZWQ+JC9MPC9vcHRpb24+CiAgICAgICAgICA8b3B0aW9uIHZhbHVlPSJldXIiPuKCrC9MPC9vcHRpb24+CiAgICAgICAgPC9zZWxlY3Q+CiAgICAgIDwvZGl2PgogICAgPC9kaXY+CiAgICA8ZGl2IGNsYXNzPSJncGwtY2FyZCI+CiAgICAgIDxoMz5IZWFkbGFuZDwvaDM+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1zbGlkZXItcm93Ij4KICAgICAgICA8aW5wdXQgdHlwZT0icmFuZ2UiIGlkPSJncGwtaGwtbXVsdCIgbWluPSIwIiBtYXg9IjQiIHN0ZXA9IjEiIHZhbHVlPSIxIiBjbGFzcz0iZ3BsLXJhbmdlIj4KICAgICAgICA8c3BhbiBjbGFzcz0iZ3BsLXNsaWRlci12YWwiIGlkPSJncGwtaGwtdmFsIj4xOCBtIMK3IDHDlyBwYXNzPC9zcGFuPgogICAgICA8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLWhpbnQiPmFsd2F5cyA9IE4gw5cgaW1wbGVtZW50IHdpZHRoIMK3IDHigJMyw5cgdHlwaWNhbDwvZGl2PgogICAgPC9kaXY+CiAgICA8ZGl2IGNsYXNzPSJncGwtY2FyZCI+CiAgICAgIDxoMz5UdXJuYXJvdW5kczwvaDM+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1zZWxlY3Qtcm93Ij4KICAgICAgICA8bGFiZWwgZm9yPSJncGwtdHVybi1zdHlsZSI+U3R5bGU8L2xhYmVsPgogICAgICAgIDxzZWxlY3QgaWQ9ImdwbC10dXJuLXN0eWxlIj4KICAgICAgICAgIDxvcHRpb24gdmFsdWU9InV0dXJuIiBzZWxlY3RlZD5VLXR1cm4gKGhhbGYtY2lyY2xlKTwvb3B0aW9uPgogICAgICAgICAgPG9wdGlvbiB2YWx1ZT0ibm9uZSI+Tm9uZSDigJQgZHJpdmVyIGRlY2lkZXM8L29wdGlvbj4KICAgICAgICA8L3NlbGVjdD4KICAgICAgPC9kaXY+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1pbnB1dC1yb3ciPgogICAgICAgIDxsYWJlbCBmb3I9ImdwbC10dXJuLXIiPk1pbiB0dXJuIHJhZGl1czwvbGFiZWw+CiAgICAgICAgPGlucHV0IHR5cGU9Im51bWJlciIgaWQ9ImdwbC10dXJuLXIiIG1pbj0iMiIgbWF4PSIzMCIgc3RlcD0iMC41IiB2YWx1ZT0iOSI+CiAgICAgICAgPHNwYW4gY2xhc3M9ImdwbC11bml0Ij5tPC9zcGFuPgogICAgICA8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLWhpbnQiIGlkPSJncGwtdHVybi1yLWhpbnQiPmF1dG8gwrcgc3RkIHRyYWN0b3I8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLWlucHV0LXJvdyI+CiAgICAgICAgPGxhYmVsIGZvcj0iZ3BsLXR1cm4tYnVmIj5PdXRzaWRlLWJvdW5kYXJ5IGJ1ZmZlcjwvbGFiZWw+CiAgICAgICAgPGlucHV0IHR5cGU9Im51bWJlciIgaWQ9ImdwbC10dXJuLWJ1ZiIgbWluPSIwIiBtYXg9IjEwMCIgc3RlcD0iMSIgdmFsdWU9IjAiPgogICAgICAgIDxzcGFuIGNsYXNzPSJncGwtdW5pdCI+bTwvc3Bhbj4KICAgICAgPC9kaXY+CiAgICA8L2Rpdj4KICAgIDxkaXYgY2xhc3M9ImdwbC1jYXJkIGdwbC1jYXJkLXRvcG8iPgogICAgICA8aDM+VG9wb2dyYXBoeTwvaDM+CiAgICAgIDxwIGNsYXNzPSJncGwtdG9wby1ibHVyYiI+UGxhbiBhcm91bmQgcmVhbCBlbGV2YXRpb24sIHNsb3BlIGFuZCBjdXJ2YXR1cmUg4oCUIGRyaXZlcyBjb250b3VyLWF3YXJlIEFkYXB0aXZlIHBhdGhzIGFuZCBwcmV2ZW50cyBlcm9zaW9uLjwvcD4KICAgICAgPGEgY2xhc3M9ImdwbC1jdGEtbWluaSIgaHJlZj0iaHR0cHM6Ly9hcHAuZ2VvcGFyZC50ZWNoL3NpZ251cD91dG1fc291cmNlPWd1aWRhbmNlLWxpbmVzJnV0bV9tZWRpdW09d3AtZW1iZWQmdXRtX2NhbXBhaWduPXRvcG9ncmFwaHkiIHRhcmdldD0iX2JsYW5rIiByZWw9Im5vb3BlbmVyIj5TZWUgaXQgaW4gR2VvUGFyZCDihpI8L2E+CiAgICA8L2Rpdj4KICA8L2FzaWRlPgogIDxkaXYgY2xhc3M9ImdwbC1zcGxpdHRlciIgaWQ9ImdwbC1zcGxpdHRlciIgYXJpYS1sYWJlbD0iUmVzaXplIHNldHRpbmdzIHBhbmVsIiB0aXRsZT0iRHJhZyB0byByZXNpemUiPjwvZGl2PgoKICA8bWFpbiBjbGFzcz0iZ3BsLW1haW4iPgogICAgPGNhbnZhcyBjbGFzcz0iZ3BsLWNhbnZhcyIgaWQ9ImdwbC1jYW52YXMiPjwvY2FudmFzPgogICAgPGRpdiBjbGFzcz0iZ3BsLXdhcm4iIGlkPSJncGwtd2FybiI+PC9kaXY+CiAgICA8ZGl2IGNsYXNzPSJncGwtdHJheSIgaWQ9ImdwbC10cmF5Ij7igJQgaGEgc2FtcGxlPC9kaXY+CiAgICA8ZGl2IGNsYXNzPSJncGwtcGIiIGlkPSJncGwtcGIiPgogICAgICA8YnV0dG9uIHR5cGU9ImJ1dHRvbiIgY2xhc3M9ImdwbC1wYi1idG4iIGlkPSJncGwtcGItcGxheSIgYXJpYS1sYWJlbD0iUGxheSAvIHBhdXNlIj7ilrY8L2J1dHRvbj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLXBiLXRyYWNrIiBpZD0iZ3BsLXBiLXRyYWNrIj4KICAgICAgICA8ZGl2IGNsYXNzPSJncGwtcGItZmlsbCIgaWQ9ImdwbC1wYi1maWxsIj48L2Rpdj4KICAgICAgICA8ZGl2IGNsYXNzPSJncGwtcGItdGh1bWIiIGlkPSJncGwtcGItdGh1bWIiPjwvZGl2PgogICAgICA8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLXBiLXNlZyI+CiAgICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJncGwtcGItc3BkIG9uIiBkYXRhLXNwZD0iMSI+McOXPC9idXR0b24+CiAgICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJncGwtcGItc3BkIiBkYXRhLXNwZD0iMiI+MsOXPC9idXR0b24+CiAgICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJncGwtcGItc3BkIiBkYXRhLXNwZD0iNCI+NMOXPC9idXR0b24+CiAgICAgIDwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtcGItc3RhdHMiIGlkPSJncGwtcGItc3RhdHMiPjAlIMK3IDAgLyAwIGttPC9kaXY+CiAgICA8L2Rpdj4KICAgIDxkaXYgY2xhc3M9ImdwbC1sZWdlbmQiPgogICAgICA8ZGl2IGNsYXNzPSJncGwtbGctcm93Ij48c3BhbiBjbGFzcz0iZ3BsLWxnLXN3YXRjaCIgc3R5bGU9ImJhY2tncm91bmQ6bGluZWFyLWdyYWRpZW50KHRvIHJpZ2h0LCM2ZDRmYTIgMCUsIzRlYzBhNyAyNSUsI2ZmZTg4MiA1MCUsI2Y1YTg1YyA3NSUsI2RiNTA1MCAxMDAlKTt3aWR0aDozMnB4O2hlaWdodDo4cHg7Ym9yZGVyLXJhZGl1czoycHgiPjwvc3Bhbj5FbGV2YXRpb24gbG93IOKGkiBoaWdoPC9kaXY+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1sZy1yb3ciPjxzcGFuIGNsYXNzPSJncGwtbGctc3dhdGNoIiBzdHlsZT0iYmFja2dyb3VuZDojMTQ1MzI4Ij48L3NwYW4+RmllbGQgYm91bmRhcnk8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLWxnLXJvdyI+PHNwYW4gY2xhc3M9ImdwbC1sZy1zd2F0Y2giIHN0eWxlPSJiYWNrZ3JvdW5kOiNmNzZhMGMiPjwvc3Bhbj5HdWlkYW5jZSBwYXNzPC9kaXY+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1sZy1yb3ciPjxzcGFuIGNsYXNzPSJncGwtbGctc3dhdGNoIiBzdHlsZT0iYmFja2dyb3VuZDpyZ2JhKDI2LDEyMSw4MSwuMzUpIj48L3NwYW4+SGVhZGxhbmQgc3RyaXA8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLWxnLXJvdyI+PHNwYW4gY2xhc3M9ImdwbC1sZy1zd2F0Y2giIHN0eWxlPSJiYWNrZ3JvdW5kOiNhMjFjYWYiPjwvc3Bhbj5VLXR1cm4gLyBkaXJlY3Rpb24g4oaSPC9kaXY+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1sZy1yb3ciPjxzcGFuIGNsYXNzPSJncGwtbGctc3dhdGNoIiBzdHlsZT0iYmFja2dyb3VuZDpyZ2JhKDE2MiwyOCwxNzUsLjIyKTt3aWR0aDoxNHB4O2hlaWdodDo4cHgiPjwvc3Bhbj5Tb2lsIGNvbXBhY3Rpb24gem9uZTwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtbGctcm93Ij48c3BhbiBjbGFzcz0iZ3BsLWxnLXN3YXRjaCIgc3R5bGU9ImJhY2tncm91bmQ6cmdiYSgyNDcsMTA2LDEyLC4zNSk7d2lkdGg6MTRweDtoZWlnaHQ6OHB4Ij48L3NwYW4+U3dhdGggY292ZXJlZDwvZGl2PgogICAgPC9kaXY+CiAgICA8ZGl2IGNsYXNzPSJncGwtc2NhbGUiIGlkPSJncGwtc2NhbGUiPjxzcGFuIGNsYXNzPSJncGwtc2NhbGUtYmFyIj48L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1zY2FsZS1sYmwiIGlkPSJncGwtc2NhbGUtbGJsIj7igJQgbTwvc3Bhbj48L2Rpdj4KICAgIDxkaXYgY2xhc3M9ImdwbC10b29scyI+CiAgICAgIDxidXR0b24gdHlwZT0iYnV0dG9uIiBjbGFzcz0iZ3BsLXRvb2wtYnRuIiBpZD0iZ3BsLXRvb2wtem9vbS1pbiIgdGl0bGU9Ilpvb20gaW4iIGFyaWEtbGFiZWw9Ilpvb20gaW4iPgogICAgICAgIDxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyLjQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PGxpbmUgeDE9IjEyIiB5MT0iNSIgeDI9IjEyIiB5Mj0iMTkiLz48bGluZSB4MT0iNSIgeTE9IjEyIiB4Mj0iMTkiIHkyPSIxMiIvPjwvc3ZnPgogICAgICA8L2J1dHRvbj4KICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJncGwtdG9vbC1idG4iIGlkPSJncGwtdG9vbC16b29tLW91dCIgdGl0bGU9Ilpvb20gb3V0IiBhcmlhLWxhYmVsPSJab29tIG91dCI+CiAgICAgICAgPHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2Utd2lkdGg9IjIuNCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48bGluZSB4MT0iNSIgeTE9IjEyIiB4Mj0iMTkiIHkyPSIxMiIvPjwvc3ZnPgogICAgICA8L2J1dHRvbj4KICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJncGwtdG9vbC1idG4iIGlkPSJncGwtdG9vbC1maXQiIHRpdGxlPSJGaXQgZmllbGQiIGFyaWEtbGFiZWw9IkZpdCBmaWVsZCI+CiAgICAgICAgPHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2Utd2lkdGg9IjIuMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNNCA5VjVoNE0xNiA1aDR2NE0yMCAxNXY0aC00TTggMTlINHYtNCIvPjwvc3ZnPgogICAgICA8L2J1dHRvbj4KICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJncGwtdG9vbC1idG4iIGlkPSJncGwtdG9vbC1ydWxlciIgdGl0bGU9IlJ1bGVyIOKAlCBjbGljayB0d28gcG9pbnRzIiBhcmlhLWxhYmVsPSJSdWxlciI+CiAgICAgICAgPHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBhdGggZD0iTTIgMTRsOC04IDEyIDEyLTggOHoiLz48cGF0aCBkPSJNNiAxMGwzIDNNMTAgNmwzIDNNMTQgMTRsMyAzTTEwIDE4bDMtMyIvPjwvc3ZnPgogICAgICA8L2J1dHRvbj4KICAgIDwvZGl2PgogICAgPGRpdiBjbGFzcz0iZ3BsLXJ1bGVyLWhpbnQiIGlkPSJncGwtcnVsZXItaGludCI+Q2xpY2sgdHdvIHBvaW50cyBvbiB0aGUgY2FudmFzIHRvIG1lYXN1cmU8L2Rpdj4KICA8L21haW4+CiAgPGFzaWRlIGNsYXNzPSJncGwtc2lkZS1yaWdodCIgaWQ9ImdwbC1zaWRlLXJpZ2h0Ij4KICAgIDxkaXYgY2xhc3M9ImdwbC1jYXJkIj4KICAgICAgPGgzPlRoaXMgYXBwcm9hY2g8L2gzPgogICAgICA8ZGl2IGNsYXNzPSJncGwtdW5pdC10b2dnbGUiIHJvbGU9InRhYmxpc3QiPgogICAgICAgIDxidXR0b24gdHlwZT0iYnV0dG9uIiBjbGFzcz0iZ3BsLXVuaXQtdGFiIGlzLW9uIiBkYXRhLXVuaXQ9ImttIj5rbTwvYnV0dG9uPgogICAgICAgIDxidXR0b24gdHlwZT0iYnV0dG9uIiBjbGFzcz0iZ3BsLXVuaXQtdGFiIiBkYXRhLXVuaXQ9Im1pIj5taTwvYnV0dG9uPgogICAgICA8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLXJlc3VsdHMiPgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1yLXJvdyI+PHNwYW4gY2xhc3M9ImdwbC1yLWsiPkZpZWxkIGFyZWE8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1yLXYiIGlkPSJncGwtci1hcmVhIj7igJQgaGE8L3NwYW4+PC9kaXY+CiAgICAgICAgPGRpdiBjbGFzcz0iZ3BsLXItcm93IGdwbC1yLXByaSI+PHNwYW4gY2xhc3M9ImdwbC1yLWsiPkNvdmVyYWdlPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtci12IiBpZD0iZ3BsLXItY292Ij7igJQgJTwvc3Bhbj48L2Rpdj4KICAgICAgICA8ZGl2IGNsYXNzPSJncGwtci1yb3ciPjxzcGFuIGNsYXNzPSJncGwtci1rIj5QYXNzZXM8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1yLXYiIGlkPSJncGwtci1wYXNzZXMiPuKAlDwvc3Bhbj48L2Rpdj4KICAgICAgICA8ZGl2IGNsYXNzPSJncGwtci1yb3ciPjxzcGFuIGNsYXNzPSJncGwtci1rIj5QYXNzIGxlbmd0aDwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLXItdiIgaWQ9ImdwbC1yLWxlbiI+4oCUIGttPC9zcGFuPjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1yLXJvdyI+PHNwYW4gY2xhc3M9ImdwbC1yLWsiPlR1cm5hcm91bmRzPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtci12IiBpZD0iZ3BsLXItdHVybnMiPuKAlDwvc3Bhbj48L2Rpdj4KICAgICAgICA8ZGl2IGNsYXNzPSJncGwtci1yb3ciPjxzcGFuIGNsYXNzPSJncGwtci1rIj5UdXJuIGRpc3RhbmNlPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtci12IiBpZD0iZ3BsLXItdHVybmxlbiI+4oCUIGttPC9zcGFuPjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1yLXJvdyBncGwtci1wcmkiPjxzcGFuIGNsYXNzPSJncGwtci1rIj5Ub3RhbCBkcml2ZTwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLXItdiIgaWQ9ImdwbC1yLWRyaXZlIj7igJQga208L3NwYW4+PC9kaXY+CiAgICAgICAgPGRpdiBjbGFzcz0iZ3BsLXItcm93Ij48c3BhbiBjbGFzcz0iZ3BsLXItayI+QXZnIGdyYWRlPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtci12IiBpZD0iZ3BsLXItZ3JhZGUiPuKAlCAlPC9zcGFuPjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1yLXJvdyBncGwtci1wcmkiPjxzcGFuIGNsYXNzPSJncGwtci1rIj5GdWVsPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtci12IiBpZD0iZ3BsLXItZnVlbCI+4oCUIEw8L3NwYW4+PC9kaXY+CiAgICAgICAgPGRpdiBjbGFzcz0iZ3BsLXItcm93Ij48c3BhbiBjbGFzcz0iZ3BsLXItayI+4oCmdHVybiBmdWVsPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtci12IiBpZD0iZ3BsLXItdHVybmZ1ZWwiPuKAlCBMPC9zcGFuPjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1yLXJvdyI+PHNwYW4gY2xhc3M9ImdwbC1yLWsiPuKApnNsb3BlIGNvc3Q8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1yLXYiIGlkPSJncGwtci1zbG9wZSI+KyAwJTwvc3Bhbj48L2Rpdj4KICAgICAgICA8ZGl2IGNsYXNzPSJncGwtci1yb3ciPjxzcGFuIGNsYXNzPSJncGwtci1rIj5Db3N0PC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtci12IiBpZD0iZ3BsLXItY29zdCI+JCDigJQ8L3NwYW4+PC9kaXY+CiAgICAgICAgPGRpdiBjbGFzcz0iZ3BsLXItcm93Ij48c3BhbiBjbGFzcz0iZ3BsLXItayI+dnMgQUIgc3RyYWlnaHQ8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1yLXNhdmluZ3MiIGlkPSJncGwtci1zYXYiPuKAlDwvc3Bhbj48L2Rpdj4KICAgICAgPC9kaXY+CiAgICA8L2Rpdj4KICAgIDxkaXYgY2xhc3M9ImdwbC1jYXJkIj4KICAgICAgPGgzPkNvbXBhcmUgYWxsPC9oMz4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLWNtcCI+CiAgICAgICAgPGRpdiBjbGFzcz0iZ3BsLWNtcC1yb3cgZ3BsLWNtcC1oZWFkIj48c3Bhbj5BcHByb2FjaDwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLWNtcC12YWwiPkNvdjwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLWNtcC12YWwiPkZ1ZWw8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1jbXAtdmFsIj4kPC9zcGFuPjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1jbXAtcm93IiBkYXRhLWNtcD0iYWItc3RyYWlnaHQiPjxzcGFuIGNsYXNzPSJncGwtY21wLW5hbWUiPkFCIHN0cmFpZ2h0PC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtY21wLXZhbCI+4oCUPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtY21wLXZhbCI+4oCUPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtY21wLXZhbCI+4oCUPC9zcGFuPjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1jbXAtcm93IiBkYXRhLWNtcD0iYWItY3VydmUiPjxzcGFuIGNsYXNzPSJncGwtY21wLW5hbWUiPkFCIGN1cnZlPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtY21wLXZhbCI+4oCUPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtY21wLXZhbCI+4oCUPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtY21wLXZhbCI+4oCUPC9zcGFuPjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1jbXAtcm93IiBkYXRhLWNtcD0iYm91bmRhcnkiPjxzcGFuIGNsYXNzPSJncGwtY21wLW5hbWUiPkJvdW5kYXJ5IGZvbGxvdzwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLWNtcC12YWwiPuKAlDwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLWNtcC12YWwiPuKAlDwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLWNtcC12YWwiPuKAlDwvc3Bhbj48L2Rpdj4KICAgICAgICA8ZGl2IGNsYXNzPSJncGwtY21wLXJvdyIgZGF0YS1jbXA9ImFkYXB0aXZlIj48c3BhbiBjbGFzcz0iZ3BsLWNtcC1uYW1lIj5BZGFwdGl2ZTwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLWNtcC12YWwiPuKAlDwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLWNtcC12YWwiPuKAlDwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLWNtcC12YWwiPuKAlDwvc3Bhbj48L2Rpdj4KICAgICAgPC9kaXY+CiAgICA8L2Rpdj4KICAgIDxkaXYgY2xhc3M9ImdwbC1jYXJkIj4KICAgICAgPGgzPkFubnVhbCBST0k8L2gzPgogICAgICA8ZGl2IGNsYXNzPSJncGwtaW5wdXQtcm93Ij4KICAgICAgICA8bGFiZWwgZm9yPSJncGwtcm9pLWZhcm0iPkZhcm0gc2l6ZTwvbGFiZWw+CiAgICAgICAgPGlucHV0IHR5cGU9Im51bWJlciIgaWQ9ImdwbC1yb2ktZmFybSIgbWluPSIxIiBtYXg9IjUwMDAwIiBzdGVwPSIxIiB2YWx1ZT0iMjAwIj4KICAgICAgICA8c3BhbiBjbGFzcz0iZ3BsLXVuaXQiPmhhPC9zcGFuPgogICAgICA8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLWlucHV0LXJvdyI+CiAgICAgICAgPGxhYmVsIGZvcj0iZ3BsLXJvaS1hcHBzIj5BcHBsaWNhdGlvbnMveXI8L2xhYmVsPgogICAgICAgIDxpbnB1dCB0eXBlPSJudW1iZXIiIGlkPSJncGwtcm9pLWFwcHMiIG1pbj0iMSIgbWF4PSIyMCIgc3RlcD0iMSIgdmFsdWU9IjQiPgogICAgICAgIDxzcGFuIGNsYXNzPSJncGwtdW5pdCI+w5c8L3NwYW4+CiAgICAgIDwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtcmVzdWx0cyI+CiAgICAgICAgPGRpdiBjbGFzcz0iZ3BsLXItcm93Ij48c3BhbiBjbGFzcz0iZ3BsLXItayI+QW5udWFsIGZ1ZWwgc2F2ZWQ8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1yLXYiIGlkPSJncGwtcm9pLWZ1ZWwiPuKAlCBMPC9zcGFuPjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1yLXJvdyI+PHNwYW4gY2xhc3M9ImdwbC1yLWsiPkFubnVhbCBjb3N0IHNhdmVkPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtci12IiBpZD0iZ3BsLXJvaS1jb3N0Ij4kIOKAlDwvc3Bhbj48L2Rpdj4KICAgICAgICA8ZGl2IGNsYXNzPSJncGwtci1yb3cgZ3BsLXItcHJpIj48c3BhbiBjbGFzcz0iZ3BsLXItayI+UGVyLWhhIHNhdmluZ3M8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1yLXYiIGlkPSJncGwtcm9pLXBlcmhhIj4kIOKAlDwvc3Bhbj48L2Rpdj4KICAgICAgPC9kaXY+CiAgICA8L2Rpdj4KICAgIDxkaXYgY2xhc3M9ImdwbC1jdGEtY2FyZCI+CiAgICAgIDxoND5SdW4gb24geW91ciByZWFsIGZpZWxkPC9oND4KICAgICAgPHVsIGNsYXNzPSJncGwtY3RhLWxpc3QiPgogICAgICAgIDxsaT5VcGxvYWQgYm91bmRhcnkgKyBhcy1hcHBsaWVkIGRhdGE8L2xpPgogICAgICAgIDxsaT5FZGdlLWF3YXJlIEFkYXB0aXZlIHBhdGhzIGZyb20gcmVhbCBlbGV2YXRpb248L2xpPgogICAgICAgIDxsaT5TZWN0aW9uLWNvbnRyb2wgZ2FwIGVzdGltYXRlcyArIFJ4IGV4cG9ydDwvbGk+CiAgICAgIDwvdWw+CiAgICAgIDxhIGNsYXNzPSJncGwtY3RhLWJ0bi1sZyIgaHJlZj0iaHR0cHM6Ly9hcHAuZ2VvcGFyZC50ZWNoL3NpZ251cD91dG1fc291cmNlPWd1aWRhbmNlLWxpbmVzJnV0bV9tZWRpdW09d3AtZW1iZWQmdXRtX2NhbXBhaWduPWN0YS1ib3R0b20iIHRhcmdldD0iX2JsYW5rIiByZWw9Im5vb3BlbmVyIj5QbGFuIGluIEdlb1BhcmQgPHNwYW4gY2xhc3M9ImdwbC1jdGEtYXJyIj7ihpI8L3NwYW4+PC9hPgogICAgICA8cCBjbGFzcz0iZ3BsLWN0YS1ub3RlIj5QcmUtY2FsaWJyYXRlZCBlc3RpbWF0ZXMuIEZpZWxkLXNwZWNpZmljIG51bWJlcnMgZGVwZW5kIG9uIGVxdWlwbWVudCwgdGVycmFpbiBhbmQgdG9wb2dyYXBoeS48L3A+CiAgICA8L2Rpdj4KICA8L2FzaWRlPgo8L2Rpdj4KCjxzY3JpcHQgbm93cHJvY2tldCBkYXRhLW5vLW9wdGltaXplPSIxIiBkYXRhLW5vLWRlZmVyPSIxIiBkYXRhLW5vLW1pbmlmeT0iMSI+CihmdW5jdGlvbigpewogIHZhciByb290ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1yb290Jyk7CiAgaWYoIXJvb3QpIHJldHVybjsKICB2YXIgY2FudmFzID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1jYW52YXMnKTsKICB2YXIgY3R4ID0gY2FudmFzLmdldENvbnRleHQoJzJkJyk7CiAgdmFyIHRyYXlFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtdHJheScpOwoKICAvLyBTYW1wbGUgZmllbGRzIOKAlCB1bml0cyBhcmUgcmVhbCBtZXRlcnMsIHJlbmRlcmVkIHdpdGggYSB1bmlmb3JtIHNjYWxlIGZpdHRpbmcKICAvLyB0aGUgY2FudmFzLiBGb3VyIHNoYXBlcyBjb3ZlciB0aGUgY29tbW9uIGNhc2VzOiBpcnJlZ3VsYXIgcG9seWdvbiwgcmVjdGFuZ3VsYXIKICAvLyBNaWR3ZXN0IHNlY3Rpb24sIEwtc2hhcGVkIChvYnN0YWNsZSAvIGhpbGwgY29ybmVyKSwgb3ZhbCAoY2VudHJlLXBpdm90IHJlbW5hbnQpLgogIHZhciBGSUVMRFMgPSB7CiAgICBoZXg6IFsKICAgICAgeyB4OiAgMjAsIHk6IDIyMCB9LCB7IHg6ICA4MCwgeTogIDYwIH0sIHsgeDogMjkwLCB5OiAgMzUgfSwKICAgICAgeyB4OiA1ODAsIHk6ICA5MCB9LCB7IHg6IDY5MCwgeTogMjQwIH0sIHsgeDogNjQwLCB5OiA0NjAgfSwKICAgICAgeyB4OiAzODAsIHk6IDU0MCB9LCB7IHg6IDEzMCwgeTogNTEwIH0sIHsgeDogIDQwLCB5OiAzODAgfQogICAgXSwKICAgIHJlY3Q6IFsKICAgICAgeyB4OiAgNDAsIHk6ICA2MCB9LCB7IHg6IDcyMCwgeTogIDcwIH0sIHsgeDogNzMwLCB5OiA1MjAgfSwgeyB4OiAgNTAsIHk6IDUxMCB9CiAgICBdLAogICAgbHNoYXBlOiBbCiAgICAgIHsgeDogIDYwLCB5OiAgNjAgfSwgeyB4OiA0NDAsIHk6ICA2MCB9LCB7IHg6IDQ0MCwgeTogMjgwIH0sCiAgICAgIHsgeDogNzIwLCB5OiAyODAgfSwgeyB4OiA3MjAsIHk6IDU0MCB9LCB7IHg6ICA2MCwgeTogNTQwIH0KICAgIF0sCiAgICAvLyBJcnJpZ2F0aW9uIHBpdm90IGZpZWxkIOKAlCBhIHRydWUgY2lyY2xlIGRyYXduIGJ5IHRoZSBjZW50cmUtcGl2b3QKICAgIC8vIHNwcmlua2xlci4gUmFkaXVzIOKJiCAzMDAgbSBnaXZlcyB+MjggaGEgd2hpY2ggbWF0Y2hlcyBhIHR5cGljYWwKICAgIC8vIHF1YXJ0ZXItc2VjdGlvbiBwaXZvdCAoMTMwIG0gd2lkZSwgMzYwwrAgY292ZXJhZ2UsIH4zMiBoYSBncm9zcyAvCiAgICAvLyB+MjggaGEgYWN0dWFsbHkgd2V0dGVkKS4KICAgIHBpdm90OiAoZnVuY3Rpb24oKXsKICAgICAgdmFyIHB0cyA9IFtdOwogICAgICB2YXIgY3ggPSAzODAsIGN5ID0gMjkwLCByID0gMzAwOwogICAgICBmb3IodmFyIGk9MDsgaTwyODsgaSsrKXsKICAgICAgICB2YXIgdCA9IChpIC8gMjgpICogTWF0aC5QSSAqIDI7CiAgICAgICAgcHRzLnB1c2goeyB4OiBjeCArIE1hdGguY29zKHQpICogciwgeTogY3kgKyBNYXRoLnNpbih0KSAqIHIgfSk7CiAgICAgIH0KICAgICAgcmV0dXJuIHB0czsKICAgIH0pKCkKICB9OwogIHZhciBjdXJyZW50RmllbGQgPSAnaGV4JzsKICB2YXIgQk9VTkRBUlkgPSBGSUVMRFNbY3VycmVudEZpZWxkXTsKICAvLyBQZXItZmllbGQgc3ludGhldGljIGVsZXZhdGlvbi4gdGVycmFpbih4LCB5KSDihpIgbWV0cmVzIGFib3ZlIHRoZSBmaWVsZCdzCiAgLy8gb3duIGxvd2VzdCBwb2ludC4gUGlja2VkIHRvIGRlbW9uc3RyYXRlIHJlYWxpc3RpYyBhZyBzY2VuYXJpb3M6CiAgLy8gICBoZXggICAgIOKAlCBlYXN0LWZhY2luZyBzbG9wZSwgMTIgbSBkcm9wIGFjcm9zcyB0aGUgZmllbGQKICAvLyAgIHJlY3QgICAg4oCUIGdlbnRsZSByaWRnZSBydW5uaW5nIGRpYWdvbmFsbHksIDE1IG0gcGVhawogIC8vICAgbHNoYXBlICDigJQgaGlsbCBhdCB0aGUgY29uY2F2ZSBjb3JuZXIgKE5FKSwgMjAgbSBwZWFrCiAgLy8gICBwaXZvdCAgIOKAlCBzaW5nbGUgcm91bmQgaGlsbCwgMTggbSBwZWFrIGluIGNlbnRyZQogIC8vICAgY3VzdG9tICDigJQgZmxhdCAobm8gZWxldmF0aW9uIGRhdGEgZm9yIHVwbG9hZGVkIGJvdW5kYXJpZXMpCiAgLy8gVGhlIGZ1bmN0aW9ucyBhcmUgZGVsaWJlcmF0ZWx5IHNtb290aCBzbyBjb250b3VyIGxpbmVzIGxvb2sgbmF0dXJhbC4KICB2YXIgVEVSUkFJTiA9IHsKICAgIGhleDogZnVuY3Rpb24oeCwgeSl7CiAgICAgIC8vIFRpbHRlZCBwbGFuZSArIGdlbnRsZSB3YXZlcwogICAgICByZXR1cm4gMTIgKiAoKHggLSAyMCkgLyA2NzApICsgMiAqIE1hdGguc2luKHkgLyA5MCkgKyAxICogTWF0aC5jb3MoeCAvIDExMCk7CiAgICB9LAogICAgcmVjdDogZnVuY3Rpb24oeCwgeSl7CiAgICAgIC8vIERpYWdvbmFsIHJpZGdlCiAgICAgIHZhciB1ID0gKHggKyB5KSAvIDEyMDA7CiAgICAgIHJldHVybiAxNSAqIE1hdGguZXhwKC1NYXRoLnBvdyh1IC0gMC41LCAyKSAqIDgpIC0gMjsKICAgIH0sCiAgICBsc2hhcGU6IGZ1bmN0aW9uKHgsIHkpewogICAgICAvLyBIaWxsIG5lYXIgdGhlIGNvbmNhdmUgY29ybmVyICg0NDAsIDI4MCkKICAgICAgdmFyIGR4ID0gKHggLSA1NDApIC8gMjAwLCBkeSA9ICh5IC0gMjIwKSAvIDE4MDsKICAgICAgcmV0dXJuIDIwICogTWF0aC5leHAoLShkeCpkeCArIGR5KmR5KSkgKyAoNTQwIC0geSkgKiAwLjAwNTsKICAgIH0sCiAgICBwaXZvdDogZnVuY3Rpb24oeCwgeSl7CiAgICAgIC8vIENlbnRyYWwgcm91bmQgaGlsbAogICAgICB2YXIgZHggPSAoeCAtIDM4MCkgLyAyMjAsIGR5ID0gKHkgLSAyOTApIC8gMjIwOwogICAgICByZXR1cm4gMTggKiBNYXRoLmV4cCgtKGR4KmR4ICsgZHkqZHkpKTsKICAgIH0sCiAgICBjdXN0b206IGZ1bmN0aW9uKCl7IHJldHVybiAwOyB9CiAgfTsKICBmdW5jdGlvbiB0ZXJyYWluQXQoeCwgeSl7CiAgICB2YXIgZm4gPSBURVJSQUlOW2N1cnJlbnRGaWVsZF0gfHwgVEVSUkFJTi5jdXN0b207CiAgICByZXR1cm4gZm4oeCwgeSk7CiAgfQogIC8vIEFCLWxpbmUgZGlyZWN0aW9uIG92ZXJyaWRlLiBudWxsID0gdXNlIFBDQSByZXN1bHQ7IG90aGVyd2lzZSBkZWdyZWVzIDDigJMxODAKICAvLyBtZWFzdXJlZCBmcm9tIHRoZSAreCBheGlzIChjb3VudGVyLWNsb2Nrd2lzZSBpbiBzY3JlZW4tY29vcmRzIHdoZXJlICt5IGlzCiAgLy8gZG93biwgc28gdGhpcyBtYXRjaGVzICJjb21wYXNzLWxpa2UiIGludHVpdGl2ZSBkaXJlY3Rpb24gb24gdGhlIGNhbnZhcykuCiAgdmFyIHVzZXJBeGlzRGVnID0gbnVsbDsKCiAgZnVuY3Rpb24gZmllbGRTdGF0cyhiKXsKICAgIHZhciBtaW5YID0gSW5maW5pdHksIG1heFggPSAtSW5maW5pdHksIG1pblkgPSBJbmZpbml0eSwgbWF4WSA9IC1JbmZpbml0eTsKICAgIGZvcih2YXIgaT0wOyBpPGIubGVuZ3RoOyBpKyspewogICAgICBpZihiW2ldLnggPCBtaW5YKSBtaW5YID0gYltpXS54OwogICAgICBpZihiW2ldLnggPiBtYXhYKSBtYXhYID0gYltpXS54OwogICAgICBpZihiW2ldLnkgPCBtaW5ZKSBtaW5ZID0gYltpXS55OwogICAgICBpZihiW2ldLnkgPiBtYXhZKSBtYXhZID0gYltpXS55OwogICAgfQogICAgdmFyIHMgPSAwOwogICAgZm9yKHZhciBqPTA7IGo8Yi5sZW5ndGg7IGorKyl7CiAgICAgIHZhciBrID0gKGogKyAxKSAlIGIubGVuZ3RoOwogICAgICBzICs9IGJbal0ueCAqIGJba10ueSAtIGJba10ueCAqIGJbal0ueTsKICAgIH0KICAgIHJldHVybiB7IG1pblg6IG1pblgsIG1heFg6IG1heFgsIG1pblk6IG1pblksIG1heFk6IG1heFksIGFyZWE6IE1hdGguYWJzKHMpICogMC41IH07CiAgfQoKICAvLyBSZWNvbW1lbmQgYW4gYXBwcm9hY2ggYnkgY29tcHV0aW5nIHJlYWwgbWV0cmljcyBvbiB0aGUgY3VycmVudCBmaWVsZCBmb3IKICAvLyBlYWNoIGNhbmRpZGF0ZSwgdGhlbiBzY29yaW5nIGFnYWluc3QgdGhlIHRocmVlIG9wZXJhdG9yIHByaW9yaXRpZXM6CiAgLy8gICAxLiBjb3ZlcmFnZSAlIOKAlCB0aGUgYmlnZ2VzdCBkaWFsOyBiYWQgY292ZXJhZ2UgbWVhbnMgdW5jb3ZlcmVkIGFjcmVzCiAgLy8gICAyLiB0dXJuYXJvdW5kIGNvdW50IOKAlCBmZXdlciB0dXJucyA9IGxlc3MgdGltZSBsb3N0ICsgbGVzcyBmdWVsIGJ1cm5lZAogIC8vICAgMy4gZnVlbCBMIOKAlCB0b3RhbCBkcml2ZS1wYXRoIMOXIGNvbnN1bXB0aW9uCiAgLy8KICAvLyBTY29yZSA9IGNvdmVyYWdlIOKIkiAwLjQgw5cgdHVybmFyb3VuZENvdW50IOKIkiAxLjUgw5cgZnVlbEwuIENvdmVyYWdlIGlzIG9uIGEKICAvLyAw4oCTMTAwIHNjYWxlOyB0dXJuIGNvdW50cyBydW4gMTDigJMzMDsgZnVlbCBydW5zIDXigJMyMCBMOyBzbyB0aGUgd2VpZ2h0cwogIC8vIGJyaW5nIHRoZW0gaW50byBzaW1pbGFyIHJhbmdlcyBhbmQgY292ZXJhZ2Ugd2lucyB0aWVzLgogIC8vCiAgLy8gRmFsbHMgYmFjayB0byB0aGUgc2hhcGUtYmFzZWQgaGV1cmlzdGljIG9ubHkgd2hlbiBtZXRyaWMgZXZhbCBmYWlscwogIC8vIChlLmcuLCB6ZXJvLXBhc3MgcmVzdWx0KS4gcmVjb21tZW5kQnlNZXRyaWNzIGlzIGNhbGxlZCBmcm9tIHJlY29tcHV0ZQogIC8vIEFGVEVSIHRoZSBmb3VyIENvbXBhcmUgQWxsIGxheW91dHMgaGF2ZSBhbHJlYWR5IGJlZW4gY29tcHV0ZWQsIHNvIHdlCiAgLy8gZG9uJ3QgcGF5IHRoZSBjb3N0IG9mIGdlbmVyYXRpbmcgbGF5b3V0cyB0d2ljZS4KICBmdW5jdGlvbiBzY29yZUFwcHJvYWNoKG1ldCl7CiAgICAvLyBDb21wb3NpdGUgb3BlcmF0b3Igc2NvcmU6IGNvdmVyYWdlIGRvbWluYXRlcywgdGhlbiBmdWVsICsgdHVybnMgdGllYnJlYWsuCiAgICAvLyBDb3ZlcmFnZSBvbiAw4oCTMTAwOyB0dXJucyAxMOKAkzMwOyBmdWVsIDXigJMyMCBMOyB3ZWlnaHRzIGJyaW5nIHRoZW0gaW50bwogICAgLy8gc2ltaWxhciByYW5nZXMuIChVc2VkIGFzIHRoZSAid2h5IiBzdHJpbmcgb25seSDigJQgcmVjb21tZW5kQnlNZXRyaWNzCiAgICAvLyB1c2VzIGEgdGllcmVkIGNvbXBhcmlzb24gaW5zdGVhZCBzbyBjb3ZlcmFnZSB0cnVseSBjb21lcyBmaXJzdC4pCiAgICB2YXIgY292ID0gbWV0LmNvdmVyYWdlUGN0IHx8IDA7CiAgICB2YXIgdHVybnMgPSBtZXQudHVybnMgfHwgMDsKICAgIHZhciBmdWVsID0gbWV0LmZ1ZWxMIHx8IDA7CiAgICByZXR1cm4gY292IC0gMC40ICogdHVybnMgLSAxLjUgKiBmdWVsOwogIH0KICAvLyBUaWVyLWJhc2VkIHJlY29tbWVuZGF0aW9uOgogIC8vICAgMS4gSWYgYW55IGFwcHJvYWNoIHJlYWNoZXMg4omlOTUgJSBjb3ZlcmFnZSwgcmVzdHJpY3QgdG8gdGhhdCB0aWVyLgogIC8vICAgMi4gT3RoZXJ3aXNlIHJlc3RyaWN0IHRvIGFwcHJvYWNoZXMgd2l0aGluIDMgJSBvZiB0aGUgYmVzdCBjb3ZlcmFnZS4KICAvLyAgIDMuIEluc2lkZSB0aGF0IHRpZXIsIHBpY2sgdGhlIG9uZSB3aXRoIHRoZSBsb3dlc3QgZnVlbCAoPSBwcm94eSBmb3IKICAvLyAgICAgIHRvdGFsIGRyaXZlIGRpc3RhbmNlLCB3aGljaCBhbHJlYWR5IGNhcHR1cmVzIGJvdGggcGFzcyBsZW5ndGggYW5kCiAgLy8gICAgICB0dXJuYXJvdW5kIGxlbmd0aCkuIFRpZXMgYnJva2VuIGJ5IGZld2VyIHR1cm5hcm91bmRzLCB0aGVuIGJ5CiAgLy8gICAgICBwcmVmZXJyaW5nIHRoZSBzaW1wbGVyIGFwcHJvYWNoIChhYi1zdHJhaWdodCA+IGFiLWN1cnZlID4gYm91bmRhcnkKICAvLyAgICAgID4gYWRhcHRpdmUpIOKAlCB0aGUgQUIgU3RyYWlnaHQgZGVmYXVsdCBpcyB3aGF0IG9wZXJhdG9ycyBydW4gd2hlbgogIC8vICAgICAgZXZlcnl0aGluZyBlbHNlIGlzIGVxdWFsLgogIGZ1bmN0aW9uIHJlY29tbWVuZEJ5TWV0cmljcyhhcE1ldHJpY3MpewogICAgdmFyIGFwcyA9IFsnYWItc3RyYWlnaHQnLCAnYWItY3VydmUnLCAnYm91bmRhcnknLCAnYWRhcHRpdmUnXTsKICAgIHZhciBzaW1wbGljaXR5ID0geyAnYWItc3RyYWlnaHQnOiAwLCAnYWItY3VydmUnOiAxLCAnYm91bmRhcnknOiAyLCAnYWRhcHRpdmUnOiAzIH07CiAgICB2YXIgc2NvcmVzID0ge307CiAgICB2YXIgY2FuZGlkYXRlcyA9IFtdOwogICAgdmFyIG1heENvdiA9IDA7CiAgICBmb3IodmFyIGk9MDsgaTxhcHMubGVuZ3RoOyBpKyspewogICAgICB2YXIgYXAgPSBhcHNbaV07CiAgICAgIHZhciBtZXQgPSBhcE1ldHJpY3NbYXBdOwogICAgICBpZighbWV0KSBjb250aW51ZTsKICAgICAgc2NvcmVzW2FwXSA9IHNjb3JlQXBwcm9hY2gobWV0KTsKICAgICAgY2FuZGlkYXRlcy5wdXNoKHsgYXA6IGFwLCBjb3Y6IG1ldC5jb3ZlcmFnZVBjdCB8fCAwLCBmdWVsOiBtZXQuZnVlbEwgfHwgMCwgdHVybnM6IG1ldC50dXJucyB8fCAwIH0pOwogICAgICBpZigobWV0LmNvdmVyYWdlUGN0IHx8IDApID4gbWF4Q292KSBtYXhDb3YgPSBtZXQuY292ZXJhZ2VQY3QgfHwgMDsKICAgIH0KICAgIGlmKGNhbmRpZGF0ZXMubGVuZ3RoID09PSAwKSByZXR1cm4geyBwaWNrOiAnYWItc3RyYWlnaHQnLCB3aHk6ICdmYWxsYmFjayBkZWZhdWx0Jywgc2NvcmVzOiBzY29yZXMgfTsKICAgIHZhciBjb3ZUaHJlc2hvbGQgPSBtYXhDb3YgPj0gOTUgPyA5NSA6IChtYXhDb3YgLSAzKTsKICAgIHZhciB0aWVyID0gY2FuZGlkYXRlcy5maWx0ZXIoZnVuY3Rpb24oYyl7IHJldHVybiBjLmNvdiA+PSBjb3ZUaHJlc2hvbGQ7IH0pOwogICAgdGllci5zb3J0KGZ1bmN0aW9uKGEsIGIpewogICAgICBpZihhLmZ1ZWwgIT09IGIuZnVlbCkgcmV0dXJuIGEuZnVlbCAtIGIuZnVlbDsKICAgICAgaWYoYS50dXJucyAhPT0gYi50dXJucykgcmV0dXJuIGEudHVybnMgLSBiLnR1cm5zOwogICAgICByZXR1cm4gc2ltcGxpY2l0eVthLmFwXSAtIHNpbXBsaWNpdHlbYi5hcF07CiAgICB9KTsKICAgIHZhciBiZXN0ID0gdGllclswXTsKICAgIHZhciB3aHkgPSBiZXN0LmNvdi50b0ZpeGVkKDApICsgJyUgY292IMK3ICcgKyBiZXN0LnR1cm5zICsgJyB0dXJucyDCtyAnICsgYmVzdC5mdWVsLnRvRml4ZWQoMSkgKyAnIEwgZnVlbCc7CiAgICByZXR1cm4geyBwaWNrOiBiZXN0LmFwLCB3aHk6IHdoeSwgc2NvcmVzOiBzY29yZXMgfTsKICB9CiAgLy8gU2hhcGUtYmFzZWQgZmFsbGJhY2sgKHVzZWQgYXQgSU5JVElBTCBsb2FkIG9ubHksIGJlZm9yZSBhbnkgbGF5b3V0IGhhcwogIC8vIHJ1bikuIFJldHVybnMganVzdCB0aGUgcGljayDigJQgcmVjb21tZW5kQnlNZXRyaWNzIHJlcGxhY2VzIHRoaXMgb24gdGhlCiAgLy8gZmlyc3QgcmVjb21wdXRlKCkuCiAgZnVuY3Rpb24gcmVjb21tZW5kQXBwcm9hY2goYil7CiAgICB2YXIgc3RhdHMgPSBmaWVsZFN0YXRzKGIpOwogICAgdmFyIGJib3hBcmVhID0gKHN0YXRzLm1heFggLSBzdGF0cy5taW5YKSAqIChzdGF0cy5tYXhZIC0gc3RhdHMubWluWSk7CiAgICB2YXIgcmVjdCA9IGJib3hBcmVhID4gMCA\/IChzdGF0cy5hcmVhIC8gYmJveEFyZWEpIDogMDsKICAgIHZhciBwZXIgPSAwOwogICAgZm9yKHZhciBpPTA7IGk8Yi5sZW5ndGg7IGkrKyl7CiAgICAgIHZhciBqID0gKGkgKyAxKSAlIGIubGVuZ3RoOwogICAgICB2YXIgZHggPSBiW2pdLnggLSBiW2ldLngsIGR5ID0gYltqXS55IC0gYltpXS55OwogICAgICBwZXIgKz0gTWF0aC5zcXJ0KGR4KmR4ICsgZHkqZHkpOwogICAgfQogICAgdmFyIGNvbXAgPSBwZXIgPiAwID8gKDQgKiBNYXRoLlBJICogc3RhdHMuYXJlYSAvIChwZXIgKiBwZXIpKSA6IDA7CiAgICB2YXIgcGljazsKICAgIGlmKGNvbXAgPiAwLjc4KSBwaWNrID0gJ2JvdW5kYXJ5JzsKICAgIGVsc2UgaWYocmVjdCA+IDAuODUpIHBpY2sgPSAnYWItc3RyYWlnaHQnOwogICAgZWxzZSBpZihyZWN0ID4gMC41NSkgcGljayA9ICdhYi1jdXJ2ZSc7CiAgICBlbHNlIHBpY2sgPSAnYWRhcHRpdmUnOwogICAgcmV0dXJuIHsgcGljazogcGljaywgd2h5OiAnYW5hbHlzaW5n4oCmJyB9OwogIH0KCiAgLy8gUENBIG9uIGJvdW5kYXJ5IHZlcnRpY2VzIOKAlCByZXR1cm5zIHByaW5jaXBhbCBheGlzICh1eCwgdXkpLgogIGZ1bmN0aW9uIGZpZWxkQXhpcyhiKXsKICAgIHZhciBuID0gYi5sZW5ndGg7CiAgICB2YXIgbXhzID0gMCwgbXlzID0gMDsKICAgIGZvcih2YXIgaT0wOyBpPG47IGkrKyl7IG14cyArPSBiW2ldLng7IG15cyArPSBiW2ldLnk7IH0KICAgIG14cyAvPSBuOyBteXMgLz0gbjsKICAgIHZhciBzeHggPSAwLCBzeXkgPSAwLCBzeHkgPSAwOwogICAgZm9yKHZhciBqPTA7IGo8bjsgaisrKXsKICAgICAgdmFyIGR4ID0gYltqXS54IC0gbXhzLCBkeSA9IGJbal0ueSAtIG15czsKICAgICAgc3h4ICs9IGR4KmR4OyBzeXkgKz0gZHkqZHk7IHN4eSArPSBkeCpkeTsKICAgIH0KICAgIHZhciBhbmcgPSAwLjUgKiBNYXRoLmF0YW4yKDIgKiBzeHksIHN4eCAtIHN5eSk7CiAgICByZXR1cm4geyB1eDogTWF0aC5jb3MoYW5nKSwgdXk6IE1hdGguc2luKGFuZykgfTsKICB9CgogIC8vIENvbmNhdmUtc2FmZSBsaW5lIGNsaXBwZXIuIEZpbmRzIGFsbCBlZGdlIGludGVyc2VjdGlvbnMsIHNvcnRzIGJ5IHQsCiAgLy8gYW5kIHBhaXJzIHRoZW0gdXA6IGVhY2ggY29uc2VjdXRpdmUgKGluc2lkZS1lbnRyeSwgaW5zaWRlLWV4aXQpIHBhaXIKICAvLyBiZWNvbWVzIG9uZSByZXR1cm5lZCBzZWdtZW50LiBXb3JrcyBmb3IgYXJiaXRyYXJ5IHNpbXBsZSBwb2x5Z29ucwogIC8vIChjb252ZXggb3IgY29uY2F2ZSkuIFJldHVybnMgYXJyYXkgb2Ygc2VnbWVudHMgW3t4MCx5MCx4MSx5MX0sIC4uLl0KICAvLyBvciBudWxsIHdoZW4gdGhlIGxpbmUgbWlzc2VzIHRoZSBwb2x5Z29uIGVudGlyZWx5LgogIC8vIExpYW5nLUJhcnNreSB3YXMgdGhlIG9sZCBpbXBsZW1lbnRhdGlvbjsgaXQgQVNTVU1FRCBjb252ZXggYW5kIHByb2R1Y2VkCiAgLy8gd3JvbmcgY2xpcHMgb24gdGhlIEwtc2hhcGUgaW50ZXJpb3IgKGNvbmNhdmUgYXQgdGhlIGlubmVyLWNvcm5lcikuCiAgZnVuY3Rpb24gY2xpcExpbmVUb0JvdW5kYXJ5U2VnbWVudHMoeDAsIHkwLCB4MSwgeTEsIGIpewogICAgdmFyIGR4ID0geDEgLSB4MCwgZHkgPSB5MSAtIHkwOwogICAgdmFyIG5iID0gYi5sZW5ndGg7CiAgICB2YXIgdHMgPSBbXTsKICAgIGZvcih2YXIgaT0wOyBpPG5iOyBpKyspewogICAgICB2YXIgaiA9IChpICsgMSkgJSBuYjsKICAgICAgdmFyIGF4ID0gYltpXS54LCBheSA9IGJbaV0ueTsKICAgICAgdmFyIGV4ID0gYltqXS54IC0gYXgsIGV5ID0gYltqXS55IC0gYXk7CiAgICAgIC8vIFBhcmFtZXRyaWMgbGluZSDDlyBwYXJhbWV0cmljIGVkZ2U6IHgwK3TCt2R4ID0gYXgrdcK3ZXggZXRjLgogICAgICAvLyBTb2x2ZSBmb3IgdCwgdSBpbiBbMCwxXS4gZGVub20gPSBkeMK3KC1leSkg4oiSIGR5wrcoLWV4KSA9IGR5wrdleCDiiJIgZHjCt2V5CiAgICAgIHZhciBkZW5vbSA9IGR5ICogZXggLSBkeCAqIGV5OwogICAgICBpZihNYXRoLmFicyhkZW5vbSkgPCAxZS05KSBjb250aW51ZTsKICAgICAgdmFyIHUgPSAoZHggKiAoYXkgLSB5MCkgLSBkeSAqIChheCAtIHgwKSkgLyBkZW5vbTsKICAgICAgdmFyIHQgPSAoZXggKiAoYXkgLSB5MCkgLSBleSAqIChheCAtIHgwKSkgLyBkZW5vbTsKICAgICAgaWYodSA8IC0xZS05ID8gdHJ1ZSA6IHUgPiAxICsgMWUtOSkgY29udGludWU7CiAgICAgIGlmKHQgPCAtMWUtOSA\/IHRydWUgOiB0ID4gMSArIDFlLTkpIGNvbnRpbnVlOwogICAgICB0cy5wdXNoKHQgPCAwID8gMCA6ICh0ID4gMSA\/IDEgOiB0KSk7CiAgICB9CiAgICBpZih0cy5sZW5ndGggPCAyKSByZXR1cm4gbnVsbDsKICAgIHRzLnNvcnQoZnVuY3Rpb24oYSwgYil7IHJldHVybiBhIC0gYjsgfSk7CiAgICAvLyBEZS1kdXAgbmVhci1lcXVhbCB0J3MgKGxpbmUgcGFzc2luZyBleGFjdGx5IHRocm91Z2ggYSB2ZXJ0ZXggaGl0cyAyIGVkZ2VzKQogICAgdmFyIGNsZWFuID0gW3RzWzBdXTsKICAgIGZvcih2YXIgaz0xOyBrPHRzLmxlbmd0aDsgaysrKXsKICAgICAgaWYodHNba10gLSBjbGVhbltjbGVhbi5sZW5ndGgtMV0gPiAxZS02KSBjbGVhbi5wdXNoKHRzW2tdKTsKICAgIH0KICAgIC8vIFBhaXIgY29uc2VjdXRpdmUgdCdzLCBidXQgb25seSBrZWVwIHBhaXJzIHdob3NlIG1pZHBvaW50IGlzIElOU0lERSB0aGUKICAgIC8vIHBvbHlnb24gKGZpbHRlcnMgYXdheSAib3V0c2lkZSBnYXBzIiBiZXR3ZWVuIGNvbmNhdmUgc2VnbWVudHMpLgogICAgdmFyIHNlZ3MgPSBbXTsKICAgIGZvcih2YXIgcD0wOyBwKzE8Y2xlYW4ubGVuZ3RoOyBwKz0yKXsKICAgICAgdmFyIHQwID0gY2xlYW5bcF0sIHQxID0gY2xlYW5bcCsxXTsKICAgICAgdmFyIG1pZFQgPSAodDAgKyB0MSkgKiAwLjU7CiAgICAgIHZhciBteCA9IHgwICsgZHggKiBtaWRULCBteSA9IHkwICsgZHkgKiBtaWRUOwogICAgICBpZighcG9pbnRJblBvbHkobXgsIG15LCBiKSkgY29udGludWU7CiAgICAgIGlmKHQxIC0gdDAgPCAxZS02KSBjb250aW51ZTsKICAgICAgc2Vncy5wdXNoKHsgeDA6IHgwICsgZHggKiB0MCwgeTA6IHkwICsgZHkgKiB0MCwgeDE6IHgwICsgZHggKiB0MSwgeTE6IHkwICsgZHkgKiB0MSB9KTsKICAgIH0KICAgIHJldHVybiBzZWdzLmxlbmd0aCA+IDAgPyBzZWdzIDogbnVsbDsKICB9CiAgLy8gQmFjay1jb21wYXQgd3JhcHBlcjogcmV0dXJuIHRoZSBMT05HRVNUIHNlZ21lbnQgKG9yIG51bGwpLiBDYWxsZXJzIHRoYXQKICAvLyB3YW50IGFsbCBzdWItc2VnbWVudHMgKGZvciBwcm9wZXIgTC1zaGFwZSBjb3ZlcmFnZSkgdXNlIC4uLlNlZ21lbnRzIGFib3ZlLgogIGZ1bmN0aW9uIGNsaXBMaW5lVG9Cb3VuZGFyeSh4MCwgeTAsIHgxLCB5MSwgYil7CiAgICB2YXIgc2VncyA9IGNsaXBMaW5lVG9Cb3VuZGFyeVNlZ21lbnRzKHgwLCB5MCwgeDEsIHkxLCBiKTsKICAgIGlmKCFzZWdzKSByZXR1cm4gbnVsbDsKICAgIHZhciBiZXN0ID0gbnVsbCwgYmVzdExlbiA9IC0xOwogICAgZm9yKHZhciBpPTA7IGk8c2Vncy5sZW5ndGg7IGkrKyl7CiAgICAgIHZhciBzID0gc2Vnc1tpXTsKICAgICAgdmFyIHNkeCA9IHMueDEgLSBzLngwLCBzZHkgPSBzLnkxIC0gcy55MDsKICAgICAgdmFyIGxlbiA9IHNkeCpzZHggKyBzZHkqc2R5OwogICAgICBpZihsZW4gPiBiZXN0TGVuKXsgYmVzdExlbiA9IGxlbjsgYmVzdCA9IHM7IH0KICAgIH0KICAgIHJldHVybiBiZXN0OwogIH0KCiAgLy8gT2Zmc2V0IGEgY2xvc2VkIHBvbHlnb24gaW53YXJkIGJ5IGRpc3RNLiBSZXR1cm5zIGFycmF5IG9mIHt4LHl9IG9yIG51bGwgd2hlbiBjb2xsYXBzZS4KICBmdW5jdGlvbiBvZmZzZXRQb2x5Z29uSW53YXJkKGIsIGRpc3RNKXsKICAgIHZhciBuID0gYi5sZW5ndGg7CiAgICB2YXIgc2hvZWxhY2UgPSAwOwogICAgZm9yKHZhciBpPTA7IGk8bjsgaSsrKXsKICAgICAgdmFyIGogPSAoaSArIDEpICUgbjsKICAgICAgc2hvZWxhY2UgKz0gYltpXS54ICogYltqXS55IC0gYltqXS54ICogYltpXS55OwogICAgfQogICAgdmFyIHdpbmRpbmcgPSBzaG9lbGFjZSA+IDAgPyAxIDogLTE7CiAgICB2YXIgc3ggPSBuZXcgQXJyYXkobiksIHN5ID0gbmV3IEFycmF5KG4pOwogICAgZm9yKHZhciB2PTA7IHY8bjsgdisrKXsKICAgICAgdmFyIHBJZHggPSAodiAtIDEgKyBuKSAlIG47CiAgICAgIHZhciBuSWR4ID0gKHYgKyAxKSAlIG47CiAgICAgIHZhciBlMXggPSBiW3ZdLnggLSBiW3BJZHhdLng7CiAgICAgIHZhciBlMXkgPSBiW3ZdLnkgLSBiW3BJZHhdLnk7CiAgICAgIHZhciBlMnggPSBiW25JZHhdLnggLSBiW3ZdLng7CiAgICAgIHZhciBlMnkgPSBiW25JZHhdLnkgLSBiW3ZdLnk7CiAgICAgIHZhciBsMSA9IE1hdGguc3FydChlMXgqZTF4ICsgZTF5KmUxeSk7CiAgICAgIHZhciBsMiA9IE1hdGguc3FydChlMngqZTJ4ICsgZTJ5KmUyeSk7CiAgICAgIGlmKGwxIDwgMWUtOSA\/IHRydWUgOiBsMiA8IDFlLTkpeyBzeFt2XSA9IGJbdl0ueDsgc3lbdl0gPSBiW3ZdLnk7IGNvbnRpbnVlOyB9CiAgICAgIHZhciBuMXggPSAtZTF5IC8gbDEgKiB3aW5kaW5nLCBuMXkgPSBlMXggLyBsMSAqIHdpbmRpbmc7CiAgICAgIHZhciBuMnggPSAtZTJ5IC8gbDIgKiB3aW5kaW5nLCBuMnkgPSBlMnggLyBsMiAqIHdpbmRpbmc7CiAgICAgIHZhciBieHYgPSBuMXggKyBuMngsIGJ5diA9IG4xeSArIG4yeTsKICAgICAgdmFyIGJsID0gTWF0aC5zcXJ0KGJ4dipieHYgKyBieXYqYnl2KTsKICAgICAgaWYoYmwgPCAxZS02KXsgc3hbdl0gPSBiW3ZdLnggKyBuMXggKiBkaXN0TTsgc3lbdl0gPSBiW3ZdLnkgKyBuMXkgKiBkaXN0TTsgY29udGludWU7IH0KICAgICAgdmFyIGNvc0Z1bGwgPSBuMXggKiBuMnggKyBuMXkgKiBuMnk7CiAgICAgIHZhciBzaW5IYWxmID0gTWF0aC5zcXJ0KCgxIC0gY29zRnVsbCkgKiAwLjUpOwogICAgICAvLyBNaXRlciBsaW1pdDogZm9yIHZlcnkgb2J0dXNlIGJvdW5kYXJ5IGNvcm5lcnMgKHNpbkhhbGYgc21hbGwpIHRoZSBjb3JuZXIKICAgICAgLy8gYmlzZWN0b3IgYmxvd3MgdXAgYW5kIHdvdWxkIHB1c2ggdGhlIG9mZnNldCB2ZXJ0ZXggcGFzdCB0aGUgZmllbGQKICAgICAgLy8gY2VudHJvaWQuIENhcCBvZmZzZXQgZGlzdGFuY2UgYXQgMsOXIGRpc3RNIHNvIHRoZSBpbnNldCBzdGF5cyBzYW5lLgogICAgICAvLyBGb3Igc2V2ZXJlbHkgb2J0dXNlIGNvcm5lcnMgdGhlIHJlc3VsdCBpcyBhIHNsaWdodCBiZXZlbCBpbnN0ZWFkIG9mIGFuCiAgICAgIC8vIGluZmluaXRlbHktZXh0cnVkZWQgbWl0ZXIg4oCUIGNsb3NlIGVub3VnaCBmb3IgaGVhZGxhbmQgZ2VvbWV0cnkuCiAgICAgIGlmKHNpbkhhbGYgPCAwLjUpIHNpbkhhbGYgPSAwLjU7CiAgICAgIHN4W3ZdID0gYlt2XS54ICsgKGJ4diAvIGJsKSAqIChkaXN0TSAvIHNpbkhhbGYpOwogICAgICBzeVt2XSA9IGJbdl0ueSArIChieXYgLyBibCkgKiAoZGlzdE0gLyBzaW5IYWxmKTsKICAgIH0KICAgIHZhciBrZXB0ID0gW107CiAgICBmb3IodmFyIGs9MDsgazxuOyBrKyspewogICAgICB2YXIgcGsgPSAoayAtIDEgKyBuKSAlIG47CiAgICAgIHZhciBuayA9IChrICsgMSkgJSBuOwogICAgICB2YXIgZTF4QyA9IGJba10ueCAtIGJbcGtdLngsIGUxeUMgPSBiW2tdLnkgLSBiW3BrXS55OwogICAgICB2YXIgYzEgPSAoZTF4QyAqIChzeVtrXSAtIGJbcGtdLnkpIC0gZTF5QyAqIChzeFtrXSAtIGJbcGtdLngpKSAqIHdpbmRpbmc7CiAgICAgIGlmKGMxIDwgMCkgY29udGludWU7CiAgICAgIHZhciBlMnhDID0gYltua10ueCAtIGJba10ueCwgZTJ5QyA9IGJbbmtdLnkgLSBiW2tdLnk7CiAgICAgIHZhciBjMiA9IChlMnhDICogKHN5W2tdIC0gYltrXS55KSAtIGUyeUMgKiAoc3hba10gLSBiW2tdLngpKSAqIHdpbmRpbmc7CiAgICAgIGlmKGMyIDwgMCkgY29udGludWU7CiAgICAgIGtlcHQucHVzaCh7IHg6IHN4W2tdLCB5OiBzeVtrXSB9KTsKICAgIH0KICAgIGlmKGtlcHQubGVuZ3RoIDwgNCkgcmV0dXJuIG51bGw7CiAgICB2YXIgb3JpZ0FyZWEgPSAwOwogICAgZm9yKHZhciBvaT0wOyBvaTxuOyBvaSsrKXsKICAgICAgdmFyIG9qID0gKG9pICsgMSkgJSBuOwogICAgICBvcmlnQXJlYSArPSBiW29pXS54ICogYltval0ueSAtIGJbb2pdLnggKiBiW29pXS55OwogICAgfQogICAgb3JpZ0FyZWEgPSBNYXRoLmFicyhvcmlnQXJlYSkgKiAwLjU7CiAgICB2YXIgbmV3QXJlYSA9IDA7CiAgICBmb3IodmFyIGtpPTA7IGtpPGtlcHQubGVuZ3RoOyBraSsrKXsKICAgICAgdmFyIGtqID0gKGtpICsgMSkgJSBrZXB0Lmxlbmd0aDsKICAgICAgbmV3QXJlYSArPSBrZXB0W2tpXS54ICoga2VwdFtral0ueSAtIGtlcHRba2pdLnggKiBrZXB0W2tpXS55OwogICAgfQogICAgbmV3QXJlYSA9IE1hdGguYWJzKG5ld0FyZWEpICogMC41OwogICAgaWYobmV3QXJlYSA8IG9yaWdBcmVhICogMC4yNSkgcmV0dXJuIG51bGw7CiAgICByZXR1cm4ga2VwdDsKICB9CgogIC8vIFBvaW50LWluLXBvbHlnb24gKHJheSBjYXN0aW5nKS4gUG9seWdvbiBpcyBhcnJheSBvZiB7eCwgeX0sIG5vdCBuZWNlc3NhcmlseSBjbG9zZWQuCiAgZnVuY3Rpb24gcG9pbnRJblBvbHkoeCwgeSwgcG9seSl7CiAgICB2YXIgaW5zaWRlID0gZmFsc2U7CiAgICB2YXIgbiA9IHBvbHkubGVuZ3RoOwogICAgZm9yKHZhciBpPTAsIGo9bi0xOyBpPG47IGo9aSsrKXsKICAgICAgdmFyIHhpID0gcG9seVtpXS54LCB5aSA9IHBvbHlbaV0ueTsKICAgICAgdmFyIHhqID0gcG9seVtqXS54LCB5aiA9IHBvbHlbal0ueTsKICAgICAgdmFyIGludGVyc2VjdCA9ICgoeWkgPiB5KSAhPT0gKHlqID4geSkpID8gKHggPCAoeGogLSB4aSkgKiAoeSAtIHlpKSAvICh5aiAtIHlpICsgMWUtMTIpICsgeGkpIDogZmFsc2U7CiAgICAgIGlmKGludGVyc2VjdCkgaW5zaWRlID0gIWluc2lkZTsKICAgIH0KICAgIHJldHVybiBpbnNpZGU7CiAgfQoKICAvLyBBbGwgYXJjIHNhbXBsZSBwb2ludHMgbXVzdCBsaWUgaW5zaWRlIGBwb2x5YC4gVXNlZCB0byByZWplY3QgYXJjcyB0aGF0IGxlYXZlCiAgLy8gdGhlIGRyaXZhYmxlIGFyZWEuCiAgZnVuY3Rpb24gYXJjSW5zaWRlUG9seShhcmMsIHBvbHkpewogICAgaWYoIWFyYyA\/IHRydWUgOiBhcmMubGVuZ3RoIDwgMikgcmV0dXJuIGZhbHNlOwogICAgZm9yKHZhciBpPTA7IGk8YXJjLmxlbmd0aDsgaSsrKXsKICAgICAgaWYoIXBvaW50SW5Qb2x5KGFyY1tpXS54LCBhcmNbaV0ueSwgcG9seSkpIHJldHVybiBmYWxzZTsKICAgIH0KICAgIHJldHVybiB0cnVlOwogIH0KCiAgLy8gTWlkZGxlIDgwJSBvZiBhcmMgc2FtcGxlcyBtdXN0IE5PVCBsaWUgaW5zaWRlIGBpbnRlcmlvcmAgKHRoZSB3b3JrZWQgem9uZSkuCiAgLy8gRW5kcG9pbnRzIHNpdCBPTiB0aGUgaW50ZXJpb3IgYm91bmRhcnkgYnkgY29uc3RydWN0aW9uIHNvIHdlIHNraXAgdGhlIGZpcnN0CiAgLy8gYW5kIGxhc3QgMTAlIG9mIHNhbXBsZXMuCiAgZnVuY3Rpb24gYXJjQXZvaWRzSW50ZXJpb3IoYXJjLCBpbnRlcmlvcil7CiAgICBpZighYXJjID8gdHJ1ZSA6ICFpbnRlcmlvcikgcmV0dXJuIHRydWU7CiAgICBpZihhcmMubGVuZ3RoIDwgNCkgcmV0dXJuIHRydWU7CiAgICAvLyBBcmMgZW5kcG9pbnRzIHNpdCBPTiB0aGUgaW50ZXJpb3IgYm91bmRhcnkgYnkgY29uc3RydWN0aW9uLiBGbG9hdGluZy1wb2ludAogICAgLy8gaml0dGVyIG5lYXIgdGhlIHN0YXJ0L2VuZCBtYXkgY2xhc3NpZnkgdGhlbSBhcyBqdXN0LWluc2lkZSwgc28gc2tpcCAxNSUKICAgIC8vIGF0IGVhY2ggZW5kLiBNaWRkbGUgNzAlIHN0aWxsIGhhcyB0byBhdm9pZCB0aGUgd29ya2VkIHpvbmUuCiAgICB2YXIgc2tpcCA9IE1hdGgubWF4KDEsIE1hdGguZmxvb3IoYXJjLmxlbmd0aCAqIDAuMTUpKTsKICAgIGZvcih2YXIgaT1za2lwOyBpPGFyYy5sZW5ndGgtc2tpcDsgaSsrKXsKICAgICAgaWYocG9pbnRJblBvbHkoYXJjW2ldLngsIGFyY1tpXS55LCBpbnRlcmlvcikpIHJldHVybiBmYWxzZTsKICAgIH0KICAgIHJldHVybiB0cnVlOwogIH0KCiAgLy8gQnVpbGQgYSBjYW5kaWRhdGUgdHVybiBhcmMgY29ubmVjdGluZyAoeDEseTEpIHRvICh4Mix5MikgZ2l2ZW4gc3R5bGUgKyByYWRpdXMKICAvLyArIHBlcnBlbmRpY3VsYXIgZGlyZWN0aW9uIChzaWduID0gKzEgb3IgLTEgPSB3aGljaCBzaWRlIHRvIGJ1bGdlKS4KICAvLyBSZXR1cm5zIGFycmF5IG9mIHt4LCB5fSBzYW1wbGUgcG9pbnRzIChsZW5ndGggfjI0Kykgb3IgbnVsbCB3aGVuIGdlb21ldHJ5IGZhaWxzLgogIGZ1bmN0aW9uIGJ1aWxkQXJjKHgxLCB5MSwgeDIsIHkyLCBzdHlsZSwgcmFkaXVzTSwgc2lnbil7CiAgICB2YXIgZHggPSB4MiAtIHgxLCBkeSA9IHkyIC0geTE7CiAgICB2YXIgZCA9IE1hdGguc3FydChkeCpkeCArIGR5KmR5KTsKICAgIGlmKGQgPCAwLjEpIHJldHVybiBudWxsOwogICAgdmFyIHV4ID0gZHggLyBkLCB1eSA9IGR5IC8gZDsKICAgIHZhciBwZXJwWCA9IC11eSAqIHNpZ24sIHBlcnBZID0gdXggKiBzaWduOwogICAgdmFyIGNvb3JkcyA9IFtdOwogICAgdmFyIG5TZWcgPSAyNDsKICAgIGlmKHN0eWxlID09PSAndXR1cm4nKXsKICAgICAgLy8gSGFsZi1jaXJjbGUsIHJhZGl1cyA9IGQvMiAoZm9yY2VkIGJ5IGdlb21ldHJ5LCBub3QgZXF1aXBtZW50KS4KICAgICAgdmFyIHIgPSBkICogMC41OwogICAgICB2YXIgbXggPSAoeDEgKyB4MikgKiAwLjUsIG15ID0gKHkxICsgeTIpICogMC41OwogICAgICAvLyBBbmdsZSBmcm9tIG1pZHBvaW50IHRvIHAxLCB0aGVuIHN3ZWVwIMKxMTgwwrAgdG8gcDIuCiAgICAgIHZhciBzdGFydEFuZyA9IE1hdGguYXRhbjIoeTEgLSBteSwgeDEgLSBteCk7CiAgICAgIHZhciBzd2VlcCA9IE1hdGguUEkgKiBzaWduOwogICAgICBmb3IodmFyIGk9MDsgaTw9blNlZzsgaSsrKXsKICAgICAgICB2YXIgdCA9IGkgLyBuU2VnOwogICAgICAgIHZhciBhbmcgPSBzdGFydEFuZyArIHN3ZWVwICogdDsKICAgICAgICBjb29yZHMucHVzaCh7IHg6IG14ICsgTWF0aC5jb3MoYW5nKSAqIHIsIHk6IG15ICsgTWF0aC5zaW4oYW5nKSAqIHIgfSk7CiAgICAgIH0KICAgIH0gZWxzZSBpZihzdHlsZSA9PT0gJ3JhY2V0cmFjaycpewogICAgICAvLyBUd28gOTDCsCBhcmNzICsgc3RyYWlnaHQgbGVnLiBSYWRpdXMgY2FwcGVkIGF0IGQvMiDDlyAwLjk1IHNvIHRoZSBsZWcgc3RheXMgPiAwLgogICAgICB2YXIgcjIgPSBNYXRoLm1pbihyYWRpdXNNLCBkICogMC41ICogMC45NSk7CiAgICAgIGlmKHIyIDw9IDAuMDEpIHJldHVybiBudWxsOwogICAgICAvLyBDaXJjbGUgY2VudHJlcyBwZXJwZW5kaWN1bGFyLW91dCBmcm9tIGVhY2ggZW5kcG9pbnQgYnkgcjIuCiAgICAgIHZhciBjMXggPSB4MSArIHBlcnBYICogcjIsIGMxeSA9IHkxICsgcGVycFkgKiByMjsKICAgICAgdmFyIGMyeCA9IHgyICsgcGVycFggKiByMiwgYzJ5ID0geTIgKyBwZXJwWSAqIHIyOwogICAgICB2YXIgYW5nMSA9IE1hdGguYXRhbjIoeTEgLSBjMXksIHgxIC0gYzF4KTsKICAgICAgdmFyIGFuZzJFbmQgPSBNYXRoLmF0YW4yKHkyIC0gYzJ5LCB4MiAtIGMyeCk7CiAgICAgIHZhciBoYWxmID0gTWF0aC5tYXgoOCwgTWF0aC5mbG9vcihuU2VnIC8gMykpOwogICAgICAvLyBBcmMgMSBhcm91bmQgYzE6IGZyb20gYW5nMSBzd2VlcGluZyArOTDCsMK3c2lnbiAob3V0d2FyZCkKICAgICAgdmFyIHN3ZWVwMSA9IE1hdGguUEkgKiAwLjUgKiBzaWduOwogICAgICBmb3IodmFyIGs9MDsgazw9aGFsZjsgaysrKXsKICAgICAgICB2YXIgdDEgPSBrIC8gaGFsZjsKICAgICAgICB2YXIgYWEgPSBhbmcxICsgc3dlZXAxICogdDE7CiAgICAgICAgY29vcmRzLnB1c2goeyB4OiBjMXggKyBNYXRoLmNvcyhhYSkgKiByMiwgeTogYzF5ICsgTWF0aC5zaW4oYWEpICogcjIgfSk7CiAgICAgIH0KICAgICAgLy8gQXJjLTEgZW5kIHBvc2l0aW9uCiAgICAgIHZhciBlbmRBMXggPSBjb29yZHNbY29vcmRzLmxlbmd0aC0xXS54LCBlbmRBMXkgPSBjb29yZHNbY29vcmRzLmxlbmd0aC0xXS55OwogICAgICAvLyBBcmMtMiBzdGFydCBwb3NpdGlvbiAobWlycm9yIG9mIGFuZzJFbmQgYnkgKzkwwrDCt3NpZ24gcmV2ZXJzZWQpCiAgICAgIHZhciBzd2VlcDJzdGFydCA9IGFuZzJFbmQgLSBzd2VlcDE7CiAgICAgIHZhciBzdGFydEEyeCA9IGMyeCArIE1hdGguY29zKHN3ZWVwMnN0YXJ0KSAqIHIyOwogICAgICB2YXIgc3RhcnRBMnkgPSBjMnkgKyBNYXRoLnNpbihzd2VlcDJzdGFydCkgKiByMjsKICAgICAgLy8gU3RyYWlnaHQgbGVnIGZyb20gZW5kQTEgdG8gc3RhcnRBMiDigJQgc2FtcGxlIDYgcG9pbnRzIHNvIHZhbGlkYXRpb24gY2FuCiAgICAgIC8vIGRldGVjdCBpZiB0aGUgbGVnIGNyb3NzZXMgdGhlIGZpZWxkIGJvdW5kYXJ5LgogICAgICB2YXIgbGVnU3RlcHMgPSA2OwogICAgICBmb3IodmFyIEw9MTsgTDxsZWdTdGVwczsgTCsrKXsKICAgICAgICB2YXIgdHQgPSBMIC8gbGVnU3RlcHM7CiAgICAgICAgY29vcmRzLnB1c2goeyB4OiBlbmRBMXggKyAoc3RhcnRBMnggLSBlbmRBMXgpICogdHQsIHk6IGVuZEExeSArIChzdGFydEEyeSAtIGVuZEExeSkgKiB0dCB9KTsKICAgICAgfQogICAgICBjb29yZHMucHVzaCh7IHg6IHN0YXJ0QTJ4LCB5OiBzdGFydEEyeSB9KTsKICAgICAgLy8gQXJjIDIgYXJvdW5kIGMyOiBmcm9tIHN3ZWVwMnN0YXJ0IGJhY2sgdG8gYW5nMkVuZCAoc3dlZXAgPSArOTDCsMK3c2lnbikKICAgICAgZm9yKHZhciBtPTE7IG08PWhhbGY7IG0rKyl7CiAgICAgICAgdmFyIHQyID0gbSAvIGhhbGY7CiAgICAgICAgdmFyIGJiID0gc3dlZXAyc3RhcnQgKyBzd2VlcDEgKiB0MjsKICAgICAgICBjb29yZHMucHVzaCh7IHg6IGMyeCArIE1hdGguY29zKGJiKSAqIHIyLCB5OiBjMnkgKyBNYXRoLnNpbihiYikgKiByMiB9KTsKICAgICAgfQogICAgfSBlbHNlIGlmKHN0eWxlID09PSAnZmxhdCcpewogICAgICAvLyBTaW51c29pZGFsIGJ1bGdlLCBwZWFrIGFtcGxpdHVkZSA9IG1pbihyYWRpdXNNLCBkLzQpLgogICAgICB2YXIgYW1wID0gTWF0aC5taW4ocmFkaXVzTSwgZCAqIDAuMjUpOwogICAgICBmb3IodmFyIGY9MDsgZjw9blNlZzsgZisrKXsKICAgICAgICB2YXIgdGYgPSBmIC8gblNlZzsKICAgICAgICB2YXIgYnggPSB4MSArIGR4ICogdGY7CiAgICAgICAgdmFyIGJ5ID0geTEgKyBkeSAqIHRmOwogICAgICAgIHZhciBidWxnZSA9IE1hdGguc2luKE1hdGguUEkgKiB0ZikgKiBhbXA7CiAgICAgICAgY29vcmRzLnB1c2goeyB4OiBieCArIHBlcnBYICogYnVsZ2UsIHk6IGJ5ICsgcGVycFkgKiBidWxnZSB9KTsKICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgcmV0dXJuIG51bGw7CiAgICB9CiAgICByZXR1cm4gY29vcmRzOwogIH0KCiAgLy8gQ29tcHV0ZSBvdXR3YXJkLWJ1bGdlIGRpcmVjdGlvbiAoc2lnbiArMSBvciAtMSkgZ2l2ZW4gcDEsIHAyLCBhbmQgdGhlCiAgLy8gaW50ZXJpb3IgY2VudHJvaWQuIFRoZSBzaWduIHRoYXQgcHVzaGVzIHRoZSBhcmMgQVBFWCBmdXJ0aGVyIGZyb20gdGhlCiAgLy8gY2VudHJvaWQgaXMgIm91dHdhcmQiIOKAlCB0aGF0J3Mgd2hlcmUgdGhlIGhlYWRsYW5kIHN0cmlwIGlzLgogIC8vCiAgLy8gSU1QT1JUQU5UIOKAlCBmb3IgYSBVLXR1cm4gYXJjIGJ1aWx0IGJ5IGJ1aWxkQXJjKC4uLikgd2l0aCBzaWduIHMsIHRoZSBhcGV4CiAgLy8gKGF0IHBhcmFtZXRyaWMgdD0wLjUpIGlzIGF0IGNob3JkLW1pZHBvaW50ICsgcmFkaXVzwrcodXnCt3MsIC11eMK3cykg4oCUIE5PVAogIC8vIHBlcnBlbmRpY3VsYXIgPSAoLXV5wrdzLCB1eMK3cykuIFRoZSBidWlsZEFyYyBhcGV4IG1hdGggc3dlZXBzIGZyb20gdGhlCiAgLy8gYW5nbGUgb2YgdmVjdG9yKG1pZHBvaW50IOKGkiBwMSkgcm90YXRlZCBieSArz4AvMsK3cywgd2hpY2ggbmVnYXRlcyB0aGUKICAvLyBwZXJwZW5kaWN1bGFyIHJlbGF0aXZlIHRvIGNob3JkIGRpcmVjdGlvbi4gVXNlICh1eSwgLXV4KSBoZXJlIHNvIHRoZQogIC8vIHJldHVybmVkIHNpZ24gYWN0dWFsbHkgbWF0Y2hlcyB0aGUgYXJjJ3MgYnVsZ2UgZGlyZWN0aW9uLgogIGZ1bmN0aW9uIG91dHdhcmRTaWduKHgxLCB5MSwgeDIsIHkyLCBpbnRlcmlvckNlbnRlclgsIGludGVyaW9yQ2VudGVyWSwgcmFkaXVzTSl7CiAgICB2YXIgbWlkWCA9ICh4MSArIHgyKSAqIDAuNTsKICAgIHZhciBtaWRZID0gKHkxICsgeTIpICogMC41OwogICAgdmFyIGR4ID0geDIgLSB4MSwgZHkgPSB5MiAtIHkxOwogICAgdmFyIGQgPSBNYXRoLnNxcnQoZHgqZHggKyBkeSpkeSk7CiAgICBpZihkIDwgMWUtNikgcmV0dXJuIDE7CiAgICB2YXIgdXggPSBkeCAvIGQsIHV5ID0gZHkgLyBkOwogICAgLy8gQXBleCBvZmZzZXQgYXQgc2lnbj0rMTogKHV5LCAtdXgpIMK3IHJhZGl1cwogICAgdmFyIGFwZXhQeCA9IG1pZFggKyB1eSAqIHJhZGl1c007CiAgICB2YXIgYXBleFB5ID0gbWlkWSAtIHV4ICogcmFkaXVzTTsKICAgIHZhciBkMSA9IChhcGV4UHggLSBpbnRlcmlvckNlbnRlclgpICogKGFwZXhQeCAtIGludGVyaW9yQ2VudGVyWCkgKyAoYXBleFB5IC0gaW50ZXJpb3JDZW50ZXJZKSAqIChhcGV4UHkgLSBpbnRlcmlvckNlbnRlclkpOwogICAgLy8gQXBleCBvZmZzZXQgYXQgc2lnbj0tMTogKC11eSwgdXgpIMK3IHJhZGl1cwogICAgdmFyIGFwZXhNeCA9IG1pZFggLSB1eSAqIHJhZGl1c007CiAgICB2YXIgYXBleE15ID0gbWlkWSArIHV4ICogcmFkaXVzTTsKICAgIHZhciBkMiA9IChhcGV4TXggLSBpbnRlcmlvckNlbnRlclgpICogKGFwZXhNeCAtIGludGVyaW9yQ2VudGVyWCkgKyAoYXBleE15IC0gaW50ZXJpb3JDZW50ZXJZKSAqIChhcGV4TXkgLSBpbnRlcmlvckNlbnRlclkpOwogICAgcmV0dXJuIGQxID49IGQyID8gMSA6IC0xOwogIH0KCiAgLy8gQnVpbGQgYSB0dXJuIGFyYyB3aXRoIHRoZSB2YWxpZGF0aW9uIGNhc2NhZGUgZGVzY3JpYmVkIGluIFJVTEVTLm1kIMKnNS4KICAvLyBSZXR1cm5zIHsgY29vcmRzLCBzdHlsZSwgcmFkaXVzLCBvaywgcmVhc29uIH0gd2hlcmUgY29vcmRzIGlzIG51bGwgb24KICAvLyB0b3RhbCBmYWlsdXJlLiBgb2s9ZmFsc2VgIHdpdGggYSBjb29yZHMgYXJyYXkgbWVhbnMgImJlc3QtZWZmb3J0IGZhbGxiYWNrLAogIC8vIHN1cmZhY2UgdGhlIHJlYXNvbiB0byB0aGUgdXNlciIuCiAgZnVuY3Rpb24gYnVpbGRUdXJuQXJjKHAxLCBwMiwgZHJpdmFibGUsIGludGVyaW9yLCBwcmVmZXJyZWRTdHlsZSwgdHVyblJhZGl1c00sIGhhbGZJbXBsZW1lbnRNLCB3TSl7CiAgICB2YXIgZHggPSBwMi54IC0gcDEueCwgZHkgPSBwMi55IC0gcDEueTsKICAgIHZhciBkID0gTWF0aC5zcXJ0KGR4KmR4ICsgZHkqZHkpOwogICAgaWYoZCA8IDAuMSkgcmV0dXJuIHsgY29vcmRzOiBudWxsLCBzdHlsZTogcHJlZmVycmVkU3R5bGUsIHJhZGl1czogMCwgb2s6IGZhbHNlLCByZWFzb246ICdwYXNzIGVuZHBvaW50cyBjb2luY2lkZScgfTsKICAgIC8vIENob3JkIHRvbyBsb25nIGZvciBhIGNsZWFuIFUtdHVybiAoZS5nLiwgY29uc2VjdXRpdmUgcGFzcyBlbmRwb2ludHMgbGFuZAogICAgLy8gYXQgdmVyeSBkaWZmZXJlbnQgYWxvbmctYXhpcyBwb3NpdGlvbnMgYmVjYXVzZSB0aGUgYm91bmRhcnkgY3VydmVzCiAgICAvLyBiZXR3ZWVuIHRoZW0pLiBBIGhhbGYtY2lyY2xlIHdpdGggcmFkaXVzIGQvMiB3b3VsZCBiZSBodWdlIGFuZCBjbGVhcmx5CiAgICAvLyBleGl0IHRoZSBmaWVsZC4gUmVhbCBwcmFjdGljZTogb3BlcmF0b3IgcGl2b3RzIHNtYWxsIGF0IHBhc3MtQSBlbmQsCiAgICAvLyBkcml2ZXMgYWxvbmcgdGhlIHdvcmtlZCBoZWFkbGFuZCBzdHJpcCB0byBwYXNzLUIgc3RhcnQsIHBpdm90cyBzbWFsbCBhdAogICAgLy8gcGFzcy1CIHN0YXJ0LiBSZXByZXNlbnQgdGhpcyBhcyBhIHN0cmFpZ2h0IGNvbm5lY3RvciAobm8gc3ludGhldGljIGFyYykKICAgIC8vIOKAlCB2aXN1YWxseSBhIHNob3J0IGhlYWRsYW5kIHRyYXZlcnNlIGxpbmUsIGFncm9ub21pY2FsbHkgY29ycmVjdC4KICAgIHZhciBtYXhSZWFzb25hYmxlQ2hvcmQgPSB3TSAqIDIuNTsKICAgIGlmKGQgPiBtYXhSZWFzb25hYmxlQ2hvcmQpewogICAgICByZXR1cm4geyBjb29yZHM6IG51bGwsIHN0eWxlOiAndHJhdmVyc2UnLCByYWRpdXM6IDAsIG9rOiB0cnVlLCByZWFzb246IG51bGwgfTsKICAgIH0KICAgIC8vIE91dHdhcmQgcmVmZXJlbmNlOiBpbnRlcmlvciBjZW50cm9pZCwgZmFsbHMgYmFjayB0byBkcml2YWJsZSBjZW50cm9pZC4KICAgIHZhciByZWYgPSBpbnRlcmlvciA\/IGludGVyaW9yIDogZHJpdmFibGU7CiAgICB2YXIgY3ggPSAwLCBjeSA9IDA7CiAgICBmb3IodmFyIGk9MDsgaTxyZWYubGVuZ3RoOyBpKyspeyBjeCArPSByZWZbaV0ueDsgY3kgKz0gcmVmW2ldLnk7IH0KICAgIGN4IC89IHJlZi5sZW5ndGg7IGN5IC89IHJlZi5sZW5ndGg7CiAgICAvLyBVLXR1cm4gcmFkaXVzIGlzIGdlb21ldHJpY2FsbHkgZm9yY2VkIHRvIGNob3JkLzIgKGhhbGYtY2lyY2xlIHRocm91Z2gKICAgIC8vIHRoZSB0d28gcGFzcyBlbmRwb2ludHMpLiBJZiBjaG9yZC8yIGlzIFRJR0hURVIgdGhhbiB0aGUgdXNlcidzIG1pbmltdW0KICAgIC8vIHR1cm4gcmFkaXVzICg9IGVxdWlwbWVudCBjYW4ndCBwaHlzaWNhbGx5IHR1cm4gdGhhdCBzaGFycCksIHNraXAgdGhlCiAgICAvLyBhcmMgYW5kIHVzZSBhIHRyYXZlcnNlIGluc3RlYWQg4oCUIG9wZXJhdG9yIGRvZXMgYSBwaXZvdCArIGRyaXZlcyBhY3Jvc3MKICAgIC8vIHRoZSBoZWFkbGFuZC4gVGhpcyBtYWtlcyAiTWluIHR1cm4gcmFkaXVzIiBhY3R1YWxseSBtYXR0ZXI6IGluY3JlYXNpbmcKICAgIC8vIGl0IGZvcmNlcyBtb3JlIHRyYW5zaXRpb25zIHRvIHRyYXZlcnNlcy4KICAgIGlmKGQgKiAwLjUgPCB0dXJuUmFkaXVzTSl7CiAgICAgIHJldHVybiB7IGNvb3JkczogbnVsbCwgc3R5bGU6ICd0cmF2ZXJzZScsIHJhZGl1czogMCwgb2s6IHRydWUsIHJlYXNvbjogbnVsbCB9OwogICAgfQogICAgdmFyIGNhbmRzID0gWwogICAgICB7IHN0eWxlOiAndXR1cm4nLCByYWRpdXM6IGQgKiAwLjUgfQogICAgXTsKICAgIC8vIFJ1bGUgwqcxNCDigJQgbWFjaGluZSArIGVxdWlwbWVudCBtdXN0IHN0YXkgaW5zaWRlIHRoZSBmaWVsZCBib3VuZGFyeSBldmVuCiAgICAvLyBkdXJpbmcgdGhlIGFyYy4gVmFsaWRhdGUgYWdhaW5zdCBkcml2YWJsZSBJTlNFVCBieSBoYWxmLWltcGxlbWVudC13aWR0aAogICAgLy8gc28gdGhlIGVxdWlwbWVudCBlZGdlIChub3QganVzdCB0aGUgY2VudHJlbGluZSkgbmV2ZXIgY3Jvc3NlcyB0aGUKICAgIC8vIGJvdW5kYXJ5LiBVc2UgYSBzb2Z0ZW5lZCBpbnNldCAoMC41IMOXIGhhbGZJbXBsKSBiZWNhdXNlIHRoZSBwb2x5Z29uCiAgICAvLyBtaXRlci1jbGFtcCBjYW4gb3Zlci1pbnNldCBhdCBvYnR1c2UgY29ybmVycywgcmVqZWN0aW5nIGFyY3MgdGhhdAogICAgLy8gcGh5c2ljYWxseSBmaXQuIFRoZSBpbXBsZW1lbnQgZWRnZSBzdGlsbCBlZmZlY3RpdmVseSBzdGF5cyBpbnNpZGUg4oCUCiAgICAvLyByZWFsIG9wZXJhdG9ycyBkcml2ZSB3aXRoIH5oYWxmIHRoZSBpbXBsZW1lbnQgd2lkdGggYXMgdG9sZXJhbmNlLCBub3QKICAgIC8vIHRoZSBmdWxsIHdpZHRoLgogICAgdmFyIHNhZmVNYXJnaW4gPSBoYWxmSW1wbGVtZW50TSAqIDAuNTsKICAgIHZhciBzYWZlID0gc2FmZU1hcmdpbiA+IDAgPyBvZmZzZXRQb2x5Z29uSW53YXJkKGRyaXZhYmxlLCBzYWZlTWFyZ2luKSA6IGRyaXZhYmxlOwogICAgaWYoIXNhZmUgPyB0cnVlIDogc2FmZS5sZW5ndGggPCA0KSBzYWZlID0gZHJpdmFibGU7CiAgICAvLyBVLXR1cm5zIGFyZSBBTFdBWVMgb3V0d2FyZCDigJQgaW50byB0aGUgaGVhZGxhbmQgc3RyaXAsIGF3YXkgZnJvbSB0aGUKICAgIC8vIHdvcmtlZCBpbnRlcmlvci4gTmV2ZXIgYnVsZ2UgaW53YXJkICh0aGF0IHdvdWxkIHJlLXdvcmsgY292ZXJlZCBncm91bmQpLgogICAgdmFyIHByZWZlclNpZ24gPSBvdXR3YXJkU2lnbihwMS54LCBwMS55LCBwMi54LCBwMi55LCBjeCwgY3ksIGQgKiAwLjUpOwogICAgLy8gU3RyaWN0IHBhc3M6IG1hY2hpbmUgZm9vdHByaW50IGluc2lkZSBib3VuZGFyeSBBTkQgbWlkZGxlIDcwJSBhdm9pZHMgd29ya2VkIGludGVyaW9yCiAgICBmb3IodmFyIGMxPTA7IGMxPGNhbmRzLmxlbmd0aDsgYzErKyl7CiAgICAgIHZhciBjYW5kID0gY2FuZHNbYzFdOwogICAgICB2YXIgYXJjID0gYnVpbGRBcmMocDEueCwgcDEueSwgcDIueCwgcDIueSwgY2FuZC5zdHlsZSwgY2FuZC5yYWRpdXMsIHByZWZlclNpZ24pOwogICAgICBpZighYXJjKSBjb250aW51ZTsKICAgICAgaWYoIWFyY0luc2lkZVBvbHkoYXJjLCBzYWZlKSkgY29udGludWU7CiAgICAgIGlmKCFhcmNBdm9pZHNJbnRlcmlvcihhcmMsIGludGVyaW9yKSkgY29udGludWU7CiAgICAgIHJldHVybiB7IGNvb3JkczogYXJjLCBzdHlsZTogY2FuZC5zdHlsZSwgcmFkaXVzOiBjYW5kLnJhZGl1cywgb2s6IHRydWUsIHJlYXNvbjogbnVsbCB9OwogICAgfQogICAgLy8gUmVsYXhlZCBwYXNzOiBvdXR3YXJkIHN0aWxsLCBtYWNoaW5lIGZvb3RwcmludCBzdGlsbCBpbnNpZGUgYm91bmRhcnksCiAgICAvLyBqdXN0IGFsbG93IHRoZSBhcmMgdG8gZGlwIHBhc3QgdGhlIGhlYWRsYW5kIGVkZ2UgaW50byB0aGUgd29ya2VkIHpvbmUuCiAgICBmb3IodmFyIGMyPTA7IGMyPGNhbmRzLmxlbmd0aDsgYzIrKyl7CiAgICAgIHZhciBjYW5kMiA9IGNhbmRzW2MyXTsKICAgICAgdmFyIGFyYzIgPSBidWlsZEFyYyhwMS54LCBwMS55LCBwMi54LCBwMi55LCBjYW5kMi5zdHlsZSwgY2FuZDIucmFkaXVzLCBwcmVmZXJTaWduKTsKICAgICAgaWYoIWFyYzIpIGNvbnRpbnVlOwogICAgICBpZighYXJjSW5zaWRlUG9seShhcmMyLCBzYWZlKSkgY29udGludWU7CiAgICAgIHJldHVybiB7CiAgICAgICAgY29vcmRzOiBhcmMyLCBzdHlsZTogY2FuZDIuc3R5bGUsIHJhZGl1czogY2FuZDIucmFkaXVzLAogICAgICAgIG9rOiBmYWxzZSwgcmVhc29uOiAnVS10dXJuIGRpcHMgaW50byB3b3JrZWQgem9uZSDigJQgd2lkZW4gaGVhZGxhbmQgc3RyaXAuJwogICAgICB9OwogICAgfQogICAgLy8gTGFzdCByZXNvcnQg4oCUIG5vIG91dHdhcmQgYXJjIGZpdHMgaW5zaWRlIHRoZSBib3VuZGFyeS4gUnVsZSDCpzE0IHNheXMKICAgIC8vIHRoZSBtYWNoaW5lIG11c3Qgc3RheSBpbnNpZGUgdGhlIGZpZWxkLCBzbyBETyBOT1QgZW1pdCBhbiBhcmMgdGhhdAogICAgLy8gd291bGQgY2xlYXJseSBsZWF2ZS4gUmV0dXJuIGEgdHJhdmVyc2UgaW5zdGVhZCDigJQgdGhlIGNhbGxlciByb3V0ZXMgaXQKICAgIC8vIGFsb25nIHRoZSBoZWFkbGFuZCByaW5nLiBPcGVyYXRvciBzZWVzIGEgd2FybmluZyArIGEgcmluZy1yb3V0ZWQgcGF0aAogICAgLy8gaW5zdGVhZCBvZiBhIHBoYW50b20gYXJjIGV4aXRpbmcgdGhlIGZpZWxkLgogICAgcmV0dXJuIHsKICAgICAgY29vcmRzOiBudWxsLCBzdHlsZTogJ3RyYXZlcnNlJywgcmFkaXVzOiAwLAogICAgICBvazogZmFsc2UsIHJlYXNvbjogJ05vIHR1cm4gZml0cyBpbnNpZGUgZmllbGQgYm91bmRhcnkg4oCUIHJvdXRpbmcgYWxvbmcgdGhlIGhlYWRsYW5kIHJpbmcgaW5zdGVhZC4nCiAgICB9OwogIH0KCiAgLy8gQnVpbGQgdGhlIGRyaXZhYmxlIHBvbHlnb24gPSBib3VuZGFyeSArIG91dHNpZGVCdWZmZXJNIG91dHdhcmQgb2Zmc2V0LgogIC8vIEZvciB0aGUgbGVhZC1tYWduZXQgTVZQIHRoZXJlIGFyZSBubyBvYnN0YWNsZXMsIHNvIHRoaXMgaXMganVzdCBib3VuZGFyeQogIC8vIGRpbGF0aW9uLiBXaXRoIHR1cm5CdWY9MCwgZHJpdmFibGUgPT09IGJvdW5kYXJ5LgogIGZ1bmN0aW9uIGJ1aWxkRHJpdmFibGUoYiwgb3V0c2lkZUJ1ZmZlck0pewogICAgaWYob3V0c2lkZUJ1ZmZlck0gPD0gMCkgcmV0dXJuIGI7CiAgICAvLyBPdXR3YXJkIG9mZnNldCA9IGlud2FyZCBvZmZzZXQgd2l0aCBuZWdhdGVkIGRpc3RhbmNlLiBOZWdhdGUgaW53YXJkIGJ5CiAgICAvLyBmbGlwcGluZyB0aGUgd2luZGluZyBzaWduIGNvbnZlbnRpb246IHJldXNlIG9mZnNldFBvbHlnb25JbndhcmQgd2l0aAogICAgLy8gbmVnYXRpdmUgZGlzdE0g4oCUIGJ1dCB0aGUgZnVuY3Rpb24gY2xhbXBzIG1pbiB2ZXJ0aWNlcyBldGMsIHNvIGRvIG1hbnVhbC4KICAgIHZhciBuID0gYi5sZW5ndGg7CiAgICB2YXIgc2hvZWxhY2UgPSAwOwogICAgZm9yKHZhciBpPTA7IGk8bjsgaSsrKXsKICAgICAgdmFyIGogPSAoaSArIDEpICUgbjsKICAgICAgc2hvZWxhY2UgKz0gYltpXS54ICogYltqXS55IC0gYltqXS54ICogYltpXS55OwogICAgfQogICAgdmFyIHdpbmRpbmcgPSBzaG9lbGFjZSA+IDAgPyAxIDogLTE7CiAgICB2YXIgb3V0ID0gW107CiAgICBmb3IodmFyIHY9MDsgdjxuOyB2KyspewogICAgICB2YXIgcElkeCA9ICh2IC0gMSArIG4pICUgbjsKICAgICAgdmFyIG5JZHggPSAodiArIDEpICUgbjsKICAgICAgdmFyIGUxeCA9IGJbdl0ueCAtIGJbcElkeF0ueDsKICAgICAgdmFyIGUxeSA9IGJbdl0ueSAtIGJbcElkeF0ueTsKICAgICAgdmFyIGUyeCA9IGJbbklkeF0ueCAtIGJbdl0ueDsKICAgICAgdmFyIGUyeSA9IGJbbklkeF0ueSAtIGJbdl0ueTsKICAgICAgdmFyIGwxID0gTWF0aC5zcXJ0KGUxeCplMXggKyBlMXkqZTF5KTsKICAgICAgdmFyIGwyID0gTWF0aC5zcXJ0KGUyeCplMnggKyBlMnkqZTJ5KTsKICAgICAgaWYobDEgPCAxZS05ID8gdHJ1ZSA6IGwyIDwgMWUtOSl7IG91dC5wdXNoKHsgeDogYlt2XS54LCB5OiBiW3ZdLnkgfSk7IGNvbnRpbnVlOyB9CiAgICAgIC8vIE9VVFdBUkQgbm9ybWFsID0gLWlud2FyZAogICAgICB2YXIgbjF4ID0gZTF5IC8gbDEgKiB3aW5kaW5nLCBuMXkgPSAtZTF4IC8gbDEgKiB3aW5kaW5nOwogICAgICB2YXIgbjJ4ID0gZTJ5IC8gbDIgKiB3aW5kaW5nLCBuMnkgPSAtZTJ4IC8gbDIgKiB3aW5kaW5nOwogICAgICB2YXIgYnh2ID0gbjF4ICsgbjJ4LCBieXYgPSBuMXkgKyBuMnk7CiAgICAgIHZhciBibCA9IE1hdGguc3FydChieHYqYnh2ICsgYnl2KmJ5dik7CiAgICAgIGlmKGJsIDwgMWUtNil7IG91dC5wdXNoKHsgeDogYlt2XS54ICsgbjF4ICogb3V0c2lkZUJ1ZmZlck0sIHk6IGJbdl0ueSArIG4xeSAqIG91dHNpZGVCdWZmZXJNIH0pOyBjb250aW51ZTsgfQogICAgICB2YXIgY29zRnVsbCA9IG4xeCAqIG4yeCArIG4xeSAqIG4yeTsKICAgICAgdmFyIHNpbkhhbGYgPSBNYXRoLnNxcnQoKDEgLSBjb3NGdWxsKSAqIDAuNSk7CiAgICAgIGlmKHNpbkhhbGYgPCAwLjEpIHNpbkhhbGYgPSAwLjE7CiAgICAgIG91dC5wdXNoKHsgeDogYlt2XS54ICsgKGJ4diAvIGJsKSAqIChvdXRzaWRlQnVmZmVyTSAvIHNpbkhhbGYpLCB5OiBiW3ZdLnkgKyAoYnl2IC8gYmwpICogKG91dHNpZGVCdWZmZXJNIC8gc2luSGFsZikgfSk7CiAgICB9CiAgICByZXR1cm4gb3V0OwogIH0KCiAgLy8gUmV0dXJucyB7eDAsIHkwLCB4MSwgeTF9IG9yaWVudGVkIHNvIGNvb3Jkc1swXSBpcyB0aGUgbG93ZXIgYWxvbmctYXhpcyBwcm9qZWN0aW9uLgogIGZ1bmN0aW9uIG9yaWVudFNlZyhzZWcsIGF4aXMpewogICAgdmFyIHAwQWxvbmcgPSBzZWcueDAgKiBheGlzLnV4ICsgc2VnLnkwICogYXhpcy51eTsKICAgIHZhciBwMUFsb25nID0gc2VnLngxICogYXhpcy51eCArIHNlZy55MSAqIGF4aXMudXk7CiAgICBpZihwMEFsb25nIDw9IHAxQWxvbmcpIHJldHVybiBzZWc7CiAgICByZXR1cm4geyB4MDogc2VnLngxLCB5MDogc2VnLnkxLCB4MTogc2VnLngwLCB5MTogc2VnLnkwLCBraW5kOiBzZWcua2luZCwgc2FtcGxlczogc2VnLnNhbXBsZXMgfTsKICB9CgogIC8vIFJ1bGUgwqcxNCBoZWxwZXIg4oCUIHNhbXBsZSB0aGUgc3RyYWlnaHQgY2hvcmQgYmV0d2VlbiB0d28gcG9pbnRzIGFuZCBjaGVjawogIC8vIGV2ZXJ5IHNhbXBsZSBpcyBpbnNpZGUgYHBvbHlgLiBVc2VkIHRvIHZhbGlkYXRlIGEgdHJhdmVyc2UgYmVmb3JlCiAgLy8gYWNjZXB0aW5nIGl0OyBpZiBmYWxzZSwgdGhlIG9wZXJhdG9yIHdvdWxkIGxlYXZlIHRoZSBmaWVsZCBib3VuZGFyeS4KICBmdW5jdGlvbiB0cmF2ZXJzZUluc2lkZUJvdW5kYXJ5KHAxLCBwMiwgcG9seSl7CiAgICB2YXIgTiA9IDEyOwogICAgZm9yKHZhciBpPTE7IGk8TjsgaSsrKXsKICAgICAgdmFyIHQgPSBpIC8gTjsKICAgICAgdmFyIHggPSBwMS54ICsgKHAyLnggLSBwMS54KSAqIHQ7CiAgICAgIHZhciB5ID0gcDEueSArIChwMi55IC0gcDEueSkgKiB0OwogICAgICBpZighcG9pbnRJblBvbHkoeCwgeSwgcG9seSkpIHJldHVybiBmYWxzZTsKICAgIH0KICAgIHJldHVybiB0cnVlOwogIH0KICAvLyBSb3V0ZSBmcm9tIHAxIHRvIHAyIGFsb25nIHRoZSBoZWFkbGFuZC1yaW5nIHBlcmltZXRlciDigJQgdGhlIGFncm9ub21pY2FsbHkKICAvLyBjb3JyZWN0IHBhdGggd2hlbiB0aGUgc3RyYWlnaHQgY2hvcmQgd291bGQgZXhpdCB0aGUgYm91bmRhcnkuIEZpbmRzIHRoZQogIC8vIGNsb3Nlc3QgcmluZyB2ZXJ0ZXggdG8gZWFjaCBlbmRwb2ludCwgd2Fsa3MgdGhlIHJpbmcgaW4gdGhlIHNob3J0ZXIKICAvLyBkaXJlY3Rpb24uIFJldHVybnMgdGhlIGZ1bGwgdmVydGV4IHNlcXVlbmNlIFtwMSwgcmluZ1ZlcnRzLi4uLCBwMl0gb3IKICAvLyBbcDEsIHAyXSBpZiBubyByaW5nIGlzIGF2YWlsYWJsZS4KICBmdW5jdGlvbiByb3V0ZUFsb25nUmluZyhwMSwgcDIsIHJpbmdQYXNzZXMpewogICAgaWYoIXJpbmdQYXNzZXMgPyB0cnVlIDogcmluZ1Bhc3Nlcy5sZW5ndGggPT09IDApIHJldHVybiBbcDEsIHAyXTsKICAgIHZhciByaW5nID0gcmluZ1Bhc3Nlc1swXS5zYW1wbGVzOwogICAgaWYoIXJpbmcgPyB0cnVlIDogcmluZy5sZW5ndGggPCA0KSByZXR1cm4gW3AxLCBwMl07CiAgICAvLyBDbG9zZWQtbG9vcDogbGFzdCBzYW1wbGUgPT0gZmlyc3Qgc2FtcGxlOyB3b3JrIHdpdGggdW5pcXVlIHZlcnRpY2VzIG9ubHkuCiAgICB2YXIgTiA9IHJpbmcubGVuZ3RoIC0gKHJpbmdbMF0ueCA9PT0gcmluZ1tyaW5nLmxlbmd0aC0xXS54ID8gcmluZ1swXS55ID09PSByaW5nW3JpbmcubGVuZ3RoLTFdLnkgPyAxIDogMCA6IDApOwogICAgZnVuY3Rpb24gbmVhcmVzdElkeChwKXsKICAgICAgdmFyIGJlc3QgPSAwLCBiZXN0RCA9IEluZmluaXR5OwogICAgICBmb3IodmFyIGk9MDsgaTxOOyBpKyspewogICAgICAgIHZhciBkeCA9IHJpbmdbaV0ueCAtIHAueCwgZHkgPSByaW5nW2ldLnkgLSBwLnk7CiAgICAgICAgdmFyIGQgPSBkeCpkeCArIGR5KmR5OwogICAgICAgIGlmKGQgPCBiZXN0RCl7IGJlc3REID0gZDsgYmVzdCA9IGk7IH0KICAgICAgfQogICAgICByZXR1cm4gYmVzdDsKICAgIH0KICAgIHZhciBpMSA9IG5lYXJlc3RJZHgocDEpOwogICAgdmFyIGkyID0gbmVhcmVzdElkeChwMik7CiAgICBpZihpMSA9PT0gaTIpIHJldHVybiBbcDEsIHJpbmdbaTFdLCBwMl07CiAgICAvLyBDb21wdXRlIGRpc3RhbmNlIHdhbGtpbmcgZm9yd2FyZCAoaTEg4oaSIGkyKSBhbmQgYmFja3dhcmQgKGkxIOKGkiBpMiB0aGUgb3RoZXIgd2F5KQogICAgZnVuY3Rpb24gcmluZ0Rpc3QoZnJvbSwgdG8pewogICAgICB2YXIgZCA9IDA7CiAgICAgIHZhciBrID0gZnJvbTsKICAgICAgd2hpbGUoayAhPT0gdG8pewogICAgICAgIHZhciBrTmV4dCA9IChrICsgMSkgJSBOOwogICAgICAgIHZhciBkeCA9IHJpbmdba05leHRdLnggLSByaW5nW2tdLngsIGR5ID0gcmluZ1trTmV4dF0ueSAtIHJpbmdba10ueTsKICAgICAgICBkICs9IE1hdGguc3FydChkeCpkeCArIGR5KmR5KTsKICAgICAgICBrID0ga05leHQ7CiAgICAgIH0KICAgICAgcmV0dXJuIGQ7CiAgICB9CiAgICB2YXIgZndkID0gcmluZ0Rpc3QoaTEsIGkyKTsKICAgIHZhciBid2QgPSByaW5nRGlzdChpMiwgaTEpOwogICAgdmFyIHBhdGggPSBbcDEsIHJpbmdbaTFdXTsKICAgIGlmKGZ3ZCA8PSBid2QpewogICAgICB2YXIgayA9IChpMSArIDEpICUgTjsKICAgICAgd2hpbGUoayAhPT0gaTIpeyBwYXRoLnB1c2gocmluZ1trXSk7IGsgPSAoayArIDEpICUgTjsgfQogICAgfSBlbHNlIHsKICAgICAgdmFyIGsyID0gKGkxIC0gMSArIE4pICUgTjsKICAgICAgd2hpbGUoazIgIT09IGkyKXsgcGF0aC5wdXNoKHJpbmdbazJdKTsgazIgPSAoazIgLSAxICsgTikgJSBOOyB9CiAgICB9CiAgICBwYXRoLnB1c2gocmluZ1tpMl0pOwogICAgcGF0aC5wdXNoKHAyKTsKICAgIHJldHVybiBwYXRoOwogIH0KCiAgLy8gQnVpbGQgc2VycGVudGluZSBkcml2ZSBwYXRoOiBzbmFrZSB0aHJvdWdoIHBhc3NlcywgZ2VuZXJhdGUgdmFsaWRhdGVkIHR1cm4KICAvLyBhcmNzIGJldHdlZW4gY29uc2VjdXRpdmUgZW5kcG9pbnRzLiBSZXR1cm5zIHsgZHJpdmVDb29yZHMsIHR1cm5BcmNzLCB3YXJuaW5nIH0uCiAgZnVuY3Rpb24gYnVpbGRTZXJwZW50aW5lKHBhc3NlcywgZHJpdmFibGUsIGludGVyaW9yLCBheGlzLCB0dXJuU3R5bGUsIHR1cm5SYWRpdXNNLCBoYWxmSW1wbGVtZW50TSwgd00pewogICAgaWYoIXBhc3NlcyA\/IHRydWUgOiBwYXNzZXMubGVuZ3RoID09PSAwKSByZXR1cm4geyBkcml2ZUNvb3JkczogW10sIHR1cm5BcmNzOiBbXSwgd2FybmluZzogbnVsbCB9OwogICAgLy8gU2VwYXJhdGUgaGVhZGxhbmQtcmluZyBwYXNzZXMgKHJ1bGUgwqcxMyDigJQgZHJpdmVuIGZpcnN0IGFzIGNsb3NlZCBsb29wcywKICAgIC8vIG5vIHNlcnBlbnRpbmUsIG5vIHR1cm4gYXJjcykgZnJvbSBib2R5IHBhc3NlcyB0aGF0IGdvIHRocm91Z2ggc2VycGVudGluZS4KICAgIHZhciByaW5nUGFzc2VzID0gW107CiAgICB2YXIgYm9keVBhc3NlcyA9IFtdOwogICAgZm9yKHZhciByaT0wOyByaTxwYXNzZXMubGVuZ3RoOyByaSsrKXsKICAgICAgaWYocGFzc2VzW3JpXS5raW5kID09PSAnaGVhZGxhbmQtcmluZycpIHJpbmdQYXNzZXMucHVzaChwYXNzZXNbcmldKTsKICAgICAgZWxzZSBib2R5UGFzc2VzLnB1c2gocGFzc2VzW3JpXSk7CiAgICB9CiAgICAvLyBPcmllbnQgKyBzb3J0IEJPRFkgcGFzc2VzIGJ5IGFsb25nLWF4aXMgcG9zaXRpb24gb2YgbWlkcG9pbnQKICAgIHZhciBvcmllbnQgPSBib2R5UGFzc2VzLm1hcChmdW5jdGlvbihwKXsKICAgICAgaWYocC5zYW1wbGVzKXsKICAgICAgICB2YXIgZmlyc3QgPSBwLnNhbXBsZXNbMF0sIGxhc3QgPSBwLnNhbXBsZXNbcC5zYW1wbGVzLmxlbmd0aCAtIDFdOwogICAgICAgIHZhciBhMCA9IGZpcnN0LnggKiBheGlzLnV4ICsgZmlyc3QueSAqIGF4aXMudXk7CiAgICAgICAgdmFyIGExID0gbGFzdC54ICogYXhpcy51eCArIGxhc3QueSAqIGF4aXMudXk7CiAgICAgICAgaWYoYTAgPD0gYTEpIHJldHVybiB7IHNhbXBsZXM6IHAuc2FtcGxlcyB9OwogICAgICAgIHZhciByZXYgPSBwLnNhbXBsZXMuc2xpY2UoKS5yZXZlcnNlKCk7CiAgICAgICAgcmV0dXJuIHsgc2FtcGxlczogcmV2IH07CiAgICAgIH0KICAgICAgcmV0dXJuIG9yaWVudFNlZyhwLCBheGlzKTsKICAgIH0pOwogICAgb3JpZW50LnNvcnQoZnVuY3Rpb24oYSwgYil7CiAgICAgIHZhciBheCA9IGEuc2FtcGxlcyA\/IGEuc2FtcGxlc1swXS54IDogYS54MDsKICAgICAgdmFyIGF5ID0gYS5zYW1wbGVzID8gYS5zYW1wbGVzWzBdLnkgOiBhLnkwOwogICAgICB2YXIgYnggPSBiLnNhbXBsZXMgPyBiLnNhbXBsZXNbMF0ueCA6IGIueDA7CiAgICAgIHZhciBieSA9IGIuc2FtcGxlcyA\/IGIuc2FtcGxlc1swXS55IDogYi55MDsKICAgICAgdmFyIGFwID0gLWF4ICogYXhpcy51eSArIGF5ICogYXhpcy51eDsKICAgICAgdmFyIGJwID0gLWJ4ICogYXhpcy51eSArIGJ5ICogYXhpcy51eDsKICAgICAgcmV0dXJuIGFwIC0gYnA7CiAgICB9KTsKICAgIHZhciBkcml2ZUNvb3JkcyA9IFtdOwogICAgdmFyIHR1cm5BcmNzID0gW107CiAgICB2YXIgd2FybmluZyA9IG51bGw7CiAgICB2YXIgb3JkZXJlZFBhc3NlcyA9IFtdOyAgLy8gYm9keSBwYXNzZXMgaW4gYWN0dWFsIGRyaXZlIGRpcmVjdGlvbiAocG9zdC1zbmFrZSkKICAgIC8vIEhlYWRsYW5kIHJpbmcocykgRklSU1Qg4oCUIGNsb3NlZC1sb29wIHRyYXZlcnNhbCwgbm8gc2VycGVudGluZSwgbm8gYXJjcwogICAgZm9yKHZhciByZz0wOyByZzxyaW5nUGFzc2VzLmxlbmd0aDsgcmcrKyl7CiAgICAgIHZhciByaW5nU2FtcHMgPSByaW5nUGFzc2VzW3JnXS5zYW1wbGVzOwogICAgICBmb3IodmFyIHJzPTA7IHJzPHJpbmdTYW1wcy5sZW5ndGg7IHJzKyspIGRyaXZlQ29vcmRzLnB1c2gocmluZ1NhbXBzW3JzXSk7CiAgICB9CiAgICAvLyBCb2R5IHBhc3NlcyDigJQgc2VycGVudGluZSB3aXRoIHZhbGlkYXRlZCBVLXR1cm4gYXJjcyBiZXR3ZWVuIHRoZW0KICAgIGZvcih2YXIgaT0wOyBpPG9yaWVudC5sZW5ndGg7IGkrKyl7CiAgICAgIHZhciBwID0gb3JpZW50W2ldOwogICAgICB2YXIgcmV2MiA9IGkgJSAyID09PSAxOwogICAgICB2YXIgZmlyc3QyLCBsYXN0MjsKICAgICAgaWYocC5zYW1wbGVzKXsKICAgICAgICB2YXIgc2FtcHMgPSByZXYyID8gcC5zYW1wbGVzLnNsaWNlKCkucmV2ZXJzZSgpIDogcC5zYW1wbGVzOwogICAgICAgIGZvcih2YXIgcz0wOyBzPHNhbXBzLmxlbmd0aDsgcysrKSBkcml2ZUNvb3Jkcy5wdXNoKHNhbXBzW3NdKTsKICAgICAgICBmaXJzdDIgPSBzYW1wc1swXTsgbGFzdDIgPSBzYW1wc1tzYW1wcy5sZW5ndGggLSAxXTsKICAgICAgICBvcmRlcmVkUGFzc2VzLnB1c2goeyBzYW1wbGVzOiBzYW1wcywga2luZDogcC5raW5kIH0pOwogICAgICB9IGVsc2UgewogICAgICAgIGlmKHJldjIpewogICAgICAgICAgZHJpdmVDb29yZHMucHVzaCh7IHg6IHAueDEsIHk6IHAueTEgfSk7CiAgICAgICAgICBkcml2ZUNvb3Jkcy5wdXNoKHsgeDogcC54MCwgeTogcC55MCB9KTsKICAgICAgICAgIGZpcnN0MiA9IHsgeDogcC54MSwgeTogcC55MSB9OyBsYXN0MiA9IHsgeDogcC54MCwgeTogcC55MCB9OwogICAgICAgICAgb3JkZXJlZFBhc3Nlcy5wdXNoKHsgeDA6IHAueDEsIHkwOiBwLnkxLCB4MTogcC54MCwgeTE6IHAueTAsIGtpbmQ6IHAua2luZCB9KTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgZHJpdmVDb29yZHMucHVzaCh7IHg6IHAueDAsIHk6IHAueTAgfSk7CiAgICAgICAgICBkcml2ZUNvb3Jkcy5wdXNoKHsgeDogcC54MSwgeTogcC55MSB9KTsKICAgICAgICAgIGZpcnN0MiA9IHsgeDogcC54MCwgeTogcC55MCB9OyBsYXN0MiA9IHsgeDogcC54MSwgeTogcC55MSB9OwogICAgICAgICAgb3JkZXJlZFBhc3Nlcy5wdXNoKHsgeDA6IHAueDAsIHkwOiBwLnkwLCB4MTogcC54MSwgeTE6IHAueTEsIGtpbmQ6IHAua2luZCB9KTsKICAgICAgICB9CiAgICAgIH0KICAgICAgaWYodHVyblN0eWxlID09PSAnbm9uZScgPyBmYWxzZSA6IChpICsgMSA8IG9yaWVudC5sZW5ndGgpKXsKICAgICAgICB2YXIgbmV4dFAgPSBvcmllbnRbaSArIDFdOwogICAgICAgIHZhciBuZXh0UmV2ID0gKGkgKyAxKSAlIDIgPT09IDE7CiAgICAgICAgdmFyIG5leHRTdGFydDsKICAgICAgICBpZihuZXh0UC5zYW1wbGVzKXsKICAgICAgICAgIHZhciBuZXh0U2FtcHMgPSBuZXh0UmV2ID8gbmV4dFAuc2FtcGxlcy5zbGljZSgpLnJldmVyc2UoKSA6IG5leHRQLnNhbXBsZXM7CiAgICAgICAgICBuZXh0U3RhcnQgPSBuZXh0U2FtcHNbMF07CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIG5leHRTdGFydCA9IG5leHRSZXYgPyB7IHg6IG5leHRQLngxLCB5OiBuZXh0UC55MSB9IDogeyB4OiBuZXh0UC54MCwgeTogbmV4dFAueTAgfTsKICAgICAgICB9CiAgICAgICAgdmFyIHR1cm4gPSBidWlsZFR1cm5BcmMobGFzdDIsIG5leHRTdGFydCwgZHJpdmFibGUsIGludGVyaW9yLCB0dXJuU3R5bGUsIHR1cm5SYWRpdXNNLCBoYWxmSW1wbGVtZW50TSwgd00pOwogICAgICAgIGlmKHR1cm4uY29vcmRzID8gdHVybi5jb29yZHMubGVuZ3RoID4gMSA6IGZhbHNlKXsKICAgICAgICAgIGZvcih2YXIgdGM9MTsgdGM8dHVybi5jb29yZHMubGVuZ3RoOyB0YysrKSBkcml2ZUNvb3Jkcy5wdXNoKHR1cm4uY29vcmRzW3RjXSk7CiAgICAgICAgICB0dXJuQXJjcy5wdXNoKHsgY29vcmRzOiB0dXJuLmNvb3Jkcywgb2s6IHR1cm4ub2ssIGtpbmQ6IHR1cm4uc3R5bGUgfSk7CiAgICAgICAgICBpZighdHVybi5vayA\/ICF3YXJuaW5nIDogZmFsc2UpIHdhcm5pbmcgPSB0dXJuLnJlYXNvbjsKICAgICAgICB9IGVsc2UgaWYodHVybi5zdHlsZSA9PT0gJ3RyYXZlcnNlJyl7CiAgICAgICAgICAvLyBMb25nLWNob3JkIGNhc2UgT1IgbGFzdC1yZXNvcnQgbm8tYXJjLWZpdHMgY2FzZTogcm91dGUgdGhlCiAgICAgICAgICAvLyBvcGVyYXRvciBhY3Jvc3MgdGhlIHdvcmtlZCBoZWFkbGFuZC4gUnVsZSDCpzE0IOKAlCB0aGUgc3RyYWlnaHQKICAgICAgICAgIC8vIGNob3JkIG1heSBleGl0IHRoZSBmaWVsZCBib3VuZGFyeSBpZiBpdCBjdXRzIGFjcm9zcyBhIGNvbmNhdmUKICAgICAgICAgIC8vIGRlbnQgKGUuZy4gdGhlIEwtc2hhcGUncyBub3RjaCkgb3IgYSBjdXJ2ZWQgYm91bmRhcnkuIFNhbXBsZQogICAgICAgICAgLy8gdGhlIGNob3JkOyBpZiBhbnkgcG9pbnQgaXMgb3V0c2lkZSBgZHJpdmFibGVgLCByb3V0ZSBhbG9uZyB0aGUKICAgICAgICAgIC8vIGhlYWRsYW5kIHJpbmcgaW5zdGVhZC4gT3RoZXJ3aXNlIHVzZSB0aGUgc3RyYWlnaHQgY2hvcmQuCiAgICAgICAgICB2YXIgc3RyYWlnaHRPSyA9IHRyYXZlcnNlSW5zaWRlQm91bmRhcnkobGFzdDIsIG5leHRTdGFydCwgZHJpdmFibGUpOwogICAgICAgICAgdmFyIHRyYXZlcnNlQ29vcmRzID0gc3RyYWlnaHRPSwogICAgICAgICAgICA\/IFtsYXN0MiwgbmV4dFN0YXJ0XQogICAgICAgICAgICA6IHJvdXRlQWxvbmdSaW5nKGxhc3QyLCBuZXh0U3RhcnQsIHJpbmdQYXNzZXMpOwogICAgICAgICAgaWYodHJhdmVyc2VDb29yZHMubGVuZ3RoID49IDIpewogICAgICAgICAgICBmb3IodmFyIHRjMj0xOyB0YzI8dHJhdmVyc2VDb29yZHMubGVuZ3RoOyB0YzIrKykgZHJpdmVDb29yZHMucHVzaCh0cmF2ZXJzZUNvb3Jkc1t0YzJdKTsKICAgICAgICAgICAgdHVybkFyY3MucHVzaCh7IGNvb3JkczogdHJhdmVyc2VDb29yZHMsIG9rOiB0cnVlLCBraW5kOiBzdHJhaWdodE9LID8gJ3RyYXZlcnNlJyA6ICdyaW5nLXJvdXRlJyB9KTsKICAgICAgICAgICAgLy8gU3VyZmFjZSB0aGUgbGFzdC1yZXNvcnQgcmVhc29uIHNvIHRoZSB1c2VyIHNlZXMgd2h5CiAgICAgICAgICAgIGlmKHR1cm4ucmVhc29uID8gIXdhcm5pbmcgOiBmYWxzZSkgd2FybmluZyA9IHR1cm4ucmVhc29uOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfQogICAgcmV0dXJuIHsgZHJpdmVDb29yZHM6IGRyaXZlQ29vcmRzLCB0dXJuQXJjczogdHVybkFyY3MsIHdhcm5pbmc6IHdhcm5pbmcsIG9yZGVyZWRQYXNzZXM6IG9yZGVyZWRQYXNzZXMgfTsKICB9CgogIC8vIEdlbmVyYXRlIGd1aWRhbmNlIGxheW91dCBmb3Igb25lIGFwcHJvYWNoLiBSZXR1cm5zOgogIC8vICAgeyBwYXNzZXM6IFsuLi5dLCBoZWFkbGFuZFBvbHksIGludGVyaW9yUG9seSwgZHJpdmFibGUsIHR1cm5BcmNzLCBkcml2ZVBhdGgsIHdhcm5pbmcgfQogIC8vIFRoZSBzbWFydCBwaXBlbGluZToKICAvLyAgIDEuIGRyaXZhYmxlID0gYm91bmRhcnkgKyBvdXRzaWRlQnVmZmVyTSBvdXR3YXJkCiAgLy8gICAyLiBpbnRlcmlvciA9IGJvdW5kYXJ5IGlud2FyZC1vZmZzZXQgYnkgaGVhZGxhbmRNICh0aGUgd29ya2VkIHpvbmUpCiAgLy8gICAzLiBoZWFkbGFuZCA9IGJvdW5kYXJ5IG1pbnVzIGludGVyaW9yICh0aGUgdHVybmFyb3VuZCB6b25lKQogIC8vICAgNC4gUGFzc2VzIGNsaXBwZWQgdG8gSU5URVJJT1IgKG5vdCBmdWxsIGJvdW5kYXJ5KSDigJQgZW5kcG9pbnRzIHNpdCBvbiB0aGUKICAvLyAgICAgIGlubmVyIGVkZ2Ugb2YgdGhlIGhlYWRsYW5kIGJ5IGNvbnN0cnVjdGlvbgogIC8vICAgNS4gU2VycGVudGluZSB0aHJvdWdoIHBhc3NlcywgZ2VuZXJhdGluZyB0dXJuIGFyY3MgdGhhdCBidWxnZSBPVVRXQVJECiAgLy8gICAgICBpbnRvIHRoZSBoZWFkbGFuZCBzdHJpcCB2aWEgdGhlIHZhbGlkYXRpb24gY2FzY2FkZQogIC8vIEZvciAnYm91bmRhcnknIGFwcHJvYWNoOiBza2lwIGludGVyaW9yIHBhc3NlcywgZ2VuZXJhdGUgb25seSB0aGUgaGVhZGxhbmQtCiAgLy8gZm9sbG93aW5nIHJpbmcocykg4oCUIHVzZWZ1bCBmb3Igb3JjaGFyZHMgLyBncmFzc2xhbmRzIHdoZXJlIHRoZSBmaWVsZCBpcwogIC8vIHdvcmtlZCBhbG9uZyBpdHMgcGVyaW1ldGVyLgogIC8vIFRyYWNlIGEgc2luZ2xlIGNvbnRvdXIgbGluZSBhdCBjb25zdGFudCBlbGV2YXRpb24gdXNpbmcgYSBwcmVkaWN0b3ItCiAgLy8gY29ycmVjdG9yIHNjaGVtZS4gRWFjaCBzdGVwOgogIC8vICAgUFJFRElDVCDigJQgbW92ZSBzdGVwTSBwZXJwZW5kaWN1bGFyIHRvIHRoZSBsb2NhbCBncmFkaWVudC4KICAvLyAgIENPUlJFQ1Qg4oCUIHNhbXBsZSBlbGV2YXRpb24gYXQgdGhlIG5ldyBwb2ludCwgbW92ZSBhbG9uZyB0aGUgZ3JhZGllbnQKICAvLyAgICAgICAgICAgICBieSAoKHRhcmdldFogLSBjdXJyZW50WikgLyB8Z3JhZGllbnR8KSB0byByZXN0b3JlIHRoZSB0YXJnZXQKICAvLyAgICAgICAgICAgICBlbGV2YXRpb24uIEtlZXBzIHRoZSBwYXRoIG9uIHRoZSBjb250b3VyIGV2ZW4gd2hlbiB0aGUKICAvLyAgICAgICAgICAgICB0ZXJyYWluIGZ1bmN0aW9uIGlzIG5vbi1saW5lYXIgKGUuZy4gYSBjaXJjdWxhciBoaWxsIG9uIHRoZQogIC8vICAgICAgICAgICAgIHBpdm90IGZpZWxkIHdvdWxkIG90aGVyd2lzZSBkcmlmdCBvZmYtbGV2ZWwgYnkgc3RlcCA1MCkuCiAgLy8gV2Fsa3MgaW4gYGRpcmAgKMKxMSkgdW50aWwgaXQgZXhpdHMgYGNsaXBQb2x5YCBvciBoaXRzIG1heFN0ZXBzLiBSZXR1cm5zCiAgLy8gc2FtcGxlIHBvaW50cy4KICBmdW5jdGlvbiB3YWxrQ29udG91cihzdGFydCwgZGlyLCBjbGlwUG9seSwgc3RlcE0sIG1heFN0ZXBzKXsKICAgIHZhciBwdHMgPSBbeyB4OiBzdGFydC54LCB5OiBzdGFydC55IH1dOwogICAgdmFyIGVwcyA9IDAuNTsKICAgIHZhciB0YXJnZXRaID0gdGVycmFpbkF0KHN0YXJ0LngsIHN0YXJ0LnkpOwogICAgdmFyIHByZXZQeCA9IG51bGwsIHByZXZQeSA9IG51bGw7CiAgICB2YXIgY2xvc2VSYWRpdXMgPSBzdGVwTSAqIDEuNTsKICAgIHZhciBjbG9zZVJhZGl1c1NxID0gY2xvc2VSYWRpdXMgKiBjbG9zZVJhZGl1czsKICAgIGZvcih2YXIgcz0wOyBzPG1heFN0ZXBzOyBzKyspewogICAgICAvLyBMb29wIGRldGVjdGlvbiDigJQgZm9yIGNsb3NlZCBjb250b3VycyAoZS5nLiBhIGNpcmNsZSBhcm91bmQgYSBoaWxsCiAgICAgIC8vIHBlYWspLCB0aGUgd2Fsa2VyIHdvdWxkIG90aGVyd2lzZSBzcGluIGZvcmV2ZXIuIFN0b3Agb25jZSB3ZSd2ZQogICAgICAvLyBjb21lIGJhY2sgd2l0aGluIHN0ZXBNIMOXIDEuNSBvZiB0aGUgc2VlZCBhZnRlciBhdCBsZWFzdCAxMCBzdGVwcy4KICAgICAgLy8gcHRzLl9jbG9zZWQgZmxhZyB0ZWxscyB0aGUgY2FsbGVyIHRoaXMgY29udG91ciB3cmFwcGVkIGFyb3VuZC4KICAgICAgaWYocyA+IDEwKXsKICAgICAgICB2YXIgZHhTID0gcHRzW3B0cy5sZW5ndGgtMV0ueCAtIHN0YXJ0Lng7CiAgICAgICAgdmFyIGR5UyA9IHB0c1twdHMubGVuZ3RoLTFdLnkgLSBzdGFydC55OwogICAgICAgIGlmKGR4UypkeFMgKyBkeVMqZHlTIDwgY2xvc2VSYWRpdXNTcSl7IHB0cy5wdXNoKHsgeDogc3RhcnQueCwgeTogc3RhcnQueSB9KTsgcHRzLl9jbG9zZWQgPSB0cnVlOyBicmVhazsgfQogICAgICB9CiAgICAgIHZhciBsYXN0ID0gcHRzW3B0cy5sZW5ndGggLSAxXTsKICAgICAgLy8gTnVtZXJpY2FsIGdyYWRpZW50IHZpYSBjZW50cmFsIGRpZmZlcmVuY2VzCiAgICAgIHZhciBneCA9ICh0ZXJyYWluQXQobGFzdC54ICsgZXBzLCBsYXN0LnkpIC0gdGVycmFpbkF0KGxhc3QueCAtIGVwcywgbGFzdC55KSkgLyAoMiAqIGVwcyk7CiAgICAgIHZhciBneSA9ICh0ZXJyYWluQXQobGFzdC54LCBsYXN0LnkgKyBlcHMpIC0gdGVycmFpbkF0KGxhc3QueCwgbGFzdC55IC0gZXBzKSkgLyAoMiAqIGVwcyk7CiAgICAgIHZhciBnTGVuMiA9IGd4Kmd4ICsgZ3kqZ3k7CiAgICAgIGlmKGdMZW4yIDwgMWUtMTIpIGJyZWFrOwogICAgICB2YXIgZ0xlbiA9IE1hdGguc3FydChnTGVuMik7CiAgICAgIC8vIFByZWRpY3RvcjogcGVycGVuZGljdWxhciB0byBncmFkaWVudCAocm90YXRlZCA5MMKwKSwgbm9ybWFsaXplZAogICAgICB2YXIgcHggPSAtZ3kgLyBnTGVuICogZGlyOwogICAgICB2YXIgcHkgPSBneCAvIGdMZW4gKiBkaXI7CiAgICAgIC8vIFNtb290aCBkaXJlY3Rpb24gc28gdGhlIGN1cnZlIGRvZXNuJ3QgcGluZy1wb25nIG9uIG5vaXN5IHRlcnJhaW4KICAgICAgaWYocHJldlB4ICE9PSBudWxsKXsKICAgICAgICBweCA9IHB4ICogMC43ICsgcHJldlB4ICogMC4zOwogICAgICAgIHB5ID0gcHkgKiAwLjcgKyBwcmV2UHkgKiAwLjM7CiAgICAgICAgdmFyIHBsID0gTWF0aC5zcXJ0KHB4KnB4ICsgcHkqcHkpOwogICAgICAgIGlmKHBsID4gMWUtNil7IHB4IC89IHBsOyBweSAvPSBwbDsgfQogICAgICB9CiAgICAgIHByZXZQeCA9IHB4OyBwcmV2UHkgPSBweTsKICAgICAgdmFyIG54ID0gbGFzdC54ICsgcHggKiBzdGVwTTsKICAgICAgdmFyIG55ID0gbGFzdC55ICsgcHkgKiBzdGVwTTsKICAgICAgLy8gQ29ycmVjdG9yOiBudWRnZSBiYWNrIHRvIHRhcmdldCBlbGV2YXRpb24gYWxvbmcgdGhlIGxvY2FsIGdyYWRpZW50CiAgICAgIHZhciBueiA9IHRlcnJhaW5BdChueCwgbnkpOwogICAgICB2YXIgZHogPSB0YXJnZXRaIC0gbno7CiAgICAgIHZhciBnTWFnMnggPSAodGVycmFpbkF0KG54ICsgZXBzLCBueSkgLSB0ZXJyYWluQXQobnggLSBlcHMsIG55KSkgLyAoMiAqIGVwcyk7CiAgICAgIHZhciBnTWFnMnkgPSAodGVycmFpbkF0KG54LCBueSArIGVwcykgLSB0ZXJyYWluQXQobngsIG55IC0gZXBzKSkgLyAoMiAqIGVwcyk7CiAgICAgIHZhciBnTWFnMnNxID0gZ01hZzJ4KmdNYWcyeCArIGdNYWcyeSpnTWFnMnk7CiAgICAgIGlmKGdNYWcyc3EgPiAxZS0xMil7CiAgICAgICAgdmFyIGNvcnIgPSBkeiAvIGdNYWcyc3E7CiAgICAgICAgbnggKz0gZ01hZzJ4ICogY29ycjsKICAgICAgICBueSArPSBnTWFnMnkgKiBjb3JyOwogICAgICB9CiAgICAgIGlmKCFwb2ludEluUG9seShueCwgbnksIGNsaXBQb2x5KSkgYnJlYWs7CiAgICAgIHB0cy5wdXNoKHsgeDogbngsIHk6IG55IH0pOwogICAgfQogICAgcmV0dXJuIHB0czsKICB9CiAgLy8gQnVpbGQgY29udG91ci1mb2xsb3dpbmcgcGFzc2VzIGZyb20gdGhlIGFjdGl2ZSB0ZXJyYWluLiBTcGFjaW5nID0gd00KICAvLyAocGVycGVuZGljdWxhciBpbXBsZW1lbnQtd2lkdGgpLCBzbyBlYWNoIHBhc3MncyBzd2F0aCB0aWxlcyB0aGUgbmV4dC4KICAvLyBSZXR1cm5zIGFycmF5IG9mIHsgc2FtcGxlcywga2luZDogJ2FkYXB0aXZlJyB9IHBhc3NlcyBjbGlwcGVkIHRvCiAgLy8gYGNsaXBQb2x5YCAodGhlIGludGVyaW9yIHBvbHlnb24pLgogIGZ1bmN0aW9uIGJ1aWxkQ29udG91clBhc3Nlcyh3TSwgY2xpcFBvbHkpewogICAgLy8gMS4gRmluZCBlbGV2YXRpb24gcmFuZ2UgYWNyb3NzIGNsaXBQb2x5CiAgICB2YXIgc3RhdHMgPSBmaWVsZFN0YXRzKGNsaXBQb2x5KTsKICAgIHZhciBsbyA9IEluZmluaXR5LCBoaSA9IC1JbmZpbml0eTsKICAgIHZhciBzYW1wbGVOID0gMjQ7ICAvLyBzcGFyc2Ugc3dlZXAgdG8gZmluZCBsby9oaQogICAgdmFyIGR4UyA9IChzdGF0cy5tYXhYIC0gc3RhdHMubWluWCkgLyBzYW1wbGVOOwogICAgdmFyIGR5UyA9IChzdGF0cy5tYXhZIC0gc3RhdHMubWluWSkgLyBzYW1wbGVOOwogICAgZm9yKHZhciBpeT0wOyBpeTxzYW1wbGVOOyBpeSsrKXsKICAgICAgZm9yKHZhciBpeD0wOyBpeDxzYW1wbGVOOyBpeCsrKXsKICAgICAgICB2YXIgY3hTID0gc3RhdHMubWluWCArIChpeCArIDAuNSkgKiBkeFM7CiAgICAgICAgdmFyIGN5UyA9IHN0YXRzLm1pblkgKyAoaXkgKyAwLjUpICogZHlTOwogICAgICAgIGlmKCFwb2ludEluUG9seShjeFMsIGN5UywgY2xpcFBvbHkpKSBjb250aW51ZTsKICAgICAgICB2YXIgeiA9IHRlcnJhaW5BdChjeFMsIGN5Uyk7CiAgICAgICAgaWYoeiA8IGxvKSBsbyA9IHo7CiAgICAgICAgaWYoeiA+IGhpKSBoaSA9IHo7CiAgICAgIH0KICAgIH0KICAgIGlmKGhpIC0gbG8gPCAwLjMpIHJldHVybiBbXTsgIC8vIGVzc2VudGlhbGx5IGZsYXQg4oCUIG5vIHVzZWZ1bCBjb250b3VycwogICAgLy8gMi4gRXN0aW1hdGUgdHlwaWNhbCBncmFkaWVudCBtYWduaXR1ZGUgYWNyb3NzIHRoZSBmaWVsZC4gU2FtcGxpbmcgdGhlCiAgICAvLyAgICBjZW50cm9pZCBhbG9uZSBmYWlscyBmb3IgZmllbGRzIHdoZXJlIHRoZSBjZW50cm9pZCBzaXRzIG9uIGEgcGVhawogICAgLy8gICAgb3Igc2FkZGxlIChlLmcuIHBpdm90IOKAlCByb3VuZCBoaWxsIGF0IHRoZSBjZW50cmUg4oaSIOKIhz0wIHRoZXJlKS4KICAgIC8vICAgIFRha2UgOSBzYW1wbGVzIG9uIGEgM8OXMyBncmlkLCB1c2UgdGhlIG1lZGlhbiBtYWduaXR1ZGUuCiAgICB2YXIgZ3JhZFNhbXBsZXMgPSBbXTsKICAgIGZvcih2YXIgZ3hpPTA7IGd4aTwzOyBneGkrKyl7CiAgICAgIGZvcih2YXIgZ3lpPTA7IGd5aTwzOyBneWkrKyl7CiAgICAgICAgdmFyIHN4ID0gc3RhdHMubWluWCArIChneGkgKyAxKSAqIChzdGF0cy5tYXhYIC0gc3RhdHMubWluWCkgLyA0OwogICAgICAgIHZhciBzeSA9IHN0YXRzLm1pblkgKyAoZ3lpICsgMSkgKiAoc3RhdHMubWF4WSAtIHN0YXRzLm1pblkpIC8gNDsKICAgICAgICBpZighcG9pbnRJblBvbHkoc3gsIHN5LCBjbGlwUG9seSkpIGNvbnRpbnVlOwogICAgICAgIHZhciBneFMgPSAodGVycmFpbkF0KHN4ICsgMSwgc3kpIC0gdGVycmFpbkF0KHN4IC0gMSwgc3kpKSAqIDAuNTsKICAgICAgICB2YXIgZ3lTID0gKHRlcnJhaW5BdChzeCwgc3kgKyAxKSAtIHRlcnJhaW5BdChzeCwgc3kgLSAxKSkgKiAwLjU7CiAgICAgICAgZ3JhZFNhbXBsZXMucHVzaChNYXRoLnNxcnQoZ3hTKmd4UyArIGd5UypneVMpKTsKICAgICAgfQogICAgfQogICAgaWYoZ3JhZFNhbXBsZXMubGVuZ3RoID09PSAwKSByZXR1cm4gW107CiAgICBncmFkU2FtcGxlcy5zb3J0KGZ1bmN0aW9uKGEsIGIpeyByZXR1cm4gYSAtIGI7IH0pOwogICAgdmFyIGdNYWcgPSBncmFkU2FtcGxlc1tNYXRoLmZsb29yKGdyYWRTYW1wbGVzLmxlbmd0aCAvIDIpXTsgIC8vIG1lZGlhbgogICAgaWYoZ01hZyA8IDFlLTQpIHJldHVybiBbXTsgIC8vIHRydWx5IGZsYXQg4oaSIG5vIHVzZWZ1bCBjb250b3VycwogICAgdmFyIGVsZXZTdGVwID0gd00gKiBnTWFnOwogICAgLy8gMy4gUGljayBOIGxldmVscyBldmVubHkgYmV0d2VlbiBsbytlbGV2U3RlcC8yIGFuZCBoaS1lbGV2U3RlcC8yCiAgICB2YXIgbkxldmVscyA9IE1hdGgubWF4KDIsIE1hdGguZmxvb3IoKGhpIC0gbG8pIC8gZWxldlN0ZXApKTsKICAgIGlmKG5MZXZlbHMgPiA2MCkgbkxldmVscyA9IDYwOyAgLy8gY2FwIHRvIGF2b2lkIHBhdGhvbG9naWNhbCB0ZXJyYWluCiAgICB2YXIgbGV2ZWxzID0gW107CiAgICBmb3IodmFyIEw9MDsgTDxuTGV2ZWxzOyBMKyspewogICAgICBsZXZlbHMucHVzaChsbyArIChMICsgMC41KSAqIChoaSAtIGxvKSAvIG5MZXZlbHMpOwogICAgfQogICAgLy8gNC4gRm9yIGVhY2ggbGV2ZWwsIGZpbmQgYSBzZWVkIHBvaW50IGluc2lkZSBjbGlwUG9seSB3aXRoIHRlcnJhaW4g4omIIGxldmVsCiAgICAvLyAgICB0aGVuIHdhbGsgdGhlIGNvbnRvdXIgaW4gYm90aCBkaXJlY3Rpb25zLCBqb2luaW5nIGludG8gb25lIHBhc3MuCiAgICB2YXIgcGFzc2VzID0gW107CiAgICB2YXIgc2VlZEdyaWQgPSAzMjsKICAgIHZhciBzZHggPSAoc3RhdHMubWF4WCAtIHN0YXRzLm1pblgpIC8gc2VlZEdyaWQ7CiAgICB2YXIgc2R5ID0gKHN0YXRzLm1heFkgLSBzdGF0cy5taW5ZKSAvIHNlZWRHcmlkOwogICAgLy8gUHJlLXNhbXBsZSBvbiBhIGZpbmVyIGdyaWQgZm9yIHNlZWRzCiAgICB2YXIgc2VlZFogPSBuZXcgRmxvYXQzMkFycmF5KHNlZWRHcmlkICogc2VlZEdyaWQpOwogICAgdmFyIHNlZWRJbiA9IG5ldyBVaW50OEFycmF5KHNlZWRHcmlkICogc2VlZEdyaWQpOwogICAgZm9yKHZhciBpeTI9MDsgaXkyPHNlZWRHcmlkOyBpeTIrKyl7CiAgICAgIGZvcih2YXIgaXgyPTA7IGl4MjxzZWVkR3JpZDsgaXgyKyspewogICAgICAgIHZhciBjeDIgPSBzdGF0cy5taW5YICsgKGl4MiArIDAuNSkgKiBzZHg7CiAgICAgICAgdmFyIGN5MiA9IHN0YXRzLm1pblkgKyAoaXkyICsgMC41KSAqIHNkeTsKICAgICAgICBzZWVkWltpeTIgKiBzZWVkR3JpZCArIGl4Ml0gPSB0ZXJyYWluQXQoY3gyLCBjeTIpOwogICAgICAgIHNlZWRJbltpeTIgKiBzZWVkR3JpZCArIGl4Ml0gPSBwb2ludEluUG9seShjeDIsIGN5MiwgY2xpcFBvbHkpID8gMSA6IDA7CiAgICAgIH0KICAgIH0KICAgIHZhciBzdGVwTSA9IE1hdGgubWF4KDIsIHdNICogMC40KTsKICAgIHZhciBtYXhTdGVwcyA9IDgwMDsKICAgIGZvcih2YXIgbGk9MDsgbGk8bGV2ZWxzLmxlbmd0aDsgbGkrKyl7CiAgICAgIHZhciBsdiA9IGxldmVsc1tsaV07CiAgICAgIC8vIEZpbmQgdGhlIHNlZWQgY2VsbCB3aGVyZSBzZWVkWiBpcyBjbG9zZXN0IHRvIGx2IChhbW9uZyBpbi1maWVsZCBjZWxscykKICAgICAgdmFyIGJlc3RJZHggPSAtMSwgYmVzdERpZmYgPSBJbmZpbml0eTsKICAgICAgZm9yKHZhciBrPTA7IGs8c2VlZFoubGVuZ3RoOyBrKyspewogICAgICAgIGlmKCFzZWVkSW5ba10pIGNvbnRpbnVlOwogICAgICAgIHZhciBkaWZmID0gTWF0aC5hYnMoc2VlZFpba10gLSBsdik7CiAgICAgICAgaWYoZGlmZiA8IGJlc3REaWZmKXsgYmVzdERpZmYgPSBkaWZmOyBiZXN0SWR4ID0gazsgfQogICAgICB9CiAgICAgIGlmKGJlc3RJZHggPCAwKSBjb250aW51ZTsKICAgICAgdmFyIGl4UyA9IGJlc3RJZHggJSBzZWVkR3JpZDsKICAgICAgdmFyIGl5UyA9IE1hdGguZmxvb3IoYmVzdElkeCAvIHNlZWRHcmlkKTsKICAgICAgdmFyIHNlZWQgPSB7IHg6IHN0YXRzLm1pblggKyAoaXhTICsgMC41KSAqIHNkeCwgeTogc3RhdHMubWluWSArIChpeVMgKyAwLjUpICogc2R5IH07CiAgICAgIC8vIFdhbGsgZm9yd2FyZCBmaXJzdC4gSWYgaXQgcmV0dXJucyBhIGNsb3NlZCBsb29wLCB0aGUgY29udG91ciBpcwogICAgICAvLyBjbG9zZWQgKGUuZy4gY2lyY3VsYXIgaGlsbCkg4oCUIHNraXAgdGhlIGJhY2t3YXJkIHdhbGsgKHdvdWxkIGp1c3QKICAgICAgLy8gdHJhY2UgdGhlIHNhbWUgbG9vcCBpbiByZXZlcnNlLCBkb3VibGluZyB0aGUgcGF0aCBsZW5ndGgpLgogICAgICB2YXIgZndkID0gd2Fsa0NvbnRvdXIoc2VlZCwgKzEsIGNsaXBQb2x5LCBzdGVwTSwgbWF4U3RlcHMpOwogICAgICB2YXIgc2FtcGxlczsKICAgICAgaWYoZndkLl9jbG9zZWQpewogICAgICAgIHNhbXBsZXMgPSBmd2Q7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgdmFyIGJ3ZCA9IHdhbGtDb250b3VyKHNlZWQsIC0xLCBjbGlwUG9seSwgc3RlcE0sIG1heFN0ZXBzKTsKICAgICAgICBid2QucmV2ZXJzZSgpOwogICAgICAgIHNhbXBsZXMgPSBid2QuY29uY2F0KGZ3ZC5zbGljZSgxKSk7CiAgICAgIH0KICAgICAgaWYoc2FtcGxlcy5sZW5ndGggPj0gNCkgcGFzc2VzLnB1c2goeyBzYW1wbGVzOiBzYW1wbGVzLCBraW5kOiAnYWRhcHRpdmUnIH0pOwogICAgfQogICAgcmV0dXJuIHBhc3NlczsKICB9CgogIGZ1bmN0aW9uIGdlbmVyYXRlTGluZXMoYXBwcm9hY2gsIHdNLCBiLCBheGlzLCBoZWFkbGFuZE0sIHR1cm5TdHlsZSwgdHVyblJhZGl1c00sIG91dHNpZGVCdWZmZXJNKXsKICAgIHZhciBkcml2YWJsZSA9IGJ1aWxkRHJpdmFibGUoYiwgb3V0c2lkZUJ1ZmZlck0pOwogICAgdmFyIGludGVyaW9yID0gaGVhZGxhbmRNID4gMCA\/IG9mZnNldFBvbHlnb25JbndhcmQoYiwgaGVhZGxhbmRNKSA6IGI7CiAgICBpZighaW50ZXJpb3IpIGludGVyaW9yID0gYjsgIC8vIGZhbGxiYWNrIHdoZW4gb2Zmc2V0IGNvbGxhcHNlcwogICAgdmFyIHV4ID0gYXhpcy51eCwgdXkgPSBheGlzLnV5OwogICAgdmFyIHBhc3NlcyA9IFtdOwoKICAgIC8vIFJ1bGUgwqcxMyDigJQgd29yayB0aGUgaGVhZGxhbmQgRklSU1QsIHRoZW4gdGhlIGJvZHkuIEVtaXQgcGVyaW1ldGVyCiAgICAvLyByaW5nKHMpIGF0IGhlYWRsYW5kLXN0cmlwIGNlbnRyZWxpbmVzIGZvciBFVkVSWSBhcHByb2FjaC4KICAgIC8vCiAgICAvLyBGb3IgaGVhZGxhbmRNID09IDHDl3dNOiBvbmUgcmluZyBhdCB3TS8yIGZyb20gYm91bmRhcnkgY292ZXJzIHRoZQogICAgLy8gd2hvbGUgc3RyaXAgWzAsIHdNXSB3aXRoIGl0cyBzd2F0aC4KICAgIC8vCiAgICAvLyBGb3IgaGVhZGxhbmRNID4gMcOXd006IGRyaXZlIE1VTFRJUExFIGNvbmNlbnRyaWMgcmluZ3Mgc28gdGhlIGZ1bGwKICAgIC8vIHN0cmlwIGlzIGNvdmVyZWQuIG5SaW5ncyA9IHJvdW5kKGhlYWRsYW5kTSAvIHdNKS4gUmluZyBrIGF0IHBlcnAgPQogICAgLy8gKGsgKyAwLjUpIMOXIHdNIGZyb20gYm91bmRhcnkgKGsgPSAwLi5uUmluZ3MtMSkgc28gc3dhdGhzIHRpbGUgdGhlCiAgICAvLyBzdHJpcCB3aXRob3V0IGdhcHMuCiAgICBpZihoZWFkbGFuZE0gPiAwID8gaW50ZXJpb3IgIT09IGIgOiBmYWxzZSl7CiAgICAgIHZhciBuUmluZ3MgPSBNYXRoLm1heCgxLCBNYXRoLnJvdW5kKGhlYWRsYW5kTSAvIHdNKSk7CiAgICAgIGZvcih2YXIgcms9MDsgcms8blJpbmdzOyByaysrKXsKICAgICAgICB2YXIgcmluZ09mZiA9IChyayArIDAuNSkgKiB3TTsKICAgICAgICB2YXIgcmluZ1JlZiA9IG9mZnNldFBvbHlnb25JbndhcmQoYiwgcmluZ09mZik7CiAgICAgICAgaWYocmluZ1JlZil7CiAgICAgICAgICBwYXNzZXMucHVzaCh7IHNhbXBsZXM6IHJpbmdSZWYuY29uY2F0KFtyaW5nUmVmWzBdXSksIGtpbmQ6ICdoZWFkbGFuZC1yaW5nJyB9KTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIHZhciBwYXNzQ2xpcFBvbHkgPSBpbnRlcmlvcjsKICAgIC8vIEJvdW5kYXJ5IEZvbGxvdyB1c2VkIHRvIHNocmluayB0aGUgYm9keSBpbnRlcmlvciBieSBhbm90aGVyIDAuNzUgw5cgd00KICAgIC8vIHRvIGF2b2lkIG92ZXJsYXAgYmV0d2VlbiByaW5nIGFuZCBib2R5IHN3YXRocy4gVGhhdCBjcmVhdGVkIGEgMC43NSDDlyB3TQogICAgLy8gVU5DT1ZFUkVEIHN0cmlwIGJldHdlZW4gdGhlIHJpbmcncyBzd2F0aCBlZGdlIGFuZCB0aGUgZmlyc3QgYm9keSBwYXNzLgogICAgLy8gUGVyIHRoZSB1c2VyIOKAlCBtYXhpbWlzZSBjb3ZlcmFnZSDigJQgYm9keSBwYXNzZXMgbm93IHVzZSB0aGUgZnVsbAogICAgLy8gaW50ZXJpb3IsIGFjY2VwdGluZyBhIHNtYWxsICh+MOKAkzI1ICUpIG92ZXJsYXAgYXQgdGhlIHJpbmcvYm9keQogICAgLy8gYm91bmRhcnksIHdoaWNoIGlzIHN0YW5kYXJkIGFncm9ub21pYyBwcmFjdGljZSAoNeKAkzEwICUgb3ZlcmxhcCBpcwogICAgLy8gcm91dGluZSBmb3IgaGVhZGxhbmQgZWRnZXMpLgogICAgLy8gQ29udG91ci1mb2xsb3cgKHRlcnJhaW4tYXdhcmUpIOKAlCBnZW5lcmF0ZSBwYXNzZXMgdGhhdCB0cmFjZSBsZXZlbAogICAgLy8gY3VydmVzIG9mIHRoZSB0ZXJyYWluIGZ1bmN0aW9uLiBFYWNoIHBhc3Mgd2Fsa3MgcGVycGVuZGljdWxhciB0byB0aGUKICAgIC8vIGxvY2FsIGdyYWRpZW50IGF0IHdNIHNwYWNpbmcuIEZhbGxzIGJhY2sgdG8gQUItY3VydmUgc3ludGhldGljIHdhdmVzCiAgICAvLyB3aGVuIHRlcnJhaW4gaXMgdG9vIGZsYXQgKG9yIHVwbG9hZGVkLW5vLXRlcnJhaW4pLgogICAgaWYoYXBwcm9hY2ggPT09ICdhZGFwdGl2ZScpewogICAgICB2YXIgY29udG91clBhc3NlcyA9IGJ1aWxkQ29udG91clBhc3Nlcyh3TSwgcGFzc0NsaXBQb2x5KTsKICAgICAgaWYoY29udG91clBhc3Nlcy5sZW5ndGggPj0gMil7CiAgICAgICAgZm9yKHZhciBjcD0wOyBjcDxjb250b3VyUGFzc2VzLmxlbmd0aDsgY3ArKykgcGFzc2VzLnB1c2goY29udG91clBhc3Nlc1tjcF0pOwogICAgICAgIHZhciBzZXJwQyA9IGJ1aWxkU2VycGVudGluZShwYXNzZXMsIGRyaXZhYmxlLCBpbnRlcmlvciwgYXhpcywgdHVyblN0eWxlLCB0dXJuUmFkaXVzTSwgd00gKiAwLjUsIHdNKTsKICAgICAgICByZXR1cm4gewogICAgICAgICAgcGFzc2VzOiBwYXNzZXMsCiAgICAgICAgICBpbnRlcmlvcjogaW50ZXJpb3IsCiAgICAgICAgICBkcml2YWJsZTogZHJpdmFibGUsCiAgICAgICAgICBib3VuZGFyeTogYiwKICAgICAgICAgIHR1cm5BcmNzOiBzZXJwQy50dXJuQXJjcywKICAgICAgICAgIGRyaXZlUGF0aDogc2VycEMuZHJpdmVDb29yZHMsCiAgICAgICAgICB3YXJuaW5nOiBzZXJwQy53YXJuaW5nLAogICAgICAgICAgb3JkZXJlZFBhc3Nlczogc2VycEMub3JkZXJlZFBhc3NlcwogICAgICAgIH07CiAgICAgIH0KICAgICAgLy8gZWxzZTogZmxhdCAvIHVwbG9hZGVkIGZpZWxkIOKGkiBmYWxsIHRocm91Z2ggdG8gdGhlIHN5bnRoZXRpYy13YXZlIGNvZGUKICAgICAgLy8gYmVsb3cgKHN0aWxsIGxhYmVsbGVkIGFkYXB0aXZlIGJ1dCB3b24ndCBhY3R1YWxseSBmb2xsb3cgdGVycmFpbikuCiAgICB9CgogICAgLy8gQUIgU3RyYWlnaHQgLyBBQiBDdXJ2ZSAvIEFkYXB0aXZlIChzeW50aGV0aWMpIC8gQm91bmRhcnkgYm9keSDigJQgcGFyYWxsZWwKICAgIC8vIG9mZnNldHMgY2xpcHBlZCB0byBgcGFzc0NsaXBQb2x5YC4KICAgIHZhciBwZXJwTWluID0gSW5maW5pdHksIHBlcnBNYXggPSAtSW5maW5pdHk7CiAgICB2YXIgYWxvbmdNaW4gPSBJbmZpbml0eSwgYWxvbmdNYXggPSAtSW5maW5pdHk7CiAgICBmb3IodmFyIGk9MDsgaTxwYXNzQ2xpcFBvbHkubGVuZ3RoOyBpKyspewogICAgICB2YXIgYWxvbmcgPSBwYXNzQ2xpcFBvbHlbaV0ueCAqIHV4ICsgcGFzc0NsaXBQb2x5W2ldLnkgKiB1eTsKICAgICAgdmFyIHBlcnAgPSAtcGFzc0NsaXBQb2x5W2ldLnggKiB1eSArIHBhc3NDbGlwUG9seVtpXS55ICogdXg7CiAgICAgIGlmKHBlcnAgPCBwZXJwTWluKSBwZXJwTWluID0gcGVycDsKICAgICAgaWYocGVycCA+IHBlcnBNYXgpIHBlcnBNYXggPSBwZXJwOwogICAgICBpZihhbG9uZyA8IGFsb25nTWluKSBhbG9uZ01pbiA9IGFsb25nOwogICAgICBpZihhbG9uZyA+IGFsb25nTWF4KSBhbG9uZ01heCA9IGFsb25nOwogICAgfQogICAgdmFyIHN0YXJ0UGVycCA9IHBlcnBNaW4gKyB3TSAqIDAuNTsKICAgIHZhciBlbmRQZXJwID0gcGVycE1heCAtIHdNICogMC41OwogICAgdmFyIGFsb25nU3BhbiA9IGFsb25nTWF4IC0gYWxvbmdNaW47CiAgICBmb3IodmFyIHBwID0gc3RhcnRQZXJwOyBwcCA8PSBlbmRQZXJwICsgMWUtNjsgcHAgKz0gd00pewogICAgICB2YXIgcDBBbG9uZyA9IGFsb25nTWluIC0gYWxvbmdTcGFuICogMC4xOwogICAgICB2YXIgcDFBbG9uZyA9IGFsb25nTWF4ICsgYWxvbmdTcGFuICogMC4xOwogICAgICB2YXIgc3RhcnRYID0gcDBBbG9uZyAqIHV4IC0gcHAgKiB1eTsKICAgICAgdmFyIHN0YXJ0WSA9IHAwQWxvbmcgKiB1eSArIHBwICogdXg7CiAgICAgIHZhciBlbmRYID0gcDFBbG9uZyAqIHV4IC0gcHAgKiB1eTsKICAgICAgdmFyIGVuZFkgPSBwMUFsb25nICogdXkgKyBwcCAqIHV4OwogICAgICAvLyBVc2UgdGhlIG11bHRpLXNlZ21lbnQgY2xpcHBlciBzbyBjb25jYXZlIHBvbHlnb25zIChMLXNoYXBlIGludGVyaW9yISkKICAgICAgLy8gcHJvZHVjZSBvbmUgcGFzcyBwZXIgImluc2lkZSIgc2VnbWVudCB3aGVuIHRoZSBsaW5lIGNyb3NzZXMgYSBnYXAuCiAgICAgIHZhciBjbGlwcGVkU2VncyA9IGNsaXBMaW5lVG9Cb3VuZGFyeVNlZ21lbnRzKHN0YXJ0WCwgc3RhcnRZLCBlbmRYLCBlbmRZLCBwYXNzQ2xpcFBvbHkpOwogICAgICBpZighY2xpcHBlZFNlZ3MpIGNvbnRpbnVlOwogICAgICBmb3IodmFyIGNzPTA7IGNzPGNsaXBwZWRTZWdzLmxlbmd0aDsgY3MrKyl7CiAgICAgICAgdmFyIGNsaXBwZWQgPSBjbGlwcGVkU2Vnc1tjc107CiAgICAgICAgaWYoYXBwcm9hY2ggPT09ICdhYi1jdXJ2ZScgfHwgYXBwcm9hY2ggPT09ICdhZGFwdGl2ZScpewogICAgICAgICAgdmFyIGR4QyA9IGNsaXBwZWQueDEgLSBjbGlwcGVkLngwOwogICAgICAgICAgdmFyIGR5QyA9IGNsaXBwZWQueTEgLSBjbGlwcGVkLnkwOwogICAgICAgICAgdmFyIGxlbkwgPSBNYXRoLnNxcnQoZHhDKmR4QyArIGR5QypkeUMpOwogICAgICAgICAgdmFyIG5TYW1wID0gTWF0aC5tYXgoOCwgTWF0aC5mbG9vcihsZW5MIC8gKHdNICogMC42KSkpOwogICAgICAgICAgdmFyIHNhbXBzID0gW107CiAgICAgICAgICB2YXIgYW1wbGl0dWRlID0gYXBwcm9hY2ggPT09ICdhZGFwdGl2ZScgPyB3TSAqIDAuMzUgOiB3TSAqIDAuMTU7CiAgICAgICAgICB2YXIgZnJlcSA9IGFwcHJvYWNoID09PSAnYWRhcHRpdmUnID8gMi44IDogMS40OwogICAgICAgICAgdmFyIHBoYXNlID0gKHBwIC0gcGVycE1pbikgLyB3TTsKICAgICAgICAgIGZvcih2YXIgc3M9MDsgc3M8PW5TYW1wOyBzcysrKXsKICAgICAgICAgICAgdmFyIHQgPSBuU2FtcCA+IDAgPyBzcyAvIG5TYW1wIDogMDsKICAgICAgICAgICAgdmFyIGJ4cyA9IGNsaXBwZWQueDAgKyBkeEMgKiB0OwogICAgICAgICAgICB2YXIgYnlzID0gY2xpcHBlZC55MCArIGR5QyAqIHQ7CiAgICAgICAgICAgIHZhciB3YXZlID0gTWF0aC5zaW4odCAqIE1hdGguUEkgKiBmcmVxICsgcGhhc2UpICogYW1wbGl0dWRlOwogICAgICAgICAgICBieHMgKz0gLXV5ICogd2F2ZTsKICAgICAgICAgICAgYnlzICs9IHV4ICogd2F2ZTsKICAgICAgICAgICAgc2FtcHMucHVzaCh7IHg6IGJ4cywgeTogYnlzIH0pOwogICAgICAgICAgfQogICAgICAgICAgcGFzc2VzLnB1c2goeyBzYW1wbGVzOiBzYW1wcywga2luZDogYXBwcm9hY2ggfSk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHBhc3Nlcy5wdXNoKHsgeDA6IGNsaXBwZWQueDAsIHkwOiBjbGlwcGVkLnkwLCB4MTogY2xpcHBlZC54MSwgeTE6IGNsaXBwZWQueTEsIGtpbmQ6IGFwcHJvYWNoIH0pOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgdmFyIHNlcnAgPSBidWlsZFNlcnBlbnRpbmUocGFzc2VzLCBkcml2YWJsZSwgaW50ZXJpb3IsIGF4aXMsIHR1cm5TdHlsZSwgdHVyblJhZGl1c00sIHdNICogMC41LCB3TSk7CiAgICByZXR1cm4gewogICAgICBwYXNzZXM6IHBhc3NlcywKICAgICAgaW50ZXJpb3I6IGludGVyaW9yLAogICAgICBkcml2YWJsZTogZHJpdmFibGUsCiAgICAgIGJvdW5kYXJ5OiBiLAogICAgICB0dXJuQXJjczogc2VycC50dXJuQXJjcywKICAgICAgZHJpdmVQYXRoOiBzZXJwLmRyaXZlQ29vcmRzLAogICAgICB3YXJuaW5nOiBzZXJwLndhcm5pbmcsCiAgICAgIG9yZGVyZWRQYXNzZXM6IHNlcnAub3JkZXJlZFBhc3NlcwogICAgfTsKICB9CgogIC8vIFJhc3RlcmlzZSB0aGUgbGF5b3V0J3Mgc3dhdGggb250byBhIGdyaWQgY292ZXJpbmcgdGhlIGZpZWxkIGJib3guIEZvcgogIC8vIGVhY2ggY2VsbCB3aG9zZSBjZW50cmUgaXMgaW5zaWRlIHRoZSBib3VuZGFyeSBBTkQgd2l0aGluIHdNLzIgb2YgYW55CiAgLy8gcGFzcy1jZW50ZXJsaW5lIG9yIHJpbmctY2VudGVybGluZSBzZWdtZW50LCBtYXJrIGl0IGNvdmVyZWQuIFJldHVybnMKICAvLyB7IGNvdmVyZWRNMiwgZmllbGRNMiwgcGN0IH0uIGNlbGxTaXplIGRlZmF1bHRzIHRvIH53TS8zIHNvIGNlbGxzIGFyZQogIC8vIHNtYWxsZXIgdGhhbiB0aGUgc3dhdGgg4oCUIHVuZGVyLWZpbGwgbmVhciBjb3JuZXJzIGlzIGNhcHR1cmVkIGhvbmVzdGx5LgogIGZ1bmN0aW9uIHJhc3RlckNvdmVyYWdlKGxheW91dCwgd00pewogICAgdmFyIGIgPSBsYXlvdXQuYm91bmRhcnkgPyBsYXlvdXQuYm91bmRhcnkgOiBCT1VOREFSWTsKICAgIHZhciBzdGF0cyA9IGZpZWxkU3RhdHMoYik7CiAgICB2YXIgY2VsbFNpemUgPSBNYXRoLm1heCgyLCB3TSAvIDMpOwogICAgdmFyIG54ID0gTWF0aC5tYXgoOCwgTWF0aC5jZWlsKChzdGF0cy5tYXhYIC0gc3RhdHMubWluWCkgLyBjZWxsU2l6ZSkpOwogICAgdmFyIG55ID0gTWF0aC5tYXgoOCwgTWF0aC5jZWlsKChzdGF0cy5tYXhZIC0gc3RhdHMubWluWSkgLyBjZWxsU2l6ZSkpOwogICAgLy8gRmlyc3QgcGFzczogbWFyayBjZWxscyBpbnNpZGUgdGhlIGZpZWxkIGJvdW5kYXJ5CiAgICB2YXIgaW5GaWVsZCA9IG5ldyBVaW50OEFycmF5KG54ICogbnkpOwogICAgdmFyIGZpZWxkQ2VsbENvdW50ID0gMDsKICAgIGZvcih2YXIgaXk9MDsgaXk8bnk7IGl5KyspewogICAgICBmb3IodmFyIGl4PTA7IGl4PG54OyBpeCsrKXsKICAgICAgICB2YXIgY3ggPSBzdGF0cy5taW5YICsgKGl4ICsgMC41KSAqIGNlbGxTaXplOwogICAgICAgIHZhciBjeSA9IHN0YXRzLm1pblkgKyAoaXkgKyAwLjUpICogY2VsbFNpemU7CiAgICAgICAgaWYocG9pbnRJblBvbHkoY3gsIGN5LCBiKSl7CiAgICAgICAgICBpbkZpZWxkW2l5ICogbnggKyBpeF0gPSAxOwogICAgICAgICAgZmllbGRDZWxsQ291bnQrKzsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIC8vIENvbGxlY3QgYWxsIHN3YXRoIHNlZ21lbnRzIOKAlCBib2R5LXBhc3Mgc2VnbWVudHMgYW5kIHJpbmcgc2VnbWVudHMuCiAgICB2YXIgc2VncyA9IFtdOwogICAgaWYobGF5b3V0LnBhc3Nlcyl7CiAgICAgIGZvcih2YXIgcGk9MDsgcGk8bGF5b3V0LnBhc3Nlcy5sZW5ndGg7IHBpKyspewogICAgICAgIHZhciBwYSA9IGxheW91dC5wYXNzZXNbcGldOwogICAgICAgIGlmKHBhLnNhbXBsZXMpewogICAgICAgICAgZm9yKHZhciBzaT0xOyBzaTxwYS5zYW1wbGVzLmxlbmd0aDsgc2krKyl7CiAgICAgICAgICAgIHNlZ3MucHVzaCh7IHgwOiBwYS5zYW1wbGVzW3NpLTFdLngsIHkwOiBwYS5zYW1wbGVzW3NpLTFdLnksIHgxOiBwYS5zYW1wbGVzW3NpXS54LCB5MTogcGEuc2FtcGxlc1tzaV0ueSB9KTsKICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgaWYocGEueDAgIT09IHVuZGVmaW5lZCl7CiAgICAgICAgICBzZWdzLnB1c2goeyB4MDogcGEueDAsIHkwOiBwYS55MCwgeDE6IHBhLngxLCB5MTogcGEueTEgfSk7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBpZihzZWdzLmxlbmd0aCA9PT0gMCl7CiAgICAgIHJldHVybiB7IGNvdmVyZWRNMjogMCwgZmllbGRNMjogZmllbGRDZWxsQ291bnQgKiBjZWxsU2l6ZSAqIGNlbGxTaXplLCBwY3Q6IDAgfTsKICAgIH0KICAgIC8vIFNlY29uZCBwYXNzOiBmb3IgZWFjaCBpbi1maWVsZCBjZWxsLCBjaGVjayBkaXN0YW5jZSB0byBuZWFyZXN0IHNlZ21lbnQuCiAgICAvLyBPKGNlbGxzIMOXIHNlZ3MpIOKAlCBhY2NlcHRhYmxlIGZvciBzYW1wbGUtc2l6ZWQgZmllbGRzICh+NjAwMCDDlyAyMCDiiYggMTIwaykuCiAgICB2YXIgaGFsZiA9IHdNICogMC41OwogICAgdmFyIGhhbGYyID0gaGFsZiAqIGhhbGY7CiAgICB2YXIgY292ZXJlZCA9IG5ldyBVaW50OEFycmF5KG54ICogbnkpOwogICAgdmFyIGNvdmVyZWRDb3VudCA9IDA7CiAgICBmb3IodmFyIGl5Mj0wOyBpeTI8bnk7IGl5MisrKXsKICAgICAgZm9yKHZhciBpeDI9MDsgaXgyPG54OyBpeDIrKyl7CiAgICAgICAgdmFyIGlkeCA9IGl5MiAqIG54ICsgaXgyOwogICAgICAgIGlmKCFpbkZpZWxkW2lkeF0pIGNvbnRpbnVlOwogICAgICAgIHZhciBjeEMgPSBzdGF0cy5taW5YICsgKGl4MiArIDAuNSkgKiBjZWxsU2l6ZTsKICAgICAgICB2YXIgY3lDID0gc3RhdHMubWluWSArIChpeTIgKyAwLjUpICogY2VsbFNpemU7CiAgICAgICAgZm9yKHZhciBzZz0wOyBzZzxzZWdzLmxlbmd0aDsgc2crKyl7CiAgICAgICAgICB2YXIgcyA9IHNlZ3Nbc2ddOwogICAgICAgICAgLy8gU3F1YXJlZCBkaXN0YW5jZSBmcm9tIChjeEMsY3lDKSB0byBzZWdtZW50IHMKICAgICAgICAgIHZhciBzZHggPSBzLngxIC0gcy54MCwgc2R5ID0gcy55MSAtIHMueTA7CiAgICAgICAgICB2YXIgTDIgPSBzZHgqc2R4ICsgc2R5KnNkeTsKICAgICAgICAgIHZhciB0ID0gTDIgPiAxZS05ID8gKChjeEMgLSBzLngwKSAqIHNkeCArIChjeUMgLSBzLnkwKSAqIHNkeSkgLyBMMiA6IDA7CiAgICAgICAgICBpZih0IDwgMCkgdCA9IDA7IGVsc2UgaWYodCA+IDEpIHQgPSAxOwogICAgICAgICAgdmFyIHB4MiA9IHMueDAgKyBzZHggKiB0IC0gY3hDOwogICAgICAgICAgdmFyIHB5MiA9IHMueTAgKyBzZHkgKiB0IC0gY3lDOwogICAgICAgICAgdmFyIGRpc3QyID0gcHgyKnB4MiArIHB5MipweTI7CiAgICAgICAgICBpZihkaXN0MiA8PSBoYWxmMil7IGNvdmVyZWRbaWR4XSA9IDE7IGNvdmVyZWRDb3VudCsrOyBicmVhazsgfQogICAgICAgIH0KICAgICAgfQogICAgfQogICAgdmFyIGNlbGxBcmVhID0gY2VsbFNpemUgKiBjZWxsU2l6ZTsKICAgIHZhciBmaWVsZE0yID0gZmllbGRDZWxsQ291bnQgKiBjZWxsQXJlYTsKICAgIHZhciBjb3ZlcmVkTTIgPSBjb3ZlcmVkQ291bnQgKiBjZWxsQXJlYTsKICAgIHJldHVybiB7IGNvdmVyZWRNMjogY292ZXJlZE0yLCBmaWVsZE0yOiBmaWVsZE0yLCBwY3Q6IGZpZWxkTTIgPiAwID8gKGNvdmVyZWRNMiAvIGZpZWxkTTIgKiAxMDApIDogMCB9OwogIH0KCiAgZnVuY3Rpb24gY29tcHV0ZU1ldHJpY3MobGF5b3V0LCB3TSwgZGllc2VsUHJpY2UsIGNvbnN1bXB0aW9uKXsKICAgIC8vIFBhc3MgKHRyYW1saW5lKSBsZW5ndGggb25seSDigJQgd2hhdCB0aGUgb3BlcmF0b3IgYWN0dWFsbHkgd29ya3Mgb24uCiAgICB2YXIgcGFzc0xlbiA9IDA7CiAgICB2YXIgblBhc3NlcyA9IGxheW91dC5wYXNzZXMubGVuZ3RoOwogICAgZm9yKHZhciBpPTA7IGk8blBhc3NlczsgaSsrKXsKICAgICAgdmFyIHAgPSBsYXlvdXQucGFzc2VzW2ldOwogICAgICBpZihwLnNhbXBsZXMpewogICAgICAgIGZvcih2YXIgcz0xOyBzPHAuc2FtcGxlcy5sZW5ndGg7IHMrKyl7CiAgICAgICAgICB2YXIgZHggPSBwLnNhbXBsZXNbc10ueCAtIHAuc2FtcGxlc1tzLTFdLng7CiAgICAgICAgICB2YXIgZHkgPSBwLnNhbXBsZXNbc10ueSAtIHAuc2FtcGxlc1tzLTFdLnk7CiAgICAgICAgICBwYXNzTGVuICs9IE1hdGguc3FydChkeCpkeCArIGR5KmR5KTsKICAgICAgICB9CiAgICAgIH0gZWxzZSB7CiAgICAgICAgdmFyIGR4TCA9IHAueDEgLSBwLngwLCBkeUwgPSBwLnkxIC0gcC55MDsKICAgICAgICBwYXNzTGVuICs9IE1hdGguc3FydChkeEwqZHhMICsgZHlMKmR5TCk7CiAgICAgIH0KICAgIH0KICAgIC8vIFR1cm4tYXJjIGxlbmd0aCDigJQgd2hhdCB0aGUgb3BlcmF0b3IgZHJpdmVzIEJFVFdFRU4gcGFzc2VzIChoZWFkZXIgdXApLgogICAgdmFyIHR1cm5MZW4gPSAwOwogICAgdmFyIG5UdXJucyA9IGxheW91dC50dXJuQXJjcyA\/IGxheW91dC50dXJuQXJjcy5sZW5ndGggOiAwOwogICAgaWYobGF5b3V0LnR1cm5BcmNzKXsKICAgICAgZm9yKHZhciB0aT0wOyB0aTxsYXlvdXQudHVybkFyY3MubGVuZ3RoOyB0aSsrKXsKICAgICAgICB2YXIgYXJjID0gbGF5b3V0LnR1cm5BcmNzW3RpXS5jb29yZHM7CiAgICAgICAgZm9yKHZhciBhcz0xOyBhczxhcmMubGVuZ3RoOyBhcysrKXsKICAgICAgICAgIHZhciBkeEEgPSBhcmNbYXNdLnggLSBhcmNbYXMtMV0ueCwgZHlBID0gYXJjW2FzXS55IC0gYXJjW2FzLTFdLnk7CiAgICAgICAgICB0dXJuTGVuICs9IE1hdGguc3FydChkeEEqZHhBICsgZHlBKmR5QSk7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICAvLyBUb3RhbCBkcml2ZSBwYXRoID0gdHJhbWxpbmUgKyB0dXJuIGFyY3MuCiAgICAvLyBQYXNzIGZ1ZWwgc2NhbGVzIGxpbmVhcmx5IHdpdGggY29uc3VtcHRpb24gw5cgbGVuZ3RoLCBQTFVTIGEgc2xvcGUKICAgIC8vIHBlbmFsdHk6IGRyaXZpbmcgYWxvbmcgYSBjb250b3VyIGxpbmUgaXMgbm9ybWFsLWZ1ZWw7IGRyaXZpbmcgYWNyb3NzCiAgICAvLyBjb250b3VycyAodXBoaWxsL2Rvd25oaWxsKSBwZW5hbGlzZXMgfjEww5cgdGhlIGFic29sdXRlIGdyYWRlwrIuIFJlYWwKICAgIC8vIHRyYWN0b3JzIGJ1cm4gMzDigJM0MCAlIG1vcmUgZGllc2VsIGF0IGEgc3VzdGFpbmVkIDUgJSB1cC1ncmFkZS4KICAgIC8vIFR1cm5hcm91bmQgZnVlbCBpcyAxLjI1w5cgcGVyIG1ldHJlIGJlY2F1c2UgdGhlIGVuZ2luZSB3b3JrcyBoYXJkZXIKICAgIC8vIHVuZGVyIGEgdGlnaHQgcGl2b3QgKGh5ZHJhdWxpY3MgcmFpc2luZy9sb3dlcmluZyB0aGUgaW1wbGVtZW50LAogICAgLy8gZ2VhciBjaGFuZ2VzKSDigJQgdHlwaWNhbCBoZWFkbGFuZC10dXJuIHBlbmFsdHkuCiAgICB2YXIgdG90YWxMZW4gPSBwYXNzTGVuICsgdHVybkxlbjsKICAgIHZhciBzbG9wZVBlbmFsdHkgPSBjb21wdXRlU2xvcGVQZW5hbHR5KGxheW91dCk7CiAgICB2YXIgcGFzc0Z1ZWxCYXNlID0gKHBhc3NMZW4gLyAxMDAwKSAqIGNvbnN1bXB0aW9uOwogICAgdmFyIHBhc3NGdWVsID0gcGFzc0Z1ZWxCYXNlICogKDEgKyBzbG9wZVBlbmFsdHkpOwogICAgdmFyIHR1cm5GdWVsID0gKHR1cm5MZW4gLyAxMDAwKSAqIGNvbnN1bXB0aW9uICogMS4yNTsKICAgIHZhciB0b3RhbEZ1ZWwgPSBwYXNzRnVlbCArIHR1cm5GdWVsOwogICAgdmFyIGNvc3QgPSB0b3RhbEZ1ZWwgKiBkaWVzZWxQcmljZTsKICAgIC8vIENvdmVyYWdlIOKAlCBSQVNURVItQkFTRUQgZm9yIGFjY3VyYWN5LiBTdW0tb2Ytc3RyaXAgbWF0aCBvdmVyc3RhdGVkCiAgICAvLyAoZG91YmxlLWNvdW50ZWQgb3ZlcmxhcHMsIGlnbm9yZWQgY29ybmVyIGdhcHMgYW5kIGhlYWRsYW5kLXJpbmcgdW5kZXItZmlsbAogICAgLy8gYXQgc2hhcnAgY29ybmVycykg4oaSIGNsYW1wZWQgdG8gMTAwJSBldmVuIHdoZW4gdGhlIHJlYWwgY292ZXJhZ2Ugd2FzIDw5NSUuCiAgICAvLyBUaGUgZ3JpZCBhcHByb2FjaCBjb21wdXRlcyB0aGUgdHJ1ZSB1bmlvbiBhcmVhOiBmb3IgZWFjaCBjZWxsIHdob3NlCiAgICAvLyBjZW50cmUgbGllcyBpbnNpZGUgdGhlIGZpZWxkIGJvdW5kYXJ5LCBjaGVjayBpZiBpdCdzIGFsc28gaW5zaWRlIGFueQogICAgLy8gc3dhdGggc3RyaXAuIGNvdmVyYWdlUGN0ID0gY292ZXJlZCAvIHRvdGFsLiBjZWxsU2l6ZSBkZWZhdWx0cyB0byB3TS8zCiAgICAvLyBzbyBjZWxscyBhcmUgc21hbGxlciB0aGFuIHRoZSBzd2F0aCwgY2FwdHVyaW5nIHVuZGVyLWNvdmVyYWdlIG5lYXIKICAgIC8vIGNvcm5lcnMgYW5kIHVuY292ZXJlZCBwb2NrZXRzIGluIGNvbmNhdmUgZmllbGRzLgogICAgdmFyIHN0YXRzID0gZmllbGRTdGF0cyhsYXlvdXQuYm91bmRhcnkgPyBsYXlvdXQuYm91bmRhcnkgOiBCT1VOREFSWSk7CiAgICB2YXIgZmllbGRNMiA9IHN0YXRzLmFyZWE7CiAgICB2YXIgY292ZXJhZ2VSZXMgPSByYXN0ZXJDb3ZlcmFnZShsYXlvdXQsIHdNKTsKICAgIHZhciBjb3ZlcmVkTTIgPSBjb3ZlcmFnZVJlcy5jb3ZlcmVkTTI7CiAgICB2YXIgY292ZXJhZ2VQY3QgPSBjb3ZlcmFnZVJlcy5wY3Q7CiAgICByZXR1cm4gewogICAgICBwYXNzZXM6IG5QYXNzZXMsCiAgICAgIHBhc3NMZW5ndGhNOiBwYXNzTGVuLAogICAgICB0dXJuTGVuZ3RoTTogdHVybkxlbiwKICAgICAgdG90YWxEcml2ZU06IHRvdGFsTGVuLAogICAgICB0dXJuczogblR1cm5zLAogICAgICBmdWVsTDogdG90YWxGdWVsLAogICAgICBwYXNzRnVlbEw6IHBhc3NGdWVsLAogICAgICB0dXJuRnVlbEw6IHR1cm5GdWVsLAogICAgICBjb3N0VVNEOiBjb3N0LAogICAgICBjb3ZlcmFnZVBjdDogY292ZXJhZ2VQY3QsCiAgICAgIGNvdmVyZWRNMjogY292ZXJlZE0yLAogICAgICBmaWVsZE0yOiBmaWVsZE0yLAogICAgICBzbG9wZVBlbmFsdHk6IHNsb3BlUGVuYWx0eSwKICAgICAgYXZnR3JhZGVQY3Q6IGxheW91dC5hdmdHcmFkZVBjdCB8fCAwCiAgICB9OwogIH0KICAvLyBDb21wdXRlIGF2ZXJhZ2UgZ3JhZGUtYWxvbmctcGFzcy1kaXJlY3Rpb24gZm9yIGJvZHkgcGFzc2VzLCByZXR1cm5zCiAgLy8gYSBmdWVsIG11bHRpcGxpZXIgcGVuYWx0eSAoMCA9IGZsYXQsIDAuMyA9IDMwJSBleHRyYSBmdWVsKS4gQWxzbyBzdG9yZXMKICAvLyB0aGUgYXZlcmFnZSBhYnNvbHV0ZSBncmFkZSAlIG9uIHRoZSBsYXlvdXQgZm9yIGRpc3BsYXkuIFBlbmFsdHkgbW9kZWw6CiAgLy8gICBwZW5hbHR5ID0gayDDlyBtZWFuKHxncmFkZXzCsikgd2hlcmUgZ3JhZGUgPSDOlHogLyDOlGhvcml6b250YWwKICAvLyAgIGsgPSAxMiDihpIgNSUgc3VzdGFpbmVkIGdyYWRlIOKGkiAwLjAzIHBlbmFsdHkgKDMlIGV4dHJhIGZ1ZWwpLCAxNSUgZ3JhZGUg4oaSIDI3JSBleHRyYQogIC8vIENyb3NzLWNvbnRvdXIgcGFzc2VzIGFjY3VtdWxhdGUgZnVsbCBzbG9wZTsgb24tY29udG91ciBwYXNzZXMgYWNjdW11bGF0ZSB+MC4KICBmdW5jdGlvbiBjb21wdXRlU2xvcGVQZW5hbHR5KGxheW91dCl7CiAgICBpZighbGF5b3V0LnBhc3NlcyA\/IHRydWUgOiBsYXlvdXQucGFzc2VzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIDA7CiAgICB2YXIgdG90YWxMZW4gPSAwOwogICAgdmFyIHdlaWdodGVkR3JhZGUyID0gMDsKICAgIHZhciB3ZWlnaHRlZEFic0dyYWRlID0gMDsKICAgIHZhciBzYW1wbGVTdGVwID0gNDsgIC8vIG1ldHJlcwogICAgZnVuY3Rpb24gYWNjdW11bGF0ZVNlZyh4MCwgeTAsIHgxLCB5MSl7CiAgICAgIHZhciBzZHggPSB4MSAtIHgwLCBzZHkgPSB5MSAtIHkwOwogICAgICB2YXIgTCA9IE1hdGguc3FydChzZHgqc2R4ICsgc2R5KnNkeSk7CiAgICAgIGlmKEwgPCAwLjUpIHJldHVybjsKICAgICAgdmFyIG5TID0gTWF0aC5tYXgoMiwgTWF0aC5jZWlsKEwgLyBzYW1wbGVTdGVwKSk7CiAgICAgIHZhciB6MCA9IHRlcnJhaW5BdCh4MCwgeTApOwogICAgICBmb3IodmFyIGs9MTsgazw9blM7IGsrKyl7CiAgICAgICAgdmFyIHQgPSBrIC8gblM7CiAgICAgICAgdmFyIG14ID0geDAgKyBzZHggKiB0LCBteSA9IHkwICsgc2R5ICogdDsKICAgICAgICB2YXIgejEgPSB0ZXJyYWluQXQobXgsIG15KTsKICAgICAgICB2YXIgZGggPSBMIC8gblM7CiAgICAgICAgdmFyIGdyYWRlID0gZGggPiAxZS02ID8gKHoxIC0gejApIC8gZGggOiAwOwogICAgICAgIHdlaWdodGVkR3JhZGUyICs9IGdyYWRlICogZ3JhZGUgKiBkaDsKICAgICAgICB3ZWlnaHRlZEFic0dyYWRlICs9IE1hdGguYWJzKGdyYWRlKSAqIGRoOwogICAgICAgIHRvdGFsTGVuICs9IGRoOwogICAgICAgIHowID0gejE7CiAgICAgIH0KICAgIH0KICAgIGZvcih2YXIgcGk9MDsgcGk8bGF5b3V0LnBhc3Nlcy5sZW5ndGg7IHBpKyspewogICAgICB2YXIgcGEgPSBsYXlvdXQucGFzc2VzW3BpXTsKICAgICAgaWYocGEua2luZCA9PT0gJ2hlYWRsYW5kLXJpbmcnKSBjb250aW51ZTsgIC8vIHJpbmcgZm9sbG93cyBib3VuZGFyeSwgaWdub3JlIHNsb3BlIGNvc3QKICAgICAgaWYocGEuc2FtcGxlcyl7CiAgICAgICAgZm9yKHZhciBzaT0xOyBzaTxwYS5zYW1wbGVzLmxlbmd0aDsgc2krKyl7CiAgICAgICAgICBhY2N1bXVsYXRlU2VnKHBhLnNhbXBsZXNbc2ktMV0ueCwgcGEuc2FtcGxlc1tzaS0xXS55LCBwYS5zYW1wbGVzW3NpXS54LCBwYS5zYW1wbGVzW3NpXS55KTsKICAgICAgICB9CiAgICAgIH0gZWxzZSBpZihwYS54MCAhPT0gdW5kZWZpbmVkKXsKICAgICAgICBhY2N1bXVsYXRlU2VnKHBhLngwLCBwYS55MCwgcGEueDEsIHBhLnkxKTsKICAgICAgfQogICAgfQogICAgaWYodG90YWxMZW4gPCAxKSByZXR1cm4gMDsKICAgIHZhciBtZWFuR3JhZGUyID0gd2VpZ2h0ZWRHcmFkZTIgLyB0b3RhbExlbjsKICAgIHZhciBtZWFuQWJzR3JhZGUgPSB3ZWlnaHRlZEFic0dyYWRlIC8gdG90YWxMZW47CiAgICBsYXlvdXQuYXZnR3JhZGVQY3QgPSBtZWFuQWJzR3JhZGUgKiAxMDA7ICAvLyBmb3IgZGlzcGxheQogICAgcmV0dXJuIDEyICogbWVhbkdyYWRlMjsgIC8vIHBlbmFsdHkgbXVsdGlwbGllcgogIH0KCiAgLy8gUkVOREVSCiAgdmFyIERQUiA9IHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvID4gMSA\/IHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvIDogMTsKICBmdW5jdGlvbiByZXNpemUoKXsKICAgIHZhciByZWN0ID0gY2FudmFzLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOwogICAgY2FudmFzLndpZHRoID0gTWF0aC5mbG9vcihyZWN0LndpZHRoICogRFBSKTsKICAgIGNhbnZhcy5oZWlnaHQgPSBNYXRoLmZsb29yKHJlY3QuaGVpZ2h0ICogRFBSKTsKICAgIGN0eC5zZXRUcmFuc2Zvcm0oRFBSLCAwLCAwLCBEUFIsIDAsIDApOwogIH0KICAvLyBWaWV3IHRyYW5zZm9ybSDigJQgZml0LXRvLWZpZWxkIGlzIHRoZSBiYXNlLCB0aGVuIHVzZXIgY2FuIHpvb20vcGFuIGFyb3VuZC4KICB2YXIgdmlldyA9IHsgem9vbTogMSwgcGFuWDogMCwgcGFuWTogMCB9OwogIGZ1bmN0aW9uIGdldFNjYWxlKCl7CiAgICB2YXIgcmVjdCA9IGNhbnZhcy5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTsKICAgIHZhciBwYWQgPSAzNjsKICAgIHZhciBzID0gZmllbGRTdGF0cyhCT1VOREFSWSk7CiAgICB2YXIgc3ggPSAocmVjdC53aWR0aCAtIHBhZCAqIDIpIC8gKHMubWF4WCAtIHMubWluWCk7CiAgICB2YXIgc3kgPSAocmVjdC5oZWlnaHQgLSBwYWQgKiAyKSAvIChzLm1heFkgLSBzLm1pblkpOwogICAgdmFyIHNjID0gKHN4IDwgc3kgPyBzeCA6IHN5KSAqIHZpZXcuem9vbTsKICAgIHZhciBiYXNlVHggPSBwYWQgLSBzLm1pblggKiBzYyArIChyZWN0LndpZHRoIC0gcGFkICogMiAtIChzLm1heFggLSBzLm1pblgpICogc2MpIC8gMjsKICAgIHZhciBiYXNlVHkgPSBwYWQgLSBzLm1pblkgKiBzYyArIChyZWN0LmhlaWdodCAtIHBhZCAqIDIgLSAocy5tYXhZIC0gcy5taW5ZKSAqIHNjKSAvIDI7CiAgICByZXR1cm4geyBzYzogc2MsIHR4OiBiYXNlVHggKyB2aWV3LnBhblgsIHR5OiBiYXNlVHkgKyB2aWV3LnBhblkgfTsKICB9CiAgZnVuY3Rpb24gcHgocHJvaiwgeCl7IHJldHVybiB4ICogcHJvai5zYyArIHByb2oudHg7IH0KICBmdW5jdGlvbiBweShwcm9qLCB5KXsgcmV0dXJuIHkgKiBwcm9qLnNjICsgcHJvai50eTsgfQogIC8vIEludmVyc2U6IHNjcmVlbiDihpIgd29ybGQgY29vcmRpbmF0ZXMgKHVzZWQgYnkgcnVsZXIgKyBwYW4pLgogIGZ1bmN0aW9uIHdvcmxkWChwcm9qLCBzeCl7IHJldHVybiAoc3ggLSBwcm9qLnR4KSAvIHByb2ouc2M7IH0KICBmdW5jdGlvbiB3b3JsZFkocHJvaiwgc3kpeyByZXR1cm4gKHN5IC0gcHJvai50eSkgLyBwcm9qLnNjOyB9CgogIC8vIFVuaXQgKyBydWxlciBzdGF0ZQogIHZhciB1bml0ID0gJ2ttJzsKICB2YXIgcnVsZXIgPSB7IGFjdGl2ZTogZmFsc2UsIHAxOiBudWxsLCBwMjogbnVsbCB9OwogIGZ1bmN0aW9uIGZtdERpc3QobWV0cmVzKXsKICAgIGlmKHVuaXQgPT09ICdtaScpewogICAgICB2YXIgbWkgPSBtZXRyZXMgLyAxNjA5LjM0NDsKICAgICAgaWYobWkgPj0gMC4yKSByZXR1cm4gbWkudG9GaXhlZCgyKSArICcgbWknOwogICAgICB2YXIgZnQgPSBtZXRyZXMgKiAzLjI4MDg0OwogICAgICByZXR1cm4gZnQudG9GaXhlZCgwKSArICcgZnQnOwogICAgfQogICAgaWYobWV0cmVzID49IDEwMDApIHJldHVybiAobWV0cmVzIC8gMTAwMCkudG9GaXhlZCgyKSArICcga20nOwogICAgcmV0dXJuIG1ldHJlcy50b0ZpeGVkKDApICsgJyBtJzsKICB9CgogIC8vIFBMQVlCQUNLIFNUQVRFIOKAlCBhbmltYXRlcyBhIHRyYWN0b3Igc3ByaXRlIGFsb25nIHRoZSBkcml2ZSBwYXRoIHdpdGggYQogIC8vIGdyYWR1YWxseS1maWxsaW5nIHN3YXRoIGJhbmQgYmVoaW5kIGl0LiBTcGVlZCBpcyAid2FsbC1jbG9jayDDlyBtdWx0aXBsaWVyIjsKICAvLyB3ZSBtYXAgfjEga20gb2YgZHJpdmUtcGF0aCBwZXIgc2Vjb25kIG9mIHdhbGwgY2xvY2sgYXQgMcOXIHNvIGEgdHlwaWNhbAogIC8vIGZpZWxkIHBsYXlzIG91dCBpbiAxMOKAkzIwIHMuCiAgdmFyIHBsYXliYWNrID0gewogICAgaXNQbGF5aW5nOiBmYWxzZSwKICAgIHQ6IDAsICAgICAgICAgICAgICAvLyAwLi4xIHByb2dyZXNzIGFsb25nIHRvdGFsIGRyaXZlLXBhdGggbGVuZ3RoCiAgICBzcGVlZDogMSwgICAgICAgICAgLy8gMSAvIDIgLyA0IG11bHRpcGxpZXIKICAgIGRyaXZlUGF0aDogW10sCiAgICBjdW1MZW46IFswXSwgICAgICAgLy8gY3VtdWxhdGl2ZSBsZW5ndGggdG8gZWFjaCB2ZXJ0ZXgKICAgIHRvdGFsTGVuOiAwLCAgICAgICAvLyBtZXRyZXMKICAgIHdNOiAxOCwgICAgICAgICAgICAvLyBpbXBsZW1lbnQgd2lkdGggZm9yIHN3YXRoCiAgICBsYXN0VGljazogMAogIH07CiAgLy8gQnVpbGQgKG9yIHJlYnVpbGQpIHRoZSBwbGF5YmFjayBwYXRoIGZyb20gYSBsYXlvdXQuIFJlc2V0cyBwcm9ncmVzcy4KICAvLyBTdWJkaXZpZGVzIGxvbmcgc2VnbWVudHMgKGxpbmUtYmFzZWQgcGFzc2VzIGNhbiBiZSA2MDAgbSBlbmQtdG8tZW5kKSBzbwogIC8vIHRoZSBzcHJpdGUgYWR2YW5jZXMgc21vb3RobHkgaW5zdGVhZCBvZiBza2lwcGluZyBpbiBiaWcgY2h1bmtzICh3aGljaAogIC8vIGxvb2tlZCBsaWtlICJ0ZWxlcG9ydHMiIGF0IDTDlyBzcGVlZCkuCiAgZnVuY3Rpb24gc2V0UGxheWJhY2tQYXRoKGxheW91dCwgd00pewogICAgdmFyIHJhdyA9IGxheW91dC5kcml2ZVBhdGggPyBsYXlvdXQuZHJpdmVQYXRoIDogW107CiAgICB2YXIgbWF4U3RlcCA9IE1hdGgubWF4KDIsIHdNKTsgIC8vIG5ldmVyIGV4Y2VlZCBvbmUgaW1wbGVtZW50LXdpZHRoIHBlciBkcml2ZS1wYXRoIHNlZ21lbnQKICAgIHZhciBkZW5zZSA9IFtdOwogICAgZm9yKHZhciBrPTA7IGs8cmF3Lmxlbmd0aDsgaysrKXsKICAgICAgaWYoayA9PT0gMCl7IGRlbnNlLnB1c2gocmF3WzBdKTsgY29udGludWU7IH0KICAgICAgdmFyIHByZXYgPSByYXdbayAtIDFdLCBjdXIgPSByYXdba107CiAgICAgIHZhciBkZHggPSBjdXIueCAtIHByZXYueCwgZGR5ID0gY3VyLnkgLSBwcmV2Lnk7CiAgICAgIHZhciBkbGVuID0gTWF0aC5zcXJ0KGRkeCpkZHggKyBkZHkqZGR5KTsKICAgICAgaWYoZGxlbiA+IG1heFN0ZXApewogICAgICAgIHZhciBuU3ViID0gTWF0aC5jZWlsKGRsZW4gLyBtYXhTdGVwKTsKICAgICAgICBmb3IodmFyIG5zPTE7IG5zPG5TdWI7IG5zKyspewogICAgICAgICAgdmFyIGYgPSBucyAvIG5TdWI7CiAgICAgICAgICBkZW5zZS5wdXNoKHsgeDogcHJldi54ICsgZGR4ICogZiwgeTogcHJldi55ICsgZGR5ICogZiB9KTsKICAgICAgICB9CiAgICAgIH0KICAgICAgZGVuc2UucHVzaChjdXIpOwogICAgfQogICAgcGxheWJhY2suZHJpdmVQYXRoID0gZGVuc2U7CiAgICBwbGF5YmFjay53TSA9IHdNOwogICAgcGxheWJhY2suY3VtTGVuID0gWzBdOwogICAgdmFyIHRvdGFsID0gMDsKICAgIGZvcih2YXIgaT0xOyBpPHBsYXliYWNrLmRyaXZlUGF0aC5sZW5ndGg7IGkrKyl7CiAgICAgIHZhciBkeCA9IHBsYXliYWNrLmRyaXZlUGF0aFtpXS54IC0gcGxheWJhY2suZHJpdmVQYXRoW2ktMV0ueDsKICAgICAgdmFyIGR5ID0gcGxheWJhY2suZHJpdmVQYXRoW2ldLnkgLSBwbGF5YmFjay5kcml2ZVBhdGhbaS0xXS55OwogICAgICB0b3RhbCArPSBNYXRoLnNxcnQoZHgqZHggKyBkeSpkeSk7CiAgICAgIHBsYXliYWNrLmN1bUxlbi5wdXNoKHRvdGFsKTsKICAgIH0KICAgIHBsYXliYWNrLnRvdGFsTGVuID0gdG90YWw7CiAgICBwbGF5YmFjay50ID0gMDsKICAgIHVwZGF0ZVBsYXliYWNrVUkoKTsKICB9CiAgLy8gUmV0dXJuIHRoZSAoeCwgeSwgaGVhZGluZ1JhZCkgYXQgcGFyYW1ldHJpYyBwb3NpdGlvbiB0ICgwLi4xKSBhbG9uZyB0aGUgcGF0aC4KICBmdW5jdGlvbiBwbGF5YmFja1Bvc0F0KHQpewogICAgaWYocGxheWJhY2suZHJpdmVQYXRoLmxlbmd0aCA8IDIpIHJldHVybiBudWxsOwogICAgdmFyIHRhcmdldCA9IHQgKiBwbGF5YmFjay50b3RhbExlbjsKICAgIHZhciBsbyA9IDAsIGhpID0gcGxheWJhY2suY3VtTGVuLmxlbmd0aCAtIDE7CiAgICB3aGlsZShsbyA8IGhpKXsKICAgICAgdmFyIG1pZCA9IChsbyArIGhpICsgMSkgPj4gMTsKICAgICAgaWYocGxheWJhY2suY3VtTGVuW21pZF0gPD0gdGFyZ2V0KSBsbyA9IG1pZDsgZWxzZSBoaSA9IG1pZCAtIDE7CiAgICB9CiAgICBpZihsbyA+PSBwbGF5YmFjay5kcml2ZVBhdGgubGVuZ3RoIC0gMSkgbG8gPSBwbGF5YmFjay5kcml2ZVBhdGgubGVuZ3RoIC0gMjsKICAgIHZhciBzZWdMZW4gPSBwbGF5YmFjay5jdW1MZW5bbG8gKyAxXSAtIHBsYXliYWNrLmN1bUxlbltsb107CiAgICB2YXIgZiA9IHNlZ0xlbiA+IDFlLTYgPyAodGFyZ2V0IC0gcGxheWJhY2suY3VtTGVuW2xvXSkgLyBzZWdMZW4gOiAwOwogICAgdmFyIHAwID0gcGxheWJhY2suZHJpdmVQYXRoW2xvXTsKICAgIHZhciBwMSA9IHBsYXliYWNrLmRyaXZlUGF0aFtsbyArIDFdOwogICAgcmV0dXJuIHsKICAgICAgeDogcDAueCArIChwMS54IC0gcDAueCkgKiBmLAogICAgICB5OiBwMC55ICsgKHAxLnkgLSBwMC55KSAqIGYsCiAgICAgIGhlYWRpbmc6IE1hdGguYXRhbjIocDEueSAtIHAwLnksIHAxLnggLSBwMC54KSwKICAgICAgc2VnSWR4OiBsbwogICAgfTsKICB9CiAgZnVuY3Rpb24gdXBkYXRlUGxheWJhY2tVSSgpewogICAgdmFyIGZpbGxFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtcGItZmlsbCcpOwogICAgdmFyIHRodW1iRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXBiLXRodW1iJyk7CiAgICB2YXIgc3RhdHNFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtcGItc3RhdHMnKTsKICAgIHZhciBwY3QgPSAocGxheWJhY2sudCAqIDEwMCkudG9GaXhlZCgwKTsKICAgIGlmKGZpbGxFbCkgZmlsbEVsLnN0eWxlLndpZHRoID0gcGN0ICsgJyUnOwogICAgaWYodGh1bWJFbCkgdGh1bWJFbC5zdHlsZS5sZWZ0ID0gcGN0ICsgJyUnOwogICAgaWYoc3RhdHNFbCl7CiAgICAgIHN0YXRzRWwudGV4dENvbnRlbnQgPSBwY3QgKyAnJSDCtyAnICsgZm10RGlzdChwbGF5YmFjay50ICogcGxheWJhY2sudG90YWxMZW4pICsgJyAvICcgKyBmbXREaXN0KHBsYXliYWNrLnRvdGFsTGVuKTsKICAgIH0KICB9CiAgZnVuY3Rpb24gZHJhd1N3YXRoKHByb2opewogICAgaWYocGxheWJhY2suZHJpdmVQYXRoLmxlbmd0aCA8IDIgPyB0cnVlIDogcGxheWJhY2sudCA8PSAwKSByZXR1cm47CiAgICB2YXIgdGFyZ2V0ID0gcGxheWJhY2sudCAqIHBsYXliYWNrLnRvdGFsTGVuOwogICAgdmFyIGhhbGZXID0gcGxheWJhY2sud00gKiAwLjUgKiBwcm9qLnNjOwogICAgaWYoaGFsZlcgPCAxKSBoYWxmVyA9IDE7CiAgICBjdHguc2F2ZSgpOwogICAgY3R4LnN0cm9rZVN0eWxlID0gJ3JnYmEoMjQ3LDEwNiwxMiwwLjMyKSc7CiAgICBjdHgubGluZVdpZHRoID0gaGFsZlcgKiAyOwogICAgY3R4LmxpbmVDYXAgPSAncm91bmQnOwogICAgY3R4LmxpbmVKb2luID0gJ3JvdW5kJzsKICAgIGN0eC5iZWdpblBhdGgoKTsKICAgIGN0eC5tb3ZlVG8ocHgocHJvaiwgcGxheWJhY2suZHJpdmVQYXRoWzBdLngpLCBweShwcm9qLCBwbGF5YmFjay5kcml2ZVBhdGhbMF0ueSkpOwogICAgZm9yKHZhciBpPTE7IGk8cGxheWJhY2suZHJpdmVQYXRoLmxlbmd0aDsgaSsrKXsKICAgICAgaWYocGxheWJhY2suY3VtTGVuW2ldIDw9IHRhcmdldCl7CiAgICAgICAgY3R4LmxpbmVUbyhweChwcm9qLCBwbGF5YmFjay5kcml2ZVBhdGhbaV0ueCksIHB5KHByb2osIHBsYXliYWNrLmRyaXZlUGF0aFtpXS55KSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgdmFyIHNlZ0xlbiA9IHBsYXliYWNrLmN1bUxlbltpXSAtIHBsYXliYWNrLmN1bUxlbltpLTFdOwogICAgICAgIHZhciBmID0gc2VnTGVuID4gMWUtNiA\/ICh0YXJnZXQgLSBwbGF5YmFjay5jdW1MZW5baS0xXSkgLyBzZWdMZW4gOiAwOwogICAgICAgIHZhciBleCA9IHBsYXliYWNrLmRyaXZlUGF0aFtpLTFdLnggKyAocGxheWJhY2suZHJpdmVQYXRoW2ldLnggLSBwbGF5YmFjay5kcml2ZVBhdGhbaS0xXS54KSAqIGY7CiAgICAgICAgdmFyIGV5ID0gcGxheWJhY2suZHJpdmVQYXRoW2ktMV0ueSArIChwbGF5YmFjay5kcml2ZVBhdGhbaV0ueSAtIHBsYXliYWNrLmRyaXZlUGF0aFtpLTFdLnkpICogZjsKICAgICAgICBjdHgubGluZVRvKHB4KHByb2osIGV4KSwgcHkocHJvaiwgZXkpKTsKICAgICAgICBicmVhazsKICAgICAgfQogICAgfQogICAgY3R4LnN0cm9rZSgpOwogICAgY3R4LnJlc3RvcmUoKTsKICB9CiAgLy8gR2VvUGFyZC1icmFuZCBlbGV2YXRpb24gcmFpbmJvdzogNSBrZXlwb2ludHMgc3Bhbm5pbmcgdCDiiIggWzAsIDFdCiAgLy8gICAwLjAwIOKGkiBkZWVwIHB1cnBsZSAobG93KQogIC8vICAgMC4yNSDihpIgdGVhbCAvIGN5YW4KICAvLyAgIDAuNTAg4oaSIHNvZnQgeWVsbG93CiAgLy8gICAwLjc1IOKGkiBvcmFuZ2UKICAvLyAgIDEuMDAg4oaSIHJlZCAoaGlnaCkKICAvLyBMaW5lYXJseSBpbnRlcnBvbGF0ZWQgYmV0d2VlbiBhZGphY2VudCBzdG9wcyBpbiBSR0Igc3BhY2UuIE1hdGNoZXMgdGhlCiAgLy8gY29sb3VyIHNjaGVtZSB1c2VkIGluIHRoZSBHZW9QYXJkIFBsYXRmb3JtJ3MgZWxldmF0aW9uIGxlZ2VuZC4KICB2YXIgRUxFVl9TVE9QUyA9IFsKICAgIFsxMDksICA3OSwgMTYyXSwgICAvLyAwLjAwIOKAlCBwdXJwbGUKICAgIFsgNzgsIDE5MiwgMTY3XSwgICAvLyAwLjI1IOKAlCB0ZWFsCiAgICBbMjU1LCAyMzIsIDEzMF0sICAgLy8gMC41MCDigJQgeWVsbG93CiAgICBbMjQ1LCAxNjgsICA5Ml0sICAgLy8gMC43NSDigJQgb3JhbmdlCiAgICBbMjE5LCAgODAsICA4MF0gICAgLy8gMS4wMCDigJQgcmVkCiAgXTsKICBmdW5jdGlvbiBlbGV2Q29sb3IodCl7CiAgICBpZih0IDw9IDApIHJldHVybiBFTEVWX1NUT1BTWzBdOwogICAgaWYodCA+PSAxKSByZXR1cm4gRUxFVl9TVE9QU1tFTEVWX1NUT1BTLmxlbmd0aCAtIDFdOwogICAgdmFyIHNlZyA9IHQgKiAoRUxFVl9TVE9QUy5sZW5ndGggLSAxKTsKICAgIHZhciBpID0gTWF0aC5mbG9vcihzZWcpOwogICAgdmFyIGYgPSBzZWcgLSBpOwogICAgdmFyIGEgPSBFTEVWX1NUT1BTW2ldLCBiID0gRUxFVl9TVE9QU1tpICsgMV07CiAgICByZXR1cm4gWwogICAgICBNYXRoLnJvdW5kKGFbMF0gKyAoYlswXSAtIGFbMF0pICogZiksCiAgICAgIE1hdGgucm91bmQoYVsxXSArIChiWzFdIC0gYVsxXSkgKiBmKSwKICAgICAgTWF0aC5yb3VuZChhWzJdICsgKGJbMl0gLSBhWzJdKSAqIGYpCiAgICBdOwogIH0KICAvLyBUZXJyYWluIGhlYXRtYXAg4oCUIHRyYW5zbHVjZW50IHJhaW5ib3cgZ3JhZGllbnQgc2hvd2luZyBlbGV2YXRpb24uCiAgLy8gSGlnaGVyIGNlbGwgZGVuc2l0eSAoNDjDlzM2KSArIEdlb1BhcmQgYnJhbmQgY29sb3VycyBAIDAuNiBhbHBoYSBzbyB0aGUKICAvLyBlbGV2YXRpb24gcGF0dGVybiByZWFkcyBjbGVhcmx5IHdoaWxlIHBhc3NlcyAvIGFyY3MgLyBzcHJpdGUgc3RheSBsZWdpYmxlLgogIGZ1bmN0aW9uIGRyYXdUZXJyYWluKHByb2opewogICAgaWYoY3VycmVudEZpZWxkID09PSAnY3VzdG9tJykgcmV0dXJuOyAgLy8gbm8gc3ludGhldGljIHRlcnJhaW4gZm9yIHVwbG9hZGVkCiAgICB2YXIgc3RhdHMgPSBmaWVsZFN0YXRzKEJPVU5EQVJZKTsKICAgIHZhciBueCA9IDQ4LCBueSA9IDM2OwogICAgdmFyIGR4ID0gKHN0YXRzLm1heFggLSBzdGF0cy5taW5YKSAvIG54OwogICAgdmFyIGR5ID0gKHN0YXRzLm1heFkgLSBzdGF0cy5taW5ZKSAvIG55OwogICAgLy8gRmluZCBlbGV2YXRpb24gcmFuZ2UgYWNyb3NzIGNlbGxzIGluc2lkZSB0aGUgYm91bmRhcnkKICAgIHZhciBsbyA9IEluZmluaXR5LCBoaSA9IC1JbmZpbml0eTsKICAgIHZhciBncmlkID0gbmV3IEZsb2F0MzJBcnJheShueCAqIG55KTsKICAgIGZvcih2YXIgaXk9MDsgaXk8bnk7IGl5KyspewogICAgICBmb3IodmFyIGl4PTA7IGl4PG54OyBpeCsrKXsKICAgICAgICB2YXIgY3ggPSBzdGF0cy5taW5YICsgKGl4ICsgMC41KSAqIGR4OwogICAgICAgIHZhciBjeSA9IHN0YXRzLm1pblkgKyAoaXkgKyAwLjUpICogZHk7CiAgICAgICAgdmFyIHogPSB0ZXJyYWluQXQoY3gsIGN5KTsKICAgICAgICBncmlkW2l5ICogbnggKyBpeF0gPSB6OwogICAgICAgIGlmKHBvaW50SW5Qb2x5KGN4LCBjeSwgQk9VTkRBUlkpKXsKICAgICAgICAgIGlmKHogPCBsbykgbG8gPSB6OwogICAgICAgICAgaWYoeiA+IGhpKSBoaSA9IHo7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBpZihoaSAtIGxvIDwgMC41KSByZXR1cm47CiAgICBjdHguc2F2ZSgpOwogICAgZm9yKHZhciBpeTI9MDsgaXkyPG55OyBpeTIrKyl7CiAgICAgIGZvcih2YXIgaXgyPTA7IGl4MjxueDsgaXgyKyspewogICAgICAgIHZhciBjeDIgPSBzdGF0cy5taW5YICsgKGl4MiArIDAuNSkgKiBkeDsKICAgICAgICB2YXIgY3kyID0gc3RhdHMubWluWSArIChpeTIgKyAwLjUpICogZHk7CiAgICAgICAgaWYoIXBvaW50SW5Qb2x5KGN4MiwgY3kyLCBCT1VOREFSWSkpIGNvbnRpbnVlOwogICAgICAgIHZhciB6MiA9IGdyaWRbaXkyICogbnggKyBpeDJdOwogICAgICAgIHZhciB0ID0gKHoyIC0gbG8pIC8gKGhpIC0gbG8pOwogICAgICAgIHZhciBjID0gZWxldkNvbG9yKHQpOwogICAgICAgIGN0eC5maWxsU3R5bGUgPSAncmdiYSgnICsgY1swXSArICcsJyArIGNbMV0gKyAnLCcgKyBjWzJdICsgJywwLjYpJzsKICAgICAgICB2YXIgeDAgPSBweChwcm9qLCBzdGF0cy5taW5YICsgaXgyICogZHgpOwogICAgICAgIHZhciB5MCA9IHB5KHByb2osIHN0YXRzLm1pblkgKyBpeTIgKiBkeSk7CiAgICAgICAgdmFyIHgxID0gcHgocHJvaiwgc3RhdHMubWluWCArIChpeDIgKyAxKSAqIGR4KTsKICAgICAgICB2YXIgeTEgPSBweShwcm9qLCBzdGF0cy5taW5ZICsgKGl5MiArIDEpICogZHkpOwogICAgICAgIGN0eC5maWxsUmVjdCh4MCAtIDAuNSwgeTAgLSAwLjUsICh4MSAtIHgwKSArIDEsICh5MSAtIHkwKSArIDEpOwogICAgICB9CiAgICB9CiAgICBjdHgucmVzdG9yZSgpOwogIH0KCiAgLy8gU29pbCBjb21wYWN0aW9uIHpvbmVzIOKAlCB3aGVyZXZlciB0aGUgbWFjaGluZSB0dXJucyBhcm91bmQsIGl0J3MgY29tcGFjdGluZwogIC8vIHRoZSBoZWFkbGFuZCBzdHJpcCBzb2lsIHdpdGggZXh0cmEgcGFzc2VzLiBWaXN1YWxpc2UgYXMgdHJhbnNsdWNlbnQgdmlvbGV0CiAgLy8gc3Ryb2tlcyB1bmRlciBlYWNoIHR1cm4tYXJjIHN3YXRoOyBtdWx0aXBsZSBuZWFyYnkgYXJjcyBhZGRpdGl2ZWx5IGRhcmtlbgogIC8vIHRoZSBzYW1lIGFyZWEsIG1ha2luZyBoZWF2eS1jb21wYWN0aW9uIGNsdXN0ZXJzIHZpc2libGUuCiAgZnVuY3Rpb24gZHJhd0NvbXBhY3Rpb25ab25lcyhwcm9qLCBsYXlvdXQpewogICAgaWYoIWxheW91dC50dXJuQXJjcyA\/IHRydWUgOiBsYXlvdXQudHVybkFyY3MubGVuZ3RoID09PSAwKSByZXR1cm47CiAgICB2YXIgaGFsZlcgPSBwbGF5YmFjay53TSAqIDAuNSAqIHByb2ouc2M7CiAgICBpZihoYWxmVyA8IDEpIGhhbGZXID0gMTsKICAgIGN0eC5zYXZlKCk7CiAgICBjdHguc3Ryb2tlU3R5bGUgPSAncmdiYSgxNjIsMjgsMTc1LDAuMjIpJzsgIC8vIHZpb2xldCwgMjIlIGFscGhhIHNvIG92ZXJsYXBzIHN0YWNrIHZpc2libHkKICAgIGN0eC5saW5lV2lkdGggPSBoYWxmVyAqIDI7CiAgICBjdHgubGluZUNhcCA9ICdyb3VuZCc7CiAgICBjdHgubGluZUpvaW4gPSAncm91bmQnOwogICAgZm9yKHZhciB0aT0wOyB0aTxsYXlvdXQudHVybkFyY3MubGVuZ3RoOyB0aSsrKXsKICAgICAgdmFyIGFyYyA9IGxheW91dC50dXJuQXJjc1t0aV07CiAgICAgIGlmKGFyYy5jb29yZHMubGVuZ3RoIDwgMikgY29udGludWU7CiAgICAgIGN0eC5iZWdpblBhdGgoKTsKICAgICAgY3R4Lm1vdmVUbyhweChwcm9qLCBhcmMuY29vcmRzWzBdLngpLCBweShwcm9qLCBhcmMuY29vcmRzWzBdLnkpKTsKICAgICAgZm9yKHZhciBhYz0xOyBhYzxhcmMuY29vcmRzLmxlbmd0aDsgYWMrKyl7CiAgICAgICAgY3R4LmxpbmVUbyhweChwcm9qLCBhcmMuY29vcmRzW2FjXS54KSwgcHkocHJvaiwgYXJjLmNvb3Jkc1thY10ueSkpOwogICAgICB9CiAgICAgIGN0eC5zdHJva2UoKTsKICAgIH0KICAgIGN0eC5yZXN0b3JlKCk7CiAgfQogIC8vIERpcmVjdGlvbiBhcnJvd3Mg4oCUIHNtYWxsIGNoZXZyb24gYXQgdGhlIG1pZGRsZSBvZiBlYWNoIHBhc3MgKyBhcmMsIHBvaW50aW5nCiAgLy8gYWxvbmcgdGhlIGRyaXZlIGRpcmVjdGlvbi4gTWFrZXMgdGhlIHNuYWtlL3NlcnBlbnRpbmUgZmxvdyB2aXNpYmxlLgogIGZ1bmN0aW9uIGRyYXdEaXJlY3Rpb25BcnJvd3MocHJvaiwgbGF5b3V0KXsKICAgIHZhciBhcnJvd1B4ID0gODsKICAgIGZ1bmN0aW9uIGRyYXdBcnJvdyhtaWRYLCBtaWRZLCBoZWFkaW5nUmFkLCBjb2xvcil7CiAgICAgIGN0eC5zYXZlKCk7CiAgICAgIGN0eC50cmFuc2xhdGUobWlkWCwgbWlkWSk7CiAgICAgIGN0eC5yb3RhdGUoaGVhZGluZ1JhZCk7CiAgICAgIGN0eC5maWxsU3R5bGUgPSBjb2xvcjsKICAgICAgY3R4LmJlZ2luUGF0aCgpOwogICAgICBjdHgubW92ZVRvKGFycm93UHgsIDApOwogICAgICBjdHgubGluZVRvKC1hcnJvd1B4ICogMC42LCAtYXJyb3dQeCAqIDAuNik7CiAgICAgIGN0eC5saW5lVG8oLWFycm93UHggKiAwLjYsIGFycm93UHggKiAwLjYpOwogICAgICBjdHguY2xvc2VQYXRoKCk7CiAgICAgIGN0eC5maWxsKCk7CiAgICAgIGN0eC5yZXN0b3JlKCk7CiAgICB9CiAgICAvLyBQYXNzIGFycm93cyDigJQgb3JhbmdlIHRvIG1hdGNoIHRoZSBwYXNzIHN0cm9rZXMuIFVzZSBvcmRlcmVkUGFzc2VzCiAgICAvLyAocG9zdC1zbmFrZSwgZHJpdmUtZGlyZWN0aW9uIG9yaWVudGVkKSBzbyBjaGV2cm9ucyBtYXRjaCBhY3R1YWwgZmxvdzoKICAgIC8vIG9kZCBwYXNzZXMgZ2V0IHJldmVyc2VkIGFycm93cywgbWlycm9yaW5nIHRoZSBvcGVyYXRvcidzIHJldmVyc2UgZHJpdmUuCiAgICB2YXIgcGFzc0xpc3QgPSBsYXlvdXQub3JkZXJlZFBhc3NlcyA\/IGxheW91dC5vcmRlcmVkUGFzc2VzIDogbGF5b3V0LnBhc3NlczsKICAgIGlmKHBhc3NMaXN0KXsKICAgICAgZm9yKHZhciBwPTA7IHA8cGFzc0xpc3QubGVuZ3RoOyBwKyspewogICAgICAgIHZhciBwYSA9IHBhc3NMaXN0W3BdOwogICAgICAgIGlmKHBhLmtpbmQgPT09ICdoZWFkbGFuZC1yaW5nJykgY29udGludWU7CiAgICAgICAgdmFyIGF4LCBheSwgYngsIGJ5OwogICAgICAgIGlmKHBhLnNhbXBsZXMgPyBwYS5zYW1wbGVzLmxlbmd0aCA+PSAyIDogZmFsc2UpewogICAgICAgICAgdmFyIG1pZEkgPSBNYXRoLmZsb29yKHBhLnNhbXBsZXMubGVuZ3RoIC8gMik7CiAgICAgICAgICBheCA9IHBhLnNhbXBsZXNbbWlkSSAtIDFdLng7IGF5ID0gcGEuc2FtcGxlc1ttaWRJIC0gMV0ueTsKICAgICAgICAgIGJ4ID0gcGEuc2FtcGxlc1ttaWRJXS54OyAgICAgYnkgPSBwYS5zYW1wbGVzW21pZEldLnk7CiAgICAgICAgfSBlbHNlIGlmKHBhLngwICE9PSB1bmRlZmluZWQpewogICAgICAgICAgYXggPSBwYS54MDsgYXkgPSBwYS55MDsgYnggPSBwYS54MTsgYnkgPSBwYS55MTsKICAgICAgICB9IGVsc2UgY29udGludWU7CiAgICAgICAgdmFyIG1pZFggPSBweChwcm9qLCAoYXggKyBieCkgKiAwLjUpOwogICAgICAgIHZhciBtaWRZID0gcHkocHJvaiwgKGF5ICsgYnkpICogMC41KTsKICAgICAgICBkcmF3QXJyb3cobWlkWCwgbWlkWSwgTWF0aC5hdGFuMihieSAtIGF5LCBieCAtIGF4KSwgJyNmNzZhMGMnKTsKICAgICAgfQogICAgfQogICAgLy8gVHVybmFyb3VuZCBhcnJvd3Mg4oCUIHZpb2xldCwgaGFsZndheSB0aHJvdWdoIHRoZSBhcmMKICAgIGlmKGxheW91dC50dXJuQXJjcyl7CiAgICAgIGZvcih2YXIgdGk9MDsgdGk8bGF5b3V0LnR1cm5BcmNzLmxlbmd0aDsgdGkrKyl7CiAgICAgICAgdmFyIGFyYyA9IGxheW91dC50dXJuQXJjc1t0aV0uY29vcmRzOwogICAgICAgIGlmKGFyYy5sZW5ndGggPCAzKSBjb250aW51ZTsKICAgICAgICB2YXIgbWkgPSBNYXRoLmZsb29yKGFyYy5sZW5ndGggLyAyKTsKICAgICAgICB2YXIgYVggPSBhcmNbbWkgLSAxXS54LCBhWSA9IGFyY1ttaSAtIDFdLnk7CiAgICAgICAgdmFyIGJYID0gYXJjW21pXS54LCAgICAgYlkgPSBhcmNbbWldLnk7CiAgICAgICAgdmFyIGFtWCA9IHB4KHByb2osIChhWCArIGJYKSAqIDAuNSk7CiAgICAgICAgdmFyIGFtWSA9IHB5KHByb2osIChhWSArIGJZKSAqIDAuNSk7CiAgICAgICAgZHJhd0Fycm93KGFtWCwgYW1ZLCBNYXRoLmF0YW4yKGJZIC0gYVksIGJYIC0gYVgpLCAnI2EyMWNhZicpOwogICAgICB9CiAgICB9CiAgfQogIGZ1bmN0aW9uIGRyYXdTcHJpdGUocHJvail7CiAgICB2YXIgcG9zID0gcGxheWJhY2tQb3NBdChwbGF5YmFjay50KTsKICAgIGlmKCFwb3MpIHJldHVybjsKICAgIHZhciBoYWxmVyA9IHBsYXliYWNrLndNICogMC41ICogcHJvai5zYzsKICAgIGlmKGhhbGZXIDwgNikgaGFsZlcgPSA2OwogICAgdmFyIGJvZHlMZW4gPSBNYXRoLm1heCgxMCwgaGFsZlcgKiAwLjYpOwogICAgY3R4LnNhdmUoKTsKICAgIGN0eC50cmFuc2xhdGUocHgocHJvaiwgcG9zLngpLCBweShwcm9qLCBwb3MueSkpOwogICAgY3R4LnJvdGF0ZShwb3MuaGVhZGluZyk7CiAgICAvLyBJbXBsZW1lbnQgYmFyICh0aGUgd2lkZSBwaWVjZSBiZWhpbmQgdGhlIGNhYiDigJQgb3JhbmdlIHRvIG1hdGNoIHBhc3NlcykKICAgIGN0eC5maWxsU3R5bGUgPSAnI2Y3NmEwYyc7CiAgICBjdHguZmlsbFJlY3QoLWJvZHlMZW4gKiAwLjQsIC1oYWxmVywgYm9keUxlbiAqIDAuMzUsIGhhbGZXICogMik7CiAgICAvLyBUcmFjdG9yIGNhYiAoY29tcGFjdCBkYXJrLWdyZWVuIGJsb2NrIGluIGZyb250IG9mIHRoZSBpbXBsZW1lbnQpCiAgICBjdHguZmlsbFN0eWxlID0gJyMxNDUzMjgnOwogICAgY3R4LmZpbGxSZWN0KDAsIC1ib2R5TGVuICogMC4zNSwgYm9keUxlbiAqIDAuNTUsIGJvZHlMZW4gKiAwLjcpOwogICAgLy8gQ2FiIHJvb2YKICAgIGN0eC5maWxsU3R5bGUgPSAnIzFhNzk1MSc7CiAgICBjdHguZmlsbFJlY3QoYm9keUxlbiAqIDAuMSwgLWJvZHlMZW4gKiAwLjIyLCBib2R5TGVuICogMC4zLCBib2R5TGVuICogMC40NCk7CiAgICBjdHgucmVzdG9yZSgpOwogIH0KCiAgZnVuY3Rpb24gZHJhdyhsYXlvdXQpewogICAgdmFyIHJlY3QgPSBjYW52YXMuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7CiAgICBjdHguY2xlYXJSZWN0KDAsIDAsIHJlY3Qud2lkdGgsIHJlY3QuaGVpZ2h0KTsKICAgIHZhciBwcm9qID0gZ2V0U2NhbGUoKTsKICAgIHZhciBib3VuZGFyeSA9IGxheW91dC5ib3VuZGFyeSA\/IGxheW91dC5ib3VuZGFyeSA6IEJPVU5EQVJZOwogICAgdmFyIGhhc0hlYWRsYW5kID0gbGF5b3V0LmludGVyaW9yID8gbGF5b3V0LmludGVyaW9yICE9PSBib3VuZGFyeSA6IGZhbHNlOwogICAgLy8gVGVycmFpbiBoZWF0bWFwIGJlaGluZCBldmVyeXRoaW5nCiAgICBkcmF3VGVycmFpbihwcm9qKTsKICAgIC8vIEhlYWRsYW5kIHN0cmlwID0gYm91bmRhcnkgbWludXMgaW50ZXJpb3IgKGV2ZW4tb2RkIGZpbGwpCiAgICBpZihoYXNIZWFkbGFuZCl7CiAgICAgIGN0eC5zYXZlKCk7CiAgICAgIGN0eC5maWxsU3R5bGUgPSAncmdiYSgyNiwxMjEsODEsMC4xOCknOwogICAgICBjdHguYmVnaW5QYXRoKCk7CiAgICAgIGZvcih2YXIgaT0wOyBpPGJvdW5kYXJ5Lmxlbmd0aDsgaSsrKXsKICAgICAgICB2YXIgYnggPSBweChwcm9qLCBib3VuZGFyeVtpXS54KTsKICAgICAgICB2YXIgYnkgPSBweShwcm9qLCBib3VuZGFyeVtpXS55KTsKICAgICAgICBpZihpID09PSAwKSBjdHgubW92ZVRvKGJ4LCBieSk7IGVsc2UgY3R4LmxpbmVUbyhieCwgYnkpOwogICAgICB9CiAgICAgIGN0eC5jbG9zZVBhdGgoKTsKICAgICAgdmFyIGlubmVyID0gbGF5b3V0LmludGVyaW9yOwogICAgICBmb3IodmFyIGo9aW5uZXIubGVuZ3RoLTE7IGo+PTA7IGotLSl7CiAgICAgICAgdmFyIGl4ID0gcHgocHJvaiwgaW5uZXJbal0ueCk7CiAgICAgICAgdmFyIGl5ID0gcHkocHJvaiwgaW5uZXJbal0ueSk7CiAgICAgICAgaWYoaiA9PT0gaW5uZXIubGVuZ3RoLTEpIGN0eC5tb3ZlVG8oaXgsIGl5KTsgZWxzZSBjdHgubGluZVRvKGl4LCBpeSk7CiAgICAgIH0KICAgICAgY3R4LmNsb3NlUGF0aCgpOwogICAgICBjdHguZmlsbCgnZXZlbm9kZCcpOwogICAgICBjdHgucmVzdG9yZSgpOwogICAgfQogICAgLy8gRHJpdmFibGUgb3V0bGluZSAob25seSBpZiBvdXRzaWRlQnVmZmVyID4gMCDihpIgZHJpdmFibGUg4omgIGJvdW5kYXJ5KQogICAgaWYobGF5b3V0LmRyaXZhYmxlID8gbGF5b3V0LmRyaXZhYmxlICE9PSBib3VuZGFyeSA6IGZhbHNlKXsKICAgICAgY3R4LnNhdmUoKTsKICAgICAgY3R4LnN0cm9rZVN0eWxlID0gJ3JnYmEoMjAsODMsNDAsMC4zNSknOwogICAgICBjdHguc2V0TGluZURhc2goWzQsIDRdKTsKICAgICAgY3R4LmxpbmVXaWR0aCA9IDE7CiAgICAgIGN0eC5iZWdpblBhdGgoKTsKICAgICAgZm9yKHZhciBkdj0wOyBkdjxsYXlvdXQuZHJpdmFibGUubGVuZ3RoOyBkdisrKXsKICAgICAgICB2YXIgZHZ4ID0gcHgocHJvaiwgbGF5b3V0LmRyaXZhYmxlW2R2XS54KTsKICAgICAgICB2YXIgZHZ5ID0gcHkocHJvaiwgbGF5b3V0LmRyaXZhYmxlW2R2XS55KTsKICAgICAgICBpZihkdiA9PT0gMCkgY3R4Lm1vdmVUbyhkdngsIGR2eSk7IGVsc2UgY3R4LmxpbmVUbyhkdngsIGR2eSk7CiAgICAgIH0KICAgICAgY3R4LmNsb3NlUGF0aCgpOwogICAgICBjdHguc3Ryb2tlKCk7CiAgICAgIGN0eC5yZXN0b3JlKCk7CiAgICB9CiAgICAvLyBGaWVsZCBib3VuZGFyeQogICAgY3R4LnNhdmUoKTsKICAgIGN0eC5zdHJva2VTdHlsZSA9ICcjMTQ1MzI4JzsKICAgIGN0eC5saW5lV2lkdGggPSAyOwogICAgY3R4LmxpbmVKb2luID0gJ3JvdW5kJzsKICAgIGN0eC5iZWdpblBhdGgoKTsKICAgIGZvcih2YXIgaz0wOyBrPGJvdW5kYXJ5Lmxlbmd0aDsgaysrKXsKICAgICAgdmFyIGJ4RiA9IHB4KHByb2osIGJvdW5kYXJ5W2tdLngpOwogICAgICB2YXIgYnlGID0gcHkocHJvaiwgYm91bmRhcnlba10ueSk7CiAgICAgIGlmKGsgPT09IDApIGN0eC5tb3ZlVG8oYnhGLCBieUYpOyBlbHNlIGN0eC5saW5lVG8oYnhGLCBieUYpOwogICAgfQogICAgY3R4LmNsb3NlUGF0aCgpOwogICAgY3R4LnN0cm9rZSgpOwogICAgY3R4LnJlc3RvcmUoKTsKICAgIC8vIEludGVyaW9yIG91dGxpbmUgKGlubmVyIGVkZ2Ugb2YgaGVhZGxhbmQgc3RyaXApCiAgICBpZihoYXNIZWFkbGFuZCl7CiAgICAgIGN0eC5zYXZlKCk7CiAgICAgIGN0eC5zdHJva2VTdHlsZSA9ICcjMWE3OTUxJzsKICAgICAgY3R4LmxpbmVXaWR0aCA9IDEuNTsKICAgICAgY3R4LmJlZ2luUGF0aCgpOwogICAgICBmb3IodmFyIHJwPTA7IHJwPGxheW91dC5pbnRlcmlvci5sZW5ndGg7IHJwKyspewogICAgICAgIHZhciByeCA9IHB4KHByb2osIGxheW91dC5pbnRlcmlvcltycF0ueCk7CiAgICAgICAgdmFyIHJ5ID0gcHkocHJvaiwgbGF5b3V0LmludGVyaW9yW3JwXS55KTsKICAgICAgICBpZihycCA9PT0gMCkgY3R4Lm1vdmVUbyhyeCwgcnkpOyBlbHNlIGN0eC5saW5lVG8ocngsIHJ5KTsKICAgICAgfQogICAgICBjdHguY2xvc2VQYXRoKCk7CiAgICAgIGN0eC5zdHJva2UoKTsKICAgICAgY3R4LnJlc3RvcmUoKTsKICAgIH0KICAgIC8vIFNvaWwgY29tcGFjdGlvbiB6b25lcyAoYWx3YXlzLXZpc2libGUgdmlvbGV0IGdsb3cgdW5kZXIgZWFjaCB0dXJuIGFyYykKICAgIGRyYXdDb21wYWN0aW9uWm9uZXMocHJvaiwgbGF5b3V0KTsKICAgIC8vIFN3YXRoIGNvdmVyYWdlIGJhbmQgKGZpbGxlZCBhcyBwbGF5YmFjayBwcm9ncmVzc2VzKQogICAgZHJhd1N3YXRoKHByb2opOwogICAgLy8gUGFzc2VzICh0aGUgd29ya2VkIGd1aWRhbmNlIGxpbmVzKQogICAgY3R4LnNhdmUoKTsKICAgIGN0eC5zdHJva2VTdHlsZSA9ICcjZjc2YTBjJzsKICAgIGN0eC5saW5lV2lkdGggPSAxLjI7CiAgICBjdHgubGluZUNhcCA9ICdyb3VuZCc7CiAgICBmb3IodmFyIHA9MDsgcDxsYXlvdXQucGFzc2VzLmxlbmd0aDsgcCsrKXsKICAgICAgdmFyIHBhID0gbGF5b3V0LnBhc3Nlc1twXTsKICAgICAgY3R4LmJlZ2luUGF0aCgpOwogICAgICBpZihwYS5zYW1wbGVzKXsKICAgICAgICBmb3IodmFyIHBzPTA7IHBzPHBhLnNhbXBsZXMubGVuZ3RoOyBwcysrKXsKICAgICAgICAgIHZhciBzc3ggPSBweChwcm9qLCBwYS5zYW1wbGVzW3BzXS54KTsKICAgICAgICAgIHZhciBzc3kgPSBweShwcm9qLCBwYS5zYW1wbGVzW3BzXS55KTsKICAgICAgICAgIGlmKHBzID09PSAwKSBjdHgubW92ZVRvKHNzeCwgc3N5KTsgZWxzZSBjdHgubGluZVRvKHNzeCwgc3N5KTsKICAgICAgICB9CiAgICAgIH0gZWxzZSB7CiAgICAgICAgY3R4Lm1vdmVUbyhweChwcm9qLCBwYS54MCksIHB5KHByb2osIHBhLnkwKSk7CiAgICAgICAgY3R4LmxpbmVUbyhweChwcm9qLCBwYS54MSksIHB5KHByb2osIHBhLnkxKSk7CiAgICAgIH0KICAgICAgY3R4LnN0cm9rZSgpOwogICAgfQogICAgY3R4LnJlc3RvcmUoKTsKICAgIC8vIFR1cm4gYXJjcyDigJQgcHVycGxlIHNvbGlkIGZvciBvayBVLXR1cm5zLCByZWQgZGFzaGVkIGZvciBwcm9ibGVtIGFyY3MsCiAgICAvLyB0ZWFsIGRvdHRlZCBmb3IgaGVhZGxhbmQgdHJhdmVyc2VzIChubyBzeW50aGV0aWMgdS10dXJuIOKAlCBvcGVyYXRvciBkaWQKICAgIC8vIHNtYWxsIHBpdm90cyArIGRyb3ZlIGFjcm9zcyB0aGUgd29ya2VkIGhlYWRsYW5kKS4KICAgIGlmKGxheW91dC50dXJuQXJjcyA\/IGxheW91dC50dXJuQXJjcy5sZW5ndGggOiBmYWxzZSl7CiAgICAgIGN0eC5zYXZlKCk7CiAgICAgIGN0eC5saW5lQ2FwID0gJ3JvdW5kJzsKICAgICAgY3R4LmxpbmVKb2luID0gJ3JvdW5kJzsKICAgICAgZm9yKHZhciB0aT0wOyB0aTxsYXlvdXQudHVybkFyY3MubGVuZ3RoOyB0aSsrKXsKICAgICAgICB2YXIgYXJjID0gbGF5b3V0LnR1cm5BcmNzW3RpXTsKICAgICAgICB2YXIgaXNUcmF2ZXJzZSA9IGFyYy5raW5kID09PSAndHJhdmVyc2UnOwogICAgICAgIHZhciBpc1JpbmdSb3V0ZSA9IGFyYy5raW5kID09PSAncmluZy1yb3V0ZSc7CiAgICAgICAgaWYoaXNUcmF2ZXJzZSl7CiAgICAgICAgICAvLyBTaG9ydCBzdHJhaWdodC1saW5lIHRyYXZlcnNlcyDigJQgc3RpbGwgcmVhbCB0dXJuYXJvdW5kcywgcmVuZGVyCiAgICAgICAgICAvLyB3aXRoIHRoZSBzYW1lIHZpb2xldCBidXQgZGFzaGVkIHNvIHRoZSB1c2VyIHNlZXMgdGhleSBleGlzdC4KICAgICAgICAgIGN0eC5zdHJva2VTdHlsZSA9ICcjYTIxY2FmJzsKICAgICAgICAgIGN0eC5saW5lV2lkdGggPSAxLjg7CiAgICAgICAgICBjdHguc2V0TGluZURhc2goWzYsIDRdKTsKICAgICAgICB9IGVsc2UgaWYoaXNSaW5nUm91dGUpewogICAgICAgICAgLy8gUmluZyByb3V0ZXMg4oCUIG9wZXJhdG9yIGRyb3ZlIGFsb25nIHRoZSBoZWFkbGFuZC1yaW5nIHRvIHJlYWNoCiAgICAgICAgICAvLyB0aGUgbmV4dCBwYXNzLiBTaG93IGFzIGRhc2hlZCB2aW9sZXQgdG9vIGJ1dCB3aXRoIGEgdGlnaHRlcgogICAgICAgICAgLy8gZGFzaCBwYXR0ZXJuIHNvIHRoZSByb3V0aW5nIGlzIHZpc3VhbGx5IGRpc3RpbmN0LgogICAgICAgICAgY3R4LnN0cm9rZVN0eWxlID0gJyNhMjFjYWYnOwogICAgICAgICAgY3R4LmxpbmVXaWR0aCA9IDEuNjsKICAgICAgICAgIGN0eC5zZXRMaW5lRGFzaChbMywgM10pOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAvLyBVLXR1cm4gYXJjIOKAlCBzb2xpZCB2aW9sZXQgZm9yIG9rLCByZWQtZGFzaGVkIHdoZW4gZ2VvbWV0cnkgZmFpbGVkLgogICAgICAgICAgY3R4LnN0cm9rZVN0eWxlID0gYXJjLm9rID8gJyNhMjFjYWYnIDogJyNkYzI2MjYnOwogICAgICAgICAgY3R4LmxpbmVXaWR0aCA9IGFyYy5vayA\/IDIgOiAxLjQ7CiAgICAgICAgICBjdHguc2V0TGluZURhc2goYXJjLm9rID8gW10gOiBbMywgM10pOwogICAgICAgIH0KICAgICAgICBjdHguYmVnaW5QYXRoKCk7CiAgICAgICAgZm9yKHZhciBhYz0wOyBhYzxhcmMuY29vcmRzLmxlbmd0aDsgYWMrKyl7CiAgICAgICAgICB2YXIgYWV4ID0gcHgocHJvaiwgYXJjLmNvb3Jkc1thY10ueCk7CiAgICAgICAgICB2YXIgYWV5ID0gcHkocHJvaiwgYXJjLmNvb3Jkc1thY10ueSk7CiAgICAgICAgICBpZihhYyA9PT0gMCkgY3R4Lm1vdmVUbyhhZXgsIGFleSk7IGVsc2UgY3R4LmxpbmVUbyhhZXgsIGFleSk7CiAgICAgICAgfQogICAgICAgIGN0eC5zdHJva2UoKTsKICAgICAgfQogICAgICBjdHgucmVzdG9yZSgpOwogICAgfQogICAgLy8gRGlyZWN0aW9uIGFycm93cyBvbiBwYXNzZXMgKyB0dXJuIGFyY3MgKGFib3ZlIGxpbmVzLCBiZWxvdyBzcHJpdGUpCiAgICBkcmF3RGlyZWN0aW9uQXJyb3dzKHByb2osIGxheW91dCk7CiAgICAvLyBUcmFjdG9yIHNwcml0ZSBvbiB0b3AKICAgIGRyYXdTcHJpdGUocHJvaik7CiAgICAvLyBTY2FsZSBiYXIg4oCUIHBpY2sgYSBuaWNlIHJvdW5kIG1ldHJlcyB2YWx1ZSBmb3IgfjYwIHB4IG9uIHNjcmVlbiBhbmQKICAgIC8vIGFkanVzdCB0aGUgYmFyIHdpZHRoIHRvIG1hdGNoIHRoZSBjaG9zZW4gdmFsdWUgYXQgY3VycmVudCBwcm9qLnNjLgogICAgdmFyIHNjYWxlQmFyRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXNjYWxlJyk7CiAgICB2YXIgc2NhbGVMYmxFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtc2NhbGUtbGJsJyk7CiAgICBpZihzY2FsZUJhckVsID8gc2NhbGVMYmxFbCA6IGZhbHNlKXsKICAgICAgdmFyIHRhcmdldFB4ID0gNjA7CiAgICAgIHZhciByYXdNZXRyZXMgPSB0YXJnZXRQeCAvIHByb2ouc2M7CiAgICAgIC8vIFNuYXAgdG8gYSAxLzIvNSDDlyAxMOKBvyBwYXR0ZXJuIChzdGFuZGFyZCBjYXJ0b2dyYXBoaWMgc2NhbGUgc3RlcHMpCiAgICAgIHZhciBwb3cxMCA9IE1hdGgucG93KDEwLCBNYXRoLmZsb29yKE1hdGgubG9nKHJhd01ldHJlcykgLyBNYXRoLkxOMTApKTsKICAgICAgdmFyIHNuYXBWYWw7CiAgICAgIHZhciBsZWFkID0gcmF3TWV0cmVzIC8gcG93MTA7CiAgICAgIGlmKGxlYWQgPCAxLjUpIHNuYXBWYWwgPSAxICogcG93MTA7CiAgICAgIGVsc2UgaWYobGVhZCA8IDMuNSkgc25hcFZhbCA9IDIgKiBwb3cxMDsKICAgICAgZWxzZSBpZihsZWFkIDwgNy41KSBzbmFwVmFsID0gNSAqIHBvdzEwOwogICAgICBlbHNlIHNuYXBWYWwgPSAxMCAqIHBvdzEwOwogICAgICB2YXIgYmFyUHggPSBzbmFwVmFsICogcHJvai5zYzsKICAgICAgdmFyIGJhckVsID0gc2NhbGVCYXJFbC5xdWVyeVNlbGVjdG9yKCcuZ3BsLXNjYWxlLWJhcicpOwogICAgICBpZihiYXJFbCkgYmFyRWwuc3R5bGUud2lkdGggPSBiYXJQeC50b0ZpeGVkKDApICsgJ3B4JzsKICAgICAgc2NhbGVMYmxFbC50ZXh0Q29udGVudCA9IGZtdERpc3Qoc25hcFZhbCk7CiAgICB9CiAgICAvLyBSdWxlciBsaW5lIG9uIGFic29sdXRlIHRvcAogICAgaWYocnVsZXIucDEgPyBydWxlci5wMiA6IGZhbHNlKXsKICAgICAgY3R4LnNhdmUoKTsKICAgICAgY3R4LnN0cm9rZVN0eWxlID0gJyNkYzI2MjYnOwogICAgICBjdHgubGluZVdpZHRoID0gMjsKICAgICAgY3R4LnNldExpbmVEYXNoKFs2LCA0XSk7CiAgICAgIGN0eC5iZWdpblBhdGgoKTsKICAgICAgY3R4Lm1vdmVUbyhweChwcm9qLCBydWxlci5wMS54KSwgcHkocHJvaiwgcnVsZXIucDEueSkpOwogICAgICBjdHgubGluZVRvKHB4KHByb2osIHJ1bGVyLnAyLngpLCBweShwcm9qLCBydWxlci5wMi55KSk7CiAgICAgIGN0eC5zdHJva2UoKTsKICAgICAgY3R4LnJlc3RvcmUoKTsKICAgICAgLy8gRW5kcG9pbnQgZG90cwogICAgICBjdHguc2F2ZSgpOwogICAgICBjdHguZmlsbFN0eWxlID0gJyNkYzI2MjYnOwogICAgICBjdHguYmVnaW5QYXRoKCk7IGN0eC5hcmMocHgocHJvaiwgcnVsZXIucDEueCksIHB5KHByb2osIHJ1bGVyLnAxLnkpLCA0LCAwLCBNYXRoLlBJKjIpOyBjdHguZmlsbCgpOwogICAgICBjdHguYmVnaW5QYXRoKCk7IGN0eC5hcmMocHgocHJvaiwgcnVsZXIucDIueCksIHB5KHByb2osIHJ1bGVyLnAyLnkpLCA0LCAwLCBNYXRoLlBJKjIpOyBjdHguZmlsbCgpOwogICAgICBjdHgucmVzdG9yZSgpOwogICAgICAvLyBEaXN0YW5jZSBsYWJlbAogICAgICB2YXIgcmR4ID0gcnVsZXIucDIueCAtIHJ1bGVyLnAxLng7CiAgICAgIHZhciByZHkgPSBydWxlci5wMi55IC0gcnVsZXIucDEueTsKICAgICAgdmFyIHJEaXN0ID0gTWF0aC5zcXJ0KHJkeCpyZHggKyByZHkqcmR5KTsKICAgICAgdmFyIGxhYmVsTXggPSBweChwcm9qLCAocnVsZXIucDEueCArIHJ1bGVyLnAyLngpICogMC41KTsKICAgICAgdmFyIGxhYmVsTXkgPSBweShwcm9qLCAocnVsZXIucDEueSArIHJ1bGVyLnAyLnkpICogMC41KTsKICAgICAgY3R4LnNhdmUoKTsKICAgICAgY3R4LmZvbnQgPSAnNzAwIDEycHggIkRNIE1vbm8iLCB1aS1tb25vc3BhY2UsIG1vbm9zcGFjZSc7CiAgICAgIHZhciBsYWJlbCA9IGZtdERpc3QockRpc3QpOwogICAgICB2YXIgdHcgPSBjdHgubWVhc3VyZVRleHQobGFiZWwpLndpZHRoICsgMTQ7CiAgICAgIGN0eC5maWxsU3R5bGUgPSAncmdiYSgyMjAsMzgsMzgsMC45NSknOwogICAgICBjdHguZmlsbFJlY3QobGFiZWxNeCAtIHR3IC8gMiwgbGFiZWxNeSAtIDExLCB0dywgMjIpOwogICAgICBjdHguZmlsbFN0eWxlID0gJyNmZmYnOwogICAgICBjdHgudGV4dEFsaWduID0gJ2NlbnRlcic7CiAgICAgIGN0eC50ZXh0QmFzZWxpbmUgPSAnbWlkZGxlJzsKICAgICAgY3R4LmZpbGxUZXh0KGxhYmVsLCBsYWJlbE14LCBsYWJlbE15KTsKICAgICAgY3R4LnJlc3RvcmUoKTsKICAgIH0gZWxzZSBpZihydWxlci5wMSl7CiAgICAgIGN0eC5zYXZlKCk7CiAgICAgIGN0eC5maWxsU3R5bGUgPSAnI2RjMjYyNic7CiAgICAgIGN0eC5iZWdpblBhdGgoKTsgY3R4LmFyYyhweChwcm9qLCBydWxlci5wMS54KSwgcHkocHJvaiwgcnVsZXIucDEueSksIDUsIDAsIE1hdGguUEkqMik7IGN0eC5maWxsKCk7CiAgICAgIGN0eC5yZXN0b3JlKCk7CiAgICB9CiAgfQoKICB2YXIgY3VycmVudCA9ICdhYi1zdHJhaWdodCc7CiAgLy8gTWFjaGluZSB0eXBlIOKGkiB0eXBpY2FsIG1pbi10dXJuLXJhZGl1cyAobSkgQU5EIHR5cGljYWwgaW1wbGVtZW50IHdpZHRoIChtKS4KICAvLyBXaWR0aHMgZnJvbSB0aGUgZmllbGQtZXhwbG9yZXIgT1BfV0lEVEhfTSB0YWJsZSDigJQgbGFyZ2UtZmFybSByb3ctY3JvcAogIC8vIGRlZmF1bHRzLiBVc2VyIHBpY2tzIEN1c3RvbSB0byBza2lwIGJvdGggYXV0by1maWxscyBhbmQgb3ZlcnJpZGUgbWFudWFsbHkuCiAgdmFyIE1BQ0hJTkVfU1BFQyA9IHsKICAgICd0cmFjdG9yLXN0ZCc6ICAgeyByOiAgOCwgdzogMTUsIGxhYmVsOiAnc3RkIHRyYWN0b3IgLyBjdWx0aXZhdG9yJyB9LAogICAgJ3RyYWN0b3ItbGFyZ2UnOiB7IHI6IDEyLCB3OiAxOCwgbGFiZWw6ICdsYXJnZSB0cmFjdG9yICsgMjQtcm93IHBsYW50ZXInIH0sCiAgICAnc3ByYXllcic6ICAgICAgIHsgcjogMTAsIHc6IDM2LCBsYWJlbDogJ3NlbGYtcHJvcGVsbGVkIHNwcmF5ZXInIH0sCiAgICAnY29tYmluZSc6ICAgICAgIHsgcjogIDcsIHc6IDEyLCBsYWJlbDogJ2NvbWJpbmUgaGFydmVzdGVyJyB9LAogICAgJ2FydGljdWxhdGVkJzogICB7IHI6IDE1LCB3OiAyNCwgbGFiZWw6ICdhcnRpY3VsYXRlZCA0V0QgKyBkcnkgc3ByZWFkZXInIH0sCiAgICAnY3VzdG9tJzogICAgICAgIHsgcjogIDAsIHc6ICAwLCBsYWJlbDogJ21hbnVhbCBvdmVycmlkZScgfQogIH07CiAgLy8gQmFjay1jb21wYXQgYWxpYXMgKHRoZSBzbW9rZSB0ZXN0cyBwb2tlIE1BQ0hJTkVfUkFESVVTKS4KICB2YXIgTUFDSElORV9SQURJVVMgPSBNQUNISU5FX1NQRUM7CiAgdmFyIENVUlJFTkNZX1NZTUJPTCA9IHsgdXNkOiAnJCcsIGV1cjogJ+KCrCcgfTsKCiAgZnVuY3Rpb24gZ2V0SW5wdXRzKCl7CiAgICB2YXIgd00gPSBwYXJzZUZsb2F0KGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtd20nKS52YWx1ZSkgfHwgMTg7CiAgICB2YXIgaGxNdWx0ID0gcGFyc2VGbG9hdChkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLWhsLW11bHQnKS52YWx1ZSk7CiAgICBpZihpc05hTihobE11bHQpKSBobE11bHQgPSAxOwogICAgLy8gSGVhZGxhbmQgaXMgQUxXQVlTIE4gw5cgaW1wbGVtZW50IHdpZHRoIChwZXIgdXNlciDigJQgY3VzdG9tIG92ZXJyaWRlCiAgICAvLyBkcm9wcGVkLCB0aGUgbXVsdGlwbGllciBhbG9uZSBkZWZpbmVzIHRoZSBzdHJpcCkuCiAgICB2YXIgaGVhZGxhbmRNID0gaGxNdWx0ICogd007CiAgICB2YXIgdHVyblN0eWxlID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC10dXJuLXN0eWxlJykudmFsdWUgfHwgJ3V0dXJuJzsKICAgIHZhciB0dXJuUiA9IHBhcnNlRmxvYXQoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC10dXJuLXInKS52YWx1ZSkgfHwgOTsKICAgIHZhciB0dXJuQnVmID0gcGFyc2VGbG9hdChkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXR1cm4tYnVmJykudmFsdWUpOwogICAgaWYoaXNOYU4odHVybkJ1ZikpIHR1cm5CdWYgPSAwOwogICAgdmFyIG1hY2hpbmVFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtbWFjaGluZScpOwogICAgdmFyIG1hY2hpbmVLZXkgPSBtYWNoaW5lRWwgPyBtYWNoaW5lRWwudmFsdWUgOiAndHJhY3Rvci1zdGQnOwogICAgdmFyIGN1ckVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1jdXJyZW5jeScpOwogICAgdmFyIGN1cnJlbmN5ID0gY3VyRWwgPyBjdXJFbC52YWx1ZSA6ICd1c2QnOwogICAgdmFyIGZhcm1FbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtcm9pLWZhcm0nKTsKICAgIHZhciBhcHBzRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXJvaS1hcHBzJyk7CiAgICB2YXIgZmFybUhhID0gZmFybUVsID8gcGFyc2VGbG9hdChmYXJtRWwudmFsdWUpIDogMjAwOwogICAgaWYoaXNOYU4oZmFybUhhKSA\/IHRydWUgOiBmYXJtSGEgPD0gMCkgZmFybUhhID0gMjAwOwogICAgdmFyIGFwcHMgPSBhcHBzRWwgPyBwYXJzZUZsb2F0KGFwcHNFbC52YWx1ZSkgOiA0OwogICAgaWYoaXNOYU4oYXBwcykgPyB0cnVlIDogYXBwcyA8PSAwKSBhcHBzID0gNDsKICAgIHJldHVybiB7CiAgICAgIHdNOiB3TSwKICAgICAgZGllc2VsOiBwYXJzZUZsb2F0KGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtZnVlbCcpLnZhbHVlKSB8fCAxLjIsCiAgICAgIGNvbnM6IHBhcnNlRmxvYXQoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1jb25zJykudmFsdWUpIHx8IDAuNiwKICAgICAgaGVhZGxhbmRNOiBoZWFkbGFuZE0sCiAgICAgIGhlYWRsYW5kTXVsdDogaGxNdWx0LAogICAgICB0dXJuU3R5bGU6IHR1cm5TdHlsZSwKICAgICAgdHVyblI6IHR1cm5SLAogICAgICB0dXJuQnVmOiB0dXJuQnVmLAogICAgICBtYWNoaW5lOiBtYWNoaW5lS2V5LAogICAgICBjdXJyZW5jeTogY3VycmVuY3ksCiAgICAgIGZhcm1IYTogZmFybUhhLAogICAgICBhcHBzOiBhcHBzCiAgICB9OwogIH0KICBmdW5jdGlvbiByZWNvbXB1dGUoKXsKICAgIHZhciBpbnAgPSBnZXRJbnB1dHMoKTsKICAgIC8vIEF4aXM6IHVzZXIgbWFudWFsIG92ZXJyaWRlIGJlYXRzIFBDQSB3aGVuIHNldAogICAgdmFyIGF4aXM7CiAgICBpZih1c2VyQXhpc0RlZyAhPT0gbnVsbCl7CiAgICAgIHZhciByID0gdXNlckF4aXNEZWcgKiBNYXRoLlBJIC8gMTgwOwogICAgICBheGlzID0geyB1eDogTWF0aC5jb3MociksIHV5OiBNYXRoLnNpbihyKSB9OwogICAgfSBlbHNlIHsKICAgICAgYXhpcyA9IGZpZWxkQXhpcyhCT1VOREFSWSk7CiAgICB9CiAgICAvLyBTeW5jIHRoZSBBQi1kaXJlY3Rpb24gc2xpZGVyIGxhYmVsIHRvIHRoZSBhY3RpdmUgYW5nbGUgKHNvIHRoZSB1c2VyCiAgICAvLyBzZWVzIHRoZSBhdXRvLVBDQSByZXN1bHQgcmVmbGVjdGVkIGluIHRoZSBVSSkuCiAgICB2YXIgYWJMYWJlbEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1hYi12YWwnKTsKICAgIHZhciBhYlNsaWRlckVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1hYi1kZWcnKTsKICAgIGlmKGFiTGFiZWxFbCA\/IGFiU2xpZGVyRWwgOiBmYWxzZSl7CiAgICAgIHZhciBkZWdOb3cgPSBNYXRoLnJvdW5kKE1hdGguYXRhbjIoYXhpcy51eSwgYXhpcy51eCkgKiAxODAgLyBNYXRoLlBJKTsKICAgICAgLy8gV3JhcCBpbnRvIFswLDE4MCkg4oCUIHRoZSBheGlzIGlzIGJpZGlyZWN0aW9uYWwgKGEgbGluZSwgbm90IGEgdmVjdG9yKS4KICAgICAgd2hpbGUoZGVnTm93IDwgMCkgZGVnTm93ICs9IDE4MDsKICAgICAgd2hpbGUoZGVnTm93ID49IDE4MCkgZGVnTm93IC09IDE4MDsKICAgICAgaWYodXNlckF4aXNEZWcgPT09IG51bGwpIGFiU2xpZGVyRWwudmFsdWUgPSBTdHJpbmcoZGVnTm93KTsKICAgICAgYWJMYWJlbEVsLnRleHRDb250ZW50ID0gKHVzZXJBeGlzRGVnID09PSBudWxsID8gJ2F1dG8gwrcgJyA6ICdtYW51YWwgwrcgJykgKyBkZWdOb3cgKyAnwrAnOwogICAgfQogICAgdmFyIHN0YXRzID0gZmllbGRTdGF0cyhCT1VOREFSWSk7CiAgICB2YXIgYXJlYUhhID0gc3RhdHMuYXJlYSAvIDEwMDAwOwogICAgdmFyIGJhc2VMYXlvdXQgPSBnZW5lcmF0ZUxpbmVzKCdhYi1zdHJhaWdodCcsIGlucC53TSwgQk9VTkRBUlksIGF4aXMsIGlucC5oZWFkbGFuZE0sIGlucC50dXJuU3R5bGUsIGlucC50dXJuUiwgaW5wLnR1cm5CdWYpOwogICAgdmFyIGJhc2VNZXQgPSBjb21wdXRlTWV0cmljcyhiYXNlTGF5b3V0LCBpbnAud00sIGlucC5kaWVzZWwsIGlucC5jb25zKTsKICAgIHZhciBsYXlvdXQgPSBnZW5lcmF0ZUxpbmVzKGN1cnJlbnQsIGlucC53TSwgQk9VTkRBUlksIGF4aXMsIGlucC5oZWFkbGFuZE0sIGlucC50dXJuU3R5bGUsIGlucC50dXJuUiwgaW5wLnR1cm5CdWYpOwogICAgdmFyIG1ldCA9IGNvbXB1dGVNZXRyaWNzKGxheW91dCwgaW5wLndNLCBpbnAuZGllc2VsLCBpbnAuY29ucyk7CiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXItYXJlYScpLnRleHRDb250ZW50ID0gYXJlYUhhLnRvRml4ZWQoMSkgKyAnIGhhJzsKICAgIHZhciBjb3ZFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtci1jb3YnKTsKICAgIGlmKGNvdkVsKXsKICAgICAgdmFyIGNvdlZhbCA9IG1ldC5jb3ZlcmFnZVBjdCB8fCAwOwogICAgICBjb3ZFbC50ZXh0Q29udGVudCA9IGNvdlZhbC50b0ZpeGVkKDApICsgJyAlJzsKICAgICAgLy8gQ29sb3I6IGdyZWVuIOKJpSA5NSUsIG9yYW5nZSA4NS05NSUsIHJlZCA8IDg1JQogICAgICBjb3ZFbC5zdHlsZS5jb2xvciA9IGNvdlZhbCA+PSA5NSA\/ICcjMTU3MDFlJyA6IChjb3ZWYWwgPj0gODUgPyAnI2Y3NmEwYycgOiAnI2RjMjYyNicpOwogICAgfQogICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1yLXBhc3NlcycpLnRleHRDb250ZW50ID0gbWV0LnBhc3NlczsKICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtci1sZW4nKS50ZXh0Q29udGVudCA9IGZtdERpc3QobWV0LnBhc3NMZW5ndGhNKTsKICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtci10dXJucycpLnRleHRDb250ZW50ID0gbWV0LnR1cm5zOwogICAgdmFyIHR1cm5MZW5FbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtci10dXJubGVuJyk7CiAgICBpZih0dXJuTGVuRWwpIHR1cm5MZW5FbC50ZXh0Q29udGVudCA9IGZtdERpc3QobWV0LnR1cm5MZW5ndGhNIHx8IDApOwogICAgdmFyIGRyaXZlRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXItZHJpdmUnKTsKICAgIGlmKGRyaXZlRWwpIGRyaXZlRWwudGV4dENvbnRlbnQgPSBmbXREaXN0KG1ldC50b3RhbERyaXZlTSB8fCAobWV0LnBhc3NMZW5ndGhNICsgKG1ldC50dXJuTGVuZ3RoTSB8fCAwKSkpOwogICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1yLWZ1ZWwnKS50ZXh0Q29udGVudCA9IG1ldC5mdWVsTC50b0ZpeGVkKDEpICsgJyBMJzsKICAgIHZhciBncmFkZUVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1yLWdyYWRlJyk7CiAgICBpZihncmFkZUVsKXsKICAgICAgdmFyIGcgPSBtZXQuYXZnR3JhZGVQY3QgfHwgMDsKICAgICAgZ3JhZGVFbC50ZXh0Q29udGVudCA9IGcudG9GaXhlZCgxKSArICcgJSc7CiAgICAgIGdyYWRlRWwuc3R5bGUuY29sb3IgPSBnID4gNSA\/ICcjZjc2YTBjJyA6IChnID4gMyA\/ICcjYTIxY2FmJyA6ICcjNGM2MDY2Jyk7CiAgICB9CiAgICB2YXIgc2xvcGVFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtci1zbG9wZScpOwogICAgaWYoc2xvcGVFbCl7CiAgICAgIHZhciBzbG9wZVBjdCA9IChtZXQuc2xvcGVQZW5hbHR5IHx8IDApICogMTAwOwogICAgICBzbG9wZUVsLnRleHRDb250ZW50ID0gJysgJyArIHNsb3BlUGN0LnRvRml4ZWQoMCkgKyAnJSc7CiAgICAgIHNsb3BlRWwuc3R5bGUuY29sb3IgPSBzbG9wZVBjdCA+IDE1ID8gJyNkYzI2MjYnIDogKHNsb3BlUGN0ID4gNSA\/ICcjZjc2YTBjJyA6ICcjNGM2MDY2Jyk7CiAgICB9CiAgICB2YXIgdHVybkZ1ZWxFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtci10dXJuZnVlbCcpOwogICAgaWYodHVybkZ1ZWxFbCl7CiAgICAgIHZhciB0ZiA9IG1ldC50dXJuRnVlbEwgfHwgMDsKICAgICAgdmFyIHRvdEYgPSBtZXQuZnVlbEwgfHwgMDsKICAgICAgdmFyIHBjdCA9IHRvdEYgPiAwID8gKHRmIC8gdG90RiAqIDEwMCkgOiAwOwogICAgICB0dXJuRnVlbEVsLnRleHRDb250ZW50ID0gdGYudG9GaXhlZCgxKSArICcgTCDCtyAnICsgcGN0LnRvRml4ZWQoMCkgKyAnJSc7CiAgICAgIHR1cm5GdWVsRWwuc3R5bGUuY29sb3IgPSBwY3QgPiAyNSA\/ICcjZjc2YTBjJyA6IChwY3QgPiAxNSA\/ICcjYTIxY2FmJyA6ICcjNGM2MDY2Jyk7CiAgICB9CiAgICB2YXIgc3ltID0gQ1VSUkVOQ1lfU1lNQk9MW2lucC5jdXJyZW5jeV0gfHwgJyQnOwogICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1yLWNvc3QnKS50ZXh0Q29udGVudCA9IHN5bSArICcgJyArIG1ldC5jb3N0VVNELnRvRml4ZWQoMik7CiAgICB2YXIgc2F2RnVlbCA9IGJhc2VNZXQuZnVlbEwgLSBtZXQuZnVlbEw7CiAgICB2YXIgc2F2UGN0ID0gYmFzZU1ldC5mdWVsTCA+IDAgPyAoc2F2RnVlbCAvIGJhc2VNZXQuZnVlbEwpICogMTAwIDogMDsKICAgIHZhciBzYXZFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtci1zYXYnKTsKICAgIGlmKGN1cnJlbnQgPT09ICdhYi1zdHJhaWdodCcpewogICAgICBzYXZFbC50ZXh0Q29udGVudCA9ICdiYXNlbGluZSc7CiAgICAgIHNhdkVsLnN0eWxlLmNvbG9yID0gJyM0YzYwNjYnOwogICAgfSBlbHNlIHsKICAgICAgdmFyIHNpZ24gPSBzYXZGdWVsID49IDAgPyAn4oiSJyA6ICcrJzsKICAgICAgdmFyIGFic1NhdiA9IE1hdGguYWJzKHNhdkZ1ZWwpOwogICAgICBzYXZFbC50ZXh0Q29udGVudCA9IHNpZ24gKyBhYnNTYXYudG9GaXhlZCgxKSArICcgTCAoJyArIChzYXZQY3QgPj0gMCA\/ICfiiJInIDogJysnKSArIE1hdGguYWJzKHNhdlBjdCkudG9GaXhlZCgwKSArICclKSc7CiAgICAgIHNhdkVsLnN0eWxlLmNvbG9yID0gc2F2RnVlbCA+PSAwID8gJyMxNTcwMWUnIDogJyNmNzZhMGMnOwogICAgfQogICAgdHJheUVsLnRleHRDb250ZW50ID0gYXJlYUhhLnRvRml4ZWQoMSkgKyAnIGhhIMK3ICcgKyBpbnAud00gKyAnIG0gwrcgJyArIG1ldC5wYXNzZXMgKyAnIHBhc3NlcyDCtyBoZWFkbGFuZCAnICsgaW5wLmhlYWRsYW5kTS50b0ZpeGVkKDApICsgJyBtJzsKICAgIC8vIFNoYXBlLWRyaXZlbiByZWNvbW1lbmRhdGlvbiBiYWRnZQogICAgdmFyIHJlY28gPSByZWNvbW1lbmRBcHByb2FjaChCT1VOREFSWSk7CiAgICB2YXIgcmVjb0JhZGdlcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy5ncGwtcmVjbycpOwogICAgZm9yKHZhciByYj0wOyByYjxyZWNvQmFkZ2VzLmxlbmd0aDsgcmIrKyl7CiAgICAgIHZhciBya2V5ID0gcmVjb0JhZGdlc1tyYl0uZ2V0QXR0cmlidXRlKCdkYXRhLXJlY28nKTsKICAgICAgcmVjb0JhZGdlc1tyYl0uY2xhc3NMaXN0LnRvZ2dsZSgnaXMtb24nLCBya2V5ID09PSByZWNvLnBpY2spOwogICAgfQogICAgdmFyIHJlY29IaW50RWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXJlY28taGludCcpOwogICAgaWYocmVjb0hpbnRFbCkgcmVjb0hpbnRFbC50ZXh0Q29udGVudCA9IHJlY28ud2h5OwogICAgLy8gQW5udWFsIFJPSSBleHRyYXBvbGF0aW9uLiBQZXItZmllbGQgZnVlbCBzYXZpbmdzIMOXIGFwcGxpY2F0aW9ucyDDlyAoZmFybS9maWVsZCkuCiAgICB2YXIgcm9pRnVlbEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1yb2ktZnVlbCcpOwogICAgdmFyIHJvaUNvc3RFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtcm9pLWNvc3QnKTsKICAgIHZhciByb2lQZXJoYUVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1yb2ktcGVyaGEnKTsKICAgIGlmKHJvaUZ1ZWxFbCA\/IHJvaUNvc3RFbCA6IGZhbHNlKXsKICAgICAgaWYoY3VycmVudCA9PT0gJ2FiLXN0cmFpZ2h0Jyl7CiAgICAgICAgcm9pRnVlbEVsLnRleHRDb250ZW50ID0gJ+KAlCBMJzsKICAgICAgICByb2lDb3N0RWwudGV4dENvbnRlbnQgPSBzeW0gKyAnIOKAlCc7CiAgICAgICAgaWYocm9pUGVyaGFFbCkgcm9pUGVyaGFFbC50ZXh0Q29udGVudCA9ICdwaWNrIG5vbi1iYXNlbGluZSc7CiAgICAgICAgcm9pRnVlbEVsLnN0eWxlLmNvbG9yID0gJyM0YzYwNjYnOwogICAgICAgIHJvaUNvc3RFbC5zdHlsZS5jb2xvciA9ICcjNGM2MDY2JzsKICAgICAgICBpZihyb2lQZXJoYUVsKSByb2lQZXJoYUVsLnN0eWxlLmNvbG9yID0gJyM0YzYwNjYnOwogICAgICB9IGVsc2UgewogICAgICAgIHZhciBwZXJGaWVsZEZ1ZWwgPSBiYXNlTWV0LmZ1ZWxMIC0gbWV0LmZ1ZWxMOwogICAgICAgIHZhciBzY2FsZSA9IGFyZWFIYSA+IDAgPyAoaW5wLmZhcm1IYSAvIGFyZWFIYSkgOiAwOwogICAgICAgIHZhciBhbm51YWxGdWVsID0gcGVyRmllbGRGdWVsICogaW5wLmFwcHMgKiBzY2FsZTsKICAgICAgICB2YXIgYW5udWFsQ29zdCA9IGFubnVhbEZ1ZWwgKiBpbnAuZGllc2VsOwogICAgICAgIHZhciBwZXJIYSA9IGlucC5mYXJtSGEgPiAwID8gKGFubnVhbENvc3QgLyBpbnAuZmFybUhhKSA6IDA7CiAgICAgICAgdmFyIHNpZ25SID0gYW5udWFsRnVlbCA+PSAwID8gJycgOiAn4oiSJzsKICAgICAgICByb2lGdWVsRWwudGV4dENvbnRlbnQgPSBzaWduUiArIE1hdGguYWJzKGFubnVhbEZ1ZWwpLnRvRml4ZWQoMCkgKyAnIEwnOwogICAgICAgIHJvaUNvc3RFbC50ZXh0Q29udGVudCA9IChhbm51YWxDb3N0ID49IDAgPyBzeW0gKyAnICcgOiAn4oiSJyArIHN5bSArICcgJykgKyBNYXRoLmFicyhhbm51YWxDb3N0KS50b0ZpeGVkKDApOwogICAgICAgIGlmKHJvaVBlcmhhRWwpIHJvaVBlcmhhRWwudGV4dENvbnRlbnQgPSAocGVySGEgPj0gMCA\/IHN5bSArICcgJyA6ICfiiJInICsgc3ltICsgJyAnKSArIE1hdGguYWJzKHBlckhhKS50b0ZpeGVkKDIpICsgJy9oYSc7CiAgICAgICAgdmFyIHJvaUNvbG9yID0gYW5udWFsRnVlbCA+PSAwID8gJyMxNTcwMWUnIDogJyNmNzZhMGMnOwogICAgICAgIHJvaUZ1ZWxFbC5zdHlsZS5jb2xvciA9IHJvaUNvbG9yOwogICAgICAgIHJvaUNvc3RFbC5zdHlsZS5jb2xvciA9IHJvaUNvbG9yOwogICAgICAgIGlmKHJvaVBlcmhhRWwpIHJvaVBlcmhhRWwuc3R5bGUuY29sb3IgPSByb2lDb2xvcjsKICAgICAgfQogICAgfQogICAgLy8gV2FybmluZyBiYW5uZXIgZnJvbSB2YWxpZGF0aW9uIGNhc2NhZGUKICAgIHZhciB3YXJuRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXdhcm4nKTsKICAgIGlmKHdhcm5FbCl7CiAgICAgIGlmKGxheW91dC53YXJuaW5nKXsKICAgICAgICB3YXJuRWwudGV4dENvbnRlbnQgPSBsYXlvdXQud2FybmluZzsKICAgICAgICB3YXJuRWwuY2xhc3NMaXN0LmFkZCgnaXMtb24nKTsKICAgICAgfSBlbHNlIHsKICAgICAgICB3YXJuRWwudGV4dENvbnRlbnQgPSAnJzsKICAgICAgICB3YXJuRWwuY2xhc3NMaXN0LnJlbW92ZSgnaXMtb24nKTsKICAgICAgfQogICAgfQogICAgdmFyIGFwcHJvYWNoZXMgPSBbJ2FiLXN0cmFpZ2h0JywgJ2FiLWN1cnZlJywgJ2JvdW5kYXJ5JywgJ2FkYXB0aXZlJ107CiAgICB2YXIgYXBNZXRyaWNzID0ge307CiAgICBmb3IodmFyIGE9MDsgYTxhcHByb2FjaGVzLmxlbmd0aDsgYSsrKXsKICAgICAgdmFyIGFwID0gYXBwcm9hY2hlc1thXTsKICAgICAgdmFyIGFwTGF5b3V0ID0gYXAgPT09IGN1cnJlbnQgPyBsYXlvdXQgOiBnZW5lcmF0ZUxpbmVzKGFwLCBpbnAud00sIEJPVU5EQVJZLCBheGlzLCBpbnAuaGVhZGxhbmRNLCBpbnAudHVyblN0eWxlLCBpbnAudHVyblIsIGlucC50dXJuQnVmKTsKICAgICAgdmFyIGFwTWV0ID0gYXAgPT09IGN1cnJlbnQgPyBtZXQgOiBjb21wdXRlTWV0cmljcyhhcExheW91dCwgaW5wLndNLCBpbnAuZGllc2VsLCBpbnAuY29ucyk7CiAgICAgIGFwTWV0cmljc1thcF0gPSBhcE1ldDsKICAgICAgdmFyIHJvd0VsID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmdwbC1jbXAtcm93W2RhdGEtY21wPSInICsgYXAgKyAnIl0nKTsKICAgICAgaWYoIXJvd0VsKSBjb250aW51ZTsKICAgICAgdmFyIHZhbHMgPSByb3dFbC5xdWVyeVNlbGVjdG9yQWxsKCcuZ3BsLWNtcC12YWwnKTsKICAgICAgdmFsc1swXS50ZXh0Q29udGVudCA9IChhcE1ldC5jb3ZlcmFnZVBjdCB8fCAwKS50b0ZpeGVkKDApICsgJyUnOwogICAgICB2YWxzWzFdLnRleHRDb250ZW50ID0gYXBNZXQuZnVlbEwudG9GaXhlZCgwKSArICcgTCc7CiAgICAgIHZhbHNbMl0udGV4dENvbnRlbnQgPSBzeW0gKyBhcE1ldC5jb3N0VVNELnRvRml4ZWQoMCk7CiAgICAgIHJvd0VsLmNsYXNzTGlzdC50b2dnbGUoJ2dwbC1jbXAtY3VycmVudCcsIGFwID09PSBjdXJyZW50KTsKICAgIH0KICAgIC8vIEF4aXMgc3dlZXAg4oCUIGZpZWxkcyB3aXRoIGxvdyBjb3ZlcmFnZSAoZS5nLiBMLXNoYXBlKSBtYXkgYmVuZWZpdCBmcm9tIGEKICAgIC8vIGRpZmZlcmVudCBBQiBheGlzLiBUcnkgNiBhbmdsZXMgKDE1wrAgaW5jcmVtZW50cyBvdmVyIDDigJM5MMKwLCBzaW5jZSB0aGUKICAgIC8vIGF4aXMgaXMgYmlkaXJlY3Rpb25hbCDihpIgOTDCsCBwZXJpb2QpIGFuZCBwZXItYXBwcm9hY2ggcGljayB0aGUgQkVTVAogICAgLy8gY292ZXJhZ2UgYXhpcy4gT25seSBraWNrcyBpbiB3aGVuIHRoZSB1c2VyIGhhc24ndCBtYW51YWxseSBvdmVycmlkZGVuCiAgICAvLyB0aGUgYXhpcyAodXNlckF4aXNEZWcgPT09IG51bGwpLgogICAgdmFyIGJlc3RBcEF4ZXMgPSB7fTsKICAgIGlmKHVzZXJBeGlzRGVnID09PSBudWxsKXsKICAgICAgdmFyIHN3ZWVwQW5nbGVzID0gWzAsIDE1LCAzMCwgNDUsIDYwLCA3NV07CiAgICAgIC8vIFBDQSBnaXZlcyB0aGUgbmF0dXJhbCBiYXNlbGluZTsgaW5jbHVkZSBpdCB0b28uCiAgICAgIHZhciBwY2FEZWcgPSBNYXRoLnJvdW5kKE1hdGguYXRhbjIoZmllbGRBeGlzKEJPVU5EQVJZKS51eSwgZmllbGRBeGlzKEJPVU5EQVJZKS51eCkgKiAxODAgLyBNYXRoLlBJKTsKICAgICAgd2hpbGUocGNhRGVnIDwgMCkgcGNhRGVnICs9IDE4MDsKICAgICAgd2hpbGUocGNhRGVnID49IDkwKSBwY2FEZWcgLT0gOTA7CiAgICAgIGlmKHN3ZWVwQW5nbGVzLmluZGV4T2YocGNhRGVnKSA8IDApIHN3ZWVwQW5nbGVzLnB1c2gocGNhRGVnKTsKICAgICAgZm9yKHZhciBhcHM9MDsgYXBzPGFwcHJvYWNoZXMubGVuZ3RoOyBhcHMrKyl7CiAgICAgICAgdmFyIGFwUyA9IGFwcHJvYWNoZXNbYXBzXTsKICAgICAgICB2YXIgYmVzdE1ldCA9IGFwTWV0cmljc1thcFNdOwogICAgICAgIHZhciBiZXN0QW5nID0gbnVsbDsKICAgICAgICBmb3IodmFyIHNhPTA7IHNhPHN3ZWVwQW5nbGVzLmxlbmd0aDsgc2ErKyl7CiAgICAgICAgICB2YXIgYW5nID0gc3dlZXBBbmdsZXNbc2FdICogTWF0aC5QSSAvIDE4MDsKICAgICAgICAgIHZhciB0cmlhbEF4aXMgPSB7IHV4OiBNYXRoLmNvcyhhbmcpLCB1eTogTWF0aC5zaW4oYW5nKSB9OwogICAgICAgICAgdmFyIHRyaWFsTGF5ID0gZ2VuZXJhdGVMaW5lcyhhcFMsIGlucC53TSwgQk9VTkRBUlksIHRyaWFsQXhpcywgaW5wLmhlYWRsYW5kTSwgaW5wLnR1cm5TdHlsZSwgaW5wLnR1cm5SLCBpbnAudHVybkJ1Zik7CiAgICAgICAgICB2YXIgdHJpYWxNZXQgPSBjb21wdXRlTWV0cmljcyh0cmlhbExheSwgaW5wLndNLCBpbnAuZGllc2VsLCBpbnAuY29ucyk7CiAgICAgICAgICBpZigodHJpYWxNZXQuY292ZXJhZ2VQY3QgfHwgMCkgPiAoYmVzdE1ldC5jb3ZlcmFnZVBjdCB8fCAwKSl7CiAgICAgICAgICAgIGJlc3RNZXQgPSB0cmlhbE1ldDsKICAgICAgICAgICAgYmVzdEFuZyA9IHN3ZWVwQW5nbGVzW3NhXTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYoYmVzdEFuZyAhPT0gbnVsbCl7CiAgICAgICAgICBhcE1ldHJpY3NbYXBTXSA9IGJlc3RNZXQ7CiAgICAgICAgICBiZXN0QXBBeGVzW2FwU10gPSBiZXN0QW5nOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgLy8gTWV0cmljLWRyaXZlbiByZWNvbW1lbmRhdGlvbiAobm93IHVzZXMgdGhlIHN3ZXB0LWF4aXMgbWV0cmljcykKICAgIHZhciByZWNvTWV0cmljID0gcmVjb21tZW5kQnlNZXRyaWNzKGFwTWV0cmljcyk7CiAgICB2YXIgcmVjb0JhZGdlczIgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcuZ3BsLXJlY28nKTsKICAgIGZvcih2YXIgcmIyPTA7IHJiMjxyZWNvQmFkZ2VzMi5sZW5ndGg7IHJiMisrKXsKICAgICAgdmFyIHJrZXkyID0gcmVjb0JhZGdlczJbcmIyXS5nZXRBdHRyaWJ1dGUoJ2RhdGEtcmVjbycpOwogICAgICByZWNvQmFkZ2VzMltyYjJdLmNsYXNzTGlzdC50b2dnbGUoJ2lzLW9uJywgcmtleTIgPT09IHJlY29NZXRyaWMucGljayk7CiAgICB9CiAgICB2YXIgcmVjb0hpbnRFbDIgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXJlY28taGludCcpOwogICAgaWYocmVjb0hpbnRFbDIpewogICAgICB2YXIgaGludFR4dCA9IHJlY29NZXRyaWMud2h5OwogICAgICBpZihiZXN0QXBBeGVzW3JlY29NZXRyaWMucGlja10gIT09IHVuZGVmaW5lZCl7CiAgICAgICAgaGludFR4dCArPSAnIMK3IGJlc3QgYXQgJyArIGJlc3RBcEF4ZXNbcmVjb01ldHJpYy5waWNrXSArICfCsCc7CiAgICAgIH0KICAgICAgLy8gU3VyZmFjZSBsb3ctY292ZXJhZ2Ugd2FybmluZyBwcm9taW5lbnRseQogICAgICB2YXIgYmVzdENvdiA9IChhcE1ldHJpY3NbcmVjb01ldHJpYy5waWNrXSB8fCB7fSkuY292ZXJhZ2VQY3QgfHwgMDsKICAgICAgaWYoYmVzdENvdiA8IDcwKXsKICAgICAgICBoaW50VHh0ICs9ICcg4oCUIHNwbGl0IGZpZWxkIGZvciBmdWxsIGNvdmVyYWdlJzsKICAgICAgfQogICAgICByZWNvSGludEVsMi50ZXh0Q29udGVudCA9IGhpbnRUeHQ7CiAgICB9CiAgICAvLyBVcGRhdGUgdGhlIENvbXBhcmUgQWxsIGNlbGxzIHdpdGggdGhlIHN3ZXB0LWF4aXMgbWV0cmljcyBzbyB0aGUgdXNlcgogICAgLy8gc2VlcyB0aGUgQkVTVCBhY2hpZXZhYmxlIGNvdmVyYWdlIHBlciBhcHByb2FjaCwgbm90IGp1c3QgUENBLWF4aXMuCiAgICBmb3IodmFyIGFhPTA7IGFhPGFwcHJvYWNoZXMubGVuZ3RoOyBhYSsrKXsKICAgICAgdmFyIGFwWCA9IGFwcHJvYWNoZXNbYWFdOwogICAgICB2YXIgcm93WCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5ncGwtY21wLXJvd1tkYXRhLWNtcD0iJyArIGFwWCArICciXScpOwogICAgICBpZighcm93WCkgY29udGludWU7CiAgICAgIHZhciBtWCA9IGFwTWV0cmljc1thcFhdOwogICAgICB2YXIgdmFsc1ggPSByb3dYLnF1ZXJ5U2VsZWN0b3JBbGwoJy5ncGwtY21wLXZhbCcpOwogICAgICB2YWxzWFswXS50ZXh0Q29udGVudCA9IChtWC5jb3ZlcmFnZVBjdCB8fCAwKS50b0ZpeGVkKDApICsgJyUnOwogICAgICB2YWxzWFsxXS50ZXh0Q29udGVudCA9IG1YLmZ1ZWxMLnRvRml4ZWQoMCkgKyAnIEwnOwogICAgICB2YWxzWFsyXS50ZXh0Q29udGVudCA9IHN5bSArIG1YLmNvc3RVU0QudG9GaXhlZCgwKTsKICAgIH0KICAgIHNldFBsYXliYWNrUGF0aChsYXlvdXQsIGlucC53TSk7CiAgICB1cGRhdGVQbGF5YmFja1VJKCk7CiAgICBkcmF3KGxheW91dCk7CiAgfQoKICAvLyBVcGRhdGUgdGhlIGhlYWRsYW5kIHNsaWRlciBsYWJlbC4gSGVhZGxhbmQgPSBtdWx0IMOXIHdNIChzb2xlIHNvdXJjZSBvZgogIC8vIHRydXRoIOKAlCBubyBzZXBhcmF0ZSBjdXN0b20td2lkdGggaW5wdXQgYW55bW9yZSkuCiAgZnVuY3Rpb24gdXBkYXRlSGVhZGxhbmRMYWJlbCgpewogICAgdmFyIHdNID0gcGFyc2VGbG9hdChkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXdtJykudmFsdWUpIHx8IDE4OwogICAgdmFyIGhsTXVsdCA9IHBhcnNlRmxvYXQoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1obC1tdWx0JykudmFsdWUpOwogICAgaWYoaXNOYU4oaGxNdWx0KSkgaGxNdWx0ID0gMTsKICAgIHZhciBsYWJlbEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1obC12YWwnKTsKICAgIGlmKCFsYWJlbEVsKSByZXR1cm47CiAgICB2YXIgbSA9IGhsTXVsdCAqIHdNOwogICAgbGFiZWxFbC50ZXh0Q29udGVudCA9IG0udG9GaXhlZCgwKSArICcgbSDCtyAnICsgaGxNdWx0ICsgJ8OXIHBhc3MnOwogIH0KCiAgdmFyIHJhZGlvcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJyNncGwtYXBwcm9hY2ggaW5wdXRbdHlwZT1yYWRpb10nKTsKICBmb3IodmFyIHJpPTA7IHJpPHJhZGlvcy5sZW5ndGg7IHJpKyspewogICAgcmFkaW9zW3JpXS5hZGRFdmVudExpc3RlbmVyKCdjaGFuZ2UnLCBmdW5jdGlvbigpewogICAgICB2YXIgbGFicyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJyNncGwtYXBwcm9hY2ggbGFiZWwnKTsKICAgICAgZm9yKHZhciBsaT0wOyBsaTxsYWJzLmxlbmd0aDsgbGkrKykgbGFic1tsaV0uY2xhc3NMaXN0LnJlbW92ZSgnaXMtb24nKTsKICAgICAgdGhpcy5wYXJlbnROb2RlLmNsYXNzTGlzdC5hZGQoJ2lzLW9uJyk7CiAgICAgIGN1cnJlbnQgPSB0aGlzLnZhbHVlOwogICAgICByZWNvbXB1dGUoKTsKICAgIH0pOwogIH0KICAvLyBFcXVpcG1lbnQgKyBlY29ub21pY3MgaW5wdXRzCiAgdmFyIGJhc2ljSWRzID0gWydncGwtd20nLCAnZ3BsLWZ1ZWwnLCAnZ3BsLWNvbnMnXTsKICBmb3IodmFyIGlpPTA7IGlpPGJhc2ljSWRzLmxlbmd0aDsgaWkrKyl7CiAgICB2YXIgZWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChiYXNpY0lkc1tpaV0pOwogICAgaWYoZWwpewogICAgICBlbC5hZGRFdmVudExpc3RlbmVyKCdpbnB1dCcsIGZ1bmN0aW9uKCl7CiAgICAgICAgdXBkYXRlSGVhZGxhbmRMYWJlbCgpOwogICAgICAgIHJlY29tcHV0ZSgpOwogICAgICB9KTsKICAgIH0KICB9CiAgLy8gSGVhZGxhbmQgc2xpZGVyIOKAlCBkcml2ZXMgaGVhZGxhbmQgPSBtdWx0IMOXIHdNCiAgdmFyIGhsU2xpZGVyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1obC1tdWx0Jyk7CiAgaWYoaGxTbGlkZXIpewogICAgaGxTbGlkZXIuYWRkRXZlbnRMaXN0ZW5lcignaW5wdXQnLCBmdW5jdGlvbigpewogICAgICB1cGRhdGVIZWFkbGFuZExhYmVsKCk7CiAgICAgIHJlY29tcHV0ZSgpOwogICAgfSk7CiAgfQogIC8vIFJPSSBpbnB1dHMg4oCUIHB1cmVseSBpbmZvcm1hdGlvbmFsLCBqdXN0IHJlLXJ1biByZWNvbXB1dGUKICB2YXIgcm9pSWRzID0gWydncGwtcm9pLWZhcm0nLCAnZ3BsLXJvaS1hcHBzJ107CiAgZm9yKHZhciByb2k9MDsgcm9pPHJvaUlkcy5sZW5ndGg7IHJvaSsrKXsKICAgIHZhciByb2lFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHJvaUlkc1tyb2ldKTsKICAgIGlmKHJvaUVsKSByb2lFbC5hZGRFdmVudExpc3RlbmVyKCdpbnB1dCcsIHJlY29tcHV0ZSk7CiAgfQogIC8vIFR1cm4tYXJvdW5kIGNvbnRyb2xzCiAgdmFyIHR1cm5JZHMgPSBbJ2dwbC10dXJuLXN0eWxlJywgJ2dwbC10dXJuLXInLCAnZ3BsLXR1cm4tYnVmJ107CiAgZm9yKHZhciB0aT0wOyB0aTx0dXJuSWRzLmxlbmd0aDsgdGkrKyl7CiAgICB2YXIgdEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodHVybklkc1t0aV0pOwogICAgaWYodEVsKXsKICAgICAgdEVsLmFkZEV2ZW50TGlzdGVuZXIoJ2lucHV0JywgcmVjb21wdXRlKTsKICAgICAgdEVsLmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIHJlY29tcHV0ZSk7CiAgICB9CiAgfQogIC8vIE1hY2hpbmUgdHlwZSDigJQgYXV0by1maWxscyBCT1RIIHR1cm4gcmFkaXVzIGFuZCBpbXBsZW1lbnQgd2lkdGggKHVubGVzcwogIC8vICdjdXN0b20nKS4gRWFjaCBtYWNoaW5lIGNsYXNzIGhhcyB0eXBpY2FsIHNwZWNzIGZyb20gbWFudWZhY3R1cmVyIGF2ZXJhZ2VzLgogIGZ1bmN0aW9uIGFwcGx5TWFjaGluZVJhZGl1cygpewogICAgdmFyIG1FbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtbWFjaGluZScpOwogICAgdmFyIHJFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtdHVybi1yJyk7CiAgICB2YXIgd0VsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC13bScpOwogICAgdmFyIGhpbnRFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtdHVybi1yLWhpbnQnKTsKICAgIGlmKCFtRWwgPyB0cnVlIDogIXJFbCkgcmV0dXJuOwogICAgdmFyIHNwZWMgPSBNQUNISU5FX1NQRUNbbUVsLnZhbHVlXSB8fCBNQUNISU5FX1NQRUNbJ3RyYWN0b3Itc3RkJ107CiAgICBpZihtRWwudmFsdWUgIT09ICdjdXN0b20nID8gc3BlYy5yID4gMCA6IGZhbHNlKXsKICAgICAgckVsLnZhbHVlID0gU3RyaW5nKHNwZWMucik7CiAgICAgIHJFbC5kaXNhYmxlZCA9IGZhbHNlOwogICAgfQogICAgaWYobUVsLnZhbHVlICE9PSAnY3VzdG9tJyA\/IChzcGVjLncgPiAwID8gd0VsIDogZmFsc2UpIDogZmFsc2UpewogICAgICB3RWwudmFsdWUgPSBTdHJpbmcoc3BlYy53KTsKICAgIH0KICAgIC8vIFN5bmMgaGVhZGxhbmQgc2xpZGVyL2xhYmVsIHRvIHRoZSBuZXcgd2lkdGggc28gaGVhZGxhbmRNIHN0YXlzIGF0IHRoZQogICAgLy8gdXNlcidzIGludGVuZGVkIG11bHRpcGxpZXIgb2YgcGFzcyB3aWR0aC4KICAgIHVwZGF0ZUhlYWRsYW5kTGFiZWwoKTsKICAgIGlmKGhpbnRFbCl7CiAgICAgIGhpbnRFbC50ZXh0Q29udGVudCA9IG1FbC52YWx1ZSA9PT0gJ2N1c3RvbScgPyAnbWFudWFsIG92ZXJyaWRlJyA6ICgnYXV0byDCtyAnICsgc3BlYy5sYWJlbCk7CiAgICB9CiAgfQogIHZhciBtYWNoaW5lU2VsRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLW1hY2hpbmUnKTsKICBpZihtYWNoaW5lU2VsRWwpewogICAgbWFjaGluZVNlbEVsLmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIGZ1bmN0aW9uKCl7CiAgICAgIGFwcGx5TWFjaGluZVJhZGl1cygpOwogICAgICByZWNvbXB1dGUoKTsKICAgIH0pOwogIH0KICAvLyBDdXJyZW5jeSBzZWxlY3Qg4oCUIHB1cmVseSBhIGxhYmVsIHN3aXRjaDsgdXNlciB0eXBlcyB0aGVpciBsb2NhbCBwcmljZQogIHZhciBjdXJTZWxFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtY3VycmVuY3knKTsKICBpZihjdXJTZWxFbCkgY3VyU2VsRWwuYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgcmVjb21wdXRlKTsKCiAgLy8gRmlsZS1pbXBvcnQgaGVscGVycyDigJQgYWNjZXB0IEdlb0pTT04sIEtNTCwgb3IgemlwcGVkIHNoYXBlZmlsZS4gRXh0cmFjdAogIC8vIEFMTCBwb2x5Z29uIG91dGVyIHJpbmdzIChzbyB1c2VycyBjYW4gaXRlcmF0ZSB0aHJvdWdoIGZpZWxkcyBpbiBhCiAgLy8gbXVsdGktZmVhdHVyZSBmaWxlKSwgcHJvamVjdCBsYXQvbG5nIHRvIGxvY2FsIG1ldGVycyB3aXRoIGVhY2ggcG9seWdvbidzCiAgLy8gb3duIGNlbnRyb2lkIGFzIG9yaWdpbiwgZml0IGludG8gdGhlIGV4aXN0aW5nIGNhbnZhcyBjb29yZGluYXRlIHNjaGVtZS4KICAvLyBJbXBvcnRlZCBwb2x5Z29ucyBsaXZlIGluIGBpbXBvcnRlZEZpZWxkc2AgKGFycmF5IG9mIHsgbmFtZSwgY29vcmRzIH0KICAvLyB3aGVyZSBjb29yZHMgaXMgY2FudmFzLW1ldGVyIHt4LHl9IHBvaW50cykuIEl0ZXJhdG9yIFVJIGxldHMgdGhlIHVzZXIKICAvLyBzdGVwIHRocm91Z2ggdGhlbS4KICB2YXIgaW1wb3J0ZWRGaWVsZHMgPSBbXTsKICB2YXIgaW1wb3J0ZWRJZHggPSAwOwogIC8vIExhenktbG9hZCBzaHBqcyBmcm9tIGpzRGVsaXZyIG9uIGRlbWFuZCBmb3IgLnppcCAvIC5zaHAgaW5wdXRzLiBUaGUKICAvLyBwcm9taXNlIGlzIGNhY2hlZCBzbyBzdWJzZXF1ZW50IHVwbG9hZHMgZG8gbm90IHJlLWZldGNoIHRoZSBsaWJyYXJ5LgogIC8vIFRoaXMgaXMgdGhlIG9ubHkgbmV0d29yayBkZXBlbmRlbmN5IGluIHRoZSB0b29sIOKAlCBvcHQtaW4gdmlhIHVwbG9hZC4KICB2YXIgc2hwanNQcm9taXNlID0gbnVsbDsKICBmdW5jdGlvbiBsb2FkU2hwanMoKXsKICAgIGlmKHR5cGVvZiB3aW5kb3cuc2hwID09PSAnZnVuY3Rpb24nKSByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7CiAgICBpZihzaHBqc1Byb21pc2UpIHJldHVybiBzaHBqc1Byb21pc2U7CiAgICBzaHBqc1Byb21pc2UgPSBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpewogICAgICB2YXIgcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NjcmlwdCcpOwogICAgICAvLyBDRE4gVVJMIGhhcyBubyBxdWVyeSBzZXBhcmF0b3JzLCBzbyBydWxlIDEgaXMgbm90IGF0IHJpc2sgaGVyZS4KICAgICAgcy5zcmMgPSAnaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9zaHBqc0A0LjAuNC9kaXN0L3NocC5taW4uanMnOwogICAgICBzLm9ubG9hZCA9IGZ1bmN0aW9uKCl7IHJlc29sdmUoKTsgfTsKICAgICAgcy5vbmVycm9yID0gZnVuY3Rpb24oKXsgc2hwanNQcm9taXNlID0gbnVsbDsgcmVqZWN0KG5ldyBFcnJvcignQ291bGQgbm90IGxvYWQgc2hhcGVmaWxlIHBhcnNlcicpKTsgfTsKICAgICAgZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZChzKTsKICAgIH0pOwogICAgcmV0dXJuIHNocGpzUHJvbWlzZTsKICB9CiAgLy8gRXh0cmFjdCBldmVyeSBwb2x5Z29uIG91dGVyIHJpbmcgZnJvbSBhbnkgR2VvSlNPTiBvYmplY3QuIFJldHVybnMKICAvLyBbeyBuYW1lLCBjb29yZHM6IFtbbG5nLGxhdF0sIOKApl0gfSwg4oCmXSBzb3J0ZWQgYnkgYXJlYSBkZXNjZW5kaW5nIHNvIHRoZQogIC8vIGJpZ2dlc3QgcG9seWdvbiAodXN1YWxseSB0aGUgZmllbGQgb2YgaW50ZXJlc3QpIGNvbWVzIGZpcnN0LgogIGZ1bmN0aW9uIGV4dHJhY3RBbGxQb2x5Z29uc0dlb0pTT04ob2JqKXsKICAgIHZhciBwb2x5cyA9IFtdOwogICAgZnVuY3Rpb24gcHVzaEZlYXR1cmUoZiwgZGVmYXVsdE5hbWUpewogICAgICBpZighZikgcmV0dXJuOwogICAgICB2YXIgcHJvcHMgPSBmLnByb3BlcnRpZXMgfHwge307CiAgICAgIHZhciBuYW1lID0gcHJvcHMubmFtZSB8fCBwcm9wcy5OYW1lIHx8IHByb3BzLk5BTUUgfHwgcHJvcHMuZmllbGQgfHwgcHJvcHMuRmllbGQgfHwgcHJvcHMuRklFTEQgfHwgcHJvcHMuaWQgfHwgZGVmYXVsdE5hbWU7CiAgICAgIHZhciBnZW9tID0gZi5nZW9tZXRyeSA\/IGYuZ2VvbWV0cnkgOiAoZi50eXBlID09PSAnUG9seWdvbicgPyBmIDogKGYudHlwZSA9PT0gJ011bHRpUG9seWdvbicgPyBmIDogbnVsbCkpOwogICAgICBpZighZ2VvbSkgcmV0dXJuOwogICAgICBpZihnZW9tLnR5cGUgPT09ICdQb2x5Z29uJyl7CiAgICAgICAgcG9seXMucHVzaCh7IG5hbWU6IG5hbWUsIGNvb3JkczogZ2VvbS5jb29yZGluYXRlc1swXSB9KTsKICAgICAgfSBlbHNlIGlmKGdlb20udHlwZSA9PT0gJ011bHRpUG9seWdvbicpewogICAgICAgIGZvcih2YXIgaT0wOyBpPGdlb20uY29vcmRpbmF0ZXMubGVuZ3RoOyBpKyspewogICAgICAgICAgcG9seXMucHVzaCh7IG5hbWU6IChuYW1lIHx8ICdwb2x5JykgKyAnICMnICsgKGkgKyAxKSwgY29vcmRzOiBnZW9tLmNvb3JkaW5hdGVzW2ldWzBdIH0pOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgaWYob2JqLnR5cGUgPT09ICdGZWF0dXJlQ29sbGVjdGlvbicgPyBvYmouZmVhdHVyZXMgOiBmYWxzZSl7CiAgICAgIGZvcih2YXIgaz0wOyBrPG9iai5mZWF0dXJlcy5sZW5ndGg7IGsrKykgcHVzaEZlYXR1cmUob2JqLmZlYXR1cmVzW2tdLCAnZmVhdHVyZSAnICsgKGsgKyAxKSk7CiAgICB9IGVsc2UgaWYob2JqLnR5cGUgPT09ICdGZWF0dXJlJyl7CiAgICAgIHB1c2hGZWF0dXJlKG9iaiwgJ2ZlYXR1cmUgMScpOwogICAgfSBlbHNlIGlmKG9iai50eXBlID09PSAnUG9seWdvbicgPyB0cnVlIDogb2JqLnR5cGUgPT09ICdNdWx0aVBvbHlnb24nKXsKICAgICAgcHVzaEZlYXR1cmUoeyBnZW9tZXRyeTogb2JqLCBwcm9wZXJ0aWVzOiB7fSB9LCAncG9seWdvbicpOwogICAgfQogICAgLy8gU29ydCBieSBhcHByb3hpbWF0ZSBhcmVhIChjcm9zcy1wcm9kdWN0IHN1bSBvZiBsbmcvbGF0IGNvb3JkcyDigJQgbm90CiAgICAvLyBtwrIgYnV0IG1vbm90b25pYywgc28gbGFyZ2VzdCBwb2x5Z29uIHN0aWxsIHdpbnMpLgogICAgcG9seXMuZm9yRWFjaChmdW5jdGlvbihwKXsKICAgICAgdmFyIGEgPSAwOwogICAgICBmb3IodmFyIGk9MDsgaTxwLmNvb3Jkcy5sZW5ndGgtMTsgaSsrKXsKICAgICAgICBhICs9IHAuY29vcmRzW2ldWzBdICogcC5jb29yZHNbaSsxXVsxXSAtIHAuY29vcmRzW2krMV1bMF0gKiBwLmNvb3Jkc1tpXVsxXTsKICAgICAgfQogICAgICBwLl9hcmVhU2NvcmUgPSBNYXRoLmFicyhhKTsKICAgIH0pOwogICAgcG9seXMuc29ydChmdW5jdGlvbihhLCBiKXsgcmV0dXJuIGIuX2FyZWFTY29yZSAtIGEuX2FyZWFTY29yZTsgfSk7CiAgICByZXR1cm4gcG9seXM7CiAgfQogIGZ1bmN0aW9uIGV4dHJhY3RBbGxQb2x5Z29uc0tNTCh0ZXh0KXsKICAgIGlmKHR5cGVvZiBET01QYXJzZXIgPT09ICd1bmRlZmluZWQnKSByZXR1cm4gW107CiAgICB2YXIgZG9jOwogICAgdHJ5IHsgZG9jID0gbmV3IERPTVBhcnNlcigpLnBhcnNlRnJvbVN0cmluZyh0ZXh0LCAnYXBwbGljYXRpb24veG1sJyk7IH0gY2F0Y2goZSl7IHJldHVybiBbXTsgfQogICAgdmFyIHBsYWNlbWFya3MgPSBkb2MuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ1BsYWNlbWFyaycpOwogICAgdmFyIHBvbHlzID0gW107CiAgICBmdW5jdGlvbiBjb29yZHNGcm9tVGV4dChyYXcpewogICAgICB2YXIgcGFpcnMgPSByYXcuc3BsaXQoL1xzKy8pLm1hcChmdW5jdGlvbihzKXsgcmV0dXJuIHMudHJpbSgpOyB9KS5maWx0ZXIoZnVuY3Rpb24ocyl7IHJldHVybiBzLmxlbmd0aCA+IDA7IH0pOwogICAgICB2YXIgb3V0ID0gW107CiAgICAgIGZvcih2YXIgaT0wOyBpPHBhaXJzLmxlbmd0aDsgaSsrKXsKICAgICAgICB2YXIgcGFydHMgPSBwYWlyc1tpXS5zcGxpdCgnLCcpOwogICAgICAgIGlmKHBhcnRzLmxlbmd0aCA8IDIpIGNvbnRpbnVlOwogICAgICAgIHZhciBsbmcgPSBwYXJzZUZsb2F0KHBhcnRzWzBdKSwgbGF0ID0gcGFyc2VGbG9hdChwYXJ0c1sxXSk7CiAgICAgICAgaWYoaXNOYU4obG5nKSA\/IHRydWUgOiBpc05hTihsYXQpKSBjb250aW51ZTsKICAgICAgICBvdXQucHVzaChbbG5nLCBsYXRdKTsKICAgICAgfQogICAgICByZXR1cm4gb3V0OwogICAgfQogICAgaWYocGxhY2VtYXJrcy5sZW5ndGggPiAwKXsKICAgICAgZm9yKHZhciBwaT0wOyBwaTxwbGFjZW1hcmtzLmxlbmd0aDsgcGkrKyl7CiAgICAgICAgdmFyIHBtID0gcGxhY2VtYXJrc1twaV07CiAgICAgICAgdmFyIG5hbWVFbCA9IHBtLmdldEVsZW1lbnRzQnlUYWdOYW1lKCduYW1lJyk7CiAgICAgICAgdmFyIG5hbWUgPSAobmFtZUVsLmxlbmd0aCA+IDAgPyBuYW1lRWxbMF0udGV4dENvbnRlbnQgOiAncGxhY2VtYXJrICcgKyAocGkgKyAxKSkgfHwgKCdwbGFjZW1hcmsgJyArIChwaSArIDEpKTsKICAgICAgICB2YXIgY29vcmRzRWxzID0gcG0uZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2Nvb3JkaW5hdGVzJyk7CiAgICAgICAgZm9yKHZhciBjaT0wOyBjaTxjb29yZHNFbHMubGVuZ3RoOyBjaSsrKXsKICAgICAgICAgIHZhciBjID0gY29vcmRzRnJvbVRleHQoY29vcmRzRWxzW2NpXS50ZXh0Q29udGVudCB8fCAnJyk7CiAgICAgICAgICBpZihjLmxlbmd0aCA+PSAzKSBwb2x5cy5wdXNoKHsgbmFtZTogbmFtZSArIChjb29yZHNFbHMubGVuZ3RoID4gMSA\/ICcgIycgKyAoY2kgKyAxKSA6ICcnKSwgY29vcmRzOiBjIH0pOwogICAgICAgIH0KICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgLy8gRmFsbGJhY2s6IGJhcmUgS01MIHdpdGggPGNvb3JkaW5hdGVzPiBlbHNld2hlcmUKICAgICAgdmFyIGNvb3Jkc0FsbCA9IGRvYy5nZXRFbGVtZW50c0J5VGFnTmFtZSgnY29vcmRpbmF0ZXMnKTsKICAgICAgZm9yKHZhciBjYT0wOyBjYTxjb29yZHNBbGwubGVuZ3RoOyBjYSsrKXsKICAgICAgICB2YXIgYzIgPSBjb29yZHNGcm9tVGV4dChjb29yZHNBbGxbY2FdLnRleHRDb250ZW50IHx8ICcnKTsKICAgICAgICBpZihjMi5sZW5ndGggPj0gMykgcG9seXMucHVzaCh7IG5hbWU6ICdwb2x5Z29uICcgKyAoY2EgKyAxKSwgY29vcmRzOiBjMiB9KTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHBvbHlzOwogIH0KICAvLyBDb252ZXJ0IFtsbmcsIGxhdF0gYXJyYXkgdG8gbG9jYWwgY2FudmFzLW1ldGVyIGNvb3Jkcy4gQ2VudGVyIHRoZSBmaWVsZCBhdAogIC8vIHRoZSBjYW52YXMgY2VudHJvaWQgKH4zODAsIDI5MCkgc28gdGhlIGV4aXN0aW5nIHNjYWxlIGxvZ2ljIGZpdHMgaXQuCiAgZnVuY3Rpb24gbG5nTGF0VG9DYW52YXMoY29vcmRzKXsKICAgIGlmKCFjb29yZHMgPyB0cnVlIDogY29vcmRzLmxlbmd0aCA8IDMpIHJldHVybiBudWxsOwogICAgLy8gVXNlIGNlbnRyb2lkIChhdmVyYWdlKSBhcyB0aGUgcHJvamVjdGlvbiBvcmlnaW4KICAgIHZhciBvTGF0ID0gMCwgb0xuZyA9IDA7CiAgICBmb3IodmFyIGk9MDsgaTxjb29yZHMubGVuZ3RoOyBpKyspeyBvTG5nICs9IGNvb3Jkc1tpXVswXTsgb0xhdCArPSBjb29yZHNbaV1bMV07IH0KICAgIG9MYXQgLz0gY29vcmRzLmxlbmd0aDsgb0xuZyAvPSBjb29yZHMubGVuZ3RoOwogICAgdmFyIGNvc0xhdCA9IE1hdGguY29zKG9MYXQgKiBNYXRoLlBJIC8gMTgwKTsKICAgIHZhciBwdHMgPSBbXTsKICAgIGZvcih2YXIgaj0wOyBqPGNvb3Jkcy5sZW5ndGg7IGorKyl7CiAgICAgIHZhciBsbmcgPSBjb29yZHNbal1bMF0sIGxhdCA9IGNvb3Jkc1tqXVsxXTsKICAgICAgdmFyIG14ID0gKGxuZyAtIG9MbmcpICogMTExMzIwICogY29zTGF0OwogICAgICB2YXIgbXkgPSAtKGxhdCAtIG9MYXQpICogMTExMzIwOyAgLy8gY2FudmFzIHkgaXMgK2Rvd24sIHNvIGZsaXAKICAgICAgcHRzLnB1c2goeyB4OiAzODAgKyBteCwgeTogMjkwICsgbXkgfSk7CiAgICB9CiAgICAvLyBTdHJpcCBhIHRyYWlsaW5nIGR1cGxpY2F0ZSB2ZXJ0ZXggKExpbmVhclJpbmdzIGNsb3NlIHRoZW1zZWx2ZXMpCiAgICB2YXIgbGFzdCA9IHB0c1twdHMubGVuZ3RoIC0gMV0sIGZpcnN0ID0gcHRzWzBdOwogICAgaWYoTWF0aC5hYnMobGFzdC54IC0gZmlyc3QueCkgPCAwLjAxID8gTWF0aC5hYnMobGFzdC55IC0gZmlyc3QueSkgPCAwLjAxIDogZmFsc2UpewogICAgICBwdHMucG9wKCk7CiAgICB9CiAgICByZXR1cm4gcHRzLmxlbmd0aCA+PSAzID8gcHRzIDogbnVsbDsKICB9CiAgZnVuY3Rpb24gc2hvd1VwbG9hZFN0YXR1cyhzdGF0ZSwgbXNnKXsKICAgIHZhciBsYmwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXVwbG9hZC1sYmwnKTsKICAgIHZhciBoaW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC11cGxvYWQtaGludCcpOwogICAgaWYoIWxibCkgcmV0dXJuOwogICAgbGJsLmNsYXNzTGlzdC5yZW1vdmUoJ2lzLWVycm9yJywgJ2lzLXN1Y2Nlc3MnKTsKICAgIGlmKHN0YXRlID09PSAnZXJyb3InKSBsYmwuY2xhc3NMaXN0LmFkZCgnaXMtZXJyb3InKTsKICAgIGVsc2UgaWYoc3RhdGUgPT09ICdzdWNjZXNzJykgbGJsLmNsYXNzTGlzdC5hZGQoJ2lzLXN1Y2Nlc3MnKTsKICAgIGlmKGhpbnQpIGhpbnQudGV4dENvbnRlbnQgPSBtc2c7CiAgfQogIC8vIEFwcGx5IGltcG9ydGVkIHBvbHlnb24gYXQgaW5kZXggaSB0byBGSUVMRFMuY3VzdG9tICsgQk9VTkRBUlkgKyByZWNvbXB1dGUuCiAgZnVuY3Rpb24gYXBwbHlJbXBvcnRlZEZpZWxkKGkpewogICAgaWYoIWltcG9ydGVkRmllbGRzLmxlbmd0aCkgcmV0dXJuOwogICAgaWYoaSA8IDApIGkgPSAwOwogICAgaWYoaSA+PSBpbXBvcnRlZEZpZWxkcy5sZW5ndGgpIGkgPSBpbXBvcnRlZEZpZWxkcy5sZW5ndGggLSAxOwogICAgaW1wb3J0ZWRJZHggPSBpOwogICAgdmFyIHBmID0gaW1wb3J0ZWRGaWVsZHNbaV07CiAgICB2YXIgcHRzID0gbG5nTGF0VG9DYW52YXMocGYuY29vcmRzKTsKICAgIGlmKCFwdHMpeyBzaG93VXBsb2FkU3RhdHVzKCdlcnJvcicsICdQb2x5Z29uIG5lZWRzIGF0IGxlYXN0IDMgdmVydGljZXMnKTsgcmV0dXJuOyB9CiAgICBGSUVMRFMuY3VzdG9tID0gcHRzOwogICAgY3VycmVudEZpZWxkID0gJ2N1c3RvbSc7CiAgICBCT1VOREFSWSA9IHB0czsKICAgIHVzZXJBeGlzRGVnID0gbnVsbDsKICAgIHZhciBwaWNrZXIgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcjZ3BsLWZpZWxkLXBpY2tlciAuZ3BsLWZsZCcpOwogICAgZm9yKHZhciBwcD0wOyBwcDxwaWNrZXIubGVuZ3RoOyBwcCsrKSBwaWNrZXJbcHBdLmNsYXNzTGlzdC5yZW1vdmUoJ2lzLW9uJyk7CiAgICB2YXIgbmF2RWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLWltcG9ydC1uYXYnKTsKICAgIHZhciBsYmxFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtaW1wLWxibCcpOwogICAgdmFyIHByZXZCdG4gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLWltcC1wcmV2Jyk7CiAgICB2YXIgbmV4dEJ0biA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtaW1wLW5leHQnKTsKICAgIGlmKG5hdkVsKSBuYXZFbC5oaWRkZW4gPSBpbXBvcnRlZEZpZWxkcy5sZW5ndGggPCAyOwogICAgaWYobGJsRWwpIGxibEVsLnRleHRDb250ZW50ID0gKGkgKyAxKSArICcgLyAnICsgaW1wb3J0ZWRGaWVsZHMubGVuZ3RoOwogICAgaWYocHJldkJ0bikgcHJldkJ0bi5kaXNhYmxlZCA9IGkgPT09IDA7CiAgICBpZihuZXh0QnRuKSBuZXh0QnRuLmRpc2FibGVkID0gaSA9PT0gaW1wb3J0ZWRGaWVsZHMubGVuZ3RoIC0gMTsKICAgIHNob3dVcGxvYWRTdGF0dXMoJ3N1Y2Nlc3MnLCAocGYubmFtZSB8fCAoJ2JvdW5kYXJ5ICcgKyAoaSArIDEpKSkgKyAnIMK3ICcgKyBwdHMubGVuZ3RoICsgJyB2ZXJ0aWNlcycpOwogICAgcmVjb21wdXRlKCk7CiAgfQogIC8vIENvbnZlcnQgcmF3IGZpbGUg4oaSIGxpc3Qgb2YgcG9seWdvbnMg4oaSIGluc3RhbGwgKyBhcHBseSBmaXJzdCBvbmUuCiAgZnVuY3Rpb24gaGFuZGxlUGFyc2VkUG9seWdvbnMocG9seXMsIGZpbGVuYW1lKXsKICAgIGlmKCFwb2x5cyA\/IHRydWUgOiBwb2x5cy5sZW5ndGggPT09IDApewogICAgICBzaG93VXBsb2FkU3RhdHVzKCdlcnJvcicsICdObyBwb2x5Z29ucyBmb3VuZCBpbiAnICsgZmlsZW5hbWUpOwogICAgICByZXR1cm47CiAgICB9CiAgICBpbXBvcnRlZEZpZWxkcyA9IHBvbHlzOwogICAgaW1wb3J0ZWRJZHggPSAwOwogICAgc2hvd1VwbG9hZFN0YXR1cygnc3VjY2VzcycsIGZpbGVuYW1lICsgJyDCtyAnICsgcG9seXMubGVuZ3RoICsgJyBib3VuZGFyeScgKyAocG9seXMubGVuZ3RoID4gMSA\/ICdpZXMnIDogJycpKTsKICAgIGFwcGx5SW1wb3J0ZWRGaWVsZCgwKTsKICB9CiAgLy8gRGV0ZWN0IGZvcm1hdCBieSBleHRlbnNpb24gKyBjb250ZW50LCBkaXNwYXRjaCB0byBwYXJzZXIuIEFzeW5jIGJlY2F1c2UKICAvLyAuemlwIG5lZWRzIHNocGpzIHdoaWNoIGxvYWRzIGxhemlseSBmcm9tIENETi4KICBmdW5jdGlvbiBpbXBvcnRGaWxlKGZpbGUpewogICAgdmFyIG5hbWUgPSAoZmlsZS5uYW1lIHx8ICcnKS50b0xvd2VyQ2FzZSgpOwogICAgc2hvd1VwbG9hZFN0YXR1cygnZGVmYXVsdCcsICdSZWFkaW5nICcgKyBmaWxlLm5hbWUgKyAn4oCmJyk7CiAgICBpZihuYW1lLmluZGV4T2YoJy56aXAnKSA+PSAwID8gdHJ1ZSA6IG5hbWUuaW5kZXhPZignLnNocCcpID49IDApewogICAgICAvLyBaaXBwZWQgc2hhcGVmaWxlIG9yIGJhcmUgLnNocCDigJQgbmVlZHMgc2hwanMKICAgICAgdmFyIHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKCk7CiAgICAgIHJlYWRlci5vbmxvYWQgPSBmdW5jdGlvbigpewogICAgICAgIGxvYWRTaHBqcygpLnRoZW4oZnVuY3Rpb24oKXsKICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgIHZhciBwID0gd2luZG93LnNocChyZWFkZXIucmVzdWx0KTsKICAgICAgICAgICAgLy8gc2hwKCkgcmV0dXJucyBlaXRoZXIgYSBzaW5nbGUgRmVhdHVyZUNvbGxlY3Rpb24gb3IgYW4gYXJyYXkgKGZvciBtdWx0aS1zaHAgemlwcykKICAgICAgICAgICAgKHAgPyAocC50aGVuID8gcCA6IFByb21pc2UucmVzb2x2ZShwKSkgOiBQcm9taXNlLnJlc29sdmUocCkpLnRoZW4oZnVuY3Rpb24ocmVzKXsKICAgICAgICAgICAgICB2YXIgY29sbGVjdGlvbnMgPSBBcnJheS5pc0FycmF5KHJlcykgPyByZXMgOiBbcmVzXTsKICAgICAgICAgICAgICB2YXIgYWxsID0gW107CiAgICAgICAgICAgICAgZm9yKHZhciBjPTA7IGM8Y29sbGVjdGlvbnMubGVuZ3RoOyBjKyspIGFsbCA9IGFsbC5jb25jYXQoZXh0cmFjdEFsbFBvbHlnb25zR2VvSlNPTihjb2xsZWN0aW9uc1tjXSkpOwogICAgICAgICAgICAgIGhhbmRsZVBhcnNlZFBvbHlnb25zKGFsbCwgZmlsZS5uYW1lKTsKICAgICAgICAgICAgfSkuY2F0Y2goZnVuY3Rpb24oZXJyKXsKICAgICAgICAgICAgICBzaG93VXBsb2FkU3RhdHVzKCdlcnJvcicsICdTaGFwZWZpbGUgcGFyc2UgZmFpbGVkOiAnICsgKGVyci5tZXNzYWdlIHx8IGVycikpOwogICAgICAgICAgICB9KTsKICAgICAgICAgIH0gY2F0Y2goZXJyKXsKICAgICAgICAgICAgc2hvd1VwbG9hZFN0YXR1cygnZXJyb3InLCAnU2hhcGVmaWxlIHBhcnNlIGZhaWxlZDogJyArIChlcnIubWVzc2FnZSB8fCBlcnIpKTsKICAgICAgICAgIH0KICAgICAgICB9KS5jYXRjaChmdW5jdGlvbihlcnIpewogICAgICAgICAgc2hvd1VwbG9hZFN0YXR1cygnZXJyb3InLCBlcnIubWVzc2FnZSB8fCAnQ291bGQgbm90IGxvYWQgc2hhcGVmaWxlIHBhcnNlcicpOwogICAgICAgIH0pOwogICAgICB9OwogICAgICByZWFkZXIub25lcnJvciA9IGZ1bmN0aW9uKCl7IHNob3dVcGxvYWRTdGF0dXMoJ2Vycm9yJywgJ0NvdWxkIG5vdCByZWFkIGZpbGUnKTsgfTsKICAgICAgcmVhZGVyLnJlYWRBc0FycmF5QnVmZmVyKGZpbGUpOwogICAgfSBlbHNlIHsKICAgICAgLy8gVGV4dC1iYXNlZCDigJQgR2VvSlNPTiBvciBLTUwKICAgICAgdmFyIHJlYWRlcjIgPSBuZXcgRmlsZVJlYWRlcigpOwogICAgICByZWFkZXIyLm9ubG9hZCA9IGZ1bmN0aW9uKCl7CiAgICAgICAgdmFyIHRleHQgPSByZWFkZXIyLnJlc3VsdDsKICAgICAgICB2YXIgcG9seXMgPSBbXTsKICAgICAgICBpZihuYW1lLmluZGV4T2YoJy5rbWwnKSA+PSAwKXsKICAgICAgICAgIHBvbHlzID0gZXh0cmFjdEFsbFBvbHlnb25zS01MKHRleHQpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAvLyBHZW9KU09OIGZpcnN0OyBpZiBpdCBmYWlscywgdHJ5IEtNTCBpbiBjYXNlIGV4dGVuc2lvbiB3YXMgd3JvbmcKICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgIHZhciBvYmogPSBKU09OLnBhcnNlKHRleHQpOwogICAgICAgICAgICBwb2x5cyA9IGV4dHJhY3RBbGxQb2x5Z29uc0dlb0pTT04ob2JqKTsKICAgICAgICAgIH0gY2F0Y2goXyl7IHBvbHlzID0gZXh0cmFjdEFsbFBvbHlnb25zS01MKHRleHQpOyB9CiAgICAgICAgfQogICAgICAgIGhhbmRsZVBhcnNlZFBvbHlnb25zKHBvbHlzLCBmaWxlLm5hbWUpOwogICAgICB9OwogICAgICByZWFkZXIyLm9uZXJyb3IgPSBmdW5jdGlvbigpeyBzaG93VXBsb2FkU3RhdHVzKCdlcnJvcicsICdDb3VsZCBub3QgcmVhZCBmaWxlJyk7IH07CiAgICAgIHJlYWRlcjIucmVhZEFzVGV4dChmaWxlKTsKICAgIH0KICB9CiAgdmFyIGZpbGVJbnB1dEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC11cGxvYWQnKTsKICBpZihmaWxlSW5wdXRFbCl7CiAgICBmaWxlSW5wdXRFbC5hZGRFdmVudExpc3RlbmVyKCdjaGFuZ2UnLCBmdW5jdGlvbigpewogICAgICB2YXIgZmlsZSA9IHRoaXMuZmlsZXMgPyB0aGlzLmZpbGVzWzBdIDogbnVsbDsKICAgICAgaWYoZmlsZSkgaW1wb3J0RmlsZShmaWxlKTsKICAgIH0pOwogIH0KICAvLyBJdGVyYXRvciBidXR0b25zIOKAlCBzdGVwIHRocm91Z2ggaW1wb3J0ZWRGaWVsZHMKICB2YXIgaW1wUHJldkVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1pbXAtcHJldicpOwogIHZhciBpbXBOZXh0RWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLWltcC1uZXh0Jyk7CiAgaWYoaW1wUHJldkVsKSBpbXBQcmV2RWwuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbigpeyBhcHBseUltcG9ydGVkRmllbGQoaW1wb3J0ZWRJZHggLSAxKTsgfSk7CiAgaWYoaW1wTmV4dEVsKSBpbXBOZXh0RWwuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbigpeyBhcHBseUltcG9ydGVkRmllbGQoaW1wb3J0ZWRJZHggKyAxKTsgfSk7CgogIC8vIEZpZWxkIHBpY2tlciDigJQgc3dhcCBCT1VOREFSWSBpbiBwbGFjZSwgYXV0by1waWNrIHRoZSByZWNvbW1lbmRlZCBhcHByb2FjaCwKICAvLyB0aGVuIHJlLWZpdCAvIHJlLXJlbmRlci4gUmVzZXRzIHRoZSBBQi1saW5lIG92ZXJyaWRlIHNvIGVhY2ggbmV3IGZpZWxkCiAgLy8gc3RhcnRzIGZyb20gaXRzIFBDQS1kZXJpdmVkIG5hdHVyYWwgYXhpcy4KICB2YXIgZmxkQnRucyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJyNncGwtZmllbGQtcGlja2VyIC5ncGwtZmxkJyk7CiAgZm9yKHZhciBmYj0wOyBmYjxmbGRCdG5zLmxlbmd0aDsgZmIrKyl7CiAgICBmbGRCdG5zW2ZiXS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uKCl7CiAgICAgIHZhciBrZXkgPSB0aGlzLmdldEF0dHJpYnV0ZSgnZGF0YS1maWVsZCcpOwogICAgICBpZigha2V5ID8gdHJ1ZSA6ICFGSUVMRFNba2V5XSkgcmV0dXJuOwogICAgICBjdXJyZW50RmllbGQgPSBrZXk7CiAgICAgIEJPVU5EQVJZID0gRklFTERTW2tleV07CiAgICAgIHVzZXJBeGlzRGVnID0gbnVsbDsgIC8vIGJhY2sgdG8gQXV0byBvbiBldmVyeSBmaWVsZCBjaGFuZ2UKICAgICAgdmFyIGF1dG9CdG4gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLWFiLWF1dG8nKTsKICAgICAgaWYoYXV0b0J0bikgYXV0b0J0bi5jbGFzc0xpc3QuYWRkKCdpcy1hdXRvJyk7CiAgICAgIGZvcih2YXIgZmk9MDsgZmk8ZmxkQnRucy5sZW5ndGg7IGZpKyspIGZsZEJ0bnNbZmldLmNsYXNzTGlzdC5yZW1vdmUoJ2lzLW9uJyk7CiAgICAgIHRoaXMuY2xhc3NMaXN0LmFkZCgnaXMtb24nKTsKICAgICAgLy8gUmVzZXQgdGhlIHVwbG9hZCBjYXJkIHN0YXR1cyBzbyBpdCBkb2Vzbid0IGtlZXAgdGhlIHN1Y2Nlc3Mtc3RhdGUgYmFkZ2UKICAgICAgc2hvd1VwbG9hZFN0YXR1cygnZGVmYXVsdCcsICdHZW9KU09OIC8gS01MIC8gU2hhcGVmaWxlIHppcCcpOwogICAgICBpZihmaWxlSW5wdXRFbCkgZmlsZUlucHV0RWwudmFsdWUgPSAnJzsKICAgICAgdmFyIG5hdjIgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLWltcG9ydC1uYXYnKTsKICAgICAgaWYobmF2MikgbmF2Mi5oaWRkZW4gPSB0cnVlOwogICAgICBpbXBvcnRlZEZpZWxkcyA9IFtdOwogICAgICBpbXBvcnRlZElkeCA9IDA7CiAgICAgIC8vIFByZS1waWNrIHdpdGggdGhlIHNoYXBlLWJhc2VkIGhldXJpc3RpYyBmb3IgaW5zdGFudCBmZWVkYmFjazsgdGhlCiAgICAgIC8vIGZpcnN0IHJlY29tcHV0ZSgpIGJlbG93IHdpbGwgdGhlbiByZS1ldmFsdWF0ZSB3aXRoIHJlYWwgbWV0cmljcwogICAgICAvLyAoY292ZXJhZ2UgKyB0dXJucyArIGZ1ZWwpIGFuZCBtYXkgZmxpcCB0byBhIGJldHRlciBhcHByb2FjaC4KICAgICAgdmFyIHBpY2sgPSByZWNvbW1lbmRBcHByb2FjaChCT1VOREFSWSkucGljazsKICAgICAgY3VycmVudCA9IHBpY2s7CiAgICAgIHZhciBhcFJhZGlvcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJyNncGwtYXBwcm9hY2ggaW5wdXRbdHlwZT1yYWRpb10nKTsKICAgICAgdmFyIGFwTGFiZWxzID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnI2dwbC1hcHByb2FjaCBsYWJlbCcpOwogICAgICBmb3IodmFyIGFyPTA7IGFyPGFwUmFkaW9zLmxlbmd0aDsgYXIrKyl7CiAgICAgICAgdmFyIG1hdGNoID0gYXBSYWRpb3NbYXJdLnZhbHVlID09PSBwaWNrOwogICAgICAgIGFwUmFkaW9zW2FyXS5jaGVja2VkID0gbWF0Y2g7CiAgICAgICAgaWYoYXBMYWJlbHNbYXJdKSBhcExhYmVsc1thcl0uY2xhc3NMaXN0LnRvZ2dsZSgnaXMtb24nLCBtYXRjaCk7CiAgICAgIH0KICAgICAgcmVjb21wdXRlKCk7CiAgICAgIC8vIE5vdyBhcHBseSB0aGUgbWV0cmljLWRyaXZlbiByZWNvbW1lbmRhdGlvbiBpZiBpdCBkaWZmZXJzCiAgICAgIHZhciBhcE1ldHJpY3NGb3JSZWNvID0ge307CiAgICAgIHZhciBheGlzUiA9IHVzZXJBeGlzRGVnICE9PSBudWxsID8geyB1eDogTWF0aC5jb3ModXNlckF4aXNEZWcgKiBNYXRoLlBJIC8gMTgwKSwgdXk6IE1hdGguc2luKHVzZXJBeGlzRGVnICogTWF0aC5QSSAvIDE4MCkgfSA6IGZpZWxkQXhpcyhCT1VOREFSWSk7CiAgICAgIHZhciBpbnBSID0gZ2V0SW5wdXRzKCk7CiAgICAgIFsnYWItc3RyYWlnaHQnLCdhYi1jdXJ2ZScsJ2JvdW5kYXJ5JywnYWRhcHRpdmUnXS5mb3JFYWNoKGZ1bmN0aW9uKGFwWCl7CiAgICAgICAgdmFyIGxheVggPSBnZW5lcmF0ZUxpbmVzKGFwWCwgaW5wUi53TSwgQk9VTkRBUlksIGF4aXNSLCBpbnBSLmhlYWRsYW5kTSwgaW5wUi50dXJuU3R5bGUsIGlucFIudHVyblIsIGlucFIudHVybkJ1Zik7CiAgICAgICAgYXBNZXRyaWNzRm9yUmVjb1thcFhdID0gY29tcHV0ZU1ldHJpY3MobGF5WCwgaW5wUi53TSwgaW5wUi5kaWVzZWwsIGlucFIuY29ucyk7CiAgICAgIH0pOwogICAgICB2YXIgbWV0cmljUGljayA9IHJlY29tbWVuZEJ5TWV0cmljcyhhcE1ldHJpY3NGb3JSZWNvKS5waWNrOwogICAgICBpZihtZXRyaWNQaWNrICE9PSBjdXJyZW50KXsKICAgICAgICBjdXJyZW50ID0gbWV0cmljUGljazsKICAgICAgICBmb3IodmFyIGFyMj0wOyBhcjI8YXBSYWRpb3MubGVuZ3RoOyBhcjIrKyl7CiAgICAgICAgICB2YXIgbWF0Y2gyID0gYXBSYWRpb3NbYXIyXS52YWx1ZSA9PT0gbWV0cmljUGljazsKICAgICAgICAgIGFwUmFkaW9zW2FyMl0uY2hlY2tlZCA9IG1hdGNoMjsKICAgICAgICAgIGlmKGFwTGFiZWxzW2FyMl0pIGFwTGFiZWxzW2FyMl0uY2xhc3NMaXN0LnRvZ2dsZSgnaXMtb24nLCBtYXRjaDIpOwogICAgICAgIH0KICAgICAgICByZWNvbXB1dGUoKTsKICAgICAgfQogICAgfSk7CiAgfQogIC8vIEFCLWRpcmVjdGlvbiBjb250cm9scwogIHZhciBhYlNsaWRlckVsMiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtYWItZGVnJyk7CiAgdmFyIGFiQXV0b0J0bkVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1hYi1hdXRvJyk7CiAgaWYoYWJTbGlkZXJFbDIpewogICAgYWJTbGlkZXJFbDIuYWRkRXZlbnRMaXN0ZW5lcignaW5wdXQnLCBmdW5jdGlvbigpewogICAgICB2YXIgZGVnID0gcGFyc2VGbG9hdCh0aGlzLnZhbHVlKTsKICAgICAgaWYoaXNOYU4oZGVnKSkgZGVnID0gMDsKICAgICAgdXNlckF4aXNEZWcgPSBkZWc7CiAgICAgIGlmKGFiQXV0b0J0bkVsKSBhYkF1dG9CdG5FbC5jbGFzc0xpc3QucmVtb3ZlKCdpcy1hdXRvJyk7CiAgICAgIHJlY29tcHV0ZSgpOwogICAgfSk7CiAgfQogIGlmKGFiQXV0b0J0bkVsKXsKICAgIGFiQXV0b0J0bkVsLmNsYXNzTGlzdC5hZGQoJ2lzLWF1dG8nKTsKICAgIGFiQXV0b0J0bkVsLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZnVuY3Rpb24oKXsKICAgICAgdXNlckF4aXNEZWcgPSBudWxsOwogICAgICB0aGlzLmNsYXNzTGlzdC5hZGQoJ2lzLWF1dG8nKTsKICAgICAgcmVjb21wdXRlKCk7CiAgICB9KTsKICB9CgogIC8vIFBsYXliYWNrIGNvbnRyb2xzCiAgdmFyIGxhc3RMYXlvdXQgPSBudWxsOwogIHZhciBwYkJ0bkVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1wYi1wbGF5Jyk7CiAgdmFyIHBiVHJhY2tFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtcGItdHJhY2snKTsKICB2YXIgcGJTcGRFbHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcuZ3BsLXBiLXNwZCcpOwogIC8vIENhY2hlIHRoZSBjdXJyZW50IGxheW91dCBzbyB0aGUgUkFGIGxvb3AgY2FuIHJlZHJhdyB3aXRob3V0IHJlY29tcHV0aW5nCiAgLy8gdGhlIHdob2xlIGdlb21ldHJ5IHBpcGVsaW5lIG9uIGV2ZXJ5IGZyYW1lLgogIHZhciBvcmlnRHJhdyA9IGRyYXc7CiAgZHJhdyA9IGZ1bmN0aW9uKGxheW91dCl7IGxhc3RMYXlvdXQgPSBsYXlvdXQ7IG9yaWdEcmF3KGxheW91dCk7IH07CiAgZnVuY3Rpb24gdGljayhub3cpewogICAgaWYoIXBsYXliYWNrLmlzUGxheWluZyl7IHBsYXliYWNrLmxhc3RUaWNrID0gbm93OyByZXR1cm47IH0KICAgIHZhciBkdCA9IHBsYXliYWNrLmxhc3RUaWNrID4gMCA\/IChub3cgLSBwbGF5YmFjay5sYXN0VGljaykgLyAxMDAwIDogMDsKICAgIHBsYXliYWNrLmxhc3RUaWNrID0gbm93OwogICAgLy8gMSBrbSBkcml2ZSBwZXIgc2Vjb25kIGF0IDHDlyAodmlzaWJsZSBidXQgbm90IGJsaW5raW5nIGZhc3QpCiAgICAvLyA3MDAgbS9zIGF0IDHDlyDigJQgMzAgJSBzbG93ZXIgdGhhbiB0aGUgcHJldmlvdXMgMTAwMCBtL3Mgc28gaW5kaXZpZHVhbAogICAgLy8gcGFzc2VzIGFyZSBlYXNpZXIgdG8gZm9sbG93IHZpc3VhbGx5IChhIDYwMCBtIHBhc3MgdGFrZXMgfjAuODUgcyB2cyAwLjYpLgogICAgdmFyIG1ldHJlc1BlclNlYyA9IDcwMCAqIHBsYXliYWNrLnNwZWVkOwogICAgdmFyIGRUID0gcGxheWJhY2sudG90YWxMZW4gPiAwID8gKGR0ICogbWV0cmVzUGVyU2VjIC8gcGxheWJhY2sudG90YWxMZW4pIDogMDsKICAgIHBsYXliYWNrLnQgKz0gZFQ7CiAgICBpZihwbGF5YmFjay50ID49IDEpewogICAgICBwbGF5YmFjay50ID0gMTsKICAgICAgcGxheWJhY2suaXNQbGF5aW5nID0gZmFsc2U7CiAgICAgIGlmKHBiQnRuRWwpewogICAgICAgIHBiQnRuRWwuY2xhc3NMaXN0LnJlbW92ZSgnaXMtcGxheWluZycpOwogICAgICAgIHBiQnRuRWwudGV4dENvbnRlbnQgPSAn4pa2JzsKICAgICAgfQogICAgfQogICAgdXBkYXRlUGxheWJhY2tVSSgpOwogICAgaWYobGFzdExheW91dCkgb3JpZ0RyYXcobGFzdExheW91dCk7CiAgICBpZihwbGF5YmFjay5pc1BsYXlpbmcpIHJlcXVlc3RBbmltYXRpb25GcmFtZSh0aWNrKTsKICB9CiAgaWYocGJCdG5FbCl7CiAgICBwYkJ0bkVsLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZnVuY3Rpb24oKXsKICAgICAgaWYocGxheWJhY2sudG90YWxMZW4gPCAxKSByZXR1cm47CiAgICAgIGlmKHBsYXliYWNrLnQgPj0gMSkgcGxheWJhY2sudCA9IDA7CiAgICAgIHBsYXliYWNrLmlzUGxheWluZyA9ICFwbGF5YmFjay5pc1BsYXlpbmc7CiAgICAgIHBiQnRuRWwuY2xhc3NMaXN0LnRvZ2dsZSgnaXMtcGxheWluZycsIHBsYXliYWNrLmlzUGxheWluZyk7CiAgICAgIHBiQnRuRWwudGV4dENvbnRlbnQgPSBwbGF5YmFjay5pc1BsYXlpbmcgPyAnJyA6ICfilrYnOwogICAgICBpZihwbGF5YmFjay5pc1BsYXlpbmcpewogICAgICAgIHBsYXliYWNrLmxhc3RUaWNrID0gMDsKICAgICAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUodGljayk7CiAgICAgIH0KICAgIH0pOwogIH0KICBpZihwYlRyYWNrRWwpewogICAgcGJUcmFja0VsLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZnVuY3Rpb24oZXYpewogICAgICB2YXIgcmVjdCA9IHBiVHJhY2tFbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTsKICAgICAgdmFyIGYgPSAoZXYuY2xpZW50WCAtIHJlY3QubGVmdCkgLyByZWN0LndpZHRoOwogICAgICBpZihmIDwgMCkgZiA9IDA7IGlmKGYgPiAxKSBmID0gMTsKICAgICAgcGxheWJhY2sudCA9IGY7CiAgICAgIHVwZGF0ZVBsYXliYWNrVUkoKTsKICAgICAgaWYobGFzdExheW91dCkgb3JpZ0RyYXcobGFzdExheW91dCk7CiAgICB9KTsKICB9CiAgZm9yKHZhciBzYj0wOyBzYjxwYlNwZEVscy5sZW5ndGg7IHNiKyspewogICAgcGJTcGRFbHNbc2JdLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZnVuY3Rpb24oKXsKICAgICAgdmFyIHMgPSBwYXJzZUZsb2F0KHRoaXMuZ2V0QXR0cmlidXRlKCdkYXRhLXNwZCcpKSB8fCAxOwogICAgICBwbGF5YmFjay5zcGVlZCA9IHM7CiAgICAgIGZvcih2YXIgc2IyPTA7IHNiMjxwYlNwZEVscy5sZW5ndGg7IHNiMisrKSBwYlNwZEVsc1tzYjJdLmNsYXNzTGlzdC5yZW1vdmUoJ29uJyk7CiAgICAgIHRoaXMuY2xhc3NMaXN0LmFkZCgnb24nKTsKICAgIH0pOwogIH0KCiAgLy8gVW5pdCB0b2dnbGUgKGttIC8gbWkpIOKAlCBwdXJlbHkgYSBsYWJlbCBzd2l0Y2g7IG51bWJlcnMgc3RheSBpbiBtZXRyZXMgaW50ZXJuYWxseQogIHZhciB1bml0VGFicyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy5ncGwtdW5pdC10YWInKTsKICBmb3IodmFyIHV0PTA7IHV0PHVuaXRUYWJzLmxlbmd0aDsgdXQrKyl7CiAgICB1bml0VGFic1t1dF0uYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbigpewogICAgICB1bml0ID0gdGhpcy5nZXRBdHRyaWJ1dGUoJ2RhdGEtdW5pdCcpIHx8ICdrbSc7CiAgICAgIGZvcih2YXIgdXQyPTA7IHV0Mjx1bml0VGFicy5sZW5ndGg7IHV0MisrKSB1bml0VGFic1t1dDJdLmNsYXNzTGlzdC5yZW1vdmUoJ2lzLW9uJyk7CiAgICAgIHRoaXMuY2xhc3NMaXN0LmFkZCgnaXMtb24nKTsKICAgICAgcmVjb21wdXRlKCk7CiAgICB9KTsKICB9CiAgLy8gWm9vbSArIGZpdCBidXR0b25zCiAgLy8gWm9vbS1hcm91bmQtY3Vyc29yIGhlbHBlci4gQWRqdXN0cyBwYW4gc28gdGhlIHdvcmxkIHBvaW50IHVuZGVyCiAgLy8gKG14LCBteSkgc3RheXMgYXQgdGhlIHNhbWUgc2NyZWVuIHBvc2l0aW9uIGFmdGVyIHRoZSB6b29tIGNoYW5nZS4KICBmdW5jdGlvbiB6b29tQXJvdW5kQ3Vyc29yKG14LCBteSwgZmFjdG9yKXsKICAgIHZhciBwcm9qQmVmb3JlID0gZ2V0U2NhbGUoKTsKICAgIHZhciB3eCA9IHdvcmxkWChwcm9qQmVmb3JlLCBteCk7CiAgICB2YXIgd3kgPSB3b3JsZFkocHJvakJlZm9yZSwgbXkpOwogICAgdmFyIG5ld1pvb20gPSB2aWV3Lnpvb20gKiBmYWN0b3I7CiAgICBpZihuZXdab29tIDwgMC4yKSBuZXdab29tID0gMC4yOwogICAgaWYobmV3Wm9vbSA+IDUwKSBuZXdab29tID0gNTA7CiAgICB2aWV3Lnpvb20gPSBuZXdab29tOwogICAgdmFyIHByb2pBZnRlciA9IGdldFNjYWxlKCk7CiAgICB2aWV3LnBhblggKz0gbXggLSBweChwcm9qQWZ0ZXIsIHd4KTsKICAgIHZpZXcucGFuWSArPSBteSAtIHB5KHByb2pBZnRlciwgd3kpOwogICAgaWYobGFzdExheW91dCkgb3JpZ0RyYXcobGFzdExheW91dCk7CiAgfQogIGZ1bmN0aW9uIHpvb21DZW50ZXIoZmFjdG9yKXsKICAgIHZhciByZWN0ID0gY2FudmFzLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOwogICAgem9vbUFyb3VuZEN1cnNvcihyZWN0LndpZHRoICogMC41LCByZWN0LmhlaWdodCAqIDAuNSwgZmFjdG9yKTsKICB9CiAgdmFyIHpJbkVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC10b29sLXpvb20taW4nKTsKICB2YXIgek91dEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC10b29sLXpvb20tb3V0Jyk7CiAgdmFyIHpGaXRFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtdG9vbC1maXQnKTsKICBpZih6SW5FbCkgekluRWwuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbigpeyB6b29tQ2VudGVyKDEuMyk7IH0pOwogIGlmKHpPdXRFbCkgek91dEVsLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZnVuY3Rpb24oKXsgem9vbUNlbnRlcigxLzEuMyk7IH0pOwogIGlmKHpGaXRFbCkgekZpdEVsLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZnVuY3Rpb24oKXsKICAgIHZpZXcuem9vbSA9IDE7IHZpZXcucGFuWCA9IDA7IHZpZXcucGFuWSA9IDA7CiAgICBpZihsYXN0TGF5b3V0KSBvcmlnRHJhdyhsYXN0TGF5b3V0KTsKICB9KTsKICAvLyBNb3VzZSB3aGVlbCDigJQgc21vb3RoIGV4cG9uZW50aWFsIHpvb20gKG1hdGNoZXMgZmllbGQtZGF0YS1leHBsb3JlciBmZWVsKQogIGNhbnZhcy5hZGRFdmVudExpc3RlbmVyKCd3aGVlbCcsIGZ1bmN0aW9uKGV2KXsKICAgIGV2LnByZXZlbnREZWZhdWx0KCk7CiAgICB2YXIgcmVjdCA9IGNhbnZhcy5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTsKICAgIHZhciBteCA9IGV2LmNsaWVudFggLSByZWN0LmxlZnQ7CiAgICB2YXIgbXkgPSBldi5jbGllbnRZIC0gcmVjdC50b3A7CiAgICB2YXIgZmFjdG9yID0gTWF0aC5leHAoLWV2LmRlbHRhWSAqIDAuMDAxNSk7CiAgICB6b29tQXJvdW5kQ3Vyc29yKG14LCBteSwgZmFjdG9yKTsKICB9LCB7IHBhc3NpdmU6IGZhbHNlIH0pOwogIC8vIERyYWctdG8tcGFuICh3aGVuIHJ1bGVyIGlzIG5vdCBhY3RpdmUpCiAgdmFyIGRyYWdTdGF0ZSA9IG51bGw7CiAgY2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlZG93bicsIGZ1bmN0aW9uKGV2KXsKICAgIHZhciByZWN0ID0gY2FudmFzLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOwogICAgdmFyIG14ID0gZXYuY2xpZW50WCAtIHJlY3QubGVmdDsKICAgIHZhciBteSA9IGV2LmNsaWVudFkgLSByZWN0LnRvcDsKICAgIGlmKHJ1bGVyLmFjdGl2ZSl7CiAgICAgIHZhciBwcm9qID0gZ2V0U2NhbGUoKTsKICAgICAgdmFyIHd4ID0gd29ybGRYKHByb2osIG14KTsKICAgICAgdmFyIHd5ID0gd29ybGRZKHByb2osIG15KTsKICAgICAgaWYoIXJ1bGVyLnAxKXsKICAgICAgICBydWxlci5wMSA9IHsgeDogd3gsIHk6IHd5IH07IHJ1bGVyLnAyID0gbnVsbDsKICAgICAgfSBlbHNlIGlmKCFydWxlci5wMil7CiAgICAgICAgcnVsZXIucDIgPSB7IHg6IHd4LCB5OiB3eSB9OwogICAgICB9IGVsc2UgewogICAgICAgIHJ1bGVyLnAxID0geyB4OiB3eCwgeTogd3kgfTsgcnVsZXIucDIgPSBudWxsOwogICAgICB9CiAgICAgIGlmKGxhc3RMYXlvdXQpIG9yaWdEcmF3KGxhc3RMYXlvdXQpOwogICAgICByZXR1cm47CiAgICB9CiAgICBkcmFnU3RhdGUgPSB7IHN0YXJ0WDogbXgsIHN0YXJ0WTogbXksIHN0YXJ0UGFuWDogdmlldy5wYW5YLCBzdGFydFBhblk6IHZpZXcucGFuWSB9OwogICAgY2FudmFzLnN0eWxlLmN1cnNvciA9ICdncmFiYmluZyc7CiAgfSk7CiAgY2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlbW92ZScsIGZ1bmN0aW9uKGV2KXsKICAgIGlmKCFkcmFnU3RhdGUpIHJldHVybjsKICAgIHZhciByZWN0ID0gY2FudmFzLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOwogICAgdmFyIG14ID0gZXYuY2xpZW50WCAtIHJlY3QubGVmdDsKICAgIHZhciBteSA9IGV2LmNsaWVudFkgLSByZWN0LnRvcDsKICAgIHZpZXcucGFuWCA9IGRyYWdTdGF0ZS5zdGFydFBhblggKyAobXggLSBkcmFnU3RhdGUuc3RhcnRYKTsKICAgIHZpZXcucGFuWSA9IGRyYWdTdGF0ZS5zdGFydFBhblkgKyAobXkgLSBkcmFnU3RhdGUuc3RhcnRZKTsKICAgIGlmKGxhc3RMYXlvdXQpIG9yaWdEcmF3KGxhc3RMYXlvdXQpOwogIH0pOwogIGZ1bmN0aW9uIGVuZERyYWcoKXsKICAgIGRyYWdTdGF0ZSA9IG51bGw7CiAgICBjYW52YXMuc3R5bGUuY3Vyc29yID0gcnVsZXIuYWN0aXZlID8gJ2Nyb3NzaGFpcicgOiAnZGVmYXVsdCc7CiAgfQogIGNhbnZhcy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgZW5kRHJhZyk7CiAgY2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlbGVhdmUnLCBlbmREcmFnKTsKICAvLyBUb3VjaCDigJQgc2luZ2xlLWZpbmdlciBwYW4sIHR3by1maW5nZXIgcGluY2gtem9vbSAobWlycm9ycyBmaWVsZC1leHBsb3JlcikKICB2YXIgdG91Y2hTdGF0ZSA9IG51bGw7CiAgZnVuY3Rpb24gX3REaXN0KGEsIGIpeyB2YXIgZHggPSBhLmNsaWVudFggLSBiLmNsaWVudFgsIGR5ID0gYS5jbGllbnRZIC0gYi5jbGllbnRZOyByZXR1cm4gTWF0aC5zcXJ0KGR4KmR4ICsgZHkqZHkpOyB9CiAgZnVuY3Rpb24gX3RDZW50ZXIoYSwgYil7IHJldHVybiBbKGEuY2xpZW50WCArIGIuY2xpZW50WCkgKiAwLjUsIChhLmNsaWVudFkgKyBiLmNsaWVudFkpICogMC41XTsgfQogIGNhbnZhcy5hZGRFdmVudExpc3RlbmVyKCd0b3VjaHN0YXJ0JywgZnVuY3Rpb24oZXYpewogICAgaWYoZXYudG91Y2hlcy5sZW5ndGggPT09IDEpewogICAgICBldi5wcmV2ZW50RGVmYXVsdCgpOwogICAgICB2YXIgcmVjdCA9IGNhbnZhcy5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTsKICAgICAgdG91Y2hTdGF0ZSA9IHsgbW9kZTogJ3BhbicsIHg6IGV2LnRvdWNoZXNbMF0uY2xpZW50WCwgeTogZXYudG91Y2hlc1swXS5jbGllbnRZLCBzeDogZXYudG91Y2hlc1swXS5jbGllbnRYIC0gcmVjdC5sZWZ0LCBzeTogZXYudG91Y2hlc1swXS5jbGllbnRZIC0gcmVjdC50b3AsIHBhblg6IHZpZXcucGFuWCwgcGFuWTogdmlldy5wYW5ZLCBtb3ZlZDogZmFsc2UgfTsKICAgIH0gZWxzZSBpZihldi50b3VjaGVzLmxlbmd0aCA+PSAyKXsKICAgICAgZXYucHJldmVudERlZmF1bHQoKTsKICAgICAgdmFyIGMgPSBfdENlbnRlcihldi50b3VjaGVzWzBdLCBldi50b3VjaGVzWzFdKTsKICAgICAgdG91Y2hTdGF0ZSA9IHsgbW9kZTogJ3BpbmNoJywgZGlzdDogX3REaXN0KGV2LnRvdWNoZXNbMF0sIGV2LnRvdWNoZXNbMV0pLCBjeDogY1swXSwgY3k6IGNbMV0gfTsKICAgIH0KICB9LCB7IHBhc3NpdmU6IGZhbHNlIH0pOwogIGNhbnZhcy5hZGRFdmVudExpc3RlbmVyKCd0b3VjaG1vdmUnLCBmdW5jdGlvbihldil7CiAgICBpZighdG91Y2hTdGF0ZSkgcmV0dXJuOwogICAgZXYucHJldmVudERlZmF1bHQoKTsKICAgIGlmKHRvdWNoU3RhdGUubW9kZSA9PT0gJ3BhbicgPyBldi50b3VjaGVzLmxlbmd0aCA9PT0gMSA6IGZhbHNlKXsKICAgICAgdmFyIHQgPSBldi50b3VjaGVzWzBdOwogICAgICB2YXIgZHggPSB0LmNsaWVudFggLSB0b3VjaFN0YXRlLng7CiAgICAgIHZhciBkeSA9IHQuY2xpZW50WSAtIHRvdWNoU3RhdGUueTsKICAgICAgdmlldy5wYW5YID0gdG91Y2hTdGF0ZS5wYW5YICsgZHg7CiAgICAgIHZpZXcucGFuWSA9IHRvdWNoU3RhdGUucGFuWSArIGR5OwogICAgICBpZihNYXRoLmFicyhkeCkgPiA0ID8gdHJ1ZSA6IE1hdGguYWJzKGR5KSA+IDQpIHRvdWNoU3RhdGUubW92ZWQgPSB0cnVlOwogICAgICBpZihsYXN0TGF5b3V0KSBvcmlnRHJhdyhsYXN0TGF5b3V0KTsKICAgIH0gZWxzZSBpZih0b3VjaFN0YXRlLm1vZGUgPT09ICdwaW5jaCcgPyBldi50b3VjaGVzLmxlbmd0aCA+PSAyIDogZmFsc2UpewogICAgICB2YXIgbmV3RGlzdCA9IF90RGlzdChldi50b3VjaGVzWzBdLCBldi50b3VjaGVzWzFdKTsKICAgICAgdmFyIG5ld0MgPSBfdENlbnRlcihldi50b3VjaGVzWzBdLCBldi50b3VjaGVzWzFdKTsKICAgICAgdmFyIHJlY3RUID0gY2FudmFzLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOwogICAgICB2YXIgbmN4ID0gbmV3Q1swXSAtIHJlY3RULmxlZnQsIG5jeSA9IG5ld0NbMV0gLSByZWN0VC50b3A7CiAgICAgIHpvb21Bcm91bmRDdXJzb3IobmN4LCBuY3ksIG5ld0Rpc3QgLyB0b3VjaFN0YXRlLmRpc3QpOwogICAgICB0b3VjaFN0YXRlLmRpc3QgPSBuZXdEaXN0OyB0b3VjaFN0YXRlLmN4ID0gbmV3Q1swXTsgdG91Y2hTdGF0ZS5jeSA9IG5ld0NbMV07CiAgICB9CiAgfSwgeyBwYXNzaXZlOiBmYWxzZSB9KTsKICBjYW52YXMuYWRkRXZlbnRMaXN0ZW5lcigndG91Y2hlbmQnLCBmdW5jdGlvbihldil7CiAgICAvLyBSdWxlciB0YXAgc3VwcG9ydDogaWYgcnVsZXIgbW9kZSBhbmQgbm8gZHJhZyBvY2N1cnJlZCwgZHJvcCBhIHBvaW50IGF0IHRoZSB0b3VjaCBwb3NpdGlvbgogICAgaWYodG91Y2hTdGF0ZSA\/ICh0b3VjaFN0YXRlLm1vZGUgPT09ICdwYW4nID8gKCF0b3VjaFN0YXRlLm1vdmVkID8gcnVsZXIuYWN0aXZlIDogZmFsc2UpIDogZmFsc2UpIDogZmFsc2UpewogICAgICB2YXIgcHJvaiA9IGdldFNjYWxlKCk7CiAgICAgIHZhciB3eCA9IHdvcmxkWChwcm9qLCB0b3VjaFN0YXRlLnN4KTsKICAgICAgdmFyIHd5ID0gd29ybGRZKHByb2osIHRvdWNoU3RhdGUuc3kpOwogICAgICBpZighcnVsZXIucDEpeyBydWxlci5wMSA9IHsgeDogd3gsIHk6IHd5IH07IHJ1bGVyLnAyID0gbnVsbDsgfQogICAgICBlbHNlIGlmKCFydWxlci5wMil7IHJ1bGVyLnAyID0geyB4OiB3eCwgeTogd3kgfTsgfQogICAgICBlbHNlIHsgcnVsZXIucDEgPSB7IHg6IHd4LCB5OiB3eSB9OyBydWxlci5wMiA9IG51bGw7IH0KICAgICAgaWYobGFzdExheW91dCkgb3JpZ0RyYXcobGFzdExheW91dCk7CiAgICB9CiAgICBpZihldi50b3VjaGVzLmxlbmd0aCA9PT0gMCkgdG91Y2hTdGF0ZSA9IG51bGw7CiAgfSk7CiAgLy8gUnVsZXIgdG9nZ2xlCiAgdmFyIHJ1bGVyQnRuRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXRvb2wtcnVsZXInKTsKICB2YXIgcnVsZXJIaW50RWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXJ1bGVyLWhpbnQnKTsKICBpZihydWxlckJ0bkVsKXsKICAgIHJ1bGVyQnRuRWwuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbigpewogICAgICBydWxlci5hY3RpdmUgPSAhcnVsZXIuYWN0aXZlOwogICAgICB0aGlzLmNsYXNzTGlzdC50b2dnbGUoJ2lzLW9uJywgcnVsZXIuYWN0aXZlKTsKICAgICAgaWYocnVsZXJIaW50RWwpIHJ1bGVySGludEVsLmNsYXNzTGlzdC50b2dnbGUoJ2lzLW9uJywgcnVsZXIuYWN0aXZlKTsKICAgICAgY2FudmFzLnN0eWxlLmN1cnNvciA9IHJ1bGVyLmFjdGl2ZSA\/ICdjcm9zc2hhaXInIDogJ2RlZmF1bHQnOwogICAgICBpZighcnVsZXIuYWN0aXZlKXsKICAgICAgICBydWxlci5wMSA9IG51bGw7IHJ1bGVyLnAyID0gbnVsbDsKICAgICAgICBpZihsYXN0TGF5b3V0KSBvcmlnRHJhdyhsYXN0TGF5b3V0KTsKICAgICAgfQogICAgfSk7CiAgfQoKICAvLyBSZXNpemFibGUgbGVmdCBwYW5lbCDigJQgZHJhZyBzcGxpdHRlciB0byBzZXQgLS1ncGwtbGVmdC13IG9uIHRoZSB3cmFwLgogIC8vIENsYW1wZWQgdG8gWzIwMCwgMzgwXSBweCBzbyB0aGUgcGFuZWwgbmV2ZXIgY29sbGFwc2VzIG9yIGVhdHMgdGhlIGNhbnZhcy4KICB2YXIgc3BsaXR0ZXJFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtc3BsaXR0ZXInKTsKICBpZihzcGxpdHRlckVsKXsKICAgIHZhciBzcFN0YXRlID0gbnVsbDsKICAgIHNwbGl0dGVyRWwuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgZnVuY3Rpb24oZXYpewogICAgICB2YXIgY3VycmVudCA9IHBhcnNlRmxvYXQoZ2V0Q29tcHV0ZWRTdHlsZShyb290KS5nZXRQcm9wZXJ0eVZhbHVlKCctLWdwbC1sZWZ0LXcnKSkgfHwgMjYwOwogICAgICBzcFN0YXRlID0geyBzdGFydFg6IGV2LmNsaWVudFgsIHN0YXJ0VzogY3VycmVudCB9OwogICAgICBzcGxpdHRlckVsLmNsYXNzTGlzdC5hZGQoJ2lzLWRyYWcnKTsKICAgICAgZXYucHJldmVudERlZmF1bHQoKTsKICAgIH0pOwogICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlbW92ZScsIGZ1bmN0aW9uKGV2KXsKICAgICAgaWYoIXNwU3RhdGUpIHJldHVybjsKICAgICAgdmFyIHcgPSBzcFN0YXRlLnN0YXJ0VyArIChldi5jbGllbnRYIC0gc3BTdGF0ZS5zdGFydFgpOwogICAgICBpZih3IDwgMjAwKSB3ID0gMjAwOwogICAgICBpZih3ID4gMzgwKSB3ID0gMzgwOwogICAgICByb290LnN0eWxlLnNldFByb3BlcnR5KCctLWdwbC1sZWZ0LXcnLCB3ICsgJ3B4Jyk7CiAgICAgIC8vIENhbnZhcyBzaXplIGNoYW5nZWQg4oaSIHJlZml0IGFuZCByZWRyYXcKICAgICAgcmVzaXplKCk7CiAgICAgIGlmKGxhc3RMYXlvdXQpIG9yaWdEcmF3KGxhc3RMYXlvdXQpOwogICAgfSk7CiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsIGZ1bmN0aW9uKCl7CiAgICAgIGlmKCFzcFN0YXRlKSByZXR1cm47CiAgICAgIHNwU3RhdGUgPSBudWxsOwogICAgICBzcGxpdHRlckVsLmNsYXNzTGlzdC5yZW1vdmUoJ2lzLWRyYWcnKTsKICAgIH0pOwogIH0KCiAgLy8gSW5pdGlhbCByZWNvbW1lbmRhdGlvbiDigJQgcHJlLXNlbGVjdCB0aGUgc2hhcGUtb3B0aW1hbCBhcHByb2FjaCBzbyB0aGUKICAvLyBwYWdlIGxhbmRzIG9uIHRoZSBhZ3Jvbm9taWNhbGx5IHNlbnNpYmxlIGRlZmF1bHQsIG5vdCBhcmJpdHJhcnkgQUIgU3RyYWlnaHQuCiAgKGZ1bmN0aW9uKCl7CiAgICB2YXIgaW5pdGlhbFBpY2sgPSByZWNvbW1lbmRBcHByb2FjaChCT1VOREFSWSkucGljazsKICAgIGN1cnJlbnQgPSBpbml0aWFsUGljazsKICAgIHZhciBhcFJhZGlvczAgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcjZ3BsLWFwcHJvYWNoIGlucHV0W3R5cGU9cmFkaW9dJyk7CiAgICB2YXIgYXBMYWJlbHMwID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnI2dwbC1hcHByb2FjaCBsYWJlbCcpOwogICAgZm9yKHZhciBhcjA9MDsgYXIwPGFwUmFkaW9zMC5sZW5ndGg7IGFyMCsrKXsKICAgICAgdmFyIG1hdGNoMCA9IGFwUmFkaW9zMFthcjBdLnZhbHVlID09PSBpbml0aWFsUGljazsKICAgICAgYXBSYWRpb3MwW2FyMF0uY2hlY2tlZCA9IG1hdGNoMDsKICAgICAgaWYoYXBMYWJlbHMwW2FyMF0pIGFwTGFiZWxzMFthcjBdLmNsYXNzTGlzdC50b2dnbGUoJ2lzLW9uJywgbWF0Y2gwKTsKICAgIH0KICB9KSgpOwoKICByZXNpemUoKTsKICB1cGRhdGVIZWFkbGFuZExhYmVsKCk7CiAgYXBwbHlNYWNoaW5lUmFkaXVzKCk7CiAgcmVjb21wdXRlKCk7CiAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsIGZ1bmN0aW9uKCl7IHJlc2l6ZSgpOyByZWNvbXB1dGUoKTsgfSk7Cn0pKCk7Cjwvc2NyaXB0Pgo8L2Rpdj4KCjwhLS0gd3A6YmxvY2sgeyJyZWYiOjEzMDk5fSAvLS0+c3RhdGV2ZXJzaW9uZG9jdW1lbnRkYXRlZG9jdW1lbnRzbHVnZG9jdW1lbnRzdGF0dXNkb2N1bWVudHRpdGxlR3VpZGFuY2UgTGluZXMgU2ltdWxhdG9yZG9jdW1lbnRjb250ZW50ZG9jdW1lbnRleGNlcnB0ZG9jdW1lbnRhdXRob3Jkb2N1bWVudGZlYXR1cmVkX21lZGlhZG9jdW1lbnRjb21tZW50X3N0YXR1c2RvY3VtZW50cGluZ19zdGF0dXNkb2N1bWVudHRlbXBsYXRlZG9jdW1lbnRtZXRhX2NvYmxvY2tzX2F0dHJfY29ibG9ja3NfZGltZW5zaW9uc19jb2Jsb2Nrc19yZXNwb25zaXZlX2hlaWdodF9jb2Jsb2Nrc19hY2NvcmRpb25faWVfc3VwcG9ydF9lYl9hdHRyY29udGVudC10eXBlZm9vdG5vdGVzYmlnX3NreV9nZW5lcmF0ZWRfZWxlbWVudG9yX2VkaXRfbW9kZV9lbGVtZW50b3JfdGVtcGxhdGVfdHlwZV9lbGVtZW50b3JfZGF0YV9lbGVtZW50b3JfcGFnZV9zZXR0aW5nc19lbGVtZW50b3JfY29uZGl0aW9uc2RvY3VtZW50YmxvY2tzY2xpZW50SWRpc1ZhbGlkb3JpZ2luYWxDb250ZW50bmFtZWF0dHJpYnV0ZXNjb250ZW50ZHJvcENhcFRycENvbnRlbnRSZXN0cmljdGlvbmZvbnRXZWlnaHR0ZXh0VHJhbnNmb3Jtbm9Cb3R0b21TcGFjaW5nbm9Ub3BTcGFjaW5naW5uZXJCbG9ja3NfZWJfbWV0YV9kYXRhc3RhdGVzYXZlZEF0c3RhdGVzYXZlZEJ5dGV4dFBhbmVsSGlkZUNvbG9ydGV4dFBhbmVsU2hvd1NwYWNpbmdDb250cm9sc3RleHRQYW5lbEhlYWRpbmdGb250U2l6ZXNjbGllbnRJZGlzVmFsaWRuYW1lYXR0cmlidXRlc2NvbnRlbnRkcm9wQ2FwVHJwQ29udGVudFJlc3RyaWN0aW9uZm9udFdlaWdodHRleHRUcmFuc2Zvcm1ub0JvdHRvbVNwYWNpbmdub1RvcFNwYWNpbmd0ZXh0UGFuZWxIaWRlQ29sb3J0ZXh0UGFuZWxTaG93U3BhY2luZ0NvbnRyb2xzdGV4dFBhbmVsSGVhZGluZ0ZvbnRTaXplc2lubmVyQmxvY2tzPCEtLSB3cDpodG1sIC0tPgo8c3R5bGU+Cn0KPC9zdHlsZT4KICA8L2Rpdj4KPC9kaXY+Cgo8L2Rpdj4KPCEtLSAvd3A6aHRtbCAtLT4KCgUHFrUung0LEhEPCAcPBAoDBxULtLICiKwQIAUHCAQIBAgGCAUYCAcIBwgGCA4IDggLSAEEDhQbHggMCREUGA8YFQgGCAcPBApHABUKDQ8MCw0FBwUHEhwZCAcECkcAFQoNDwwSHBkLEQgCSQAHAQcTFwEAAAkBBAAAAQAAAAEGAAwBAAAOAQEADUEAAEIBAQBBAABBAAAfQQGoCSFBFa4BQRU8QR4ljyue\/wGPBLcCl+ABqcsONAIkAH0BdxMyMDI2LTA1LTE5VDE1OjAwOjIwdyRlODZhZmI5ZS1iMjUyLTQ5YzAtOGE0MS05OGE0Nzk3MGQxMzR32B48ZGl2IGNsYXNzPSJncC1sZWFkIj4KPHN0eWxlPgouZ3AtbGVhZHtmb250LWZhbWlseTp2YXIoLS13cC0tcHJlc2V0LS1mb250LWZhbWlseS0tbnVuaXRvLCJOdW5pdG8iLHN5c3RlbS11aSwtYXBwbGUtc3lzdGVtLFNlZ29lIFVJLHNhbnMtc2VyaWYpO2NvbG9yOiMyMTIxMjE7bWF4LXdpZHRoOjEwODBweDttYXJnaW46MCBhdXRvO3BhZGRpbmc6MCA4cHh9Ci5ncC1sZWFkIGgxe2ZvbnQtZmFtaWx5OnZhcigtLXdwLS1wcmVzZXQtLWZvbnQtZmFtaWx5LS1wb3BwaW5zLCJQb3BwaW5zIixzeXN0ZW0tdWksc2Fucy1zZXJpZik7Zm9udC13ZWlnaHQ6ODAwO2NvbG9yOiMwZTNhMWM7bGluZS1oZWlnaHQ6MS4xNTtsZXR0ZXItc3BhY2luZzotMC4wMThlbTttYXJnaW46MCAwIDEycHg7Zm9udC1zaXplOjEuOTVyZW07bWF4LXdpZHRoOjgyMHB4fQouZ3AtbGVhZCBoMSAuYWNjZW50e2JhY2tncm91bmQ6bGluZWFyLWdyYWRpZW50KDEyMGRlZywjZjc2YTBjIDAlLCMxNTcwMWUgMTAwJSk7LXdlYmtpdC1iYWNrZ3JvdW5kLWNsaXA6dGV4dDtiYWNrZ3JvdW5kLWNsaXA6dGV4dDtjb2xvcjp0cmFuc3BhcmVudH0KLmdwLWxlYWQgLmdwbC1oZXJve3Bvc2l0aW9uOnJlbGF0aXZlO2JhY2tncm91bmQ6cmFkaWFsLWdyYWRpZW50KDkwMHB4IDM2MHB4IGF0IDAlIC0xMCUscmdiYSg3NCwyMjIsMTI4LDAuMTgpLHRyYW5zcGFyZW50IDYwJSkscmFkaWFsLWdyYWRpZW50KDcwMHB4IDMyMHB4IGF0IDEwNSUgMTEwJSxyZ2JhKDI0NywxMDYsMTIsMC4xMCksdHJhbnNwYXJlbnQgNjAlKSxsaW5lYXItZ3JhZGllbnQoMTgwZGVnLCNmYmZjZjYgMCUsI2YxZjZlOCAxMDAlKTtib3JkZXI6MXB4IHNvbGlkICNkNmUyYzU7Ym9yZGVyLXJhZGl1czoyMHB4O3BhZGRpbmc6MjZweCAzMHB4IDIycHg7bWFyZ2luOjZweCAwIDI0cHg7b3ZlcmZsb3c6aGlkZGVuO2JveC1zaGFkb3c6MCAxMnB4IDMycHggcmdiYSgyMCw4Myw0MCwwLjA2KSwwIDAgMCAxcHggcmdiYSgyNTUsMjU1LDI1NSwwLjU1KSBpbnNldH0KLmdwLWxlYWQgLmdwbC1oZXJvLWV5ZWJyb3d7ZGlzcGxheTppbmxpbmUtZmxleDthbGlnbi1pdGVtczpjZW50ZXI7Z2FwOjhweDtmb250LWZhbWlseTp2YXIoLS13cC0tcHJlc2V0LS1mb250LWZhbWlseS0tcG9wcGlucywiUG9wcGlucyIsc2Fucy1zZXJpZik7Zm9udC1zaXplOi43NHJlbTtmb250LXdlaWdodDo3MDA7bGV0dGVyLXNwYWNpbmc6LjE0ZW07dGV4dC10cmFuc2Zvcm06dXBwZXJjYXNlO2NvbG9yOiMxNTcwMWU7YmFja2dyb3VuZDojZmZmO2JvcmRlcjoxcHggc29saWQgI2NmZTRkNDtib3JkZXItcmFkaXVzOjk5OXB4O3BhZGRpbmc6NnB4IDEycHg7bWFyZ2luOjAgMCAxNHB4O2JveC1zaGFkb3c6MCAxcHggMnB4IHJnYmEoMjAsODMsNDAsMC4wNSl9Ci5ncC1sZWFkIC5ncGwtaGVyby1leWVicm93OjpiZWZvcmV7Y29udGVudDoiIjt3aWR0aDo3cHg7aGVpZ2h0OjdweDtib3JkZXItcmFkaXVzOjUwJTtiYWNrZ3JvdW5kOiMyMmM1NWU7Ym94LXNoYWRvdzowIDAgMCAzcHggcmdiYSgzNCwxOTcsOTQsMC4yMil9Ci5ncC1sZWFkIC5ncGwtaGVybyAubGVkZXtmb250LXNpemU6MS4wMnJlbTtsaW5lLWhlaWdodDoxLjU1O2NvbG9yOiMyNDMwMjQ7bWFyZ2luOjA7bWF4LXdpZHRoOjgyMHB4O2ZvbnQtd2VpZ2h0OjQwMH0KLmdwLWxlYWQgLmdwbC1oZXJvIC5sZWRlIHN0cm9uZ3tjb2xvcjojMGUzYTFjO2ZvbnQtd2VpZ2h0OjYwMH0KLmdwLWxlYWQgLmdwbC1oZXJvLWZlYXR1cmVze2Rpc3BsYXk6ZmxleDtmbGV4LXdyYXA6d3JhcDtnYXA6OHB4O21hcmdpbjoxOHB4IDAgMH0KLmdwLWxlYWQgLmdwbC1oZXJvLWZlYXR7ZGlzcGxheTppbmxpbmUtZmxleDthbGlnbi1pdGVtczpjZW50ZXI7Z2FwOjhweDtiYWNrZ3JvdW5kOiNmZmY7Ym9yZGVyOjFweCBzb2xpZCAjZDhlNmQ4O2NvbG9yOiMxYzRhMmE7Zm9udC1zaXplOi44NnJlbTtmb250LXdlaWdodDo2MDA7cGFkZGluZzo2cHggMTJweDtib3JkZXItcmFkaXVzOjk5OXB4O2ZvbnQtZmFtaWx5OnZhcigtLXdwLS1wcmVzZXQtLWZvbnQtZmFtaWx5LS1wb3BwaW5zLCJQb3BwaW5zIixzYW5zLXNlcmlmKTtib3gtc2hhZG93OjAgMXB4IDJweCByZ2JhKDIwLDgzLDQwLDAuMDQpfQouZ3AtbGVhZCAuZ3BsLWhlcm8tZmVhdDo6YmVmb3Jle2NvbnRlbnQ6IlwyNzEzIjt3aWR0aDoxNnB4O2hlaWdodDoxNnB4O2ZsZXg6MCAwIDE2cHg7YmFja2dyb3VuZDojMjJjNTVlO2NvbG9yOiNmZmY7Ym9yZGVyLXJhZGl1czo1MCU7Zm9udC1zaXplOjEwcHg7Zm9udC13ZWlnaHQ6ODAwO2xpbmUtaGVpZ2h0OjE2cHg7dGV4dC1hbGlnbjpjZW50ZXJ9Ci5ncC1sZWFkIC5ncGwtaGVyby1mZWF0LmlzLXRydXN0e2JhY2tncm91bmQ6dHJhbnNwYXJlbnQ7Ym9yZGVyLWNvbG9yOnRyYW5zcGFyZW50O2NvbG9yOiMzYTRhM2E7cGFkZGluZzo2cHggNHB4O2JveC1zaGFkb3c6bm9uZX0KLmdwLWxlYWQgLmdwbC1oZXJvLWZlYXQuaXMtdHJ1c3Q6OmJlZm9yZXtjb250ZW50OiJcMUY1MTIiO3dpZHRoOmF1dG87aGVpZ2h0OmF1dG87YmFja2dyb3VuZDp0cmFuc3BhcmVudDtjb2xvcjojMTU3MDFlO2ZvbnQtc2l6ZToxM3B4O2xpbmUtaGVpZ2h0OjF9CkBtZWRpYSAobWF4LXdpZHRoOjc2MHB4KXsKICAuZ3AtbGVhZCAuZ3BsLWhlcm97cGFkZGluZzoyMHB4IDE4cHg7bWFyZ2luOjRweCAwIDE2cHg7Ym9yZGVyLXJhZGl1czoxNnB4fQogIC5ncC1sZWFkIC5ncGwtaGVyby1leWVicm93e2ZvbnQtc2l6ZTouNjZyZW07bGV0dGVyLXNwYWNpbmc6LjEyZW07cGFkZGluZzo1cHggMTBweDttYXJnaW4tYm90dG9tOjEwcHh9CiAgLmdwLWxlYWQgaDF7Zm9udC1zaXplOjEuMzVyZW07bGluZS1oZWlnaHQ6MS4yO21hcmdpbi1ib3R0b206OHB4fQogIC5ncC1sZWFkIC5ncGwtaGVybyAubGVkZXtmb250LXNpemU6Ljk1cmVtO2xpbmUtaGVpZ2h0OjEuNX0KICAuZ3AtbGVhZCAuZ3BsLWhlcm8tZmVhdHVyZXN7Z2FwOjZweDttYXJnaW4tdG9wOjEycHh9CiAgLmdwLWxlYWQgLmdwbC1oZXJvLWZlYXR7Zm9udC1zaXplOi43OHJlbTtwYWRkaW5nOjVweCAxMHB4fQp9Cjwvc3R5bGU+CjxzZWN0aW9uIGNsYXNzPSJncGwtaGVybyI+CiAgPGRpdiBjbGFzcz0iZ3BsLWhlcm8tZXllYnJvdyI+R3VpZGFuY2UgTGluZXMgU2ltdWxhdG9yIMK3IEZyZWUgwrcgTm8gc2lnbnVwPC9kaXY+CiAgPGgxPlBsYW4geW91ciB0cmFjdG9yIHBhdGguIEZpbmQgdGhlIDxzcGFuIGNsYXNzPSJhY2NlbnQiPmxvd2VzdC1mdWVsLCBoaWdoZXN0LWNvdmVyYWdlPC9zcGFuPiBkcml2ZSBwbGFuIGZvciB5b3VyIGZpZWxkLjwvaDE+CiAgPHAgY2xhc3M9ImxlZGUiPkNvbXBhcmUgQUIgU3RyYWlnaHQsIEFCIEN1cnZlLCBCb3VuZGFyeSBGb2xsb3csIGFuZCBDb250b3VyLWZvbGxvdyBzaWRlIGJ5IHNpZGUuIFNlZSA8c3Ryb25nPmNvdmVyYWdlICUsIHR1cm5hcm91bmRzLCBmdWVsLCBzbG9wZSBjb3N0PC9zdHJvbmc+LCB0aGVuIHdhdGNoIHRoZSBmdWxsIHBsYXliYWNrLiBEcm9wIHlvdXIgb3duIGJvdW5kYXJ5IChHZW9KU09OIC8gS01MIC8gc2hhcGVmaWxlKSBvciB0cnkgb25lIG9mIGZvdXIgc2FtcGxlIGZpZWxkcy48L3A+CiAgPGRpdiBjbGFzcz0iZ3BsLWhlcm8tZmVhdHVyZXMiPgogICAgPHNwYW4gY2xhc3M9ImdwbC1oZXJvLWZlYXQiPjQgYXBwcm9hY2hlcyBzY29yZWQ8L3NwYW4+CiAgICA8c3BhbiBjbGFzcz0iZ3BsLWhlcm8tZmVhdCI+U2xvcGUtYXdhcmUgZnVlbDwvc3Bhbj4KICAgIDxzcGFuIGNsYXNzPSJncGwtaGVyby1mZWF0Ij5Db3ZlcmFnZSByYXN0ZXJpc2VyPC9zcGFuPgogICAgPHNwYW4gY2xhc3M9ImdwbC1oZXJvLWZlYXQiPkRyb3AgeW91ciBvd24gZmllbGQ8L3NwYW4+CiAgICA8c3BhbiBjbGFzcz0iZ3BsLWhlcm8tZmVhdCBpcy10cnVzdCI+RGF0YSBzdGF5cyBpbiB5b3VyIGJyb3dzZXI8L3NwYW4+CiAgPC9kaXY+Cjwvc2VjdGlvbj4KPC9kaXY+d9gePGRpdiBjbGFzcz0iZ3AtbGVhZCI+CjxzdHlsZT4KLmdwLWxlYWR7Zm9udC1mYW1pbHk6dmFyKC0td3AtLXByZXNldC0tZm9udC1mYW1pbHktLW51bml0bywiTnVuaXRvIixzeXN0ZW0tdWksLWFwcGxlLXN5c3RlbSxTZWdvZSBVSSxzYW5zLXNlcmlmKTtjb2xvcjojMjEyMTIxO21heC13aWR0aDoxMDgwcHg7bWFyZ2luOjAgYXV0bztwYWRkaW5nOjAgOHB4fQouZ3AtbGVhZCBoMXtmb250LWZhbWlseTp2YXIoLS13cC0tcHJlc2V0LS1mb250LWZhbWlseS0tcG9wcGlucywiUG9wcGlucyIsc3lzdGVtLXVpLHNhbnMtc2VyaWYpO2ZvbnQtd2VpZ2h0OjgwMDtjb2xvcjojMGUzYTFjO2xpbmUtaGVpZ2h0OjEuMTU7bGV0dGVyLXNwYWNpbmc6LTAuMDE4ZW07bWFyZ2luOjAgMCAxMnB4O2ZvbnQtc2l6ZToxLjk1cmVtO21heC13aWR0aDo4MjBweH0KLmdwLWxlYWQgaDEgLmFjY2VudHtiYWNrZ3JvdW5kOmxpbmVhci1ncmFkaWVudCgxMjBkZWcsI2Y3NmEwYyAwJSwjMTU3MDFlIDEwMCUpOy13ZWJraXQtYmFja2dyb3VuZC1jbGlwOnRleHQ7YmFja2dyb3VuZC1jbGlwOnRleHQ7Y29sb3I6dHJhbnNwYXJlbnR9Ci5ncC1sZWFkIC5ncGwtaGVyb3twb3NpdGlvbjpyZWxhdGl2ZTtiYWNrZ3JvdW5kOnJhZGlhbC1ncmFkaWVudCg5MDBweCAzNjBweCBhdCAwJSAtMTAlLHJnYmEoNzQsMjIyLDEyOCwwLjE4KSx0cmFuc3BhcmVudCA2MCUpLHJhZGlhbC1ncmFkaWVudCg3MDBweCAzMjBweCBhdCAxMDUlIDExMCUscmdiYSgyNDcsMTA2LDEyLDAuMTApLHRyYW5zcGFyZW50IDYwJSksbGluZWFyLWdyYWRpZW50KDE4MGRlZywjZmJmY2Y2IDAlLCNmMWY2ZTggMTAwJSk7Ym9yZGVyOjFweCBzb2xpZCAjZDZlMmM1O2JvcmRlci1yYWRpdXM6MjBweDtwYWRkaW5nOjI2cHggMzBweCAyMnB4O21hcmdpbjo2cHggMCAyNHB4O292ZXJmbG93OmhpZGRlbjtib3gtc2hhZG93OjAgMTJweCAzMnB4IHJnYmEoMjAsODMsNDAsMC4wNiksMCAwIDAgMXB4IHJnYmEoMjU1LDI1NSwyNTUsMC41NSkgaW5zZXR9Ci5ncC1sZWFkIC5ncGwtaGVyby1leWVicm93e2Rpc3BsYXk6aW5saW5lLWZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2dhcDo4cHg7Zm9udC1mYW1pbHk6dmFyKC0td3AtLXByZXNldC0tZm9udC1mYW1pbHktLXBvcHBpbnMsIlBvcHBpbnMiLHNhbnMtc2VyaWYpO2ZvbnQtc2l6ZTouNzRyZW07Zm9udC13ZWlnaHQ6NzAwO2xldHRlci1zcGFjaW5nOi4xNGVtO3RleHQtdHJhbnNmb3JtOnVwcGVyY2FzZTtjb2xvcjojMTU3MDFlO2JhY2tncm91bmQ6I2ZmZjtib3JkZXI6MXB4IHNvbGlkICNjZmU0ZDQ7Ym9yZGVyLXJhZGl1czo5OTlweDtwYWRkaW5nOjZweCAxMnB4O21hcmdpbjowIDAgMTRweDtib3gtc2hhZG93OjAgMXB4IDJweCByZ2JhKDIwLDgzLDQwLDAuMDUpfQouZ3AtbGVhZCAuZ3BsLWhlcm8tZXllYnJvdzo6YmVmb3Jle2NvbnRlbnQ6IiI7d2lkdGg6N3B4O2hlaWdodDo3cHg7Ym9yZGVyLXJhZGl1czo1MCU7YmFja2dyb3VuZDojMjJjNTVlO2JveC1zaGFkb3c6MCAwIDAgM3B4IHJnYmEoMzQsMTk3LDk0LDAuMjIpfQouZ3AtbGVhZCAuZ3BsLWhlcm8gLmxlZGV7Zm9udC1zaXplOjEuMDJyZW07bGluZS1oZWlnaHQ6MS41NTtjb2xvcjojMjQzMDI0O21hcmdpbjowO21heC13aWR0aDo4MjBweDtmb250LXdlaWdodDo0MDB9Ci5ncC1sZWFkIC5ncGwtaGVybyAubGVkZSBzdHJvbmd7Y29sb3I6IzBlM2ExYztmb250LXdlaWdodDo2MDB9Ci5ncC1sZWFkIC5ncGwtaGVyby1mZWF0dXJlc3tkaXNwbGF5OmZsZXg7ZmxleC13cmFwOndyYXA7Z2FwOjhweDttYXJnaW46MThweCAwIDB9Ci5ncC1sZWFkIC5ncGwtaGVyby1mZWF0e2Rpc3BsYXk6aW5saW5lLWZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2dhcDo4cHg7YmFja2dyb3VuZDojZmZmO2JvcmRlcjoxcHggc29saWQgI2Q4ZTZkODtjb2xvcjojMWM0YTJhO2ZvbnQtc2l6ZTouODZyZW07Zm9udC13ZWlnaHQ6NjAwO3BhZGRpbmc6NnB4IDEycHg7Ym9yZGVyLXJhZGl1czo5OTlweDtmb250LWZhbWlseTp2YXIoLS13cC0tcHJlc2V0LS1mb250LWZhbWlseS0tcG9wcGlucywiUG9wcGlucyIsc2Fucy1zZXJpZik7Ym94LXNoYWRvdzowIDFweCAycHggcmdiYSgyMCw4Myw0MCwwLjA0KX0KLmdwLWxlYWQgLmdwbC1oZXJvLWZlYXQ6OmJlZm9yZXtjb250ZW50OiJcMjcxMyI7d2lkdGg6MTZweDtoZWlnaHQ6MTZweDtmbGV4OjAgMCAxNnB4O2JhY2tncm91bmQ6IzIyYzU1ZTtjb2xvcjojZmZmO2JvcmRlci1yYWRpdXM6NTAlO2ZvbnQtc2l6ZToxMHB4O2ZvbnQtd2VpZ2h0OjgwMDtsaW5lLWhlaWdodDoxNnB4O3RleHQtYWxpZ246Y2VudGVyfQouZ3AtbGVhZCAuZ3BsLWhlcm8tZmVhdC5pcy10cnVzdHtiYWNrZ3JvdW5kOnRyYW5zcGFyZW50O2JvcmRlci1jb2xvcjp0cmFuc3BhcmVudDtjb2xvcjojM2E0YTNhO3BhZGRpbmc6NnB4IDRweDtib3gtc2hhZG93Om5vbmV9Ci5ncC1sZWFkIC5ncGwtaGVyby1mZWF0LmlzLXRydXN0OjpiZWZvcmV7Y29udGVudDoiXDFGNTEyIjt3aWR0aDphdXRvO2hlaWdodDphdXRvO2JhY2tncm91bmQ6dHJhbnNwYXJlbnQ7Y29sb3I6IzE1NzAxZTtmb250LXNpemU6MTNweDtsaW5lLWhlaWdodDoxfQpAbWVkaWEgKG1heC13aWR0aDo3NjBweCl7CiAgLmdwLWxlYWQgLmdwbC1oZXJve3BhZGRpbmc6MjBweCAxOHB4O21hcmdpbjo0cHggMCAxNnB4O2JvcmRlci1yYWRpdXM6MTZweH0KICAuZ3AtbGVhZCAuZ3BsLWhlcm8tZXllYnJvd3tmb250LXNpemU6LjY2cmVtO2xldHRlci1zcGFjaW5nOi4xMmVtO3BhZGRpbmc6NXB4IDEwcHg7bWFyZ2luLWJvdHRvbToxMHB4fQogIC5ncC1sZWFkIGgxe2ZvbnQtc2l6ZToxLjM1cmVtO2xpbmUtaGVpZ2h0OjEuMjttYXJnaW4tYm90dG9tOjhweH0KICAuZ3AtbGVhZCAuZ3BsLWhlcm8gLmxlZGV7Zm9udC1zaXplOi45NXJlbTtsaW5lLWhlaWdodDoxLjV9CiAgLmdwLWxlYWQgLmdwbC1oZXJvLWZlYXR1cmVze2dhcDo2cHg7bWFyZ2luLXRvcDoxMnB4fQogIC5ncC1sZWFkIC5ncGwtaGVyby1mZWF0e2ZvbnQtc2l6ZTouNzhyZW07cGFkZGluZzo1cHggMTBweH0KfQo8L3N0eWxlPgo8c2VjdGlvbiBjbGFzcz0iZ3BsLWhlcm8iPgogIDxkaXYgY2xhc3M9ImdwbC1oZXJvLWV5ZWJyb3ciPkd1aWRhbmNlIExpbmVzIFNpbXVsYXRvciDCtyBGcmVlIMK3IE5vIHNpZ251cDwvZGl2PgogIDxoMT5QbGFuIHlvdXIgdHJhY3RvciBwYXRoLiBGaW5kIHRoZSA8c3BhbiBjbGFzcz0iYWNjZW50Ij5sb3dlc3QtZnVlbCwgaGlnaGVzdC1jb3ZlcmFnZTwvc3Bhbj4gZHJpdmUgcGxhbiBmb3IgeW91ciBmaWVsZC48L2gxPgogIDxwIGNsYXNzPSJsZWRlIj5Db21wYXJlIEFCIFN0cmFpZ2h0LCBBQiBDdXJ2ZSwgQm91bmRhcnkgRm9sbG93LCBhbmQgQ29udG91ci1mb2xsb3cgc2lkZSBieSBzaWRlLiBTZWUgPHN0cm9uZz5jb3ZlcmFnZSAlLCB0dXJuYXJvdW5kcywgZnVlbCwgc2xvcGUgY29zdDwvc3Ryb25nPiwgdGhlbiB3YXRjaCB0aGUgZnVsbCBwbGF5YmFjay4gRHJvcCB5b3VyIG93biBib3VuZGFyeSAoR2VvSlNPTiAvIEtNTCAvIHNoYXBlZmlsZSkgb3IgdHJ5IG9uZSBvZiBmb3VyIHNhbXBsZSBmaWVsZHMuPC9wPgogIDxkaXYgY2xhc3M9ImdwbC1oZXJvLWZlYXR1cmVzIj4KICAgIDxzcGFuIGNsYXNzPSJncGwtaGVyby1mZWF0Ij40IGFwcHJvYWNoZXMgc2NvcmVkPC9zcGFuPgogICAgPHNwYW4gY2xhc3M9ImdwbC1oZXJvLWZlYXQiPlNsb3BlLWF3YXJlIGZ1ZWw8L3NwYW4+CiAgICA8c3BhbiBjbGFzcz0iZ3BsLWhlcm8tZmVhdCI+Q292ZXJhZ2UgcmFzdGVyaXNlcjwvc3Bhbj4KICAgIDxzcGFuIGNsYXNzPSJncGwtaGVyby1mZWF0Ij5Ecm9wIHlvdXIgb3duIGZpZWxkPC9zcGFuPgogICAgPHNwYW4gY2xhc3M9ImdwbC1oZXJvLWZlYXQgaXMtdHJ1c3QiPkRhdGEgc3RheXMgaW4geW91ciBicm93c2VyPC9zcGFuPgogIDwvZGl2Pgo8L3NlY3Rpb24+CjwvZGl2PnckM2UyZjBmMDAtNjY3Yi00ODE2LWIwZDktNDRjNGVlMDc5Zjkzd6IFPCEtLSDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAgUkVQTEFDRSBUSElTIEJMT0NLIFdJVEggYnVpbGQvZW1iZWRfb25seS5odG1sIOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkCAtLT4KPCEtLSBSdW46IGJhc2ggc2NyaXB0cy9yZWJ1aWxkLnNoIGd1aWRhbmNlLWxpbmVzICAobG9hZHMgY2xpcGJvYXJkKSAtLT4KPCEtLSBUaGVuIGluIFdQIGFkbWluOiBjbGljayB0aGlzIEN1c3RvbSBIVE1MIGJsb2NrLCB0b29sYmFyIOKLriDihpIgRWRpdCBhcyBIVE1MLCBzZWxlY3QgYWxsLCBDbWQrViAtLT4KPGRpdiBzdHlsZT0icGFkZGluZzo0OHB4O3RleHQtYWxpZ246Y2VudGVyO2JhY2tncm91bmQ6I2ZhZmJmNDtib3JkZXI6MnB4IGRhc2hlZCAjMTU3MDFlO2JvcmRlci1yYWRpdXM6MTJweDtjb2xvcjojMTU3MDFlO2ZvbnQtZmFtaWx5OidETSBNb25vJyxtb25vc3BhY2U7Zm9udC13ZWlnaHQ6NjAwIj4KICBFbWJlZCBwbGFjZWhvbGRlcjxicj4KICA8c3BhbiBzdHlsZT0iZm9udC1zaXplOjEzcHg7Zm9udC13ZWlnaHQ6NDAwO2NvbG9yOiM0YzYwNjYiPlJlcGxhY2UgdGhpcyBDdXN0b20gSFRNTCBibG9jayB3aXRoIGJ1aWxkL2VtYmVkX29ubHkuaHRtbCAocnVuIHJlYnVpbGQuc2ggZmlyc3QgdG8gbG9hZCBjbGlwYm9hcmQpPC9zcGFuPgo8L2Rpdj53CWNvcmUvaHRtbHeiBTwhLS0g4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQIFJFUExBQ0UgVEhJUyBCTE9DSyBXSVRIIGJ1aWxkL2VtYmVkX29ubHkuaHRtbCDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAgLS0+CjwhLS0gUnVuOiBiYXNoIHNjcmlwdHMvcmVidWlsZC5zaCBndWlkYW5jZS1saW5lcyAgKGxvYWRzIGNsaXBib2FyZCkgLS0+CjwhLS0gVGhlbiBpbiBXUCBhZG1pbjogY2xpY2sgdGhpcyBDdXN0b20gSFRNTCBibG9jaywgdG9vbGJhciDii64g4oaSIEVkaXQgYXMgSFRNTCwgc2VsZWN0IGFsbCwgQ21kK1YgLS0+CjxkaXYgc3R5bGU9InBhZGRpbmc6NDhweDt0ZXh0LWFsaWduOmNlbnRlcjtiYWNrZ3JvdW5kOiNmYWZiZjQ7Ym9yZGVyOjJweCBkYXNoZWQgIzE1NzAxZTtib3JkZXItcmFkaXVzOjEycHg7Y29sb3I6IzE1NzAxZTtmb250LWZhbWlseTonRE0gTW9ubycsbW9ub3NwYWNlO2ZvbnQtd2VpZ2h0OjYwMCI+CiAgRW1iZWQgcGxhY2Vob2xkZXI8YnI+CiAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxM3B4O2ZvbnQtd2VpZ2h0OjQwMDtjb2xvcjojNGM2MDY2Ij5SZXBsYWNlIHRoaXMgQ3VzdG9tIEhUTUwgYmxvY2sgd2l0aCBidWlsZC9lbWJlZF9vbmx5Lmh0bWwgKHJ1biByZWJ1aWxkLnNoIGZpcnN0IHRvIGxvYWQgY2xpcGJvYXJkKTwvc3Bhbj4KPC9kaXY+dyQwMmYyMzAwYS1mZmQyLTQ1ODEtOTViNC1iNDE2MDYyMDM4Mzh4dwB3CmNvcmUvYmxvY2t9q8wBdQB2AxByZXN0cmljdGlvbl90eXBldwdleGNsdWRlEnNlbGVjdGVkX2xhbmd1YWdlc3UACnBhbmVsX29wZW54e0J55Ah7YqAAfYaEn6ANdyQxZjAyMzE0MS01YzA2LTQ5MWMtOTkxZC0yZmUzYmNiMjE3MDl34rMJPGRpdiBjbGFzcz0iZ3BsLXdyYXAiIGlkPSJncGwtcm9vdCI+CjxzdHlsZT4KLmdwbC13cmFwe2FsbDppbml0aWFsO2Rpc3BsYXk6YmxvY2s7Zm9udC1mYW1pbHk6Ik51bml0byIsc3lzdGVtLXVpLC1hcHBsZS1zeXN0ZW0sc2Fucy1zZXJpZjtmb250LXNpemU6MTNweDtsaW5lLWhlaWdodDoxLjQ1O2NvbG9yOiMyMTIxMjE7YmFja2dyb3VuZDojZmFmYmY0O2JvcmRlcjoxcHggc29saWQgI2VlZWVlZTtib3JkZXItcmFkaXVzOjEycHg7b3ZlcmZsb3c6aGlkZGVuO21heC13aWR0aDoxMDAlO2JveC1zaGFkb3c6MCA0cHggMjBweCByZ2JhKDIwLDgzLDQwLC4wNSl9Ci5ncGwtd3JhcCAqLC5ncGwtd3JhcCAqOjpiZWZvcmUsLmdwbC13cmFwICo6OmFmdGVye2JveC1zaXppbmc6Ym9yZGVyLWJveH0KLmdwbC13cmFwIC5ncGwtdG9we2Rpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpjZW50ZXI7anVzdGlmeS1jb250ZW50OnNwYWNlLWJldHdlZW47cGFkZGluZzoxNHB4IDE4cHg7Ym9yZGVyLWJvdHRvbToxcHggc29saWQgI2VlZWVlZTtiYWNrZ3JvdW5kOiNmZmZmZmY7Z2FwOjE2cHg7ZmxleC13cmFwOndyYXB9Ci5ncGwtd3JhcCAuZ3BsLWJyYW5ke2Rpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpjZW50ZXI7Z2FwOjEycHg7bWluLXdpZHRoOjA7ZmxleDoxfQouZ3BsLXdyYXAgLmdwbC1sb2dve3dpZHRoOjI4cHg7aGVpZ2h0OjI4cHg7Ym9yZGVyLXJhZGl1czo3cHg7YmFja2dyb3VuZDpsaW5lYXItZ3JhZGllbnQoMTM1ZGVnLCMxNDUzMjggMCUsIzFhNzk1MSAxMDAlKTtkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2p1c3RpZnktY29udGVudDpjZW50ZXI7Y29sb3I6I2ZmZjtmb250LXdlaWdodDo3MDA7Zm9udC1zaXplOjE0cHg7ZmxleDpub25lfQouZ3BsLXdyYXAgLmdwbC1oMXtmb250LXNpemU6MTVweDtmb250LXdlaWdodDo2MDA7bGV0dGVyLXNwYWNpbmc6LS4wMWVtO2ZvbnQtZmFtaWx5OiJQb3BwaW5zIixzeXN0ZW0tdWksc2Fucy1zZXJpZn0KLmdwbC13cmFwIC5ncGwtY2hpcHtkaXNwbGF5OmlubGluZS1mbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtnYXA6NnB4O2ZvbnQtZmFtaWx5OiJETSBNb25vIix1aS1tb25vc3BhY2UsbW9ub3NwYWNlO2ZvbnQtc2l6ZToxMXB4O3BhZGRpbmc6MnB4IDhweDtib3JkZXItcmFkaXVzOjEwcHg7YmFja2dyb3VuZDojZmFmYmY0O2NvbG9yOiM0YzYwNjY7Ym9yZGVyOjFweCBzb2xpZCAjZWVlZWVlO21hcmdpbi10b3A6M3B4fQouZ3BsLXdyYXAgLmdwbC1jaGlwIC5ncGwtZG90e3dpZHRoOjZweDtoZWlnaHQ6NnB4O2JvcmRlci1yYWRpdXM6NTAlO2JhY2tncm91bmQ6IzE1NzAxZTtmbGV4Om5vbmV9Ci5ncGwtd3JhcCAuZ3BsLWN0YXtiYWNrZ3JvdW5kOiMxNTcwMWU7Y29sb3I6I2ZmZjtib3JkZXI6MDtwYWRkaW5nOjlweCAxNHB4O2JvcmRlci1yYWRpdXM6N3B4O2ZvbnQtd2VpZ2h0OjYwMDtmb250LXNpemU6MTNweDtjdXJzb3I6cG9pbnRlcjtmb250LWZhbWlseTppbmhlcml0O2Rpc3BsYXk6aW5saW5lLWZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2dhcDo3cHg7dGV4dC1kZWNvcmF0aW9uOm5vbmU7dHJhbnNpdGlvbjpiYWNrZ3JvdW5kIC4xNXN9Ci5ncGwtd3JhcCAuZ3BsLWN0YTpob3ZlcntiYWNrZ3JvdW5kOiMxYjdhMmF9Ci5ncGwtd3JhcCAuZ3BsLWdyaWR7ZGlzcGxheTpncmlkO2dyaWQtdGVtcGxhdGUtY29sdW1uczp2YXIoLS1ncGwtbGVmdC13LDIwMHB4KSA1cHggMWZyIDI0MHB4O2dyaWQtdGVtcGxhdGUtYXJlYXM6ImxlZnQgc3BsaXR0ZXIgbWFpbiByaWdodCI7bWluLWhlaWdodDo2MDBweH0KLmdwbC13cmFwIC5ncGwtc2lkZXtncmlkLWFyZWE6bGVmdDtiYWNrZ3JvdW5kOiNmZmZmZmY7Ym9yZGVyLXJpZ2h0OjFweCBzb2xpZCAjZWVlZWVlO3BhZGRpbmc6MTBweCA4cHg7ZGlzcGxheTpmbGV4O2ZsZXgtZGlyZWN0aW9uOmNvbHVtbjtnYXA6N3B4O21pbi13aWR0aDowO292ZXJmbG93LXk6YXV0b30KLmdwbC13cmFwIC5ncGwtc3BsaXR0ZXJ7Z3JpZC1hcmVhOnNwbGl0dGVyO2JhY2tncm91bmQ6dHJhbnNwYXJlbnQ7Y3Vyc29yOmNvbC1yZXNpemU7cG9zaXRpb246cmVsYXRpdmU7dXNlci1zZWxlY3Q6bm9uZTstd2Via2l0LXVzZXItc2VsZWN0Om5vbmU7dG91Y2gtYWN0aW9uOm5vbmV9Ci5ncGwtd3JhcCAuZ3BsLXNwbGl0dGVyOjpiZWZvcmV7Y29udGVudDoiIjtwb3NpdGlvbjphYnNvbHV0ZTtsZWZ0OjUwJTt0b3A6NTAlO3dpZHRoOjFweDtoZWlnaHQ6MzRweDt0cmFuc2Zvcm06dHJhbnNsYXRlKC01MCUsLTUwJSk7YmFja2dyb3VuZDojZGRkZGRkO3RyYW5zaXRpb246YmFja2dyb3VuZCAuMTVzLHdpZHRoIC4xNXN9Ci5ncGwtd3JhcCAuZ3BsLXNwbGl0dGVyOmhvdmVyOjpiZWZvcmUsLmdwbC13cmFwIC5ncGwtc3BsaXR0ZXIuaXMtZHJhZzo6YmVmb3Jle2JhY2tncm91bmQ6IzE1NzAxZTt3aWR0aDozcHg7Ym9yZGVyLXJhZGl1czoycHg7aGVpZ2h0OjQ4cHh9Ci5ncGwtd3JhcCAuZ3BsLW1haW57Z3JpZC1hcmVhOm1haW47cG9zaXRpb246cmVsYXRpdmU7YmFja2dyb3VuZDojZmFmYmY0fQouZ3BsLXdyYXAgLmdwbC1zaWRlLXJpZ2h0e2dyaWQtYXJlYTpyaWdodDtiYWNrZ3JvdW5kOiNmZmZmZmY7Ym9yZGVyLWxlZnQ6MXB4IHNvbGlkICNlZWVlZWU7cGFkZGluZzoxMHB4IDhweDtkaXNwbGF5OmZsZXg7ZmxleC1kaXJlY3Rpb246Y29sdW1uO2dhcDo3cHg7bWluLXdpZHRoOjA7b3ZlcmZsb3cteTphdXRvfQpAbWVkaWEgKG1heC13aWR0aDoxMDk5cHgpewogIC5ncGwtd3JhcCAuZ3BsLWdyaWR7Z3JpZC10ZW1wbGF0ZS1jb2x1bW5zOnZhcigtLWdwbC1sZWZ0LXcsMTgwcHgpIDVweCAxZnIgMjIwcHh9Cn0KLmdwbC13cmFwIC5ncGwtY2FudmFze2Rpc3BsYXk6YmxvY2s7d2lkdGg6MTAwJTtoZWlnaHQ6MTAwJTtjdXJzb3I6ZGVmYXVsdDtiYWNrZ3JvdW5kOiNmYWZiZjR9Ci5ncGwtd3JhcCAuZ3BsLWNhcmQgaDN7Zm9udC1zaXplOjlweDtmb250LXdlaWdodDo3MDA7dGV4dC10cmFuc2Zvcm06dXBwZXJjYXNlO2xldHRlci1zcGFjaW5nOi4wOGVtO2NvbG9yOiM0YzYwNjY7bWFyZ2luOjAgMCA0cHggMDtmb250LWZhbWlseToiUG9wcGlucyIsc3lzdGVtLXVpLHNhbnMtc2VyaWZ9Ci5ncGwtd3JhcCAuZ3BsLWNhcmR7ZGlzcGxheTpmbGV4O2ZsZXgtZGlyZWN0aW9uOmNvbHVtbjtnYXA6NHB4O3BhZGRpbmc6MH0KLmdwbC13cmFwIC5ncGwtYXBwcm9hY2h7ZGlzcGxheTpmbGV4O2ZsZXgtZGlyZWN0aW9uOmNvbHVtbjtnYXA6M3B4fQouZ3BsLXdyYXAgLmdwbC1hcHByb2FjaCBsYWJlbHtkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2dhcDo1cHg7cGFkZGluZzo1cHggN3B4O2JvcmRlcjoxcHggc29saWQgI2VlZWVlZTtib3JkZXItcmFkaXVzOjVweDtjdXJzb3I6cG9pbnRlcjtiYWNrZ3JvdW5kOiNmZmZmZmY7Zm9udC1zaXplOjEycHg7dHJhbnNpdGlvbjphbGwgLjEyczttaW4taGVpZ2h0OjMycHg7bGluZS1oZWlnaHQ6MS4xNX0KLmdwbC13cmFwIC5ncGwtYXBwcm9hY2ggbGFiZWw6aG92ZXJ7Ym9yZGVyLWNvbG9yOiMxYjdhMmE7YmFja2dyb3VuZDojZmFmYmY0fQouZ3BsLXdyYXAgLmdwbC1hcHByb2FjaCBpbnB1dFt0eXBlPXJhZGlvXXthY2NlbnQtY29sb3I6IzE1NzAxZTt3aWR0aDoxNnB4O2hlaWdodDoxNnB4O21hcmdpbjowfQouZ3BsLXdyYXAgLmdwbC1hcHByb2FjaCBsYWJlbC5pcy1vbntib3JkZXItY29sb3I6IzE1NzAxZTtiYWNrZ3JvdW5kOiNmYWZiZjQ7Zm9udC13ZWlnaHQ6NjAwfQouZ3BsLXdyYXAgLmdwbC1yZWNve2Rpc3BsYXk6bm9uZTtmb250LXNpemU6OXB4O2ZvbnQtd2VpZ2h0OjcwMDt0ZXh0LXRyYW5zZm9ybTp1cHBlcmNhc2U7bGV0dGVyLXNwYWNpbmc6LjA2ZW07Y29sb3I6IzE1NzAxZTtiYWNrZ3JvdW5kOiNkZmY1ZTY7cGFkZGluZzoycHggNnB4O2JvcmRlci1yYWRpdXM6NHB4O21hcmdpbi1sZWZ0OmF1dG87Zm9udC1mYW1pbHk6IkRNIE1vbm8iLHVpLW1vbm9zcGFjZSxtb25vc3BhY2V9Ci5ncGwtd3JhcCAuZ3BsLXJlY28uaXMtb257ZGlzcGxheTppbmxpbmUtYmxvY2t9Ci5ncGwtd3JhcCAuZ3BsLWlucHV0LXJvd3tkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2dhcDo1cHh9Ci5ncGwtd3JhcCAuZ3BsLWlucHV0LXJvdyBsYWJlbHtmb250LXNpemU6MTFweDtjb2xvcjojNGM2MDY2O2ZsZXg6MX0KLmdwbC13cmFwIC5ncGwtaW5wdXQtcm93IGlucHV0e3dpZHRoOjU0cHg7cGFkZGluZzo0cHggNnB4O2JvcmRlcjoxcHggc29saWQgI2VlZWVlZTtib3JkZXItcmFkaXVzOjRweDtmb250LWZhbWlseTppbmhlcml0O2ZvbnQtc2l6ZToxM3B4O3RleHQtYWxpZ246cmlnaHQ7bWluLWhlaWdodDoyOHB4fQouZ3BsLXdyYXAgLmdwbC1pbnB1dC1yb3cgLmdwbC11bml0e2ZvbnQtc2l6ZToxMHB4O2NvbG9yOiM0YzYwNjY7d2lkdGg6MjZweH0KLmdwbC13cmFwIC5ncGwtcmVzdWx0c3tkaXNwbGF5OmZsZXg7ZmxleC1kaXJlY3Rpb246Y29sdW1uO2dhcDoycHg7Zm9udC1mYW1pbHk6IkRNIE1vbm8iLHVpLW1vbm9zcGFjZSxtb25vc3BhY2U7Zm9udC1zaXplOjExcHg7YmFja2dyb3VuZDojZmFmYmY0O3BhZGRpbmc6NnB4IDhweDtib3JkZXItcmFkaXVzOjVweDtib3JkZXI6MXB4IHNvbGlkICNlZWVlZWV9Ci5ncGwtd3JhcCAuZ3BsLXItcm93e2Rpc3BsYXk6ZmxleDtqdXN0aWZ5LWNvbnRlbnQ6c3BhY2UtYmV0d2VlbjthbGlnbi1pdGVtczpiYXNlbGluZTtwYWRkaW5nOjFweCAwfQouZ3BsLXdyYXAgLmdwbC1yLWt7Y29sb3I6IzRjNjA2Njtmb250LXNpemU6MTBweH0KLmdwbC13cmFwIC5ncGwtci12e2ZvbnQtd2VpZ2h0OjYwMDtjb2xvcjojMjEyMTIxO2ZvbnQtc2l6ZToxMnB4fQouZ3BsLXdyYXAgLmdwbC1yLXNhdmluZ3N7Zm9udC1zaXplOjExcHg7Zm9udC13ZWlnaHQ6NjAwfQouZ3BsLXdyYXAgLmdwbC1yLXJvdy5ncGwtci1wcml7Ym9yZGVyLXRvcDoxcHggc29saWQgI2VlZWVlZTtwYWRkaW5nLXRvcDo2cHg7bWFyZ2luLXRvcDoycHh9Ci5ncGwtd3JhcCAuZ3BsLWNtcHttYXJnaW4tdG9wOjZweDtiYWNrZ3JvdW5kOiNmZmZmZmY7Ym9yZGVyOjFweCBzb2xpZCAjZWVlZWVlO2JvcmRlci1yYWRpdXM6NnB4O292ZXJmbG93OmhpZGRlbn0KLmdwbC13cmFwIC5ncGwtY21wLXJvd3tkaXNwbGF5OmdyaWQ7Z3JpZC10ZW1wbGF0ZS1jb2x1bW5zOjFmciA0MnB4IDUwcHggNTBweDthbGlnbi1pdGVtczpjZW50ZXI7cGFkZGluZzo2cHggOHB4O2ZvbnQtc2l6ZToxMXB4O2JvcmRlci1ib3R0b206MXB4IHNvbGlkICNmNWYzZWI7Z2FwOjRweH0KLmdwbC13cmFwIC5ncGwtY21wLXJvdzpsYXN0LWNoaWxke2JvcmRlci1ib3R0b206MH0KLmdwbC13cmFwIC5ncGwtY21wLXJvdy5ncGwtY21wLWhlYWR7Zm9udC13ZWlnaHQ6NjAwO2NvbG9yOiM0YzYwNjY7dGV4dC10cmFuc2Zvcm06dXBwZXJjYXNlO2xldHRlci1zcGFjaW5nOi4wNGVtO2ZvbnQtc2l6ZToxMHB4O2JhY2tncm91bmQ6I2ZhZmJmNH0KLmdwbC13cmFwIC5ncGwtY21wLW5hbWV7Zm9udC1mYW1pbHk6IkRNIE1vbm8iLHVpLW1vbm9zcGFjZSxtb25vc3BhY2V9Ci5ncGwtd3JhcCAuZ3BsLWNtcC12YWx7dGV4dC1hbGlnbjpyaWdodDtmb250LWZhbWlseToiRE0gTW9ubyIsdWktbW9ub3NwYWNlLG1vbm9zcGFjZX0KLmdwbC13cmFwIC5ncGwtY21wLXJvdy5ncGwtY21wLWN1cnJlbnR7YmFja2dyb3VuZDojZmFmYmY0fQouZ3BsLXdyYXAgLmdwbC11bml0LXRvZ2dsZXtkaXNwbGF5OmlubGluZS1mbGV4O2dhcDoycHg7YmFja2dyb3VuZDojZmFmYmY0O2JvcmRlcjoxcHggc29saWQgI2VlZWVlZTtib3JkZXItcmFkaXVzOjZweDtwYWRkaW5nOjJweDttYXJnaW4tYm90dG9tOjVweDthbGlnbi1zZWxmOmZsZXgtc3RhcnR9Ci5ncGwtd3JhcCAuZ3BsLXVuaXQtdGFie2JhY2tncm91bmQ6dHJhbnNwYXJlbnQ7Ym9yZGVyOjA7cGFkZGluZzozcHggOHB4O2ZvbnQtc2l6ZToxMHB4O2ZvbnQtZmFtaWx5OiJETSBNb25vIix1aS1tb25vc3BhY2UsbW9ub3NwYWNlO2ZvbnQtd2VpZ2h0OjcwMDtjb2xvcjojNGM2MDY2O2N1cnNvcjpwb2ludGVyO2JvcmRlci1yYWRpdXM6NHB4O21pbi13aWR0aDoyOHB4fQouZ3BsLXdyYXAgLmdwbC11bml0LXRhYi5pcy1vbntiYWNrZ3JvdW5kOiMxNTcwMWU7Y29sb3I6I2ZmZn0KLmdwbC13cmFwIC5ncGwtc2xpZGVyLXJvd3tkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2dhcDo2cHh9Ci5ncGwtd3JhcCAuZ3BsLXJhbmdle2ZsZXg6MTthY2NlbnQtY29sb3I6IzE1NzAxZTttaW4taGVpZ2h0OjI0cHh9Ci5ncGwtd3JhcCAuZ3BsLXNsaWRlci12YWx7Zm9udC1mYW1pbHk6IkRNIE1vbm8iLHVpLW1vbm9zcGFjZSxtb25vc3BhY2U7Zm9udC1zaXplOjEwcHg7Y29sb3I6IzRjNjA2NjttaW4td2lkdGg6OTBweDt0ZXh0LWFsaWduOnJpZ2h0fQouZ3BsLXdyYXAgLmdwbC1zZWxlY3Qtcm93e2Rpc3BsYXk6ZmxleDtmbGV4LWRpcmVjdGlvbjpjb2x1bW47Z2FwOjJweH0KLmdwbC13cmFwIC5ncGwtc2VsZWN0LXJvdyBsYWJlbHtmb250LXNpemU6MTBweDtjb2xvcjojNGM2MDY2fQouZ3BsLXdyYXAgLmdwbC1zZWxlY3Qtcm93IHNlbGVjdHtwYWRkaW5nOjRweCA2cHg7Ym9yZGVyOjFweCBzb2xpZCAjZWVlZWVlO2JvcmRlci1yYWRpdXM6NHB4O2ZvbnQtZmFtaWx5OmluaGVyaXQ7Zm9udC1zaXplOjEycHg7YmFja2dyb3VuZDojZmZmZmZmO21pbi1oZWlnaHQ6MzJweH0KLmdwbC13cmFwIC5ncGwtY3VyLXNlbHttYXJnaW4tbGVmdDo0cHg7cGFkZGluZzo0cHggNnB4O2JvcmRlcjoxcHggc29saWQgI2VlZWVlZTtib3JkZXItcmFkaXVzOjVweDtmb250LWZhbWlseTppbmhlcml0O2ZvbnQtc2l6ZToxMXB4O2JhY2tncm91bmQ6I2ZmZmZmZjttaW4taGVpZ2h0OjMycHg7d2lkdGg6NDZweH0KLmdwbC13cmFwIC5ncGwtaGludHtmb250LXNpemU6OXB4O2NvbG9yOiM0YzYwNjY7Zm9udC1mYW1pbHk6IkRNIE1vbm8iLHVpLW1vbm9zcGFjZSxtb25vc3BhY2U7bWFyZ2luOi0xcHggMCAycHggMDtsaW5lLWhlaWdodDoxLjM7Zm9udC1zdHlsZTppdGFsaWN9Ci5ncGwtd3JhcCAuZ3BsLWZpZWxkLXBpY2tlcntkaXNwbGF5OmdyaWQ7Z3JpZC10ZW1wbGF0ZS1jb2x1bW5zOjFmciAxZnI7Z2FwOjNweH0KLmdwbC13cmFwIC5ncGwtZmxke2JhY2tncm91bmQ6I2ZmZmZmZjtib3JkZXI6MXB4IHNvbGlkICNlZWVlZWU7Ym9yZGVyLXJhZGl1czo1cHg7cGFkZGluZzo0cHggNXB4O2ZvbnQtZmFtaWx5OmluaGVyaXQ7Zm9udC1zaXplOjEwcHg7Zm9udC13ZWlnaHQ6NjAwO2N1cnNvcjpwb2ludGVyO2NvbG9yOiMyMTIxMjE7ZGlzcGxheTpmbGV4O2ZsZXgtZGlyZWN0aW9uOmNvbHVtbjthbGlnbi1pdGVtczpmbGV4LXN0YXJ0O2dhcDowO3RleHQtYWxpZ246bGVmdDt0cmFuc2l0aW9uOmFsbCAuMTJzO21pbi1oZWlnaHQ6MzRweDtsaW5lLWhlaWdodDoxLjF9Ci5ncGwtd3JhcCAuZ3BsLWZsZDpob3Zlcntib3JkZXItY29sb3I6IzFiN2EyYTtiYWNrZ3JvdW5kOiNmYWZiZjR9Ci5ncGwtd3JhcCAuZ3BsLWZsZC5pcy1vbntib3JkZXItY29sb3I6IzE1NzAxZTtiYWNrZ3JvdW5kOiNmYWZiZjQ7Zm9udC13ZWlnaHQ6NzAwfQouZ3BsLXdyYXAgLmdwbC1mbGQtc3Vie2ZvbnQtc2l6ZTo4cHg7Y29sb3I6IzRjNjA2Njtmb250LXdlaWdodDo1MDA7Zm9udC1zdHlsZTppdGFsaWM7dGV4dC10cmFuc2Zvcm06bm9uZTtsZXR0ZXItc3BhY2luZzowfQouZ3BsLXdyYXAgLmdwbC11cGxvYWR7ZGlzcGxheTpmbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtqdXN0aWZ5LWNvbnRlbnQ6Y2VudGVyO2dhcDo1cHg7YmFja2dyb3VuZDojZmFmYmY0O2NvbG9yOiMxNTcwMWU7Ym9yZGVyOjFweCBkYXNoZWQgI2I4ZTVjNjtwYWRkaW5nOjVweCA4cHg7Ym9yZGVyLXJhZGl1czo1cHg7Zm9udC1mYW1pbHk6aW5oZXJpdDtmb250LXNpemU6MTBweDtmb250LXdlaWdodDo2MDA7Y3Vyc29yOnBvaW50ZXI7bWluLWhlaWdodDozMHB4O21hcmdpbi10b3A6MnB4O3RyYW5zaXRpb246YWxsIC4xMnN9Ci5ncGwtd3JhcCAuZ3BsLXVwbG9hZDpob3ZlcntiYWNrZ3JvdW5kOiNlOWYzZWM7Ym9yZGVyLWNvbG9yOiMxNTcwMWU7Ym9yZGVyLXN0eWxlOnNvbGlkfQouZ3BsLXdyYXAgLmdwbC11cGxvYWQtaWNve2ZvbnQtc2l6ZToxM3B4O2xpbmUtaGVpZ2h0OjF9Ci5ncGwtd3JhcCAuZ3BsLXVwbG9hZC5pcy1lcnJvcntjb2xvcjojZGMyNjI2O2JvcmRlci1jb2xvcjojZmNhNWE1O2JhY2tncm91bmQ6I2ZlZjJmMn0KLmdwbC13cmFwIC5ncGwtdXBsb2FkLmlzLXN1Y2Nlc3N7Y29sb3I6IzE1NzAxZTtiYWNrZ3JvdW5kOiNkZmY1ZTY7Ym9yZGVyLWNvbG9yOiMxNTcwMWU7Ym9yZGVyLXN0eWxlOnNvbGlkfQouZ3BsLXdyYXAgLmdwbC1pbXBvcnQtbmF2e2Rpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpjZW50ZXI7Z2FwOjZweDttYXJnaW4tdG9wOjNweDtqdXN0aWZ5LWNvbnRlbnQ6Y2VudGVyfQouZ3BsLXdyYXAgLmdwbC1pbXAtYnRue3dpZHRoOjI4cHg7aGVpZ2h0OjI4cHg7YmFja2dyb3VuZDojZmFmYmY0O2JvcmRlcjoxcHggc29saWQgI2Q5ZTdkYztib3JkZXItcmFkaXVzOjVweDtjb2xvcjojMTU3MDFlO2N1cnNvcjpwb2ludGVyO2ZvbnQtc2l6ZToxNHB4O2ZvbnQtd2VpZ2h0OjcwMDtmb250LWZhbWlseTppbmhlcml0O2xpbmUtaGVpZ2h0OjE7cGFkZGluZzowO3RyYW5zaXRpb246YWxsIC4xMnN9Ci5ncGwtd3JhcCAuZ3BsLWltcC1idG46aG92ZXJ7YmFja2dyb3VuZDojZGZmNWU2O2JvcmRlci1jb2xvcjojMTU3MDFlfQouZ3BsLXdyYXAgLmdwbC1pbXAtYnRuOmRpc2FibGVke29wYWNpdHk6MC4zNTtjdXJzb3I6bm90LWFsbG93ZWR9Ci5ncGwtd3JhcCAuZ3BsLWltcC1sYmx7Zm9udC1mYW1pbHk6IkRNIE1vbm8iLHVpLW1vbm9zcGFjZSxtb25vc3BhY2U7Zm9udC1zaXplOjExcHg7Zm9udC13ZWlnaHQ6NjAwO2NvbG9yOiM0YzYwNjY7bWluLXdpZHRoOjYwcHg7dGV4dC1hbGlnbjpjZW50ZXJ9Ci5ncGwtd3JhcCAuZ3BsLWFiLWF1dG97YmFja2dyb3VuZDojZmFmYmY0O2NvbG9yOiMxNTcwMWU7Ym9yZGVyOjFweCBzb2xpZCAjZDllN2RjO3BhZGRpbmc6NHB4IDhweDtib3JkZXItcmFkaXVzOjRweDtmb250LWZhbWlseTppbmhlcml0O2ZvbnQtc2l6ZToxMHB4O2ZvbnQtd2VpZ2h0OjYwMDtjdXJzb3I6cG9pbnRlcjttaW4taGVpZ2h0OjI2cHg7dHJhbnNpdGlvbjphbGwgLjEyczt3aWR0aDoxMDAlO21hcmdpbi10b3A6MXB4fQouZ3BsLXdyYXAgLmdwbC1hYi1hdXRvOmhvdmVye2JhY2tncm91bmQ6I2U5ZjNlYztib3JkZXItY29sb3I6IzE1NzAxZX0KLmdwbC13cmFwIC5ncGwtYWItYXV0by5pcy1hdXRve2JhY2tncm91bmQ6I2RmZjVlNjtib3JkZXItY29sb3I6IzE1NzAxZX0KLmdwbC13cmFwIC5ncGwtd2Fybntwb3NpdGlvbjphYnNvbHV0ZTt0b3A6MTBweDtsZWZ0OjUwJTt0cmFuc2Zvcm06dHJhbnNsYXRlWCgtNTAlKTtiYWNrZ3JvdW5kOnJnYmEoMjQ3LDEwNiwxMiwwLjk1KTtjb2xvcjojZmZmO3BhZGRpbmc6OHB4IDE0cHg7Ym9yZGVyLXJhZGl1czo4cHg7Zm9udC1zaXplOjEycHg7Zm9udC13ZWlnaHQ6NjAwO2JveC1zaGFkb3c6MCAycHggOHB4IHJnYmEoMjQ3LDEwNiwxMiwuMyk7bWF4LXdpZHRoOjkwJTt0ZXh0LWFsaWduOmNlbnRlcjtkaXNwbGF5Om5vbmV9Ci5ncGwtd3JhcCAuZ3BsLXdhcm4uaXMtb257ZGlzcGxheTpibG9ja30KLmdwbC13cmFwIC5ncGwtY2FyZC10b3Bve2JhY2tncm91bmQ6bGluZWFyLWdyYWRpZW50KDEzNWRlZywjZmFmYmY0IDAlLCNlZWY0ZWMgMTAwJSk7Ym9yZGVyOjFweCBzb2xpZCAjZDllN2RjO2JvcmRlci1yYWRpdXM6OHB4O3BhZGRpbmc6MTBweCAxMnB4fQouZ3BsLXdyYXAgLmdwbC10b3BvLWJsdXJie2ZvbnQtc2l6ZToxMXB4O2xpbmUtaGVpZ2h0OjEuNDU7Y29sb3I6IzRjNjA2NjttYXJnaW46MCAwIDhweCAwfQouZ3BsLXdyYXAgLmdwbC1jdGEtbWluaXtkaXNwbGF5OmlubGluZS1mbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtnYXA6NXB4O2JhY2tncm91bmQ6IzE1NzAxZTtjb2xvcjojZmZmO3RleHQtZGVjb3JhdGlvbjpub25lO3BhZGRpbmc6N3B4IDExcHg7Ym9yZGVyLXJhZGl1czo2cHg7Zm9udC1zaXplOjEycHg7Zm9udC13ZWlnaHQ6NjAwO2ZvbnQtZmFtaWx5OmluaGVyaXQ7dHJhbnNpdGlvbjpiYWNrZ3JvdW5kIC4xNXM7bWluLWhlaWdodDo0NHB4O2xpbmUtaGVpZ2h0OjF9Ci5ncGwtd3JhcCAuZ3BsLWN0YS1taW5pOmhvdmVye2JhY2tncm91bmQ6IzFiN2EyYX0KLmdwbC13cmFwIC5ncGwtY3RhLWNhcmR7YmFja2dyb3VuZDpsaW5lYXItZ3JhZGllbnQoMTQ1ZGVnLCNlZWZiZjMgMCUsI2RmZjVlNiAxMDAlKTtib3JkZXI6MXB4IHNvbGlkICNiOGU1YzY7Ym9yZGVyLXJhZGl1czoxMHB4O3BhZGRpbmc6MTRweDttYXJnaW4tdG9wOmF1dG87cG9zaXRpb246cmVsYXRpdmU7b3ZlcmZsb3c6aGlkZGVufQouZ3BsLXdyYXAgLmdwbC1jdGEtY2FyZDo6YmVmb3Jle2NvbnRlbnQ6IiI7cG9zaXRpb246YWJzb2x1dGU7dG9wOi0zMHB4O3JpZ2h0Oi0zMHB4O3dpZHRoOjgwcHg7aGVpZ2h0OjgwcHg7YmFja2dyb3VuZDpyYWRpYWwtZ3JhZGllbnQoY2lyY2xlLHJnYmEoMjEsMTEyLDMwLC4xNCkgMCUsdHJhbnNwYXJlbnQgNzAlKTtwb2ludGVyLWV2ZW50czpub25lfQouZ3BsLXdyYXAgLmdwbC1jdGEtY2FyZCBoNHtmb250LXNpemU6MTBweDt0ZXh0LXRyYW5zZm9ybTp1cHBlcmNhc2U7bGV0dGVyLXNwYWNpbmc6LjE0ZW07Y29sb3I6IzBmNTAzMzttYXJnaW46MCAwIDEwcHggMDtmb250LXdlaWdodDo3MDA7Zm9udC1mYW1pbHk6IlBvcHBpbnMiLHN5c3RlbS11aSxzYW5zLXNlcmlmO3Bvc2l0aW9uOnJlbGF0aXZlfQouZ3BsLXdyYXAgLmdwbC1jdGEtbGlzdHtsaXN0LXN0eWxlOm5vbmU7cGFkZGluZzowO21hcmdpbjowIDAgMTJweCAwO2ZvbnQtc2l6ZToxMnB4O2xpbmUtaGVpZ2h0OjEuNjtwb3NpdGlvbjpyZWxhdGl2ZX0KLmdwbC13cmFwIC5ncGwtY3RhLWxpc3QgbGl7Y29sb3I6IzFlNWQzYTtkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6ZmxleC1zdGFydDtnYXA6OHB4O2ZvbnQtd2VpZ2h0OjUwMDttYXJnaW4tYm90dG9tOjRweH0KLmdwbC13cmFwIC5ncGwtY3RhLWxpc3QgbGk6OmJlZm9yZXtjb250ZW50OiLinJMiO2NvbG9yOiMxNTcwMWU7Zm9udC13ZWlnaHQ6NzAwO2ZsZXg6bm9uZX0KLmdwbC13cmFwIC5ncGwtY3RhLWJ0bi1sZ3tkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2p1c3RpZnktY29udGVudDpjZW50ZXI7Z2FwOjZweDtiYWNrZ3JvdW5kOiMxNTcwMWU7Y29sb3I6I2ZmZjt0ZXh0LWRlY29yYXRpb246bm9uZTtwYWRkaW5nOjExcHggMTJweDtib3JkZXItcmFkaXVzOjdweDtmb250LXdlaWdodDo3MDA7Zm9udC1zaXplOjEzcHg7Zm9udC1mYW1pbHk6aW5oZXJpdDtwb3NpdGlvbjpyZWxhdGl2ZTt3aWR0aDoxMDAlO3RyYW5zaXRpb246YmFja2dyb3VuZCAuMTVzO21pbi1oZWlnaHQ6NDRweDtib3gtc2l6aW5nOmJvcmRlci1ib3h9Ci5ncGwtd3JhcCAuZ3BsLWN0YS1idG4tbGc6aG92ZXJ7YmFja2dyb3VuZDojMWI3YTJhfQouZ3BsLXdyYXAgLmdwbC1jdGEtYXJye3RyYW5zaXRpb246dHJhbnNmb3JtIC4xNXN9Ci5ncGwtd3JhcCAuZ3BsLWN0YS1idG4tbGc6aG92ZXIgLmdwbC1jdGEtYXJye3RyYW5zZm9ybTp0cmFuc2xhdGVYKDNweCl9Ci5ncGwtd3JhcCAuZ3BsLWN0YS1ub3Rle2ZvbnQtc2l6ZToxMHB4O2NvbG9yOiM0YzYwNjY7bWFyZ2luOjhweCAwIDAgMDtsaW5lLWhlaWdodDoxLjQ1O3RleHQtYWxpZ246Y2VudGVyO2ZvbnQtc3R5bGU6aXRhbGljfQouZ3BsLXdyYXAgLmdwbC10cmF5e3Bvc2l0aW9uOmFic29sdXRlO3RvcDo2MHB4O2xlZnQ6MTBweDtiYWNrZ3JvdW5kOnJnYmEoMjU1LDI1NSwyNTUsLjk1KTtib3JkZXI6MXB4IHNvbGlkICNlZWVlZWU7Ym9yZGVyLXJhZGl1czo4cHg7cGFkZGluZzo2cHggMTBweDtmb250LWZhbWlseToiRE0gTW9ubyIsdWktbW9ub3NwYWNlLG1vbm9zcGFjZTtmb250LXNpemU6MTFweDtjb2xvcjojNGM2MDY2O2JhY2tkcm9wLWZpbHRlcjpibHVyKDRweCk7Ym94LXNoYWRvdzowIDJweCA2cHggcmdiYSgwLDAsMCwuMDUpO3otaW5kZXg6Mn0KLmdwbC13cmFwIC5ncGwtcGJ7cG9zaXRpb246YWJzb2x1dGU7dG9wOjEwcHg7bGVmdDoxMHB4O3JpZ2h0OjEwcHg7YmFja2dyb3VuZDpyZ2JhKDI1NSwyNTUsMjU1LC45NSk7Ym9yZGVyOjFweCBzb2xpZCAjZWVlZWVlO2JvcmRlci1yYWRpdXM6OHB4O3BhZGRpbmc6N3B4IDEwcHg7ZGlzcGxheTpmbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtnYXA6OHB4O2JhY2tkcm9wLWZpbHRlcjpibHVyKDRweCk7Ym94LXNoYWRvdzowIDJweCA2cHggcmdiYSgwLDAsMCwuMDUpO3otaW5kZXg6MztmbGV4LXdyYXA6d3JhcH0KLmdwbC13cmFwIC5ncGwtcGItYnRue2JhY2tncm91bmQ6IzE1NzAxZTtjb2xvcjojZmZmO2JvcmRlcjowO3dpZHRoOjMycHg7aGVpZ2h0OjMycHg7Ym9yZGVyLXJhZGl1czo2cHg7Y3Vyc29yOnBvaW50ZXI7Zm9udC1zaXplOjEzcHg7ZGlzcGxheTpmbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtqdXN0aWZ5LWNvbnRlbnQ6Y2VudGVyO3BhZGRpbmc6MDtmb250LWZhbWlseTppbmhlcml0O3RyYW5zaXRpb246YmFja2dyb3VuZCAuMTVzO2ZsZXg6bm9uZTtsaW5lLWhlaWdodDoxfQouZ3BsLXdyYXAgLmdwbC1wYi1idG46aG92ZXJ7YmFja2dyb3VuZDojMWI3YTJhfQouZ3BsLXdyYXAgLmdwbC1wYi1idG4uaXMtcGxheWluZzo6YmVmb3Jle2NvbnRlbnQ6IuKdmuKdmiI7Zm9udC1zaXplOjExcHg7bGV0dGVyLXNwYWNpbmc6LTFweH0KLmdwbC13cmFwIC5ncGwtcGItYnRuLmlzLXBsYXlpbmd7Zm9udC1zaXplOjB9Ci5ncGwtd3JhcCAuZ3BsLXBiLXRyYWNre2ZsZXg6MTtoZWlnaHQ6OHB4O2JhY2tncm91bmQ6I2ZhZmJmNDtib3JkZXItcmFkaXVzOjRweDtwb3NpdGlvbjpyZWxhdGl2ZTtjdXJzb3I6cG9pbnRlcjttaW4td2lkdGg6ODBweDtib3JkZXI6MXB4IHNvbGlkICNlZWVlZWV9Ci5ncGwtd3JhcCAuZ3BsLXBiLWZpbGx7cG9zaXRpb246YWJzb2x1dGU7bGVmdDowO3RvcDowO2hlaWdodDoxMDAlO2JhY2tncm91bmQ6IzE1NzAxZTtib3JkZXItcmFkaXVzOjNweDtwb2ludGVyLWV2ZW50czpub25lO3dpZHRoOjAlfQouZ3BsLXdyYXAgLmdwbC1wYi10aHVtYntwb3NpdGlvbjphYnNvbHV0ZTt0b3A6NTAlO2xlZnQ6MCU7dHJhbnNmb3JtOnRyYW5zbGF0ZSgtNTAlLC01MCUpO3dpZHRoOjE0cHg7aGVpZ2h0OjE0cHg7YmFja2dyb3VuZDojMTU3MDFlO2JvcmRlcjoycHggc29saWQgI2ZmZmZmZjtib3JkZXItcmFkaXVzOjUwJTtwb2ludGVyLWV2ZW50czpub25lO2JveC1zaGFkb3c6MCAxcHggNHB4IHJnYmEoMCwwLDAsLjI1KX0KLmdwbC13cmFwIC5ncGwtcGItc2Vne2ZsZXg6bm9uZTtkaXNwbGF5OmZsZXg7Z2FwOjJweDtwYWRkaW5nOjJweDtiYWNrZ3JvdW5kOiNmYWZiZjQ7Ym9yZGVyOjFweCBzb2xpZCAjZWVlZWVlO2JvcmRlci1yYWRpdXM6NnB4fQouZ3BsLXdyYXAgLmdwbC1wYi1zcGR7cGFkZGluZzo0cHggN3B4O2ZvbnQtc2l6ZToxMHB4O2JhY2tncm91bmQ6dHJhbnNwYXJlbnQ7Ym9yZGVyOjA7Y29sb3I6IzRjNjA2NjtjdXJzb3I6cG9pbnRlcjtib3JkZXItcmFkaXVzOjRweDtmb250LWZhbWlseToiRE0gTW9ubyIsdWktbW9ub3NwYWNlLG1vbm9zcGFjZTtmb250LXdlaWdodDo3MDA7bWluLXdpZHRoOjI4cHg7Zm9udC1mYW1pbHk6aW5oZXJpdH0KLmdwbC13cmFwIC5ncGwtcGItc3BkLm9ue2JhY2tncm91bmQ6IzE1NzAxZTtjb2xvcjojZmZmfQouZ3BsLXdyYXAgLmdwbC1wYi1zdGF0c3tmbGV4Om5vbmU7Zm9udC1mYW1pbHk6IkRNIE1vbm8iLHVpLW1vbm9zcGFjZSxtb25vc3BhY2U7Zm9udC1zaXplOjEwcHg7Y29sb3I6IzRjNjA2Njt0ZXh0LWFsaWduOnJpZ2h0O21pbi13aWR0aDoxMzBweDtsaW5lLWhlaWdodDoxLjM7Zm9udC13ZWlnaHQ6NjAwfQouZ3BsLXdyYXAgLmdwbC1zY2FsZXtwb3NpdGlvbjphYnNvbHV0ZTtsZWZ0OjEwcHg7Ym90dG9tOjEwcHg7YmFja2dyb3VuZDpyZ2JhKDI1NSwyNTUsMjU1LC45NSk7Ym9yZGVyOjFweCBzb2xpZCAjZWVlZWVlO2JvcmRlci1yYWRpdXM6NnB4O3BhZGRpbmc6NHB4IDhweDtmb250LWZhbWlseToiRE0gTW9ubyIsdWktbW9ub3NwYWNlLG1vbm9zcGFjZTtmb250LXNpemU6MTBweDtmb250LXdlaWdodDo2MDA7Y29sb3I6IzRjNjA2NjtkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2dhcDo2cHg7YmFja2Ryb3AtZmlsdGVyOmJsdXIoNHB4KTt6LWluZGV4OjM7bGluZS1oZWlnaHQ6MTtib3gtc2hhZG93OjAgMnB4IDRweCByZ2JhKDAsMCwwLC4wNSl9Ci5ncGwtd3JhcCAuZ3BsLXNjYWxlLWJhcntkaXNwbGF5OmlubGluZS1ibG9jazt3aWR0aDo2MHB4O2hlaWdodDo2cHg7Ym9yZGVyLWxlZnQ6MnB4IHNvbGlkICMxNDUzMjg7Ym9yZGVyLXJpZ2h0OjJweCBzb2xpZCAjMTQ1MzI4O2JvcmRlci1ib3R0b206MnB4IHNvbGlkICMxNDUzMjg7Ym94LXNpemluZzpib3JkZXItYm94fQouZ3BsLXdyYXAgLmdwbC1zY2FsZS1sYmx7d2hpdGUtc3BhY2U6bm93cmFwfQouZ3BsLXdyYXAgLmdwbC10b29sc3twb3NpdGlvbjphYnNvbHV0ZTtyaWdodDoxMHB4O3RvcDo2MHB4O2Rpc3BsYXk6ZmxleDtmbGV4LWRpcmVjdGlvbjpjb2x1bW47Z2FwOjVweDt6LWluZGV4OjR9Ci5ncGwtd3JhcCAuZ3BsLXRvb2wtYnRue3dpZHRoOjM2cHg7aGVpZ2h0OjM2cHg7YmFja2dyb3VuZDpyZ2JhKDI1NSwyNTUsMjU1LC45NSk7Ym9yZGVyOjFweCBzb2xpZCAjZWVlZWVlO2JvcmRlci1yYWRpdXM6N3B4O2ZvbnQtZmFtaWx5OmluaGVyaXQ7Zm9udC1zaXplOjE2cHg7Zm9udC13ZWlnaHQ6NjAwO2N1cnNvcjpwb2ludGVyO2Rpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpjZW50ZXI7anVzdGlmeS1jb250ZW50OmNlbnRlcjtsaW5lLWhlaWdodDoxO3BhZGRpbmc6MDtjb2xvcjojNGM2MDY2O3RyYW5zaXRpb246YWxsIC4xMnM7Ym94LXNoYWRvdzowIDJweCA0cHggcmdiYSgwLDAsMCwuMDgpfQouZ3BsLXdyYXAgLmdwbC10b29sLWJ0biBzdmd7d2lkdGg6MThweDtoZWlnaHQ6MThweDtkaXNwbGF5OmJsb2NrfQouZ3BsLXdyYXAgLmdwbC10b29sLWJ0bjpob3Zlcntib3JkZXItY29sb3I6IzE1NzAxZTtjb2xvcjojMTU3MDFlfQouZ3BsLXdyYXAgLmdwbC10b29sLWJ0bi5pcy1vbntiYWNrZ3JvdW5kOiMxNTcwMWU7Y29sb3I6I2ZmZjtib3JkZXItY29sb3I6IzE1NzAxZX0KLmdwbC13cmFwIC5ncGwtcnVsZXItaGludHtwb3NpdGlvbjphYnNvbHV0ZTtsZWZ0OjUwJTtib3R0b206MTRweDt0cmFuc2Zvcm06dHJhbnNsYXRlWCgtNTAlKTtiYWNrZ3JvdW5kOnJnYmEoMjAsODMsNDAsMC45Mik7Y29sb3I6I2ZmZjtwYWRkaW5nOjdweCAxMnB4O2JvcmRlci1yYWRpdXM6N3B4O2ZvbnQtc2l6ZToxMXB4O2ZvbnQtd2VpZ2h0OjYwMDtmb250LWZhbWlseToiRE0gTW9ubyIsdWktbW9ub3NwYWNlLG1vbm9zcGFjZTtkaXNwbGF5Om5vbmU7ei1pbmRleDozO2JveC1zaGFkb3c6MCAycHggOHB4IHJnYmEoMCwwLDAsLjE1KX0KLmdwbC13cmFwIC5ncGwtcnVsZXItaGludC5pcy1vbntkaXNwbGF5OmJsb2NrfQouZ3BsLXdyYXAgLmdwbC1sZWdlbmR7cG9zaXRpb246YWJzb2x1dGU7Ym90dG9tOjEwcHg7bGVmdDoxMHB4O2JhY2tncm91bmQ6cmdiYSgyNTUsMjU1LDI1NSwuOTUpO2JvcmRlcjoxcHggc29saWQgI2VlZWVlZTtib3JkZXItcmFkaXVzOjhweDtwYWRkaW5nOjhweCAxMnB4O2ZvbnQtc2l6ZToxMXB4O2Rpc3BsYXk6ZmxleDtmbGV4LWRpcmVjdGlvbjpjb2x1bW47Z2FwOjRweDtiYWNrZHJvcC1maWx0ZXI6Ymx1cig0cHgpfQouZ3BsLXdyYXAgLmdwbC1sZy1yb3d7ZGlzcGxheTpmbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtnYXA6NnB4fQouZ3BsLXdyYXAgLmdwbC1sZy1zd2F0Y2h7d2lkdGg6MTRweDtoZWlnaHQ6M3B4O2JvcmRlci1yYWRpdXM6MnB4O2ZsZXg6bm9uZX0KCkBtZWRpYSAobWF4LXdpZHRoOiA4MjBweCl7CiAgLmdwbC13cmFwIC5ncGwtZ3JpZHtncmlkLXRlbXBsYXRlLWNvbHVtbnM6MWZyO2dyaWQtdGVtcGxhdGUtYXJlYXM6Im1haW4iICJyaWdodCIgImxlZnQiO2dyaWQtdGVtcGxhdGUtcm93czo2MnZoIGF1dG8gYXV0bzttaW4taGVpZ2h0OmF1dG99CiAgLmdwbC13cmFwIC5ncGwtc2lkZXtib3JkZXItcmlnaHQ6MDtib3JkZXItdG9wOjFweCBzb2xpZCAjZWVlZWVlO21heC1oZWlnaHQ6bm9uZTtwYWRkaW5nOjEycHggMTRweDtnYXA6MTBweH0KICAuZ3BsLXdyYXAgLmdwbC1zcGxpdHRlcntkaXNwbGF5Om5vbmV9CiAgLmdwbC13cmFwIC5ncGwtc2lkZS1yaWdodHtib3JkZXItbGVmdDowO2JvcmRlci10b3A6MXB4IHNvbGlkICNlZWVlZWU7bWF4LWhlaWdodDpub25lO3BhZGRpbmc6MTJweCAxNHB4O2dhcDoxMHB4fQogIC5ncGwtd3JhcCAuZ3BsLW1haW57bWluLWhlaWdodDo2MnZofQogIC8qIEJpZ2dlciBjYXJkcyArIHRhcCB0YXJnZXRzIG9uIHRvdWNoICovCiAgLmdwbC13cmFwIC5ncGwtY2FyZCBoM3tmb250LXNpemU6MTBweH0KICAuZ3BsLXdyYXAgLmdwbC1hcHByb2FjaCBsYWJlbHttaW4taGVpZ2h0OjQ0cHg7Zm9udC1zaXplOjEzcHg7cGFkZGluZzo3cHggMTBweH0KICAuZ3BsLXdyYXAgaW5wdXRbdHlwZT1udW1iZXJdLC5ncGwtd3JhcCBzZWxlY3R7Zm9udC1zaXplOjE0cHg7bWluLWhlaWdodDozOHB4fQogIC5ncGwtd3JhcCAuZ3BsLWZsZHttaW4taGVpZ2h0OjQ0cHg7Zm9udC1zaXplOjExcHg7cGFkZGluZzo2cHggOHB4fQogIC5ncGwtd3JhcCAuZ3BsLWZsZC1zdWJ7Zm9udC1zaXplOjlweH0KICAuZ3BsLXdyYXAgLmdwbC11cGxvYWR7bWluLWhlaWdodDo0MHB4O2ZvbnQtc2l6ZToxMXB4fQogIC5ncGwtd3JhcCAuZ3BsLWFiLWF1dG97bWluLWhlaWdodDozNnB4O2ZvbnQtc2l6ZToxMXB4fQogIC5ncGwtd3JhcCAuZ3BsLXRvb2wtYnRue3dpZHRoOjQwcHg7aGVpZ2h0OjQwcHh9CiAgLmdwbC13cmFwIC5ncGwtdG9vbC1idG4gc3Zne3dpZHRoOjIwcHg7aGVpZ2h0OjIwcHh9CiAgLmdwbC13cmFwIC5ncGwtY3RhLW1pbmksLmdwbC13cmFwIC5ncGwtY3RhLWJ0bi1sZ3ttaW4taGVpZ2h0OjQ0cHh9CiAgLmdwbC13cmFwIC5ncGwtc2xpZGVyLXZhbHtmb250LXNpemU6MTFweDttaW4td2lkdGg6ODBweH0KICAuZ3BsLXdyYXAgLmdwbC1yYW5nZXttaW4taGVpZ2h0OjMycHh9CiAgLyogUmVzdWx0cyByb3cgZm9udCArIHNwYWNpbmcg4oCUIGVhc2llciB0byByZWFkIG9uIHBob25lcyAqLwogIC5ncGwtd3JhcCAuZ3BsLXJlc3VsdHN7Zm9udC1zaXplOjEycHg7cGFkZGluZzo4cHggMTBweDtnYXA6M3B4fQogIC5ncGwtd3JhcCAuZ3BsLXIta3tmb250LXNpemU6MTFweH0KICAuZ3BsLXdyYXAgLmdwbC1yLXZ7Zm9udC1zaXplOjEzcHh9CiAgLyogQ29tcGFyZSBBbGwgZ3JpZCDigJQga2VlcCA0IGNvbHVtbnMgYnV0IHRpZ2h0ZXIgKi8KICAuZ3BsLXdyYXAgLmdwbC1jbXAtcm93e3BhZGRpbmc6N3B4IDhweDtmb250LXNpemU6MTFweDtncmlkLXRlbXBsYXRlLWNvbHVtbnM6MWZyIDM4cHggNDZweCA0NnB4fQogIC8qIFBsYXliYWNrIHN0cmlwIOKAlCB3cmFwIGJldHRlciB3aGVuIG5hcnJvdyAqLwogIC5ncGwtd3JhcCAuZ3BsLXBie2ZsZXgtd3JhcDp3cmFwO3BhZGRpbmc6NnB4IDhweDtnYXA6NnB4fQogIC5ncGwtd3JhcCAuZ3BsLXBiLXN0YXRze21pbi13aWR0aDowO2ZsZXgtYmFzaXM6MTAwJTt0ZXh0LWFsaWduOmxlZnQ7Zm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MS4zNTtwYWRkaW5nLXRvcDoycHg7Ym9yZGVyLXRvcDoxcHggZGFzaGVkICNlZWVlZWV9CiAgLmdwbC13cmFwIC5ncGwtcGItdHJhY2t7bWluLXdpZHRoOjUwcHh9CiAgLyogVG9vbHMg4oCUIHB1c2ggYmVsb3cgdGhlICh0YWxsZXIpIHdyYXBwZWQgcGxheWJhY2sgc3RyaXAgKi8KICAuZ3BsLXdyYXAgLmdwbC10b29sc3t0b3A6OTBweH0KICAuZ3BsLXdyYXAgLmdwbC10cmF5e3RvcDo5MHB4O2ZvbnQtc2l6ZToxMHB4O3BhZGRpbmc6NXB4IDhweH0KICAvKiBMZWdlbmQgYW5kIHNjYWxlLWJhciDigJQgc21hbGxlciwgbGVzcyBpbiB0aGUgd2F5IG9uIHBob25lcyAqLwogIC5ncGwtd3JhcCAuZ3BsLWxlZ2VuZHtmb250LXNpemU6MTBweDtwYWRkaW5nOjdweCAxMHB4O2dhcDozcHh9CiAgLmdwbC13cmFwIC5ncGwtc2NhbGV7Zm9udC1zaXplOjlweDtwYWRkaW5nOjNweCA3cHh9CiAgLyogVW5pdC10b2dnbGUgKGttL21pKSB0YWJzIOKAlCBiaWdnZXIgdGFwIHRhcmdldCAqLwogIC5ncGwtd3JhcCAuZ3BsLXVuaXQtdGFie3BhZGRpbmc6NXB4IDEycHg7Zm9udC1zaXplOjExcHg7bWluLWhlaWdodDozMnB4fQogIC8qIEZpZWxkLXBpY2tlciBncmlkIOKAlCAyw5cyIHN0aWxsLCBzbGlnaHRseSBtb3JlIGJyZWF0aGluZyByb29tICovCiAgLmdwbC13cmFwIC5ncGwtZmllbGQtcGlja2Vye2dhcDo1cHh9Cn0KQG1lZGlhIChtYXgtd2lkdGg6IDQ4MHB4KXsKICAuZ3BsLXdyYXAgLmdwbC1tYWlue21pbi1oZWlnaHQ6NTh2aH0KICAuZ3BsLXdyYXAgLmdwbC1ncmlke2dyaWQtdGVtcGxhdGUtcm93czo1OHZoIGF1dG8gYXV0b30KICAuZ3BsLXdyYXAgLmdwbC1hcHByb2FjaCBsYWJlbHttaW4taGVpZ2h0OjQ0cHg7Zm9udC1zaXplOjE0cHh9CiAgLmdwbC13cmFwIGlucHV0W3R5cGU9bnVtYmVyXSwuZ3BsLXdyYXAgc2VsZWN0e2ZvbnQtc2l6ZToxNHB4O21pbi1oZWlnaHQ6NDBweH0KICAuZ3BsLXdyYXAgLmdwbC1jdGEtbWluaSwuZ3BsLXdyYXAgLmdwbC1jdGEtYnRuLWxne21pbi1oZWlnaHQ6NDRweH0KICAuZ3BsLXdyYXAgLmdwbC1mbGR7bWluLWhlaWdodDo0NnB4O2ZvbnQtc2l6ZToxMnB4fQogIC5ncGwtd3JhcCAuZ3BsLXRvb2wtYnRue3dpZHRoOjQycHg7aGVpZ2h0OjQycHh9CiAgLmdwbC13cmFwIC5ncGwtdG9vbC1idG4gc3Zne3dpZHRoOjIycHg7aGVpZ2h0OjIycHh9CiAgLmdwbC13cmFwIC5ncGwtY21wLXJvd3tncmlkLXRlbXBsYXRlLWNvbHVtbnM6MWZyIDM0cHggNDJweCA0MnB4O2ZvbnQtc2l6ZToxMC41cHh9CiAgLmdwbC13cmFwIC5ncGwtaW5wdXQtcm93IC5ncGwtdW5pdHtmb250LXNpemU6MTFweDt3aWR0aDozMHB4fQogIC8qIFRvcCBiYXIgKGhlYWRlciArIENUQSkg4oCUIGxldCB0aGUgQ1RBIHdyYXAgb250byBpdHMgb3duIHJvdyBvbiBzbWFsbCBzY3JlZW5zICovCiAgLmdwbC13cmFwIC5ncGwtdG9we3BhZGRpbmc6MTBweCAxMnB4O2dhcDo4cHh9CiAgLmdwbC13cmFwIC5ncGwtY3Rhe3BhZGRpbmc6MTBweCAxNHB4O2ZvbnQtc2l6ZToxM3B4O21pbi1oZWlnaHQ6NDJweH0KICAuZ3BsLXdyYXAgLmdwbC1oMXtmb250LXNpemU6MTRweH0KfQo8L3N0eWxlPgoKPGRpdiBjbGFzcz0iZ3BsLXRvcCI+CiAgPGRpdiBjbGFzcz0iZ3BsLWJyYW5kIj4KICAgIDxkaXYgY2xhc3M9ImdwbC1sb2dvIj5HPC9kaXY+CiAgICA8ZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtaDEiPkd1aWRhbmNlIExpbmVzIFNpbXVsYXRvcjwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtY2hpcCI+PHNwYW4gY2xhc3M9ImdwbC1kb3QiPjwvc3Bhbj48c3Bhbj5Db21wYXJlIDQgYXBwcm9hY2hlcyDCtyBmdWVsICsgUk9JPC9zcGFuPjwvZGl2PgogICAgPC9kaXY+CiAgPC9kaXY+CiAgPGEgY2xhc3M9ImdwbC1jdGEiIGhyZWY9Imh0dHBzOi8vYXBwLmdlb3BhcmQudGVjaC9zaWdudXA\/dXRtX3NvdXJjZT1ndWlkYW5jZS1saW5lcyZ1dG1fbWVkaXVtPXdwLWVtYmVkJnV0bV9jYW1wYWlnbj1yZWdpc3RlciIgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9vcGVuZXIiPlJ1biBvbiB5b3VyIGZpZWxkIOKGkjwvYT4KPC9kaXY+Cgo8ZGl2IGNsYXNzPSJncGwtZ3JpZCI+CiAgPGFzaWRlIGNsYXNzPSJncGwtc2lkZSI+CiAgICA8ZGl2IGNsYXNzPSJncGwtY2FyZCI+CiAgICAgIDxoMz5TYW1wbGUgZmllbGQ8L2gzPgogICAgICA8ZGl2IGNsYXNzPSJncGwtZmllbGQtcGlja2VyIiBpZD0iZ3BsLWZpZWxkLXBpY2tlciI+CiAgICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJncGwtZmxkIGlzLW9uIiBkYXRhLWZpZWxkPSJoZXgiPkhleCAyNyBoYTxzcGFuIGNsYXNzPSJncGwtZmxkLXN1YiI+aXJyZWd1bGFyIGhleDwvc3Bhbj48L2J1dHRvbj4KICAgICAgICA8YnV0dG9uIHR5cGU9ImJ1dHRvbiIgY2xhc3M9ImdwbC1mbGQiIGRhdGEtZmllbGQ9InJlY3QiPlJlY3QgMzEgaGE8c3BhbiBjbGFzcz0iZ3BsLWZsZC1zdWIiPmNsYXNzaWMgTWlkd2VzdDwvc3Bhbj48L2J1dHRvbj4KICAgICAgICA8YnV0dG9uIHR5cGU9ImJ1dHRvbiIgY2xhc3M9ImdwbC1mbGQiIGRhdGEtZmllbGQ9ImxzaGFwZSI+TC1zaGFwZSAyNSBoYTxzcGFuIGNsYXNzPSJncGwtZmxkLXN1YiI+b2JzdGFjbGUgLyBoaWxsPC9zcGFuPjwvYnV0dG9uPgogICAgICAgIDxidXR0b24gdHlwZT0iYnV0dG9uIiBjbGFzcz0iZ3BsLWZsZCIgZGF0YS1maWVsZD0icGl2b3QiPlBpdm90IDI4IGhhPHNwYW4gY2xhc3M9ImdwbC1mbGQtc3ViIj5pcnJpZ2F0aW9uIGNpcmNsZTwvc3Bhbj48L2J1dHRvbj4KICAgICAgPC9kaXY+CiAgICAgIDxsYWJlbCBjbGFzcz0iZ3BsLXVwbG9hZCIgaWQ9ImdwbC11cGxvYWQtbGJsIj4KICAgICAgICA8aW5wdXQgdHlwZT0iZmlsZSIgaWQ9ImdwbC11cGxvYWQiIGFjY2VwdD0iLmdlb2pzb24sLmpzb24sLmttbCwuemlwLC5zaHAsYXBwbGljYXRpb24vanNvbixhcHBsaWNhdGlvbi96aXAsYXBwbGljYXRpb24vdm5kLmdvb2dsZS1lYXJ0aC5rbWwreG1sIiBoaWRkZW4+CiAgICAgICAgPHNwYW4gY2xhc3M9ImdwbC11cGxvYWQtaWNvIj7ipLQ8L3NwYW4+CiAgICAgICAgPHNwYW4+VXBsb2FkIHlvdXIgZmllbGQ8L3NwYW4+CiAgICAgIDwvbGFiZWw+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1oaW50IiBpZD0iZ3BsLXVwbG9hZC1oaW50Ij5HZW9KU09OIC8gS01MIC8gU2hhcGVmaWxlIHppcDwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtaW1wb3J0LW5hdiIgaWQ9ImdwbC1pbXBvcnQtbmF2IiBoaWRkZW4+CiAgICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJncGwtaW1wLWJ0biIgaWQ9ImdwbC1pbXAtcHJldiIgYXJpYS1sYWJlbD0iUHJldmlvdXMgYm91bmRhcnkiPuKAuTwvYnV0dG9uPgogICAgICAgIDxzcGFuIGNsYXNzPSJncGwtaW1wLWxibCIgaWQ9ImdwbC1pbXAtbGJsIj7igJQgLyDigJQ8L3NwYW4+CiAgICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJncGwtaW1wLWJ0biIgaWQ9ImdwbC1pbXAtbmV4dCIgYXJpYS1sYWJlbD0iTmV4dCBib3VuZGFyeSI+4oC6PC9idXR0b24+CiAgICAgIDwvZGl2PgogICAgPC9kaXY+CiAgICA8ZGl2IGNsYXNzPSJncGwtY2FyZCI+CiAgICAgIDxoMz5BcHByb2FjaDwvaDM+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1hcHByb2FjaCIgaWQ9ImdwbC1hcHByb2FjaCI+CiAgICAgICAgPGxhYmVsIGNsYXNzPSJpcy1vbiI+PGlucHV0IHR5cGU9InJhZGlvIiBuYW1lPSJncGwtYXAiIHZhbHVlPSJhYi1zdHJhaWdodCIgY2hlY2tlZD48c3Bhbj5BQiBTdHJhaWdodDwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLXJlY28iIGRhdGEtcmVjbz0iYWItc3RyYWlnaHQiPlJlY29tbWVuZGVkPC9zcGFuPjwvbGFiZWw+CiAgICAgICAgPGxhYmVsPjxpbnB1dCB0eXBlPSJyYWRpbyIgbmFtZT0iZ3BsLWFwIiB2YWx1ZT0iYWItY3VydmUiPjxzcGFuPkFCIEN1cnZlPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtcmVjbyIgZGF0YS1yZWNvPSJhYi1jdXJ2ZSI+UmVjb21tZW5kZWQ8L3NwYW4+PC9sYWJlbD4KICAgICAgICA8bGFiZWw+PGlucHV0IHR5cGU9InJhZGlvIiBuYW1lPSJncGwtYXAiIHZhbHVlPSJib3VuZGFyeSI+PHNwYW4+Qm91bmRhcnkgRm9sbG93PC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtcmVjbyIgZGF0YS1yZWNvPSJib3VuZGFyeSI+UmVjb21tZW5kZWQ8L3NwYW4+PC9sYWJlbD4KICAgICAgICA8bGFiZWw+PGlucHV0IHR5cGU9InJhZGlvIiBuYW1lPSJncGwtYXAiIHZhbHVlPSJhZGFwdGl2ZSI+PHNwYW4+Q29udG91ci1mb2xsb3cgKHRlcnJhaW4pPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtcmVjbyIgZGF0YS1yZWNvPSJhZGFwdGl2ZSI+UmVjb21tZW5kZWQ8L3NwYW4+PC9sYWJlbD4KICAgICAgPC9kaXY+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1oaW50IiBpZD0iZ3BsLXJlY28taGludCI+YW5hbHlzaW5nIHNoYXBl4oCmPC9kaXY+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1oaW50Ij5Db250b3VyLWZvbGxvdyB1c2VzIGVsZXZhdGlvbjsgb3RoZXJzIGlnbm9yZSBpdC48L2Rpdj4KICAgIDwvZGl2PgogICAgPGRpdiBjbGFzcz0iZ3BsLWNhcmQiPgogICAgICA8aDM+QUIgbGluZSBkaXJlY3Rpb248L2gzPgogICAgICA8ZGl2IGNsYXNzPSJncGwtc2xpZGVyLXJvdyI+CiAgICAgICAgPGlucHV0IHR5cGU9InJhbmdlIiBpZD0iZ3BsLWFiLWRlZyIgbWluPSIwIiBtYXg9IjE4MCIgc3RlcD0iMSIgdmFsdWU9IjAiIGNsYXNzPSJncGwtcmFuZ2UiPgogICAgICAgIDxzcGFuIGNsYXNzPSJncGwtc2xpZGVyLXZhbCIgaWQ9ImdwbC1hYi12YWwiPmF1dG8gwrcgMMKwPC9zcGFuPgogICAgICA8L2Rpdj4KICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGlkPSJncGwtYWItYXV0byIgY2xhc3M9ImdwbC1hYi1hdXRvIj7ihrogQXV0byAoYmVzdCBmaXQpPC9idXR0b24+CiAgICA8L2Rpdj4KICAgIDxkaXYgY2xhc3M9ImdwbC1jYXJkIj4KICAgICAgPGgzPkVxdWlwbWVudDwvaDM+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1zZWxlY3Qtcm93Ij4KICAgICAgICA8bGFiZWwgZm9yPSJncGwtbWFjaGluZSI+TWFjaGluZTwvbGFiZWw+CiAgICAgICAgPHNlbGVjdCBpZD0iZ3BsLW1hY2hpbmUiPgogICAgICAgICAgPG9wdGlvbiB2YWx1ZT0idHJhY3Rvci1zdGQiIHNlbGVjdGVkPlRyYWN0b3IgKyBpbXBsZW1lbnQgKHN0ZCk8L29wdGlvbj4KICAgICAgICAgIDxvcHRpb24gdmFsdWU9InRyYWN0b3ItbGFyZ2UiPkxhcmdlIHRyYWN0b3IgKyBwbGFudGVyPC9vcHRpb24+CiAgICAgICAgICA8b3B0aW9uIHZhbHVlPSJzcHJheWVyIj5TZWxmLXByb3BlbGxlZCBzcHJheWVyPC9vcHRpb24+CiAgICAgICAgICA8b3B0aW9uIHZhbHVlPSJjb21iaW5lIj5Db21iaW5lIGhhcnZlc3Rlcjwvb3B0aW9uPgogICAgICAgICAgPG9wdGlvbiB2YWx1ZT0iYXJ0aWN1bGF0ZWQiPkFydGljdWxhdGVkIDRXRDwvb3B0aW9uPgogICAgICAgICAgPG9wdGlvbiB2YWx1ZT0iY3VzdG9tIj5DdXN0b20gKG1hbnVhbCByYWRpdXMpPC9vcHRpb24+CiAgICAgICAgPC9zZWxlY3Q+CiAgICAgIDwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtaW5wdXQtcm93Ij4KICAgICAgICA8bGFiZWwgZm9yPSJncGwtd20iPkltcGxlbWVudCB3aWR0aDwvbGFiZWw+CiAgICAgICAgPGlucHV0IHR5cGU9Im51bWJlciIgaWQ9ImdwbC13bSIgbWluPSIzIiBtYXg9IjYwIiBzdGVwPSIwLjUiIHZhbHVlPSIxOCI+CiAgICAgICAgPHNwYW4gY2xhc3M9ImdwbC11bml0Ij5tPC9zcGFuPgogICAgICA8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLWlucHV0LXJvdyI+CiAgICAgICAgPGxhYmVsIGZvcj0iZ3BsLWNvbnMiPkNvbnN1bXB0aW9uPC9sYWJlbD4KICAgICAgICA8aW5wdXQgdHlwZT0ibnVtYmVyIiBpZD0iZ3BsLWNvbnMiIG1pbj0iMC4xIiBtYXg9IjUiIHN0ZXA9IjAuMSIgdmFsdWU9IjAuNiI+CiAgICAgICAgPHNwYW4gY2xhc3M9ImdwbC11bml0Ij5ML2ttPC9zcGFuPgogICAgICA8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLWlucHV0LXJvdyI+CiAgICAgICAgPGxhYmVsIGZvcj0iZ3BsLWZ1ZWwiPkRpZXNlbCBwcmljZTwvbGFiZWw+CiAgICAgICAgPGlucHV0IHR5cGU9Im51bWJlciIgaWQ9ImdwbC1mdWVsIiBtaW49IjAuMSIgbWF4PSIzIiBzdGVwPSIwLjA1IiB2YWx1ZT0iMS4yMCI+CiAgICAgICAgPHNlbGVjdCBpZD0iZ3BsLWN1cnJlbmN5IiBjbGFzcz0iZ3BsLWN1ci1zZWwiPgogICAgICAgICAgPG9wdGlvbiB2YWx1ZT0idXNkIiBzZWxlY3RlZD4kL0w8L29wdGlvbj4KICAgICAgICAgIDxvcHRpb24gdmFsdWU9ImV1ciI+4oKsL0w8L29wdGlvbj4KICAgICAgICA8L3NlbGVjdD4KICAgICAgPC9kaXY+CiAgICA8L2Rpdj4KICAgIDxkaXYgY2xhc3M9ImdwbC1jYXJkIj4KICAgICAgPGgzPkhlYWRsYW5kPC9oMz4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLXNsaWRlci1yb3ciPgogICAgICAgIDxpbnB1dCB0eXBlPSJyYW5nZSIgaWQ9ImdwbC1obC1tdWx0IiBtaW49IjAiIG1heD0iNCIgc3RlcD0iMSIgdmFsdWU9IjEiIGNsYXNzPSJncGwtcmFuZ2UiPgogICAgICAgIDxzcGFuIGNsYXNzPSJncGwtc2xpZGVyLXZhbCIgaWQ9ImdwbC1obC12YWwiPjE4IG0gwrcgMcOXIHBhc3M8L3NwYW4+CiAgICAgIDwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtaGludCI+YWx3YXlzID0gTiDDlyBpbXBsZW1lbnQgd2lkdGggwrcgMeKAkzLDlyB0eXBpY2FsPC9kaXY+CiAgICA8L2Rpdj4KICAgIDxkaXYgY2xhc3M9ImdwbC1jYXJkIj4KICAgICAgPGgzPlR1cm5hcm91bmRzPC9oMz4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLXNlbGVjdC1yb3ciPgogICAgICAgIDxsYWJlbCBmb3I9ImdwbC10dXJuLXN0eWxlIj5TdHlsZTwvbGFiZWw+CiAgICAgICAgPHNlbGVjdCBpZD0iZ3BsLXR1cm4tc3R5bGUiPgogICAgICAgICAgPG9wdGlvbiB2YWx1ZT0idXR1cm4iIHNlbGVjdGVkPlUtdHVybiAoaGFsZi1jaXJjbGUpPC9vcHRpb24+CiAgICAgICAgICA8b3B0aW9uIHZhbHVlPSJub25lIj5Ob25lIOKAlCBkcml2ZXIgZGVjaWRlczwvb3B0aW9uPgogICAgICAgIDwvc2VsZWN0PgogICAgICA8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLWlucHV0LXJvdyI+CiAgICAgICAgPGxhYmVsIGZvcj0iZ3BsLXR1cm4tciI+TWluIHR1cm4gcmFkaXVzPC9sYWJlbD4KICAgICAgICA8aW5wdXQgdHlwZT0ibnVtYmVyIiBpZD0iZ3BsLXR1cm4tciIgbWluPSIyIiBtYXg9IjMwIiBzdGVwPSIwLjUiIHZhbHVlPSI5Ij4KICAgICAgICA8c3BhbiBjbGFzcz0iZ3BsLXVuaXQiPm08L3NwYW4+CiAgICAgIDwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtaGludCIgaWQ9ImdwbC10dXJuLXItaGludCI+YXV0byDCtyBzdGQgdHJhY3RvcjwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtaW5wdXQtcm93Ij4KICAgICAgICA8bGFiZWwgZm9yPSJncGwtdHVybi1idWYiPk91dHNpZGUtYm91bmRhcnkgYnVmZmVyPC9sYWJlbD4KICAgICAgICA8aW5wdXQgdHlwZT0ibnVtYmVyIiBpZD0iZ3BsLXR1cm4tYnVmIiBtaW49IjAiIG1heD0iMTAwIiBzdGVwPSIxIiB2YWx1ZT0iMCI+CiAgICAgICAgPHNwYW4gY2xhc3M9ImdwbC11bml0Ij5tPC9zcGFuPgogICAgICA8L2Rpdj4KICAgIDwvZGl2PgogICAgPGRpdiBjbGFzcz0iZ3BsLWNhcmQgZ3BsLWNhcmQtdG9wbyI+CiAgICAgIDxoMz5Ub3BvZ3JhcGh5PC9oMz4KICAgICAgPHAgY2xhc3M9ImdwbC10b3BvLWJsdXJiIj5QbGFuIGFyb3VuZCByZWFsIGVsZXZhdGlvbiwgc2xvcGUgYW5kIGN1cnZhdHVyZSDigJQgZHJpdmVzIGNvbnRvdXItYXdhcmUgQWRhcHRpdmUgcGF0aHMgYW5kIHByZXZlbnRzIGVyb3Npb24uPC9wPgogICAgICA8YSBjbGFzcz0iZ3BsLWN0YS1taW5pIiBocmVmPSJodHRwczovL2FwcC5nZW9wYXJkLnRlY2gvc2lnbnVwP3V0bV9zb3VyY2U9Z3VpZGFuY2UtbGluZXMmdXRtX21lZGl1bT13cC1lbWJlZCZ1dG1fY2FtcGFpZ249dG9wb2dyYXBoeSIgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9vcGVuZXIiPlNlZSBpdCBpbiBHZW9QYXJkIOKGkjwvYT4KICAgIDwvZGl2PgogIDwvYXNpZGU+CiAgPGRpdiBjbGFzcz0iZ3BsLXNwbGl0dGVyIiBpZD0iZ3BsLXNwbGl0dGVyIiBhcmlhLWxhYmVsPSJSZXNpemUgc2V0dGluZ3MgcGFuZWwiIHRpdGxlPSJEcmFnIHRvIHJlc2l6ZSI+PC9kaXY+CgogIDxtYWluIGNsYXNzPSJncGwtbWFpbiI+CiAgICA8Y2FudmFzIGNsYXNzPSJncGwtY2FudmFzIiBpZD0iZ3BsLWNhbnZhcyI+PC9jYW52YXM+CiAgICA8ZGl2IGNsYXNzPSJncGwtd2FybiIgaWQ9ImdwbC13YXJuIj48L2Rpdj4KICAgIDxkaXYgY2xhc3M9ImdwbC10cmF5IiBpZD0iZ3BsLXRyYXkiPuKAlCBoYSBzYW1wbGU8L2Rpdj4KICAgIDxkaXYgY2xhc3M9ImdwbC1wYiIgaWQ9ImdwbC1wYiI+CiAgICAgIDxidXR0b24gdHlwZT0iYnV0dG9uIiBjbGFzcz0iZ3BsLXBiLWJ0biIgaWQ9ImdwbC1wYi1wbGF5IiBhcmlhLWxhYmVsPSJQbGF5IC8gcGF1c2UiPuKWtjwvYnV0dG9uPgogICAgICA8ZGl2IGNsYXNzPSJncGwtcGItdHJhY2siIGlkPSJncGwtcGItdHJhY2siPgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1wYi1maWxsIiBpZD0iZ3BsLXBiLWZpbGwiPjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1wYi10aHVtYiIgaWQ9ImdwbC1wYi10aHVtYiI+PC9kaXY+CiAgICAgIDwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtcGItc2VnIj4KICAgICAgICA8YnV0dG9uIHR5cGU9ImJ1dHRvbiIgY2xhc3M9ImdwbC1wYi1zcGQgb24iIGRhdGEtc3BkPSIxIj4xw5c8L2J1dHRvbj4KICAgICAgICA8YnV0dG9uIHR5cGU9ImJ1dHRvbiIgY2xhc3M9ImdwbC1wYi1zcGQiIGRhdGEtc3BkPSIyIj4yw5c8L2J1dHRvbj4KICAgICAgICA8YnV0dG9uIHR5cGU9ImJ1dHRvbiIgY2xhc3M9ImdwbC1wYi1zcGQiIGRhdGEtc3BkPSI0Ij40w5c8L2J1dHRvbj4KICAgICAgPC9kaXY+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1wYi1zdGF0cyIgaWQ9ImdwbC1wYi1zdGF0cyI+MCUgwrcgMCAvIDAga208L2Rpdj4KICAgIDwvZGl2PgogICAgPGRpdiBjbGFzcz0iZ3BsLWxlZ2VuZCI+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1sZy1yb3ciPjxzcGFuIGNsYXNzPSJncGwtbGctc3dhdGNoIiBzdHlsZT0iYmFja2dyb3VuZDpsaW5lYXItZ3JhZGllbnQodG8gcmlnaHQsIzZkNGZhMiAwJSwjNGVjMGE3IDI1JSwjZmZlODgyIDUwJSwjZjVhODVjIDc1JSwjZGI1MDUwIDEwMCUpO3dpZHRoOjMycHg7aGVpZ2h0OjhweDtib3JkZXItcmFkaXVzOjJweCI+PC9zcGFuPkVsZXZhdGlvbiBsb3cg4oaSIGhpZ2g8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLWxnLXJvdyI+PHNwYW4gY2xhc3M9ImdwbC1sZy1zd2F0Y2giIHN0eWxlPSJiYWNrZ3JvdW5kOiMxNDUzMjgiPjwvc3Bhbj5GaWVsZCBib3VuZGFyeTwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtbGctcm93Ij48c3BhbiBjbGFzcz0iZ3BsLWxnLXN3YXRjaCIgc3R5bGU9ImJhY2tncm91bmQ6I2Y3NmEwYyI+PC9zcGFuPkd1aWRhbmNlIHBhc3M8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLWxnLXJvdyI+PHNwYW4gY2xhc3M9ImdwbC1sZy1zd2F0Y2giIHN0eWxlPSJiYWNrZ3JvdW5kOnJnYmEoMjYsMTIxLDgxLC4zNSkiPjwvc3Bhbj5IZWFkbGFuZCBzdHJpcDwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtbGctcm93Ij48c3BhbiBjbGFzcz0iZ3BsLWxnLXN3YXRjaCIgc3R5bGU9ImJhY2tncm91bmQ6I2EyMWNhZiI+PC9zcGFuPlUtdHVybiAvIGRpcmVjdGlvbiDihpI8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iZ3BsLWxnLXJvdyI+PHNwYW4gY2xhc3M9ImdwbC1sZy1zd2F0Y2giIHN0eWxlPSJiYWNrZ3JvdW5kOnJnYmEoMTYyLDI4LDE3NSwuMjIpO3dpZHRoOjE0cHg7aGVpZ2h0OjhweCI+PC9zcGFuPlNvaWwgY29tcGFjdGlvbiB6b25lPC9kaXY+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1sZy1yb3ciPjxzcGFuIGNsYXNzPSJncGwtbGctc3dhdGNoIiBzdHlsZT0iYmFja2dyb3VuZDpyZ2JhKDI0NywxMDYsMTIsLjM1KTt3aWR0aDoxNHB4O2hlaWdodDo4cHgiPjwvc3Bhbj5Td2F0aCBjb3ZlcmVkPC9kaXY+CiAgICA8L2Rpdj4KICAgIDxkaXYgY2xhc3M9ImdwbC1zY2FsZSIgaWQ9ImdwbC1zY2FsZSI+PHNwYW4gY2xhc3M9ImdwbC1zY2FsZS1iYXIiPjwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLXNjYWxlLWxibCIgaWQ9ImdwbC1zY2FsZS1sYmwiPuKAlCBtPC9zcGFuPjwvZGl2PgogICAgPGRpdiBjbGFzcz0iZ3BsLXRvb2xzIj4KICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJncGwtdG9vbC1idG4iIGlkPSJncGwtdG9vbC16b29tLWluIiB0aXRsZT0iWm9vbSBpbiIgYXJpYS1sYWJlbD0iWm9vbSBpbiI+CiAgICAgICAgPHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2Utd2lkdGg9IjIuNCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48bGluZSB4MT0iMTIiIHkxPSI1IiB4Mj0iMTIiIHkyPSIxOSIvPjxsaW5lIHgxPSI1IiB5MT0iMTIiIHgyPSIxOSIgeTI9IjEyIi8+PC9zdmc+CiAgICAgIDwvYnV0dG9uPgogICAgICA8YnV0dG9uIHR5cGU9ImJ1dHRvbiIgY2xhc3M9ImdwbC10b29sLWJ0biIgaWQ9ImdwbC10b29sLXpvb20tb3V0IiB0aXRsZT0iWm9vbSBvdXQiIGFyaWEtbGFiZWw9Ilpvb20gb3V0Ij4KICAgICAgICA8c3ZnIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIHN0cm9rZS13aWR0aD0iMi40IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxsaW5lIHgxPSI1IiB5MT0iMTIiIHgyPSIxOSIgeTI9IjEyIi8+PC9zdmc+CiAgICAgIDwvYnV0dG9uPgogICAgICA8YnV0dG9uIHR5cGU9ImJ1dHRvbiIgY2xhc3M9ImdwbC10b29sLWJ0biIgaWQ9ImdwbC10b29sLWZpdCIgdGl0bGU9IkZpdCBmaWVsZCIgYXJpYS1sYWJlbD0iRml0IGZpZWxkIj4KICAgICAgICA8c3ZnIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIHN0cm9rZS13aWR0aD0iMi4yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik00IDlWNWg0TTE2IDVoNHY0TTIwIDE1djRoLTRNOCAxOUg0di00Ii8+PC9zdmc+CiAgICAgIDwvYnV0dG9uPgogICAgICA8YnV0dG9uIHR5cGU9ImJ1dHRvbiIgY2xhc3M9ImdwbC10b29sLWJ0biIgaWQ9ImdwbC10b29sLXJ1bGVyIiB0aXRsZT0iUnVsZXIg4oCUIGNsaWNrIHR3byBwb2ludHMiIGFyaWEtbGFiZWw9IlJ1bGVyIj4KICAgICAgICA8c3ZnIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMiAxNGw4LTggMTIgMTItOCA4eiIvPjxwYXRoIGQ9Ik02IDEwbDMgM00xMCA2bDMgM00xNCAxNGwzIDNNMTAgMThsMy0zIi8+PC9zdmc+CiAgICAgIDwvYnV0dG9uPgogICAgPC9kaXY+CiAgICA8ZGl2IGNsYXNzPSJncGwtcnVsZXItaGludCIgaWQ9ImdwbC1ydWxlci1oaW50Ij5DbGljayB0d28gcG9pbnRzIG9uIHRoZSBjYW52YXMgdG8gbWVhc3VyZTwvZGl2PgogIDwvbWFpbj4KICA8YXNpZGUgY2xhc3M9ImdwbC1zaWRlLXJpZ2h0IiBpZD0iZ3BsLXNpZGUtcmlnaHQiPgogICAgPGRpdiBjbGFzcz0iZ3BsLWNhcmQiPgogICAgICA8aDM+VGhpcyBhcHByb2FjaDwvaDM+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC11bml0LXRvZ2dsZSIgcm9sZT0idGFibGlzdCI+CiAgICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJncGwtdW5pdC10YWIgaXMtb24iIGRhdGEtdW5pdD0ia20iPmttPC9idXR0b24+CiAgICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJncGwtdW5pdC10YWIiIGRhdGEtdW5pdD0ibWkiPm1pPC9idXR0b24+CiAgICAgIDwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtcmVzdWx0cyI+CiAgICAgICAgPGRpdiBjbGFzcz0iZ3BsLXItcm93Ij48c3BhbiBjbGFzcz0iZ3BsLXItayI+RmllbGQgYXJlYTwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLXItdiIgaWQ9ImdwbC1yLWFyZWEiPuKAlCBoYTwvc3Bhbj48L2Rpdj4KICAgICAgICA8ZGl2IGNsYXNzPSJncGwtci1yb3cgZ3BsLXItcHJpIj48c3BhbiBjbGFzcz0iZ3BsLXItayI+Q292ZXJhZ2U8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1yLXYiIGlkPSJncGwtci1jb3YiPuKAlCAlPC9zcGFuPjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1yLXJvdyI+PHNwYW4gY2xhc3M9ImdwbC1yLWsiPlBhc3Nlczwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLXItdiIgaWQ9ImdwbC1yLXBhc3NlcyI+4oCUPC9zcGFuPjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1yLXJvdyI+PHNwYW4gY2xhc3M9ImdwbC1yLWsiPlBhc3MgbGVuZ3RoPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtci12IiBpZD0iZ3BsLXItbGVuIj7igJQga208L3NwYW4+PC9kaXY+CiAgICAgICAgPGRpdiBjbGFzcz0iZ3BsLXItcm93Ij48c3BhbiBjbGFzcz0iZ3BsLXItayI+VHVybmFyb3VuZHM8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1yLXYiIGlkPSJncGwtci10dXJucyI+4oCUPC9zcGFuPjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1yLXJvdyI+PHNwYW4gY2xhc3M9ImdwbC1yLWsiPlR1cm4gZGlzdGFuY2U8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1yLXYiIGlkPSJncGwtci10dXJubGVuIj7igJQga208L3NwYW4+PC9kaXY+CiAgICAgICAgPGRpdiBjbGFzcz0iZ3BsLXItcm93IGdwbC1yLXByaSI+PHNwYW4gY2xhc3M9ImdwbC1yLWsiPlRvdGFsIGRyaXZlPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtci12IiBpZD0iZ3BsLXItZHJpdmUiPuKAlCBrbTwvc3Bhbj48L2Rpdj4KICAgICAgICA8ZGl2IGNsYXNzPSJncGwtci1yb3ciPjxzcGFuIGNsYXNzPSJncGwtci1rIj5BdmcgZ3JhZGU8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1yLXYiIGlkPSJncGwtci1ncmFkZSI+4oCUICU8L3NwYW4+PC9kaXY+CiAgICAgICAgPGRpdiBjbGFzcz0iZ3BsLXItcm93IGdwbC1yLXByaSI+PHNwYW4gY2xhc3M9ImdwbC1yLWsiPkZ1ZWw8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1yLXYiIGlkPSJncGwtci1mdWVsIj7igJQgTDwvc3Bhbj48L2Rpdj4KICAgICAgICA8ZGl2IGNsYXNzPSJncGwtci1yb3ciPjxzcGFuIGNsYXNzPSJncGwtci1rIj7igKZ0dXJuIGZ1ZWw8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1yLXYiIGlkPSJncGwtci10dXJuZnVlbCI+4oCUIEw8L3NwYW4+PC9kaXY+CiAgICAgICAgPGRpdiBjbGFzcz0iZ3BsLXItcm93Ij48c3BhbiBjbGFzcz0iZ3BsLXItayI+4oCmc2xvcGUgY29zdDwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLXItdiIgaWQ9ImdwbC1yLXNsb3BlIj4rIDAlPC9zcGFuPjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1yLXJvdyI+PHNwYW4gY2xhc3M9ImdwbC1yLWsiPkNvc3Q8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1yLXYiIGlkPSJncGwtci1jb3N0Ij4kIOKAlDwvc3Bhbj48L2Rpdj4KICAgICAgICA8ZGl2IGNsYXNzPSJncGwtci1yb3ciPjxzcGFuIGNsYXNzPSJncGwtci1rIj52cyBBQiBzdHJhaWdodDwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLXItc2F2aW5ncyIgaWQ9ImdwbC1yLXNhdiI+4oCUPC9zcGFuPjwvZGl2PgogICAgICA8L2Rpdj4KICAgIDwvZGl2PgogICAgPGRpdiBjbGFzcz0iZ3BsLWNhcmQiPgogICAgICA8aDM+Q29tcGFyZSBhbGw8L2gzPgogICAgICA8ZGl2IGNsYXNzPSJncGwtY21wIj4KICAgICAgICA8ZGl2IGNsYXNzPSJncGwtY21wLXJvdyBncGwtY21wLWhlYWQiPjxzcGFuPkFwcHJvYWNoPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtY21wLXZhbCI+Q292PC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtY21wLXZhbCI+RnVlbDwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLWNtcC12YWwiPiQ8L3NwYW4+PC9kaXY+CiAgICAgICAgPGRpdiBjbGFzcz0iZ3BsLWNtcC1yb3ciIGRhdGEtY21wPSJhYi1zdHJhaWdodCI+PHNwYW4gY2xhc3M9ImdwbC1jbXAtbmFtZSI+QUIgc3RyYWlnaHQ8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1jbXAtdmFsIj7igJQ8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1jbXAtdmFsIj7igJQ8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1jbXAtdmFsIj7igJQ8L3NwYW4+PC9kaXY+CiAgICAgICAgPGRpdiBjbGFzcz0iZ3BsLWNtcC1yb3ciIGRhdGEtY21wPSJhYi1jdXJ2ZSI+PHNwYW4gY2xhc3M9ImdwbC1jbXAtbmFtZSI+QUIgY3VydmU8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1jbXAtdmFsIj7igJQ8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1jbXAtdmFsIj7igJQ8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1jbXAtdmFsIj7igJQ8L3NwYW4+PC9kaXY+CiAgICAgICAgPGRpdiBjbGFzcz0iZ3BsLWNtcC1yb3ciIGRhdGEtY21wPSJib3VuZGFyeSI+PHNwYW4gY2xhc3M9ImdwbC1jbXAtbmFtZSI+Qm91bmRhcnkgZm9sbG93PC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtY21wLXZhbCI+4oCUPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtY21wLXZhbCI+4oCUPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtY21wLXZhbCI+4oCUPC9zcGFuPjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1jbXAtcm93IiBkYXRhLWNtcD0iYWRhcHRpdmUiPjxzcGFuIGNsYXNzPSJncGwtY21wLW5hbWUiPkFkYXB0aXZlPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtY21wLXZhbCI+4oCUPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtY21wLXZhbCI+4oCUPC9zcGFuPjxzcGFuIGNsYXNzPSJncGwtY21wLXZhbCI+4oCUPC9zcGFuPjwvZGl2PgogICAgICA8L2Rpdj4KICAgIDwvZGl2PgogICAgPGRpdiBjbGFzcz0iZ3BsLWNhcmQiPgogICAgICA8aDM+QW5udWFsIFJPSTwvaDM+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1pbnB1dC1yb3ciPgogICAgICAgIDxsYWJlbCBmb3I9ImdwbC1yb2ktZmFybSI+RmFybSBzaXplPC9sYWJlbD4KICAgICAgICA8aW5wdXQgdHlwZT0ibnVtYmVyIiBpZD0iZ3BsLXJvaS1mYXJtIiBtaW49IjEiIG1heD0iNTAwMDAiIHN0ZXA9IjEiIHZhbHVlPSIyMDAiPgogICAgICAgIDxzcGFuIGNsYXNzPSJncGwtdW5pdCI+aGE8L3NwYW4+CiAgICAgIDwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJncGwtaW5wdXQtcm93Ij4KICAgICAgICA8bGFiZWwgZm9yPSJncGwtcm9pLWFwcHMiPkFwcGxpY2F0aW9ucy95cjwvbGFiZWw+CiAgICAgICAgPGlucHV0IHR5cGU9Im51bWJlciIgaWQ9ImdwbC1yb2ktYXBwcyIgbWluPSIxIiBtYXg9IjIwIiBzdGVwPSIxIiB2YWx1ZT0iNCI+CiAgICAgICAgPHNwYW4gY2xhc3M9ImdwbC11bml0Ij7Dlzwvc3Bhbj4KICAgICAgPC9kaXY+CiAgICAgIDxkaXYgY2xhc3M9ImdwbC1yZXN1bHRzIj4KICAgICAgICA8ZGl2IGNsYXNzPSJncGwtci1yb3ciPjxzcGFuIGNsYXNzPSJncGwtci1rIj5Bbm51YWwgZnVlbCBzYXZlZDwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLXItdiIgaWQ9ImdwbC1yb2ktZnVlbCI+4oCUIEw8L3NwYW4+PC9kaXY+CiAgICAgICAgPGRpdiBjbGFzcz0iZ3BsLXItcm93Ij48c3BhbiBjbGFzcz0iZ3BsLXItayI+QW5udWFsIGNvc3Qgc2F2ZWQ8L3NwYW4+PHNwYW4gY2xhc3M9ImdwbC1yLXYiIGlkPSJncGwtcm9pLWNvc3QiPiQg4oCUPC9zcGFuPjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImdwbC1yLXJvdyBncGwtci1wcmkiPjxzcGFuIGNsYXNzPSJncGwtci1rIj5QZXItaGEgc2F2aW5nczwvc3Bhbj48c3BhbiBjbGFzcz0iZ3BsLXItdiIgaWQ9ImdwbC1yb2ktcGVyaGEiPiQg4oCUPC9zcGFuPjwvZGl2PgogICAgICA8L2Rpdj4KICAgIDwvZGl2PgogICAgPGRpdiBjbGFzcz0iZ3BsLWN0YS1jYXJkIj4KICAgICAgPGg0PlJ1biBvbiB5b3VyIHJlYWwgZmllbGQ8L2g0PgogICAgICA8dWwgY2xhc3M9ImdwbC1jdGEtbGlzdCI+CiAgICAgICAgPGxpPlVwbG9hZCBib3VuZGFyeSArIGFzLWFwcGxpZWQgZGF0YTwvbGk+CiAgICAgICAgPGxpPkVkZ2UtYXdhcmUgQWRhcHRpdmUgcGF0aHMgZnJvbSByZWFsIGVsZXZhdGlvbjwvbGk+CiAgICAgICAgPGxpPlNlY3Rpb24tY29udHJvbCBnYXAgZXN0aW1hdGVzICsgUnggZXhwb3J0PC9saT4KICAgICAgPC91bD4KICAgICAgPGEgY2xhc3M9ImdwbC1jdGEtYnRuLWxnIiBocmVmPSJodHRwczovL2FwcC5nZW9wYXJkLnRlY2gvc2lnbnVwP3V0bV9zb3VyY2U9Z3VpZGFuY2UtbGluZXMmdXRtX21lZGl1bT13cC1lbWJlZCZ1dG1fY2FtcGFpZ249Y3RhLWJvdHRvbSIgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9vcGVuZXIiPlBsYW4gaW4gR2VvUGFyZCA8c3BhbiBjbGFzcz0iZ3BsLWN0YS1hcnIiPuKGkjwvc3Bhbj48L2E+CiAgICAgIDxwIGNsYXNzPSJncGwtY3RhLW5vdGUiPlByZS1jYWxpYnJhdGVkIGVzdGltYXRlcy4gRmllbGQtc3BlY2lmaWMgbnVtYmVycyBkZXBlbmQgb24gZXF1aXBtZW50LCB0ZXJyYWluIGFuZCB0b3BvZ3JhcGh5LjwvcD4KICAgIDwvZGl2PgogIDwvYXNpZGU+CjwvZGl2PgoKPHNjcmlwdCBub3dwcm9ja2V0IGRhdGEtbm8tb3B0aW1pemU9IjEiIGRhdGEtbm8tZGVmZXI9IjEiIGRhdGEtbm8tbWluaWZ5PSIxIj4KKGZ1bmN0aW9uKCl7CiAgdmFyIHJvb3QgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXJvb3QnKTsKICBpZighcm9vdCkgcmV0dXJuOwogIHZhciBjYW52YXMgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLWNhbnZhcycpOwogIHZhciBjdHggPSBjYW52YXMuZ2V0Q29udGV4dCgnMmQnKTsKICB2YXIgdHJheUVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC10cmF5Jyk7CgogIC8vIFNhbXBsZSBmaWVsZHMg4oCUIHVuaXRzIGFyZSByZWFsIG1ldGVycywgcmVuZGVyZWQgd2l0aCBhIHVuaWZvcm0gc2NhbGUgZml0dGluZwogIC8vIHRoZSBjYW52YXMuIEZvdXIgc2hhcGVzIGNvdmVyIHRoZSBjb21tb24gY2FzZXM6IGlycmVndWxhciBwb2x5Z29uLCByZWN0YW5ndWxhcgogIC8vIE1pZHdlc3Qgc2VjdGlvbiwgTC1zaGFwZWQgKG9ic3RhY2xlIC8gaGlsbCBjb3JuZXIpLCBvdmFsIChjZW50cmUtcGl2b3QgcmVtbmFudCkuCiAgdmFyIEZJRUxEUyA9IHsKICAgIGhleDogWwogICAgICB7IHg6ICAyMCwgeTogMjIwIH0sIHsgeDogIDgwLCB5OiAgNjAgfSwgeyB4OiAyOTAsIHk6ICAzNSB9LAogICAgICB7IHg6IDU4MCwgeTogIDkwIH0sIHsgeDogNjkwLCB5OiAyNDAgfSwgeyB4OiA2NDAsIHk6IDQ2MCB9LAogICAgICB7IHg6IDM4MCwgeTogNTQwIH0sIHsgeDogMTMwLCB5OiA1MTAgfSwgeyB4OiAgNDAsIHk6IDM4MCB9CiAgICBdLAogICAgcmVjdDogWwogICAgICB7IHg6ICA0MCwgeTogIDYwIH0sIHsgeDogNzIwLCB5OiAgNzAgfSwgeyB4OiA3MzAsIHk6IDUyMCB9LCB7IHg6ICA1MCwgeTogNTEwIH0KICAgIF0sCiAgICBsc2hhcGU6IFsKICAgICAgeyB4OiAgNjAsIHk6ICA2MCB9LCB7IHg6IDQ0MCwgeTogIDYwIH0sIHsgeDogNDQwLCB5OiAyODAgfSwKICAgICAgeyB4OiA3MjAsIHk6IDI4MCB9LCB7IHg6IDcyMCwgeTogNTQwIH0sIHsgeDogIDYwLCB5OiA1NDAgfQogICAgXSwKICAgIC8vIElycmlnYXRpb24gcGl2b3QgZmllbGQg4oCUIGEgdHJ1ZSBjaXJjbGUgZHJhd24gYnkgdGhlIGNlbnRyZS1waXZvdAogICAgLy8gc3ByaW5rbGVyLiBSYWRpdXMg4omIIDMwMCBtIGdpdmVzIH4yOCBoYSB3aGljaCBtYXRjaGVzIGEgdHlwaWNhbAogICAgLy8gcXVhcnRlci1zZWN0aW9uIHBpdm90ICgxMzAgbSB3aWRlLCAzNjDCsCBjb3ZlcmFnZSwgfjMyIGhhIGdyb3NzIC8KICAgIC8vIH4yOCBoYSBhY3R1YWxseSB3ZXR0ZWQpLgogICAgcGl2b3Q6IChmdW5jdGlvbigpewogICAgICB2YXIgcHRzID0gW107CiAgICAgIHZhciBjeCA9IDM4MCwgY3kgPSAyOTAsIHIgPSAzMDA7CiAgICAgIGZvcih2YXIgaT0wOyBpPDI4OyBpKyspewogICAgICAgIHZhciB0ID0gKGkgLyAyOCkgKiBNYXRoLlBJICogMjsKICAgICAgICBwdHMucHVzaCh7IHg6IGN4ICsgTWF0aC5jb3ModCkgKiByLCB5OiBjeSArIE1hdGguc2luKHQpICogciB9KTsKICAgICAgfQogICAgICByZXR1cm4gcHRzOwogICAgfSkoKQogIH07CiAgdmFyIGN1cnJlbnRGaWVsZCA9ICdoZXgnOwogIHZhciBCT1VOREFSWSA9IEZJRUxEU1tjdXJyZW50RmllbGRdOwogIC8vIFBlci1maWVsZCBzeW50aGV0aWMgZWxldmF0aW9uLiB0ZXJyYWluKHgsIHkpIOKGkiBtZXRyZXMgYWJvdmUgdGhlIGZpZWxkJ3MKICAvLyBvd24gbG93ZXN0IHBvaW50LiBQaWNrZWQgdG8gZGVtb25zdHJhdGUgcmVhbGlzdGljIGFnIHNjZW5hcmlvczoKICAvLyAgIGhleCAgICAg4oCUIGVhc3QtZmFjaW5nIHNsb3BlLCAxMiBtIGRyb3AgYWNyb3NzIHRoZSBmaWVsZAogIC8vICAgcmVjdCAgICDigJQgZ2VudGxlIHJpZGdlIHJ1bm5pbmcgZGlhZ29uYWxseSwgMTUgbSBwZWFrCiAgLy8gICBsc2hhcGUgIOKAlCBoaWxsIGF0IHRoZSBjb25jYXZlIGNvcm5lciAoTkUpLCAyMCBtIHBlYWsKICAvLyAgIHBpdm90ICAg4oCUIHNpbmdsZSByb3VuZCBoaWxsLCAxOCBtIHBlYWsgaW4gY2VudHJlCiAgLy8gICBjdXN0b20gIOKAlCBmbGF0IChubyBlbGV2YXRpb24gZGF0YSBmb3IgdXBsb2FkZWQgYm91bmRhcmllcykKICAvLyBUaGUgZnVuY3Rpb25zIGFyZSBkZWxpYmVyYXRlbHkgc21vb3RoIHNvIGNvbnRvdXIgbGluZXMgbG9vayBuYXR1cmFsLgogIHZhciBURVJSQUlOID0gewogICAgaGV4OiBmdW5jdGlvbih4LCB5KXsKICAgICAgLy8gVGlsdGVkIHBsYW5lICsgZ2VudGxlIHdhdmVzCiAgICAgIHJldHVybiAxMiAqICgoeCAtIDIwKSAvIDY3MCkgKyAyICogTWF0aC5zaW4oeSAvIDkwKSArIDEgKiBNYXRoLmNvcyh4IC8gMTEwKTsKICAgIH0sCiAgICByZWN0OiBmdW5jdGlvbih4LCB5KXsKICAgICAgLy8gRGlhZ29uYWwgcmlkZ2UKICAgICAgdmFyIHUgPSAoeCArIHkpIC8gMTIwMDsKICAgICAgcmV0dXJuIDE1ICogTWF0aC5leHAoLU1hdGgucG93KHUgLSAwLjUsIDIpICogOCkgLSAyOwogICAgfSwKICAgIGxzaGFwZTogZnVuY3Rpb24oeCwgeSl7CiAgICAgIC8vIEhpbGwgbmVhciB0aGUgY29uY2F2ZSBjb3JuZXIgKDQ0MCwgMjgwKQogICAgICB2YXIgZHggPSAoeCAtIDU0MCkgLyAyMDAsIGR5ID0gKHkgLSAyMjApIC8gMTgwOwogICAgICByZXR1cm4gMjAgKiBNYXRoLmV4cCgtKGR4KmR4ICsgZHkqZHkpKSArICg1NDAgLSB5KSAqIDAuMDA1OwogICAgfSwKICAgIHBpdm90OiBmdW5jdGlvbih4LCB5KXsKICAgICAgLy8gQ2VudHJhbCByb3VuZCBoaWxsCiAgICAgIHZhciBkeCA9ICh4IC0gMzgwKSAvIDIyMCwgZHkgPSAoeSAtIDI5MCkgLyAyMjA7CiAgICAgIHJldHVybiAxOCAqIE1hdGguZXhwKC0oZHgqZHggKyBkeSpkeSkpOwogICAgfSwKICAgIGN1c3RvbTogZnVuY3Rpb24oKXsgcmV0dXJuIDA7IH0KICB9OwogIGZ1bmN0aW9uIHRlcnJhaW5BdCh4LCB5KXsKICAgIHZhciBmbiA9IFRFUlJBSU5bY3VycmVudEZpZWxkXSB8fCBURVJSQUlOLmN1c3RvbTsKICAgIHJldHVybiBmbih4LCB5KTsKICB9CiAgLy8gQUItbGluZSBkaXJlY3Rpb24gb3ZlcnJpZGUuIG51bGwgPSB1c2UgUENBIHJlc3VsdDsgb3RoZXJ3aXNlIGRlZ3JlZXMgMOKAkzE4MAogIC8vIG1lYXN1cmVkIGZyb20gdGhlICt4IGF4aXMgKGNvdW50ZXItY2xvY2t3aXNlIGluIHNjcmVlbi1jb29yZHMgd2hlcmUgK3kgaXMKICAvLyBkb3duLCBzbyB0aGlzIG1hdGNoZXMgImNvbXBhc3MtbGlrZSIgaW50dWl0aXZlIGRpcmVjdGlvbiBvbiB0aGUgY2FudmFzKS4KICB2YXIgdXNlckF4aXNEZWcgPSBudWxsOwoKICBmdW5jdGlvbiBmaWVsZFN0YXRzKGIpewogICAgdmFyIG1pblggPSBJbmZpbml0eSwgbWF4WCA9IC1JbmZpbml0eSwgbWluWSA9IEluZmluaXR5LCBtYXhZID0gLUluZmluaXR5OwogICAgZm9yKHZhciBpPTA7IGk8Yi5sZW5ndGg7IGkrKyl7CiAgICAgIGlmKGJbaV0ueCA8IG1pblgpIG1pblggPSBiW2ldLng7CiAgICAgIGlmKGJbaV0ueCA+IG1heFgpIG1heFggPSBiW2ldLng7CiAgICAgIGlmKGJbaV0ueSA8IG1pblkpIG1pblkgPSBiW2ldLnk7CiAgICAgIGlmKGJbaV0ueSA+IG1heFkpIG1heFkgPSBiW2ldLnk7CiAgICB9CiAgICB2YXIgcyA9IDA7CiAgICBmb3IodmFyIGo9MDsgajxiLmxlbmd0aDsgaisrKXsKICAgICAgdmFyIGsgPSAoaiArIDEpICUgYi5sZW5ndGg7CiAgICAgIHMgKz0gYltqXS54ICogYltrXS55IC0gYltrXS54ICogYltqXS55OwogICAgfQogICAgcmV0dXJuIHsgbWluWDogbWluWCwgbWF4WDogbWF4WCwgbWluWTogbWluWSwgbWF4WTogbWF4WSwgYXJlYTogTWF0aC5hYnMocykgKiAwLjUgfTsKICB9CgogIC8vIFJlY29tbWVuZCBhbiBhcHByb2FjaCBieSBjb21wdXRpbmcgcmVhbCBtZXRyaWNzIG9uIHRoZSBjdXJyZW50IGZpZWxkIGZvcgogIC8vIGVhY2ggY2FuZGlkYXRlLCB0aGVuIHNjb3JpbmcgYWdhaW5zdCB0aGUgdGhyZWUgb3BlcmF0b3IgcHJpb3JpdGllczoKICAvLyAgIDEuIGNvdmVyYWdlICUg4oCUIHRoZSBiaWdnZXN0IGRpYWw7IGJhZCBjb3ZlcmFnZSBtZWFucyB1bmNvdmVyZWQgYWNyZXMKICAvLyAgIDIuIHR1cm5hcm91bmQgY291bnQg4oCUIGZld2VyIHR1cm5zID0gbGVzcyB0aW1lIGxvc3QgKyBsZXNzIGZ1ZWwgYnVybmVkCiAgLy8gICAzLiBmdWVsIEwg4oCUIHRvdGFsIGRyaXZlLXBhdGggw5cgY29uc3VtcHRpb24KICAvLwogIC8vIFNjb3JlID0gY292ZXJhZ2Ug4oiSIDAuNCDDlyB0dXJuYXJvdW5kQ291bnQg4oiSIDEuNSDDlyBmdWVsTC4gQ292ZXJhZ2UgaXMgb24gYQogIC8vIDDigJMxMDAgc2NhbGU7IHR1cm4gY291bnRzIHJ1biAxMOKAkzMwOyBmdWVsIHJ1bnMgNeKAkzIwIEw7IHNvIHRoZSB3ZWlnaHRzCiAgLy8gYnJpbmcgdGhlbSBpbnRvIHNpbWlsYXIgcmFuZ2VzIGFuZCBjb3ZlcmFnZSB3aW5zIHRpZXMuCiAgLy8KICAvLyBGYWxscyBiYWNrIHRvIHRoZSBzaGFwZS1iYXNlZCBoZXVyaXN0aWMgb25seSB3aGVuIG1ldHJpYyBldmFsIGZhaWxzCiAgLy8gKGUuZy4sIHplcm8tcGFzcyByZXN1bHQpLiByZWNvbW1lbmRCeU1ldHJpY3MgaXMgY2FsbGVkIGZyb20gcmVjb21wdXRlCiAgLy8gQUZURVIgdGhlIGZvdXIgQ29tcGFyZSBBbGwgbGF5b3V0cyBoYXZlIGFscmVhZHkgYmVlbiBjb21wdXRlZCwgc28gd2UKICAvLyBkb24ndCBwYXkgdGhlIGNvc3Qgb2YgZ2VuZXJhdGluZyBsYXlvdXRzIHR3aWNlLgogIGZ1bmN0aW9uIHNjb3JlQXBwcm9hY2gobWV0KXsKICAgIC8vIENvbXBvc2l0ZSBvcGVyYXRvciBzY29yZTogY292ZXJhZ2UgZG9taW5hdGVzLCB0aGVuIGZ1ZWwgKyB0dXJucyB0aWVicmVhay4KICAgIC8vIENvdmVyYWdlIG9uIDDigJMxMDA7IHR1cm5zIDEw4oCTMzA7IGZ1ZWwgNeKAkzIwIEw7IHdlaWdodHMgYnJpbmcgdGhlbSBpbnRvCiAgICAvLyBzaW1pbGFyIHJhbmdlcy4gKFVzZWQgYXMgdGhlICJ3aHkiIHN0cmluZyBvbmx5IOKAlCByZWNvbW1lbmRCeU1ldHJpY3MKICAgIC8vIHVzZXMgYSB0aWVyZWQgY29tcGFyaXNvbiBpbnN0ZWFkIHNvIGNvdmVyYWdlIHRydWx5IGNvbWVzIGZpcnN0LikKICAgIHZhciBjb3YgPSBtZXQuY292ZXJhZ2VQY3QgfHwgMDsKICAgIHZhciB0dXJucyA9IG1ldC50dXJucyB8fCAwOwogICAgdmFyIGZ1ZWwgPSBtZXQuZnVlbEwgfHwgMDsKICAgIHJldHVybiBjb3YgLSAwLjQgKiB0dXJucyAtIDEuNSAqIGZ1ZWw7CiAgfQogIC8vIFRpZXItYmFzZWQgcmVjb21tZW5kYXRpb246CiAgLy8gICAxLiBJZiBhbnkgYXBwcm9hY2ggcmVhY2hlcyDiiaU5NSAlIGNvdmVyYWdlLCByZXN0cmljdCB0byB0aGF0IHRpZXIuCiAgLy8gICAyLiBPdGhlcndpc2UgcmVzdHJpY3QgdG8gYXBwcm9hY2hlcyB3aXRoaW4gMyAlIG9mIHRoZSBiZXN0IGNvdmVyYWdlLgogIC8vICAgMy4gSW5zaWRlIHRoYXQgdGllciwgcGljayB0aGUgb25lIHdpdGggdGhlIGxvd2VzdCBmdWVsICg9IHByb3h5IGZvcgogIC8vICAgICAgdG90YWwgZHJpdmUgZGlzdGFuY2UsIHdoaWNoIGFscmVhZHkgY2FwdHVyZXMgYm90aCBwYXNzIGxlbmd0aCBhbmQKICAvLyAgICAgIHR1cm5hcm91bmQgbGVuZ3RoKS4gVGllcyBicm9rZW4gYnkgZmV3ZXIgdHVybmFyb3VuZHMsIHRoZW4gYnkKICAvLyAgICAgIHByZWZlcnJpbmcgdGhlIHNpbXBsZXIgYXBwcm9hY2ggKGFiLXN0cmFpZ2h0ID4gYWItY3VydmUgPiBib3VuZGFyeQogIC8vICAgICAgPiBhZGFwdGl2ZSkg4oCUIHRoZSBBQiBTdHJhaWdodCBkZWZhdWx0IGlzIHdoYXQgb3BlcmF0b3JzIHJ1biB3aGVuCiAgLy8gICAgICBldmVyeXRoaW5nIGVsc2UgaXMgZXF1YWwuCiAgZnVuY3Rpb24gcmVjb21tZW5kQnlNZXRyaWNzKGFwTWV0cmljcyl7CiAgICB2YXIgYXBzID0gWydhYi1zdHJhaWdodCcsICdhYi1jdXJ2ZScsICdib3VuZGFyeScsICdhZGFwdGl2ZSddOwogICAgdmFyIHNpbXBsaWNpdHkgPSB7ICdhYi1zdHJhaWdodCc6IDAsICdhYi1jdXJ2ZSc6IDEsICdib3VuZGFyeSc6IDIsICdhZGFwdGl2ZSc6IDMgfTsKICAgIHZhciBzY29yZXMgPSB7fTsKICAgIHZhciBjYW5kaWRhdGVzID0gW107CiAgICB2YXIgbWF4Q292ID0gMDsKICAgIGZvcih2YXIgaT0wOyBpPGFwcy5sZW5ndGg7IGkrKyl7CiAgICAgIHZhciBhcCA9IGFwc1tpXTsKICAgICAgdmFyIG1ldCA9IGFwTWV0cmljc1thcF07CiAgICAgIGlmKCFtZXQpIGNvbnRpbnVlOwogICAgICBzY29yZXNbYXBdID0gc2NvcmVBcHByb2FjaChtZXQpOwogICAgICBjYW5kaWRhdGVzLnB1c2goeyBhcDogYXAsIGNvdjogbWV0LmNvdmVyYWdlUGN0IHx8IDAsIGZ1ZWw6IG1ldC5mdWVsTCB8fCAwLCB0dXJuczogbWV0LnR1cm5zIHx8IDAgfSk7CiAgICAgIGlmKChtZXQuY292ZXJhZ2VQY3QgfHwgMCkgPiBtYXhDb3YpIG1heENvdiA9IG1ldC5jb3ZlcmFnZVBjdCB8fCAwOwogICAgfQogICAgaWYoY2FuZGlkYXRlcy5sZW5ndGggPT09IDApIHJldHVybiB7IHBpY2s6ICdhYi1zdHJhaWdodCcsIHdoeTogJ2ZhbGxiYWNrIGRlZmF1bHQnLCBzY29yZXM6IHNjb3JlcyB9OwogICAgdmFyIGNvdlRocmVzaG9sZCA9IG1heENvdiA+PSA5NSA\/IDk1IDogKG1heENvdiAtIDMpOwogICAgdmFyIHRpZXIgPSBjYW5kaWRhdGVzLmZpbHRlcihmdW5jdGlvbihjKXsgcmV0dXJuIGMuY292ID49IGNvdlRocmVzaG9sZDsgfSk7CiAgICB0aWVyLnNvcnQoZnVuY3Rpb24oYSwgYil7CiAgICAgIGlmKGEuZnVlbCAhPT0gYi5mdWVsKSByZXR1cm4gYS5mdWVsIC0gYi5mdWVsOwogICAgICBpZihhLnR1cm5zICE9PSBiLnR1cm5zKSByZXR1cm4gYS50dXJucyAtIGIudHVybnM7CiAgICAgIHJldHVybiBzaW1wbGljaXR5W2EuYXBdIC0gc2ltcGxpY2l0eVtiLmFwXTsKICAgIH0pOwogICAgdmFyIGJlc3QgPSB0aWVyWzBdOwogICAgdmFyIHdoeSA9IGJlc3QuY292LnRvRml4ZWQoMCkgKyAnJSBjb3YgwrcgJyArIGJlc3QudHVybnMgKyAnIHR1cm5zIMK3ICcgKyBiZXN0LmZ1ZWwudG9GaXhlZCgxKSArICcgTCBmdWVsJzsKICAgIHJldHVybiB7IHBpY2s6IGJlc3QuYXAsIHdoeTogd2h5LCBzY29yZXM6IHNjb3JlcyB9OwogIH0KICAvLyBTaGFwZS1iYXNlZCBmYWxsYmFjayAodXNlZCBhdCBJTklUSUFMIGxvYWQgb25seSwgYmVmb3JlIGFueSBsYXlvdXQgaGFzCiAgLy8gcnVuKS4gUmV0dXJucyBqdXN0IHRoZSBwaWNrIOKAlCByZWNvbW1lbmRCeU1ldHJpY3MgcmVwbGFjZXMgdGhpcyBvbiB0aGUKICAvLyBmaXJzdCByZWNvbXB1dGUoKS4KICBmdW5jdGlvbiByZWNvbW1lbmRBcHByb2FjaChiKXsKICAgIHZhciBzdGF0cyA9IGZpZWxkU3RhdHMoYik7CiAgICB2YXIgYmJveEFyZWEgPSAoc3RhdHMubWF4WCAtIHN0YXRzLm1pblgpICogKHN0YXRzLm1heFkgLSBzdGF0cy5taW5ZKTsKICAgIHZhciByZWN0ID0gYmJveEFyZWEgPiAwID8gKHN0YXRzLmFyZWEgLyBiYm94QXJlYSkgOiAwOwogICAgdmFyIHBlciA9IDA7CiAgICBmb3IodmFyIGk9MDsgaTxiLmxlbmd0aDsgaSsrKXsKICAgICAgdmFyIGogPSAoaSArIDEpICUgYi5sZW5ndGg7CiAgICAgIHZhciBkeCA9IGJbal0ueCAtIGJbaV0ueCwgZHkgPSBiW2pdLnkgLSBiW2ldLnk7CiAgICAgIHBlciArPSBNYXRoLnNxcnQoZHgqZHggKyBkeSpkeSk7CiAgICB9CiAgICB2YXIgY29tcCA9IHBlciA+IDAgPyAoNCAqIE1hdGguUEkgKiBzdGF0cy5hcmVhIC8gKHBlciAqIHBlcikpIDogMDsKICAgIHZhciBwaWNrOwogICAgaWYoY29tcCA+IDAuNzgpIHBpY2sgPSAnYm91bmRhcnknOwogICAgZWxzZSBpZihyZWN0ID4gMC44NSkgcGljayA9ICdhYi1zdHJhaWdodCc7CiAgICBlbHNlIGlmKHJlY3QgPiAwLjU1KSBwaWNrID0gJ2FiLWN1cnZlJzsKICAgIGVsc2UgcGljayA9ICdhZGFwdGl2ZSc7CiAgICByZXR1cm4geyBwaWNrOiBwaWNrLCB3aHk6ICdhbmFseXNpbmfigKYnIH07CiAgfQoKICAvLyBQQ0Egb24gYm91bmRhcnkgdmVydGljZXMg4oCUIHJldHVybnMgcHJpbmNpcGFsIGF4aXMgKHV4LCB1eSkuCiAgZnVuY3Rpb24gZmllbGRBeGlzKGIpewogICAgdmFyIG4gPSBiLmxlbmd0aDsKICAgIHZhciBteHMgPSAwLCBteXMgPSAwOwogICAgZm9yKHZhciBpPTA7IGk8bjsgaSsrKXsgbXhzICs9IGJbaV0ueDsgbXlzICs9IGJbaV0ueTsgfQogICAgbXhzIC89IG47IG15cyAvPSBuOwogICAgdmFyIHN4eCA9IDAsIHN5eSA9IDAsIHN4eSA9IDA7CiAgICBmb3IodmFyIGo9MDsgajxuOyBqKyspewogICAgICB2YXIgZHggPSBiW2pdLnggLSBteHMsIGR5ID0gYltqXS55IC0gbXlzOwogICAgICBzeHggKz0gZHgqZHg7IHN5eSArPSBkeSpkeTsgc3h5ICs9IGR4KmR5OwogICAgfQogICAgdmFyIGFuZyA9IDAuNSAqIE1hdGguYXRhbjIoMiAqIHN4eSwgc3h4IC0gc3l5KTsKICAgIHJldHVybiB7IHV4OiBNYXRoLmNvcyhhbmcpLCB1eTogTWF0aC5zaW4oYW5nKSB9OwogIH0KCiAgLy8gQ29uY2F2ZS1zYWZlIGxpbmUgY2xpcHBlci4gRmluZHMgYWxsIGVkZ2UgaW50ZXJzZWN0aW9ucywgc29ydHMgYnkgdCwKICAvLyBhbmQgcGFpcnMgdGhlbSB1cDogZWFjaCBjb25zZWN1dGl2ZSAoaW5zaWRlLWVudHJ5LCBpbnNpZGUtZXhpdCkgcGFpcgogIC8vIGJlY29tZXMgb25lIHJldHVybmVkIHNlZ21lbnQuIFdvcmtzIGZvciBhcmJpdHJhcnkgc2ltcGxlIHBvbHlnb25zCiAgLy8gKGNvbnZleCBvciBjb25jYXZlKS4gUmV0dXJucyBhcnJheSBvZiBzZWdtZW50cyBbe3gwLHkwLHgxLHkxfSwgLi4uXQogIC8vIG9yIG51bGwgd2hlbiB0aGUgbGluZSBtaXNzZXMgdGhlIHBvbHlnb24gZW50aXJlbHkuCiAgLy8gTGlhbmctQmFyc2t5IHdhcyB0aGUgb2xkIGltcGxlbWVudGF0aW9uOyBpdCBBU1NVTUVEIGNvbnZleCBhbmQgcHJvZHVjZWQKICAvLyB3cm9uZyBjbGlwcyBvbiB0aGUgTC1zaGFwZSBpbnRlcmlvciAoY29uY2F2ZSBhdCB0aGUgaW5uZXItY29ybmVyKS4KICBmdW5jdGlvbiBjbGlwTGluZVRvQm91bmRhcnlTZWdtZW50cyh4MCwgeTAsIHgxLCB5MSwgYil7CiAgICB2YXIgZHggPSB4MSAtIHgwLCBkeSA9IHkxIC0geTA7CiAgICB2YXIgbmIgPSBiLmxlbmd0aDsKICAgIHZhciB0cyA9IFtdOwogICAgZm9yKHZhciBpPTA7IGk8bmI7IGkrKyl7CiAgICAgIHZhciBqID0gKGkgKyAxKSAlIG5iOwogICAgICB2YXIgYXggPSBiW2ldLngsIGF5ID0gYltpXS55OwogICAgICB2YXIgZXggPSBiW2pdLnggLSBheCwgZXkgPSBiW2pdLnkgLSBheTsKICAgICAgLy8gUGFyYW1ldHJpYyBsaW5lIMOXIHBhcmFtZXRyaWMgZWRnZTogeDArdMK3ZHggPSBheCt1wrdleCBldGMuCiAgICAgIC8vIFNvbHZlIGZvciB0LCB1IGluIFswLDFdLiBkZW5vbSA9IGR4wrcoLWV5KSDiiJIgZHnCtygtZXgpID0gZHnCt2V4IOKIkiBkeMK3ZXkKICAgICAgdmFyIGRlbm9tID0gZHkgKiBleCAtIGR4ICogZXk7CiAgICAgIGlmKE1hdGguYWJzKGRlbm9tKSA8IDFlLTkpIGNvbnRpbnVlOwogICAgICB2YXIgdSA9IChkeCAqIChheSAtIHkwKSAtIGR5ICogKGF4IC0geDApKSAvIGRlbm9tOwogICAgICB2YXIgdCA9IChleCAqIChheSAtIHkwKSAtIGV5ICogKGF4IC0geDApKSAvIGRlbm9tOwogICAgICBpZih1IDwgLTFlLTkgPyB0cnVlIDogdSA+IDEgKyAxZS05KSBjb250aW51ZTsKICAgICAgaWYodCA8IC0xZS05ID8gdHJ1ZSA6IHQgPiAxICsgMWUtOSkgY29udGludWU7CiAgICAgIHRzLnB1c2godCA8IDAgPyAwIDogKHQgPiAxID8gMSA6IHQpKTsKICAgIH0KICAgIGlmKHRzLmxlbmd0aCA8IDIpIHJldHVybiBudWxsOwogICAgdHMuc29ydChmdW5jdGlvbihhLCBiKXsgcmV0dXJuIGEgLSBiOyB9KTsKICAgIC8vIERlLWR1cCBuZWFyLWVxdWFsIHQncyAobGluZSBwYXNzaW5nIGV4YWN0bHkgdGhyb3VnaCBhIHZlcnRleCBoaXRzIDIgZWRnZXMpCiAgICB2YXIgY2xlYW4gPSBbdHNbMF1dOwogICAgZm9yKHZhciBrPTE7IGs8dHMubGVuZ3RoOyBrKyspewogICAgICBpZih0c1trXSAtIGNsZWFuW2NsZWFuLmxlbmd0aC0xXSA+IDFlLTYpIGNsZWFuLnB1c2godHNba10pOwogICAgfQogICAgLy8gUGFpciBjb25zZWN1dGl2ZSB0J3MsIGJ1dCBvbmx5IGtlZXAgcGFpcnMgd2hvc2UgbWlkcG9pbnQgaXMgSU5TSURFIHRoZQogICAgLy8gcG9seWdvbiAoZmlsdGVycyBhd2F5ICJvdXRzaWRlIGdhcHMiIGJldHdlZW4gY29uY2F2ZSBzZWdtZW50cykuCiAgICB2YXIgc2VncyA9IFtdOwogICAgZm9yKHZhciBwPTA7IHArMTxjbGVhbi5sZW5ndGg7IHArPTIpewogICAgICB2YXIgdDAgPSBjbGVhbltwXSwgdDEgPSBjbGVhbltwKzFdOwogICAgICB2YXIgbWlkVCA9ICh0MCArIHQxKSAqIDAuNTsKICAgICAgdmFyIG14ID0geDAgKyBkeCAqIG1pZFQsIG15ID0geTAgKyBkeSAqIG1pZFQ7CiAgICAgIGlmKCFwb2ludEluUG9seShteCwgbXksIGIpKSBjb250aW51ZTsKICAgICAgaWYodDEgLSB0MCA8IDFlLTYpIGNvbnRpbnVlOwogICAgICBzZWdzLnB1c2goeyB4MDogeDAgKyBkeCAqIHQwLCB5MDogeTAgKyBkeSAqIHQwLCB4MTogeDAgKyBkeCAqIHQxLCB5MTogeTAgKyBkeSAqIHQxIH0pOwogICAgfQogICAgcmV0dXJuIHNlZ3MubGVuZ3RoID4gMCA\/IHNlZ3MgOiBudWxsOwogIH0KICAvLyBCYWNrLWNvbXBhdCB3cmFwcGVyOiByZXR1cm4gdGhlIExPTkdFU1Qgc2VnbWVudCAob3IgbnVsbCkuIENhbGxlcnMgdGhhdAogIC8vIHdhbnQgYWxsIHN1Yi1zZWdtZW50cyAoZm9yIHByb3BlciBMLXNoYXBlIGNvdmVyYWdlKSB1c2UgLi4uU2VnbWVudHMgYWJvdmUuCiAgZnVuY3Rpb24gY2xpcExpbmVUb0JvdW5kYXJ5KHgwLCB5MCwgeDEsIHkxLCBiKXsKICAgIHZhciBzZWdzID0gY2xpcExpbmVUb0JvdW5kYXJ5U2VnbWVudHMoeDAsIHkwLCB4MSwgeTEsIGIpOwogICAgaWYoIXNlZ3MpIHJldHVybiBudWxsOwogICAgdmFyIGJlc3QgPSBudWxsLCBiZXN0TGVuID0gLTE7CiAgICBmb3IodmFyIGk9MDsgaTxzZWdzLmxlbmd0aDsgaSsrKXsKICAgICAgdmFyIHMgPSBzZWdzW2ldOwogICAgICB2YXIgc2R4ID0gcy54MSAtIHMueDAsIHNkeSA9IHMueTEgLSBzLnkwOwogICAgICB2YXIgbGVuID0gc2R4KnNkeCArIHNkeSpzZHk7CiAgICAgIGlmKGxlbiA+IGJlc3RMZW4peyBiZXN0TGVuID0gbGVuOyBiZXN0ID0gczsgfQogICAgfQogICAgcmV0dXJuIGJlc3Q7CiAgfQoKICAvLyBPZmZzZXQgYSBjbG9zZWQgcG9seWdvbiBpbndhcmQgYnkgZGlzdE0uIFJldHVybnMgYXJyYXkgb2Yge3gseX0gb3IgbnVsbCB3aGVuIGNvbGxhcHNlLgogIGZ1bmN0aW9uIG9mZnNldFBvbHlnb25JbndhcmQoYiwgZGlzdE0pewogICAgdmFyIG4gPSBiLmxlbmd0aDsKICAgIHZhciBzaG9lbGFjZSA9IDA7CiAgICBmb3IodmFyIGk9MDsgaTxuOyBpKyspewogICAgICB2YXIgaiA9IChpICsgMSkgJSBuOwogICAgICBzaG9lbGFjZSArPSBiW2ldLnggKiBiW2pdLnkgLSBiW2pdLnggKiBiW2ldLnk7CiAgICB9CiAgICB2YXIgd2luZGluZyA9IHNob2VsYWNlID4gMCA\/IDEgOiAtMTsKICAgIHZhciBzeCA9IG5ldyBBcnJheShuKSwgc3kgPSBuZXcgQXJyYXkobik7CiAgICBmb3IodmFyIHY9MDsgdjxuOyB2KyspewogICAgICB2YXIgcElkeCA9ICh2IC0gMSArIG4pICUgbjsKICAgICAgdmFyIG5JZHggPSAodiArIDEpICUgbjsKICAgICAgdmFyIGUxeCA9IGJbdl0ueCAtIGJbcElkeF0ueDsKICAgICAgdmFyIGUxeSA9IGJbdl0ueSAtIGJbcElkeF0ueTsKICAgICAgdmFyIGUyeCA9IGJbbklkeF0ueCAtIGJbdl0ueDsKICAgICAgdmFyIGUyeSA9IGJbbklkeF0ueSAtIGJbdl0ueTsKICAgICAgdmFyIGwxID0gTWF0aC5zcXJ0KGUxeCplMXggKyBlMXkqZTF5KTsKICAgICAgdmFyIGwyID0gTWF0aC5zcXJ0KGUyeCplMnggKyBlMnkqZTJ5KTsKICAgICAgaWYobDEgPCAxZS05ID8gdHJ1ZSA6IGwyIDwgMWUtOSl7IHN4W3ZdID0gYlt2XS54OyBzeVt2XSA9IGJbdl0ueTsgY29udGludWU7IH0KICAgICAgdmFyIG4xeCA9IC1lMXkgLyBsMSAqIHdpbmRpbmcsIG4xeSA9IGUxeCAvIGwxICogd2luZGluZzsKICAgICAgdmFyIG4yeCA9IC1lMnkgLyBsMiAqIHdpbmRpbmcsIG4yeSA9IGUyeCAvIGwyICogd2luZGluZzsKICAgICAgdmFyIGJ4diA9IG4xeCArIG4yeCwgYnl2ID0gbjF5ICsgbjJ5OwogICAgICB2YXIgYmwgPSBNYXRoLnNxcnQoYnh2KmJ4diArIGJ5dipieXYpOwogICAgICBpZihibCA8IDFlLTYpeyBzeFt2XSA9IGJbdl0ueCArIG4xeCAqIGRpc3RNOyBzeVt2XSA9IGJbdl0ueSArIG4xeSAqIGRpc3RNOyBjb250aW51ZTsgfQogICAgICB2YXIgY29zRnVsbCA9IG4xeCAqIG4yeCArIG4xeSAqIG4yeTsKICAgICAgdmFyIHNpbkhhbGYgPSBNYXRoLnNxcnQoKDEgLSBjb3NGdWxsKSAqIDAuNSk7CiAgICAgIC8vIE1pdGVyIGxpbWl0OiBmb3IgdmVyeSBvYnR1c2UgYm91bmRhcnkgY29ybmVycyAoc2luSGFsZiBzbWFsbCkgdGhlIGNvcm5lcgogICAgICAvLyBiaXNlY3RvciBibG93cyB1cCBhbmQgd291bGQgcHVzaCB0aGUgb2Zmc2V0IHZlcnRleCBwYXN0IHRoZSBmaWVsZAogICAgICAvLyBjZW50cm9pZC4gQ2FwIG9mZnNldCBkaXN0YW5jZSBhdCAyw5cgZGlzdE0gc28gdGhlIGluc2V0IHN0YXlzIHNhbmUuCiAgICAgIC8vIEZvciBzZXZlcmVseSBvYnR1c2UgY29ybmVycyB0aGUgcmVzdWx0IGlzIGEgc2xpZ2h0IGJldmVsIGluc3RlYWQgb2YgYW4KICAgICAgLy8gaW5maW5pdGVseS1leHRydWRlZCBtaXRlciDigJQgY2xvc2UgZW5vdWdoIGZvciBoZWFkbGFuZCBnZW9tZXRyeS4KICAgICAgaWYoc2luSGFsZiA8IDAuNSkgc2luSGFsZiA9IDAuNTsKICAgICAgc3hbdl0gPSBiW3ZdLnggKyAoYnh2IC8gYmwpICogKGRpc3RNIC8gc2luSGFsZik7CiAgICAgIHN5W3ZdID0gYlt2XS55ICsgKGJ5diAvIGJsKSAqIChkaXN0TSAvIHNpbkhhbGYpOwogICAgfQogICAgdmFyIGtlcHQgPSBbXTsKICAgIGZvcih2YXIgaz0wOyBrPG47IGsrKyl7CiAgICAgIHZhciBwayA9IChrIC0gMSArIG4pICUgbjsKICAgICAgdmFyIG5rID0gKGsgKyAxKSAlIG47CiAgICAgIHZhciBlMXhDID0gYltrXS54IC0gYltwa10ueCwgZTF5QyA9IGJba10ueSAtIGJbcGtdLnk7CiAgICAgIHZhciBjMSA9IChlMXhDICogKHN5W2tdIC0gYltwa10ueSkgLSBlMXlDICogKHN4W2tdIC0gYltwa10ueCkpICogd2luZGluZzsKICAgICAgaWYoYzEgPCAwKSBjb250aW51ZTsKICAgICAgdmFyIGUyeEMgPSBiW25rXS54IC0gYltrXS54LCBlMnlDID0gYltua10ueSAtIGJba10ueTsKICAgICAgdmFyIGMyID0gKGUyeEMgKiAoc3lba10gLSBiW2tdLnkpIC0gZTJ5QyAqIChzeFtrXSAtIGJba10ueCkpICogd2luZGluZzsKICAgICAgaWYoYzIgPCAwKSBjb250aW51ZTsKICAgICAga2VwdC5wdXNoKHsgeDogc3hba10sIHk6IHN5W2tdIH0pOwogICAgfQogICAgaWYoa2VwdC5sZW5ndGggPCA0KSByZXR1cm4gbnVsbDsKICAgIHZhciBvcmlnQXJlYSA9IDA7CiAgICBmb3IodmFyIG9pPTA7IG9pPG47IG9pKyspewogICAgICB2YXIgb2ogPSAob2kgKyAxKSAlIG47CiAgICAgIG9yaWdBcmVhICs9IGJbb2ldLnggKiBiW29qXS55IC0gYltval0ueCAqIGJbb2ldLnk7CiAgICB9CiAgICBvcmlnQXJlYSA9IE1hdGguYWJzKG9yaWdBcmVhKSAqIDAuNTsKICAgIHZhciBuZXdBcmVhID0gMDsKICAgIGZvcih2YXIga2k9MDsga2k8a2VwdC5sZW5ndGg7IGtpKyspewogICAgICB2YXIga2ogPSAoa2kgKyAxKSAlIGtlcHQubGVuZ3RoOwogICAgICBuZXdBcmVhICs9IGtlcHRba2ldLnggKiBrZXB0W2tqXS55IC0ga2VwdFtral0ueCAqIGtlcHRba2ldLnk7CiAgICB9CiAgICBuZXdBcmVhID0gTWF0aC5hYnMobmV3QXJlYSkgKiAwLjU7CiAgICBpZihuZXdBcmVhIDwgb3JpZ0FyZWEgKiAwLjI1KSByZXR1cm4gbnVsbDsKICAgIHJldHVybiBrZXB0OwogIH0KCiAgLy8gUG9pbnQtaW4tcG9seWdvbiAocmF5IGNhc3RpbmcpLiBQb2x5Z29uIGlzIGFycmF5IG9mIHt4LCB5fSwgbm90IG5lY2Vzc2FyaWx5IGNsb3NlZC4KICBmdW5jdGlvbiBwb2ludEluUG9seSh4LCB5LCBwb2x5KXsKICAgIHZhciBpbnNpZGUgPSBmYWxzZTsKICAgIHZhciBuID0gcG9seS5sZW5ndGg7CiAgICBmb3IodmFyIGk9MCwgaj1uLTE7IGk8bjsgaj1pKyspewogICAgICB2YXIgeGkgPSBwb2x5W2ldLngsIHlpID0gcG9seVtpXS55OwogICAgICB2YXIgeGogPSBwb2x5W2pdLngsIHlqID0gcG9seVtqXS55OwogICAgICB2YXIgaW50ZXJzZWN0ID0gKCh5aSA+IHkpICE9PSAoeWogPiB5KSkgPyAoeCA8ICh4aiAtIHhpKSAqICh5IC0geWkpIC8gKHlqIC0geWkgKyAxZS0xMikgKyB4aSkgOiBmYWxzZTsKICAgICAgaWYoaW50ZXJzZWN0KSBpbnNpZGUgPSAhaW5zaWRlOwogICAgfQogICAgcmV0dXJuIGluc2lkZTsKICB9CgogIC8vIEFsbCBhcmMgc2FtcGxlIHBvaW50cyBtdXN0IGxpZSBpbnNpZGUgYHBvbHlgLiBVc2VkIHRvIHJlamVjdCBhcmNzIHRoYXQgbGVhdmUKICAvLyB0aGUgZHJpdmFibGUgYXJlYS4KICBmdW5jdGlvbiBhcmNJbnNpZGVQb2x5KGFyYywgcG9seSl7CiAgICBpZighYXJjID8gdHJ1ZSA6IGFyYy5sZW5ndGggPCAyKSByZXR1cm4gZmFsc2U7CiAgICBmb3IodmFyIGk9MDsgaTxhcmMubGVuZ3RoOyBpKyspewogICAgICBpZighcG9pbnRJblBvbHkoYXJjW2ldLngsIGFyY1tpXS55LCBwb2x5KSkgcmV0dXJuIGZhbHNlOwogICAgfQogICAgcmV0dXJuIHRydWU7CiAgfQoKICAvLyBNaWRkbGUgODAlIG9mIGFyYyBzYW1wbGVzIG11c3QgTk9UIGxpZSBpbnNpZGUgYGludGVyaW9yYCAodGhlIHdvcmtlZCB6b25lKS4KICAvLyBFbmRwb2ludHMgc2l0IE9OIHRoZSBpbnRlcmlvciBib3VuZGFyeSBieSBjb25zdHJ1Y3Rpb24gc28gd2Ugc2tpcCB0aGUgZmlyc3QKICAvLyBhbmQgbGFzdCAxMCUgb2Ygc2FtcGxlcy4KICBmdW5jdGlvbiBhcmNBdm9pZHNJbnRlcmlvcihhcmMsIGludGVyaW9yKXsKICAgIGlmKCFhcmMgPyB0cnVlIDogIWludGVyaW9yKSByZXR1cm4gdHJ1ZTsKICAgIGlmKGFyYy5sZW5ndGggPCA0KSByZXR1cm4gdHJ1ZTsKICAgIC8vIEFyYyBlbmRwb2ludHMgc2l0IE9OIHRoZSBpbnRlcmlvciBib3VuZGFyeSBieSBjb25zdHJ1Y3Rpb24uIEZsb2F0aW5nLXBvaW50CiAgICAvLyBqaXR0ZXIgbmVhciB0aGUgc3RhcnQvZW5kIG1heSBjbGFzc2lmeSB0aGVtIGFzIGp1c3QtaW5zaWRlLCBzbyBza2lwIDE1JQogICAgLy8gYXQgZWFjaCBlbmQuIE1pZGRsZSA3MCUgc3RpbGwgaGFzIHRvIGF2b2lkIHRoZSB3b3JrZWQgem9uZS4KICAgIHZhciBza2lwID0gTWF0aC5tYXgoMSwgTWF0aC5mbG9vcihhcmMubGVuZ3RoICogMC4xNSkpOwogICAgZm9yKHZhciBpPXNraXA7IGk8YXJjLmxlbmd0aC1za2lwOyBpKyspewogICAgICBpZihwb2ludEluUG9seShhcmNbaV0ueCwgYXJjW2ldLnksIGludGVyaW9yKSkgcmV0dXJuIGZhbHNlOwogICAgfQogICAgcmV0dXJuIHRydWU7CiAgfQoKICAvLyBCdWlsZCBhIGNhbmRpZGF0ZSB0dXJuIGFyYyBjb25uZWN0aW5nICh4MSx5MSkgdG8gKHgyLHkyKSBnaXZlbiBzdHlsZSArIHJhZGl1cwogIC8vICsgcGVycGVuZGljdWxhciBkaXJlY3Rpb24gKHNpZ24gPSArMSBvciAtMSA9IHdoaWNoIHNpZGUgdG8gYnVsZ2UpLgogIC8vIFJldHVybnMgYXJyYXkgb2Yge3gsIHl9IHNhbXBsZSBwb2ludHMgKGxlbmd0aCB+MjQrKSBvciBudWxsIHdoZW4gZ2VvbWV0cnkgZmFpbHMuCiAgZnVuY3Rpb24gYnVpbGRBcmMoeDEsIHkxLCB4MiwgeTIsIHN0eWxlLCByYWRpdXNNLCBzaWduKXsKICAgIHZhciBkeCA9IHgyIC0geDEsIGR5ID0geTIgLSB5MTsKICAgIHZhciBkID0gTWF0aC5zcXJ0KGR4KmR4ICsgZHkqZHkpOwogICAgaWYoZCA8IDAuMSkgcmV0dXJuIG51bGw7CiAgICB2YXIgdXggPSBkeCAvIGQsIHV5ID0gZHkgLyBkOwogICAgdmFyIHBlcnBYID0gLXV5ICogc2lnbiwgcGVycFkgPSB1eCAqIHNpZ247CiAgICB2YXIgY29vcmRzID0gW107CiAgICB2YXIgblNlZyA9IDI0OwogICAgaWYoc3R5bGUgPT09ICd1dHVybicpewogICAgICAvLyBIYWxmLWNpcmNsZSwgcmFkaXVzID0gZC8yIChmb3JjZWQgYnkgZ2VvbWV0cnksIG5vdCBlcXVpcG1lbnQpLgogICAgICB2YXIgciA9IGQgKiAwLjU7CiAgICAgIHZhciBteCA9ICh4MSArIHgyKSAqIDAuNSwgbXkgPSAoeTEgKyB5MikgKiAwLjU7CiAgICAgIC8vIEFuZ2xlIGZyb20gbWlkcG9pbnQgdG8gcDEsIHRoZW4gc3dlZXAgwrExODDCsCB0byBwMi4KICAgICAgdmFyIHN0YXJ0QW5nID0gTWF0aC5hdGFuMih5MSAtIG15LCB4MSAtIG14KTsKICAgICAgdmFyIHN3ZWVwID0gTWF0aC5QSSAqIHNpZ247CiAgICAgIGZvcih2YXIgaT0wOyBpPD1uU2VnOyBpKyspewogICAgICAgIHZhciB0ID0gaSAvIG5TZWc7CiAgICAgICAgdmFyIGFuZyA9IHN0YXJ0QW5nICsgc3dlZXAgKiB0OwogICAgICAgIGNvb3Jkcy5wdXNoKHsgeDogbXggKyBNYXRoLmNvcyhhbmcpICogciwgeTogbXkgKyBNYXRoLnNpbihhbmcpICogciB9KTsKICAgICAgfQogICAgfSBlbHNlIGlmKHN0eWxlID09PSAncmFjZXRyYWNrJyl7CiAgICAgIC8vIFR3byA5MMKwIGFyY3MgKyBzdHJhaWdodCBsZWcuIFJhZGl1cyBjYXBwZWQgYXQgZC8yIMOXIDAuOTUgc28gdGhlIGxlZyBzdGF5cyA+IDAuCiAgICAgIHZhciByMiA9IE1hdGgubWluKHJhZGl1c00sIGQgKiAwLjUgKiAwLjk1KTsKICAgICAgaWYocjIgPD0gMC4wMSkgcmV0dXJuIG51bGw7CiAgICAgIC8vIENpcmNsZSBjZW50cmVzIHBlcnBlbmRpY3VsYXItb3V0IGZyb20gZWFjaCBlbmRwb2ludCBieSByMi4KICAgICAgdmFyIGMxeCA9IHgxICsgcGVycFggKiByMiwgYzF5ID0geTEgKyBwZXJwWSAqIHIyOwogICAgICB2YXIgYzJ4ID0geDIgKyBwZXJwWCAqIHIyLCBjMnkgPSB5MiArIHBlcnBZICogcjI7CiAgICAgIHZhciBhbmcxID0gTWF0aC5hdGFuMih5MSAtIGMxeSwgeDEgLSBjMXgpOwogICAgICB2YXIgYW5nMkVuZCA9IE1hdGguYXRhbjIoeTIgLSBjMnksIHgyIC0gYzJ4KTsKICAgICAgdmFyIGhhbGYgPSBNYXRoLm1heCg4LCBNYXRoLmZsb29yKG5TZWcgLyAzKSk7CiAgICAgIC8vIEFyYyAxIGFyb3VuZCBjMTogZnJvbSBhbmcxIHN3ZWVwaW5nICs5MMKwwrdzaWduIChvdXR3YXJkKQogICAgICB2YXIgc3dlZXAxID0gTWF0aC5QSSAqIDAuNSAqIHNpZ247CiAgICAgIGZvcih2YXIgaz0wOyBrPD1oYWxmOyBrKyspewogICAgICAgIHZhciB0MSA9IGsgLyBoYWxmOwogICAgICAgIHZhciBhYSA9IGFuZzEgKyBzd2VlcDEgKiB0MTsKICAgICAgICBjb29yZHMucHVzaCh7IHg6IGMxeCArIE1hdGguY29zKGFhKSAqIHIyLCB5OiBjMXkgKyBNYXRoLnNpbihhYSkgKiByMiB9KTsKICAgICAgfQogICAgICAvLyBBcmMtMSBlbmQgcG9zaXRpb24KICAgICAgdmFyIGVuZEExeCA9IGNvb3Jkc1tjb29yZHMubGVuZ3RoLTFdLngsIGVuZEExeSA9IGNvb3Jkc1tjb29yZHMubGVuZ3RoLTFdLnk7CiAgICAgIC8vIEFyYy0yIHN0YXJ0IHBvc2l0aW9uIChtaXJyb3Igb2YgYW5nMkVuZCBieSArOTDCsMK3c2lnbiByZXZlcnNlZCkKICAgICAgdmFyIHN3ZWVwMnN0YXJ0ID0gYW5nMkVuZCAtIHN3ZWVwMTsKICAgICAgdmFyIHN0YXJ0QTJ4ID0gYzJ4ICsgTWF0aC5jb3Moc3dlZXAyc3RhcnQpICogcjI7CiAgICAgIHZhciBzdGFydEEyeSA9IGMyeSArIE1hdGguc2luKHN3ZWVwMnN0YXJ0KSAqIHIyOwogICAgICAvLyBTdHJhaWdodCBsZWcgZnJvbSBlbmRBMSB0byBzdGFydEEyIOKAlCBzYW1wbGUgNiBwb2ludHMgc28gdmFsaWRhdGlvbiBjYW4KICAgICAgLy8gZGV0ZWN0IGlmIHRoZSBsZWcgY3Jvc3NlcyB0aGUgZmllbGQgYm91bmRhcnkuCiAgICAgIHZhciBsZWdTdGVwcyA9IDY7CiAgICAgIGZvcih2YXIgTD0xOyBMPGxlZ1N0ZXBzOyBMKyspewogICAgICAgIHZhciB0dCA9IEwgLyBsZWdTdGVwczsKICAgICAgICBjb29yZHMucHVzaCh7IHg6IGVuZEExeCArIChzdGFydEEyeCAtIGVuZEExeCkgKiB0dCwgeTogZW5kQTF5ICsgKHN0YXJ0QTJ5IC0gZW5kQTF5KSAqIHR0IH0pOwogICAgICB9CiAgICAgIGNvb3Jkcy5wdXNoKHsgeDogc3RhcnRBMngsIHk6IHN0YXJ0QTJ5IH0pOwogICAgICAvLyBBcmMgMiBhcm91bmQgYzI6IGZyb20gc3dlZXAyc3RhcnQgYmFjayB0byBhbmcyRW5kIChzd2VlcCA9ICs5MMKwwrdzaWduKQogICAgICBmb3IodmFyIG09MTsgbTw9aGFsZjsgbSsrKXsKICAgICAgICB2YXIgdDIgPSBtIC8gaGFsZjsKICAgICAgICB2YXIgYmIgPSBzd2VlcDJzdGFydCArIHN3ZWVwMSAqIHQyOwogICAgICAgIGNvb3Jkcy5wdXNoKHsgeDogYzJ4ICsgTWF0aC5jb3MoYmIpICogcjIsIHk6IGMyeSArIE1hdGguc2luKGJiKSAqIHIyIH0pOwogICAgICB9CiAgICB9IGVsc2UgaWYoc3R5bGUgPT09ICdmbGF0Jyl7CiAgICAgIC8vIFNpbnVzb2lkYWwgYnVsZ2UsIHBlYWsgYW1wbGl0dWRlID0gbWluKHJhZGl1c00sIGQvNCkuCiAgICAgIHZhciBhbXAgPSBNYXRoLm1pbihyYWRpdXNNLCBkICogMC4yNSk7CiAgICAgIGZvcih2YXIgZj0wOyBmPD1uU2VnOyBmKyspewogICAgICAgIHZhciB0ZiA9IGYgLyBuU2VnOwogICAgICAgIHZhciBieCA9IHgxICsgZHggKiB0ZjsKICAgICAgICB2YXIgYnkgPSB5MSArIGR5ICogdGY7CiAgICAgICAgdmFyIGJ1bGdlID0gTWF0aC5zaW4oTWF0aC5QSSAqIHRmKSAqIGFtcDsKICAgICAgICBjb29yZHMucHVzaCh7IHg6IGJ4ICsgcGVycFggKiBidWxnZSwgeTogYnkgKyBwZXJwWSAqIGJ1bGdlIH0pOwogICAgICB9CiAgICB9IGVsc2UgewogICAgICByZXR1cm4gbnVsbDsKICAgIH0KICAgIHJldHVybiBjb29yZHM7CiAgfQoKICAvLyBDb21wdXRlIG91dHdhcmQtYnVsZ2UgZGlyZWN0aW9uIChzaWduICsxIG9yIC0xKSBnaXZlbiBwMSwgcDIsIGFuZCB0aGUKICAvLyBpbnRlcmlvciBjZW50cm9pZC4gVGhlIHNpZ24gdGhhdCBwdXNoZXMgdGhlIGFyYyBBUEVYIGZ1cnRoZXIgZnJvbSB0aGUKICAvLyBjZW50cm9pZCBpcyAib3V0d2FyZCIg4oCUIHRoYXQncyB3aGVyZSB0aGUgaGVhZGxhbmQgc3RyaXAgaXMuCiAgLy8KICAvLyBJTVBPUlRBTlQg4oCUIGZvciBhIFUtdHVybiBhcmMgYnVpbHQgYnkgYnVpbGRBcmMoLi4uKSB3aXRoIHNpZ24gcywgdGhlIGFwZXgKICAvLyAoYXQgcGFyYW1ldHJpYyB0PTAuNSkgaXMgYXQgY2hvcmQtbWlkcG9pbnQgKyByYWRpdXPCtyh1ecK3cywgLXV4wrdzKSDigJQgTk9UCiAgLy8gcGVycGVuZGljdWxhciA9ICgtdXnCt3MsIHV4wrdzKS4gVGhlIGJ1aWxkQXJjIGFwZXggbWF0aCBzd2VlcHMgZnJvbSB0aGUKICAvLyBhbmdsZSBvZiB2ZWN0b3IobWlkcG9pbnQg4oaSIHAxKSByb3RhdGVkIGJ5ICvPgC8ywrdzLCB3aGljaCBuZWdhdGVzIHRoZQogIC8vIHBlcnBlbmRpY3VsYXIgcmVsYXRpdmUgdG8gY2hvcmQgZGlyZWN0aW9uLiBVc2UgKHV5LCAtdXgpIGhlcmUgc28gdGhlCiAgLy8gcmV0dXJuZWQgc2lnbiBhY3R1YWxseSBtYXRjaGVzIHRoZSBhcmMncyBidWxnZSBkaXJlY3Rpb24uCiAgZnVuY3Rpb24gb3V0d2FyZFNpZ24oeDEsIHkxLCB4MiwgeTIsIGludGVyaW9yQ2VudGVyWCwgaW50ZXJpb3JDZW50ZXJZLCByYWRpdXNNKXsKICAgIHZhciBtaWRYID0gKHgxICsgeDIpICogMC41OwogICAgdmFyIG1pZFkgPSAoeTEgKyB5MikgKiAwLjU7CiAgICB2YXIgZHggPSB4MiAtIHgxLCBkeSA9IHkyIC0geTE7CiAgICB2YXIgZCA9IE1hdGguc3FydChkeCpkeCArIGR5KmR5KTsKICAgIGlmKGQgPCAxZS02KSByZXR1cm4gMTsKICAgIHZhciB1eCA9IGR4IC8gZCwgdXkgPSBkeSAvIGQ7CiAgICAvLyBBcGV4IG9mZnNldCBhdCBzaWduPSsxOiAodXksIC11eCkgwrcgcmFkaXVzCiAgICB2YXIgYXBleFB4ID0gbWlkWCArIHV5ICogcmFkaXVzTTsKICAgIHZhciBhcGV4UHkgPSBtaWRZIC0gdXggKiByYWRpdXNNOwogICAgdmFyIGQxID0gKGFwZXhQeCAtIGludGVyaW9yQ2VudGVyWCkgKiAoYXBleFB4IC0gaW50ZXJpb3JDZW50ZXJYKSArIChhcGV4UHkgLSBpbnRlcmlvckNlbnRlclkpICogKGFwZXhQeSAtIGludGVyaW9yQ2VudGVyWSk7CiAgICAvLyBBcGV4IG9mZnNldCBhdCBzaWduPS0xOiAoLXV5LCB1eCkgwrcgcmFkaXVzCiAgICB2YXIgYXBleE14ID0gbWlkWCAtIHV5ICogcmFkaXVzTTsKICAgIHZhciBhcGV4TXkgPSBtaWRZICsgdXggKiByYWRpdXNNOwogICAgdmFyIGQyID0gKGFwZXhNeCAtIGludGVyaW9yQ2VudGVyWCkgKiAoYXBleE14IC0gaW50ZXJpb3JDZW50ZXJYKSArIChhcGV4TXkgLSBpbnRlcmlvckNlbnRlclkpICogKGFwZXhNeSAtIGludGVyaW9yQ2VudGVyWSk7CiAgICByZXR1cm4gZDEgPj0gZDIgPyAxIDogLTE7CiAgfQoKICAvLyBCdWlsZCBhIHR1cm4gYXJjIHdpdGggdGhlIHZhbGlkYXRpb24gY2FzY2FkZSBkZXNjcmliZWQgaW4gUlVMRVMubWQgwqc1LgogIC8vIFJldHVybnMgeyBjb29yZHMsIHN0eWxlLCByYWRpdXMsIG9rLCByZWFzb24gfSB3aGVyZSBjb29yZHMgaXMgbnVsbCBvbgogIC8vIHRvdGFsIGZhaWx1cmUuIGBvaz1mYWxzZWAgd2l0aCBhIGNvb3JkcyBhcnJheSBtZWFucyAiYmVzdC1lZmZvcnQgZmFsbGJhY2ssCiAgLy8gc3VyZmFjZSB0aGUgcmVhc29uIHRvIHRoZSB1c2VyIi4KICBmdW5jdGlvbiBidWlsZFR1cm5BcmMocDEsIHAyLCBkcml2YWJsZSwgaW50ZXJpb3IsIHByZWZlcnJlZFN0eWxlLCB0dXJuUmFkaXVzTSwgaGFsZkltcGxlbWVudE0sIHdNKXsKICAgIHZhciBkeCA9IHAyLnggLSBwMS54LCBkeSA9IHAyLnkgLSBwMS55OwogICAgdmFyIGQgPSBNYXRoLnNxcnQoZHgqZHggKyBkeSpkeSk7CiAgICBpZihkIDwgMC4xKSByZXR1cm4geyBjb29yZHM6IG51bGwsIHN0eWxlOiBwcmVmZXJyZWRTdHlsZSwgcmFkaXVzOiAwLCBvazogZmFsc2UsIHJlYXNvbjogJ3Bhc3MgZW5kcG9pbnRzIGNvaW5jaWRlJyB9OwogICAgLy8gQ2hvcmQgdG9vIGxvbmcgZm9yIGEgY2xlYW4gVS10dXJuIChlLmcuLCBjb25zZWN1dGl2ZSBwYXNzIGVuZHBvaW50cyBsYW5kCiAgICAvLyBhdCB2ZXJ5IGRpZmZlcmVudCBhbG9uZy1heGlzIHBvc2l0aW9ucyBiZWNhdXNlIHRoZSBib3VuZGFyeSBjdXJ2ZXMKICAgIC8vIGJldHdlZW4gdGhlbSkuIEEgaGFsZi1jaXJjbGUgd2l0aCByYWRpdXMgZC8yIHdvdWxkIGJlIGh1Z2UgYW5kIGNsZWFybHkKICAgIC8vIGV4aXQgdGhlIGZpZWxkLiBSZWFsIHByYWN0aWNlOiBvcGVyYXRvciBwaXZvdHMgc21hbGwgYXQgcGFzcy1BIGVuZCwKICAgIC8vIGRyaXZlcyBhbG9uZyB0aGUgd29ya2VkIGhlYWRsYW5kIHN0cmlwIHRvIHBhc3MtQiBzdGFydCwgcGl2b3RzIHNtYWxsIGF0CiAgICAvLyBwYXNzLUIgc3RhcnQuIFJlcHJlc2VudCB0aGlzIGFzIGEgc3RyYWlnaHQgY29ubmVjdG9yIChubyBzeW50aGV0aWMgYXJjKQogICAgLy8g4oCUIHZpc3VhbGx5IGEgc2hvcnQgaGVhZGxhbmQgdHJhdmVyc2UgbGluZSwgYWdyb25vbWljYWxseSBjb3JyZWN0LgogICAgdmFyIG1heFJlYXNvbmFibGVDaG9yZCA9IHdNICogMi41OwogICAgaWYoZCA+IG1heFJlYXNvbmFibGVDaG9yZCl7CiAgICAgIHJldHVybiB7IGNvb3JkczogbnVsbCwgc3R5bGU6ICd0cmF2ZXJzZScsIHJhZGl1czogMCwgb2s6IHRydWUsIHJlYXNvbjogbnVsbCB9OwogICAgfQogICAgLy8gT3V0d2FyZCByZWZlcmVuY2U6IGludGVyaW9yIGNlbnRyb2lkLCBmYWxscyBiYWNrIHRvIGRyaXZhYmxlIGNlbnRyb2lkLgogICAgdmFyIHJlZiA9IGludGVyaW9yID8gaW50ZXJpb3IgOiBkcml2YWJsZTsKICAgIHZhciBjeCA9IDAsIGN5ID0gMDsKICAgIGZvcih2YXIgaT0wOyBpPHJlZi5sZW5ndGg7IGkrKyl7IGN4ICs9IHJlZltpXS54OyBjeSArPSByZWZbaV0ueTsgfQogICAgY3ggLz0gcmVmLmxlbmd0aDsgY3kgLz0gcmVmLmxlbmd0aDsKICAgIC8vIFUtdHVybiByYWRpdXMgaXMgZ2VvbWV0cmljYWxseSBmb3JjZWQgdG8gY2hvcmQvMiAoaGFsZi1jaXJjbGUgdGhyb3VnaAogICAgLy8gdGhlIHR3byBwYXNzIGVuZHBvaW50cykuIElmIGNob3JkLzIgaXMgVElHSFRFUiB0aGFuIHRoZSB1c2VyJ3MgbWluaW11bQogICAgLy8gdHVybiByYWRpdXMgKD0gZXF1aXBtZW50IGNhbid0IHBoeXNpY2FsbHkgdHVybiB0aGF0IHNoYXJwKSwgc2tpcCB0aGUKICAgIC8vIGFyYyBhbmQgdXNlIGEgdHJhdmVyc2UgaW5zdGVhZCDigJQgb3BlcmF0b3IgZG9lcyBhIHBpdm90ICsgZHJpdmVzIGFjcm9zcwogICAgLy8gdGhlIGhlYWRsYW5kLiBUaGlzIG1ha2VzICJNaW4gdHVybiByYWRpdXMiIGFjdHVhbGx5IG1hdHRlcjogaW5jcmVhc2luZwogICAgLy8gaXQgZm9yY2VzIG1vcmUgdHJhbnNpdGlvbnMgdG8gdHJhdmVyc2VzLgogICAgaWYoZCAqIDAuNSA8IHR1cm5SYWRpdXNNKXsKICAgICAgcmV0dXJuIHsgY29vcmRzOiBudWxsLCBzdHlsZTogJ3RyYXZlcnNlJywgcmFkaXVzOiAwLCBvazogdHJ1ZSwgcmVhc29uOiBudWxsIH07CiAgICB9CiAgICB2YXIgY2FuZHMgPSBbCiAgICAgIHsgc3R5bGU6ICd1dHVybicsIHJhZGl1czogZCAqIDAuNSB9CiAgICBdOwogICAgLy8gUnVsZSDCpzE0IOKAlCBtYWNoaW5lICsgZXF1aXBtZW50IG11c3Qgc3RheSBpbnNpZGUgdGhlIGZpZWxkIGJvdW5kYXJ5IGV2ZW4KICAgIC8vIGR1cmluZyB0aGUgYXJjLiBWYWxpZGF0ZSBhZ2FpbnN0IGRyaXZhYmxlIElOU0VUIGJ5IGhhbGYtaW1wbGVtZW50LXdpZHRoCiAgICAvLyBzbyB0aGUgZXF1aXBtZW50IGVkZ2UgKG5vdCBqdXN0IHRoZSBjZW50cmVsaW5lKSBuZXZlciBjcm9zc2VzIHRoZQogICAgLy8gYm91bmRhcnkuIFVzZSBhIHNvZnRlbmVkIGluc2V0ICgwLjUgw5cgaGFsZkltcGwpIGJlY2F1c2UgdGhlIHBvbHlnb24KICAgIC8vIG1pdGVyLWNsYW1wIGNhbiBvdmVyLWluc2V0IGF0IG9idHVzZSBjb3JuZXJzLCByZWplY3RpbmcgYXJjcyB0aGF0CiAgICAvLyBwaHlzaWNhbGx5IGZpdC4gVGhlIGltcGxlbWVudCBlZGdlIHN0aWxsIGVmZmVjdGl2ZWx5IHN0YXlzIGluc2lkZSDigJQKICAgIC8vIHJlYWwgb3BlcmF0b3JzIGRyaXZlIHdpdGggfmhhbGYgdGhlIGltcGxlbWVudCB3aWR0aCBhcyB0b2xlcmFuY2UsIG5vdAogICAgLy8gdGhlIGZ1bGwgd2lkdGguCiAgICB2YXIgc2FmZU1hcmdpbiA9IGhhbGZJbXBsZW1lbnRNICogMC41OwogICAgdmFyIHNhZmUgPSBzYWZlTWFyZ2luID4gMCA\/IG9mZnNldFBvbHlnb25JbndhcmQoZHJpdmFibGUsIHNhZmVNYXJnaW4pIDogZHJpdmFibGU7CiAgICBpZighc2FmZSA\/IHRydWUgOiBzYWZlLmxlbmd0aCA8IDQpIHNhZmUgPSBkcml2YWJsZTsKICAgIC8vIFUtdHVybnMgYXJlIEFMV0FZUyBvdXR3YXJkIOKAlCBpbnRvIHRoZSBoZWFkbGFuZCBzdHJpcCwgYXdheSBmcm9tIHRoZQogICAgLy8gd29ya2VkIGludGVyaW9yLiBOZXZlciBidWxnZSBpbndhcmQgKHRoYXQgd291bGQgcmUtd29yayBjb3ZlcmVkIGdyb3VuZCkuCiAgICB2YXIgcHJlZmVyU2lnbiA9IG91dHdhcmRTaWduKHAxLngsIHAxLnksIHAyLngsIHAyLnksIGN4LCBjeSwgZCAqIDAuNSk7CiAgICAvLyBTdHJpY3QgcGFzczogbWFjaGluZSBmb290cHJpbnQgaW5zaWRlIGJvdW5kYXJ5IEFORCBtaWRkbGUgNzAlIGF2b2lkcyB3b3JrZWQgaW50ZXJpb3IKICAgIGZvcih2YXIgYzE9MDsgYzE8Y2FuZHMubGVuZ3RoOyBjMSsrKXsKICAgICAgdmFyIGNhbmQgPSBjYW5kc1tjMV07CiAgICAgIHZhciBhcmMgPSBidWlsZEFyYyhwMS54LCBwMS55LCBwMi54LCBwMi55LCBjYW5kLnN0eWxlLCBjYW5kLnJhZGl1cywgcHJlZmVyU2lnbik7CiAgICAgIGlmKCFhcmMpIGNvbnRpbnVlOwogICAgICBpZighYXJjSW5zaWRlUG9seShhcmMsIHNhZmUpKSBjb250aW51ZTsKICAgICAgaWYoIWFyY0F2b2lkc0ludGVyaW9yKGFyYywgaW50ZXJpb3IpKSBjb250aW51ZTsKICAgICAgcmV0dXJuIHsgY29vcmRzOiBhcmMsIHN0eWxlOiBjYW5kLnN0eWxlLCByYWRpdXM6IGNhbmQucmFkaXVzLCBvazogdHJ1ZSwgcmVhc29uOiBudWxsIH07CiAgICB9CiAgICAvLyBSZWxheGVkIHBhc3M6IG91dHdhcmQgc3RpbGwsIG1hY2hpbmUgZm9vdHByaW50IHN0aWxsIGluc2lkZSBib3VuZGFyeSwKICAgIC8vIGp1c3QgYWxsb3cgdGhlIGFyYyB0byBkaXAgcGFzdCB0aGUgaGVhZGxhbmQgZWRnZSBpbnRvIHRoZSB3b3JrZWQgem9uZS4KICAgIGZvcih2YXIgYzI9MDsgYzI8Y2FuZHMubGVuZ3RoOyBjMisrKXsKICAgICAgdmFyIGNhbmQyID0gY2FuZHNbYzJdOwogICAgICB2YXIgYXJjMiA9IGJ1aWxkQXJjKHAxLngsIHAxLnksIHAyLngsIHAyLnksIGNhbmQyLnN0eWxlLCBjYW5kMi5yYWRpdXMsIHByZWZlclNpZ24pOwogICAgICBpZighYXJjMikgY29udGludWU7CiAgICAgIGlmKCFhcmNJbnNpZGVQb2x5KGFyYzIsIHNhZmUpKSBjb250aW51ZTsKICAgICAgcmV0dXJuIHsKICAgICAgICBjb29yZHM6IGFyYzIsIHN0eWxlOiBjYW5kMi5zdHlsZSwgcmFkaXVzOiBjYW5kMi5yYWRpdXMsCiAgICAgICAgb2s6IGZhbHNlLCByZWFzb246ICdVLXR1cm4gZGlwcyBpbnRvIHdvcmtlZCB6b25lIOKAlCB3aWRlbiBoZWFkbGFuZCBzdHJpcC4nCiAgICAgIH07CiAgICB9CiAgICAvLyBMYXN0IHJlc29ydCDigJQgbm8gb3V0d2FyZCBhcmMgZml0cyBpbnNpZGUgdGhlIGJvdW5kYXJ5LiBSdWxlIMKnMTQgc2F5cwogICAgLy8gdGhlIG1hY2hpbmUgbXVzdCBzdGF5IGluc2lkZSB0aGUgZmllbGQsIHNvIERPIE5PVCBlbWl0IGFuIGFyYyB0aGF0CiAgICAvLyB3b3VsZCBjbGVhcmx5IGxlYXZlLiBSZXR1cm4gYSB0cmF2ZXJzZSBpbnN0ZWFkIOKAlCB0aGUgY2FsbGVyIHJvdXRlcyBpdAogICAgLy8gYWxvbmcgdGhlIGhlYWRsYW5kIHJpbmcuIE9wZXJhdG9yIHNlZXMgYSB3YXJuaW5nICsgYSByaW5nLXJvdXRlZCBwYXRoCiAgICAvLyBpbnN0ZWFkIG9mIGEgcGhhbnRvbSBhcmMgZXhpdGluZyB0aGUgZmllbGQuCiAgICByZXR1cm4gewogICAgICBjb29yZHM6IG51bGwsIHN0eWxlOiAndHJhdmVyc2UnLCByYWRpdXM6IDAsCiAgICAgIG9rOiBmYWxzZSwgcmVhc29uOiAnTm8gdHVybiBmaXRzIGluc2lkZSBmaWVsZCBib3VuZGFyeSDigJQgcm91dGluZyBhbG9uZyB0aGUgaGVhZGxhbmQgcmluZyBpbnN0ZWFkLicKICAgIH07CiAgfQoKICAvLyBCdWlsZCB0aGUgZHJpdmFibGUgcG9seWdvbiA9IGJvdW5kYXJ5ICsgb3V0c2lkZUJ1ZmZlck0gb3V0d2FyZCBvZmZzZXQuCiAgLy8gRm9yIHRoZSBsZWFkLW1hZ25ldCBNVlAgdGhlcmUgYXJlIG5vIG9ic3RhY2xlcywgc28gdGhpcyBpcyBqdXN0IGJvdW5kYXJ5CiAgLy8gZGlsYXRpb24uIFdpdGggdHVybkJ1Zj0wLCBkcml2YWJsZSA9PT0gYm91bmRhcnkuCiAgZnVuY3Rpb24gYnVpbGREcml2YWJsZShiLCBvdXRzaWRlQnVmZmVyTSl7CiAgICBpZihvdXRzaWRlQnVmZmVyTSA8PSAwKSByZXR1cm4gYjsKICAgIC8vIE91dHdhcmQgb2Zmc2V0ID0gaW53YXJkIG9mZnNldCB3aXRoIG5lZ2F0ZWQgZGlzdGFuY2UuIE5lZ2F0ZSBpbndhcmQgYnkKICAgIC8vIGZsaXBwaW5nIHRoZSB3aW5kaW5nIHNpZ24gY29udmVudGlvbjogcmV1c2Ugb2Zmc2V0UG9seWdvbklud2FyZCB3aXRoCiAgICAvLyBuZWdhdGl2ZSBkaXN0TSDigJQgYnV0IHRoZSBmdW5jdGlvbiBjbGFtcHMgbWluIHZlcnRpY2VzIGV0Yywgc28gZG8gbWFudWFsLgogICAgdmFyIG4gPSBiLmxlbmd0aDsKICAgIHZhciBzaG9lbGFjZSA9IDA7CiAgICBmb3IodmFyIGk9MDsgaTxuOyBpKyspewogICAgICB2YXIgaiA9IChpICsgMSkgJSBuOwogICAgICBzaG9lbGFjZSArPSBiW2ldLnggKiBiW2pdLnkgLSBiW2pdLnggKiBiW2ldLnk7CiAgICB9CiAgICB2YXIgd2luZGluZyA9IHNob2VsYWNlID4gMCA\/IDEgOiAtMTsKICAgIHZhciBvdXQgPSBbXTsKICAgIGZvcih2YXIgdj0wOyB2PG47IHYrKyl7CiAgICAgIHZhciBwSWR4ID0gKHYgLSAxICsgbikgJSBuOwogICAgICB2YXIgbklkeCA9ICh2ICsgMSkgJSBuOwogICAgICB2YXIgZTF4ID0gYlt2XS54IC0gYltwSWR4XS54OwogICAgICB2YXIgZTF5ID0gYlt2XS55IC0gYltwSWR4XS55OwogICAgICB2YXIgZTJ4ID0gYltuSWR4XS54IC0gYlt2XS54OwogICAgICB2YXIgZTJ5ID0gYltuSWR4XS55IC0gYlt2XS55OwogICAgICB2YXIgbDEgPSBNYXRoLnNxcnQoZTF4KmUxeCArIGUxeSplMXkpOwogICAgICB2YXIgbDIgPSBNYXRoLnNxcnQoZTJ4KmUyeCArIGUyeSplMnkpOwogICAgICBpZihsMSA8IDFlLTkgPyB0cnVlIDogbDIgPCAxZS05KXsgb3V0LnB1c2goeyB4OiBiW3ZdLngsIHk6IGJbdl0ueSB9KTsgY29udGludWU7IH0KICAgICAgLy8gT1VUV0FSRCBub3JtYWwgPSAtaW53YXJkCiAgICAgIHZhciBuMXggPSBlMXkgLyBsMSAqIHdpbmRpbmcsIG4xeSA9IC1lMXggLyBsMSAqIHdpbmRpbmc7CiAgICAgIHZhciBuMnggPSBlMnkgLyBsMiAqIHdpbmRpbmcsIG4yeSA9IC1lMnggLyBsMiAqIHdpbmRpbmc7CiAgICAgIHZhciBieHYgPSBuMXggKyBuMngsIGJ5diA9IG4xeSArIG4yeTsKICAgICAgdmFyIGJsID0gTWF0aC5zcXJ0KGJ4dipieHYgKyBieXYqYnl2KTsKICAgICAgaWYoYmwgPCAxZS02KXsgb3V0LnB1c2goeyB4OiBiW3ZdLnggKyBuMXggKiBvdXRzaWRlQnVmZmVyTSwgeTogYlt2XS55ICsgbjF5ICogb3V0c2lkZUJ1ZmZlck0gfSk7IGNvbnRpbnVlOyB9CiAgICAgIHZhciBjb3NGdWxsID0gbjF4ICogbjJ4ICsgbjF5ICogbjJ5OwogICAgICB2YXIgc2luSGFsZiA9IE1hdGguc3FydCgoMSAtIGNvc0Z1bGwpICogMC41KTsKICAgICAgaWYoc2luSGFsZiA8IDAuMSkgc2luSGFsZiA9IDAuMTsKICAgICAgb3V0LnB1c2goeyB4OiBiW3ZdLnggKyAoYnh2IC8gYmwpICogKG91dHNpZGVCdWZmZXJNIC8gc2luSGFsZiksIHk6IGJbdl0ueSArIChieXYgLyBibCkgKiAob3V0c2lkZUJ1ZmZlck0gLyBzaW5IYWxmKSB9KTsKICAgIH0KICAgIHJldHVybiBvdXQ7CiAgfQoKICAvLyBSZXR1cm5zIHt4MCwgeTAsIHgxLCB5MX0gb3JpZW50ZWQgc28gY29vcmRzWzBdIGlzIHRoZSBsb3dlciBhbG9uZy1heGlzIHByb2plY3Rpb24uCiAgZnVuY3Rpb24gb3JpZW50U2VnKHNlZywgYXhpcyl7CiAgICB2YXIgcDBBbG9uZyA9IHNlZy54MCAqIGF4aXMudXggKyBzZWcueTAgKiBheGlzLnV5OwogICAgdmFyIHAxQWxvbmcgPSBzZWcueDEgKiBheGlzLnV4ICsgc2VnLnkxICogYXhpcy51eTsKICAgIGlmKHAwQWxvbmcgPD0gcDFBbG9uZykgcmV0dXJuIHNlZzsKICAgIHJldHVybiB7IHgwOiBzZWcueDEsIHkwOiBzZWcueTEsIHgxOiBzZWcueDAsIHkxOiBzZWcueTAsIGtpbmQ6IHNlZy5raW5kLCBzYW1wbGVzOiBzZWcuc2FtcGxlcyB9OwogIH0KCiAgLy8gUnVsZSDCpzE0IGhlbHBlciDigJQgc2FtcGxlIHRoZSBzdHJhaWdodCBjaG9yZCBiZXR3ZWVuIHR3byBwb2ludHMgYW5kIGNoZWNrCiAgLy8gZXZlcnkgc2FtcGxlIGlzIGluc2lkZSBgcG9seWAuIFVzZWQgdG8gdmFsaWRhdGUgYSB0cmF2ZXJzZSBiZWZvcmUKICAvLyBhY2NlcHRpbmcgaXQ7IGlmIGZhbHNlLCB0aGUgb3BlcmF0b3Igd291bGQgbGVhdmUgdGhlIGZpZWxkIGJvdW5kYXJ5LgogIGZ1bmN0aW9uIHRyYXZlcnNlSW5zaWRlQm91bmRhcnkocDEsIHAyLCBwb2x5KXsKICAgIHZhciBOID0gMTI7CiAgICBmb3IodmFyIGk9MTsgaTxOOyBpKyspewogICAgICB2YXIgdCA9IGkgLyBOOwogICAgICB2YXIgeCA9IHAxLnggKyAocDIueCAtIHAxLngpICogdDsKICAgICAgdmFyIHkgPSBwMS55ICsgKHAyLnkgLSBwMS55KSAqIHQ7CiAgICAgIGlmKCFwb2ludEluUG9seSh4LCB5LCBwb2x5KSkgcmV0dXJuIGZhbHNlOwogICAgfQogICAgcmV0dXJuIHRydWU7CiAgfQogIC8vIFJvdXRlIGZyb20gcDEgdG8gcDIgYWxvbmcgdGhlIGhlYWRsYW5kLXJpbmcgcGVyaW1ldGVyIOKAlCB0aGUgYWdyb25vbWljYWxseQogIC8vIGNvcnJlY3QgcGF0aCB3aGVuIHRoZSBzdHJhaWdodCBjaG9yZCB3b3VsZCBleGl0IHRoZSBib3VuZGFyeS4gRmluZHMgdGhlCiAgLy8gY2xvc2VzdCByaW5nIHZlcnRleCB0byBlYWNoIGVuZHBvaW50LCB3YWxrcyB0aGUgcmluZyBpbiB0aGUgc2hvcnRlcgogIC8vIGRpcmVjdGlvbi4gUmV0dXJucyB0aGUgZnVsbCB2ZXJ0ZXggc2VxdWVuY2UgW3AxLCByaW5nVmVydHMuLi4sIHAyXSBvcgogIC8vIFtwMSwgcDJdIGlmIG5vIHJpbmcgaXMgYXZhaWxhYmxlLgogIGZ1bmN0aW9uIHJvdXRlQWxvbmdSaW5nKHAxLCBwMiwgcmluZ1Bhc3Nlcyl7CiAgICBpZighcmluZ1Bhc3NlcyA\/IHRydWUgOiByaW5nUGFzc2VzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIFtwMSwgcDJdOwogICAgdmFyIHJpbmcgPSByaW5nUGFzc2VzWzBdLnNhbXBsZXM7CiAgICBpZighcmluZyA\/IHRydWUgOiByaW5nLmxlbmd0aCA8IDQpIHJldHVybiBbcDEsIHAyXTsKICAgIC8vIENsb3NlZC1sb29wOiBsYXN0IHNhbXBsZSA9PSBmaXJzdCBzYW1wbGU7IHdvcmsgd2l0aCB1bmlxdWUgdmVydGljZXMgb25seS4KICAgIHZhciBOID0gcmluZy5sZW5ndGggLSAocmluZ1swXS54ID09PSByaW5nW3JpbmcubGVuZ3RoLTFdLnggPyByaW5nWzBdLnkgPT09IHJpbmdbcmluZy5sZW5ndGgtMV0ueSA\/IDEgOiAwIDogMCk7CiAgICBmdW5jdGlvbiBuZWFyZXN0SWR4KHApewogICAgICB2YXIgYmVzdCA9IDAsIGJlc3REID0gSW5maW5pdHk7CiAgICAgIGZvcih2YXIgaT0wOyBpPE47IGkrKyl7CiAgICAgICAgdmFyIGR4ID0gcmluZ1tpXS54IC0gcC54LCBkeSA9IHJpbmdbaV0ueSAtIHAueTsKICAgICAgICB2YXIgZCA9IGR4KmR4ICsgZHkqZHk7CiAgICAgICAgaWYoZCA8IGJlc3REKXsgYmVzdEQgPSBkOyBiZXN0ID0gaTsgfQogICAgICB9CiAgICAgIHJldHVybiBiZXN0OwogICAgfQogICAgdmFyIGkxID0gbmVhcmVzdElkeChwMSk7CiAgICB2YXIgaTIgPSBuZWFyZXN0SWR4KHAyKTsKICAgIGlmKGkxID09PSBpMikgcmV0dXJuIFtwMSwgcmluZ1tpMV0sIHAyXTsKICAgIC8vIENvbXB1dGUgZGlzdGFuY2Ugd2Fsa2luZyBmb3J3YXJkIChpMSDihpIgaTIpIGFuZCBiYWNrd2FyZCAoaTEg4oaSIGkyIHRoZSBvdGhlciB3YXkpCiAgICBmdW5jdGlvbiByaW5nRGlzdChmcm9tLCB0byl7CiAgICAgIHZhciBkID0gMDsKICAgICAgdmFyIGsgPSBmcm9tOwogICAgICB3aGlsZShrICE9PSB0byl7CiAgICAgICAgdmFyIGtOZXh0ID0gKGsgKyAxKSAlIE47CiAgICAgICAgdmFyIGR4ID0gcmluZ1trTmV4dF0ueCAtIHJpbmdba10ueCwgZHkgPSByaW5nW2tOZXh0XS55IC0gcmluZ1trXS55OwogICAgICAgIGQgKz0gTWF0aC5zcXJ0KGR4KmR4ICsgZHkqZHkpOwogICAgICAgIGsgPSBrTmV4dDsKICAgICAgfQogICAgICByZXR1cm4gZDsKICAgIH0KICAgIHZhciBmd2QgPSByaW5nRGlzdChpMSwgaTIpOwogICAgdmFyIGJ3ZCA9IHJpbmdEaXN0KGkyLCBpMSk7CiAgICB2YXIgcGF0aCA9IFtwMSwgcmluZ1tpMV1dOwogICAgaWYoZndkIDw9IGJ3ZCl7CiAgICAgIHZhciBrID0gKGkxICsgMSkgJSBOOwogICAgICB3aGlsZShrICE9PSBpMil7IHBhdGgucHVzaChyaW5nW2tdKTsgayA9IChrICsgMSkgJSBOOyB9CiAgICB9IGVsc2UgewogICAgICB2YXIgazIgPSAoaTEgLSAxICsgTikgJSBOOwogICAgICB3aGlsZShrMiAhPT0gaTIpeyBwYXRoLnB1c2gocmluZ1trMl0pOyBrMiA9IChrMiAtIDEgKyBOKSAlIE47IH0KICAgIH0KICAgIHBhdGgucHVzaChyaW5nW2kyXSk7CiAgICBwYXRoLnB1c2gocDIpOwogICAgcmV0dXJuIHBhdGg7CiAgfQoKICAvLyBCdWlsZCBzZXJwZW50aW5lIGRyaXZlIHBhdGg6IHNuYWtlIHRocm91Z2ggcGFzc2VzLCBnZW5lcmF0ZSB2YWxpZGF0ZWQgdHVybgogIC8vIGFyY3MgYmV0d2VlbiBjb25zZWN1dGl2ZSBlbmRwb2ludHMuIFJldHVybnMgeyBkcml2ZUNvb3JkcywgdHVybkFyY3MsIHdhcm5pbmcgfS4KICBmdW5jdGlvbiBidWlsZFNlcnBlbnRpbmUocGFzc2VzLCBkcml2YWJsZSwgaW50ZXJpb3IsIGF4aXMsIHR1cm5TdHlsZSwgdHVyblJhZGl1c00sIGhhbGZJbXBsZW1lbnRNLCB3TSl7CiAgICBpZighcGFzc2VzID8gdHJ1ZSA6IHBhc3Nlcy5sZW5ndGggPT09IDApIHJldHVybiB7IGRyaXZlQ29vcmRzOiBbXSwgdHVybkFyY3M6IFtdLCB3YXJuaW5nOiBudWxsIH07CiAgICAvLyBTZXBhcmF0ZSBoZWFkbGFuZC1yaW5nIHBhc3NlcyAocnVsZSDCpzEzIOKAlCBkcml2ZW4gZmlyc3QgYXMgY2xvc2VkIGxvb3BzLAogICAgLy8gbm8gc2VycGVudGluZSwgbm8gdHVybiBhcmNzKSBmcm9tIGJvZHkgcGFzc2VzIHRoYXQgZ28gdGhyb3VnaCBzZXJwZW50aW5lLgogICAgdmFyIHJpbmdQYXNzZXMgPSBbXTsKICAgIHZhciBib2R5UGFzc2VzID0gW107CiAgICBmb3IodmFyIHJpPTA7IHJpPHBhc3Nlcy5sZW5ndGg7IHJpKyspewogICAgICBpZihwYXNzZXNbcmldLmtpbmQgPT09ICdoZWFkbGFuZC1yaW5nJykgcmluZ1Bhc3Nlcy5wdXNoKHBhc3Nlc1tyaV0pOwogICAgICBlbHNlIGJvZHlQYXNzZXMucHVzaChwYXNzZXNbcmldKTsKICAgIH0KICAgIC8vIE9yaWVudCArIHNvcnQgQk9EWSBwYXNzZXMgYnkgYWxvbmctYXhpcyBwb3NpdGlvbiBvZiBtaWRwb2ludAogICAgdmFyIG9yaWVudCA9IGJvZHlQYXNzZXMubWFwKGZ1bmN0aW9uKHApewogICAgICBpZihwLnNhbXBsZXMpewogICAgICAgIHZhciBmaXJzdCA9IHAuc2FtcGxlc1swXSwgbGFzdCA9IHAuc2FtcGxlc1twLnNhbXBsZXMubGVuZ3RoIC0gMV07CiAgICAgICAgdmFyIGEwID0gZmlyc3QueCAqIGF4aXMudXggKyBmaXJzdC55ICogYXhpcy51eTsKICAgICAgICB2YXIgYTEgPSBsYXN0LnggKiBheGlzLnV4ICsgbGFzdC55ICogYXhpcy51eTsKICAgICAgICBpZihhMCA8PSBhMSkgcmV0dXJuIHsgc2FtcGxlczogcC5zYW1wbGVzIH07CiAgICAgICAgdmFyIHJldiA9IHAuc2FtcGxlcy5zbGljZSgpLnJldmVyc2UoKTsKICAgICAgICByZXR1cm4geyBzYW1wbGVzOiByZXYgfTsKICAgICAgfQogICAgICByZXR1cm4gb3JpZW50U2VnKHAsIGF4aXMpOwogICAgfSk7CiAgICBvcmllbnQuc29ydChmdW5jdGlvbihhLCBiKXsKICAgICAgdmFyIGF4ID0gYS5zYW1wbGVzID8gYS5zYW1wbGVzWzBdLnggOiBhLngwOwogICAgICB2YXIgYXkgPSBhLnNhbXBsZXMgPyBhLnNhbXBsZXNbMF0ueSA6IGEueTA7CiAgICAgIHZhciBieCA9IGIuc2FtcGxlcyA\/IGIuc2FtcGxlc1swXS54IDogYi54MDsKICAgICAgdmFyIGJ5ID0gYi5zYW1wbGVzID8gYi5zYW1wbGVzWzBdLnkgOiBiLnkwOwogICAgICB2YXIgYXAgPSAtYXggKiBheGlzLnV5ICsgYXkgKiBheGlzLnV4OwogICAgICB2YXIgYnAgPSAtYnggKiBheGlzLnV5ICsgYnkgKiBheGlzLnV4OwogICAgICByZXR1cm4gYXAgLSBicDsKICAgIH0pOwogICAgdmFyIGRyaXZlQ29vcmRzID0gW107CiAgICB2YXIgdHVybkFyY3MgPSBbXTsKICAgIHZhciB3YXJuaW5nID0gbnVsbDsKICAgIHZhciBvcmRlcmVkUGFzc2VzID0gW107ICAvLyBib2R5IHBhc3NlcyBpbiBhY3R1YWwgZHJpdmUgZGlyZWN0aW9uIChwb3N0LXNuYWtlKQogICAgLy8gSGVhZGxhbmQgcmluZyhzKSBGSVJTVCDigJQgY2xvc2VkLWxvb3AgdHJhdmVyc2FsLCBubyBzZXJwZW50aW5lLCBubyBhcmNzCiAgICBmb3IodmFyIHJnPTA7IHJnPHJpbmdQYXNzZXMubGVuZ3RoOyByZysrKXsKICAgICAgdmFyIHJpbmdTYW1wcyA9IHJpbmdQYXNzZXNbcmddLnNhbXBsZXM7CiAgICAgIGZvcih2YXIgcnM9MDsgcnM8cmluZ1NhbXBzLmxlbmd0aDsgcnMrKykgZHJpdmVDb29yZHMucHVzaChyaW5nU2FtcHNbcnNdKTsKICAgIH0KICAgIC8vIEJvZHkgcGFzc2VzIOKAlCBzZXJwZW50aW5lIHdpdGggdmFsaWRhdGVkIFUtdHVybiBhcmNzIGJldHdlZW4gdGhlbQogICAgZm9yKHZhciBpPTA7IGk8b3JpZW50Lmxlbmd0aDsgaSsrKXsKICAgICAgdmFyIHAgPSBvcmllbnRbaV07CiAgICAgIHZhciByZXYyID0gaSAlIDIgPT09IDE7CiAgICAgIHZhciBmaXJzdDIsIGxhc3QyOwogICAgICBpZihwLnNhbXBsZXMpewogICAgICAgIHZhciBzYW1wcyA9IHJldjIgPyBwLnNhbXBsZXMuc2xpY2UoKS5yZXZlcnNlKCkgOiBwLnNhbXBsZXM7CiAgICAgICAgZm9yKHZhciBzPTA7IHM8c2FtcHMubGVuZ3RoOyBzKyspIGRyaXZlQ29vcmRzLnB1c2goc2FtcHNbc10pOwogICAgICAgIGZpcnN0MiA9IHNhbXBzWzBdOyBsYXN0MiA9IHNhbXBzW3NhbXBzLmxlbmd0aCAtIDFdOwogICAgICAgIG9yZGVyZWRQYXNzZXMucHVzaCh7IHNhbXBsZXM6IHNhbXBzLCBraW5kOiBwLmtpbmQgfSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgaWYocmV2Mil7CiAgICAgICAgICBkcml2ZUNvb3Jkcy5wdXNoKHsgeDogcC54MSwgeTogcC55MSB9KTsKICAgICAgICAgIGRyaXZlQ29vcmRzLnB1c2goeyB4OiBwLngwLCB5OiBwLnkwIH0pOwogICAgICAgICAgZmlyc3QyID0geyB4OiBwLngxLCB5OiBwLnkxIH07IGxhc3QyID0geyB4OiBwLngwLCB5OiBwLnkwIH07CiAgICAgICAgICBvcmRlcmVkUGFzc2VzLnB1c2goeyB4MDogcC54MSwgeTA6IHAueTEsIHgxOiBwLngwLCB5MTogcC55MCwga2luZDogcC5raW5kIH0pOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBkcml2ZUNvb3Jkcy5wdXNoKHsgeDogcC54MCwgeTogcC55MCB9KTsKICAgICAgICAgIGRyaXZlQ29vcmRzLnB1c2goeyB4OiBwLngxLCB5OiBwLnkxIH0pOwogICAgICAgICAgZmlyc3QyID0geyB4OiBwLngwLCB5OiBwLnkwIH07IGxhc3QyID0geyB4OiBwLngxLCB5OiBwLnkxIH07CiAgICAgICAgICBvcmRlcmVkUGFzc2VzLnB1c2goeyB4MDogcC54MCwgeTA6IHAueTAsIHgxOiBwLngxLCB5MTogcC55MSwga2luZDogcC5raW5kIH0pOwogICAgICAgIH0KICAgICAgfQogICAgICBpZih0dXJuU3R5bGUgPT09ICdub25lJyA\/IGZhbHNlIDogKGkgKyAxIDwgb3JpZW50Lmxlbmd0aCkpewogICAgICAgIHZhciBuZXh0UCA9IG9yaWVudFtpICsgMV07CiAgICAgICAgdmFyIG5leHRSZXYgPSAoaSArIDEpICUgMiA9PT0gMTsKICAgICAgICB2YXIgbmV4dFN0YXJ0OwogICAgICAgIGlmKG5leHRQLnNhbXBsZXMpewogICAgICAgICAgdmFyIG5leHRTYW1wcyA9IG5leHRSZXYgPyBuZXh0UC5zYW1wbGVzLnNsaWNlKCkucmV2ZXJzZSgpIDogbmV4dFAuc2FtcGxlczsKICAgICAgICAgIG5leHRTdGFydCA9IG5leHRTYW1wc1swXTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgbmV4dFN0YXJ0ID0gbmV4dFJldiA\/IHsgeDogbmV4dFAueDEsIHk6IG5leHRQLnkxIH0gOiB7IHg6IG5leHRQLngwLCB5OiBuZXh0UC55MCB9OwogICAgICAgIH0KICAgICAgICB2YXIgdHVybiA9IGJ1aWxkVHVybkFyYyhsYXN0MiwgbmV4dFN0YXJ0LCBkcml2YWJsZSwgaW50ZXJpb3IsIHR1cm5TdHlsZSwgdHVyblJhZGl1c00sIGhhbGZJbXBsZW1lbnRNLCB3TSk7CiAgICAgICAgaWYodHVybi5jb29yZHMgPyB0dXJuLmNvb3Jkcy5sZW5ndGggPiAxIDogZmFsc2UpewogICAgICAgICAgZm9yKHZhciB0Yz0xOyB0Yzx0dXJuLmNvb3Jkcy5sZW5ndGg7IHRjKyspIGRyaXZlQ29vcmRzLnB1c2godHVybi5jb29yZHNbdGNdKTsKICAgICAgICAgIHR1cm5BcmNzLnB1c2goeyBjb29yZHM6IHR1cm4uY29vcmRzLCBvazogdHVybi5vaywga2luZDogdHVybi5zdHlsZSB9KTsKICAgICAgICAgIGlmKCF0dXJuLm9rID8gIXdhcm5pbmcgOiBmYWxzZSkgd2FybmluZyA9IHR1cm4ucmVhc29uOwogICAgICAgIH0gZWxzZSBpZih0dXJuLnN0eWxlID09PSAndHJhdmVyc2UnKXsKICAgICAgICAgIC8vIExvbmctY2hvcmQgY2FzZSBPUiBsYXN0LXJlc29ydCBuby1hcmMtZml0cyBjYXNlOiByb3V0ZSB0aGUKICAgICAgICAgIC8vIG9wZXJhdG9yIGFjcm9zcyB0aGUgd29ya2VkIGhlYWRsYW5kLiBSdWxlIMKnMTQg4oCUIHRoZSBzdHJhaWdodAogICAgICAgICAgLy8gY2hvcmQgbWF5IGV4aXQgdGhlIGZpZWxkIGJvdW5kYXJ5IGlmIGl0IGN1dHMgYWNyb3NzIGEgY29uY2F2ZQogICAgICAgICAgLy8gZGVudCAoZS5nLiB0aGUgTC1zaGFwZSdzIG5vdGNoKSBvciBhIGN1cnZlZCBib3VuZGFyeS4gU2FtcGxlCiAgICAgICAgICAvLyB0aGUgY2hvcmQ7IGlmIGFueSBwb2ludCBpcyBvdXRzaWRlIGBkcml2YWJsZWAsIHJvdXRlIGFsb25nIHRoZQogICAgICAgICAgLy8gaGVhZGxhbmQgcmluZyBpbnN0ZWFkLiBPdGhlcndpc2UgdXNlIHRoZSBzdHJhaWdodCBjaG9yZC4KICAgICAgICAgIHZhciBzdHJhaWdodE9LID0gdHJhdmVyc2VJbnNpZGVCb3VuZGFyeShsYXN0MiwgbmV4dFN0YXJ0LCBkcml2YWJsZSk7CiAgICAgICAgICB2YXIgdHJhdmVyc2VDb29yZHMgPSBzdHJhaWdodE9LCiAgICAgICAgICAgID8gW2xhc3QyLCBuZXh0U3RhcnRdCiAgICAgICAgICAgIDogcm91dGVBbG9uZ1JpbmcobGFzdDIsIG5leHRTdGFydCwgcmluZ1Bhc3Nlcyk7CiAgICAgICAgICBpZih0cmF2ZXJzZUNvb3Jkcy5sZW5ndGggPj0gMil7CiAgICAgICAgICAgIGZvcih2YXIgdGMyPTE7IHRjMjx0cmF2ZXJzZUNvb3Jkcy5sZW5ndGg7IHRjMisrKSBkcml2ZUNvb3Jkcy5wdXNoKHRyYXZlcnNlQ29vcmRzW3RjMl0pOwogICAgICAgICAgICB0dXJuQXJjcy5wdXNoKHsgY29vcmRzOiB0cmF2ZXJzZUNvb3Jkcywgb2s6IHRydWUsIGtpbmQ6IHN0cmFpZ2h0T0sgPyAndHJhdmVyc2UnIDogJ3Jpbmctcm91dGUnIH0pOwogICAgICAgICAgICAvLyBTdXJmYWNlIHRoZSBsYXN0LXJlc29ydCByZWFzb24gc28gdGhlIHVzZXIgc2VlcyB3aHkKICAgICAgICAgICAgaWYodHVybi5yZWFzb24gPyAhd2FybmluZyA6IGZhbHNlKSB3YXJuaW5nID0gdHVybi5yZWFzb247CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICByZXR1cm4geyBkcml2ZUNvb3JkczogZHJpdmVDb29yZHMsIHR1cm5BcmNzOiB0dXJuQXJjcywgd2FybmluZzogd2FybmluZywgb3JkZXJlZFBhc3Nlczogb3JkZXJlZFBhc3NlcyB9OwogIH0KCiAgLy8gR2VuZXJhdGUgZ3VpZGFuY2UgbGF5b3V0IGZvciBvbmUgYXBwcm9hY2guIFJldHVybnM6CiAgLy8gICB7IHBhc3NlczogWy4uLl0sIGhlYWRsYW5kUG9seSwgaW50ZXJpb3JQb2x5LCBkcml2YWJsZSwgdHVybkFyY3MsIGRyaXZlUGF0aCwgd2FybmluZyB9CiAgLy8gVGhlIHNtYXJ0IHBpcGVsaW5lOgogIC8vICAgMS4gZHJpdmFibGUgPSBib3VuZGFyeSArIG91dHNpZGVCdWZmZXJNIG91dHdhcmQKICAvLyAgIDIuIGludGVyaW9yID0gYm91bmRhcnkgaW53YXJkLW9mZnNldCBieSBoZWFkbGFuZE0gKHRoZSB3b3JrZWQgem9uZSkKICAvLyAgIDMuIGhlYWRsYW5kID0gYm91bmRhcnkgbWludXMgaW50ZXJpb3IgKHRoZSB0dXJuYXJvdW5kIHpvbmUpCiAgLy8gICA0LiBQYXNzZXMgY2xpcHBlZCB0byBJTlRFUklPUiAobm90IGZ1bGwgYm91bmRhcnkpIOKAlCBlbmRwb2ludHMgc2l0IG9uIHRoZQogIC8vICAgICAgaW5uZXIgZWRnZSBvZiB0aGUgaGVhZGxhbmQgYnkgY29uc3RydWN0aW9uCiAgLy8gICA1LiBTZXJwZW50aW5lIHRocm91Z2ggcGFzc2VzLCBnZW5lcmF0aW5nIHR1cm4gYXJjcyB0aGF0IGJ1bGdlIE9VVFdBUkQKICAvLyAgICAgIGludG8gdGhlIGhlYWRsYW5kIHN0cmlwIHZpYSB0aGUgdmFsaWRhdGlvbiBjYXNjYWRlCiAgLy8gRm9yICdib3VuZGFyeScgYXBwcm9hY2g6IHNraXAgaW50ZXJpb3IgcGFzc2VzLCBnZW5lcmF0ZSBvbmx5IHRoZSBoZWFkbGFuZC0KICAvLyBmb2xsb3dpbmcgcmluZyhzKSDigJQgdXNlZnVsIGZvciBvcmNoYXJkcyAvIGdyYXNzbGFuZHMgd2hlcmUgdGhlIGZpZWxkIGlzCiAgLy8gd29ya2VkIGFsb25nIGl0cyBwZXJpbWV0ZXIuCiAgLy8gVHJhY2UgYSBzaW5nbGUgY29udG91ciBsaW5lIGF0IGNvbnN0YW50IGVsZXZhdGlvbiB1c2luZyBhIHByZWRpY3Rvci0KICAvLyBjb3JyZWN0b3Igc2NoZW1lLiBFYWNoIHN0ZXA6CiAgLy8gICBQUkVESUNUIOKAlCBtb3ZlIHN0ZXBNIHBlcnBlbmRpY3VsYXIgdG8gdGhlIGxvY2FsIGdyYWRpZW50LgogIC8vICAgQ09SUkVDVCDigJQgc2FtcGxlIGVsZXZhdGlvbiBhdCB0aGUgbmV3IHBvaW50LCBtb3ZlIGFsb25nIHRoZSBncmFkaWVudAogIC8vICAgICAgICAgICAgIGJ5ICgodGFyZ2V0WiAtIGN1cnJlbnRaKSAvIHxncmFkaWVudHwpIHRvIHJlc3RvcmUgdGhlIHRhcmdldAogIC8vICAgICAgICAgICAgIGVsZXZhdGlvbi4gS2VlcHMgdGhlIHBhdGggb24gdGhlIGNvbnRvdXIgZXZlbiB3aGVuIHRoZQogIC8vICAgICAgICAgICAgIHRlcnJhaW4gZnVuY3Rpb24gaXMgbm9uLWxpbmVhciAoZS5nLiBhIGNpcmN1bGFyIGhpbGwgb24gdGhlCiAgLy8gICAgICAgICAgICAgcGl2b3QgZmllbGQgd291bGQgb3RoZXJ3aXNlIGRyaWZ0IG9mZi1sZXZlbCBieSBzdGVwIDUwKS4KICAvLyBXYWxrcyBpbiBgZGlyYCAowrExKSB1bnRpbCBpdCBleGl0cyBgY2xpcFBvbHlgIG9yIGhpdHMgbWF4U3RlcHMuIFJldHVybnMKICAvLyBzYW1wbGUgcG9pbnRzLgogIGZ1bmN0aW9uIHdhbGtDb250b3VyKHN0YXJ0LCBkaXIsIGNsaXBQb2x5LCBzdGVwTSwgbWF4U3RlcHMpewogICAgdmFyIHB0cyA9IFt7IHg6IHN0YXJ0LngsIHk6IHN0YXJ0LnkgfV07CiAgICB2YXIgZXBzID0gMC41OwogICAgdmFyIHRhcmdldFogPSB0ZXJyYWluQXQoc3RhcnQueCwgc3RhcnQueSk7CiAgICB2YXIgcHJldlB4ID0gbnVsbCwgcHJldlB5ID0gbnVsbDsKICAgIHZhciBjbG9zZVJhZGl1cyA9IHN0ZXBNICogMS41OwogICAgdmFyIGNsb3NlUmFkaXVzU3EgPSBjbG9zZVJhZGl1cyAqIGNsb3NlUmFkaXVzOwogICAgZm9yKHZhciBzPTA7IHM8bWF4U3RlcHM7IHMrKyl7CiAgICAgIC8vIExvb3AgZGV0ZWN0aW9uIOKAlCBmb3IgY2xvc2VkIGNvbnRvdXJzIChlLmcuIGEgY2lyY2xlIGFyb3VuZCBhIGhpbGwKICAgICAgLy8gcGVhayksIHRoZSB3YWxrZXIgd291bGQgb3RoZXJ3aXNlIHNwaW4gZm9yZXZlci4gU3RvcCBvbmNlIHdlJ3ZlCiAgICAgIC8vIGNvbWUgYmFjayB3aXRoaW4gc3RlcE0gw5cgMS41IG9mIHRoZSBzZWVkIGFmdGVyIGF0IGxlYXN0IDEwIHN0ZXBzLgogICAgICAvLyBwdHMuX2Nsb3NlZCBmbGFnIHRlbGxzIHRoZSBjYWxsZXIgdGhpcyBjb250b3VyIHdyYXBwZWQgYXJvdW5kLgogICAgICBpZihzID4gMTApewogICAgICAgIHZhciBkeFMgPSBwdHNbcHRzLmxlbmd0aC0xXS54IC0gc3RhcnQueDsKICAgICAgICB2YXIgZHlTID0gcHRzW3B0cy5sZW5ndGgtMV0ueSAtIHN0YXJ0Lnk7CiAgICAgICAgaWYoZHhTKmR4UyArIGR5UypkeVMgPCBjbG9zZVJhZGl1c1NxKXsgcHRzLnB1c2goeyB4OiBzdGFydC54LCB5OiBzdGFydC55IH0pOyBwdHMuX2Nsb3NlZCA9IHRydWU7IGJyZWFrOyB9CiAgICAgIH0KICAgICAgdmFyIGxhc3QgPSBwdHNbcHRzLmxlbmd0aCAtIDFdOwogICAgICAvLyBOdW1lcmljYWwgZ3JhZGllbnQgdmlhIGNlbnRyYWwgZGlmZmVyZW5jZXMKICAgICAgdmFyIGd4ID0gKHRlcnJhaW5BdChsYXN0LnggKyBlcHMsIGxhc3QueSkgLSB0ZXJyYWluQXQobGFzdC54IC0gZXBzLCBsYXN0LnkpKSAvICgyICogZXBzKTsKICAgICAgdmFyIGd5ID0gKHRlcnJhaW5BdChsYXN0LngsIGxhc3QueSArIGVwcykgLSB0ZXJyYWluQXQobGFzdC54LCBsYXN0LnkgLSBlcHMpKSAvICgyICogZXBzKTsKICAgICAgdmFyIGdMZW4yID0gZ3gqZ3ggKyBneSpneTsKICAgICAgaWYoZ0xlbjIgPCAxZS0xMikgYnJlYWs7CiAgICAgIHZhciBnTGVuID0gTWF0aC5zcXJ0KGdMZW4yKTsKICAgICAgLy8gUHJlZGljdG9yOiBwZXJwZW5kaWN1bGFyIHRvIGdyYWRpZW50IChyb3RhdGVkIDkwwrApLCBub3JtYWxpemVkCiAgICAgIHZhciBweCA9IC1neSAvIGdMZW4gKiBkaXI7CiAgICAgIHZhciBweSA9IGd4IC8gZ0xlbiAqIGRpcjsKICAgICAgLy8gU21vb3RoIGRpcmVjdGlvbiBzbyB0aGUgY3VydmUgZG9lc24ndCBwaW5nLXBvbmcgb24gbm9pc3kgdGVycmFpbgogICAgICBpZihwcmV2UHggIT09IG51bGwpewogICAgICAgIHB4ID0gcHggKiAwLjcgKyBwcmV2UHggKiAwLjM7CiAgICAgICAgcHkgPSBweSAqIDAuNyArIHByZXZQeSAqIDAuMzsKICAgICAgICB2YXIgcGwgPSBNYXRoLnNxcnQocHgqcHggKyBweSpweSk7CiAgICAgICAgaWYocGwgPiAxZS02KXsgcHggLz0gcGw7IHB5IC89IHBsOyB9CiAgICAgIH0KICAgICAgcHJldlB4ID0gcHg7IHByZXZQeSA9IHB5OwogICAgICB2YXIgbnggPSBsYXN0LnggKyBweCAqIHN0ZXBNOwogICAgICB2YXIgbnkgPSBsYXN0LnkgKyBweSAqIHN0ZXBNOwogICAgICAvLyBDb3JyZWN0b3I6IG51ZGdlIGJhY2sgdG8gdGFyZ2V0IGVsZXZhdGlvbiBhbG9uZyB0aGUgbG9jYWwgZ3JhZGllbnQKICAgICAgdmFyIG56ID0gdGVycmFpbkF0KG54LCBueSk7CiAgICAgIHZhciBkeiA9IHRhcmdldFogLSBuejsKICAgICAgdmFyIGdNYWcyeCA9ICh0ZXJyYWluQXQobnggKyBlcHMsIG55KSAtIHRlcnJhaW5BdChueCAtIGVwcywgbnkpKSAvICgyICogZXBzKTsKICAgICAgdmFyIGdNYWcyeSA9ICh0ZXJyYWluQXQobngsIG55ICsgZXBzKSAtIHRlcnJhaW5BdChueCwgbnkgLSBlcHMpKSAvICgyICogZXBzKTsKICAgICAgdmFyIGdNYWcyc3EgPSBnTWFnMngqZ01hZzJ4ICsgZ01hZzJ5KmdNYWcyeTsKICAgICAgaWYoZ01hZzJzcSA+IDFlLTEyKXsKICAgICAgICB2YXIgY29yciA9IGR6IC8gZ01hZzJzcTsKICAgICAgICBueCArPSBnTWFnMnggKiBjb3JyOwogICAgICAgIG55ICs9IGdNYWcyeSAqIGNvcnI7CiAgICAgIH0KICAgICAgaWYoIXBvaW50SW5Qb2x5KG54LCBueSwgY2xpcFBvbHkpKSBicmVhazsKICAgICAgcHRzLnB1c2goeyB4OiBueCwgeTogbnkgfSk7CiAgICB9CiAgICByZXR1cm4gcHRzOwogIH0KICAvLyBCdWlsZCBjb250b3VyLWZvbGxvd2luZyBwYXNzZXMgZnJvbSB0aGUgYWN0aXZlIHRlcnJhaW4uIFNwYWNpbmcgPSB3TQogIC8vIChwZXJwZW5kaWN1bGFyIGltcGxlbWVudC13aWR0aCksIHNvIGVhY2ggcGFzcydzIHN3YXRoIHRpbGVzIHRoZSBuZXh0LgogIC8vIFJldHVybnMgYXJyYXkgb2YgeyBzYW1wbGVzLCBraW5kOiAnYWRhcHRpdmUnIH0gcGFzc2VzIGNsaXBwZWQgdG8KICAvLyBgY2xpcFBvbHlgICh0aGUgaW50ZXJpb3IgcG9seWdvbikuCiAgZnVuY3Rpb24gYnVpbGRDb250b3VyUGFzc2VzKHdNLCBjbGlwUG9seSl7CiAgICAvLyAxLiBGaW5kIGVsZXZhdGlvbiByYW5nZSBhY3Jvc3MgY2xpcFBvbHkKICAgIHZhciBzdGF0cyA9IGZpZWxkU3RhdHMoY2xpcFBvbHkpOwogICAgdmFyIGxvID0gSW5maW5pdHksIGhpID0gLUluZmluaXR5OwogICAgdmFyIHNhbXBsZU4gPSAyNDsgIC8vIHNwYXJzZSBzd2VlcCB0byBmaW5kIGxvL2hpCiAgICB2YXIgZHhTID0gKHN0YXRzLm1heFggLSBzdGF0cy5taW5YKSAvIHNhbXBsZU47CiAgICB2YXIgZHlTID0gKHN0YXRzLm1heFkgLSBzdGF0cy5taW5ZKSAvIHNhbXBsZU47CiAgICBmb3IodmFyIGl5PTA7IGl5PHNhbXBsZU47IGl5KyspewogICAgICBmb3IodmFyIGl4PTA7IGl4PHNhbXBsZU47IGl4KyspewogICAgICAgIHZhciBjeFMgPSBzdGF0cy5taW5YICsgKGl4ICsgMC41KSAqIGR4UzsKICAgICAgICB2YXIgY3lTID0gc3RhdHMubWluWSArIChpeSArIDAuNSkgKiBkeVM7CiAgICAgICAgaWYoIXBvaW50SW5Qb2x5KGN4UywgY3lTLCBjbGlwUG9seSkpIGNvbnRpbnVlOwogICAgICAgIHZhciB6ID0gdGVycmFpbkF0KGN4UywgY3lTKTsKICAgICAgICBpZih6IDwgbG8pIGxvID0gejsKICAgICAgICBpZih6ID4gaGkpIGhpID0gejsKICAgICAgfQogICAgfQogICAgaWYoaGkgLSBsbyA8IDAuMykgcmV0dXJuIFtdOyAgLy8gZXNzZW50aWFsbHkgZmxhdCDigJQgbm8gdXNlZnVsIGNvbnRvdXJzCiAgICAvLyAyLiBFc3RpbWF0ZSB0eXBpY2FsIGdyYWRpZW50IG1hZ25pdHVkZSBhY3Jvc3MgdGhlIGZpZWxkLiBTYW1wbGluZyB0aGUKICAgIC8vICAgIGNlbnRyb2lkIGFsb25lIGZhaWxzIGZvciBmaWVsZHMgd2hlcmUgdGhlIGNlbnRyb2lkIHNpdHMgb24gYSBwZWFrCiAgICAvLyAgICBvciBzYWRkbGUgKGUuZy4gcGl2b3Qg4oCUIHJvdW5kIGhpbGwgYXQgdGhlIGNlbnRyZSDihpIg4oiHPTAgdGhlcmUpLgogICAgLy8gICAgVGFrZSA5IHNhbXBsZXMgb24gYSAzw5czIGdyaWQsIHVzZSB0aGUgbWVkaWFuIG1hZ25pdHVkZS4KICAgIHZhciBncmFkU2FtcGxlcyA9IFtdOwogICAgZm9yKHZhciBneGk9MDsgZ3hpPDM7IGd4aSsrKXsKICAgICAgZm9yKHZhciBneWk9MDsgZ3lpPDM7IGd5aSsrKXsKICAgICAgICB2YXIgc3ggPSBzdGF0cy5taW5YICsgKGd4aSArIDEpICogKHN0YXRzLm1heFggLSBzdGF0cy5taW5YKSAvIDQ7CiAgICAgICAgdmFyIHN5ID0gc3RhdHMubWluWSArIChneWkgKyAxKSAqIChzdGF0cy5tYXhZIC0gc3RhdHMubWluWSkgLyA0OwogICAgICAgIGlmKCFwb2ludEluUG9seShzeCwgc3ksIGNsaXBQb2x5KSkgY29udGludWU7CiAgICAgICAgdmFyIGd4UyA9ICh0ZXJyYWluQXQoc3ggKyAxLCBzeSkgLSB0ZXJyYWluQXQoc3ggLSAxLCBzeSkpICogMC41OwogICAgICAgIHZhciBneVMgPSAodGVycmFpbkF0KHN4LCBzeSArIDEpIC0gdGVycmFpbkF0KHN4LCBzeSAtIDEpKSAqIDAuNTsKICAgICAgICBncmFkU2FtcGxlcy5wdXNoKE1hdGguc3FydChneFMqZ3hTICsgZ3lTKmd5UykpOwogICAgICB9CiAgICB9CiAgICBpZihncmFkU2FtcGxlcy5sZW5ndGggPT09IDApIHJldHVybiBbXTsKICAgIGdyYWRTYW1wbGVzLnNvcnQoZnVuY3Rpb24oYSwgYil7IHJldHVybiBhIC0gYjsgfSk7CiAgICB2YXIgZ01hZyA9IGdyYWRTYW1wbGVzW01hdGguZmxvb3IoZ3JhZFNhbXBsZXMubGVuZ3RoIC8gMildOyAgLy8gbWVkaWFuCiAgICBpZihnTWFnIDwgMWUtNCkgcmV0dXJuIFtdOyAgLy8gdHJ1bHkgZmxhdCDihpIgbm8gdXNlZnVsIGNvbnRvdXJzCiAgICB2YXIgZWxldlN0ZXAgPSB3TSAqIGdNYWc7CiAgICAvLyAzLiBQaWNrIE4gbGV2ZWxzIGV2ZW5seSBiZXR3ZWVuIGxvK2VsZXZTdGVwLzIgYW5kIGhpLWVsZXZTdGVwLzIKICAgIHZhciBuTGV2ZWxzID0gTWF0aC5tYXgoMiwgTWF0aC5mbG9vcigoaGkgLSBsbykgLyBlbGV2U3RlcCkpOwogICAgaWYobkxldmVscyA+IDYwKSBuTGV2ZWxzID0gNjA7ICAvLyBjYXAgdG8gYXZvaWQgcGF0aG9sb2dpY2FsIHRlcnJhaW4KICAgIHZhciBsZXZlbHMgPSBbXTsKICAgIGZvcih2YXIgTD0wOyBMPG5MZXZlbHM7IEwrKyl7CiAgICAgIGxldmVscy5wdXNoKGxvICsgKEwgKyAwLjUpICogKGhpIC0gbG8pIC8gbkxldmVscyk7CiAgICB9CiAgICAvLyA0LiBGb3IgZWFjaCBsZXZlbCwgZmluZCBhIHNlZWQgcG9pbnQgaW5zaWRlIGNsaXBQb2x5IHdpdGggdGVycmFpbiDiiYggbGV2ZWwKICAgIC8vICAgIHRoZW4gd2FsayB0aGUgY29udG91ciBpbiBib3RoIGRpcmVjdGlvbnMsIGpvaW5pbmcgaW50byBvbmUgcGFzcy4KICAgIHZhciBwYXNzZXMgPSBbXTsKICAgIHZhciBzZWVkR3JpZCA9IDMyOwogICAgdmFyIHNkeCA9IChzdGF0cy5tYXhYIC0gc3RhdHMubWluWCkgLyBzZWVkR3JpZDsKICAgIHZhciBzZHkgPSAoc3RhdHMubWF4WSAtIHN0YXRzLm1pblkpIC8gc2VlZEdyaWQ7CiAgICAvLyBQcmUtc2FtcGxlIG9uIGEgZmluZXIgZ3JpZCBmb3Igc2VlZHMKICAgIHZhciBzZWVkWiA9IG5ldyBGbG9hdDMyQXJyYXkoc2VlZEdyaWQgKiBzZWVkR3JpZCk7CiAgICB2YXIgc2VlZEluID0gbmV3IFVpbnQ4QXJyYXkoc2VlZEdyaWQgKiBzZWVkR3JpZCk7CiAgICBmb3IodmFyIGl5Mj0wOyBpeTI8c2VlZEdyaWQ7IGl5MisrKXsKICAgICAgZm9yKHZhciBpeDI9MDsgaXgyPHNlZWRHcmlkOyBpeDIrKyl7CiAgICAgICAgdmFyIGN4MiA9IHN0YXRzLm1pblggKyAoaXgyICsgMC41KSAqIHNkeDsKICAgICAgICB2YXIgY3kyID0gc3RhdHMubWluWSArIChpeTIgKyAwLjUpICogc2R5OwogICAgICAgIHNlZWRaW2l5MiAqIHNlZWRHcmlkICsgaXgyXSA9IHRlcnJhaW5BdChjeDIsIGN5Mik7CiAgICAgICAgc2VlZEluW2l5MiAqIHNlZWRHcmlkICsgaXgyXSA9IHBvaW50SW5Qb2x5KGN4MiwgY3kyLCBjbGlwUG9seSkgPyAxIDogMDsKICAgICAgfQogICAgfQogICAgdmFyIHN0ZXBNID0gTWF0aC5tYXgoMiwgd00gKiAwLjQpOwogICAgdmFyIG1heFN0ZXBzID0gODAwOwogICAgZm9yKHZhciBsaT0wOyBsaTxsZXZlbHMubGVuZ3RoOyBsaSsrKXsKICAgICAgdmFyIGx2ID0gbGV2ZWxzW2xpXTsKICAgICAgLy8gRmluZCB0aGUgc2VlZCBjZWxsIHdoZXJlIHNlZWRaIGlzIGNsb3Nlc3QgdG8gbHYgKGFtb25nIGluLWZpZWxkIGNlbGxzKQogICAgICB2YXIgYmVzdElkeCA9IC0xLCBiZXN0RGlmZiA9IEluZmluaXR5OwogICAgICBmb3IodmFyIGs9MDsgazxzZWVkWi5sZW5ndGg7IGsrKyl7CiAgICAgICAgaWYoIXNlZWRJbltrXSkgY29udGludWU7CiAgICAgICAgdmFyIGRpZmYgPSBNYXRoLmFicyhzZWVkWltrXSAtIGx2KTsKICAgICAgICBpZihkaWZmIDwgYmVzdERpZmYpeyBiZXN0RGlmZiA9IGRpZmY7IGJlc3RJZHggPSBrOyB9CiAgICAgIH0KICAgICAgaWYoYmVzdElkeCA8IDApIGNvbnRpbnVlOwogICAgICB2YXIgaXhTID0gYmVzdElkeCAlIHNlZWRHcmlkOwogICAgICB2YXIgaXlTID0gTWF0aC5mbG9vcihiZXN0SWR4IC8gc2VlZEdyaWQpOwogICAgICB2YXIgc2VlZCA9IHsgeDogc3RhdHMubWluWCArIChpeFMgKyAwLjUpICogc2R4LCB5OiBzdGF0cy5taW5ZICsgKGl5UyArIDAuNSkgKiBzZHkgfTsKICAgICAgLy8gV2FsayBmb3J3YXJkIGZpcnN0LiBJZiBpdCByZXR1cm5zIGEgY2xvc2VkIGxvb3AsIHRoZSBjb250b3VyIGlzCiAgICAgIC8vIGNsb3NlZCAoZS5nLiBjaXJjdWxhciBoaWxsKSDigJQgc2tpcCB0aGUgYmFja3dhcmQgd2FsayAod291bGQganVzdAogICAgICAvLyB0cmFjZSB0aGUgc2FtZSBsb29wIGluIHJldmVyc2UsIGRvdWJsaW5nIHRoZSBwYXRoIGxlbmd0aCkuCiAgICAgIHZhciBmd2QgPSB3YWxrQ29udG91cihzZWVkLCArMSwgY2xpcFBvbHksIHN0ZXBNLCBtYXhTdGVwcyk7CiAgICAgIHZhciBzYW1wbGVzOwogICAgICBpZihmd2QuX2Nsb3NlZCl7CiAgICAgICAgc2FtcGxlcyA9IGZ3ZDsKICAgICAgfSBlbHNlIHsKICAgICAgICB2YXIgYndkID0gd2Fsa0NvbnRvdXIoc2VlZCwgLTEsIGNsaXBQb2x5LCBzdGVwTSwgbWF4U3RlcHMpOwogICAgICAgIGJ3ZC5yZXZlcnNlKCk7CiAgICAgICAgc2FtcGxlcyA9IGJ3ZC5jb25jYXQoZndkLnNsaWNlKDEpKTsKICAgICAgfQogICAgICBpZihzYW1wbGVzLmxlbmd0aCA+PSA0KSBwYXNzZXMucHVzaCh7IHNhbXBsZXM6IHNhbXBsZXMsIGtpbmQ6ICdhZGFwdGl2ZScgfSk7CiAgICB9CiAgICByZXR1cm4gcGFzc2VzOwogIH0KCiAgZnVuY3Rpb24gZ2VuZXJhdGVMaW5lcyhhcHByb2FjaCwgd00sIGIsIGF4aXMsIGhlYWRsYW5kTSwgdHVyblN0eWxlLCB0dXJuUmFkaXVzTSwgb3V0c2lkZUJ1ZmZlck0pewogICAgdmFyIGRyaXZhYmxlID0gYnVpbGREcml2YWJsZShiLCBvdXRzaWRlQnVmZmVyTSk7CiAgICB2YXIgaW50ZXJpb3IgPSBoZWFkbGFuZE0gPiAwID8gb2Zmc2V0UG9seWdvbklud2FyZChiLCBoZWFkbGFuZE0pIDogYjsKICAgIGlmKCFpbnRlcmlvcikgaW50ZXJpb3IgPSBiOyAgLy8gZmFsbGJhY2sgd2hlbiBvZmZzZXQgY29sbGFwc2VzCiAgICB2YXIgdXggPSBheGlzLnV4LCB1eSA9IGF4aXMudXk7CiAgICB2YXIgcGFzc2VzID0gW107CgogICAgLy8gUnVsZSDCpzEzIOKAlCB3b3JrIHRoZSBoZWFkbGFuZCBGSVJTVCwgdGhlbiB0aGUgYm9keS4gRW1pdCBwZXJpbWV0ZXIKICAgIC8vIHJpbmcocykgYXQgaGVhZGxhbmQtc3RyaXAgY2VudHJlbGluZXMgZm9yIEVWRVJZIGFwcHJvYWNoLgogICAgLy8KICAgIC8vIEZvciBoZWFkbGFuZE0gPT0gMcOXd006IG9uZSByaW5nIGF0IHdNLzIgZnJvbSBib3VuZGFyeSBjb3ZlcnMgdGhlCiAgICAvLyB3aG9sZSBzdHJpcCBbMCwgd01dIHdpdGggaXRzIHN3YXRoLgogICAgLy8KICAgIC8vIEZvciBoZWFkbGFuZE0gPiAxw5d3TTogZHJpdmUgTVVMVElQTEUgY29uY2VudHJpYyByaW5ncyBzbyB0aGUgZnVsbAogICAgLy8gc3RyaXAgaXMgY292ZXJlZC4gblJpbmdzID0gcm91bmQoaGVhZGxhbmRNIC8gd00pLiBSaW5nIGsgYXQgcGVycCA9CiAgICAvLyAoayArIDAuNSkgw5cgd00gZnJvbSBib3VuZGFyeSAoayA9IDAuLm5SaW5ncy0xKSBzbyBzd2F0aHMgdGlsZSB0aGUKICAgIC8vIHN0cmlwIHdpdGhvdXQgZ2Fwcy4KICAgIGlmKGhlYWRsYW5kTSA+IDAgPyBpbnRlcmlvciAhPT0gYiA6IGZhbHNlKXsKICAgICAgdmFyIG5SaW5ncyA9IE1hdGgubWF4KDEsIE1hdGgucm91bmQoaGVhZGxhbmRNIC8gd00pKTsKICAgICAgZm9yKHZhciByaz0wOyByazxuUmluZ3M7IHJrKyspewogICAgICAgIHZhciByaW5nT2ZmID0gKHJrICsgMC41KSAqIHdNOwogICAgICAgIHZhciByaW5nUmVmID0gb2Zmc2V0UG9seWdvbklud2FyZChiLCByaW5nT2ZmKTsKICAgICAgICBpZihyaW5nUmVmKXsKICAgICAgICAgIHBhc3Nlcy5wdXNoKHsgc2FtcGxlczogcmluZ1JlZi5jb25jYXQoW3JpbmdSZWZbMF1dKSwga2luZDogJ2hlYWRsYW5kLXJpbmcnIH0pOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgdmFyIHBhc3NDbGlwUG9seSA9IGludGVyaW9yOwogICAgLy8gQm91bmRhcnkgRm9sbG93IHVzZWQgdG8gc2hyaW5rIHRoZSBib2R5IGludGVyaW9yIGJ5IGFub3RoZXIgMC43NSDDlyB3TQogICAgLy8gdG8gYXZvaWQgb3ZlcmxhcCBiZXR3ZWVuIHJpbmcgYW5kIGJvZHkgc3dhdGhzLiBUaGF0IGNyZWF0ZWQgYSAwLjc1IMOXIHdNCiAgICAvLyBVTkNPVkVSRUQgc3RyaXAgYmV0d2VlbiB0aGUgcmluZydzIHN3YXRoIGVkZ2UgYW5kIHRoZSBmaXJzdCBib2R5IHBhc3MuCiAgICAvLyBQZXIgdGhlIHVzZXIg4oCUIG1heGltaXNlIGNvdmVyYWdlIOKAlCBib2R5IHBhc3NlcyBub3cgdXNlIHRoZSBmdWxsCiAgICAvLyBpbnRlcmlvciwgYWNjZXB0aW5nIGEgc21hbGwgKH4w4oCTMjUgJSkgb3ZlcmxhcCBhdCB0aGUgcmluZy9ib2R5CiAgICAvLyBib3VuZGFyeSwgd2hpY2ggaXMgc3RhbmRhcmQgYWdyb25vbWljIHByYWN0aWNlICg14oCTMTAgJSBvdmVybGFwIGlzCiAgICAvLyByb3V0aW5lIGZvciBoZWFkbGFuZCBlZGdlcykuCiAgICAvLyBDb250b3VyLWZvbGxvdyAodGVycmFpbi1hd2FyZSkg4oCUIGdlbmVyYXRlIHBhc3NlcyB0aGF0IHRyYWNlIGxldmVsCiAgICAvLyBjdXJ2ZXMgb2YgdGhlIHRlcnJhaW4gZnVuY3Rpb24uIEVhY2ggcGFzcyB3YWxrcyBwZXJwZW5kaWN1bGFyIHRvIHRoZQogICAgLy8gbG9jYWwgZ3JhZGllbnQgYXQgd00gc3BhY2luZy4gRmFsbHMgYmFjayB0byBBQi1jdXJ2ZSBzeW50aGV0aWMgd2F2ZXMKICAgIC8vIHdoZW4gdGVycmFpbiBpcyB0b28gZmxhdCAob3IgdXBsb2FkZWQtbm8tdGVycmFpbikuCiAgICBpZihhcHByb2FjaCA9PT0gJ2FkYXB0aXZlJyl7CiAgICAgIHZhciBjb250b3VyUGFzc2VzID0gYnVpbGRDb250b3VyUGFzc2VzKHdNLCBwYXNzQ2xpcFBvbHkpOwogICAgICBpZihjb250b3VyUGFzc2VzLmxlbmd0aCA+PSAyKXsKICAgICAgICBmb3IodmFyIGNwPTA7IGNwPGNvbnRvdXJQYXNzZXMubGVuZ3RoOyBjcCsrKSBwYXNzZXMucHVzaChjb250b3VyUGFzc2VzW2NwXSk7CiAgICAgICAgdmFyIHNlcnBDID0gYnVpbGRTZXJwZW50aW5lKHBhc3NlcywgZHJpdmFibGUsIGludGVyaW9yLCBheGlzLCB0dXJuU3R5bGUsIHR1cm5SYWRpdXNNLCB3TSAqIDAuNSwgd00pOwogICAgICAgIHJldHVybiB7CiAgICAgICAgICBwYXNzZXM6IHBhc3NlcywKICAgICAgICAgIGludGVyaW9yOiBpbnRlcmlvciwKICAgICAgICAgIGRyaXZhYmxlOiBkcml2YWJsZSwKICAgICAgICAgIGJvdW5kYXJ5OiBiLAogICAgICAgICAgdHVybkFyY3M6IHNlcnBDLnR1cm5BcmNzLAogICAgICAgICAgZHJpdmVQYXRoOiBzZXJwQy5kcml2ZUNvb3JkcywKICAgICAgICAgIHdhcm5pbmc6IHNlcnBDLndhcm5pbmcsCiAgICAgICAgICBvcmRlcmVkUGFzc2VzOiBzZXJwQy5vcmRlcmVkUGFzc2VzCiAgICAgICAgfTsKICAgICAgfQogICAgICAvLyBlbHNlOiBmbGF0IC8gdXBsb2FkZWQgZmllbGQg4oaSIGZhbGwgdGhyb3VnaCB0byB0aGUgc3ludGhldGljLXdhdmUgY29kZQogICAgICAvLyBiZWxvdyAoc3RpbGwgbGFiZWxsZWQgYWRhcHRpdmUgYnV0IHdvbid0IGFjdHVhbGx5IGZvbGxvdyB0ZXJyYWluKS4KICAgIH0KCiAgICAvLyBBQiBTdHJhaWdodCAvIEFCIEN1cnZlIC8gQWRhcHRpdmUgKHN5bnRoZXRpYykgLyBCb3VuZGFyeSBib2R5IOKAlCBwYXJhbGxlbAogICAgLy8gb2Zmc2V0cyBjbGlwcGVkIHRvIGBwYXNzQ2xpcFBvbHlgLgogICAgdmFyIHBlcnBNaW4gPSBJbmZpbml0eSwgcGVycE1heCA9IC1JbmZpbml0eTsKICAgIHZhciBhbG9uZ01pbiA9IEluZmluaXR5LCBhbG9uZ01heCA9IC1JbmZpbml0eTsKICAgIGZvcih2YXIgaT0wOyBpPHBhc3NDbGlwUG9seS5sZW5ndGg7IGkrKyl7CiAgICAgIHZhciBhbG9uZyA9IHBhc3NDbGlwUG9seVtpXS54ICogdXggKyBwYXNzQ2xpcFBvbHlbaV0ueSAqIHV5OwogICAgICB2YXIgcGVycCA9IC1wYXNzQ2xpcFBvbHlbaV0ueCAqIHV5ICsgcGFzc0NsaXBQb2x5W2ldLnkgKiB1eDsKICAgICAgaWYocGVycCA8IHBlcnBNaW4pIHBlcnBNaW4gPSBwZXJwOwogICAgICBpZihwZXJwID4gcGVycE1heCkgcGVycE1heCA9IHBlcnA7CiAgICAgIGlmKGFsb25nIDwgYWxvbmdNaW4pIGFsb25nTWluID0gYWxvbmc7CiAgICAgIGlmKGFsb25nID4gYWxvbmdNYXgpIGFsb25nTWF4ID0gYWxvbmc7CiAgICB9CiAgICB2YXIgc3RhcnRQZXJwID0gcGVycE1pbiArIHdNICogMC41OwogICAgdmFyIGVuZFBlcnAgPSBwZXJwTWF4IC0gd00gKiAwLjU7CiAgICB2YXIgYWxvbmdTcGFuID0gYWxvbmdNYXggLSBhbG9uZ01pbjsKICAgIGZvcih2YXIgcHAgPSBzdGFydFBlcnA7IHBwIDw9IGVuZFBlcnAgKyAxZS02OyBwcCArPSB3TSl7CiAgICAgIHZhciBwMEFsb25nID0gYWxvbmdNaW4gLSBhbG9uZ1NwYW4gKiAwLjE7CiAgICAgIHZhciBwMUFsb25nID0gYWxvbmdNYXggKyBhbG9uZ1NwYW4gKiAwLjE7CiAgICAgIHZhciBzdGFydFggPSBwMEFsb25nICogdXggLSBwcCAqIHV5OwogICAgICB2YXIgc3RhcnRZID0gcDBBbG9uZyAqIHV5ICsgcHAgKiB1eDsKICAgICAgdmFyIGVuZFggPSBwMUFsb25nICogdXggLSBwcCAqIHV5OwogICAgICB2YXIgZW5kWSA9IHAxQWxvbmcgKiB1eSArIHBwICogdXg7CiAgICAgIC8vIFVzZSB0aGUgbXVsdGktc2VnbWVudCBjbGlwcGVyIHNvIGNvbmNhdmUgcG9seWdvbnMgKEwtc2hhcGUgaW50ZXJpb3IhKQogICAgICAvLyBwcm9kdWNlIG9uZSBwYXNzIHBlciAiaW5zaWRlIiBzZWdtZW50IHdoZW4gdGhlIGxpbmUgY3Jvc3NlcyBhIGdhcC4KICAgICAgdmFyIGNsaXBwZWRTZWdzID0gY2xpcExpbmVUb0JvdW5kYXJ5U2VnbWVudHMoc3RhcnRYLCBzdGFydFksIGVuZFgsIGVuZFksIHBhc3NDbGlwUG9seSk7CiAgICAgIGlmKCFjbGlwcGVkU2VncykgY29udGludWU7CiAgICAgIGZvcih2YXIgY3M9MDsgY3M8Y2xpcHBlZFNlZ3MubGVuZ3RoOyBjcysrKXsKICAgICAgICB2YXIgY2xpcHBlZCA9IGNsaXBwZWRTZWdzW2NzXTsKICAgICAgICBpZihhcHByb2FjaCA9PT0gJ2FiLWN1cnZlJyB8fCBhcHByb2FjaCA9PT0gJ2FkYXB0aXZlJyl7CiAgICAgICAgICB2YXIgZHhDID0gY2xpcHBlZC54MSAtIGNsaXBwZWQueDA7CiAgICAgICAgICB2YXIgZHlDID0gY2xpcHBlZC55MSAtIGNsaXBwZWQueTA7CiAgICAgICAgICB2YXIgbGVuTCA9IE1hdGguc3FydChkeEMqZHhDICsgZHlDKmR5Qyk7CiAgICAgICAgICB2YXIgblNhbXAgPSBNYXRoLm1heCg4LCBNYXRoLmZsb29yKGxlbkwgLyAod00gKiAwLjYpKSk7CiAgICAgICAgICB2YXIgc2FtcHMgPSBbXTsKICAgICAgICAgIHZhciBhbXBsaXR1ZGUgPSBhcHByb2FjaCA9PT0gJ2FkYXB0aXZlJyA\/IHdNICogMC4zNSA6IHdNICogMC4xNTsKICAgICAgICAgIHZhciBmcmVxID0gYXBwcm9hY2ggPT09ICdhZGFwdGl2ZScgPyAyLjggOiAxLjQ7CiAgICAgICAgICB2YXIgcGhhc2UgPSAocHAgLSBwZXJwTWluKSAvIHdNOwogICAgICAgICAgZm9yKHZhciBzcz0wOyBzczw9blNhbXA7IHNzKyspewogICAgICAgICAgICB2YXIgdCA9IG5TYW1wID4gMCA\/IHNzIC8gblNhbXAgOiAwOwogICAgICAgICAgICB2YXIgYnhzID0gY2xpcHBlZC54MCArIGR4QyAqIHQ7CiAgICAgICAgICAgIHZhciBieXMgPSBjbGlwcGVkLnkwICsgZHlDICogdDsKICAgICAgICAgICAgdmFyIHdhdmUgPSBNYXRoLnNpbih0ICogTWF0aC5QSSAqIGZyZXEgKyBwaGFzZSkgKiBhbXBsaXR1ZGU7CiAgICAgICAgICAgIGJ4cyArPSAtdXkgKiB3YXZlOwogICAgICAgICAgICBieXMgKz0gdXggKiB3YXZlOwogICAgICAgICAgICBzYW1wcy5wdXNoKHsgeDogYnhzLCB5OiBieXMgfSk7CiAgICAgICAgICB9CiAgICAgICAgICBwYXNzZXMucHVzaCh7IHNhbXBsZXM6IHNhbXBzLCBraW5kOiBhcHByb2FjaCB9KTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgcGFzc2VzLnB1c2goeyB4MDogY2xpcHBlZC54MCwgeTA6IGNsaXBwZWQueTAsIHgxOiBjbGlwcGVkLngxLCB5MTogY2xpcHBlZC55MSwga2luZDogYXBwcm9hY2ggfSk7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICB2YXIgc2VycCA9IGJ1aWxkU2VycGVudGluZShwYXNzZXMsIGRyaXZhYmxlLCBpbnRlcmlvciwgYXhpcywgdHVyblN0eWxlLCB0dXJuUmFkaXVzTSwgd00gKiAwLjUsIHdNKTsKICAgIHJldHVybiB7CiAgICAgIHBhc3NlczogcGFzc2VzLAogICAgICBpbnRlcmlvcjogaW50ZXJpb3IsCiAgICAgIGRyaXZhYmxlOiBkcml2YWJsZSwKICAgICAgYm91bmRhcnk6IGIsCiAgICAgIHR1cm5BcmNzOiBzZXJwLnR1cm5BcmNzLAogICAgICBkcml2ZVBhdGg6IHNlcnAuZHJpdmVDb29yZHMsCiAgICAgIHdhcm5pbmc6IHNlcnAud2FybmluZywKICAgICAgb3JkZXJlZFBhc3Nlczogc2VycC5vcmRlcmVkUGFzc2VzCiAgICB9OwogIH0KCiAgLy8gUmFzdGVyaXNlIHRoZSBsYXlvdXQncyBzd2F0aCBvbnRvIGEgZ3JpZCBjb3ZlcmluZyB0aGUgZmllbGQgYmJveC4gRm9yCiAgLy8gZWFjaCBjZWxsIHdob3NlIGNlbnRyZSBpcyBpbnNpZGUgdGhlIGJvdW5kYXJ5IEFORCB3aXRoaW4gd00vMiBvZiBhbnkKICAvLyBwYXNzLWNlbnRlcmxpbmUgb3IgcmluZy1jZW50ZXJsaW5lIHNlZ21lbnQsIG1hcmsgaXQgY292ZXJlZC4gUmV0dXJucwogIC8vIHsgY292ZXJlZE0yLCBmaWVsZE0yLCBwY3QgfS4gY2VsbFNpemUgZGVmYXVsdHMgdG8gfndNLzMgc28gY2VsbHMgYXJlCiAgLy8gc21hbGxlciB0aGFuIHRoZSBzd2F0aCDigJQgdW5kZXItZmlsbCBuZWFyIGNvcm5lcnMgaXMgY2FwdHVyZWQgaG9uZXN0bHkuCiAgZnVuY3Rpb24gcmFzdGVyQ292ZXJhZ2UobGF5b3V0LCB3TSl7CiAgICB2YXIgYiA9IGxheW91dC5ib3VuZGFyeSA\/IGxheW91dC5ib3VuZGFyeSA6IEJPVU5EQVJZOwogICAgdmFyIHN0YXRzID0gZmllbGRTdGF0cyhiKTsKICAgIHZhciBjZWxsU2l6ZSA9IE1hdGgubWF4KDIsIHdNIC8gMyk7CiAgICB2YXIgbnggPSBNYXRoLm1heCg4LCBNYXRoLmNlaWwoKHN0YXRzLm1heFggLSBzdGF0cy5taW5YKSAvIGNlbGxTaXplKSk7CiAgICB2YXIgbnkgPSBNYXRoLm1heCg4LCBNYXRoLmNlaWwoKHN0YXRzLm1heFkgLSBzdGF0cy5taW5ZKSAvIGNlbGxTaXplKSk7CiAgICAvLyBGaXJzdCBwYXNzOiBtYXJrIGNlbGxzIGluc2lkZSB0aGUgZmllbGQgYm91bmRhcnkKICAgIHZhciBpbkZpZWxkID0gbmV3IFVpbnQ4QXJyYXkobnggKiBueSk7CiAgICB2YXIgZmllbGRDZWxsQ291bnQgPSAwOwogICAgZm9yKHZhciBpeT0wOyBpeTxueTsgaXkrKyl7CiAgICAgIGZvcih2YXIgaXg9MDsgaXg8bng7IGl4KyspewogICAgICAgIHZhciBjeCA9IHN0YXRzLm1pblggKyAoaXggKyAwLjUpICogY2VsbFNpemU7CiAgICAgICAgdmFyIGN5ID0gc3RhdHMubWluWSArIChpeSArIDAuNSkgKiBjZWxsU2l6ZTsKICAgICAgICBpZihwb2ludEluUG9seShjeCwgY3ksIGIpKXsKICAgICAgICAgIGluRmllbGRbaXkgKiBueCArIGl4XSA9IDE7CiAgICAgICAgICBmaWVsZENlbGxDb3VudCsrOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgLy8gQ29sbGVjdCBhbGwgc3dhdGggc2VnbWVudHMg4oCUIGJvZHktcGFzcyBzZWdtZW50cyBhbmQgcmluZyBzZWdtZW50cy4KICAgIHZhciBzZWdzID0gW107CiAgICBpZihsYXlvdXQucGFzc2VzKXsKICAgICAgZm9yKHZhciBwaT0wOyBwaTxsYXlvdXQucGFzc2VzLmxlbmd0aDsgcGkrKyl7CiAgICAgICAgdmFyIHBhID0gbGF5b3V0LnBhc3Nlc1twaV07CiAgICAgICAgaWYocGEuc2FtcGxlcyl7CiAgICAgICAgICBmb3IodmFyIHNpPTE7IHNpPHBhLnNhbXBsZXMubGVuZ3RoOyBzaSsrKXsKICAgICAgICAgICAgc2Vncy5wdXNoKHsgeDA6IHBhLnNhbXBsZXNbc2ktMV0ueCwgeTA6IHBhLnNhbXBsZXNbc2ktMV0ueSwgeDE6IHBhLnNhbXBsZXNbc2ldLngsIHkxOiBwYS5zYW1wbGVzW3NpXS55IH0pOwogICAgICAgICAgfQogICAgICAgIH0gZWxzZSBpZihwYS54MCAhPT0gdW5kZWZpbmVkKXsKICAgICAgICAgIHNlZ3MucHVzaCh7IHgwOiBwYS54MCwgeTA6IHBhLnkwLCB4MTogcGEueDEsIHkxOiBwYS55MSB9KTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIGlmKHNlZ3MubGVuZ3RoID09PSAwKXsKICAgICAgcmV0dXJuIHsgY292ZXJlZE0yOiAwLCBmaWVsZE0yOiBmaWVsZENlbGxDb3VudCAqIGNlbGxTaXplICogY2VsbFNpemUsIHBjdDogMCB9OwogICAgfQogICAgLy8gU2Vjb25kIHBhc3M6IGZvciBlYWNoIGluLWZpZWxkIGNlbGwsIGNoZWNrIGRpc3RhbmNlIHRvIG5lYXJlc3Qgc2VnbWVudC4KICAgIC8vIE8oY2VsbHMgw5cgc2Vncykg4oCUIGFjY2VwdGFibGUgZm9yIHNhbXBsZS1zaXplZCBmaWVsZHMgKH42MDAwIMOXIDIwIOKJiCAxMjBrKS4KICAgIHZhciBoYWxmID0gd00gKiAwLjU7CiAgICB2YXIgaGFsZjIgPSBoYWxmICogaGFsZjsKICAgIHZhciBjb3ZlcmVkID0gbmV3IFVpbnQ4QXJyYXkobnggKiBueSk7CiAgICB2YXIgY292ZXJlZENvdW50ID0gMDsKICAgIGZvcih2YXIgaXkyPTA7IGl5MjxueTsgaXkyKyspewogICAgICBmb3IodmFyIGl4Mj0wOyBpeDI8bng7IGl4MisrKXsKICAgICAgICB2YXIgaWR4ID0gaXkyICogbnggKyBpeDI7CiAgICAgICAgaWYoIWluRmllbGRbaWR4XSkgY29udGludWU7CiAgICAgICAgdmFyIGN4QyA9IHN0YXRzLm1pblggKyAoaXgyICsgMC41KSAqIGNlbGxTaXplOwogICAgICAgIHZhciBjeUMgPSBzdGF0cy5taW5ZICsgKGl5MiArIDAuNSkgKiBjZWxsU2l6ZTsKICAgICAgICBmb3IodmFyIHNnPTA7IHNnPHNlZ3MubGVuZ3RoOyBzZysrKXsKICAgICAgICAgIHZhciBzID0gc2Vnc1tzZ107CiAgICAgICAgICAvLyBTcXVhcmVkIGRpc3RhbmNlIGZyb20gKGN4QyxjeUMpIHRvIHNlZ21lbnQgcwogICAgICAgICAgdmFyIHNkeCA9IHMueDEgLSBzLngwLCBzZHkgPSBzLnkxIC0gcy55MDsKICAgICAgICAgIHZhciBMMiA9IHNkeCpzZHggKyBzZHkqc2R5OwogICAgICAgICAgdmFyIHQgPSBMMiA+IDFlLTkgPyAoKGN4QyAtIHMueDApICogc2R4ICsgKGN5QyAtIHMueTApICogc2R5KSAvIEwyIDogMDsKICAgICAgICAgIGlmKHQgPCAwKSB0ID0gMDsgZWxzZSBpZih0ID4gMSkgdCA9IDE7CiAgICAgICAgICB2YXIgcHgyID0gcy54MCArIHNkeCAqIHQgLSBjeEM7CiAgICAgICAgICB2YXIgcHkyID0gcy55MCArIHNkeSAqIHQgLSBjeUM7CiAgICAgICAgICB2YXIgZGlzdDIgPSBweDIqcHgyICsgcHkyKnB5MjsKICAgICAgICAgIGlmKGRpc3QyIDw9IGhhbGYyKXsgY292ZXJlZFtpZHhdID0gMTsgY292ZXJlZENvdW50Kys7IGJyZWFrOyB9CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICB2YXIgY2VsbEFyZWEgPSBjZWxsU2l6ZSAqIGNlbGxTaXplOwogICAgdmFyIGZpZWxkTTIgPSBmaWVsZENlbGxDb3VudCAqIGNlbGxBcmVhOwogICAgdmFyIGNvdmVyZWRNMiA9IGNvdmVyZWRDb3VudCAqIGNlbGxBcmVhOwogICAgcmV0dXJuIHsgY292ZXJlZE0yOiBjb3ZlcmVkTTIsIGZpZWxkTTI6IGZpZWxkTTIsIHBjdDogZmllbGRNMiA+IDAgPyAoY292ZXJlZE0yIC8gZmllbGRNMiAqIDEwMCkgOiAwIH07CiAgfQoKICBmdW5jdGlvbiBjb21wdXRlTWV0cmljcyhsYXlvdXQsIHdNLCBkaWVzZWxQcmljZSwgY29uc3VtcHRpb24pewogICAgLy8gUGFzcyAodHJhbWxpbmUpIGxlbmd0aCBvbmx5IOKAlCB3aGF0IHRoZSBvcGVyYXRvciBhY3R1YWxseSB3b3JrcyBvbi4KICAgIHZhciBwYXNzTGVuID0gMDsKICAgIHZhciBuUGFzc2VzID0gbGF5b3V0LnBhc3Nlcy5sZW5ndGg7CiAgICBmb3IodmFyIGk9MDsgaTxuUGFzc2VzOyBpKyspewogICAgICB2YXIgcCA9IGxheW91dC5wYXNzZXNbaV07CiAgICAgIGlmKHAuc2FtcGxlcyl7CiAgICAgICAgZm9yKHZhciBzPTE7IHM8cC5zYW1wbGVzLmxlbmd0aDsgcysrKXsKICAgICAgICAgIHZhciBkeCA9IHAuc2FtcGxlc1tzXS54IC0gcC5zYW1wbGVzW3MtMV0ueDsKICAgICAgICAgIHZhciBkeSA9IHAuc2FtcGxlc1tzXS55IC0gcC5zYW1wbGVzW3MtMV0ueTsKICAgICAgICAgIHBhc3NMZW4gKz0gTWF0aC5zcXJ0KGR4KmR4ICsgZHkqZHkpOwogICAgICAgIH0KICAgICAgfSBlbHNlIHsKICAgICAgICB2YXIgZHhMID0gcC54MSAtIHAueDAsIGR5TCA9IHAueTEgLSBwLnkwOwogICAgICAgIHBhc3NMZW4gKz0gTWF0aC5zcXJ0KGR4TCpkeEwgKyBkeUwqZHlMKTsKICAgICAgfQogICAgfQogICAgLy8gVHVybi1hcmMgbGVuZ3RoIOKAlCB3aGF0IHRoZSBvcGVyYXRvciBkcml2ZXMgQkVUV0VFTiBwYXNzZXMgKGhlYWRlciB1cCkuCiAgICB2YXIgdHVybkxlbiA9IDA7CiAgICB2YXIgblR1cm5zID0gbGF5b3V0LnR1cm5BcmNzID8gbGF5b3V0LnR1cm5BcmNzLmxlbmd0aCA6IDA7CiAgICBpZihsYXlvdXQudHVybkFyY3MpewogICAgICBmb3IodmFyIHRpPTA7IHRpPGxheW91dC50dXJuQXJjcy5sZW5ndGg7IHRpKyspewogICAgICAgIHZhciBhcmMgPSBsYXlvdXQudHVybkFyY3NbdGldLmNvb3JkczsKICAgICAgICBmb3IodmFyIGFzPTE7IGFzPGFyYy5sZW5ndGg7IGFzKyspewogICAgICAgICAgdmFyIGR4QSA9IGFyY1thc10ueCAtIGFyY1thcy0xXS54LCBkeUEgPSBhcmNbYXNdLnkgLSBhcmNbYXMtMV0ueTsKICAgICAgICAgIHR1cm5MZW4gKz0gTWF0aC5zcXJ0KGR4QSpkeEEgKyBkeUEqZHlBKTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIC8vIFRvdGFsIGRyaXZlIHBhdGggPSB0cmFtbGluZSArIHR1cm4gYXJjcy4KICAgIC8vIFBhc3MgZnVlbCBzY2FsZXMgbGluZWFybHkgd2l0aCBjb25zdW1wdGlvbiDDlyBsZW5ndGgsIFBMVVMgYSBzbG9wZQogICAgLy8gcGVuYWx0eTogZHJpdmluZyBhbG9uZyBhIGNvbnRvdXIgbGluZSBpcyBub3JtYWwtZnVlbDsgZHJpdmluZyBhY3Jvc3MKICAgIC8vIGNvbnRvdXJzICh1cGhpbGwvZG93bmhpbGwpIHBlbmFsaXNlcyB+MTDDlyB0aGUgYWJzb2x1dGUgZ3JhZGXCsi4gUmVhbAogICAgLy8gdHJhY3RvcnMgYnVybiAzMOKAkzQwICUgbW9yZSBkaWVzZWwgYXQgYSBzdXN0YWluZWQgNSAlIHVwLWdyYWRlLgogICAgLy8gVHVybmFyb3VuZCBmdWVsIGlzIDEuMjXDlyBwZXIgbWV0cmUgYmVjYXVzZSB0aGUgZW5naW5lIHdvcmtzIGhhcmRlcgogICAgLy8gdW5kZXIgYSB0aWdodCBwaXZvdCAoaHlkcmF1bGljcyByYWlzaW5nL2xvd2VyaW5nIHRoZSBpbXBsZW1lbnQsCiAgICAvLyBnZWFyIGNoYW5nZXMpIOKAlCB0eXBpY2FsIGhlYWRsYW5kLXR1cm4gcGVuYWx0eS4KICAgIHZhciB0b3RhbExlbiA9IHBhc3NMZW4gKyB0dXJuTGVuOwogICAgdmFyIHNsb3BlUGVuYWx0eSA9IGNvbXB1dGVTbG9wZVBlbmFsdHkobGF5b3V0KTsKICAgIHZhciBwYXNzRnVlbEJhc2UgPSAocGFzc0xlbiAvIDEwMDApICogY29uc3VtcHRpb247CiAgICB2YXIgcGFzc0Z1ZWwgPSBwYXNzRnVlbEJhc2UgKiAoMSArIHNsb3BlUGVuYWx0eSk7CiAgICB2YXIgdHVybkZ1ZWwgPSAodHVybkxlbiAvIDEwMDApICogY29uc3VtcHRpb24gKiAxLjI1OwogICAgdmFyIHRvdGFsRnVlbCA9IHBhc3NGdWVsICsgdHVybkZ1ZWw7CiAgICB2YXIgY29zdCA9IHRvdGFsRnVlbCAqIGRpZXNlbFByaWNlOwogICAgLy8gQ292ZXJhZ2Ug4oCUIFJBU1RFUi1CQVNFRCBmb3IgYWNjdXJhY3kuIFN1bS1vZi1zdHJpcCBtYXRoIG92ZXJzdGF0ZWQKICAgIC8vIChkb3VibGUtY291bnRlZCBvdmVybGFwcywgaWdub3JlZCBjb3JuZXIgZ2FwcyBhbmQgaGVhZGxhbmQtcmluZyB1bmRlci1maWxsCiAgICAvLyBhdCBzaGFycCBjb3JuZXJzKSDihpIgY2xhbXBlZCB0byAxMDAlIGV2ZW4gd2hlbiB0aGUgcmVhbCBjb3ZlcmFnZSB3YXMgPDk1JS4KICAgIC8vIFRoZSBncmlkIGFwcHJvYWNoIGNvbXB1dGVzIHRoZSB0cnVlIHVuaW9uIGFyZWE6IGZvciBlYWNoIGNlbGwgd2hvc2UKICAgIC8vIGNlbnRyZSBsaWVzIGluc2lkZSB0aGUgZmllbGQgYm91bmRhcnksIGNoZWNrIGlmIGl0J3MgYWxzbyBpbnNpZGUgYW55CiAgICAvLyBzd2F0aCBzdHJpcC4gY292ZXJhZ2VQY3QgPSBjb3ZlcmVkIC8gdG90YWwuIGNlbGxTaXplIGRlZmF1bHRzIHRvIHdNLzMKICAgIC8vIHNvIGNlbGxzIGFyZSBzbWFsbGVyIHRoYW4gdGhlIHN3YXRoLCBjYXB0dXJpbmcgdW5kZXItY292ZXJhZ2UgbmVhcgogICAgLy8gY29ybmVycyBhbmQgdW5jb3ZlcmVkIHBvY2tldHMgaW4gY29uY2F2ZSBmaWVsZHMuCiAgICB2YXIgc3RhdHMgPSBmaWVsZFN0YXRzKGxheW91dC5ib3VuZGFyeSA\/IGxheW91dC5ib3VuZGFyeSA6IEJPVU5EQVJZKTsKICAgIHZhciBmaWVsZE0yID0gc3RhdHMuYXJlYTsKICAgIHZhciBjb3ZlcmFnZVJlcyA9IHJhc3RlckNvdmVyYWdlKGxheW91dCwgd00pOwogICAgdmFyIGNvdmVyZWRNMiA9IGNvdmVyYWdlUmVzLmNvdmVyZWRNMjsKICAgIHZhciBjb3ZlcmFnZVBjdCA9IGNvdmVyYWdlUmVzLnBjdDsKICAgIHJldHVybiB7CiAgICAgIHBhc3NlczogblBhc3NlcywKICAgICAgcGFzc0xlbmd0aE06IHBhc3NMZW4sCiAgICAgIHR1cm5MZW5ndGhNOiB0dXJuTGVuLAogICAgICB0b3RhbERyaXZlTTogdG90YWxMZW4sCiAgICAgIHR1cm5zOiBuVHVybnMsCiAgICAgIGZ1ZWxMOiB0b3RhbEZ1ZWwsCiAgICAgIHBhc3NGdWVsTDogcGFzc0Z1ZWwsCiAgICAgIHR1cm5GdWVsTDogdHVybkZ1ZWwsCiAgICAgIGNvc3RVU0Q6IGNvc3QsCiAgICAgIGNvdmVyYWdlUGN0OiBjb3ZlcmFnZVBjdCwKICAgICAgY292ZXJlZE0yOiBjb3ZlcmVkTTIsCiAgICAgIGZpZWxkTTI6IGZpZWxkTTIsCiAgICAgIHNsb3BlUGVuYWx0eTogc2xvcGVQZW5hbHR5LAogICAgICBhdmdHcmFkZVBjdDogbGF5b3V0LmF2Z0dyYWRlUGN0IHx8IDAKICAgIH07CiAgfQogIC8vIENvbXB1dGUgYXZlcmFnZSBncmFkZS1hbG9uZy1wYXNzLWRpcmVjdGlvbiBmb3IgYm9keSBwYXNzZXMsIHJldHVybnMKICAvLyBhIGZ1ZWwgbXVsdGlwbGllciBwZW5hbHR5ICgwID0gZmxhdCwgMC4zID0gMzAlIGV4dHJhIGZ1ZWwpLiBBbHNvIHN0b3JlcwogIC8vIHRoZSBhdmVyYWdlIGFic29sdXRlIGdyYWRlICUgb24gdGhlIGxheW91dCBmb3IgZGlzcGxheS4gUGVuYWx0eSBtb2RlbDoKICAvLyAgIHBlbmFsdHkgPSBrIMOXIG1lYW4ofGdyYWRlfMKyKSB3aGVyZSBncmFkZSA9IM6UeiAvIM6UaG9yaXpvbnRhbAogIC8vICAgayA9IDEyIOKGkiA1JSBzdXN0YWluZWQgZ3JhZGUg4oaSIDAuMDMgcGVuYWx0eSAoMyUgZXh0cmEgZnVlbCksIDE1JSBncmFkZSDihpIgMjclIGV4dHJhCiAgLy8gQ3Jvc3MtY29udG91ciBwYXNzZXMgYWNjdW11bGF0ZSBmdWxsIHNsb3BlOyBvbi1jb250b3VyIHBhc3NlcyBhY2N1bXVsYXRlIH4wLgogIGZ1bmN0aW9uIGNvbXB1dGVTbG9wZVBlbmFsdHkobGF5b3V0KXsKICAgIGlmKCFsYXlvdXQucGFzc2VzID8gdHJ1ZSA6IGxheW91dC5wYXNzZXMubGVuZ3RoID09PSAwKSByZXR1cm4gMDsKICAgIHZhciB0b3RhbExlbiA9IDA7CiAgICB2YXIgd2VpZ2h0ZWRHcmFkZTIgPSAwOwogICAgdmFyIHdlaWdodGVkQWJzR3JhZGUgPSAwOwogICAgdmFyIHNhbXBsZVN0ZXAgPSA0OyAgLy8gbWV0cmVzCiAgICBmdW5jdGlvbiBhY2N1bXVsYXRlU2VnKHgwLCB5MCwgeDEsIHkxKXsKICAgICAgdmFyIHNkeCA9IHgxIC0geDAsIHNkeSA9IHkxIC0geTA7CiAgICAgIHZhciBMID0gTWF0aC5zcXJ0KHNkeCpzZHggKyBzZHkqc2R5KTsKICAgICAgaWYoTCA8IDAuNSkgcmV0dXJuOwogICAgICB2YXIgblMgPSBNYXRoLm1heCgyLCBNYXRoLmNlaWwoTCAvIHNhbXBsZVN0ZXApKTsKICAgICAgdmFyIHowID0gdGVycmFpbkF0KHgwLCB5MCk7CiAgICAgIGZvcih2YXIgaz0xOyBrPD1uUzsgaysrKXsKICAgICAgICB2YXIgdCA9IGsgLyBuUzsKICAgICAgICB2YXIgbXggPSB4MCArIHNkeCAqIHQsIG15ID0geTAgKyBzZHkgKiB0OwogICAgICAgIHZhciB6MSA9IHRlcnJhaW5BdChteCwgbXkpOwogICAgICAgIHZhciBkaCA9IEwgLyBuUzsKICAgICAgICB2YXIgZ3JhZGUgPSBkaCA+IDFlLTYgPyAoejEgLSB6MCkgLyBkaCA6IDA7CiAgICAgICAgd2VpZ2h0ZWRHcmFkZTIgKz0gZ3JhZGUgKiBncmFkZSAqIGRoOwogICAgICAgIHdlaWdodGVkQWJzR3JhZGUgKz0gTWF0aC5hYnMoZ3JhZGUpICogZGg7CiAgICAgICAgdG90YWxMZW4gKz0gZGg7CiAgICAgICAgejAgPSB6MTsKICAgICAgfQogICAgfQogICAgZm9yKHZhciBwaT0wOyBwaTxsYXlvdXQucGFzc2VzLmxlbmd0aDsgcGkrKyl7CiAgICAgIHZhciBwYSA9IGxheW91dC5wYXNzZXNbcGldOwogICAgICBpZihwYS5raW5kID09PSAnaGVhZGxhbmQtcmluZycpIGNvbnRpbnVlOyAgLy8gcmluZyBmb2xsb3dzIGJvdW5kYXJ5LCBpZ25vcmUgc2xvcGUgY29zdAogICAgICBpZihwYS5zYW1wbGVzKXsKICAgICAgICBmb3IodmFyIHNpPTE7IHNpPHBhLnNhbXBsZXMubGVuZ3RoOyBzaSsrKXsKICAgICAgICAgIGFjY3VtdWxhdGVTZWcocGEuc2FtcGxlc1tzaS0xXS54LCBwYS5zYW1wbGVzW3NpLTFdLnksIHBhLnNhbXBsZXNbc2ldLngsIHBhLnNhbXBsZXNbc2ldLnkpOwogICAgICAgIH0KICAgICAgfSBlbHNlIGlmKHBhLngwICE9PSB1bmRlZmluZWQpewogICAgICAgIGFjY3VtdWxhdGVTZWcocGEueDAsIHBhLnkwLCBwYS54MSwgcGEueTEpOwogICAgICB9CiAgICB9CiAgICBpZih0b3RhbExlbiA8IDEpIHJldHVybiAwOwogICAgdmFyIG1lYW5HcmFkZTIgPSB3ZWlnaHRlZEdyYWRlMiAvIHRvdGFsTGVuOwogICAgdmFyIG1lYW5BYnNHcmFkZSA9IHdlaWdodGVkQWJzR3JhZGUgLyB0b3RhbExlbjsKICAgIGxheW91dC5hdmdHcmFkZVBjdCA9IG1lYW5BYnNHcmFkZSAqIDEwMDsgIC8vIGZvciBkaXNwbGF5CiAgICByZXR1cm4gMTIgKiBtZWFuR3JhZGUyOyAgLy8gcGVuYWx0eSBtdWx0aXBsaWVyCiAgfQoKICAvLyBSRU5ERVIKICB2YXIgRFBSID0gd2luZG93LmRldmljZVBpeGVsUmF0aW8gPiAxID8gd2luZG93LmRldmljZVBpeGVsUmF0aW8gOiAxOwogIGZ1bmN0aW9uIHJlc2l6ZSgpewogICAgdmFyIHJlY3QgPSBjYW52YXMuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7CiAgICBjYW52YXMud2lkdGggPSBNYXRoLmZsb29yKHJlY3Qud2lkdGggKiBEUFIpOwogICAgY2FudmFzLmhlaWdodCA9IE1hdGguZmxvb3IocmVjdC5oZWlnaHQgKiBEUFIpOwogICAgY3R4LnNldFRyYW5zZm9ybShEUFIsIDAsIDAsIERQUiwgMCwgMCk7CiAgfQogIC8vIFZpZXcgdHJhbnNmb3JtIOKAlCBmaXQtdG8tZmllbGQgaXMgdGhlIGJhc2UsIHRoZW4gdXNlciBjYW4gem9vbS9wYW4gYXJvdW5kLgogIHZhciB2aWV3ID0geyB6b29tOiAxLCBwYW5YOiAwLCBwYW5ZOiAwIH07CiAgZnVuY3Rpb24gZ2V0U2NhbGUoKXsKICAgIHZhciByZWN0ID0gY2FudmFzLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOwogICAgdmFyIHBhZCA9IDM2OwogICAgdmFyIHMgPSBmaWVsZFN0YXRzKEJPVU5EQVJZKTsKICAgIHZhciBzeCA9IChyZWN0LndpZHRoIC0gcGFkICogMikgLyAocy5tYXhYIC0gcy5taW5YKTsKICAgIHZhciBzeSA9IChyZWN0LmhlaWdodCAtIHBhZCAqIDIpIC8gKHMubWF4WSAtIHMubWluWSk7CiAgICB2YXIgc2MgPSAoc3ggPCBzeSA\/IHN4IDogc3kpICogdmlldy56b29tOwogICAgdmFyIGJhc2VUeCA9IHBhZCAtIHMubWluWCAqIHNjICsgKHJlY3Qud2lkdGggLSBwYWQgKiAyIC0gKHMubWF4WCAtIHMubWluWCkgKiBzYykgLyAyOwogICAgdmFyIGJhc2VUeSA9IHBhZCAtIHMubWluWSAqIHNjICsgKHJlY3QuaGVpZ2h0IC0gcGFkICogMiAtIChzLm1heFkgLSBzLm1pblkpICogc2MpIC8gMjsKICAgIHJldHVybiB7IHNjOiBzYywgdHg6IGJhc2VUeCArIHZpZXcucGFuWCwgdHk6IGJhc2VUeSArIHZpZXcucGFuWSB9OwogIH0KICBmdW5jdGlvbiBweChwcm9qLCB4KXsgcmV0dXJuIHggKiBwcm9qLnNjICsgcHJvai50eDsgfQogIGZ1bmN0aW9uIHB5KHByb2osIHkpeyByZXR1cm4geSAqIHByb2ouc2MgKyBwcm9qLnR5OyB9CiAgLy8gSW52ZXJzZTogc2NyZWVuIOKGkiB3b3JsZCBjb29yZGluYXRlcyAodXNlZCBieSBydWxlciArIHBhbikuCiAgZnVuY3Rpb24gd29ybGRYKHByb2osIHN4KXsgcmV0dXJuIChzeCAtIHByb2oudHgpIC8gcHJvai5zYzsgfQogIGZ1bmN0aW9uIHdvcmxkWShwcm9qLCBzeSl7IHJldHVybiAoc3kgLSBwcm9qLnR5KSAvIHByb2ouc2M7IH0KCiAgLy8gVW5pdCArIHJ1bGVyIHN0YXRlCiAgdmFyIHVuaXQgPSAna20nOwogIHZhciBydWxlciA9IHsgYWN0aXZlOiBmYWxzZSwgcDE6IG51bGwsIHAyOiBudWxsIH07CiAgZnVuY3Rpb24gZm10RGlzdChtZXRyZXMpewogICAgaWYodW5pdCA9PT0gJ21pJyl7CiAgICAgIHZhciBtaSA9IG1ldHJlcyAvIDE2MDkuMzQ0OwogICAgICBpZihtaSA+PSAwLjIpIHJldHVybiBtaS50b0ZpeGVkKDIpICsgJyBtaSc7CiAgICAgIHZhciBmdCA9IG1ldHJlcyAqIDMuMjgwODQ7CiAgICAgIHJldHVybiBmdC50b0ZpeGVkKDApICsgJyBmdCc7CiAgICB9CiAgICBpZihtZXRyZXMgPj0gMTAwMCkgcmV0dXJuIChtZXRyZXMgLyAxMDAwKS50b0ZpeGVkKDIpICsgJyBrbSc7CiAgICByZXR1cm4gbWV0cmVzLnRvRml4ZWQoMCkgKyAnIG0nOwogIH0KCiAgLy8gUExBWUJBQ0sgU1RBVEUg4oCUIGFuaW1hdGVzIGEgdHJhY3RvciBzcHJpdGUgYWxvbmcgdGhlIGRyaXZlIHBhdGggd2l0aCBhCiAgLy8gZ3JhZHVhbGx5LWZpbGxpbmcgc3dhdGggYmFuZCBiZWhpbmQgaXQuIFNwZWVkIGlzICJ3YWxsLWNsb2NrIMOXIG11bHRpcGxpZXIiOwogIC8vIHdlIG1hcCB+MSBrbSBvZiBkcml2ZS1wYXRoIHBlciBzZWNvbmQgb2Ygd2FsbCBjbG9jayBhdCAxw5cgc28gYSB0eXBpY2FsCiAgLy8gZmllbGQgcGxheXMgb3V0IGluIDEw4oCTMjAgcy4KICB2YXIgcGxheWJhY2sgPSB7CiAgICBpc1BsYXlpbmc6IGZhbHNlLAogICAgdDogMCwgICAgICAgICAgICAgIC8vIDAuLjEgcHJvZ3Jlc3MgYWxvbmcgdG90YWwgZHJpdmUtcGF0aCBsZW5ndGgKICAgIHNwZWVkOiAxLCAgICAgICAgICAvLyAxIC8gMiAvIDQgbXVsdGlwbGllcgogICAgZHJpdmVQYXRoOiBbXSwKICAgIGN1bUxlbjogWzBdLCAgICAgICAvLyBjdW11bGF0aXZlIGxlbmd0aCB0byBlYWNoIHZlcnRleAogICAgdG90YWxMZW46IDAsICAgICAgIC8vIG1ldHJlcwogICAgd006IDE4LCAgICAgICAgICAgIC8vIGltcGxlbWVudCB3aWR0aCBmb3Igc3dhdGgKICAgIGxhc3RUaWNrOiAwCiAgfTsKICAvLyBCdWlsZCAob3IgcmVidWlsZCkgdGhlIHBsYXliYWNrIHBhdGggZnJvbSBhIGxheW91dC4gUmVzZXRzIHByb2dyZXNzLgogIC8vIFN1YmRpdmlkZXMgbG9uZyBzZWdtZW50cyAobGluZS1iYXNlZCBwYXNzZXMgY2FuIGJlIDYwMCBtIGVuZC10by1lbmQpIHNvCiAgLy8gdGhlIHNwcml0ZSBhZHZhbmNlcyBzbW9vdGhseSBpbnN0ZWFkIG9mIHNraXBwaW5nIGluIGJpZyBjaHVua3MgKHdoaWNoCiAgLy8gbG9va2VkIGxpa2UgInRlbGVwb3J0cyIgYXQgNMOXIHNwZWVkKS4KICBmdW5jdGlvbiBzZXRQbGF5YmFja1BhdGgobGF5b3V0LCB3TSl7CiAgICB2YXIgcmF3ID0gbGF5b3V0LmRyaXZlUGF0aCA\/IGxheW91dC5kcml2ZVBhdGggOiBbXTsKICAgIHZhciBtYXhTdGVwID0gTWF0aC5tYXgoMiwgd00pOyAgLy8gbmV2ZXIgZXhjZWVkIG9uZSBpbXBsZW1lbnQtd2lkdGggcGVyIGRyaXZlLXBhdGggc2VnbWVudAogICAgdmFyIGRlbnNlID0gW107CiAgICBmb3IodmFyIGs9MDsgazxyYXcubGVuZ3RoOyBrKyspewogICAgICBpZihrID09PSAwKXsgZGVuc2UucHVzaChyYXdbMF0pOyBjb250aW51ZTsgfQogICAgICB2YXIgcHJldiA9IHJhd1trIC0gMV0sIGN1ciA9IHJhd1trXTsKICAgICAgdmFyIGRkeCA9IGN1ci54IC0gcHJldi54LCBkZHkgPSBjdXIueSAtIHByZXYueTsKICAgICAgdmFyIGRsZW4gPSBNYXRoLnNxcnQoZGR4KmRkeCArIGRkeSpkZHkpOwogICAgICBpZihkbGVuID4gbWF4U3RlcCl7CiAgICAgICAgdmFyIG5TdWIgPSBNYXRoLmNlaWwoZGxlbiAvIG1heFN0ZXApOwogICAgICAgIGZvcih2YXIgbnM9MTsgbnM8blN1YjsgbnMrKyl7CiAgICAgICAgICB2YXIgZiA9IG5zIC8gblN1YjsKICAgICAgICAgIGRlbnNlLnB1c2goeyB4OiBwcmV2LnggKyBkZHggKiBmLCB5OiBwcmV2LnkgKyBkZHkgKiBmIH0pOwogICAgICAgIH0KICAgICAgfQogICAgICBkZW5zZS5wdXNoKGN1cik7CiAgICB9CiAgICBwbGF5YmFjay5kcml2ZVBhdGggPSBkZW5zZTsKICAgIHBsYXliYWNrLndNID0gd007CiAgICBwbGF5YmFjay5jdW1MZW4gPSBbMF07CiAgICB2YXIgdG90YWwgPSAwOwogICAgZm9yKHZhciBpPTE7IGk8cGxheWJhY2suZHJpdmVQYXRoLmxlbmd0aDsgaSsrKXsKICAgICAgdmFyIGR4ID0gcGxheWJhY2suZHJpdmVQYXRoW2ldLnggLSBwbGF5YmFjay5kcml2ZVBhdGhbaS0xXS54OwogICAgICB2YXIgZHkgPSBwbGF5YmFjay5kcml2ZVBhdGhbaV0ueSAtIHBsYXliYWNrLmRyaXZlUGF0aFtpLTFdLnk7CiAgICAgIHRvdGFsICs9IE1hdGguc3FydChkeCpkeCArIGR5KmR5KTsKICAgICAgcGxheWJhY2suY3VtTGVuLnB1c2godG90YWwpOwogICAgfQogICAgcGxheWJhY2sudG90YWxMZW4gPSB0b3RhbDsKICAgIHBsYXliYWNrLnQgPSAwOwogICAgdXBkYXRlUGxheWJhY2tVSSgpOwogIH0KICAvLyBSZXR1cm4gdGhlICh4LCB5LCBoZWFkaW5nUmFkKSBhdCBwYXJhbWV0cmljIHBvc2l0aW9uIHQgKDAuLjEpIGFsb25nIHRoZSBwYXRoLgogIGZ1bmN0aW9uIHBsYXliYWNrUG9zQXQodCl7CiAgICBpZihwbGF5YmFjay5kcml2ZVBhdGgubGVuZ3RoIDwgMikgcmV0dXJuIG51bGw7CiAgICB2YXIgdGFyZ2V0ID0gdCAqIHBsYXliYWNrLnRvdGFsTGVuOwogICAgdmFyIGxvID0gMCwgaGkgPSBwbGF5YmFjay5jdW1MZW4ubGVuZ3RoIC0gMTsKICAgIHdoaWxlKGxvIDwgaGkpewogICAgICB2YXIgbWlkID0gKGxvICsgaGkgKyAxKSA+PiAxOwogICAgICBpZihwbGF5YmFjay5jdW1MZW5bbWlkXSA8PSB0YXJnZXQpIGxvID0gbWlkOyBlbHNlIGhpID0gbWlkIC0gMTsKICAgIH0KICAgIGlmKGxvID49IHBsYXliYWNrLmRyaXZlUGF0aC5sZW5ndGggLSAxKSBsbyA9IHBsYXliYWNrLmRyaXZlUGF0aC5sZW5ndGggLSAyOwogICAgdmFyIHNlZ0xlbiA9IHBsYXliYWNrLmN1bUxlbltsbyArIDFdIC0gcGxheWJhY2suY3VtTGVuW2xvXTsKICAgIHZhciBmID0gc2VnTGVuID4gMWUtNiA\/ICh0YXJnZXQgLSBwbGF5YmFjay5jdW1MZW5bbG9dKSAvIHNlZ0xlbiA6IDA7CiAgICB2YXIgcDAgPSBwbGF5YmFjay5kcml2ZVBhdGhbbG9dOwogICAgdmFyIHAxID0gcGxheWJhY2suZHJpdmVQYXRoW2xvICsgMV07CiAgICByZXR1cm4gewogICAgICB4OiBwMC54ICsgKHAxLnggLSBwMC54KSAqIGYsCiAgICAgIHk6IHAwLnkgKyAocDEueSAtIHAwLnkpICogZiwKICAgICAgaGVhZGluZzogTWF0aC5hdGFuMihwMS55IC0gcDAueSwgcDEueCAtIHAwLngpLAogICAgICBzZWdJZHg6IGxvCiAgICB9OwogIH0KICBmdW5jdGlvbiB1cGRhdGVQbGF5YmFja1VJKCl7CiAgICB2YXIgZmlsbEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1wYi1maWxsJyk7CiAgICB2YXIgdGh1bWJFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtcGItdGh1bWInKTsKICAgIHZhciBzdGF0c0VsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1wYi1zdGF0cycpOwogICAgdmFyIHBjdCA9IChwbGF5YmFjay50ICogMTAwKS50b0ZpeGVkKDApOwogICAgaWYoZmlsbEVsKSBmaWxsRWwuc3R5bGUud2lkdGggPSBwY3QgKyAnJSc7CiAgICBpZih0aHVtYkVsKSB0aHVtYkVsLnN0eWxlLmxlZnQgPSBwY3QgKyAnJSc7CiAgICBpZihzdGF0c0VsKXsKICAgICAgc3RhdHNFbC50ZXh0Q29udGVudCA9IHBjdCArICclIMK3ICcgKyBmbXREaXN0KHBsYXliYWNrLnQgKiBwbGF5YmFjay50b3RhbExlbikgKyAnIC8gJyArIGZtdERpc3QocGxheWJhY2sudG90YWxMZW4pOwogICAgfQogIH0KICBmdW5jdGlvbiBkcmF3U3dhdGgocHJvail7CiAgICBpZihwbGF5YmFjay5kcml2ZVBhdGgubGVuZ3RoIDwgMiA\/IHRydWUgOiBwbGF5YmFjay50IDw9IDApIHJldHVybjsKICAgIHZhciB0YXJnZXQgPSBwbGF5YmFjay50ICogcGxheWJhY2sudG90YWxMZW47CiAgICB2YXIgaGFsZlcgPSBwbGF5YmFjay53TSAqIDAuNSAqIHByb2ouc2M7CiAgICBpZihoYWxmVyA8IDEpIGhhbGZXID0gMTsKICAgIGN0eC5zYXZlKCk7CiAgICBjdHguc3Ryb2tlU3R5bGUgPSAncmdiYSgyNDcsMTA2LDEyLDAuMzIpJzsKICAgIGN0eC5saW5lV2lkdGggPSBoYWxmVyAqIDI7CiAgICBjdHgubGluZUNhcCA9ICdyb3VuZCc7CiAgICBjdHgubGluZUpvaW4gPSAncm91bmQnOwogICAgY3R4LmJlZ2luUGF0aCgpOwogICAgY3R4Lm1vdmVUbyhweChwcm9qLCBwbGF5YmFjay5kcml2ZVBhdGhbMF0ueCksIHB5KHByb2osIHBsYXliYWNrLmRyaXZlUGF0aFswXS55KSk7CiAgICBmb3IodmFyIGk9MTsgaTxwbGF5YmFjay5kcml2ZVBhdGgubGVuZ3RoOyBpKyspewogICAgICBpZihwbGF5YmFjay5jdW1MZW5baV0gPD0gdGFyZ2V0KXsKICAgICAgICBjdHgubGluZVRvKHB4KHByb2osIHBsYXliYWNrLmRyaXZlUGF0aFtpXS54KSwgcHkocHJvaiwgcGxheWJhY2suZHJpdmVQYXRoW2ldLnkpKTsKICAgICAgfSBlbHNlIHsKICAgICAgICB2YXIgc2VnTGVuID0gcGxheWJhY2suY3VtTGVuW2ldIC0gcGxheWJhY2suY3VtTGVuW2ktMV07CiAgICAgICAgdmFyIGYgPSBzZWdMZW4gPiAxZS02ID8gKHRhcmdldCAtIHBsYXliYWNrLmN1bUxlbltpLTFdKSAvIHNlZ0xlbiA6IDA7CiAgICAgICAgdmFyIGV4ID0gcGxheWJhY2suZHJpdmVQYXRoW2ktMV0ueCArIChwbGF5YmFjay5kcml2ZVBhdGhbaV0ueCAtIHBsYXliYWNrLmRyaXZlUGF0aFtpLTFdLngpICogZjsKICAgICAgICB2YXIgZXkgPSBwbGF5YmFjay5kcml2ZVBhdGhbaS0xXS55ICsgKHBsYXliYWNrLmRyaXZlUGF0aFtpXS55IC0gcGxheWJhY2suZHJpdmVQYXRoW2ktMV0ueSkgKiBmOwogICAgICAgIGN0eC5saW5lVG8ocHgocHJvaiwgZXgpLCBweShwcm9qLCBleSkpOwogICAgICAgIGJyZWFrOwogICAgICB9CiAgICB9CiAgICBjdHguc3Ryb2tlKCk7CiAgICBjdHgucmVzdG9yZSgpOwogIH0KICAvLyBHZW9QYXJkLWJyYW5kIGVsZXZhdGlvbiByYWluYm93OiA1IGtleXBvaW50cyBzcGFubmluZyB0IOKIiCBbMCwgMV0KICAvLyAgIDAuMDAg4oaSIGRlZXAgcHVycGxlIChsb3cpCiAgLy8gICAwLjI1IOKGkiB0ZWFsIC8gY3lhbgogIC8vICAgMC41MCDihpIgc29mdCB5ZWxsb3cKICAvLyAgIDAuNzUg4oaSIG9yYW5nZQogIC8vICAgMS4wMCDihpIgcmVkIChoaWdoKQogIC8vIExpbmVhcmx5IGludGVycG9sYXRlZCBiZXR3ZWVuIGFkamFjZW50IHN0b3BzIGluIFJHQiBzcGFjZS4gTWF0Y2hlcyB0aGUKICAvLyBjb2xvdXIgc2NoZW1lIHVzZWQgaW4gdGhlIEdlb1BhcmQgUGxhdGZvcm0ncyBlbGV2YXRpb24gbGVnZW5kLgogIHZhciBFTEVWX1NUT1BTID0gWwogICAgWzEwOSwgIDc5LCAxNjJdLCAgIC8vIDAuMDAg4oCUIHB1cnBsZQogICAgWyA3OCwgMTkyLCAxNjddLCAgIC8vIDAuMjUg4oCUIHRlYWwKICAgIFsyNTUsIDIzMiwgMTMwXSwgICAvLyAwLjUwIOKAlCB5ZWxsb3cKICAgIFsyNDUsIDE2OCwgIDkyXSwgICAvLyAwLjc1IOKAlCBvcmFuZ2UKICAgIFsyMTksICA4MCwgIDgwXSAgICAvLyAxLjAwIOKAlCByZWQKICBdOwogIGZ1bmN0aW9uIGVsZXZDb2xvcih0KXsKICAgIGlmKHQgPD0gMCkgcmV0dXJuIEVMRVZfU1RPUFNbMF07CiAgICBpZih0ID49IDEpIHJldHVybiBFTEVWX1NUT1BTW0VMRVZfU1RPUFMubGVuZ3RoIC0gMV07CiAgICB2YXIgc2VnID0gdCAqIChFTEVWX1NUT1BTLmxlbmd0aCAtIDEpOwogICAgdmFyIGkgPSBNYXRoLmZsb29yKHNlZyk7CiAgICB2YXIgZiA9IHNlZyAtIGk7CiAgICB2YXIgYSA9IEVMRVZfU1RPUFNbaV0sIGIgPSBFTEVWX1NUT1BTW2kgKyAxXTsKICAgIHJldHVybiBbCiAgICAgIE1hdGgucm91bmQoYVswXSArIChiWzBdIC0gYVswXSkgKiBmKSwKICAgICAgTWF0aC5yb3VuZChhWzFdICsgKGJbMV0gLSBhWzFdKSAqIGYpLAogICAgICBNYXRoLnJvdW5kKGFbMl0gKyAoYlsyXSAtIGFbMl0pICogZikKICAgIF07CiAgfQogIC8vIFRlcnJhaW4gaGVhdG1hcCDigJQgdHJhbnNsdWNlbnQgcmFpbmJvdyBncmFkaWVudCBzaG93aW5nIGVsZXZhdGlvbi4KICAvLyBIaWdoZXIgY2VsbCBkZW5zaXR5ICg0OMOXMzYpICsgR2VvUGFyZCBicmFuZCBjb2xvdXJzIEAgMC42IGFscGhhIHNvIHRoZQogIC8vIGVsZXZhdGlvbiBwYXR0ZXJuIHJlYWRzIGNsZWFybHkgd2hpbGUgcGFzc2VzIC8gYXJjcyAvIHNwcml0ZSBzdGF5IGxlZ2libGUuCiAgZnVuY3Rpb24gZHJhd1RlcnJhaW4ocHJvail7CiAgICBpZihjdXJyZW50RmllbGQgPT09ICdjdXN0b20nKSByZXR1cm47ICAvLyBubyBzeW50aGV0aWMgdGVycmFpbiBmb3IgdXBsb2FkZWQKICAgIHZhciBzdGF0cyA9IGZpZWxkU3RhdHMoQk9VTkRBUlkpOwogICAgdmFyIG54ID0gNDgsIG55ID0gMzY7CiAgICB2YXIgZHggPSAoc3RhdHMubWF4WCAtIHN0YXRzLm1pblgpIC8gbng7CiAgICB2YXIgZHkgPSAoc3RhdHMubWF4WSAtIHN0YXRzLm1pblkpIC8gbnk7CiAgICAvLyBGaW5kIGVsZXZhdGlvbiByYW5nZSBhY3Jvc3MgY2VsbHMgaW5zaWRlIHRoZSBib3VuZGFyeQogICAgdmFyIGxvID0gSW5maW5pdHksIGhpID0gLUluZmluaXR5OwogICAgdmFyIGdyaWQgPSBuZXcgRmxvYXQzMkFycmF5KG54ICogbnkpOwogICAgZm9yKHZhciBpeT0wOyBpeTxueTsgaXkrKyl7CiAgICAgIGZvcih2YXIgaXg9MDsgaXg8bng7IGl4KyspewogICAgICAgIHZhciBjeCA9IHN0YXRzLm1pblggKyAoaXggKyAwLjUpICogZHg7CiAgICAgICAgdmFyIGN5ID0gc3RhdHMubWluWSArIChpeSArIDAuNSkgKiBkeTsKICAgICAgICB2YXIgeiA9IHRlcnJhaW5BdChjeCwgY3kpOwogICAgICAgIGdyaWRbaXkgKiBueCArIGl4XSA9IHo7CiAgICAgICAgaWYocG9pbnRJblBvbHkoY3gsIGN5LCBCT1VOREFSWSkpewogICAgICAgICAgaWYoeiA8IGxvKSBsbyA9IHo7CiAgICAgICAgICBpZih6ID4gaGkpIGhpID0gejsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIGlmKGhpIC0gbG8gPCAwLjUpIHJldHVybjsKICAgIGN0eC5zYXZlKCk7CiAgICBmb3IodmFyIGl5Mj0wOyBpeTI8bnk7IGl5MisrKXsKICAgICAgZm9yKHZhciBpeDI9MDsgaXgyPG54OyBpeDIrKyl7CiAgICAgICAgdmFyIGN4MiA9IHN0YXRzLm1pblggKyAoaXgyICsgMC41KSAqIGR4OwogICAgICAgIHZhciBjeTIgPSBzdGF0cy5taW5ZICsgKGl5MiArIDAuNSkgKiBkeTsKICAgICAgICBpZighcG9pbnRJblBvbHkoY3gyLCBjeTIsIEJPVU5EQVJZKSkgY29udGludWU7CiAgICAgICAgdmFyIHoyID0gZ3JpZFtpeTIgKiBueCArIGl4Ml07CiAgICAgICAgdmFyIHQgPSAoejIgLSBsbykgLyAoaGkgLSBsbyk7CiAgICAgICAgdmFyIGMgPSBlbGV2Q29sb3IodCk7CiAgICAgICAgY3R4LmZpbGxTdHlsZSA9ICdyZ2JhKCcgKyBjWzBdICsgJywnICsgY1sxXSArICcsJyArIGNbMl0gKyAnLDAuNiknOwogICAgICAgIHZhciB4MCA9IHB4KHByb2osIHN0YXRzLm1pblggKyBpeDIgKiBkeCk7CiAgICAgICAgdmFyIHkwID0gcHkocHJvaiwgc3RhdHMubWluWSArIGl5MiAqIGR5KTsKICAgICAgICB2YXIgeDEgPSBweChwcm9qLCBzdGF0cy5taW5YICsgKGl4MiArIDEpICogZHgpOwogICAgICAgIHZhciB5MSA9IHB5KHByb2osIHN0YXRzLm1pblkgKyAoaXkyICsgMSkgKiBkeSk7CiAgICAgICAgY3R4LmZpbGxSZWN0KHgwIC0gMC41LCB5MCAtIDAuNSwgKHgxIC0geDApICsgMSwgKHkxIC0geTApICsgMSk7CiAgICAgIH0KICAgIH0KICAgIGN0eC5yZXN0b3JlKCk7CiAgfQoKICAvLyBTb2lsIGNvbXBhY3Rpb24gem9uZXMg4oCUIHdoZXJldmVyIHRoZSBtYWNoaW5lIHR1cm5zIGFyb3VuZCwgaXQncyBjb21wYWN0aW5nCiAgLy8gdGhlIGhlYWRsYW5kIHN0cmlwIHNvaWwgd2l0aCBleHRyYSBwYXNzZXMuIFZpc3VhbGlzZSBhcyB0cmFuc2x1Y2VudCB2aW9sZXQKICAvLyBzdHJva2VzIHVuZGVyIGVhY2ggdHVybi1hcmMgc3dhdGg7IG11bHRpcGxlIG5lYXJieSBhcmNzIGFkZGl0aXZlbHkgZGFya2VuCiAgLy8gdGhlIHNhbWUgYXJlYSwgbWFraW5nIGhlYXZ5LWNvbXBhY3Rpb24gY2x1c3RlcnMgdmlzaWJsZS4KICBmdW5jdGlvbiBkcmF3Q29tcGFjdGlvblpvbmVzKHByb2osIGxheW91dCl7CiAgICBpZighbGF5b3V0LnR1cm5BcmNzID8gdHJ1ZSA6IGxheW91dC50dXJuQXJjcy5sZW5ndGggPT09IDApIHJldHVybjsKICAgIHZhciBoYWxmVyA9IHBsYXliYWNrLndNICogMC41ICogcHJvai5zYzsKICAgIGlmKGhhbGZXIDwgMSkgaGFsZlcgPSAxOwogICAgY3R4LnNhdmUoKTsKICAgIGN0eC5zdHJva2VTdHlsZSA9ICdyZ2JhKDE2MiwyOCwxNzUsMC4yMiknOyAgLy8gdmlvbGV0LCAyMiUgYWxwaGEgc28gb3ZlcmxhcHMgc3RhY2sgdmlzaWJseQogICAgY3R4LmxpbmVXaWR0aCA9IGhhbGZXICogMjsKICAgIGN0eC5saW5lQ2FwID0gJ3JvdW5kJzsKICAgIGN0eC5saW5lSm9pbiA9ICdyb3VuZCc7CiAgICBmb3IodmFyIHRpPTA7IHRpPGxheW91dC50dXJuQXJjcy5sZW5ndGg7IHRpKyspewogICAgICB2YXIgYXJjID0gbGF5b3V0LnR1cm5BcmNzW3RpXTsKICAgICAgaWYoYXJjLmNvb3Jkcy5sZW5ndGggPCAyKSBjb250aW51ZTsKICAgICAgY3R4LmJlZ2luUGF0aCgpOwogICAgICBjdHgubW92ZVRvKHB4KHByb2osIGFyYy5jb29yZHNbMF0ueCksIHB5KHByb2osIGFyYy5jb29yZHNbMF0ueSkpOwogICAgICBmb3IodmFyIGFjPTE7IGFjPGFyYy5jb29yZHMubGVuZ3RoOyBhYysrKXsKICAgICAgICBjdHgubGluZVRvKHB4KHByb2osIGFyYy5jb29yZHNbYWNdLngpLCBweShwcm9qLCBhcmMuY29vcmRzW2FjXS55KSk7CiAgICAgIH0KICAgICAgY3R4LnN0cm9rZSgpOwogICAgfQogICAgY3R4LnJlc3RvcmUoKTsKICB9CiAgLy8gRGlyZWN0aW9uIGFycm93cyDigJQgc21hbGwgY2hldnJvbiBhdCB0aGUgbWlkZGxlIG9mIGVhY2ggcGFzcyArIGFyYywgcG9pbnRpbmcKICAvLyBhbG9uZyB0aGUgZHJpdmUgZGlyZWN0aW9uLiBNYWtlcyB0aGUgc25ha2Uvc2VycGVudGluZSBmbG93IHZpc2libGUuCiAgZnVuY3Rpb24gZHJhd0RpcmVjdGlvbkFycm93cyhwcm9qLCBsYXlvdXQpewogICAgdmFyIGFycm93UHggPSA4OwogICAgZnVuY3Rpb24gZHJhd0Fycm93KG1pZFgsIG1pZFksIGhlYWRpbmdSYWQsIGNvbG9yKXsKICAgICAgY3R4LnNhdmUoKTsKICAgICAgY3R4LnRyYW5zbGF0ZShtaWRYLCBtaWRZKTsKICAgICAgY3R4LnJvdGF0ZShoZWFkaW5nUmFkKTsKICAgICAgY3R4LmZpbGxTdHlsZSA9IGNvbG9yOwogICAgICBjdHguYmVnaW5QYXRoKCk7CiAgICAgIGN0eC5tb3ZlVG8oYXJyb3dQeCwgMCk7CiAgICAgIGN0eC5saW5lVG8oLWFycm93UHggKiAwLjYsIC1hcnJvd1B4ICogMC42KTsKICAgICAgY3R4LmxpbmVUbygtYXJyb3dQeCAqIDAuNiwgYXJyb3dQeCAqIDAuNik7CiAgICAgIGN0eC5jbG9zZVBhdGgoKTsKICAgICAgY3R4LmZpbGwoKTsKICAgICAgY3R4LnJlc3RvcmUoKTsKICAgIH0KICAgIC8vIFBhc3MgYXJyb3dzIOKAlCBvcmFuZ2UgdG8gbWF0Y2ggdGhlIHBhc3Mgc3Ryb2tlcy4gVXNlIG9yZGVyZWRQYXNzZXMKICAgIC8vIChwb3N0LXNuYWtlLCBkcml2ZS1kaXJlY3Rpb24gb3JpZW50ZWQpIHNvIGNoZXZyb25zIG1hdGNoIGFjdHVhbCBmbG93OgogICAgLy8gb2RkIHBhc3NlcyBnZXQgcmV2ZXJzZWQgYXJyb3dzLCBtaXJyb3JpbmcgdGhlIG9wZXJhdG9yJ3MgcmV2ZXJzZSBkcml2ZS4KICAgIHZhciBwYXNzTGlzdCA9IGxheW91dC5vcmRlcmVkUGFzc2VzID8gbGF5b3V0Lm9yZGVyZWRQYXNzZXMgOiBsYXlvdXQucGFzc2VzOwogICAgaWYocGFzc0xpc3QpewogICAgICBmb3IodmFyIHA9MDsgcDxwYXNzTGlzdC5sZW5ndGg7IHArKyl7CiAgICAgICAgdmFyIHBhID0gcGFzc0xpc3RbcF07CiAgICAgICAgaWYocGEua2luZCA9PT0gJ2hlYWRsYW5kLXJpbmcnKSBjb250aW51ZTsKICAgICAgICB2YXIgYXgsIGF5LCBieCwgYnk7CiAgICAgICAgaWYocGEuc2FtcGxlcyA\/IHBhLnNhbXBsZXMubGVuZ3RoID49IDIgOiBmYWxzZSl7CiAgICAgICAgICB2YXIgbWlkSSA9IE1hdGguZmxvb3IocGEuc2FtcGxlcy5sZW5ndGggLyAyKTsKICAgICAgICAgIGF4ID0gcGEuc2FtcGxlc1ttaWRJIC0gMV0ueDsgYXkgPSBwYS5zYW1wbGVzW21pZEkgLSAxXS55OwogICAgICAgICAgYnggPSBwYS5zYW1wbGVzW21pZEldLng7ICAgICBieSA9IHBhLnNhbXBsZXNbbWlkSV0ueTsKICAgICAgICB9IGVsc2UgaWYocGEueDAgIT09IHVuZGVmaW5lZCl7CiAgICAgICAgICBheCA9IHBhLngwOyBheSA9IHBhLnkwOyBieCA9IHBhLngxOyBieSA9IHBhLnkxOwogICAgICAgIH0gZWxzZSBjb250aW51ZTsKICAgICAgICB2YXIgbWlkWCA9IHB4KHByb2osIChheCArIGJ4KSAqIDAuNSk7CiAgICAgICAgdmFyIG1pZFkgPSBweShwcm9qLCAoYXkgKyBieSkgKiAwLjUpOwogICAgICAgIGRyYXdBcnJvdyhtaWRYLCBtaWRZLCBNYXRoLmF0YW4yKGJ5IC0gYXksIGJ4IC0gYXgpLCAnI2Y3NmEwYycpOwogICAgICB9CiAgICB9CiAgICAvLyBUdXJuYXJvdW5kIGFycm93cyDigJQgdmlvbGV0LCBoYWxmd2F5IHRocm91Z2ggdGhlIGFyYwogICAgaWYobGF5b3V0LnR1cm5BcmNzKXsKICAgICAgZm9yKHZhciB0aT0wOyB0aTxsYXlvdXQudHVybkFyY3MubGVuZ3RoOyB0aSsrKXsKICAgICAgICB2YXIgYXJjID0gbGF5b3V0LnR1cm5BcmNzW3RpXS5jb29yZHM7CiAgICAgICAgaWYoYXJjLmxlbmd0aCA8IDMpIGNvbnRpbnVlOwogICAgICAgIHZhciBtaSA9IE1hdGguZmxvb3IoYXJjLmxlbmd0aCAvIDIpOwogICAgICAgIHZhciBhWCA9IGFyY1ttaSAtIDFdLngsIGFZID0gYXJjW21pIC0gMV0ueTsKICAgICAgICB2YXIgYlggPSBhcmNbbWldLngsICAgICBiWSA9IGFyY1ttaV0ueTsKICAgICAgICB2YXIgYW1YID0gcHgocHJvaiwgKGFYICsgYlgpICogMC41KTsKICAgICAgICB2YXIgYW1ZID0gcHkocHJvaiwgKGFZICsgYlkpICogMC41KTsKICAgICAgICBkcmF3QXJyb3coYW1YLCBhbVksIE1hdGguYXRhbjIoYlkgLSBhWSwgYlggLSBhWCksICcjYTIxY2FmJyk7CiAgICAgIH0KICAgIH0KICB9CiAgZnVuY3Rpb24gZHJhd1Nwcml0ZShwcm9qKXsKICAgIHZhciBwb3MgPSBwbGF5YmFja1Bvc0F0KHBsYXliYWNrLnQpOwogICAgaWYoIXBvcykgcmV0dXJuOwogICAgdmFyIGhhbGZXID0gcGxheWJhY2sud00gKiAwLjUgKiBwcm9qLnNjOwogICAgaWYoaGFsZlcgPCA2KSBoYWxmVyA9IDY7CiAgICB2YXIgYm9keUxlbiA9IE1hdGgubWF4KDEwLCBoYWxmVyAqIDAuNik7CiAgICBjdHguc2F2ZSgpOwogICAgY3R4LnRyYW5zbGF0ZShweChwcm9qLCBwb3MueCksIHB5KHByb2osIHBvcy55KSk7CiAgICBjdHgucm90YXRlKHBvcy5oZWFkaW5nKTsKICAgIC8vIEltcGxlbWVudCBiYXIgKHRoZSB3aWRlIHBpZWNlIGJlaGluZCB0aGUgY2FiIOKAlCBvcmFuZ2UgdG8gbWF0Y2ggcGFzc2VzKQogICAgY3R4LmZpbGxTdHlsZSA9ICcjZjc2YTBjJzsKICAgIGN0eC5maWxsUmVjdCgtYm9keUxlbiAqIDAuNCwgLWhhbGZXLCBib2R5TGVuICogMC4zNSwgaGFsZlcgKiAyKTsKICAgIC8vIFRyYWN0b3IgY2FiIChjb21wYWN0IGRhcmstZ3JlZW4gYmxvY2sgaW4gZnJvbnQgb2YgdGhlIGltcGxlbWVudCkKICAgIGN0eC5maWxsU3R5bGUgPSAnIzE0NTMyOCc7CiAgICBjdHguZmlsbFJlY3QoMCwgLWJvZHlMZW4gKiAwLjM1LCBib2R5TGVuICogMC41NSwgYm9keUxlbiAqIDAuNyk7CiAgICAvLyBDYWIgcm9vZgogICAgY3R4LmZpbGxTdHlsZSA9ICcjMWE3OTUxJzsKICAgIGN0eC5maWxsUmVjdChib2R5TGVuICogMC4xLCAtYm9keUxlbiAqIDAuMjIsIGJvZHlMZW4gKiAwLjMsIGJvZHlMZW4gKiAwLjQ0KTsKICAgIGN0eC5yZXN0b3JlKCk7CiAgfQoKICBmdW5jdGlvbiBkcmF3KGxheW91dCl7CiAgICB2YXIgcmVjdCA9IGNhbnZhcy5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTsKICAgIGN0eC5jbGVhclJlY3QoMCwgMCwgcmVjdC53aWR0aCwgcmVjdC5oZWlnaHQpOwogICAgdmFyIHByb2ogPSBnZXRTY2FsZSgpOwogICAgdmFyIGJvdW5kYXJ5ID0gbGF5b3V0LmJvdW5kYXJ5ID8gbGF5b3V0LmJvdW5kYXJ5IDogQk9VTkRBUlk7CiAgICB2YXIgaGFzSGVhZGxhbmQgPSBsYXlvdXQuaW50ZXJpb3IgPyBsYXlvdXQuaW50ZXJpb3IgIT09IGJvdW5kYXJ5IDogZmFsc2U7CiAgICAvLyBUZXJyYWluIGhlYXRtYXAgYmVoaW5kIGV2ZXJ5dGhpbmcKICAgIGRyYXdUZXJyYWluKHByb2opOwogICAgLy8gSGVhZGxhbmQgc3RyaXAgPSBib3VuZGFyeSBtaW51cyBpbnRlcmlvciAoZXZlbi1vZGQgZmlsbCkKICAgIGlmKGhhc0hlYWRsYW5kKXsKICAgICAgY3R4LnNhdmUoKTsKICAgICAgY3R4LmZpbGxTdHlsZSA9ICdyZ2JhKDI2LDEyMSw4MSwwLjE4KSc7CiAgICAgIGN0eC5iZWdpblBhdGgoKTsKICAgICAgZm9yKHZhciBpPTA7IGk8Ym91bmRhcnkubGVuZ3RoOyBpKyspewogICAgICAgIHZhciBieCA9IHB4KHByb2osIGJvdW5kYXJ5W2ldLngpOwogICAgICAgIHZhciBieSA9IHB5KHByb2osIGJvdW5kYXJ5W2ldLnkpOwogICAgICAgIGlmKGkgPT09IDApIGN0eC5tb3ZlVG8oYngsIGJ5KTsgZWxzZSBjdHgubGluZVRvKGJ4LCBieSk7CiAgICAgIH0KICAgICAgY3R4LmNsb3NlUGF0aCgpOwogICAgICB2YXIgaW5uZXIgPSBsYXlvdXQuaW50ZXJpb3I7CiAgICAgIGZvcih2YXIgaj1pbm5lci5sZW5ndGgtMTsgaj49MDsgai0tKXsKICAgICAgICB2YXIgaXggPSBweChwcm9qLCBpbm5lcltqXS54KTsKICAgICAgICB2YXIgaXkgPSBweShwcm9qLCBpbm5lcltqXS55KTsKICAgICAgICBpZihqID09PSBpbm5lci5sZW5ndGgtMSkgY3R4Lm1vdmVUbyhpeCwgaXkpOyBlbHNlIGN0eC5saW5lVG8oaXgsIGl5KTsKICAgICAgfQogICAgICBjdHguY2xvc2VQYXRoKCk7CiAgICAgIGN0eC5maWxsKCdldmVub2RkJyk7CiAgICAgIGN0eC5yZXN0b3JlKCk7CiAgICB9CiAgICAvLyBEcml2YWJsZSBvdXRsaW5lIChvbmx5IGlmIG91dHNpZGVCdWZmZXIgPiAwIOKGkiBkcml2YWJsZSDiiaAgYm91bmRhcnkpCiAgICBpZihsYXlvdXQuZHJpdmFibGUgPyBsYXlvdXQuZHJpdmFibGUgIT09IGJvdW5kYXJ5IDogZmFsc2UpewogICAgICBjdHguc2F2ZSgpOwogICAgICBjdHguc3Ryb2tlU3R5bGUgPSAncmdiYSgyMCw4Myw0MCwwLjM1KSc7CiAgICAgIGN0eC5zZXRMaW5lRGFzaChbNCwgNF0pOwogICAgICBjdHgubGluZVdpZHRoID0gMTsKICAgICAgY3R4LmJlZ2luUGF0aCgpOwogICAgICBmb3IodmFyIGR2PTA7IGR2PGxheW91dC5kcml2YWJsZS5sZW5ndGg7IGR2KyspewogICAgICAgIHZhciBkdnggPSBweChwcm9qLCBsYXlvdXQuZHJpdmFibGVbZHZdLngpOwogICAgICAgIHZhciBkdnkgPSBweShwcm9qLCBsYXlvdXQuZHJpdmFibGVbZHZdLnkpOwogICAgICAgIGlmKGR2ID09PSAwKSBjdHgubW92ZVRvKGR2eCwgZHZ5KTsgZWxzZSBjdHgubGluZVRvKGR2eCwgZHZ5KTsKICAgICAgfQogICAgICBjdHguY2xvc2VQYXRoKCk7CiAgICAgIGN0eC5zdHJva2UoKTsKICAgICAgY3R4LnJlc3RvcmUoKTsKICAgIH0KICAgIC8vIEZpZWxkIGJvdW5kYXJ5CiAgICBjdHguc2F2ZSgpOwogICAgY3R4LnN0cm9rZVN0eWxlID0gJyMxNDUzMjgnOwogICAgY3R4LmxpbmVXaWR0aCA9IDI7CiAgICBjdHgubGluZUpvaW4gPSAncm91bmQnOwogICAgY3R4LmJlZ2luUGF0aCgpOwogICAgZm9yKHZhciBrPTA7IGs8Ym91bmRhcnkubGVuZ3RoOyBrKyspewogICAgICB2YXIgYnhGID0gcHgocHJvaiwgYm91bmRhcnlba10ueCk7CiAgICAgIHZhciBieUYgPSBweShwcm9qLCBib3VuZGFyeVtrXS55KTsKICAgICAgaWYoayA9PT0gMCkgY3R4Lm1vdmVUbyhieEYsIGJ5Rik7IGVsc2UgY3R4LmxpbmVUbyhieEYsIGJ5Rik7CiAgICB9CiAgICBjdHguY2xvc2VQYXRoKCk7CiAgICBjdHguc3Ryb2tlKCk7CiAgICBjdHgucmVzdG9yZSgpOwogICAgLy8gSW50ZXJpb3Igb3V0bGluZSAoaW5uZXIgZWRnZSBvZiBoZWFkbGFuZCBzdHJpcCkKICAgIGlmKGhhc0hlYWRsYW5kKXsKICAgICAgY3R4LnNhdmUoKTsKICAgICAgY3R4LnN0cm9rZVN0eWxlID0gJyMxYTc5NTEnOwogICAgICBjdHgubGluZVdpZHRoID0gMS41OwogICAgICBjdHguYmVnaW5QYXRoKCk7CiAgICAgIGZvcih2YXIgcnA9MDsgcnA8bGF5b3V0LmludGVyaW9yLmxlbmd0aDsgcnArKyl7CiAgICAgICAgdmFyIHJ4ID0gcHgocHJvaiwgbGF5b3V0LmludGVyaW9yW3JwXS54KTsKICAgICAgICB2YXIgcnkgPSBweShwcm9qLCBsYXlvdXQuaW50ZXJpb3JbcnBdLnkpOwogICAgICAgIGlmKHJwID09PSAwKSBjdHgubW92ZVRvKHJ4LCByeSk7IGVsc2UgY3R4LmxpbmVUbyhyeCwgcnkpOwogICAgICB9CiAgICAgIGN0eC5jbG9zZVBhdGgoKTsKICAgICAgY3R4LnN0cm9rZSgpOwogICAgICBjdHgucmVzdG9yZSgpOwogICAgfQogICAgLy8gU29pbCBjb21wYWN0aW9uIHpvbmVzIChhbHdheXMtdmlzaWJsZSB2aW9sZXQgZ2xvdyB1bmRlciBlYWNoIHR1cm4gYXJjKQogICAgZHJhd0NvbXBhY3Rpb25ab25lcyhwcm9qLCBsYXlvdXQpOwogICAgLy8gU3dhdGggY292ZXJhZ2UgYmFuZCAoZmlsbGVkIGFzIHBsYXliYWNrIHByb2dyZXNzZXMpCiAgICBkcmF3U3dhdGgocHJvaik7CiAgICAvLyBQYXNzZXMgKHRoZSB3b3JrZWQgZ3VpZGFuY2UgbGluZXMpCiAgICBjdHguc2F2ZSgpOwogICAgY3R4LnN0cm9rZVN0eWxlID0gJyNmNzZhMGMnOwogICAgY3R4LmxpbmVXaWR0aCA9IDEuMjsKICAgIGN0eC5saW5lQ2FwID0gJ3JvdW5kJzsKICAgIGZvcih2YXIgcD0wOyBwPGxheW91dC5wYXNzZXMubGVuZ3RoOyBwKyspewogICAgICB2YXIgcGEgPSBsYXlvdXQucGFzc2VzW3BdOwogICAgICBjdHguYmVnaW5QYXRoKCk7CiAgICAgIGlmKHBhLnNhbXBsZXMpewogICAgICAgIGZvcih2YXIgcHM9MDsgcHM8cGEuc2FtcGxlcy5sZW5ndGg7IHBzKyspewogICAgICAgICAgdmFyIHNzeCA9IHB4KHByb2osIHBhLnNhbXBsZXNbcHNdLngpOwogICAgICAgICAgdmFyIHNzeSA9IHB5KHByb2osIHBhLnNhbXBsZXNbcHNdLnkpOwogICAgICAgICAgaWYocHMgPT09IDApIGN0eC5tb3ZlVG8oc3N4LCBzc3kpOyBlbHNlIGN0eC5saW5lVG8oc3N4LCBzc3kpOwogICAgICAgIH0KICAgICAgfSBlbHNlIHsKICAgICAgICBjdHgubW92ZVRvKHB4KHByb2osIHBhLngwKSwgcHkocHJvaiwgcGEueTApKTsKICAgICAgICBjdHgubGluZVRvKHB4KHByb2osIHBhLngxKSwgcHkocHJvaiwgcGEueTEpKTsKICAgICAgfQogICAgICBjdHguc3Ryb2tlKCk7CiAgICB9CiAgICBjdHgucmVzdG9yZSgpOwogICAgLy8gVHVybiBhcmNzIOKAlCBwdXJwbGUgc29saWQgZm9yIG9rIFUtdHVybnMsIHJlZCBkYXNoZWQgZm9yIHByb2JsZW0gYXJjcywKICAgIC8vIHRlYWwgZG90dGVkIGZvciBoZWFkbGFuZCB0cmF2ZXJzZXMgKG5vIHN5bnRoZXRpYyB1LXR1cm4g4oCUIG9wZXJhdG9yIGRpZAogICAgLy8gc21hbGwgcGl2b3RzICsgZHJvdmUgYWNyb3NzIHRoZSB3b3JrZWQgaGVhZGxhbmQpLgogICAgaWYobGF5b3V0LnR1cm5BcmNzID8gbGF5b3V0LnR1cm5BcmNzLmxlbmd0aCA6IGZhbHNlKXsKICAgICAgY3R4LnNhdmUoKTsKICAgICAgY3R4LmxpbmVDYXAgPSAncm91bmQnOwogICAgICBjdHgubGluZUpvaW4gPSAncm91bmQnOwogICAgICBmb3IodmFyIHRpPTA7IHRpPGxheW91dC50dXJuQXJjcy5sZW5ndGg7IHRpKyspewogICAgICAgIHZhciBhcmMgPSBsYXlvdXQudHVybkFyY3NbdGldOwogICAgICAgIHZhciBpc1RyYXZlcnNlID0gYXJjLmtpbmQgPT09ICd0cmF2ZXJzZSc7CiAgICAgICAgdmFyIGlzUmluZ1JvdXRlID0gYXJjLmtpbmQgPT09ICdyaW5nLXJvdXRlJzsKICAgICAgICBpZihpc1RyYXZlcnNlKXsKICAgICAgICAgIC8vIFNob3J0IHN0cmFpZ2h0LWxpbmUgdHJhdmVyc2VzIOKAlCBzdGlsbCByZWFsIHR1cm5hcm91bmRzLCByZW5kZXIKICAgICAgICAgIC8vIHdpdGggdGhlIHNhbWUgdmlvbGV0IGJ1dCBkYXNoZWQgc28gdGhlIHVzZXIgc2VlcyB0aGV5IGV4aXN0LgogICAgICAgICAgY3R4LnN0cm9rZVN0eWxlID0gJyNhMjFjYWYnOwogICAgICAgICAgY3R4LmxpbmVXaWR0aCA9IDEuODsKICAgICAgICAgIGN0eC5zZXRMaW5lRGFzaChbNiwgNF0pOwogICAgICAgIH0gZWxzZSBpZihpc1JpbmdSb3V0ZSl7CiAgICAgICAgICAvLyBSaW5nIHJvdXRlcyDigJQgb3BlcmF0b3IgZHJvdmUgYWxvbmcgdGhlIGhlYWRsYW5kLXJpbmcgdG8gcmVhY2gKICAgICAgICAgIC8vIHRoZSBuZXh0IHBhc3MuIFNob3cgYXMgZGFzaGVkIHZpb2xldCB0b28gYnV0IHdpdGggYSB0aWdodGVyCiAgICAgICAgICAvLyBkYXNoIHBhdHRlcm4gc28gdGhlIHJvdXRpbmcgaXMgdmlzdWFsbHkgZGlzdGluY3QuCiAgICAgICAgICBjdHguc3Ryb2tlU3R5bGUgPSAnI2EyMWNhZic7CiAgICAgICAgICBjdHgubGluZVdpZHRoID0gMS42OwogICAgICAgICAgY3R4LnNldExpbmVEYXNoKFszLCAzXSk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIC8vIFUtdHVybiBhcmMg4oCUIHNvbGlkIHZpb2xldCBmb3Igb2ssIHJlZC1kYXNoZWQgd2hlbiBnZW9tZXRyeSBmYWlsZWQuCiAgICAgICAgICBjdHguc3Ryb2tlU3R5bGUgPSBhcmMub2sgPyAnI2EyMWNhZicgOiAnI2RjMjYyNic7CiAgICAgICAgICBjdHgubGluZVdpZHRoID0gYXJjLm9rID8gMiA6IDEuNDsKICAgICAgICAgIGN0eC5zZXRMaW5lRGFzaChhcmMub2sgPyBbXSA6IFszLCAzXSk7CiAgICAgICAgfQogICAgICAgIGN0eC5iZWdpblBhdGgoKTsKICAgICAgICBmb3IodmFyIGFjPTA7IGFjPGFyYy5jb29yZHMubGVuZ3RoOyBhYysrKXsKICAgICAgICAgIHZhciBhZXggPSBweChwcm9qLCBhcmMuY29vcmRzW2FjXS54KTsKICAgICAgICAgIHZhciBhZXkgPSBweShwcm9qLCBhcmMuY29vcmRzW2FjXS55KTsKICAgICAgICAgIGlmKGFjID09PSAwKSBjdHgubW92ZVRvKGFleCwgYWV5KTsgZWxzZSBjdHgubGluZVRvKGFleCwgYWV5KTsKICAgICAgICB9CiAgICAgICAgY3R4LnN0cm9rZSgpOwogICAgICB9CiAgICAgIGN0eC5yZXN0b3JlKCk7CiAgICB9CiAgICAvLyBEaXJlY3Rpb24gYXJyb3dzIG9uIHBhc3NlcyArIHR1cm4gYXJjcyAoYWJvdmUgbGluZXMsIGJlbG93IHNwcml0ZSkKICAgIGRyYXdEaXJlY3Rpb25BcnJvd3MocHJvaiwgbGF5b3V0KTsKICAgIC8vIFRyYWN0b3Igc3ByaXRlIG9uIHRvcAogICAgZHJhd1Nwcml0ZShwcm9qKTsKICAgIC8vIFNjYWxlIGJhciDigJQgcGljayBhIG5pY2Ugcm91bmQgbWV0cmVzIHZhbHVlIGZvciB+NjAgcHggb24gc2NyZWVuIGFuZAogICAgLy8gYWRqdXN0IHRoZSBiYXIgd2lkdGggdG8gbWF0Y2ggdGhlIGNob3NlbiB2YWx1ZSBhdCBjdXJyZW50IHByb2ouc2MuCiAgICB2YXIgc2NhbGVCYXJFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtc2NhbGUnKTsKICAgIHZhciBzY2FsZUxibEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1zY2FsZS1sYmwnKTsKICAgIGlmKHNjYWxlQmFyRWwgPyBzY2FsZUxibEVsIDogZmFsc2UpewogICAgICB2YXIgdGFyZ2V0UHggPSA2MDsKICAgICAgdmFyIHJhd01ldHJlcyA9IHRhcmdldFB4IC8gcHJvai5zYzsKICAgICAgLy8gU25hcCB0byBhIDEvMi81IMOXIDEw4oG\/IHBhdHRlcm4gKHN0YW5kYXJkIGNhcnRvZ3JhcGhpYyBzY2FsZSBzdGVwcykKICAgICAgdmFyIHBvdzEwID0gTWF0aC5wb3coMTAsIE1hdGguZmxvb3IoTWF0aC5sb2cocmF3TWV0cmVzKSAvIE1hdGguTE4xMCkpOwogICAgICB2YXIgc25hcFZhbDsKICAgICAgdmFyIGxlYWQgPSByYXdNZXRyZXMgLyBwb3cxMDsKICAgICAgaWYobGVhZCA8IDEuNSkgc25hcFZhbCA9IDEgKiBwb3cxMDsKICAgICAgZWxzZSBpZihsZWFkIDwgMy41KSBzbmFwVmFsID0gMiAqIHBvdzEwOwogICAgICBlbHNlIGlmKGxlYWQgPCA3LjUpIHNuYXBWYWwgPSA1ICogcG93MTA7CiAgICAgIGVsc2Ugc25hcFZhbCA9IDEwICogcG93MTA7CiAgICAgIHZhciBiYXJQeCA9IHNuYXBWYWwgKiBwcm9qLnNjOwogICAgICB2YXIgYmFyRWwgPSBzY2FsZUJhckVsLnF1ZXJ5U2VsZWN0b3IoJy5ncGwtc2NhbGUtYmFyJyk7CiAgICAgIGlmKGJhckVsKSBiYXJFbC5zdHlsZS53aWR0aCA9IGJhclB4LnRvRml4ZWQoMCkgKyAncHgnOwogICAgICBzY2FsZUxibEVsLnRleHRDb250ZW50ID0gZm10RGlzdChzbmFwVmFsKTsKICAgIH0KICAgIC8vIFJ1bGVyIGxpbmUgb24gYWJzb2x1dGUgdG9wCiAgICBpZihydWxlci5wMSA\/IHJ1bGVyLnAyIDogZmFsc2UpewogICAgICBjdHguc2F2ZSgpOwogICAgICBjdHguc3Ryb2tlU3R5bGUgPSAnI2RjMjYyNic7CiAgICAgIGN0eC5saW5lV2lkdGggPSAyOwogICAgICBjdHguc2V0TGluZURhc2goWzYsIDRdKTsKICAgICAgY3R4LmJlZ2luUGF0aCgpOwogICAgICBjdHgubW92ZVRvKHB4KHByb2osIHJ1bGVyLnAxLngpLCBweShwcm9qLCBydWxlci5wMS55KSk7CiAgICAgIGN0eC5saW5lVG8ocHgocHJvaiwgcnVsZXIucDIueCksIHB5KHByb2osIHJ1bGVyLnAyLnkpKTsKICAgICAgY3R4LnN0cm9rZSgpOwogICAgICBjdHgucmVzdG9yZSgpOwogICAgICAvLyBFbmRwb2ludCBkb3RzCiAgICAgIGN0eC5zYXZlKCk7CiAgICAgIGN0eC5maWxsU3R5bGUgPSAnI2RjMjYyNic7CiAgICAgIGN0eC5iZWdpblBhdGgoKTsgY3R4LmFyYyhweChwcm9qLCBydWxlci5wMS54KSwgcHkocHJvaiwgcnVsZXIucDEueSksIDQsIDAsIE1hdGguUEkqMik7IGN0eC5maWxsKCk7CiAgICAgIGN0eC5iZWdpblBhdGgoKTsgY3R4LmFyYyhweChwcm9qLCBydWxlci5wMi54KSwgcHkocHJvaiwgcnVsZXIucDIueSksIDQsIDAsIE1hdGguUEkqMik7IGN0eC5maWxsKCk7CiAgICAgIGN0eC5yZXN0b3JlKCk7CiAgICAgIC8vIERpc3RhbmNlIGxhYmVsCiAgICAgIHZhciByZHggPSBydWxlci5wMi54IC0gcnVsZXIucDEueDsKICAgICAgdmFyIHJkeSA9IHJ1bGVyLnAyLnkgLSBydWxlci5wMS55OwogICAgICB2YXIgckRpc3QgPSBNYXRoLnNxcnQocmR4KnJkeCArIHJkeSpyZHkpOwogICAgICB2YXIgbGFiZWxNeCA9IHB4KHByb2osIChydWxlci5wMS54ICsgcnVsZXIucDIueCkgKiAwLjUpOwogICAgICB2YXIgbGFiZWxNeSA9IHB5KHByb2osIChydWxlci5wMS55ICsgcnVsZXIucDIueSkgKiAwLjUpOwogICAgICBjdHguc2F2ZSgpOwogICAgICBjdHguZm9udCA9ICc3MDAgMTJweCAiRE0gTW9ubyIsIHVpLW1vbm9zcGFjZSwgbW9ub3NwYWNlJzsKICAgICAgdmFyIGxhYmVsID0gZm10RGlzdChyRGlzdCk7CiAgICAgIHZhciB0dyA9IGN0eC5tZWFzdXJlVGV4dChsYWJlbCkud2lkdGggKyAxNDsKICAgICAgY3R4LmZpbGxTdHlsZSA9ICdyZ2JhKDIyMCwzOCwzOCwwLjk1KSc7CiAgICAgIGN0eC5maWxsUmVjdChsYWJlbE14IC0gdHcgLyAyLCBsYWJlbE15IC0gMTEsIHR3LCAyMik7CiAgICAgIGN0eC5maWxsU3R5bGUgPSAnI2ZmZic7CiAgICAgIGN0eC50ZXh0QWxpZ24gPSAnY2VudGVyJzsKICAgICAgY3R4LnRleHRCYXNlbGluZSA9ICdtaWRkbGUnOwogICAgICBjdHguZmlsbFRleHQobGFiZWwsIGxhYmVsTXgsIGxhYmVsTXkpOwogICAgICBjdHgucmVzdG9yZSgpOwogICAgfSBlbHNlIGlmKHJ1bGVyLnAxKXsKICAgICAgY3R4LnNhdmUoKTsKICAgICAgY3R4LmZpbGxTdHlsZSA9ICcjZGMyNjI2JzsKICAgICAgY3R4LmJlZ2luUGF0aCgpOyBjdHguYXJjKHB4KHByb2osIHJ1bGVyLnAxLngpLCBweShwcm9qLCBydWxlci5wMS55KSwgNSwgMCwgTWF0aC5QSSoyKTsgY3R4LmZpbGwoKTsKICAgICAgY3R4LnJlc3RvcmUoKTsKICAgIH0KICB9CgogIHZhciBjdXJyZW50ID0gJ2FiLXN0cmFpZ2h0JzsKICAvLyBNYWNoaW5lIHR5cGUg4oaSIHR5cGljYWwgbWluLXR1cm4tcmFkaXVzIChtKSBBTkQgdHlwaWNhbCBpbXBsZW1lbnQgd2lkdGggKG0pLgogIC8vIFdpZHRocyBmcm9tIHRoZSBmaWVsZC1leHBsb3JlciBPUF9XSURUSF9NIHRhYmxlIOKAlCBsYXJnZS1mYXJtIHJvdy1jcm9wCiAgLy8gZGVmYXVsdHMuIFVzZXIgcGlja3MgQ3VzdG9tIHRvIHNraXAgYm90aCBhdXRvLWZpbGxzIGFuZCBvdmVycmlkZSBtYW51YWxseS4KICB2YXIgTUFDSElORV9TUEVDID0gewogICAgJ3RyYWN0b3Itc3RkJzogICB7IHI6ICA4LCB3OiAxNSwgbGFiZWw6ICdzdGQgdHJhY3RvciAvIGN1bHRpdmF0b3InIH0sCiAgICAndHJhY3Rvci1sYXJnZSc6IHsgcjogMTIsIHc6IDE4LCBsYWJlbDogJ2xhcmdlIHRyYWN0b3IgKyAyNC1yb3cgcGxhbnRlcicgfSwKICAgICdzcHJheWVyJzogICAgICAgeyByOiAxMCwgdzogMzYsIGxhYmVsOiAnc2VsZi1wcm9wZWxsZWQgc3ByYXllcicgfSwKICAgICdjb21iaW5lJzogICAgICAgeyByOiAgNywgdzogMTIsIGxhYmVsOiAnY29tYmluZSBoYXJ2ZXN0ZXInIH0sCiAgICAnYXJ0aWN1bGF0ZWQnOiAgIHsgcjogMTUsIHc6IDI0LCBsYWJlbDogJ2FydGljdWxhdGVkIDRXRCArIGRyeSBzcHJlYWRlcicgfSwKICAgICdjdXN0b20nOiAgICAgICAgeyByOiAgMCwgdzogIDAsIGxhYmVsOiAnbWFudWFsIG92ZXJyaWRlJyB9CiAgfTsKICAvLyBCYWNrLWNvbXBhdCBhbGlhcyAodGhlIHNtb2tlIHRlc3RzIHBva2UgTUFDSElORV9SQURJVVMpLgogIHZhciBNQUNISU5FX1JBRElVUyA9IE1BQ0hJTkVfU1BFQzsKICB2YXIgQ1VSUkVOQ1lfU1lNQk9MID0geyB1c2Q6ICckJywgZXVyOiAn4oKsJyB9OwoKICBmdW5jdGlvbiBnZXRJbnB1dHMoKXsKICAgIHZhciB3TSA9IHBhcnNlRmxvYXQoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC13bScpLnZhbHVlKSB8fCAxODsKICAgIHZhciBobE11bHQgPSBwYXJzZUZsb2F0KGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtaGwtbXVsdCcpLnZhbHVlKTsKICAgIGlmKGlzTmFOKGhsTXVsdCkpIGhsTXVsdCA9IDE7CiAgICAvLyBIZWFkbGFuZCBpcyBBTFdBWVMgTiDDlyBpbXBsZW1lbnQgd2lkdGggKHBlciB1c2VyIOKAlCBjdXN0b20gb3ZlcnJpZGUKICAgIC8vIGRyb3BwZWQsIHRoZSBtdWx0aXBsaWVyIGFsb25lIGRlZmluZXMgdGhlIHN0cmlwKS4KICAgIHZhciBoZWFkbGFuZE0gPSBobE11bHQgKiB3TTsKICAgIHZhciB0dXJuU3R5bGUgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXR1cm4tc3R5bGUnKS52YWx1ZSB8fCAndXR1cm4nOwogICAgdmFyIHR1cm5SID0gcGFyc2VGbG9hdChkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXR1cm4tcicpLnZhbHVlKSB8fCA5OwogICAgdmFyIHR1cm5CdWYgPSBwYXJzZUZsb2F0KGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtdHVybi1idWYnKS52YWx1ZSk7CiAgICBpZihpc05hTih0dXJuQnVmKSkgdHVybkJ1ZiA9IDA7CiAgICB2YXIgbWFjaGluZUVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1tYWNoaW5lJyk7CiAgICB2YXIgbWFjaGluZUtleSA9IG1hY2hpbmVFbCA\/IG1hY2hpbmVFbC52YWx1ZSA6ICd0cmFjdG9yLXN0ZCc7CiAgICB2YXIgY3VyRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLWN1cnJlbmN5Jyk7CiAgICB2YXIgY3VycmVuY3kgPSBjdXJFbCA\/IGN1ckVsLnZhbHVlIDogJ3VzZCc7CiAgICB2YXIgZmFybUVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1yb2ktZmFybScpOwogICAgdmFyIGFwcHNFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtcm9pLWFwcHMnKTsKICAgIHZhciBmYXJtSGEgPSBmYXJtRWwgPyBwYXJzZUZsb2F0KGZhcm1FbC52YWx1ZSkgOiAyMDA7CiAgICBpZihpc05hTihmYXJtSGEpID8gdHJ1ZSA6IGZhcm1IYSA8PSAwKSBmYXJtSGEgPSAyMDA7CiAgICB2YXIgYXBwcyA9IGFwcHNFbCA\/IHBhcnNlRmxvYXQoYXBwc0VsLnZhbHVlKSA6IDQ7CiAgICBpZihpc05hTihhcHBzKSA\/IHRydWUgOiBhcHBzIDw9IDApIGFwcHMgPSA0OwogICAgcmV0dXJuIHsKICAgICAgd006IHdNLAogICAgICBkaWVzZWw6IHBhcnNlRmxvYXQoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1mdWVsJykudmFsdWUpIHx8IDEuMiwKICAgICAgY29uczogcGFyc2VGbG9hdChkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLWNvbnMnKS52YWx1ZSkgfHwgMC42LAogICAgICBoZWFkbGFuZE06IGhlYWRsYW5kTSwKICAgICAgaGVhZGxhbmRNdWx0OiBobE11bHQsCiAgICAgIHR1cm5TdHlsZTogdHVyblN0eWxlLAogICAgICB0dXJuUjogdHVyblIsCiAgICAgIHR1cm5CdWY6IHR1cm5CdWYsCiAgICAgIG1hY2hpbmU6IG1hY2hpbmVLZXksCiAgICAgIGN1cnJlbmN5OiBjdXJyZW5jeSwKICAgICAgZmFybUhhOiBmYXJtSGEsCiAgICAgIGFwcHM6IGFwcHMKICAgIH07CiAgfQogIGZ1bmN0aW9uIHJlY29tcHV0ZSgpewogICAgdmFyIGlucCA9IGdldElucHV0cygpOwogICAgLy8gQXhpczogdXNlciBtYW51YWwgb3ZlcnJpZGUgYmVhdHMgUENBIHdoZW4gc2V0CiAgICB2YXIgYXhpczsKICAgIGlmKHVzZXJBeGlzRGVnICE9PSBudWxsKXsKICAgICAgdmFyIHIgPSB1c2VyQXhpc0RlZyAqIE1hdGguUEkgLyAxODA7CiAgICAgIGF4aXMgPSB7IHV4OiBNYXRoLmNvcyhyKSwgdXk6IE1hdGguc2luKHIpIH07CiAgICB9IGVsc2UgewogICAgICBheGlzID0gZmllbGRBeGlzKEJPVU5EQVJZKTsKICAgIH0KICAgIC8vIFN5bmMgdGhlIEFCLWRpcmVjdGlvbiBzbGlkZXIgbGFiZWwgdG8gdGhlIGFjdGl2ZSBhbmdsZSAoc28gdGhlIHVzZXIKICAgIC8vIHNlZXMgdGhlIGF1dG8tUENBIHJlc3VsdCByZWZsZWN0ZWQgaW4gdGhlIFVJKS4KICAgIHZhciBhYkxhYmVsRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLWFiLXZhbCcpOwogICAgdmFyIGFiU2xpZGVyRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLWFiLWRlZycpOwogICAgaWYoYWJMYWJlbEVsID8gYWJTbGlkZXJFbCA6IGZhbHNlKXsKICAgICAgdmFyIGRlZ05vdyA9IE1hdGgucm91bmQoTWF0aC5hdGFuMihheGlzLnV5LCBheGlzLnV4KSAqIDE4MCAvIE1hdGguUEkpOwogICAgICAvLyBXcmFwIGludG8gWzAsMTgwKSDigJQgdGhlIGF4aXMgaXMgYmlkaXJlY3Rpb25hbCAoYSBsaW5lLCBub3QgYSB2ZWN0b3IpLgogICAgICB3aGlsZShkZWdOb3cgPCAwKSBkZWdOb3cgKz0gMTgwOwogICAgICB3aGlsZShkZWdOb3cgPj0gMTgwKSBkZWdOb3cgLT0gMTgwOwogICAgICBpZih1c2VyQXhpc0RlZyA9PT0gbnVsbCkgYWJTbGlkZXJFbC52YWx1ZSA9IFN0cmluZyhkZWdOb3cpOwogICAgICBhYkxhYmVsRWwudGV4dENvbnRlbnQgPSAodXNlckF4aXNEZWcgPT09IG51bGwgPyAnYXV0byDCtyAnIDogJ21hbnVhbCDCtyAnKSArIGRlZ05vdyArICfCsCc7CiAgICB9CiAgICB2YXIgc3RhdHMgPSBmaWVsZFN0YXRzKEJPVU5EQVJZKTsKICAgIHZhciBhcmVhSGEgPSBzdGF0cy5hcmVhIC8gMTAwMDA7CiAgICB2YXIgYmFzZUxheW91dCA9IGdlbmVyYXRlTGluZXMoJ2FiLXN0cmFpZ2h0JywgaW5wLndNLCBCT1VOREFSWSwgYXhpcywgaW5wLmhlYWRsYW5kTSwgaW5wLnR1cm5TdHlsZSwgaW5wLnR1cm5SLCBpbnAudHVybkJ1Zik7CiAgICB2YXIgYmFzZU1ldCA9IGNvbXB1dGVNZXRyaWNzKGJhc2VMYXlvdXQsIGlucC53TSwgaW5wLmRpZXNlbCwgaW5wLmNvbnMpOwogICAgdmFyIGxheW91dCA9IGdlbmVyYXRlTGluZXMoY3VycmVudCwgaW5wLndNLCBCT1VOREFSWSwgYXhpcywgaW5wLmhlYWRsYW5kTSwgaW5wLnR1cm5TdHlsZSwgaW5wLnR1cm5SLCBpbnAudHVybkJ1Zik7CiAgICB2YXIgbWV0ID0gY29tcHV0ZU1ldHJpY3MobGF5b3V0LCBpbnAud00sIGlucC5kaWVzZWwsIGlucC5jb25zKTsKICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtci1hcmVhJykudGV4dENvbnRlbnQgPSBhcmVhSGEudG9GaXhlZCgxKSArICcgaGEnOwogICAgdmFyIGNvdkVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1yLWNvdicpOwogICAgaWYoY292RWwpewogICAgICB2YXIgY292VmFsID0gbWV0LmNvdmVyYWdlUGN0IHx8IDA7CiAgICAgIGNvdkVsLnRleHRDb250ZW50ID0gY292VmFsLnRvRml4ZWQoMCkgKyAnICUnOwogICAgICAvLyBDb2xvcjogZ3JlZW4g4omlIDk1JSwgb3JhbmdlIDg1LTk1JSwgcmVkIDwgODUlCiAgICAgIGNvdkVsLnN0eWxlLmNvbG9yID0gY292VmFsID49IDk1ID8gJyMxNTcwMWUnIDogKGNvdlZhbCA+PSA4NSA\/ICcjZjc2YTBjJyA6ICcjZGMyNjI2Jyk7CiAgICB9CiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXItcGFzc2VzJykudGV4dENvbnRlbnQgPSBtZXQucGFzc2VzOwogICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1yLWxlbicpLnRleHRDb250ZW50ID0gZm10RGlzdChtZXQucGFzc0xlbmd0aE0pOwogICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1yLXR1cm5zJykudGV4dENvbnRlbnQgPSBtZXQudHVybnM7CiAgICB2YXIgdHVybkxlbkVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1yLXR1cm5sZW4nKTsKICAgIGlmKHR1cm5MZW5FbCkgdHVybkxlbkVsLnRleHRDb250ZW50ID0gZm10RGlzdChtZXQudHVybkxlbmd0aE0gfHwgMCk7CiAgICB2YXIgZHJpdmVFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtci1kcml2ZScpOwogICAgaWYoZHJpdmVFbCkgZHJpdmVFbC50ZXh0Q29udGVudCA9IGZtdERpc3QobWV0LnRvdGFsRHJpdmVNIHx8IChtZXQucGFzc0xlbmd0aE0gKyAobWV0LnR1cm5MZW5ndGhNIHx8IDApKSk7CiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXItZnVlbCcpLnRleHRDb250ZW50ID0gbWV0LmZ1ZWxMLnRvRml4ZWQoMSkgKyAnIEwnOwogICAgdmFyIGdyYWRlRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXItZ3JhZGUnKTsKICAgIGlmKGdyYWRlRWwpewogICAgICB2YXIgZyA9IG1ldC5hdmdHcmFkZVBjdCB8fCAwOwogICAgICBncmFkZUVsLnRleHRDb250ZW50ID0gZy50b0ZpeGVkKDEpICsgJyAlJzsKICAgICAgZ3JhZGVFbC5zdHlsZS5jb2xvciA9IGcgPiA1ID8gJyNmNzZhMGMnIDogKGcgPiAzID8gJyNhMjFjYWYnIDogJyM0YzYwNjYnKTsKICAgIH0KICAgIHZhciBzbG9wZUVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1yLXNsb3BlJyk7CiAgICBpZihzbG9wZUVsKXsKICAgICAgdmFyIHNsb3BlUGN0ID0gKG1ldC5zbG9wZVBlbmFsdHkgfHwgMCkgKiAxMDA7CiAgICAgIHNsb3BlRWwudGV4dENvbnRlbnQgPSAnKyAnICsgc2xvcGVQY3QudG9GaXhlZCgwKSArICclJzsKICAgICAgc2xvcGVFbC5zdHlsZS5jb2xvciA9IHNsb3BlUGN0ID4gMTUgPyAnI2RjMjYyNicgOiAoc2xvcGVQY3QgPiA1ID8gJyNmNzZhMGMnIDogJyM0YzYwNjYnKTsKICAgIH0KICAgIHZhciB0dXJuRnVlbEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1yLXR1cm5mdWVsJyk7CiAgICBpZih0dXJuRnVlbEVsKXsKICAgICAgdmFyIHRmID0gbWV0LnR1cm5GdWVsTCB8fCAwOwogICAgICB2YXIgdG90RiA9IG1ldC5mdWVsTCB8fCAwOwogICAgICB2YXIgcGN0ID0gdG90RiA+IDAgPyAodGYgLyB0b3RGICogMTAwKSA6IDA7CiAgICAgIHR1cm5GdWVsRWwudGV4dENvbnRlbnQgPSB0Zi50b0ZpeGVkKDEpICsgJyBMIMK3ICcgKyBwY3QudG9GaXhlZCgwKSArICclJzsKICAgICAgdHVybkZ1ZWxFbC5zdHlsZS5jb2xvciA9IHBjdCA+IDI1ID8gJyNmNzZhMGMnIDogKHBjdCA+IDE1ID8gJyNhMjFjYWYnIDogJyM0YzYwNjYnKTsKICAgIH0KICAgIHZhciBzeW0gPSBDVVJSRU5DWV9TWU1CT0xbaW5wLmN1cnJlbmN5XSB8fCAnJCc7CiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXItY29zdCcpLnRleHRDb250ZW50ID0gc3ltICsgJyAnICsgbWV0LmNvc3RVU0QudG9GaXhlZCgyKTsKICAgIHZhciBzYXZGdWVsID0gYmFzZU1ldC5mdWVsTCAtIG1ldC5mdWVsTDsKICAgIHZhciBzYXZQY3QgPSBiYXNlTWV0LmZ1ZWxMID4gMCA\/IChzYXZGdWVsIC8gYmFzZU1ldC5mdWVsTCkgKiAxMDAgOiAwOwogICAgdmFyIHNhdkVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1yLXNhdicpOwogICAgaWYoY3VycmVudCA9PT0gJ2FiLXN0cmFpZ2h0Jyl7CiAgICAgIHNhdkVsLnRleHRDb250ZW50ID0gJ2Jhc2VsaW5lJzsKICAgICAgc2F2RWwuc3R5bGUuY29sb3IgPSAnIzRjNjA2Nic7CiAgICB9IGVsc2UgewogICAgICB2YXIgc2lnbiA9IHNhdkZ1ZWwgPj0gMCA\/ICfiiJInIDogJysnOwogICAgICB2YXIgYWJzU2F2ID0gTWF0aC5hYnMoc2F2RnVlbCk7CiAgICAgIHNhdkVsLnRleHRDb250ZW50ID0gc2lnbiArIGFic1Nhdi50b0ZpeGVkKDEpICsgJyBMICgnICsgKHNhdlBjdCA+PSAwID8gJ+KIkicgOiAnKycpICsgTWF0aC5hYnMoc2F2UGN0KS50b0ZpeGVkKDApICsgJyUpJzsKICAgICAgc2F2RWwuc3R5bGUuY29sb3IgPSBzYXZGdWVsID49IDAgPyAnIzE1NzAxZScgOiAnI2Y3NmEwYyc7CiAgICB9CiAgICB0cmF5RWwudGV4dENvbnRlbnQgPSBhcmVhSGEudG9GaXhlZCgxKSArICcgaGEgwrcgJyArIGlucC53TSArICcgbSDCtyAnICsgbWV0LnBhc3NlcyArICcgcGFzc2VzIMK3IGhlYWRsYW5kICcgKyBpbnAuaGVhZGxhbmRNLnRvRml4ZWQoMCkgKyAnIG0nOwogICAgLy8gU2hhcGUtZHJpdmVuIHJlY29tbWVuZGF0aW9uIGJhZGdlCiAgICB2YXIgcmVjbyA9IHJlY29tbWVuZEFwcHJvYWNoKEJPVU5EQVJZKTsKICAgIHZhciByZWNvQmFkZ2VzID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLmdwbC1yZWNvJyk7CiAgICBmb3IodmFyIHJiPTA7IHJiPHJlY29CYWRnZXMubGVuZ3RoOyByYisrKXsKICAgICAgdmFyIHJrZXkgPSByZWNvQmFkZ2VzW3JiXS5nZXRBdHRyaWJ1dGUoJ2RhdGEtcmVjbycpOwogICAgICByZWNvQmFkZ2VzW3JiXS5jbGFzc0xpc3QudG9nZ2xlKCdpcy1vbicsIHJrZXkgPT09IHJlY28ucGljayk7CiAgICB9CiAgICB2YXIgcmVjb0hpbnRFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtcmVjby1oaW50Jyk7CiAgICBpZihyZWNvSGludEVsKSByZWNvSGludEVsLnRleHRDb250ZW50ID0gcmVjby53aHk7CiAgICAvLyBBbm51YWwgUk9JIGV4dHJhcG9sYXRpb24uIFBlci1maWVsZCBmdWVsIHNhdmluZ3Mgw5cgYXBwbGljYXRpb25zIMOXIChmYXJtL2ZpZWxkKS4KICAgIHZhciByb2lGdWVsRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXJvaS1mdWVsJyk7CiAgICB2YXIgcm9pQ29zdEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1yb2ktY29zdCcpOwogICAgdmFyIHJvaVBlcmhhRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXJvaS1wZXJoYScpOwogICAgaWYocm9pRnVlbEVsID8gcm9pQ29zdEVsIDogZmFsc2UpewogICAgICBpZihjdXJyZW50ID09PSAnYWItc3RyYWlnaHQnKXsKICAgICAgICByb2lGdWVsRWwudGV4dENvbnRlbnQgPSAn4oCUIEwnOwogICAgICAgIHJvaUNvc3RFbC50ZXh0Q29udGVudCA9IHN5bSArICcg4oCUJzsKICAgICAgICBpZihyb2lQZXJoYUVsKSByb2lQZXJoYUVsLnRleHRDb250ZW50ID0gJ3BpY2sgbm9uLWJhc2VsaW5lJzsKICAgICAgICByb2lGdWVsRWwuc3R5bGUuY29sb3IgPSAnIzRjNjA2Nic7CiAgICAgICAgcm9pQ29zdEVsLnN0eWxlLmNvbG9yID0gJyM0YzYwNjYnOwogICAgICAgIGlmKHJvaVBlcmhhRWwpIHJvaVBlcmhhRWwuc3R5bGUuY29sb3IgPSAnIzRjNjA2Nic7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgdmFyIHBlckZpZWxkRnVlbCA9IGJhc2VNZXQuZnVlbEwgLSBtZXQuZnVlbEw7CiAgICAgICAgdmFyIHNjYWxlID0gYXJlYUhhID4gMCA\/IChpbnAuZmFybUhhIC8gYXJlYUhhKSA6IDA7CiAgICAgICAgdmFyIGFubnVhbEZ1ZWwgPSBwZXJGaWVsZEZ1ZWwgKiBpbnAuYXBwcyAqIHNjYWxlOwogICAgICAgIHZhciBhbm51YWxDb3N0ID0gYW5udWFsRnVlbCAqIGlucC5kaWVzZWw7CiAgICAgICAgdmFyIHBlckhhID0gaW5wLmZhcm1IYSA+IDAgPyAoYW5udWFsQ29zdCAvIGlucC5mYXJtSGEpIDogMDsKICAgICAgICB2YXIgc2lnblIgPSBhbm51YWxGdWVsID49IDAgPyAnJyA6ICfiiJInOwogICAgICAgIHJvaUZ1ZWxFbC50ZXh0Q29udGVudCA9IHNpZ25SICsgTWF0aC5hYnMoYW5udWFsRnVlbCkudG9GaXhlZCgwKSArICcgTCc7CiAgICAgICAgcm9pQ29zdEVsLnRleHRDb250ZW50ID0gKGFubnVhbENvc3QgPj0gMCA\/IHN5bSArICcgJyA6ICfiiJInICsgc3ltICsgJyAnKSArIE1hdGguYWJzKGFubnVhbENvc3QpLnRvRml4ZWQoMCk7CiAgICAgICAgaWYocm9pUGVyaGFFbCkgcm9pUGVyaGFFbC50ZXh0Q29udGVudCA9IChwZXJIYSA+PSAwID8gc3ltICsgJyAnIDogJ+KIkicgKyBzeW0gKyAnICcpICsgTWF0aC5hYnMocGVySGEpLnRvRml4ZWQoMikgKyAnL2hhJzsKICAgICAgICB2YXIgcm9pQ29sb3IgPSBhbm51YWxGdWVsID49IDAgPyAnIzE1NzAxZScgOiAnI2Y3NmEwYyc7CiAgICAgICAgcm9pRnVlbEVsLnN0eWxlLmNvbG9yID0gcm9pQ29sb3I7CiAgICAgICAgcm9pQ29zdEVsLnN0eWxlLmNvbG9yID0gcm9pQ29sb3I7CiAgICAgICAgaWYocm9pUGVyaGFFbCkgcm9pUGVyaGFFbC5zdHlsZS5jb2xvciA9IHJvaUNvbG9yOwogICAgICB9CiAgICB9CiAgICAvLyBXYXJuaW5nIGJhbm5lciBmcm9tIHZhbGlkYXRpb24gY2FzY2FkZQogICAgdmFyIHdhcm5FbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtd2FybicpOwogICAgaWYod2FybkVsKXsKICAgICAgaWYobGF5b3V0Lndhcm5pbmcpewogICAgICAgIHdhcm5FbC50ZXh0Q29udGVudCA9IGxheW91dC53YXJuaW5nOwogICAgICAgIHdhcm5FbC5jbGFzc0xpc3QuYWRkKCdpcy1vbicpOwogICAgICB9IGVsc2UgewogICAgICAgIHdhcm5FbC50ZXh0Q29udGVudCA9ICcnOwogICAgICAgIHdhcm5FbC5jbGFzc0xpc3QucmVtb3ZlKCdpcy1vbicpOwogICAgICB9CiAgICB9CiAgICB2YXIgYXBwcm9hY2hlcyA9IFsnYWItc3RyYWlnaHQnLCAnYWItY3VydmUnLCAnYm91bmRhcnknLCAnYWRhcHRpdmUnXTsKICAgIHZhciBhcE1ldHJpY3MgPSB7fTsKICAgIGZvcih2YXIgYT0wOyBhPGFwcHJvYWNoZXMubGVuZ3RoOyBhKyspewogICAgICB2YXIgYXAgPSBhcHByb2FjaGVzW2FdOwogICAgICB2YXIgYXBMYXlvdXQgPSBhcCA9PT0gY3VycmVudCA\/IGxheW91dCA6IGdlbmVyYXRlTGluZXMoYXAsIGlucC53TSwgQk9VTkRBUlksIGF4aXMsIGlucC5oZWFkbGFuZE0sIGlucC50dXJuU3R5bGUsIGlucC50dXJuUiwgaW5wLnR1cm5CdWYpOwogICAgICB2YXIgYXBNZXQgPSBhcCA9PT0gY3VycmVudCA\/IG1ldCA6IGNvbXB1dGVNZXRyaWNzKGFwTGF5b3V0LCBpbnAud00sIGlucC5kaWVzZWwsIGlucC5jb25zKTsKICAgICAgYXBNZXRyaWNzW2FwXSA9IGFwTWV0OwogICAgICB2YXIgcm93RWwgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuZ3BsLWNtcC1yb3dbZGF0YS1jbXA9IicgKyBhcCArICciXScpOwogICAgICBpZighcm93RWwpIGNvbnRpbnVlOwogICAgICB2YXIgdmFscyA9IHJvd0VsLnF1ZXJ5U2VsZWN0b3JBbGwoJy5ncGwtY21wLXZhbCcpOwogICAgICB2YWxzWzBdLnRleHRDb250ZW50ID0gKGFwTWV0LmNvdmVyYWdlUGN0IHx8IDApLnRvRml4ZWQoMCkgKyAnJSc7CiAgICAgIHZhbHNbMV0udGV4dENvbnRlbnQgPSBhcE1ldC5mdWVsTC50b0ZpeGVkKDApICsgJyBMJzsKICAgICAgdmFsc1syXS50ZXh0Q29udGVudCA9IHN5bSArIGFwTWV0LmNvc3RVU0QudG9GaXhlZCgwKTsKICAgICAgcm93RWwuY2xhc3NMaXN0LnRvZ2dsZSgnZ3BsLWNtcC1jdXJyZW50JywgYXAgPT09IGN1cnJlbnQpOwogICAgfQogICAgLy8gQXhpcyBzd2VlcCDigJQgZmllbGRzIHdpdGggbG93IGNvdmVyYWdlIChlLmcuIEwtc2hhcGUpIG1heSBiZW5lZml0IGZyb20gYQogICAgLy8gZGlmZmVyZW50IEFCIGF4aXMuIFRyeSA2IGFuZ2xlcyAoMTXCsCBpbmNyZW1lbnRzIG92ZXIgMOKAkzkwwrAsIHNpbmNlIHRoZQogICAgLy8gYXhpcyBpcyBiaWRpcmVjdGlvbmFsIOKGkiA5MMKwIHBlcmlvZCkgYW5kIHBlci1hcHByb2FjaCBwaWNrIHRoZSBCRVNUCiAgICAvLyBjb3ZlcmFnZSBheGlzLiBPbmx5IGtpY2tzIGluIHdoZW4gdGhlIHVzZXIgaGFzbid0IG1hbnVhbGx5IG92ZXJyaWRkZW4KICAgIC8vIHRoZSBheGlzICh1c2VyQXhpc0RlZyA9PT0gbnVsbCkuCiAgICB2YXIgYmVzdEFwQXhlcyA9IHt9OwogICAgaWYodXNlckF4aXNEZWcgPT09IG51bGwpewogICAgICB2YXIgc3dlZXBBbmdsZXMgPSBbMCwgMTUsIDMwLCA0NSwgNjAsIDc1XTsKICAgICAgLy8gUENBIGdpdmVzIHRoZSBuYXR1cmFsIGJhc2VsaW5lOyBpbmNsdWRlIGl0IHRvby4KICAgICAgdmFyIHBjYURlZyA9IE1hdGgucm91bmQoTWF0aC5hdGFuMihmaWVsZEF4aXMoQk9VTkRBUlkpLnV5LCBmaWVsZEF4aXMoQk9VTkRBUlkpLnV4KSAqIDE4MCAvIE1hdGguUEkpOwogICAgICB3aGlsZShwY2FEZWcgPCAwKSBwY2FEZWcgKz0gMTgwOwogICAgICB3aGlsZShwY2FEZWcgPj0gOTApIHBjYURlZyAtPSA5MDsKICAgICAgaWYoc3dlZXBBbmdsZXMuaW5kZXhPZihwY2FEZWcpIDwgMCkgc3dlZXBBbmdsZXMucHVzaChwY2FEZWcpOwogICAgICBmb3IodmFyIGFwcz0wOyBhcHM8YXBwcm9hY2hlcy5sZW5ndGg7IGFwcysrKXsKICAgICAgICB2YXIgYXBTID0gYXBwcm9hY2hlc1thcHNdOwogICAgICAgIHZhciBiZXN0TWV0ID0gYXBNZXRyaWNzW2FwU107CiAgICAgICAgdmFyIGJlc3RBbmcgPSBudWxsOwogICAgICAgIGZvcih2YXIgc2E9MDsgc2E8c3dlZXBBbmdsZXMubGVuZ3RoOyBzYSsrKXsKICAgICAgICAgIHZhciBhbmcgPSBzd2VlcEFuZ2xlc1tzYV0gKiBNYXRoLlBJIC8gMTgwOwogICAgICAgICAgdmFyIHRyaWFsQXhpcyA9IHsgdXg6IE1hdGguY29zKGFuZyksIHV5OiBNYXRoLnNpbihhbmcpIH07CiAgICAgICAgICB2YXIgdHJpYWxMYXkgPSBnZW5lcmF0ZUxpbmVzKGFwUywgaW5wLndNLCBCT1VOREFSWSwgdHJpYWxBeGlzLCBpbnAuaGVhZGxhbmRNLCBpbnAudHVyblN0eWxlLCBpbnAudHVyblIsIGlucC50dXJuQnVmKTsKICAgICAgICAgIHZhciB0cmlhbE1ldCA9IGNvbXB1dGVNZXRyaWNzKHRyaWFsTGF5LCBpbnAud00sIGlucC5kaWVzZWwsIGlucC5jb25zKTsKICAgICAgICAgIGlmKCh0cmlhbE1ldC5jb3ZlcmFnZVBjdCB8fCAwKSA+IChiZXN0TWV0LmNvdmVyYWdlUGN0IHx8IDApKXsKICAgICAgICAgICAgYmVzdE1ldCA9IHRyaWFsTWV0OwogICAgICAgICAgICBiZXN0QW5nID0gc3dlZXBBbmdsZXNbc2FdOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZihiZXN0QW5nICE9PSBudWxsKXsKICAgICAgICAgIGFwTWV0cmljc1thcFNdID0gYmVzdE1ldDsKICAgICAgICAgIGJlc3RBcEF4ZXNbYXBTXSA9IGJlc3RBbmc7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICAvLyBNZXRyaWMtZHJpdmVuIHJlY29tbWVuZGF0aW9uIChub3cgdXNlcyB0aGUgc3dlcHQtYXhpcyBtZXRyaWNzKQogICAgdmFyIHJlY29NZXRyaWMgPSByZWNvbW1lbmRCeU1ldHJpY3MoYXBNZXRyaWNzKTsKICAgIHZhciByZWNvQmFkZ2VzMiA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy5ncGwtcmVjbycpOwogICAgZm9yKHZhciByYjI9MDsgcmIyPHJlY29CYWRnZXMyLmxlbmd0aDsgcmIyKyspewogICAgICB2YXIgcmtleTIgPSByZWNvQmFkZ2VzMltyYjJdLmdldEF0dHJpYnV0ZSgnZGF0YS1yZWNvJyk7CiAgICAgIHJlY29CYWRnZXMyW3JiMl0uY2xhc3NMaXN0LnRvZ2dsZSgnaXMtb24nLCBya2V5MiA9PT0gcmVjb01ldHJpYy5waWNrKTsKICAgIH0KICAgIHZhciByZWNvSGludEVsMiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtcmVjby1oaW50Jyk7CiAgICBpZihyZWNvSGludEVsMil7CiAgICAgIHZhciBoaW50VHh0ID0gcmVjb01ldHJpYy53aHk7CiAgICAgIGlmKGJlc3RBcEF4ZXNbcmVjb01ldHJpYy5waWNrXSAhPT0gdW5kZWZpbmVkKXsKICAgICAgICBoaW50VHh0ICs9ICcgwrcgYmVzdCBhdCAnICsgYmVzdEFwQXhlc1tyZWNvTWV0cmljLnBpY2tdICsgJ8KwJzsKICAgICAgfQogICAgICAvLyBTdXJmYWNlIGxvdy1jb3ZlcmFnZSB3YXJuaW5nIHByb21pbmVudGx5CiAgICAgIHZhciBiZXN0Q292ID0gKGFwTWV0cmljc1tyZWNvTWV0cmljLnBpY2tdIHx8IHt9KS5jb3ZlcmFnZVBjdCB8fCAwOwogICAgICBpZihiZXN0Q292IDwgNzApewogICAgICAgIGhpbnRUeHQgKz0gJyDigJQgc3BsaXQgZmllbGQgZm9yIGZ1bGwgY292ZXJhZ2UnOwogICAgICB9CiAgICAgIHJlY29IaW50RWwyLnRleHRDb250ZW50ID0gaGludFR4dDsKICAgIH0KICAgIC8vIFVwZGF0ZSB0aGUgQ29tcGFyZSBBbGwgY2VsbHMgd2l0aCB0aGUgc3dlcHQtYXhpcyBtZXRyaWNzIHNvIHRoZSB1c2VyCiAgICAvLyBzZWVzIHRoZSBCRVNUIGFjaGlldmFibGUgY292ZXJhZ2UgcGVyIGFwcHJvYWNoLCBub3QganVzdCBQQ0EtYXhpcy4KICAgIGZvcih2YXIgYWE9MDsgYWE8YXBwcm9hY2hlcy5sZW5ndGg7IGFhKyspewogICAgICB2YXIgYXBYID0gYXBwcm9hY2hlc1thYV07CiAgICAgIHZhciByb3dYID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmdwbC1jbXAtcm93W2RhdGEtY21wPSInICsgYXBYICsgJyJdJyk7CiAgICAgIGlmKCFyb3dYKSBjb250aW51ZTsKICAgICAgdmFyIG1YID0gYXBNZXRyaWNzW2FwWF07CiAgICAgIHZhciB2YWxzWCA9IHJvd1gucXVlcnlTZWxlY3RvckFsbCgnLmdwbC1jbXAtdmFsJyk7CiAgICAgIHZhbHNYWzBdLnRleHRDb250ZW50ID0gKG1YLmNvdmVyYWdlUGN0IHx8IDApLnRvRml4ZWQoMCkgKyAnJSc7CiAgICAgIHZhbHNYWzFdLnRleHRDb250ZW50ID0gbVguZnVlbEwudG9GaXhlZCgwKSArICcgTCc7CiAgICAgIHZhbHNYWzJdLnRleHRDb250ZW50ID0gc3ltICsgbVguY29zdFVTRC50b0ZpeGVkKDApOwogICAgfQogICAgc2V0UGxheWJhY2tQYXRoKGxheW91dCwgaW5wLndNKTsKICAgIHVwZGF0ZVBsYXliYWNrVUkoKTsKICAgIGRyYXcobGF5b3V0KTsKICB9CgogIC8vIFVwZGF0ZSB0aGUgaGVhZGxhbmQgc2xpZGVyIGxhYmVsLiBIZWFkbGFuZCA9IG11bHQgw5cgd00gKHNvbGUgc291cmNlIG9mCiAgLy8gdHJ1dGgg4oCUIG5vIHNlcGFyYXRlIGN1c3RvbS13aWR0aCBpbnB1dCBhbnltb3JlKS4KICBmdW5jdGlvbiB1cGRhdGVIZWFkbGFuZExhYmVsKCl7CiAgICB2YXIgd00gPSBwYXJzZUZsb2F0KGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtd20nKS52YWx1ZSkgfHwgMTg7CiAgICB2YXIgaGxNdWx0ID0gcGFyc2VGbG9hdChkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLWhsLW11bHQnKS52YWx1ZSk7CiAgICBpZihpc05hTihobE11bHQpKSBobE11bHQgPSAxOwogICAgdmFyIGxhYmVsRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLWhsLXZhbCcpOwogICAgaWYoIWxhYmVsRWwpIHJldHVybjsKICAgIHZhciBtID0gaGxNdWx0ICogd007CiAgICBsYWJlbEVsLnRleHRDb250ZW50ID0gbS50b0ZpeGVkKDApICsgJyBtIMK3ICcgKyBobE11bHQgKyAnw5cgcGFzcyc7CiAgfQoKICB2YXIgcmFkaW9zID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnI2dwbC1hcHByb2FjaCBpbnB1dFt0eXBlPXJhZGlvXScpOwogIGZvcih2YXIgcmk9MDsgcmk8cmFkaW9zLmxlbmd0aDsgcmkrKyl7CiAgICByYWRpb3NbcmldLmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIGZ1bmN0aW9uKCl7CiAgICAgIHZhciBsYWJzID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnI2dwbC1hcHByb2FjaCBsYWJlbCcpOwogICAgICBmb3IodmFyIGxpPTA7IGxpPGxhYnMubGVuZ3RoOyBsaSsrKSBsYWJzW2xpXS5jbGFzc0xpc3QucmVtb3ZlKCdpcy1vbicpOwogICAgICB0aGlzLnBhcmVudE5vZGUuY2xhc3NMaXN0LmFkZCgnaXMtb24nKTsKICAgICAgY3VycmVudCA9IHRoaXMudmFsdWU7CiAgICAgIHJlY29tcHV0ZSgpOwogICAgfSk7CiAgfQogIC8vIEVxdWlwbWVudCArIGVjb25vbWljcyBpbnB1dHMKICB2YXIgYmFzaWNJZHMgPSBbJ2dwbC13bScsICdncGwtZnVlbCcsICdncGwtY29ucyddOwogIGZvcih2YXIgaWk9MDsgaWk8YmFzaWNJZHMubGVuZ3RoOyBpaSsrKXsKICAgIHZhciBlbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGJhc2ljSWRzW2lpXSk7CiAgICBpZihlbCl7CiAgICAgIGVsLmFkZEV2ZW50TGlzdGVuZXIoJ2lucHV0JywgZnVuY3Rpb24oKXsKICAgICAgICB1cGRhdGVIZWFkbGFuZExhYmVsKCk7CiAgICAgICAgcmVjb21wdXRlKCk7CiAgICAgIH0pOwogICAgfQogIH0KICAvLyBIZWFkbGFuZCBzbGlkZXIg4oCUIGRyaXZlcyBoZWFkbGFuZCA9IG11bHQgw5cgd00KICB2YXIgaGxTbGlkZXIgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLWhsLW11bHQnKTsKICBpZihobFNsaWRlcil7CiAgICBobFNsaWRlci5hZGRFdmVudExpc3RlbmVyKCdpbnB1dCcsIGZ1bmN0aW9uKCl7CiAgICAgIHVwZGF0ZUhlYWRsYW5kTGFiZWwoKTsKICAgICAgcmVjb21wdXRlKCk7CiAgICB9KTsKICB9CiAgLy8gUk9JIGlucHV0cyDigJQgcHVyZWx5IGluZm9ybWF0aW9uYWwsIGp1c3QgcmUtcnVuIHJlY29tcHV0ZQogIHZhciByb2lJZHMgPSBbJ2dwbC1yb2ktZmFybScsICdncGwtcm9pLWFwcHMnXTsKICBmb3IodmFyIHJvaT0wOyByb2k8cm9pSWRzLmxlbmd0aDsgcm9pKyspewogICAgdmFyIHJvaUVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQocm9pSWRzW3JvaV0pOwogICAgaWYocm9pRWwpIHJvaUVsLmFkZEV2ZW50TGlzdGVuZXIoJ2lucHV0JywgcmVjb21wdXRlKTsKICB9CiAgLy8gVHVybi1hcm91bmQgY29udHJvbHMKICB2YXIgdHVybklkcyA9IFsnZ3BsLXR1cm4tc3R5bGUnLCAnZ3BsLXR1cm4tcicsICdncGwtdHVybi1idWYnXTsKICBmb3IodmFyIHRpPTA7IHRpPHR1cm5JZHMubGVuZ3RoOyB0aSsrKXsKICAgIHZhciB0RWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0dXJuSWRzW3RpXSk7CiAgICBpZih0RWwpewogICAgICB0RWwuYWRkRXZlbnRMaXN0ZW5lcignaW5wdXQnLCByZWNvbXB1dGUpOwogICAgICB0RWwuYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgcmVjb21wdXRlKTsKICAgIH0KICB9CiAgLy8gTWFjaGluZSB0eXBlIOKAlCBhdXRvLWZpbGxzIEJPVEggdHVybiByYWRpdXMgYW5kIGltcGxlbWVudCB3aWR0aCAodW5sZXNzCiAgLy8gJ2N1c3RvbScpLiBFYWNoIG1hY2hpbmUgY2xhc3MgaGFzIHR5cGljYWwgc3BlY3MgZnJvbSBtYW51ZmFjdHVyZXIgYXZlcmFnZXMuCiAgZnVuY3Rpb24gYXBwbHlNYWNoaW5lUmFkaXVzKCl7CiAgICB2YXIgbUVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1tYWNoaW5lJyk7CiAgICB2YXIgckVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC10dXJuLXInKTsKICAgIHZhciB3RWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXdtJyk7CiAgICB2YXIgaGludEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC10dXJuLXItaGludCcpOwogICAgaWYoIW1FbCA\/IHRydWUgOiAhckVsKSByZXR1cm47CiAgICB2YXIgc3BlYyA9IE1BQ0hJTkVfU1BFQ1ttRWwudmFsdWVdIHx8IE1BQ0hJTkVfU1BFQ1sndHJhY3Rvci1zdGQnXTsKICAgIGlmKG1FbC52YWx1ZSAhPT0gJ2N1c3RvbScgPyBzcGVjLnIgPiAwIDogZmFsc2UpewogICAgICByRWwudmFsdWUgPSBTdHJpbmcoc3BlYy5yKTsKICAgICAgckVsLmRpc2FibGVkID0gZmFsc2U7CiAgICB9CiAgICBpZihtRWwudmFsdWUgIT09ICdjdXN0b20nID8gKHNwZWMudyA+IDAgPyB3RWwgOiBmYWxzZSkgOiBmYWxzZSl7CiAgICAgIHdFbC52YWx1ZSA9IFN0cmluZyhzcGVjLncpOwogICAgfQogICAgLy8gU3luYyBoZWFkbGFuZCBzbGlkZXIvbGFiZWwgdG8gdGhlIG5ldyB3aWR0aCBzbyBoZWFkbGFuZE0gc3RheXMgYXQgdGhlCiAgICAvLyB1c2VyJ3MgaW50ZW5kZWQgbXVsdGlwbGllciBvZiBwYXNzIHdpZHRoLgogICAgdXBkYXRlSGVhZGxhbmRMYWJlbCgpOwogICAgaWYoaGludEVsKXsKICAgICAgaGludEVsLnRleHRDb250ZW50ID0gbUVsLnZhbHVlID09PSAnY3VzdG9tJyA\/ICdtYW51YWwgb3ZlcnJpZGUnIDogKCdhdXRvIMK3ICcgKyBzcGVjLmxhYmVsKTsKICAgIH0KICB9CiAgdmFyIG1hY2hpbmVTZWxFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtbWFjaGluZScpOwogIGlmKG1hY2hpbmVTZWxFbCl7CiAgICBtYWNoaW5lU2VsRWwuYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgZnVuY3Rpb24oKXsKICAgICAgYXBwbHlNYWNoaW5lUmFkaXVzKCk7CiAgICAgIHJlY29tcHV0ZSgpOwogICAgfSk7CiAgfQogIC8vIEN1cnJlbmN5IHNlbGVjdCDigJQgcHVyZWx5IGEgbGFiZWwgc3dpdGNoOyB1c2VyIHR5cGVzIHRoZWlyIGxvY2FsIHByaWNlCiAgdmFyIGN1clNlbEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1jdXJyZW5jeScpOwogIGlmKGN1clNlbEVsKSBjdXJTZWxFbC5hZGRFdmVudExpc3RlbmVyKCdjaGFuZ2UnLCByZWNvbXB1dGUpOwoKICAvLyBGaWxlLWltcG9ydCBoZWxwZXJzIOKAlCBhY2NlcHQgR2VvSlNPTiwgS01MLCBvciB6aXBwZWQgc2hhcGVmaWxlLiBFeHRyYWN0CiAgLy8gQUxMIHBvbHlnb24gb3V0ZXIgcmluZ3MgKHNvIHVzZXJzIGNhbiBpdGVyYXRlIHRocm91Z2ggZmllbGRzIGluIGEKICAvLyBtdWx0aS1mZWF0dXJlIGZpbGUpLCBwcm9qZWN0IGxhdC9sbmcgdG8gbG9jYWwgbWV0ZXJzIHdpdGggZWFjaCBwb2x5Z29uJ3MKICAvLyBvd24gY2VudHJvaWQgYXMgb3JpZ2luLCBmaXQgaW50byB0aGUgZXhpc3RpbmcgY2FudmFzIGNvb3JkaW5hdGUgc2NoZW1lLgogIC8vIEltcG9ydGVkIHBvbHlnb25zIGxpdmUgaW4gYGltcG9ydGVkRmllbGRzYCAoYXJyYXkgb2YgeyBuYW1lLCBjb29yZHMgfQogIC8vIHdoZXJlIGNvb3JkcyBpcyBjYW52YXMtbWV0ZXIge3gseX0gcG9pbnRzKS4gSXRlcmF0b3IgVUkgbGV0cyB0aGUgdXNlcgogIC8vIHN0ZXAgdGhyb3VnaCB0aGVtLgogIHZhciBpbXBvcnRlZEZpZWxkcyA9IFtdOwogIHZhciBpbXBvcnRlZElkeCA9IDA7CiAgLy8gTGF6eS1sb2FkIHNocGpzIGZyb20ganNEZWxpdnIgb24gZGVtYW5kIGZvciAuemlwIC8gLnNocCBpbnB1dHMuIFRoZQogIC8vIHByb21pc2UgaXMgY2FjaGVkIHNvIHN1YnNlcXVlbnQgdXBsb2FkcyBkbyBub3QgcmUtZmV0Y2ggdGhlIGxpYnJhcnkuCiAgLy8gVGhpcyBpcyB0aGUgb25seSBuZXR3b3JrIGRlcGVuZGVuY3kgaW4gdGhlIHRvb2wg4oCUIG9wdC1pbiB2aWEgdXBsb2FkLgogIHZhciBzaHBqc1Byb21pc2UgPSBudWxsOwogIGZ1bmN0aW9uIGxvYWRTaHBqcygpewogICAgaWYodHlwZW9mIHdpbmRvdy5zaHAgPT09ICdmdW5jdGlvbicpIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTsKICAgIGlmKHNocGpzUHJvbWlzZSkgcmV0dXJuIHNocGpzUHJvbWlzZTsKICAgIHNocGpzUHJvbWlzZSA9IG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCl7CiAgICAgIHZhciBzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc2NyaXB0Jyk7CiAgICAgIC8vIENETiBVUkwgaGFzIG5vIHF1ZXJ5IHNlcGFyYXRvcnMsIHNvIHJ1bGUgMSBpcyBub3QgYXQgcmlzayBoZXJlLgogICAgICBzLnNyYyA9ICdodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL3NocGpzQDQuMC40L2Rpc3Qvc2hwLm1pbi5qcyc7CiAgICAgIHMub25sb2FkID0gZnVuY3Rpb24oKXsgcmVzb2x2ZSgpOyB9OwogICAgICBzLm9uZXJyb3IgPSBmdW5jdGlvbigpeyBzaHBqc1Byb21pc2UgPSBudWxsOyByZWplY3QobmV3IEVycm9yKCdDb3VsZCBub3QgbG9hZCBzaGFwZWZpbGUgcGFyc2VyJykpOyB9OwogICAgICBkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKHMpOwogICAgfSk7CiAgICByZXR1cm4gc2hwanNQcm9taXNlOwogIH0KICAvLyBFeHRyYWN0IGV2ZXJ5IHBvbHlnb24gb3V0ZXIgcmluZyBmcm9tIGFueSBHZW9KU09OIG9iamVjdC4gUmV0dXJucwogIC8vIFt7IG5hbWUsIGNvb3JkczogW1tsbmcsbGF0XSwg4oCmXSB9LCDigKZdIHNvcnRlZCBieSBhcmVhIGRlc2NlbmRpbmcgc28gdGhlCiAgLy8gYmlnZ2VzdCBwb2x5Z29uICh1c3VhbGx5IHRoZSBmaWVsZCBvZiBpbnRlcmVzdCkgY29tZXMgZmlyc3QuCiAgZnVuY3Rpb24gZXh0cmFjdEFsbFBvbHlnb25zR2VvSlNPTihvYmopewogICAgdmFyIHBvbHlzID0gW107CiAgICBmdW5jdGlvbiBwdXNoRmVhdHVyZShmLCBkZWZhdWx0TmFtZSl7CiAgICAgIGlmKCFmKSByZXR1cm47CiAgICAgIHZhciBwcm9wcyA9IGYucHJvcGVydGllcyB8fCB7fTsKICAgICAgdmFyIG5hbWUgPSBwcm9wcy5uYW1lIHx8IHByb3BzLk5hbWUgfHwgcHJvcHMuTkFNRSB8fCBwcm9wcy5maWVsZCB8fCBwcm9wcy5GaWVsZCB8fCBwcm9wcy5GSUVMRCB8fCBwcm9wcy5pZCB8fCBkZWZhdWx0TmFtZTsKICAgICAgdmFyIGdlb20gPSBmLmdlb21ldHJ5ID8gZi5nZW9tZXRyeSA6IChmLnR5cGUgPT09ICdQb2x5Z29uJyA\/IGYgOiAoZi50eXBlID09PSAnTXVsdGlQb2x5Z29uJyA\/IGYgOiBudWxsKSk7CiAgICAgIGlmKCFnZW9tKSByZXR1cm47CiAgICAgIGlmKGdlb20udHlwZSA9PT0gJ1BvbHlnb24nKXsKICAgICAgICBwb2x5cy5wdXNoKHsgbmFtZTogbmFtZSwgY29vcmRzOiBnZW9tLmNvb3JkaW5hdGVzWzBdIH0pOwogICAgICB9IGVsc2UgaWYoZ2VvbS50eXBlID09PSAnTXVsdGlQb2x5Z29uJyl7CiAgICAgICAgZm9yKHZhciBpPTA7IGk8Z2VvbS5jb29yZGluYXRlcy5sZW5ndGg7IGkrKyl7CiAgICAgICAgICBwb2x5cy5wdXNoKHsgbmFtZTogKG5hbWUgfHwgJ3BvbHknKSArICcgIycgKyAoaSArIDEpLCBjb29yZHM6IGdlb20uY29vcmRpbmF0ZXNbaV1bMF0gfSk7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBpZihvYmoudHlwZSA9PT0gJ0ZlYXR1cmVDb2xsZWN0aW9uJyA\/IG9iai5mZWF0dXJlcyA6IGZhbHNlKXsKICAgICAgZm9yKHZhciBrPTA7IGs8b2JqLmZlYXR1cmVzLmxlbmd0aDsgaysrKSBwdXNoRmVhdHVyZShvYmouZmVhdHVyZXNba10sICdmZWF0dXJlICcgKyAoayArIDEpKTsKICAgIH0gZWxzZSBpZihvYmoudHlwZSA9PT0gJ0ZlYXR1cmUnKXsKICAgICAgcHVzaEZlYXR1cmUob2JqLCAnZmVhdHVyZSAxJyk7CiAgICB9IGVsc2UgaWYob2JqLnR5cGUgPT09ICdQb2x5Z29uJyA\/IHRydWUgOiBvYmoudHlwZSA9PT0gJ011bHRpUG9seWdvbicpewogICAgICBwdXNoRmVhdHVyZSh7IGdlb21ldHJ5OiBvYmosIHByb3BlcnRpZXM6IHt9IH0sICdwb2x5Z29uJyk7CiAgICB9CiAgICAvLyBTb3J0IGJ5IGFwcHJveGltYXRlIGFyZWEgKGNyb3NzLXByb2R1Y3Qgc3VtIG9mIGxuZy9sYXQgY29vcmRzIOKAlCBub3QKICAgIC8vIG3CsiBidXQgbW9ub3RvbmljLCBzbyBsYXJnZXN0IHBvbHlnb24gc3RpbGwgd2lucykuCiAgICBwb2x5cy5mb3JFYWNoKGZ1bmN0aW9uKHApewogICAgICB2YXIgYSA9IDA7CiAgICAgIGZvcih2YXIgaT0wOyBpPHAuY29vcmRzLmxlbmd0aC0xOyBpKyspewogICAgICAgIGEgKz0gcC5jb29yZHNbaV1bMF0gKiBwLmNvb3Jkc1tpKzFdWzFdIC0gcC5jb29yZHNbaSsxXVswXSAqIHAuY29vcmRzW2ldWzFdOwogICAgICB9CiAgICAgIHAuX2FyZWFTY29yZSA9IE1hdGguYWJzKGEpOwogICAgfSk7CiAgICBwb2x5cy5zb3J0KGZ1bmN0aW9uKGEsIGIpeyByZXR1cm4gYi5fYXJlYVNjb3JlIC0gYS5fYXJlYVNjb3JlOyB9KTsKICAgIHJldHVybiBwb2x5czsKICB9CiAgZnVuY3Rpb24gZXh0cmFjdEFsbFBvbHlnb25zS01MKHRleHQpewogICAgaWYodHlwZW9mIERPTVBhcnNlciA9PT0gJ3VuZGVmaW5lZCcpIHJldHVybiBbXTsKICAgIHZhciBkb2M7CiAgICB0cnkgeyBkb2MgPSBuZXcgRE9NUGFyc2VyKCkucGFyc2VGcm9tU3RyaW5nKHRleHQsICdhcHBsaWNhdGlvbi94bWwnKTsgfSBjYXRjaChlKXsgcmV0dXJuIFtdOyB9CiAgICB2YXIgcGxhY2VtYXJrcyA9IGRvYy5nZXRFbGVtZW50c0J5VGFnTmFtZSgnUGxhY2VtYXJrJyk7CiAgICB2YXIgcG9seXMgPSBbXTsKICAgIGZ1bmN0aW9uIGNvb3Jkc0Zyb21UZXh0KHJhdyl7CiAgICAgIHZhciBwYWlycyA9IHJhdy5zcGxpdCgvXHMrLykubWFwKGZ1bmN0aW9uKHMpeyByZXR1cm4gcy50cmltKCk7IH0pLmZpbHRlcihmdW5jdGlvbihzKXsgcmV0dXJuIHMubGVuZ3RoID4gMDsgfSk7CiAgICAgIHZhciBvdXQgPSBbXTsKICAgICAgZm9yKHZhciBpPTA7IGk8cGFpcnMubGVuZ3RoOyBpKyspewogICAgICAgIHZhciBwYXJ0cyA9IHBhaXJzW2ldLnNwbGl0KCcsJyk7CiAgICAgICAgaWYocGFydHMubGVuZ3RoIDwgMikgY29udGludWU7CiAgICAgICAgdmFyIGxuZyA9IHBhcnNlRmxvYXQocGFydHNbMF0pLCBsYXQgPSBwYXJzZUZsb2F0KHBhcnRzWzFdKTsKICAgICAgICBpZihpc05hTihsbmcpID8gdHJ1ZSA6IGlzTmFOKGxhdCkpIGNvbnRpbnVlOwogICAgICAgIG91dC5wdXNoKFtsbmcsIGxhdF0pOwogICAgICB9CiAgICAgIHJldHVybiBvdXQ7CiAgICB9CiAgICBpZihwbGFjZW1hcmtzLmxlbmd0aCA+IDApewogICAgICBmb3IodmFyIHBpPTA7IHBpPHBsYWNlbWFya3MubGVuZ3RoOyBwaSsrKXsKICAgICAgICB2YXIgcG0gPSBwbGFjZW1hcmtzW3BpXTsKICAgICAgICB2YXIgbmFtZUVsID0gcG0uZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ25hbWUnKTsKICAgICAgICB2YXIgbmFtZSA9IChuYW1lRWwubGVuZ3RoID4gMCA\/IG5hbWVFbFswXS50ZXh0Q29udGVudCA6ICdwbGFjZW1hcmsgJyArIChwaSArIDEpKSB8fCAoJ3BsYWNlbWFyayAnICsgKHBpICsgMSkpOwogICAgICAgIHZhciBjb29yZHNFbHMgPSBwbS5nZXRFbGVtZW50c0J5VGFnTmFtZSgnY29vcmRpbmF0ZXMnKTsKICAgICAgICBmb3IodmFyIGNpPTA7IGNpPGNvb3Jkc0Vscy5sZW5ndGg7IGNpKyspewogICAgICAgICAgdmFyIGMgPSBjb29yZHNGcm9tVGV4dChjb29yZHNFbHNbY2ldLnRleHRDb250ZW50IHx8ICcnKTsKICAgICAgICAgIGlmKGMubGVuZ3RoID49IDMpIHBvbHlzLnB1c2goeyBuYW1lOiBuYW1lICsgKGNvb3Jkc0Vscy5sZW5ndGggPiAxID8gJyAjJyArIChjaSArIDEpIDogJycpLCBjb29yZHM6IGMgfSk7CiAgICAgICAgfQogICAgICB9CiAgICB9IGVsc2UgewogICAgICAvLyBGYWxsYmFjazogYmFyZSBLTUwgd2l0aCA8Y29vcmRpbmF0ZXM+IGVsc2V3aGVyZQogICAgICB2YXIgY29vcmRzQWxsID0gZG9jLmdldEVsZW1lbnRzQnlUYWdOYW1lKCdjb29yZGluYXRlcycpOwogICAgICBmb3IodmFyIGNhPTA7IGNhPGNvb3Jkc0FsbC5sZW5ndGg7IGNhKyspewogICAgICAgIHZhciBjMiA9IGNvb3Jkc0Zyb21UZXh0KGNvb3Jkc0FsbFtjYV0udGV4dENvbnRlbnQgfHwgJycpOwogICAgICAgIGlmKGMyLmxlbmd0aCA+PSAzKSBwb2x5cy5wdXNoKHsgbmFtZTogJ3BvbHlnb24gJyArIChjYSArIDEpLCBjb29yZHM6IGMyIH0pOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gcG9seXM7CiAgfQogIC8vIENvbnZlcnQgW2xuZywgbGF0XSBhcnJheSB0byBsb2NhbCBjYW52YXMtbWV0ZXIgY29vcmRzLiBDZW50ZXIgdGhlIGZpZWxkIGF0CiAgLy8gdGhlIGNhbnZhcyBjZW50cm9pZCAofjM4MCwgMjkwKSBzbyB0aGUgZXhpc3Rpbmcgc2NhbGUgbG9naWMgZml0cyBpdC4KICBmdW5jdGlvbiBsbmdMYXRUb0NhbnZhcyhjb29yZHMpewogICAgaWYoIWNvb3JkcyA\/IHRydWUgOiBjb29yZHMubGVuZ3RoIDwgMykgcmV0dXJuIG51bGw7CiAgICAvLyBVc2UgY2VudHJvaWQgKGF2ZXJhZ2UpIGFzIHRoZSBwcm9qZWN0aW9uIG9yaWdpbgogICAgdmFyIG9MYXQgPSAwLCBvTG5nID0gMDsKICAgIGZvcih2YXIgaT0wOyBpPGNvb3Jkcy5sZW5ndGg7IGkrKyl7IG9MbmcgKz0gY29vcmRzW2ldWzBdOyBvTGF0ICs9IGNvb3Jkc1tpXVsxXTsgfQogICAgb0xhdCAvPSBjb29yZHMubGVuZ3RoOyBvTG5nIC89IGNvb3Jkcy5sZW5ndGg7CiAgICB2YXIgY29zTGF0ID0gTWF0aC5jb3Mob0xhdCAqIE1hdGguUEkgLyAxODApOwogICAgdmFyIHB0cyA9IFtdOwogICAgZm9yKHZhciBqPTA7IGo8Y29vcmRzLmxlbmd0aDsgaisrKXsKICAgICAgdmFyIGxuZyA9IGNvb3Jkc1tqXVswXSwgbGF0ID0gY29vcmRzW2pdWzFdOwogICAgICB2YXIgbXggPSAobG5nIC0gb0xuZykgKiAxMTEzMjAgKiBjb3NMYXQ7CiAgICAgIHZhciBteSA9IC0obGF0IC0gb0xhdCkgKiAxMTEzMjA7ICAvLyBjYW52YXMgeSBpcyArZG93biwgc28gZmxpcAogICAgICBwdHMucHVzaCh7IHg6IDM4MCArIG14LCB5OiAyOTAgKyBteSB9KTsKICAgIH0KICAgIC8vIFN0cmlwIGEgdHJhaWxpbmcgZHVwbGljYXRlIHZlcnRleCAoTGluZWFyUmluZ3MgY2xvc2UgdGhlbXNlbHZlcykKICAgIHZhciBsYXN0ID0gcHRzW3B0cy5sZW5ndGggLSAxXSwgZmlyc3QgPSBwdHNbMF07CiAgICBpZihNYXRoLmFicyhsYXN0LnggLSBmaXJzdC54KSA8IDAuMDEgPyBNYXRoLmFicyhsYXN0LnkgLSBmaXJzdC55KSA8IDAuMDEgOiBmYWxzZSl7CiAgICAgIHB0cy5wb3AoKTsKICAgIH0KICAgIHJldHVybiBwdHMubGVuZ3RoID49IDMgPyBwdHMgOiBudWxsOwogIH0KICBmdW5jdGlvbiBzaG93VXBsb2FkU3RhdHVzKHN0YXRlLCBtc2cpewogICAgdmFyIGxibCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtdXBsb2FkLWxibCcpOwogICAgdmFyIGhpbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXVwbG9hZC1oaW50Jyk7CiAgICBpZighbGJsKSByZXR1cm47CiAgICBsYmwuY2xhc3NMaXN0LnJlbW92ZSgnaXMtZXJyb3InLCAnaXMtc3VjY2VzcycpOwogICAgaWYoc3RhdGUgPT09ICdlcnJvcicpIGxibC5jbGFzc0xpc3QuYWRkKCdpcy1lcnJvcicpOwogICAgZWxzZSBpZihzdGF0ZSA9PT0gJ3N1Y2Nlc3MnKSBsYmwuY2xhc3NMaXN0LmFkZCgnaXMtc3VjY2VzcycpOwogICAgaWYoaGludCkgaGludC50ZXh0Q29udGVudCA9IG1zZzsKICB9CiAgLy8gQXBwbHkgaW1wb3J0ZWQgcG9seWdvbiBhdCBpbmRleCBpIHRvIEZJRUxEUy5jdXN0b20gKyBCT1VOREFSWSArIHJlY29tcHV0ZS4KICBmdW5jdGlvbiBhcHBseUltcG9ydGVkRmllbGQoaSl7CiAgICBpZighaW1wb3J0ZWRGaWVsZHMubGVuZ3RoKSByZXR1cm47CiAgICBpZihpIDwgMCkgaSA9IDA7CiAgICBpZihpID49IGltcG9ydGVkRmllbGRzLmxlbmd0aCkgaSA9IGltcG9ydGVkRmllbGRzLmxlbmd0aCAtIDE7CiAgICBpbXBvcnRlZElkeCA9IGk7CiAgICB2YXIgcGYgPSBpbXBvcnRlZEZpZWxkc1tpXTsKICAgIHZhciBwdHMgPSBsbmdMYXRUb0NhbnZhcyhwZi5jb29yZHMpOwogICAgaWYoIXB0cyl7IHNob3dVcGxvYWRTdGF0dXMoJ2Vycm9yJywgJ1BvbHlnb24gbmVlZHMgYXQgbGVhc3QgMyB2ZXJ0aWNlcycpOyByZXR1cm47IH0KICAgIEZJRUxEUy5jdXN0b20gPSBwdHM7CiAgICBjdXJyZW50RmllbGQgPSAnY3VzdG9tJzsKICAgIEJPVU5EQVJZID0gcHRzOwogICAgdXNlckF4aXNEZWcgPSBudWxsOwogICAgdmFyIHBpY2tlciA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJyNncGwtZmllbGQtcGlja2VyIC5ncGwtZmxkJyk7CiAgICBmb3IodmFyIHBwPTA7IHBwPHBpY2tlci5sZW5ndGg7IHBwKyspIHBpY2tlcltwcF0uY2xhc3NMaXN0LnJlbW92ZSgnaXMtb24nKTsKICAgIHZhciBuYXZFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtaW1wb3J0LW5hdicpOwogICAgdmFyIGxibEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1pbXAtbGJsJyk7CiAgICB2YXIgcHJldkJ0biA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtaW1wLXByZXYnKTsKICAgIHZhciBuZXh0QnRuID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1pbXAtbmV4dCcpOwogICAgaWYobmF2RWwpIG5hdkVsLmhpZGRlbiA9IGltcG9ydGVkRmllbGRzLmxlbmd0aCA8IDI7CiAgICBpZihsYmxFbCkgbGJsRWwudGV4dENvbnRlbnQgPSAoaSArIDEpICsgJyAvICcgKyBpbXBvcnRlZEZpZWxkcy5sZW5ndGg7CiAgICBpZihwcmV2QnRuKSBwcmV2QnRuLmRpc2FibGVkID0gaSA9PT0gMDsKICAgIGlmKG5leHRCdG4pIG5leHRCdG4uZGlzYWJsZWQgPSBpID09PSBpbXBvcnRlZEZpZWxkcy5sZW5ndGggLSAxOwogICAgc2hvd1VwbG9hZFN0YXR1cygnc3VjY2VzcycsIChwZi5uYW1lIHx8ICgnYm91bmRhcnkgJyArIChpICsgMSkpKSArICcgwrcgJyArIHB0cy5sZW5ndGggKyAnIHZlcnRpY2VzJyk7CiAgICByZWNvbXB1dGUoKTsKICB9CiAgLy8gQ29udmVydCByYXcgZmlsZSDihpIgbGlzdCBvZiBwb2x5Z29ucyDihpIgaW5zdGFsbCArIGFwcGx5IGZpcnN0IG9uZS4KICBmdW5jdGlvbiBoYW5kbGVQYXJzZWRQb2x5Z29ucyhwb2x5cywgZmlsZW5hbWUpewogICAgaWYoIXBvbHlzID8gdHJ1ZSA6IHBvbHlzLmxlbmd0aCA9PT0gMCl7CiAgICAgIHNob3dVcGxvYWRTdGF0dXMoJ2Vycm9yJywgJ05vIHBvbHlnb25zIGZvdW5kIGluICcgKyBmaWxlbmFtZSk7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGltcG9ydGVkRmllbGRzID0gcG9seXM7CiAgICBpbXBvcnRlZElkeCA9IDA7CiAgICBzaG93VXBsb2FkU3RhdHVzKCdzdWNjZXNzJywgZmlsZW5hbWUgKyAnIMK3ICcgKyBwb2x5cy5sZW5ndGggKyAnIGJvdW5kYXJ5JyArIChwb2x5cy5sZW5ndGggPiAxID8gJ2llcycgOiAnJykpOwogICAgYXBwbHlJbXBvcnRlZEZpZWxkKDApOwogIH0KICAvLyBEZXRlY3QgZm9ybWF0IGJ5IGV4dGVuc2lvbiArIGNvbnRlbnQsIGRpc3BhdGNoIHRvIHBhcnNlci4gQXN5bmMgYmVjYXVzZQogIC8vIC56aXAgbmVlZHMgc2hwanMgd2hpY2ggbG9hZHMgbGF6aWx5IGZyb20gQ0ROLgogIGZ1bmN0aW9uIGltcG9ydEZpbGUoZmlsZSl7CiAgICB2YXIgbmFtZSA9IChmaWxlLm5hbWUgfHwgJycpLnRvTG93ZXJDYXNlKCk7CiAgICBzaG93VXBsb2FkU3RhdHVzKCdkZWZhdWx0JywgJ1JlYWRpbmcgJyArIGZpbGUubmFtZSArICfigKYnKTsKICAgIGlmKG5hbWUuaW5kZXhPZignLnppcCcpID49IDAgPyB0cnVlIDogbmFtZS5pbmRleE9mKCcuc2hwJykgPj0gMCl7CiAgICAgIC8vIFppcHBlZCBzaGFwZWZpbGUgb3IgYmFyZSAuc2hwIOKAlCBuZWVkcyBzaHBqcwogICAgICB2YXIgcmVhZGVyID0gbmV3IEZpbGVSZWFkZXIoKTsKICAgICAgcmVhZGVyLm9ubG9hZCA9IGZ1bmN0aW9uKCl7CiAgICAgICAgbG9hZFNocGpzKCkudGhlbihmdW5jdGlvbigpewogICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgdmFyIHAgPSB3aW5kb3cuc2hwKHJlYWRlci5yZXN1bHQpOwogICAgICAgICAgICAvLyBzaHAoKSByZXR1cm5zIGVpdGhlciBhIHNpbmdsZSBGZWF0dXJlQ29sbGVjdGlvbiBvciBhbiBhcnJheSAoZm9yIG11bHRpLXNocCB6aXBzKQogICAgICAgICAgICAocCA\/IChwLnRoZW4gPyBwIDogUHJvbWlzZS5yZXNvbHZlKHApKSA6IFByb21pc2UucmVzb2x2ZShwKSkudGhlbihmdW5jdGlvbihyZXMpewogICAgICAgICAgICAgIHZhciBjb2xsZWN0aW9ucyA9IEFycmF5LmlzQXJyYXkocmVzKSA\/IHJlcyA6IFtyZXNdOwogICAgICAgICAgICAgIHZhciBhbGwgPSBbXTsKICAgICAgICAgICAgICBmb3IodmFyIGM9MDsgYzxjb2xsZWN0aW9ucy5sZW5ndGg7IGMrKykgYWxsID0gYWxsLmNvbmNhdChleHRyYWN0QWxsUG9seWdvbnNHZW9KU09OKGNvbGxlY3Rpb25zW2NdKSk7CiAgICAgICAgICAgICAgaGFuZGxlUGFyc2VkUG9seWdvbnMoYWxsLCBmaWxlLm5hbWUpOwogICAgICAgICAgICB9KS5jYXRjaChmdW5jdGlvbihlcnIpewogICAgICAgICAgICAgIHNob3dVcGxvYWRTdGF0dXMoJ2Vycm9yJywgJ1NoYXBlZmlsZSBwYXJzZSBmYWlsZWQ6ICcgKyAoZXJyLm1lc3NhZ2UgfHwgZXJyKSk7CiAgICAgICAgICAgIH0pOwogICAgICAgICAgfSBjYXRjaChlcnIpewogICAgICAgICAgICBzaG93VXBsb2FkU3RhdHVzKCdlcnJvcicsICdTaGFwZWZpbGUgcGFyc2UgZmFpbGVkOiAnICsgKGVyci5tZXNzYWdlIHx8IGVycikpOwogICAgICAgICAgfQogICAgICAgIH0pLmNhdGNoKGZ1bmN0aW9uKGVycil7CiAgICAgICAgICBzaG93VXBsb2FkU3RhdHVzKCdlcnJvcicsIGVyci5tZXNzYWdlIHx8ICdDb3VsZCBub3QgbG9hZCBzaGFwZWZpbGUgcGFyc2VyJyk7CiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIHJlYWRlci5vbmVycm9yID0gZnVuY3Rpb24oKXsgc2hvd1VwbG9hZFN0YXR1cygnZXJyb3InLCAnQ291bGQgbm90IHJlYWQgZmlsZScpOyB9OwogICAgICByZWFkZXIucmVhZEFzQXJyYXlCdWZmZXIoZmlsZSk7CiAgICB9IGVsc2UgewogICAgICAvLyBUZXh0LWJhc2VkIOKAlCBHZW9KU09OIG9yIEtNTAogICAgICB2YXIgcmVhZGVyMiA9IG5ldyBGaWxlUmVhZGVyKCk7CiAgICAgIHJlYWRlcjIub25sb2FkID0gZnVuY3Rpb24oKXsKICAgICAgICB2YXIgdGV4dCA9IHJlYWRlcjIucmVzdWx0OwogICAgICAgIHZhciBwb2x5cyA9IFtdOwogICAgICAgIGlmKG5hbWUuaW5kZXhPZignLmttbCcpID49IDApewogICAgICAgICAgcG9seXMgPSBleHRyYWN0QWxsUG9seWdvbnNLTUwodGV4dCk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIC8vIEdlb0pTT04gZmlyc3Q7IGlmIGl0IGZhaWxzLCB0cnkgS01MIGluIGNhc2UgZXh0ZW5zaW9uIHdhcyB3cm9uZwogICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgdmFyIG9iaiA9IEpTT04ucGFyc2UodGV4dCk7CiAgICAgICAgICAgIHBvbHlzID0gZXh0cmFjdEFsbFBvbHlnb25zR2VvSlNPTihvYmopOwogICAgICAgICAgfSBjYXRjaChfKXsgcG9seXMgPSBleHRyYWN0QWxsUG9seWdvbnNLTUwodGV4dCk7IH0KICAgICAgICB9CiAgICAgICAgaGFuZGxlUGFyc2VkUG9seWdvbnMocG9seXMsIGZpbGUubmFtZSk7CiAgICAgIH07CiAgICAgIHJlYWRlcjIub25lcnJvciA9IGZ1bmN0aW9uKCl7IHNob3dVcGxvYWRTdGF0dXMoJ2Vycm9yJywgJ0NvdWxkIG5vdCByZWFkIGZpbGUnKTsgfTsKICAgICAgcmVhZGVyMi5yZWFkQXNUZXh0KGZpbGUpOwogICAgfQogIH0KICB2YXIgZmlsZUlucHV0RWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXVwbG9hZCcpOwogIGlmKGZpbGVJbnB1dEVsKXsKICAgIGZpbGVJbnB1dEVsLmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIGZ1bmN0aW9uKCl7CiAgICAgIHZhciBmaWxlID0gdGhpcy5maWxlcyA\/IHRoaXMuZmlsZXNbMF0gOiBudWxsOwogICAgICBpZihmaWxlKSBpbXBvcnRGaWxlKGZpbGUpOwogICAgfSk7CiAgfQogIC8vIEl0ZXJhdG9yIGJ1dHRvbnMg4oCUIHN0ZXAgdGhyb3VnaCBpbXBvcnRlZEZpZWxkcwogIHZhciBpbXBQcmV2RWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLWltcC1wcmV2Jyk7CiAgdmFyIGltcE5leHRFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtaW1wLW5leHQnKTsKICBpZihpbXBQcmV2RWwpIGltcFByZXZFbC5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uKCl7IGFwcGx5SW1wb3J0ZWRGaWVsZChpbXBvcnRlZElkeCAtIDEpOyB9KTsKICBpZihpbXBOZXh0RWwpIGltcE5leHRFbC5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uKCl7IGFwcGx5SW1wb3J0ZWRGaWVsZChpbXBvcnRlZElkeCArIDEpOyB9KTsKCiAgLy8gRmllbGQgcGlja2VyIOKAlCBzd2FwIEJPVU5EQVJZIGluIHBsYWNlLCBhdXRvLXBpY2sgdGhlIHJlY29tbWVuZGVkIGFwcHJvYWNoLAogIC8vIHRoZW4gcmUtZml0IC8gcmUtcmVuZGVyLiBSZXNldHMgdGhlIEFCLWxpbmUgb3ZlcnJpZGUgc28gZWFjaCBuZXcgZmllbGQKICAvLyBzdGFydHMgZnJvbSBpdHMgUENBLWRlcml2ZWQgbmF0dXJhbCBheGlzLgogIHZhciBmbGRCdG5zID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnI2dwbC1maWVsZC1waWNrZXIgLmdwbC1mbGQnKTsKICBmb3IodmFyIGZiPTA7IGZiPGZsZEJ0bnMubGVuZ3RoOyBmYisrKXsKICAgIGZsZEJ0bnNbZmJdLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZnVuY3Rpb24oKXsKICAgICAgdmFyIGtleSA9IHRoaXMuZ2V0QXR0cmlidXRlKCdkYXRhLWZpZWxkJyk7CiAgICAgIGlmKCFrZXkgPyB0cnVlIDogIUZJRUxEU1trZXldKSByZXR1cm47CiAgICAgIGN1cnJlbnRGaWVsZCA9IGtleTsKICAgICAgQk9VTkRBUlkgPSBGSUVMRFNba2V5XTsKICAgICAgdXNlckF4aXNEZWcgPSBudWxsOyAgLy8gYmFjayB0byBBdXRvIG9uIGV2ZXJ5IGZpZWxkIGNoYW5nZQogICAgICB2YXIgYXV0b0J0biA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtYWItYXV0bycpOwogICAgICBpZihhdXRvQnRuKSBhdXRvQnRuLmNsYXNzTGlzdC5hZGQoJ2lzLWF1dG8nKTsKICAgICAgZm9yKHZhciBmaT0wOyBmaTxmbGRCdG5zLmxlbmd0aDsgZmkrKykgZmxkQnRuc1tmaV0uY2xhc3NMaXN0LnJlbW92ZSgnaXMtb24nKTsKICAgICAgdGhpcy5jbGFzc0xpc3QuYWRkKCdpcy1vbicpOwogICAgICAvLyBSZXNldCB0aGUgdXBsb2FkIGNhcmQgc3RhdHVzIHNvIGl0IGRvZXNuJ3Qga2VlcCB0aGUgc3VjY2Vzcy1zdGF0ZSBiYWRnZQogICAgICBzaG93VXBsb2FkU3RhdHVzKCdkZWZhdWx0JywgJ0dlb0pTT04gLyBLTUwgLyBTaGFwZWZpbGUgemlwJyk7CiAgICAgIGlmKGZpbGVJbnB1dEVsKSBmaWxlSW5wdXRFbC52YWx1ZSA9ICcnOwogICAgICB2YXIgbmF2MiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtaW1wb3J0LW5hdicpOwogICAgICBpZihuYXYyKSBuYXYyLmhpZGRlbiA9IHRydWU7CiAgICAgIGltcG9ydGVkRmllbGRzID0gW107CiAgICAgIGltcG9ydGVkSWR4ID0gMDsKICAgICAgLy8gUHJlLXBpY2sgd2l0aCB0aGUgc2hhcGUtYmFzZWQgaGV1cmlzdGljIGZvciBpbnN0YW50IGZlZWRiYWNrOyB0aGUKICAgICAgLy8gZmlyc3QgcmVjb21wdXRlKCkgYmVsb3cgd2lsbCB0aGVuIHJlLWV2YWx1YXRlIHdpdGggcmVhbCBtZXRyaWNzCiAgICAgIC8vIChjb3ZlcmFnZSArIHR1cm5zICsgZnVlbCkgYW5kIG1heSBmbGlwIHRvIGEgYmV0dGVyIGFwcHJvYWNoLgogICAgICB2YXIgcGljayA9IHJlY29tbWVuZEFwcHJvYWNoKEJPVU5EQVJZKS5waWNrOwogICAgICBjdXJyZW50ID0gcGljazsKICAgICAgdmFyIGFwUmFkaW9zID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnI2dwbC1hcHByb2FjaCBpbnB1dFt0eXBlPXJhZGlvXScpOwogICAgICB2YXIgYXBMYWJlbHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcjZ3BsLWFwcHJvYWNoIGxhYmVsJyk7CiAgICAgIGZvcih2YXIgYXI9MDsgYXI8YXBSYWRpb3MubGVuZ3RoOyBhcisrKXsKICAgICAgICB2YXIgbWF0Y2ggPSBhcFJhZGlvc1thcl0udmFsdWUgPT09IHBpY2s7CiAgICAgICAgYXBSYWRpb3NbYXJdLmNoZWNrZWQgPSBtYXRjaDsKICAgICAgICBpZihhcExhYmVsc1thcl0pIGFwTGFiZWxzW2FyXS5jbGFzc0xpc3QudG9nZ2xlKCdpcy1vbicsIG1hdGNoKTsKICAgICAgfQogICAgICByZWNvbXB1dGUoKTsKICAgICAgLy8gTm93IGFwcGx5IHRoZSBtZXRyaWMtZHJpdmVuIHJlY29tbWVuZGF0aW9uIGlmIGl0IGRpZmZlcnMKICAgICAgdmFyIGFwTWV0cmljc0ZvclJlY28gPSB7fTsKICAgICAgdmFyIGF4aXNSID0gdXNlckF4aXNEZWcgIT09IG51bGwgPyB7IHV4OiBNYXRoLmNvcyh1c2VyQXhpc0RlZyAqIE1hdGguUEkgLyAxODApLCB1eTogTWF0aC5zaW4odXNlckF4aXNEZWcgKiBNYXRoLlBJIC8gMTgwKSB9IDogZmllbGRBeGlzKEJPVU5EQVJZKTsKICAgICAgdmFyIGlucFIgPSBnZXRJbnB1dHMoKTsKICAgICAgWydhYi1zdHJhaWdodCcsJ2FiLWN1cnZlJywnYm91bmRhcnknLCdhZGFwdGl2ZSddLmZvckVhY2goZnVuY3Rpb24oYXBYKXsKICAgICAgICB2YXIgbGF5WCA9IGdlbmVyYXRlTGluZXMoYXBYLCBpbnBSLndNLCBCT1VOREFSWSwgYXhpc1IsIGlucFIuaGVhZGxhbmRNLCBpbnBSLnR1cm5TdHlsZSwgaW5wUi50dXJuUiwgaW5wUi50dXJuQnVmKTsKICAgICAgICBhcE1ldHJpY3NGb3JSZWNvW2FwWF0gPSBjb21wdXRlTWV0cmljcyhsYXlYLCBpbnBSLndNLCBpbnBSLmRpZXNlbCwgaW5wUi5jb25zKTsKICAgICAgfSk7CiAgICAgIHZhciBtZXRyaWNQaWNrID0gcmVjb21tZW5kQnlNZXRyaWNzKGFwTWV0cmljc0ZvclJlY28pLnBpY2s7CiAgICAgIGlmKG1ldHJpY1BpY2sgIT09IGN1cnJlbnQpewogICAgICAgIGN1cnJlbnQgPSBtZXRyaWNQaWNrOwogICAgICAgIGZvcih2YXIgYXIyPTA7IGFyMjxhcFJhZGlvcy5sZW5ndGg7IGFyMisrKXsKICAgICAgICAgIHZhciBtYXRjaDIgPSBhcFJhZGlvc1thcjJdLnZhbHVlID09PSBtZXRyaWNQaWNrOwogICAgICAgICAgYXBSYWRpb3NbYXIyXS5jaGVja2VkID0gbWF0Y2gyOwogICAgICAgICAgaWYoYXBMYWJlbHNbYXIyXSkgYXBMYWJlbHNbYXIyXS5jbGFzc0xpc3QudG9nZ2xlKCdpcy1vbicsIG1hdGNoMik7CiAgICAgICAgfQogICAgICAgIHJlY29tcHV0ZSgpOwogICAgICB9CiAgICB9KTsKICB9CiAgLy8gQUItZGlyZWN0aW9uIGNvbnRyb2xzCiAgdmFyIGFiU2xpZGVyRWwyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1hYi1kZWcnKTsKICB2YXIgYWJBdXRvQnRuRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLWFiLWF1dG8nKTsKICBpZihhYlNsaWRlckVsMil7CiAgICBhYlNsaWRlckVsMi5hZGRFdmVudExpc3RlbmVyKCdpbnB1dCcsIGZ1bmN0aW9uKCl7CiAgICAgIHZhciBkZWcgPSBwYXJzZUZsb2F0KHRoaXMudmFsdWUpOwogICAgICBpZihpc05hTihkZWcpKSBkZWcgPSAwOwogICAgICB1c2VyQXhpc0RlZyA9IGRlZzsKICAgICAgaWYoYWJBdXRvQnRuRWwpIGFiQXV0b0J0bkVsLmNsYXNzTGlzdC5yZW1vdmUoJ2lzLWF1dG8nKTsKICAgICAgcmVjb21wdXRlKCk7CiAgICB9KTsKICB9CiAgaWYoYWJBdXRvQnRuRWwpewogICAgYWJBdXRvQnRuRWwuY2xhc3NMaXN0LmFkZCgnaXMtYXV0bycpOwogICAgYWJBdXRvQnRuRWwuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbigpewogICAgICB1c2VyQXhpc0RlZyA9IG51bGw7CiAgICAgIHRoaXMuY2xhc3NMaXN0LmFkZCgnaXMtYXV0bycpOwogICAgICByZWNvbXB1dGUoKTsKICAgIH0pOwogIH0KCiAgLy8gUGxheWJhY2sgY29udHJvbHMKICB2YXIgbGFzdExheW91dCA9IG51bGw7CiAgdmFyIHBiQnRuRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXBiLXBsYXknKTsKICB2YXIgcGJUcmFja0VsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1wYi10cmFjaycpOwogIHZhciBwYlNwZEVscyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy5ncGwtcGItc3BkJyk7CiAgLy8gQ2FjaGUgdGhlIGN1cnJlbnQgbGF5b3V0IHNvIHRoZSBSQUYgbG9vcCBjYW4gcmVkcmF3IHdpdGhvdXQgcmVjb21wdXRpbmcKICAvLyB0aGUgd2hvbGUgZ2VvbWV0cnkgcGlwZWxpbmUgb24gZXZlcnkgZnJhbWUuCiAgdmFyIG9yaWdEcmF3ID0gZHJhdzsKICBkcmF3ID0gZnVuY3Rpb24obGF5b3V0KXsgbGFzdExheW91dCA9IGxheW91dDsgb3JpZ0RyYXcobGF5b3V0KTsgfTsKICBmdW5jdGlvbiB0aWNrKG5vdyl7CiAgICBpZighcGxheWJhY2suaXNQbGF5aW5nKXsgcGxheWJhY2subGFzdFRpY2sgPSBub3c7IHJldHVybjsgfQogICAgdmFyIGR0ID0gcGxheWJhY2subGFzdFRpY2sgPiAwID8gKG5vdyAtIHBsYXliYWNrLmxhc3RUaWNrKSAvIDEwMDAgOiAwOwogICAgcGxheWJhY2subGFzdFRpY2sgPSBub3c7CiAgICAvLyAxIGttIGRyaXZlIHBlciBzZWNvbmQgYXQgMcOXICh2aXNpYmxlIGJ1dCBub3QgYmxpbmtpbmcgZmFzdCkKICAgIC8vIDcwMCBtL3MgYXQgMcOXIOKAlCAzMCAlIHNsb3dlciB0aGFuIHRoZSBwcmV2aW91cyAxMDAwIG0vcyBzbyBpbmRpdmlkdWFsCiAgICAvLyBwYXNzZXMgYXJlIGVhc2llciB0byBmb2xsb3cgdmlzdWFsbHkgKGEgNjAwIG0gcGFzcyB0YWtlcyB+MC44NSBzIHZzIDAuNikuCiAgICB2YXIgbWV0cmVzUGVyU2VjID0gNzAwICogcGxheWJhY2suc3BlZWQ7CiAgICB2YXIgZFQgPSBwbGF5YmFjay50b3RhbExlbiA+IDAgPyAoZHQgKiBtZXRyZXNQZXJTZWMgLyBwbGF5YmFjay50b3RhbExlbikgOiAwOwogICAgcGxheWJhY2sudCArPSBkVDsKICAgIGlmKHBsYXliYWNrLnQgPj0gMSl7CiAgICAgIHBsYXliYWNrLnQgPSAxOwogICAgICBwbGF5YmFjay5pc1BsYXlpbmcgPSBmYWxzZTsKICAgICAgaWYocGJCdG5FbCl7CiAgICAgICAgcGJCdG5FbC5jbGFzc0xpc3QucmVtb3ZlKCdpcy1wbGF5aW5nJyk7CiAgICAgICAgcGJCdG5FbC50ZXh0Q29udGVudCA9ICfilrYnOwogICAgICB9CiAgICB9CiAgICB1cGRhdGVQbGF5YmFja1VJKCk7CiAgICBpZihsYXN0TGF5b3V0KSBvcmlnRHJhdyhsYXN0TGF5b3V0KTsKICAgIGlmKHBsYXliYWNrLmlzUGxheWluZykgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKHRpY2spOwogIH0KICBpZihwYkJ0bkVsKXsKICAgIHBiQnRuRWwuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbigpewogICAgICBpZihwbGF5YmFjay50b3RhbExlbiA8IDEpIHJldHVybjsKICAgICAgaWYocGxheWJhY2sudCA+PSAxKSBwbGF5YmFjay50ID0gMDsKICAgICAgcGxheWJhY2suaXNQbGF5aW5nID0gIXBsYXliYWNrLmlzUGxheWluZzsKICAgICAgcGJCdG5FbC5jbGFzc0xpc3QudG9nZ2xlKCdpcy1wbGF5aW5nJywgcGxheWJhY2suaXNQbGF5aW5nKTsKICAgICAgcGJCdG5FbC50ZXh0Q29udGVudCA9IHBsYXliYWNrLmlzUGxheWluZyA\/ICcnIDogJ+KWtic7CiAgICAgIGlmKHBsYXliYWNrLmlzUGxheWluZyl7CiAgICAgICAgcGxheWJhY2subGFzdFRpY2sgPSAwOwogICAgICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZSh0aWNrKTsKICAgICAgfQogICAgfSk7CiAgfQogIGlmKHBiVHJhY2tFbCl7CiAgICBwYlRyYWNrRWwuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbihldil7CiAgICAgIHZhciByZWN0ID0gcGJUcmFja0VsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOwogICAgICB2YXIgZiA9IChldi5jbGllbnRYIC0gcmVjdC5sZWZ0KSAvIHJlY3Qud2lkdGg7CiAgICAgIGlmKGYgPCAwKSBmID0gMDsgaWYoZiA+IDEpIGYgPSAxOwogICAgICBwbGF5YmFjay50ID0gZjsKICAgICAgdXBkYXRlUGxheWJhY2tVSSgpOwogICAgICBpZihsYXN0TGF5b3V0KSBvcmlnRHJhdyhsYXN0TGF5b3V0KTsKICAgIH0pOwogIH0KICBmb3IodmFyIHNiPTA7IHNiPHBiU3BkRWxzLmxlbmd0aDsgc2IrKyl7CiAgICBwYlNwZEVsc1tzYl0uYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbigpewogICAgICB2YXIgcyA9IHBhcnNlRmxvYXQodGhpcy5nZXRBdHRyaWJ1dGUoJ2RhdGEtc3BkJykpIHx8IDE7CiAgICAgIHBsYXliYWNrLnNwZWVkID0gczsKICAgICAgZm9yKHZhciBzYjI9MDsgc2IyPHBiU3BkRWxzLmxlbmd0aDsgc2IyKyspIHBiU3BkRWxzW3NiMl0uY2xhc3NMaXN0LnJlbW92ZSgnb24nKTsKICAgICAgdGhpcy5jbGFzc0xpc3QuYWRkKCdvbicpOwogICAgfSk7CiAgfQoKICAvLyBVbml0IHRvZ2dsZSAoa20gLyBtaSkg4oCUIHB1cmVseSBhIGxhYmVsIHN3aXRjaDsgbnVtYmVycyBzdGF5IGluIG1ldHJlcyBpbnRlcm5hbGx5CiAgdmFyIHVuaXRUYWJzID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLmdwbC11bml0LXRhYicpOwogIGZvcih2YXIgdXQ9MDsgdXQ8dW5pdFRhYnMubGVuZ3RoOyB1dCsrKXsKICAgIHVuaXRUYWJzW3V0XS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uKCl7CiAgICAgIHVuaXQgPSB0aGlzLmdldEF0dHJpYnV0ZSgnZGF0YS11bml0JykgfHwgJ2ttJzsKICAgICAgZm9yKHZhciB1dDI9MDsgdXQyPHVuaXRUYWJzLmxlbmd0aDsgdXQyKyspIHVuaXRUYWJzW3V0Ml0uY2xhc3NMaXN0LnJlbW92ZSgnaXMtb24nKTsKICAgICAgdGhpcy5jbGFzc0xpc3QuYWRkKCdpcy1vbicpOwogICAgICByZWNvbXB1dGUoKTsKICAgIH0pOwogIH0KICAvLyBab29tICsgZml0IGJ1dHRvbnMKICAvLyBab29tLWFyb3VuZC1jdXJzb3IgaGVscGVyLiBBZGp1c3RzIHBhbiBzbyB0aGUgd29ybGQgcG9pbnQgdW5kZXIKICAvLyAobXgsIG15KSBzdGF5cyBhdCB0aGUgc2FtZSBzY3JlZW4gcG9zaXRpb24gYWZ0ZXIgdGhlIHpvb20gY2hhbmdlLgogIGZ1bmN0aW9uIHpvb21Bcm91bmRDdXJzb3IobXgsIG15LCBmYWN0b3IpewogICAgdmFyIHByb2pCZWZvcmUgPSBnZXRTY2FsZSgpOwogICAgdmFyIHd4ID0gd29ybGRYKHByb2pCZWZvcmUsIG14KTsKICAgIHZhciB3eSA9IHdvcmxkWShwcm9qQmVmb3JlLCBteSk7CiAgICB2YXIgbmV3Wm9vbSA9IHZpZXcuem9vbSAqIGZhY3RvcjsKICAgIGlmKG5ld1pvb20gPCAwLjIpIG5ld1pvb20gPSAwLjI7CiAgICBpZihuZXdab29tID4gNTApIG5ld1pvb20gPSA1MDsKICAgIHZpZXcuem9vbSA9IG5ld1pvb207CiAgICB2YXIgcHJvakFmdGVyID0gZ2V0U2NhbGUoKTsKICAgIHZpZXcucGFuWCArPSBteCAtIHB4KHByb2pBZnRlciwgd3gpOwogICAgdmlldy5wYW5ZICs9IG15IC0gcHkocHJvakFmdGVyLCB3eSk7CiAgICBpZihsYXN0TGF5b3V0KSBvcmlnRHJhdyhsYXN0TGF5b3V0KTsKICB9CiAgZnVuY3Rpb24gem9vbUNlbnRlcihmYWN0b3IpewogICAgdmFyIHJlY3QgPSBjYW52YXMuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7CiAgICB6b29tQXJvdW5kQ3Vyc29yKHJlY3Qud2lkdGggKiAwLjUsIHJlY3QuaGVpZ2h0ICogMC41LCBmYWN0b3IpOwogIH0KICB2YXIgekluRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXRvb2wtem9vbS1pbicpOwogIHZhciB6T3V0RWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZ3BsLXRvb2wtem9vbS1vdXQnKTsKICB2YXIgekZpdEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC10b29sLWZpdCcpOwogIGlmKHpJbkVsKSB6SW5FbC5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uKCl7IHpvb21DZW50ZXIoMS4zKTsgfSk7CiAgaWYoek91dEVsKSB6T3V0RWwuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbigpeyB6b29tQ2VudGVyKDEvMS4zKTsgfSk7CiAgaWYoekZpdEVsKSB6Rml0RWwuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbigpewogICAgdmlldy56b29tID0gMTsgdmlldy5wYW5YID0gMDsgdmlldy5wYW5ZID0gMDsKICAgIGlmKGxhc3RMYXlvdXQpIG9yaWdEcmF3KGxhc3RMYXlvdXQpOwogIH0pOwogIC8vIE1vdXNlIHdoZWVsIOKAlCBzbW9vdGggZXhwb25lbnRpYWwgem9vbSAobWF0Y2hlcyBmaWVsZC1kYXRhLWV4cGxvcmVyIGZlZWwpCiAgY2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoJ3doZWVsJywgZnVuY3Rpb24oZXYpewogICAgZXYucHJldmVudERlZmF1bHQoKTsKICAgIHZhciByZWN0ID0gY2FudmFzLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOwogICAgdmFyIG14ID0gZXYuY2xpZW50WCAtIHJlY3QubGVmdDsKICAgIHZhciBteSA9IGV2LmNsaWVudFkgLSByZWN0LnRvcDsKICAgIHZhciBmYWN0b3IgPSBNYXRoLmV4cCgtZXYuZGVsdGFZICogMC4wMDE1KTsKICAgIHpvb21Bcm91bmRDdXJzb3IobXgsIG15LCBmYWN0b3IpOwogIH0sIHsgcGFzc2l2ZTogZmFsc2UgfSk7CiAgLy8gRHJhZy10by1wYW4gKHdoZW4gcnVsZXIgaXMgbm90IGFjdGl2ZSkKICB2YXIgZHJhZ1N0YXRlID0gbnVsbDsKICBjYW52YXMuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgZnVuY3Rpb24oZXYpewogICAgdmFyIHJlY3QgPSBjYW52YXMuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7CiAgICB2YXIgbXggPSBldi5jbGllbnRYIC0gcmVjdC5sZWZ0OwogICAgdmFyIG15ID0gZXYuY2xpZW50WSAtIHJlY3QudG9wOwogICAgaWYocnVsZXIuYWN0aXZlKXsKICAgICAgdmFyIHByb2ogPSBnZXRTY2FsZSgpOwogICAgICB2YXIgd3ggPSB3b3JsZFgocHJvaiwgbXgpOwogICAgICB2YXIgd3kgPSB3b3JsZFkocHJvaiwgbXkpOwogICAgICBpZighcnVsZXIucDEpewogICAgICAgIHJ1bGVyLnAxID0geyB4OiB3eCwgeTogd3kgfTsgcnVsZXIucDIgPSBudWxsOwogICAgICB9IGVsc2UgaWYoIXJ1bGVyLnAyKXsKICAgICAgICBydWxlci5wMiA9IHsgeDogd3gsIHk6IHd5IH07CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcnVsZXIucDEgPSB7IHg6IHd4LCB5OiB3eSB9OyBydWxlci5wMiA9IG51bGw7CiAgICAgIH0KICAgICAgaWYobGFzdExheW91dCkgb3JpZ0RyYXcobGFzdExheW91dCk7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGRyYWdTdGF0ZSA9IHsgc3RhcnRYOiBteCwgc3RhcnRZOiBteSwgc3RhcnRQYW5YOiB2aWV3LnBhblgsIHN0YXJ0UGFuWTogdmlldy5wYW5ZIH07CiAgICBjYW52YXMuc3R5bGUuY3Vyc29yID0gJ2dyYWJiaW5nJzsKICB9KTsKICBjYW52YXMuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgZnVuY3Rpb24oZXYpewogICAgaWYoIWRyYWdTdGF0ZSkgcmV0dXJuOwogICAgdmFyIHJlY3QgPSBjYW52YXMuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7CiAgICB2YXIgbXggPSBldi5jbGllbnRYIC0gcmVjdC5sZWZ0OwogICAgdmFyIG15ID0gZXYuY2xpZW50WSAtIHJlY3QudG9wOwogICAgdmlldy5wYW5YID0gZHJhZ1N0YXRlLnN0YXJ0UGFuWCArIChteCAtIGRyYWdTdGF0ZS5zdGFydFgpOwogICAgdmlldy5wYW5ZID0gZHJhZ1N0YXRlLnN0YXJ0UGFuWSArIChteSAtIGRyYWdTdGF0ZS5zdGFydFkpOwogICAgaWYobGFzdExheW91dCkgb3JpZ0RyYXcobGFzdExheW91dCk7CiAgfSk7CiAgZnVuY3Rpb24gZW5kRHJhZygpewogICAgZHJhZ1N0YXRlID0gbnVsbDsKICAgIGNhbnZhcy5zdHlsZS5jdXJzb3IgPSBydWxlci5hY3RpdmUgPyAnY3Jvc3NoYWlyJyA6ICdkZWZhdWx0JzsKICB9CiAgY2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNldXAnLCBlbmREcmFnKTsKICBjYW52YXMuYWRkRXZlbnRMaXN0ZW5lcignbW91c2VsZWF2ZScsIGVuZERyYWcpOwogIC8vIFRvdWNoIOKAlCBzaW5nbGUtZmluZ2VyIHBhbiwgdHdvLWZpbmdlciBwaW5jaC16b29tIChtaXJyb3JzIGZpZWxkLWV4cGxvcmVyKQogIHZhciB0b3VjaFN0YXRlID0gbnVsbDsKICBmdW5jdGlvbiBfdERpc3QoYSwgYil7IHZhciBkeCA9IGEuY2xpZW50WCAtIGIuY2xpZW50WCwgZHkgPSBhLmNsaWVudFkgLSBiLmNsaWVudFk7IHJldHVybiBNYXRoLnNxcnQoZHgqZHggKyBkeSpkeSk7IH0KICBmdW5jdGlvbiBfdENlbnRlcihhLCBiKXsgcmV0dXJuIFsoYS5jbGllbnRYICsgYi5jbGllbnRYKSAqIDAuNSwgKGEuY2xpZW50WSArIGIuY2xpZW50WSkgKiAwLjVdOyB9CiAgY2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNoc3RhcnQnLCBmdW5jdGlvbihldil7CiAgICBpZihldi50b3VjaGVzLmxlbmd0aCA9PT0gMSl7CiAgICAgIGV2LnByZXZlbnREZWZhdWx0KCk7CiAgICAgIHZhciByZWN0ID0gY2FudmFzLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOwogICAgICB0b3VjaFN0YXRlID0geyBtb2RlOiAncGFuJywgeDogZXYudG91Y2hlc1swXS5jbGllbnRYLCB5OiBldi50b3VjaGVzWzBdLmNsaWVudFksIHN4OiBldi50b3VjaGVzWzBdLmNsaWVudFggLSByZWN0LmxlZnQsIHN5OiBldi50b3VjaGVzWzBdLmNsaWVudFkgLSByZWN0LnRvcCwgcGFuWDogdmlldy5wYW5YLCBwYW5ZOiB2aWV3LnBhblksIG1vdmVkOiBmYWxzZSB9OwogICAgfSBlbHNlIGlmKGV2LnRvdWNoZXMubGVuZ3RoID49IDIpewogICAgICBldi5wcmV2ZW50RGVmYXVsdCgpOwogICAgICB2YXIgYyA9IF90Q2VudGVyKGV2LnRvdWNoZXNbMF0sIGV2LnRvdWNoZXNbMV0pOwogICAgICB0b3VjaFN0YXRlID0geyBtb2RlOiAncGluY2gnLCBkaXN0OiBfdERpc3QoZXYudG91Y2hlc1swXSwgZXYudG91Y2hlc1sxXSksIGN4OiBjWzBdLCBjeTogY1sxXSB9OwogICAgfQogIH0sIHsgcGFzc2l2ZTogZmFsc2UgfSk7CiAgY2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNobW92ZScsIGZ1bmN0aW9uKGV2KXsKICAgIGlmKCF0b3VjaFN0YXRlKSByZXR1cm47CiAgICBldi5wcmV2ZW50RGVmYXVsdCgpOwogICAgaWYodG91Y2hTdGF0ZS5tb2RlID09PSAncGFuJyA\/IGV2LnRvdWNoZXMubGVuZ3RoID09PSAxIDogZmFsc2UpewogICAgICB2YXIgdCA9IGV2LnRvdWNoZXNbMF07CiAgICAgIHZhciBkeCA9IHQuY2xpZW50WCAtIHRvdWNoU3RhdGUueDsKICAgICAgdmFyIGR5ID0gdC5jbGllbnRZIC0gdG91Y2hTdGF0ZS55OwogICAgICB2aWV3LnBhblggPSB0b3VjaFN0YXRlLnBhblggKyBkeDsKICAgICAgdmlldy5wYW5ZID0gdG91Y2hTdGF0ZS5wYW5ZICsgZHk7CiAgICAgIGlmKE1hdGguYWJzKGR4KSA+IDQgPyB0cnVlIDogTWF0aC5hYnMoZHkpID4gNCkgdG91Y2hTdGF0ZS5tb3ZlZCA9IHRydWU7CiAgICAgIGlmKGxhc3RMYXlvdXQpIG9yaWdEcmF3KGxhc3RMYXlvdXQpOwogICAgfSBlbHNlIGlmKHRvdWNoU3RhdGUubW9kZSA9PT0gJ3BpbmNoJyA\/IGV2LnRvdWNoZXMubGVuZ3RoID49IDIgOiBmYWxzZSl7CiAgICAgIHZhciBuZXdEaXN0ID0gX3REaXN0KGV2LnRvdWNoZXNbMF0sIGV2LnRvdWNoZXNbMV0pOwogICAgICB2YXIgbmV3QyA9IF90Q2VudGVyKGV2LnRvdWNoZXNbMF0sIGV2LnRvdWNoZXNbMV0pOwogICAgICB2YXIgcmVjdFQgPSBjYW52YXMuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7CiAgICAgIHZhciBuY3ggPSBuZXdDWzBdIC0gcmVjdFQubGVmdCwgbmN5ID0gbmV3Q1sxXSAtIHJlY3RULnRvcDsKICAgICAgem9vbUFyb3VuZEN1cnNvcihuY3gsIG5jeSwgbmV3RGlzdCAvIHRvdWNoU3RhdGUuZGlzdCk7CiAgICAgIHRvdWNoU3RhdGUuZGlzdCA9IG5ld0Rpc3Q7IHRvdWNoU3RhdGUuY3ggPSBuZXdDWzBdOyB0b3VjaFN0YXRlLmN5ID0gbmV3Q1sxXTsKICAgIH0KICB9LCB7IHBhc3NpdmU6IGZhbHNlIH0pOwogIGNhbnZhcy5hZGRFdmVudExpc3RlbmVyKCd0b3VjaGVuZCcsIGZ1bmN0aW9uKGV2KXsKICAgIC8vIFJ1bGVyIHRhcCBzdXBwb3J0OiBpZiBydWxlciBtb2RlIGFuZCBubyBkcmFnIG9jY3VycmVkLCBkcm9wIGEgcG9pbnQgYXQgdGhlIHRvdWNoIHBvc2l0aW9uCiAgICBpZih0b3VjaFN0YXRlID8gKHRvdWNoU3RhdGUubW9kZSA9PT0gJ3BhbicgPyAoIXRvdWNoU3RhdGUubW92ZWQgPyBydWxlci5hY3RpdmUgOiBmYWxzZSkgOiBmYWxzZSkgOiBmYWxzZSl7CiAgICAgIHZhciBwcm9qID0gZ2V0U2NhbGUoKTsKICAgICAgdmFyIHd4ID0gd29ybGRYKHByb2osIHRvdWNoU3RhdGUuc3gpOwogICAgICB2YXIgd3kgPSB3b3JsZFkocHJvaiwgdG91Y2hTdGF0ZS5zeSk7CiAgICAgIGlmKCFydWxlci5wMSl7IHJ1bGVyLnAxID0geyB4OiB3eCwgeTogd3kgfTsgcnVsZXIucDIgPSBudWxsOyB9CiAgICAgIGVsc2UgaWYoIXJ1bGVyLnAyKXsgcnVsZXIucDIgPSB7IHg6IHd4LCB5OiB3eSB9OyB9CiAgICAgIGVsc2UgeyBydWxlci5wMSA9IHsgeDogd3gsIHk6IHd5IH07IHJ1bGVyLnAyID0gbnVsbDsgfQogICAgICBpZihsYXN0TGF5b3V0KSBvcmlnRHJhdyhsYXN0TGF5b3V0KTsKICAgIH0KICAgIGlmKGV2LnRvdWNoZXMubGVuZ3RoID09PSAwKSB0b3VjaFN0YXRlID0gbnVsbDsKICB9KTsKICAvLyBSdWxlciB0b2dnbGUKICB2YXIgcnVsZXJCdG5FbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtdG9vbC1ydWxlcicpOwogIHZhciBydWxlckhpbnRFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncGwtcnVsZXItaGludCcpOwogIGlmKHJ1bGVyQnRuRWwpewogICAgcnVsZXJCdG5FbC5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uKCl7CiAgICAgIHJ1bGVyLmFjdGl2ZSA9ICFydWxlci5hY3RpdmU7CiAgICAgIHRoaXMuY2xhc3NMaXN0LnRvZ2dsZSgnaXMtb24nLCBydWxlci5hY3RpdmUpOwogICAgICBpZihydWxlckhpbnRFbCkgcnVsZXJIaW50RWwuY2xhc3NMaXN0LnRvZ2dsZSgnaXMtb24nLCBydWxlci5hY3RpdmUpOwogICAgICBjYW52YXMuc3R5bGUuY3Vyc29yID0gcnVsZXIuYWN0aXZlID8gJ2Nyb3NzaGFpcicgOiAnZGVmYXVsdCc7CiAgICAgIGlmKCFydWxlci5hY3RpdmUpewogICAgICAgIHJ1bGVyLnAxID0gbnVsbDsgcnVsZXIucDIgPSBudWxsOwogICAgICAgIGlmKGxhc3RMYXlvdXQpIG9yaWdEcmF3KGxhc3RMYXlvdXQpOwogICAgICB9CiAgICB9KTsKICB9CgogIC8vIFJlc2l6YWJsZSBsZWZ0IHBhbmVsIOKAlCBkcmFnIHNwbGl0dGVyIHRvIHNldCAtLWdwbC1sZWZ0LXcgb24gdGhlIHdyYXAuCiAgLy8gQ2xhbXBlZCB0byBbMjAwLCAzODBdIHB4IHNvIHRoZSBwYW5lbCBuZXZlciBjb2xsYXBzZXMgb3IgZWF0cyB0aGUgY2FudmFzLgogIHZhciBzcGxpdHRlckVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwbC1zcGxpdHRlcicpOwogIGlmKHNwbGl0dGVyRWwpewogICAgdmFyIHNwU3RhdGUgPSBudWxsOwogICAgc3BsaXR0ZXJFbC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZWRvd24nLCBmdW5jdGlvbihldil7CiAgICAgIHZhciBjdXJyZW50ID0gcGFyc2VGbG9hdChnZXRDb21wdXRlZFN0eWxlKHJvb3QpLmdldFByb3BlcnR5VmFsdWUoJy0tZ3BsLWxlZnQtdycpKSB8fCAyNjA7CiAgICAgIHNwU3RhdGUgPSB7IHN0YXJ0WDogZXYuY2xpZW50WCwgc3RhcnRXOiBjdXJyZW50IH07CiAgICAgIHNwbGl0dGVyRWwuY2xhc3NMaXN0LmFkZCgnaXMtZHJhZycpOwogICAgICBldi5wcmV2ZW50RGVmYXVsdCgpOwogICAgfSk7CiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgZnVuY3Rpb24oZXYpewogICAgICBpZighc3BTdGF0ZSkgcmV0dXJuOwogICAgICB2YXIgdyA9IHNwU3RhdGUuc3RhcnRXICsgKGV2LmNsaWVudFggLSBzcFN0YXRlLnN0YXJ0WCk7CiAgICAgIGlmKHcgPCAyMDApIHcgPSAyMDA7CiAgICAgIGlmKHcgPiAzODApIHcgPSAzODA7CiAgICAgIHJvb3Quc3R5bGUuc2V0UHJvcGVydHkoJy0tZ3BsLWxlZnQtdycsIHcgKyAncHgnKTsKICAgICAgLy8gQ2FudmFzIHNpemUgY2hhbmdlZCDihpIgcmVmaXQgYW5kIHJlZHJhdwogICAgICByZXNpemUoKTsKICAgICAgaWYobGFzdExheW91dCkgb3JpZ0RyYXcobGFzdExheW91dCk7CiAgICB9KTsKICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgZnVuY3Rpb24oKXsKICAgICAgaWYoIXNwU3RhdGUpIHJldHVybjsKICAgICAgc3BTdGF0ZSA9IG51bGw7CiAgICAgIHNwbGl0dGVyRWwuY2xhc3NMaXN0LnJlbW92ZSgnaXMtZHJhZycpOwogICAgfSk7CiAgfQoKICAvLyBJbml0aWFsIHJlY29tbWVuZGF0aW9uIOKAlCBwcmUtc2VsZWN0IHRoZSBzaGFwZS1vcHRpbWFsIGFwcHJvYWNoIHNvIHRoZQogIC8vIHBhZ2UgbGFuZHMgb24gdGhlIGFncm9ub21pY2FsbHkgc2Vuc2libGUgZGVmYXVsdCwgbm90IGFyYml0cmFyeSBBQiBTdHJhaWdodC4KICAoZnVuY3Rpb24oKXsKICAgIHZhciBpbml0aWFsUGljayA9IHJlY29tbWVuZEFwcHJvYWNoKEJPVU5EQVJZKS5waWNrOwogICAgY3VycmVudCA9IGluaXRpYWxQaWNrOwogICAgdmFyIGFwUmFkaW9zMCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJyNncGwtYXBwcm9hY2ggaW5wdXRbdHlwZT1yYWRpb10nKTsKICAgIHZhciBhcExhYmVsczAgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcjZ3BsLWFwcHJvYWNoIGxhYmVsJyk7CiAgICBmb3IodmFyIGFyMD0wOyBhcjA8YXBSYWRpb3MwLmxlbmd0aDsgYXIwKyspewogICAgICB2YXIgbWF0Y2gwID0gYXBSYWRpb3MwW2FyMF0udmFsdWUgPT09IGluaXRpYWxQaWNrOwogICAgICBhcFJhZGlvczBbYXIwXS5jaGVja2VkID0gbWF0Y2gwOwogICAgICBpZihhcExhYmVsczBbYXIwXSkgYXBMYWJlbHMwW2FyMF0uY2xhc3NMaXN0LnRvZ2dsZSgnaXMtb24nLCBtYXRjaDApOwogICAgfQogIH0pKCk7CgogIHJlc2l6ZSgpOwogIHVwZGF0ZUhlYWRsYW5kTGFiZWwoKTsKICBhcHBseU1hY2hpbmVSYWRpdXMoKTsKICByZWNvbXB1dGUoKTsKICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigncmVzaXplJywgZnVuY3Rpb24oKXsgcmVzaXplKCk7IHJlY29tcHV0ZSgpOyB9KTsKfSkoKTsKPC9zY3JpcHQ+CjwvZGl2Pgp3B3B1Ymxpc2haAHcOZ3VpZGFuY2UtbGluZXN9iIa2yAF9AHcGY2xvc2VkdwZjbG9zZWR3AHcAdwB3AHcAdwB3AHcAeXcAdwB3AH51AHh2AxByZXN0cmljdGlvbl90eXBldwdleGNsdWRlEnNlbGVjdGVkX2xhbmd1YWdlc3UACnBhbmVsX29wZW54fQF4dgMQcmVzdHJpY3Rpb25fdHlwZXcHZXhjbHVkZRJzZWxlY3RlZF9sYW5ndWFnZXN1AApwYW5lbF9vcGVueHcJY29yZS9odG1sAobCj9AGBAIA1x6IBQMAAgDi+8F\/FgABAQAabRYAAQEBPQEDAgYBAAEAAQEBBgEBAQERJAjOFQLdfwmOAgm2AQiWcAfopQcTMw==\",\"updateId\":232278092}","content-type":"","footnotes":"","big_sky_generated":false},"class_list":["post-13171","page","type-page","status-publish","hentry"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Guidance Lines Simulator - GeoPard Agriculture<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/geopard.tech\/es\/lineas-de-orientacion\/\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Guidance Lines Simulator - GeoPard Agriculture\" \/>\n<meta property=\"og:description\" content=\"Guidance Lines Simulator \u00b7 Free \u00b7 No signup Plan your tractor path. Find the lowest-fuel, highest-coverage drive plan for your field. Compare AB Straight, AB...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/geopard.tech\/es\/lineas-de-orientacion\/\" \/>\n<meta property=\"og:site_name\" content=\"GeoPard - Precision agriculture Mapping software\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/geopardAgriculture\/\" \/>\n<meta property=\"article:modified_time\" content=\"2026-05-19T13:59:18+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/i0.wp.com\/geopard.tech\/wp-content\/uploads\/2026\/03\/GeoPard-Background-Precision-Ag-software-Do-more-with-your-data.png?fit=3116%2C1754&ssl=1\" \/>\n\t<meta property=\"og:image:width\" content=\"3116\" \/>\n\t<meta property=\"og:image:height\" content=\"1754\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:site\" content=\"@geopardagri\" \/>\n<meta name=\"twitter:label1\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data1\" content=\"4 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/geopard.tech\\\/guidance-lines\\\/\",\"url\":\"https:\\\/\\\/geopard.tech\\\/guidance-lines\\\/\",\"name\":\"Guidance Lines Simulator - GeoPard Agriculture\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/geopard.tech\\\/#website\"},\"datePublished\":\"2026-05-19T13:00:20+00:00\",\"dateModified\":\"2026-05-19T13:59:18+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/geopard.tech\\\/guidance-lines\\\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/geopard.tech\\\/guidance-lines\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/geopard.tech\\\/guidance-lines\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/geopard.tech\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Guidance Lines Simulator\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/geopard.tech\\\/#website\",\"url\":\"https:\\\/\\\/geopard.tech\\\/\",\"name\":\"GeoPard - Precision agriculture software\",\"description\":\"Precision agriculture Mapping software\",\"publisher\":{\"@id\":\"https:\\\/\\\/geopard.tech\\\/#organization\"},\"alternateName\":\"GeoPard\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/geopard.tech\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/geopard.tech\\\/#organization\",\"name\":\"GeoPard Agriculture\",\"alternateName\":\"GeoPard\",\"url\":\"https:\\\/\\\/geopard.tech\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/geopard.tech\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/geopard.tech\\\/wp-content\\\/uploads\\\/2022\\\/03\\\/favicon.png?fit=200%2C200&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/geopard.tech\\\/wp-content\\\/uploads\\\/2022\\\/03\\\/favicon.png?fit=200%2C200&ssl=1\",\"width\":200,\"height\":200,\"caption\":\"GeoPard Agriculture\"},\"image\":{\"@id\":\"https:\\\/\\\/geopard.tech\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/geopardAgriculture\\\/\",\"https:\\\/\\\/x.com\\\/geopardagri\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/geopard-agriculture\\\/\",\"https:\\\/\\\/www.instagram.com\\\/geopardagriculture\\\/\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Simulador de l\u00edneas de gu\u00eda - GeoPard Agriculture","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/geopard.tech\/es\/lineas-de-orientacion\/","og_locale":"es_ES","og_type":"article","og_title":"Guidance Lines Simulator - GeoPard Agriculture","og_description":"Guidance Lines Simulator \u00b7 Free \u00b7 No signup Plan your tractor path. Find the lowest-fuel, highest-coverage drive plan for your field. Compare AB Straight, AB...","og_url":"https:\/\/geopard.tech\/es\/lineas-de-orientacion\/","og_site_name":"GeoPard - Precision agriculture Mapping software","article_publisher":"https:\/\/www.facebook.com\/geopardAgriculture\/","article_modified_time":"2026-05-19T13:59:18+00:00","og_image":[{"width":3116,"height":1754,"url":"https:\/\/i0.wp.com\/geopard.tech\/wp-content\/uploads\/2026\/03\/GeoPard-Background-Precision-Ag-software-Do-more-with-your-data.png?fit=3116%2C1754&ssl=1","type":"image\/png"}],"twitter_card":"summary_large_image","twitter_site":"@geopardagri","twitter_misc":{"Tiempo de lectura":"4 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/geopard.tech\/guidance-lines\/","url":"https:\/\/geopard.tech\/guidance-lines\/","name":"Simulador de l\u00edneas de gu\u00eda - GeoPard Agriculture","isPartOf":{"@id":"https:\/\/geopard.tech\/#website"},"datePublished":"2026-05-19T13:00:20+00:00","dateModified":"2026-05-19T13:59:18+00:00","breadcrumb":{"@id":"https:\/\/geopard.tech\/guidance-lines\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/geopard.tech\/guidance-lines\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/geopard.tech\/guidance-lines\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/geopard.tech\/"},{"@type":"ListItem","position":2,"name":"Guidance Lines Simulator"}]},{"@type":"WebSite","@id":"https:\/\/geopard.tech\/#website","url":"https:\/\/geopard.tech\/","name":"GeoPard - Software para agricultura de precisi\u00f3n","description":"Software de mapeo para agricultura de precisi\u00f3n","publisher":{"@id":"https:\/\/geopard.tech\/#organization"},"alternateName":"GeoPard","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/geopard.tech\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/geopard.tech\/#organization","name":"GeoPard Agricultura","alternateName":"GeoPard","url":"https:\/\/geopard.tech\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/geopard.tech\/#\/schema\/logo\/image\/","url":"https:\/\/i0.wp.com\/geopard.tech\/wp-content\/uploads\/2022\/03\/favicon.png?fit=200%2C200&ssl=1","contentUrl":"https:\/\/i0.wp.com\/geopard.tech\/wp-content\/uploads\/2022\/03\/favicon.png?fit=200%2C200&ssl=1","width":200,"height":200,"caption":"GeoPard Agriculture"},"image":{"@id":"https:\/\/geopard.tech\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/geopardAgriculture\/","https:\/\/x.com\/geopardagri","https:\/\/www.linkedin.com\/company\/geopard-agriculture\/","https:\/\/www.instagram.com\/geopardagriculture\/"]}]}},"jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/PdiCPa-3qr","_links":{"self":[{"href":"https:\/\/geopard.tech\/es\/wp-json\/wp\/v2\/pages\/13171","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/geopard.tech\/es\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/geopard.tech\/es\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/geopard.tech\/es\/wp-json\/wp\/v2\/users\/210157960"}],"replies":[{"embeddable":true,"href":"https:\/\/geopard.tech\/es\/wp-json\/wp\/v2\/comments?post=13171"}],"version-history":[{"count":0,"href":"https:\/\/geopard.tech\/es\/wp-json\/wp\/v2\/pages\/13171\/revisions"}],"wp:attachment":[{"href":"https:\/\/geopard.tech\/es\/wp-json\/wp\/v2\/media?parent=13171"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}