UNPKG

@tato30/vue-pdf

Version:
804 lines 1.4 MB
var Gl = Object.defineProperty; var Nl = (b, W, Z) => W in b ? Gl(b, W, { enumerable: !0, configurable: !0, writable: !0, value: Z }) : b[W] = Z; var q = (b, W, Z) => (Nl(b, typeof W != "symbol" ? W + "" : W, Z), Z); import { defineComponent as v, ref as U, watch as k, onMounted as e, openBlock as K, createElementBlock as A, toRaw as g, computed as f, onUnmounted as Xl, createBlock as _, mergeProps as r, createCommentVNode as $, createVNode as Yl, withDirectives as Ml, createElementVNode as dl, renderSlot as Tl, vShow as Vl, shallowRef as P, isRef as yl } from "vue"; import * as F from "pdfjs-dist"; const B = "internal-link", hl = "link", Ll = "file-attachment", zl = "form-text", sl = "form-select", Il = "form-checkbox", ul = "form-radio", pl = "form-button", ll = ["click", "dblclick", "mouseover", "input", "change"]; function E(b, W, Z) { const l = []; if (Z) for (const d of Z) d[b] === W && l.push(d); return l; } function j(b, W) { return { type: b, data: W }; } function n(b, W) { switch (b.type) { case "textarea": case "text": return j(zl, { fieldName: b.name, value: b.value }); case "select-one": case "select-multiple": const Z = []; for (const d of b.options) Z.push({ value: d.value, label: d.label }); const l = []; for (const d of b.selectedOptions) l.push({ value: d.value, label: d.label }); return j(sl, { fieldName: b.name, value: l, options: Z }); case "checkbox": return j(Il, { fieldName: b.name, checked: b.checked }); case "radio": return j(ul, { fieldName: b.name, ...W }); case "button": return j(pl, { fieldName: b.name, ...W }); } } function il(b) { return j(Ll, b.file); } async function al(b, W) { if (b.dest) { let Z; if (typeof b.dest == "string" ? Z = await W.getDestination(b.dest) : Z = b.dest, !Array.isArray(Z)) return console.warn(`Destination "${Z}" is not a valid destination (dest="${b.dest}")`), j(B, { referencedPage: null, offset: null }); let l = null; Z.length === 5 && (l = { left: b.dest[2], bottom: b.dest[3] }); const [d] = Z; if (Number.isInteger(d)) return j(B, { referencedPage: Number(d) + 1, offset: l }); if (typeof d == "object") { const c = await W.getPageIndex(d); return j(B, { referencedPage: c + 1, offset: l }); } else return console.warn( `Destination "${d}" is not a valid destination (dest="${b.dest}")` ), j(B, { referencedPage: null, offset: null }); } else if (b.url) return j(hl, { url: b.url, unsafeUrl: b.unsafeUrl }); } function Zl(b) { for (const W of b.getElementsByTagName("span")) { let Z = W.textContent; const l = JSON.parse(W.dataset.l10nArgs ?? "{}"); if (Z) for (const d in l) Z = Z.replace(`{{${d}}}`, l[d]); W.textContent = Z; } } function Rl(b, W, Z) { var d; let l = b.target.parentNode; if (l.tagName === "DIV" && (l = l.firstChild), l.className === "linkAnnotation" && b.type === "click") { const c = (d = l.dataset) == null ? void 0 : d.annotationId; if (c) return al(E("id", c, Z)[0], W); } else if (l.className.includes("popupAnnotation") || l.className.includes("textAnnotation")) Zl(l); else if (l.className.includes("fileAttachmentAnnotation")) { Zl(l); const c = l.dataset.annotationId; if (c && b.type === "dblclick") return il(E("id", c, Z)[0]); } else if (l.className.includes("textWidgetAnnotation") && b.type === "input") { let c = l.getElementsByTagName("input")[0]; return c || (c = l.getElementsByTagName("textarea")[0]), n(c); } else { if (l.className.includes("choiceWidgetAnnotation") && b.type === "input") return n(l.getElementsByTagName("select")[0]); if (l.className.includes("buttonWidgetAnnotation checkBox") && b.type === "change") return n(l.getElementsByTagName("input")[0]); if (l.className.includes("buttonWidgetAnnotation radioButton") && b.type === "change") { const c = l.dataset.annotationId; if (c) { const m = E("id", c, Z)[0], z = []; for (const h of E("fieldName", m.fieldName, Z)) h.buttonValue && z.push(h.buttonValue); return n(l.getElementsByTagName("input")[0], { value: m.buttonValue, defaultValue: m.fieldValue, options: z }); } } else if (l.className.includes("buttonWidgetAnnotation pushButton") && b.type === "click") { const c = l.dataset.annotationId; if (c) { const m = E("id", c, Z)[0]; return m.resetForm ? n( { name: m.fieldName, type: "button" }, { actions: m.actions, reset: !0 } ) : n( { name: m.fieldName, type: "button" }, { actions: m.actions, reset: !1 } ); } } } } class cl { constructor() { q(this, "externalLinkEnabled"); this.externalLinkEnabled = !0; } /** * @type {number} */ get pagesCount() { return 0; } /** * @type {number} */ get page() { return 0; } /** * @param {number} _value */ set page(W) { } /** * @type {number} */ get rotation() { return 0; } /** * @param {number} _value */ set rotation(W) { } /** * @type {boolean} */ get isInPresentationMode() { return !1; } /** * @param {string|Array} _dest - The named, or explicit, PDF destination. */ async goToDestination(W) { } /** * @param {number|string} _val - The page number, or page label. */ goToPage(W) { } /** * @param {HTMLAnchorElement} link * @param {string} url * @param {boolean} [_newWindow] */ addLinkAttributes(W, Z, l = !1) { } /** * @param _dest - The PDF destination object. * @returns {string} The hyperlink to the PDF object. */ getDestinationHash(W) { return "#"; } /** * @param _hash - The PDF parameters/hash. * @returns {string} The hyperlink to the PDF object. */ getAnchorUrl(W) { return "#"; } /** * @param {string} _hash */ setHash(W) { } /** * @param {string} _action */ executeNamedAction(W) { } /** * @param {Object} _action */ executeSetOCGState(W) { } /** * @param {number} _pageNum - page number. * @param {Object} _pageRef - reference to the page. */ cachePageRef(W, Z) { } } const wl = /* @__PURE__ */ v({ __name: "AnnotationLayer", props: { page: {}, viewport: {}, document: {}, annotationsFilter: {}, annotationsMap: {}, imageResourcesPath: {}, hideForms: { type: Boolean }, enableScripting: { type: Boolean }, intent: {} }, emits: ["annotation", "annotationLoaded"], setup(b, { emit: W }) { const Z = b, l = W, d = U(), c = U(); function m(I) { const Y = Rl(I, Z.document, c.value); Promise.resolve(Y).then((V) => { V && l("annotation", V); }); } async function z() { var Y; return await ((Y = g(Z.document)) == null ? void 0 : Y.getFieldObjects()); } async function h() { var Y; return await ((Y = g(Z.document)) == null ? void 0 : Y.hasJSActions()); } async function T() { const I = Z.page; let Y = await (I == null ? void 0 : I.getAnnotations({ intent: Z.intent })); if (Z.annotationsFilter) { const V = Z.annotationsFilter; Y = Y.filter((N) => { const G = N.subtype, L = N.fieldType ? `${G}.${N.fieldType}` : null; return (V == null ? void 0 : V.includes(G)) || L !== null && (V == null ? void 0 : V.includes(L)); }); } return Y; } async function u() { var R, a; (a = (R = d.value).replaceChildren) == null || a.call(R); for (const i of ll) d.value.removeEventListener(i, m); const I = g(Z.document), Y = Z.page, V = Z.viewport; c.value = await T(); const N = /* @__PURE__ */ new Map([]); for (const i of c.value) if (i.subtype === "Widget" && i.fieldType === "Btn" && i.pushButton) { const x = i.rect[2] - i.rect[0], J = i.rect[3] - i.rect[1], X = document.createElement("canvas"); X.setAttribute("width", (x * V.scale).toString()), X.setAttribute("height", (J * V.scale).toString()), N.set(i.id, X); } const G = I.annotationStorage; if (Z.annotationsMap) for (const [i, x] of Object.entries(Z.annotationsMap)) G.setValue(i, x); const L = { accessibilityManager: void 0, annotationCanvasMap: N, div: d.value, page: Y, viewport: V.clone({ dontFlip: !0 }), annotationEditorUIManager: null, l10n: null, structTreeLayer: null }, p = { annotations: c.value, viewport: V.clone({ dontFlip: !0 }), linkService: new cl(), annotationCanvasMap: N, div: d.value, annotationStorage: G, renderForms: !Z.hideForms, page: Y, enableScripting: !1, hasJSActions: await h(), fieldObjects: await z(), downloadManager: null, imageResourcesPath: Z.imageResourcesPath }; new F.AnnotationLayer(L).render(p).then(async () => { l("annotationLoaded", await T()); }); for (const i of ll) d.value.addEventListener(i, m); } return k(() => Z.viewport, () => { Z.page && Z.viewport && d.value && u(); }), e(() => { Z.page && Z.viewport && d.value && u(); }), (I, Y) => (K(), A("div", { ref_key: "layer", ref: d, class: "annotationLayer", style: { display: "block" } }, null, 512)); } }); function Sl(b, W, Z) { const l = []; for (const u of b.items) l.push(u.str), u.hasEOL && l.push(` `); let d = l.join(""); d = d.replace(new RegExp("(?<=\\p{Ideographic}|[\\u3040-\\u30FF])\\n(\\p{Ideographic}|[\\u3040-\\u30FF])", "gmu"), "$1"), d = d.replace(new RegExp("(?<=\\S)-\\n", "gmu"), ""), d = d.replace(/\n/g, " "); const c = ["g"]; Z.ignoreCase && c.push("i"); let m = W.trim().replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); Z.completeWords && (m = `\\b${m}\\b`); const z = new RegExp(m, c.join("")), h = []; let T; for (; (T = z.exec(d)) !== null; ) h.push([T.index, T[0].length, T[0]]); return h; } function jl(b, W) { function Z(h, T, u) { if (h.hasEOL && h.str.length === 0) { const I = T == null ? void 0 : T.str[T.str.length - 1], Y = u == null ? void 0 : u.str[0], V = new RegExp(/(\p{Ideographic}|[\u3040-\u30FF])/u); if (I && V.test(I) && Y && V.test(Y)) return 0; } return h.hasEOL ? h.str.endsWith("-") ? -1 : 1 : 0; } let l = 0, d = 0; const c = W.items, m = c.length - 1, z = []; for (let h = 0; h < b.length; h++) { let T = b[h][0]; for (; l !== m && T >= d + c[l].str.length; ) { const Y = c[l]; d += Y.str.length + Z( Y, l - 1 < 0 ? null : c[l - 1], l + 1 >= c.length ? null : c[l + 1] ), l++; } const u = { idx: l, offset: T - d }; for (T += b[h][1]; l !== m && T > d + c[l].str.length; ) { const Y = c[l]; d += Y.str.length + Z( Y, l - 1 < 0 ? null : c[l - 1], l + 1 >= c.length ? null : c[l + 1] ), l++; } const I = { idx: l, offset: T - d }; z.push({ start: u, end: I, str: b[h][2], oindex: b[h][0] }); } return z; } function xl(b, W, Z) { function l(d, c = -1, m = -1) { const z = W.items[d], h = []; let T = "", u = "", I = "", Y = Z[d]; if (!Y) return; if (Y.nodeType === Node.TEXT_NODE) { const G = document.createElement("span"); Y.before(G), G.append(Y), Z[d] = G, Y = G; } c >= 0 && m >= 0 ? T = z.str.substring(c, m) : c < 0 && m < 0 ? T = z.str : c >= 0 ? T = z.str.substring(c) : m >= 0 && (T = z.str.substring(0, m)); const V = document.createTextNode(T), N = document.createElement("span"); if (N.className = "highlight appended", N.append(V), h.push(N), c > 0) if (Y.childNodes.length === 1 && Y.childNodes[0].nodeType === Node.TEXT_NODE) { u = z.str.substring(0, c); const G = document.createTextNode(u); h.unshift(G); } else { let G = 0; const L = []; for (const p of Y.childNodes) { const s = p.nodeType === Node.TEXT_NODE ? p.nodeValue : p.firstChild.nodeValue; G += s.length, G <= c ? L.push(p) : c >= G - s.length && m <= G && L.push(document.createTextNode(s.substring(0, c - (G - s.length)))); } h.unshift(...L); } if (m > 0) { I = z.str.substring(m); const G = document.createTextNode(I); h.push(G); } Y.replaceChildren(...h); } for (const d of b.sort((c, m) => c.oindex - m.oindex)) if (d.start.idx === d.end.idx) l(d.start.idx, d.start.offset, d.end.offset); else for (let c = d.start.idx, m = d.end.idx; c <= m; c++) c === d.start.idx ? l(c, d.start.offset) : c === d.end.idx ? l(c, -1, d.end.offset) : l(c); } function Jl(b, W) { const Z = b.items.map((l) => l.str); for (let l = 0; l < W.length; l++) { const d = W[l]; if (d && d.nodeType !== Node.TEXT_NODE) { const c = document.createTextNode(Z[l]); d.replaceChildren(c); } } } function Dl(b, W, Z) { const l = []; for (const d of b) { const c = Sl(W, d, Z); l.push(...jl(c, W)); } return l; } const tl = /* @__PURE__ */ v({ __name: "TextLayer", props: { page: {}, viewport: {}, highlightText: {}, highlightOptions: {}, highlightPages: {} }, emits: ["highlight", "textLoaded"], setup(b, { emit: W }) { const Z = b, l = W, d = U(), c = U(); let m = [], z = null; function h() { return Object.assign( {}, { ignoreCase: !0, completeWords: !1 }, Z.highlightOptions ); } async function T(N = !1) { const G = Z.page, L = await (G == null ? void 0 : G.getTextContent()); if (L && (N && Jl(L, m), Z.highlightText && (!Z.highlightPages || Z.highlightPages.includes(G.pageNumber)))) { const p = typeof Z.highlightText == "string" ? [Z.highlightText] : Z.highlightText, s = Dl( p, L, h() ); xl(s, L, m), l("highlight", { matches: s, textContent: L, textDivs: m, page: (G == null ? void 0 : G.pageNumber) || 1 }); } } async function u() { var R, a; z == null || z.cancel(), (a = (R = d.value).replaceChildren) == null || a.call(R); const N = Z.page, G = Z.viewport, L = N == null ? void 0 : N.streamTextContent({ includeMarkedContent: !0, disableNormalization: !0 }), p = new F.TextLayer({ container: d.value, textContentSource: L, viewport: G }); z = p, await p.render(), m = p.textDivs; const s = await (N == null ? void 0 : N.getTextContent()); l("textLoaded", { textDivs: m, textContent: s }), I(), T(); } function I() { var G; const N = document.createElement("div"); N.className = "endOfContent", (G = d.value) == null || G.appendChild(N), c.value = N; } function Y() { c.value && c.value.classList.add("active"); } function V() { c.value && c.value.classList.remove("active"); } return k( () => Z.viewport, (N) => { Z.page && Z.viewport && d.value && u(); } ), k( () => [Z.highlightText, Z.highlightOptions], (N) => { T(!0); }, { deep: !0 } ), e(() => { Z.page && Z.viewport && d.value && u(); }), (N, G) => (K(), A("div", { ref_key: "layer", ref: d, class: "textLayer", style: { display: "block" }, onMousedown: Y, onMouseup: V }, null, 544)); } }), Ul = /* @__PURE__ */ v({ __name: "XFALayer", props: { page: {}, document: {}, viewport: {} }, emits: ["xfaLoaded"], setup(b, { emit: W }) { const Z = b, l = W, d = U(); async function c() { var T, u; (u = (T = d.value).replaceChildren) == null || u.call(T); const m = g(Z.document), z = Z.page, h = Z.viewport; if (m.isPureXfa) { const I = await z.getXfa(), Y = { div: d.value, viewport: h.clone({ dontFlip: !0 }), linkService: new cl(), annotationStorage: m == null ? void 0 : m.annotationStorage, xfaHtml: I }; F.XfaLayer.render(Y), l("xfaLoaded"); } } return k(() => Z.viewport, (m) => { Z.page && Z.viewport && d.value && c(); }), e(() => { Z.page && Z.viewport && d.value && c(); }), (m, z) => (K(), A("div", { ref_key: "layer", ref: d, style: { display: "block" } }, null, 512)); } }); const Fl = /* @__PURE__ */ dl("canvas", { dir: "ltr", style: { display: "block" }, role: "main" }, null, -1), bl = /* @__PURE__ */ v({ __name: "VuePDF", props: { pdf: {}, page: { default: 1 }, scale: { default: 1 }, rotation: {}, fitParent: { type: Boolean }, width: {}, height: {}, textLayer: { type: Boolean }, autoDestroy: { type: Boolean, default: !1 }, imageResourcesPath: {}, hideForms: { type: Boolean }, intent: { default: "display" }, annotationLayer: { type: Boolean }, annotationsFilter: {}, annotationsMap: {}, watermarkText: {}, watermarkOptions: {}, highlightText: {}, highlightOptions: {}, highlightPages: {} }, emits: ["annotation", "highlight", "loaded", "textLoaded", "annotationLoaded", "xfaLoaded"], setup(b, { expose: W, emit: Z }) { const l = b, d = Z, c = U(), m = U(), z = U(!1); let h; const T = f(() => ({ viewport: void 0, document: void 0, page: void 0 })), u = f(() => ({ annotationsMap: l.annotationsMap, annotationsFilter: l.annotationsFilter, imageResourcesPath: l.imageResourcesPath, hideForms: l.hideForms, intent: l.intent })), I = f(() => ({ highlightText: l.highlightText, highlightOptions: l.highlightOptions, highlightPages: l.highlightPages })); function Y() { return Object.assign( {}, { columns: 4, rows: 4, rotation: 45, fontSize: 18, color: "rgba(211, 210, 211, 0.4)" }, l.watermarkOptions ); } function V(X) { if (!(typeof X == "number" && X % 90 === 0)) return 0; const M = X / 90; return M > 4 ? V(X - 360) : M < 0 ? V(X + 360) : X; } function N(X) { let M = l.scale; if (l.fitParent) { const y = c.value.parentNode.clientWidth, S = X.getViewport({ scale: 1 }).width; M = y / S; } else if (l.width) { const y = X.getViewport({ scale: 1 }).width; M = l.width / y; } else if (l.height) { const y = X.getViewport({ scale: 1 }).height; M = l.height / y; } return M; } function G(X = 1) { if (!l.watermarkText) return; const M = L(); if (!M) return; const y = M.getContext("2d"); if (!y) return; const S = Y(), O = l.watermarkText, w = S.columns, D = S.rows, t = w * D, o = S.rotation, Q = S.fontSize * X; y.font = `${Q}px Trebuchet MS`, y.fillStyle = S.color; for (let C = 0; C < t; C++) { const H = C % w * (M.width / w) + M.width / (w * 2), Wl = Math.floor(C / w) * (M.height / D) + M.height / (D * 2), ml = y.measureText(O).width; y.save(), y.translate(H, Wl), y.rotate(-o * (Math.PI / 180)), y.fillText(O, -ml / 2, Q / 2), y.restore(); } } function L() { var M; let X = null; return (M = c.value) == null || M.childNodes.forEach((y) => { y.tagName === "CANVAS" && (X = y); }), X; } function p(X) { var O, w, D; let M; const y = L(); y && (y == null ? void 0 : y.getAttribute("role")) === "main" ? M = y : (M = document.createElement("canvas"), M.style.display = "block", M.setAttribute("dir", "ltr")); const S = window.devicePixelRatio || 1; return M.width = Math.floor(X.width * S), M.height = Math.floor(X.height * S), M.style.width = `${Math.floor(X.width)}px`, M.style.height = `${Math.floor(X.height)}px`, (O = c.value) == null || O.style.setProperty("--scale-factor", `${X.scale}`), (w = c.value) == null || w.style.setProperty("--user-unit", `${X.userUnit}`), (D = c.value) == null || D.style.setProperty("--total-scale-factor", "calc(var(--scale-factor) * var(--user-unit))"), m.value.style.width = `${Math.floor(X.width)}px`, m.value.style.height = `${Math.floor(X.height)}px`, m.value.style.top = "0", m.value.style.left = "0", z.value = !0, M; } function s() { h && h.cancel(); } function R(X) { var M; (M = g(T.value.document)) == null || M.getPage(X).then((y) => { var H; s(); const S = y.getViewport(), O = { scale: N(y), rotation: V((l.rotation || 0) + S.rotation) }, w = y.getViewport(O), D = L(), t = p(w), o = window.devicePixelRatio || 1, Q = o !== 1 ? [o, 0, 0, o, 0, 0] : void 0, C = { canvasContext: t.getContext("2d"), viewport: w, annotationMode: l.hideForms ? F.AnnotationMode.ENABLE : F.AnnotationMode.ENABLE_FORMS, transform: Q, intent: l.intent }; (t == null ? void 0 : t.getAttribute("role")) !== "main" ? D && ((H = c.value) == null || H.replaceChild(t, D)) : t.removeAttribute("role"), T.value.page = y, T.value.viewport = w, h = y.render(C), h.promise.then(() => { z.value = !1, G(w.scale), d("loaded", T.value.viewport); }).catch(() => { }); }); } function a(X) { X.promise.then(async (M) => { T.value.document = M, R(l.page); }); } k( () => l.pdf, (X) => { X !== void 0 && a(X); } ), k( () => [ l.scale, l.width, l.height, l.rotation, l.page, l.hideForms, l.intent ], () => { R(l.page); } ), e(() => { l.pdf !== void 0 && a(l.pdf); }), Xl(() => { var X; l.autoDestroy && ((X = l.pdf) == null || X.destroy()); }); function i() { var X; (X = l.pdf) == null || X.destroy(); } function x() { R(l.page); } function J() { s(); } return W({ reload: x, cancel: J, destroy: i }), (X, M) => (K(), A("div", { ref_key: "container", ref: c, style: { position: "relative", display: "block" } }, [ Fl, X.annotationLayer ? (K(), _(wl, r({ key: 0 }, { ...T.value, ...u.value }, { onAnnotation: M[0] || (M[0] = (y) => d("annotation", y)), onAnnotationLoaded: M[1] || (M[1] = (y) => d("annotationLoaded", y)) }), null, 16)) : $("", !0), X.textLayer ? (K(), _(tl, r({ key: 1 }, { ...T.value, ...I.value }, { onHighlight: M[2] || (M[2] = (y) => d("highlight", y)), onTextLoaded: M[3] || (M[3] = (y) => d("textLoaded", y)) }), null, 16)) : $("", !0), Yl(Ul, r({ ...T.value }, { onXfaLoaded: M[4] || (M[4] = (y) => d("xfaLoaded")) }), null, 16), Ml(dl("div", { ref_key: "loadingLayer", ref: m, style: { position: "absolute" } }, [ Tl(X.$slots, "default") ], 512), [ [Vl, z.value] ]) ], 512)); } }), Ol = "data:application/javascript;base64,LyoqCiAqIEBsaWNzdGFydCBUaGUgZm9sbG93aW5nIGlzIHRoZSBlbnRpcmUgbGljZW5zZSBub3RpY2UgZm9yIHRoZQogKiBKYXZhU2NyaXB0IGNvZGUgaW4gdGhpcyBwYWdlCiAqCiAqIENvcHlyaWdodCAyMDI0IE1vemlsbGEgRm91bmRhdGlvbgogKgogKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLgogKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKICoKICogICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAogKgogKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgogKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgogKgogKiBAbGljZW5kIFRoZSBhYm92ZSBpcyB0aGUgZW50aXJlIGxpY2Vuc2Ugbm90aWNlIGZvciB0aGUKICogSmF2YVNjcmlwdCBjb2RlIGluIHRoaXMgcGFnZQogKi8KLyoqCiAqIHBkZmpzVmVyc2lvbiA9IDUuMy4zMQogKiBwZGZqc0J1aWxkID0gNDdhZDgyMGQ5CiAqLwpjb25zdCBlPSEoIm9iamVjdCIhPXR5cGVvZiBwcm9jZXNzfHxwcm9jZXNzKyIiIT0iW29iamVjdCBwcm9jZXNzXSJ8fHByb2Nlc3MudmVyc2lvbnMubnd8fHByb2Nlc3MudmVyc2lvbnMuZWxlY3Ryb24mJnByb2Nlc3MudHlwZSYmImJyb3dzZXIiIT09cHJvY2Vzcy50eXBlKSx0PVsuMDAxLDAsMCwuMDAxLDAsMF0sYT0xLjM1LHI9LjM1LGk9LjI1OTI1OTI1OTI1OTI1OTI0LG49MSxzPTIsbz00LGM9OCxsPTE2LGg9NjQsdT0xMjgsZD0yNTYsZj0icGRmanNfaW50ZXJuYWxfZWRpdG9yXyIsZz0zLHA9OSxtPTEzLGI9MTUseT0xMDEsdz17UFJJTlQ6NCxNT0RJRllfQ09OVEVOVFM6OCxDT1BZOjE2LE1PRElGWV9BTk5PVEFUSU9OUzozMixGSUxMX0lOVEVSQUNUSVZFX0ZPUk1TOjI1NixDT1BZX0ZPUl9BQ0NFU1NJQklMSVRZOjUxMixBU1NFTUJMRToxMDI0LFBSSU5UX0hJR0hfUVVBTElUWToyMDQ4fSxTPTAseD00LGs9MSxDPTIsdj0zLEY9MSxPPTIsVD0zLE09NCxEPTUsUj02LE49NyxFPTgsTD05LGo9MTAsXz0xMSxVPTEyLFg9MTMscT0xNCxIPTE1LFc9MTYsej0xNywkPTIwLEc9Ikdyb3VwIixWPSJSIixLPTEsSj0yLFk9NCxaPTE2LFE9MzIsZWU9MTI4LHRlPTUxMixhZT0xLHJlPTIsaWU9NDA5NixuZT04MTkyLHNlPTMyNzY4LG9lPTY1NTM2LGNlPTEzMTA3MixsZT0xMDQ4NTc2LGhlPTIwOTcxNTIsdWU9ODM4ODYwOCxkZT0xNjc3NzIxNixmZT0xLGdlPTIscGU9MyxtZT00LGJlPTUseWU9e0U6Ik1vdXNlIEVudGVyIixYOiJNb3VzZSBFeGl0IixEOiJNb3VzZSBEb3duIixVOiJNb3VzZSBVcCIsRm86IkZvY3VzIixCbDoiQmx1ciIsUE86IlBhZ2VPcGVuIixQQzoiUGFnZUNsb3NlIixQVjoiUGFnZVZpc2libGUiLFBJOiJQYWdlSW52aXNpYmxlIixLOiJLZXlzdHJva2UiLEY6IkZvcm1hdCIsVjoiVmFsaWRhdGUiLEM6IkNhbGN1bGF0ZSJ9LHdlPXtXQzoiV2lsbENsb3NlIixXUzoiV2lsbFNhdmUiLERTOiJEaWRTYXZlIixXUDoiV2lsbFByaW50IixEUDoiRGlkUHJpbnQifSxTZT17TzoiUGFnZU9wZW4iLEM6IlBhZ2VDbG9zZSJ9LHhlPTEsQWU9NSxrZT0xLENlPTIsdmU9MyxGZT00LEllPTUsT2U9NixUZT03LE1lPTgsRGU9OSxCZT0xMCxSZT0xMSxOZT0xMixFZT0xMyxQZT0xNCxMZT0xNSxqZT0xNixfZT0xNyxVZT0xOCxYZT0xOSxxZT0yMCxIZT0yMSxXZT0yMix6ZT0yMywkZT0yNCxHZT0yNSxWZT0yNixLZT0yNyxKZT0yOCxZZT0yOSxaZT0zMCxRZT0zMSxldD0zMix0dD0zMyxhdD0zNCxydD0zNSxpdD0zNixudD0zNyxzdD0zOCxvdD0zOSxjdD00MCxsdD00MSxodD00Mix1dD00MyxkdD00NCxmdD00NSxndD00NixwdD00NyxtdD00OCxidD00OSx5dD01MCx3dD01MSxTdD01Mix4dD01MyxBdD01NCxrdD01NSxDdD01Nix2dD01NyxGdD01OCxJdD01OSxPdD02MCxUdD02MSxNdD02MixEdD02MyxCdD02NCxSdD02NSxOdD02NixFdD02NyxQdD02OCxMdD02OSxqdD03MCxfdD03MSxVdD03MixYdD03MyxxdD03NCxIdD03NSxXdD03Nix6dD03NywkdD04MCxHdD04MSxWdD04MyxLdD04NCxKdD04NSxZdD04NixadD04NyxRdD04OCxlYT04OSx0YT05MCxhYT05MSxyYT05MixpYT05MyxuYT05NCxzYT0wLG9hPTEsY2E9MixsYT0zLGhhPTEsdWE9MjtsZXQgZGE9eGU7ZnVuY3Rpb24gZ2V0VmVyYm9zaXR5TGV2ZWwoKXtyZXR1cm4gZGF9ZnVuY3Rpb24gaW5mbyhlKXtkYT49QWUmJmNvbnNvbGUubG9nKGBJbmZvOiAke2V9YCl9ZnVuY3Rpb24gd2FybihlKXtkYT49eGUmJmNvbnNvbGUubG9nKGBXYXJuaW5nOiAke2V9YCl9ZnVuY3Rpb24gdW5yZWFjaGFibGUoZSl7dGhyb3cgbmV3IEVycm9yKGUpfWZ1bmN0aW9uIGFzc2VydChlLHQpe2V8fHVucmVhY2hhYmxlKHQpfWZ1bmN0aW9uIGNyZWF0ZVZhbGlkQWJzb2x1dGVVcmwoZSx0PW51bGwsYT1udWxsKXtpZighZSlyZXR1cm4gbnVsbDtpZihhJiYic3RyaW5nIj09dHlwZW9mIGUpe2lmKGEuYWRkRGVmYXVsdFByb3RvY29sJiZlLnN0YXJ0c1dpdGgoInd3dy4iKSl7Y29uc3QgdD1lLm1hdGNoKC9cLi9nKTt0Py5sZW5ndGg+PTImJihlPWBodHRwOi8vJHtlfWApfWlmKGEudHJ5Q29udmVydEVuY29kaW5nKXRyeXtlPXN0cmluZ1RvVVRGOFN0cmluZyhlKX1jYXRjaHt9fWNvbnN0IHI9dD9VUkwucGFyc2UoZSx0KTpVUkwucGFyc2UoZSk7cmV0dXJuIGZ1bmN0aW9uIF9pc1ZhbGlkUHJvdG9jb2woZSl7c3dpdGNoKGU/LnByb3RvY29sKXtjYXNlImh0dHA6IjpjYXNlImh0dHBzOiI6Y2FzZSJmdHA6IjpjYXNlIm1haWx0bzoiOmNhc2UidGVsOiI6cmV0dXJuITA7ZGVmYXVsdDpyZXR1cm4hMX19KHIpP3I6bnVsbH1mdW5jdGlvbiBzaGFkb3coZSx0LGEscj0hMSl7T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsdCx7dmFsdWU6YSxlbnVtZXJhYmxlOiFyLGNvbmZpZ3VyYWJsZTohMCx3cml0YWJsZTohMX0pO3JldHVybiBhfWNvbnN0IGZhPWZ1bmN0aW9uIEJhc2VFeGNlcHRpb25DbG9zdXJlKCl7ZnVuY3Rpb24gQmFzZUV4Y2VwdGlvbihlLHQpe3RoaXMubWVzc2FnZT1lO3RoaXMubmFtZT10fUJhc2VFeGNlcHRpb24ucHJvdG90eXBlPW5ldyBFcnJvcjtCYXNlRXhjZXB0aW9uLmNvbnN0cnVjdG9yPUJhc2VFeGNlcHRpb247cmV0dXJuIEJhc2VFeGNlcHRpb259KCk7Y2xhc3MgUGFzc3dvcmRFeGNlcHRpb24gZXh0ZW5kcyBmYXtjb25zdHJ1Y3RvcihlLHQpe3N1cGVyKGUsIlBhc3N3b3JkRXhjZXB0aW9uIik7dGhpcy5jb2RlPXR9fWNsYXNzIFVua25vd25FcnJvckV4Y2VwdGlvbiBleHRlbmRzIGZhe2NvbnN0cnVjdG9yKGUsdCl7c3VwZXIoZSwiVW5rbm93bkVycm9yRXhjZXB0aW9uIik7dGhpcy5kZXRhaWxzPXR9fWNsYXNzIEludmFsaWRQREZFeGNlcHRpb24gZXh0ZW5kcyBmYXtjb25zdHJ1Y3RvcihlKXtzdXBlcihlLCJJbnZhbGlkUERGRXhjZXB0aW9uIil9fWNsYXNzIFJlc3BvbnNlRXhjZXB0aW9uIGV4dGVuZHMgZmF7Y29uc3RydWN0b3IoZSx0LGEpe3N1cGVyKGUsIlJlc3BvbnNlRXhjZXB0aW9uIik7dGhpcy5zdGF0dXM9dDt0aGlzLm1pc3Npbmc9YX19Y2xhc3MgRm9ybWF0RXJyb3IgZXh0ZW5kcyBmYXtjb25zdHJ1Y3RvcihlKXtzdXBlcihlLCJGb3JtYXRFcnJvciIpfX1jbGFzcyBBYm9ydEV4Y2VwdGlvbiBleHRlbmRzIGZhe2NvbnN0cnVjdG9yKGUpe3N1cGVyKGUsIkFib3J0RXhjZXB0aW9uIil9fWZ1bmN0aW9uIGJ5dGVzVG9TdHJpbmcoZSl7Im9iamVjdCI9PXR5cGVvZiBlJiZ2b2lkIDAhPT1lPy5sZW5ndGh8fHVucmVhY2hhYmxlKCJJbnZhbGlkIGFyZ3VtZW50IGZvciBieXRlc1RvU3RyaW5nIik7Y29uc3QgdD1lLmxlbmd0aCxhPTgxOTI7aWYodDxhKXJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KG51bGwsZSk7Y29uc3Qgcj1bXTtmb3IobGV0IGk9MDtpPHQ7aSs9YSl7Y29uc3Qgbj1NYXRoLm1pbihpK2EsdCkscz1lLnN1YmFycmF5KGksbik7ci5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkobnVsbCxzKSl9cmV0dXJuIHIuam9pbigiIil9ZnVuY3Rpb24gc3RyaW5nVG9CeXRlcyhlKXsic3RyaW5nIiE9dHlwZW9mIGUmJnVucmVhY2hhYmxlKCJJbnZhbGlkIGFyZ3VtZW50IGZvciBzdHJpbmdUb0J5dGVzIik7Y29uc3QgdD1lLmxlbmd0aCxhPW5ldyBVaW50OEFycmF5KHQpO2ZvcihsZXQgcj0wO3I8dDsrK3IpYVtyXT0yNTUmZS5jaGFyQ29kZUF0KHIpO3JldHVybiBhfWZ1bmN0aW9uIHN0cmluZzMyKGUpe3JldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlKGU+PjI0JjI1NSxlPj4xNiYyNTUsZT4+OCYyNTUsMjU1JmUpfWZ1bmN0aW9uIG9iamVjdFNpemUoZSl7cmV0dXJuIE9iamVjdC5rZXlzKGUpLmxlbmd0aH1jbGFzcyBGZWF0dXJlVGVzdHtzdGF0aWMgZ2V0IGlzTGl0dGxlRW5kaWFuKCl7cmV0dXJuIHNoYWRvdyh0aGlzLCJpc0xpdHRsZUVuZGlhbiIsZnVuY3Rpb24gaXNMaXR0bGVFbmRpYW4oKXtjb25zdCBlPW5ldyBVaW50OEFycmF5KDQpO2VbMF09MTtyZXR1cm4gMT09PW5ldyBVaW50MzJBcnJheShlLmJ1ZmZlciwwLDEpWzBdfSgpKX1zdGF0aWMgZ2V0IGlzRXZhbFN1cHBvcnRlZCgpe3JldHVybiBzaGFkb3codGhpcywiaXNFdmFsU3VwcG9ydGVkIixmdW5jdGlvbiBpc0V2YWxTdXBwb3J0ZWQoKXt0cnl7bmV3IEZ1bmN0aW9uKCIiKTtyZXR1cm4hMH1jYXRjaHtyZXR1cm4hMX19KCkpfXN0YXRpYyBnZXQgaXNPZmZzY3JlZW5DYW52YXNTdXBwb3J0ZWQoKXtyZXR1cm4gc2hhZG93KHRoaXMsImlzT2Zmc2NyZWVuQ2FudmFzU3VwcG9ydGVkIiwidW5kZWZpbmVkIiE9dHlwZW9mIE9mZnNjcmVlbkNhbnZhcyl9c3RhdGljIGdldCBpc0ltYWdlRGVjb2RlclN1cHBvcnRlZCgpe3JldHVybiBzaGFkb3codGhpcywiaXNJbWFnZURlY29kZXJTdXBwb3J0ZWQiLCJ1bmRlZmluZWQiIT10eXBlb2YgSW1hZ2VEZWNvZGVyKX1zdGF0aWMgZ2V0IHBsYXRmb3JtKCl7Y29uc3R7cGxhdGZvcm06ZSx1c2VyQWdlbnQ6dH09bmF2aWdhdG9yO3JldHVybiBzaGFkb3codGhpcywicGxhdGZvcm0iLHtpc0FuZHJvaWQ6dC5pbmNsdWRlcygiQW5kcm9pZCIpLGlzTGludXg6ZS5pbmNsdWRlcygiTGludXgiKSxpc01hYzplLmluY2x1ZGVzKCJNYWMiKSxpc1dpbmRvd3M6ZS5pbmNsdWRlcygiV2luIiksaXNGaXJlZm94OnQuaW5jbHVkZXMoIkZpcmVmb3giKX0pfXN0YXRpYyBnZXQgaXNDU1NSb3VuZFN1cHBvcnRlZCgpe3JldHVybiBzaGFkb3codGhpcywiaXNDU1NSb3VuZFN1cHBvcnRlZCIsZ2xvYmFsVGhpcy5DU1M/LnN1cHBvcnRzPy4oIndpZHRoOiByb3VuZCgxLjVweCwgMXB4KSIpKX19Y29uc3QgZ2E9QXJyYXkuZnJvbShBcnJheSgyNTYpLmtleXMoKSwoZT0+ZS50b1N0cmluZygxNikucGFkU3RhcnQoMiwiMCIpKSk7Y2xhc3MgVXRpbHtzdGF0aWMgbWFrZUhleENvbG9yKGUsdCxhKXtyZXR1cm5gIyR7Z2FbZV19JHtnYVt0XX0ke2dhW2FdfWB9c3RhdGljIHNjYWxlTWluTWF4KGUsdCl7bGV0IGE7aWYoZVswXSl7aWYoZVswXTwwKXthPXRbMF07dFswXT10WzJdO3RbMl09YX10WzBdKj1lWzBdO3RbMl0qPWVbMF07aWYoZVszXTwwKXthPXRbMV07dFsxXT10WzNdO3RbM109YX10WzFdKj1lWzNdO3RbM10qPWVbM119ZWxzZXthPXRbMF07dFswXT10WzFdO3RbMV09YTthPXRbMl07dFsyXT10WzNdO3RbM109YTtpZihlWzFdPDApe2E9dFsxXTt0WzFdPXRbM107dFszXT1hfXRbMV0qPWVbMV07dFszXSo9ZVsxXTtpZihlWzJdPDApe2E9dFswXTt0WzBdPXRbMl07dFsyXT1hfXRbMF0qPWVbMl07dFsyXSo9ZVsyXX10WzBdKz1lWzRdO3RbMV0rPWVbNV07dFsyXSs9ZVs0XTt0WzNdKz1lWzVdfXN0YXRpYyB0cmFuc2Zvcm0oZSx0KXtyZXR1cm5bZVswXSp0WzBdK2VbMl0qdFsxXSxlWzFdKnRbMF0rZVszXSp0WzFdLGVbMF0qdFsyXStlWzJdKnRbM10sZVsxXSp0WzJdK2VbM10qdFszXSxlWzBdKnRbNF0rZVsyXSp0WzVdK2VbNF0sZVsxXSp0WzRdK2VbM10qdFs1XStlWzVdXX1zdGF0aWMgYXBwbHlUcmFuc2Zvcm0oZSx0LGE9MCl7Y29uc3Qgcj1lW2FdLGk9ZVthKzFdO2VbYV09cip0WzBdK2kqdFsyXSt0WzRdO2VbYSsxXT1yKnRbMV0raSp0WzNdK3RbNV19c3RhdGljIGFwcGx5VHJhbnNmb3JtVG9CZXppZXIoZSx0LGE9MCl7Y29uc3Qgcj10WzBdLGk9dFsxXSxuPXRbMl0scz10WzNdLG89dFs0XSxjPXRbNV07Zm9yKGxldCB0PTA7dDw2O3QrPTIpe2NvbnN0IGw9ZVthK3RdLGg9ZVthK3QrMV07ZVthK3RdPWwqcitoKm4rbztlW2ErdCsxXT1sKmkraCpzK2N9fXN0YXRpYyBhcHBseUludmVyc2VUcmFuc2Zvcm0oZSx0KXtjb25zdCBhPWVbMF0scj1lWzFdLGk9dFswXSp0WzNdLXRbMV0qdFsyXTtlWzBdPShhKnRbM10tcip0WzJdK3RbMl0qdFs1XS10WzRdKnRbM10pL2k7ZVsxXT0oLWEqdFsxXStyKnRbMF0rdFs0XSp0WzFdLXRbNV0qdFswXSkvaX1zdGF0aWMgYXhpYWxBbGlnbmVkQm91bmRpbmdCb3goZSx0LGEpe2NvbnN0IHI9dFswXSxpPXRbMV0sbj10WzJdLHM9dFszXSxvPXRbNF0sYz10WzVdLGw9ZVswXSxoPWVbMV0sdT1lWzJdLGQ9ZVszXTtsZXQgZj1yKmwrbyxnPWYscD1yKnUrbyxtPXAsYj1zKmgrYyx5PWIsdz1zKmQrYyxTPXc7aWYoMCE9PWl8fDAhPT1uKXtjb25zdCBlPWkqbCx0PWkqdSxhPW4qaCxyPW4qZDtmKz1hO20rPWE7cCs9cjtnKz1yO2IrPWU7Uys9ZTt3Kz10O3krPXR9YVswXT1NYXRoLm1pbihhWzBdLGYscCxnLG0pO2FbMV09TWF0aC5taW4oYVsxXSxiLHcseSxTKTthWzJdPU1hdGgubWF4KGFbMl0sZixwLGcsbSk7YVszXT1NYXRoLm1heChhWzNdLGIsdyx5LFMpfXN0YXRpYyBpbnZlcnNlVHJhbnNmb3JtKGUpe2NvbnN0IHQ9ZVswXSplWzNdLWVbMV0qZVsyXTtyZXR1cm5bZVszXS90LC1lWzFdL3QsLWVbMl0vdCxlWzBdL3QsKGVbMl0qZVs1XS1lWzRdKmVbM10pL3QsKGVbNF0qZVsxXS1lWzVdKmVbMF0pL3RdfXN0YXRpYyBzaW5ndWxhclZhbHVlRGVjb21wb3NlMmRTY2FsZShlLHQpe2NvbnN0IGE9ZVswXSxyPWVbMV0saT1lWzJdLG49ZVszXSxzPWEqKjIrcioqMixvPWEqaStyKm4sYz1pKioyK24qKjIsbD0ocytjKS8yLGg9TWF0aC5zcXJ0KGwqKjItKHMqYy1vKioyKSk7dFswXT1NYXRoLnNxcnQobCtofHwxKTt0WzFdPU1hdGguc3FydChsLWh8fDEpfXN0YXRpYyBub3JtYWxpemVSZWN0KGUpe2NvbnN0IHQ9ZS5zbGljZSgwKTtpZihlWzBdPmVbMl0pe3RbMF09ZVsyXTt0WzJdPWVbMF19aWYoZVsxXT5lWzNdKXt0WzFdPWVbM107dFszXT1lWzFdfXJldHVybiB0fXN0YXRpYyBpbnRlcnNlY3QoZSx0KXtjb25zdCBhPU1hdGgubWF4KE1hdGgubWluKGVbMF0sZVsyXSksTWF0aC5taW4odFswXSx0WzJdKSkscj1NYXRoLm1pbihNYXRoLm1heChlWzBdLGVbMl0pLE1hdGgubWF4KHRbMF0sdFsyXSkpO2lmKGE+cilyZXR1cm4gbnVsbDtjb25zdCBpPU1hdGgubWF4KE1hdGgubWluKGVbMV0sZVszXSksTWF0aC5taW4odFsxXSx0WzNdKSksbj1NYXRoLm1pbihNYXRoLm1heChlWzFdLGVbM10pLE1hdGgubWF4KHRbMV0sdFszXSkpO3JldHVybiBpPm4/bnVsbDpbYSxpLHIsbl19c3RhdGljIHBvaW50Qm91bmRpbmdCb3goZSx0LGEpe2FbMF09TWF0aC5taW4oYVswXSxlKTthWzFdPU1hdGgubWluKGFbMV0sdCk7YVsyXT1NYXRoLm1heChhWzJdLGUpO2FbM109TWF0aC5tYXgoYVszXSx0KX1zdGF0aWMgcmVjdEJvdW5kaW5nQm94KGUsdCxhLHIsaSl7aVswXT1NYXRoLm1pbihpWzBdLGUsYSk7aVsxXT1NYXRoLm1pbihpWzFdLHQscik7aVsyXT1NYXRoLm1heChpWzJdLGUsYSk7aVszXT1NYXRoLm1heChpWzNdLHQscil9c3RhdGljI2UoZSx0LGEscixpLG4scyxvLGMsbCl7aWYoYzw9MHx8Yz49MSlyZXR1cm47Y29uc3QgaD0xLWMsdT1jKmMsZD11KmMsZj1oKihoKihoKmUrMypjKnQpKzMqdSphKStkKnIsZz1oKihoKihoKmkrMypjKm4pKzMqdSpzKStkKm87bFswXT1NYXRoLm1pbihsWzBdLGYpO2xbMV09TWF0aC5taW4obFsxXSxnKTtsWzJdPU1hdGgubWF4KGxbMl0sZik7bFszXT1NYXRoLm1heChsWzNdLGcpfXN0YXRpYyN0KGUsdCxhLHIsaSxuLHMsbyxjLGwsaCx1KXtpZihNYXRoLmFicyhjKTwxZS0xMil7TWF0aC5hYnMobCk+PTFlLTEyJiZ0aGlzLiNlKGUsdCxhLHIsaSxuLHMsbywtaC9sLHUpO3JldHVybn1jb25zdCBkPWwqKjItNCpoKmM7aWYoZDwwKXJldHVybjtjb25zdCBmPU1hdGguc3FydChkKSxnPTIqYzt0aGlzLiNlKGUsdCxhLHIsaSxuLHMsbywoLWwrZikvZyx1KTt0aGlzLiNlKGUsdCxhLHIsaSxuLHMsbywoLWwtZikvZyx1KX1zdGF0aWMgYmV6aWVyQm91bmRpbmdCb3goZSx0LGEscixpLG4scyxvLGMpe2NbMF09TWF0aC5taW4oY1swXSxlLHMpO2NbMV09TWF0aC5taW4oY1sxXSx0LG8pO2NbMl09TWF0aC5tYXgoY1syXSxlLHMpO2NbM109TWF0aC5tYXgoY1szXSx0LG8pO3RoaXMuI3QoZSxhLGkscyx0LHIsbixvLDMqKDMqKGEtaSktZStzKSw2KihlLTIqYStpKSwzKihhLWUpLGMpO3RoaXMuI3QoZSxhLGkscyx0LHIsbixvLDMqKDMqKHItbiktdCtvKSw2Kih0LTIqcituKSwzKihyLXQpLGMpfX1jb25zdCBwYT1bMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsNzI4LDcxMSw3MTAsNzI5LDczMyw3MzEsNzMwLDczMiwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCw4MjI2LDgyMjQsODIyNSw4MjMwLDgyMTIsODIxMSw0MDIsODI2MCw4MjQ5LDgyNTAsODcyMiw4MjQwLDgyMjIsODIyMCw4MjIxLDgyMTYsODIxNyw4MjE4LDg0ODIsNjQyNTcsNjQyNTgsMzIxLDMzOCwzNTIsMzc2LDM4MSwzMDUsMzIyLDMzOSwzNTMsMzgyLDAsODM2NF07ZnVuY3Rpb24gc3RyaW5nVG9QREZTdHJpbmcoZSx0PSExKXtpZihlWzBdPj0iw68iKXtsZXQgYTtpZigiw74iPT09ZVswXSYmIsO/Ij09PWVbMV0pe2E9InV0Zi0xNmJlIjtlLmxlbmd0aCUyPT0xJiYoZT1lLnNsaWNlKDAsLTEpKX1lbHNlIGlmKCLDvyI9PT1lWzBdJiYiw74iPT09ZVsxXSl7YT0idXRmLTE2bGUiO2UubGVuZ3RoJTI9PTEmJihlPWUuc2xpY2UoMCwtMSkpfWVsc2Uiw68iPT09ZVswXSYmIsK7Ij09PWVbMV0mJiLCvyI9PT1lWzJdJiYoYT0idXRmLTgiKTtpZihhKXRyeXtjb25zdCByPW5ldyBUZXh0RGVjb2RlcihhLHtmYXRhbDohMH0pLGk9c3RyaW5nVG9CeXRlcyhlKSxuPXIuZGVjb2RlKGkpO3JldHVybiB0fHwhbi5pbmNsdWRlcygiGyIpP246bi5yZXBsYWNlQWxsKC9ceDFiW15ceDFiXSooPzpceDFifCQpL2csIiIpfWNhdGNoKGUpe3dhcm4oYHN0cmluZ1RvUERGU3RyaW5nOiAiJHtlfSIuYCl9fWNvbnN0IGE9W107Zm9yKGxldCByPTAsaT1lLmxlbmd0aDtyPGk7cisrKXtjb25zdCBuPWUuY2hhckNvZGVBdChyKTtpZighdCYmMjc9PT1uKXtmb3IoOysrcjxpJiYyNyE9PWUuY2hhckNvZGVBdChyKTspO2NvbnRpbnVlfWNvbnN0IHM9cGFbbl07YS5wdXNoKHM/U3RyaW5nLmZyb21DaGFyQ29kZShzKTplLmNoYXJBdChyKSl9cmV0dXJuIGEuam9pbigiIil9ZnVuY3Rpb24gc3RyaW5nVG9VVEY4U3RyaW5nKGUpe3JldHVybiBkZWNvZGVVUklDb21wb25lbnQoZXNjYXBlKGUpKX1mdW5jdGlvbiB1dGY4U3RyaW5nVG9TdHJpbmcoZSl7cmV0dXJuIHVuZXNjYXBlKGVuY29kZVVSSUNvbXBvbmVudChlKSl9ZnVuY3Rpb24gaXNBcnJheUVxdWFsKGUsdCl7aWYoZS5sZW5ndGghPT10Lmxlbmd0aClyZXR1cm4hMTtmb3IobGV0IGE9MCxyPWUubGVuZ3RoO2E8cjthKyspaWYoZVthXSE9PXRbYV0pcmV0dXJuITE7cmV0dXJuITB9ZnVuY3Rpb24gZ2V0TW9kaWZpY2F0aW9uRGF0ZShlPW5ldyBEYXRlKXtyZXR1cm5bZS5nZXRVVENGdWxsWWVhcigpLnRvU3RyaW5nKCksKGUuZ2V0VVRDTW9udGgoKSsxKS50b1N0cmluZygpLnBhZFN0YXJ0KDIsIjAiKSxlLmdldFVUQ0RhdGUoKS50b1N0cmluZygpLnBhZFN0YXJ0KDIsIjAiKSxlLmdldFVUQ0hvdXJzKCkudG9TdHJpbmcoKS5wYWRTdGFydCgyLCIwIiksZS5nZXRVVENNaW51dGVzKCkudG9TdHJpbmcoKS5wYWRTdGFydCgyLCIwIiksZS5nZXRVVENTZWNvbmRzKCkudG9TdHJpbmcoKS5wYWRTdGFydCgyLCIwIildLmpvaW4oIiIpfWxldCBtYT1udWxsLGJhPW51bGw7ZnVuY3Rpb24gTWF0aENsYW1wKGUsdCxhKXtyZXR1cm4gTWF0aC5taW4oTWF0aC5tYXgoZSx0KSxhKX1mdW5jdGlvbiB0b0hleFV0aWwoZSl7cmV0dXJuIFVpbnQ4QXJyYXkucHJvdG90eXBlLnRvSGV4P2UudG9IZXgoKTpBcnJheS5mcm9tKGUsKGU9PmdhW2VdKSkuam9pbigiIil9ImZ1bmN0aW9uIiE9dHlwZW9mIFByb21pc2UudHJ5JiYoUHJvbWlzZS50cnk9ZnVuY3Rpb24oZSwuLi50KXtyZXR1cm4gbmV3IFByb21pc2UoKGE9PnthKGUoLi4udCkpfSkpfSk7ImZ1bmN0aW9uIiE9dHlwZW9mIE1hdGguc3VtUHJlY2lzZSYmKE1hdGguc3VtUHJlY2lzZT1mdW5jdGlvbihlKXtyZXR1cm4gZS5yZWR1Y2UoKChlLHQpPT5lK3QpLDApfSk7Y29uc3QgeWE9U3ltYm9sKCJDSVJDVUxBUl9SRUYiKSx3YT1TeW1ib2woIkVPRiIpO2xldCBTYT1PYmplY3QuY3JlYXRlKG51bGwpLHhhPU9iamVjdC5jcmVhdGUobnVsbCksQWE9T2JqZWN0LmNyZWF0ZShudWxsKTtjbGFzcyBOYW1le2NvbnN0cnVjdG9yKGUpe3RoaXMubmFtZT1lfXN0YXRpYyBnZXQoZSl7cmV0dXJuIHhhW2VdfHw9bmV3IE5hbWUoZSl9fWNsYXNzIENtZHtjb25zdHJ1Y3RvcihlKXt0aGlzLmNtZD1lfXN0YXRpYyBnZXQoZSl7cmV0dXJuIFNhW2VdfHw9bmV3IENtZChlKX19Y29uc3Qga2E9ZnVuY3Rpb24gbm9uU2VyaWFsaXphYmxlQ2xvc3VyZSgpe3JldHVybiBrYX07Y2xhc3MgRGljdHtjb25zdHJ1Y3RvcihlPW51bGwpe3RoaXMuX21hcD1uZXcgTWFwO3RoaXMueHJlZj1lO3RoaXMub2JqSWQ9bnVsbDt0aGlzLnN1cHByZXNzRW5jcnlwdGlvbj0hMTt0aGlzLl9fbm9uU2VyaWFsaXphYmxlX189a2F9YXNzaWduWHJlZihlKXt0aGlzLnhyZWY9ZX1nZXQgc2l6ZSgpe3JldHVybiB0aGlzLl9tYXAuc2l6ZX1nZXQoZSx0LGEpe2xldCByPXRoaXMuX21hcC5nZXQoZSk7aWYodm9pZCAwPT09ciYmdm9pZCAwIT09dCl7cj10aGlzLl9tYXAuZ2V0KHQpO3ZvaWQgMD09PXImJnZvaWQgMCE9PWEmJihyPXRoaXMuX21hcC5nZXQoYSkpfXJldHVybiByIGluc3RhbmNlb2YgUmVmJiZ0aGlzLnhyZWY/dGhpcy54cmVmLmZldGNoKHIsdGhpcy5zdXBwcmVzc0VuY3J5cHRpb24pOnJ9YXN5bmMgZ2V0QXN5bmMoZSx0LGEpe2xldCByPXRoaXMuX21hcC5nZXQoZSk7aWYodm9pZCAwPT09ciYmdm9pZCAwIT09dCl7cj10aGlzLl9tYXAuZ2V0KHQpO3ZvaWQgMD09PXImJnZvaWQgMCE9PWEmJihyPXRoaXMuX21hcC5nZXQoYSkpfXJldHVybiByIGluc3RhbmNlb2YgUmVmJiZ0aGlzLnhyZWY/dGhpcy54cmVmLmZldGNoQXN5bmMocix0aGlzLnN1cHByZXNzRW5jcnlwdGlvbik6cn1nZXRBcnJheShlLHQsYSl7bGV0IHI9dGhpcy5fbWFwLmdldChlKTtpZih2b2lkIDA9PT1yJiZ2b2lkIDAhPT10KXtyPXRoaXMuX21hcC5nZXQodCk7dm9pZCAwPT09ciYmdm9pZCAwIT09YSYmKHI9dGhpcy5fbWFwLmdldChhKSl9ciBpbnN0YW5jZW9mIFJlZiYmdGhpcy54cmVmJiYocj10aGlzLnhyZWYuZmV0Y2gocix0aGlzLnN1cHByZXNzRW5jcnlwdGlvbikpO2lmKEFycmF5LmlzQXJyYXkocikpe3I9ci5zbGljZSgpO2ZvcihsZXQgZT0wLHQ9ci5sZW5ndGg7ZTx0O2UrKylyW2VdaW5zdGFuY2VvZiBSZWYmJnRoaXMueHJlZiYmKHJbZV09dGhpcy54cmVmLmZldGNoKHJbZV0sdGhpcy5zdXBwcmVzc0VuY3J5cHRpb24pKX1yZXR1cm4gcn1nZXRSYXcoZSl7cmV0dXJuIHRoaXMuX21hcC5nZXQoZSl9Z2V0S2V5cygpe3JldHVyblsuLi50aGlzLl9tYXAua2V5cygpXX1nZXRSYXdWYWx1ZXMoKXtyZXR1cm5bLi4udGhpcy5fbWFwLnZhbHVlcygpXX1zZXQoZSx0KXt0aGlzLl9tYXAuc2V0KGUsdCl9aGFzKGUpe3JldHVybiB0aGlzLl9tYXAuaGFzKGUpfSpbU3ltYm9sLml0ZXJhdG9yXSgpe2Zvcihjb25zdFtlLHRdb2YgdGhpcy5fbWFwKXlpZWxkW2UsdCBpbnN0YW5jZW9mIFJlZiYmdGhpcy54cmVmP3RoaXMueHJlZi5mZXRjaCh0LHRoaXMuc3VwcHJlc3NFbmNyeXB0aW9uKTp0XX1zdGF0aWMgZ2V0IGVtcHR5KCl7Y29uc3QgZT1uZXcgRGljdChudWxsKTtlLnNldD0oZSx0KT0+e3VucmVhY2hhYmxlKCJTaG91bGQgbm90IGNhbGwgYHNldGAgb24gdGhlIGVtcHR5IGRpY3Rpb25hcnkuIil9O3JldHVybiBzaGFkb3codGhpcywiZW1wdHkiLGUpfXN0YXRpYyBtZXJnZSh7eHJlZjplLGRpY3RBcnJheTp0LG1lcmdlU3ViRGljdHM6YT0hMX0pe2NvbnN0IHI9bmV3IERpY3QoZSksaT1uZXcgTWFwO2Zvcihjb25zdCBlIG9mIHQpaWYoZSBpbnN0YW5jZW9mIERpY3QpZm9yKGNvbnN0W3Qscl1vZiBlLl9tYXApe2xldCBlPWkuZ2V0KHQpO2lmKHZvaWQgMD09PWUpe2U9W107aS5zZXQodCxlKX1lbHNlIGlmKCEoYSYmciBpbnN0YW5jZW9mIERpY3QpKWNvbnRpbnVlO2UucHVzaChyKX1mb3IoY29uc3RbdCxhXW9mIGkpe2lmKDE9PT1hLmxlbmd0aHx8IShhWzBdaW5zdGFuY2VvZiBEaWN0KSl7ci5fbWFwLnNldCh0LGFbMF0pO2NvbnRpbnVlfWNvbnN0IGk9bmV3IERpY3QoZSk7Zm9yKGNvbnN0IGUgb2YgYSlmb3IoY29uc3RbdCxhXW9mIGUuX21hcClpLl9tYXAuaGFzKHQpfHxpLl9tYXAuc2V0KHQsYSk7aS5zaXplPjAmJnIuX21hcC5zZXQodCxpKX1pLmNsZWFyKCk7cmV0dXJuIHIuc2l6ZT4wP3I6RGljdC5lbXB0eX1jbG9uZSgpe2NvbnN0IGU9bmV3IERpY3QodGhpcy54cmVmKTtmb3IoY29uc3QgdCBvZiB0aGlzLmdldEtleXMoKSllLnNldCh0LHRoaXMuZ2V0UmF3KHQpKTtyZXR1cm4gZX1kZWxldGUoZSl7ZGVsZXRlIHRoaXMuX21hcFtlXX19Y2xhc3MgUmVme2NvbnN0cnVjdG9yKGUsdCl7dGhpcy5udW09ZTt0aGlzLmdlbj10fXRvU3RyaW5nKCl7cmV0dXJuIDA9PT10aGlzLmdlbj9gJHt0aGlzLm51bX1SYDpgJHt0aGlzLm51bX1SJHt0aGlzLmdlbn1gfXN0YXRpYyBmcm9tU3RyaW5nKGUpe2NvbnN0IHQ9QWFbZV07aWYodClyZXR1cm4gdDtjb25zdCBhPS9eKFxkKylSKFxkKikkLy5leGVjKGUpO3JldHVybiBhJiYiMCIhPT1hWzFdP0FhW2VdPW5ldyBSZWYocGFyc2VJbnQoYVsxXSksYVsyXT9wYXJzZUludChhWzJdKTowKTpudWxsfXN0YXRpYyBnZXQoZSx0KXtjb25zdCBhPTA9PT10P2Ake2V9UmA6YCR7ZX1SJHt0fWA7cmV0dXJuIEFhW2FdfHw9bmV3IFJlZihlLHQpfX1jbGFzcyBSZWZTZXR7Y29uc3RydWN0b3IoZT1udWxsKXt0aGlzLl9zZXQ9bmV3IFNldChlPy5fc2V0KX1oYXMoZSl7cmV0dXJuIHRoaXMuX3NldC5oYXMoZS50b1N0cmluZygpKX1wdXQoZSl7dGhpcy5fc2V0LmFkZChlLnRvU3RyaW5nKCkpfXJlbW92ZShlKXt0aGlzLl9zZXQuZGVsZXRlKGUudG9TdHJpbmcoKSl9W1N5bWJvbC5pdGVyYXRvcl0oKXtyZXR1cm4gdGhpcy5fc2V0LnZhbHVlcygpfWNsZWFyKCl7dGhpcy5fc2V0LmNsZWFyKCl9fWNsYXNzIFJlZlNldENhY2hle2NvbnN0cnVjdG9yKCl7dGhpcy5fbWFwPW5ldyBNYXB9Z2V0IHNpemUoKXtyZXR1cm4gdGhpcy5fbWFwLnNpemV9Z2V0KGUpe3JldHVybiB0aGlzLl9tYXAuZ2V0KGUudG9TdHJpbmcoKSl9aGFzKGUpe3JldHVybiB0aGlzLl9tYXAuaGFzKGUudG9TdHJpbmcoKSl9cHV0KGUsdCl7dGhpcy5fbWFwLnNldChlLnRvU3RyaW5nKCksdCl9cHV0QWxpYXMoZSx0KXt0aGlzLl9tYXAuc2V0KGUudG9TdHJpbmcoKSx0aGlzLmdldCh0KSl9W1N5bWJvbC5pdGVyYXRvcl0oKXtyZXR1cm4gdGhpcy5fbWFwLnZhbHVlcygpfWNsZWFyKCl7dGhpcy5fbWFwLmNsZWFyKCl9KnZhbHVlcygpe3lpZWxkKnRoaXMuX21hcC52YWx1ZXMoKX0qaXRlbXMoKXtmb3IoY29uc3RbZSx0XW9mIHRoaXMuX21hcCl5aWVsZFtSZWYuZnJvbVN0cmluZyhlKSx0XX19ZnVuY3Rpb24gaXNOYW1lKGUsdCl7cmV0dXJuIGUgaW5zdGFuY2VvZiBOYW1lJiYodm9pZCAwPT09dHx8ZS5uYW1lPT09dCl9ZnVuY3Rpb24gaXNDbWQoZSx0KXtyZXR1cm4gZSBpbnN0YW5jZW9mIENtZCYmKHZvaWQgMD09PXR8fGUuY21kPT09dCl9ZnVuY3Rpb24gaXNEaWN0KGUsdCl7cmV0dXJuIGUgaW5zdGFuY2VvZiBEaWN0JiYodm9pZCAwPT09dHx8aXNOYW1lKGUuZ2V0KCJUeXBlIiksdCkpfWZ1bmN0aW9uIGlzUmVmc0VxdWFsKGUsdCl7cmV0dXJuIGUubnVtPT09dC5udW0mJmUuZ2VuPT09dC5nZW59Y2xhc3MgQmFzZVN0cmVhbXtnZXQgbGVuZ3RoKCl7dW5yZWFjaGFibGUoIkFic3RyYWN0IGdldHRlciBgbGVuZ3RoYCBhY2Nlc3NlZCIpfWdldCBpc0VtcHR5KCl7dW5yZWFjaGFibGUoIkFic3RyYWN0IGdldHRlciBgaXNFbXB0eWAgYWNjZXNzZWQiKX1nZXQgaXNEYXRhTG9hZGVkKCl7cmV0dXJuIHNoYWRvdyh0aGlzLCJpc0RhdGFMb2FkZWQiLCEwKX1nZXRCeXRlKCl7dW5yZWFjaGFibGUoIkFic3RyYWN0IG1ldGhvZCBgZ2V0Qnl0ZWAgY2FsbGVkIil9Z2V0Qnl0ZXMoZSl7dW5yZWFjaGFibGUoIkFic3RyYWN0IG1ldGhvZCBgZ2V0Qnl0ZXNgIGNhbGxlZCIpfWFzeW5jIGdldEltYWdlRGF0YShlLHQpe3JldHVybiB0aGlzLmdldEJ5dGVzKGUsdCl9YXN5bmMgYXN5bmNHZXRCeXRlcygpe3VucmVhY2hhYmxlKCJBYnN0cmFjdCBtZXRob2QgYGFzeW5jR2V0Qnl0ZXNgIGNhbGxlZCIpfWdldCBpc0FzeW5jKCl7cmV0dXJuITF9Z2V0IGlzQXN5bmNEZWNvZGVyKCl7cmV0dXJuITF9Z2V0IGNhbkFzeW5jRGVjb2RlSW1hZ2VGcm9tQnVmZmVyKCl7cmV0dXJuITF9YXN5bmMgZ2V0VHJhbnNmZXJhYmxlSW1hZ2UoKXtyZXR1cm4gbnVsbH1wZWVrQnl0ZSgpe2NvbnN0IGU9dGhpcy5nZXRCeXRlKCk7LTEhPT1lJiZ0aGlzLnBvcy0tO3JldHVybiBlfXBlZWtCeXRlcyhlKXtjb25zdCB0PXRoaXMuZ2V0Qnl0ZXMoZSk7dGhpcy5wb3MtPXQubGVuZ3RoO3JldHVybiB0fWdldFVpbnQxNigpe2NvbnN0IGU9dGhpcy5nZXRCeXRlKCksdD10aGlzLmdldEJ5dGUoKTtyZXR1cm4tMT09PWV8fC0xPT09dD8tMTooZTw8OCkrdH1nZXRJbnQzMigpe3JldHVybih0aGlzLmdldEJ5dGUoKTw8MjQpKyh0aGlzLmdldEJ5dGUoKTw8MTYpKyh0aGlzLmdldEJ5dGUoKTw8OCkrdGhpcy5nZXRCeXRlKCl9Z2V0Qnl0ZVJhbmdlKGUsdCl7dW5yZWFjaGFibGUoIkFic3RyYWN0IG1ldGhvZCBgZ2V0Qnl0ZVJhbmdlYCBjYWxsZWQiKX1nZXRTdHJpbmcoZSl7cmV0dXJuIGJ5dGVzVG9TdHJpbmcodGhpcy5nZXRCeXRlcyhlKSl9c2tpcChlKXt0aGlzLnBvcys9ZXx8MX1yZXNldCgpe3VucmVhY2hhYmxlKCJBYnN0cmFjdCBtZXRob2QgYHJlc2V0YCBjYWxsZWQiKX1tb3ZlU3RhcnQoKXt1bnJlYWNoYWJsZSgiQWJzdHJhY3QgbWV0aG9kIGBtb3ZlU3RhcnRgIGNhbGxlZCIpfW1ha2VTdWJTdHJlYW0oZSx0LGE9bnVsbCl7dW5yZWFjaGFibGUoIkFic3RyYWN0IG1ldGhvZCBgbWFrZVN1YlN0cmVhbWAgY2FsbGVkIil9Z2V0QmFzZVN0cmVhbXMoKXtyZXR1cm4gbnVsbH19Y29uc3QgQ2E9L15bMS05XVwuXGQkLyx2YT0yKiozMS0xLEZhPVsxLDAsMCwxLDAsMF0sSWE9WyJDb2xvclNwYWNlIiwiRXh0R1N0YXRlIiwiRm9udCIsIlBhdHRlcm4iLCJQcm9wZXJ0aWVzIiwiU2hhZGluZyIsIlhPYmplY3QiXSxPYT1bIkV4dEdTdGF0ZSIsIkZvbnQiLCJQcm9wZXJ0aWVzIiwiWE9iamVjdCJdO2Z1bmN0aW9uIGdldExvb2t1cFRhYmxlRmFjdG9yeShlKXtsZXQgdDtyZXR1cm4gZnVuY3Rpb24oKXtpZihlKXt0PU9iamVjdC5jcmVhdGUobnVsbCk7ZSh0KTtlPW51bGx9cmV0dXJuIHR9fWNsYXNzIE1pc3NpbmdEYXRhRXhjZXB0aW9uIGV4dGVuZHMgZmF7Y29uc3RydWN0b3IoZSx0KXtzdXBlcihgTWlzc2luZyBkYXRhIFske2V9LCAke3R9KWAsIk1pc3NpbmdEYXRhRXhjZXB0aW9uIik7dGhpcy5iZWdpbj1lO3RoaXMuZW5kPXR9fWNsYXNzIFBhcnNlckVPRkV4Y2VwdGlvbiBleHRlbmRzIGZhe2NvbnN0cnVjdG9yKGUpe3N1cGVyKGUsIlBhcnNlckVPRkV4Y2VwdGlvbiIpfX1jbGFzcyBYUmVmRW50cnlFeGNlcHRpb24gZXh0ZW5kcyBmYXtjb25zdHJ1Y3RvcihlKXtzdXBlcihlLCJYUmVmRW50cnlFeGNlcHRpb24iKX19Y2xhc3MgWFJlZlBhcnNlRXhjZXB0aW9uIGV4dGVuZHMgZmF7Y29uc3RydWN0b3IoZSl7c3VwZXIoZSwiWFJlZlBhcnNlRXhjZXB0aW9uIil9fWZ1bmN0aW9uIGFycmF5QnVmZmVyc1RvQnl0ZXMoZSl7Y29uc3QgdD1lLmxlbmd0aDtpZigwPT09dClyZXR1cm4gbmV3IFVpbnQ4QXJyYXkoMCk7aWYoMT09PXQpcmV0dXJuIG5ldyBVaW50OEFycmF5KGVbMF0pO2xldCBhPTA7Zm9yKGxldCByPTA7cjx0O3IrKylhKz1lW3JdLmJ5dGVMZW5ndGg7Y29uc3Qgcj1uZXcgVWludDhBcnJheShhKTtsZXQgaT0wO2ZvcihsZXQgYT0wO2E8dDthKyspe2NvbnN0IHQ9bmV3IFVpbnQ4QXJyYXkoZVthXSk7ci5zZXQodCxpKTtpKz10LmJ5dGVMZW5ndGh9cmV0dXJuIHJ9YXN5bmMgZnVuY3Rpb24gZmV0Y2hCaW5hcnlEYXRhKGUpe2NvbnN0IHQ9YXdhaXQgZmV0Y2goZSk7aWYoIXQub2spdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gZmV0Y2ggZmlsZSAiJHtlfSIgd2l0aCAiJHt0LnN0YXR1c1RleHR9Ii5gKTtyZXR1cm4gbmV3IFVpbnQ4QXJyYXkoYXdhaXQgdC5hcnJheUJ1ZmZlcigpKX1mdW5jdGlvbiBnZXRJbmhlcml0YWJsZVByb3BlcnR5KHtkaWN0OmUsa2V5OnQsZ2V0QXJyYXk6YT0hMSxzdG9wV2hlbkZvdW5kOnI9ITB9KXtsZXQgaTtjb25zdCBuPW5ldyBSZWZTZXQ7Zm9yKDtlIGluc3RhbmNlb2YgRGljdCYmKCFlLm9iaklkfHwhbi5oYXMoZS5vYmpJZCkpOyl7ZS5vYmpJZCYmbi5wdXQoZS5vYmpJZCk7Y29uc3Qgcz1hP2UuZ2V0QXJyYXkodCk6ZS5nZXQodCk7aWYodm9pZCAwIT09cyl7aWYocilyZXR1cm4gczsoaXx8PVtdKS5wdXNoKHMpfWU9ZS5nZXQoIlBhcmVudCIpfXJldHVybiBpfWNvbnN0IFRhPVsiIiwiQyIsIkNDIiwiQ0NDIiwiQ0QiLCJEIiwiREMiLCJEQ0MiLCJEQ0NDIiwiQ00iLCIiLCJYIiwiWFgiLCJYWFgiLCJYTCIsIkwiLCJMWCIsIkxYWCIsIkxYWFgiLCJYQyIsIiIsIkkiLCJJSSIsIklJSSIsIklWIiwiViIsIlZJIiwiVklJIiwiVklJSSIsIklYIl07ZnVuY3Rpb24gdG9Sb21hbk51bWVyYWxzKGUsdD0hMSl7YXNzZXJ0KE51bWJlci5pc0ludGVnZXIoZSkmJmU+MCwiVGhlIG51bWJlciBzaG91bGQgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyLiIpO2NvbnN0IGE9Ik0iLnJlcGVhdChlLzFlM3wwKStUYVtlJTFlMy8xMDB8MF0rVGFbMTArKGUlMTAwLzEwfDApXStUYVsyMCtlJTEwXTtyZXR1cm4gdD9hLnRvTG93ZXJDYXNlKCk6YX1mdW5jdGlvbiBsb2cyKGUpe3JldHVybiBlPjA/TWF0aC5jZWlsKE1hdGgubG9nMihlKSk6MH1mdW5jdGlvbiByZWFkSW50OChlLHQpe3JldHVybiBlW3RdPDwyND4+MjR9ZnVuY3Rpb24gcmVhZEludDE2KGUsdCl7cmV0dXJuKGVbdF08PDI0fGVbdCsxXTw8MTYpPj4xNn1mdW5jdGlvbiByZWFkVWludDE2KGUsdCl7cmV0dXJuIGVbdF08PDh8ZVt0KzFdfWZ1bmN0aW9uIHJlYWRVaW50MzIoZSx0KXtyZXR1cm4oZVt0XTw8MjR8ZVt0KzFdPDwxNnxlW3QrMl08PDh8ZVt0KzNdKT4+PjB9ZnVuY3Rpb24gaXNXaGl0ZVNwYWNlKGUpe3JldHVybiAzMj09PWV8fDk9PT1lfHwxMz09PWV8fDEwPT09ZX1mdW5jdGlvbiBpc051bWJlckFycmF5KGUsdCl7cmV0dXJuIEFycmF5LmlzQXJyYXkoZSk/KG51bGw9PT10fHxlLmxlbmd0aD09PXQpJiZlLmV2ZXJ5KChlPT4ibnVtYmVyIj09dHlwZW9mIGUpKTpBcnJheUJ1ZmZlci5pc1ZpZXcoZSkmJiEoZSBpbnN0YW5jZW9mIEJpZ0ludDY0QXJyYXl8fGUgaW5zdGFuY2VvZiBCaWdVaW50NjRBcnJheSkmJihudWxsPT09dHx8ZS5sZW5ndGg9PT10KX1mdW5jdGlvbiBsb29rdXBNYXRyaXgoZSx0KXtyZXR1cm4gaXNOdW1iZXJBcnJheShlLDYpP2U6dH1mdW5jdGlvbiBsb29rdXBSZWN0KGUsdCl7cmV0dXJuIGlzTnVtYmVyQXJyYXkoZSw0KT9lOnR9ZnVuY3Rpb24gbG9va3VwTm9ybWFsUmVjdChlLHQpe3JldHVybiBpc051bWJlckFycmF5KGUsNCk/VXRpbC5ub3JtYWxpemVSZWN0KGUpOnR9ZnVuY3Rpb24gcGFyc2VYRkFQYXRoKGUpe2NvbnN0IHQ9LyguKylcWyhcZCspXF0kLztyZXR1cm4gZS5zcGxpdCgiLiIpLm1hcCgoZT0+e2NvbnN0IGE9ZS5tYXRjaCh0KTtyZXR1cm4gYT97bmFtZTphWzFdLHBvczpwYXJzZUludChhWzJdLDEwKX06e25hbWU6ZSxwb3M6MH19KSl9ZnVuY3Rpb24gZXNjYXBlUERGTmFtZShlKXtjb25zdCB0PVtdO2xldCBhPTA7Zm9yKGxldCByPTAsaT1lLmxlbmd0aDtyPGk7cisrKXtjb25zdCBpPWUuY2hhckNvZGVBdChyKTtpZihpPDMzfHxpPjEyNnx8MzU9PT1pfHw0MD09PWl8fDQxPT09aXx8NjA9PT1pfHw2Mj09PWl8fDkxPT09aXx8OTM9PT1pfHwxMjM9PT1pfHwxMjU9PT1pfHw0Nz09PWl8fDM3PT09aSl7YTxyJiZ0LnB1c2goZS5zdWJzdHJpbmcoYSxyKSk7dC5wdXNoKGAjJHtpLnRvU3RyaW5nKDE2KX1gKTthPXIrMX19aWYoMD09PXQubGVuZ3RoKXJldHVybiBlO2E8ZS5sZW5ndGgmJnQucHVzaChlLnN1YnN0cmluZyhhLGUubGVuZ3RoKSk7cmV0dXJuIHQuam9pbigiIil9ZnVuY3Rpb24gZXNjYXBlU3RyaW5nKGUpe3JldHVybiBlLnJlcGxhY2VBbGwoLyhbKClcXFxuXHJdKS9nLChlPT4iXG4iPT09ZT8iXFxuIjoiXHIiPT09ZT8iXFxyIjpgXFwke2V9YCkpfWZ1bmN0aW9uIF9jb2xsZWN0SlMoZSx0LGEscil7aWYoIWUpcmV0dXJuO2xldCBpPW51bGw7aWYoZSBpbnN0YW5jZW9mIFJlZil7aWYoci5oYXMoZSkpcmV0dXJuO2k9ZTtyLnB1dChpKTtlPXQuZmV0Y2goZSl9aWYoQXJyYXkuaXNBcnJheShlKSlmb3IoY29uc3QgaSBvZiBlKV9jb2xsZWN0SlMoaSx0LGEscik7ZWxzZSBpZihlIGluc3RhbmNlb2YgRGljdCl7aWYoaXNOYW1lKGUuZ2V0KCJTIiksIkphdmFTY3JpcHQiKSl7Y29uc3QgdD1lLmdldCgiSlMiKTtsZXQgcjt0IGluc3RhbmNlb2YgQmFzZVN0cmVhbT9yPXQuZ2V0U3RyaW5nKCk6InN0cmluZyI9PXR5cGVvZiB0JiYocj10KTtyJiY9c3RyaW5nVG9QREZTdHJpbmcociwhMCkucmVwbGFjZUFsbCgiXDAiLCIiKTtyJiZhLnB1c2gocil9X2NvbGxlY3RKUyhlLmdldFJhdygiTmV4dCIpLHQsYSxy