(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["vendors~fullcalendar"],{ /***/ "./node_modules/@fullcalendar/core/locales/fr.js": /*!*******************************************************!*\ !*** ./node_modules/@fullcalendar/core/locales/fr.js ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { (function (global, factory) { true ? module.exports = factory() : undefined; }(this, function () { 'use strict'; var fr = { code: "fr", week: { dow: 1, doy: 4 // The week that contains Jan 4th is the first week of the year. }, buttonText: { prev: "Précédent", next: "Suivant", today: "Aujourd'hui", year: "Année", month: "Mois", week: "Semaine", day: "Jour", list: "Planning" }, weekLabel: "Sem.", allDayHtml: "Toute la
journée", eventLimitText: "en plus", noEventsMessage: "Aucun événement à afficher" }; return fr; })); /***/ }), /***/ "./node_modules/@fullcalendar/core/main.css": /*!**************************************************!*\ !*** ./node_modules/@fullcalendar/core/main.css ***! \**************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { // extracted by mini-css-extract-plugin /***/ }), /***/ "./node_modules/@fullcalendar/core/main.esm.js": /*!*****************************************************!*\ !*** ./node_modules/@fullcalendar/core/main.esm.js ***! \*****************************************************/ /*! exports provided: Calendar, Component, ComponentContext, DateComponent, DateEnv, DateProfileGenerator, DayHeader, DaySeries, DayTable, ElementDragging, ElementScrollController, EmitterMixin, EventApi, FgEventRenderer, FillRenderer, Interaction, Mixin, NamedTimeZoneImpl, PositionCache, ScrollComponent, ScrollController, Slicer, Splitter, Theme, View, WindowScrollController, addDays, addDurations, addMs, addWeeks, allowContextMenu, allowSelection, appendToElement, applyAll, applyMutationToEventStore, applyStyle, applyStyleProp, asRoughMinutes, asRoughMs, asRoughSeconds, buildGotoAnchorHtml, buildSegCompareObj, capitaliseFirstLetter, combineEventUis, compareByFieldSpec, compareByFieldSpecs, compareNumbers, compensateScroll, computeClippingRect, computeEdges, computeEventDraggable, computeEventEndResizable, computeEventStartResizable, computeFallbackHeaderFormat, computeHeightAndMargins, computeInnerRect, computeRect, computeVisibleDayRange, config, constrainPoint, createDuration, createElement, createEmptyEventStore, createEventInstance, createFormatter, createPlugin, cssToStr, debounce, diffDates, diffDayAndTime, diffDays, diffPoints, diffWeeks, diffWholeDays, diffWholeWeeks, disableCursor, distributeHeight, elementClosest, elementMatches, enableCursor, eventTupleToStore, filterEventStoreDefs, filterHash, findChildren, findElements, flexibleCompare, forceClassName, formatDate, formatIsoTimeString, formatRange, getAllDayHtml, getClippingParents, getDayClasses, getElSeg, getRectCenter, getRelevantEvents, globalDefaults, greatestDurationDenominator, hasBgRendering, htmlEscape, htmlToElement, insertAfterElement, interactionSettingsStore, interactionSettingsToStore, intersectRanges, intersectRects, isArraysEqual, isDateSpansEqual, isInt, isInteractionValid, isMultiDayRange, isPropsEqual, isPropsValid, isSingleDay, isValidDate, listenBySelector, mapHash, matchCellWidths, memoize, memoizeOutput, memoizeRendering, mergeEventStores, multiplyDuration, padStart, parseBusinessHours, parseDragMeta, parseEventDef, parseFieldSpecs, parseMarker, pointInsideRect, prependToElement, preventContextMenu, preventDefault, preventSelection, processScopedUiProps, rangeContainsMarker, rangeContainsRange, rangesEqual, rangesIntersect, refineProps, removeElement, removeExact, renderDateCell, requestJson, sliceEventStore, startOfDay, subtractInnerElHeight, translateRect, uncompensateScroll, undistributeHeight, unpromisify, version, whenTransitionDone, wholeDivideDurations */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Calendar", function() { return Calendar; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Component", function() { return Component; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ComponentContext", function() { return ComponentContext; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DateComponent", function() { return DateComponent; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DateEnv", function() { return DateEnv; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DateProfileGenerator", function() { return DateProfileGenerator; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DayHeader", function() { return DayHeader; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DaySeries", function() { return DaySeries; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DayTable", function() { return DayTable; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ElementDragging", function() { return ElementDragging; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ElementScrollController", function() { return ElementScrollController; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EmitterMixin", function() { return EmitterMixin; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EventApi", function() { return EventApi; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FgEventRenderer", function() { return FgEventRenderer; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FillRenderer", function() { return FillRenderer; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Interaction", function() { return Interaction; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Mixin", function() { return Mixin; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NamedTimeZoneImpl", function() { return NamedTimeZoneImpl; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PositionCache", function() { return PositionCache; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ScrollComponent", function() { return ScrollComponent; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ScrollController", function() { return ScrollController; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Slicer", function() { return Slicer; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Splitter", function() { return Splitter; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Theme", function() { return Theme; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "View", function() { return View; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WindowScrollController", function() { return WindowScrollController; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "addDays", function() { return addDays; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "addDurations", function() { return addDurations; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "addMs", function() { return addMs; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "addWeeks", function() { return addWeeks; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "allowContextMenu", function() { return allowContextMenu; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "allowSelection", function() { return allowSelection; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "appendToElement", function() { return appendToElement; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "applyAll", function() { return applyAll; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "applyMutationToEventStore", function() { return applyMutationToEventStore; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "applyStyle", function() { return applyStyle; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "applyStyleProp", function() { return applyStyleProp; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "asRoughMinutes", function() { return asRoughMinutes; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "asRoughMs", function() { return asRoughMs; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "asRoughSeconds", function() { return asRoughSeconds; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildGotoAnchorHtml", function() { return buildGotoAnchorHtml; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildSegCompareObj", function() { return buildSegCompareObj; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "capitaliseFirstLetter", function() { return capitaliseFirstLetter; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "combineEventUis", function() { return combineEventUis; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "compareByFieldSpec", function() { return compareByFieldSpec; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "compareByFieldSpecs", function() { return compareByFieldSpecs; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "compareNumbers", function() { return compareNumbers; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "compensateScroll", function() { return compensateScroll; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "computeClippingRect", function() { return computeClippingRect; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "computeEdges", function() { return computeEdges; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "computeEventDraggable", function() { return computeEventDraggable; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "computeEventEndResizable", function() { return computeEventEndResizable; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "computeEventStartResizable", function() { return computeEventStartResizable; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "computeFallbackHeaderFormat", function() { return computeFallbackHeaderFormat; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "computeHeightAndMargins", function() { return computeHeightAndMargins; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "computeInnerRect", function() { return computeInnerRect; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "computeRect", function() { return computeRect; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "computeVisibleDayRange", function() { return computeVisibleDayRange; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "config", function() { return config; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "constrainPoint", function() { return constrainPoint; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createDuration", function() { return createDuration; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createElement", function() { return createElement; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createEmptyEventStore", function() { return createEmptyEventStore; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createEventInstance", function() { return createEventInstance; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createFormatter", function() { return createFormatter; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createPlugin", function() { return createPlugin; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "cssToStr", function() { return cssToStr; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "debounce", function() { return debounce; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "diffDates", function() { return diffDates; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "diffDayAndTime", function() { return diffDayAndTime; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "diffDays", function() { return diffDays; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "diffPoints", function() { return diffPoints; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "diffWeeks", function() { return diffWeeks; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "diffWholeDays", function() { return diffWholeDays; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "diffWholeWeeks", function() { return diffWholeWeeks; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "disableCursor", function() { return disableCursor; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "distributeHeight", function() { return distributeHeight; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "elementClosest", function() { return elementClosest; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "elementMatches", function() { return elementMatches; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "enableCursor", function() { return enableCursor; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "eventTupleToStore", function() { return eventTupleToStore; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "filterEventStoreDefs", function() { return filterEventStoreDefs; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "filterHash", function() { return filterHash; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "findChildren", function() { return findChildren; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "findElements", function() { return findElements; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "flexibleCompare", function() { return flexibleCompare; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "forceClassName", function() { return forceClassName; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "formatDate", function() { return formatDate; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "formatIsoTimeString", function() { return formatIsoTimeString; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "formatRange", function() { return formatRange; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getAllDayHtml", function() { return getAllDayHtml; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getClippingParents", function() { return getClippingParents; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getDayClasses", function() { return getDayClasses; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getElSeg", function() { return getElSeg; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getRectCenter", function() { return getRectCenter; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getRelevantEvents", function() { return getRelevantEvents; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "globalDefaults", function() { return globalDefaults; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "greatestDurationDenominator", function() { return greatestDurationDenominator; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hasBgRendering", function() { return hasBgRendering; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "htmlEscape", function() { return htmlEscape; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "htmlToElement", function() { return htmlToElement; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "insertAfterElement", function() { return insertAfterElement; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "interactionSettingsStore", function() { return interactionSettingsStore; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "interactionSettingsToStore", function() { return interactionSettingsToStore; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "intersectRanges", function() { return intersectRanges; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "intersectRects", function() { return intersectRects; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isArraysEqual", function() { return isArraysEqual; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isDateSpansEqual", function() { return isDateSpansEqual; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isInt", function() { return isInt; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isInteractionValid", function() { return isInteractionValid; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isMultiDayRange", function() { return isMultiDayRange; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isPropsEqual", function() { return isPropsEqual; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isPropsValid", function() { return isPropsValid; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isSingleDay", function() { return isSingleDay; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isValidDate", function() { return isValidDate; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "listenBySelector", function() { return listenBySelector; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mapHash", function() { return mapHash; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "matchCellWidths", function() { return matchCellWidths; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "memoize", function() { return memoize; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "memoizeOutput", function() { return memoizeOutput; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "memoizeRendering", function() { return memoizeRendering; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mergeEventStores", function() { return mergeEventStores; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiplyDuration", function() { return multiplyDuration; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "padStart", function() { return padStart; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "parseBusinessHours", function() { return parseBusinessHours; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "parseDragMeta", function() { return parseDragMeta; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "parseEventDef", function() { return parseEventDef; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "parseFieldSpecs", function() { return parseFieldSpecs; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "parseMarker", function() { return parse; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "pointInsideRect", function() { return pointInsideRect; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "prependToElement", function() { return prependToElement; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "preventContextMenu", function() { return preventContextMenu; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "preventDefault", function() { return preventDefault; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "preventSelection", function() { return preventSelection; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "processScopedUiProps", function() { return processScopedUiProps; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rangeContainsMarker", function() { return rangeContainsMarker; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rangeContainsRange", function() { return rangeContainsRange; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rangesEqual", function() { return rangesEqual; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rangesIntersect", function() { return rangesIntersect; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "refineProps", function() { return refineProps; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "removeElement", function() { return removeElement; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "removeExact", function() { return removeExact; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "renderDateCell", function() { return renderDateCell; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "requestJson", function() { return requestJson; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sliceEventStore", function() { return sliceEventStore; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "startOfDay", function() { return startOfDay; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subtractInnerElHeight", function() { return subtractInnerElHeight; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "translateRect", function() { return translateRect; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "uncompensateScroll", function() { return uncompensateScroll; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "undistributeHeight", function() { return undistributeHeight; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "unpromisify", function() { return unpromisify; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "version", function() { return version; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "whenTransitionDone", function() { return whenTransitionDone; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "wholeDivideDurations", function() { return wholeDivideDurations; }); /*! FullCalendar Core Package v4.4.0 Docs & License: https://fullcalendar.io/ (c) 2019 Adam Shaw */ // Creating // ---------------------------------------------------------------------------------------------------------------- var elementPropHash = { className: true, colSpan: true, rowSpan: true }; var containerTagHash = { '= rect.left && point.left < rect.right && point.top >= rect.top && point.top < rect.bottom; } // Returns a new rectangle that is the intersection of the two rectangles. If they don't intersect, returns false function intersectRects(rect1, rect2) { var res = { left: Math.max(rect1.left, rect2.left), right: Math.min(rect1.right, rect2.right), top: Math.max(rect1.top, rect2.top), bottom: Math.min(rect1.bottom, rect2.bottom) }; if (res.left < res.right && res.top < res.bottom) { return res; } return false; } function translateRect(rect, deltaX, deltaY) { return { left: rect.left + deltaX, right: rect.right + deltaX, top: rect.top + deltaY, bottom: rect.bottom + deltaY }; } // Returns a new point that will have been moved to reside within the given rectangle function constrainPoint(point, rect) { return { left: Math.min(Math.max(point.left, rect.left), rect.right), top: Math.min(Math.max(point.top, rect.top), rect.bottom) }; } // Returns a point that is the center of the given rectangle function getRectCenter(rect) { return { left: (rect.left + rect.right) / 2, top: (rect.top + rect.bottom) / 2 }; } // Subtracts point2's coordinates from point1's coordinates, returning a delta function diffPoints(point1, point2) { return { left: point1.left - point2.left, top: point1.top - point2.top }; } // Logic for determining if, when the element is right-to-left, the scrollbar appears on the left side var isRtlScrollbarOnLeft = null; function getIsRtlScrollbarOnLeft() { if (isRtlScrollbarOnLeft === null) { isRtlScrollbarOnLeft = computeIsRtlScrollbarOnLeft(); } return isRtlScrollbarOnLeft; } function computeIsRtlScrollbarOnLeft() { var outerEl = createElement('div', { style: { position: 'absolute', top: -1000, left: 0, border: 0, padding: 0, overflow: 'scroll', direction: 'rtl' } }, '
'); document.body.appendChild(outerEl); var innerEl = outerEl.firstChild; var res = innerEl.getBoundingClientRect().left > outerEl.getBoundingClientRect().left; removeElement(outerEl); return res; } // The scrollbar width computations in computeEdges are sometimes flawed when it comes to // retina displays, rounding, and IE11. Massage them into a usable value. function sanitizeScrollbarWidth(width) { width = Math.max(0, width); // no negatives width = Math.round(width); return width; } function computeEdges(el, getPadding) { if (getPadding === void 0) { getPadding = false; } var computedStyle = window.getComputedStyle(el); var borderLeft = parseInt(computedStyle.borderLeftWidth, 10) || 0; var borderRight = parseInt(computedStyle.borderRightWidth, 10) || 0; var borderTop = parseInt(computedStyle.borderTopWidth, 10) || 0; var borderBottom = parseInt(computedStyle.borderBottomWidth, 10) || 0; // must use offset(Width|Height) because compatible with client(Width|Height) var scrollbarLeftRight = sanitizeScrollbarWidth(el.offsetWidth - el.clientWidth - borderLeft - borderRight); var scrollbarBottom = sanitizeScrollbarWidth(el.offsetHeight - el.clientHeight - borderTop - borderBottom); var res = { borderLeft: borderLeft, borderRight: borderRight, borderTop: borderTop, borderBottom: borderBottom, scrollbarBottom: scrollbarBottom, scrollbarLeft: 0, scrollbarRight: 0 }; if (getIsRtlScrollbarOnLeft() && computedStyle.direction === 'rtl') { // is the scrollbar on the left side? res.scrollbarLeft = scrollbarLeftRight; } else { res.scrollbarRight = scrollbarLeftRight; } if (getPadding) { res.paddingLeft = parseInt(computedStyle.paddingLeft, 10) || 0; res.paddingRight = parseInt(computedStyle.paddingRight, 10) || 0; res.paddingTop = parseInt(computedStyle.paddingTop, 10) || 0; res.paddingBottom = parseInt(computedStyle.paddingBottom, 10) || 0; } return res; } function computeInnerRect(el, goWithinPadding) { if (goWithinPadding === void 0) { goWithinPadding = false; } var outerRect = computeRect(el); var edges = computeEdges(el, goWithinPadding); var res = { left: outerRect.left + edges.borderLeft + edges.scrollbarLeft, right: outerRect.right - edges.borderRight - edges.scrollbarRight, top: outerRect.top + edges.borderTop, bottom: outerRect.bottom - edges.borderBottom - edges.scrollbarBottom }; if (goWithinPadding) { res.left += edges.paddingLeft; res.right -= edges.paddingRight; res.top += edges.paddingTop; res.bottom -= edges.paddingBottom; } return res; } function computeRect(el) { var rect = el.getBoundingClientRect(); return { left: rect.left + window.pageXOffset, top: rect.top + window.pageYOffset, right: rect.right + window.pageXOffset, bottom: rect.bottom + window.pageYOffset }; } function computeViewportRect() { return { left: window.pageXOffset, right: window.pageXOffset + document.documentElement.clientWidth, top: window.pageYOffset, bottom: window.pageYOffset + document.documentElement.clientHeight }; } function computeHeightAndMargins(el) { return el.getBoundingClientRect().height + computeVMargins(el); } function computeVMargins(el) { var computed = window.getComputedStyle(el); return parseInt(computed.marginTop, 10) + parseInt(computed.marginBottom, 10); } // does not return window function getClippingParents(el) { var parents = []; while (el instanceof HTMLElement) { // will stop when gets to document or null var computedStyle = window.getComputedStyle(el); if (computedStyle.position === 'fixed') { break; } if ((/(auto|scroll)/).test(computedStyle.overflow + computedStyle.overflowY + computedStyle.overflowX)) { parents.push(el); } el = el.parentNode; } return parents; } function computeClippingRect(el) { return getClippingParents(el) .map(function (el) { return computeInnerRect(el); }) .concat(computeViewportRect()) .reduce(function (rect0, rect1) { return intersectRects(rect0, rect1) || rect1; // should always intersect }); } // Stops a mouse/touch event from doing it's native browser action function preventDefault(ev) { ev.preventDefault(); } // Event Delegation // ---------------------------------------------------------------------------------------------------------------- function listenBySelector(container, eventType, selector, handler) { function realHandler(ev) { var matchedChild = elementClosest(ev.target, selector); if (matchedChild) { handler.call(matchedChild, ev, matchedChild); } } container.addEventListener(eventType, realHandler); return function () { container.removeEventListener(eventType, realHandler); }; } function listenToHoverBySelector(container, selector, onMouseEnter, onMouseLeave) { var currentMatchedChild; return listenBySelector(container, 'mouseover', selector, function (ev, matchedChild) { if (matchedChild !== currentMatchedChild) { currentMatchedChild = matchedChild; onMouseEnter(ev, matchedChild); var realOnMouseLeave_1 = function (ev) { currentMatchedChild = null; onMouseLeave(ev, matchedChild); matchedChild.removeEventListener('mouseleave', realOnMouseLeave_1); }; // listen to the next mouseleave, and then unattach matchedChild.addEventListener('mouseleave', realOnMouseLeave_1); } }); } // Animation // ---------------------------------------------------------------------------------------------------------------- var transitionEventNames = [ 'webkitTransitionEnd', 'otransitionend', 'oTransitionEnd', 'msTransitionEnd', 'transitionend' ]; // triggered only when the next single subsequent transition finishes function whenTransitionDone(el, callback) { var realCallback = function (ev) { callback(ev); transitionEventNames.forEach(function (eventName) { el.removeEventListener(eventName, realCallback); }); }; transitionEventNames.forEach(function (eventName) { el.addEventListener(eventName, realCallback); // cross-browser way to determine when the transition finishes }); } var DAY_IDS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']; // Adding function addWeeks(m, n) { var a = dateToUtcArray(m); a[2] += n * 7; return arrayToUtcDate(a); } function addDays(m, n) { var a = dateToUtcArray(m); a[2] += n; return arrayToUtcDate(a); } function addMs(m, n) { var a = dateToUtcArray(m); a[6] += n; return arrayToUtcDate(a); } // Diffing (all return floats) function diffWeeks(m0, m1) { return diffDays(m0, m1) / 7; } function diffDays(m0, m1) { return (m1.valueOf() - m0.valueOf()) / (1000 * 60 * 60 * 24); } function diffHours(m0, m1) { return (m1.valueOf() - m0.valueOf()) / (1000 * 60 * 60); } function diffMinutes(m0, m1) { return (m1.valueOf() - m0.valueOf()) / (1000 * 60); } function diffSeconds(m0, m1) { return (m1.valueOf() - m0.valueOf()) / 1000; } function diffDayAndTime(m0, m1) { var m0day = startOfDay(m0); var m1day = startOfDay(m1); return { years: 0, months: 0, days: Math.round(diffDays(m0day, m1day)), milliseconds: (m1.valueOf() - m1day.valueOf()) - (m0.valueOf() - m0day.valueOf()) }; } // Diffing Whole Units function diffWholeWeeks(m0, m1) { var d = diffWholeDays(m0, m1); if (d !== null && d % 7 === 0) { return d / 7; } return null; } function diffWholeDays(m0, m1) { if (timeAsMs(m0) === timeAsMs(m1)) { return Math.round(diffDays(m0, m1)); } return null; } // Start-Of function startOfDay(m) { return arrayToUtcDate([ m.getUTCFullYear(), m.getUTCMonth(), m.getUTCDate() ]); } function startOfHour(m) { return arrayToUtcDate([ m.getUTCFullYear(), m.getUTCMonth(), m.getUTCDate(), m.getUTCHours() ]); } function startOfMinute(m) { return arrayToUtcDate([ m.getUTCFullYear(), m.getUTCMonth(), m.getUTCDate(), m.getUTCHours(), m.getUTCMinutes() ]); } function startOfSecond(m) { return arrayToUtcDate([ m.getUTCFullYear(), m.getUTCMonth(), m.getUTCDate(), m.getUTCHours(), m.getUTCMinutes(), m.getUTCSeconds() ]); } // Week Computation function weekOfYear(marker, dow, doy) { var y = marker.getUTCFullYear(); var w = weekOfGivenYear(marker, y, dow, doy); if (w < 1) { return weekOfGivenYear(marker, y - 1, dow, doy); } var nextW = weekOfGivenYear(marker, y + 1, dow, doy); if (nextW >= 1) { return Math.min(w, nextW); } return w; } function weekOfGivenYear(marker, year, dow, doy) { var firstWeekStart = arrayToUtcDate([year, 0, 1 + firstWeekOffset(year, dow, doy)]); var dayStart = startOfDay(marker); var days = Math.round(diffDays(firstWeekStart, dayStart)); return Math.floor(days / 7) + 1; // zero-indexed } // start-of-first-week - start-of-year function firstWeekOffset(year, dow, doy) { // first-week day -- which january is always in the first week (4 for iso, 1 for other) var fwd = 7 + dow - doy; // first-week day local weekday -- which local weekday is fwd var fwdlw = (7 + arrayToUtcDate([year, 0, fwd]).getUTCDay() - dow) % 7; return -fwdlw + fwd - 1; } // Array Conversion function dateToLocalArray(date) { return [ date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds() ]; } function arrayToLocalDate(a) { return new Date(a[0], a[1] || 0, a[2] == null ? 1 : a[2], // day of month a[3] || 0, a[4] || 0, a[5] || 0); } function dateToUtcArray(date) { return [ date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds() ]; } function arrayToUtcDate(a) { // according to web standards (and Safari), a month index is required. // massage if only given a year. if (a.length === 1) { a = a.concat([0]); } return new Date(Date.UTC.apply(Date, a)); } // Other Utils function isValidDate(m) { return !isNaN(m.valueOf()); } function timeAsMs(m) { return m.getUTCHours() * 1000 * 60 * 60 + m.getUTCMinutes() * 1000 * 60 + m.getUTCSeconds() * 1000 + m.getUTCMilliseconds(); } var INTERNAL_UNITS = ['years', 'months', 'days', 'milliseconds']; var PARSE_RE = /^(-?)(?:(\d+)\.)?(\d+):(\d\d)(?::(\d\d)(?:\.(\d\d\d))?)?/; // Parsing and Creation function createDuration(input, unit) { var _a; if (typeof input === 'string') { return parseString(input); } else if (typeof input === 'object' && input) { // non-null object return normalizeObject(input); } else if (typeof input === 'number') { return normalizeObject((_a = {}, _a[unit || 'milliseconds'] = input, _a)); } else { return null; } } function parseString(s) { var m = PARSE_RE.exec(s); if (m) { var sign = m[1] ? -1 : 1; return { years: 0, months: 0, days: sign * (m[2] ? parseInt(m[2], 10) : 0), milliseconds: sign * ((m[3] ? parseInt(m[3], 10) : 0) * 60 * 60 * 1000 + // hours (m[4] ? parseInt(m[4], 10) : 0) * 60 * 1000 + // minutes (m[5] ? parseInt(m[5], 10) : 0) * 1000 + // seconds (m[6] ? parseInt(m[6], 10) : 0) // ms ) }; } return null; } function normalizeObject(obj) { return { years: obj.years || obj.year || 0, months: obj.months || obj.month || 0, days: (obj.days || obj.day || 0) + getWeeksFromInput(obj) * 7, milliseconds: (obj.hours || obj.hour || 0) * 60 * 60 * 1000 + // hours (obj.minutes || obj.minute || 0) * 60 * 1000 + // minutes (obj.seconds || obj.second || 0) * 1000 + // seconds (obj.milliseconds || obj.millisecond || obj.ms || 0) // ms }; } function getWeeksFromInput(obj) { return obj.weeks || obj.week || 0; } // Equality function durationsEqual(d0, d1) { return d0.years === d1.years && d0.months === d1.months && d0.days === d1.days && d0.milliseconds === d1.milliseconds; } function isSingleDay(dur) { return dur.years === 0 && dur.months === 0 && dur.days === 1 && dur.milliseconds === 0; } // Simple Math function addDurations(d0, d1) { return { years: d0.years + d1.years, months: d0.months + d1.months, days: d0.days + d1.days, milliseconds: d0.milliseconds + d1.milliseconds }; } function subtractDurations(d1, d0) { return { years: d1.years - d0.years, months: d1.months - d0.months, days: d1.days - d0.days, milliseconds: d1.milliseconds - d0.milliseconds }; } function multiplyDuration(d, n) { return { years: d.years * n, months: d.months * n, days: d.days * n, milliseconds: d.milliseconds * n }; } // Conversions // "Rough" because they are based on average-case Gregorian months/years function asRoughYears(dur) { return asRoughDays(dur) / 365; } function asRoughMonths(dur) { return asRoughDays(dur) / 30; } function asRoughDays(dur) { return asRoughMs(dur) / 864e5; } function asRoughMinutes(dur) { return asRoughMs(dur) / (1000 * 60); } function asRoughSeconds(dur) { return asRoughMs(dur) / 1000; } function asRoughMs(dur) { return dur.years * (365 * 864e5) + dur.months * (30 * 864e5) + dur.days * 864e5 + dur.milliseconds; } // Advanced Math function wholeDivideDurations(numerator, denominator) { var res = null; for (var i = 0; i < INTERNAL_UNITS.length; i++) { var unit = INTERNAL_UNITS[i]; if (denominator[unit]) { var localRes = numerator[unit] / denominator[unit]; if (!isInt(localRes) || (res !== null && res !== localRes)) { return null; } res = localRes; } else if (numerator[unit]) { // needs to divide by something but can't! return null; } } return res; } function greatestDurationDenominator(dur, dontReturnWeeks) { var ms = dur.milliseconds; if (ms) { if (ms % 1000 !== 0) { return { unit: 'millisecond', value: ms }; } if (ms % (1000 * 60) !== 0) { return { unit: 'second', value: ms / 1000 }; } if (ms % (1000 * 60 * 60) !== 0) { return { unit: 'minute', value: ms / (1000 * 60) }; } if (ms) { return { unit: 'hour', value: ms / (1000 * 60 * 60) }; } } if (dur.days) { if (!dontReturnWeeks && dur.days % 7 === 0) { return { unit: 'week', value: dur.days / 7 }; } return { unit: 'day', value: dur.days }; } if (dur.months) { return { unit: 'month', value: dur.months }; } if (dur.years) { return { unit: 'year', value: dur.years }; } return { unit: 'millisecond', value: 0 }; } /* FullCalendar-specific DOM Utilities ----------------------------------------------------------------------------------------------------------------------*/ // Given the scrollbar widths of some other container, create borders/margins on rowEls in order to match the left // and right space that was offset by the scrollbars. A 1-pixel border first, then margin beyond that. function compensateScroll(rowEl, scrollbarWidths) { if (scrollbarWidths.left) { applyStyle(rowEl, { borderLeftWidth: 1, marginLeft: scrollbarWidths.left - 1 }); } if (scrollbarWidths.right) { applyStyle(rowEl, { borderRightWidth: 1, marginRight: scrollbarWidths.right - 1 }); } } // Undoes compensateScroll and restores all borders/margins function uncompensateScroll(rowEl) { applyStyle(rowEl, { marginLeft: '', marginRight: '', borderLeftWidth: '', borderRightWidth: '' }); } // Make the mouse cursor express that an event is not allowed in the current area function disableCursor() { document.body.classList.add('fc-not-allowed'); } // Returns the mouse cursor to its original look function enableCursor() { document.body.classList.remove('fc-not-allowed'); } // Given a total available height to fill, have `els` (essentially child rows) expand to accomodate. // By default, all elements that are shorter than the recommended height are expanded uniformly, not considering // any other els that are already too tall. if `shouldRedistribute` is on, it considers these tall rows and // reduces the available height. function distributeHeight(els, availableHeight, shouldRedistribute) { // *FLOORING NOTE*: we floor in certain places because zoom can give inaccurate floating-point dimensions, // and it is better to be shorter than taller, to avoid creating unnecessary scrollbars. var minOffset1 = Math.floor(availableHeight / els.length); // for non-last element var minOffset2 = Math.floor(availableHeight - minOffset1 * (els.length - 1)); // for last element *FLOORING NOTE* var flexEls = []; // elements that are allowed to expand. array of DOM nodes var flexOffsets = []; // amount of vertical space it takes up var flexHeights = []; // actual css height var usedHeight = 0; undistributeHeight(els); // give all elements their natural height // find elements that are below the recommended height (expandable). // important to query for heights in a single first pass (to avoid reflow oscillation). els.forEach(function (el, i) { var minOffset = i === els.length - 1 ? minOffset2 : minOffset1; var naturalHeight = el.getBoundingClientRect().height; var naturalOffset = naturalHeight + computeVMargins(el); if (naturalOffset < minOffset) { flexEls.push(el); flexOffsets.push(naturalOffset); flexHeights.push(naturalHeight); } else { // this element stretches past recommended height (non-expandable). mark the space as occupied. usedHeight += naturalOffset; } }); // readjust the recommended height to only consider the height available to non-maxed-out rows. if (shouldRedistribute) { availableHeight -= usedHeight; minOffset1 = Math.floor(availableHeight / flexEls.length); minOffset2 = Math.floor(availableHeight - minOffset1 * (flexEls.length - 1)); // *FLOORING NOTE* } // assign heights to all expandable elements flexEls.forEach(function (el, i) { var minOffset = i === flexEls.length - 1 ? minOffset2 : minOffset1; var naturalOffset = flexOffsets[i]; var naturalHeight = flexHeights[i]; var newHeight = minOffset - (naturalOffset - naturalHeight); // subtract the margin/padding if (naturalOffset < minOffset) { // we check this again because redistribution might have changed things el.style.height = newHeight + 'px'; } }); } // Undoes distrubuteHeight, restoring all els to their natural height function undistributeHeight(els) { els.forEach(function (el) { el.style.height = ''; }); } // Given `els`, a set of cells, find the cell with the largest natural width and set the widths of all the // cells to be that width. // PREREQUISITE: if you want a cell to take up width, it needs to have a single inner element w/ display:inline function matchCellWidths(els) { var maxInnerWidth = 0; els.forEach(function (el) { var innerEl = el.firstChild; // hopefully an element if (innerEl instanceof HTMLElement) { var innerWidth_1 = innerEl.getBoundingClientRect().width; if (innerWidth_1 > maxInnerWidth) { maxInnerWidth = innerWidth_1; } } }); maxInnerWidth++; // sometimes not accurate of width the text needs to stay on one line. insurance els.forEach(function (el) { el.style.width = maxInnerWidth + 'px'; }); return maxInnerWidth; } // Given one element that resides inside another, // Subtracts the height of the inner element from the outer element. function subtractInnerElHeight(outerEl, innerEl) { // effin' IE8/9/10/11 sometimes returns 0 for dimensions. this weird hack was the only thing that worked var reflowStyleProps = { position: 'relative', left: -1 // ensure reflow in case the el was already relative. negative is less likely to cause new scroll }; applyStyle(outerEl, reflowStyleProps); applyStyle(innerEl, reflowStyleProps); var diff = // grab the dimensions outerEl.getBoundingClientRect().height - innerEl.getBoundingClientRect().height; // undo hack var resetStyleProps = { position: '', left: '' }; applyStyle(outerEl, resetStyleProps); applyStyle(innerEl, resetStyleProps); return diff; } /* Selection ----------------------------------------------------------------------------------------------------------------------*/ function preventSelection(el) { el.classList.add('fc-unselectable'); el.addEventListener('selectstart', preventDefault); } function allowSelection(el) { el.classList.remove('fc-unselectable'); el.removeEventListener('selectstart', preventDefault); } /* Context Menu ----------------------------------------------------------------------------------------------------------------------*/ function preventContextMenu(el) { el.addEventListener('contextmenu', preventDefault); } function allowContextMenu(el) { el.removeEventListener('contextmenu', preventDefault); } /* Object Ordering by Field ----------------------------------------------------------------------------------------------------------------------*/ function parseFieldSpecs(input) { var specs = []; var tokens = []; var i; var token; if (typeof input === 'string') { tokens = input.split(/\s*,\s*/); } else if (typeof input === 'function') { tokens = [input]; } else if (Array.isArray(input)) { tokens = input; } for (i = 0; i < tokens.length; i++) { token = tokens[i]; if (typeof token === 'string') { specs.push(token.charAt(0) === '-' ? { field: token.substring(1), order: -1 } : { field: token, order: 1 }); } else if (typeof token === 'function') { specs.push({ func: token }); } } return specs; } function compareByFieldSpecs(obj0, obj1, fieldSpecs) { var i; var cmp; for (i = 0; i < fieldSpecs.length; i++) { cmp = compareByFieldSpec(obj0, obj1, fieldSpecs[i]); if (cmp) { return cmp; } } return 0; } function compareByFieldSpec(obj0, obj1, fieldSpec) { if (fieldSpec.func) { return fieldSpec.func(obj0, obj1); } return flexibleCompare(obj0[fieldSpec.field], obj1[fieldSpec.field]) * (fieldSpec.order || 1); } function flexibleCompare(a, b) { if (!a && !b) { return 0; } if (b == null) { return -1; } if (a == null) { return 1; } if (typeof a === 'string' || typeof b === 'string') { return String(a).localeCompare(String(b)); } return a - b; } /* String Utilities ----------------------------------------------------------------------------------------------------------------------*/ function capitaliseFirstLetter(str) { return str.charAt(0).toUpperCase() + str.slice(1); } function padStart(val, len) { var s = String(val); return '000'.substr(0, len - s.length) + s; } /* Number Utilities ----------------------------------------------------------------------------------------------------------------------*/ function compareNumbers(a, b) { return a - b; } function isInt(n) { return n % 1 === 0; } /* Weird Utilities ----------------------------------------------------------------------------------------------------------------------*/ function applyAll(functions, thisObj, args) { if (typeof functions === 'function') { // supplied a single function functions = [functions]; } if (functions) { var i = void 0; var ret = void 0; for (i = 0; i < functions.length; i++) { ret = functions[i].apply(thisObj, args) || ret; } return ret; } } function firstDefined() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } for (var i = 0; i < args.length; i++) { if (args[i] !== undefined) { return args[i]; } } } // Returns a function, that, as long as it continues to be invoked, will not // be triggered. The function will be called after it stops being called for // N milliseconds. If `immediate` is passed, trigger the function on the // leading edge, instead of the trailing. // https://github.com/jashkenas/underscore/blob/1.6.0/underscore.js#L714 function debounce(func, wait) { var timeout; var args; var context; var timestamp; var result; var later = function () { var last = new Date().valueOf() - timestamp; if (last < wait) { timeout = setTimeout(later, wait - last); } else { timeout = null; result = func.apply(context, args); context = args = null; } }; return function () { context = this; args = arguments; timestamp = new Date().valueOf(); if (!timeout) { timeout = setTimeout(later, wait); } return result; }; } // Number and Boolean are only types that defaults or not computed for // TODO: write more comments function refineProps(rawProps, processors, defaults, leftoverProps) { if (defaults === void 0) { defaults = {}; } var refined = {}; for (var key in processors) { var processor = processors[key]; if (rawProps[key] !== undefined) { // found if (processor === Function) { refined[key] = typeof rawProps[key] === 'function' ? rawProps[key] : null; } else if (processor) { // a refining function? refined[key] = processor(rawProps[key]); } else { refined[key] = rawProps[key]; } } else if (defaults[key] !== undefined) { // there's an explicit default refined[key] = defaults[key]; } else { // must compute a default if (processor === String) { refined[key] = ''; // empty string is default for String } else if (!processor || processor === Number || processor === Boolean || processor === Function) { refined[key] = null; // assign null for other non-custom processor funcs } else { refined[key] = processor(null); // run the custom processor func } } } if (leftoverProps) { for (var key in rawProps) { if (processors[key] === undefined) { leftoverProps[key] = rawProps[key]; } } } return refined; } /* Date stuff that doesn't belong in datelib core ----------------------------------------------------------------------------------------------------------------------*/ // given a timed range, computes an all-day range that has the same exact duration, // but whose start time is aligned with the start of the day. function computeAlignedDayRange(timedRange) { var dayCnt = Math.floor(diffDays(timedRange.start, timedRange.end)) || 1; var start = startOfDay(timedRange.start); var end = addDays(start, dayCnt); return { start: start, end: end }; } // given a timed range, computes an all-day range based on how for the end date bleeds into the next day // TODO: give nextDayThreshold a default arg function computeVisibleDayRange(timedRange, nextDayThreshold) { if (nextDayThreshold === void 0) { nextDayThreshold = createDuration(0); } var startDay = null; var endDay = null; if (timedRange.end) { endDay = startOfDay(timedRange.end); var endTimeMS = timedRange.end.valueOf() - endDay.valueOf(); // # of milliseconds into `endDay` // If the end time is actually inclusively part of the next day and is equal to or // beyond the next day threshold, adjust the end to be the exclusive end of `endDay`. // Otherwise, leaving it as inclusive will cause it to exclude `endDay`. if (endTimeMS && endTimeMS >= asRoughMs(nextDayThreshold)) { endDay = addDays(endDay, 1); } } if (timedRange.start) { startDay = startOfDay(timedRange.start); // the beginning of the day the range starts // If end is within `startDay` but not past nextDayThreshold, assign the default duration of one day. if (endDay && endDay <= startDay) { endDay = addDays(startDay, 1); } } return { start: startDay, end: endDay }; } // spans from one day into another? function isMultiDayRange(range) { var visibleRange = computeVisibleDayRange(range); return diffDays(visibleRange.start, visibleRange.end) > 1; } function diffDates(date0, date1, dateEnv, largeUnit) { if (largeUnit === 'year') { return createDuration(dateEnv.diffWholeYears(date0, date1), 'year'); } else if (largeUnit === 'month') { return createDuration(dateEnv.diffWholeMonths(date0, date1), 'month'); } else { return diffDayAndTime(date0, date1); // returns a duration } } /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function parseRecurring(eventInput, allDayDefault, dateEnv, recurringTypes, leftovers) { for (var i = 0; i < recurringTypes.length; i++) { var localLeftovers = {}; var parsed = recurringTypes[i].parse(eventInput, localLeftovers, dateEnv); if (parsed) { var allDay = localLeftovers.allDay; delete localLeftovers.allDay; // remove from leftovers if (allDay == null) { allDay = allDayDefault; if (allDay == null) { allDay = parsed.allDayGuess; if (allDay == null) { allDay = false; } } } __assign(leftovers, localLeftovers); return { allDay: allDay, duration: parsed.duration, typeData: parsed.typeData, typeId: i }; } } return null; } /* Event MUST have a recurringDef */ function expandRecurringRanges(eventDef, duration, framingRange, dateEnv, recurringTypes) { var typeDef = recurringTypes[eventDef.recurringDef.typeId]; var markers = typeDef.expand(eventDef.recurringDef.typeData, { start: dateEnv.subtract(framingRange.start, duration), end: framingRange.end }, dateEnv); // the recurrence plugins don't guarantee that all-day events are start-of-day, so we have to if (eventDef.allDay) { markers = markers.map(startOfDay); } return markers; } var hasOwnProperty = Object.prototype.hasOwnProperty; // Merges an array of objects into a single object. // The second argument allows for an array of property names who's object values will be merged together. function mergeProps(propObjs, complexProps) { var dest = {}; var i; var name; var complexObjs; var j; var val; var props; if (complexProps) { for (i = 0; i < complexProps.length; i++) { name = complexProps[i]; complexObjs = []; // collect the trailing object values, stopping when a non-object is discovered for (j = propObjs.length - 1; j >= 0; j--) { val = propObjs[j][name]; if (typeof val === 'object' && val) { // non-null object complexObjs.unshift(val); } else if (val !== undefined) { dest[name] = val; // if there were no objects, this value will be used break; } } // if the trailing values were objects, use the merged value if (complexObjs.length) { dest[name] = mergeProps(complexObjs); } } } // copy values into the destination, going from last to first for (i = propObjs.length - 1; i >= 0; i--) { props = propObjs[i]; for (name in props) { if (!(name in dest)) { // if already assigned by previous props or complex props, don't reassign dest[name] = props[name]; } } } return dest; } function filterHash(hash, func) { var filtered = {}; for (var key in hash) { if (func(hash[key], key)) { filtered[key] = hash[key]; } } return filtered; } function mapHash(hash, func) { var newHash = {}; for (var key in hash) { newHash[key] = func(hash[key], key); } return newHash; } function arrayToHash(a) { var hash = {}; for (var _i = 0, a_1 = a; _i < a_1.length; _i++) { var item = a_1[_i]; hash[item] = true; } return hash; } function hashValuesToArray(obj) { var a = []; for (var key in obj) { a.push(obj[key]); } return a; } function isPropsEqual(obj0, obj1) { for (var key in obj0) { if (hasOwnProperty.call(obj0, key)) { if (!(key in obj1)) { return false; } } } for (var key in obj1) { if (hasOwnProperty.call(obj1, key)) { if (obj0[key] !== obj1[key]) { return false; } } } return true; } function parseEvents(rawEvents, sourceId, calendar, allowOpenRange) { var eventStore = createEmptyEventStore(); for (var _i = 0, rawEvents_1 = rawEvents; _i < rawEvents_1.length; _i++) { var rawEvent = rawEvents_1[_i]; var tuple = parseEvent(rawEvent, sourceId, calendar, allowOpenRange); if (tuple) { eventTupleToStore(tuple, eventStore); } } return eventStore; } function eventTupleToStore(tuple, eventStore) { if (eventStore === void 0) { eventStore = createEmptyEventStore(); } eventStore.defs[tuple.def.defId] = tuple.def; if (tuple.instance) { eventStore.instances[tuple.instance.instanceId] = tuple.instance; } return eventStore; } function expandRecurring(eventStore, framingRange, calendar) { var dateEnv = calendar.dateEnv; var defs = eventStore.defs, instances = eventStore.instances; // remove existing recurring instances instances = filterHash(instances, function (instance) { return !defs[instance.defId].recurringDef; }); for (var defId in defs) { var def = defs[defId]; if (def.recurringDef) { var duration = def.recurringDef.duration; if (!duration) { duration = def.allDay ? calendar.defaultAllDayEventDuration : calendar.defaultTimedEventDuration; } var starts = expandRecurringRanges(def, duration, framingRange, calendar.dateEnv, calendar.pluginSystem.hooks.recurringTypes); for (var _i = 0, starts_1 = starts; _i < starts_1.length; _i++) { var start = starts_1[_i]; var instance = createEventInstance(defId, { start: start, end: dateEnv.add(start, duration) }); instances[instance.instanceId] = instance; } } } return { defs: defs, instances: instances }; } // retrieves events that have the same groupId as the instance specified by `instanceId` // or they are the same as the instance. // why might instanceId not be in the store? an event from another calendar? function getRelevantEvents(eventStore, instanceId) { var instance = eventStore.instances[instanceId]; if (instance) { var def_1 = eventStore.defs[instance.defId]; // get events/instances with same group var newStore = filterEventStoreDefs(eventStore, function (lookDef) { return isEventDefsGrouped(def_1, lookDef); }); // add the original // TODO: wish we could use eventTupleToStore or something like it newStore.defs[def_1.defId] = def_1; newStore.instances[instance.instanceId] = instance; return newStore; } return createEmptyEventStore(); } function isEventDefsGrouped(def0, def1) { return Boolean(def0.groupId && def0.groupId === def1.groupId); } function transformRawEvents(rawEvents, eventSource, calendar) { var calEachTransform = calendar.opt('eventDataTransform'); var sourceEachTransform = eventSource ? eventSource.eventDataTransform : null; if (sourceEachTransform) { rawEvents = transformEachRawEvent(rawEvents, sourceEachTransform); } if (calEachTransform) { rawEvents = transformEachRawEvent(rawEvents, calEachTransform); } return rawEvents; } function transformEachRawEvent(rawEvents, func) { var refinedEvents; if (!func) { refinedEvents = rawEvents; } else { refinedEvents = []; for (var _i = 0, rawEvents_2 = rawEvents; _i < rawEvents_2.length; _i++) { var rawEvent = rawEvents_2[_i]; var refinedEvent = func(rawEvent); if (refinedEvent) { refinedEvents.push(refinedEvent); } else if (refinedEvent == null) { refinedEvents.push(rawEvent); } // if a different falsy value, do nothing } } return refinedEvents; } function createEmptyEventStore() { return { defs: {}, instances: {} }; } function mergeEventStores(store0, store1) { return { defs: __assign({}, store0.defs, store1.defs), instances: __assign({}, store0.instances, store1.instances) }; } function filterEventStoreDefs(eventStore, filterFunc) { var defs = filterHash(eventStore.defs, filterFunc); var instances = filterHash(eventStore.instances, function (instance) { return defs[instance.defId]; // still exists? }); return { defs: defs, instances: instances }; } function parseRange(input, dateEnv) { var start = null; var end = null; if (input.start) { start = dateEnv.createMarker(input.start); } if (input.end) { end = dateEnv.createMarker(input.end); } if (!start && !end) { return null; } if (start && end && end < start) { return null; } return { start: start, end: end }; } // SIDE-EFFECT: will mutate ranges. // Will return a new array result. function invertRanges(ranges, constraintRange) { var invertedRanges = []; var start = constraintRange.start; // the end of the previous range. the start of the new range var i; var dateRange; // ranges need to be in order. required for our date-walking algorithm ranges.sort(compareRanges); for (i = 0; i < ranges.length; i++) { dateRange = ranges[i]; // add the span of time before the event (if there is any) if (dateRange.start > start) { // compare millisecond time (skip any ambig logic) invertedRanges.push({ start: start, end: dateRange.start }); } if (dateRange.end > start) { start = dateRange.end; } } // add the span of time after the last event (if there is any) if (start < constraintRange.end) { // compare millisecond time (skip any ambig logic) invertedRanges.push({ start: start, end: constraintRange.end }); } return invertedRanges; } function compareRanges(range0, range1) { return range0.start.valueOf() - range1.start.valueOf(); // earlier ranges go first } function intersectRanges(range0, range1) { var start = range0.start; var end = range0.end; var newRange = null; if (range1.start !== null) { if (start === null) { start = range1.start; } else { start = new Date(Math.max(start.valueOf(), range1.start.valueOf())); } } if (range1.end != null) { if (end === null) { end = range1.end; } else { end = new Date(Math.min(end.valueOf(), range1.end.valueOf())); } } if (start === null || end === null || start < end) { newRange = { start: start, end: end }; } return newRange; } function rangesEqual(range0, range1) { return (range0.start === null ? null : range0.start.valueOf()) === (range1.start === null ? null : range1.start.valueOf()) && (range0.end === null ? null : range0.end.valueOf()) === (range1.end === null ? null : range1.end.valueOf()); } function rangesIntersect(range0, range1) { return (range0.end === null || range1.start === null || range0.end > range1.start) && (range0.start === null || range1.end === null || range0.start < range1.end); } function rangeContainsRange(outerRange, innerRange) { return (outerRange.start === null || (innerRange.start !== null && innerRange.start >= outerRange.start)) && (outerRange.end === null || (innerRange.end !== null && innerRange.end <= outerRange.end)); } function rangeContainsMarker(range, date) { return (range.start === null || date >= range.start) && (range.end === null || date < range.end); } // If the given date is not within the given range, move it inside. // (If it's past the end, make it one millisecond before the end). function constrainMarkerToRange(date, range) { if (range.start != null && date < range.start) { return range.start; } if (range.end != null && date >= range.end) { return new Date(range.end.valueOf() - 1); } return date; } function removeExact(array, exactVal) { var removeCnt = 0; var i = 0; while (i < array.length) { if (array[i] === exactVal) { array.splice(i, 1); removeCnt++; } else { i++; } } return removeCnt; } function isArraysEqual(a0, a1) { var len = a0.length; var i; if (len !== a1.length) { // not array? or not same length? return false; } for (i = 0; i < len; i++) { if (a0[i] !== a1[i]) { return false; } } return true; } function memoize(workerFunc) { var args; var res; return function () { if (!args || !isArraysEqual(args, arguments)) { args = arguments; res = workerFunc.apply(this, arguments); } return res; }; } /* always executes the workerFunc, but if the result is equal to the previous result, return the previous result instead. */ function memoizeOutput(workerFunc, equalityFunc) { var cachedRes = null; return function () { var newRes = workerFunc.apply(this, arguments); if (cachedRes === null || !(cachedRes === newRes || equalityFunc(cachedRes, newRes))) { cachedRes = newRes; } return cachedRes; }; } var EXTENDED_SETTINGS_AND_SEVERITIES = { week: 3, separator: 0, omitZeroMinute: 0, meridiem: 0, omitCommas: 0 }; var STANDARD_DATE_PROP_SEVERITIES = { timeZoneName: 7, era: 6, year: 5, month: 4, day: 2, weekday: 2, hour: 1, minute: 1, second: 1 }; var MERIDIEM_RE = /\s*([ap])\.?m\.?/i; // eats up leading spaces too var COMMA_RE = /,/g; // we need re for globalness var MULTI_SPACE_RE = /\s+/g; var LTR_RE = /\u200e/g; // control character var UTC_RE = /UTC|GMT/; var NativeFormatter = /** @class */ (function () { function NativeFormatter(formatSettings) { var standardDateProps = {}; var extendedSettings = {}; var severity = 0; for (var name_1 in formatSettings) { if (name_1 in EXTENDED_SETTINGS_AND_SEVERITIES) { extendedSettings[name_1] = formatSettings[name_1]; severity = Math.max(EXTENDED_SETTINGS_AND_SEVERITIES[name_1], severity); } else { standardDateProps[name_1] = formatSettings[name_1]; if (name_1 in STANDARD_DATE_PROP_SEVERITIES) { severity = Math.max(STANDARD_DATE_PROP_SEVERITIES[name_1], severity); } } } this.standardDateProps = standardDateProps; this.extendedSettings = extendedSettings; this.severity = severity; this.buildFormattingFunc = memoize(buildFormattingFunc); } NativeFormatter.prototype.format = function (date, context) { return this.buildFormattingFunc(this.standardDateProps, this.extendedSettings, context)(date); }; NativeFormatter.prototype.formatRange = function (start, end, context) { var _a = this, standardDateProps = _a.standardDateProps, extendedSettings = _a.extendedSettings; var diffSeverity = computeMarkerDiffSeverity(start.marker, end.marker, context.calendarSystem); if (!diffSeverity) { return this.format(start, context); } var biggestUnitForPartial = diffSeverity; if (biggestUnitForPartial > 1 && // the two dates are different in a way that's larger scale than time (standardDateProps.year === 'numeric' || standardDateProps.year === '2-digit') && (standardDateProps.month === 'numeric' || standardDateProps.month === '2-digit') && (standardDateProps.day === 'numeric' || standardDateProps.day === '2-digit')) { biggestUnitForPartial = 1; // make it look like the dates are only different in terms of time } var full0 = this.format(start, context); var full1 = this.format(end, context); if (full0 === full1) { return full0; } var partialDateProps = computePartialFormattingOptions(standardDateProps, biggestUnitForPartial); var partialFormattingFunc = buildFormattingFunc(partialDateProps, extendedSettings, context); var partial0 = partialFormattingFunc(start); var partial1 = partialFormattingFunc(end); var insertion = findCommonInsertion(full0, partial0, full1, partial1); var separator = extendedSettings.separator || ''; if (insertion) { return insertion.before + partial0 + separator + partial1 + insertion.after; } return full0 + separator + full1; }; NativeFormatter.prototype.getLargestUnit = function () { switch (this.severity) { case 7: case 6: case 5: return 'year'; case 4: return 'month'; case 3: return 'week'; default: return 'day'; } }; return NativeFormatter; }()); function buildFormattingFunc(standardDateProps, extendedSettings, context) { var standardDatePropCnt = Object.keys(standardDateProps).length; if (standardDatePropCnt === 1 && standardDateProps.timeZoneName === 'short') { return function (date) { return formatTimeZoneOffset(date.timeZoneOffset); }; } if (standardDatePropCnt === 0 && extendedSettings.week) { return function (date) { return formatWeekNumber(context.computeWeekNumber(date.marker), context.weekLabel, context.locale, extendedSettings.week); }; } return buildNativeFormattingFunc(standardDateProps, extendedSettings, context); } function buildNativeFormattingFunc(standardDateProps, extendedSettings, context) { standardDateProps = __assign({}, standardDateProps); // copy extendedSettings = __assign({}, extendedSettings); // copy sanitizeSettings(standardDateProps, extendedSettings); standardDateProps.timeZone = 'UTC'; // we leverage the only guaranteed timeZone for our UTC markers var normalFormat = new Intl.DateTimeFormat(context.locale.codes, standardDateProps); var zeroFormat; // needed? if (extendedSettings.omitZeroMinute) { var zeroProps = __assign({}, standardDateProps); delete zeroProps.minute; // seconds and ms were already considered in sanitizeSettings zeroFormat = new Intl.DateTimeFormat(context.locale.codes, zeroProps); } return function (date) { var marker = date.marker; var format; if (zeroFormat && !marker.getUTCMinutes()) { format = zeroFormat; } else { format = normalFormat; } var s = format.format(marker); return postProcess(s, date, standardDateProps, extendedSettings, context); }; } function sanitizeSettings(standardDateProps, extendedSettings) { // deal with a browser inconsistency where formatting the timezone // requires that the hour/minute be present. if (standardDateProps.timeZoneName) { if (!standardDateProps.hour) { standardDateProps.hour = '2-digit'; } if (!standardDateProps.minute) { standardDateProps.minute = '2-digit'; } } // only support short timezone names if (standardDateProps.timeZoneName === 'long') { standardDateProps.timeZoneName = 'short'; } // if requesting to display seconds, MUST display minutes if (extendedSettings.omitZeroMinute && (standardDateProps.second || standardDateProps.millisecond)) { delete extendedSettings.omitZeroMinute; } } function postProcess(s, date, standardDateProps, extendedSettings, context) { s = s.replace(LTR_RE, ''); // remove left-to-right control chars. do first. good for other regexes if (standardDateProps.timeZoneName === 'short') { s = injectTzoStr(s, (context.timeZone === 'UTC' || date.timeZoneOffset == null) ? 'UTC' : // important to normalize for IE, which does "GMT" formatTimeZoneOffset(date.timeZoneOffset)); } if (extendedSettings.omitCommas) { s = s.replace(COMMA_RE, '').trim(); } if (extendedSettings.omitZeroMinute) { s = s.replace(':00', ''); // zeroFormat doesn't always achieve this } // ^ do anything that might create adjacent spaces before this point, // because MERIDIEM_RE likes to eat up loading spaces if (extendedSettings.meridiem === false) { s = s.replace(MERIDIEM_RE, '').trim(); } else if (extendedSettings.meridiem === 'narrow') { // a/p s = s.replace(MERIDIEM_RE, function (m0, m1) { return m1.toLocaleLowerCase(); }); } else if (extendedSettings.meridiem === 'short') { // am/pm s = s.replace(MERIDIEM_RE, function (m0, m1) { return m1.toLocaleLowerCase() + 'm'; }); } else if (extendedSettings.meridiem === 'lowercase') { // other meridiem transformers already converted to lowercase s = s.replace(MERIDIEM_RE, function (m0) { return m0.toLocaleLowerCase(); }); } s = s.replace(MULTI_SPACE_RE, ' '); s = s.trim(); return s; } function injectTzoStr(s, tzoStr) { var replaced = false; s = s.replace(UTC_RE, function () { replaced = true; return tzoStr; }); // IE11 doesn't include UTC/GMT in the original string, so append to end if (!replaced) { s += ' ' + tzoStr; } return s; } function formatWeekNumber(num, weekLabel, locale, display) { var parts = []; if (display === 'narrow') { parts.push(weekLabel); } else if (display === 'short') { parts.push(weekLabel, ' '); } // otherwise, considered 'numeric' parts.push(locale.simpleNumberFormat.format(num)); if (locale.options.isRtl) { // TODO: use control characters instead? parts.reverse(); } return parts.join(''); } // Range Formatting Utils // 0 = exactly the same // 1 = different by time // and bigger function computeMarkerDiffSeverity(d0, d1, ca) { if (ca.getMarkerYear(d0) !== ca.getMarkerYear(d1)) { return 5; } if (ca.getMarkerMonth(d0) !== ca.getMarkerMonth(d1)) { return 4; } if (ca.getMarkerDay(d0) !== ca.getMarkerDay(d1)) { return 2; } if (timeAsMs(d0) !== timeAsMs(d1)) { return 1; } return 0; } function computePartialFormattingOptions(options, biggestUnit) { var partialOptions = {}; for (var name_2 in options) { if (!(name_2 in STANDARD_DATE_PROP_SEVERITIES) || // not a date part prop (like timeZone) STANDARD_DATE_PROP_SEVERITIES[name_2] <= biggestUnit) { partialOptions[name_2] = options[name_2]; } } return partialOptions; } function findCommonInsertion(full0, partial0, full1, partial1) { var i0 = 0; while (i0 < full0.length) { var found0 = full0.indexOf(partial0, i0); if (found0 === -1) { break; } var before0 = full0.substr(0, found0); i0 = found0 + partial0.length; var after0 = full0.substr(i0); var i1 = 0; while (i1 < full1.length) { var found1 = full1.indexOf(partial1, i1); if (found1 === -1) { break; } var before1 = full1.substr(0, found1); i1 = found1 + partial1.length; var after1 = full1.substr(i1); if (before0 === before1 && after0 === after1) { return { before: before0, after: after0 }; } } } return null; } /* TODO: fix the terminology of "formatter" vs "formatting func" */ /* At the time of instantiation, this object does not know which cmd-formatting system it will use. It receives this at the time of formatting, as a setting. */ var CmdFormatter = /** @class */ (function () { function CmdFormatter(cmdStr, separator) { this.cmdStr = cmdStr; this.separator = separator; } CmdFormatter.prototype.format = function (date, context) { return context.cmdFormatter(this.cmdStr, createVerboseFormattingArg(date, null, context, this.separator)); }; CmdFormatter.prototype.formatRange = function (start, end, context) { return context.cmdFormatter(this.cmdStr, createVerboseFormattingArg(start, end, context, this.separator)); }; return CmdFormatter; }()); var FuncFormatter = /** @class */ (function () { function FuncFormatter(func) { this.func = func; } FuncFormatter.prototype.format = function (date, context) { return this.func(createVerboseFormattingArg(date, null, context)); }; FuncFormatter.prototype.formatRange = function (start, end, context) { return this.func(createVerboseFormattingArg(start, end, context)); }; return FuncFormatter; }()); // Formatter Object Creation function createFormatter(input, defaultSeparator) { if (typeof input === 'object' && input) { // non-null object if (typeof defaultSeparator === 'string') { input = __assign({ separator: defaultSeparator }, input); } return new NativeFormatter(input); } else if (typeof input === 'string') { return new CmdFormatter(input, defaultSeparator); } else if (typeof input === 'function') { return new FuncFormatter(input); } } // String Utils // timeZoneOffset is in minutes function buildIsoString(marker, timeZoneOffset, stripZeroTime) { if (stripZeroTime === void 0) { stripZeroTime = false; } var s = marker.toISOString(); s = s.replace('.000', ''); if (stripZeroTime) { s = s.replace('T00:00:00Z', ''); } if (s.length > 10) { // time part wasn't stripped, can add timezone info if (timeZoneOffset == null) { s = s.replace('Z', ''); } else if (timeZoneOffset !== 0) { s = s.replace('Z', formatTimeZoneOffset(timeZoneOffset, true)); } // otherwise, its UTC-0 and we want to keep the Z } return s; } function formatIsoTimeString(marker) { return padStart(marker.getUTCHours(), 2) + ':' + padStart(marker.getUTCMinutes(), 2) + ':' + padStart(marker.getUTCSeconds(), 2); } function formatTimeZoneOffset(minutes, doIso) { if (doIso === void 0) { doIso = false; } var sign = minutes < 0 ? '-' : '+'; var abs = Math.abs(minutes); var hours = Math.floor(abs / 60); var mins = Math.round(abs % 60); if (doIso) { return sign + padStart(hours, 2) + ':' + padStart(mins, 2); } else { return 'GMT' + sign + hours + (mins ? ':' + padStart(mins, 2) : ''); } } // Arg Utils function createVerboseFormattingArg(start, end, context, separator) { var startInfo = expandZonedMarker(start, context.calendarSystem); var endInfo = end ? expandZonedMarker(end, context.calendarSystem) : null; return { date: startInfo, start: startInfo, end: endInfo, timeZone: context.timeZone, localeCodes: context.locale.codes, separator: separator }; } function expandZonedMarker(dateInfo, calendarSystem) { var a = calendarSystem.markerToArray(dateInfo.marker); return { marker: dateInfo.marker, timeZoneOffset: dateInfo.timeZoneOffset, array: a, year: a[0], month: a[1], day: a[2], hour: a[3], minute: a[4], second: a[5], millisecond: a[6] }; } var EventSourceApi = /** @class */ (function () { function EventSourceApi(calendar, internalEventSource) { this.calendar = calendar; this.internalEventSource = internalEventSource; } EventSourceApi.prototype.remove = function () { this.calendar.dispatch({ type: 'REMOVE_EVENT_SOURCE', sourceId: this.internalEventSource.sourceId }); }; EventSourceApi.prototype.refetch = function () { this.calendar.dispatch({ type: 'FETCH_EVENT_SOURCES', sourceIds: [this.internalEventSource.sourceId] }); }; Object.defineProperty(EventSourceApi.prototype, "id", { get: function () { return this.internalEventSource.publicId; }, enumerable: true, configurable: true }); Object.defineProperty(EventSourceApi.prototype, "url", { // only relevant to json-feed event sources get: function () { return this.internalEventSource.meta.url; }, enumerable: true, configurable: true }); return EventSourceApi; }()); var EventApi = /** @class */ (function () { function EventApi(calendar, def, instance) { this._calendar = calendar; this._def = def; this._instance = instance || null; } /* TODO: make event struct more responsible for this */ EventApi.prototype.setProp = function (name, val) { var _a, _b; if (name in DATE_PROPS) ; else if (name in NON_DATE_PROPS) { if (typeof NON_DATE_PROPS[name] === 'function') { val = NON_DATE_PROPS[name](val); } this.mutate({ standardProps: (_a = {}, _a[name] = val, _a) }); } else if (name in UNSCOPED_EVENT_UI_PROPS) { var ui = void 0; if (typeof UNSCOPED_EVENT_UI_PROPS[name] === 'function') { val = UNSCOPED_EVENT_UI_PROPS[name](val); } if (name === 'color') { ui = { backgroundColor: val, borderColor: val }; } else if (name === 'editable') { ui = { startEditable: val, durationEditable: val }; } else { ui = (_b = {}, _b[name] = val, _b); } this.mutate({ standardProps: { ui: ui } }); } }; EventApi.prototype.setExtendedProp = function (name, val) { var _a; this.mutate({ extendedProps: (_a = {}, _a[name] = val, _a) }); }; EventApi.prototype.setStart = function (startInput, options) { if (options === void 0) { options = {}; } var dateEnv = this._calendar.dateEnv; var start = dateEnv.createMarker(startInput); if (start && this._instance) { // TODO: warning if parsed bad var instanceRange = this._instance.range; var startDelta = diffDates(instanceRange.start, start, dateEnv, options.granularity); // what if parsed bad!? if (options.maintainDuration) { this.mutate({ datesDelta: startDelta }); } else { this.mutate({ startDelta: startDelta }); } } }; EventApi.prototype.setEnd = function (endInput, options) { if (options === void 0) { options = {}; } var dateEnv = this._calendar.dateEnv; var end; if (endInput != null) { end = dateEnv.createMarker(endInput); if (!end) { return; // TODO: warning if parsed bad } } if (this._instance) { if (end) { var endDelta = diffDates(this._instance.range.end, end, dateEnv, options.granularity); this.mutate({ endDelta: endDelta }); } else { this.mutate({ standardProps: { hasEnd: false } }); } } }; EventApi.prototype.setDates = function (startInput, endInput, options) { if (options === void 0) { options = {}; } var dateEnv = this._calendar.dateEnv; var standardProps = { allDay: options.allDay }; var start = dateEnv.createMarker(startInput); var end; if (!start) { return; // TODO: warning if parsed bad } if (endInput != null) { end = dateEnv.createMarker(endInput); if (!end) { // TODO: warning if parsed bad return; } } if (this._instance) { var instanceRange = this._instance.range; // when computing the diff for an event being converted to all-day, // compute diff off of the all-day values the way event-mutation does. if (options.allDay === true) { instanceRange = computeAlignedDayRange(instanceRange); } var startDelta = diffDates(instanceRange.start, start, dateEnv, options.granularity); if (end) { var endDelta = diffDates(instanceRange.end, end, dateEnv, options.granularity); if (durationsEqual(startDelta, endDelta)) { this.mutate({ datesDelta: startDelta, standardProps: standardProps }); } else { this.mutate({ startDelta: startDelta, endDelta: endDelta, standardProps: standardProps }); } } else { // means "clear the end" standardProps.hasEnd = false; this.mutate({ datesDelta: startDelta, standardProps: standardProps }); } } }; EventApi.prototype.moveStart = function (deltaInput) { var delta = createDuration(deltaInput); if (delta) { // TODO: warning if parsed bad this.mutate({ startDelta: delta }); } }; EventApi.prototype.moveEnd = function (deltaInput) { var delta = createDuration(deltaInput); if (delta) { // TODO: warning if parsed bad this.mutate({ endDelta: delta }); } }; EventApi.prototype.moveDates = function (deltaInput) { var delta = createDuration(deltaInput); if (delta) { // TODO: warning if parsed bad this.mutate({ datesDelta: delta }); } }; EventApi.prototype.setAllDay = function (allDay, options) { if (options === void 0) { options = {}; } var standardProps = { allDay: allDay }; var maintainDuration = options.maintainDuration; if (maintainDuration == null) { maintainDuration = this._calendar.opt('allDayMaintainDuration'); } if (this._def.allDay !== allDay) { standardProps.hasEnd = maintainDuration; } this.mutate({ standardProps: standardProps }); }; EventApi.prototype.formatRange = function (formatInput) { var dateEnv = this._calendar.dateEnv; var instance = this._instance; var formatter = createFormatter(formatInput, this._calendar.opt('defaultRangeSeparator')); if (this._def.hasEnd) { return dateEnv.formatRange(instance.range.start, instance.range.end, formatter, { forcedStartTzo: instance.forcedStartTzo, forcedEndTzo: instance.forcedEndTzo }); } else { return dateEnv.format(instance.range.start, formatter, { forcedTzo: instance.forcedStartTzo }); } }; EventApi.prototype.mutate = function (mutation) { var def = this._def; var instance = this._instance; if (instance) { this._calendar.dispatch({ type: 'MUTATE_EVENTS', instanceId: instance.instanceId, mutation: mutation, fromApi: true }); var eventStore = this._calendar.state.eventStore; this._def = eventStore.defs[def.defId]; this._instance = eventStore.instances[instance.instanceId]; } }; EventApi.prototype.remove = function () { this._calendar.dispatch({ type: 'REMOVE_EVENT_DEF', defId: this._def.defId }); }; Object.defineProperty(EventApi.prototype, "source", { get: function () { var sourceId = this._def.sourceId; if (sourceId) { return new EventSourceApi(this._calendar, this._calendar.state.eventSources[sourceId]); } return null; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "start", { get: function () { return this._instance ? this._calendar.dateEnv.toDate(this._instance.range.start) : null; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "end", { get: function () { return (this._instance && this._def.hasEnd) ? this._calendar.dateEnv.toDate(this._instance.range.end) : null; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "id", { // computable props that all access the def // TODO: find a TypeScript-compatible way to do this at scale get: function () { return this._def.publicId; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "groupId", { get: function () { return this._def.groupId; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "allDay", { get: function () { return this._def.allDay; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "title", { get: function () { return this._def.title; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "url", { get: function () { return this._def.url; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "rendering", { get: function () { return this._def.rendering; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "startEditable", { get: function () { return this._def.ui.startEditable; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "durationEditable", { get: function () { return this._def.ui.durationEditable; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "constraint", { get: function () { return this._def.ui.constraints[0] || null; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "overlap", { get: function () { return this._def.ui.overlap; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "allow", { get: function () { return this._def.ui.allows[0] || null; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "backgroundColor", { get: function () { return this._def.ui.backgroundColor; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "borderColor", { get: function () { return this._def.ui.borderColor; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "textColor", { get: function () { return this._def.ui.textColor; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "classNames", { // NOTE: user can't modify these because Object.freeze was called in event-def parsing get: function () { return this._def.ui.classNames; }, enumerable: true, configurable: true }); Object.defineProperty(EventApi.prototype, "extendedProps", { get: function () { return this._def.extendedProps; }, enumerable: true, configurable: true }); return EventApi; }()); /* Specifying nextDayThreshold signals that all-day ranges should be sliced. */ function sliceEventStore(eventStore, eventUiBases, framingRange, nextDayThreshold) { var inverseBgByGroupId = {}; var inverseBgByDefId = {}; var defByGroupId = {}; var bgRanges = []; var fgRanges = []; var eventUis = compileEventUis(eventStore.defs, eventUiBases); for (var defId in eventStore.defs) { var def = eventStore.defs[defId]; if (def.rendering === 'inverse-background') { if (def.groupId) { inverseBgByGroupId[def.groupId] = []; if (!defByGroupId[def.groupId]) { defByGroupId[def.groupId] = def; } } else { inverseBgByDefId[defId] = []; } } } for (var instanceId in eventStore.instances) { var instance = eventStore.instances[instanceId]; var def = eventStore.defs[instance.defId]; var ui = eventUis[def.defId]; var origRange = instance.range; var normalRange = (!def.allDay && nextDayThreshold) ? computeVisibleDayRange(origRange, nextDayThreshold) : origRange; var slicedRange = intersectRanges(normalRange, framingRange); if (slicedRange) { if (def.rendering === 'inverse-background') { if (def.groupId) { inverseBgByGroupId[def.groupId].push(slicedRange); } else { inverseBgByDefId[instance.defId].push(slicedRange); } } else { (def.rendering === 'background' ? bgRanges : fgRanges).push({ def: def, ui: ui, instance: instance, range: slicedRange, isStart: normalRange.start && normalRange.start.valueOf() === slicedRange.start.valueOf(), isEnd: normalRange.end && normalRange.end.valueOf() === slicedRange.end.valueOf() }); } } } for (var groupId in inverseBgByGroupId) { // BY GROUP var ranges = inverseBgByGroupId[groupId]; var invertedRanges = invertRanges(ranges, framingRange); for (var _i = 0, invertedRanges_1 = invertedRanges; _i < invertedRanges_1.length; _i++) { var invertedRange = invertedRanges_1[_i]; var def = defByGroupId[groupId]; var ui = eventUis[def.defId]; bgRanges.push({ def: def, ui: ui, instance: null, range: invertedRange, isStart: false, isEnd: false }); } } for (var defId in inverseBgByDefId) { var ranges = inverseBgByDefId[defId]; var invertedRanges = invertRanges(ranges, framingRange); for (var _a = 0, invertedRanges_2 = invertedRanges; _a < invertedRanges_2.length; _a++) { var invertedRange = invertedRanges_2[_a]; bgRanges.push({ def: eventStore.defs[defId], ui: eventUis[defId], instance: null, range: invertedRange, isStart: false, isEnd: false }); } } return { bg: bgRanges, fg: fgRanges }; } function hasBgRendering(def) { return def.rendering === 'background' || def.rendering === 'inverse-background'; } function filterSegsViaEls(context, segs, isMirror) { var calendar = context.calendar, view = context.view; if (calendar.hasPublicHandlers('eventRender')) { segs = segs.filter(function (seg) { var custom = calendar.publiclyTrigger('eventRender', [ { event: new EventApi(calendar, seg.eventRange.def, seg.eventRange.instance), isMirror: isMirror, isStart: seg.isStart, isEnd: seg.isEnd, // TODO: include seg.range once all components consistently generate it el: seg.el, view: view } ]); if (custom === false) { // means don't render at all return false; } else if (custom && custom !== true) { seg.el = custom; } return true; }); } for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) { var seg = segs_1[_i]; setElSeg(seg.el, seg); } return segs; } function setElSeg(el, seg) { el.fcSeg = seg; } function getElSeg(el) { return el.fcSeg || null; } // event ui computation function compileEventUis(eventDefs, eventUiBases) { return mapHash(eventDefs, function (eventDef) { return compileEventUi(eventDef, eventUiBases); }); } function compileEventUi(eventDef, eventUiBases) { var uis = []; if (eventUiBases['']) { uis.push(eventUiBases['']); } if (eventUiBases[eventDef.defId]) { uis.push(eventUiBases[eventDef.defId]); } uis.push(eventDef.ui); return combineEventUis(uis); } // triggers function triggerRenderedSegs(context, segs, isMirrors) { var calendar = context.calendar, view = context.view; if (calendar.hasPublicHandlers('eventPositioned')) { for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) { var seg = segs_2[_i]; calendar.publiclyTriggerAfterSizing('eventPositioned', [ { event: new EventApi(calendar, seg.eventRange.def, seg.eventRange.instance), isMirror: isMirrors, isStart: seg.isStart, isEnd: seg.isEnd, el: seg.el, view: view } ]); } } if (!calendar.state.loadingLevel) { // avoid initial empty state while pending calendar.afterSizingTriggers._eventsPositioned = [null]; // fire once } } function triggerWillRemoveSegs(context, segs, isMirrors) { var calendar = context.calendar, view = context.view; for (var _i = 0, segs_3 = segs; _i < segs_3.length; _i++) { var seg = segs_3[_i]; calendar.trigger('eventElRemove', seg.el); } if (calendar.hasPublicHandlers('eventDestroy')) { for (var _a = 0, segs_4 = segs; _a < segs_4.length; _a++) { var seg = segs_4[_a]; calendar.publiclyTrigger('eventDestroy', [ { event: new EventApi(calendar, seg.eventRange.def, seg.eventRange.instance), isMirror: isMirrors, el: seg.el, view: view } ]); } } } // is-interactable function computeEventDraggable(context, eventDef, eventUi) { var calendar = context.calendar, view = context.view; var transformers = calendar.pluginSystem.hooks.isDraggableTransformers; var val = eventUi.startEditable; for (var _i = 0, transformers_1 = transformers; _i < transformers_1.length; _i++) { var transformer = transformers_1[_i]; val = transformer(val, eventDef, eventUi, view); } return val; } function computeEventStartResizable(context, eventDef, eventUi) { return eventUi.durationEditable && context.options.eventResizableFromStart; } function computeEventEndResizable(context, eventDef, eventUi) { return eventUi.durationEditable; } // applies the mutation to ALL defs/instances within the event store function applyMutationToEventStore(eventStore, eventConfigBase, mutation, calendar) { var eventConfigs = compileEventUis(eventStore.defs, eventConfigBase); var dest = createEmptyEventStore(); for (var defId in eventStore.defs) { var def = eventStore.defs[defId]; dest.defs[defId] = applyMutationToEventDef(def, eventConfigs[defId], mutation, calendar.pluginSystem.hooks.eventDefMutationAppliers, calendar); } for (var instanceId in eventStore.instances) { var instance = eventStore.instances[instanceId]; var def = dest.defs[instance.defId]; // important to grab the newly modified def dest.instances[instanceId] = applyMutationToEventInstance(instance, def, eventConfigs[instance.defId], mutation, calendar); } return dest; } function applyMutationToEventDef(eventDef, eventConfig, mutation, appliers, calendar) { var standardProps = mutation.standardProps || {}; // if hasEnd has not been specified, guess a good value based on deltas. // if duration will change, there's no way the default duration will persist, // and thus, we need to mark the event as having a real end if (standardProps.hasEnd == null && eventConfig.durationEditable && (mutation.startDelta || mutation.endDelta)) { standardProps.hasEnd = true; // TODO: is this mutation okay? } var copy = __assign({}, eventDef, standardProps, { ui: __assign({}, eventDef.ui, standardProps.ui) }); if (mutation.extendedProps) { copy.extendedProps = __assign({}, copy.extendedProps, mutation.extendedProps); } for (var _i = 0, appliers_1 = appliers; _i < appliers_1.length; _i++) { var applier = appliers_1[_i]; applier(copy, mutation, calendar); } if (!copy.hasEnd && calendar.opt('forceEventDuration')) { copy.hasEnd = true; } return copy; } function applyMutationToEventInstance(eventInstance, eventDef, // must first be modified by applyMutationToEventDef eventConfig, mutation, calendar) { var dateEnv = calendar.dateEnv; var forceAllDay = mutation.standardProps && mutation.standardProps.allDay === true; var clearEnd = mutation.standardProps && mutation.standardProps.hasEnd === false; var copy = __assign({}, eventInstance); if (forceAllDay) { copy.range = computeAlignedDayRange(copy.range); } if (mutation.datesDelta && eventConfig.startEditable) { copy.range = { start: dateEnv.add(copy.range.start, mutation.datesDelta), end: dateEnv.add(copy.range.end, mutation.datesDelta) }; } if (mutation.startDelta && eventConfig.durationEditable) { copy.range = { start: dateEnv.add(copy.range.start, mutation.startDelta), end: copy.range.end }; } if (mutation.endDelta && eventConfig.durationEditable) { copy.range = { start: copy.range.start, end: dateEnv.add(copy.range.end, mutation.endDelta) }; } if (clearEnd) { copy.range = { start: copy.range.start, end: calendar.getDefaultEventEnd(eventDef.allDay, copy.range.start) }; } // in case event was all-day but the supplied deltas were not // better util for this? if (eventDef.allDay) { copy.range = { start: startOfDay(copy.range.start), end: startOfDay(copy.range.end) }; } // handle invalid durations if (copy.range.end < copy.range.start) { copy.range.end = calendar.getDefaultEventEnd(eventDef.allDay, copy.range.start); } return copy; } function reduceEventStore (eventStore, action, eventSources, dateProfile, calendar) { switch (action.type) { case 'RECEIVE_EVENTS': // raw return receiveRawEvents(eventStore, eventSources[action.sourceId], action.fetchId, action.fetchRange, action.rawEvents, calendar); case 'ADD_EVENTS': // already parsed, but not expanded return addEvent(eventStore, action.eventStore, // new ones dateProfile ? dateProfile.activeRange : null, calendar); case 'MERGE_EVENTS': // already parsed and expanded return mergeEventStores(eventStore, action.eventStore); case 'PREV': // TODO: how do we track all actions that affect dateProfile :( case 'NEXT': case 'SET_DATE': case 'SET_VIEW_TYPE': if (dateProfile) { return expandRecurring(eventStore, dateProfile.activeRange, calendar); } else { return eventStore; } case 'CHANGE_TIMEZONE': return rezoneDates(eventStore, action.oldDateEnv, calendar.dateEnv); case 'MUTATE_EVENTS': return applyMutationToRelated(eventStore, action.instanceId, action.mutation, action.fromApi, calendar); case 'REMOVE_EVENT_INSTANCES': return excludeInstances(eventStore, action.instances); case 'REMOVE_EVENT_DEF': return filterEventStoreDefs(eventStore, function (eventDef) { return eventDef.defId !== action.defId; }); case 'REMOVE_EVENT_SOURCE': return excludeEventsBySourceId(eventStore, action.sourceId); case 'REMOVE_ALL_EVENT_SOURCES': return filterEventStoreDefs(eventStore, function (eventDef) { return !eventDef.sourceId; // only keep events with no source id }); case 'REMOVE_ALL_EVENTS': return createEmptyEventStore(); case 'RESET_EVENTS': return { defs: eventStore.defs, instances: eventStore.instances }; default: return eventStore; } } function receiveRawEvents(eventStore, eventSource, fetchId, fetchRange, rawEvents, calendar) { if (eventSource && // not already removed fetchId === eventSource.latestFetchId // TODO: wish this logic was always in event-sources ) { var subset = parseEvents(transformRawEvents(rawEvents, eventSource, calendar), eventSource.sourceId, calendar); if (fetchRange) { subset = expandRecurring(subset, fetchRange, calendar); } return mergeEventStores(excludeEventsBySourceId(eventStore, eventSource.sourceId), subset); } return eventStore; } function addEvent(eventStore, subset, expandRange, calendar) { if (expandRange) { subset = expandRecurring(subset, expandRange, calendar); } return mergeEventStores(eventStore, subset); } function rezoneDates(eventStore, oldDateEnv, newDateEnv) { var defs = eventStore.defs; var instances = mapHash(eventStore.instances, function (instance) { var def = defs[instance.defId]; if (def.allDay || def.recurringDef) { return instance; // isn't dependent on timezone } else { return __assign({}, instance, { range: { start: newDateEnv.createMarker(oldDateEnv.toDate(instance.range.start, instance.forcedStartTzo)), end: newDateEnv.createMarker(oldDateEnv.toDate(instance.range.end, instance.forcedEndTzo)) }, forcedStartTzo: newDateEnv.canComputeOffset ? null : instance.forcedStartTzo, forcedEndTzo: newDateEnv.canComputeOffset ? null : instance.forcedEndTzo }); } }); return { defs: defs, instances: instances }; } function applyMutationToRelated(eventStore, instanceId, mutation, fromApi, calendar) { var relevant = getRelevantEvents(eventStore, instanceId); var eventConfigBase = fromApi ? { '': { startEditable: true, durationEditable: true, constraints: [], overlap: null, allows: [], backgroundColor: '', borderColor: '', textColor: '', classNames: [] } } : calendar.eventUiBases; relevant = applyMutationToEventStore(relevant, eventConfigBase, mutation, calendar); return mergeEventStores(eventStore, relevant); } function excludeEventsBySourceId(eventStore, sourceId) { return filterEventStoreDefs(eventStore, function (eventDef) { return eventDef.sourceId !== sourceId; }); } // QUESTION: why not just return instances? do a general object-property-exclusion util function excludeInstances(eventStore, removals) { return { defs: eventStore.defs, instances: filterHash(eventStore.instances, function (instance) { return !removals[instance.instanceId]; }) }; } // high-level segmenting-aware tester functions // ------------------------------------------------------------------------------------------------------------------------ function isInteractionValid(interaction, calendar) { return isNewPropsValid({ eventDrag: interaction }, calendar); // HACK: the eventDrag props is used for ALL interactions } function isDateSelectionValid(dateSelection, calendar) { return isNewPropsValid({ dateSelection: dateSelection }, calendar); } function isNewPropsValid(newProps, calendar) { var view = calendar.view; var props = __assign({ businessHours: view ? view.props.businessHours : createEmptyEventStore(), dateSelection: '', eventStore: calendar.state.eventStore, eventUiBases: calendar.eventUiBases, eventSelection: '', eventDrag: null, eventResize: null }, newProps); return (calendar.pluginSystem.hooks.isPropsValid || isPropsValid)(props, calendar); } function isPropsValid(state, calendar, dateSpanMeta, filterConfig) { if (dateSpanMeta === void 0) { dateSpanMeta = {}; } if (state.eventDrag && !isInteractionPropsValid(state, calendar, dateSpanMeta, filterConfig)) { return false; } if (state.dateSelection && !isDateSelectionPropsValid(state, calendar, dateSpanMeta, filterConfig)) { return false; } return true; } // Moving Event Validation // ------------------------------------------------------------------------------------------------------------------------ function isInteractionPropsValid(state, calendar, dateSpanMeta, filterConfig) { var interaction = state.eventDrag; // HACK: the eventDrag props is used for ALL interactions var subjectEventStore = interaction.mutatedEvents; var subjectDefs = subjectEventStore.defs; var subjectInstances = subjectEventStore.instances; var subjectConfigs = compileEventUis(subjectDefs, interaction.isEvent ? state.eventUiBases : { '': calendar.selectionConfig } // if not a real event, validate as a selection ); if (filterConfig) { subjectConfigs = mapHash(subjectConfigs, filterConfig); } var otherEventStore = excludeInstances(state.eventStore, interaction.affectedEvents.instances); // exclude the subject events. TODO: exclude defs too? var otherDefs = otherEventStore.defs; var otherInstances = otherEventStore.instances; var otherConfigs = compileEventUis(otherDefs, state.eventUiBases); for (var subjectInstanceId in subjectInstances) { var subjectInstance = subjectInstances[subjectInstanceId]; var subjectRange = subjectInstance.range; var subjectConfig = subjectConfigs[subjectInstance.defId]; var subjectDef = subjectDefs[subjectInstance.defId]; // constraint if (!allConstraintsPass(subjectConfig.constraints, subjectRange, otherEventStore, state.businessHours, calendar)) { return false; } // overlap var overlapFunc = calendar.opt('eventOverlap'); if (typeof overlapFunc !== 'function') { overlapFunc = null; } for (var otherInstanceId in otherInstances) { var otherInstance = otherInstances[otherInstanceId]; // intersect! evaluate if (rangesIntersect(subjectRange, otherInstance.range)) { var otherOverlap = otherConfigs[otherInstance.defId].overlap; // consider the other event's overlap. only do this if the subject event is a "real" event if (otherOverlap === false && interaction.isEvent) { return false; } if (subjectConfig.overlap === false) { return false; } if (overlapFunc && !overlapFunc(new EventApi(calendar, otherDefs[otherInstance.defId], otherInstance), // still event new EventApi(calendar, subjectDef, subjectInstance) // moving event )) { return false; } } } // allow (a function) var calendarEventStore = calendar.state.eventStore; // need global-to-calendar, not local to component (splittable)state for (var _i = 0, _a = subjectConfig.allows; _i < _a.length; _i++) { var subjectAllow = _a[_i]; var subjectDateSpan = __assign({}, dateSpanMeta, { range: subjectInstance.range, allDay: subjectDef.allDay }); var origDef = calendarEventStore.defs[subjectDef.defId]; var origInstance = calendarEventStore.instances[subjectInstanceId]; var eventApi = void 0; if (origDef) { // was previously in the calendar eventApi = new EventApi(calendar, origDef, origInstance); } else { // was an external event eventApi = new EventApi(calendar, subjectDef); // no instance, because had no dates } if (!subjectAllow(calendar.buildDateSpanApi(subjectDateSpan), eventApi)) { return false; } } } return true; } // Date Selection Validation // ------------------------------------------------------------------------------------------------------------------------ function isDateSelectionPropsValid(state, calendar, dateSpanMeta, filterConfig) { var relevantEventStore = state.eventStore; var relevantDefs = relevantEventStore.defs; var relevantInstances = relevantEventStore.instances; var selection = state.dateSelection; var selectionRange = selection.range; var selectionConfig = calendar.selectionConfig; if (filterConfig) { selectionConfig = filterConfig(selectionConfig); } // constraint if (!allConstraintsPass(selectionConfig.constraints, selectionRange, relevantEventStore, state.businessHours, calendar)) { return false; } // overlap var overlapFunc = calendar.opt('selectOverlap'); if (typeof overlapFunc !== 'function') { overlapFunc = null; } for (var relevantInstanceId in relevantInstances) { var relevantInstance = relevantInstances[relevantInstanceId]; // intersect! evaluate if (rangesIntersect(selectionRange, relevantInstance.range)) { if (selectionConfig.overlap === false) { return false; } if (overlapFunc && !overlapFunc(new EventApi(calendar, relevantDefs[relevantInstance.defId], relevantInstance))) { return false; } } } // allow (a function) for (var _i = 0, _a = selectionConfig.allows; _i < _a.length; _i++) { var selectionAllow = _a[_i]; var fullDateSpan = __assign({}, dateSpanMeta, selection); if (!selectionAllow(calendar.buildDateSpanApi(fullDateSpan), null)) { return false; } } return true; } // Constraint Utils // ------------------------------------------------------------------------------------------------------------------------ function allConstraintsPass(constraints, subjectRange, otherEventStore, businessHoursUnexpanded, calendar) { for (var _i = 0, constraints_1 = constraints; _i < constraints_1.length; _i++) { var constraint = constraints_1[_i]; if (!anyRangesContainRange(constraintToRanges(constraint, subjectRange, otherEventStore, businessHoursUnexpanded, calendar), subjectRange)) { return false; } } return true; } function constraintToRanges(constraint, subjectRange, // for expanding a recurring constraint, or expanding business hours otherEventStore, // for if constraint is an even group ID businessHoursUnexpanded, // for if constraint is 'businessHours' calendar // for expanding businesshours ) { if (constraint === 'businessHours') { return eventStoreToRanges(expandRecurring(businessHoursUnexpanded, subjectRange, calendar)); } else if (typeof constraint === 'string') { // an group ID return eventStoreToRanges(filterEventStoreDefs(otherEventStore, function (eventDef) { return eventDef.groupId === constraint; })); } else if (typeof constraint === 'object' && constraint) { // non-null object return eventStoreToRanges(expandRecurring(constraint, subjectRange, calendar)); } return []; // if it's false } // TODO: move to event-store file? function eventStoreToRanges(eventStore) { var instances = eventStore.instances; var ranges = []; for (var instanceId in instances) { ranges.push(instances[instanceId].range); } return ranges; } // TODO: move to geom file? function anyRangesContainRange(outerRanges, innerRange) { for (var _i = 0, outerRanges_1 = outerRanges; _i < outerRanges_1.length; _i++) { var outerRange = outerRanges_1[_i]; if (rangeContainsRange(outerRange, innerRange)) { return true; } } return false; } // Parsing // ------------------------------------------------------------------------------------------------------------------------ function normalizeConstraint(input, calendar) { if (Array.isArray(input)) { return parseEvents(input, '', calendar, true); // allowOpenRange=true } else if (typeof input === 'object' && input) { // non-null object return parseEvents([input], '', calendar, true); // allowOpenRange=true } else if (input != null) { return String(input); } else { return null; } } function htmlEscape(s) { return (s + '').replace(/&/g, '&') .replace(//g, '>') .replace(/'/g, ''') .replace(/"/g, '"') .replace(/\n/g, '
'); } // Given a hash of CSS properties, returns a string of CSS. // Uses property names as-is (no camel-case conversion). Will not make statements for null/undefined values. function cssToStr(cssProps) { var statements = []; for (var name_1 in cssProps) { var val = cssProps[name_1]; if (val != null && val !== '') { statements.push(name_1 + ':' + val); } } return statements.join(';'); } // Given an object hash of HTML attribute names to values, // generates a string that can be injected between < > in HTML function attrsToStr(attrs) { var parts = []; for (var name_2 in attrs) { var val = attrs[name_2]; if (val != null) { parts.push(name_2 + '="' + htmlEscape(val) + '"'); } } return parts.join(' '); } function parseClassName(raw) { if (Array.isArray(raw)) { return raw; } else if (typeof raw === 'string') { return raw.split(/\s+/); } else { return []; } } var UNSCOPED_EVENT_UI_PROPS = { editable: Boolean, startEditable: Boolean, durationEditable: Boolean, constraint: null, overlap: null, allow: null, className: parseClassName, classNames: parseClassName, color: String, backgroundColor: String, borderColor: String, textColor: String }; function processUnscopedUiProps(rawProps, calendar, leftovers) { var props = refineProps(rawProps, UNSCOPED_EVENT_UI_PROPS, {}, leftovers); var constraint = normalizeConstraint(props.constraint, calendar); return { startEditable: props.startEditable != null ? props.startEditable : props.editable, durationEditable: props.durationEditable != null ? props.durationEditable : props.editable, constraints: constraint != null ? [constraint] : [], overlap: props.overlap, allows: props.allow != null ? [props.allow] : [], backgroundColor: props.backgroundColor || props.color, borderColor: props.borderColor || props.color, textColor: props.textColor, classNames: props.classNames.concat(props.className) }; } function processScopedUiProps(prefix, rawScoped, calendar, leftovers) { var rawUnscoped = {}; var wasFound = {}; for (var key in UNSCOPED_EVENT_UI_PROPS) { var scopedKey = prefix + capitaliseFirstLetter(key); rawUnscoped[key] = rawScoped[scopedKey]; wasFound[scopedKey] = true; } if (prefix === 'event') { rawUnscoped.editable = rawScoped.editable; // special case. there is no 'eventEditable', just 'editable' } if (leftovers) { for (var key in rawScoped) { if (!wasFound[key]) { leftovers[key] = rawScoped[key]; } } } return processUnscopedUiProps(rawUnscoped, calendar); } var EMPTY_EVENT_UI = { startEditable: null, durationEditable: null, constraints: [], overlap: null, allows: [], backgroundColor: '', borderColor: '', textColor: '', classNames: [] }; // prevent against problems with <2 args! function combineEventUis(uis) { return uis.reduce(combineTwoEventUis, EMPTY_EVENT_UI); } function combineTwoEventUis(item0, item1) { return { startEditable: item1.startEditable != null ? item1.startEditable : item0.startEditable, durationEditable: item1.durationEditable != null ? item1.durationEditable : item0.durationEditable, constraints: item0.constraints.concat(item1.constraints), overlap: typeof item1.overlap === 'boolean' ? item1.overlap : item0.overlap, allows: item0.allows.concat(item1.allows), backgroundColor: item1.backgroundColor || item0.backgroundColor, borderColor: item1.borderColor || item0.borderColor, textColor: item1.textColor || item0.textColor, classNames: item0.classNames.concat(item1.classNames) }; } var NON_DATE_PROPS = { id: String, groupId: String, title: String, url: String, rendering: String, extendedProps: null }; var DATE_PROPS = { start: null, date: null, end: null, allDay: null }; var uid = 0; function parseEvent(raw, sourceId, calendar, allowOpenRange) { var allDayDefault = computeIsAllDayDefault(sourceId, calendar); var leftovers0 = {}; var recurringRes = parseRecurring(raw, // raw, but with single-event stuff stripped out allDayDefault, calendar.dateEnv, calendar.pluginSystem.hooks.recurringTypes, leftovers0 // will populate with non-recurring props ); if (recurringRes) { var def = parseEventDef(leftovers0, sourceId, recurringRes.allDay, Boolean(recurringRes.duration), calendar); def.recurringDef = { typeId: recurringRes.typeId, typeData: recurringRes.typeData, duration: recurringRes.duration }; return { def: def, instance: null }; } else { var leftovers1 = {}; var singleRes = parseSingle(raw, allDayDefault, calendar, leftovers1, allowOpenRange); if (singleRes) { var def = parseEventDef(leftovers1, sourceId, singleRes.allDay, singleRes.hasEnd, calendar); var instance = createEventInstance(def.defId, singleRes.range, singleRes.forcedStartTzo, singleRes.forcedEndTzo); return { def: def, instance: instance }; } } return null; } /* Will NOT populate extendedProps with the leftover properties. Will NOT populate date-related props. The EventNonDateInput has been normalized (id => publicId, etc). */ function parseEventDef(raw, sourceId, allDay, hasEnd, calendar) { var leftovers = {}; var def = pluckNonDateProps(raw, calendar, leftovers); def.defId = String(uid++); def.sourceId = sourceId; def.allDay = allDay; def.hasEnd = hasEnd; for (var _i = 0, _a = calendar.pluginSystem.hooks.eventDefParsers; _i < _a.length; _i++) { var eventDefParser = _a[_i]; var newLeftovers = {}; eventDefParser(def, leftovers, newLeftovers); leftovers = newLeftovers; } def.extendedProps = __assign(leftovers, def.extendedProps || {}); // help out EventApi from having user modify props Object.freeze(def.ui.classNames); Object.freeze(def.extendedProps); return def; } function createEventInstance(defId, range, forcedStartTzo, forcedEndTzo) { return { instanceId: String(uid++), defId: defId, range: range, forcedStartTzo: forcedStartTzo == null ? null : forcedStartTzo, forcedEndTzo: forcedEndTzo == null ? null : forcedEndTzo }; } function parseSingle(raw, allDayDefault, calendar, leftovers, allowOpenRange) { var props = pluckDateProps(raw, leftovers); var allDay = props.allDay; var startMeta; var startMarker = null; var hasEnd = false; var endMeta; var endMarker = null; startMeta = calendar.dateEnv.createMarkerMeta(props.start); if (startMeta) { startMarker = startMeta.marker; } else if (!allowOpenRange) { return null; } if (props.end != null) { endMeta = calendar.dateEnv.createMarkerMeta(props.end); } if (allDay == null) { if (allDayDefault != null) { allDay = allDayDefault; } else { // fall back to the date props LAST allDay = (!startMeta || startMeta.isTimeUnspecified) && (!endMeta || endMeta.isTimeUnspecified); } } if (allDay && startMarker) { startMarker = startOfDay(startMarker); } if (endMeta) { endMarker = endMeta.marker; if (allDay) { endMarker = startOfDay(endMarker); } if (startMarker && endMarker <= startMarker) { endMarker = null; } } if (endMarker) { hasEnd = true; } else if (!allowOpenRange) { hasEnd = calendar.opt('forceEventDuration') || false; endMarker = calendar.dateEnv.add(startMarker, allDay ? calendar.defaultAllDayEventDuration : calendar.defaultTimedEventDuration); } return { allDay: allDay, hasEnd: hasEnd, range: { start: startMarker, end: endMarker }, forcedStartTzo: startMeta ? startMeta.forcedTzo : null, forcedEndTzo: endMeta ? endMeta.forcedTzo : null }; } function pluckDateProps(raw, leftovers) { var props = refineProps(raw, DATE_PROPS, {}, leftovers); props.start = (props.start !== null) ? props.start : props.date; delete props.date; return props; } function pluckNonDateProps(raw, calendar, leftovers) { var preLeftovers = {}; var props = refineProps(raw, NON_DATE_PROPS, {}, preLeftovers); var ui = processUnscopedUiProps(preLeftovers, calendar, leftovers); props.publicId = props.id; delete props.id; props.ui = ui; return props; } function computeIsAllDayDefault(sourceId, calendar) { var res = null; if (sourceId) { var source = calendar.state.eventSources[sourceId]; res = source.allDayDefault; } if (res == null) { res = calendar.opt('allDayDefault'); } return res; } var DEF_DEFAULTS = { startTime: '09:00', endTime: '17:00', daysOfWeek: [1, 2, 3, 4, 5], rendering: 'inverse-background', classNames: 'fc-nonbusiness', groupId: '_businessHours' // so multiple defs get grouped }; /* TODO: pass around as EventDefHash!!! */ function parseBusinessHours(input, calendar) { return parseEvents(refineInputs(input), '', calendar); } function refineInputs(input) { var rawDefs; if (input === true) { rawDefs = [{}]; // will get DEF_DEFAULTS verbatim } else if (Array.isArray(input)) { // if specifying an array, every sub-definition NEEDS a day-of-week rawDefs = input.filter(function (rawDef) { return rawDef.daysOfWeek; }); } else if (typeof input === 'object' && input) { // non-null object rawDefs = [input]; } else { // is probably false rawDefs = []; } rawDefs = rawDefs.map(function (rawDef) { return __assign({}, DEF_DEFAULTS, rawDef); }); return rawDefs; } function memoizeRendering(renderFunc, unrenderFunc, dependencies) { if (dependencies === void 0) { dependencies = []; } var dependents = []; var thisContext; var prevArgs; function unrender() { if (prevArgs) { for (var _i = 0, dependents_1 = dependents; _i < dependents_1.length; _i++) { var dependent = dependents_1[_i]; dependent.unrender(); } if (unrenderFunc) { unrenderFunc.apply(thisContext, prevArgs); } prevArgs = null; } } function res() { if (!prevArgs || !isArraysEqual(prevArgs, arguments)) { unrender(); thisContext = this; prevArgs = arguments; renderFunc.apply(this, arguments); } } res.dependents = dependents; res.unrender = unrender; for (var _i = 0, dependencies_1 = dependencies; _i < dependencies_1.length; _i++) { var dependency = dependencies_1[_i]; dependency.dependents.push(res); } return res; } var EMPTY_EVENT_STORE = createEmptyEventStore(); // for purecomponents. TODO: keep elsewhere var Splitter = /** @class */ (function () { function Splitter() { this.getKeysForEventDefs = memoize(this._getKeysForEventDefs); this.splitDateSelection = memoize(this._splitDateSpan); this.splitEventStore = memoize(this._splitEventStore); this.splitIndividualUi = memoize(this._splitIndividualUi); this.splitEventDrag = memoize(this._splitInteraction); this.splitEventResize = memoize(this._splitInteraction); this.eventUiBuilders = {}; // TODO: typescript protection } Splitter.prototype.splitProps = function (props) { var _this = this; var keyInfos = this.getKeyInfo(props); var defKeys = this.getKeysForEventDefs(props.eventStore); var dateSelections = this.splitDateSelection(props.dateSelection); var individualUi = this.splitIndividualUi(props.eventUiBases, defKeys); // the individual *bases* var eventStores = this.splitEventStore(props.eventStore, defKeys); var eventDrags = this.splitEventDrag(props.eventDrag); var eventResizes = this.splitEventResize(props.eventResize); var splitProps = {}; this.eventUiBuilders = mapHash(keyInfos, function (info, key) { return _this.eventUiBuilders[key] || memoize(buildEventUiForKey); }); for (var key in keyInfos) { var keyInfo = keyInfos[key]; var eventStore = eventStores[key] || EMPTY_EVENT_STORE; var buildEventUi = this.eventUiBuilders[key]; splitProps[key] = { businessHours: keyInfo.businessHours || props.businessHours, dateSelection: dateSelections[key] || null, eventStore: eventStore, eventUiBases: buildEventUi(props.eventUiBases[''], keyInfo.ui, individualUi[key]), eventSelection: eventStore.instances[props.eventSelection] ? props.eventSelection : '', eventDrag: eventDrags[key] || null, eventResize: eventResizes[key] || null }; } return splitProps; }; Splitter.prototype._splitDateSpan = function (dateSpan) { var dateSpans = {}; if (dateSpan) { var keys = this.getKeysForDateSpan(dateSpan); for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) { var key = keys_1[_i]; dateSpans[key] = dateSpan; } } return dateSpans; }; Splitter.prototype._getKeysForEventDefs = function (eventStore) { var _this = this; return mapHash(eventStore.defs, function (eventDef) { return _this.getKeysForEventDef(eventDef); }); }; Splitter.prototype._splitEventStore = function (eventStore, defKeys) { var defs = eventStore.defs, instances = eventStore.instances; var splitStores = {}; for (var defId in defs) { for (var _i = 0, _a = defKeys[defId]; _i < _a.length; _i++) { var key = _a[_i]; if (!splitStores[key]) { splitStores[key] = createEmptyEventStore(); } splitStores[key].defs[defId] = defs[defId]; } } for (var instanceId in instances) { var instance = instances[instanceId]; for (var _b = 0, _c = defKeys[instance.defId]; _b < _c.length; _b++) { var key = _c[_b]; if (splitStores[key]) { // must have already been created splitStores[key].instances[instanceId] = instance; } } } return splitStores; }; Splitter.prototype._splitIndividualUi = function (eventUiBases, defKeys) { var splitHashes = {}; for (var defId in eventUiBases) { if (defId) { // not the '' key for (var _i = 0, _a = defKeys[defId]; _i < _a.length; _i++) { var key = _a[_i]; if (!splitHashes[key]) { splitHashes[key] = {}; } splitHashes[key][defId] = eventUiBases[defId]; } } } return splitHashes; }; Splitter.prototype._splitInteraction = function (interaction) { var splitStates = {}; if (interaction) { var affectedStores_1 = this._splitEventStore(interaction.affectedEvents, this._getKeysForEventDefs(interaction.affectedEvents) // can't use cached. might be events from other calendar ); // can't rely on defKeys because event data is mutated var mutatedKeysByDefId = this._getKeysForEventDefs(interaction.mutatedEvents); var mutatedStores_1 = this._splitEventStore(interaction.mutatedEvents, mutatedKeysByDefId); var populate = function (key) { if (!splitStates[key]) { splitStates[key] = { affectedEvents: affectedStores_1[key] || EMPTY_EVENT_STORE, mutatedEvents: mutatedStores_1[key] || EMPTY_EVENT_STORE, isEvent: interaction.isEvent, origSeg: interaction.origSeg }; } }; for (var key in affectedStores_1) { populate(key); } for (var key in mutatedStores_1) { populate(key); } } return splitStates; }; return Splitter; }()); function buildEventUiForKey(allUi, eventUiForKey, individualUi) { var baseParts = []; if (allUi) { baseParts.push(allUi); } if (eventUiForKey) { baseParts.push(eventUiForKey); } var stuff = { '': combineEventUis(baseParts) }; if (individualUi) { __assign(stuff, individualUi); } return stuff; } // Generates HTML for an anchor to another view into the calendar. // Will either generate an tag or a non-clickable tag, depending on enabled settings. // `gotoOptions` can either be a DateMarker, or an object with the form: // { date, type, forceOff } // `type` is a view-type like "day" or "week". default value is "day". // `attrs` and `innerHtml` are use to generate the rest of the HTML tag. function buildGotoAnchorHtml(allOptions, dateEnv, gotoOptions, attrs, innerHtml) { var date; var type; var forceOff; var finalOptions; if (gotoOptions instanceof Date) { date = gotoOptions; // a single date-like input } else { date = gotoOptions.date; type = gotoOptions.type; forceOff = gotoOptions.forceOff; } finalOptions = { date: dateEnv.formatIso(date, { omitTime: true }), type: type || 'day' }; if (typeof attrs === 'string') { innerHtml = attrs; attrs = null; } attrs = attrs ? ' ' + attrsToStr(attrs) : ''; // will have a leading space innerHtml = innerHtml || ''; if (!forceOff && allOptions.navLinks) { return '' + innerHtml + ''; } else { return '' + innerHtml + ''; } } function getAllDayHtml(allOptions) { return allOptions.allDayHtml || htmlEscape(allOptions.allDayText); } // Computes HTML classNames for a single-day element function getDayClasses(date, dateProfile, context, noThemeHighlight) { var calendar = context.calendar, options = context.options, theme = context.theme, dateEnv = context.dateEnv; var classes = []; var todayStart; var todayEnd; if (!rangeContainsMarker(dateProfile.activeRange, date)) { classes.push('fc-disabled-day'); } else { classes.push('fc-' + DAY_IDS[date.getUTCDay()]); if (options.monthMode && dateEnv.getMonth(date) !== dateEnv.getMonth(dateProfile.currentRange.start)) { classes.push('fc-other-month'); } todayStart = startOfDay(calendar.getNow()); todayEnd = addDays(todayStart, 1); if (date < todayStart) { classes.push('fc-past'); } else if (date >= todayEnd) { classes.push('fc-future'); } else { classes.push('fc-today'); if (noThemeHighlight !== true) { classes.push(theme.getClass('today')); } } } return classes; } // given a function that resolves a result asynchronously. // the function can either call passed-in success and failure callbacks, // or it can return a promise. // if you need to pass additional params to func, bind them first. function unpromisify(func, success, failure) { // guard against success/failure callbacks being called more than once // and guard against a promise AND callback being used together. var isResolved = false; var wrappedSuccess = function () { if (!isResolved) { isResolved = true; success.apply(this, arguments); } }; var wrappedFailure = function () { if (!isResolved) { isResolved = true; if (failure) { failure.apply(this, arguments); } } }; var res = func(wrappedSuccess, wrappedFailure); if (res && typeof res.then === 'function') { res.then(wrappedSuccess, wrappedFailure); } } var Mixin = /** @class */ (function () { function Mixin() { } // mix into a CLASS Mixin.mixInto = function (destClass) { this.mixIntoObj(destClass.prototype); }; // mix into ANY object Mixin.mixIntoObj = function (destObj) { var _this = this; Object.getOwnPropertyNames(this.prototype).forEach(function (name) { if (!destObj[name]) { // if destination doesn't already define it destObj[name] = _this.prototype[name]; } }); }; /* will override existing methods TODO: remove! not used anymore */ Mixin.mixOver = function (destClass) { var _this = this; Object.getOwnPropertyNames(this.prototype).forEach(function (name) { destClass.prototype[name] = _this.prototype[name]; }); }; return Mixin; }()); /* USAGE: import { default as EmitterMixin, EmitterInterface } from './EmitterMixin' in class: on: EmitterInterface['on'] one: EmitterInterface['one'] off: EmitterInterface['off'] trigger: EmitterInterface['trigger'] triggerWith: EmitterInterface['triggerWith'] hasHandlers: EmitterInterface['hasHandlers'] after class: EmitterMixin.mixInto(TheClass) */ var EmitterMixin = /** @class */ (function (_super) { __extends(EmitterMixin, _super); function EmitterMixin() { return _super !== null && _super.apply(this, arguments) || this; } EmitterMixin.prototype.on = function (type, handler) { addToHash(this._handlers || (this._handlers = {}), type, handler); return this; // for chaining }; // todo: add comments EmitterMixin.prototype.one = function (type, handler) { addToHash(this._oneHandlers || (this._oneHandlers = {}), type, handler); return this; // for chaining }; EmitterMixin.prototype.off = function (type, handler) { if (this._handlers) { removeFromHash(this._handlers, type, handler); } if (this._oneHandlers) { removeFromHash(this._oneHandlers, type, handler); } return this; // for chaining }; EmitterMixin.prototype.trigger = function (type) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } this.triggerWith(type, this, args); return this; // for chaining }; EmitterMixin.prototype.triggerWith = function (type, context, args) { if (this._handlers) { applyAll(this._handlers[type], context, args); } if (this._oneHandlers) { applyAll(this._oneHandlers[type], context, args); delete this._oneHandlers[type]; // will never fire again } return this; // for chaining }; EmitterMixin.prototype.hasHandlers = function (type) { return (this._handlers && this._handlers[type] && this._handlers[type].length) || (this._oneHandlers && this._oneHandlers[type] && this._oneHandlers[type].length); }; return EmitterMixin; }(Mixin)); function addToHash(hash, type, handler) { (hash[type] || (hash[type] = [])) .push(handler); } function removeFromHash(hash, type, handler) { if (handler) { if (hash[type]) { hash[type] = hash[type].filter(function (func) { return func !== handler; }); } } else { delete hash[type]; // remove all handler funcs for this type } } /* Records offset information for a set of elements, relative to an origin element. Can record the left/right OR the top/bottom OR both. Provides methods for querying the cache by position. */ var PositionCache = /** @class */ (function () { function PositionCache(originEl, els, isHorizontal, isVertical) { this.originEl = originEl; this.els = els; this.isHorizontal = isHorizontal; this.isVertical = isVertical; } // Queries the els for coordinates and stores them. // Call this method before using and of the get* methods below. PositionCache.prototype.build = function () { var originEl = this.originEl; var originClientRect = this.originClientRect = originEl.getBoundingClientRect(); // relative to viewport top-left if (this.isHorizontal) { this.buildElHorizontals(originClientRect.left); } if (this.isVertical) { this.buildElVerticals(originClientRect.top); } }; // Populates the left/right internal coordinate arrays PositionCache.prototype.buildElHorizontals = function (originClientLeft) { var lefts = []; var rights = []; for (var _i = 0, _a = this.els; _i < _a.length; _i++) { var el = _a[_i]; var rect = el.getBoundingClientRect(); lefts.push(rect.left - originClientLeft); rights.push(rect.right - originClientLeft); } this.lefts = lefts; this.rights = rights; }; // Populates the top/bottom internal coordinate arrays PositionCache.prototype.buildElVerticals = function (originClientTop) { var tops = []; var bottoms = []; for (var _i = 0, _a = this.els; _i < _a.length; _i++) { var el = _a[_i]; var rect = el.getBoundingClientRect(); tops.push(rect.top - originClientTop); bottoms.push(rect.bottom - originClientTop); } this.tops = tops; this.bottoms = bottoms; }; // Given a left offset (from document left), returns the index of the el that it horizontally intersects. // If no intersection is made, returns undefined. PositionCache.prototype.leftToIndex = function (leftPosition) { var lefts = this.lefts; var rights = this.rights; var len = lefts.length; var i; for (i = 0; i < len; i++) { if (leftPosition >= lefts[i] && leftPosition < rights[i]) { return i; } } }; // Given a top offset (from document top), returns the index of the el that it vertically intersects. // If no intersection is made, returns undefined. PositionCache.prototype.topToIndex = function (topPosition) { var tops = this.tops; var bottoms = this.bottoms; var len = tops.length; var i; for (i = 0; i < len; i++) { if (topPosition >= tops[i] && topPosition < bottoms[i]) { return i; } } }; // Gets the width of the element at the given index PositionCache.prototype.getWidth = function (leftIndex) { return this.rights[leftIndex] - this.lefts[leftIndex]; }; // Gets the height of the element at the given index PositionCache.prototype.getHeight = function (topIndex) { return this.bottoms[topIndex] - this.tops[topIndex]; }; return PositionCache; }()); /* An object for getting/setting scroll-related information for an element. Internally, this is done very differently for window versus DOM element, so this object serves as a common interface. */ var ScrollController = /** @class */ (function () { function ScrollController() { } ScrollController.prototype.getMaxScrollTop = function () { return this.getScrollHeight() - this.getClientHeight(); }; ScrollController.prototype.getMaxScrollLeft = function () { return this.getScrollWidth() - this.getClientWidth(); }; ScrollController.prototype.canScrollVertically = function () { return this.getMaxScrollTop() > 0; }; ScrollController.prototype.canScrollHorizontally = function () { return this.getMaxScrollLeft() > 0; }; ScrollController.prototype.canScrollUp = function () { return this.getScrollTop() > 0; }; ScrollController.prototype.canScrollDown = function () { return this.getScrollTop() < this.getMaxScrollTop(); }; ScrollController.prototype.canScrollLeft = function () { return this.getScrollLeft() > 0; }; ScrollController.prototype.canScrollRight = function () { return this.getScrollLeft() < this.getMaxScrollLeft(); }; return ScrollController; }()); var ElementScrollController = /** @class */ (function (_super) { __extends(ElementScrollController, _super); function ElementScrollController(el) { var _this = _super.call(this) || this; _this.el = el; return _this; } ElementScrollController.prototype.getScrollTop = function () { return this.el.scrollTop; }; ElementScrollController.prototype.getScrollLeft = function () { return this.el.scrollLeft; }; ElementScrollController.prototype.setScrollTop = function (top) { this.el.scrollTop = top; }; ElementScrollController.prototype.setScrollLeft = function (left) { this.el.scrollLeft = left; }; ElementScrollController.prototype.getScrollWidth = function () { return this.el.scrollWidth; }; ElementScrollController.prototype.getScrollHeight = function () { return this.el.scrollHeight; }; ElementScrollController.prototype.getClientHeight = function () { return this.el.clientHeight; }; ElementScrollController.prototype.getClientWidth = function () { return this.el.clientWidth; }; return ElementScrollController; }(ScrollController)); var WindowScrollController = /** @class */ (function (_super) { __extends(WindowScrollController, _super); function WindowScrollController() { return _super !== null && _super.apply(this, arguments) || this; } WindowScrollController.prototype.getScrollTop = function () { return window.pageYOffset; }; WindowScrollController.prototype.getScrollLeft = function () { return window.pageXOffset; }; WindowScrollController.prototype.setScrollTop = function (n) { window.scroll(window.pageXOffset, n); }; WindowScrollController.prototype.setScrollLeft = function (n) { window.scroll(n, window.pageYOffset); }; WindowScrollController.prototype.getScrollWidth = function () { return document.documentElement.scrollWidth; }; WindowScrollController.prototype.getScrollHeight = function () { return document.documentElement.scrollHeight; }; WindowScrollController.prototype.getClientHeight = function () { return document.documentElement.clientHeight; }; WindowScrollController.prototype.getClientWidth = function () { return document.documentElement.clientWidth; }; return WindowScrollController; }(ScrollController)); /* Embodies a div that has potential scrollbars */ var ScrollComponent = /** @class */ (function (_super) { __extends(ScrollComponent, _super); function ScrollComponent(overflowX, overflowY) { var _this = _super.call(this, createElement('div', { className: 'fc-scroller' })) || this; _this.overflowX = overflowX; _this.overflowY = overflowY; _this.applyOverflow(); return _this; } // sets to natural height, unlocks overflow ScrollComponent.prototype.clear = function () { this.setHeight('auto'); this.applyOverflow(); }; ScrollComponent.prototype.destroy = function () { removeElement(this.el); }; // Overflow // ----------------------------------------------------------------------------------------------------------------- ScrollComponent.prototype.applyOverflow = function () { applyStyle(this.el, { overflowX: this.overflowX, overflowY: this.overflowY }); }; // Causes any 'auto' overflow values to resolves to 'scroll' or 'hidden'. // Useful for preserving scrollbar widths regardless of future resizes. // Can pass in scrollbarWidths for optimization. ScrollComponent.prototype.lockOverflow = function (scrollbarWidths) { var overflowX = this.overflowX; var overflowY = this.overflowY; scrollbarWidths = scrollbarWidths || this.getScrollbarWidths(); if (overflowX === 'auto') { overflowX = (scrollbarWidths.bottom || // horizontal scrollbars? this.canScrollHorizontally() // OR scrolling pane with massless scrollbars? ) ? 'scroll' : 'hidden'; } if (overflowY === 'auto') { overflowY = (scrollbarWidths.left || scrollbarWidths.right || // horizontal scrollbars? this.canScrollVertically() // OR scrolling pane with massless scrollbars? ) ? 'scroll' : 'hidden'; } applyStyle(this.el, { overflowX: overflowX, overflowY: overflowY }); }; ScrollComponent.prototype.setHeight = function (height) { applyStyleProp(this.el, 'height', height); }; ScrollComponent.prototype.getScrollbarWidths = function () { var edges = computeEdges(this.el); return { left: edges.scrollbarLeft, right: edges.scrollbarRight, bottom: edges.scrollbarBottom }; }; return ScrollComponent; }(ElementScrollController)); var Theme = /** @class */ (function () { function Theme(calendarOptions) { this.calendarOptions = calendarOptions; this.processIconOverride(); } Theme.prototype.processIconOverride = function () { if (this.iconOverrideOption) { this.setIconOverride(this.calendarOptions[this.iconOverrideOption]); } }; Theme.prototype.setIconOverride = function (iconOverrideHash) { var iconClassesCopy; var buttonName; if (typeof iconOverrideHash === 'object' && iconOverrideHash) { // non-null object iconClassesCopy = __assign({}, this.iconClasses); for (buttonName in iconOverrideHash) { iconClassesCopy[buttonName] = this.applyIconOverridePrefix(iconOverrideHash[buttonName]); } this.iconClasses = iconClassesCopy; } else if (iconOverrideHash === false) { this.iconClasses = {}; } }; Theme.prototype.applyIconOverridePrefix = function (className) { var prefix = this.iconOverridePrefix; if (prefix && className.indexOf(prefix) !== 0) { // if not already present className = prefix + className; } return className; }; Theme.prototype.getClass = function (key) { return this.classes[key] || ''; }; Theme.prototype.getIconClass = function (buttonName) { var className = this.iconClasses[buttonName]; if (className) { return this.baseIconClass + ' ' + className; } return ''; }; Theme.prototype.getCustomButtonIconClass = function (customButtonProps) { var className; if (this.iconOverrideCustomButtonOption) { className = customButtonProps[this.iconOverrideCustomButtonOption]; if (className) { return this.baseIconClass + ' ' + this.applyIconOverridePrefix(className); } } return ''; }; return Theme; }()); Theme.prototype.classes = {}; Theme.prototype.iconClasses = {}; Theme.prototype.baseIconClass = ''; Theme.prototype.iconOverridePrefix = ''; var guid = 0; var ComponentContext = /** @class */ (function () { function ComponentContext(calendar, theme, dateEnv, options, view) { this.calendar = calendar; this.theme = theme; this.dateEnv = dateEnv; this.options = options; this.view = view; this.isRtl = options.dir === 'rtl'; this.eventOrderSpecs = parseFieldSpecs(options.eventOrder); this.nextDayThreshold = createDuration(options.nextDayThreshold); } ComponentContext.prototype.extend = function (options, view) { return new ComponentContext(this.calendar, this.theme, this.dateEnv, options || this.options, view || this.view); }; return ComponentContext; }()); var Component = /** @class */ (function () { function Component() { this.uid = String(guid++); } Component.addEqualityFuncs = function (newFuncs) { this.prototype.equalityFuncs = __assign({}, this.prototype.equalityFuncs, newFuncs); }; Component.prototype.receiveProps = function (props, context) { var oldContext = this.context; this.context = context; if (!oldContext) { this.firstContext(context); } var _a = recycleProps(this.props || {}, props, this.equalityFuncs), anyChanges = _a.anyChanges, comboProps = _a.comboProps; this.props = comboProps; if (anyChanges) { if (oldContext) { this.beforeUpdate(); } this.render(comboProps, context); if (oldContext) { this.afterUpdate(); } } }; Component.prototype.render = function (props, context) { }; Component.prototype.firstContext = function (context) { }; Component.prototype.beforeUpdate = function () { }; Component.prototype.afterUpdate = function () { }; // after destroy is called, this component won't ever be used again Component.prototype.destroy = function () { }; return Component; }()); Component.prototype.equalityFuncs = {}; /* Reuses old values when equal. If anything is unequal, returns newProps as-is. Great for PureComponent, but won't be feasible with React, so just eliminate and use React's DOM diffing. */ function recycleProps(oldProps, newProps, equalityFuncs) { var comboProps = {}; // some old, some new var anyChanges = false; for (var key in newProps) { if (key in oldProps && (oldProps[key] === newProps[key] || (equalityFuncs[key] && equalityFuncs[key](oldProps[key], newProps[key])))) { // equal to old? use old prop comboProps[key] = oldProps[key]; } else { comboProps[key] = newProps[key]; anyChanges = true; } } for (var key in oldProps) { if (!(key in newProps)) { anyChanges = true; break; } } return { anyChanges: anyChanges, comboProps: comboProps }; } /* PURPOSES: - hook up to fg, fill, and mirror renderers - interface for dragging and hits */ var DateComponent = /** @class */ (function (_super) { __extends(DateComponent, _super); function DateComponent(el) { var _this = _super.call(this) || this; _this.el = el; return _this; } DateComponent.prototype.destroy = function () { _super.prototype.destroy.call(this); removeElement(this.el); }; // Hit System // ----------------------------------------------------------------------------------------------------------------- DateComponent.prototype.buildPositionCaches = function () { }; DateComponent.prototype.queryHit = function (positionLeft, positionTop, elWidth, elHeight) { return null; // this should be abstract }; // Validation // ----------------------------------------------------------------------------------------------------------------- DateComponent.prototype.isInteractionValid = function (interaction) { var calendar = this.context.calendar; var dateProfile = this.props.dateProfile; // HACK var instances = interaction.mutatedEvents.instances; if (dateProfile) { // HACK for DayTile for (var instanceId in instances) { if (!rangeContainsRange(dateProfile.validRange, instances[instanceId].range)) { return false; } } } return isInteractionValid(interaction, calendar); }; DateComponent.prototype.isDateSelectionValid = function (selection) { var calendar = this.context.calendar; var dateProfile = this.props.dateProfile; // HACK if (dateProfile && // HACK for DayTile !rangeContainsRange(dateProfile.validRange, selection.range)) { return false; } return isDateSelectionValid(selection, calendar); }; // Pointer Interaction Utils // ----------------------------------------------------------------------------------------------------------------- DateComponent.prototype.isValidSegDownEl = function (el) { return !this.props.eventDrag && // HACK !this.props.eventResize && // HACK !elementClosest(el, '.fc-mirror') && (this.isPopover() || !this.isInPopover(el)); // ^above line ensures we don't detect a seg interaction within a nested component. // it's a HACK because it only supports a popover as the nested component. }; DateComponent.prototype.isValidDateDownEl = function (el) { var segEl = elementClosest(el, this.fgSegSelector); return (!segEl || segEl.classList.contains('fc-mirror')) && !elementClosest(el, '.fc-more') && // a "more.." link !elementClosest(el, 'a[data-goto]') && // a clickable nav link !this.isInPopover(el); }; DateComponent.prototype.isPopover = function () { return this.el.classList.contains('fc-popover'); }; DateComponent.prototype.isInPopover = function (el) { return Boolean(elementClosest(el, '.fc-popover')); }; return DateComponent; }(Component)); DateComponent.prototype.fgSegSelector = '.fc-event-container > *'; DateComponent.prototype.bgSegSelector = '.fc-bgevent:not(.fc-nonbusiness)'; var uid$1 = 0; function createPlugin(input) { return { id: String(uid$1++), deps: input.deps || [], reducers: input.reducers || [], eventDefParsers: input.eventDefParsers || [], isDraggableTransformers: input.isDraggableTransformers || [], eventDragMutationMassagers: input.eventDragMutationMassagers || [], eventDefMutationAppliers: input.eventDefMutationAppliers || [], dateSelectionTransformers: input.dateSelectionTransformers || [], datePointTransforms: input.datePointTransforms || [], dateSpanTransforms: input.dateSpanTransforms || [], views: input.views || {}, viewPropsTransformers: input.viewPropsTransformers || [], isPropsValid: input.isPropsValid || null, externalDefTransforms: input.externalDefTransforms || [], eventResizeJoinTransforms: input.eventResizeJoinTransforms || [], viewContainerModifiers: input.viewContainerModifiers || [], eventDropTransformers: input.eventDropTransformers || [], componentInteractions: input.componentInteractions || [], calendarInteractions: input.calendarInteractions || [], themeClasses: input.themeClasses || {}, eventSourceDefs: input.eventSourceDefs || [], cmdFormatter: input.cmdFormatter, recurringTypes: input.recurringTypes || [], namedTimeZonedImpl: input.namedTimeZonedImpl, defaultView: input.defaultView || '', elementDraggingImpl: input.elementDraggingImpl, optionChangeHandlers: input.optionChangeHandlers || {} }; } var PluginSystem = /** @class */ (function () { function PluginSystem() { this.hooks = { reducers: [], eventDefParsers: [], isDraggableTransformers: [], eventDragMutationMassagers: [], eventDefMutationAppliers: [], dateSelectionTransformers: [], datePointTransforms: [], dateSpanTransforms: [], views: {}, viewPropsTransformers: [], isPropsValid: null, externalDefTransforms: [], eventResizeJoinTransforms: [], viewContainerModifiers: [], eventDropTransformers: [], componentInteractions: [], calendarInteractions: [], themeClasses: {}, eventSourceDefs: [], cmdFormatter: null, recurringTypes: [], namedTimeZonedImpl: null, defaultView: '', elementDraggingImpl: null, optionChangeHandlers: {} }; this.addedHash = {}; } PluginSystem.prototype.add = function (plugin) { if (!this.addedHash[plugin.id]) { this.addedHash[plugin.id] = true; for (var _i = 0, _a = plugin.deps; _i < _a.length; _i++) { var dep = _a[_i]; this.add(dep); } this.hooks = combineHooks(this.hooks, plugin); } }; return PluginSystem; }()); function combineHooks(hooks0, hooks1) { return { reducers: hooks0.reducers.concat(hooks1.reducers), eventDefParsers: hooks0.eventDefParsers.concat(hooks1.eventDefParsers), isDraggableTransformers: hooks0.isDraggableTransformers.concat(hooks1.isDraggableTransformers), eventDragMutationMassagers: hooks0.eventDragMutationMassagers.concat(hooks1.eventDragMutationMassagers), eventDefMutationAppliers: hooks0.eventDefMutationAppliers.concat(hooks1.eventDefMutationAppliers), dateSelectionTransformers: hooks0.dateSelectionTransformers.concat(hooks1.dateSelectionTransformers), datePointTransforms: hooks0.datePointTransforms.concat(hooks1.datePointTransforms), dateSpanTransforms: hooks0.dateSpanTransforms.concat(hooks1.dateSpanTransforms), views: __assign({}, hooks0.views, hooks1.views), viewPropsTransformers: hooks0.viewPropsTransformers.concat(hooks1.viewPropsTransformers), isPropsValid: hooks1.isPropsValid || hooks0.isPropsValid, externalDefTransforms: hooks0.externalDefTransforms.concat(hooks1.externalDefTransforms), eventResizeJoinTransforms: hooks0.eventResizeJoinTransforms.concat(hooks1.eventResizeJoinTransforms), viewContainerModifiers: hooks0.viewContainerModifiers.concat(hooks1.viewContainerModifiers), eventDropTransformers: hooks0.eventDropTransformers.concat(hooks1.eventDropTransformers), calendarInteractions: hooks0.calendarInteractions.concat(hooks1.calendarInteractions), componentInteractions: hooks0.componentInteractions.concat(hooks1.componentInteractions), themeClasses: __assign({}, hooks0.themeClasses, hooks1.themeClasses), eventSourceDefs: hooks0.eventSourceDefs.concat(hooks1.eventSourceDefs), cmdFormatter: hooks1.cmdFormatter || hooks0.cmdFormatter, recurringTypes: hooks0.recurringTypes.concat(hooks1.recurringTypes), namedTimeZonedImpl: hooks1.namedTimeZonedImpl || hooks0.namedTimeZonedImpl, defaultView: hooks0.defaultView || hooks1.defaultView, elementDraggingImpl: hooks0.elementDraggingImpl || hooks1.elementDraggingImpl, optionChangeHandlers: __assign({}, hooks0.optionChangeHandlers, hooks1.optionChangeHandlers) }; } var eventSourceDef = { ignoreRange: true, parseMeta: function (raw) { if (Array.isArray(raw)) { // short form return raw; } else if (Array.isArray(raw.events)) { return raw.events; } return null; }, fetch: function (arg, success) { success({ rawEvents: arg.eventSource.meta }); } }; var ArrayEventSourcePlugin = createPlugin({ eventSourceDefs: [eventSourceDef] }); var eventSourceDef$1 = { parseMeta: function (raw) { if (typeof raw === 'function') { // short form return raw; } else if (typeof raw.events === 'function') { return raw.events; } return null; }, fetch: function (arg, success, failure) { var dateEnv = arg.calendar.dateEnv; var func = arg.eventSource.meta; unpromisify(func.bind(null, { start: dateEnv.toDate(arg.range.start), end: dateEnv.toDate(arg.range.end), startStr: dateEnv.formatIso(arg.range.start), endStr: dateEnv.formatIso(arg.range.end), timeZone: dateEnv.timeZone }), function (rawEvents) { success({ rawEvents: rawEvents }); // needs an object response }, failure // send errorObj directly to failure callback ); } }; var FuncEventSourcePlugin = createPlugin({ eventSourceDefs: [eventSourceDef$1] }); function requestJson(method, url, params, successCallback, failureCallback) { method = method.toUpperCase(); var body = null; if (method === 'GET') { url = injectQueryStringParams(url, params); } else { body = encodeParams(params); } var xhr = new XMLHttpRequest(); xhr.open(method, url, true); if (method !== 'GET') { xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); } xhr.onload = function () { if (xhr.status >= 200 && xhr.status < 400) { try { var res = JSON.parse(xhr.responseText); successCallback(res, xhr); } catch (err) { failureCallback('Failure parsing JSON', xhr); } } else { failureCallback('Request failed', xhr); } }; xhr.onerror = function () { failureCallback('Request failed', xhr); }; xhr.send(body); } function injectQueryStringParams(url, params) { return url + (url.indexOf('?') === -1 ? '?' : '&') + encodeParams(params); } function encodeParams(params) { var parts = []; for (var key in params) { parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key])); } return parts.join('&'); } var eventSourceDef$2 = { parseMeta: function (raw) { if (typeof raw === 'string') { // short form raw = { url: raw }; } else if (!raw || typeof raw !== 'object' || !raw.url) { return null; } return { url: raw.url, method: (raw.method || 'GET').toUpperCase(), extraParams: raw.extraParams, startParam: raw.startParam, endParam: raw.endParam, timeZoneParam: raw.timeZoneParam }; }, fetch: function (arg, success, failure) { var meta = arg.eventSource.meta; var requestParams = buildRequestParams(meta, arg.range, arg.calendar); requestJson(meta.method, meta.url, requestParams, function (rawEvents, xhr) { success({ rawEvents: rawEvents, xhr: xhr }); }, function (errorMessage, xhr) { failure({ message: errorMessage, xhr: xhr }); }); } }; var JsonFeedEventSourcePlugin = createPlugin({ eventSourceDefs: [eventSourceDef$2] }); function buildRequestParams(meta, range, calendar) { var dateEnv = calendar.dateEnv; var startParam; var endParam; var timeZoneParam; var customRequestParams; var params = {}; startParam = meta.startParam; if (startParam == null) { startParam = calendar.opt('startParam'); } endParam = meta.endParam; if (endParam == null) { endParam = calendar.opt('endParam'); } timeZoneParam = meta.timeZoneParam; if (timeZoneParam == null) { timeZoneParam = calendar.opt('timeZoneParam'); } // retrieve any outbound GET/POST data from the options if (typeof meta.extraParams === 'function') { // supplied as a function that returns a key/value object customRequestParams = meta.extraParams(); } else { // probably supplied as a straight key/value object customRequestParams = meta.extraParams || {}; } __assign(params, customRequestParams); params[startParam] = dateEnv.formatIso(range.start); params[endParam] = dateEnv.formatIso(range.end); if (dateEnv.timeZone !== 'local') { params[timeZoneParam] = dateEnv.timeZone; } return params; } var recurring = { parse: function (rawEvent, leftoverProps, dateEnv) { var createMarker = dateEnv.createMarker.bind(dateEnv); var processors = { daysOfWeek: null, startTime: createDuration, endTime: createDuration, startRecur: createMarker, endRecur: createMarker }; var props = refineProps(rawEvent, processors, {}, leftoverProps); var anyValid = false; for (var propName in props) { if (props[propName] != null) { anyValid = true; break; } } if (anyValid) { var duration = null; if ('duration' in leftoverProps) { duration = createDuration(leftoverProps.duration); delete leftoverProps.duration; } if (!duration && props.startTime && props.endTime) { duration = subtractDurations(props.endTime, props.startTime); } return { allDayGuess: Boolean(!props.startTime && !props.endTime), duration: duration, typeData: props // doesn't need endTime anymore but oh well }; } return null; }, expand: function (typeData, framingRange, dateEnv) { var clippedFramingRange = intersectRanges(framingRange, { start: typeData.startRecur, end: typeData.endRecur }); if (clippedFramingRange) { return expandRanges(typeData.daysOfWeek, typeData.startTime, clippedFramingRange, dateEnv); } else { return []; } } }; var SimpleRecurrencePlugin = createPlugin({ recurringTypes: [recurring] }); function expandRanges(daysOfWeek, startTime, framingRange, dateEnv) { var dowHash = daysOfWeek ? arrayToHash(daysOfWeek) : null; var dayMarker = startOfDay(framingRange.start); var endMarker = framingRange.end; var instanceStarts = []; while (dayMarker < endMarker) { var instanceStart // if everyday, or this particular day-of-week = void 0; // if everyday, or this particular day-of-week if (!dowHash || dowHash[dayMarker.getUTCDay()]) { if (startTime) { instanceStart = dateEnv.add(dayMarker, startTime); } else { instanceStart = dayMarker; } instanceStarts.push(instanceStart); } dayMarker = addDays(dayMarker, 1); } return instanceStarts; } var DefaultOptionChangeHandlers = createPlugin({ optionChangeHandlers: { events: function (events, calendar, deepEqual) { handleEventSources([events], calendar, deepEqual); }, eventSources: handleEventSources, plugins: handlePlugins } }); function handleEventSources(inputs, calendar, deepEqual) { var unfoundSources = hashValuesToArray(calendar.state.eventSources); var newInputs = []; for (var _i = 0, inputs_1 = inputs; _i < inputs_1.length; _i++) { var input = inputs_1[_i]; var inputFound = false; for (var i = 0; i < unfoundSources.length; i++) { if (deepEqual(unfoundSources[i]._raw, input)) { unfoundSources.splice(i, 1); // delete inputFound = true; break; } } if (!inputFound) { newInputs.push(input); } } for (var _a = 0, unfoundSources_1 = unfoundSources; _a < unfoundSources_1.length; _a++) { var unfoundSource = unfoundSources_1[_a]; calendar.dispatch({ type: 'REMOVE_EVENT_SOURCE', sourceId: unfoundSource.sourceId }); } for (var _b = 0, newInputs_1 = newInputs; _b < newInputs_1.length; _b++) { var newInput = newInputs_1[_b]; calendar.addEventSource(newInput); } } // shortcoming: won't remove plugins function handlePlugins(inputs, calendar) { calendar.addPluginInputs(inputs); // will gracefully handle duplicates } var config = {}; // TODO: make these options var globalDefaults = { defaultRangeSeparator: ' - ', titleRangeSeparator: ' \u2013 ', defaultTimedEventDuration: '01:00:00', defaultAllDayEventDuration: { day: 1 }, forceEventDuration: false, nextDayThreshold: '00:00:00', // display columnHeader: true, defaultView: '', aspectRatio: 1.35, header: { left: 'title', center: '', right: 'today prev,next' }, weekends: true, weekNumbers: false, weekNumberCalculation: 'local', editable: false, // nowIndicator: false, scrollTime: '06:00:00', minTime: '00:00:00', maxTime: '24:00:00', showNonCurrentDates: true, // event ajax lazyFetching: true, startParam: 'start', endParam: 'end', timeZoneParam: 'timeZone', timeZone: 'local', // allDayDefault: undefined, // locale locales: [], locale: '', // dir: will get this from the default locale // buttonIcons: null, // allows setting a min-height to the event segment to prevent short events overlapping each other timeGridEventMinHeight: 0, themeSystem: 'standard', // eventResizableFromStart: false, dragRevertDuration: 500, dragScroll: true, allDayMaintainDuration: false, // selectable: false, unselectAuto: true, // selectMinDistance: 0, dropAccept: '*', eventOrder: 'start,-duration,allDay,title', // ^ if start tie, longer events go before shorter. final tie-breaker is title text // rerenderDelay: null, eventLimit: false, eventLimitClick: 'popover', dayPopoverFormat: { month: 'long', day: 'numeric', year: 'numeric' }, handleWindowResize: true, windowResizeDelay: 100, longPressDelay: 1000, eventDragMinDistance: 5 // only applies to mouse }; var rtlDefaults = { header: { left: 'next,prev today', center: '', right: 'title' }, buttonIcons: { // TODO: make RTL support the responibility of the theme prev: 'fc-icon-chevron-right', next: 'fc-icon-chevron-left', prevYear: 'fc-icon-chevrons-right', nextYear: 'fc-icon-chevrons-left' } }; var complexOptions = [ 'header', 'footer', 'buttonText', 'buttonIcons' ]; // Merges an array of option objects into a single object function mergeOptions(optionObjs) { return mergeProps(optionObjs, complexOptions); } // TODO: move this stuff to a "plugin"-related file... var INTERNAL_PLUGINS = [ ArrayEventSourcePlugin, FuncEventSourcePlugin, JsonFeedEventSourcePlugin, SimpleRecurrencePlugin, DefaultOptionChangeHandlers ]; function refinePluginDefs(pluginInputs) { var plugins = []; for (var _i = 0, pluginInputs_1 = pluginInputs; _i < pluginInputs_1.length; _i++) { var pluginInput = pluginInputs_1[_i]; if (typeof pluginInput === 'string') { var globalName = 'FullCalendar' + capitaliseFirstLetter(pluginInput); if (!window[globalName]) { console.warn('Plugin file not loaded for ' + pluginInput); } else { plugins.push(window[globalName].default); // is an ES6 module } } else { plugins.push(pluginInput); } } return INTERNAL_PLUGINS.concat(plugins); } var RAW_EN_LOCALE = { code: 'en', week: { dow: 0, doy: 4 // 4 days need to be within the year to be considered the first week }, dir: 'ltr', buttonText: { prev: 'prev', next: 'next', prevYear: 'prev year', nextYear: 'next year', year: 'year', today: 'today', month: 'month', week: 'week', day: 'day', list: 'list' }, weekLabel: 'W', allDayText: 'all-day', eventLimitText: 'more', noEventsMessage: 'No events to display' }; function parseRawLocales(explicitRawLocales) { var defaultCode = explicitRawLocales.length > 0 ? explicitRawLocales[0].code : 'en'; var globalArray = window['FullCalendarLocalesAll'] || []; // from locales-all.js var globalObject = window['FullCalendarLocales'] || {}; // from locales/*.js. keys are meaningless var allRawLocales = globalArray.concat(// globalArray is low prio hashValuesToArray(globalObject), // medium prio explicitRawLocales // highest prio ); var rawLocaleMap = { en: RAW_EN_LOCALE // necessary? }; for (var _i = 0, allRawLocales_1 = allRawLocales; _i < allRawLocales_1.length; _i++) { var rawLocale = allRawLocales_1[_i]; rawLocaleMap[rawLocale.code] = rawLocale; } return { map: rawLocaleMap, defaultCode: defaultCode }; } function buildLocale(inputSingular, available) { if (typeof inputSingular === 'object' && !Array.isArray(inputSingular)) { return parseLocale(inputSingular.code, [inputSingular.code], inputSingular); } else { return queryLocale(inputSingular, available); } } function queryLocale(codeArg, available) { var codes = [].concat(codeArg || []); // will convert to array var raw = queryRawLocale(codes, available) || RAW_EN_LOCALE; return parseLocale(codeArg, codes, raw); } function queryRawLocale(codes, available) { for (var i = 0; i < codes.length; i++) { var parts = codes[i].toLocaleLowerCase().split('-'); for (var j = parts.length; j > 0; j--) { var simpleId = parts.slice(0, j).join('-'); if (available[simpleId]) { return available[simpleId]; } } } return null; } function parseLocale(codeArg, codes, raw) { var merged = mergeProps([RAW_EN_LOCALE, raw], ['buttonText']); delete merged.code; // don't want this part of the options var week = merged.week; delete merged.week; return { codeArg: codeArg, codes: codes, week: week, simpleNumberFormat: new Intl.NumberFormat(codeArg), options: merged }; } var OptionsManager = /** @class */ (function () { function OptionsManager(overrides) { this.overrides = __assign({}, overrides); // make a copy this.dynamicOverrides = {}; this.compute(); } OptionsManager.prototype.mutate = function (updates, removals, isDynamic) { if (!Object.keys(updates).length && !removals.length) { return; } var overrideHash = isDynamic ? this.dynamicOverrides : this.overrides; __assign(overrideHash, updates); for (var _i = 0, removals_1 = removals; _i < removals_1.length; _i++) { var propName = removals_1[_i]; delete overrideHash[propName]; } this.compute(); }; // Computes the flattened options hash for the calendar and assigns to `this.options`. // Assumes this.overrides and this.dynamicOverrides have already been initialized. OptionsManager.prototype.compute = function () { // TODO: not a very efficient system var locales = firstDefined(// explicit locale option given? this.dynamicOverrides.locales, this.overrides.locales, globalDefaults.locales); var locale = firstDefined(// explicit locales option given? this.dynamicOverrides.locale, this.overrides.locale, globalDefaults.locale); var available = parseRawLocales(locales); var localeDefaults = buildLocale(locale || available.defaultCode, available.map).options; var dir = firstDefined(// based on options computed so far, is direction RTL? this.dynamicOverrides.dir, this.overrides.dir, localeDefaults.dir); var dirDefaults = dir === 'rtl' ? rtlDefaults : {}; this.dirDefaults = dirDefaults; this.localeDefaults = localeDefaults; this.computed = mergeOptions([ globalDefaults, dirDefaults, localeDefaults, this.overrides, this.dynamicOverrides ]); }; return OptionsManager; }()); var calendarSystemClassMap = {}; function registerCalendarSystem(name, theClass) { calendarSystemClassMap[name] = theClass; } function createCalendarSystem(name) { return new calendarSystemClassMap[name](); } var GregorianCalendarSystem = /** @class */ (function () { function GregorianCalendarSystem() { } GregorianCalendarSystem.prototype.getMarkerYear = function (d) { return d.getUTCFullYear(); }; GregorianCalendarSystem.prototype.getMarkerMonth = function (d) { return d.getUTCMonth(); }; GregorianCalendarSystem.prototype.getMarkerDay = function (d) { return d.getUTCDate(); }; GregorianCalendarSystem.prototype.arrayToMarker = function (arr) { return arrayToUtcDate(arr); }; GregorianCalendarSystem.prototype.markerToArray = function (marker) { return dateToUtcArray(marker); }; return GregorianCalendarSystem; }()); registerCalendarSystem('gregory', GregorianCalendarSystem); var ISO_RE = /^\s*(\d{4})(-(\d{2})(-(\d{2})([T ](\d{2}):(\d{2})(:(\d{2})(\.(\d+))?)?(Z|(([-+])(\d{2})(:?(\d{2}))?))?)?)?)?$/; function parse(str) { var m = ISO_RE.exec(str); if (m) { var marker = new Date(Date.UTC(Number(m[1]), m[3] ? Number(m[3]) - 1 : 0, Number(m[5] || 1), Number(m[7] || 0), Number(m[8] || 0), Number(m[10] || 0), m[12] ? Number('0.' + m[12]) * 1000 : 0)); if (isValidDate(marker)) { var timeZoneOffset = null; if (m[13]) { timeZoneOffset = (m[15] === '-' ? -1 : 1) * (Number(m[16] || 0) * 60 + Number(m[18] || 0)); } return { marker: marker, isTimeUnspecified: !m[6], timeZoneOffset: timeZoneOffset }; } } return null; } var DateEnv = /** @class */ (function () { function DateEnv(settings) { var timeZone = this.timeZone = settings.timeZone; var isNamedTimeZone = timeZone !== 'local' && timeZone !== 'UTC'; if (settings.namedTimeZoneImpl && isNamedTimeZone) { this.namedTimeZoneImpl = new settings.namedTimeZoneImpl(timeZone); } this.canComputeOffset = Boolean(!isNamedTimeZone || this.namedTimeZoneImpl); this.calendarSystem = createCalendarSystem(settings.calendarSystem); this.locale = settings.locale; this.weekDow = settings.locale.week.dow; this.weekDoy = settings.locale.week.doy; if (settings.weekNumberCalculation === 'ISO') { this.weekDow = 1; this.weekDoy = 4; } if (typeof settings.firstDay === 'number') { this.weekDow = settings.firstDay; } if (typeof settings.weekNumberCalculation === 'function') { this.weekNumberFunc = settings.weekNumberCalculation; } this.weekLabel = settings.weekLabel != null ? settings.weekLabel : settings.locale.options.weekLabel; this.cmdFormatter = settings.cmdFormatter; } // Creating / Parsing DateEnv.prototype.createMarker = function (input) { var meta = this.createMarkerMeta(input); if (meta === null) { return null; } return meta.marker; }; DateEnv.prototype.createNowMarker = function () { if (this.canComputeOffset) { return this.timestampToMarker(new Date().valueOf()); } else { // if we can't compute the current date val for a timezone, // better to give the current local date vals than UTC return arrayToUtcDate(dateToLocalArray(new Date())); } }; DateEnv.prototype.createMarkerMeta = function (input) { if (typeof input === 'string') { return this.parse(input); } var marker = null; if (typeof input === 'number') { marker = this.timestampToMarker(input); } else if (input instanceof Date) { input = input.valueOf(); if (!isNaN(input)) { marker = this.timestampToMarker(input); } } else if (Array.isArray(input)) { marker = arrayToUtcDate(input); } if (marker === null || !isValidDate(marker)) { return null; } return { marker: marker, isTimeUnspecified: false, forcedTzo: null }; }; DateEnv.prototype.parse = function (s) { var parts = parse(s); if (parts === null) { return null; } var marker = parts.marker; var forcedTzo = null; if (parts.timeZoneOffset !== null) { if (this.canComputeOffset) { marker = this.timestampToMarker(marker.valueOf() - parts.timeZoneOffset * 60 * 1000); } else { forcedTzo = parts.timeZoneOffset; } } return { marker: marker, isTimeUnspecified: parts.isTimeUnspecified, forcedTzo: forcedTzo }; }; // Accessors DateEnv.prototype.getYear = function (marker) { return this.calendarSystem.getMarkerYear(marker); }; DateEnv.prototype.getMonth = function (marker) { return this.calendarSystem.getMarkerMonth(marker); }; // Adding / Subtracting DateEnv.prototype.add = function (marker, dur) { var a = this.calendarSystem.markerToArray(marker); a[0] += dur.years; a[1] += dur.months; a[2] += dur.days; a[6] += dur.milliseconds; return this.calendarSystem.arrayToMarker(a); }; DateEnv.prototype.subtract = function (marker, dur) { var a = this.calendarSystem.markerToArray(marker); a[0] -= dur.years; a[1] -= dur.months; a[2] -= dur.days; a[6] -= dur.milliseconds; return this.calendarSystem.arrayToMarker(a); }; DateEnv.prototype.addYears = function (marker, n) { var a = this.calendarSystem.markerToArray(marker); a[0] += n; return this.calendarSystem.arrayToMarker(a); }; DateEnv.prototype.addMonths = function (marker, n) { var a = this.calendarSystem.markerToArray(marker); a[1] += n; return this.calendarSystem.arrayToMarker(a); }; // Diffing Whole Units DateEnv.prototype.diffWholeYears = function (m0, m1) { var calendarSystem = this.calendarSystem; if (timeAsMs(m0) === timeAsMs(m1) && calendarSystem.getMarkerDay(m0) === calendarSystem.getMarkerDay(m1) && calendarSystem.getMarkerMonth(m0) === calendarSystem.getMarkerMonth(m1)) { return calendarSystem.getMarkerYear(m1) - calendarSystem.getMarkerYear(m0); } return null; }; DateEnv.prototype.diffWholeMonths = function (m0, m1) { var calendarSystem = this.calendarSystem; if (timeAsMs(m0) === timeAsMs(m1) && calendarSystem.getMarkerDay(m0) === calendarSystem.getMarkerDay(m1)) { return (calendarSystem.getMarkerMonth(m1) - calendarSystem.getMarkerMonth(m0)) + (calendarSystem.getMarkerYear(m1) - calendarSystem.getMarkerYear(m0)) * 12; } return null; }; // Range / Duration DateEnv.prototype.greatestWholeUnit = function (m0, m1) { var n = this.diffWholeYears(m0, m1); if (n !== null) { return { unit: 'year', value: n }; } n = this.diffWholeMonths(m0, m1); if (n !== null) { return { unit: 'month', value: n }; } n = diffWholeWeeks(m0, m1); if (n !== null) { return { unit: 'week', value: n }; } n = diffWholeDays(m0, m1); if (n !== null) { return { unit: 'day', value: n }; } n = diffHours(m0, m1); if (isInt(n)) { return { unit: 'hour', value: n }; } n = diffMinutes(m0, m1); if (isInt(n)) { return { unit: 'minute', value: n }; } n = diffSeconds(m0, m1); if (isInt(n)) { return { unit: 'second', value: n }; } return { unit: 'millisecond', value: m1.valueOf() - m0.valueOf() }; }; DateEnv.prototype.countDurationsBetween = function (m0, m1, d) { // TODO: can use greatestWholeUnit var diff; if (d.years) { diff = this.diffWholeYears(m0, m1); if (diff !== null) { return diff / asRoughYears(d); } } if (d.months) { diff = this.diffWholeMonths(m0, m1); if (diff !== null) { return diff / asRoughMonths(d); } } if (d.days) { diff = diffWholeDays(m0, m1); if (diff !== null) { return diff / asRoughDays(d); } } return (m1.valueOf() - m0.valueOf()) / asRoughMs(d); }; // Start-Of DateEnv.prototype.startOf = function (m, unit) { if (unit === 'year') { return this.startOfYear(m); } else if (unit === 'month') { return this.startOfMonth(m); } else if (unit === 'week') { return this.startOfWeek(m); } else if (unit === 'day') { return startOfDay(m); } else if (unit === 'hour') { return startOfHour(m); } else if (unit === 'minute') { return startOfMinute(m); } else if (unit === 'second') { return startOfSecond(m); } }; DateEnv.prototype.startOfYear = function (m) { return this.calendarSystem.arrayToMarker([ this.calendarSystem.getMarkerYear(m) ]); }; DateEnv.prototype.startOfMonth = function (m) { return this.calendarSystem.arrayToMarker([ this.calendarSystem.getMarkerYear(m), this.calendarSystem.getMarkerMonth(m) ]); }; DateEnv.prototype.startOfWeek = function (m) { return this.calendarSystem.arrayToMarker([ this.calendarSystem.getMarkerYear(m), this.calendarSystem.getMarkerMonth(m), m.getUTCDate() - ((m.getUTCDay() - this.weekDow + 7) % 7) ]); }; // Week Number DateEnv.prototype.computeWeekNumber = function (marker) { if (this.weekNumberFunc) { return this.weekNumberFunc(this.toDate(marker)); } else { return weekOfYear(marker, this.weekDow, this.weekDoy); } }; // TODO: choke on timeZoneName: long DateEnv.prototype.format = function (marker, formatter, dateOptions) { if (dateOptions === void 0) { dateOptions = {}; } return formatter.format({ marker: marker, timeZoneOffset: dateOptions.forcedTzo != null ? dateOptions.forcedTzo : this.offsetForMarker(marker) }, this); }; DateEnv.prototype.formatRange = function (start, end, formatter, dateOptions) { if (dateOptions === void 0) { dateOptions = {}; } if (dateOptions.isEndExclusive) { end = addMs(end, -1); } return formatter.formatRange({ marker: start, timeZoneOffset: dateOptions.forcedStartTzo != null ? dateOptions.forcedStartTzo : this.offsetForMarker(start) }, { marker: end, timeZoneOffset: dateOptions.forcedEndTzo != null ? dateOptions.forcedEndTzo : this.offsetForMarker(end) }, this); }; DateEnv.prototype.formatIso = function (marker, extraOptions) { if (extraOptions === void 0) { extraOptions = {}; } var timeZoneOffset = null; if (!extraOptions.omitTimeZoneOffset) { if (extraOptions.forcedTzo != null) { timeZoneOffset = extraOptions.forcedTzo; } else { timeZoneOffset = this.offsetForMarker(marker); } } return buildIsoString(marker, timeZoneOffset, extraOptions.omitTime); }; // TimeZone DateEnv.prototype.timestampToMarker = function (ms) { if (this.timeZone === 'local') { return arrayToUtcDate(dateToLocalArray(new Date(ms))); } else if (this.timeZone === 'UTC' || !this.namedTimeZoneImpl) { return new Date(ms); } else { return arrayToUtcDate(this.namedTimeZoneImpl.timestampToArray(ms)); } }; DateEnv.prototype.offsetForMarker = function (m) { if (this.timeZone === 'local') { return -arrayToLocalDate(dateToUtcArray(m)).getTimezoneOffset(); // convert "inverse" offset to "normal" offset } else if (this.timeZone === 'UTC') { return 0; } else if (this.namedTimeZoneImpl) { return this.namedTimeZoneImpl.offsetForArray(dateToUtcArray(m)); } return null; }; // Conversion DateEnv.prototype.toDate = function (m, forcedTzo) { if (this.timeZone === 'local') { return arrayToLocalDate(dateToUtcArray(m)); } else if (this.timeZone === 'UTC') { return new Date(m.valueOf()); // make sure it's a copy } else if (!this.namedTimeZoneImpl) { return new Date(m.valueOf() - (forcedTzo || 0)); } else { return new Date(m.valueOf() - this.namedTimeZoneImpl.offsetForArray(dateToUtcArray(m)) * 1000 * 60 // convert minutes -> ms ); } }; return DateEnv; }()); var SIMPLE_SOURCE_PROPS = { id: String, allDayDefault: Boolean, eventDataTransform: Function, success: Function, failure: Function }; var uid$2 = 0; function doesSourceNeedRange(eventSource, calendar) { var defs = calendar.pluginSystem.hooks.eventSourceDefs; return !defs[eventSource.sourceDefId].ignoreRange; } function parseEventSource(raw, calendar) { var defs = calendar.pluginSystem.hooks.eventSourceDefs; for (var i = defs.length - 1; i >= 0; i--) { // later-added plugins take precedence var def = defs[i]; var meta = def.parseMeta(raw); if (meta) { var res = parseEventSourceProps(typeof raw === 'object' ? raw : {}, meta, i, calendar); res._raw = raw; return res; } } return null; } function parseEventSourceProps(raw, meta, sourceDefId, calendar) { var leftovers0 = {}; var props = refineProps(raw, SIMPLE_SOURCE_PROPS, {}, leftovers0); var leftovers1 = {}; var ui = processUnscopedUiProps(leftovers0, calendar, leftovers1); props.isFetching = false; props.latestFetchId = ''; props.fetchRange = null; props.publicId = String(raw.id || ''); props.sourceId = String(uid$2++); props.sourceDefId = sourceDefId; props.meta = meta; props.ui = ui; props.extendedProps = leftovers1; return props; } function reduceEventSources (eventSources, action, dateProfile, calendar) { switch (action.type) { case 'ADD_EVENT_SOURCES': // already parsed return addSources(eventSources, action.sources, dateProfile ? dateProfile.activeRange : null, calendar); case 'REMOVE_EVENT_SOURCE': return removeSource(eventSources, action.sourceId); case 'PREV': // TODO: how do we track all actions that affect dateProfile :( case 'NEXT': case 'SET_DATE': case 'SET_VIEW_TYPE': if (dateProfile) { return fetchDirtySources(eventSources, dateProfile.activeRange, calendar); } else { return eventSources; } case 'FETCH_EVENT_SOURCES': case 'CHANGE_TIMEZONE': return fetchSourcesByIds(eventSources, action.sourceIds ? arrayToHash(action.sourceIds) : excludeStaticSources(eventSources, calendar), dateProfile ? dateProfile.activeRange : null, calendar); case 'RECEIVE_EVENTS': case 'RECEIVE_EVENT_ERROR': return receiveResponse(eventSources, action.sourceId, action.fetchId, action.fetchRange); case 'REMOVE_ALL_EVENT_SOURCES': return {}; default: return eventSources; } } var uid$3 = 0; function addSources(eventSourceHash, sources, fetchRange, calendar) { var hash = {}; for (var _i = 0, sources_1 = sources; _i < sources_1.length; _i++) { var source = sources_1[_i]; hash[source.sourceId] = source; } if (fetchRange) { hash = fetchDirtySources(hash, fetchRange, calendar); } return __assign({}, eventSourceHash, hash); } function removeSource(eventSourceHash, sourceId) { return filterHash(eventSourceHash, function (eventSource) { return eventSource.sourceId !== sourceId; }); } function fetchDirtySources(sourceHash, fetchRange, calendar) { return fetchSourcesByIds(sourceHash, filterHash(sourceHash, function (eventSource) { return isSourceDirty(eventSource, fetchRange, calendar); }), fetchRange, calendar); } function isSourceDirty(eventSource, fetchRange, calendar) { if (!doesSourceNeedRange(eventSource, calendar)) { return !eventSource.latestFetchId; } else { return !calendar.opt('lazyFetching') || !eventSource.fetchRange || eventSource.isFetching || // always cancel outdated in-progress fetches fetchRange.start < eventSource.fetchRange.start || fetchRange.end > eventSource.fetchRange.end; } } function fetchSourcesByIds(prevSources, sourceIdHash, fetchRange, calendar) { var nextSources = {}; for (var sourceId in prevSources) { var source = prevSources[sourceId]; if (sourceIdHash[sourceId]) { nextSources[sourceId] = fetchSource(source, fetchRange, calendar); } else { nextSources[sourceId] = source; } } return nextSources; } function fetchSource(eventSource, fetchRange, calendar) { var sourceDef = calendar.pluginSystem.hooks.eventSourceDefs[eventSource.sourceDefId]; var fetchId = String(uid$3++); sourceDef.fetch({ eventSource: eventSource, calendar: calendar, range: fetchRange }, function (res) { var rawEvents = res.rawEvents; var calSuccess = calendar.opt('eventSourceSuccess'); var calSuccessRes; var sourceSuccessRes; if (eventSource.success) { sourceSuccessRes = eventSource.success(rawEvents, res.xhr); } if (calSuccess) { calSuccessRes = calSuccess(rawEvents, res.xhr); } rawEvents = sourceSuccessRes || calSuccessRes || rawEvents; calendar.dispatch({ type: 'RECEIVE_EVENTS', sourceId: eventSource.sourceId, fetchId: fetchId, fetchRange: fetchRange, rawEvents: rawEvents }); }, function (error) { var callFailure = calendar.opt('eventSourceFailure'); console.warn(error.message, error); if (eventSource.failure) { eventSource.failure(error); } if (callFailure) { callFailure(error); } calendar.dispatch({ type: 'RECEIVE_EVENT_ERROR', sourceId: eventSource.sourceId, fetchId: fetchId, fetchRange: fetchRange, error: error }); }); return __assign({}, eventSource, { isFetching: true, latestFetchId: fetchId }); } function receiveResponse(sourceHash, sourceId, fetchId, fetchRange) { var _a; var eventSource = sourceHash[sourceId]; if (eventSource && // not already removed fetchId === eventSource.latestFetchId) { return __assign({}, sourceHash, (_a = {}, _a[sourceId] = __assign({}, eventSource, { isFetching: false, fetchRange: fetchRange // also serves as a marker that at least one fetch has completed }), _a)); } return sourceHash; } function excludeStaticSources(eventSources, calendar) { return filterHash(eventSources, function (eventSource) { return doesSourceNeedRange(eventSource, calendar); }); } var DateProfileGenerator = /** @class */ (function () { function DateProfileGenerator(viewSpec, calendar) { this.viewSpec = viewSpec; this.options = viewSpec.options; this.dateEnv = calendar.dateEnv; this.calendar = calendar; this.initHiddenDays(); } /* Date Range Computation ------------------------------------------------------------------------------------------------------------------*/ // Builds a structure with info about what the dates/ranges will be for the "prev" view. DateProfileGenerator.prototype.buildPrev = function (currentDateProfile, currentDate) { var dateEnv = this.dateEnv; var prevDate = dateEnv.subtract(dateEnv.startOf(currentDate, currentDateProfile.currentRangeUnit), // important for start-of-month currentDateProfile.dateIncrement); return this.build(prevDate, -1); }; // Builds a structure with info about what the dates/ranges will be for the "next" view. DateProfileGenerator.prototype.buildNext = function (currentDateProfile, currentDate) { var dateEnv = this.dateEnv; var nextDate = dateEnv.add(dateEnv.startOf(currentDate, currentDateProfile.currentRangeUnit), // important for start-of-month currentDateProfile.dateIncrement); return this.build(nextDate, 1); }; // Builds a structure holding dates/ranges for rendering around the given date. // Optional direction param indicates whether the date is being incremented/decremented // from its previous value. decremented = -1, incremented = 1 (default). DateProfileGenerator.prototype.build = function (currentDate, direction, forceToValid) { if (forceToValid === void 0) { forceToValid = false; } var validRange; var minTime = null; var maxTime = null; var currentInfo; var isRangeAllDay; var renderRange; var activeRange; var isValid; validRange = this.buildValidRange(); validRange = this.trimHiddenDays(validRange); if (forceToValid) { currentDate = constrainMarkerToRange(currentDate, validRange); } currentInfo = this.buildCurrentRangeInfo(currentDate, direction); isRangeAllDay = /^(year|month|week|day)$/.test(currentInfo.unit); renderRange = this.buildRenderRange(this.trimHiddenDays(currentInfo.range), currentInfo.unit, isRangeAllDay); renderRange = this.trimHiddenDays(renderRange); activeRange = renderRange; if (!this.options.showNonCurrentDates) { activeRange = intersectRanges(activeRange, currentInfo.range); } minTime = createDuration(this.options.minTime); maxTime = createDuration(this.options.maxTime); activeRange = this.adjustActiveRange(activeRange, minTime, maxTime); activeRange = intersectRanges(activeRange, validRange); // might return null // it's invalid if the originally requested date is not contained, // or if the range is completely outside of the valid range. isValid = rangesIntersect(currentInfo.range, validRange); return { // constraint for where prev/next operations can go and where events can be dragged/resized to. // an object with optional start and end properties. validRange: validRange, // range the view is formally responsible for. // for example, a month view might have 1st-31st, excluding padded dates currentRange: currentInfo.range, // name of largest unit being displayed, like "month" or "week" currentRangeUnit: currentInfo.unit, isRangeAllDay: isRangeAllDay, // dates that display events and accept drag-n-drop // will be `null` if no dates accept events activeRange: activeRange, // date range with a rendered skeleton // includes not-active days that need some sort of DOM renderRange: renderRange, // Duration object that denotes the first visible time of any given day minTime: minTime, // Duration object that denotes the exclusive visible end time of any given day maxTime: maxTime, isValid: isValid, // how far the current date will move for a prev/next operation dateIncrement: this.buildDateIncrement(currentInfo.duration) // pass a fallback (might be null) ^ }; }; // Builds an object with optional start/end properties. // Indicates the minimum/maximum dates to display. // not responsible for trimming hidden days. DateProfileGenerator.prototype.buildValidRange = function () { return this.getRangeOption('validRange', this.calendar.getNow()) || { start: null, end: null }; // completely open-ended }; // Builds a structure with info about the "current" range, the range that is // highlighted as being the current month for example. // See build() for a description of `direction`. // Guaranteed to have `range` and `unit` properties. `duration` is optional. DateProfileGenerator.prototype.buildCurrentRangeInfo = function (date, direction) { var _a = this, viewSpec = _a.viewSpec, dateEnv = _a.dateEnv; var duration = null; var unit = null; var range = null; var dayCount; if (viewSpec.duration) { duration = viewSpec.duration; unit = viewSpec.durationUnit; range = this.buildRangeFromDuration(date, direction, duration, unit); } else if ((dayCount = this.options.dayCount)) { unit = 'day'; range = this.buildRangeFromDayCount(date, direction, dayCount); } else if ((range = this.buildCustomVisibleRange(date))) { unit = dateEnv.greatestWholeUnit(range.start, range.end).unit; } else { duration = this.getFallbackDuration(); unit = greatestDurationDenominator(duration).unit; range = this.buildRangeFromDuration(date, direction, duration, unit); } return { duration: duration, unit: unit, range: range }; }; DateProfileGenerator.prototype.getFallbackDuration = function () { return createDuration({ day: 1 }); }; // Returns a new activeRange to have time values (un-ambiguate) // minTime or maxTime causes the range to expand. DateProfileGenerator.prototype.adjustActiveRange = function (range, minTime, maxTime) { var dateEnv = this.dateEnv; var start = range.start; var end = range.end; if (this.viewSpec.class.prototype.usesMinMaxTime) { // expand active range if minTime is negative (why not when positive?) if (asRoughDays(minTime) < 0) { start = startOfDay(start); // necessary? start = dateEnv.add(start, minTime); } // expand active range if maxTime is beyond one day (why not when positive?) if (asRoughDays(maxTime) > 1) { end = startOfDay(end); // necessary? end = addDays(end, -1); end = dateEnv.add(end, maxTime); } } return { start: start, end: end }; }; // Builds the "current" range when it is specified as an explicit duration. // `unit` is the already-computed greatestDurationDenominator unit of duration. DateProfileGenerator.prototype.buildRangeFromDuration = function (date, direction, duration, unit) { var dateEnv = this.dateEnv; var alignment = this.options.dateAlignment; var dateIncrementInput; var dateIncrementDuration; var start; var end; var res; // compute what the alignment should be if (!alignment) { dateIncrementInput = this.options.dateIncrement; if (dateIncrementInput) { dateIncrementDuration = createDuration(dateIncrementInput); // use the smaller of the two units if (asRoughMs(dateIncrementDuration) < asRoughMs(duration)) { alignment = greatestDurationDenominator(dateIncrementDuration, !getWeeksFromInput(dateIncrementInput)).unit; } else { alignment = unit; } } else { alignment = unit; } } // if the view displays a single day or smaller if (asRoughDays(duration) <= 1) { if (this.isHiddenDay(start)) { start = this.skipHiddenDays(start, direction); start = startOfDay(start); } } function computeRes() { start = dateEnv.startOf(date, alignment); end = dateEnv.add(start, duration); res = { start: start, end: end }; } computeRes(); // if range is completely enveloped by hidden days, go past the hidden days if (!this.trimHiddenDays(res)) { date = this.skipHiddenDays(date, direction); computeRes(); } return res; }; // Builds the "current" range when a dayCount is specified. DateProfileGenerator.prototype.buildRangeFromDayCount = function (date, direction, dayCount) { var dateEnv = this.dateEnv; var customAlignment = this.options.dateAlignment; var runningCount = 0; var start = date; var end; if (customAlignment) { start = dateEnv.startOf(start, customAlignment); } start = startOfDay(start); start = this.skipHiddenDays(start, direction); end = start; do { end = addDays(end, 1); if (!this.isHiddenDay(end)) { runningCount++; } } while (runningCount < dayCount); return { start: start, end: end }; }; // Builds a normalized range object for the "visible" range, // which is a way to define the currentRange and activeRange at the same time. DateProfileGenerator.prototype.buildCustomVisibleRange = function (date) { var dateEnv = this.dateEnv; var visibleRange = this.getRangeOption('visibleRange', dateEnv.toDate(date)); if (visibleRange && (visibleRange.start == null || visibleRange.end == null)) { return null; } return visibleRange; }; // Computes the range that will represent the element/cells for *rendering*, // but which may have voided days/times. // not responsible for trimming hidden days. DateProfileGenerator.prototype.buildRenderRange = function (currentRange, currentRangeUnit, isRangeAllDay) { return currentRange; }; // Compute the duration value that should be added/substracted to the current date // when a prev/next operation happens. DateProfileGenerator.prototype.buildDateIncrement = function (fallback) { var dateIncrementInput = this.options.dateIncrement; var customAlignment; if (dateIncrementInput) { return createDuration(dateIncrementInput); } else if ((customAlignment = this.options.dateAlignment)) { return createDuration(1, customAlignment); } else if (fallback) { return fallback; } else { return createDuration({ days: 1 }); } }; // Arguments after name will be forwarded to a hypothetical function value // WARNING: passed-in arguments will be given to generator functions as-is and can cause side-effects. // Always clone your objects if you fear mutation. DateProfileGenerator.prototype.getRangeOption = function (name) { var otherArgs = []; for (var _i = 1; _i < arguments.length; _i++) { otherArgs[_i - 1] = arguments[_i]; } var val = this.options[name]; if (typeof val === 'function') { val = val.apply(null, otherArgs); } if (val) { val = parseRange(val, this.dateEnv); } if (val) { val = computeVisibleDayRange(val); } return val; }; /* Hidden Days ------------------------------------------------------------------------------------------------------------------*/ // Initializes internal variables related to calculating hidden days-of-week DateProfileGenerator.prototype.initHiddenDays = function () { var hiddenDays = this.options.hiddenDays || []; // array of day-of-week indices that are hidden var isHiddenDayHash = []; // is the day-of-week hidden? (hash with day-of-week-index -> bool) var dayCnt = 0; var i; if (this.options.weekends === false) { hiddenDays.push(0, 6); // 0=sunday, 6=saturday } for (i = 0; i < 7; i++) { if (!(isHiddenDayHash[i] = hiddenDays.indexOf(i) !== -1)) { dayCnt++; } } if (!dayCnt) { throw new Error('invalid hiddenDays'); // all days were hidden? bad. } this.isHiddenDayHash = isHiddenDayHash; }; // Remove days from the beginning and end of the range that are computed as hidden. // If the whole range is trimmed off, returns null DateProfileGenerator.prototype.trimHiddenDays = function (range) { var start = range.start; var end = range.end; if (start) { start = this.skipHiddenDays(start); } if (end) { end = this.skipHiddenDays(end, -1, true); } if (start == null || end == null || start < end) { return { start: start, end: end }; } return null; }; // Is the current day hidden? // `day` is a day-of-week index (0-6), or a Date (used for UTC) DateProfileGenerator.prototype.isHiddenDay = function (day) { if (day instanceof Date) { day = day.getUTCDay(); } return this.isHiddenDayHash[day]; }; // Incrementing the current day until it is no longer a hidden day, returning a copy. // DOES NOT CONSIDER validRange! // If the initial value of `date` is not a hidden day, don't do anything. // Pass `isExclusive` as `true` if you are dealing with an end date. // `inc` defaults to `1` (increment one day forward each time) DateProfileGenerator.prototype.skipHiddenDays = function (date, inc, isExclusive) { if (inc === void 0) { inc = 1; } if (isExclusive === void 0) { isExclusive = false; } while (this.isHiddenDayHash[(date.getUTCDay() + (isExclusive ? inc : 0) + 7) % 7]) { date = addDays(date, inc); } return date; }; return DateProfileGenerator; }()); // TODO: find a way to avoid comparing DateProfiles. it's tedious function isDateProfilesEqual(p0, p1) { return rangesEqual(p0.validRange, p1.validRange) && rangesEqual(p0.activeRange, p1.activeRange) && rangesEqual(p0.renderRange, p1.renderRange) && durationsEqual(p0.minTime, p1.minTime) && durationsEqual(p0.maxTime, p1.maxTime); /* TODO: compare more? currentRange: DateRange currentRangeUnit: string isRangeAllDay: boolean isValid: boolean dateIncrement: Duration */ } function reduce (state, action, calendar) { var viewType = reduceViewType(state.viewType, action); var dateProfile = reduceDateProfile(state.dateProfile, action, state.currentDate, viewType, calendar); var eventSources = reduceEventSources(state.eventSources, action, dateProfile, calendar); var nextState = __assign({}, state, { viewType: viewType, dateProfile: dateProfile, currentDate: reduceCurrentDate(state.currentDate, action, dateProfile), eventSources: eventSources, eventStore: reduceEventStore(state.eventStore, action, eventSources, dateProfile, calendar), dateSelection: reduceDateSelection(state.dateSelection, action, calendar), eventSelection: reduceSelectedEvent(state.eventSelection, action), eventDrag: reduceEventDrag(state.eventDrag, action, eventSources, calendar), eventResize: reduceEventResize(state.eventResize, action, eventSources, calendar), eventSourceLoadingLevel: computeLoadingLevel(eventSources), loadingLevel: computeLoadingLevel(eventSources) }); for (var _i = 0, _a = calendar.pluginSystem.hooks.reducers; _i < _a.length; _i++) { var reducerFunc = _a[_i]; nextState = reducerFunc(nextState, action, calendar); } // console.log(action.type, nextState) return nextState; } function reduceViewType(currentViewType, action) { switch (action.type) { case 'SET_VIEW_TYPE': return action.viewType; default: return currentViewType; } } function reduceDateProfile(currentDateProfile, action, currentDate, viewType, calendar) { var newDateProfile; switch (action.type) { case 'PREV': newDateProfile = calendar.dateProfileGenerators[viewType].buildPrev(currentDateProfile, currentDate); break; case 'NEXT': newDateProfile = calendar.dateProfileGenerators[viewType].buildNext(currentDateProfile, currentDate); break; case 'SET_DATE': if (!currentDateProfile.activeRange || !rangeContainsMarker(currentDateProfile.currentRange, action.dateMarker)) { newDateProfile = calendar.dateProfileGenerators[viewType].build(action.dateMarker, undefined, true // forceToValid ); } break; case 'SET_VIEW_TYPE': var generator = calendar.dateProfileGenerators[viewType]; if (!generator) { throw new Error(viewType ? 'The FullCalendar view "' + viewType + '" does not exist. Make sure your plugins are loaded correctly.' : 'No available FullCalendar view plugins.'); } newDateProfile = generator.build(action.dateMarker || currentDate, undefined, true // forceToValid ); break; } if (newDateProfile && newDateProfile.isValid && !(currentDateProfile && isDateProfilesEqual(currentDateProfile, newDateProfile))) { return newDateProfile; } else { return currentDateProfile; } } function reduceCurrentDate(currentDate, action, dateProfile) { switch (action.type) { case 'PREV': case 'NEXT': if (!rangeContainsMarker(dateProfile.currentRange, currentDate)) { return dateProfile.currentRange.start; } else { return currentDate; } case 'SET_DATE': case 'SET_VIEW_TYPE': var newDate = action.dateMarker || currentDate; if (dateProfile.activeRange && !rangeContainsMarker(dateProfile.activeRange, newDate)) { return dateProfile.currentRange.start; } else { return newDate; } default: return currentDate; } } function reduceDateSelection(currentSelection, action, calendar) { switch (action.type) { case 'SELECT_DATES': return action.selection; case 'UNSELECT_DATES': return null; default: return currentSelection; } } function reduceSelectedEvent(currentInstanceId, action) { switch (action.type) { case 'SELECT_EVENT': return action.eventInstanceId; case 'UNSELECT_EVENT': return ''; default: return currentInstanceId; } } function reduceEventDrag(currentDrag, action, sources, calendar) { switch (action.type) { case 'SET_EVENT_DRAG': var newDrag = action.state; return { affectedEvents: newDrag.affectedEvents, mutatedEvents: newDrag.mutatedEvents, isEvent: newDrag.isEvent, origSeg: newDrag.origSeg }; case 'UNSET_EVENT_DRAG': return null; default: return currentDrag; } } function reduceEventResize(currentResize, action, sources, calendar) { switch (action.type) { case 'SET_EVENT_RESIZE': var newResize = action.state; return { affectedEvents: newResize.affectedEvents, mutatedEvents: newResize.mutatedEvents, isEvent: newResize.isEvent, origSeg: newResize.origSeg }; case 'UNSET_EVENT_RESIZE': return null; default: return currentResize; } } function computeLoadingLevel(eventSources) { var cnt = 0; for (var sourceId in eventSources) { if (eventSources[sourceId].isFetching) { cnt++; } } return cnt; } var STANDARD_PROPS = { start: null, end: null, allDay: Boolean }; function parseDateSpan(raw, dateEnv, defaultDuration) { var span = parseOpenDateSpan(raw, dateEnv); var range = span.range; if (!range.start) { return null; } if (!range.end) { if (defaultDuration == null) { return null; } else { range.end = dateEnv.add(range.start, defaultDuration); } } return span; } /* TODO: somehow combine with parseRange? Will return null if the start/end props were present but parsed invalidly. */ function parseOpenDateSpan(raw, dateEnv) { var leftovers = {}; var standardProps = refineProps(raw, STANDARD_PROPS, {}, leftovers); var startMeta = standardProps.start ? dateEnv.createMarkerMeta(standardProps.start) : null; var endMeta = standardProps.end ? dateEnv.createMarkerMeta(standardProps.end) : null; var allDay = standardProps.allDay; if (allDay == null) { allDay = (startMeta && startMeta.isTimeUnspecified) && (!endMeta || endMeta.isTimeUnspecified); } // use this leftover object as the selection object leftovers.range = { start: startMeta ? startMeta.marker : null, end: endMeta ? endMeta.marker : null }; leftovers.allDay = allDay; return leftovers; } function isDateSpansEqual(span0, span1) { return rangesEqual(span0.range, span1.range) && span0.allDay === span1.allDay && isSpanPropsEqual(span0, span1); } // the NON-DATE-RELATED props function isSpanPropsEqual(span0, span1) { for (var propName in span1) { if (propName !== 'range' && propName !== 'allDay') { if (span0[propName] !== span1[propName]) { return false; } } } // are there any props that span0 has that span1 DOESN'T have? // both have range/allDay, so no need to special-case. for (var propName in span0) { if (!(propName in span1)) { return false; } } return true; } function buildDateSpanApi(span, dateEnv) { return { start: dateEnv.toDate(span.range.start), end: dateEnv.toDate(span.range.end), startStr: dateEnv.formatIso(span.range.start, { omitTime: span.allDay }), endStr: dateEnv.formatIso(span.range.end, { omitTime: span.allDay }), allDay: span.allDay }; } function buildDatePointApi(span, dateEnv) { return { date: dateEnv.toDate(span.range.start), dateStr: dateEnv.formatIso(span.range.start, { omitTime: span.allDay }), allDay: span.allDay }; } function fabricateEventRange(dateSpan, eventUiBases, calendar) { var def = parseEventDef({ editable: false }, '', // sourceId dateSpan.allDay, true, // hasEnd calendar); return { def: def, ui: compileEventUi(def, eventUiBases), instance: createEventInstance(def.defId, dateSpan.range), range: dateSpan.range, isStart: true, isEnd: true }; } function compileViewDefs(defaultConfigs, overrideConfigs) { var hash = {}; var viewType; for (viewType in defaultConfigs) { ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs); } for (viewType in overrideConfigs) { ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs); } return hash; } function ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs) { if (hash[viewType]) { return hash[viewType]; } var viewDef = buildViewDef(viewType, hash, defaultConfigs, overrideConfigs); if (viewDef) { hash[viewType] = viewDef; } return viewDef; } function buildViewDef(viewType, hash, defaultConfigs, overrideConfigs) { var defaultConfig = defaultConfigs[viewType]; var overrideConfig = overrideConfigs[viewType]; var queryProp = function (name) { return (defaultConfig && defaultConfig[name] !== null) ? defaultConfig[name] : ((overrideConfig && overrideConfig[name] !== null) ? overrideConfig[name] : null); }; var theClass = queryProp('class'); var superType = queryProp('superType'); if (!superType && theClass) { superType = findViewNameBySubclass(theClass, overrideConfigs) || findViewNameBySubclass(theClass, defaultConfigs); } var superDef = null; if (superType) { if (superType === viewType) { throw new Error('Can\'t have a custom view type that references itself'); } superDef = ensureViewDef(superType, hash, defaultConfigs, overrideConfigs); } if (!theClass && superDef) { theClass = superDef.class; } if (!theClass) { return null; // don't throw a warning, might be settings for a single-unit view } return { type: viewType, class: theClass, defaults: __assign({}, (superDef ? superDef.defaults : {}), (defaultConfig ? defaultConfig.options : {})), overrides: __assign({}, (superDef ? superDef.overrides : {}), (overrideConfig ? overrideConfig.options : {})) }; } function findViewNameBySubclass(viewSubclass, configs) { var superProto = Object.getPrototypeOf(viewSubclass.prototype); for (var viewType in configs) { var parsed = configs[viewType]; // need DIRECT subclass, so instanceof won't do it if (parsed.class && parsed.class.prototype === superProto) { return viewType; } } return ''; } function parseViewConfigs(inputs) { return mapHash(inputs, parseViewConfig); } var VIEW_DEF_PROPS = { type: String, class: null }; function parseViewConfig(input) { if (typeof input === 'function') { input = { class: input }; } var options = {}; var props = refineProps(input, VIEW_DEF_PROPS, {}, options); return { superType: props.type, class: props.class, options: options }; } function buildViewSpecs(defaultInputs, optionsManager) { var defaultConfigs = parseViewConfigs(defaultInputs); var overrideConfigs = parseViewConfigs(optionsManager.overrides.views); var viewDefs = compileViewDefs(defaultConfigs, overrideConfigs); return mapHash(viewDefs, function (viewDef) { return buildViewSpec(viewDef, overrideConfigs, optionsManager); }); } function buildViewSpec(viewDef, overrideConfigs, optionsManager) { var durationInput = viewDef.overrides.duration || viewDef.defaults.duration || optionsManager.dynamicOverrides.duration || optionsManager.overrides.duration; var duration = null; var durationUnit = ''; var singleUnit = ''; var singleUnitOverrides = {}; if (durationInput) { duration = createDuration(durationInput); if (duration) { // valid? var denom = greatestDurationDenominator(duration, !getWeeksFromInput(durationInput)); durationUnit = denom.unit; if (denom.value === 1) { singleUnit = durationUnit; singleUnitOverrides = overrideConfigs[durationUnit] ? overrideConfigs[durationUnit].options : {}; } } } var queryButtonText = function (options) { var buttonTextMap = options.buttonText || {}; var buttonTextKey = viewDef.defaults.buttonTextKey; if (buttonTextKey != null && buttonTextMap[buttonTextKey] != null) { return buttonTextMap[buttonTextKey]; } if (buttonTextMap[viewDef.type] != null) { return buttonTextMap[viewDef.type]; } if (buttonTextMap[singleUnit] != null) { return buttonTextMap[singleUnit]; } }; return { type: viewDef.type, class: viewDef.class, duration: duration, durationUnit: durationUnit, singleUnit: singleUnit, options: __assign({}, globalDefaults, viewDef.defaults, optionsManager.dirDefaults, optionsManager.localeDefaults, optionsManager.overrides, singleUnitOverrides, viewDef.overrides, optionsManager.dynamicOverrides), buttonTextOverride: queryButtonText(optionsManager.dynamicOverrides) || queryButtonText(optionsManager.overrides) || // constructor-specified buttonText lookup hash takes precedence viewDef.overrides.buttonText, buttonTextDefault: queryButtonText(optionsManager.localeDefaults) || queryButtonText(optionsManager.dirDefaults) || viewDef.defaults.buttonText || queryButtonText(globalDefaults) || viewDef.type // fall back to given view name }; } var Toolbar = /** @class */ (function (_super) { __extends(Toolbar, _super); function Toolbar(extraClassName) { var _this = _super.call(this) || this; _this._renderLayout = memoizeRendering(_this.renderLayout, _this.unrenderLayout); _this._updateTitle = memoizeRendering(_this.updateTitle, null, [_this._renderLayout]); _this._updateActiveButton = memoizeRendering(_this.updateActiveButton, null, [_this._renderLayout]); _this._updateToday = memoizeRendering(_this.updateToday, null, [_this._renderLayout]); _this._updatePrev = memoizeRendering(_this.updatePrev, null, [_this._renderLayout]); _this._updateNext = memoizeRendering(_this.updateNext, null, [_this._renderLayout]); _this.el = createElement('div', { className: 'fc-toolbar ' + extraClassName }); return _this; } Toolbar.prototype.destroy = function () { _super.prototype.destroy.call(this); this._renderLayout.unrender(); // should unrender everything else removeElement(this.el); }; Toolbar.prototype.render = function (props) { this._renderLayout(props.layout); this._updateTitle(props.title); this._updateActiveButton(props.activeButton); this._updateToday(props.isTodayEnabled); this._updatePrev(props.isPrevEnabled); this._updateNext(props.isNextEnabled); }; Toolbar.prototype.renderLayout = function (layout) { var el = this.el; this.viewsWithButtons = []; appendToElement(el, this.renderSection('left', layout.left)); appendToElement(el, this.renderSection('center', layout.center)); appendToElement(el, this.renderSection('right', layout.right)); }; Toolbar.prototype.unrenderLayout = function () { this.el.innerHTML = ''; }; Toolbar.prototype.renderSection = function (position, buttonStr) { var _this = this; var _a = this.context, theme = _a.theme, calendar = _a.calendar; var optionsManager = calendar.optionsManager; var viewSpecs = calendar.viewSpecs; var sectionEl = createElement('div', { className: 'fc-' + position }); var calendarCustomButtons = optionsManager.computed.customButtons || {}; var calendarButtonTextOverrides = optionsManager.overrides.buttonText || {}; var calendarButtonText = optionsManager.computed.buttonText || {}; if (buttonStr) { buttonStr.split(' ').forEach(function (buttonGroupStr, i) { var groupChildren = []; var isOnlyButtons = true; var groupEl; buttonGroupStr.split(',').forEach(function (buttonName, j) { var customButtonProps; var viewSpec; var buttonClick; var buttonIcon; // only one of these will be set var buttonText; // " var buttonInnerHtml; var buttonClasses; var buttonEl; var buttonAriaAttr; if (buttonName === 'title') { groupChildren.push(htmlToElement('

 

')); // we always want it to take up height isOnlyButtons = false; } else { if ((customButtonProps = calendarCustomButtons[buttonName])) { buttonClick = function (ev) { if (customButtonProps.click) { customButtonProps.click.call(buttonEl, ev); } }; (buttonIcon = theme.getCustomButtonIconClass(customButtonProps)) || (buttonIcon = theme.getIconClass(buttonName)) || (buttonText = customButtonProps.text); } else if ((viewSpec = viewSpecs[buttonName])) { _this.viewsWithButtons.push(buttonName); buttonClick = function () { calendar.changeView(buttonName); }; (buttonText = viewSpec.buttonTextOverride) || (buttonIcon = theme.getIconClass(buttonName)) || (buttonText = viewSpec.buttonTextDefault); } else if (calendar[buttonName]) { // a calendar method buttonClick = function () { calendar[buttonName](); }; (buttonText = calendarButtonTextOverrides[buttonName]) || (buttonIcon = theme.getIconClass(buttonName)) || (buttonText = calendarButtonText[buttonName]); // ^ everything else is considered default } if (buttonClick) { buttonClasses = [ 'fc-' + buttonName + '-button', theme.getClass('button') ]; if (buttonText) { buttonInnerHtml = htmlEscape(buttonText); buttonAriaAttr = ''; } else if (buttonIcon) { buttonInnerHtml = ""; buttonAriaAttr = ' aria-label="' + buttonName + '"'; } buttonEl = htmlToElement(// type="button" so that it doesn't submit a form ''); buttonEl.addEventListener('click', buttonClick); groupChildren.push(buttonEl); } } }); if (groupChildren.length > 1) { groupEl = document.createElement('div'); var buttonGroupClassName = theme.getClass('buttonGroup'); if (isOnlyButtons && buttonGroupClassName) { groupEl.classList.add(buttonGroupClassName); } appendToElement(groupEl, groupChildren); sectionEl.appendChild(groupEl); } else { appendToElement(sectionEl, groupChildren); // 1 or 0 children } }); } return sectionEl; }; Toolbar.prototype.updateToday = function (isTodayEnabled) { this.toggleButtonEnabled('today', isTodayEnabled); }; Toolbar.prototype.updatePrev = function (isPrevEnabled) { this.toggleButtonEnabled('prev', isPrevEnabled); }; Toolbar.prototype.updateNext = function (isNextEnabled) { this.toggleButtonEnabled('next', isNextEnabled); }; Toolbar.prototype.updateTitle = function (text) { findElements(this.el, 'h2').forEach(function (titleEl) { titleEl.innerText = text; }); }; Toolbar.prototype.updateActiveButton = function (buttonName) { var theme = this.context.theme; var className = theme.getClass('buttonActive'); findElements(this.el, 'button').forEach(function (buttonEl) { if (buttonName && buttonEl.classList.contains('fc-' + buttonName + '-button')) { buttonEl.classList.add(className); } else { buttonEl.classList.remove(className); } }); }; Toolbar.prototype.toggleButtonEnabled = function (buttonName, bool) { findElements(this.el, '.fc-' + buttonName + '-button').forEach(function (buttonEl) { buttonEl.disabled = !bool; }); }; return Toolbar; }(Component)); var CalendarComponent = /** @class */ (function (_super) { __extends(CalendarComponent, _super); function CalendarComponent(el) { var _this = _super.call(this) || this; _this.elClassNames = []; _this.renderSkeleton = memoizeRendering(_this._renderSkeleton, _this._unrenderSkeleton); _this.renderToolbars = memoizeRendering(_this._renderToolbars, _this._unrenderToolbars, [_this.renderSkeleton]); _this.buildComponentContext = memoize(buildComponentContext); _this.buildViewPropTransformers = memoize(buildViewPropTransformers); _this.el = el; _this.computeTitle = memoize(computeTitle); _this.parseBusinessHours = memoize(function (input) { return parseBusinessHours(input, _this.context.calendar); }); return _this; } CalendarComponent.prototype.render = function (props, context) { this.freezeHeight(); var title = this.computeTitle(props.dateProfile, props.viewSpec.options); this.renderSkeleton(context); this.renderToolbars(props.viewSpec, props.dateProfile, props.currentDate, title); this.renderView(props, title); this.updateSize(); this.thawHeight(); }; CalendarComponent.prototype.destroy = function () { if (this.header) { this.header.destroy(); } if (this.footer) { this.footer.destroy(); } this.renderSkeleton.unrender(); // will call destroyView _super.prototype.destroy.call(this); }; CalendarComponent.prototype._renderSkeleton = function (context) { this.updateElClassNames(context); prependToElement(this.el, this.contentEl = createElement('div', { className: 'fc-view-container' })); var calendar = context.calendar; for (var _i = 0, _a = calendar.pluginSystem.hooks.viewContainerModifiers; _i < _a.length; _i++) { var modifyViewContainer = _a[_i]; modifyViewContainer(this.contentEl, calendar); } }; CalendarComponent.prototype._unrenderSkeleton = function () { // weird to have this here if (this.view) { this.savedScroll = this.view.queryScroll(); this.view.destroy(); this.view = null; } removeElement(this.contentEl); this.removeElClassNames(); }; CalendarComponent.prototype.removeElClassNames = function () { var classList = this.el.classList; for (var _i = 0, _a = this.elClassNames; _i < _a.length; _i++) { var className = _a[_i]; classList.remove(className); } this.elClassNames = []; }; CalendarComponent.prototype.updateElClassNames = function (context) { this.removeElClassNames(); var theme = context.theme, options = context.options; this.elClassNames = [ 'fc', 'fc-' + options.dir, theme.getClass('widget') ]; var classList = this.el.classList; for (var _i = 0, _a = this.elClassNames; _i < _a.length; _i++) { var className = _a[_i]; classList.add(className); } }; CalendarComponent.prototype._renderToolbars = function (viewSpec, dateProfile, currentDate, title) { var _a = this, context = _a.context, header = _a.header, footer = _a.footer; var options = context.options, calendar = context.calendar; var headerLayout = options.header; var footerLayout = options.footer; var dateProfileGenerator = this.props.dateProfileGenerator; var now = calendar.getNow(); var todayInfo = dateProfileGenerator.build(now); var prevInfo = dateProfileGenerator.buildPrev(dateProfile, currentDate); var nextInfo = dateProfileGenerator.buildNext(dateProfile, currentDate); var toolbarProps = { title: title, activeButton: viewSpec.type, isTodayEnabled: todayInfo.isValid && !rangeContainsMarker(dateProfile.currentRange, now), isPrevEnabled: prevInfo.isValid, isNextEnabled: nextInfo.isValid }; if (headerLayout) { if (!header) { header = this.header = new Toolbar('fc-header-toolbar'); prependToElement(this.el, header.el); } header.receiveProps(__assign({ layout: headerLayout }, toolbarProps), context); } else if (header) { header.destroy(); header = this.header = null; } if (footerLayout) { if (!footer) { footer = this.footer = new Toolbar('fc-footer-toolbar'); appendToElement(this.el, footer.el); } footer.receiveProps(__assign({ layout: footerLayout }, toolbarProps), context); } else if (footer) { footer.destroy(); footer = this.footer = null; } }; CalendarComponent.prototype._unrenderToolbars = function () { if (this.header) { this.header.destroy(); this.header = null; } if (this.footer) { this.footer.destroy(); this.footer = null; } }; CalendarComponent.prototype.renderView = function (props, title) { var view = this.view; var _a = this.context, calendar = _a.calendar, options = _a.options; var viewSpec = props.viewSpec, dateProfileGenerator = props.dateProfileGenerator; if (!view || view.viewSpec !== viewSpec) { if (view) { view.destroy(); } view = this.view = new viewSpec['class'](viewSpec, this.contentEl); if (this.savedScroll) { view.addScroll(this.savedScroll, true); this.savedScroll = null; } } view.title = title; // for the API var viewProps = { dateProfileGenerator: dateProfileGenerator, dateProfile: props.dateProfile, businessHours: this.parseBusinessHours(viewSpec.options.businessHours), eventStore: props.eventStore, eventUiBases: props.eventUiBases, dateSelection: props.dateSelection, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize }; var transformers = this.buildViewPropTransformers(calendar.pluginSystem.hooks.viewPropsTransformers); for (var _i = 0, transformers_1 = transformers; _i < transformers_1.length; _i++) { var transformer = transformers_1[_i]; __assign(viewProps, transformer.transform(viewProps, viewSpec, props, options)); } view.receiveProps(viewProps, this.buildComponentContext(this.context, viewSpec, view)); }; // Sizing // ----------------------------------------------------------------------------------------------------------------- CalendarComponent.prototype.updateSize = function (isResize) { if (isResize === void 0) { isResize = false; } var view = this.view; if (!view) { return; // why? } if (isResize || this.isHeightAuto == null) { this.computeHeightVars(); } view.updateSize(isResize, this.viewHeight, this.isHeightAuto); view.updateNowIndicator(); // we need to guarantee this will run after updateSize view.popScroll(isResize); }; CalendarComponent.prototype.computeHeightVars = function () { var calendar = this.context.calendar; // yuck. need to handle dynamic options var heightInput = calendar.opt('height'); var contentHeightInput = calendar.opt('contentHeight'); this.isHeightAuto = heightInput === 'auto' || contentHeightInput === 'auto'; if (typeof contentHeightInput === 'number') { // exists and not 'auto' this.viewHeight = contentHeightInput; } else if (typeof contentHeightInput === 'function') { // exists and is a function this.viewHeight = contentHeightInput(); } else if (typeof heightInput === 'number') { // exists and not 'auto' this.viewHeight = heightInput - this.queryToolbarsHeight(); } else if (typeof heightInput === 'function') { // exists and is a function this.viewHeight = heightInput() - this.queryToolbarsHeight(); } else if (heightInput === 'parent') { // set to height of parent element var parentEl = this.el.parentNode; this.viewHeight = parentEl.getBoundingClientRect().height - this.queryToolbarsHeight(); } else { this.viewHeight = Math.round(this.contentEl.getBoundingClientRect().width / Math.max(calendar.opt('aspectRatio'), .5)); } }; CalendarComponent.prototype.queryToolbarsHeight = function () { var height = 0; if (this.header) { height += computeHeightAndMargins(this.header.el); } if (this.footer) { height += computeHeightAndMargins(this.footer.el); } return height; }; // Height "Freezing" // ----------------------------------------------------------------------------------------------------------------- CalendarComponent.prototype.freezeHeight = function () { applyStyle(this.el, { height: this.el.getBoundingClientRect().height, overflow: 'hidden' }); }; CalendarComponent.prototype.thawHeight = function () { applyStyle(this.el, { height: '', overflow: '' }); }; return CalendarComponent; }(Component)); // Title and Date Formatting // ----------------------------------------------------------------------------------------------------------------- // Computes what the title at the top of the calendar should be for this view function computeTitle(dateProfile, viewOptions) { var range; // for views that span a large unit of time, show the proper interval, ignoring stray days before and after if (/^(year|month)$/.test(dateProfile.currentRangeUnit)) { range = dateProfile.currentRange; } else { // for day units or smaller, use the actual day range range = dateProfile.activeRange; } return this.context.dateEnv.formatRange(range.start, range.end, createFormatter(viewOptions.titleFormat || computeTitleFormat(dateProfile), viewOptions.titleRangeSeparator), { isEndExclusive: dateProfile.isRangeAllDay }); } // Generates the format string that should be used to generate the title for the current date range. // Attempts to compute the most appropriate format if not explicitly specified with `titleFormat`. function computeTitleFormat(dateProfile) { var currentRangeUnit = dateProfile.currentRangeUnit; if (currentRangeUnit === 'year') { return { year: 'numeric' }; } else if (currentRangeUnit === 'month') { return { year: 'numeric', month: 'long' }; // like "September 2014" } else { var days = diffWholeDays(dateProfile.currentRange.start, dateProfile.currentRange.end); if (days !== null && days > 1) { // multi-day range. shorter, like "Sep 9 - 10 2014" return { year: 'numeric', month: 'short', day: 'numeric' }; } else { // one day. longer, like "September 9 2014" return { year: 'numeric', month: 'long', day: 'numeric' }; } } } // build a context scoped to the view function buildComponentContext(context, viewSpec, view) { return context.extend(viewSpec.options, view); } // Plugin // ----------------------------------------------------------------------------------------------------------------- function buildViewPropTransformers(theClasses) { return theClasses.map(function (theClass) { return new theClass(); }); } var Interaction = /** @class */ (function () { function Interaction(settings) { this.component = settings.component; } Interaction.prototype.destroy = function () { }; return Interaction; }()); function parseInteractionSettings(component, input) { return { component: component, el: input.el, useEventCenter: input.useEventCenter != null ? input.useEventCenter : true }; } function interactionSettingsToStore(settings) { var _a; return _a = {}, _a[settings.component.uid] = settings, _a; } // global state var interactionSettingsStore = {}; /* Detects when the user clicks on an event within a DateComponent */ var EventClicking = /** @class */ (function (_super) { __extends(EventClicking, _super); function EventClicking(settings) { var _this = _super.call(this, settings) || this; _this.handleSegClick = function (ev, segEl) { var component = _this.component; var _a = component.context, calendar = _a.calendar, view = _a.view; var seg = getElSeg(segEl); if (seg && // might be the
surrounding the more link component.isValidSegDownEl(ev.target)) { // our way to simulate a link click for elements that can't be tags // grab before trigger fired in case trigger trashes DOM thru rerendering var hasUrlContainer = elementClosest(ev.target, '.fc-has-url'); var url = hasUrlContainer ? hasUrlContainer.querySelector('a[href]').href : ''; calendar.publiclyTrigger('eventClick', [ { el: segEl, event: new EventApi(component.context.calendar, seg.eventRange.def, seg.eventRange.instance), jsEvent: ev, view: view } ]); if (url && !ev.defaultPrevented) { window.location.href = url; } } }; var component = settings.component; _this.destroy = listenBySelector(component.el, 'click', component.fgSegSelector + ',' + component.bgSegSelector, _this.handleSegClick); return _this; } return EventClicking; }(Interaction)); /* Triggers events and adds/removes core classNames when the user's pointer enters/leaves event-elements of a component. */ var EventHovering = /** @class */ (function (_super) { __extends(EventHovering, _super); function EventHovering(settings) { var _this = _super.call(this, settings) || this; // for simulating an eventMouseLeave when the event el is destroyed while mouse is over it _this.handleEventElRemove = function (el) { if (el === _this.currentSegEl) { _this.handleSegLeave(null, _this.currentSegEl); } }; _this.handleSegEnter = function (ev, segEl) { if (getElSeg(segEl)) { // TODO: better way to make sure not hovering over more+ link or its wrapper segEl.classList.add('fc-allow-mouse-resize'); _this.currentSegEl = segEl; _this.triggerEvent('eventMouseEnter', ev, segEl); } }; _this.handleSegLeave = function (ev, segEl) { if (_this.currentSegEl) { segEl.classList.remove('fc-allow-mouse-resize'); _this.currentSegEl = null; _this.triggerEvent('eventMouseLeave', ev, segEl); } }; var component = settings.component; _this.removeHoverListeners = listenToHoverBySelector(component.el, component.fgSegSelector + ',' + component.bgSegSelector, _this.handleSegEnter, _this.handleSegLeave); // how to make sure component already has context? component.context.calendar.on('eventElRemove', _this.handleEventElRemove); return _this; } EventHovering.prototype.destroy = function () { this.removeHoverListeners(); this.component.context.calendar.off('eventElRemove', this.handleEventElRemove); }; EventHovering.prototype.triggerEvent = function (publicEvName, ev, segEl) { var component = this.component; var _a = component.context, calendar = _a.calendar, view = _a.view; var seg = getElSeg(segEl); if (!ev || component.isValidSegDownEl(ev.target)) { calendar.publiclyTrigger(publicEvName, [ { el: segEl, event: new EventApi(calendar, seg.eventRange.def, seg.eventRange.instance), jsEvent: ev, view: view } ]); } }; return EventHovering; }(Interaction)); var StandardTheme = /** @class */ (function (_super) { __extends(StandardTheme, _super); function StandardTheme() { return _super !== null && _super.apply(this, arguments) || this; } return StandardTheme; }(Theme)); StandardTheme.prototype.classes = { widget: 'fc-unthemed', widgetHeader: 'fc-widget-header', widgetContent: 'fc-widget-content', buttonGroup: 'fc-button-group', button: 'fc-button fc-button-primary', buttonActive: 'fc-button-active', popoverHeader: 'fc-widget-header', popoverContent: 'fc-widget-content', // day grid headerRow: 'fc-widget-header', dayRow: 'fc-widget-content', // list view listView: 'fc-widget-content' }; StandardTheme.prototype.baseIconClass = 'fc-icon'; StandardTheme.prototype.iconClasses = { close: 'fc-icon-x', prev: 'fc-icon-chevron-left', next: 'fc-icon-chevron-right', prevYear: 'fc-icon-chevrons-left', nextYear: 'fc-icon-chevrons-right' }; StandardTheme.prototype.iconOverrideOption = 'buttonIcons'; StandardTheme.prototype.iconOverrideCustomButtonOption = 'icon'; StandardTheme.prototype.iconOverridePrefix = 'fc-icon-'; var Calendar = /** @class */ (function () { function Calendar(el, overrides) { var _this = this; this.buildComponentContext = memoize(buildComponentContext$1); this.parseRawLocales = memoize(parseRawLocales); this.buildLocale = memoize(buildLocale); this.buildDateEnv = memoize(buildDateEnv); this.buildTheme = memoize(buildTheme); this.buildEventUiSingleBase = memoize(this._buildEventUiSingleBase); this.buildSelectionConfig = memoize(this._buildSelectionConfig); this.buildEventUiBySource = memoizeOutput(buildEventUiBySource, isPropsEqual); this.buildEventUiBases = memoize(buildEventUiBases); this.interactionsStore = {}; this.actionQueue = []; this.isReducing = false; // isDisplaying: boolean = false // installed in DOM? accepting renders? this.needsRerender = false; // needs a render? this.isRendering = false; // currently in the executeRender function? this.renderingPauseDepth = 0; this.buildDelayedRerender = memoize(buildDelayedRerender); this.afterSizingTriggers = {}; this.isViewUpdated = false; this.isDatesUpdated = false; this.isEventsUpdated = false; this.el = el; this.optionsManager = new OptionsManager(overrides || {}); this.pluginSystem = new PluginSystem(); // only do once. don't do in handleOptions. because can't remove plugins this.addPluginInputs(this.optionsManager.computed.plugins || []); this.handleOptions(this.optionsManager.computed); this.publiclyTrigger('_init'); // for tests this.hydrate(); this.calendarInteractions = this.pluginSystem.hooks.calendarInteractions .map(function (calendarInteractionClass) { return new calendarInteractionClass(_this); }); } Calendar.prototype.addPluginInputs = function (pluginInputs) { var pluginDefs = refinePluginDefs(pluginInputs); for (var _i = 0, pluginDefs_1 = pluginDefs; _i < pluginDefs_1.length; _i++) { var pluginDef = pluginDefs_1[_i]; this.pluginSystem.add(pluginDef); } }; Object.defineProperty(Calendar.prototype, "view", { // public API get: function () { return this.component ? this.component.view : null; }, enumerable: true, configurable: true }); // Public API for rendering // ----------------------------------------------------------------------------------------------------------------- Calendar.prototype.render = function () { if (!this.component) { this.component = new CalendarComponent(this.el); this.renderableEventStore = createEmptyEventStore(); this.bindHandlers(); this.executeRender(); } else { this.requestRerender(); } }; Calendar.prototype.destroy = function () { if (this.component) { this.unbindHandlers(); this.component.destroy(); // don't null-out. in case API needs access this.component = null; // umm ??? for (var _i = 0, _a = this.calendarInteractions; _i < _a.length; _i++) { var interaction = _a[_i]; interaction.destroy(); } this.publiclyTrigger('_destroyed'); } }; // Handlers // ----------------------------------------------------------------------------------------------------------------- Calendar.prototype.bindHandlers = function () { var _this = this; // event delegation for nav links this.removeNavLinkListener = listenBySelector(this.el, 'click', 'a[data-goto]', function (ev, anchorEl) { var gotoOptions = anchorEl.getAttribute('data-goto'); gotoOptions = gotoOptions ? JSON.parse(gotoOptions) : {}; var dateEnv = _this.dateEnv; var dateMarker = dateEnv.createMarker(gotoOptions.date); var viewType = gotoOptions.type; // property like "navLinkDayClick". might be a string or a function var customAction = _this.viewOpt('navLink' + capitaliseFirstLetter(viewType) + 'Click'); if (typeof customAction === 'function') { customAction(dateEnv.toDate(dateMarker), ev); } else { if (typeof customAction === 'string') { viewType = customAction; } _this.zoomTo(dateMarker, viewType); } }); if (this.opt('handleWindowResize')) { window.addEventListener('resize', this.windowResizeProxy = debounce(// prevents rapid calls this.windowResize.bind(this), this.opt('windowResizeDelay'))); } }; Calendar.prototype.unbindHandlers = function () { this.removeNavLinkListener(); if (this.windowResizeProxy) { window.removeEventListener('resize', this.windowResizeProxy); this.windowResizeProxy = null; } }; // Dispatcher // ----------------------------------------------------------------------------------------------------------------- Calendar.prototype.hydrate = function () { var _this = this; this.state = this.buildInitialState(); var rawSources = this.opt('eventSources') || []; var singleRawSource = this.opt('events'); var sources = []; // parsed if (singleRawSource) { rawSources.unshift(singleRawSource); } for (var _i = 0, rawSources_1 = rawSources; _i < rawSources_1.length; _i++) { var rawSource = rawSources_1[_i]; var source = parseEventSource(rawSource, this); if (source) { sources.push(source); } } this.batchRendering(function () { _this.dispatch({ type: 'INIT' }); // pass in sources here? _this.dispatch({ type: 'ADD_EVENT_SOURCES', sources: sources }); _this.dispatch({ type: 'SET_VIEW_TYPE', viewType: _this.opt('defaultView') || _this.pluginSystem.hooks.defaultView }); }); }; Calendar.prototype.buildInitialState = function () { return { viewType: null, loadingLevel: 0, eventSourceLoadingLevel: 0, currentDate: this.getInitialDate(), dateProfile: null, eventSources: {}, eventStore: createEmptyEventStore(), dateSelection: null, eventSelection: '', eventDrag: null, eventResize: null }; }; Calendar.prototype.dispatch = function (action) { this.actionQueue.push(action); if (!this.isReducing) { this.isReducing = true; var oldState = this.state; while (this.actionQueue.length) { this.state = this.reduce(this.state, this.actionQueue.shift(), this); } var newState = this.state; this.isReducing = false; if (!oldState.loadingLevel && newState.loadingLevel) { this.publiclyTrigger('loading', [true]); } else if (oldState.loadingLevel && !newState.loadingLevel) { this.publiclyTrigger('loading', [false]); } var view = this.component && this.component.view; if (oldState.eventStore !== newState.eventStore) { if (oldState.eventStore) { this.isEventsUpdated = true; } } if (oldState.dateProfile !== newState.dateProfile) { if (oldState.dateProfile && view) { // why would view be null!? this.publiclyTrigger('datesDestroy', [ { view: view, el: view.el } ]); } this.isDatesUpdated = true; } if (oldState.viewType !== newState.viewType) { if (oldState.viewType && view) { // why would view be null!? this.publiclyTrigger('viewSkeletonDestroy', [ { view: view, el: view.el } ]); } this.isViewUpdated = true; } this.requestRerender(); } }; Calendar.prototype.reduce = function (state, action, calendar) { return reduce(state, action, calendar); }; // Render Queue // ----------------------------------------------------------------------------------------------------------------- Calendar.prototype.requestRerender = function () { this.needsRerender = true; this.delayedRerender(); // will call a debounced-version of tryRerender }; Calendar.prototype.tryRerender = function () { if (this.component && // must be accepting renders this.needsRerender && // indicates that a rerender was requested !this.renderingPauseDepth && // not paused !this.isRendering // not currently in the render loop ) { this.executeRender(); } }; Calendar.prototype.batchRendering = function (func) { this.renderingPauseDepth++; func(); this.renderingPauseDepth--; if (this.needsRerender) { this.requestRerender(); } }; // Rendering // ----------------------------------------------------------------------------------------------------------------- Calendar.prototype.executeRender = function () { // clear these BEFORE the render so that new values will accumulate during render this.needsRerender = false; this.isRendering = true; this.renderComponent(); this.isRendering = false; // received a rerender request while rendering if (this.needsRerender) { this.delayedRerender(); } }; /* don't call this directly. use executeRender instead */ Calendar.prototype.renderComponent = function () { var _a = this, state = _a.state, component = _a.component; var viewType = state.viewType; var viewSpec = this.viewSpecs[viewType]; if (!viewSpec) { throw new Error("View type \"" + viewType + "\" is not valid"); } // if event sources are still loading and progressive rendering hasn't been enabled, // keep rendering the last fully loaded set of events var renderableEventStore = this.renderableEventStore = (state.eventSourceLoadingLevel && !this.opt('progressiveEventRendering')) ? this.renderableEventStore : state.eventStore; var eventUiSingleBase = this.buildEventUiSingleBase(viewSpec.options); var eventUiBySource = this.buildEventUiBySource(state.eventSources); var eventUiBases = this.eventUiBases = this.buildEventUiBases(renderableEventStore.defs, eventUiSingleBase, eventUiBySource); component.receiveProps(__assign({}, state, { viewSpec: viewSpec, dateProfileGenerator: this.dateProfileGenerators[viewType], dateProfile: state.dateProfile, eventStore: renderableEventStore, eventUiBases: eventUiBases, dateSelection: state.dateSelection, eventSelection: state.eventSelection, eventDrag: state.eventDrag, eventResize: state.eventResize }), this.buildComponentContext(this.theme, this.dateEnv, this.optionsManager.computed)); if (this.isViewUpdated) { this.isViewUpdated = false; this.publiclyTrigger('viewSkeletonRender', [ { view: component.view, el: component.view.el } ]); } if (this.isDatesUpdated) { this.isDatesUpdated = false; this.publiclyTrigger('datesRender', [ { view: component.view, el: component.view.el } ]); } if (this.isEventsUpdated) { this.isEventsUpdated = false; } this.releaseAfterSizingTriggers(); }; // Options // ----------------------------------------------------------------------------------------------------------------- Calendar.prototype.setOption = function (name, val) { var _a; this.mutateOptions((_a = {}, _a[name] = val, _a), [], true); }; Calendar.prototype.getOption = function (name) { return this.optionsManager.computed[name]; }; Calendar.prototype.opt = function (name) { return this.optionsManager.computed[name]; }; Calendar.prototype.viewOpt = function (name) { return this.viewOpts()[name]; }; Calendar.prototype.viewOpts = function () { return this.viewSpecs[this.state.viewType].options; }; /* handles option changes (like a diff) */ Calendar.prototype.mutateOptions = function (updates, removals, isDynamic, deepEqual) { var _this = this; var changeHandlers = this.pluginSystem.hooks.optionChangeHandlers; var normalUpdates = {}; var specialUpdates = {}; var oldDateEnv = this.dateEnv; // do this before handleOptions var isTimeZoneDirty = false; var isSizeDirty = false; var anyDifficultOptions = Boolean(removals.length); for (var name_1 in updates) { if (changeHandlers[name_1]) { specialUpdates[name_1] = updates[name_1]; } else { normalUpdates[name_1] = updates[name_1]; } } for (var name_2 in normalUpdates) { if (/^(height|contentHeight|aspectRatio)$/.test(name_2)) { isSizeDirty = true; } else if (/^(defaultDate|defaultView)$/.test(name_2)) ; else { anyDifficultOptions = true; if (name_2 === 'timeZone') { isTimeZoneDirty = true; } } } this.optionsManager.mutate(normalUpdates, removals, isDynamic); if (anyDifficultOptions) { this.handleOptions(this.optionsManager.computed); } this.batchRendering(function () { if (anyDifficultOptions) { if (isTimeZoneDirty) { _this.dispatch({ type: 'CHANGE_TIMEZONE', oldDateEnv: oldDateEnv }); } /* HACK has the same effect as calling this.requestRerender() but recomputes the state's dateProfile */ _this.dispatch({ type: 'SET_VIEW_TYPE', viewType: _this.state.viewType }); } else if (isSizeDirty) { _this.updateSize(); } // special updates if (deepEqual) { for (var name_3 in specialUpdates) { changeHandlers[name_3](specialUpdates[name_3], _this, deepEqual); } } }); }; /* rebuilds things based off of a complete set of refined options */ Calendar.prototype.handleOptions = function (options) { var _this = this; var pluginHooks = this.pluginSystem.hooks; this.defaultAllDayEventDuration = createDuration(options.defaultAllDayEventDuration); this.defaultTimedEventDuration = createDuration(options.defaultTimedEventDuration); this.delayedRerender = this.buildDelayedRerender(options.rerenderDelay); this.theme = this.buildTheme(options); var available = this.parseRawLocales(options.locales); this.availableRawLocales = available.map; var locale = this.buildLocale(options.locale || available.defaultCode, available.map); this.dateEnv = this.buildDateEnv(locale, options.timeZone, pluginHooks.namedTimeZonedImpl, options.firstDay, options.weekNumberCalculation, options.weekLabel, pluginHooks.cmdFormatter); this.selectionConfig = this.buildSelectionConfig(options); // needs dateEnv. do after :( // ineffecient to do every time? this.viewSpecs = buildViewSpecs(pluginHooks.views, this.optionsManager); // ineffecient to do every time? this.dateProfileGenerators = mapHash(this.viewSpecs, function (viewSpec) { return new viewSpec.class.prototype.dateProfileGeneratorClass(viewSpec, _this); }); }; Calendar.prototype.getAvailableLocaleCodes = function () { return Object.keys(this.availableRawLocales); }; Calendar.prototype._buildSelectionConfig = function (rawOpts) { return processScopedUiProps('select', rawOpts, this); }; Calendar.prototype._buildEventUiSingleBase = function (rawOpts) { if (rawOpts.editable) { // so 'editable' affected events rawOpts = __assign({}, rawOpts, { eventEditable: true }); } return processScopedUiProps('event', rawOpts, this); }; // Trigger // ----------------------------------------------------------------------------------------------------------------- Calendar.prototype.hasPublicHandlers = function (name) { return this.hasHandlers(name) || this.opt(name); // handler specified in options }; Calendar.prototype.publiclyTrigger = function (name, args) { var optHandler = this.opt(name); this.triggerWith(name, this, args); if (optHandler) { return optHandler.apply(this, args); } }; Calendar.prototype.publiclyTriggerAfterSizing = function (name, args) { var afterSizingTriggers = this.afterSizingTriggers; (afterSizingTriggers[name] || (afterSizingTriggers[name] = [])).push(args); }; Calendar.prototype.releaseAfterSizingTriggers = function () { var afterSizingTriggers = this.afterSizingTriggers; for (var name_4 in afterSizingTriggers) { for (var _i = 0, _a = afterSizingTriggers[name_4]; _i < _a.length; _i++) { var args = _a[_i]; this.publiclyTrigger(name_4, args); } } this.afterSizingTriggers = {}; }; // View // ----------------------------------------------------------------------------------------------------------------- // Returns a boolean about whether the view is okay to instantiate at some point Calendar.prototype.isValidViewType = function (viewType) { return Boolean(this.viewSpecs[viewType]); }; Calendar.prototype.changeView = function (viewType, dateOrRange) { var dateMarker = null; if (dateOrRange) { if (dateOrRange.start && dateOrRange.end) { // a range this.optionsManager.mutate({ visibleRange: dateOrRange }, []); // will not rerender this.handleOptions(this.optionsManager.computed); // ...but yuck } else { // a date dateMarker = this.dateEnv.createMarker(dateOrRange); // just like gotoDate } } this.unselect(); this.dispatch({ type: 'SET_VIEW_TYPE', viewType: viewType, dateMarker: dateMarker }); }; // Forces navigation to a view for the given date. // `viewType` can be a specific view name or a generic one like "week" or "day". // needs to change Calendar.prototype.zoomTo = function (dateMarker, viewType) { var spec; viewType = viewType || 'day'; // day is default zoom spec = this.viewSpecs[viewType] || this.getUnitViewSpec(viewType); this.unselect(); if (spec) { this.dispatch({ type: 'SET_VIEW_TYPE', viewType: spec.type, dateMarker: dateMarker }); } else { this.dispatch({ type: 'SET_DATE', dateMarker: dateMarker }); } }; // Given a duration singular unit, like "week" or "day", finds a matching view spec. // Preference is given to views that have corresponding buttons. Calendar.prototype.getUnitViewSpec = function (unit) { var component = this.component; var viewTypes = []; var i; var spec; // put views that have buttons first. there will be duplicates, but oh if (component.header) { viewTypes.push.apply(viewTypes, component.header.viewsWithButtons); } if (component.footer) { viewTypes.push.apply(viewTypes, component.footer.viewsWithButtons); } for (var viewType in this.viewSpecs) { viewTypes.push(viewType); } for (i = 0; i < viewTypes.length; i++) { spec = this.viewSpecs[viewTypes[i]]; if (spec) { if (spec.singleUnit === unit) { return spec; } } } }; // Current Date // ----------------------------------------------------------------------------------------------------------------- Calendar.prototype.getInitialDate = function () { var defaultDateInput = this.opt('defaultDate'); // compute the initial ambig-timezone date if (defaultDateInput != null) { return this.dateEnv.createMarker(defaultDateInput); } else { return this.getNow(); // getNow already returns unzoned } }; Calendar.prototype.prev = function () { this.unselect(); this.dispatch({ type: 'PREV' }); }; Calendar.prototype.next = function () { this.unselect(); this.dispatch({ type: 'NEXT' }); }; Calendar.prototype.prevYear = function () { this.unselect(); this.dispatch({ type: 'SET_DATE', dateMarker: this.dateEnv.addYears(this.state.currentDate, -1) }); }; Calendar.prototype.nextYear = function () { this.unselect(); this.dispatch({ type: 'SET_DATE', dateMarker: this.dateEnv.addYears(this.state.currentDate, 1) }); }; Calendar.prototype.today = function () { this.unselect(); this.dispatch({ type: 'SET_DATE', dateMarker: this.getNow() }); }; Calendar.prototype.gotoDate = function (zonedDateInput) { this.unselect(); this.dispatch({ type: 'SET_DATE', dateMarker: this.dateEnv.createMarker(zonedDateInput) }); }; Calendar.prototype.incrementDate = function (deltaInput) { var delta = createDuration(deltaInput); if (delta) { // else, warn about invalid input? this.unselect(); this.dispatch({ type: 'SET_DATE', dateMarker: this.dateEnv.add(this.state.currentDate, delta) }); } }; // for external API Calendar.prototype.getDate = function () { return this.dateEnv.toDate(this.state.currentDate); }; // Date Formatting Utils // ----------------------------------------------------------------------------------------------------------------- Calendar.prototype.formatDate = function (d, formatter) { var dateEnv = this.dateEnv; return dateEnv.format(dateEnv.createMarker(d), createFormatter(formatter)); }; // `settings` is for formatter AND isEndExclusive Calendar.prototype.formatRange = function (d0, d1, settings) { var dateEnv = this.dateEnv; return dateEnv.formatRange(dateEnv.createMarker(d0), dateEnv.createMarker(d1), createFormatter(settings, this.opt('defaultRangeSeparator')), settings); }; Calendar.prototype.formatIso = function (d, omitTime) { var dateEnv = this.dateEnv; return dateEnv.formatIso(dateEnv.createMarker(d), { omitTime: omitTime }); }; // Sizing // ----------------------------------------------------------------------------------------------------------------- Calendar.prototype.windowResize = function (ev) { if (!this.isHandlingWindowResize && this.component && // why? ev.target === window // not a jqui resize event ) { this.isHandlingWindowResize = true; this.updateSize(); this.publiclyTrigger('windowResize', [this.view]); this.isHandlingWindowResize = false; } }; Calendar.prototype.updateSize = function () { if (this.component) { // when? this.component.updateSize(true); } }; // Component Registration // ----------------------------------------------------------------------------------------------------------------- Calendar.prototype.registerInteractiveComponent = function (component, settingsInput) { var settings = parseInteractionSettings(component, settingsInput); var DEFAULT_INTERACTIONS = [ EventClicking, EventHovering ]; var interactionClasses = DEFAULT_INTERACTIONS.concat(this.pluginSystem.hooks.componentInteractions); var interactions = interactionClasses.map(function (interactionClass) { return new interactionClass(settings); }); this.interactionsStore[component.uid] = interactions; interactionSettingsStore[component.uid] = settings; }; Calendar.prototype.unregisterInteractiveComponent = function (component) { for (var _i = 0, _a = this.interactionsStore[component.uid]; _i < _a.length; _i++) { var listener = _a[_i]; listener.destroy(); } delete this.interactionsStore[component.uid]; delete interactionSettingsStore[component.uid]; }; // Date Selection / Event Selection / DayClick // ----------------------------------------------------------------------------------------------------------------- // this public method receives start/end dates in any format, with any timezone // NOTE: args were changed from v3 Calendar.prototype.select = function (dateOrObj, endDate) { var selectionInput; if (endDate == null) { if (dateOrObj.start != null) { selectionInput = dateOrObj; } else { selectionInput = { start: dateOrObj, end: null }; } } else { selectionInput = { start: dateOrObj, end: endDate }; } var selection = parseDateSpan(selectionInput, this.dateEnv, createDuration({ days: 1 }) // TODO: cache this? ); if (selection) { // throw parse error otherwise? this.dispatch({ type: 'SELECT_DATES', selection: selection }); this.triggerDateSelect(selection); } }; // public method Calendar.prototype.unselect = function (pev) { if (this.state.dateSelection) { this.dispatch({ type: 'UNSELECT_DATES' }); this.triggerDateUnselect(pev); } }; Calendar.prototype.triggerDateSelect = function (selection, pev) { var arg = __assign({}, this.buildDateSpanApi(selection), { jsEvent: pev ? pev.origEvent : null, view: this.view }); this.publiclyTrigger('select', [arg]); }; Calendar.prototype.triggerDateUnselect = function (pev) { this.publiclyTrigger('unselect', [ { jsEvent: pev ? pev.origEvent : null, view: this.view } ]); }; // TODO: receive pev? Calendar.prototype.triggerDateClick = function (dateSpan, dayEl, view, ev) { var arg = __assign({}, this.buildDatePointApi(dateSpan), { dayEl: dayEl, jsEvent: ev, // Is this always a mouse event? See #4655 view: view }); this.publiclyTrigger('dateClick', [arg]); }; Calendar.prototype.buildDatePointApi = function (dateSpan) { var props = {}; for (var _i = 0, _a = this.pluginSystem.hooks.datePointTransforms; _i < _a.length; _i++) { var transform = _a[_i]; __assign(props, transform(dateSpan, this)); } __assign(props, buildDatePointApi(dateSpan, this.dateEnv)); return props; }; Calendar.prototype.buildDateSpanApi = function (dateSpan) { var props = {}; for (var _i = 0, _a = this.pluginSystem.hooks.dateSpanTransforms; _i < _a.length; _i++) { var transform = _a[_i]; __assign(props, transform(dateSpan, this)); } __assign(props, buildDateSpanApi(dateSpan, this.dateEnv)); return props; }; // Date Utils // ----------------------------------------------------------------------------------------------------------------- // Returns a DateMarker for the current date, as defined by the client's computer or from the `now` option Calendar.prototype.getNow = function () { var now = this.opt('now'); if (typeof now === 'function') { now = now(); } if (now == null) { return this.dateEnv.createNowMarker(); } return this.dateEnv.createMarker(now); }; // Event-Date Utilities // ----------------------------------------------------------------------------------------------------------------- // Given an event's allDay status and start date, return what its fallback end date should be. // TODO: rename to computeDefaultEventEnd Calendar.prototype.getDefaultEventEnd = function (allDay, marker) { var end = marker; if (allDay) { end = startOfDay(end); end = this.dateEnv.add(end, this.defaultAllDayEventDuration); } else { end = this.dateEnv.add(end, this.defaultTimedEventDuration); } return end; }; // Public Events API // ----------------------------------------------------------------------------------------------------------------- Calendar.prototype.addEvent = function (eventInput, sourceInput) { if (eventInput instanceof EventApi) { var def = eventInput._def; var instance = eventInput._instance; // not already present? don't want to add an old snapshot if (!this.state.eventStore.defs[def.defId]) { this.dispatch({ type: 'ADD_EVENTS', eventStore: eventTupleToStore({ def: def, instance: instance }) // TODO: better util for two args? }); } return eventInput; } var sourceId; if (sourceInput instanceof EventSourceApi) { sourceId = sourceInput.internalEventSource.sourceId; } else if (sourceInput != null) { var sourceApi = this.getEventSourceById(sourceInput); // TODO: use an internal function if (!sourceApi) { console.warn('Could not find an event source with ID "' + sourceInput + '"'); // TODO: test return null; } else { sourceId = sourceApi.internalEventSource.sourceId; } } var tuple = parseEvent(eventInput, sourceId, this); if (tuple) { this.dispatch({ type: 'ADD_EVENTS', eventStore: eventTupleToStore(tuple) }); return new EventApi(this, tuple.def, tuple.def.recurringDef ? null : tuple.instance); } return null; }; // TODO: optimize Calendar.prototype.getEventById = function (id) { var _a = this.state.eventStore, defs = _a.defs, instances = _a.instances; id = String(id); for (var defId in defs) { var def = defs[defId]; if (def.publicId === id) { if (def.recurringDef) { return new EventApi(this, def, null); } else { for (var instanceId in instances) { var instance = instances[instanceId]; if (instance.defId === def.defId) { return new EventApi(this, def, instance); } } } } } return null; }; Calendar.prototype.getEvents = function () { var _a = this.state.eventStore, defs = _a.defs, instances = _a.instances; var eventApis = []; for (var id in instances) { var instance = instances[id]; var def = defs[instance.defId]; eventApis.push(new EventApi(this, def, instance)); } return eventApis; }; Calendar.prototype.removeAllEvents = function () { this.dispatch({ type: 'REMOVE_ALL_EVENTS' }); }; Calendar.prototype.rerenderEvents = function () { this.dispatch({ type: 'RESET_EVENTS' }); }; // Public Event Sources API // ----------------------------------------------------------------------------------------------------------------- Calendar.prototype.getEventSources = function () { var sourceHash = this.state.eventSources; var sourceApis = []; for (var internalId in sourceHash) { sourceApis.push(new EventSourceApi(this, sourceHash[internalId])); } return sourceApis; }; Calendar.prototype.getEventSourceById = function (id) { var sourceHash = this.state.eventSources; id = String(id); for (var sourceId in sourceHash) { if (sourceHash[sourceId].publicId === id) { return new EventSourceApi(this, sourceHash[sourceId]); } } return null; }; Calendar.prototype.addEventSource = function (sourceInput) { if (sourceInput instanceof EventSourceApi) { // not already present? don't want to add an old snapshot if (!this.state.eventSources[sourceInput.internalEventSource.sourceId]) { this.dispatch({ type: 'ADD_EVENT_SOURCES', sources: [sourceInput.internalEventSource] }); } return sourceInput; } var eventSource = parseEventSource(sourceInput, this); if (eventSource) { // TODO: error otherwise? this.dispatch({ type: 'ADD_EVENT_SOURCES', sources: [eventSource] }); return new EventSourceApi(this, eventSource); } return null; }; Calendar.prototype.removeAllEventSources = function () { this.dispatch({ type: 'REMOVE_ALL_EVENT_SOURCES' }); }; Calendar.prototype.refetchEvents = function () { this.dispatch({ type: 'FETCH_EVENT_SOURCES' }); }; // Scroll // ----------------------------------------------------------------------------------------------------------------- Calendar.prototype.scrollToTime = function (timeInput) { var duration = createDuration(timeInput); if (duration) { this.component.view.scrollToDuration(duration); } }; return Calendar; }()); EmitterMixin.mixInto(Calendar); // for memoizers // ----------------------------------------------------------------------------------------------------------------- function buildComponentContext$1(theme, dateEnv, options) { return new ComponentContext(this, theme, dateEnv, options, null); } function buildDateEnv(locale, timeZone, namedTimeZoneImpl, firstDay, weekNumberCalculation, weekLabel, cmdFormatter) { return new DateEnv({ calendarSystem: 'gregory', timeZone: timeZone, namedTimeZoneImpl: namedTimeZoneImpl, locale: locale, weekNumberCalculation: weekNumberCalculation, firstDay: firstDay, weekLabel: weekLabel, cmdFormatter: cmdFormatter }); } function buildTheme(calendarOptions) { var themeClass = this.pluginSystem.hooks.themeClasses[calendarOptions.themeSystem] || StandardTheme; return new themeClass(calendarOptions); } function buildDelayedRerender(wait) { var func = this.tryRerender.bind(this); if (wait != null) { func = debounce(func, wait); } return func; } function buildEventUiBySource(eventSources) { return mapHash(eventSources, function (eventSource) { return eventSource.ui; }); } function buildEventUiBases(eventDefs, eventUiSingleBase, eventUiBySource) { var eventUiBases = { '': eventUiSingleBase }; for (var defId in eventDefs) { var def = eventDefs[defId]; if (def.sourceId && eventUiBySource[def.sourceId]) { eventUiBases[defId] = eventUiBySource[def.sourceId]; } } return eventUiBases; } var View = /** @class */ (function (_super) { __extends(View, _super); function View(viewSpec, parentEl) { var _this = _super.call(this, createElement('div', { className: 'fc-view fc-' + viewSpec.type + '-view' })) || this; _this.renderDatesMem = memoizeRendering(_this.renderDatesWrap, _this.unrenderDatesWrap); _this.renderBusinessHoursMem = memoizeRendering(_this.renderBusinessHours, _this.unrenderBusinessHours, [_this.renderDatesMem]); _this.renderDateSelectionMem = memoizeRendering(_this.renderDateSelectionWrap, _this.unrenderDateSelectionWrap, [_this.renderDatesMem]); _this.renderEventsMem = memoizeRendering(_this.renderEvents, _this.unrenderEvents, [_this.renderDatesMem]); _this.renderEventSelectionMem = memoizeRendering(_this.renderEventSelectionWrap, _this.unrenderEventSelectionWrap, [_this.renderEventsMem]); _this.renderEventDragMem = memoizeRendering(_this.renderEventDragWrap, _this.unrenderEventDragWrap, [_this.renderDatesMem]); _this.renderEventResizeMem = memoizeRendering(_this.renderEventResizeWrap, _this.unrenderEventResizeWrap, [_this.renderDatesMem]); _this.viewSpec = viewSpec; _this.type = viewSpec.type; parentEl.appendChild(_this.el); _this.initialize(); return _this; } View.prototype.initialize = function () { }; Object.defineProperty(View.prototype, "activeStart", { // Date Setting/Unsetting // ----------------------------------------------------------------------------------------------------------------- get: function () { return this.context.dateEnv.toDate(this.props.dateProfile.activeRange.start); }, enumerable: true, configurable: true }); Object.defineProperty(View.prototype, "activeEnd", { get: function () { return this.context.dateEnv.toDate(this.props.dateProfile.activeRange.end); }, enumerable: true, configurable: true }); Object.defineProperty(View.prototype, "currentStart", { get: function () { return this.context.dateEnv.toDate(this.props.dateProfile.currentRange.start); }, enumerable: true, configurable: true }); Object.defineProperty(View.prototype, "currentEnd", { get: function () { return this.context.dateEnv.toDate(this.props.dateProfile.currentRange.end); }, enumerable: true, configurable: true }); // General Rendering // ----------------------------------------------------------------------------------------------------------------- View.prototype.render = function (props, context) { this.renderDatesMem(props.dateProfile); this.renderBusinessHoursMem(props.businessHours); this.renderDateSelectionMem(props.dateSelection); this.renderEventsMem(props.eventStore); this.renderEventSelectionMem(props.eventSelection); this.renderEventDragMem(props.eventDrag); this.renderEventResizeMem(props.eventResize); }; View.prototype.beforeUpdate = function () { this.addScroll(this.queryScroll()); }; View.prototype.destroy = function () { _super.prototype.destroy.call(this); this.renderDatesMem.unrender(); // should unrender everything else }; // Sizing // ----------------------------------------------------------------------------------------------------------------- View.prototype.updateSize = function (isResize, viewHeight, isAuto) { var calendar = this.context.calendar; if (isResize) { this.addScroll(this.queryScroll()); // NOTE: same code as in beforeUpdate } if (isResize || // HACKS... calendar.isViewUpdated || calendar.isDatesUpdated || calendar.isEventsUpdated) { // sort of the catch-all sizing // anything that might cause dimension changes this.updateBaseSize(isResize, viewHeight, isAuto); } // NOTE: popScroll is called by CalendarComponent }; View.prototype.updateBaseSize = function (isResize, viewHeight, isAuto) { }; // Date Rendering // ----------------------------------------------------------------------------------------------------------------- View.prototype.renderDatesWrap = function (dateProfile) { this.renderDates(dateProfile); this.addScroll({ duration: createDuration(this.context.options.scrollTime) }); }; View.prototype.unrenderDatesWrap = function () { this.stopNowIndicator(); this.unrenderDates(); }; View.prototype.renderDates = function (dateProfile) { }; View.prototype.unrenderDates = function () { }; // Business Hours // ----------------------------------------------------------------------------------------------------------------- View.prototype.renderBusinessHours = function (businessHours) { }; View.prototype.unrenderBusinessHours = function () { }; // Date Selection // ----------------------------------------------------------------------------------------------------------------- View.prototype.renderDateSelectionWrap = function (selection) { if (selection) { this.renderDateSelection(selection); } }; View.prototype.unrenderDateSelectionWrap = function (selection) { if (selection) { this.unrenderDateSelection(selection); } }; View.prototype.renderDateSelection = function (selection) { }; View.prototype.unrenderDateSelection = function (selection) { }; // Event Rendering // ----------------------------------------------------------------------------------------------------------------- View.prototype.renderEvents = function (eventStore) { }; View.prototype.unrenderEvents = function () { }; // util for subclasses View.prototype.sliceEvents = function (eventStore, allDay) { var props = this.props; return sliceEventStore(eventStore, props.eventUiBases, props.dateProfile.activeRange, allDay ? this.context.nextDayThreshold : null).fg; }; // Event Selection // ----------------------------------------------------------------------------------------------------------------- View.prototype.renderEventSelectionWrap = function (instanceId) { if (instanceId) { this.renderEventSelection(instanceId); } }; View.prototype.unrenderEventSelectionWrap = function (instanceId) { if (instanceId) { this.unrenderEventSelection(instanceId); } }; View.prototype.renderEventSelection = function (instanceId) { }; View.prototype.unrenderEventSelection = function (instanceId) { }; // Event Drag // ----------------------------------------------------------------------------------------------------------------- View.prototype.renderEventDragWrap = function (state) { if (state) { this.renderEventDrag(state); } }; View.prototype.unrenderEventDragWrap = function (state) { if (state) { this.unrenderEventDrag(state); } }; View.prototype.renderEventDrag = function (state) { }; View.prototype.unrenderEventDrag = function (state) { }; // Event Resize // ----------------------------------------------------------------------------------------------------------------- View.prototype.renderEventResizeWrap = function (state) { if (state) { this.renderEventResize(state); } }; View.prototype.unrenderEventResizeWrap = function (state) { if (state) { this.unrenderEventResize(state); } }; View.prototype.renderEventResize = function (state) { }; View.prototype.unrenderEventResize = function (state) { }; /* Now Indicator ------------------------------------------------------------------------------------------------------------------*/ // Immediately render the current time indicator and begins re-rendering it at an interval, // which is defined by this.getNowIndicatorUnit(). // TODO: somehow do this for the current whole day's background too // USAGE: must be called manually from subclasses' render methods! don't need to call stopNowIndicator tho View.prototype.startNowIndicator = function (dateProfile, dateProfileGenerator) { var _this = this; var _a = this.context, calendar = _a.calendar, dateEnv = _a.dateEnv, options = _a.options; var unit; var update; var delay; // ms wait value if (options.nowIndicator && !this.initialNowDate) { unit = this.getNowIndicatorUnit(dateProfile, dateProfileGenerator); if (unit) { update = this.updateNowIndicator.bind(this); this.initialNowDate = calendar.getNow(); this.initialNowQueriedMs = new Date().valueOf(); // wait until the beginning of the next interval delay = dateEnv.add(dateEnv.startOf(this.initialNowDate, unit), createDuration(1, unit)).valueOf() - this.initialNowDate.valueOf(); // TODO: maybe always use setTimeout, waiting until start of next unit this.nowIndicatorTimeoutID = setTimeout(function () { _this.nowIndicatorTimeoutID = null; update(); if (unit === 'second') { delay = 1000; // every second } else { delay = 1000 * 60; // otherwise, every minute } _this.nowIndicatorIntervalID = setInterval(update, delay); // update every interval }, delay); } // rendering will be initiated in updateSize } }; // rerenders the now indicator, computing the new current time from the amount of time that has passed // since the initial getNow call. View.prototype.updateNowIndicator = function () { if (this.props.dateProfile && // a way to determine if dates were rendered yet this.initialNowDate // activated before? ) { this.unrenderNowIndicator(); // won't unrender if unnecessary this.renderNowIndicator(addMs(this.initialNowDate, new Date().valueOf() - this.initialNowQueriedMs)); this.isNowIndicatorRendered = true; } }; // Immediately unrenders the view's current time indicator and stops any re-rendering timers. // Won't cause side effects if indicator isn't rendered. View.prototype.stopNowIndicator = function () { if (this.nowIndicatorTimeoutID) { clearTimeout(this.nowIndicatorTimeoutID); this.nowIndicatorTimeoutID = null; } if (this.nowIndicatorIntervalID) { clearInterval(this.nowIndicatorIntervalID); this.nowIndicatorIntervalID = null; } if (this.isNowIndicatorRendered) { this.unrenderNowIndicator(); this.isNowIndicatorRendered = false; } }; View.prototype.getNowIndicatorUnit = function (dateProfile, dateProfileGenerator) { // subclasses should implement }; // Renders a current time indicator at the given datetime View.prototype.renderNowIndicator = function (date) { // SUBCLASSES MUST PASS TO CHILDREN! }; // Undoes the rendering actions from renderNowIndicator View.prototype.unrenderNowIndicator = function () { // SUBCLASSES MUST PASS TO CHILDREN! }; /* Scroller ------------------------------------------------------------------------------------------------------------------*/ View.prototype.addScroll = function (scroll, isForced) { if (isForced) { scroll.isForced = isForced; } __assign(this.queuedScroll || (this.queuedScroll = {}), scroll); }; View.prototype.popScroll = function (isResize) { this.applyQueuedScroll(isResize); this.queuedScroll = null; }; View.prototype.applyQueuedScroll = function (isResize) { if (this.queuedScroll) { this.applyScroll(this.queuedScroll, isResize); } }; View.prototype.queryScroll = function () { var scroll = {}; if (this.props.dateProfile) { // dates rendered yet? __assign(scroll, this.queryDateScroll()); } return scroll; }; View.prototype.applyScroll = function (scroll, isResize) { var duration = scroll.duration, isForced = scroll.isForced; if (duration != null && !isForced) { delete scroll.duration; if (this.props.dateProfile) { // dates rendered yet? __assign(scroll, this.computeDateScroll(duration)); } } if (this.props.dateProfile) { // dates rendered yet? this.applyDateScroll(scroll); } }; View.prototype.computeDateScroll = function (duration) { return {}; // subclasses must implement }; View.prototype.queryDateScroll = function () { return {}; // subclasses must implement }; View.prototype.applyDateScroll = function (scroll) { // subclasses must implement }; // for API View.prototype.scrollToDuration = function (duration) { this.applyScroll({ duration: duration }, false); }; return View; }(DateComponent)); EmitterMixin.mixInto(View); View.prototype.usesMinMaxTime = false; View.prototype.dateProfileGeneratorClass = DateProfileGenerator; var FgEventRenderer = /** @class */ (function () { function FgEventRenderer() { this.segs = []; this.isSizeDirty = false; } FgEventRenderer.prototype.renderSegs = function (context, segs, mirrorInfo) { this.context = context; this.rangeUpdated(); // called too frequently :( // render an `.el` on each seg // returns a subset of the segs. segs that were actually rendered segs = this.renderSegEls(segs, mirrorInfo); this.segs = segs; this.attachSegs(segs, mirrorInfo); this.isSizeDirty = true; triggerRenderedSegs(this.context, this.segs, Boolean(mirrorInfo)); }; FgEventRenderer.prototype.unrender = function (context, _segs, mirrorInfo) { triggerWillRemoveSegs(this.context, this.segs, Boolean(mirrorInfo)); this.detachSegs(this.segs); this.segs = []; }; // Updates values that rely on options and also relate to range FgEventRenderer.prototype.rangeUpdated = function () { var options = this.context.options; var displayEventTime; var displayEventEnd; this.eventTimeFormat = createFormatter(options.eventTimeFormat || this.computeEventTimeFormat(), options.defaultRangeSeparator); displayEventTime = options.displayEventTime; if (displayEventTime == null) { displayEventTime = this.computeDisplayEventTime(); // might be based off of range } displayEventEnd = options.displayEventEnd; if (displayEventEnd == null) { displayEventEnd = this.computeDisplayEventEnd(); // might be based off of range } this.displayEventTime = displayEventTime; this.displayEventEnd = displayEventEnd; }; // Renders and assigns an `el` property for each foreground event segment. // Only returns segments that successfully rendered. FgEventRenderer.prototype.renderSegEls = function (segs, mirrorInfo) { var html = ''; var i; if (segs.length) { // don't build an empty html string // build a large concatenation of event segment HTML for (i = 0; i < segs.length; i++) { html += this.renderSegHtml(segs[i], mirrorInfo); } // Grab individual elements from the combined HTML string. Use each as the default rendering. // Then, compute the 'el' for each segment. An el might be null if the eventRender callback returned false. htmlToElements(html).forEach(function (el, i) { var seg = segs[i]; if (el) { seg.el = el; } }); segs = filterSegsViaEls(this.context, segs, Boolean(mirrorInfo)); } return segs; }; // Generic utility for generating the HTML classNames for an event segment's element FgEventRenderer.prototype.getSegClasses = function (seg, isDraggable, isResizable, mirrorInfo) { var classes = [ 'fc-event', seg.isStart ? 'fc-start' : 'fc-not-start', seg.isEnd ? 'fc-end' : 'fc-not-end' ].concat(seg.eventRange.ui.classNames); if (isDraggable) { classes.push('fc-draggable'); } if (isResizable) { classes.push('fc-resizable'); } if (mirrorInfo) { classes.push('fc-mirror'); if (mirrorInfo.isDragging) { classes.push('fc-dragging'); } if (mirrorInfo.isResizing) { classes.push('fc-resizing'); } } return classes; }; // Compute the text that should be displayed on an event's element. // `range` can be the Event object itself, or something range-like, with at least a `start`. // If event times are disabled, or the event has no time, will return a blank string. // If not specified, formatter will default to the eventTimeFormat setting, // and displayEnd will default to the displayEventEnd setting. FgEventRenderer.prototype.getTimeText = function (eventRange, formatter, displayEnd) { var def = eventRange.def, instance = eventRange.instance; return this._getTimeText(instance.range.start, def.hasEnd ? instance.range.end : null, def.allDay, formatter, displayEnd, instance.forcedStartTzo, instance.forcedEndTzo); }; FgEventRenderer.prototype._getTimeText = function (start, end, allDay, formatter, displayEnd, forcedStartTzo, forcedEndTzo) { var dateEnv = this.context.dateEnv; if (formatter == null) { formatter = this.eventTimeFormat; } if (displayEnd == null) { displayEnd = this.displayEventEnd; } if (this.displayEventTime && !allDay) { if (displayEnd && end) { return dateEnv.formatRange(start, end, formatter, { forcedStartTzo: forcedStartTzo, forcedEndTzo: forcedEndTzo }); } else { return dateEnv.format(start, formatter, { forcedTzo: forcedStartTzo }); } } return ''; }; FgEventRenderer.prototype.computeEventTimeFormat = function () { return { hour: 'numeric', minute: '2-digit', omitZeroMinute: true }; }; FgEventRenderer.prototype.computeDisplayEventTime = function () { return true; }; FgEventRenderer.prototype.computeDisplayEventEnd = function () { return true; }; // Utility for generating event skin-related CSS properties FgEventRenderer.prototype.getSkinCss = function (ui) { return { 'background-color': ui.backgroundColor, 'border-color': ui.borderColor, color: ui.textColor }; }; FgEventRenderer.prototype.sortEventSegs = function (segs) { var specs = this.context.eventOrderSpecs; var objs = segs.map(buildSegCompareObj); objs.sort(function (obj0, obj1) { return compareByFieldSpecs(obj0, obj1, specs); }); return objs.map(function (c) { return c._seg; }); }; FgEventRenderer.prototype.computeSizes = function (force) { if (force || this.isSizeDirty) { this.computeSegSizes(this.segs); } }; FgEventRenderer.prototype.assignSizes = function (force) { if (force || this.isSizeDirty) { this.assignSegSizes(this.segs); this.isSizeDirty = false; } }; FgEventRenderer.prototype.computeSegSizes = function (segs) { }; FgEventRenderer.prototype.assignSegSizes = function (segs) { }; // Manipulation on rendered segs FgEventRenderer.prototype.hideByHash = function (hash) { if (hash) { for (var _i = 0, _a = this.segs; _i < _a.length; _i++) { var seg = _a[_i]; if (hash[seg.eventRange.instance.instanceId]) { seg.el.style.visibility = 'hidden'; } } } }; FgEventRenderer.prototype.showByHash = function (hash) { if (hash) { for (var _i = 0, _a = this.segs; _i < _a.length; _i++) { var seg = _a[_i]; if (hash[seg.eventRange.instance.instanceId]) { seg.el.style.visibility = ''; } } } }; FgEventRenderer.prototype.selectByInstanceId = function (instanceId) { if (instanceId) { for (var _i = 0, _a = this.segs; _i < _a.length; _i++) { var seg = _a[_i]; var eventInstance = seg.eventRange.instance; if (eventInstance && eventInstance.instanceId === instanceId && seg.el // necessary? ) { seg.el.classList.add('fc-selected'); } } } }; FgEventRenderer.prototype.unselectByInstanceId = function (instanceId) { if (instanceId) { for (var _i = 0, _a = this.segs; _i < _a.length; _i++) { var seg = _a[_i]; if (seg.el) { // necessary? seg.el.classList.remove('fc-selected'); } } } }; return FgEventRenderer; }()); // returns a object with all primitive props that can be compared function buildSegCompareObj(seg) { var eventDef = seg.eventRange.def; var range = seg.eventRange.instance.range; var start = range.start ? range.start.valueOf() : 0; // TODO: better support for open-range events var end = range.end ? range.end.valueOf() : 0; // " return __assign({}, eventDef.extendedProps, eventDef, { id: eventDef.publicId, start: start, end: end, duration: end - start, allDay: Number(eventDef.allDay), _seg: seg // for later retrieval }); } /* TODO: when refactoring this class, make a new FillRenderer instance for each `type` */ var FillRenderer = /** @class */ (function () { function FillRenderer() { this.fillSegTag = 'div'; this.dirtySizeFlags = {}; this.containerElsByType = {}; this.segsByType = {}; } FillRenderer.prototype.getSegsByType = function (type) { return this.segsByType[type] || []; }; FillRenderer.prototype.renderSegs = function (type, context, segs) { var _a; this.context = context; var renderedSegs = this.renderSegEls(type, segs); // assignes `.el` to each seg. returns successfully rendered segs var containerEls = this.attachSegs(type, renderedSegs); if (containerEls) { (_a = (this.containerElsByType[type] || (this.containerElsByType[type] = []))).push.apply(_a, containerEls); } this.segsByType[type] = renderedSegs; if (type === 'bgEvent') { triggerRenderedSegs(context, renderedSegs, false); // isMirror=false } this.dirtySizeFlags[type] = true; }; // Unrenders a specific type of fill that is currently rendered on the grid FillRenderer.prototype.unrender = function (type, context) { var segs = this.segsByType[type]; if (segs) { if (type === 'bgEvent') { triggerWillRemoveSegs(context, segs, false); // isMirror=false } this.detachSegs(type, segs); } }; // Renders and assigns an `el` property for each fill segment. Generic enough to work with different types. // Only returns segments that successfully rendered. FillRenderer.prototype.renderSegEls = function (type, segs) { var _this = this; var html = ''; var i; if (segs.length) { // build a large concatenation of segment HTML for (i = 0; i < segs.length; i++) { html += this.renderSegHtml(type, segs[i]); } // Grab individual elements from the combined HTML string. Use each as the default rendering. // Then, compute the 'el' for each segment. htmlToElements(html).forEach(function (el, i) { var seg = segs[i]; if (el) { seg.el = el; } }); if (type === 'bgEvent') { segs = filterSegsViaEls(this.context, segs, false // isMirror. background events can never be mirror elements ); } // correct element type? (would be bad if a non-TD were inserted into a table for example) segs = segs.filter(function (seg) { return elementMatches(seg.el, _this.fillSegTag); }); } return segs; }; // Builds the HTML needed for one fill segment. Generic enough to work with different types. FillRenderer.prototype.renderSegHtml = function (type, seg) { var css = null; var classNames = []; if (type !== 'highlight' && type !== 'businessHours') { css = { 'background-color': seg.eventRange.ui.backgroundColor }; } if (type !== 'highlight') { classNames = classNames.concat(seg.eventRange.ui.classNames); } if (type === 'businessHours') { classNames.push('fc-bgevent'); } else { classNames.push('fc-' + type.toLowerCase()); } return '<' + this.fillSegTag + (classNames.length ? ' class="' + classNames.join(' ') + '"' : '') + (css ? ' style="' + cssToStr(css) + '"' : '') + '>'; }; FillRenderer.prototype.detachSegs = function (type, segs) { var containerEls = this.containerElsByType[type]; if (containerEls) { containerEls.forEach(removeElement); delete this.containerElsByType[type]; } }; FillRenderer.prototype.computeSizes = function (force) { for (var type in this.segsByType) { if (force || this.dirtySizeFlags[type]) { this.computeSegSizes(this.segsByType[type]); } } }; FillRenderer.prototype.assignSizes = function (force) { for (var type in this.segsByType) { if (force || this.dirtySizeFlags[type]) { this.assignSegSizes(this.segsByType[type]); } } this.dirtySizeFlags = {}; }; FillRenderer.prototype.computeSegSizes = function (segs) { }; FillRenderer.prototype.assignSegSizes = function (segs) { }; return FillRenderer; }()); var NamedTimeZoneImpl = /** @class */ (function () { function NamedTimeZoneImpl(timeZoneName) { this.timeZoneName = timeZoneName; } return NamedTimeZoneImpl; }()); /* An abstraction for a dragging interaction originating on an event. Does higher-level things than PointerDragger, such as possibly: - a "mirror" that moves with the pointer - a minimum number of pixels or other criteria for a true drag to begin subclasses must emit: - pointerdown - dragstart - dragmove - pointerup - dragend */ var ElementDragging = /** @class */ (function () { function ElementDragging(el) { this.emitter = new EmitterMixin(); } ElementDragging.prototype.destroy = function () { }; ElementDragging.prototype.setMirrorIsVisible = function (bool) { // optional if subclass doesn't want to support a mirror }; ElementDragging.prototype.setMirrorNeedsRevert = function (bool) { // optional if subclass doesn't want to support a mirror }; ElementDragging.prototype.setAutoScrollEnabled = function (bool) { // optional }; return ElementDragging; }()); function formatDate(dateInput, settings) { if (settings === void 0) { settings = {}; } var dateEnv = buildDateEnv$1(settings); var formatter = createFormatter(settings); var dateMeta = dateEnv.createMarkerMeta(dateInput); if (!dateMeta) { // TODO: warning? return ''; } return dateEnv.format(dateMeta.marker, formatter, { forcedTzo: dateMeta.forcedTzo }); } function formatRange(startInput, endInput, settings // mixture of env and formatter settings ) { var dateEnv = buildDateEnv$1(typeof settings === 'object' && settings ? settings : {}); // pass in if non-null object var formatter = createFormatter(settings, globalDefaults.defaultRangeSeparator); var startMeta = dateEnv.createMarkerMeta(startInput); var endMeta = dateEnv.createMarkerMeta(endInput); if (!startMeta || !endMeta) { // TODO: warning? return ''; } return dateEnv.formatRange(startMeta.marker, endMeta.marker, formatter, { forcedStartTzo: startMeta.forcedTzo, forcedEndTzo: endMeta.forcedTzo, isEndExclusive: settings.isEndExclusive }); } // TODO: more DRY and optimized function buildDateEnv$1(settings) { var locale = buildLocale(settings.locale || 'en', parseRawLocales([]).map); // TODO: don't hardcode 'en' everywhere // ensure required settings settings = __assign({ timeZone: globalDefaults.timeZone, calendarSystem: 'gregory' }, settings, { locale: locale }); return new DateEnv(settings); } var DRAG_META_PROPS = { startTime: createDuration, duration: createDuration, create: Boolean, sourceId: String }; var DRAG_META_DEFAULTS = { create: true }; function parseDragMeta(raw) { var leftoverProps = {}; var refined = refineProps(raw, DRAG_META_PROPS, DRAG_META_DEFAULTS, leftoverProps); refined.leftoverProps = leftoverProps; return refined; } // Computes a default column header formatting string if `colFormat` is not explicitly defined function computeFallbackHeaderFormat(datesRepDistinctDays, dayCnt) { // if more than one week row, or if there are a lot of columns with not much space, // put just the day numbers will be in each cell if (!datesRepDistinctDays || dayCnt > 10) { return { weekday: 'short' }; // "Sat" } else if (dayCnt > 1) { return { weekday: 'short', month: 'numeric', day: 'numeric', omitCommas: true }; // "Sat 11/12" } else { return { weekday: 'long' }; // "Saturday" } } function renderDateCell(dateMarker, dateProfile, datesRepDistinctDays, colCnt, colHeadFormat, context, colspan, otherAttrs) { var dateEnv = context.dateEnv, theme = context.theme, options = context.options; var isDateValid = rangeContainsMarker(dateProfile.activeRange, dateMarker); // TODO: called too frequently. cache somehow. var classNames = [ 'fc-day-header', theme.getClass('widgetHeader') ]; var innerHtml; if (typeof options.columnHeaderHtml === 'function') { innerHtml = options.columnHeaderHtml(dateEnv.toDate(dateMarker)); } else if (typeof options.columnHeaderText === 'function') { innerHtml = htmlEscape(options.columnHeaderText(dateEnv.toDate(dateMarker))); } else { innerHtml = htmlEscape(dateEnv.format(dateMarker, colHeadFormat)); } // if only one row of days, the classNames on the header can represent the specific days beneath if (datesRepDistinctDays) { classNames = classNames.concat( // includes the day-of-week class // noThemeHighlight=true (don't highlight the header) getDayClasses(dateMarker, dateProfile, context, true)); } else { classNames.push('fc-' + DAY_IDS[dateMarker.getUTCDay()]); // only add the day-of-week class } return '' + ' 1 ? ' colspan="' + colspan + '"' : '') + (otherAttrs ? ' ' + otherAttrs : '') + '>' + (isDateValid ? // don't make a link if the heading could represent multiple days, or if there's only one day (forceOff) buildGotoAnchorHtml(options, dateEnv, { date: dateMarker, forceOff: !datesRepDistinctDays || colCnt === 1 }, innerHtml) : // if not valid, display text, but no link innerHtml) + ''; } var DayHeader = /** @class */ (function (_super) { __extends(DayHeader, _super); function DayHeader(parentEl) { var _this = _super.call(this) || this; _this.renderSkeleton = memoizeRendering(_this._renderSkeleton, _this._unrenderSkeleton); _this.parentEl = parentEl; return _this; } DayHeader.prototype.render = function (props, context) { var dates = props.dates, datesRepDistinctDays = props.datesRepDistinctDays; var parts = []; this.renderSkeleton(context); if (props.renderIntroHtml) { parts.push(props.renderIntroHtml()); } var colHeadFormat = createFormatter(context.options.columnHeaderFormat || computeFallbackHeaderFormat(datesRepDistinctDays, dates.length)); for (var _i = 0, dates_1 = dates; _i < dates_1.length; _i++) { var date = dates_1[_i]; parts.push(renderDateCell(date, props.dateProfile, datesRepDistinctDays, dates.length, colHeadFormat, context)); } if (context.isRtl) { parts.reverse(); } this.thead.innerHTML = '' + parts.join('') + ''; }; DayHeader.prototype.destroy = function () { _super.prototype.destroy.call(this); this.renderSkeleton.unrender(); }; DayHeader.prototype._renderSkeleton = function (context) { var theme = context.theme; var parentEl = this.parentEl; parentEl.innerHTML = ''; // because might be nbsp parentEl.appendChild(this.el = htmlToElement('
' + '' + '' + '
' + '
')); this.thead = this.el.querySelector('thead'); }; DayHeader.prototype._unrenderSkeleton = function () { removeElement(this.el); }; return DayHeader; }(Component)); var DaySeries = /** @class */ (function () { function DaySeries(range, dateProfileGenerator) { var date = range.start; var end = range.end; var indices = []; var dates = []; var dayIndex = -1; while (date < end) { // loop each day from start to end if (dateProfileGenerator.isHiddenDay(date)) { indices.push(dayIndex + 0.5); // mark that it's between indices } else { dayIndex++; indices.push(dayIndex); dates.push(date); } date = addDays(date, 1); } this.dates = dates; this.indices = indices; this.cnt = dates.length; } DaySeries.prototype.sliceRange = function (range) { var firstIndex = this.getDateDayIndex(range.start); // inclusive first index var lastIndex = this.getDateDayIndex(addDays(range.end, -1)); // inclusive last index var clippedFirstIndex = Math.max(0, firstIndex); var clippedLastIndex = Math.min(this.cnt - 1, lastIndex); // deal with in-between indices clippedFirstIndex = Math.ceil(clippedFirstIndex); // in-between starts round to next cell clippedLastIndex = Math.floor(clippedLastIndex); // in-between ends round to prev cell if (clippedFirstIndex <= clippedLastIndex) { return { firstIndex: clippedFirstIndex, lastIndex: clippedLastIndex, isStart: firstIndex === clippedFirstIndex, isEnd: lastIndex === clippedLastIndex }; } else { return null; } }; // Given a date, returns its chronolocial cell-index from the first cell of the grid. // If the date lies between cells (because of hiddenDays), returns a floating-point value between offsets. // If before the first offset, returns a negative number. // If after the last offset, returns an offset past the last cell offset. // Only works for *start* dates of cells. Will not work for exclusive end dates for cells. DaySeries.prototype.getDateDayIndex = function (date) { var indices = this.indices; var dayOffset = Math.floor(diffDays(this.dates[0], date)); if (dayOffset < 0) { return indices[0] - 1; } else if (dayOffset >= indices.length) { return indices[indices.length - 1] + 1; } else { return indices[dayOffset]; } }; return DaySeries; }()); var DayTable = /** @class */ (function () { function DayTable(daySeries, breakOnWeeks) { var dates = daySeries.dates; var daysPerRow; var firstDay; var rowCnt; if (breakOnWeeks) { // count columns until the day-of-week repeats firstDay = dates[0].getUTCDay(); for (daysPerRow = 1; daysPerRow < dates.length; daysPerRow++) { if (dates[daysPerRow].getUTCDay() === firstDay) { break; } } rowCnt = Math.ceil(dates.length / daysPerRow); } else { rowCnt = 1; daysPerRow = dates.length; } this.rowCnt = rowCnt; this.colCnt = daysPerRow; this.daySeries = daySeries; this.cells = this.buildCells(); this.headerDates = this.buildHeaderDates(); } DayTable.prototype.buildCells = function () { var rows = []; for (var row = 0; row < this.rowCnt; row++) { var cells = []; for (var col = 0; col < this.colCnt; col++) { cells.push(this.buildCell(row, col)); } rows.push(cells); } return rows; }; DayTable.prototype.buildCell = function (row, col) { return { date: this.daySeries.dates[row * this.colCnt + col] }; }; DayTable.prototype.buildHeaderDates = function () { var dates = []; for (var col = 0; col < this.colCnt; col++) { dates.push(this.cells[0][col].date); } return dates; }; DayTable.prototype.sliceRange = function (range) { var colCnt = this.colCnt; var seriesSeg = this.daySeries.sliceRange(range); var segs = []; if (seriesSeg) { var firstIndex = seriesSeg.firstIndex, lastIndex = seriesSeg.lastIndex; var index = firstIndex; while (index <= lastIndex) { var row = Math.floor(index / colCnt); var nextIndex = Math.min((row + 1) * colCnt, lastIndex + 1); segs.push({ row: row, firstCol: index % colCnt, lastCol: (nextIndex - 1) % colCnt, isStart: seriesSeg.isStart && index === firstIndex, isEnd: seriesSeg.isEnd && (nextIndex - 1) === lastIndex }); index = nextIndex; } } return segs; }; return DayTable; }()); var Slicer = /** @class */ (function () { function Slicer() { this.sliceBusinessHours = memoize(this._sliceBusinessHours); this.sliceDateSelection = memoize(this._sliceDateSpan); this.sliceEventStore = memoize(this._sliceEventStore); this.sliceEventDrag = memoize(this._sliceInteraction); this.sliceEventResize = memoize(this._sliceInteraction); } Slicer.prototype.sliceProps = function (props, dateProfile, nextDayThreshold, calendar, component) { var extraArgs = []; for (var _i = 5; _i < arguments.length; _i++) { extraArgs[_i - 5] = arguments[_i]; } var eventUiBases = props.eventUiBases; var eventSegs = this.sliceEventStore.apply(this, [props.eventStore, eventUiBases, dateProfile, nextDayThreshold, component].concat(extraArgs)); return { dateSelectionSegs: this.sliceDateSelection.apply(this, [props.dateSelection, eventUiBases, component].concat(extraArgs)), businessHourSegs: this.sliceBusinessHours.apply(this, [props.businessHours, dateProfile, nextDayThreshold, calendar, component].concat(extraArgs)), fgEventSegs: eventSegs.fg, bgEventSegs: eventSegs.bg, eventDrag: this.sliceEventDrag.apply(this, [props.eventDrag, eventUiBases, dateProfile, nextDayThreshold, component].concat(extraArgs)), eventResize: this.sliceEventResize.apply(this, [props.eventResize, eventUiBases, dateProfile, nextDayThreshold, component].concat(extraArgs)), eventSelection: props.eventSelection }; // TODO: give interactionSegs? }; Slicer.prototype.sliceNowDate = function (// does not memoize date, component) { var extraArgs = []; for (var _i = 2; _i < arguments.length; _i++) { extraArgs[_i - 2] = arguments[_i]; } return this._sliceDateSpan.apply(this, [{ range: { start: date, end: addMs(date, 1) }, allDay: false }, {}, component].concat(extraArgs)); }; Slicer.prototype._sliceBusinessHours = function (businessHours, dateProfile, nextDayThreshold, calendar, component) { var extraArgs = []; for (var _i = 5; _i < arguments.length; _i++) { extraArgs[_i - 5] = arguments[_i]; } if (!businessHours) { return []; } return this._sliceEventStore.apply(this, [expandRecurring(businessHours, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), calendar), {}, dateProfile, nextDayThreshold, component].concat(extraArgs)).bg; }; Slicer.prototype._sliceEventStore = function (eventStore, eventUiBases, dateProfile, nextDayThreshold, component) { var extraArgs = []; for (var _i = 5; _i < arguments.length; _i++) { extraArgs[_i - 5] = arguments[_i]; } if (eventStore) { var rangeRes = sliceEventStore(eventStore, eventUiBases, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), nextDayThreshold); return { bg: this.sliceEventRanges(rangeRes.bg, component, extraArgs), fg: this.sliceEventRanges(rangeRes.fg, component, extraArgs) }; } else { return { bg: [], fg: [] }; } }; Slicer.prototype._sliceInteraction = function (interaction, eventUiBases, dateProfile, nextDayThreshold, component) { var extraArgs = []; for (var _i = 5; _i < arguments.length; _i++) { extraArgs[_i - 5] = arguments[_i]; } if (!interaction) { return null; } var rangeRes = sliceEventStore(interaction.mutatedEvents, eventUiBases, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), nextDayThreshold); return { segs: this.sliceEventRanges(rangeRes.fg, component, extraArgs), affectedInstances: interaction.affectedEvents.instances, isEvent: interaction.isEvent, sourceSeg: interaction.origSeg }; }; Slicer.prototype._sliceDateSpan = function (dateSpan, eventUiBases, component) { var extraArgs = []; for (var _i = 3; _i < arguments.length; _i++) { extraArgs[_i - 3] = arguments[_i]; } if (!dateSpan) { return []; } var eventRange = fabricateEventRange(dateSpan, eventUiBases, component.context.calendar); var segs = this.sliceRange.apply(this, [dateSpan.range].concat(extraArgs)); for (var _a = 0, segs_1 = segs; _a < segs_1.length; _a++) { var seg = segs_1[_a]; seg.component = component; seg.eventRange = eventRange; } return segs; }; /* "complete" seg means it has component and eventRange */ Slicer.prototype.sliceEventRanges = function (eventRanges, component, // TODO: kill extraArgs) { var segs = []; for (var _i = 0, eventRanges_1 = eventRanges; _i < eventRanges_1.length; _i++) { var eventRange = eventRanges_1[_i]; segs.push.apply(segs, this.sliceEventRange(eventRange, component, extraArgs)); } return segs; }; /* "complete" seg means it has component and eventRange */ Slicer.prototype.sliceEventRange = function (eventRange, component, // TODO: kill extraArgs) { var segs = this.sliceRange.apply(this, [eventRange.range].concat(extraArgs)); for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) { var seg = segs_2[_i]; seg.component = component; seg.eventRange = eventRange; seg.isStart = eventRange.isStart && seg.isStart; seg.isEnd = eventRange.isEnd && seg.isEnd; } return segs; }; return Slicer; }()); /* for incorporating minTime/maxTime if appropriate TODO: should be part of DateProfile! TimelineDateProfile already does this btw */ function computeActiveRange(dateProfile, isComponentAllDay) { var range = dateProfile.activeRange; if (isComponentAllDay) { return range; } return { start: addMs(range.start, dateProfile.minTime.milliseconds), end: addMs(range.end, dateProfile.maxTime.milliseconds - 864e5) // 864e5 = ms in a day }; } // exports // -------------------------------------------------------------------------------------------------- var version = '4.4.0'; /***/ }), /***/ "./node_modules/@fullcalendar/daygrid/main.css": /*!*****************************************************!*\ !*** ./node_modules/@fullcalendar/daygrid/main.css ***! \*****************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { // extracted by mini-css-extract-plugin /***/ }), /***/ "./node_modules/@fullcalendar/daygrid/main.esm.js": /*!********************************************************!*\ !*** ./node_modules/@fullcalendar/daygrid/main.esm.js ***! \********************************************************/ /*! exports provided: default, AbstractDayGridView, DayBgRow, DayGrid, DayGridSlicer, DayGridView, SimpleDayGrid, buildBasicDayTable */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AbstractDayGridView", function() { return AbstractDayGridView; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DayBgRow", function() { return DayBgRow; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DayGrid", function() { return DayGrid; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DayGridSlicer", function() { return DayGridSlicer; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DayGridView", function() { return DayGridView; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SimpleDayGrid", function() { return SimpleDayGrid; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildBasicDayTable", function() { return buildDayTable; }); /* harmony import */ var _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @fullcalendar/core */ "./node_modules/@fullcalendar/core/main.esm.js"); /*! FullCalendar Day Grid Plugin v4.4.0 Docs & License: https://fullcalendar.io/ (c) 2019 Adam Shaw */ /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var DayGridDateProfileGenerator = /** @class */ (function (_super) { __extends(DayGridDateProfileGenerator, _super); function DayGridDateProfileGenerator() { return _super !== null && _super.apply(this, arguments) || this; } // Computes the date range that will be rendered. DayGridDateProfileGenerator.prototype.buildRenderRange = function (currentRange, currentRangeUnit, isRangeAllDay) { var dateEnv = this.dateEnv; var renderRange = _super.prototype.buildRenderRange.call(this, currentRange, currentRangeUnit, isRangeAllDay); var start = renderRange.start; var end = renderRange.end; var endOfWeek; // year and month views should be aligned with weeks. this is already done for week if (/^(year|month)$/.test(currentRangeUnit)) { start = dateEnv.startOfWeek(start); // make end-of-week if not already endOfWeek = dateEnv.startOfWeek(end); if (endOfWeek.valueOf() !== end.valueOf()) { end = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["addWeeks"])(endOfWeek, 1); } } // ensure 6 weeks if (this.options.monthMode && this.options.fixedWeekCount) { var rowCnt = Math.ceil(// could be partial weeks due to hiddenDays Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["diffWeeks"])(start, end)); end = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["addWeeks"])(end, 6 - rowCnt); } return { start: start, end: end }; }; return DayGridDateProfileGenerator; }(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["DateProfileGenerator"])); /* A rectangular panel that is absolutely positioned over other content ------------------------------------------------------------------------------------------------------------------------ Options: - className (string) - content (HTML string, element, or element array) - parentEl - top - left - right (the x coord of where the right edge should be. not a "CSS" right) - autoHide (boolean) - show (callback) - hide (callback) */ var Popover = /** @class */ (function () { function Popover(options) { var _this = this; this.isHidden = true; this.margin = 10; // the space required between the popover and the edges of the scroll container // Triggered when the user clicks *anywhere* in the document, for the autoHide feature this.documentMousedown = function (ev) { // only hide the popover if the click happened outside the popover if (_this.el && !_this.el.contains(ev.target)) { _this.hide(); } }; this.options = options; } // Shows the popover on the specified position. Renders it if not already Popover.prototype.show = function () { if (this.isHidden) { if (!this.el) { this.render(); } this.el.style.display = ''; this.position(); this.isHidden = false; this.trigger('show'); } }; // Hides the popover, through CSS, but does not remove it from the DOM Popover.prototype.hide = function () { if (!this.isHidden) { this.el.style.display = 'none'; this.isHidden = true; this.trigger('hide'); } }; // Creates `this.el` and renders content inside of it Popover.prototype.render = function () { var _this = this; var options = this.options; var el = this.el = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createElement"])('div', { className: 'fc-popover ' + (options.className || ''), style: { top: '0', left: '0' } }); if (typeof options.content === 'function') { options.content(el); } options.parentEl.appendChild(el); // when a click happens on anything inside with a 'fc-close' className, hide the popover Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["listenBySelector"])(el, 'click', '.fc-close', function (ev) { _this.hide(); }); if (options.autoHide) { document.addEventListener('mousedown', this.documentMousedown); } }; // Hides and unregisters any handlers Popover.prototype.destroy = function () { this.hide(); if (this.el) { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["removeElement"])(this.el); this.el = null; } document.removeEventListener('mousedown', this.documentMousedown); }; // Positions the popover optimally, using the top/left/right options Popover.prototype.position = function () { var options = this.options; var el = this.el; var elDims = el.getBoundingClientRect(); // only used for width,height var origin = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["computeRect"])(el.offsetParent); var clippingRect = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["computeClippingRect"])(options.parentEl); var top; // the "position" (not "offset") values for the popover var left; // // compute top and left top = options.top || 0; if (options.left !== undefined) { left = options.left; } else if (options.right !== undefined) { left = options.right - elDims.width; // derive the left value from the right value } else { left = 0; } // constrain to the view port. if constrained by two edges, give precedence to top/left top = Math.min(top, clippingRect.bottom - elDims.height - this.margin); top = Math.max(top, clippingRect.top + this.margin); left = Math.min(left, clippingRect.right - elDims.width - this.margin); left = Math.max(left, clippingRect.left + this.margin); Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["applyStyle"])(el, { top: top - origin.top, left: left - origin.left }); }; // Triggers a callback. Calls a function in the option hash of the same name. // Arguments beyond the first `name` are forwarded on. // TODO: better code reuse for this. Repeat code // can kill this??? Popover.prototype.trigger = function (name) { if (this.options[name]) { this.options[name].apply(this, Array.prototype.slice.call(arguments, 1)); } }; return Popover; }()); /* Event-rendering methods for the DayGrid class ----------------------------------------------------------------------------------------------------------------------*/ // "Simple" is bad a name. has nothing to do with SimpleDayGrid var SimpleDayGridEventRenderer = /** @class */ (function (_super) { __extends(SimpleDayGridEventRenderer, _super); function SimpleDayGridEventRenderer() { return _super !== null && _super.apply(this, arguments) || this; } // Builds the HTML to be used for the default element for an individual segment SimpleDayGridEventRenderer.prototype.renderSegHtml = function (seg, mirrorInfo) { var context = this.context; var eventRange = seg.eventRange; var eventDef = eventRange.def; var eventUi = eventRange.ui; var allDay = eventDef.allDay; var isDraggable = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["computeEventDraggable"])(context, eventDef, eventUi); var isResizableFromStart = allDay && seg.isStart && Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["computeEventStartResizable"])(context, eventDef, eventUi); var isResizableFromEnd = allDay && seg.isEnd && Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["computeEventEndResizable"])(context, eventDef, eventUi); var classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd, mirrorInfo); var skinCss = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["cssToStr"])(this.getSkinCss(eventUi)); var timeHtml = ''; var timeText; var titleHtml; classes.unshift('fc-day-grid-event', 'fc-h-event'); // Only display a timed events time if it is the starting segment if (seg.isStart) { timeText = this.getTimeText(eventRange); if (timeText) { timeHtml = '' + Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["htmlEscape"])(timeText) + ''; } } titleHtml = '' + (Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["htmlEscape"])(eventDef.title || '') || ' ') + // we always want one line of height ''; return '
' + '
' + (context.options.dir === 'rtl' ? titleHtml + ' ' + timeHtml : // put a natural space in between timeHtml + ' ' + titleHtml // ) + '
' + (isResizableFromStart ? '
' : '') + (isResizableFromEnd ? '
' : '') + '
'; }; // Computes a default event time formatting string if `eventTimeFormat` is not explicitly defined SimpleDayGridEventRenderer.prototype.computeEventTimeFormat = function () { return { hour: 'numeric', minute: '2-digit', omitZeroMinute: true, meridiem: 'narrow' }; }; SimpleDayGridEventRenderer.prototype.computeDisplayEventEnd = function () { return false; // TODO: somehow consider the originating DayGrid's column count }; return SimpleDayGridEventRenderer; }(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["FgEventRenderer"])); /* Event-rendering methods for the DayGrid class ----------------------------------------------------------------------------------------------------------------------*/ var DayGridEventRenderer = /** @class */ (function (_super) { __extends(DayGridEventRenderer, _super); function DayGridEventRenderer(dayGrid) { var _this = _super.call(this) || this; _this.dayGrid = dayGrid; return _this; } // Renders the given foreground event segments onto the grid DayGridEventRenderer.prototype.attachSegs = function (segs, mirrorInfo) { var rowStructs = this.rowStructs = this.renderSegRows(segs); // append to each row's content skeleton this.dayGrid.rowEls.forEach(function (rowNode, i) { rowNode.querySelector('.fc-content-skeleton > table').appendChild(rowStructs[i].tbodyEl); }); // removes the "more.." events popover if (!mirrorInfo) { this.dayGrid.removeSegPopover(); } }; // Unrenders all currently rendered foreground event segments DayGridEventRenderer.prototype.detachSegs = function () { var rowStructs = this.rowStructs || []; var rowStruct; while ((rowStruct = rowStructs.pop())) { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["removeElement"])(rowStruct.tbodyEl); } this.rowStructs = null; }; // Uses the given events array to generate elements that should be appended to each row's content skeleton. // Returns an array of rowStruct objects (see the bottom of `renderSegRow`). // PRECONDITION: each segment shoud already have a rendered and assigned `.el` DayGridEventRenderer.prototype.renderSegRows = function (segs) { var rowStructs = []; var segRows; var row; segRows = this.groupSegRows(segs); // group into nested arrays // iterate each row of segment groupings for (row = 0; row < segRows.length; row++) { rowStructs.push(this.renderSegRow(row, segRows[row])); } return rowStructs; }; // Given a row # and an array of segments all in the same row, render a element, a skeleton that contains // the segments. Returns object with a bunch of internal data about how the render was calculated. // NOTE: modifies rowSegs DayGridEventRenderer.prototype.renderSegRow = function (row, rowSegs) { var isRtl = this.context.isRtl; var dayGrid = this.dayGrid; var colCnt = dayGrid.colCnt; var segLevels = this.buildSegLevels(rowSegs); // group into sub-arrays of levels var levelCnt = Math.max(1, segLevels.length); // ensure at least one level var tbody = document.createElement('tbody'); var segMatrix = []; // lookup for which segments are rendered into which level+col cells var cellMatrix = []; // lookup for all elements of the level+col matrix var loneCellMatrix = []; // lookup for elements that only take up a single column var i; var levelSegs; var col; var tr; var j; var seg; var td; // populates empty cells from the current column (`col`) to `endCol` function emptyCellsUntil(endCol) { while (col < endCol) { // try to grab a cell from the level above and extend its rowspan. otherwise, create a fresh cell td = (loneCellMatrix[i - 1] || [])[col]; if (td) { td.rowSpan = (td.rowSpan || 1) + 1; } else { td = document.createElement('td'); tr.appendChild(td); } cellMatrix[i][col] = td; loneCellMatrix[i][col] = td; col++; } } for (i = 0; i < levelCnt; i++) { // iterate through all levels levelSegs = segLevels[i]; col = 0; tr = document.createElement('tr'); segMatrix.push([]); cellMatrix.push([]); loneCellMatrix.push([]); // levelCnt might be 1 even though there are no actual levels. protect against this. // this single empty row is useful for styling. if (levelSegs) { for (j = 0; j < levelSegs.length; j++) { // iterate through segments in level seg = levelSegs[j]; var leftCol = isRtl ? (colCnt - 1 - seg.lastCol) : seg.firstCol; var rightCol = isRtl ? (colCnt - 1 - seg.firstCol) : seg.lastCol; emptyCellsUntil(leftCol); // create a container that occupies or more columns. append the event element. td = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createElement"])('td', { className: 'fc-event-container' }, seg.el); if (leftCol !== rightCol) { td.colSpan = rightCol - leftCol + 1; } else { // a single-column segment loneCellMatrix[i][col] = td; } while (col <= rightCol) { cellMatrix[i][col] = td; segMatrix[i][col] = seg; col++; } tr.appendChild(td); } } emptyCellsUntil(colCnt); // finish off the row var introHtml = dayGrid.renderProps.renderIntroHtml(); if (introHtml) { if (isRtl) { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["appendToElement"])(tr, introHtml); } else { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["prependToElement"])(tr, introHtml); } } tbody.appendChild(tr); } return { row: row, tbodyEl: tbody, cellMatrix: cellMatrix, segMatrix: segMatrix, segLevels: segLevels, segs: rowSegs }; }; // Stacks a flat array of segments, which are all assumed to be in the same row, into subarrays of vertical levels. // NOTE: modifies segs DayGridEventRenderer.prototype.buildSegLevels = function (segs) { var isRtl = this.context.isRtl; var colCnt = this.dayGrid.colCnt; var levels = []; var i; var seg; var j; // Give preference to elements with certain criteria, so they have // a chance to be closer to the top. segs = this.sortEventSegs(segs); for (i = 0; i < segs.length; i++) { seg = segs[i]; // loop through levels, starting with the topmost, until the segment doesn't collide with other segments for (j = 0; j < levels.length; j++) { if (!isDaySegCollision(seg, levels[j])) { break; } } // `j` now holds the desired subrow index seg.level = j; seg.leftCol = isRtl ? (colCnt - 1 - seg.lastCol) : seg.firstCol; // for sorting only seg.rightCol = isRtl ? (colCnt - 1 - seg.firstCol) : seg.lastCol // for sorting only ; (levels[j] || (levels[j] = [])).push(seg); } // order segments left-to-right. very important if calendar is RTL for (j = 0; j < levels.length; j++) { levels[j].sort(compareDaySegCols); } return levels; }; // Given a flat array of segments, return an array of sub-arrays, grouped by each segment's row DayGridEventRenderer.prototype.groupSegRows = function (segs) { var segRows = []; var i; for (i = 0; i < this.dayGrid.rowCnt; i++) { segRows.push([]); } for (i = 0; i < segs.length; i++) { segRows[segs[i].row].push(segs[i]); } return segRows; }; // Computes a default `displayEventEnd` value if one is not expliclty defined DayGridEventRenderer.prototype.computeDisplayEventEnd = function () { return this.dayGrid.colCnt === 1; // we'll likely have space if there's only one day }; return DayGridEventRenderer; }(SimpleDayGridEventRenderer)); // Computes whether two segments' columns collide. They are assumed to be in the same row. function isDaySegCollision(seg, otherSegs) { var i; var otherSeg; for (i = 0; i < otherSegs.length; i++) { otherSeg = otherSegs[i]; if (otherSeg.firstCol <= seg.lastCol && otherSeg.lastCol >= seg.firstCol) { return true; } } return false; } // A cmp function for determining the leftmost event function compareDaySegCols(a, b) { return a.leftCol - b.leftCol; } var DayGridMirrorRenderer = /** @class */ (function (_super) { __extends(DayGridMirrorRenderer, _super); function DayGridMirrorRenderer() { return _super !== null && _super.apply(this, arguments) || this; } DayGridMirrorRenderer.prototype.attachSegs = function (segs, mirrorInfo) { var sourceSeg = mirrorInfo.sourceSeg; var rowStructs = this.rowStructs = this.renderSegRows(segs); // inject each new event skeleton into each associated row this.dayGrid.rowEls.forEach(function (rowNode, row) { var skeletonEl = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["htmlToElement"])('
'); // will be absolutely positioned var skeletonTopEl; var skeletonTop; // If there is an original segment, match the top position. Otherwise, put it at the row's top level if (sourceSeg && sourceSeg.row === row) { skeletonTopEl = sourceSeg.el; } else { skeletonTopEl = rowNode.querySelector('.fc-content-skeleton tbody'); if (!skeletonTopEl) { // when no events skeletonTopEl = rowNode.querySelector('.fc-content-skeleton table'); } } skeletonTop = skeletonTopEl.getBoundingClientRect().top - rowNode.getBoundingClientRect().top; // the offsetParent origin skeletonEl.style.top = skeletonTop + 'px'; skeletonEl.querySelector('table').appendChild(rowStructs[row].tbodyEl); rowNode.appendChild(skeletonEl); }); }; return DayGridMirrorRenderer; }(DayGridEventRenderer)); var EMPTY_CELL_HTML = ''; var DayGridFillRenderer = /** @class */ (function (_super) { __extends(DayGridFillRenderer, _super); function DayGridFillRenderer(dayGrid) { var _this = _super.call(this) || this; _this.fillSegTag = 'td'; // override the default tag name _this.dayGrid = dayGrid; return _this; } DayGridFillRenderer.prototype.renderSegs = function (type, context, segs) { // don't render timed background events if (type === 'bgEvent') { segs = segs.filter(function (seg) { return seg.eventRange.def.allDay; }); } _super.prototype.renderSegs.call(this, type, context, segs); }; DayGridFillRenderer.prototype.attachSegs = function (type, segs) { var els = []; var i; var seg; var skeletonEl; for (i = 0; i < segs.length; i++) { seg = segs[i]; skeletonEl = this.renderFillRow(type, seg); this.dayGrid.rowEls[seg.row].appendChild(skeletonEl); els.push(skeletonEl); } return els; }; // Generates the HTML needed for one row of a fill. Requires the seg's el to be rendered. DayGridFillRenderer.prototype.renderFillRow = function (type, seg) { var dayGrid = this.dayGrid; var isRtl = this.context.isRtl; var colCnt = dayGrid.colCnt; var leftCol = isRtl ? (colCnt - 1 - seg.lastCol) : seg.firstCol; var rightCol = isRtl ? (colCnt - 1 - seg.firstCol) : seg.lastCol; var startCol = leftCol; var endCol = rightCol + 1; var className; var skeletonEl; var trEl; if (type === 'businessHours') { className = 'bgevent'; } else { className = type.toLowerCase(); } skeletonEl = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["htmlToElement"])('
' + '
' + '
'); trEl = skeletonEl.getElementsByTagName('tr')[0]; if (startCol > 0) { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["appendToElement"])(trEl, // will create (startCol + 1) td's new Array(startCol + 1).join(EMPTY_CELL_HTML)); } seg.el.colSpan = endCol - startCol; trEl.appendChild(seg.el); if (endCol < colCnt) { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["appendToElement"])(trEl, // will create (colCnt - endCol) td's new Array(colCnt - endCol + 1).join(EMPTY_CELL_HTML)); } var introHtml = dayGrid.renderProps.renderIntroHtml(); if (introHtml) { if (isRtl) { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["appendToElement"])(trEl, introHtml); } else { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["prependToElement"])(trEl, introHtml); } } return skeletonEl; }; return DayGridFillRenderer; }(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["FillRenderer"])); var DayTile = /** @class */ (function (_super) { __extends(DayTile, _super); function DayTile(el) { var _this = _super.call(this, el) || this; var eventRenderer = _this.eventRenderer = new DayTileEventRenderer(_this); var renderFrame = _this.renderFrame = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["memoizeRendering"])(_this._renderFrame); _this.renderFgEvents = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["memoizeRendering"])(eventRenderer.renderSegs.bind(eventRenderer), eventRenderer.unrender.bind(eventRenderer), [renderFrame]); _this.renderEventSelection = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["memoizeRendering"])(eventRenderer.selectByInstanceId.bind(eventRenderer), eventRenderer.unselectByInstanceId.bind(eventRenderer), [_this.renderFgEvents]); _this.renderEventDrag = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["memoizeRendering"])(eventRenderer.hideByHash.bind(eventRenderer), eventRenderer.showByHash.bind(eventRenderer), [renderFrame]); _this.renderEventResize = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["memoizeRendering"])(eventRenderer.hideByHash.bind(eventRenderer), eventRenderer.showByHash.bind(eventRenderer), [renderFrame]); return _this; } DayTile.prototype.firstContext = function (context) { context.calendar.registerInteractiveComponent(this, { el: this.el, useEventCenter: false }); }; DayTile.prototype.render = function (props, context) { this.renderFrame(props.date); this.renderFgEvents(context, props.fgSegs); this.renderEventSelection(props.eventSelection); this.renderEventDrag(props.eventDragInstances); this.renderEventResize(props.eventResizeInstances); }; DayTile.prototype.destroy = function () { _super.prototype.destroy.call(this); this.renderFrame.unrender(); // should unrender everything else this.context.calendar.unregisterInteractiveComponent(this); }; DayTile.prototype._renderFrame = function (date) { var _a = this.context, theme = _a.theme, dateEnv = _a.dateEnv, options = _a.options; var title = dateEnv.format(date, Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createFormatter"])(options.dayPopoverFormat) // TODO: cache ); this.el.innerHTML = '
' + '' + Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["htmlEscape"])(title) + '' + '' + '
' + '
' + '
' + '
'; this.segContainerEl = this.el.querySelector('.fc-event-container'); }; DayTile.prototype.queryHit = function (positionLeft, positionTop, elWidth, elHeight) { var date = this.props.date; // HACK if (positionLeft < elWidth && positionTop < elHeight) { return { component: this, dateSpan: { allDay: true, range: { start: date, end: Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["addDays"])(date, 1) } }, dayEl: this.el, rect: { left: 0, top: 0, right: elWidth, bottom: elHeight }, layer: 1 }; } }; return DayTile; }(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["DateComponent"])); var DayTileEventRenderer = /** @class */ (function (_super) { __extends(DayTileEventRenderer, _super); function DayTileEventRenderer(dayTile) { var _this = _super.call(this) || this; _this.dayTile = dayTile; return _this; } DayTileEventRenderer.prototype.attachSegs = function (segs) { for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) { var seg = segs_1[_i]; this.dayTile.segContainerEl.appendChild(seg.el); } }; DayTileEventRenderer.prototype.detachSegs = function (segs) { for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) { var seg = segs_2[_i]; Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["removeElement"])(seg.el); } }; return DayTileEventRenderer; }(SimpleDayGridEventRenderer)); var DayBgRow = /** @class */ (function () { function DayBgRow(context) { this.context = context; } DayBgRow.prototype.renderHtml = function (props) { var parts = []; if (props.renderIntroHtml) { parts.push(props.renderIntroHtml()); } for (var _i = 0, _a = props.cells; _i < _a.length; _i++) { var cell = _a[_i]; parts.push(renderCellHtml(cell.date, props.dateProfile, this.context, cell.htmlAttrs)); } if (!props.cells.length) { parts.push(''); } if (this.context.options.dir === 'rtl') { parts.reverse(); } return '' + parts.join('') + ''; }; return DayBgRow; }()); function renderCellHtml(date, dateProfile, context, otherAttrs) { var dateEnv = context.dateEnv, theme = context.theme; var isDateValid = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["rangeContainsMarker"])(dateProfile.activeRange, date); // TODO: called too frequently. cache somehow. var classes = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["getDayClasses"])(date, dateProfile, context); classes.unshift('fc-day', theme.getClass('widgetContent')); return ''; } var DAY_NUM_FORMAT = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createFormatter"])({ day: 'numeric' }); var WEEK_NUM_FORMAT = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createFormatter"])({ week: 'numeric' }); var DayGrid = /** @class */ (function (_super) { __extends(DayGrid, _super); function DayGrid(el, renderProps) { var _this = _super.call(this, el) || this; _this.bottomCoordPadding = 0; // hack for extending the hit area for the last row of the coordinate grid _this.isCellSizesDirty = false; _this.renderProps = renderProps; var eventRenderer = _this.eventRenderer = new DayGridEventRenderer(_this); var fillRenderer = _this.fillRenderer = new DayGridFillRenderer(_this); _this.mirrorRenderer = new DayGridMirrorRenderer(_this); var renderCells = _this.renderCells = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["memoizeRendering"])(_this._renderCells, _this._unrenderCells); _this.renderBusinessHours = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["memoizeRendering"])(fillRenderer.renderSegs.bind(fillRenderer, 'businessHours'), fillRenderer.unrender.bind(fillRenderer, 'businessHours'), [renderCells]); _this.renderDateSelection = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["memoizeRendering"])(fillRenderer.renderSegs.bind(fillRenderer, 'highlight'), fillRenderer.unrender.bind(fillRenderer, 'highlight'), [renderCells]); _this.renderBgEvents = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["memoizeRendering"])(fillRenderer.renderSegs.bind(fillRenderer, 'bgEvent'), fillRenderer.unrender.bind(fillRenderer, 'bgEvent'), [renderCells]); _this.renderFgEvents = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["memoizeRendering"])(eventRenderer.renderSegs.bind(eventRenderer), eventRenderer.unrender.bind(eventRenderer), [renderCells]); _this.renderEventSelection = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["memoizeRendering"])(eventRenderer.selectByInstanceId.bind(eventRenderer), eventRenderer.unselectByInstanceId.bind(eventRenderer), [_this.renderFgEvents]); _this.renderEventDrag = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["memoizeRendering"])(_this._renderEventDrag, _this._unrenderEventDrag, [renderCells]); _this.renderEventResize = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["memoizeRendering"])(_this._renderEventResize, _this._unrenderEventResize, [renderCells]); return _this; } DayGrid.prototype.render = function (props, context) { var cells = props.cells; this.rowCnt = cells.length; this.colCnt = cells[0].length; this.renderCells(cells, props.isRigid); this.renderBusinessHours(context, props.businessHourSegs); this.renderDateSelection(context, props.dateSelectionSegs); this.renderBgEvents(context, props.bgEventSegs); this.renderFgEvents(context, props.fgEventSegs); this.renderEventSelection(props.eventSelection); this.renderEventDrag(props.eventDrag); this.renderEventResize(props.eventResize); if (this.segPopoverTile) { this.updateSegPopoverTile(); } }; DayGrid.prototype.destroy = function () { _super.prototype.destroy.call(this); this.renderCells.unrender(); // will unrender everything else }; DayGrid.prototype.getCellRange = function (row, col) { var start = this.props.cells[row][col].date; var end = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["addDays"])(start, 1); return { start: start, end: end }; }; DayGrid.prototype.updateSegPopoverTile = function (date, segs) { var ownProps = this.props; this.segPopoverTile.receiveProps({ date: date || this.segPopoverTile.props.date, fgSegs: segs || this.segPopoverTile.props.fgSegs, eventSelection: ownProps.eventSelection, eventDragInstances: ownProps.eventDrag ? ownProps.eventDrag.affectedInstances : null, eventResizeInstances: ownProps.eventResize ? ownProps.eventResize.affectedInstances : null }, this.context); }; /* Date Rendering ------------------------------------------------------------------------------------------------------------------*/ DayGrid.prototype._renderCells = function (cells, isRigid) { var _a = this.context, calendar = _a.calendar, view = _a.view, isRtl = _a.isRtl, dateEnv = _a.dateEnv; var _b = this, rowCnt = _b.rowCnt, colCnt = _b.colCnt; var html = ''; var row; var col; for (row = 0; row < rowCnt; row++) { html += this.renderDayRowHtml(row, isRigid); } this.el.innerHTML = html; this.rowEls = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["findElements"])(this.el, '.fc-row'); this.cellEls = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["findElements"])(this.el, '.fc-day, .fc-disabled-day'); if (isRtl) { this.cellEls.reverse(); } this.rowPositions = new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["PositionCache"](this.el, this.rowEls, false, true // vertical ); this.colPositions = new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["PositionCache"](this.el, this.cellEls.slice(0, colCnt), // only the first row true, false // horizontal ); // trigger dayRender with each cell's element for (row = 0; row < rowCnt; row++) { for (col = 0; col < colCnt; col++) { calendar.publiclyTrigger('dayRender', [ { date: dateEnv.toDate(cells[row][col].date), el: this.getCellEl(row, col), view: view } ]); } } this.isCellSizesDirty = true; }; DayGrid.prototype._unrenderCells = function () { this.removeSegPopover(); }; // Generates the HTML for a single row, which is a div that wraps a table. // `row` is the row number. DayGrid.prototype.renderDayRowHtml = function (row, isRigid) { var theme = this.context.theme; var classes = ['fc-row', 'fc-week', theme.getClass('dayRow')]; if (isRigid) { classes.push('fc-rigid'); } var bgRow = new DayBgRow(this.context); return '' + '
' + '
' + '' + bgRow.renderHtml({ cells: this.props.cells[row], dateProfile: this.props.dateProfile, renderIntroHtml: this.renderProps.renderBgIntroHtml }) + '
' + '
' + '
' + '' + (this.getIsNumbersVisible() ? '' + this.renderNumberTrHtml(row) + '' : '') + '
' + '
' + '
'; }; DayGrid.prototype.getIsNumbersVisible = function () { return this.getIsDayNumbersVisible() || this.renderProps.cellWeekNumbersVisible || this.renderProps.colWeekNumbersVisible; }; DayGrid.prototype.getIsDayNumbersVisible = function () { return this.rowCnt > 1; }; /* Grid Number Rendering ------------------------------------------------------------------------------------------------------------------*/ DayGrid.prototype.renderNumberTrHtml = function (row) { var isRtl = this.context.isRtl; var intro = this.renderProps.renderNumberIntroHtml(row, this); return '' + '' + (isRtl ? '' : intro) + this.renderNumberCellsHtml(row) + (isRtl ? intro : '') + ''; }; DayGrid.prototype.renderNumberCellsHtml = function (row) { var htmls = []; var col; var date; for (col = 0; col < this.colCnt; col++) { date = this.props.cells[row][col].date; htmls.push(this.renderNumberCellHtml(date)); } if (this.context.isRtl) { htmls.reverse(); } return htmls.join(''); }; // Generates the HTML for the s of the "number" row in the DayGrid's content skeleton. // The number row will only exist if either day numbers or week numbers are turned on. DayGrid.prototype.renderNumberCellHtml = function (date) { var _a = this.context, dateEnv = _a.dateEnv, options = _a.options; var html = ''; var isDateValid = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["rangeContainsMarker"])(this.props.dateProfile.activeRange, date); // TODO: called too frequently. cache somehow. var isDayNumberVisible = this.getIsDayNumbersVisible() && isDateValid; var classes; var weekCalcFirstDow; if (!isDayNumberVisible && !this.renderProps.cellWeekNumbersVisible) { // no numbers in day cell (week number must be along the side) return ''; // will create an empty space above events :( } classes = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["getDayClasses"])(date, this.props.dateProfile, this.context); classes.unshift('fc-day-top'); if (this.renderProps.cellWeekNumbersVisible) { weekCalcFirstDow = dateEnv.weekDow; } html += ''; if (this.renderProps.cellWeekNumbersVisible && (date.getUTCDay() === weekCalcFirstDow)) { html += Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["buildGotoAnchorHtml"])(options, dateEnv, { date: date, type: 'week' }, { 'class': 'fc-week-number' }, dateEnv.format(date, WEEK_NUM_FORMAT) // inner HTML ); } if (isDayNumberVisible) { html += Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["buildGotoAnchorHtml"])(options, dateEnv, date, { 'class': 'fc-day-number' }, dateEnv.format(date, DAY_NUM_FORMAT) // inner HTML ); } html += ''; return html; }; /* Sizing ------------------------------------------------------------------------------------------------------------------*/ DayGrid.prototype.updateSize = function (isResize) { var calendar = this.context.calendar; var _a = this, fillRenderer = _a.fillRenderer, eventRenderer = _a.eventRenderer, mirrorRenderer = _a.mirrorRenderer; if (isResize || this.isCellSizesDirty || calendar.isEventsUpdated // hack ) { this.buildPositionCaches(); this.isCellSizesDirty = false; } fillRenderer.computeSizes(isResize); eventRenderer.computeSizes(isResize); mirrorRenderer.computeSizes(isResize); fillRenderer.assignSizes(isResize); eventRenderer.assignSizes(isResize); mirrorRenderer.assignSizes(isResize); }; DayGrid.prototype.buildPositionCaches = function () { this.buildColPositions(); this.buildRowPositions(); }; DayGrid.prototype.buildColPositions = function () { this.colPositions.build(); }; DayGrid.prototype.buildRowPositions = function () { this.rowPositions.build(); this.rowPositions.bottoms[this.rowCnt - 1] += this.bottomCoordPadding; // hack }; /* Hit System ------------------------------------------------------------------------------------------------------------------*/ DayGrid.prototype.positionToHit = function (leftPosition, topPosition) { var _a = this, colPositions = _a.colPositions, rowPositions = _a.rowPositions; var col = colPositions.leftToIndex(leftPosition); var row = rowPositions.topToIndex(topPosition); if (row != null && col != null) { return { row: row, col: col, dateSpan: { range: this.getCellRange(row, col), allDay: true }, dayEl: this.getCellEl(row, col), relativeRect: { left: colPositions.lefts[col], right: colPositions.rights[col], top: rowPositions.tops[row], bottom: rowPositions.bottoms[row] } }; } }; /* Cell System ------------------------------------------------------------------------------------------------------------------*/ // FYI: the first column is the leftmost column, regardless of date DayGrid.prototype.getCellEl = function (row, col) { return this.cellEls[row * this.colCnt + col]; }; /* Event Drag Visualization ------------------------------------------------------------------------------------------------------------------*/ DayGrid.prototype._renderEventDrag = function (state) { if (state) { this.eventRenderer.hideByHash(state.affectedInstances); this.fillRenderer.renderSegs('highlight', this.context, state.segs); } }; DayGrid.prototype._unrenderEventDrag = function (state) { if (state) { this.eventRenderer.showByHash(state.affectedInstances); this.fillRenderer.unrender('highlight', this.context); } }; /* Event Resize Visualization ------------------------------------------------------------------------------------------------------------------*/ DayGrid.prototype._renderEventResize = function (state) { if (state) { this.eventRenderer.hideByHash(state.affectedInstances); this.fillRenderer.renderSegs('highlight', this.context, state.segs); this.mirrorRenderer.renderSegs(this.context, state.segs, { isResizing: true, sourceSeg: state.sourceSeg }); } }; DayGrid.prototype._unrenderEventResize = function (state) { if (state) { this.eventRenderer.showByHash(state.affectedInstances); this.fillRenderer.unrender('highlight', this.context); this.mirrorRenderer.unrender(this.context, state.segs, { isResizing: true, sourceSeg: state.sourceSeg }); } }; /* More+ Link Popover ------------------------------------------------------------------------------------------------------------------*/ DayGrid.prototype.removeSegPopover = function () { if (this.segPopover) { this.segPopover.hide(); // in handler, will call segPopover's removeElement } }; // Limits the number of "levels" (vertically stacking layers of events) for each row of the grid. // `levelLimit` can be false (don't limit), a number, or true (should be computed). DayGrid.prototype.limitRows = function (levelLimit) { var rowStructs = this.eventRenderer.rowStructs || []; var row; // row # var rowLevelLimit; for (row = 0; row < rowStructs.length; row++) { this.unlimitRow(row); if (!levelLimit) { rowLevelLimit = false; } else if (typeof levelLimit === 'number') { rowLevelLimit = levelLimit; } else { rowLevelLimit = this.computeRowLevelLimit(row); } if (rowLevelLimit !== false) { this.limitRow(row, rowLevelLimit); } } }; // Computes the number of levels a row will accomodate without going outside its bounds. // Assumes the row is "rigid" (maintains a constant height regardless of what is inside). // `row` is the row number. DayGrid.prototype.computeRowLevelLimit = function (row) { var rowEl = this.rowEls[row]; // the containing "fake" row div var rowBottom = rowEl.getBoundingClientRect().bottom; // relative to viewport! var trEls = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["findChildren"])(this.eventRenderer.rowStructs[row].tbodyEl); var i; var trEl; // Reveal one level at a time and stop when we find one out of bounds for (i = 0; i < trEls.length; i++) { trEl = trEls[i]; trEl.classList.remove('fc-limited'); // reset to original state (reveal) if (trEl.getBoundingClientRect().bottom > rowBottom) { return i; } } return false; // should not limit at all }; // Limits the given grid row to the maximum number of levels and injects "more" links if necessary. // `row` is the row number. // `levelLimit` is a number for the maximum (inclusive) number of levels allowed. DayGrid.prototype.limitRow = function (row, levelLimit) { var _this = this; var colCnt = this.colCnt; var isRtl = this.context.isRtl; var rowStruct = this.eventRenderer.rowStructs[row]; var moreNodes = []; // array of "more" links and DOM nodes var col = 0; // col #, left-to-right (not chronologically) var levelSegs; // array of segment objects in the last allowable level, ordered left-to-right var cellMatrix; // a matrix (by level, then column) of all elements in the row var limitedNodes; // array of temporarily hidden level and segment DOM nodes var i; var seg; var segsBelow; // array of segment objects below `seg` in the current `col` var totalSegsBelow; // total number of segments below `seg` in any of the columns `seg` occupies var colSegsBelow; // array of segment arrays, below seg, one for each column (offset from segs's first column) var td; var rowSpan; var segMoreNodes; // array of "more" cells that will stand-in for the current seg's cell var j; var moreTd; var moreWrap; var moreLink; // Iterates through empty level cells and places "more" links inside if need be var emptyCellsUntil = function (endCol) { while (col < endCol) { segsBelow = _this.getCellSegs(row, col, levelLimit); if (segsBelow.length) { td = cellMatrix[levelLimit - 1][col]; moreLink = _this.renderMoreLink(row, col, segsBelow); moreWrap = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createElement"])('div', null, moreLink); td.appendChild(moreWrap); moreNodes.push(moreWrap); } col++; } }; if (levelLimit && levelLimit < rowStruct.segLevels.length) { // is it actually over the limit? levelSegs = rowStruct.segLevels[levelLimit - 1]; cellMatrix = rowStruct.cellMatrix; limitedNodes = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["findChildren"])(rowStruct.tbodyEl).slice(levelLimit); // get level elements past the limit limitedNodes.forEach(function (node) { node.classList.add('fc-limited'); // hide elements and get a simple DOM-nodes array }); // iterate though segments in the last allowable level for (i = 0; i < levelSegs.length; i++) { seg = levelSegs[i]; var leftCol = isRtl ? (colCnt - 1 - seg.lastCol) : seg.firstCol; var rightCol = isRtl ? (colCnt - 1 - seg.firstCol) : seg.lastCol; emptyCellsUntil(leftCol); // process empty cells before the segment // determine *all* segments below `seg` that occupy the same columns colSegsBelow = []; totalSegsBelow = 0; while (col <= rightCol) { segsBelow = this.getCellSegs(row, col, levelLimit); colSegsBelow.push(segsBelow); totalSegsBelow += segsBelow.length; col++; } if (totalSegsBelow) { // do we need to replace this segment with one or many "more" links? td = cellMatrix[levelLimit - 1][leftCol]; // the segment's parent cell rowSpan = td.rowSpan || 1; segMoreNodes = []; // make a replacement for each column the segment occupies. will be one for each colspan for (j = 0; j < colSegsBelow.length; j++) { moreTd = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createElement"])('td', { className: 'fc-more-cell', rowSpan: rowSpan }); segsBelow = colSegsBelow[j]; moreLink = this.renderMoreLink(row, leftCol + j, [seg].concat(segsBelow) // count seg as hidden too ); moreWrap = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createElement"])('div', null, moreLink); moreTd.appendChild(moreWrap); segMoreNodes.push(moreTd); moreNodes.push(moreTd); } td.classList.add('fc-limited'); Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["insertAfterElement"])(td, segMoreNodes); limitedNodes.push(td); } } emptyCellsUntil(this.colCnt); // finish off the level rowStruct.moreEls = moreNodes; // for easy undoing later rowStruct.limitedEls = limitedNodes; // for easy undoing later } }; // Reveals all levels and removes all "more"-related elements for a grid's row. // `row` is a row number. DayGrid.prototype.unlimitRow = function (row) { var rowStruct = this.eventRenderer.rowStructs[row]; if (rowStruct.moreEls) { rowStruct.moreEls.forEach(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["removeElement"]); rowStruct.moreEls = null; } if (rowStruct.limitedEls) { rowStruct.limitedEls.forEach(function (limitedEl) { limitedEl.classList.remove('fc-limited'); }); rowStruct.limitedEls = null; } }; // Renders an element that represents hidden event element for a cell. // Responsible for attaching click handler as well. DayGrid.prototype.renderMoreLink = function (row, col, hiddenSegs) { var _this = this; var _a = this.context, calendar = _a.calendar, view = _a.view, dateEnv = _a.dateEnv, options = _a.options, isRtl = _a.isRtl; var a = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createElement"])('a', { className: 'fc-more' }); a.innerText = this.getMoreLinkText(hiddenSegs.length); a.addEventListener('click', function (ev) { var clickOption = options.eventLimitClick; var _col = isRtl ? _this.colCnt - col - 1 : col; // HACK: props.cells has different dir system? var date = _this.props.cells[row][_col].date; var moreEl = ev.currentTarget; var dayEl = _this.getCellEl(row, col); var allSegs = _this.getCellSegs(row, col); // rescope the segments to be within the cell's date var reslicedAllSegs = _this.resliceDaySegs(allSegs, date); var reslicedHiddenSegs = _this.resliceDaySegs(hiddenSegs, date); if (typeof clickOption === 'function') { // the returned value can be an atomic option clickOption = calendar.publiclyTrigger('eventLimitClick', [ { date: dateEnv.toDate(date), allDay: true, dayEl: dayEl, moreEl: moreEl, segs: reslicedAllSegs, hiddenSegs: reslicedHiddenSegs, jsEvent: ev, view: view } ]); } if (clickOption === 'popover') { _this.showSegPopover(row, col, moreEl, reslicedAllSegs); } else if (typeof clickOption === 'string') { // a view name calendar.zoomTo(date, clickOption); } }); return a; }; // Reveals the popover that displays all events within a cell DayGrid.prototype.showSegPopover = function (row, col, moreLink, segs) { var _this = this; var _a = this.context, calendar = _a.calendar, view = _a.view, theme = _a.theme, isRtl = _a.isRtl; var _col = isRtl ? this.colCnt - col - 1 : col; // HACK: props.cells has different dir system? var moreWrap = moreLink.parentNode; // the
wrapper around the var topEl; // the element we want to match the top coordinate of var options; if (this.rowCnt === 1) { topEl = view.el; // will cause the popover to cover any sort of header } else { topEl = this.rowEls[row]; // will align with top of row } options = { className: 'fc-more-popover ' + theme.getClass('popover'), parentEl: view.el, top: Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["computeRect"])(topEl).top, autoHide: true, content: function (el) { _this.segPopoverTile = new DayTile(el); _this.updateSegPopoverTile(_this.props.cells[row][_col].date, segs); }, hide: function () { _this.segPopoverTile.destroy(); _this.segPopoverTile = null; _this.segPopover.destroy(); _this.segPopover = null; } }; // Determine horizontal coordinate. // We use the moreWrap instead of the to avoid border confusion. if (isRtl) { options.right = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["computeRect"])(moreWrap).right + 1; // +1 to be over cell border } else { options.left = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["computeRect"])(moreWrap).left - 1; // -1 to be over cell border } this.segPopover = new Popover(options); this.segPopover.show(); calendar.releaseAfterSizingTriggers(); // hack for eventPositioned }; // Given the events within an array of segment objects, reslice them to be in a single day DayGrid.prototype.resliceDaySegs = function (segs, dayDate) { var dayStart = dayDate; var dayEnd = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["addDays"])(dayStart, 1); var dayRange = { start: dayStart, end: dayEnd }; var newSegs = []; for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) { var seg = segs_1[_i]; var eventRange = seg.eventRange; var origRange = eventRange.range; var slicedRange = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["intersectRanges"])(origRange, dayRange); if (slicedRange) { newSegs.push(__assign({}, seg, { eventRange: { def: eventRange.def, ui: __assign({}, eventRange.ui, { durationEditable: false }), instance: eventRange.instance, range: slicedRange }, isStart: seg.isStart && slicedRange.start.valueOf() === origRange.start.valueOf(), isEnd: seg.isEnd && slicedRange.end.valueOf() === origRange.end.valueOf() })); } } return newSegs; }; // Generates the text that should be inside a "more" link, given the number of events it represents DayGrid.prototype.getMoreLinkText = function (num) { var opt = this.context.options.eventLimitText; if (typeof opt === 'function') { return opt(num); } else { return '+' + num + ' ' + opt; } }; // Returns segments within a given cell. // If `startLevel` is specified, returns only events including and below that level. Otherwise returns all segs. DayGrid.prototype.getCellSegs = function (row, col, startLevel) { var segMatrix = this.eventRenderer.rowStructs[row].segMatrix; var level = startLevel || 0; var segs = []; var seg; while (level < segMatrix.length) { seg = segMatrix[level][col]; if (seg) { segs.push(seg); } level++; } return segs; }; return DayGrid; }(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["DateComponent"])); var WEEK_NUM_FORMAT$1 = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createFormatter"])({ week: 'numeric' }); /* An abstract class for the daygrid views, as well as month view. Renders one or more rows of day cells. ----------------------------------------------------------------------------------------------------------------------*/ // It is a manager for a DayGrid subcomponent, which does most of the heavy lifting. // It is responsible for managing width/height. var AbstractDayGridView = /** @class */ (function (_super) { __extends(AbstractDayGridView, _super); function AbstractDayGridView() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.processOptions = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["memoize"])(_this._processOptions); _this.renderSkeleton = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["memoizeRendering"])(_this._renderSkeleton, _this._unrenderSkeleton); /* Header Rendering ------------------------------------------------------------------------------------------------------------------*/ // Generates the HTML that will go before the day-of week header cells _this.renderHeadIntroHtml = function () { var _a = _this.context, theme = _a.theme, options = _a.options; if (_this.colWeekNumbersVisible) { return '' + '' + '' + // needed for matchCellWidths Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["htmlEscape"])(options.weekLabel) + '' + ''; } return ''; }; /* Day Grid Rendering ------------------------------------------------------------------------------------------------------------------*/ // Generates the HTML that will go before content-skeleton cells that display the day/week numbers _this.renderDayGridNumberIntroHtml = function (row, dayGrid) { var _a = _this.context, options = _a.options, dateEnv = _a.dateEnv; var weekStart = dayGrid.props.cells[row][0].date; if (_this.colWeekNumbersVisible) { return '' + '' + Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["buildGotoAnchorHtml"])(// aside from link, important for matchCellWidths options, dateEnv, { date: weekStart, type: 'week', forceOff: dayGrid.colCnt === 1 }, dateEnv.format(weekStart, WEEK_NUM_FORMAT$1) // inner HTML ) + ''; } return ''; }; // Generates the HTML that goes before the day bg cells for each day-row _this.renderDayGridBgIntroHtml = function () { var theme = _this.context.theme; if (_this.colWeekNumbersVisible) { return ''; } return ''; }; // Generates the HTML that goes before every other type of row generated by DayGrid. // Affects mirror-skeleton and highlight-skeleton rows. _this.renderDayGridIntroHtml = function () { if (_this.colWeekNumbersVisible) { return ''; } return ''; }; return _this; } AbstractDayGridView.prototype._processOptions = function (options) { if (options.weekNumbers) { if (options.weekNumbersWithinDays) { this.cellWeekNumbersVisible = true; this.colWeekNumbersVisible = false; } else { this.cellWeekNumbersVisible = false; this.colWeekNumbersVisible = true; } } else { this.colWeekNumbersVisible = false; this.cellWeekNumbersVisible = false; } }; AbstractDayGridView.prototype.render = function (props, context) { _super.prototype.render.call(this, props, context); this.processOptions(context.options); this.renderSkeleton(context); }; AbstractDayGridView.prototype.destroy = function () { _super.prototype.destroy.call(this); this.renderSkeleton.unrender(); }; AbstractDayGridView.prototype._renderSkeleton = function (context) { this.el.classList.add('fc-dayGrid-view'); this.el.innerHTML = this.renderSkeletonHtml(); this.scroller = new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["ScrollComponent"]('hidden', // overflow x 'auto' // overflow y ); var dayGridContainerEl = this.scroller.el; this.el.querySelector('.fc-body > tr > td').appendChild(dayGridContainerEl); dayGridContainerEl.classList.add('fc-day-grid-container'); var dayGridEl = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createElement"])('div', { className: 'fc-day-grid' }); dayGridContainerEl.appendChild(dayGridEl); this.dayGrid = new DayGrid(dayGridEl, { renderNumberIntroHtml: this.renderDayGridNumberIntroHtml, renderBgIntroHtml: this.renderDayGridBgIntroHtml, renderIntroHtml: this.renderDayGridIntroHtml, colWeekNumbersVisible: this.colWeekNumbersVisible, cellWeekNumbersVisible: this.cellWeekNumbersVisible }); }; AbstractDayGridView.prototype._unrenderSkeleton = function () { this.el.classList.remove('fc-dayGrid-view'); this.dayGrid.destroy(); this.scroller.destroy(); }; // Builds the HTML skeleton for the view. // The day-grid component will render inside of a container defined by this HTML. AbstractDayGridView.prototype.renderSkeletonHtml = function () { var _a = this.context, theme = _a.theme, options = _a.options; return '' + '' + (options.columnHeader ? '' + '' + '' + '' + '' : '') + '' + '' + '' + '' + '' + '
 
'; }; // Generates an HTML attribute string for setting the width of the week number column, if it is known AbstractDayGridView.prototype.weekNumberStyleAttr = function () { if (this.weekNumberWidth != null) { return 'style="width:' + this.weekNumberWidth + 'px"'; } return ''; }; // Determines whether each row should have a constant height AbstractDayGridView.prototype.hasRigidRows = function () { var eventLimit = this.context.options.eventLimit; return eventLimit && typeof eventLimit !== 'number'; }; /* Dimensions ------------------------------------------------------------------------------------------------------------------*/ AbstractDayGridView.prototype.updateSize = function (isResize, viewHeight, isAuto) { _super.prototype.updateSize.call(this, isResize, viewHeight, isAuto); // will call updateBaseSize. important that executes first this.dayGrid.updateSize(isResize); }; // Refreshes the horizontal dimensions of the view AbstractDayGridView.prototype.updateBaseSize = function (isResize, viewHeight, isAuto) { var dayGrid = this.dayGrid; var eventLimit = this.context.options.eventLimit; var headRowEl = this.header ? this.header.el : null; // HACK var scrollerHeight; var scrollbarWidths; // hack to give the view some height prior to dayGrid's columns being rendered // TODO: separate setting height from scroller VS dayGrid. if (!dayGrid.rowEls) { if (!isAuto) { scrollerHeight = this.computeScrollerHeight(viewHeight); this.scroller.setHeight(scrollerHeight); } return; } if (this.colWeekNumbersVisible) { // Make sure all week number cells running down the side have the same width. this.weekNumberWidth = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["matchCellWidths"])(Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["findElements"])(this.el, '.fc-week-number')); } // reset all heights to be natural this.scroller.clear(); if (headRowEl) { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["uncompensateScroll"])(headRowEl); } dayGrid.removeSegPopover(); // kill the "more" popover if displayed // is the event limit a constant level number? if (eventLimit && typeof eventLimit === 'number') { dayGrid.limitRows(eventLimit); // limit the levels first so the height can redistribute after } // distribute the height to the rows // (viewHeight is a "recommended" value if isAuto) scrollerHeight = this.computeScrollerHeight(viewHeight); this.setGridHeight(scrollerHeight, isAuto); // is the event limit dynamically calculated? if (eventLimit && typeof eventLimit !== 'number') { dayGrid.limitRows(eventLimit); // limit the levels after the grid's row heights have been set } if (!isAuto) { // should we force dimensions of the scroll container? this.scroller.setHeight(scrollerHeight); scrollbarWidths = this.scroller.getScrollbarWidths(); if (scrollbarWidths.left || scrollbarWidths.right) { // using scrollbars? if (headRowEl) { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["compensateScroll"])(headRowEl, scrollbarWidths); } // doing the scrollbar compensation might have created text overflow which created more height. redo scrollerHeight = this.computeScrollerHeight(viewHeight); this.scroller.setHeight(scrollerHeight); } // guarantees the same scrollbar widths this.scroller.lockOverflow(scrollbarWidths); } }; // given a desired total height of the view, returns what the height of the scroller should be AbstractDayGridView.prototype.computeScrollerHeight = function (viewHeight) { return viewHeight - Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["subtractInnerElHeight"])(this.el, this.scroller.el); // everything that's NOT the scroller }; // Sets the height of just the DayGrid component in this view AbstractDayGridView.prototype.setGridHeight = function (height, isAuto) { if (this.context.options.monthMode) { // if auto, make the height of each row the height that it would be if there were 6 weeks if (isAuto) { height *= this.dayGrid.rowCnt / 6; } Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["distributeHeight"])(this.dayGrid.rowEls, height, !isAuto); // if auto, don't compensate for height-hogging rows } else { if (isAuto) { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["undistributeHeight"])(this.dayGrid.rowEls); // let the rows be their natural height with no expanding } else { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["distributeHeight"])(this.dayGrid.rowEls, height, true); // true = compensate for height-hogging rows } } }; /* Scroll ------------------------------------------------------------------------------------------------------------------*/ AbstractDayGridView.prototype.computeDateScroll = function (duration) { return { top: 0 }; }; AbstractDayGridView.prototype.queryDateScroll = function () { return { top: this.scroller.getScrollTop() }; }; AbstractDayGridView.prototype.applyDateScroll = function (scroll) { if (scroll.top !== undefined) { this.scroller.setScrollTop(scroll.top); } }; return AbstractDayGridView; }(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["View"])); AbstractDayGridView.prototype.dateProfileGeneratorClass = DayGridDateProfileGenerator; var SimpleDayGrid = /** @class */ (function (_super) { __extends(SimpleDayGrid, _super); function SimpleDayGrid(dayGrid) { var _this = _super.call(this, dayGrid.el) || this; _this.slicer = new DayGridSlicer(); _this.dayGrid = dayGrid; return _this; } SimpleDayGrid.prototype.firstContext = function (context) { context.calendar.registerInteractiveComponent(this, { el: this.dayGrid.el }); }; SimpleDayGrid.prototype.destroy = function () { _super.prototype.destroy.call(this); this.context.calendar.unregisterInteractiveComponent(this); }; SimpleDayGrid.prototype.render = function (props, context) { var dayGrid = this.dayGrid; var dateProfile = props.dateProfile, dayTable = props.dayTable; dayGrid.receiveProps(__assign({}, this.slicer.sliceProps(props, dateProfile, props.nextDayThreshold, context.calendar, dayGrid, dayTable), { dateProfile: dateProfile, cells: dayTable.cells, isRigid: props.isRigid }), context); }; SimpleDayGrid.prototype.buildPositionCaches = function () { this.dayGrid.buildPositionCaches(); }; SimpleDayGrid.prototype.queryHit = function (positionLeft, positionTop) { var rawHit = this.dayGrid.positionToHit(positionLeft, positionTop); if (rawHit) { return { component: this.dayGrid, dateSpan: rawHit.dateSpan, dayEl: rawHit.dayEl, rect: { left: rawHit.relativeRect.left, right: rawHit.relativeRect.right, top: rawHit.relativeRect.top, bottom: rawHit.relativeRect.bottom }, layer: 0 }; } }; return SimpleDayGrid; }(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["DateComponent"])); var DayGridSlicer = /** @class */ (function (_super) { __extends(DayGridSlicer, _super); function DayGridSlicer() { return _super !== null && _super.apply(this, arguments) || this; } DayGridSlicer.prototype.sliceRange = function (dateRange, dayTable) { return dayTable.sliceRange(dateRange); }; return DayGridSlicer; }(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["Slicer"])); var DayGridView = /** @class */ (function (_super) { __extends(DayGridView, _super); function DayGridView() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.buildDayTable = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["memoize"])(buildDayTable); return _this; } DayGridView.prototype.render = function (props, context) { _super.prototype.render.call(this, props, context); // will call _renderSkeleton/_unrenderSkeleton var dateProfile = this.props.dateProfile; var dayTable = this.dayTable = this.buildDayTable(dateProfile, props.dateProfileGenerator); if (this.header) { this.header.receiveProps({ dateProfile: dateProfile, dates: dayTable.headerDates, datesRepDistinctDays: dayTable.rowCnt === 1, renderIntroHtml: this.renderHeadIntroHtml }, context); } this.simpleDayGrid.receiveProps({ dateProfile: dateProfile, dayTable: dayTable, businessHours: props.businessHours, dateSelection: props.dateSelection, eventStore: props.eventStore, eventUiBases: props.eventUiBases, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, isRigid: this.hasRigidRows(), nextDayThreshold: this.context.nextDayThreshold }, context); }; DayGridView.prototype._renderSkeleton = function (context) { _super.prototype._renderSkeleton.call(this, context); if (context.options.columnHeader) { this.header = new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["DayHeader"](this.el.querySelector('.fc-head-container')); } this.simpleDayGrid = new SimpleDayGrid(this.dayGrid); }; DayGridView.prototype._unrenderSkeleton = function () { _super.prototype._unrenderSkeleton.call(this); if (this.header) { this.header.destroy(); } this.simpleDayGrid.destroy(); }; return DayGridView; }(AbstractDayGridView)); function buildDayTable(dateProfile, dateProfileGenerator) { var daySeries = new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["DaySeries"](dateProfile.renderRange, dateProfileGenerator); return new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["DayTable"](daySeries, /year|month|week/.test(dateProfile.currentRangeUnit)); } var main = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createPlugin"])({ defaultView: 'dayGridMonth', views: { dayGrid: DayGridView, dayGridDay: { type: 'dayGrid', duration: { days: 1 } }, dayGridWeek: { type: 'dayGrid', duration: { weeks: 1 } }, dayGridMonth: { type: 'dayGrid', duration: { months: 1 }, monthMode: true, fixedWeekCount: true } } }); /* harmony default export */ __webpack_exports__["default"] = (main); /***/ }), /***/ "./node_modules/@fullcalendar/interaction/main.esm.js": /*!************************************************************!*\ !*** ./node_modules/@fullcalendar/interaction/main.esm.js ***! \************************************************************/ /*! exports provided: default, Draggable, FeaturefulElementDragging, PointerDragging, ThirdPartyDraggable */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Draggable", function() { return ExternalDraggable; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FeaturefulElementDragging", function() { return FeaturefulElementDragging; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointerDragging", function() { return PointerDragging; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ThirdPartyDraggable", function() { return ThirdPartyDraggable; }); /* harmony import */ var _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @fullcalendar/core */ "./node_modules/@fullcalendar/core/main.esm.js"); /*! FullCalendar Interaction Plugin v4.4.0 Docs & License: https://fullcalendar.io/ (c) 2019 Adam Shaw */ /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["config"].touchMouseIgnoreWait = 500; var ignoreMouseDepth = 0; var listenerCnt = 0; var isWindowTouchMoveCancelled = false; /* Uses a "pointer" abstraction, which monitors UI events for both mouse and touch. Tracks when the pointer "drags" on a certain element, meaning down+move+up. Also, tracks if there was touch-scrolling. Also, can prevent touch-scrolling from happening. Also, can fire pointermove events when scrolling happens underneath, even when no real pointer movement. emits: - pointerdown - pointermove - pointerup */ var PointerDragging = /** @class */ (function () { function PointerDragging(containerEl) { var _this = this; this.subjectEl = null; this.downEl = null; // options that can be directly assigned by caller this.selector = ''; // will cause subjectEl in all emitted events to be this element this.handleSelector = ''; this.shouldIgnoreMove = false; this.shouldWatchScroll = true; // for simulating pointermove on scroll // internal states this.isDragging = false; this.isTouchDragging = false; this.wasTouchScroll = false; // Mouse // ---------------------------------------------------------------------------------------------------- this.handleMouseDown = function (ev) { if (!_this.shouldIgnoreMouse() && isPrimaryMouseButton(ev) && _this.tryStart(ev)) { var pev = _this.createEventFromMouse(ev, true); _this.emitter.trigger('pointerdown', pev); _this.initScrollWatch(pev); if (!_this.shouldIgnoreMove) { document.addEventListener('mousemove', _this.handleMouseMove); } document.addEventListener('mouseup', _this.handleMouseUp); } }; this.handleMouseMove = function (ev) { var pev = _this.createEventFromMouse(ev); _this.recordCoords(pev); _this.emitter.trigger('pointermove', pev); }; this.handleMouseUp = function (ev) { document.removeEventListener('mousemove', _this.handleMouseMove); document.removeEventListener('mouseup', _this.handleMouseUp); _this.emitter.trigger('pointerup', _this.createEventFromMouse(ev)); _this.cleanup(); // call last so that pointerup has access to props }; // Touch // ---------------------------------------------------------------------------------------------------- this.handleTouchStart = function (ev) { if (_this.tryStart(ev)) { _this.isTouchDragging = true; var pev = _this.createEventFromTouch(ev, true); _this.emitter.trigger('pointerdown', pev); _this.initScrollWatch(pev); // unlike mouse, need to attach to target, not document // https://stackoverflow.com/a/45760014 var target = ev.target; if (!_this.shouldIgnoreMove) { target.addEventListener('touchmove', _this.handleTouchMove); } target.addEventListener('touchend', _this.handleTouchEnd); target.addEventListener('touchcancel', _this.handleTouchEnd); // treat it as a touch end // attach a handler to get called when ANY scroll action happens on the page. // this was impossible to do with normal on/off because 'scroll' doesn't bubble. // http://stackoverflow.com/a/32954565/96342 window.addEventListener('scroll', _this.handleTouchScroll, true // useCapture ); } }; this.handleTouchMove = function (ev) { var pev = _this.createEventFromTouch(ev); _this.recordCoords(pev); _this.emitter.trigger('pointermove', pev); }; this.handleTouchEnd = function (ev) { if (_this.isDragging) { // done to guard against touchend followed by touchcancel var target = ev.target; target.removeEventListener('touchmove', _this.handleTouchMove); target.removeEventListener('touchend', _this.handleTouchEnd); target.removeEventListener('touchcancel', _this.handleTouchEnd); window.removeEventListener('scroll', _this.handleTouchScroll, true); // useCaptured=true _this.emitter.trigger('pointerup', _this.createEventFromTouch(ev)); _this.cleanup(); // call last so that pointerup has access to props _this.isTouchDragging = false; startIgnoringMouse(); } }; this.handleTouchScroll = function () { _this.wasTouchScroll = true; }; this.handleScroll = function (ev) { if (!_this.shouldIgnoreMove) { var pageX = (window.pageXOffset - _this.prevScrollX) + _this.prevPageX; var pageY = (window.pageYOffset - _this.prevScrollY) + _this.prevPageY; _this.emitter.trigger('pointermove', { origEvent: ev, isTouch: _this.isTouchDragging, subjectEl: _this.subjectEl, pageX: pageX, pageY: pageY, deltaX: pageX - _this.origPageX, deltaY: pageY - _this.origPageY }); } }; this.containerEl = containerEl; this.emitter = new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["EmitterMixin"](); containerEl.addEventListener('mousedown', this.handleMouseDown); containerEl.addEventListener('touchstart', this.handleTouchStart, { passive: true }); listenerCreated(); } PointerDragging.prototype.destroy = function () { this.containerEl.removeEventListener('mousedown', this.handleMouseDown); this.containerEl.removeEventListener('touchstart', this.handleTouchStart, { passive: true }); listenerDestroyed(); }; PointerDragging.prototype.tryStart = function (ev) { var subjectEl = this.querySubjectEl(ev); var downEl = ev.target; if (subjectEl && (!this.handleSelector || Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["elementClosest"])(downEl, this.handleSelector))) { this.subjectEl = subjectEl; this.downEl = downEl; this.isDragging = true; // do this first so cancelTouchScroll will work this.wasTouchScroll = false; return true; } return false; }; PointerDragging.prototype.cleanup = function () { isWindowTouchMoveCancelled = false; this.isDragging = false; this.subjectEl = null; this.downEl = null; // keep wasTouchScroll around for later access this.destroyScrollWatch(); }; PointerDragging.prototype.querySubjectEl = function (ev) { if (this.selector) { return Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["elementClosest"])(ev.target, this.selector); } else { return this.containerEl; } }; PointerDragging.prototype.shouldIgnoreMouse = function () { return ignoreMouseDepth || this.isTouchDragging; }; // can be called by user of this class, to cancel touch-based scrolling for the current drag PointerDragging.prototype.cancelTouchScroll = function () { if (this.isDragging) { isWindowTouchMoveCancelled = true; } }; // Scrolling that simulates pointermoves // ---------------------------------------------------------------------------------------------------- PointerDragging.prototype.initScrollWatch = function (ev) { if (this.shouldWatchScroll) { this.recordCoords(ev); window.addEventListener('scroll', this.handleScroll, true); // useCapture=true } }; PointerDragging.prototype.recordCoords = function (ev) { if (this.shouldWatchScroll) { this.prevPageX = ev.pageX; this.prevPageY = ev.pageY; this.prevScrollX = window.pageXOffset; this.prevScrollY = window.pageYOffset; } }; PointerDragging.prototype.destroyScrollWatch = function () { if (this.shouldWatchScroll) { window.removeEventListener('scroll', this.handleScroll, true); // useCaptured=true } }; // Event Normalization // ---------------------------------------------------------------------------------------------------- PointerDragging.prototype.createEventFromMouse = function (ev, isFirst) { var deltaX = 0; var deltaY = 0; // TODO: repeat code if (isFirst) { this.origPageX = ev.pageX; this.origPageY = ev.pageY; } else { deltaX = ev.pageX - this.origPageX; deltaY = ev.pageY - this.origPageY; } return { origEvent: ev, isTouch: false, subjectEl: this.subjectEl, pageX: ev.pageX, pageY: ev.pageY, deltaX: deltaX, deltaY: deltaY }; }; PointerDragging.prototype.createEventFromTouch = function (ev, isFirst) { var touches = ev.touches; var pageX; var pageY; var deltaX = 0; var deltaY = 0; // if touch coords available, prefer, // because FF would give bad ev.pageX ev.pageY if (touches && touches.length) { pageX = touches[0].pageX; pageY = touches[0].pageY; } else { pageX = ev.pageX; pageY = ev.pageY; } // TODO: repeat code if (isFirst) { this.origPageX = pageX; this.origPageY = pageY; } else { deltaX = pageX - this.origPageX; deltaY = pageY - this.origPageY; } return { origEvent: ev, isTouch: true, subjectEl: this.subjectEl, pageX: pageX, pageY: pageY, deltaX: deltaX, deltaY: deltaY }; }; return PointerDragging; }()); // Returns a boolean whether this was a left mouse click and no ctrl key (which means right click on Mac) function isPrimaryMouseButton(ev) { return ev.button === 0 && !ev.ctrlKey; } // Ignoring fake mouse events generated by touch // ---------------------------------------------------------------------------------------------------- function startIgnoringMouse() { ignoreMouseDepth++; setTimeout(function () { ignoreMouseDepth--; }, _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["config"].touchMouseIgnoreWait); } // We want to attach touchmove as early as possible for Safari // ---------------------------------------------------------------------------------------------------- function listenerCreated() { if (!(listenerCnt++)) { window.addEventListener('touchmove', onWindowTouchMove, { passive: false }); } } function listenerDestroyed() { if (!(--listenerCnt)) { window.removeEventListener('touchmove', onWindowTouchMove, { passive: false }); } } function onWindowTouchMove(ev) { if (isWindowTouchMoveCancelled) { ev.preventDefault(); } } /* An effect in which an element follows the movement of a pointer across the screen. The moving element is a clone of some other element. Must call start + handleMove + stop. */ var ElementMirror = /** @class */ (function () { function ElementMirror() { this.isVisible = false; // must be explicitly enabled this.sourceEl = null; this.mirrorEl = null; this.sourceElRect = null; // screen coords relative to viewport // options that can be set directly by caller this.parentNode = document.body; this.zIndex = 9999; this.revertDuration = 0; } ElementMirror.prototype.start = function (sourceEl, pageX, pageY) { this.sourceEl = sourceEl; this.sourceElRect = this.sourceEl.getBoundingClientRect(); this.origScreenX = pageX - window.pageXOffset; this.origScreenY = pageY - window.pageYOffset; this.deltaX = 0; this.deltaY = 0; this.updateElPosition(); }; ElementMirror.prototype.handleMove = function (pageX, pageY) { this.deltaX = (pageX - window.pageXOffset) - this.origScreenX; this.deltaY = (pageY - window.pageYOffset) - this.origScreenY; this.updateElPosition(); }; // can be called before start ElementMirror.prototype.setIsVisible = function (bool) { if (bool) { if (!this.isVisible) { if (this.mirrorEl) { this.mirrorEl.style.display = ''; } this.isVisible = bool; // needs to happen before updateElPosition this.updateElPosition(); // because was not updating the position while invisible } } else { if (this.isVisible) { if (this.mirrorEl) { this.mirrorEl.style.display = 'none'; } this.isVisible = bool; } } }; // always async ElementMirror.prototype.stop = function (needsRevertAnimation, callback) { var _this = this; var done = function () { _this.cleanup(); callback(); }; if (needsRevertAnimation && this.mirrorEl && this.isVisible && this.revertDuration && // if 0, transition won't work (this.deltaX || this.deltaY) // if same coords, transition won't work ) { this.doRevertAnimation(done, this.revertDuration); } else { setTimeout(done, 0); } }; ElementMirror.prototype.doRevertAnimation = function (callback, revertDuration) { var mirrorEl = this.mirrorEl; var finalSourceElRect = this.sourceEl.getBoundingClientRect(); // because autoscrolling might have happened mirrorEl.style.transition = 'top ' + revertDuration + 'ms,' + 'left ' + revertDuration + 'ms'; Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["applyStyle"])(mirrorEl, { left: finalSourceElRect.left, top: finalSourceElRect.top }); Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["whenTransitionDone"])(mirrorEl, function () { mirrorEl.style.transition = ''; callback(); }); }; ElementMirror.prototype.cleanup = function () { if (this.mirrorEl) { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["removeElement"])(this.mirrorEl); this.mirrorEl = null; } this.sourceEl = null; }; ElementMirror.prototype.updateElPosition = function () { if (this.sourceEl && this.isVisible) { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["applyStyle"])(this.getMirrorEl(), { left: this.sourceElRect.left + this.deltaX, top: this.sourceElRect.top + this.deltaY }); } }; ElementMirror.prototype.getMirrorEl = function () { var sourceElRect = this.sourceElRect; var mirrorEl = this.mirrorEl; if (!mirrorEl) { mirrorEl = this.mirrorEl = this.sourceEl.cloneNode(true); // cloneChildren=true // we don't want long taps or any mouse interaction causing selection/menus. // would use preventSelection(), but that prevents selectstart, causing problems. mirrorEl.classList.add('fc-unselectable'); mirrorEl.classList.add('fc-dragging'); Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["applyStyle"])(mirrorEl, { position: 'fixed', zIndex: this.zIndex, visibility: '', boxSizing: 'border-box', width: sourceElRect.right - sourceElRect.left, height: sourceElRect.bottom - sourceElRect.top, right: 'auto', bottom: 'auto', margin: 0 }); this.parentNode.appendChild(mirrorEl); } return mirrorEl; }; return ElementMirror; }()); /* Is a cache for a given element's scroll information (all the info that ScrollController stores) in addition the "client rectangle" of the element.. the area within the scrollbars. The cache can be in one of two modes: - doesListening:false - ignores when the container is scrolled by someone else - doesListening:true - watch for scrolling and update the cache */ var ScrollGeomCache = /** @class */ (function (_super) { __extends(ScrollGeomCache, _super); function ScrollGeomCache(scrollController, doesListening) { var _this = _super.call(this) || this; _this.handleScroll = function () { _this.scrollTop = _this.scrollController.getScrollTop(); _this.scrollLeft = _this.scrollController.getScrollLeft(); _this.handleScrollChange(); }; _this.scrollController = scrollController; _this.doesListening = doesListening; _this.scrollTop = _this.origScrollTop = scrollController.getScrollTop(); _this.scrollLeft = _this.origScrollLeft = scrollController.getScrollLeft(); _this.scrollWidth = scrollController.getScrollWidth(); _this.scrollHeight = scrollController.getScrollHeight(); _this.clientWidth = scrollController.getClientWidth(); _this.clientHeight = scrollController.getClientHeight(); _this.clientRect = _this.computeClientRect(); // do last in case it needs cached values if (_this.doesListening) { _this.getEventTarget().addEventListener('scroll', _this.handleScroll); } return _this; } ScrollGeomCache.prototype.destroy = function () { if (this.doesListening) { this.getEventTarget().removeEventListener('scroll', this.handleScroll); } }; ScrollGeomCache.prototype.getScrollTop = function () { return this.scrollTop; }; ScrollGeomCache.prototype.getScrollLeft = function () { return this.scrollLeft; }; ScrollGeomCache.prototype.setScrollTop = function (top) { this.scrollController.setScrollTop(top); if (!this.doesListening) { // we are not relying on the element to normalize out-of-bounds scroll values // so we need to sanitize ourselves this.scrollTop = Math.max(Math.min(top, this.getMaxScrollTop()), 0); this.handleScrollChange(); } }; ScrollGeomCache.prototype.setScrollLeft = function (top) { this.scrollController.setScrollLeft(top); if (!this.doesListening) { // we are not relying on the element to normalize out-of-bounds scroll values // so we need to sanitize ourselves this.scrollLeft = Math.max(Math.min(top, this.getMaxScrollLeft()), 0); this.handleScrollChange(); } }; ScrollGeomCache.prototype.getClientWidth = function () { return this.clientWidth; }; ScrollGeomCache.prototype.getClientHeight = function () { return this.clientHeight; }; ScrollGeomCache.prototype.getScrollWidth = function () { return this.scrollWidth; }; ScrollGeomCache.prototype.getScrollHeight = function () { return this.scrollHeight; }; ScrollGeomCache.prototype.handleScrollChange = function () { }; return ScrollGeomCache; }(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["ScrollController"])); var ElementScrollGeomCache = /** @class */ (function (_super) { __extends(ElementScrollGeomCache, _super); function ElementScrollGeomCache(el, doesListening) { return _super.call(this, new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["ElementScrollController"](el), doesListening) || this; } ElementScrollGeomCache.prototype.getEventTarget = function () { return this.scrollController.el; }; ElementScrollGeomCache.prototype.computeClientRect = function () { return Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["computeInnerRect"])(this.scrollController.el); }; return ElementScrollGeomCache; }(ScrollGeomCache)); var WindowScrollGeomCache = /** @class */ (function (_super) { __extends(WindowScrollGeomCache, _super); function WindowScrollGeomCache(doesListening) { return _super.call(this, new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["WindowScrollController"](), doesListening) || this; } WindowScrollGeomCache.prototype.getEventTarget = function () { return window; }; WindowScrollGeomCache.prototype.computeClientRect = function () { return { left: this.scrollLeft, right: this.scrollLeft + this.clientWidth, top: this.scrollTop, bottom: this.scrollTop + this.clientHeight }; }; // the window is the only scroll object that changes it's rectangle relative // to the document's topleft as it scrolls WindowScrollGeomCache.prototype.handleScrollChange = function () { this.clientRect = this.computeClientRect(); }; return WindowScrollGeomCache; }(ScrollGeomCache)); // If available we are using native "performance" API instead of "Date" // Read more about it on MDN: // https://developer.mozilla.org/en-US/docs/Web/API/Performance var getTime = typeof performance === 'function' ? performance.now : Date.now; /* For a pointer interaction, automatically scrolls certain scroll containers when the pointer approaches the edge. The caller must call start + handleMove + stop. */ var AutoScroller = /** @class */ (function () { function AutoScroller() { var _this = this; // options that can be set by caller this.isEnabled = true; this.scrollQuery = [window, '.fc-scroller']; this.edgeThreshold = 50; // pixels this.maxVelocity = 300; // pixels per second // internal state this.pointerScreenX = null; this.pointerScreenY = null; this.isAnimating = false; this.scrollCaches = null; // protect against the initial pointerdown being too close to an edge and starting the scroll this.everMovedUp = false; this.everMovedDown = false; this.everMovedLeft = false; this.everMovedRight = false; this.animate = function () { if (_this.isAnimating) { // wasn't cancelled between animation calls var edge = _this.computeBestEdge(_this.pointerScreenX + window.pageXOffset, _this.pointerScreenY + window.pageYOffset); if (edge) { var now = getTime(); _this.handleSide(edge, (now - _this.msSinceRequest) / 1000); _this.requestAnimation(now); } else { _this.isAnimating = false; // will stop animation } } }; } AutoScroller.prototype.start = function (pageX, pageY) { if (this.isEnabled) { this.scrollCaches = this.buildCaches(); this.pointerScreenX = null; this.pointerScreenY = null; this.everMovedUp = false; this.everMovedDown = false; this.everMovedLeft = false; this.everMovedRight = false; this.handleMove(pageX, pageY); } }; AutoScroller.prototype.handleMove = function (pageX, pageY) { if (this.isEnabled) { var pointerScreenX = pageX - window.pageXOffset; var pointerScreenY = pageY - window.pageYOffset; var yDelta = this.pointerScreenY === null ? 0 : pointerScreenY - this.pointerScreenY; var xDelta = this.pointerScreenX === null ? 0 : pointerScreenX - this.pointerScreenX; if (yDelta < 0) { this.everMovedUp = true; } else if (yDelta > 0) { this.everMovedDown = true; } if (xDelta < 0) { this.everMovedLeft = true; } else if (xDelta > 0) { this.everMovedRight = true; } this.pointerScreenX = pointerScreenX; this.pointerScreenY = pointerScreenY; if (!this.isAnimating) { this.isAnimating = true; this.requestAnimation(getTime()); } } }; AutoScroller.prototype.stop = function () { if (this.isEnabled) { this.isAnimating = false; // will stop animation for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { var scrollCache = _a[_i]; scrollCache.destroy(); } this.scrollCaches = null; } }; AutoScroller.prototype.requestAnimation = function (now) { this.msSinceRequest = now; requestAnimationFrame(this.animate); }; AutoScroller.prototype.handleSide = function (edge, seconds) { var scrollCache = edge.scrollCache; var edgeThreshold = this.edgeThreshold; var invDistance = edgeThreshold - edge.distance; var velocity = // the closer to the edge, the faster we scroll (invDistance * invDistance) / (edgeThreshold * edgeThreshold) * // quadratic this.maxVelocity * seconds; var sign = 1; switch (edge.name) { case 'left': sign = -1; // falls through case 'right': scrollCache.setScrollLeft(scrollCache.getScrollLeft() + velocity * sign); break; case 'top': sign = -1; // falls through case 'bottom': scrollCache.setScrollTop(scrollCache.getScrollTop() + velocity * sign); break; } }; // left/top are relative to document topleft AutoScroller.prototype.computeBestEdge = function (left, top) { var edgeThreshold = this.edgeThreshold; var bestSide = null; for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { var scrollCache = _a[_i]; var rect = scrollCache.clientRect; var leftDist = left - rect.left; var rightDist = rect.right - left; var topDist = top - rect.top; var bottomDist = rect.bottom - top; // completely within the rect? if (leftDist >= 0 && rightDist >= 0 && topDist >= 0 && bottomDist >= 0) { if (topDist <= edgeThreshold && this.everMovedUp && scrollCache.canScrollUp() && (!bestSide || bestSide.distance > topDist)) { bestSide = { scrollCache: scrollCache, name: 'top', distance: topDist }; } if (bottomDist <= edgeThreshold && this.everMovedDown && scrollCache.canScrollDown() && (!bestSide || bestSide.distance > bottomDist)) { bestSide = { scrollCache: scrollCache, name: 'bottom', distance: bottomDist }; } if (leftDist <= edgeThreshold && this.everMovedLeft && scrollCache.canScrollLeft() && (!bestSide || bestSide.distance > leftDist)) { bestSide = { scrollCache: scrollCache, name: 'left', distance: leftDist }; } if (rightDist <= edgeThreshold && this.everMovedRight && scrollCache.canScrollRight() && (!bestSide || bestSide.distance > rightDist)) { bestSide = { scrollCache: scrollCache, name: 'right', distance: rightDist }; } } } return bestSide; }; AutoScroller.prototype.buildCaches = function () { return this.queryScrollEls().map(function (el) { if (el === window) { return new WindowScrollGeomCache(false); // false = don't listen to user-generated scrolls } else { return new ElementScrollGeomCache(el, false); // false = don't listen to user-generated scrolls } }); }; AutoScroller.prototype.queryScrollEls = function () { var els = []; for (var _i = 0, _a = this.scrollQuery; _i < _a.length; _i++) { var query = _a[_i]; if (typeof query === 'object') { els.push(query); } else { els.push.apply(els, Array.prototype.slice.call(document.querySelectorAll(query))); } } return els; }; return AutoScroller; }()); /* Monitors dragging on an element. Has a number of high-level features: - minimum distance required before dragging - minimum wait time ("delay") before dragging - a mirror element that follows the pointer */ var FeaturefulElementDragging = /** @class */ (function (_super) { __extends(FeaturefulElementDragging, _super); function FeaturefulElementDragging(containerEl) { var _this = _super.call(this, containerEl) || this; // options that can be directly set by caller // the caller can also set the PointerDragging's options as well _this.delay = null; _this.minDistance = 0; _this.touchScrollAllowed = true; // prevents drag from starting and blocks scrolling during drag _this.mirrorNeedsRevert = false; _this.isInteracting = false; // is the user validly moving the pointer? lasts until pointerup _this.isDragging = false; // is it INTENTFULLY dragging? lasts until after revert animation _this.isDelayEnded = false; _this.isDistanceSurpassed = false; _this.delayTimeoutId = null; _this.onPointerDown = function (ev) { if (!_this.isDragging) { // so new drag doesn't happen while revert animation is going _this.isInteracting = true; _this.isDelayEnded = false; _this.isDistanceSurpassed = false; Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["preventSelection"])(document.body); Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["preventContextMenu"])(document.body); // prevent links from being visited if there's an eventual drag. // also prevents selection in older browsers (maybe?). // not necessary for touch, besides, browser would complain about passiveness. if (!ev.isTouch) { ev.origEvent.preventDefault(); } _this.emitter.trigger('pointerdown', ev); if (!_this.pointer.shouldIgnoreMove) { // actions related to initiating dragstart+dragmove+dragend... _this.mirror.setIsVisible(false); // reset. caller must set-visible _this.mirror.start(ev.subjectEl, ev.pageX, ev.pageY); // must happen on first pointer down _this.startDelay(ev); if (!_this.minDistance) { _this.handleDistanceSurpassed(ev); } } } }; _this.onPointerMove = function (ev) { if (_this.isInteracting) { // if false, still waiting for previous drag's revert _this.emitter.trigger('pointermove', ev); if (!_this.isDistanceSurpassed) { var minDistance = _this.minDistance; var distanceSq = void 0; // current distance from the origin, squared var deltaX = ev.deltaX, deltaY = ev.deltaY; distanceSq = deltaX * deltaX + deltaY * deltaY; if (distanceSq >= minDistance * minDistance) { // use pythagorean theorem _this.handleDistanceSurpassed(ev); } } if (_this.isDragging) { // a real pointer move? (not one simulated by scrolling) if (ev.origEvent.type !== 'scroll') { _this.mirror.handleMove(ev.pageX, ev.pageY); _this.autoScroller.handleMove(ev.pageX, ev.pageY); } _this.emitter.trigger('dragmove', ev); } } }; _this.onPointerUp = function (ev) { if (_this.isInteracting) { // if false, still waiting for previous drag's revert _this.isInteracting = false; Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["allowSelection"])(document.body); Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["allowContextMenu"])(document.body); _this.emitter.trigger('pointerup', ev); // can potentially set mirrorNeedsRevert if (_this.isDragging) { _this.autoScroller.stop(); _this.tryStopDrag(ev); // which will stop the mirror } if (_this.delayTimeoutId) { clearTimeout(_this.delayTimeoutId); _this.delayTimeoutId = null; } } }; var pointer = _this.pointer = new PointerDragging(containerEl); pointer.emitter.on('pointerdown', _this.onPointerDown); pointer.emitter.on('pointermove', _this.onPointerMove); pointer.emitter.on('pointerup', _this.onPointerUp); _this.mirror = new ElementMirror(); _this.autoScroller = new AutoScroller(); return _this; } FeaturefulElementDragging.prototype.destroy = function () { this.pointer.destroy(); }; FeaturefulElementDragging.prototype.startDelay = function (ev) { var _this = this; if (typeof this.delay === 'number') { this.delayTimeoutId = setTimeout(function () { _this.delayTimeoutId = null; _this.handleDelayEnd(ev); }, this.delay); // not assignable to number! } else { this.handleDelayEnd(ev); } }; FeaturefulElementDragging.prototype.handleDelayEnd = function (ev) { this.isDelayEnded = true; this.tryStartDrag(ev); }; FeaturefulElementDragging.prototype.handleDistanceSurpassed = function (ev) { this.isDistanceSurpassed = true; this.tryStartDrag(ev); }; FeaturefulElementDragging.prototype.tryStartDrag = function (ev) { if (this.isDelayEnded && this.isDistanceSurpassed) { if (!this.pointer.wasTouchScroll || this.touchScrollAllowed) { this.isDragging = true; this.mirrorNeedsRevert = false; this.autoScroller.start(ev.pageX, ev.pageY); this.emitter.trigger('dragstart', ev); if (this.touchScrollAllowed === false) { this.pointer.cancelTouchScroll(); } } } }; FeaturefulElementDragging.prototype.tryStopDrag = function (ev) { // .stop() is ALWAYS asynchronous, which we NEED because we want all pointerup events // that come from the document to fire beforehand. much more convenient this way. this.mirror.stop(this.mirrorNeedsRevert, this.stopDrag.bind(this, ev) // bound with args ); }; FeaturefulElementDragging.prototype.stopDrag = function (ev) { this.isDragging = false; this.emitter.trigger('dragend', ev); }; // fill in the implementations... FeaturefulElementDragging.prototype.setIgnoreMove = function (bool) { this.pointer.shouldIgnoreMove = bool; }; FeaturefulElementDragging.prototype.setMirrorIsVisible = function (bool) { this.mirror.setIsVisible(bool); }; FeaturefulElementDragging.prototype.setMirrorNeedsRevert = function (bool) { this.mirrorNeedsRevert = bool; }; FeaturefulElementDragging.prototype.setAutoScrollEnabled = function (bool) { this.autoScroller.isEnabled = bool; }; return FeaturefulElementDragging; }(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["ElementDragging"])); /* When this class is instantiated, it records the offset of an element (relative to the document topleft), and continues to monitor scrolling, updating the cached coordinates if it needs to. Does not access the DOM after instantiation, so highly performant. Also keeps track of all scrolling/overflow:hidden containers that are parents of the given element and an determine if a given point is inside the combined clipping rectangle. */ var OffsetTracker = /** @class */ (function () { function OffsetTracker(el) { this.origRect = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["computeRect"])(el); // will work fine for divs that have overflow:hidden this.scrollCaches = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["getClippingParents"])(el).map(function (el) { return new ElementScrollGeomCache(el, true); // listen=true }); } OffsetTracker.prototype.destroy = function () { for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { var scrollCache = _a[_i]; scrollCache.destroy(); } }; OffsetTracker.prototype.computeLeft = function () { var left = this.origRect.left; for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { var scrollCache = _a[_i]; left += scrollCache.origScrollLeft - scrollCache.getScrollLeft(); } return left; }; OffsetTracker.prototype.computeTop = function () { var top = this.origRect.top; for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { var scrollCache = _a[_i]; top += scrollCache.origScrollTop - scrollCache.getScrollTop(); } return top; }; OffsetTracker.prototype.isWithinClipping = function (pageX, pageY) { var point = { left: pageX, top: pageY }; for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { var scrollCache = _a[_i]; if (!isIgnoredClipping(scrollCache.getEventTarget()) && !Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["pointInsideRect"])(point, scrollCache.clientRect)) { return false; } } return true; }; return OffsetTracker; }()); // certain clipping containers should never constrain interactions, like and // https://github.com/fullcalendar/fullcalendar/issues/3615 function isIgnoredClipping(node) { var tagName = node.tagName; return tagName === 'HTML' || tagName === 'BODY'; } /* Tracks movement over multiple droppable areas (aka "hits") that exist in one or more DateComponents. Relies on an existing draggable. emits: - pointerdown - dragstart - hitchange - fires initially, even if not over a hit - pointerup - (hitchange - again, to null, if ended over a hit) - dragend */ var HitDragging = /** @class */ (function () { function HitDragging(dragging, droppableStore) { var _this = this; // options that can be set by caller this.useSubjectCenter = false; this.requireInitial = true; // if doesn't start out on a hit, won't emit any events this.initialHit = null; this.movingHit = null; this.finalHit = null; // won't ever be populated if shouldIgnoreMove this.handlePointerDown = function (ev) { var dragging = _this.dragging; _this.initialHit = null; _this.movingHit = null; _this.finalHit = null; _this.prepareHits(); _this.processFirstCoord(ev); if (_this.initialHit || !_this.requireInitial) { dragging.setIgnoreMove(false); _this.emitter.trigger('pointerdown', ev); // TODO: fire this before computing processFirstCoord, so listeners can cancel. this gets fired by almost every handler :( } else { dragging.setIgnoreMove(true); } }; this.handleDragStart = function (ev) { _this.emitter.trigger('dragstart', ev); _this.handleMove(ev, true); // force = fire even if initially null }; this.handleDragMove = function (ev) { _this.emitter.trigger('dragmove', ev); _this.handleMove(ev); }; this.handlePointerUp = function (ev) { _this.releaseHits(); _this.emitter.trigger('pointerup', ev); }; this.handleDragEnd = function (ev) { if (_this.movingHit) { _this.emitter.trigger('hitupdate', null, true, ev); } _this.finalHit = _this.movingHit; _this.movingHit = null; _this.emitter.trigger('dragend', ev); }; this.droppableStore = droppableStore; dragging.emitter.on('pointerdown', this.handlePointerDown); dragging.emitter.on('dragstart', this.handleDragStart); dragging.emitter.on('dragmove', this.handleDragMove); dragging.emitter.on('pointerup', this.handlePointerUp); dragging.emitter.on('dragend', this.handleDragEnd); this.dragging = dragging; this.emitter = new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["EmitterMixin"](); } // sets initialHit // sets coordAdjust HitDragging.prototype.processFirstCoord = function (ev) { var origPoint = { left: ev.pageX, top: ev.pageY }; var adjustedPoint = origPoint; var subjectEl = ev.subjectEl; var subjectRect; if (subjectEl !== document) { subjectRect = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["computeRect"])(subjectEl); adjustedPoint = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["constrainPoint"])(adjustedPoint, subjectRect); } var initialHit = this.initialHit = this.queryHitForOffset(adjustedPoint.left, adjustedPoint.top); if (initialHit) { if (this.useSubjectCenter && subjectRect) { var slicedSubjectRect = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["intersectRects"])(subjectRect, initialHit.rect); if (slicedSubjectRect) { adjustedPoint = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["getRectCenter"])(slicedSubjectRect); } } this.coordAdjust = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["diffPoints"])(adjustedPoint, origPoint); } else { this.coordAdjust = { left: 0, top: 0 }; } }; HitDragging.prototype.handleMove = function (ev, forceHandle) { var hit = this.queryHitForOffset(ev.pageX + this.coordAdjust.left, ev.pageY + this.coordAdjust.top); if (forceHandle || !isHitsEqual(this.movingHit, hit)) { this.movingHit = hit; this.emitter.trigger('hitupdate', hit, false, ev); } }; HitDragging.prototype.prepareHits = function () { this.offsetTrackers = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["mapHash"])(this.droppableStore, function (interactionSettings) { interactionSettings.component.buildPositionCaches(); return new OffsetTracker(interactionSettings.el); }); }; HitDragging.prototype.releaseHits = function () { var offsetTrackers = this.offsetTrackers; for (var id in offsetTrackers) { offsetTrackers[id].destroy(); } this.offsetTrackers = {}; }; HitDragging.prototype.queryHitForOffset = function (offsetLeft, offsetTop) { var _a = this, droppableStore = _a.droppableStore, offsetTrackers = _a.offsetTrackers; var bestHit = null; for (var id in droppableStore) { var component = droppableStore[id].component; var offsetTracker = offsetTrackers[id]; if (offsetTracker.isWithinClipping(offsetLeft, offsetTop)) { var originLeft = offsetTracker.computeLeft(); var originTop = offsetTracker.computeTop(); var positionLeft = offsetLeft - originLeft; var positionTop = offsetTop - originTop; var origRect = offsetTracker.origRect; var width = origRect.right - origRect.left; var height = origRect.bottom - origRect.top; if ( // must be within the element's bounds positionLeft >= 0 && positionLeft < width && positionTop >= 0 && positionTop < height) { var hit = component.queryHit(positionLeft, positionTop, width, height); if (hit && ( // make sure the hit is within activeRange, meaning it's not a deal cell !component.props.dateProfile || // hack for DayTile Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["rangeContainsRange"])(component.props.dateProfile.activeRange, hit.dateSpan.range)) && (!bestHit || hit.layer > bestHit.layer)) { // TODO: better way to re-orient rectangle hit.rect.left += originLeft; hit.rect.right += originLeft; hit.rect.top += originTop; hit.rect.bottom += originTop; bestHit = hit; } } } } return bestHit; }; return HitDragging; }()); function isHitsEqual(hit0, hit1) { if (!hit0 && !hit1) { return true; } if (Boolean(hit0) !== Boolean(hit1)) { return false; } return Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["isDateSpansEqual"])(hit0.dateSpan, hit1.dateSpan); } /* Monitors when the user clicks on a specific date/time of a component. A pointerdown+pointerup on the same "hit" constitutes a click. */ var DateClicking = /** @class */ (function (_super) { __extends(DateClicking, _super); function DateClicking(settings) { var _this = _super.call(this, settings) || this; _this.handlePointerDown = function (ev) { var dragging = _this.dragging; // do this in pointerdown (not dragend) because DOM might be mutated by the time dragend is fired dragging.setIgnoreMove(!_this.component.isValidDateDownEl(dragging.pointer.downEl)); }; // won't even fire if moving was ignored _this.handleDragEnd = function (ev) { var component = _this.component; var _a = component.context, calendar = _a.calendar, view = _a.view; var pointer = _this.dragging.pointer; if (!pointer.wasTouchScroll) { var _b = _this.hitDragging, initialHit = _b.initialHit, finalHit = _b.finalHit; if (initialHit && finalHit && isHitsEqual(initialHit, finalHit)) { calendar.triggerDateClick(initialHit.dateSpan, initialHit.dayEl, view, ev.origEvent); } } }; var component = settings.component; // we DO want to watch pointer moves because otherwise finalHit won't get populated _this.dragging = new FeaturefulElementDragging(component.el); _this.dragging.autoScroller.isEnabled = false; var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["interactionSettingsToStore"])(settings)); hitDragging.emitter.on('pointerdown', _this.handlePointerDown); hitDragging.emitter.on('dragend', _this.handleDragEnd); return _this; } DateClicking.prototype.destroy = function () { this.dragging.destroy(); }; return DateClicking; }(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["Interaction"])); /* Tracks when the user selects a portion of time of a component, constituted by a drag over date cells, with a possible delay at the beginning of the drag. */ var DateSelecting = /** @class */ (function (_super) { __extends(DateSelecting, _super); function DateSelecting(settings) { var _this = _super.call(this, settings) || this; _this.dragSelection = null; _this.handlePointerDown = function (ev) { var _a = _this, component = _a.component, dragging = _a.dragging; var options = component.context.options; var canSelect = options.selectable && component.isValidDateDownEl(ev.origEvent.target); // don't bother to watch expensive moves if component won't do selection dragging.setIgnoreMove(!canSelect); // if touch, require user to hold down dragging.delay = ev.isTouch ? getComponentTouchDelay(component) : null; }; _this.handleDragStart = function (ev) { _this.component.context.calendar.unselect(ev); // unselect previous selections }; _this.handleHitUpdate = function (hit, isFinal) { var calendar = _this.component.context.calendar; var dragSelection = null; var isInvalid = false; if (hit) { dragSelection = joinHitsIntoSelection(_this.hitDragging.initialHit, hit, calendar.pluginSystem.hooks.dateSelectionTransformers); if (!dragSelection || !_this.component.isDateSelectionValid(dragSelection)) { isInvalid = true; dragSelection = null; } } if (dragSelection) { calendar.dispatch({ type: 'SELECT_DATES', selection: dragSelection }); } else if (!isFinal) { // only unselect if moved away while dragging calendar.dispatch({ type: 'UNSELECT_DATES' }); } if (!isInvalid) { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["enableCursor"])(); } else { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["disableCursor"])(); } if (!isFinal) { _this.dragSelection = dragSelection; // only clear if moved away from all hits while dragging } }; _this.handlePointerUp = function (pev) { if (_this.dragSelection) { // selection is already rendered, so just need to report selection _this.component.context.calendar.triggerDateSelect(_this.dragSelection, pev); _this.dragSelection = null; } }; var component = settings.component; var options = component.context.options; var dragging = _this.dragging = new FeaturefulElementDragging(component.el); dragging.touchScrollAllowed = false; dragging.minDistance = options.selectMinDistance || 0; dragging.autoScroller.isEnabled = options.dragScroll; var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["interactionSettingsToStore"])(settings)); hitDragging.emitter.on('pointerdown', _this.handlePointerDown); hitDragging.emitter.on('dragstart', _this.handleDragStart); hitDragging.emitter.on('hitupdate', _this.handleHitUpdate); hitDragging.emitter.on('pointerup', _this.handlePointerUp); return _this; } DateSelecting.prototype.destroy = function () { this.dragging.destroy(); }; return DateSelecting; }(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["Interaction"])); function getComponentTouchDelay(component) { var options = component.context.options; var delay = options.selectLongPressDelay; if (delay == null) { delay = options.longPressDelay; } return delay; } function joinHitsIntoSelection(hit0, hit1, dateSelectionTransformers) { var dateSpan0 = hit0.dateSpan; var dateSpan1 = hit1.dateSpan; var ms = [ dateSpan0.range.start, dateSpan0.range.end, dateSpan1.range.start, dateSpan1.range.end ]; ms.sort(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["compareNumbers"]); var props = {}; for (var _i = 0, dateSelectionTransformers_1 = dateSelectionTransformers; _i < dateSelectionTransformers_1.length; _i++) { var transformer = dateSelectionTransformers_1[_i]; var res = transformer(hit0, hit1); if (res === false) { return null; } else if (res) { __assign(props, res); } } props.range = { start: ms[0], end: ms[3] }; props.allDay = dateSpan0.allDay; return props; } var EventDragging = /** @class */ (function (_super) { __extends(EventDragging, _super); function EventDragging(settings) { var _this = _super.call(this, settings) || this; // internal state _this.subjectSeg = null; // the seg being selected/dragged _this.isDragging = false; _this.eventRange = null; _this.relevantEvents = null; // the events being dragged _this.receivingCalendar = null; _this.validMutation = null; _this.mutatedRelevantEvents = null; _this.handlePointerDown = function (ev) { var origTarget = ev.origEvent.target; var _a = _this, component = _a.component, dragging = _a.dragging; var mirror = dragging.mirror; var options = component.context.options; var initialCalendar = component.context.calendar; var subjectSeg = _this.subjectSeg = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["getElSeg"])(ev.subjectEl); var eventRange = _this.eventRange = subjectSeg.eventRange; var eventInstanceId = eventRange.instance.instanceId; _this.relevantEvents = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["getRelevantEvents"])(initialCalendar.state.eventStore, eventInstanceId); dragging.minDistance = ev.isTouch ? 0 : options.eventDragMinDistance; dragging.delay = // only do a touch delay if touch and this event hasn't been selected yet (ev.isTouch && eventInstanceId !== component.props.eventSelection) ? getComponentTouchDelay$1(component) : null; mirror.parentNode = initialCalendar.el; mirror.revertDuration = options.dragRevertDuration; var isValid = component.isValidSegDownEl(origTarget) && !Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["elementClosest"])(origTarget, '.fc-resizer'); // NOT on a resizer dragging.setIgnoreMove(!isValid); // disable dragging for elements that are resizable (ie, selectable) // but are not draggable _this.isDragging = isValid && ev.subjectEl.classList.contains('fc-draggable'); }; _this.handleDragStart = function (ev) { var context = _this.component.context; var initialCalendar = context.calendar; var eventRange = _this.eventRange; var eventInstanceId = eventRange.instance.instanceId; if (ev.isTouch) { // need to select a different event? if (eventInstanceId !== _this.component.props.eventSelection) { initialCalendar.dispatch({ type: 'SELECT_EVENT', eventInstanceId: eventInstanceId }); } } else { // if now using mouse, but was previous touch interaction, clear selected event initialCalendar.dispatch({ type: 'UNSELECT_EVENT' }); } if (_this.isDragging) { initialCalendar.unselect(ev); // unselect *date* selection initialCalendar.publiclyTrigger('eventDragStart', [ { el: _this.subjectSeg.el, event: new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["EventApi"](initialCalendar, eventRange.def, eventRange.instance), jsEvent: ev.origEvent, view: context.view } ]); } }; _this.handleHitUpdate = function (hit, isFinal) { if (!_this.isDragging) { return; } var relevantEvents = _this.relevantEvents; var initialHit = _this.hitDragging.initialHit; var initialCalendar = _this.component.context.calendar; // states based on new hit var receivingCalendar = null; var mutation = null; var mutatedRelevantEvents = null; var isInvalid = false; var interaction = { affectedEvents: relevantEvents, mutatedEvents: Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createEmptyEventStore"])(), isEvent: true, origSeg: _this.subjectSeg }; if (hit) { var receivingComponent = hit.component; receivingCalendar = receivingComponent.context.calendar; var receivingOptions = receivingComponent.context.options; if (initialCalendar === receivingCalendar || receivingOptions.editable && receivingOptions.droppable) { mutation = computeEventMutation(initialHit, hit, receivingCalendar.pluginSystem.hooks.eventDragMutationMassagers); if (mutation) { mutatedRelevantEvents = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["applyMutationToEventStore"])(relevantEvents, receivingCalendar.eventUiBases, mutation, receivingCalendar); interaction.mutatedEvents = mutatedRelevantEvents; if (!receivingComponent.isInteractionValid(interaction)) { isInvalid = true; mutation = null; mutatedRelevantEvents = null; interaction.mutatedEvents = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createEmptyEventStore"])(); } } } else { receivingCalendar = null; } } _this.displayDrag(receivingCalendar, interaction); if (!isInvalid) { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["enableCursor"])(); } else { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["disableCursor"])(); } if (!isFinal) { if (initialCalendar === receivingCalendar && // TODO: write test for this isHitsEqual(initialHit, hit)) { mutation = null; } _this.dragging.setMirrorNeedsRevert(!mutation); // render the mirror if no already-rendered mirror // TODO: wish we could somehow wait for dispatch to guarantee render _this.dragging.setMirrorIsVisible(!hit || !document.querySelector('.fc-mirror')); // assign states based on new hit _this.receivingCalendar = receivingCalendar; _this.validMutation = mutation; _this.mutatedRelevantEvents = mutatedRelevantEvents; } }; _this.handlePointerUp = function () { if (!_this.isDragging) { _this.cleanup(); // because handleDragEnd won't fire } }; _this.handleDragEnd = function (ev) { if (_this.isDragging) { var context = _this.component.context; var initialCalendar_1 = context.calendar; var initialView = context.view; var _a = _this, receivingCalendar = _a.receivingCalendar, validMutation = _a.validMutation; var eventDef = _this.eventRange.def; var eventInstance = _this.eventRange.instance; var eventApi = new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["EventApi"](initialCalendar_1, eventDef, eventInstance); var relevantEvents_1 = _this.relevantEvents; var mutatedRelevantEvents = _this.mutatedRelevantEvents; var finalHit = _this.hitDragging.finalHit; _this.clearDrag(); // must happen after revert animation initialCalendar_1.publiclyTrigger('eventDragStop', [ { el: _this.subjectSeg.el, event: eventApi, jsEvent: ev.origEvent, view: initialView } ]); if (validMutation) { // dropped within same calendar if (receivingCalendar === initialCalendar_1) { initialCalendar_1.dispatch({ type: 'MERGE_EVENTS', eventStore: mutatedRelevantEvents }); var transformed = {}; for (var _i = 0, _b = initialCalendar_1.pluginSystem.hooks.eventDropTransformers; _i < _b.length; _i++) { var transformer = _b[_i]; __assign(transformed, transformer(validMutation, initialCalendar_1)); } var eventDropArg = __assign({}, transformed, { el: ev.subjectEl, delta: validMutation.datesDelta, oldEvent: eventApi, event: new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["EventApi"](// the data AFTER the mutation initialCalendar_1, mutatedRelevantEvents.defs[eventDef.defId], eventInstance ? mutatedRelevantEvents.instances[eventInstance.instanceId] : null), revert: function () { initialCalendar_1.dispatch({ type: 'MERGE_EVENTS', eventStore: relevantEvents_1 }); }, jsEvent: ev.origEvent, view: initialView }); initialCalendar_1.publiclyTrigger('eventDrop', [eventDropArg]); // dropped in different calendar } else if (receivingCalendar) { initialCalendar_1.publiclyTrigger('eventLeave', [ { draggedEl: ev.subjectEl, event: eventApi, view: initialView } ]); initialCalendar_1.dispatch({ type: 'REMOVE_EVENT_INSTANCES', instances: _this.mutatedRelevantEvents.instances }); receivingCalendar.dispatch({ type: 'MERGE_EVENTS', eventStore: _this.mutatedRelevantEvents }); if (ev.isTouch) { receivingCalendar.dispatch({ type: 'SELECT_EVENT', eventInstanceId: eventInstance.instanceId }); } var dropArg = __assign({}, receivingCalendar.buildDatePointApi(finalHit.dateSpan), { draggedEl: ev.subjectEl, jsEvent: ev.origEvent, view: finalHit.component // should this be finalHit.component.view? See #4644 }); receivingCalendar.publiclyTrigger('drop', [dropArg]); receivingCalendar.publiclyTrigger('eventReceive', [ { draggedEl: ev.subjectEl, event: new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["EventApi"](// the data AFTER the mutation receivingCalendar, mutatedRelevantEvents.defs[eventDef.defId], mutatedRelevantEvents.instances[eventInstance.instanceId]), view: finalHit.component // should this be finalHit.component.view? See #4644 } ]); } } else { initialCalendar_1.publiclyTrigger('_noEventDrop'); } } _this.cleanup(); }; var component = _this.component; var options = component.context.options; var dragging = _this.dragging = new FeaturefulElementDragging(component.el); dragging.pointer.selector = EventDragging.SELECTOR; dragging.touchScrollAllowed = false; dragging.autoScroller.isEnabled = options.dragScroll; var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["interactionSettingsStore"]); hitDragging.useSubjectCenter = settings.useEventCenter; hitDragging.emitter.on('pointerdown', _this.handlePointerDown); hitDragging.emitter.on('dragstart', _this.handleDragStart); hitDragging.emitter.on('hitupdate', _this.handleHitUpdate); hitDragging.emitter.on('pointerup', _this.handlePointerUp); hitDragging.emitter.on('dragend', _this.handleDragEnd); return _this; } EventDragging.prototype.destroy = function () { this.dragging.destroy(); }; // render a drag state on the next receivingCalendar EventDragging.prototype.displayDrag = function (nextCalendar, state) { var initialCalendar = this.component.context.calendar; var prevCalendar = this.receivingCalendar; // does the previous calendar need to be cleared? if (prevCalendar && prevCalendar !== nextCalendar) { // does the initial calendar need to be cleared? // if so, don't clear all the way. we still need to to hide the affectedEvents if (prevCalendar === initialCalendar) { prevCalendar.dispatch({ type: 'SET_EVENT_DRAG', state: { affectedEvents: state.affectedEvents, mutatedEvents: Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createEmptyEventStore"])(), isEvent: true, origSeg: state.origSeg } }); // completely clear the old calendar if it wasn't the initial } else { prevCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' }); } } if (nextCalendar) { nextCalendar.dispatch({ type: 'SET_EVENT_DRAG', state: state }); } }; EventDragging.prototype.clearDrag = function () { var initialCalendar = this.component.context.calendar; var receivingCalendar = this.receivingCalendar; if (receivingCalendar) { receivingCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' }); } // the initial calendar might have an dummy drag state from displayDrag if (initialCalendar !== receivingCalendar) { initialCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' }); } }; EventDragging.prototype.cleanup = function () { this.subjectSeg = null; this.isDragging = false; this.eventRange = null; this.relevantEvents = null; this.receivingCalendar = null; this.validMutation = null; this.mutatedRelevantEvents = null; }; EventDragging.SELECTOR = '.fc-draggable, .fc-resizable'; // TODO: test this in IE11 return EventDragging; }(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["Interaction"])); function computeEventMutation(hit0, hit1, massagers) { var dateSpan0 = hit0.dateSpan; var dateSpan1 = hit1.dateSpan; var date0 = dateSpan0.range.start; var date1 = dateSpan1.range.start; var standardProps = {}; if (dateSpan0.allDay !== dateSpan1.allDay) { standardProps.allDay = dateSpan1.allDay; standardProps.hasEnd = hit1.component.context.options.allDayMaintainDuration; if (dateSpan1.allDay) { // means date1 is already start-of-day, // but date0 needs to be converted date0 = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["startOfDay"])(date0); } } var delta = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["diffDates"])(date0, date1, hit0.component.context.dateEnv, hit0.component === hit1.component ? hit0.component.largeUnit : null); if (delta.milliseconds) { // has hours/minutes/seconds standardProps.allDay = false; } var mutation = { datesDelta: delta, standardProps: standardProps }; for (var _i = 0, massagers_1 = massagers; _i < massagers_1.length; _i++) { var massager = massagers_1[_i]; massager(mutation, hit0, hit1); } return mutation; } function getComponentTouchDelay$1(component) { var options = component.context.options; var delay = options.eventLongPressDelay; if (delay == null) { delay = options.longPressDelay; } return delay; } var EventDragging$1 = /** @class */ (function (_super) { __extends(EventDragging, _super); function EventDragging(settings) { var _this = _super.call(this, settings) || this; // internal state _this.draggingSeg = null; // TODO: rename to resizingSeg? subjectSeg? _this.eventRange = null; _this.relevantEvents = null; _this.validMutation = null; _this.mutatedRelevantEvents = null; _this.handlePointerDown = function (ev) { var component = _this.component; var seg = _this.querySeg(ev); var eventRange = _this.eventRange = seg.eventRange; _this.dragging.minDistance = component.context.options.eventDragMinDistance; // if touch, need to be working with a selected event _this.dragging.setIgnoreMove(!_this.component.isValidSegDownEl(ev.origEvent.target) || (ev.isTouch && _this.component.props.eventSelection !== eventRange.instance.instanceId)); }; _this.handleDragStart = function (ev) { var _a = _this.component.context, calendar = _a.calendar, view = _a.view; var eventRange = _this.eventRange; _this.relevantEvents = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["getRelevantEvents"])(calendar.state.eventStore, _this.eventRange.instance.instanceId); _this.draggingSeg = _this.querySeg(ev); calendar.unselect(); calendar.publiclyTrigger('eventResizeStart', [ { el: _this.draggingSeg.el, event: new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["EventApi"](calendar, eventRange.def, eventRange.instance), jsEvent: ev.origEvent, view: view } ]); }; _this.handleHitUpdate = function (hit, isFinal, ev) { var calendar = _this.component.context.calendar; var relevantEvents = _this.relevantEvents; var initialHit = _this.hitDragging.initialHit; var eventInstance = _this.eventRange.instance; var mutation = null; var mutatedRelevantEvents = null; var isInvalid = false; var interaction = { affectedEvents: relevantEvents, mutatedEvents: Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createEmptyEventStore"])(), isEvent: true, origSeg: _this.draggingSeg }; if (hit) { mutation = computeMutation(initialHit, hit, ev.subjectEl.classList.contains('fc-start-resizer'), eventInstance.range, calendar.pluginSystem.hooks.eventResizeJoinTransforms); } if (mutation) { mutatedRelevantEvents = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["applyMutationToEventStore"])(relevantEvents, calendar.eventUiBases, mutation, calendar); interaction.mutatedEvents = mutatedRelevantEvents; if (!_this.component.isInteractionValid(interaction)) { isInvalid = true; mutation = null; mutatedRelevantEvents = null; interaction.mutatedEvents = null; } } if (mutatedRelevantEvents) { calendar.dispatch({ type: 'SET_EVENT_RESIZE', state: interaction }); } else { calendar.dispatch({ type: 'UNSET_EVENT_RESIZE' }); } if (!isInvalid) { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["enableCursor"])(); } else { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["disableCursor"])(); } if (!isFinal) { if (mutation && isHitsEqual(initialHit, hit)) { mutation = null; } _this.validMutation = mutation; _this.mutatedRelevantEvents = mutatedRelevantEvents; } }; _this.handleDragEnd = function (ev) { var _a = _this.component.context, calendar = _a.calendar, view = _a.view; var eventDef = _this.eventRange.def; var eventInstance = _this.eventRange.instance; var eventApi = new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["EventApi"](calendar, eventDef, eventInstance); var relevantEvents = _this.relevantEvents; var mutatedRelevantEvents = _this.mutatedRelevantEvents; calendar.publiclyTrigger('eventResizeStop', [ { el: _this.draggingSeg.el, event: eventApi, jsEvent: ev.origEvent, view: view } ]); if (_this.validMutation) { calendar.dispatch({ type: 'MERGE_EVENTS', eventStore: mutatedRelevantEvents }); calendar.publiclyTrigger('eventResize', [ { el: _this.draggingSeg.el, startDelta: _this.validMutation.startDelta || Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createDuration"])(0), endDelta: _this.validMutation.endDelta || Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createDuration"])(0), prevEvent: eventApi, event: new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["EventApi"](// the data AFTER the mutation calendar, mutatedRelevantEvents.defs[eventDef.defId], eventInstance ? mutatedRelevantEvents.instances[eventInstance.instanceId] : null), revert: function () { calendar.dispatch({ type: 'MERGE_EVENTS', eventStore: relevantEvents }); }, jsEvent: ev.origEvent, view: view } ]); } else { calendar.publiclyTrigger('_noEventResize'); } // reset all internal state _this.draggingSeg = null; _this.relevantEvents = null; _this.validMutation = null; // okay to keep eventInstance around. useful to set it in handlePointerDown }; var component = settings.component; var dragging = _this.dragging = new FeaturefulElementDragging(component.el); dragging.pointer.selector = '.fc-resizer'; dragging.touchScrollAllowed = false; dragging.autoScroller.isEnabled = component.context.options.dragScroll; var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["interactionSettingsToStore"])(settings)); hitDragging.emitter.on('pointerdown', _this.handlePointerDown); hitDragging.emitter.on('dragstart', _this.handleDragStart); hitDragging.emitter.on('hitupdate', _this.handleHitUpdate); hitDragging.emitter.on('dragend', _this.handleDragEnd); return _this; } EventDragging.prototype.destroy = function () { this.dragging.destroy(); }; EventDragging.prototype.querySeg = function (ev) { return Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["getElSeg"])(Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["elementClosest"])(ev.subjectEl, this.component.fgSegSelector)); }; return EventDragging; }(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["Interaction"])); function computeMutation(hit0, hit1, isFromStart, instanceRange, transforms) { var dateEnv = hit0.component.context.dateEnv; var date0 = hit0.dateSpan.range.start; var date1 = hit1.dateSpan.range.start; var delta = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["diffDates"])(date0, date1, dateEnv, hit0.component.largeUnit); var props = {}; for (var _i = 0, transforms_1 = transforms; _i < transforms_1.length; _i++) { var transform = transforms_1[_i]; var res = transform(hit0, hit1); if (res === false) { return null; } else if (res) { __assign(props, res); } } if (isFromStart) { if (dateEnv.add(instanceRange.start, delta) < instanceRange.end) { props.startDelta = delta; return props; } } else { if (dateEnv.add(instanceRange.end, delta) > instanceRange.start) { props.endDelta = delta; return props; } } return null; } var UnselectAuto = /** @class */ (function () { function UnselectAuto(calendar) { var _this = this; this.isRecentPointerDateSelect = false; // wish we could use a selector to detect date selection, but uses hit system this.onSelect = function (selectInfo) { if (selectInfo.jsEvent) { _this.isRecentPointerDateSelect = true; } }; this.onDocumentPointerUp = function (pev) { var _a = _this, calendar = _a.calendar, documentPointer = _a.documentPointer; var state = calendar.state; // touch-scrolling should never unfocus any type of selection if (!documentPointer.wasTouchScroll) { if (state.dateSelection && // an existing date selection? !_this.isRecentPointerDateSelect // a new pointer-initiated date selection since last onDocumentPointerUp? ) { var unselectAuto = calendar.viewOpt('unselectAuto'); var unselectCancel = calendar.viewOpt('unselectCancel'); if (unselectAuto && (!unselectAuto || !Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["elementClosest"])(documentPointer.downEl, unselectCancel))) { calendar.unselect(pev); } } if (state.eventSelection && // an existing event selected? !Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["elementClosest"])(documentPointer.downEl, EventDragging.SELECTOR) // interaction DIDN'T start on an event ) { calendar.dispatch({ type: 'UNSELECT_EVENT' }); } } _this.isRecentPointerDateSelect = false; }; this.calendar = calendar; var documentPointer = this.documentPointer = new PointerDragging(document); documentPointer.shouldIgnoreMove = true; documentPointer.shouldWatchScroll = false; documentPointer.emitter.on('pointerup', this.onDocumentPointerUp); /* TODO: better way to know about whether there was a selection with the pointer */ calendar.on('select', this.onSelect); } UnselectAuto.prototype.destroy = function () { this.calendar.off('select', this.onSelect); this.documentPointer.destroy(); }; return UnselectAuto; }()); /* Given an already instantiated draggable object for one-or-more elements, Interprets any dragging as an attempt to drag an events that lives outside of a calendar onto a calendar. */ var ExternalElementDragging = /** @class */ (function () { function ExternalElementDragging(dragging, suppliedDragMeta) { var _this = this; this.receivingCalendar = null; this.droppableEvent = null; // will exist for all drags, even if create:false this.suppliedDragMeta = null; this.dragMeta = null; this.handleDragStart = function (ev) { _this.dragMeta = _this.buildDragMeta(ev.subjectEl); }; this.handleHitUpdate = function (hit, isFinal, ev) { var dragging = _this.hitDragging.dragging; var receivingCalendar = null; var droppableEvent = null; var isInvalid = false; var interaction = { affectedEvents: Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createEmptyEventStore"])(), mutatedEvents: Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createEmptyEventStore"])(), isEvent: _this.dragMeta.create, origSeg: null }; if (hit) { receivingCalendar = hit.component.context.calendar; if (_this.canDropElOnCalendar(ev.subjectEl, receivingCalendar)) { droppableEvent = computeEventForDateSpan(hit.dateSpan, _this.dragMeta, receivingCalendar); interaction.mutatedEvents = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["eventTupleToStore"])(droppableEvent); isInvalid = !Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["isInteractionValid"])(interaction, receivingCalendar); if (isInvalid) { interaction.mutatedEvents = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createEmptyEventStore"])(); droppableEvent = null; } } } _this.displayDrag(receivingCalendar, interaction); // show mirror if no already-rendered mirror element OR if we are shutting down the mirror (?) // TODO: wish we could somehow wait for dispatch to guarantee render dragging.setMirrorIsVisible(isFinal || !droppableEvent || !document.querySelector('.fc-mirror')); if (!isInvalid) { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["enableCursor"])(); } else { Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["disableCursor"])(); } if (!isFinal) { dragging.setMirrorNeedsRevert(!droppableEvent); _this.receivingCalendar = receivingCalendar; _this.droppableEvent = droppableEvent; } }; this.handleDragEnd = function (pev) { var _a = _this, receivingCalendar = _a.receivingCalendar, droppableEvent = _a.droppableEvent; _this.clearDrag(); if (receivingCalendar && droppableEvent) { var finalHit = _this.hitDragging.finalHit; var finalView = finalHit.component.context.view; var dragMeta = _this.dragMeta; var arg = __assign({}, receivingCalendar.buildDatePointApi(finalHit.dateSpan), { draggedEl: pev.subjectEl, jsEvent: pev.origEvent, view: finalView }); receivingCalendar.publiclyTrigger('drop', [arg]); if (dragMeta.create) { receivingCalendar.dispatch({ type: 'MERGE_EVENTS', eventStore: Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["eventTupleToStore"])(droppableEvent) }); if (pev.isTouch) { receivingCalendar.dispatch({ type: 'SELECT_EVENT', eventInstanceId: droppableEvent.instance.instanceId }); } // signal that an external event landed receivingCalendar.publiclyTrigger('eventReceive', [ { draggedEl: pev.subjectEl, event: new _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["EventApi"](receivingCalendar, droppableEvent.def, droppableEvent.instance), view: finalView } ]); } } _this.receivingCalendar = null; _this.droppableEvent = null; }; var hitDragging = this.hitDragging = new HitDragging(dragging, _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["interactionSettingsStore"]); hitDragging.requireInitial = false; // will start outside of a component hitDragging.emitter.on('dragstart', this.handleDragStart); hitDragging.emitter.on('hitupdate', this.handleHitUpdate); hitDragging.emitter.on('dragend', this.handleDragEnd); this.suppliedDragMeta = suppliedDragMeta; } ExternalElementDragging.prototype.buildDragMeta = function (subjectEl) { if (typeof this.suppliedDragMeta === 'object') { return Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["parseDragMeta"])(this.suppliedDragMeta); } else if (typeof this.suppliedDragMeta === 'function') { return Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["parseDragMeta"])(this.suppliedDragMeta(subjectEl)); } else { return getDragMetaFromEl(subjectEl); } }; ExternalElementDragging.prototype.displayDrag = function (nextCalendar, state) { var prevCalendar = this.receivingCalendar; if (prevCalendar && prevCalendar !== nextCalendar) { prevCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' }); } if (nextCalendar) { nextCalendar.dispatch({ type: 'SET_EVENT_DRAG', state: state }); } }; ExternalElementDragging.prototype.clearDrag = function () { if (this.receivingCalendar) { this.receivingCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' }); } }; ExternalElementDragging.prototype.canDropElOnCalendar = function (el, receivingCalendar) { var dropAccept = receivingCalendar.opt('dropAccept'); if (typeof dropAccept === 'function') { return dropAccept(el); } else if (typeof dropAccept === 'string' && dropAccept) { return Boolean(Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["elementMatches"])(el, dropAccept)); } return true; }; return ExternalElementDragging; }()); // Utils for computing event store from the DragMeta // ---------------------------------------------------------------------------------------------------- function computeEventForDateSpan(dateSpan, dragMeta, calendar) { var defProps = __assign({}, dragMeta.leftoverProps); for (var _i = 0, _a = calendar.pluginSystem.hooks.externalDefTransforms; _i < _a.length; _i++) { var transform = _a[_i]; __assign(defProps, transform(dateSpan, dragMeta)); } var def = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["parseEventDef"])(defProps, dragMeta.sourceId, dateSpan.allDay, calendar.opt('forceEventDuration') || Boolean(dragMeta.duration), // hasEnd calendar); var start = dateSpan.range.start; // only rely on time info if drop zone is all-day, // otherwise, we already know the time if (dateSpan.allDay && dragMeta.startTime) { start = calendar.dateEnv.add(start, dragMeta.startTime); } var end = dragMeta.duration ? calendar.dateEnv.add(start, dragMeta.duration) : calendar.getDefaultEventEnd(dateSpan.allDay, start); var instance = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createEventInstance"])(def.defId, { start: start, end: end }); return { def: def, instance: instance }; } // Utils for extracting data from element // ---------------------------------------------------------------------------------------------------- function getDragMetaFromEl(el) { var str = getEmbeddedElData(el, 'event'); var obj = str ? JSON.parse(str) : { create: false }; // if no embedded data, assume no event creation return Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["parseDragMeta"])(obj); } _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["config"].dataAttrPrefix = ''; function getEmbeddedElData(el, name) { var prefix = _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["config"].dataAttrPrefix; var prefixedName = (prefix ? prefix + '-' : '') + name; return el.getAttribute('data-' + prefixedName) || ''; } /* Makes an element (that is *external* to any calendar) draggable. Can pass in data that determines how an event will be created when dropped onto a calendar. Leverages FullCalendar's internal drag-n-drop functionality WITHOUT a third-party drag system. */ var ExternalDraggable = /** @class */ (function () { function ExternalDraggable(el, settings) { var _this = this; if (settings === void 0) { settings = {}; } this.handlePointerDown = function (ev) { var dragging = _this.dragging; var _a = _this.settings, minDistance = _a.minDistance, longPressDelay = _a.longPressDelay; dragging.minDistance = minDistance != null ? minDistance : (ev.isTouch ? 0 : _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["globalDefaults"].eventDragMinDistance); dragging.delay = ev.isTouch ? // TODO: eventually read eventLongPressDelay instead vvv (longPressDelay != null ? longPressDelay : _fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["globalDefaults"].longPressDelay) : 0; }; this.handleDragStart = function (ev) { if (ev.isTouch && _this.dragging.delay && ev.subjectEl.classList.contains('fc-event')) { _this.dragging.mirror.getMirrorEl().classList.add('fc-selected'); } }; this.settings = settings; var dragging = this.dragging = new FeaturefulElementDragging(el); dragging.touchScrollAllowed = false; if (settings.itemSelector != null) { dragging.pointer.selector = settings.itemSelector; } if (settings.appendTo != null) { dragging.mirror.parentNode = settings.appendTo; // TODO: write tests } dragging.emitter.on('pointerdown', this.handlePointerDown); dragging.emitter.on('dragstart', this.handleDragStart); new ExternalElementDragging(dragging, settings.eventData); } ExternalDraggable.prototype.destroy = function () { this.dragging.destroy(); }; return ExternalDraggable; }()); /* Detects when a *THIRD-PARTY* drag-n-drop system interacts with elements. The third-party system is responsible for drawing the visuals effects of the drag. This class simply monitors for pointer movements and fires events. It also has the ability to hide the moving element (the "mirror") during the drag. */ var InferredElementDragging = /** @class */ (function (_super) { __extends(InferredElementDragging, _super); function InferredElementDragging(containerEl) { var _this = _super.call(this, containerEl) || this; _this.shouldIgnoreMove = false; _this.mirrorSelector = ''; _this.currentMirrorEl = null; _this.handlePointerDown = function (ev) { _this.emitter.trigger('pointerdown', ev); if (!_this.shouldIgnoreMove) { // fire dragstart right away. does not support delay or min-distance _this.emitter.trigger('dragstart', ev); } }; _this.handlePointerMove = function (ev) { if (!_this.shouldIgnoreMove) { _this.emitter.trigger('dragmove', ev); } }; _this.handlePointerUp = function (ev) { _this.emitter.trigger('pointerup', ev); if (!_this.shouldIgnoreMove) { // fire dragend right away. does not support a revert animation _this.emitter.trigger('dragend', ev); } }; var pointer = _this.pointer = new PointerDragging(containerEl); pointer.emitter.on('pointerdown', _this.handlePointerDown); pointer.emitter.on('pointermove', _this.handlePointerMove); pointer.emitter.on('pointerup', _this.handlePointerUp); return _this; } InferredElementDragging.prototype.destroy = function () { this.pointer.destroy(); }; InferredElementDragging.prototype.setIgnoreMove = function (bool) { this.shouldIgnoreMove = bool; }; InferredElementDragging.prototype.setMirrorIsVisible = function (bool) { if (bool) { // restore a previously hidden element. // use the reference in case the selector class has already been removed. if (this.currentMirrorEl) { this.currentMirrorEl.style.visibility = ''; this.currentMirrorEl = null; } } else { var mirrorEl = this.mirrorSelector ? document.querySelector(this.mirrorSelector) : null; if (mirrorEl) { this.currentMirrorEl = mirrorEl; mirrorEl.style.visibility = 'hidden'; } } }; return InferredElementDragging; }(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["ElementDragging"])); /* Bridges third-party drag-n-drop systems with FullCalendar. Must be instantiated and destroyed by caller. */ var ThirdPartyDraggable = /** @class */ (function () { function ThirdPartyDraggable(containerOrSettings, settings) { var containerEl = document; if ( // wish we could just test instanceof EventTarget, but doesn't work in IE11 containerOrSettings === document || containerOrSettings instanceof Element) { containerEl = containerOrSettings; settings = settings || {}; } else { settings = (containerOrSettings || {}); } var dragging = this.dragging = new InferredElementDragging(containerEl); if (typeof settings.itemSelector === 'string') { dragging.pointer.selector = settings.itemSelector; } else if (containerEl === document) { dragging.pointer.selector = '[data-event]'; } if (typeof settings.mirrorSelector === 'string') { dragging.mirrorSelector = settings.mirrorSelector; } new ExternalElementDragging(dragging, settings.eventData); } ThirdPartyDraggable.prototype.destroy = function () { this.dragging.destroy(); }; return ThirdPartyDraggable; }()); var main = Object(_fullcalendar_core__WEBPACK_IMPORTED_MODULE_0__["createPlugin"])({ componentInteractions: [DateClicking, DateSelecting, EventDragging, EventDragging$1], calendarInteractions: [UnselectAuto], elementDraggingImpl: FeaturefulElementDragging }); /* harmony default export */ __webpack_exports__["default"] = (main); /***/ }), /***/ "./node_modules/core-js/internals/an-object.js": /*!*****************************************************!*\ !*** ./node_modules/core-js/internals/an-object.js ***! \*****************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var isObject = __webpack_require__(/*! ../internals/is-object */ "./node_modules/core-js/internals/is-object.js"); module.exports = function (it) { if (!isObject(it)) { throw TypeError(String(it) + ' is not an object'); } return it; }; /***/ }), /***/ "./node_modules/core-js/internals/classof-raw.js": /*!*******************************************************!*\ !*** ./node_modules/core-js/internals/classof-raw.js ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports) { var toString = {}.toString; module.exports = function (it) { return toString.call(it).slice(8, -1); }; /***/ }), /***/ "./node_modules/core-js/internals/classof.js": /*!***************************************************!*\ !*** ./node_modules/core-js/internals/classof.js ***! \***************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var TO_STRING_TAG_SUPPORT = __webpack_require__(/*! ../internals/to-string-tag-support */ "./node_modules/core-js/internals/to-string-tag-support.js"); var classofRaw = __webpack_require__(/*! ../internals/classof-raw */ "./node_modules/core-js/internals/classof-raw.js"); var wellKnownSymbol = __webpack_require__(/*! ../internals/well-known-symbol */ "./node_modules/core-js/internals/well-known-symbol.js"); var TO_STRING_TAG = wellKnownSymbol('toStringTag'); // ES3 wrong here var CORRECT_ARGUMENTS = classofRaw(function () { return arguments; }()) == 'Arguments'; // fallback for IE11 Script Access Denied error var tryGet = function (it, key) { try { return it[key]; } catch (error) { /* empty */ } }; // getting tag from ES6+ `Object.prototype.toString` module.exports = TO_STRING_TAG_SUPPORT ? classofRaw : function (it) { var O, tag, result; return it === undefined ? 'Undefined' : it === null ? 'Null' // @@toStringTag case : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG)) == 'string' ? tag // builtinTag case : CORRECT_ARGUMENTS ? classofRaw(O) // ES3 arguments fallback : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result; }; /***/ }), /***/ "./node_modules/core-js/internals/create-non-enumerable-property.js": /*!**************************************************************************!*\ !*** ./node_modules/core-js/internals/create-non-enumerable-property.js ***! \**************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var DESCRIPTORS = __webpack_require__(/*! ../internals/descriptors */ "./node_modules/core-js/internals/descriptors.js"); var definePropertyModule = __webpack_require__(/*! ../internals/object-define-property */ "./node_modules/core-js/internals/object-define-property.js"); var createPropertyDescriptor = __webpack_require__(/*! ../internals/create-property-descriptor */ "./node_modules/core-js/internals/create-property-descriptor.js"); module.exports = DESCRIPTORS ? function (object, key, value) { return definePropertyModule.f(object, key, createPropertyDescriptor(1, value)); } : function (object, key, value) { object[key] = value; return object; }; /***/ }), /***/ "./node_modules/core-js/internals/create-property-descriptor.js": /*!**********************************************************************!*\ !*** ./node_modules/core-js/internals/create-property-descriptor.js ***! \**********************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { module.exports = function (bitmap, value) { return { enumerable: !(bitmap & 1), configurable: !(bitmap & 2), writable: !(bitmap & 4), value: value }; }; /***/ }), /***/ "./node_modules/core-js/internals/descriptors.js": /*!*******************************************************!*\ !*** ./node_modules/core-js/internals/descriptors.js ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var fails = __webpack_require__(/*! ../internals/fails */ "./node_modules/core-js/internals/fails.js"); // Thank's IE8 for his funny defineProperty module.exports = !fails(function () { return Object.defineProperty({}, 1, { get: function () { return 7; } })[1] != 7; }); /***/ }), /***/ "./node_modules/core-js/internals/document-create-element.js": /*!*******************************************************************!*\ !*** ./node_modules/core-js/internals/document-create-element.js ***! \*******************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var global = __webpack_require__(/*! ../internals/global */ "./node_modules/core-js/internals/global.js"); var isObject = __webpack_require__(/*! ../internals/is-object */ "./node_modules/core-js/internals/is-object.js"); var document = global.document; // typeof document.createElement is 'object' in old IE var EXISTS = isObject(document) && isObject(document.createElement); module.exports = function (it) { return EXISTS ? document.createElement(it) : {}; }; /***/ }), /***/ "./node_modules/core-js/internals/fails.js": /*!*************************************************!*\ !*** ./node_modules/core-js/internals/fails.js ***! \*************************************************/ /*! no static exports found */ /***/ (function(module, exports) { module.exports = function (exec) { try { return !!exec(); } catch (error) { return true; } }; /***/ }), /***/ "./node_modules/core-js/internals/global.js": /*!**************************************************!*\ !*** ./node_modules/core-js/internals/global.js ***! \**************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global) {var check = function (it) { return it && it.Math == Math && it; }; // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 module.exports = // eslint-disable-next-line no-undef check(typeof globalThis == 'object' && globalThis) || check(typeof window == 'object' && window) || check(typeof self == 'object' && self) || check(typeof global == 'object' && global) || // eslint-disable-next-line no-new-func Function('return this')(); /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../../webpack/buildin/global.js */ "./node_modules/webpack/buildin/global.js"))) /***/ }), /***/ "./node_modules/core-js/internals/has.js": /*!***********************************************!*\ !*** ./node_modules/core-js/internals/has.js ***! \***********************************************/ /*! no static exports found */ /***/ (function(module, exports) { var hasOwnProperty = {}.hasOwnProperty; module.exports = function (it, key) { return hasOwnProperty.call(it, key); }; /***/ }), /***/ "./node_modules/core-js/internals/hidden-keys.js": /*!*******************************************************!*\ !*** ./node_modules/core-js/internals/hidden-keys.js ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports) { module.exports = {}; /***/ }), /***/ "./node_modules/core-js/internals/ie8-dom-define.js": /*!**********************************************************!*\ !*** ./node_modules/core-js/internals/ie8-dom-define.js ***! \**********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var DESCRIPTORS = __webpack_require__(/*! ../internals/descriptors */ "./node_modules/core-js/internals/descriptors.js"); var fails = __webpack_require__(/*! ../internals/fails */ "./node_modules/core-js/internals/fails.js"); var createElement = __webpack_require__(/*! ../internals/document-create-element */ "./node_modules/core-js/internals/document-create-element.js"); // Thank's IE8 for his funny defineProperty module.exports = !DESCRIPTORS && !fails(function () { return Object.defineProperty(createElement('div'), 'a', { get: function () { return 7; } }).a != 7; }); /***/ }), /***/ "./node_modules/core-js/internals/inspect-source.js": /*!**********************************************************!*\ !*** ./node_modules/core-js/internals/inspect-source.js ***! \**********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var store = __webpack_require__(/*! ../internals/shared-store */ "./node_modules/core-js/internals/shared-store.js"); var functionToString = Function.toString; // this helper broken in `3.4.1-3.4.4`, so we can't use `shared` helper if (typeof store.inspectSource != 'function') { store.inspectSource = function (it) { return functionToString.call(it); }; } module.exports = store.inspectSource; /***/ }), /***/ "./node_modules/core-js/internals/internal-state.js": /*!**********************************************************!*\ !*** ./node_modules/core-js/internals/internal-state.js ***! \**********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var NATIVE_WEAK_MAP = __webpack_require__(/*! ../internals/native-weak-map */ "./node_modules/core-js/internals/native-weak-map.js"); var global = __webpack_require__(/*! ../internals/global */ "./node_modules/core-js/internals/global.js"); var isObject = __webpack_require__(/*! ../internals/is-object */ "./node_modules/core-js/internals/is-object.js"); var createNonEnumerableProperty = __webpack_require__(/*! ../internals/create-non-enumerable-property */ "./node_modules/core-js/internals/create-non-enumerable-property.js"); var objectHas = __webpack_require__(/*! ../internals/has */ "./node_modules/core-js/internals/has.js"); var sharedKey = __webpack_require__(/*! ../internals/shared-key */ "./node_modules/core-js/internals/shared-key.js"); var hiddenKeys = __webpack_require__(/*! ../internals/hidden-keys */ "./node_modules/core-js/internals/hidden-keys.js"); var WeakMap = global.WeakMap; var set, get, has; var enforce = function (it) { return has(it) ? get(it) : set(it, {}); }; var getterFor = function (TYPE) { return function (it) { var state; if (!isObject(it) || (state = get(it)).type !== TYPE) { throw TypeError('Incompatible receiver, ' + TYPE + ' required'); } return state; }; }; if (NATIVE_WEAK_MAP) { var store = new WeakMap(); var wmget = store.get; var wmhas = store.has; var wmset = store.set; set = function (it, metadata) { wmset.call(store, it, metadata); return metadata; }; get = function (it) { return wmget.call(store, it) || {}; }; has = function (it) { return wmhas.call(store, it); }; } else { var STATE = sharedKey('state'); hiddenKeys[STATE] = true; set = function (it, metadata) { createNonEnumerableProperty(it, STATE, metadata); return metadata; }; get = function (it) { return objectHas(it, STATE) ? it[STATE] : {}; }; has = function (it) { return objectHas(it, STATE); }; } module.exports = { set: set, get: get, has: has, enforce: enforce, getterFor: getterFor }; /***/ }), /***/ "./node_modules/core-js/internals/is-object.js": /*!*****************************************************!*\ !*** ./node_modules/core-js/internals/is-object.js ***! \*****************************************************/ /*! no static exports found */ /***/ (function(module, exports) { module.exports = function (it) { return typeof it === 'object' ? it !== null : typeof it === 'function'; }; /***/ }), /***/ "./node_modules/core-js/internals/is-pure.js": /*!***************************************************!*\ !*** ./node_modules/core-js/internals/is-pure.js ***! \***************************************************/ /*! no static exports found */ /***/ (function(module, exports) { module.exports = false; /***/ }), /***/ "./node_modules/core-js/internals/native-symbol.js": /*!*********************************************************!*\ !*** ./node_modules/core-js/internals/native-symbol.js ***! \*********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var fails = __webpack_require__(/*! ../internals/fails */ "./node_modules/core-js/internals/fails.js"); module.exports = !!Object.getOwnPropertySymbols && !fails(function () { // Chrome 38 Symbol has incorrect toString conversion // eslint-disable-next-line no-undef return !String(Symbol()); }); /***/ }), /***/ "./node_modules/core-js/internals/native-weak-map.js": /*!***********************************************************!*\ !*** ./node_modules/core-js/internals/native-weak-map.js ***! \***********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var global = __webpack_require__(/*! ../internals/global */ "./node_modules/core-js/internals/global.js"); var inspectSource = __webpack_require__(/*! ../internals/inspect-source */ "./node_modules/core-js/internals/inspect-source.js"); var WeakMap = global.WeakMap; module.exports = typeof WeakMap === 'function' && /native code/.test(inspectSource(WeakMap)); /***/ }), /***/ "./node_modules/core-js/internals/object-define-property.js": /*!******************************************************************!*\ !*** ./node_modules/core-js/internals/object-define-property.js ***! \******************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var DESCRIPTORS = __webpack_require__(/*! ../internals/descriptors */ "./node_modules/core-js/internals/descriptors.js"); var IE8_DOM_DEFINE = __webpack_require__(/*! ../internals/ie8-dom-define */ "./node_modules/core-js/internals/ie8-dom-define.js"); var anObject = __webpack_require__(/*! ../internals/an-object */ "./node_modules/core-js/internals/an-object.js"); var toPrimitive = __webpack_require__(/*! ../internals/to-primitive */ "./node_modules/core-js/internals/to-primitive.js"); var nativeDefineProperty = Object.defineProperty; // `Object.defineProperty` method // https://tc39.github.io/ecma262/#sec-object.defineproperty exports.f = DESCRIPTORS ? nativeDefineProperty : function defineProperty(O, P, Attributes) { anObject(O); P = toPrimitive(P, true); anObject(Attributes); if (IE8_DOM_DEFINE) try { return nativeDefineProperty(O, P, Attributes); } catch (error) { /* empty */ } if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported'); if ('value' in Attributes) O[P] = Attributes.value; return O; }; /***/ }), /***/ "./node_modules/core-js/internals/object-to-string.js": /*!************************************************************!*\ !*** ./node_modules/core-js/internals/object-to-string.js ***! \************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var TO_STRING_TAG_SUPPORT = __webpack_require__(/*! ../internals/to-string-tag-support */ "./node_modules/core-js/internals/to-string-tag-support.js"); var classof = __webpack_require__(/*! ../internals/classof */ "./node_modules/core-js/internals/classof.js"); // `Object.prototype.toString` method implementation // https://tc39.github.io/ecma262/#sec-object.prototype.tostring module.exports = TO_STRING_TAG_SUPPORT ? {}.toString : function toString() { return '[object ' + classof(this) + ']'; }; /***/ }), /***/ "./node_modules/core-js/internals/redefine.js": /*!****************************************************!*\ !*** ./node_modules/core-js/internals/redefine.js ***! \****************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var global = __webpack_require__(/*! ../internals/global */ "./node_modules/core-js/internals/global.js"); var createNonEnumerableProperty = __webpack_require__(/*! ../internals/create-non-enumerable-property */ "./node_modules/core-js/internals/create-non-enumerable-property.js"); var has = __webpack_require__(/*! ../internals/has */ "./node_modules/core-js/internals/has.js"); var setGlobal = __webpack_require__(/*! ../internals/set-global */ "./node_modules/core-js/internals/set-global.js"); var inspectSource = __webpack_require__(/*! ../internals/inspect-source */ "./node_modules/core-js/internals/inspect-source.js"); var InternalStateModule = __webpack_require__(/*! ../internals/internal-state */ "./node_modules/core-js/internals/internal-state.js"); var getInternalState = InternalStateModule.get; var enforceInternalState = InternalStateModule.enforce; var TEMPLATE = String(String).split('String'); (module.exports = function (O, key, value, options) { var unsafe = options ? !!options.unsafe : false; var simple = options ? !!options.enumerable : false; var noTargetGet = options ? !!options.noTargetGet : false; if (typeof value == 'function') { if (typeof key == 'string' && !has(value, 'name')) createNonEnumerableProperty(value, 'name', key); enforceInternalState(value).source = TEMPLATE.join(typeof key == 'string' ? key : ''); } if (O === global) { if (simple) O[key] = value; else setGlobal(key, value); return; } else if (!unsafe) { delete O[key]; } else if (!noTargetGet && O[key]) { simple = true; } if (simple) O[key] = value; else createNonEnumerableProperty(O, key, value); // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative })(Function.prototype, 'toString', function toString() { return typeof this == 'function' && getInternalState(this).source || inspectSource(this); }); /***/ }), /***/ "./node_modules/core-js/internals/regexp-flags.js": /*!********************************************************!*\ !*** ./node_modules/core-js/internals/regexp-flags.js ***! \********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var anObject = __webpack_require__(/*! ../internals/an-object */ "./node_modules/core-js/internals/an-object.js"); // `RegExp.prototype.flags` getter implementation // https://tc39.github.io/ecma262/#sec-get-regexp.prototype.flags module.exports = function () { var that = anObject(this); var result = ''; if (that.global) result += 'g'; if (that.ignoreCase) result += 'i'; if (that.multiline) result += 'm'; if (that.dotAll) result += 's'; if (that.unicode) result += 'u'; if (that.sticky) result += 'y'; return result; }; /***/ }), /***/ "./node_modules/core-js/internals/set-global.js": /*!******************************************************!*\ !*** ./node_modules/core-js/internals/set-global.js ***! \******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var global = __webpack_require__(/*! ../internals/global */ "./node_modules/core-js/internals/global.js"); var createNonEnumerableProperty = __webpack_require__(/*! ../internals/create-non-enumerable-property */ "./node_modules/core-js/internals/create-non-enumerable-property.js"); module.exports = function (key, value) { try { createNonEnumerableProperty(global, key, value); } catch (error) { global[key] = value; } return value; }; /***/ }), /***/ "./node_modules/core-js/internals/shared-key.js": /*!******************************************************!*\ !*** ./node_modules/core-js/internals/shared-key.js ***! \******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var shared = __webpack_require__(/*! ../internals/shared */ "./node_modules/core-js/internals/shared.js"); var uid = __webpack_require__(/*! ../internals/uid */ "./node_modules/core-js/internals/uid.js"); var keys = shared('keys'); module.exports = function (key) { return keys[key] || (keys[key] = uid(key)); }; /***/ }), /***/ "./node_modules/core-js/internals/shared-store.js": /*!********************************************************!*\ !*** ./node_modules/core-js/internals/shared-store.js ***! \********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var global = __webpack_require__(/*! ../internals/global */ "./node_modules/core-js/internals/global.js"); var setGlobal = __webpack_require__(/*! ../internals/set-global */ "./node_modules/core-js/internals/set-global.js"); var SHARED = '__core-js_shared__'; var store = global[SHARED] || setGlobal(SHARED, {}); module.exports = store; /***/ }), /***/ "./node_modules/core-js/internals/shared.js": /*!**************************************************!*\ !*** ./node_modules/core-js/internals/shared.js ***! \**************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var IS_PURE = __webpack_require__(/*! ../internals/is-pure */ "./node_modules/core-js/internals/is-pure.js"); var store = __webpack_require__(/*! ../internals/shared-store */ "./node_modules/core-js/internals/shared-store.js"); (module.exports = function (key, value) { return store[key] || (store[key] = value !== undefined ? value : {}); })('versions', []).push({ version: '3.6.4', mode: IS_PURE ? 'pure' : 'global', copyright: '© 2020 Denis Pushkarev (zloirock.ru)' }); /***/ }), /***/ "./node_modules/core-js/internals/to-primitive.js": /*!********************************************************!*\ !*** ./node_modules/core-js/internals/to-primitive.js ***! \********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var isObject = __webpack_require__(/*! ../internals/is-object */ "./node_modules/core-js/internals/is-object.js"); // `ToPrimitive` abstract operation // https://tc39.github.io/ecma262/#sec-toprimitive // instead of the ES6 spec version, we didn't implement @@toPrimitive case // and the second argument - flag - preferred type is a string module.exports = function (input, PREFERRED_STRING) { if (!isObject(input)) return input; var fn, val; if (PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val; if (typeof (fn = input.valueOf) == 'function' && !isObject(val = fn.call(input))) return val; if (!PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val; throw TypeError("Can't convert object to primitive value"); }; /***/ }), /***/ "./node_modules/core-js/internals/to-string-tag-support.js": /*!*****************************************************************!*\ !*** ./node_modules/core-js/internals/to-string-tag-support.js ***! \*****************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var wellKnownSymbol = __webpack_require__(/*! ../internals/well-known-symbol */ "./node_modules/core-js/internals/well-known-symbol.js"); var TO_STRING_TAG = wellKnownSymbol('toStringTag'); var test = {}; test[TO_STRING_TAG] = 'z'; module.exports = String(test) === '[object z]'; /***/ }), /***/ "./node_modules/core-js/internals/uid.js": /*!***********************************************!*\ !*** ./node_modules/core-js/internals/uid.js ***! \***********************************************/ /*! no static exports found */ /***/ (function(module, exports) { var id = 0; var postfix = Math.random(); module.exports = function (key) { return 'Symbol(' + String(key === undefined ? '' : key) + ')_' + (++id + postfix).toString(36); }; /***/ }), /***/ "./node_modules/core-js/internals/use-symbol-as-uid.js": /*!*************************************************************!*\ !*** ./node_modules/core-js/internals/use-symbol-as-uid.js ***! \*************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var NATIVE_SYMBOL = __webpack_require__(/*! ../internals/native-symbol */ "./node_modules/core-js/internals/native-symbol.js"); module.exports = NATIVE_SYMBOL // eslint-disable-next-line no-undef && !Symbol.sham // eslint-disable-next-line no-undef && typeof Symbol.iterator == 'symbol'; /***/ }), /***/ "./node_modules/core-js/internals/well-known-symbol.js": /*!*************************************************************!*\ !*** ./node_modules/core-js/internals/well-known-symbol.js ***! \*************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var global = __webpack_require__(/*! ../internals/global */ "./node_modules/core-js/internals/global.js"); var shared = __webpack_require__(/*! ../internals/shared */ "./node_modules/core-js/internals/shared.js"); var has = __webpack_require__(/*! ../internals/has */ "./node_modules/core-js/internals/has.js"); var uid = __webpack_require__(/*! ../internals/uid */ "./node_modules/core-js/internals/uid.js"); var NATIVE_SYMBOL = __webpack_require__(/*! ../internals/native-symbol */ "./node_modules/core-js/internals/native-symbol.js"); var USE_SYMBOL_AS_UID = __webpack_require__(/*! ../internals/use-symbol-as-uid */ "./node_modules/core-js/internals/use-symbol-as-uid.js"); var WellKnownSymbolsStore = shared('wks'); var Symbol = global.Symbol; var createWellKnownSymbol = USE_SYMBOL_AS_UID ? Symbol : Symbol && Symbol.withoutSetter || uid; module.exports = function (name) { if (!has(WellKnownSymbolsStore, name)) { if (NATIVE_SYMBOL && has(Symbol, name)) WellKnownSymbolsStore[name] = Symbol[name]; else WellKnownSymbolsStore[name] = createWellKnownSymbol('Symbol.' + name); } return WellKnownSymbolsStore[name]; }; /***/ }), /***/ "./node_modules/core-js/modules/es.date.to-string.js": /*!***********************************************************!*\ !*** ./node_modules/core-js/modules/es.date.to-string.js ***! \***********************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var redefine = __webpack_require__(/*! ../internals/redefine */ "./node_modules/core-js/internals/redefine.js"); var DatePrototype = Date.prototype; var INVALID_DATE = 'Invalid Date'; var TO_STRING = 'toString'; var nativeDateToString = DatePrototype[TO_STRING]; var getTime = DatePrototype.getTime; // `Date.prototype.toString` method // https://tc39.github.io/ecma262/#sec-date.prototype.tostring if (new Date(NaN) + '' != INVALID_DATE) { redefine(DatePrototype, TO_STRING, function toString() { var value = getTime.call(this); // eslint-disable-next-line no-self-compare return value === value ? nativeDateToString.call(this) : INVALID_DATE; }); } /***/ }), /***/ "./node_modules/core-js/modules/es.object.to-string.js": /*!*************************************************************!*\ !*** ./node_modules/core-js/modules/es.object.to-string.js ***! \*************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var TO_STRING_TAG_SUPPORT = __webpack_require__(/*! ../internals/to-string-tag-support */ "./node_modules/core-js/internals/to-string-tag-support.js"); var redefine = __webpack_require__(/*! ../internals/redefine */ "./node_modules/core-js/internals/redefine.js"); var toString = __webpack_require__(/*! ../internals/object-to-string */ "./node_modules/core-js/internals/object-to-string.js"); // `Object.prototype.toString` method // https://tc39.github.io/ecma262/#sec-object.prototype.tostring if (!TO_STRING_TAG_SUPPORT) { redefine(Object.prototype, 'toString', toString, { unsafe: true }); } /***/ }), /***/ "./node_modules/core-js/modules/es.regexp.to-string.js": /*!*************************************************************!*\ !*** ./node_modules/core-js/modules/es.regexp.to-string.js ***! \*************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var redefine = __webpack_require__(/*! ../internals/redefine */ "./node_modules/core-js/internals/redefine.js"); var anObject = __webpack_require__(/*! ../internals/an-object */ "./node_modules/core-js/internals/an-object.js"); var fails = __webpack_require__(/*! ../internals/fails */ "./node_modules/core-js/internals/fails.js"); var flags = __webpack_require__(/*! ../internals/regexp-flags */ "./node_modules/core-js/internals/regexp-flags.js"); var TO_STRING = 'toString'; var RegExpPrototype = RegExp.prototype; var nativeToString = RegExpPrototype[TO_STRING]; var NOT_GENERIC = fails(function () { return nativeToString.call({ source: 'a', flags: 'b' }) != '/a/b'; }); // FF44- RegExp#toString has a wrong name var INCORRECT_NAME = nativeToString.name != TO_STRING; // `RegExp.prototype.toString` method // https://tc39.github.io/ecma262/#sec-regexp.prototype.tostring if (NOT_GENERIC || INCORRECT_NAME) { redefine(RegExp.prototype, TO_STRING, function toString() { var R = anObject(this); var p = String(R.source); var rf = R.flags; var f = String(rf === undefined && R instanceof RegExp && !('flags' in RegExpPrototype) ? flags.call(R) : rf); return '/' + p + '/' + f; }, { unsafe: true }); } /***/ }), /***/ "./node_modules/webpack/buildin/global.js": /*!***********************************!*\ !*** (webpack)/buildin/global.js ***! \***********************************/ /*! no static exports found */ /***/ (function(module, exports) { var g; // This works in non-strict mode g = (function() { return this; })(); try { // This works if eval is allowed (see CSP) g = g || new Function("return this")(); } catch (e) { // This works if the window reference is available if (typeof window === "object") g = window; } // g can still be undefined, but nothing to do about it... // We return undefined, instead of nothing here, so it's // easier to handle this case. if(!global) { ...} module.exports = g; /***/ }) }]); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvQGZ1bGxjYWxlbmRhci9jb3JlL2xvY2FsZXMvZnIuanMiLCJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL0BmdWxsY2FsZW5kYXIvY29yZS9tYWluLmNzcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvQGZ1bGxjYWxlbmRhci9jb3JlL21haW4uZXNtLmpzIiwid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9AZnVsbGNhbGVuZGFyL2RheWdyaWQvbWFpbi5jc3MiLCJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL0BmdWxsY2FsZW5kYXIvZGF5Z3JpZC9tYWluLmVzbS5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvQGZ1bGxjYWxlbmRhci9pbnRlcmFjdGlvbi9tYWluLmVzbS5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvY29yZS1qcy9pbnRlcm5hbHMvYW4tb2JqZWN0LmpzIiwid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9jb3JlLWpzL2ludGVybmFscy9jbGFzc29mLXJhdy5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvY29yZS1qcy9pbnRlcm5hbHMvY2xhc3NvZi5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvY29yZS1qcy9pbnRlcm5hbHMvY3JlYXRlLW5vbi1lbnVtZXJhYmxlLXByb3BlcnR5LmpzIiwid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9jb3JlLWpzL2ludGVybmFscy9jcmVhdGUtcHJvcGVydHktZGVzY3JpcHRvci5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvY29yZS1qcy9pbnRlcm5hbHMvZGVzY3JpcHRvcnMuanMiLCJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL2NvcmUtanMvaW50ZXJuYWxzL2RvY3VtZW50LWNyZWF0ZS1lbGVtZW50LmpzIiwid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9jb3JlLWpzL2ludGVybmFscy9mYWlscy5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvY29yZS1qcy9pbnRlcm5hbHMvZ2xvYmFsLmpzIiwid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9jb3JlLWpzL2ludGVybmFscy9oYXMuanMiLCJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL2NvcmUtanMvaW50ZXJuYWxzL2hpZGRlbi1rZXlzLmpzIiwid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9jb3JlLWpzL2ludGVybmFscy9pZTgtZG9tLWRlZmluZS5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvY29yZS1qcy9pbnRlcm5hbHMvaW5zcGVjdC1zb3VyY2UuanMiLCJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL2NvcmUtanMvaW50ZXJuYWxzL2ludGVybmFsLXN0YXRlLmpzIiwid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9jb3JlLWpzL2ludGVybmFscy9pcy1vYmplY3QuanMiLCJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL2NvcmUtanMvaW50ZXJuYWxzL2lzLXB1cmUuanMiLCJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL2NvcmUtanMvaW50ZXJuYWxzL25hdGl2ZS1zeW1ib2wuanMiLCJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL2NvcmUtanMvaW50ZXJuYWxzL25hdGl2ZS13ZWFrLW1hcC5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvY29yZS1qcy9pbnRlcm5hbHMvb2JqZWN0LWRlZmluZS1wcm9wZXJ0eS5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvY29yZS1qcy9pbnRlcm5hbHMvb2JqZWN0LXRvLXN0cmluZy5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvY29yZS1qcy9pbnRlcm5hbHMvcmVkZWZpbmUuanMiLCJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL2NvcmUtanMvaW50ZXJuYWxzL3JlZ2V4cC1mbGFncy5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvY29yZS1qcy9pbnRlcm5hbHMvc2V0LWdsb2JhbC5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvY29yZS1qcy9pbnRlcm5hbHMvc2hhcmVkLWtleS5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvY29yZS1qcy9pbnRlcm5hbHMvc2hhcmVkLXN0b3JlLmpzIiwid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9jb3JlLWpzL2ludGVybmFscy9zaGFyZWQuanMiLCJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL2NvcmUtanMvaW50ZXJuYWxzL3RvLXByaW1pdGl2ZS5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvY29yZS1qcy9pbnRlcm5hbHMvdG8tc3RyaW5nLXRhZy1zdXBwb3J0LmpzIiwid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9jb3JlLWpzL2ludGVybmFscy91aWQuanMiLCJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL2NvcmUtanMvaW50ZXJuYWxzL3VzZS1zeW1ib2wtYXMtdWlkLmpzIiwid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9jb3JlLWpzL2ludGVybmFscy93ZWxsLWtub3duLXN5bWJvbC5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvY29yZS1qcy9tb2R1bGVzL2VzLmRhdGUudG8tc3RyaW5nLmpzIiwid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9jb3JlLWpzL21vZHVsZXMvZXMub2JqZWN0LnRvLXN0cmluZy5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvY29yZS1qcy9tb2R1bGVzL2VzLnJlZ2V4cC50by1zdHJpbmcuanMiLCJ3ZWJwYWNrOi8vLyh3ZWJwYWNrKS9idWlsZGluL2dsb2JhbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFBQTtBQUNBLElBQUksS0FBNEQ7QUFDaEUsSUFBSSxTQUNxSTtBQUN6SSxDQUFDLG9CQUFvQjs7QUFFckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxDQUFDOzs7Ozs7Ozs7Ozs7QUM5QkQsdUM7Ozs7Ozs7Ozs7OztBQ0FBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7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QUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUM7QUFDdkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxxREFBcUQ7QUFDckQsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLHFEQUFxRDtBQUNyRCxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQ0FBb0M7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrREFBa0Q7QUFDbEQ7QUFDQTtBQUNBO0FBQ0EsdUNBQXVDO0FBQ3ZDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7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O0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQjtBQUMzQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVDQUF1QyxpQkFBaUI7QUFDeEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaURBQWlEO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlDQUFpQztBQUNqQztBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0EsVUFBVSw0Q0FBNEM7QUFDdEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3REFBd0Q7QUFDeEQsb0JBQW9CO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBLDhEQUE4RDtBQUM5RCxvQkFBb0I7QUFDcEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQjtBQUNwQjtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IsdUJBQXVCO0FBQy9DO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQjtBQUNwQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJDQUEyQztBQUMzQztBQUNBLG9CQUFvQjtBQUNwQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQjtBQUMxQjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw2Q0FBNkM7QUFDN0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVDQUF1QyxnQkFBZ0I7QUFDdkQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUNBQXVDLGdCQUFnQjtBQUN2RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQkFBbUIsU0FBUztBQUM1QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQkFBbUIsU0FBUztBQUM1QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCLDZDQUE2QztBQUMxRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1RUFBdUU7QUFDdkUseUNBQXlDO0FBQ3pDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3REFBd0Q7QUFDeEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtEQUFrRDtBQUNsRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhDQUE4QztBQUM5QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3QjtBQUN4QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpREFBaUQ7QUFDakQ7QUFDQSwwQkFBMEI7QUFDMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpREFBaUQ7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0M7QUFDaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhDQUE4QztBQUM5QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0QkFBNEI7QUFDNUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsZ0JBQWdCO0FBQzlEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMEJBQTBCO0FBQzFCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQ0FBaUM7QUFDakM7QUFDQTtBQUNBO0FB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O0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1QkFBdUI7QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLG9DQUFvQyxhQUFhO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtDQUErQyx3QkFBd0I7QUFDdkU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7QUFDRDs7QUFFQSxzQkFBc0IsRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLDJCQUEyQixFQUFFLFFBQVEsRUFBRTtBQUM5RztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQkFBb0I7QUFDcEI7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQjtBQUNwQjtBQUNBO0FBQ0E7QUFDQSxvQkFBb0I7QUFDcEI7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQjtBQUNwQjtBQUNBO0FBQ0E7QUFDQSxvQkFBb0I7QUFDcEI7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNB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QUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtCQUErQixVQUFVO0FBQ3pDLDhuQkFBOG5CO0FBQzluQiwrREFBK0QsZ0JBQWdCO0FBQy9FO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Es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Q0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCO0FBQ2hCO0FBQ0E7QUFDQSxnQkFBZ0Isa0NBQWtDO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQkFBb0I7QUFDcEI7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQkFBa0I7QUFDbEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQ0FBa0M7QUFDbEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBbUM7QUFDbkMsaUNBQWlDO0FBQ2pDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0VBQWdFO0FBQ2hFO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0NBQXNDO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLG1EQUFtRCwwQkFBMEI7QUFDN0U7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDO0FBQ3JDLGtDQUFrQztBQUNsQyw0REFBNEQsZ0JBQWdCO0FBQzVFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBLG1EQUFtRCwwQkFBMEI7QUFDN0U7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0QkFBNEIsZUFBZSxFQUFFO0FBQzdDLDRCQUE0Qiw4Q0FBOEM7QUFDMUU7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCO0FBQzVCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1EQUFtRDtBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdEQUFnRDtBQUNoRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtCQUErQjtBQUMvQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMENBQTBDLFVBQVUscVRBQXFUO0FBQ3pXO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1DQUFtQztBQUNuQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFD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QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQ0FBc0M7QUFDdEMsd0NBQXdDO0FBQ3hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzRUFBc0U7QUFDdEU7QUFDQTtBQUNBO0FBQ0EsUUFBUSxxRUFBVTtBQUNsQjtBQUNBO0FBQ0EsU0FBUztBQUNULFFBQVEsNkVBQWtCO0FBQzFCO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0EsWUFBWSx3RUFBYTtBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLHFFQUFVO0FBQ3RCO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUVBQXFFO0FBQ3JFO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxxRUFBVTtBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFEQUFxRDtBQUNyRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FB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QkFBMEIsWUFBWSxFQUFFO0FBQzFHO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRyxHQUFHLGVBQWU7QUFDckI7Ozs7Ozs7Ozs7OztBQ3hCQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBLENBQUM7QUFDRDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLDRDQUE0Qzs7QUFFNUMiLCJmaWxlIjoidmVuZG9yc35mdWxsY2FsZW5kYXIuanMiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gKGdsb2JhbCwgZmFjdG9yeSkge1xuICAgIHR5cGVvZiBleHBvcnRzID09PSAnb2JqZWN0JyAmJiB0eXBlb2YgbW9kdWxlICE9PSAndW5kZWZpbmVkJyA/IG1vZHVsZS5leHBvcnRzID0gZmFjdG9yeSgpIDpcbiAgICB0eXBlb2YgZGVmaW5lID09PSAnZnVuY3Rpb24nICYmIGRlZmluZS5hbWQgPyBkZWZpbmUoZmFjdG9yeSkgOlxuICAgIChnbG9iYWwgPSBnbG9iYWwgfHwgc2VsZiwgKGdsb2JhbC5GdWxsQ2FsZW5kYXJMb2NhbGVzID0gZ2xvYmFsLkZ1bGxDYWxlbmRhckxvY2FsZXMgfHwge30sIGdsb2JhbC5GdWxsQ2FsZW5kYXJMb2NhbGVzLmZyID0gZmFjdG9yeSgpKSk7XG59KHRoaXMsIGZ1bmN0aW9uICgpIHsgJ3VzZSBzdHJpY3QnO1xuXG4gICAgdmFyIGZyID0ge1xuICAgICAgICBjb2RlOiBcImZyXCIsXG4gICAgICAgIHdlZWs6IHtcbiAgICAgICAgICAgIGRvdzogMSxcbiAgICAgICAgICAgIGRveTogNCAvLyBUaGUgd2VlayB0aGF0IGNvbnRhaW5zIEphbiA0dGggaXMgdGhlIGZpcnN0IHdlZWsgb2YgdGhlIHllYXIuXG4gICAgICAgIH0sXG4gICAgICAgIGJ1dHRvblRleHQ6IHtcbiAgICAgICAgICAgIHByZXY6IFwiUHLDqWPDqWRlbnRcIixcbiAgICAgICAgICAgIG5leHQ6IFwiU3VpdmFudFwiLFxuICAgICAgICAgICAgdG9kYXk6IFwiQXVqb3VyZCdodWlcIixcbiAgICAgICAgICAgIHllYXI6IFwiQW5uw6llXCIsXG4gICAgICAgICAgICBtb250aDogXCJNb2lzXCIsXG4gICAgICAgICAgICB3ZWVrOiBcIlNlbWFpbmVcIixcbiAgICAgICAgICAgIGRheTogXCJKb3VyXCIsXG4gICAgICAgICAgICBsaXN0OiBcIlBsYW5uaW5nXCJcbiAgICAgICAgfSxcbiAgICAgICAgd2Vla0xhYmVsOiBcIlNlbS5cIixcbiAgICAgICAgYWxsRGF5SHRtbDogXCJUb3V0ZSBsYTxici8+am91cm7DqWVcIixcbiAgICAgICAgZXZlbnRMaW1pdFRleHQ6IFwiZW4gcGx1c1wiLFxuICAgICAgICBub0V2ZW50c01lc3NhZ2U6IFwiQXVjdW4gw6l2w6luZW1lbnQgw6AgYWZmaWNoZXJcIlxuICAgIH07XG5cbiAgICByZXR1cm4gZnI7XG5cbn0pKTtcbiIsIi8vIGV4dHJhY3RlZCBieSBtaW5pLWNzcy1leHRyYWN0LXBsdWdpbiIsIi8qIVxuRnVsbENhbGVuZGFyIENvcmUgUGFja2FnZSB2NC40LjBcbkRvY3MgJiBMaWNlbnNlOiBodHRwczovL2Z1bGxjYWxlbmRhci5pby9cbihjKSAyMDE5IEFkYW0gU2hhd1xuKi9cblxuLy8gQ3JlYXRpbmdcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbnZhciBlbGVtZW50UHJvcEhhc2ggPSB7XG4gICAgY2xhc3NOYW1lOiB0cnVlLFxuICAgIGNvbFNwYW46IHRydWUsXG4gICAgcm93U3BhbjogdHJ1ZVxufTtcbnZhciBjb250YWluZXJUYWdIYXNoID0ge1xuICAgICc8dHInOiAndGJvZHknLFxuICAgICc8dGQnOiAndHInXG59O1xuZnVuY3Rpb24gY3JlYXRlRWxlbWVudCh0YWdOYW1lLCBhdHRycywgY29udGVudCkge1xuICAgIHZhciBlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQodGFnTmFtZSk7XG4gICAgaWYgKGF0dHJzKSB7XG4gICAgICAgIGZvciAodmFyIGF0dHJOYW1lIGluIGF0dHJzKSB7XG4gICAgICAgICAgICBpZiAoYXR0ck5hbWUgPT09ICdzdHlsZScpIHtcbiAgICAgICAgICAgICAgICBhcHBseVN0eWxlKGVsLCBhdHRyc1thdHRyTmFtZV0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoZWxlbWVudFByb3BIYXNoW2F0dHJOYW1lXSkge1xuICAgICAgICAgICAgICAgIGVsW2F0dHJOYW1lXSA9IGF0dHJzW2F0dHJOYW1lXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGVsLnNldEF0dHJpYnV0ZShhdHRyTmFtZSwgYXR0cnNbYXR0ck5hbWVdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAodHlwZW9mIGNvbnRlbnQgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgIGVsLmlubmVySFRNTCA9IGNvbnRlbnQ7IC8vIHNob3J0Y3V0LiBubyBuZWVkIHRvIHByb2Nlc3MgSFRNTCBpbiBhbnkgd2F5XG4gICAgfVxuICAgIGVsc2UgaWYgKGNvbnRlbnQgIT0gbnVsbCkge1xuICAgICAgICBhcHBlbmRUb0VsZW1lbnQoZWwsIGNvbnRlbnQpO1xuICAgIH1cbiAgICByZXR1cm4gZWw7XG59XG5mdW5jdGlvbiBodG1sVG9FbGVtZW50KGh0bWwpIHtcbiAgICBodG1sID0gaHRtbC50cmltKCk7XG4gICAgdmFyIGNvbnRhaW5lciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoY29tcHV0ZUNvbnRhaW5lclRhZyhodG1sKSk7XG4gICAgY29udGFpbmVyLmlubmVySFRNTCA9IGh0bWw7XG4gICAgcmV0dXJuIGNvbnRhaW5lci5maXJzdENoaWxkO1xufVxuZnVuY3Rpb24gaHRtbFRvRWxlbWVudHMoaHRtbCkge1xuICAgIHJldHVybiBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChodG1sVG9Ob2RlTGlzdChodG1sKSk7XG59XG5mdW5jdGlvbiBodG1sVG9Ob2RlTGlzdChodG1sKSB7XG4gICAgaHRtbCA9IGh0bWwudHJpbSgpO1xuICAgIHZhciBjb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KGNvbXB1dGVDb250YWluZXJUYWcoaHRtbCkpO1xuICAgIGNvbnRhaW5lci5pbm5lckhUTUwgPSBodG1sO1xuICAgIHJldHVybiBjb250YWluZXIuY2hpbGROb2Rlcztcbn1cbi8vIGFzc3VtZXMgaHRtbCBhbHJlYWR5IHRyaW1tZWQgYW5kIHRhZyBuYW1lcyBhcmUgbG93ZXJjYXNlXG5mdW5jdGlvbiBjb21wdXRlQ29udGFpbmVyVGFnKGh0bWwpIHtcbiAgICByZXR1cm4gY29udGFpbmVyVGFnSGFzaFtodG1sLnN1YnN0cigwLCAzKSAvLyBmYXN0ZXIgdGhhbiB1c2luZyByZWdleFxuICAgIF0gfHwgJ2Rpdic7XG59XG5mdW5jdGlvbiBhcHBlbmRUb0VsZW1lbnQoZWwsIGNvbnRlbnQpIHtcbiAgICB2YXIgY2hpbGROb2RlcyA9IG5vcm1hbGl6ZUNvbnRlbnQoY29udGVudCk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjaGlsZE5vZGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGVsLmFwcGVuZENoaWxkKGNoaWxkTm9kZXNbaV0pO1xuICAgIH1cbn1cbmZ1bmN0aW9uIHByZXBlbmRUb0VsZW1lbnQocGFyZW50LCBjb250ZW50KSB7XG4gICAgdmFyIG5ld0VscyA9IG5vcm1hbGl6ZUNvbnRlbnQoY29udGVudCk7XG4gICAgdmFyIGFmdGVyRWwgPSBwYXJlbnQuZmlyc3RDaGlsZCB8fCBudWxsOyAvLyBpZiBubyBmaXJzdENoaWxkLCB3aWxsIGFwcGVuZCB0byBlbmQsIGJ1dCB0aGF0J3Mgb2theSwgYi9jIHRoZXJlIHdlcmUgbm8gY2hpbGRyZW5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG5ld0Vscy5sZW5ndGg7IGkrKykge1xuICAgICAgICBwYXJlbnQuaW5zZXJ0QmVmb3JlKG5ld0Vsc1tpXSwgYWZ0ZXJFbCk7XG4gICAgfVxufVxuZnVuY3Rpb24gaW5zZXJ0QWZ0ZXJFbGVtZW50KHJlZkVsLCBjb250ZW50KSB7XG4gICAgdmFyIG5ld0VscyA9IG5vcm1hbGl6ZUNvbnRlbnQoY29udGVudCk7XG4gICAgdmFyIGFmdGVyRWwgPSByZWZFbC5uZXh0U2libGluZyB8fCBudWxsO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbmV3RWxzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHJlZkVsLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKG5ld0Vsc1tpXSwgYWZ0ZXJFbCk7XG4gICAgfVxufVxuZnVuY3Rpb24gbm9ybWFsaXplQ29udGVudChjb250ZW50KSB7XG4gICAgdmFyIGVscztcbiAgICBpZiAodHlwZW9mIGNvbnRlbnQgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgIGVscyA9IGh0bWxUb0VsZW1lbnRzKGNvbnRlbnQpO1xuICAgIH1cbiAgICBlbHNlIGlmIChjb250ZW50IGluc3RhbmNlb2YgTm9kZSkge1xuICAgICAgICBlbHMgPSBbY29udGVudF07XG4gICAgfVxuICAgIGVsc2UgeyAvLyBOb2RlW10gb3IgTm9kZUxpc3RcbiAgICAgICAgZWxzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoY29udGVudCk7XG4gICAgfVxuICAgIHJldHVybiBlbHM7XG59XG5mdW5jdGlvbiByZW1vdmVFbGVtZW50KGVsKSB7XG4gICAgaWYgKGVsLnBhcmVudE5vZGUpIHtcbiAgICAgICAgZWwucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChlbCk7XG4gICAgfVxufVxuLy8gUXVlcnlpbmdcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIGZyb20gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL0VsZW1lbnQvY2xvc2VzdFxudmFyIG1hdGNoZXNNZXRob2QgPSBFbGVtZW50LnByb3RvdHlwZS5tYXRjaGVzIHx8XG4gICAgRWxlbWVudC5wcm90b3R5cGUubWF0Y2hlc1NlbGVjdG9yIHx8XG4gICAgRWxlbWVudC5wcm90b3R5cGUubXNNYXRjaGVzU2VsZWN0b3I7XG52YXIgY2xvc2VzdE1ldGhvZCA9IEVsZW1lbnQucHJvdG90eXBlLmNsb3Nlc3QgfHwgZnVuY3Rpb24gKHNlbGVjdG9yKSB7XG4gICAgLy8gcG9seWZpbGxcbiAgICB2YXIgZWwgPSB0aGlzO1xuICAgIGlmICghZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNvbnRhaW5zKGVsKSkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgZG8ge1xuICAgICAgICBpZiAoZWxlbWVudE1hdGNoZXMoZWwsIHNlbGVjdG9yKSkge1xuICAgICAgICAgICAgcmV0dXJuIGVsO1xuICAgICAgICB9XG4gICAgICAgIGVsID0gZWwucGFyZW50RWxlbWVudCB8fCBlbC5wYXJlbnROb2RlO1xuICAgIH0gd2hpbGUgKGVsICE9PSBudWxsICYmIGVsLm5vZGVUeXBlID09PSAxKTtcbiAgICByZXR1cm4gbnVsbDtcbn07XG5mdW5jdGlvbiBlbGVtZW50Q2xvc2VzdChlbCwgc2VsZWN0b3IpIHtcbiAgICByZXR1cm4gY2xvc2VzdE1ldGhvZC5jYWxsKGVsLCBzZWxlY3Rvcik7XG59XG5mdW5jdGlvbiBlbGVtZW50TWF0Y2hlcyhlbCwgc2VsZWN0b3IpIHtcbiAgICByZXR1cm4gbWF0Y2hlc01ldGhvZC5jYWxsKGVsLCBzZWxlY3Rvcik7XG59XG4vLyBhY2NlcHRzIG11bHRpcGxlIHN1YmplY3QgZWxzXG4vLyByZXR1cm5zIGEgcmVhbCBhcnJheS4gZ29vZCBmb3IgbWV0aG9kcyBsaWtlIGZvckVhY2hcbmZ1bmN0aW9uIGZpbmRFbGVtZW50cyhjb250YWluZXIsIHNlbGVjdG9yKSB7XG4gICAgdmFyIGNvbnRhaW5lcnMgPSBjb250YWluZXIgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCA/IFtjb250YWluZXJdIDogY29udGFpbmVyO1xuICAgIHZhciBhbGxNYXRjaGVzID0gW107XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb250YWluZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBtYXRjaGVzID0gY29udGFpbmVyc1tpXS5xdWVyeVNlbGVjdG9yQWxsKHNlbGVjdG9yKTtcbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBtYXRjaGVzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICBhbGxNYXRjaGVzLnB1c2gobWF0Y2hlc1tqXSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGFsbE1hdGNoZXM7XG59XG4vLyBhY2NlcHRzIG11bHRpcGxlIHN1YmplY3QgZWxzXG4vLyBvbmx5IHF1ZXJpZXMgZGlyZWN0IGNoaWxkIGVsZW1lbnRzXG5mdW5jdGlvbiBmaW5kQ2hpbGRyZW4ocGFyZW50LCBzZWxlY3Rvcikge1xuICAgIHZhciBwYXJlbnRzID0gcGFyZW50IGluc3RhbmNlb2YgSFRNTEVsZW1lbnQgPyBbcGFyZW50XSA6IHBhcmVudDtcbiAgICB2YXIgYWxsTWF0Y2hlcyA9IFtdO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcGFyZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgY2hpbGROb2RlcyA9IHBhcmVudHNbaV0uY2hpbGRyZW47IC8vIG9ubHkgZXZlciBlbGVtZW50c1xuICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGNoaWxkTm9kZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgIHZhciBjaGlsZE5vZGUgPSBjaGlsZE5vZGVzW2pdO1xuICAgICAgICAgICAgaWYgKCFzZWxlY3RvciB8fCBlbGVtZW50TWF0Y2hlcyhjaGlsZE5vZGUsIHNlbGVjdG9yKSkge1xuICAgICAgICAgICAgICAgIGFsbE1hdGNoZXMucHVzaChjaGlsZE5vZGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBhbGxNYXRjaGVzO1xufVxuLy8gQXR0cmlidXRlc1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuZnVuY3Rpb24gZm9yY2VDbGFzc05hbWUoZWwsIGNsYXNzTmFtZSwgYm9vbCkge1xuICAgIGlmIChib29sKSB7XG4gICAgICAgIGVsLmNsYXNzTGlzdC5hZGQoY2xhc3NOYW1lKTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGVsLmNsYXNzTGlzdC5yZW1vdmUoY2xhc3NOYW1lKTtcbiAgICB9XG59XG4vLyBTdHlsZVxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxudmFyIFBJWEVMX1BST1BfUkUgPSAvKHRvcHxsZWZ0fHJpZ2h0fGJvdHRvbXx3aWR0aHxoZWlnaHQpJC9pO1xuZnVuY3Rpb24gYXBwbHlTdHlsZShlbCwgcHJvcHMpIHtcbiAgICBmb3IgKHZhciBwcm9wTmFtZSBpbiBwcm9wcykge1xuICAgICAgICBhcHBseVN0eWxlUHJvcChlbCwgcHJvcE5hbWUsIHByb3BzW3Byb3BOYW1lXSk7XG4gICAgfVxufVxuZnVuY3Rpb24gYXBwbHlTdHlsZVByb3AoZWwsIG5hbWUsIHZhbCkge1xuICAgIGlmICh2YWwgPT0gbnVsbCkge1xuICAgICAgICBlbC5zdHlsZVtuYW1lXSA9ICcnO1xuICAgIH1cbiAgICBlbHNlIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJyAmJiBQSVhFTF9QUk9QX1JFLnRlc3QobmFtZSkpIHtcbiAgICAgICAgZWwuc3R5bGVbbmFtZV0gPSB2YWwgKyAncHgnO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgZWwuc3R5bGVbbmFtZV0gPSB2YWw7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBwb2ludEluc2lkZVJlY3QocG9pbnQsIHJlY3QpIHtcbiAgICByZXR1cm4gcG9pbnQubGVmdCA+PSByZWN0LmxlZnQgJiZcbiAgICAgICAgcG9pbnQubGVmdCA8IHJlY3QucmlnaHQgJiZcbiAgICAgICAgcG9pbnQudG9wID49IHJlY3QudG9wICYmXG4gICAgICAgIHBvaW50LnRvcCA8IHJlY3QuYm90dG9tO1xufVxuLy8gUmV0dXJucyBhIG5ldyByZWN0YW5nbGUgdGhhdCBpcyB0aGUgaW50ZXJzZWN0aW9uIG9mIHRoZSB0d28gcmVjdGFuZ2xlcy4gSWYgdGhleSBkb24ndCBpbnRlcnNlY3QsIHJldHVybnMgZmFsc2VcbmZ1bmN0aW9uIGludGVyc2VjdFJlY3RzKHJlY3QxLCByZWN0Mikge1xuICAgIHZhciByZXMgPSB7XG4gICAgICAgIGxlZnQ6IE1hdGgubWF4KHJlY3QxLmxlZnQsIHJlY3QyLmxlZnQpLFxuICAgICAgICByaWdodDogTWF0aC5taW4ocmVjdDEucmlnaHQsIHJlY3QyLnJpZ2h0KSxcbiAgICAgICAgdG9wOiBNYXRoLm1heChyZWN0MS50b3AsIHJlY3QyLnRvcCksXG4gICAgICAgIGJvdHRvbTogTWF0aC5taW4ocmVjdDEuYm90dG9tLCByZWN0Mi5ib3R0b20pXG4gICAgfTtcbiAgICBpZiAocmVzLmxlZnQgPCByZXMucmlnaHQgJiYgcmVzLnRvcCA8IHJlcy5ib3R0b20pIHtcbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xufVxuZnVuY3Rpb24gdHJhbnNsYXRlUmVjdChyZWN0LCBkZWx0YVgsIGRlbHRhWSkge1xuICAgIHJldHVybiB7XG4gICAgICAgIGxlZnQ6IHJlY3QubGVmdCArIGRlbHRhWCxcbiAgICAgICAgcmlnaHQ6IHJlY3QucmlnaHQgKyBkZWx0YVgsXG4gICAgICAgIHRvcDogcmVjdC50b3AgKyBkZWx0YVksXG4gICAgICAgIGJvdHRvbTogcmVjdC5ib3R0b20gKyBkZWx0YVlcbiAgICB9O1xufVxuLy8gUmV0dXJucyBhIG5ldyBwb2ludCB0aGF0IHdpbGwgaGF2ZSBiZWVuIG1vdmVkIHRvIHJlc2lkZSB3aXRoaW4gdGhlIGdpdmVuIHJlY3RhbmdsZVxuZnVuY3Rpb24gY29uc3RyYWluUG9pbnQocG9pbnQsIHJlY3QpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBsZWZ0OiBNYXRoLm1pbihNYXRoLm1heChwb2ludC5sZWZ0LCByZWN0LmxlZnQpLCByZWN0LnJpZ2h0KSxcbiAgICAgICAgdG9wOiBNYXRoLm1pbihNYXRoLm1heChwb2ludC50b3AsIHJlY3QudG9wKSwgcmVjdC5ib3R0b20pXG4gICAgfTtcbn1cbi8vIFJldHVybnMgYSBwb2ludCB0aGF0IGlzIHRoZSBjZW50ZXIgb2YgdGhlIGdpdmVuIHJlY3RhbmdsZVxuZnVuY3Rpb24gZ2V0UmVjdENlbnRlcihyZWN0KSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgbGVmdDogKHJlY3QubGVmdCArIHJlY3QucmlnaHQpIC8gMixcbiAgICAgICAgdG9wOiAocmVjdC50b3AgKyByZWN0LmJvdHRvbSkgLyAyXG4gICAgfTtcbn1cbi8vIFN1YnRyYWN0cyBwb2ludDIncyBjb29yZGluYXRlcyBmcm9tIHBvaW50MSdzIGNvb3JkaW5hdGVzLCByZXR1cm5pbmcgYSBkZWx0YVxuZnVuY3Rpb24gZGlmZlBvaW50cyhwb2ludDEsIHBvaW50Mikge1xuICAgIHJldHVybiB7XG4gICAgICAgIGxlZnQ6IHBvaW50MS5sZWZ0IC0gcG9pbnQyLmxlZnQsXG4gICAgICAgIHRvcDogcG9pbnQxLnRvcCAtIHBvaW50Mi50b3BcbiAgICB9O1xufVxuXG4vLyBMb2dpYyBmb3IgZGV0ZXJtaW5pbmcgaWYsIHdoZW4gdGhlIGVsZW1lbnQgaXMgcmlnaHQtdG8tbGVmdCwgdGhlIHNjcm9sbGJhciBhcHBlYXJzIG9uIHRoZSBsZWZ0IHNpZGVcbnZhciBpc1J0bFNjcm9sbGJhck9uTGVmdCA9IG51bGw7XG5mdW5jdGlvbiBnZXRJc1J0bFNjcm9sbGJhck9uTGVmdCgpIHtcbiAgICBpZiAoaXNSdGxTY3JvbGxiYXJPbkxlZnQgPT09IG51bGwpIHtcbiAgICAgICAgaXNSdGxTY3JvbGxiYXJPbkxlZnQgPSBjb21wdXRlSXNSdGxTY3JvbGxiYXJPbkxlZnQoKTtcbiAgICB9XG4gICAgcmV0dXJuIGlzUnRsU2Nyb2xsYmFyT25MZWZ0O1xufVxuZnVuY3Rpb24gY29tcHV0ZUlzUnRsU2Nyb2xsYmFyT25MZWZ0KCkge1xuICAgIHZhciBvdXRlckVsID0gY3JlYXRlRWxlbWVudCgnZGl2Jywge1xuICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgcG9zaXRpb246ICdhYnNvbHV0ZScsXG4gICAgICAgICAgICB0b3A6IC0xMDAwLFxuICAgICAgICAgICAgbGVmdDogMCxcbiAgICAgICAgICAgIGJvcmRlcjogMCxcbiAgICAgICAgICAgIHBhZGRpbmc6IDAsXG4gICAgICAgICAgICBvdmVyZmxvdzogJ3Njcm9sbCcsXG4gICAgICAgICAgICBkaXJlY3Rpb246ICdydGwnXG4gICAgICAgIH1cbiAgICB9LCAnPGRpdj48L2Rpdj4nKTtcbiAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKG91dGVyRWwpO1xuICAgIHZhciBpbm5lckVsID0gb3V0ZXJFbC5maXJzdENoaWxkO1xuICAgIHZhciByZXMgPSBpbm5lckVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQgPiBvdXRlckVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQ7XG4gICAgcmVtb3ZlRWxlbWVudChvdXRlckVsKTtcbiAgICByZXR1cm4gcmVzO1xufVxuLy8gVGhlIHNjcm9sbGJhciB3aWR0aCBjb21wdXRhdGlvbnMgaW4gY29tcHV0ZUVkZ2VzIGFyZSBzb21ldGltZXMgZmxhd2VkIHdoZW4gaXQgY29tZXMgdG9cbi8vIHJldGluYSBkaXNwbGF5cywgcm91bmRpbmcsIGFuZCBJRTExLiBNYXNzYWdlIHRoZW0gaW50byBhIHVzYWJsZSB2YWx1ZS5cbmZ1bmN0aW9uIHNhbml0aXplU2Nyb2xsYmFyV2lkdGgod2lkdGgpIHtcbiAgICB3aWR0aCA9IE1hdGgubWF4KDAsIHdpZHRoKTsgLy8gbm8gbmVnYXRpdmVzXG4gICAgd2lkdGggPSBNYXRoLnJvdW5kKHdpZHRoKTtcbiAgICByZXR1cm4gd2lkdGg7XG59XG5cbmZ1bmN0aW9uIGNvbXB1dGVFZGdlcyhlbCwgZ2V0UGFkZGluZykge1xuICAgIGlmIChnZXRQYWRkaW5nID09PSB2b2lkIDApIHsgZ2V0UGFkZGluZyA9IGZhbHNlOyB9XG4gICAgdmFyIGNvbXB1dGVkU3R5bGUgPSB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShlbCk7XG4gICAgdmFyIGJvcmRlckxlZnQgPSBwYXJzZUludChjb21wdXRlZFN0eWxlLmJvcmRlckxlZnRXaWR0aCwgMTApIHx8IDA7XG4gICAgdmFyIGJvcmRlclJpZ2h0ID0gcGFyc2VJbnQoY29tcHV0ZWRTdHlsZS5ib3JkZXJSaWdodFdpZHRoLCAxMCkgfHwgMDtcbiAgICB2YXIgYm9yZGVyVG9wID0gcGFyc2VJbnQoY29tcHV0ZWRTdHlsZS5ib3JkZXJUb3BXaWR0aCwgMTApIHx8IDA7XG4gICAgdmFyIGJvcmRlckJvdHRvbSA9IHBhcnNlSW50KGNvbXB1dGVkU3R5bGUuYm9yZGVyQm90dG9tV2lkdGgsIDEwKSB8fCAwO1xuICAgIC8vIG11c3QgdXNlIG9mZnNldChXaWR0aHxIZWlnaHQpIGJlY2F1c2UgY29tcGF0aWJsZSB3aXRoIGNsaWVudChXaWR0aHxIZWlnaHQpXG4gICAgdmFyIHNjcm9sbGJhckxlZnRSaWdodCA9IHNhbml0aXplU2Nyb2xsYmFyV2lkdGgoZWwub2Zmc2V0V2lkdGggLSBlbC5jbGllbnRXaWR0aCAtIGJvcmRlckxlZnQgLSBib3JkZXJSaWdodCk7XG4gICAgdmFyIHNjcm9sbGJhckJvdHRvbSA9IHNhbml0aXplU2Nyb2xsYmFyV2lkdGgoZWwub2Zmc2V0SGVpZ2h0IC0gZWwuY2xpZW50SGVpZ2h0IC0gYm9yZGVyVG9wIC0gYm9yZGVyQm90dG9tKTtcbiAgICB2YXIgcmVzID0ge1xuICAgICAgICBib3JkZXJMZWZ0OiBib3JkZXJMZWZ0LFxuICAgICAgICBib3JkZXJSaWdodDogYm9yZGVyUmlnaHQsXG4gICAgICAgIGJvcmRlclRvcDogYm9yZGVyVG9wLFxuICAgICAgICBib3JkZXJCb3R0b206IGJvcmRlckJvdHRvbSxcbiAgICAgICAgc2Nyb2xsYmFyQm90dG9tOiBzY3JvbGxiYXJCb3R0b20sXG4gICAgICAgIHNjcm9sbGJhckxlZnQ6IDAsXG4gICAgICAgIHNjcm9sbGJhclJpZ2h0OiAwXG4gICAgfTtcbiAgICBpZiAoZ2V0SXNSdGxTY3JvbGxiYXJPbkxlZnQoKSAmJiBjb21wdXRlZFN0eWxlLmRpcmVjdGlvbiA9PT0gJ3J0bCcpIHsgLy8gaXMgdGhlIHNjcm9sbGJhciBvbiB0aGUgbGVmdCBzaWRlP1xuICAgICAgICByZXMuc2Nyb2xsYmFyTGVmdCA9IHNjcm9sbGJhckxlZnRSaWdodDtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHJlcy5zY3JvbGxiYXJSaWdodCA9IHNjcm9sbGJhckxlZnRSaWdodDtcbiAgICB9XG4gICAgaWYgKGdldFBhZGRpbmcpIHtcbiAgICAgICAgcmVzLnBhZGRpbmdMZWZ0ID0gcGFyc2VJbnQoY29tcHV0ZWRTdHlsZS5wYWRkaW5nTGVmdCwgMTApIHx8IDA7XG4gICAgICAgIHJlcy5wYWRkaW5nUmlnaHQgPSBwYXJzZUludChjb21wdXRlZFN0eWxlLnBhZGRpbmdSaWdodCwgMTApIHx8IDA7XG4gICAgICAgIHJlcy5wYWRkaW5nVG9wID0gcGFyc2VJbnQoY29tcHV0ZWRTdHlsZS5wYWRkaW5nVG9wLCAxMCkgfHwgMDtcbiAgICAgICAgcmVzLnBhZGRpbmdCb3R0b20gPSBwYXJzZUludChjb21wdXRlZFN0eWxlLnBhZGRpbmdCb3R0b20sIDEwKSB8fCAwO1xuICAgIH1cbiAgICByZXR1cm4gcmVzO1xufVxuZnVuY3Rpb24gY29tcHV0ZUlubmVyUmVjdChlbCwgZ29XaXRoaW5QYWRkaW5nKSB7XG4gICAgaWYgKGdvV2l0aGluUGFkZGluZyA9PT0gdm9pZCAwKSB7IGdvV2l0aGluUGFkZGluZyA9IGZhbHNlOyB9XG4gICAgdmFyIG91dGVyUmVjdCA9IGNvbXB1dGVSZWN0KGVsKTtcbiAgICB2YXIgZWRnZXMgPSBjb21wdXRlRWRnZXMoZWwsIGdvV2l0aGluUGFkZGluZyk7XG4gICAgdmFyIHJlcyA9IHtcbiAgICAgICAgbGVmdDogb3V0ZXJSZWN0LmxlZnQgKyBlZGdlcy5ib3JkZXJMZWZ0ICsgZWRnZXMuc2Nyb2xsYmFyTGVmdCxcbiAgICAgICAgcmlnaHQ6IG91dGVyUmVjdC5yaWdodCAtIGVkZ2VzLmJvcmRlclJpZ2h0IC0gZWRnZXMuc2Nyb2xsYmFyUmlnaHQsXG4gICAgICAgIHRvcDogb3V0ZXJSZWN0LnRvcCArIGVkZ2VzLmJvcmRlclRvcCxcbiAgICAgICAgYm90dG9tOiBvdXRlclJlY3QuYm90dG9tIC0gZWRnZXMuYm9yZGVyQm90dG9tIC0gZWRnZXMuc2Nyb2xsYmFyQm90dG9tXG4gICAgfTtcbiAgICBpZiAoZ29XaXRoaW5QYWRkaW5nKSB7XG4gICAgICAgIHJlcy5sZWZ0ICs9IGVkZ2VzLnBhZGRpbmdMZWZ0O1xuICAgICAgICByZXMucmlnaHQgLT0gZWRnZXMucGFkZGluZ1JpZ2h0O1xuICAgICAgICByZXMudG9wICs9IGVkZ2VzLnBhZGRpbmdUb3A7XG4gICAgICAgIHJlcy5ib3R0b20gLT0gZWRnZXMucGFkZGluZ0JvdHRvbTtcbiAgICB9XG4gICAgcmV0dXJuIHJlcztcbn1cbmZ1bmN0aW9uIGNvbXB1dGVSZWN0KGVsKSB7XG4gICAgdmFyIHJlY3QgPSBlbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICByZXR1cm4ge1xuICAgICAgICBsZWZ0OiByZWN0LmxlZnQgKyB3aW5kb3cucGFnZVhPZmZzZXQsXG4gICAgICAgIHRvcDogcmVjdC50b3AgKyB3aW5kb3cucGFnZVlPZmZzZXQsXG4gICAgICAgIHJpZ2h0OiByZWN0LnJpZ2h0ICsgd2luZG93LnBhZ2VYT2Zmc2V0LFxuICAgICAgICBib3R0b206IHJlY3QuYm90dG9tICsgd2luZG93LnBhZ2VZT2Zmc2V0XG4gICAgfTtcbn1cbmZ1bmN0aW9uIGNvbXB1dGVWaWV3cG9ydFJlY3QoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgbGVmdDogd2luZG93LnBhZ2VYT2Zmc2V0LFxuICAgICAgICByaWdodDogd2luZG93LnBhZ2VYT2Zmc2V0ICsgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudFdpZHRoLFxuICAgICAgICB0b3A6IHdpbmRvdy5wYWdlWU9mZnNldCxcbiAgICAgICAgYm90dG9tOiB3aW5kb3cucGFnZVlPZmZzZXQgKyBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50SGVpZ2h0XG4gICAgfTtcbn1cbmZ1bmN0aW9uIGNvbXB1dGVIZWlnaHRBbmRNYXJnaW5zKGVsKSB7XG4gICAgcmV0dXJuIGVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmhlaWdodCArIGNvbXB1dGVWTWFyZ2lucyhlbCk7XG59XG5mdW5jdGlvbiBjb21wdXRlVk1hcmdpbnMoZWwpIHtcbiAgICB2YXIgY29tcHV0ZWQgPSB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShlbCk7XG4gICAgcmV0dXJuIHBhcnNlSW50KGNvbXB1dGVkLm1hcmdpblRvcCwgMTApICtcbiAgICAgICAgcGFyc2VJbnQoY29tcHV0ZWQubWFyZ2luQm90dG9tLCAxMCk7XG59XG4vLyBkb2VzIG5vdCByZXR1cm4gd2luZG93XG5mdW5jdGlvbiBnZXRDbGlwcGluZ1BhcmVudHMoZWwpIHtcbiAgICB2YXIgcGFyZW50cyA9IFtdO1xuICAgIHdoaWxlIChlbCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KSB7IC8vIHdpbGwgc3RvcCB3aGVuIGdldHMgdG8gZG9jdW1lbnQgb3IgbnVsbFxuICAgICAgICB2YXIgY29tcHV0ZWRTdHlsZSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGVsKTtcbiAgICAgICAgaWYgKGNvbXB1dGVkU3R5bGUucG9zaXRpb24gPT09ICdmaXhlZCcpIHtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIGlmICgoLyhhdXRvfHNjcm9sbCkvKS50ZXN0KGNvbXB1dGVkU3R5bGUub3ZlcmZsb3cgKyBjb21wdXRlZFN0eWxlLm92ZXJmbG93WSArIGNvbXB1dGVkU3R5bGUub3ZlcmZsb3dYKSkge1xuICAgICAgICAgICAgcGFyZW50cy5wdXNoKGVsKTtcbiAgICAgICAgfVxuICAgICAgICBlbCA9IGVsLnBhcmVudE5vZGU7XG4gICAgfVxuICAgIHJldHVybiBwYXJlbnRzO1xufVxuZnVuY3Rpb24gY29tcHV0ZUNsaXBwaW5nUmVjdChlbCkge1xuICAgIHJldHVybiBnZXRDbGlwcGluZ1BhcmVudHMoZWwpXG4gICAgICAgIC5tYXAoZnVuY3Rpb24gKGVsKSB7XG4gICAgICAgIHJldHVybiBjb21wdXRlSW5uZXJSZWN0KGVsKTtcbiAgICB9KVxuICAgICAgICAuY29uY2F0KGNvbXB1dGVWaWV3cG9ydFJlY3QoKSlcbiAgICAgICAgLnJlZHVjZShmdW5jdGlvbiAocmVjdDAsIHJlY3QxKSB7XG4gICAgICAgIHJldHVybiBpbnRlcnNlY3RSZWN0cyhyZWN0MCwgcmVjdDEpIHx8IHJlY3QxOyAvLyBzaG91bGQgYWx3YXlzIGludGVyc2VjdFxuICAgIH0pO1xufVxuXG4vLyBTdG9wcyBhIG1vdXNlL3RvdWNoIGV2ZW50IGZyb20gZG9pbmcgaXQncyBuYXRpdmUgYnJvd3NlciBhY3Rpb25cbmZ1bmN0aW9uIHByZXZlbnREZWZhdWx0KGV2KSB7XG4gICAgZXYucHJldmVudERlZmF1bHQoKTtcbn1cbi8vIEV2ZW50IERlbGVnYXRpb25cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbmZ1bmN0aW9uIGxpc3RlbkJ5U2VsZWN0b3IoY29udGFpbmVyLCBldmVudFR5cGUsIHNlbGVjdG9yLCBoYW5kbGVyKSB7XG4gICAgZnVuY3Rpb24gcmVhbEhhbmRsZXIoZXYpIHtcbiAgICAgICAgdmFyIG1hdGNoZWRDaGlsZCA9IGVsZW1lbnRDbG9zZXN0KGV2LnRhcmdldCwgc2VsZWN0b3IpO1xuICAgICAgICBpZiAobWF0Y2hlZENoaWxkKSB7XG4gICAgICAgICAgICBoYW5kbGVyLmNhbGwobWF0Y2hlZENoaWxkLCBldiwgbWF0Y2hlZENoaWxkKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBjb250YWluZXIuYWRkRXZlbnRMaXN0ZW5lcihldmVudFR5cGUsIHJlYWxIYW5kbGVyKTtcbiAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgICBjb250YWluZXIucmVtb3ZlRXZlbnRMaXN0ZW5lcihldmVudFR5cGUsIHJlYWxIYW5kbGVyKTtcbiAgICB9O1xufVxuZnVuY3Rpb24gbGlzdGVuVG9Ib3ZlckJ5U2VsZWN0b3IoY29udGFpbmVyLCBzZWxlY3Rvciwgb25Nb3VzZUVudGVyLCBvbk1vdXNlTGVhdmUpIHtcbiAgICB2YXIgY3VycmVudE1hdGNoZWRDaGlsZDtcbiAgICByZXR1cm4gbGlzdGVuQnlTZWxlY3Rvcihjb250YWluZXIsICdtb3VzZW92ZXInLCBzZWxlY3RvciwgZnVuY3Rpb24gKGV2LCBtYXRjaGVkQ2hpbGQpIHtcbiAgICAgICAgaWYgKG1hdGNoZWRDaGlsZCAhPT0gY3VycmVudE1hdGNoZWRDaGlsZCkge1xuICAgICAgICAgICAgY3VycmVudE1hdGNoZWRDaGlsZCA9IG1hdGNoZWRDaGlsZDtcbiAgICAgICAgICAgIG9uTW91c2VFbnRlcihldiwgbWF0Y2hlZENoaWxkKTtcbiAgICAgICAgICAgIHZhciByZWFsT25Nb3VzZUxlYXZlXzEgPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgICAgICAgICBjdXJyZW50TWF0Y2hlZENoaWxkID0gbnVsbDtcbiAgICAgICAgICAgICAgICBvbk1vdXNlTGVhdmUoZXYsIG1hdGNoZWRDaGlsZCk7XG4gICAgICAgICAgICAgICAgbWF0Y2hlZENoaWxkLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21vdXNlbGVhdmUnLCByZWFsT25Nb3VzZUxlYXZlXzEpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIC8vIGxpc3RlbiB0byB0aGUgbmV4dCBtb3VzZWxlYXZlLCBhbmQgdGhlbiB1bmF0dGFjaFxuICAgICAgICAgICAgbWF0Y2hlZENoaWxkLmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlbGVhdmUnLCByZWFsT25Nb3VzZUxlYXZlXzEpO1xuICAgICAgICB9XG4gICAgfSk7XG59XG4vLyBBbmltYXRpb25cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbnZhciB0cmFuc2l0aW9uRXZlbnROYW1lcyA9IFtcbiAgICAnd2Via2l0VHJhbnNpdGlvbkVuZCcsXG4gICAgJ290cmFuc2l0aW9uZW5kJyxcbiAgICAnb1RyYW5zaXRpb25FbmQnLFxuICAgICdtc1RyYW5zaXRpb25FbmQnLFxuICAgICd0cmFuc2l0aW9uZW5kJ1xuXTtcbi8vIHRyaWdnZXJlZCBvbmx5IHdoZW4gdGhlIG5leHQgc2luZ2xlIHN1YnNlcXVlbnQgdHJhbnNpdGlvbiBmaW5pc2hlc1xuZnVuY3Rpb24gd2hlblRyYW5zaXRpb25Eb25lKGVsLCBjYWxsYmFjaykge1xuICAgIHZhciByZWFsQ2FsbGJhY2sgPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgY2FsbGJhY2soZXYpO1xuICAgICAgICB0cmFuc2l0aW9uRXZlbnROYW1lcy5mb3JFYWNoKGZ1bmN0aW9uIChldmVudE5hbWUpIHtcbiAgICAgICAgICAgIGVsLnJlbW92ZUV2ZW50TGlzdGVuZXIoZXZlbnROYW1lLCByZWFsQ2FsbGJhY2spO1xuICAgICAgICB9KTtcbiAgICB9O1xuICAgIHRyYW5zaXRpb25FdmVudE5hbWVzLmZvckVhY2goZnVuY3Rpb24gKGV2ZW50TmFtZSkge1xuICAgICAgICBlbC5hZGRFdmVudExpc3RlbmVyKGV2ZW50TmFtZSwgcmVhbENhbGxiYWNrKTsgLy8gY3Jvc3MtYnJvd3NlciB3YXkgdG8gZGV0ZXJtaW5lIHdoZW4gdGhlIHRyYW5zaXRpb24gZmluaXNoZXNcbiAgICB9KTtcbn1cblxudmFyIERBWV9JRFMgPSBbJ3N1bicsICdtb24nLCAndHVlJywgJ3dlZCcsICd0aHUnLCAnZnJpJywgJ3NhdCddO1xuLy8gQWRkaW5nXG5mdW5jdGlvbiBhZGRXZWVrcyhtLCBuKSB7XG4gICAgdmFyIGEgPSBkYXRlVG9VdGNBcnJheShtKTtcbiAgICBhWzJdICs9IG4gKiA3O1xuICAgIHJldHVybiBhcnJheVRvVXRjRGF0ZShhKTtcbn1cbmZ1bmN0aW9uIGFkZERheXMobSwgbikge1xuICAgIHZhciBhID0gZGF0ZVRvVXRjQXJyYXkobSk7XG4gICAgYVsyXSArPSBuO1xuICAgIHJldHVybiBhcnJheVRvVXRjRGF0ZShhKTtcbn1cbmZ1bmN0aW9uIGFkZE1zKG0sIG4pIHtcbiAgICB2YXIgYSA9IGRhdGVUb1V0Y0FycmF5KG0pO1xuICAgIGFbNl0gKz0gbjtcbiAgICByZXR1cm4gYXJyYXlUb1V0Y0RhdGUoYSk7XG59XG4vLyBEaWZmaW5nIChhbGwgcmV0dXJuIGZsb2F0cylcbmZ1bmN0aW9uIGRpZmZXZWVrcyhtMCwgbTEpIHtcbiAgICByZXR1cm4gZGlmZkRheXMobTAsIG0xKSAvIDc7XG59XG5mdW5jdGlvbiBkaWZmRGF5cyhtMCwgbTEpIHtcbiAgICByZXR1cm4gKG0xLnZhbHVlT2YoKSAtIG0wLnZhbHVlT2YoKSkgLyAoMTAwMCAqIDYwICogNjAgKiAyNCk7XG59XG5mdW5jdGlvbiBkaWZmSG91cnMobTAsIG0xKSB7XG4gICAgcmV0dXJuIChtMS52YWx1ZU9mKCkgLSBtMC52YWx1ZU9mKCkpIC8gKDEwMDAgKiA2MCAqIDYwKTtcbn1cbmZ1bmN0aW9uIGRpZmZNaW51dGVzKG0wLCBtMSkge1xuICAgIHJldHVybiAobTEudmFsdWVPZigpIC0gbTAudmFsdWVPZigpKSAvICgxMDAwICogNjApO1xufVxuZnVuY3Rpb24gZGlmZlNlY29uZHMobTAsIG0xKSB7XG4gICAgcmV0dXJuIChtMS52YWx1ZU9mKCkgLSBtMC52YWx1ZU9mKCkpIC8gMTAwMDtcbn1cbmZ1bmN0aW9uIGRpZmZEYXlBbmRUaW1lKG0wLCBtMSkge1xuICAgIHZhciBtMGRheSA9IHN0YXJ0T2ZEYXkobTApO1xuICAgIHZhciBtMWRheSA9IHN0YXJ0T2ZEYXkobTEpO1xuICAgIHJldHVybiB7XG4gICAgICAgIHllYXJzOiAwLFxuICAgICAgICBtb250aHM6IDAsXG4gICAgICAgIGRheXM6IE1hdGgucm91bmQoZGlmZkRheXMobTBkYXksIG0xZGF5KSksXG4gICAgICAgIG1pbGxpc2Vjb25kczogKG0xLnZhbHVlT2YoKSAtIG0xZGF5LnZhbHVlT2YoKSkgLSAobTAudmFsdWVPZigpIC0gbTBkYXkudmFsdWVPZigpKVxuICAgIH07XG59XG4vLyBEaWZmaW5nIFdob2xlIFVuaXRzXG5mdW5jdGlvbiBkaWZmV2hvbGVXZWVrcyhtMCwgbTEpIHtcbiAgICB2YXIgZCA9IGRpZmZXaG9sZURheXMobTAsIG0xKTtcbiAgICBpZiAoZCAhPT0gbnVsbCAmJiBkICUgNyA9PT0gMCkge1xuICAgICAgICByZXR1cm4gZCAvIDc7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufVxuZnVuY3Rpb24gZGlmZldob2xlRGF5cyhtMCwgbTEpIHtcbiAgICBpZiAodGltZUFzTXMobTApID09PSB0aW1lQXNNcyhtMSkpIHtcbiAgICAgICAgcmV0dXJuIE1hdGgucm91bmQoZGlmZkRheXMobTAsIG0xKSk7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufVxuLy8gU3RhcnQtT2ZcbmZ1bmN0aW9uIHN0YXJ0T2ZEYXkobSkge1xuICAgIHJldHVybiBhcnJheVRvVXRjRGF0ZShbXG4gICAgICAgIG0uZ2V0VVRDRnVsbFllYXIoKSxcbiAgICAgICAgbS5nZXRVVENNb250aCgpLFxuICAgICAgICBtLmdldFVUQ0RhdGUoKVxuICAgIF0pO1xufVxuZnVuY3Rpb24gc3RhcnRPZkhvdXIobSkge1xuICAgIHJldHVybiBhcnJheVRvVXRjRGF0ZShbXG4gICAgICAgIG0uZ2V0VVRDRnVsbFllYXIoKSxcbiAgICAgICAgbS5nZXRVVENNb250aCgpLFxuICAgICAgICBtLmdldFVUQ0RhdGUoKSxcbiAgICAgICAgbS5nZXRVVENIb3VycygpXG4gICAgXSk7XG59XG5mdW5jdGlvbiBzdGFydE9mTWludXRlKG0pIHtcbiAgICByZXR1cm4gYXJyYXlUb1V0Y0RhdGUoW1xuICAgICAgICBtLmdldFVUQ0Z1bGxZZWFyKCksXG4gICAgICAgIG0uZ2V0VVRDTW9udGgoKSxcbiAgICAgICAgbS5nZXRVVENEYXRlKCksXG4gICAgICAgIG0uZ2V0VVRDSG91cnMoKSxcbiAgICAgICAgbS5nZXRVVENNaW51dGVzKClcbiAgICBdKTtcbn1cbmZ1bmN0aW9uIHN0YXJ0T2ZTZWNvbmQobSkge1xuICAgIHJldHVybiBhcnJheVRvVXRjRGF0ZShbXG4gICAgICAgIG0uZ2V0VVRDRnVsbFllYXIoKSxcbiAgICAgICAgbS5nZXRVVENNb250aCgpLFxuICAgICAgICBtLmdldFVUQ0RhdGUoKSxcbiAgICAgICAgbS5nZXRVVENIb3VycygpLFxuICAgICAgICBtLmdldFVUQ01pbnV0ZXMoKSxcbiAgICAgICAgbS5nZXRVVENTZWNvbmRzKClcbiAgICBdKTtcbn1cbi8vIFdlZWsgQ29tcHV0YXRpb25cbmZ1bmN0aW9uIHdlZWtPZlllYXIobWFya2VyLCBkb3csIGRveSkge1xuICAgIHZhciB5ID0gbWFya2VyLmdldFVUQ0Z1bGxZZWFyKCk7XG4gICAgdmFyIHcgPSB3ZWVrT2ZHaXZlblllYXIobWFya2VyLCB5LCBkb3csIGRveSk7XG4gICAgaWYgKHcgPCAxKSB7XG4gICAgICAgIHJldHVybiB3ZWVrT2ZHaXZlblllYXIobWFya2VyLCB5IC0gMSwgZG93LCBkb3kpO1xuICAgIH1cbiAgICB2YXIgbmV4dFcgPSB3ZWVrT2ZHaXZlblllYXIobWFya2VyLCB5ICsgMSwgZG93LCBkb3kpO1xuICAgIGlmIChuZXh0VyA+PSAxKSB7XG4gICAgICAgIHJldHVybiBNYXRoLm1pbih3LCBuZXh0Vyk7XG4gICAgfVxuICAgIHJldHVybiB3O1xufVxuZnVuY3Rpb24gd2Vla09mR2l2ZW5ZZWFyKG1hcmtlciwgeWVhciwgZG93LCBkb3kpIHtcbiAgICB2YXIgZmlyc3RXZWVrU3RhcnQgPSBhcnJheVRvVXRjRGF0ZShbeWVhciwgMCwgMSArIGZpcnN0V2Vla09mZnNldCh5ZWFyLCBkb3csIGRveSldKTtcbiAgICB2YXIgZGF5U3RhcnQgPSBzdGFydE9mRGF5KG1hcmtlcik7XG4gICAgdmFyIGRheXMgPSBNYXRoLnJvdW5kKGRpZmZEYXlzKGZpcnN0V2Vla1N0YXJ0LCBkYXlTdGFydCkpO1xuICAgIHJldHVybiBNYXRoLmZsb29yKGRheXMgLyA3KSArIDE7IC8vIHplcm8taW5kZXhlZFxufVxuLy8gc3RhcnQtb2YtZmlyc3Qtd2VlayAtIHN0YXJ0LW9mLXllYXJcbmZ1bmN0aW9uIGZpcnN0V2Vla09mZnNldCh5ZWFyLCBkb3csIGRveSkge1xuICAgIC8vIGZpcnN0LXdlZWsgZGF5IC0tIHdoaWNoIGphbnVhcnkgaXMgYWx3YXlzIGluIHRoZSBmaXJzdCB3ZWVrICg0IGZvciBpc28sIDEgZm9yIG90aGVyKVxuICAgIHZhciBmd2QgPSA3ICsgZG93IC0gZG95O1xuICAgIC8vIGZpcnN0LXdlZWsgZGF5IGxvY2FsIHdlZWtkYXkgLS0gd2hpY2ggbG9jYWwgd2Vla2RheSBpcyBmd2RcbiAgICB2YXIgZndkbHcgPSAoNyArIGFycmF5VG9VdGNEYXRlKFt5ZWFyLCAwLCBmd2RdKS5nZXRVVENEYXkoKSAtIGRvdykgJSA3O1xuICAgIHJldHVybiAtZndkbHcgKyBmd2QgLSAxO1xufVxuLy8gQXJyYXkgQ29udmVyc2lvblxuZnVuY3Rpb24gZGF0ZVRvTG9jYWxBcnJheShkYXRlKSB7XG4gICAgcmV0dXJuIFtcbiAgICAgICAgZGF0ZS5nZXRGdWxsWWVhcigpLFxuICAgICAgICBkYXRlLmdldE1vbnRoKCksXG4gICAgICAgIGRhdGUuZ2V0RGF0ZSgpLFxuICAgICAgICBkYXRlLmdldEhvdXJzKCksXG4gICAgICAgIGRhdGUuZ2V0TWludXRlcygpLFxuICAgICAgICBkYXRlLmdldFNlY29uZHMoKSxcbiAgICAgICAgZGF0ZS5nZXRNaWxsaXNlY29uZHMoKVxuICAgIF07XG59XG5mdW5jdGlvbiBhcnJheVRvTG9jYWxEYXRlKGEpIHtcbiAgICByZXR1cm4gbmV3IERhdGUoYVswXSwgYVsxXSB8fCAwLCBhWzJdID09IG51bGwgPyAxIDogYVsyXSwgLy8gZGF5IG9mIG1vbnRoXG4gICAgYVszXSB8fCAwLCBhWzRdIHx8IDAsIGFbNV0gfHwgMCk7XG59XG5mdW5jdGlvbiBkYXRlVG9VdGNBcnJheShkYXRlKSB7XG4gICAgcmV0dXJuIFtcbiAgICAgICAgZGF0ZS5nZXRVVENGdWxsWWVhcigpLFxuICAgICAgICBkYXRlLmdldFVUQ01vbnRoKCksXG4gICAgICAgIGRhdGUuZ2V0VVRDRGF0ZSgpLFxuICAgICAgICBkYXRlLmdldFVUQ0hvdXJzKCksXG4gICAgICAgIGRhdGUuZ2V0VVRDTWludXRlcygpLFxuICAgICAgICBkYXRlLmdldFVUQ1NlY29uZHMoKSxcbiAgICAgICAgZGF0ZS5nZXRVVENNaWxsaXNlY29uZHMoKVxuICAgIF07XG59XG5mdW5jdGlvbiBhcnJheVRvVXRjRGF0ZShhKSB7XG4gICAgLy8gYWNjb3JkaW5nIHRvIHdlYiBzdGFuZGFyZHMgKGFuZCBTYWZhcmkpLCBhIG1vbnRoIGluZGV4IGlzIHJlcXVpcmVkLlxuICAgIC8vIG1hc3NhZ2UgaWYgb25seSBnaXZlbiBhIHllYXIuXG4gICAgaWYgKGEubGVuZ3RoID09PSAxKSB7XG4gICAgICAgIGEgPSBhLmNvbmNhdChbMF0pO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IERhdGUoRGF0ZS5VVEMuYXBwbHkoRGF0ZSwgYSkpO1xufVxuLy8gT3RoZXIgVXRpbHNcbmZ1bmN0aW9uIGlzVmFsaWREYXRlKG0pIHtcbiAgICByZXR1cm4gIWlzTmFOKG0udmFsdWVPZigpKTtcbn1cbmZ1bmN0aW9uIHRpbWVBc01zKG0pIHtcbiAgICByZXR1cm4gbS5nZXRVVENIb3VycygpICogMTAwMCAqIDYwICogNjAgK1xuICAgICAgICBtLmdldFVUQ01pbnV0ZXMoKSAqIDEwMDAgKiA2MCArXG4gICAgICAgIG0uZ2V0VVRDU2Vjb25kcygpICogMTAwMCArXG4gICAgICAgIG0uZ2V0VVRDTWlsbGlzZWNvbmRzKCk7XG59XG5cbnZhciBJTlRFUk5BTF9VTklUUyA9IFsneWVhcnMnLCAnbW9udGhzJywgJ2RheXMnLCAnbWlsbGlzZWNvbmRzJ107XG52YXIgUEFSU0VfUkUgPSAvXigtPykoPzooXFxkKylcXC4pPyhcXGQrKTooXFxkXFxkKSg/OjooXFxkXFxkKSg/OlxcLihcXGRcXGRcXGQpKT8pPy87XG4vLyBQYXJzaW5nIGFuZCBDcmVhdGlvblxuZnVuY3Rpb24gY3JlYXRlRHVyYXRpb24oaW5wdXQsIHVuaXQpIHtcbiAgICB2YXIgX2E7XG4gICAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgcmV0dXJuIHBhcnNlU3RyaW5nKGlucHV0KTtcbiAgICB9XG4gICAgZWxzZSBpZiAodHlwZW9mIGlucHV0ID09PSAnb2JqZWN0JyAmJiBpbnB1dCkgeyAvLyBub24tbnVsbCBvYmplY3RcbiAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZU9iamVjdChpbnB1dCk7XG4gICAgfVxuICAgIGVsc2UgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZU9iamVjdCgoX2EgPSB7fSwgX2FbdW5pdCB8fCAnbWlsbGlzZWNvbmRzJ10gPSBpbnB1dCwgX2EpKTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbn1cbmZ1bmN0aW9uIHBhcnNlU3RyaW5nKHMpIHtcbiAgICB2YXIgbSA9IFBBUlNFX1JFLmV4ZWMocyk7XG4gICAgaWYgKG0pIHtcbiAgICAgICAgdmFyIHNpZ24gPSBtWzFdID8gLTEgOiAxO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgeWVhcnM6IDAsXG4gICAgICAgICAgICBtb250aHM6IDAsXG4gICAgICAgICAgICBkYXlzOiBzaWduICogKG1bMl0gPyBwYXJzZUludChtWzJdLCAxMCkgOiAwKSxcbiAgICAgICAgICAgIG1pbGxpc2Vjb25kczogc2lnbiAqICgobVszXSA/IHBhcnNlSW50KG1bM10sIDEwKSA6IDApICogNjAgKiA2MCAqIDEwMDAgKyAvLyBob3Vyc1xuICAgICAgICAgICAgICAgIChtWzRdID8gcGFyc2VJbnQobVs0XSwgMTApIDogMCkgKiA2MCAqIDEwMDAgKyAvLyBtaW51dGVzXG4gICAgICAgICAgICAgICAgKG1bNV0gPyBwYXJzZUludChtWzVdLCAxMCkgOiAwKSAqIDEwMDAgKyAvLyBzZWNvbmRzXG4gICAgICAgICAgICAgICAgKG1bNl0gPyBwYXJzZUludChtWzZdLCAxMCkgOiAwKSAvLyBtc1xuICAgICAgICAgICAgKVxuICAgICAgICB9O1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cbmZ1bmN0aW9uIG5vcm1hbGl6ZU9iamVjdChvYmopIHtcbiAgICByZXR1cm4ge1xuICAgICAgICB5ZWFyczogb2JqLnllYXJzIHx8IG9iai55ZWFyIHx8IDAsXG4gICAgICAgIG1vbnRoczogb2JqLm1vbnRocyB8fCBvYmoubW9udGggfHwgMCxcbiAgICAgICAgZGF5czogKG9iai5kYXlzIHx8IG9iai5kYXkgfHwgMCkgK1xuICAgICAgICAgICAgZ2V0V2Vla3NGcm9tSW5wdXQob2JqKSAqIDcsXG4gICAgICAgIG1pbGxpc2Vjb25kczogKG9iai5ob3VycyB8fCBvYmouaG91ciB8fCAwKSAqIDYwICogNjAgKiAxMDAwICsgLy8gaG91cnNcbiAgICAgICAgICAgIChvYmoubWludXRlcyB8fCBvYmoubWludXRlIHx8IDApICogNjAgKiAxMDAwICsgLy8gbWludXRlc1xuICAgICAgICAgICAgKG9iai5zZWNvbmRzIHx8IG9iai5zZWNvbmQgfHwgMCkgKiAxMDAwICsgLy8gc2Vjb25kc1xuICAgICAgICAgICAgKG9iai5taWxsaXNlY29uZHMgfHwgb2JqLm1pbGxpc2Vjb25kIHx8IG9iai5tcyB8fCAwKSAvLyBtc1xuICAgIH07XG59XG5mdW5jdGlvbiBnZXRXZWVrc0Zyb21JbnB1dChvYmopIHtcbiAgICByZXR1cm4gb2JqLndlZWtzIHx8IG9iai53ZWVrIHx8IDA7XG59XG4vLyBFcXVhbGl0eVxuZnVuY3Rpb24gZHVyYXRpb25zRXF1YWwoZDAsIGQxKSB7XG4gICAgcmV0dXJuIGQwLnllYXJzID09PSBkMS55ZWFycyAmJlxuICAgICAgICBkMC5tb250aHMgPT09IGQxLm1vbnRocyAmJlxuICAgICAgICBkMC5kYXlzID09PSBkMS5kYXlzICYmXG4gICAgICAgIGQwLm1pbGxpc2Vjb25kcyA9PT0gZDEubWlsbGlzZWNvbmRzO1xufVxuZnVuY3Rpb24gaXNTaW5nbGVEYXkoZHVyKSB7XG4gICAgcmV0dXJuIGR1ci55ZWFycyA9PT0gMCAmJiBkdXIubW9udGhzID09PSAwICYmIGR1ci5kYXlzID09PSAxICYmIGR1ci5taWxsaXNlY29uZHMgPT09IDA7XG59XG4vLyBTaW1wbGUgTWF0aFxuZnVuY3Rpb24gYWRkRHVyYXRpb25zKGQwLCBkMSkge1xuICAgIHJldHVybiB7XG4gICAgICAgIHllYXJzOiBkMC55ZWFycyArIGQxLnllYXJzLFxuICAgICAgICBtb250aHM6IGQwLm1vbnRocyArIGQxLm1vbnRocyxcbiAgICAgICAgZGF5czogZDAuZGF5cyArIGQxLmRheXMsXG4gICAgICAgIG1pbGxpc2Vjb25kczogZDAubWlsbGlzZWNvbmRzICsgZDEubWlsbGlzZWNvbmRzXG4gICAgfTtcbn1cbmZ1bmN0aW9uIHN1YnRyYWN0RHVyYXRpb25zKGQxLCBkMCkge1xuICAgIHJldHVybiB7XG4gICAgICAgIHllYXJzOiBkMS55ZWFycyAtIGQwLnllYXJzLFxuICAgICAgICBtb250aHM6IGQxLm1vbnRocyAtIGQwLm1vbnRocyxcbiAgICAgICAgZGF5czogZDEuZGF5cyAtIGQwLmRheXMsXG4gICAgICAgIG1pbGxpc2Vjb25kczogZDEubWlsbGlzZWNvbmRzIC0gZDAubWlsbGlzZWNvbmRzXG4gICAgfTtcbn1cbmZ1bmN0aW9uIG11bHRpcGx5RHVyYXRpb24oZCwgbikge1xuICAgIHJldHVybiB7XG4gICAgICAgIHllYXJzOiBkLnllYXJzICogbixcbiAgICAgICAgbW9udGhzOiBkLm1vbnRocyAqIG4sXG4gICAgICAgIGRheXM6IGQuZGF5cyAqIG4sXG4gICAgICAgIG1pbGxpc2Vjb25kczogZC5taWxsaXNlY29uZHMgKiBuXG4gICAgfTtcbn1cbi8vIENvbnZlcnNpb25zXG4vLyBcIlJvdWdoXCIgYmVjYXVzZSB0aGV5IGFyZSBiYXNlZCBvbiBhdmVyYWdlLWNhc2UgR3JlZ29yaWFuIG1vbnRocy95ZWFyc1xuZnVuY3Rpb24gYXNSb3VnaFllYXJzKGR1cikge1xuICAgIHJldHVybiBhc1JvdWdoRGF5cyhkdXIpIC8gMzY1O1xufVxuZnVuY3Rpb24gYXNSb3VnaE1vbnRocyhkdXIpIHtcbiAgICByZXR1cm4gYXNSb3VnaERheXMoZHVyKSAvIDMwO1xufVxuZnVuY3Rpb24gYXNSb3VnaERheXMoZHVyKSB7XG4gICAgcmV0dXJuIGFzUm91Z2hNcyhkdXIpIC8gODY0ZTU7XG59XG5mdW5jdGlvbiBhc1JvdWdoTWludXRlcyhkdXIpIHtcbiAgICByZXR1cm4gYXNSb3VnaE1zKGR1cikgLyAoMTAwMCAqIDYwKTtcbn1cbmZ1bmN0aW9uIGFzUm91Z2hTZWNvbmRzKGR1cikge1xuICAgIHJldHVybiBhc1JvdWdoTXMoZHVyKSAvIDEwMDA7XG59XG5mdW5jdGlvbiBhc1JvdWdoTXMoZHVyKSB7XG4gICAgcmV0dXJuIGR1ci55ZWFycyAqICgzNjUgKiA4NjRlNSkgK1xuICAgICAgICBkdXIubW9udGhzICogKDMwICogODY0ZTUpICtcbiAgICAgICAgZHVyLmRheXMgKiA4NjRlNSArXG4gICAgICAgIGR1ci5taWxsaXNlY29uZHM7XG59XG4vLyBBZHZhbmNlZCBNYXRoXG5mdW5jdGlvbiB3aG9sZURpdmlkZUR1cmF0aW9ucyhudW1lcmF0b3IsIGRlbm9taW5hdG9yKSB7XG4gICAgdmFyIHJlcyA9IG51bGw7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBJTlRFUk5BTF9VTklUUy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgdW5pdCA9IElOVEVSTkFMX1VOSVRTW2ldO1xuICAgICAgICBpZiAoZGVub21pbmF0b3JbdW5pdF0pIHtcbiAgICAgICAgICAgIHZhciBsb2NhbFJlcyA9IG51bWVyYXRvclt1bml0XSAvIGRlbm9taW5hdG9yW3VuaXRdO1xuICAgICAgICAgICAgaWYgKCFpc0ludChsb2NhbFJlcykgfHwgKHJlcyAhPT0gbnVsbCAmJiByZXMgIT09IGxvY2FsUmVzKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVzID0gbG9jYWxSZXM7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAobnVtZXJhdG9yW3VuaXRdKSB7XG4gICAgICAgICAgICAvLyBuZWVkcyB0byBkaXZpZGUgYnkgc29tZXRoaW5nIGJ1dCBjYW4ndCFcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXM7XG59XG5mdW5jdGlvbiBncmVhdGVzdER1cmF0aW9uRGVub21pbmF0b3IoZHVyLCBkb250UmV0dXJuV2Vla3MpIHtcbiAgICB2YXIgbXMgPSBkdXIubWlsbGlzZWNvbmRzO1xuICAgIGlmIChtcykge1xuICAgICAgICBpZiAobXMgJSAxMDAwICE9PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4geyB1bml0OiAnbWlsbGlzZWNvbmQnLCB2YWx1ZTogbXMgfTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobXMgJSAoMTAwMCAqIDYwKSAhPT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHsgdW5pdDogJ3NlY29uZCcsIHZhbHVlOiBtcyAvIDEwMDAgfTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobXMgJSAoMTAwMCAqIDYwICogNjApICE9PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4geyB1bml0OiAnbWludXRlJywgdmFsdWU6IG1zIC8gKDEwMDAgKiA2MCkgfTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobXMpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHVuaXQ6ICdob3VyJywgdmFsdWU6IG1zIC8gKDEwMDAgKiA2MCAqIDYwKSB9O1xuICAgICAgICB9XG4gICAgfVxuICAgIGlmIChkdXIuZGF5cykge1xuICAgICAgICBpZiAoIWRvbnRSZXR1cm5XZWVrcyAmJiBkdXIuZGF5cyAlIDcgPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybiB7IHVuaXQ6ICd3ZWVrJywgdmFsdWU6IGR1ci5kYXlzIC8gNyB9O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IHVuaXQ6ICdkYXknLCB2YWx1ZTogZHVyLmRheXMgfTtcbiAgICB9XG4gICAgaWYgKGR1ci5tb250aHMpIHtcbiAgICAgICAgcmV0dXJuIHsgdW5pdDogJ21vbnRoJywgdmFsdWU6IGR1ci5tb250aHMgfTtcbiAgICB9XG4gICAgaWYgKGR1ci55ZWFycykge1xuICAgICAgICByZXR1cm4geyB1bml0OiAneWVhcicsIHZhbHVlOiBkdXIueWVhcnMgfTtcbiAgICB9XG4gICAgcmV0dXJuIHsgdW5pdDogJ21pbGxpc2Vjb25kJywgdmFsdWU6IDAgfTtcbn1cblxuLyogRnVsbENhbGVuZGFyLXNwZWNpZmljIERPTSBVdGlsaXRpZXNcbi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuLy8gR2l2ZW4gdGhlIHNjcm9sbGJhciB3aWR0aHMgb2Ygc29tZSBvdGhlciBjb250YWluZXIsIGNyZWF0ZSBib3JkZXJzL21hcmdpbnMgb24gcm93RWxzIGluIG9yZGVyIHRvIG1hdGNoIHRoZSBsZWZ0XG4vLyBhbmQgcmlnaHQgc3BhY2UgdGhhdCB3YXMgb2Zmc2V0IGJ5IHRoZSBzY3JvbGxiYXJzLiBBIDEtcGl4ZWwgYm9yZGVyIGZpcnN0LCB0aGVuIG1hcmdpbiBiZXlvbmQgdGhhdC5cbmZ1bmN0aW9uIGNvbXBlbnNhdGVTY3JvbGwocm93RWwsIHNjcm9sbGJhcldpZHRocykge1xuICAgIGlmIChzY3JvbGxiYXJXaWR0aHMubGVmdCkge1xuICAgICAgICBhcHBseVN0eWxlKHJvd0VsLCB7XG4gICAgICAgICAgICBib3JkZXJMZWZ0V2lkdGg6IDEsXG4gICAgICAgICAgICBtYXJnaW5MZWZ0OiBzY3JvbGxiYXJXaWR0aHMubGVmdCAtIDFcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGlmIChzY3JvbGxiYXJXaWR0aHMucmlnaHQpIHtcbiAgICAgICAgYXBwbHlTdHlsZShyb3dFbCwge1xuICAgICAgICAgICAgYm9yZGVyUmlnaHRXaWR0aDogMSxcbiAgICAgICAgICAgIG1hcmdpblJpZ2h0OiBzY3JvbGxiYXJXaWR0aHMucmlnaHQgLSAxXG4gICAgICAgIH0pO1xuICAgIH1cbn1cbi8vIFVuZG9lcyBjb21wZW5zYXRlU2Nyb2xsIGFuZCByZXN0b3JlcyBhbGwgYm9yZGVycy9tYXJnaW5zXG5mdW5jdGlvbiB1bmNvbXBlbnNhdGVTY3JvbGwocm93RWwpIHtcbiAgICBhcHBseVN0eWxlKHJvd0VsLCB7XG4gICAgICAgIG1hcmdpbkxlZnQ6ICcnLFxuICAgICAgICBtYXJnaW5SaWdodDogJycsXG4gICAgICAgIGJvcmRlckxlZnRXaWR0aDogJycsXG4gICAgICAgIGJvcmRlclJpZ2h0V2lkdGg6ICcnXG4gICAgfSk7XG59XG4vLyBNYWtlIHRoZSBtb3VzZSBjdXJzb3IgZXhwcmVzcyB0aGF0IGFuIGV2ZW50IGlzIG5vdCBhbGxvd2VkIGluIHRoZSBjdXJyZW50IGFyZWFcbmZ1bmN0aW9uIGRpc2FibGVDdXJzb3IoKSB7XG4gICAgZG9jdW1lbnQuYm9keS5jbGFzc0xpc3QuYWRkKCdmYy1ub3QtYWxsb3dlZCcpO1xufVxuLy8gUmV0dXJucyB0aGUgbW91c2UgY3Vyc29yIHRvIGl0cyBvcmlnaW5hbCBsb29rXG5mdW5jdGlvbiBlbmFibGVDdXJzb3IoKSB7XG4gICAgZG9jdW1lbnQuYm9keS5jbGFzc0xpc3QucmVtb3ZlKCdmYy1ub3QtYWxsb3dlZCcpO1xufVxuLy8gR2l2ZW4gYSB0b3RhbCBhdmFpbGFibGUgaGVpZ2h0IHRvIGZpbGwsIGhhdmUgYGVsc2AgKGVzc2VudGlhbGx5IGNoaWxkIHJvd3MpIGV4cGFuZCB0byBhY2NvbW9kYXRlLlxuLy8gQnkgZGVmYXVsdCwgYWxsIGVsZW1lbnRzIHRoYXQgYXJlIHNob3J0ZXIgdGhhbiB0aGUgcmVjb21tZW5kZWQgaGVpZ2h0IGFyZSBleHBhbmRlZCB1bmlmb3JtbHksIG5vdCBjb25zaWRlcmluZ1xuLy8gYW55IG90aGVyIGVscyB0aGF0IGFyZSBhbHJlYWR5IHRvbyB0YWxsLiBpZiBgc2hvdWxkUmVkaXN0cmlidXRlYCBpcyBvbiwgaXQgY29uc2lkZXJzIHRoZXNlIHRhbGwgcm93cyBhbmRcbi8vIHJlZHVjZXMgdGhlIGF2YWlsYWJsZSBoZWlnaHQuXG5mdW5jdGlvbiBkaXN0cmlidXRlSGVpZ2h0KGVscywgYXZhaWxhYmxlSGVpZ2h0LCBzaG91bGRSZWRpc3RyaWJ1dGUpIHtcbiAgICAvLyAqRkxPT1JJTkcgTk9URSo6IHdlIGZsb29yIGluIGNlcnRhaW4gcGxhY2VzIGJlY2F1c2Ugem9vbSBjYW4gZ2l2ZSBpbmFjY3VyYXRlIGZsb2F0aW5nLXBvaW50IGRpbWVuc2lvbnMsXG4gICAgLy8gYW5kIGl0IGlzIGJldHRlciB0byBiZSBzaG9ydGVyIHRoYW4gdGFsbGVyLCB0byBhdm9pZCBjcmVhdGluZyB1bm5lY2Vzc2FyeSBzY3JvbGxiYXJzLlxuICAgIHZhciBtaW5PZmZzZXQxID0gTWF0aC5mbG9vcihhdmFpbGFibGVIZWlnaHQgLyBlbHMubGVuZ3RoKTsgLy8gZm9yIG5vbi1sYXN0IGVsZW1lbnRcbiAgICB2YXIgbWluT2Zmc2V0MiA9IE1hdGguZmxvb3IoYXZhaWxhYmxlSGVpZ2h0IC0gbWluT2Zmc2V0MSAqIChlbHMubGVuZ3RoIC0gMSkpOyAvLyBmb3IgbGFzdCBlbGVtZW50ICpGTE9PUklORyBOT1RFKlxuICAgIHZhciBmbGV4RWxzID0gW107IC8vIGVsZW1lbnRzIHRoYXQgYXJlIGFsbG93ZWQgdG8gZXhwYW5kLiBhcnJheSBvZiBET00gbm9kZXNcbiAgICB2YXIgZmxleE9mZnNldHMgPSBbXTsgLy8gYW1vdW50IG9mIHZlcnRpY2FsIHNwYWNlIGl0IHRha2VzIHVwXG4gICAgdmFyIGZsZXhIZWlnaHRzID0gW107IC8vIGFjdHVhbCBjc3MgaGVpZ2h0XG4gICAgdmFyIHVzZWRIZWlnaHQgPSAwO1xuICAgIHVuZGlzdHJpYnV0ZUhlaWdodChlbHMpOyAvLyBnaXZlIGFsbCBlbGVtZW50cyB0aGVpciBuYXR1cmFsIGhlaWdodFxuICAgIC8vIGZpbmQgZWxlbWVudHMgdGhhdCBhcmUgYmVsb3cgdGhlIHJlY29tbWVuZGVkIGhlaWdodCAoZXhwYW5kYWJsZSkuXG4gICAgLy8gaW1wb3J0YW50IHRvIHF1ZXJ5IGZvciBoZWlnaHRzIGluIGEgc2luZ2xlIGZpcnN0IHBhc3MgKHRvIGF2b2lkIHJlZmxvdyBvc2NpbGxhdGlvbikuXG4gICAgZWxzLmZvckVhY2goZnVuY3Rpb24gKGVsLCBpKSB7XG4gICAgICAgIHZhciBtaW5PZmZzZXQgPSBpID09PSBlbHMubGVuZ3RoIC0gMSA/IG1pbk9mZnNldDIgOiBtaW5PZmZzZXQxO1xuICAgICAgICB2YXIgbmF0dXJhbEhlaWdodCA9IGVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmhlaWdodDtcbiAgICAgICAgdmFyIG5hdHVyYWxPZmZzZXQgPSBuYXR1cmFsSGVpZ2h0ICsgY29tcHV0ZVZNYXJnaW5zKGVsKTtcbiAgICAgICAgaWYgKG5hdHVyYWxPZmZzZXQgPCBtaW5PZmZzZXQpIHtcbiAgICAgICAgICAgIGZsZXhFbHMucHVzaChlbCk7XG4gICAgICAgICAgICBmbGV4T2Zmc2V0cy5wdXNoKG5hdHVyYWxPZmZzZXQpO1xuICAgICAgICAgICAgZmxleEhlaWdodHMucHVzaChuYXR1cmFsSGVpZ2h0KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIC8vIHRoaXMgZWxlbWVudCBzdHJldGNoZXMgcGFzdCByZWNvbW1lbmRlZCBoZWlnaHQgKG5vbi1leHBhbmRhYmxlKS4gbWFyayB0aGUgc3BhY2UgYXMgb2NjdXBpZWQuXG4gICAgICAgICAgICB1c2VkSGVpZ2h0ICs9IG5hdHVyYWxPZmZzZXQ7XG4gICAgICAgIH1cbiAgICB9KTtcbiAgICAvLyByZWFkanVzdCB0aGUgcmVjb21tZW5kZWQgaGVpZ2h0IHRvIG9ubHkgY29uc2lkZXIgdGhlIGhlaWdodCBhdmFpbGFibGUgdG8gbm9uLW1heGVkLW91dCByb3dzLlxuICAgIGlmIChzaG91bGRSZWRpc3RyaWJ1dGUpIHtcbiAgICAgICAgYXZhaWxhYmxlSGVpZ2h0IC09IHVzZWRIZWlnaHQ7XG4gICAgICAgIG1pbk9mZnNldDEgPSBNYXRoLmZsb29yKGF2YWlsYWJsZUhlaWdodCAvIGZsZXhFbHMubGVuZ3RoKTtcbiAgICAgICAgbWluT2Zmc2V0MiA9IE1hdGguZmxvb3IoYXZhaWxhYmxlSGVpZ2h0IC0gbWluT2Zmc2V0MSAqIChmbGV4RWxzLmxlbmd0aCAtIDEpKTsgLy8gKkZMT09SSU5HIE5PVEUqXG4gICAgfVxuICAgIC8vIGFzc2lnbiBoZWlnaHRzIHRvIGFsbCBleHBhbmRhYmxlIGVsZW1lbnRzXG4gICAgZmxleEVscy5mb3JFYWNoKGZ1bmN0aW9uIChlbCwgaSkge1xuICAgICAgICB2YXIgbWluT2Zmc2V0ID0gaSA9PT0gZmxleEVscy5sZW5ndGggLSAxID8gbWluT2Zmc2V0MiA6IG1pbk9mZnNldDE7XG4gICAgICAgIHZhciBuYXR1cmFsT2Zmc2V0ID0gZmxleE9mZnNldHNbaV07XG4gICAgICAgIHZhciBuYXR1cmFsSGVpZ2h0ID0gZmxleEhlaWdodHNbaV07XG4gICAgICAgIHZhciBuZXdIZWlnaHQgPSBtaW5PZmZzZXQgLSAobmF0dXJhbE9mZnNldCAtIG5hdHVyYWxIZWlnaHQpOyAvLyBzdWJ0cmFjdCB0aGUgbWFyZ2luL3BhZGRpbmdcbiAgICAgICAgaWYgKG5hdHVyYWxPZmZzZXQgPCBtaW5PZmZzZXQpIHsgLy8gd2UgY2hlY2sgdGhpcyBhZ2FpbiBiZWNhdXNlIHJlZGlzdHJpYnV0aW9uIG1pZ2h0IGhhdmUgY2hhbmdlZCB0aGluZ3NcbiAgICAgICAgICAgIGVsLnN0eWxlLmhlaWdodCA9IG5ld0hlaWdodCArICdweCc7XG4gICAgICAgIH1cbiAgICB9KTtcbn1cbi8vIFVuZG9lcyBkaXN0cnVidXRlSGVpZ2h0LCByZXN0b3JpbmcgYWxsIGVscyB0byB0aGVpciBuYXR1cmFsIGhlaWdodFxuZnVuY3Rpb24gdW5kaXN0cmlidXRlSGVpZ2h0KGVscykge1xuICAgIGVscy5mb3JFYWNoKGZ1bmN0aW9uIChlbCkge1xuICAgICAgICBlbC5zdHlsZS5oZWlnaHQgPSAnJztcbiAgICB9KTtcbn1cbi8vIEdpdmVuIGBlbHNgLCBhIHNldCBvZiA8dGQ+IGNlbGxzLCBmaW5kIHRoZSBjZWxsIHdpdGggdGhlIGxhcmdlc3QgbmF0dXJhbCB3aWR0aCBhbmQgc2V0IHRoZSB3aWR0aHMgb2YgYWxsIHRoZVxuLy8gY2VsbHMgdG8gYmUgdGhhdCB3aWR0aC5cbi8vIFBSRVJFUVVJU0lURTogaWYgeW91IHdhbnQgYSBjZWxsIHRvIHRha2UgdXAgd2lkdGgsIGl0IG5lZWRzIHRvIGhhdmUgYSBzaW5nbGUgaW5uZXIgZWxlbWVudCB3LyBkaXNwbGF5OmlubGluZVxuZnVuY3Rpb24gbWF0Y2hDZWxsV2lkdGhzKGVscykge1xuICAgIHZhciBtYXhJbm5lcldpZHRoID0gMDtcbiAgICBlbHMuZm9yRWFjaChmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgdmFyIGlubmVyRWwgPSBlbC5maXJzdENoaWxkOyAvLyBob3BlZnVsbHkgYW4gZWxlbWVudFxuICAgICAgICBpZiAoaW5uZXJFbCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KSB7XG4gICAgICAgICAgICB2YXIgaW5uZXJXaWR0aF8xID0gaW5uZXJFbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS53aWR0aDtcbiAgICAgICAgICAgIGlmIChpbm5lcldpZHRoXzEgPiBtYXhJbm5lcldpZHRoKSB7XG4gICAgICAgICAgICAgICAgbWF4SW5uZXJXaWR0aCA9IGlubmVyV2lkdGhfMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0pO1xuICAgIG1heElubmVyV2lkdGgrKzsgLy8gc29tZXRpbWVzIG5vdCBhY2N1cmF0ZSBvZiB3aWR0aCB0aGUgdGV4dCBuZWVkcyB0byBzdGF5IG9uIG9uZSBsaW5lLiBpbnN1cmFuY2VcbiAgICBlbHMuZm9yRWFjaChmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgZWwuc3R5bGUud2lkdGggPSBtYXhJbm5lcldpZHRoICsgJ3B4JztcbiAgICB9KTtcbiAgICByZXR1cm4gbWF4SW5uZXJXaWR0aDtcbn1cbi8vIEdpdmVuIG9uZSBlbGVtZW50IHRoYXQgcmVzaWRlcyBpbnNpZGUgYW5vdGhlcixcbi8vIFN1YnRyYWN0cyB0aGUgaGVpZ2h0IG9mIHRoZSBpbm5lciBlbGVtZW50IGZyb20gdGhlIG91dGVyIGVsZW1lbnQuXG5mdW5jdGlvbiBzdWJ0cmFjdElubmVyRWxIZWlnaHQob3V0ZXJFbCwgaW5uZXJFbCkge1xuICAgIC8vIGVmZmluJyBJRTgvOS8xMC8xMSBzb21ldGltZXMgcmV0dXJucyAwIGZvciBkaW1lbnNpb25zLiB0aGlzIHdlaXJkIGhhY2sgd2FzIHRoZSBvbmx5IHRoaW5nIHRoYXQgd29ya2VkXG4gICAgdmFyIHJlZmxvd1N0eWxlUHJvcHMgPSB7XG4gICAgICAgIHBvc2l0aW9uOiAncmVsYXRpdmUnLFxuICAgICAgICBsZWZ0OiAtMSAvLyBlbnN1cmUgcmVmbG93IGluIGNhc2UgdGhlIGVsIHdhcyBhbHJlYWR5IHJlbGF0aXZlLiBuZWdhdGl2ZSBpcyBsZXNzIGxpa2VseSB0byBjYXVzZSBuZXcgc2Nyb2xsXG4gICAgfTtcbiAgICBhcHBseVN0eWxlKG91dGVyRWwsIHJlZmxvd1N0eWxlUHJvcHMpO1xuICAgIGFwcGx5U3R5bGUoaW5uZXJFbCwgcmVmbG93U3R5bGVQcm9wcyk7XG4gICAgdmFyIGRpZmYgPSAvLyBncmFiIHRoZSBkaW1lbnNpb25zXG4gICAgIG91dGVyRWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuaGVpZ2h0IC1cbiAgICAgICAgaW5uZXJFbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5oZWlnaHQ7XG4gICAgLy8gdW5kbyBoYWNrXG4gICAgdmFyIHJlc2V0U3R5bGVQcm9wcyA9IHsgcG9zaXRpb246ICcnLCBsZWZ0OiAnJyB9O1xuICAgIGFwcGx5U3R5bGUob3V0ZXJFbCwgcmVzZXRTdHlsZVByb3BzKTtcbiAgICBhcHBseVN0eWxlKGlubmVyRWwsIHJlc2V0U3R5bGVQcm9wcyk7XG4gICAgcmV0dXJuIGRpZmY7XG59XG4vKiBTZWxlY3Rpb25cbi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuZnVuY3Rpb24gcHJldmVudFNlbGVjdGlvbihlbCkge1xuICAgIGVsLmNsYXNzTGlzdC5hZGQoJ2ZjLXVuc2VsZWN0YWJsZScpO1xuICAgIGVsLmFkZEV2ZW50TGlzdGVuZXIoJ3NlbGVjdHN0YXJ0JywgcHJldmVudERlZmF1bHQpO1xufVxuZnVuY3Rpb24gYWxsb3dTZWxlY3Rpb24oZWwpIHtcbiAgICBlbC5jbGFzc0xpc3QucmVtb3ZlKCdmYy11bnNlbGVjdGFibGUnKTtcbiAgICBlbC5yZW1vdmVFdmVudExpc3RlbmVyKCdzZWxlY3RzdGFydCcsIHByZXZlbnREZWZhdWx0KTtcbn1cbi8qIENvbnRleHQgTWVudVxuLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5mdW5jdGlvbiBwcmV2ZW50Q29udGV4dE1lbnUoZWwpIHtcbiAgICBlbC5hZGRFdmVudExpc3RlbmVyKCdjb250ZXh0bWVudScsIHByZXZlbnREZWZhdWx0KTtcbn1cbmZ1bmN0aW9uIGFsbG93Q29udGV4dE1lbnUoZWwpIHtcbiAgICBlbC5yZW1vdmVFdmVudExpc3RlbmVyKCdjb250ZXh0bWVudScsIHByZXZlbnREZWZhdWx0KTtcbn1cbi8qIE9iamVjdCBPcmRlcmluZyBieSBGaWVsZFxuLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5mdW5jdGlvbiBwYXJzZUZpZWxkU3BlY3MoaW5wdXQpIHtcbiAgICB2YXIgc3BlY3MgPSBbXTtcbiAgICB2YXIgdG9rZW5zID0gW107XG4gICAgdmFyIGk7XG4gICAgdmFyIHRva2VuO1xuICAgIGlmICh0eXBlb2YgaW5wdXQgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgIHRva2VucyA9IGlucHV0LnNwbGl0KC9cXHMqLFxccyovKTtcbiAgICB9XG4gICAgZWxzZSBpZiAodHlwZW9mIGlucHV0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHRva2VucyA9IFtpbnB1dF07XG4gICAgfVxuICAgIGVsc2UgaWYgKEFycmF5LmlzQXJyYXkoaW5wdXQpKSB7XG4gICAgICAgIHRva2VucyA9IGlucHV0O1xuICAgIH1cbiAgICBmb3IgKGkgPSAwOyBpIDwgdG9rZW5zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHRva2VuID0gdG9rZW5zW2ldO1xuICAgICAgICBpZiAodHlwZW9mIHRva2VuID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgc3BlY3MucHVzaCh0b2tlbi5jaGFyQXQoMCkgPT09ICctJyA/XG4gICAgICAgICAgICAgICAgeyBmaWVsZDogdG9rZW4uc3Vic3RyaW5nKDEpLCBvcmRlcjogLTEgfSA6XG4gICAgICAgICAgICAgICAgeyBmaWVsZDogdG9rZW4sIG9yZGVyOiAxIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHR5cGVvZiB0b2tlbiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgc3BlY3MucHVzaCh7IGZ1bmM6IHRva2VuIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBzcGVjcztcbn1cbmZ1bmN0aW9uIGNvbXBhcmVCeUZpZWxkU3BlY3Mob2JqMCwgb2JqMSwgZmllbGRTcGVjcykge1xuICAgIHZhciBpO1xuICAgIHZhciBjbXA7XG4gICAgZm9yIChpID0gMDsgaSA8IGZpZWxkU3BlY3MubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgY21wID0gY29tcGFyZUJ5RmllbGRTcGVjKG9iajAsIG9iajEsIGZpZWxkU3BlY3NbaV0pO1xuICAgICAgICBpZiAoY21wKSB7XG4gICAgICAgICAgICByZXR1cm4gY21wO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiAwO1xufVxuZnVuY3Rpb24gY29tcGFyZUJ5RmllbGRTcGVjKG9iajAsIG9iajEsIGZpZWxkU3BlYykge1xuICAgIGlmIChmaWVsZFNwZWMuZnVuYykge1xuICAgICAgICByZXR1cm4gZmllbGRTcGVjLmZ1bmMob2JqMCwgb2JqMSk7XG4gICAgfVxuICAgIHJldHVybiBmbGV4aWJsZUNvbXBhcmUob2JqMFtmaWVsZFNwZWMuZmllbGRdLCBvYmoxW2ZpZWxkU3BlYy5maWVsZF0pXG4gICAgICAgICogKGZpZWxkU3BlYy5vcmRlciB8fCAxKTtcbn1cbmZ1bmN0aW9uIGZsZXhpYmxlQ29tcGFyZShhLCBiKSB7XG4gICAgaWYgKCFhICYmICFiKSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgIH1cbiAgICBpZiAoYiA9PSBudWxsKSB7XG4gICAgICAgIHJldHVybiAtMTtcbiAgICB9XG4gICAgaWYgKGEgPT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gMTtcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBhID09PSAnc3RyaW5nJyB8fCB0eXBlb2YgYiA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgcmV0dXJuIFN0cmluZyhhKS5sb2NhbGVDb21wYXJlKFN0cmluZyhiKSk7XG4gICAgfVxuICAgIHJldHVybiBhIC0gYjtcbn1cbi8qIFN0cmluZyBVdGlsaXRpZXNcbi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuZnVuY3Rpb24gY2FwaXRhbGlzZUZpcnN0TGV0dGVyKHN0cikge1xuICAgIHJldHVybiBzdHIuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkgKyBzdHIuc2xpY2UoMSk7XG59XG5mdW5jdGlvbiBwYWRTdGFydCh2YWwsIGxlbikge1xuICAgIHZhciBzID0gU3RyaW5nKHZhbCk7XG4gICAgcmV0dXJuICcwMDAnLnN1YnN0cigwLCBsZW4gLSBzLmxlbmd0aCkgKyBzO1xufVxuLyogTnVtYmVyIFV0aWxpdGllc1xuLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5mdW5jdGlvbiBjb21wYXJlTnVtYmVycyhhLCBiKSB7XG4gICAgcmV0dXJuIGEgLSBiO1xufVxuZnVuY3Rpb24gaXNJbnQobikge1xuICAgIHJldHVybiBuICUgMSA9PT0gMDtcbn1cbi8qIFdlaXJkIFV0aWxpdGllc1xuLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5mdW5jdGlvbiBhcHBseUFsbChmdW5jdGlvbnMsIHRoaXNPYmosIGFyZ3MpIHtcbiAgICBpZiAodHlwZW9mIGZ1bmN0aW9ucyA9PT0gJ2Z1bmN0aW9uJykgeyAvLyBzdXBwbGllZCBhIHNpbmdsZSBmdW5jdGlvblxuICAgICAgICBmdW5jdGlvbnMgPSBbZnVuY3Rpb25zXTtcbiAgICB9XG4gICAgaWYgKGZ1bmN0aW9ucykge1xuICAgICAgICB2YXIgaSA9IHZvaWQgMDtcbiAgICAgICAgdmFyIHJldCA9IHZvaWQgMDtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGZ1bmN0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgcmV0ID0gZnVuY3Rpb25zW2ldLmFwcGx5KHRoaXNPYmosIGFyZ3MpIHx8IHJldDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmV0O1xuICAgIH1cbn1cbmZ1bmN0aW9uIGZpcnN0RGVmaW5lZCgpIHtcbiAgICB2YXIgYXJncyA9IFtdO1xuICAgIGZvciAodmFyIF9pID0gMDsgX2kgPCBhcmd1bWVudHMubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgIGFyZ3NbX2ldID0gYXJndW1lbnRzW19pXTtcbiAgICB9XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhcmdzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmIChhcmdzW2ldICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHJldHVybiBhcmdzW2ldO1xuICAgICAgICB9XG4gICAgfVxufVxuLy8gUmV0dXJucyBhIGZ1bmN0aW9uLCB0aGF0LCBhcyBsb25nIGFzIGl0IGNvbnRpbnVlcyB0byBiZSBpbnZva2VkLCB3aWxsIG5vdFxuLy8gYmUgdHJpZ2dlcmVkLiBUaGUgZnVuY3Rpb24gd2lsbCBiZSBjYWxsZWQgYWZ0ZXIgaXQgc3RvcHMgYmVpbmcgY2FsbGVkIGZvclxuLy8gTiBtaWxsaXNlY29uZHMuIElmIGBpbW1lZGlhdGVgIGlzIHBhc3NlZCwgdHJpZ2dlciB0aGUgZnVuY3Rpb24gb24gdGhlXG4vLyBsZWFkaW5nIGVkZ2UsIGluc3RlYWQgb2YgdGhlIHRyYWlsaW5nLlxuLy8gaHR0cHM6Ly9naXRodWIuY29tL2phc2hrZW5hcy91bmRlcnNjb3JlL2Jsb2IvMS42LjAvdW5kZXJzY29yZS5qcyNMNzE0XG5mdW5jdGlvbiBkZWJvdW5jZShmdW5jLCB3YWl0KSB7XG4gICAgdmFyIHRpbWVvdXQ7XG4gICAgdmFyIGFyZ3M7XG4gICAgdmFyIGNvbnRleHQ7XG4gICAgdmFyIHRpbWVzdGFtcDtcbiAgICB2YXIgcmVzdWx0O1xuICAgIHZhciBsYXRlciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGxhc3QgPSBuZXcgRGF0ZSgpLnZhbHVlT2YoKSAtIHRpbWVzdGFtcDtcbiAgICAgICAgaWYgKGxhc3QgPCB3YWl0KSB7XG4gICAgICAgICAgICB0aW1lb3V0ID0gc2V0VGltZW91dChsYXRlciwgd2FpdCAtIGxhc3QpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGltZW91dCA9IG51bGw7XG4gICAgICAgICAgICByZXN1bHQgPSBmdW5jLmFwcGx5KGNvbnRleHQsIGFyZ3MpO1xuICAgICAgICAgICAgY29udGV4dCA9IGFyZ3MgPSBudWxsO1xuICAgICAgICB9XG4gICAgfTtcbiAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgICBjb250ZXh0ID0gdGhpcztcbiAgICAgICAgYXJncyA9IGFyZ3VtZW50cztcbiAgICAgICAgdGltZXN0YW1wID0gbmV3IERhdGUoKS52YWx1ZU9mKCk7XG4gICAgICAgIGlmICghdGltZW91dCkge1xuICAgICAgICAgICAgdGltZW91dCA9IHNldFRpbWVvdXQobGF0ZXIsIHdhaXQpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfTtcbn1cbi8vIE51bWJlciBhbmQgQm9vbGVhbiBhcmUgb25seSB0eXBlcyB0aGF0IGRlZmF1bHRzIG9yIG5vdCBjb21wdXRlZCBmb3Jcbi8vIFRPRE86IHdyaXRlIG1vcmUgY29tbWVudHNcbmZ1bmN0aW9uIHJlZmluZVByb3BzKHJhd1Byb3BzLCBwcm9jZXNzb3JzLCBkZWZhdWx0cywgbGVmdG92ZXJQcm9wcykge1xuICAgIGlmIChkZWZhdWx0cyA9PT0gdm9pZCAwKSB7IGRlZmF1bHRzID0ge307IH1cbiAgICB2YXIgcmVmaW5lZCA9IHt9O1xuICAgIGZvciAodmFyIGtleSBpbiBwcm9jZXNzb3JzKSB7XG4gICAgICAgIHZhciBwcm9jZXNzb3IgPSBwcm9jZXNzb3JzW2tleV07XG4gICAgICAgIGlmIChyYXdQcm9wc1trZXldICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIC8vIGZvdW5kXG4gICAgICAgICAgICBpZiAocHJvY2Vzc29yID09PSBGdW5jdGlvbikge1xuICAgICAgICAgICAgICAgIHJlZmluZWRba2V5XSA9IHR5cGVvZiByYXdQcm9wc1trZXldID09PSAnZnVuY3Rpb24nID8gcmF3UHJvcHNba2V5XSA6IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmIChwcm9jZXNzb3IpIHsgLy8gYSByZWZpbmluZyBmdW5jdGlvbj9cbiAgICAgICAgICAgICAgICByZWZpbmVkW2tleV0gPSBwcm9jZXNzb3IocmF3UHJvcHNba2V5XSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICByZWZpbmVkW2tleV0gPSByYXdQcm9wc1trZXldO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGRlZmF1bHRzW2tleV0gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgLy8gdGhlcmUncyBhbiBleHBsaWNpdCBkZWZhdWx0XG4gICAgICAgICAgICByZWZpbmVkW2tleV0gPSBkZWZhdWx0c1trZXldO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgLy8gbXVzdCBjb21wdXRlIGEgZGVmYXVsdFxuICAgICAgICAgICAgaWYgKHByb2Nlc3NvciA9PT0gU3RyaW5nKSB7XG4gICAgICAgICAgICAgICAgcmVmaW5lZFtrZXldID0gJyc7IC8vIGVtcHR5IHN0cmluZyBpcyBkZWZhdWx0IGZvciBTdHJpbmdcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKCFwcm9jZXNzb3IgfHwgcHJvY2Vzc29yID09PSBOdW1iZXIgfHwgcHJvY2Vzc29yID09PSBCb29sZWFuIHx8IHByb2Nlc3NvciA9PT0gRnVuY3Rpb24pIHtcbiAgICAgICAgICAgICAgICByZWZpbmVkW2tleV0gPSBudWxsOyAvLyBhc3NpZ24gbnVsbCBmb3Igb3RoZXIgbm9uLWN1c3RvbSBwcm9jZXNzb3IgZnVuY3NcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHJlZmluZWRba2V5XSA9IHByb2Nlc3NvcihudWxsKTsgLy8gcnVuIHRoZSBjdXN0b20gcHJvY2Vzc29yIGZ1bmNcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAobGVmdG92ZXJQcm9wcykge1xuICAgICAgICBmb3IgKHZhciBrZXkgaW4gcmF3UHJvcHMpIHtcbiAgICAgICAgICAgIGlmIChwcm9jZXNzb3JzW2tleV0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIGxlZnRvdmVyUHJvcHNba2V5XSA9IHJhd1Byb3BzW2tleV07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlZmluZWQ7XG59XG4vKiBEYXRlIHN0dWZmIHRoYXQgZG9lc24ndCBiZWxvbmcgaW4gZGF0ZWxpYiBjb3JlXG4tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbi8vIGdpdmVuIGEgdGltZWQgcmFuZ2UsIGNvbXB1dGVzIGFuIGFsbC1kYXkgcmFuZ2UgdGhhdCBoYXMgdGhlIHNhbWUgZXhhY3QgZHVyYXRpb24sXG4vLyBidXQgd2hvc2Ugc3RhcnQgdGltZSBpcyBhbGlnbmVkIHdpdGggdGhlIHN0YXJ0IG9mIHRoZSBkYXkuXG5mdW5jdGlvbiBjb21wdXRlQWxpZ25lZERheVJhbmdlKHRpbWVkUmFuZ2UpIHtcbiAgICB2YXIgZGF5Q250ID0gTWF0aC5mbG9vcihkaWZmRGF5cyh0aW1lZFJhbmdlLnN0YXJ0LCB0aW1lZFJhbmdlLmVuZCkpIHx8IDE7XG4gICAgdmFyIHN0YXJ0ID0gc3RhcnRPZkRheSh0aW1lZFJhbmdlLnN0YXJ0KTtcbiAgICB2YXIgZW5kID0gYWRkRGF5cyhzdGFydCwgZGF5Q250KTtcbiAgICByZXR1cm4geyBzdGFydDogc3RhcnQsIGVuZDogZW5kIH07XG59XG4vLyBnaXZlbiBhIHRpbWVkIHJhbmdlLCBjb21wdXRlcyBhbiBhbGwtZGF5IHJhbmdlIGJhc2VkIG9uIGhvdyBmb3IgdGhlIGVuZCBkYXRlIGJsZWVkcyBpbnRvIHRoZSBuZXh0IGRheVxuLy8gVE9ETzogZ2l2ZSBuZXh0RGF5VGhyZXNob2xkIGEgZGVmYXVsdCBhcmdcbmZ1bmN0aW9uIGNvbXB1dGVWaXNpYmxlRGF5UmFuZ2UodGltZWRSYW5nZSwgbmV4dERheVRocmVzaG9sZCkge1xuICAgIGlmIChuZXh0RGF5VGhyZXNob2xkID09PSB2b2lkIDApIHsgbmV4dERheVRocmVzaG9sZCA9IGNyZWF0ZUR1cmF0aW9uKDApOyB9XG4gICAgdmFyIHN0YXJ0RGF5ID0gbnVsbDtcbiAgICB2YXIgZW5kRGF5ID0gbnVsbDtcbiAgICBpZiAodGltZWRSYW5nZS5lbmQpIHtcbiAgICAgICAgZW5kRGF5ID0gc3RhcnRPZkRheSh0aW1lZFJhbmdlLmVuZCk7XG4gICAgICAgIHZhciBlbmRUaW1lTVMgPSB0aW1lZFJhbmdlLmVuZC52YWx1ZU9mKCkgLSBlbmREYXkudmFsdWVPZigpOyAvLyAjIG9mIG1pbGxpc2Vjb25kcyBpbnRvIGBlbmREYXlgXG4gICAgICAgIC8vIElmIHRoZSBlbmQgdGltZSBpcyBhY3R1YWxseSBpbmNsdXNpdmVseSBwYXJ0IG9mIHRoZSBuZXh0IGRheSBhbmQgaXMgZXF1YWwgdG8gb3JcbiAgICAgICAgLy8gYmV5b25kIHRoZSBuZXh0IGRheSB0aHJlc2hvbGQsIGFkanVzdCB0aGUgZW5kIHRvIGJlIHRoZSBleGNsdXNpdmUgZW5kIG9mIGBlbmREYXlgLlxuICAgICAgICAvLyBPdGhlcndpc2UsIGxlYXZpbmcgaXQgYXMgaW5jbHVzaXZlIHdpbGwgY2F1c2UgaXQgdG8gZXhjbHVkZSBgZW5kRGF5YC5cbiAgICAgICAgaWYgKGVuZFRpbWVNUyAmJiBlbmRUaW1lTVMgPj0gYXNSb3VnaE1zKG5leHREYXlUaHJlc2hvbGQpKSB7XG4gICAgICAgICAgICBlbmREYXkgPSBhZGREYXlzKGVuZERheSwgMSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgaWYgKHRpbWVkUmFuZ2Uuc3RhcnQpIHtcbiAgICAgICAgc3RhcnREYXkgPSBzdGFydE9mRGF5KHRpbWVkUmFuZ2Uuc3RhcnQpOyAvLyB0aGUgYmVnaW5uaW5nIG9mIHRoZSBkYXkgdGhlIHJhbmdlIHN0YXJ0c1xuICAgICAgICAvLyBJZiBlbmQgaXMgd2l0aGluIGBzdGFydERheWAgYnV0IG5vdCBwYXN0IG5leHREYXlUaHJlc2hvbGQsIGFzc2lnbiB0aGUgZGVmYXVsdCBkdXJhdGlvbiBvZiBvbmUgZGF5LlxuICAgICAgICBpZiAoZW5kRGF5ICYmIGVuZERheSA8PSBzdGFydERheSkge1xuICAgICAgICAgICAgZW5kRGF5ID0gYWRkRGF5cyhzdGFydERheSwgMSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgc3RhcnQ6IHN0YXJ0RGF5LCBlbmQ6IGVuZERheSB9O1xufVxuLy8gc3BhbnMgZnJvbSBvbmUgZGF5IGludG8gYW5vdGhlcj9cbmZ1bmN0aW9uIGlzTXVsdGlEYXlSYW5nZShyYW5nZSkge1xuICAgIHZhciB2aXNpYmxlUmFuZ2UgPSBjb21wdXRlVmlzaWJsZURheVJhbmdlKHJhbmdlKTtcbiAgICByZXR1cm4gZGlmZkRheXModmlzaWJsZVJhbmdlLnN0YXJ0LCB2aXNpYmxlUmFuZ2UuZW5kKSA+IDE7XG59XG5mdW5jdGlvbiBkaWZmRGF0ZXMoZGF0ZTAsIGRhdGUxLCBkYXRlRW52LCBsYXJnZVVuaXQpIHtcbiAgICBpZiAobGFyZ2VVbml0ID09PSAneWVhcicpIHtcbiAgICAgICAgcmV0dXJuIGNyZWF0ZUR1cmF0aW9uKGRhdGVFbnYuZGlmZldob2xlWWVhcnMoZGF0ZTAsIGRhdGUxKSwgJ3llYXInKTtcbiAgICB9XG4gICAgZWxzZSBpZiAobGFyZ2VVbml0ID09PSAnbW9udGgnKSB7XG4gICAgICAgIHJldHVybiBjcmVhdGVEdXJhdGlvbihkYXRlRW52LmRpZmZXaG9sZU1vbnRocyhkYXRlMCwgZGF0ZTEpLCAnbW9udGgnKTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHJldHVybiBkaWZmRGF5QW5kVGltZShkYXRlMCwgZGF0ZTEpOyAvLyByZXR1cm5zIGEgZHVyYXRpb25cbiAgICB9XG59XG5cbi8qISAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5Db3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cclxuTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTsgeW91IG1heSBub3QgdXNlXHJcbnRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlXHJcbkxpY2Vuc2UgYXQgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXHJcblxyXG5USElTIENPREUgSVMgUFJPVklERUQgT04gQU4gKkFTIElTKiBCQVNJUywgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZXHJcbktJTkQsIEVJVEhFUiBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBXSVRIT1VUIExJTUlUQVRJT04gQU5ZIElNUExJRURcclxuV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIFRJVExFLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSxcclxuTUVSQ0hBTlRBQkxJVFkgT1IgTk9OLUlORlJJTkdFTUVOVC5cclxuXHJcblNlZSB0aGUgQXBhY2hlIFZlcnNpb24gMi4wIExpY2Vuc2UgZm9yIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9uc1xyXG5hbmQgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXHJcbi8qIGdsb2JhbCBSZWZsZWN0LCBQcm9taXNlICovXHJcblxyXG52YXIgZXh0ZW5kU3RhdGljcyA9IGZ1bmN0aW9uKGQsIGIpIHtcclxuICAgIGV4dGVuZFN0YXRpY3MgPSBPYmplY3Quc2V0UHJvdG90eXBlT2YgfHxcclxuICAgICAgICAoeyBfX3Byb3RvX186IFtdIH0gaW5zdGFuY2VvZiBBcnJheSAmJiBmdW5jdGlvbiAoZCwgYikgeyBkLl9fcHJvdG9fXyA9IGI7IH0pIHx8XHJcbiAgICAgICAgZnVuY3Rpb24gKGQsIGIpIHsgZm9yICh2YXIgcCBpbiBiKSBpZiAoYi5oYXNPd25Qcm9wZXJ0eShwKSkgZFtwXSA9IGJbcF07IH07XHJcbiAgICByZXR1cm4gZXh0ZW5kU3RhdGljcyhkLCBiKTtcclxufTtcclxuXHJcbmZ1bmN0aW9uIF9fZXh0ZW5kcyhkLCBiKSB7XHJcbiAgICBleHRlbmRTdGF0aWNzKGQsIGIpO1xyXG4gICAgZnVuY3Rpb24gX18oKSB7IHRoaXMuY29uc3RydWN0b3IgPSBkOyB9XHJcbiAgICBkLnByb3RvdHlwZSA9IGIgPT09IG51bGwgPyBPYmplY3QuY3JlYXRlKGIpIDogKF9fLnByb3RvdHlwZSA9IGIucHJvdG90eXBlLCBuZXcgX18oKSk7XHJcbn1cclxuXHJcbnZhciBfX2Fzc2lnbiA9IGZ1bmN0aW9uKCkge1xyXG4gICAgX19hc3NpZ24gPSBPYmplY3QuYXNzaWduIHx8IGZ1bmN0aW9uIF9fYXNzaWduKHQpIHtcclxuICAgICAgICBmb3IgKHZhciBzLCBpID0gMSwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcclxuICAgICAgICAgICAgcyA9IGFyZ3VtZW50c1tpXTtcclxuICAgICAgICAgICAgZm9yICh2YXIgcCBpbiBzKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHMsIHApKSB0W3BdID0gc1twXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHQ7XHJcbiAgICB9O1xyXG4gICAgcmV0dXJuIF9fYXNzaWduLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XHJcbn07XG5cbmZ1bmN0aW9uIHBhcnNlUmVjdXJyaW5nKGV2ZW50SW5wdXQsIGFsbERheURlZmF1bHQsIGRhdGVFbnYsIHJlY3VycmluZ1R5cGVzLCBsZWZ0b3ZlcnMpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHJlY3VycmluZ1R5cGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBsb2NhbExlZnRvdmVycyA9IHt9O1xuICAgICAgICB2YXIgcGFyc2VkID0gcmVjdXJyaW5nVHlwZXNbaV0ucGFyc2UoZXZlbnRJbnB1dCwgbG9jYWxMZWZ0b3ZlcnMsIGRhdGVFbnYpO1xuICAgICAgICBpZiAocGFyc2VkKSB7XG4gICAgICAgICAgICB2YXIgYWxsRGF5ID0gbG9jYWxMZWZ0b3ZlcnMuYWxsRGF5O1xuICAgICAgICAgICAgZGVsZXRlIGxvY2FsTGVmdG92ZXJzLmFsbERheTsgLy8gcmVtb3ZlIGZyb20gbGVmdG92ZXJzXG4gICAgICAgICAgICBpZiAoYWxsRGF5ID09IG51bGwpIHtcbiAgICAgICAgICAgICAgICBhbGxEYXkgPSBhbGxEYXlEZWZhdWx0O1xuICAgICAgICAgICAgICAgIGlmIChhbGxEYXkgPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICBhbGxEYXkgPSBwYXJzZWQuYWxsRGF5R3Vlc3M7XG4gICAgICAgICAgICAgICAgICAgIGlmIChhbGxEYXkgPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgYWxsRGF5ID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBfX2Fzc2lnbihsZWZ0b3ZlcnMsIGxvY2FsTGVmdG92ZXJzKTtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgYWxsRGF5OiBhbGxEYXksXG4gICAgICAgICAgICAgICAgZHVyYXRpb246IHBhcnNlZC5kdXJhdGlvbixcbiAgICAgICAgICAgICAgICB0eXBlRGF0YTogcGFyc2VkLnR5cGVEYXRhLFxuICAgICAgICAgICAgICAgIHR5cGVJZDogaVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cbi8qXG5FdmVudCBNVVNUIGhhdmUgYSByZWN1cnJpbmdEZWZcbiovXG5mdW5jdGlvbiBleHBhbmRSZWN1cnJpbmdSYW5nZXMoZXZlbnREZWYsIGR1cmF0aW9uLCBmcmFtaW5nUmFuZ2UsIGRhdGVFbnYsIHJlY3VycmluZ1R5cGVzKSB7XG4gICAgdmFyIHR5cGVEZWYgPSByZWN1cnJpbmdUeXBlc1tldmVudERlZi5yZWN1cnJpbmdEZWYudHlwZUlkXTtcbiAgICB2YXIgbWFya2VycyA9IHR5cGVEZWYuZXhwYW5kKGV2ZW50RGVmLnJlY3VycmluZ0RlZi50eXBlRGF0YSwge1xuICAgICAgICBzdGFydDogZGF0ZUVudi5zdWJ0cmFjdChmcmFtaW5nUmFuZ2Uuc3RhcnQsIGR1cmF0aW9uKSxcbiAgICAgICAgZW5kOiBmcmFtaW5nUmFuZ2UuZW5kXG4gICAgfSwgZGF0ZUVudik7XG4gICAgLy8gdGhlIHJlY3VycmVuY2UgcGx1Z2lucyBkb24ndCBndWFyYW50ZWUgdGhhdCBhbGwtZGF5IGV2ZW50cyBhcmUgc3RhcnQtb2YtZGF5LCBzbyB3ZSBoYXZlIHRvXG4gICAgaWYgKGV2ZW50RGVmLmFsbERheSkge1xuICAgICAgICBtYXJrZXJzID0gbWFya2Vycy5tYXAoc3RhcnRPZkRheSk7XG4gICAgfVxuICAgIHJldHVybiBtYXJrZXJzO1xufVxuXG52YXIgaGFzT3duUHJvcGVydHkgPSBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5O1xuLy8gTWVyZ2VzIGFuIGFycmF5IG9mIG9iamVjdHMgaW50byBhIHNpbmdsZSBvYmplY3QuXG4vLyBUaGUgc2Vjb25kIGFyZ3VtZW50IGFsbG93cyBmb3IgYW4gYXJyYXkgb2YgcHJvcGVydHkgbmFtZXMgd2hvJ3Mgb2JqZWN0IHZhbHVlcyB3aWxsIGJlIG1lcmdlZCB0b2dldGhlci5cbmZ1bmN0aW9uIG1lcmdlUHJvcHMocHJvcE9ianMsIGNvbXBsZXhQcm9wcykge1xuICAgIHZhciBkZXN0ID0ge307XG4gICAgdmFyIGk7XG4gICAgdmFyIG5hbWU7XG4gICAgdmFyIGNvbXBsZXhPYmpzO1xuICAgIHZhciBqO1xuICAgIHZhciB2YWw7XG4gICAgdmFyIHByb3BzO1xuICAgIGlmIChjb21wbGV4UHJvcHMpIHtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGNvbXBsZXhQcm9wcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgbmFtZSA9IGNvbXBsZXhQcm9wc1tpXTtcbiAgICAgICAgICAgIGNvbXBsZXhPYmpzID0gW107XG4gICAgICAgICAgICAvLyBjb2xsZWN0IHRoZSB0cmFpbGluZyBvYmplY3QgdmFsdWVzLCBzdG9wcGluZyB3aGVuIGEgbm9uLW9iamVjdCBpcyBkaXNjb3ZlcmVkXG4gICAgICAgICAgICBmb3IgKGogPSBwcm9wT2Jqcy5sZW5ndGggLSAxOyBqID49IDA7IGotLSkge1xuICAgICAgICAgICAgICAgIHZhbCA9IHByb3BPYmpzW2pdW25hbWVdO1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsID09PSAnb2JqZWN0JyAmJiB2YWwpIHsgLy8gbm9uLW51bGwgb2JqZWN0XG4gICAgICAgICAgICAgICAgICAgIGNvbXBsZXhPYmpzLnVuc2hpZnQodmFsKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAodmFsICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgZGVzdFtuYW1lXSA9IHZhbDsgLy8gaWYgdGhlcmUgd2VyZSBubyBvYmplY3RzLCB0aGlzIHZhbHVlIHdpbGwgYmUgdXNlZFxuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBpZiB0aGUgdHJhaWxpbmcgdmFsdWVzIHdlcmUgb2JqZWN0cywgdXNlIHRoZSBtZXJnZWQgdmFsdWVcbiAgICAgICAgICAgIGlmIChjb21wbGV4T2Jqcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBkZXN0W25hbWVdID0gbWVyZ2VQcm9wcyhjb21wbGV4T2Jqcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gY29weSB2YWx1ZXMgaW50byB0aGUgZGVzdGluYXRpb24sIGdvaW5nIGZyb20gbGFzdCB0byBmaXJzdFxuICAgIGZvciAoaSA9IHByb3BPYmpzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICAgIHByb3BzID0gcHJvcE9ianNbaV07XG4gICAgICAgIGZvciAobmFtZSBpbiBwcm9wcykge1xuICAgICAgICAgICAgaWYgKCEobmFtZSBpbiBkZXN0KSkgeyAvLyBpZiBhbHJlYWR5IGFzc2lnbmVkIGJ5IHByZXZpb3VzIHByb3BzIG9yIGNvbXBsZXggcHJvcHMsIGRvbid0IHJlYXNzaWduXG4gICAgICAgICAgICAgICAgZGVzdFtuYW1lXSA9IHByb3BzW25hbWVdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBkZXN0O1xufVxuZnVuY3Rpb24gZmlsdGVySGFzaChoYXNoLCBmdW5jKSB7XG4gICAgdmFyIGZpbHRlcmVkID0ge307XG4gICAgZm9yICh2YXIga2V5IGluIGhhc2gpIHtcbiAgICAgICAgaWYgKGZ1bmMoaGFzaFtrZXldLCBrZXkpKSB7XG4gICAgICAgICAgICBmaWx0ZXJlZFtrZXldID0gaGFzaFtrZXldO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBmaWx0ZXJlZDtcbn1cbmZ1bmN0aW9uIG1hcEhhc2goaGFzaCwgZnVuYykge1xuICAgIHZhciBuZXdIYXNoID0ge307XG4gICAgZm9yICh2YXIga2V5IGluIGhhc2gpIHtcbiAgICAgICAgbmV3SGFzaFtrZXldID0gZnVuYyhoYXNoW2tleV0sIGtleSk7XG4gICAgfVxuICAgIHJldHVybiBuZXdIYXNoO1xufVxuZnVuY3Rpb24gYXJyYXlUb0hhc2goYSkge1xuICAgIHZhciBoYXNoID0ge307XG4gICAgZm9yICh2YXIgX2kgPSAwLCBhXzEgPSBhOyBfaSA8IGFfMS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgdmFyIGl0ZW0gPSBhXzFbX2ldO1xuICAgICAgICBoYXNoW2l0ZW1dID0gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGhhc2g7XG59XG5mdW5jdGlvbiBoYXNoVmFsdWVzVG9BcnJheShvYmopIHtcbiAgICB2YXIgYSA9IFtdO1xuICAgIGZvciAodmFyIGtleSBpbiBvYmopIHtcbiAgICAgICAgYS5wdXNoKG9ialtrZXldKTtcbiAgICB9XG4gICAgcmV0dXJuIGE7XG59XG5mdW5jdGlvbiBpc1Byb3BzRXF1YWwob2JqMCwgb2JqMSkge1xuICAgIGZvciAodmFyIGtleSBpbiBvYmowKSB7XG4gICAgICAgIGlmIChoYXNPd25Qcm9wZXJ0eS5jYWxsKG9iajAsIGtleSkpIHtcbiAgICAgICAgICAgIGlmICghKGtleSBpbiBvYmoxKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICBmb3IgKHZhciBrZXkgaW4gb2JqMSkge1xuICAgICAgICBpZiAoaGFzT3duUHJvcGVydHkuY2FsbChvYmoxLCBrZXkpKSB7XG4gICAgICAgICAgICBpZiAob2JqMFtrZXldICE9PSBvYmoxW2tleV0pIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG59XG5cbmZ1bmN0aW9uIHBhcnNlRXZlbnRzKHJhd0V2ZW50cywgc291cmNlSWQsIGNhbGVuZGFyLCBhbGxvd09wZW5SYW5nZSkge1xuICAgIHZhciBldmVudFN0b3JlID0gY3JlYXRlRW1wdHlFdmVudFN0b3JlKCk7XG4gICAgZm9yICh2YXIgX2kgPSAwLCByYXdFdmVudHNfMSA9IHJhd0V2ZW50czsgX2kgPCByYXdFdmVudHNfMS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgdmFyIHJhd0V2ZW50ID0gcmF3RXZlbnRzXzFbX2ldO1xuICAgICAgICB2YXIgdHVwbGUgPSBwYXJzZUV2ZW50KHJhd0V2ZW50LCBzb3VyY2VJZCwgY2FsZW5kYXIsIGFsbG93T3BlblJhbmdlKTtcbiAgICAgICAgaWYgKHR1cGxlKSB7XG4gICAgICAgICAgICBldmVudFR1cGxlVG9TdG9yZSh0dXBsZSwgZXZlbnRTdG9yZSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGV2ZW50U3RvcmU7XG59XG5mdW5jdGlvbiBldmVudFR1cGxlVG9TdG9yZSh0dXBsZSwgZXZlbnRTdG9yZSkge1xuICAgIGlmIChldmVudFN0b3JlID09PSB2b2lkIDApIHsgZXZlbnRTdG9yZSA9IGNyZWF0ZUVtcHR5RXZlbnRTdG9yZSgpOyB9XG4gICAgZXZlbnRTdG9yZS5kZWZzW3R1cGxlLmRlZi5kZWZJZF0gPSB0dXBsZS5kZWY7XG4gICAgaWYgKHR1cGxlLmluc3RhbmNlKSB7XG4gICAgICAgIGV2ZW50U3RvcmUuaW5zdGFuY2VzW3R1cGxlLmluc3RhbmNlLmluc3RhbmNlSWRdID0gdHVwbGUuaW5zdGFuY2U7XG4gICAgfVxuICAgIHJldHVybiBldmVudFN0b3JlO1xufVxuZnVuY3Rpb24gZXhwYW5kUmVjdXJyaW5nKGV2ZW50U3RvcmUsIGZyYW1pbmdSYW5nZSwgY2FsZW5kYXIpIHtcbiAgICB2YXIgZGF0ZUVudiA9IGNhbGVuZGFyLmRhdGVFbnY7XG4gICAgdmFyIGRlZnMgPSBldmVudFN0b3JlLmRlZnMsIGluc3RhbmNlcyA9IGV2ZW50U3RvcmUuaW5zdGFuY2VzO1xuICAgIC8vIHJlbW92ZSBleGlzdGluZyByZWN1cnJpbmcgaW5zdGFuY2VzXG4gICAgaW5zdGFuY2VzID0gZmlsdGVySGFzaChpbnN0YW5jZXMsIGZ1bmN0aW9uIChpbnN0YW5jZSkge1xuICAgICAgICByZXR1cm4gIWRlZnNbaW5zdGFuY2UuZGVmSWRdLnJlY3VycmluZ0RlZjtcbiAgICB9KTtcbiAgICBmb3IgKHZhciBkZWZJZCBpbiBkZWZzKSB7XG4gICAgICAgIHZhciBkZWYgPSBkZWZzW2RlZklkXTtcbiAgICAgICAgaWYgKGRlZi5yZWN1cnJpbmdEZWYpIHtcbiAgICAgICAgICAgIHZhciBkdXJhdGlvbiA9IGRlZi5yZWN1cnJpbmdEZWYuZHVyYXRpb247XG4gICAgICAgICAgICBpZiAoIWR1cmF0aW9uKSB7XG4gICAgICAgICAgICAgICAgZHVyYXRpb24gPSBkZWYuYWxsRGF5ID9cbiAgICAgICAgICAgICAgICAgICAgY2FsZW5kYXIuZGVmYXVsdEFsbERheUV2ZW50RHVyYXRpb24gOlxuICAgICAgICAgICAgICAgICAgICBjYWxlbmRhci5kZWZhdWx0VGltZWRFdmVudER1cmF0aW9uO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHN0YXJ0cyA9IGV4cGFuZFJlY3VycmluZ1JhbmdlcyhkZWYsIGR1cmF0aW9uLCBmcmFtaW5nUmFuZ2UsIGNhbGVuZGFyLmRhdGVFbnYsIGNhbGVuZGFyLnBsdWdpblN5c3RlbS5ob29rcy5yZWN1cnJpbmdUeXBlcyk7XG4gICAgICAgICAgICBmb3IgKHZhciBfaSA9IDAsIHN0YXJ0c18xID0gc3RhcnRzOyBfaSA8IHN0YXJ0c18xLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgICAgIHZhciBzdGFydCA9IHN0YXJ0c18xW19pXTtcbiAgICAgICAgICAgICAgICB2YXIgaW5zdGFuY2UgPSBjcmVhdGVFdmVudEluc3RhbmNlKGRlZklkLCB7XG4gICAgICAgICAgICAgICAgICAgIHN0YXJ0OiBzdGFydCxcbiAgICAgICAgICAgICAgICAgICAgZW5kOiBkYXRlRW52LmFkZChzdGFydCwgZHVyYXRpb24pXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgaW5zdGFuY2VzW2luc3RhbmNlLmluc3RhbmNlSWRdID0gaW5zdGFuY2U7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgZGVmczogZGVmcywgaW5zdGFuY2VzOiBpbnN0YW5jZXMgfTtcbn1cbi8vIHJldHJpZXZlcyBldmVudHMgdGhhdCBoYXZlIHRoZSBzYW1lIGdyb3VwSWQgYXMgdGhlIGluc3RhbmNlIHNwZWNpZmllZCBieSBgaW5zdGFuY2VJZGBcbi8vIG9yIHRoZXkgYXJlIHRoZSBzYW1lIGFzIHRoZSBpbnN0YW5jZS5cbi8vIHdoeSBtaWdodCBpbnN0YW5jZUlkIG5vdCBiZSBpbiB0aGUgc3RvcmU/IGFuIGV2ZW50IGZyb20gYW5vdGhlciBjYWxlbmRhcj9cbmZ1bmN0aW9uIGdldFJlbGV2YW50RXZlbnRzKGV2ZW50U3RvcmUsIGluc3RhbmNlSWQpIHtcbiAgICB2YXIgaW5zdGFuY2UgPSBldmVudFN0b3JlLmluc3RhbmNlc1tpbnN0YW5jZUlkXTtcbiAgICBpZiAoaW5zdGFuY2UpIHtcbiAgICAgICAgdmFyIGRlZl8xID0gZXZlbnRTdG9yZS5kZWZzW2luc3RhbmNlLmRlZklkXTtcbiAgICAgICAgLy8gZ2V0IGV2ZW50cy9pbnN0YW5jZXMgd2l0aCBzYW1lIGdyb3VwXG4gICAgICAgIHZhciBuZXdTdG9yZSA9IGZpbHRlckV2ZW50U3RvcmVEZWZzKGV2ZW50U3RvcmUsIGZ1bmN0aW9uIChsb29rRGVmKSB7XG4gICAgICAgICAgICByZXR1cm4gaXNFdmVudERlZnNHcm91cGVkKGRlZl8xLCBsb29rRGVmKTtcbiAgICAgICAgfSk7XG4gICAgICAgIC8vIGFkZCB0aGUgb3JpZ2luYWxcbiAgICAgICAgLy8gVE9ETzogd2lzaCB3ZSBjb3VsZCB1c2UgZXZlbnRUdXBsZVRvU3RvcmUgb3Igc29tZXRoaW5nIGxpa2UgaXRcbiAgICAgICAgbmV3U3RvcmUuZGVmc1tkZWZfMS5kZWZJZF0gPSBkZWZfMTtcbiAgICAgICAgbmV3U3RvcmUuaW5zdGFuY2VzW2luc3RhbmNlLmluc3RhbmNlSWRdID0gaW5zdGFuY2U7XG4gICAgICAgIHJldHVybiBuZXdTdG9yZTtcbiAgICB9XG4gICAgcmV0dXJuIGNyZWF0ZUVtcHR5RXZlbnRTdG9yZSgpO1xufVxuZnVuY3Rpb24gaXNFdmVudERlZnNHcm91cGVkKGRlZjAsIGRlZjEpIHtcbiAgICByZXR1cm4gQm9vbGVhbihkZWYwLmdyb3VwSWQgJiYgZGVmMC5ncm91cElkID09PSBkZWYxLmdyb3VwSWQpO1xufVxuZnVuY3Rpb24gdHJhbnNmb3JtUmF3RXZlbnRzKHJhd0V2ZW50cywgZXZlbnRTb3VyY2UsIGNhbGVuZGFyKSB7XG4gICAgdmFyIGNhbEVhY2hUcmFuc2Zvcm0gPSBjYWxlbmRhci5vcHQoJ2V2ZW50RGF0YVRyYW5zZm9ybScpO1xuICAgIHZhciBzb3VyY2VFYWNoVHJhbnNmb3JtID0gZXZlbnRTb3VyY2UgPyBldmVudFNvdXJjZS5ldmVudERhdGFUcmFuc2Zvcm0gOiBudWxsO1xuICAgIGlmIChzb3VyY2VFYWNoVHJhbnNmb3JtKSB7XG4gICAgICAgIHJhd0V2ZW50cyA9IHRyYW5zZm9ybUVhY2hSYXdFdmVudChyYXdFdmVudHMsIHNvdXJjZUVhY2hUcmFuc2Zvcm0pO1xuICAgIH1cbiAgICBpZiAoY2FsRWFjaFRyYW5zZm9ybSkge1xuICAgICAgICByYXdFdmVudHMgPSB0cmFuc2Zvcm1FYWNoUmF3RXZlbnQocmF3RXZlbnRzLCBjYWxFYWNoVHJhbnNmb3JtKTtcbiAgICB9XG4gICAgcmV0dXJuIHJhd0V2ZW50cztcbn1cbmZ1bmN0aW9uIHRyYW5zZm9ybUVhY2hSYXdFdmVudChyYXdFdmVudHMsIGZ1bmMpIHtcbiAgICB2YXIgcmVmaW5lZEV2ZW50cztcbiAgICBpZiAoIWZ1bmMpIHtcbiAgICAgICAgcmVmaW5lZEV2ZW50cyA9IHJhd0V2ZW50cztcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHJlZmluZWRFdmVudHMgPSBbXTtcbiAgICAgICAgZm9yICh2YXIgX2kgPSAwLCByYXdFdmVudHNfMiA9IHJhd0V2ZW50czsgX2kgPCByYXdFdmVudHNfMi5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIHZhciByYXdFdmVudCA9IHJhd0V2ZW50c18yW19pXTtcbiAgICAgICAgICAgIHZhciByZWZpbmVkRXZlbnQgPSBmdW5jKHJhd0V2ZW50KTtcbiAgICAgICAgICAgIGlmIChyZWZpbmVkRXZlbnQpIHtcbiAgICAgICAgICAgICAgICByZWZpbmVkRXZlbnRzLnB1c2gocmVmaW5lZEV2ZW50KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKHJlZmluZWRFdmVudCA9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgcmVmaW5lZEV2ZW50cy5wdXNoKHJhd0V2ZW50KTtcbiAgICAgICAgICAgIH0gLy8gaWYgYSBkaWZmZXJlbnQgZmFsc3kgdmFsdWUsIGRvIG5vdGhpbmdcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVmaW5lZEV2ZW50cztcbn1cbmZ1bmN0aW9uIGNyZWF0ZUVtcHR5RXZlbnRTdG9yZSgpIHtcbiAgICByZXR1cm4geyBkZWZzOiB7fSwgaW5zdGFuY2VzOiB7fSB9O1xufVxuZnVuY3Rpb24gbWVyZ2VFdmVudFN0b3JlcyhzdG9yZTAsIHN0b3JlMSkge1xuICAgIHJldHVybiB7XG4gICAgICAgIGRlZnM6IF9fYXNzaWduKHt9LCBzdG9yZTAuZGVmcywgc3RvcmUxLmRlZnMpLFxuICAgICAgICBpbnN0YW5jZXM6IF9fYXNzaWduKHt9LCBzdG9yZTAuaW5zdGFuY2VzLCBzdG9yZTEuaW5zdGFuY2VzKVxuICAgIH07XG59XG5mdW5jdGlvbiBmaWx0ZXJFdmVudFN0b3JlRGVmcyhldmVudFN0b3JlLCBmaWx0ZXJGdW5jKSB7XG4gICAgdmFyIGRlZnMgPSBmaWx0ZXJIYXNoKGV2ZW50U3RvcmUuZGVmcywgZmlsdGVyRnVuYyk7XG4gICAgdmFyIGluc3RhbmNlcyA9IGZpbHRlckhhc2goZXZlbnRTdG9yZS5pbnN0YW5jZXMsIGZ1bmN0aW9uIChpbnN0YW5jZSkge1xuICAgICAgICByZXR1cm4gZGVmc1tpbnN0YW5jZS5kZWZJZF07IC8vIHN0aWxsIGV4aXN0cz9cbiAgICB9KTtcbiAgICByZXR1cm4geyBkZWZzOiBkZWZzLCBpbnN0YW5jZXM6IGluc3RhbmNlcyB9O1xufVxuXG5mdW5jdGlvbiBwYXJzZVJhbmdlKGlucHV0LCBkYXRlRW52KSB7XG4gICAgdmFyIHN0YXJ0ID0gbnVsbDtcbiAgICB2YXIgZW5kID0gbnVsbDtcbiAgICBpZiAoaW5wdXQuc3RhcnQpIHtcbiAgICAgICAgc3RhcnQgPSBkYXRlRW52LmNyZWF0ZU1hcmtlcihpbnB1dC5zdGFydCk7XG4gICAgfVxuICAgIGlmIChpbnB1dC5lbmQpIHtcbiAgICAgICAgZW5kID0gZGF0ZUVudi5jcmVhdGVNYXJrZXIoaW5wdXQuZW5kKTtcbiAgICB9XG4gICAgaWYgKCFzdGFydCAmJiAhZW5kKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBpZiAoc3RhcnQgJiYgZW5kICYmIGVuZCA8IHN0YXJ0KSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICByZXR1cm4geyBzdGFydDogc3RhcnQsIGVuZDogZW5kIH07XG59XG4vLyBTSURFLUVGRkVDVDogd2lsbCBtdXRhdGUgcmFuZ2VzLlxuLy8gV2lsbCByZXR1cm4gYSBuZXcgYXJyYXkgcmVzdWx0LlxuZnVuY3Rpb24gaW52ZXJ0UmFuZ2VzKHJhbmdlcywgY29uc3RyYWludFJhbmdlKSB7XG4gICAgdmFyIGludmVydGVkUmFuZ2VzID0gW107XG4gICAgdmFyIHN0YXJ0ID0gY29uc3RyYWludFJhbmdlLnN0YXJ0OyAvLyB0aGUgZW5kIG9mIHRoZSBwcmV2aW91cyByYW5nZS4gdGhlIHN0YXJ0IG9mIHRoZSBuZXcgcmFuZ2VcbiAgICB2YXIgaTtcbiAgICB2YXIgZGF0ZVJhbmdlO1xuICAgIC8vIHJhbmdlcyBuZWVkIHRvIGJlIGluIG9yZGVyLiByZXF1aXJlZCBmb3Igb3VyIGRhdGUtd2Fsa2luZyBhbGdvcml0aG1cbiAgICByYW5nZXMuc29ydChjb21wYXJlUmFuZ2VzKTtcbiAgICBmb3IgKGkgPSAwOyBpIDwgcmFuZ2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGRhdGVSYW5nZSA9IHJhbmdlc1tpXTtcbiAgICAgICAgLy8gYWRkIHRoZSBzcGFuIG9mIHRpbWUgYmVmb3JlIHRoZSBldmVudCAoaWYgdGhlcmUgaXMgYW55KVxuICAgICAgICBpZiAoZGF0ZVJhbmdlLnN0YXJ0ID4gc3RhcnQpIHsgLy8gY29tcGFyZSBtaWxsaXNlY29uZCB0aW1lIChza2lwIGFueSBhbWJpZyBsb2dpYylcbiAgICAgICAgICAgIGludmVydGVkUmFuZ2VzLnB1c2goeyBzdGFydDogc3RhcnQsIGVuZDogZGF0ZVJhbmdlLnN0YXJ0IH0pO1xuICAgICAgICB9XG4gICAgICAgIGlmIChkYXRlUmFuZ2UuZW5kID4gc3RhcnQpIHtcbiAgICAgICAgICAgIHN0YXJ0ID0gZGF0ZVJhbmdlLmVuZDtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBhZGQgdGhlIHNwYW4gb2YgdGltZSBhZnRlciB0aGUgbGFzdCBldmVudCAoaWYgdGhlcmUgaXMgYW55KVxuICAgIGlmIChzdGFydCA8IGNvbnN0cmFpbnRSYW5nZS5lbmQpIHsgLy8gY29tcGFyZSBtaWxsaXNlY29uZCB0aW1lIChza2lwIGFueSBhbWJpZyBsb2dpYylcbiAgICAgICAgaW52ZXJ0ZWRSYW5nZXMucHVzaCh7IHN0YXJ0OiBzdGFydCwgZW5kOiBjb25zdHJhaW50UmFuZ2UuZW5kIH0pO1xuICAgIH1cbiAgICByZXR1cm4gaW52ZXJ0ZWRSYW5nZXM7XG59XG5mdW5jdGlvbiBjb21wYXJlUmFuZ2VzKHJhbmdlMCwgcmFuZ2UxKSB7XG4gICAgcmV0dXJuIHJhbmdlMC5zdGFydC52YWx1ZU9mKCkgLSByYW5nZTEuc3RhcnQudmFsdWVPZigpOyAvLyBlYXJsaWVyIHJhbmdlcyBnbyBmaXJzdFxufVxuZnVuY3Rpb24gaW50ZXJzZWN0UmFuZ2VzKHJhbmdlMCwgcmFuZ2UxKSB7XG4gICAgdmFyIHN0YXJ0ID0gcmFuZ2UwLnN0YXJ0O1xuICAgIHZhciBlbmQgPSByYW5nZTAuZW5kO1xuICAgIHZhciBuZXdSYW5nZSA9IG51bGw7XG4gICAgaWYgKHJhbmdlMS5zdGFydCAhPT0gbnVsbCkge1xuICAgICAgICBpZiAoc3RhcnQgPT09IG51bGwpIHtcbiAgICAgICAgICAgIHN0YXJ0ID0gcmFuZ2UxLnN0YXJ0O1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgc3RhcnQgPSBuZXcgRGF0ZShNYXRoLm1heChzdGFydC52YWx1ZU9mKCksIHJhbmdlMS5zdGFydC52YWx1ZU9mKCkpKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAocmFuZ2UxLmVuZCAhPSBudWxsKSB7XG4gICAgICAgIGlmIChlbmQgPT09IG51bGwpIHtcbiAgICAgICAgICAgIGVuZCA9IHJhbmdlMS5lbmQ7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBlbmQgPSBuZXcgRGF0ZShNYXRoLm1pbihlbmQudmFsdWVPZigpLCByYW5nZTEuZW5kLnZhbHVlT2YoKSkpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGlmIChzdGFydCA9PT0gbnVsbCB8fCBlbmQgPT09IG51bGwgfHwgc3RhcnQgPCBlbmQpIHtcbiAgICAgICAgbmV3UmFuZ2UgPSB7IHN0YXJ0OiBzdGFydCwgZW5kOiBlbmQgfTtcbiAgICB9XG4gICAgcmV0dXJuIG5ld1JhbmdlO1xufVxuZnVuY3Rpb24gcmFuZ2VzRXF1YWwocmFuZ2UwLCByYW5nZTEpIHtcbiAgICByZXR1cm4gKHJhbmdlMC5zdGFydCA9PT0gbnVsbCA/IG51bGwgOiByYW5nZTAuc3RhcnQudmFsdWVPZigpKSA9PT0gKHJhbmdlMS5zdGFydCA9PT0gbnVsbCA/IG51bGwgOiByYW5nZTEuc3RhcnQudmFsdWVPZigpKSAmJlxuICAgICAgICAocmFuZ2UwLmVuZCA9PT0gbnVsbCA/IG51bGwgOiByYW5nZTAuZW5kLnZhbHVlT2YoKSkgPT09IChyYW5nZTEuZW5kID09PSBudWxsID8gbnVsbCA6IHJhbmdlMS5lbmQudmFsdWVPZigpKTtcbn1cbmZ1bmN0aW9uIHJhbmdlc0ludGVyc2VjdChyYW5nZTAsIHJhbmdlMSkge1xuICAgIHJldHVybiAocmFuZ2UwLmVuZCA9PT0gbnVsbCB8fCByYW5nZTEuc3RhcnQgPT09IG51bGwgfHwgcmFuZ2UwLmVuZCA+IHJhbmdlMS5zdGFydCkgJiZcbiAgICAgICAgKHJhbmdlMC5zdGFydCA9PT0gbnVsbCB8fCByYW5nZTEuZW5kID09PSBudWxsIHx8IHJhbmdlMC5zdGFydCA8IHJhbmdlMS5lbmQpO1xufVxuZnVuY3Rpb24gcmFuZ2VDb250YWluc1JhbmdlKG91dGVyUmFuZ2UsIGlubmVyUmFuZ2UpIHtcbiAgICByZXR1cm4gKG91dGVyUmFuZ2Uuc3RhcnQgPT09IG51bGwgfHwgKGlubmVyUmFuZ2Uuc3RhcnQgIT09IG51bGwgJiYgaW5uZXJSYW5nZS5zdGFydCA+PSBvdXRlclJhbmdlLnN0YXJ0KSkgJiZcbiAgICAgICAgKG91dGVyUmFuZ2UuZW5kID09PSBudWxsIHx8IChpbm5lclJhbmdlLmVuZCAhPT0gbnVsbCAmJiBpbm5lclJhbmdlLmVuZCA8PSBvdXRlclJhbmdlLmVuZCkpO1xufVxuZnVuY3Rpb24gcmFuZ2VDb250YWluc01hcmtlcihyYW5nZSwgZGF0ZSkge1xuICAgIHJldHVybiAocmFuZ2Uuc3RhcnQgPT09IG51bGwgfHwgZGF0ZSA+PSByYW5nZS5zdGFydCkgJiZcbiAgICAgICAgKHJhbmdlLmVuZCA9PT0gbnVsbCB8fCBkYXRlIDwgcmFuZ2UuZW5kKTtcbn1cbi8vIElmIHRoZSBnaXZlbiBkYXRlIGlzIG5vdCB3aXRoaW4gdGhlIGdpdmVuIHJhbmdlLCBtb3ZlIGl0IGluc2lkZS5cbi8vIChJZiBpdCdzIHBhc3QgdGhlIGVuZCwgbWFrZSBpdCBvbmUgbWlsbGlzZWNvbmQgYmVmb3JlIHRoZSBlbmQpLlxuZnVuY3Rpb24gY29uc3RyYWluTWFya2VyVG9SYW5nZShkYXRlLCByYW5nZSkge1xuICAgIGlmIChyYW5nZS5zdGFydCAhPSBudWxsICYmIGRhdGUgPCByYW5nZS5zdGFydCkge1xuICAgICAgICByZXR1cm4gcmFuZ2Uuc3RhcnQ7XG4gICAgfVxuICAgIGlmIChyYW5nZS5lbmQgIT0gbnVsbCAmJiBkYXRlID49IHJhbmdlLmVuZCkge1xuICAgICAgICByZXR1cm4gbmV3IERhdGUocmFuZ2UuZW5kLnZhbHVlT2YoKSAtIDEpO1xuICAgIH1cbiAgICByZXR1cm4gZGF0ZTtcbn1cblxuZnVuY3Rpb24gcmVtb3ZlRXhhY3QoYXJyYXksIGV4YWN0VmFsKSB7XG4gICAgdmFyIHJlbW92ZUNudCA9IDA7XG4gICAgdmFyIGkgPSAwO1xuICAgIHdoaWxlIChpIDwgYXJyYXkubGVuZ3RoKSB7XG4gICAgICAgIGlmIChhcnJheVtpXSA9PT0gZXhhY3RWYWwpIHtcbiAgICAgICAgICAgIGFycmF5LnNwbGljZShpLCAxKTtcbiAgICAgICAgICAgIHJlbW92ZUNudCsrO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgaSsrO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZW1vdmVDbnQ7XG59XG5mdW5jdGlvbiBpc0FycmF5c0VxdWFsKGEwLCBhMSkge1xuICAgIHZhciBsZW4gPSBhMC5sZW5ndGg7XG4gICAgdmFyIGk7XG4gICAgaWYgKGxlbiAhPT0gYTEubGVuZ3RoKSB7IC8vIG5vdCBhcnJheT8gb3Igbm90IHNhbWUgbGVuZ3RoP1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgICBpZiAoYTBbaV0gIT09IGExW2ldKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG59XG5cbmZ1bmN0aW9uIG1lbW9pemUod29ya2VyRnVuYykge1xuICAgIHZhciBhcmdzO1xuICAgIHZhciByZXM7XG4gICAgcmV0dXJuIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCFhcmdzIHx8ICFpc0FycmF5c0VxdWFsKGFyZ3MsIGFyZ3VtZW50cykpIHtcbiAgICAgICAgICAgIGFyZ3MgPSBhcmd1bWVudHM7XG4gICAgICAgICAgICByZXMgPSB3b3JrZXJGdW5jLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9O1xufVxuLypcbmFsd2F5cyBleGVjdXRlcyB0aGUgd29ya2VyRnVuYywgYnV0IGlmIHRoZSByZXN1bHQgaXMgZXF1YWwgdG8gdGhlIHByZXZpb3VzIHJlc3VsdCxcbnJldHVybiB0aGUgcHJldmlvdXMgcmVzdWx0IGluc3RlYWQuXG4qL1xuZnVuY3Rpb24gbWVtb2l6ZU91dHB1dCh3b3JrZXJGdW5jLCBlcXVhbGl0eUZ1bmMpIHtcbiAgICB2YXIgY2FjaGVkUmVzID0gbnVsbDtcbiAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgbmV3UmVzID0gd29ya2VyRnVuYy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICBpZiAoY2FjaGVkUmVzID09PSBudWxsIHx8ICEoY2FjaGVkUmVzID09PSBuZXdSZXMgfHwgZXF1YWxpdHlGdW5jKGNhY2hlZFJlcywgbmV3UmVzKSkpIHtcbiAgICAgICAgICAgIGNhY2hlZFJlcyA9IG5ld1JlcztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY2FjaGVkUmVzO1xuICAgIH07XG59XG5cbnZhciBFWFRFTkRFRF9TRVRUSU5HU19BTkRfU0VWRVJJVElFUyA9IHtcbiAgICB3ZWVrOiAzLFxuICAgIHNlcGFyYXRvcjogMCxcbiAgICBvbWl0WmVyb01pbnV0ZTogMCxcbiAgICBtZXJpZGllbTogMCxcbiAgICBvbWl0Q29tbWFzOiAwXG59O1xudmFyIFNUQU5EQVJEX0RBVEVfUFJPUF9TRVZFUklUSUVTID0ge1xuICAgIHRpbWVab25lTmFtZTogNyxcbiAgICBlcmE6IDYsXG4gICAgeWVhcjogNSxcbiAgICBtb250aDogNCxcbiAgICBkYXk6IDIsXG4gICAgd2Vla2RheTogMixcbiAgICBob3VyOiAxLFxuICAgIG1pbnV0ZTogMSxcbiAgICBzZWNvbmQ6IDFcbn07XG52YXIgTUVSSURJRU1fUkUgPSAvXFxzKihbYXBdKVxcLj9tXFwuPy9pOyAvLyBlYXRzIHVwIGxlYWRpbmcgc3BhY2VzIHRvb1xudmFyIENPTU1BX1JFID0gLywvZzsgLy8gd2UgbmVlZCByZSBmb3IgZ2xvYmFsbmVzc1xudmFyIE1VTFRJX1NQQUNFX1JFID0gL1xccysvZztcbnZhciBMVFJfUkUgPSAvXFx1MjAwZS9nOyAvLyBjb250cm9sIGNoYXJhY3RlclxudmFyIFVUQ19SRSA9IC9VVEN8R01ULztcbnZhciBOYXRpdmVGb3JtYXR0ZXIgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gTmF0aXZlRm9ybWF0dGVyKGZvcm1hdFNldHRpbmdzKSB7XG4gICAgICAgIHZhciBzdGFuZGFyZERhdGVQcm9wcyA9IHt9O1xuICAgICAgICB2YXIgZXh0ZW5kZWRTZXR0aW5ncyA9IHt9O1xuICAgICAgICB2YXIgc2V2ZXJpdHkgPSAwO1xuICAgICAgICBmb3IgKHZhciBuYW1lXzEgaW4gZm9ybWF0U2V0dGluZ3MpIHtcbiAgICAgICAgICAgIGlmIChuYW1lXzEgaW4gRVhURU5ERURfU0VUVElOR1NfQU5EX1NFVkVSSVRJRVMpIHtcbiAgICAgICAgICAgICAgICBleHRlbmRlZFNldHRpbmdzW25hbWVfMV0gPSBmb3JtYXRTZXR0aW5nc1tuYW1lXzFdO1xuICAgICAgICAgICAgICAgIHNldmVyaXR5ID0gTWF0aC5tYXgoRVhURU5ERURfU0VUVElOR1NfQU5EX1NFVkVSSVRJRVNbbmFtZV8xXSwgc2V2ZXJpdHkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgc3RhbmRhcmREYXRlUHJvcHNbbmFtZV8xXSA9IGZvcm1hdFNldHRpbmdzW25hbWVfMV07XG4gICAgICAgICAgICAgICAgaWYgKG5hbWVfMSBpbiBTVEFOREFSRF9EQVRFX1BST1BfU0VWRVJJVElFUykge1xuICAgICAgICAgICAgICAgICAgICBzZXZlcml0eSA9IE1hdGgubWF4KFNUQU5EQVJEX0RBVEVfUFJPUF9TRVZFUklUSUVTW25hbWVfMV0sIHNldmVyaXR5KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zdGFuZGFyZERhdGVQcm9wcyA9IHN0YW5kYXJkRGF0ZVByb3BzO1xuICAgICAgICB0aGlzLmV4dGVuZGVkU2V0dGluZ3MgPSBleHRlbmRlZFNldHRpbmdzO1xuICAgICAgICB0aGlzLnNldmVyaXR5ID0gc2V2ZXJpdHk7XG4gICAgICAgIHRoaXMuYnVpbGRGb3JtYXR0aW5nRnVuYyA9IG1lbW9pemUoYnVpbGRGb3JtYXR0aW5nRnVuYyk7XG4gICAgfVxuICAgIE5hdGl2ZUZvcm1hdHRlci5wcm90b3R5cGUuZm9ybWF0ID0gZnVuY3Rpb24gKGRhdGUsIGNvbnRleHQpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYnVpbGRGb3JtYXR0aW5nRnVuYyh0aGlzLnN0YW5kYXJkRGF0ZVByb3BzLCB0aGlzLmV4dGVuZGVkU2V0dGluZ3MsIGNvbnRleHQpKGRhdGUpO1xuICAgIH07XG4gICAgTmF0aXZlRm9ybWF0dGVyLnByb3RvdHlwZS5mb3JtYXRSYW5nZSA9IGZ1bmN0aW9uIChzdGFydCwgZW5kLCBjb250ZXh0KSB7XG4gICAgICAgIHZhciBfYSA9IHRoaXMsIHN0YW5kYXJkRGF0ZVByb3BzID0gX2Euc3RhbmRhcmREYXRlUHJvcHMsIGV4dGVuZGVkU2V0dGluZ3MgPSBfYS5leHRlbmRlZFNldHRpbmdzO1xuICAgICAgICB2YXIgZGlmZlNldmVyaXR5ID0gY29tcHV0ZU1hcmtlckRpZmZTZXZlcml0eShzdGFydC5tYXJrZXIsIGVuZC5tYXJrZXIsIGNvbnRleHQuY2FsZW5kYXJTeXN0ZW0pO1xuICAgICAgICBpZiAoIWRpZmZTZXZlcml0eSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZm9ybWF0KHN0YXJ0LCBjb250ZXh0KTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgYmlnZ2VzdFVuaXRGb3JQYXJ0aWFsID0gZGlmZlNldmVyaXR5O1xuICAgICAgICBpZiAoYmlnZ2VzdFVuaXRGb3JQYXJ0aWFsID4gMSAmJiAvLyB0aGUgdHdvIGRhdGVzIGFyZSBkaWZmZXJlbnQgaW4gYSB3YXkgdGhhdCdzIGxhcmdlciBzY2FsZSB0aGFuIHRpbWVcbiAgICAgICAgICAgIChzdGFuZGFyZERhdGVQcm9wcy55ZWFyID09PSAnbnVtZXJpYycgfHwgc3RhbmRhcmREYXRlUHJvcHMueWVhciA9PT0gJzItZGlnaXQnKSAmJlxuICAgICAgICAgICAgKHN0YW5kYXJkRGF0ZVByb3BzLm1vbnRoID09PSAnbnVtZXJpYycgfHwgc3RhbmRhcmREYXRlUHJvcHMubW9udGggPT09ICcyLWRpZ2l0JykgJiZcbiAgICAgICAgICAgIChzdGFuZGFyZERhdGVQcm9wcy5kYXkgPT09ICdudW1lcmljJyB8fCBzdGFuZGFyZERhdGVQcm9wcy5kYXkgPT09ICcyLWRpZ2l0JykpIHtcbiAgICAgICAgICAgIGJpZ2dlc3RVbml0Rm9yUGFydGlhbCA9IDE7IC8vIG1ha2UgaXQgbG9vayBsaWtlIHRoZSBkYXRlcyBhcmUgb25seSBkaWZmZXJlbnQgaW4gdGVybXMgb2YgdGltZVxuICAgICAgICB9XG4gICAgICAgIHZhciBmdWxsMCA9IHRoaXMuZm9ybWF0KHN0YXJ0LCBjb250ZXh0KTtcbiAgICAgICAgdmFyIGZ1bGwxID0gdGhpcy5mb3JtYXQoZW5kLCBjb250ZXh0KTtcbiAgICAgICAgaWYgKGZ1bGwwID09PSBmdWxsMSkge1xuICAgICAgICAgICAgcmV0dXJuIGZ1bGwwO1xuICAgICAgICB9XG4gICAgICAgIHZhciBwYXJ0aWFsRGF0ZVByb3BzID0gY29tcHV0ZVBhcnRpYWxGb3JtYXR0aW5nT3B0aW9ucyhzdGFuZGFyZERhdGVQcm9wcywgYmlnZ2VzdFVuaXRGb3JQYXJ0aWFsKTtcbiAgICAgICAgdmFyIHBhcnRpYWxGb3JtYXR0aW5nRnVuYyA9IGJ1aWxkRm9ybWF0dGluZ0Z1bmMocGFydGlhbERhdGVQcm9wcywgZXh0ZW5kZWRTZXR0aW5ncywgY29udGV4dCk7XG4gICAgICAgIHZhciBwYXJ0aWFsMCA9IHBhcnRpYWxGb3JtYXR0aW5nRnVuYyhzdGFydCk7XG4gICAgICAgIHZhciBwYXJ0aWFsMSA9IHBhcnRpYWxGb3JtYXR0aW5nRnVuYyhlbmQpO1xuICAgICAgICB2YXIgaW5zZXJ0aW9uID0gZmluZENvbW1vbkluc2VydGlvbihmdWxsMCwgcGFydGlhbDAsIGZ1bGwxLCBwYXJ0aWFsMSk7XG4gICAgICAgIHZhciBzZXBhcmF0b3IgPSBleHRlbmRlZFNldHRpbmdzLnNlcGFyYXRvciB8fCAnJztcbiAgICAgICAgaWYgKGluc2VydGlvbikge1xuICAgICAgICAgICAgcmV0dXJuIGluc2VydGlvbi5iZWZvcmUgKyBwYXJ0aWFsMCArIHNlcGFyYXRvciArIHBhcnRpYWwxICsgaW5zZXJ0aW9uLmFmdGVyO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmdWxsMCArIHNlcGFyYXRvciArIGZ1bGwxO1xuICAgIH07XG4gICAgTmF0aXZlRm9ybWF0dGVyLnByb3RvdHlwZS5nZXRMYXJnZXN0VW5pdCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgc3dpdGNoICh0aGlzLnNldmVyaXR5KSB7XG4gICAgICAgICAgICBjYXNlIDc6XG4gICAgICAgICAgICBjYXNlIDY6XG4gICAgICAgICAgICBjYXNlIDU6XG4gICAgICAgICAgICAgICAgcmV0dXJuICd5ZWFyJztcbiAgICAgICAgICAgIGNhc2UgNDpcbiAgICAgICAgICAgICAgICByZXR1cm4gJ21vbnRoJztcbiAgICAgICAgICAgIGNhc2UgMzpcbiAgICAgICAgICAgICAgICByZXR1cm4gJ3dlZWsnO1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICByZXR1cm4gJ2RheSc7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIHJldHVybiBOYXRpdmVGb3JtYXR0ZXI7XG59KCkpO1xuZnVuY3Rpb24gYnVpbGRGb3JtYXR0aW5nRnVuYyhzdGFuZGFyZERhdGVQcm9wcywgZXh0ZW5kZWRTZXR0aW5ncywgY29udGV4dCkge1xuICAgIHZhciBzdGFuZGFyZERhdGVQcm9wQ250ID0gT2JqZWN0LmtleXMoc3RhbmRhcmREYXRlUHJvcHMpLmxlbmd0aDtcbiAgICBpZiAoc3RhbmRhcmREYXRlUHJvcENudCA9PT0gMSAmJiBzdGFuZGFyZERhdGVQcm9wcy50aW1lWm9uZU5hbWUgPT09ICdzaG9ydCcpIHtcbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChkYXRlKSB7XG4gICAgICAgICAgICByZXR1cm4gZm9ybWF0VGltZVpvbmVPZmZzZXQoZGF0ZS50aW1lWm9uZU9mZnNldCk7XG4gICAgICAgIH07XG4gICAgfVxuICAgIGlmIChzdGFuZGFyZERhdGVQcm9wQ250ID09PSAwICYmIGV4dGVuZGVkU2V0dGluZ3Mud2Vlaykge1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gKGRhdGUpIHtcbiAgICAgICAgICAgIHJldHVybiBmb3JtYXRXZWVrTnVtYmVyKGNvbnRleHQuY29tcHV0ZVdlZWtOdW1iZXIoZGF0ZS5tYXJrZXIpLCBjb250ZXh0LndlZWtMYWJlbCwgY29udGV4dC5sb2NhbGUsIGV4dGVuZGVkU2V0dGluZ3Mud2Vlayk7XG4gICAgICAgIH07XG4gICAgfVxuICAgIHJldHVybiBidWlsZE5hdGl2ZUZvcm1hdHRpbmdGdW5jKHN0YW5kYXJkRGF0ZVByb3BzLCBleHRlbmRlZFNldHRpbmdzLCBjb250ZXh0KTtcbn1cbmZ1bmN0aW9uIGJ1aWxkTmF0aXZlRm9ybWF0dGluZ0Z1bmMoc3RhbmRhcmREYXRlUHJvcHMsIGV4dGVuZGVkU2V0dGluZ3MsIGNvbnRleHQpIHtcbiAgICBzdGFuZGFyZERhdGVQcm9wcyA9IF9fYXNzaWduKHt9LCBzdGFuZGFyZERhdGVQcm9wcyk7IC8vIGNvcHlcbiAgICBleHRlbmRlZFNldHRpbmdzID0gX19hc3NpZ24oe30sIGV4dGVuZGVkU2V0dGluZ3MpOyAvLyBjb3B5XG4gICAgc2FuaXRpemVTZXR0aW5ncyhzdGFuZGFyZERhdGVQcm9wcywgZXh0ZW5kZWRTZXR0aW5ncyk7XG4gICAgc3RhbmRhcmREYXRlUHJvcHMudGltZVpvbmUgPSAnVVRDJzsgLy8gd2UgbGV2ZXJhZ2UgdGhlIG9ubHkgZ3VhcmFudGVlZCB0aW1lWm9uZSBmb3Igb3VyIFVUQyBtYXJrZXJzXG4gICAgdmFyIG5vcm1hbEZvcm1hdCA9IG5ldyBJbnRsLkRhdGVUaW1lRm9ybWF0KGNvbnRleHQubG9jYWxlLmNvZGVzLCBzdGFuZGFyZERhdGVQcm9wcyk7XG4gICAgdmFyIHplcm9Gb3JtYXQ7IC8vIG5lZWRlZD9cbiAgICBpZiAoZXh0ZW5kZWRTZXR0aW5ncy5vbWl0WmVyb01pbnV0ZSkge1xuICAgICAgICB2YXIgemVyb1Byb3BzID0gX19hc3NpZ24oe30sIHN0YW5kYXJkRGF0ZVByb3BzKTtcbiAgICAgICAgZGVsZXRlIHplcm9Qcm9wcy5taW51dGU7IC8vIHNlY29uZHMgYW5kIG1zIHdlcmUgYWxyZWFkeSBjb25zaWRlcmVkIGluIHNhbml0aXplU2V0dGluZ3NcbiAgICAgICAgemVyb0Zvcm1hdCA9IG5ldyBJbnRsLkRhdGVUaW1lRm9ybWF0KGNvbnRleHQubG9jYWxlLmNvZGVzLCB6ZXJvUHJvcHMpO1xuICAgIH1cbiAgICByZXR1cm4gZnVuY3Rpb24gKGRhdGUpIHtcbiAgICAgICAgdmFyIG1hcmtlciA9IGRhdGUubWFya2VyO1xuICAgICAgICB2YXIgZm9ybWF0O1xuICAgICAgICBpZiAoemVyb0Zvcm1hdCAmJiAhbWFya2VyLmdldFVUQ01pbnV0ZXMoKSkge1xuICAgICAgICAgICAgZm9ybWF0ID0gemVyb0Zvcm1hdDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGZvcm1hdCA9IG5vcm1hbEZvcm1hdDtcbiAgICAgICAgfVxuICAgICAgICB2YXIgcyA9IGZvcm1hdC5mb3JtYXQobWFya2VyKTtcbiAgICAgICAgcmV0dXJuIHBvc3RQcm9jZXNzKHMsIGRhdGUsIHN0YW5kYXJkRGF0ZVByb3BzLCBleHRlbmRlZFNldHRpbmdzLCBjb250ZXh0KTtcbiAgICB9O1xufVxuZnVuY3Rpb24gc2FuaXRpemVTZXR0aW5ncyhzdGFuZGFyZERhdGVQcm9wcywgZXh0ZW5kZWRTZXR0aW5ncykge1xuICAgIC8vIGRlYWwgd2l0aCBhIGJyb3dzZXIgaW5jb25zaXN0ZW5jeSB3aGVyZSBmb3JtYXR0aW5nIHRoZSB0aW1lem9uZVxuICAgIC8vIHJlcXVpcmVzIHRoYXQgdGhlIGhvdXIvbWludXRlIGJlIHByZXNlbnQuXG4gICAgaWYgKHN0YW5kYXJkRGF0ZVByb3BzLnRpbWVab25lTmFtZSkge1xuICAgICAgICBpZiAoIXN0YW5kYXJkRGF0ZVByb3BzLmhvdXIpIHtcbiAgICAgICAgICAgIHN0YW5kYXJkRGF0ZVByb3BzLmhvdXIgPSAnMi1kaWdpdCc7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzdGFuZGFyZERhdGVQcm9wcy5taW51dGUpIHtcbiAgICAgICAgICAgIHN0YW5kYXJkRGF0ZVByb3BzLm1pbnV0ZSA9ICcyLWRpZ2l0JztcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBvbmx5IHN1cHBvcnQgc2hvcnQgdGltZXpvbmUgbmFtZXNcbiAgICBpZiAoc3RhbmRhcmREYXRlUHJvcHMudGltZVpvbmVOYW1lID09PSAnbG9uZycpIHtcbiAgICAgICAgc3RhbmRhcmREYXRlUHJvcHMudGltZVpvbmVOYW1lID0gJ3Nob3J0JztcbiAgICB9XG4gICAgLy8gaWYgcmVxdWVzdGluZyB0byBkaXNwbGF5IHNlY29uZHMsIE1VU1QgZGlzcGxheSBtaW51dGVzXG4gICAgaWYgKGV4dGVuZGVkU2V0dGluZ3Mub21pdFplcm9NaW51dGUgJiYgKHN0YW5kYXJkRGF0ZVByb3BzLnNlY29uZCB8fCBzdGFuZGFyZERhdGVQcm9wcy5taWxsaXNlY29uZCkpIHtcbiAgICAgICAgZGVsZXRlIGV4dGVuZGVkU2V0dGluZ3Mub21pdFplcm9NaW51dGU7XG4gICAgfVxufVxuZnVuY3Rpb24gcG9zdFByb2Nlc3MocywgZGF0ZSwgc3RhbmRhcmREYXRlUHJvcHMsIGV4dGVuZGVkU2V0dGluZ3MsIGNvbnRleHQpIHtcbiAgICBzID0gcy5yZXBsYWNlKExUUl9SRSwgJycpOyAvLyByZW1vdmUgbGVmdC10by1yaWdodCBjb250cm9sIGNoYXJzLiBkbyBmaXJzdC4gZ29vZCBmb3Igb3RoZXIgcmVnZXhlc1xuICAgIGlmIChzdGFuZGFyZERhdGVQcm9wcy50aW1lWm9uZU5hbWUgPT09ICdzaG9ydCcpIHtcbiAgICAgICAgcyA9IGluamVjdFR6b1N0cihzLCAoY29udGV4dC50aW1lWm9uZSA9PT0gJ1VUQycgfHwgZGF0ZS50aW1lWm9uZU9mZnNldCA9PSBudWxsKSA/XG4gICAgICAgICAgICAnVVRDJyA6IC8vIGltcG9ydGFudCB0byBub3JtYWxpemUgZm9yIElFLCB3aGljaCBkb2VzIFwiR01UXCJcbiAgICAgICAgICAgIGZvcm1hdFRpbWVab25lT2Zmc2V0KGRhdGUudGltZVpvbmVPZmZzZXQpKTtcbiAgICB9XG4gICAgaWYgKGV4dGVuZGVkU2V0dGluZ3Mub21pdENvbW1hcykge1xuICAgICAgICBzID0gcy5yZXBsYWNlKENPTU1BX1JFLCAnJykudHJpbSgpO1xuICAgIH1cbiAgICBpZiAoZXh0ZW5kZWRTZXR0aW5ncy5vbWl0WmVyb01pbnV0ZSkge1xuICAgICAgICBzID0gcy5yZXBsYWNlKCc6MDAnLCAnJyk7IC8vIHplcm9Gb3JtYXQgZG9lc24ndCBhbHdheXMgYWNoaWV2ZSB0aGlzXG4gICAgfVxuICAgIC8vIF4gZG8gYW55dGhpbmcgdGhhdCBtaWdodCBjcmVhdGUgYWRqYWNlbnQgc3BhY2VzIGJlZm9yZSB0aGlzIHBvaW50LFxuICAgIC8vIGJlY2F1c2UgTUVSSURJRU1fUkUgbGlrZXMgdG8gZWF0IHVwIGxvYWRpbmcgc3BhY2VzXG4gICAgaWYgKGV4dGVuZGVkU2V0dGluZ3MubWVyaWRpZW0gPT09IGZhbHNlKSB7XG4gICAgICAgIHMgPSBzLnJlcGxhY2UoTUVSSURJRU1fUkUsICcnKS50cmltKCk7XG4gICAgfVxuICAgIGVsc2UgaWYgKGV4dGVuZGVkU2V0dGluZ3MubWVyaWRpZW0gPT09ICduYXJyb3cnKSB7IC8vIGEvcFxuICAgICAgICBzID0gcy5yZXBsYWNlKE1FUklESUVNX1JFLCBmdW5jdGlvbiAobTAsIG0xKSB7XG4gICAgICAgICAgICByZXR1cm4gbTEudG9Mb2NhbGVMb3dlckNhc2UoKTtcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGVsc2UgaWYgKGV4dGVuZGVkU2V0dGluZ3MubWVyaWRpZW0gPT09ICdzaG9ydCcpIHsgLy8gYW0vcG1cbiAgICAgICAgcyA9IHMucmVwbGFjZShNRVJJRElFTV9SRSwgZnVuY3Rpb24gKG0wLCBtMSkge1xuICAgICAgICAgICAgcmV0dXJuIG0xLnRvTG9jYWxlTG93ZXJDYXNlKCkgKyAnbSc7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBlbHNlIGlmIChleHRlbmRlZFNldHRpbmdzLm1lcmlkaWVtID09PSAnbG93ZXJjYXNlJykgeyAvLyBvdGhlciBtZXJpZGllbSB0cmFuc2Zvcm1lcnMgYWxyZWFkeSBjb252ZXJ0ZWQgdG8gbG93ZXJjYXNlXG4gICAgICAgIHMgPSBzLnJlcGxhY2UoTUVSSURJRU1fUkUsIGZ1bmN0aW9uIChtMCkge1xuICAgICAgICAgICAgcmV0dXJuIG0wLnRvTG9jYWxlTG93ZXJDYXNlKCk7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBzID0gcy5yZXBsYWNlKE1VTFRJX1NQQUNFX1JFLCAnICcpO1xuICAgIHMgPSBzLnRyaW0oKTtcbiAgICByZXR1cm4gcztcbn1cbmZ1bmN0aW9uIGluamVjdFR6b1N0cihzLCB0em9TdHIpIHtcbiAgICB2YXIgcmVwbGFjZWQgPSBmYWxzZTtcbiAgICBzID0gcy5yZXBsYWNlKFVUQ19SRSwgZnVuY3Rpb24gKCkge1xuICAgICAgICByZXBsYWNlZCA9IHRydWU7XG4gICAgICAgIHJldHVybiB0em9TdHI7XG4gICAgfSk7XG4gICAgLy8gSUUxMSBkb2Vzbid0IGluY2x1ZGUgVVRDL0dNVCBpbiB0aGUgb3JpZ2luYWwgc3RyaW5nLCBzbyBhcHBlbmQgdG8gZW5kXG4gICAgaWYgKCFyZXBsYWNlZCkge1xuICAgICAgICBzICs9ICcgJyArIHR6b1N0cjtcbiAgICB9XG4gICAgcmV0dXJuIHM7XG59XG5mdW5jdGlvbiBmb3JtYXRXZWVrTnVtYmVyKG51bSwgd2Vla0xhYmVsLCBsb2NhbGUsIGRpc3BsYXkpIHtcbiAgICB2YXIgcGFydHMgPSBbXTtcbiAgICBpZiAoZGlzcGxheSA9PT0gJ25hcnJvdycpIHtcbiAgICAgICAgcGFydHMucHVzaCh3ZWVrTGFiZWwpO1xuICAgIH1cbiAgICBlbHNlIGlmIChkaXNwbGF5ID09PSAnc2hvcnQnKSB7XG4gICAgICAgIHBhcnRzLnB1c2god2Vla0xhYmVsLCAnICcpO1xuICAgIH1cbiAgICAvLyBvdGhlcndpc2UsIGNvbnNpZGVyZWQgJ251bWVyaWMnXG4gICAgcGFydHMucHVzaChsb2NhbGUuc2ltcGxlTnVtYmVyRm9ybWF0LmZvcm1hdChudW0pKTtcbiAgICBpZiAobG9jYWxlLm9wdGlvbnMuaXNSdGwpIHsgLy8gVE9ETzogdXNlIGNvbnRyb2wgY2hhcmFjdGVycyBpbnN0ZWFkP1xuICAgICAgICBwYXJ0cy5yZXZlcnNlKCk7XG4gICAgfVxuICAgIHJldHVybiBwYXJ0cy5qb2luKCcnKTtcbn1cbi8vIFJhbmdlIEZvcm1hdHRpbmcgVXRpbHNcbi8vIDAgPSBleGFjdGx5IHRoZSBzYW1lXG4vLyAxID0gZGlmZmVyZW50IGJ5IHRpbWVcbi8vIGFuZCBiaWdnZXJcbmZ1bmN0aW9uIGNvbXB1dGVNYXJrZXJEaWZmU2V2ZXJpdHkoZDAsIGQxLCBjYSkge1xuICAgIGlmIChjYS5nZXRNYXJrZXJZZWFyKGQwKSAhPT0gY2EuZ2V0TWFya2VyWWVhcihkMSkpIHtcbiAgICAgICAgcmV0dXJuIDU7XG4gICAgfVxuICAgIGlmIChjYS5nZXRNYXJrZXJNb250aChkMCkgIT09IGNhLmdldE1hcmtlck1vbnRoKGQxKSkge1xuICAgICAgICByZXR1cm4gNDtcbiAgICB9XG4gICAgaWYgKGNhLmdldE1hcmtlckRheShkMCkgIT09IGNhLmdldE1hcmtlckRheShkMSkpIHtcbiAgICAgICAgcmV0dXJuIDI7XG4gICAgfVxuICAgIGlmICh0aW1lQXNNcyhkMCkgIT09IHRpbWVBc01zKGQxKSkge1xuICAgICAgICByZXR1cm4gMTtcbiAgICB9XG4gICAgcmV0dXJuIDA7XG59XG5mdW5jdGlvbiBjb21wdXRlUGFydGlhbEZvcm1hdHRpbmdPcHRpb25zKG9wdGlvbnMsIGJpZ2dlc3RVbml0KSB7XG4gICAgdmFyIHBhcnRpYWxPcHRpb25zID0ge307XG4gICAgZm9yICh2YXIgbmFtZV8yIGluIG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKCEobmFtZV8yIGluIFNUQU5EQVJEX0RBVEVfUFJPUF9TRVZFUklUSUVTKSB8fCAvLyBub3QgYSBkYXRlIHBhcnQgcHJvcCAobGlrZSB0aW1lWm9uZSlcbiAgICAgICAgICAgIFNUQU5EQVJEX0RBVEVfUFJPUF9TRVZFUklUSUVTW25hbWVfMl0gPD0gYmlnZ2VzdFVuaXQpIHtcbiAgICAgICAgICAgIHBhcnRpYWxPcHRpb25zW25hbWVfMl0gPSBvcHRpb25zW25hbWVfMl07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHBhcnRpYWxPcHRpb25zO1xufVxuZnVuY3Rpb24gZmluZENvbW1vbkluc2VydGlvbihmdWxsMCwgcGFydGlhbDAsIGZ1bGwxLCBwYXJ0aWFsMSkge1xuICAgIHZhciBpMCA9IDA7XG4gICAgd2hpbGUgKGkwIDwgZnVsbDAubGVuZ3RoKSB7XG4gICAgICAgIHZhciBmb3VuZDAgPSBmdWxsMC5pbmRleE9mKHBhcnRpYWwwLCBpMCk7XG4gICAgICAgIGlmIChmb3VuZDAgPT09IC0xKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICB2YXIgYmVmb3JlMCA9IGZ1bGwwLnN1YnN0cigwLCBmb3VuZDApO1xuICAgICAgICBpMCA9IGZvdW5kMCArIHBhcnRpYWwwLmxlbmd0aDtcbiAgICAgICAgdmFyIGFmdGVyMCA9IGZ1bGwwLnN1YnN0cihpMCk7XG4gICAgICAgIHZhciBpMSA9IDA7XG4gICAgICAgIHdoaWxlIChpMSA8IGZ1bGwxLmxlbmd0aCkge1xuICAgICAgICAgICAgdmFyIGZvdW5kMSA9IGZ1bGwxLmluZGV4T2YocGFydGlhbDEsIGkxKTtcbiAgICAgICAgICAgIGlmIChmb3VuZDEgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgYmVmb3JlMSA9IGZ1bGwxLnN1YnN0cigwLCBmb3VuZDEpO1xuICAgICAgICAgICAgaTEgPSBmb3VuZDEgKyBwYXJ0aWFsMS5sZW5ndGg7XG4gICAgICAgICAgICB2YXIgYWZ0ZXIxID0gZnVsbDEuc3Vic3RyKGkxKTtcbiAgICAgICAgICAgIGlmIChiZWZvcmUwID09PSBiZWZvcmUxICYmIGFmdGVyMCA9PT0gYWZ0ZXIxKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgYmVmb3JlOiBiZWZvcmUwLFxuICAgICAgICAgICAgICAgICAgICBhZnRlcjogYWZ0ZXIwXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cblxuLypcblRPRE86IGZpeCB0aGUgdGVybWlub2xvZ3kgb2YgXCJmb3JtYXR0ZXJcIiB2cyBcImZvcm1hdHRpbmcgZnVuY1wiXG4qL1xuLypcbkF0IHRoZSB0aW1lIG9mIGluc3RhbnRpYXRpb24sIHRoaXMgb2JqZWN0IGRvZXMgbm90IGtub3cgd2hpY2ggY21kLWZvcm1hdHRpbmcgc3lzdGVtIGl0IHdpbGwgdXNlLlxuSXQgcmVjZWl2ZXMgdGhpcyBhdCB0aGUgdGltZSBvZiBmb3JtYXR0aW5nLCBhcyBhIHNldHRpbmcuXG4qL1xudmFyIENtZEZvcm1hdHRlciA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBDbWRGb3JtYXR0ZXIoY21kU3RyLCBzZXBhcmF0b3IpIHtcbiAgICAgICAgdGhpcy5jbWRTdHIgPSBjbWRTdHI7XG4gICAgICAgIHRoaXMuc2VwYXJhdG9yID0gc2VwYXJhdG9yO1xuICAgIH1cbiAgICBDbWRGb3JtYXR0ZXIucHJvdG90eXBlLmZvcm1hdCA9IGZ1bmN0aW9uIChkYXRlLCBjb250ZXh0KSB7XG4gICAgICAgIHJldHVybiBjb250ZXh0LmNtZEZvcm1hdHRlcih0aGlzLmNtZFN0ciwgY3JlYXRlVmVyYm9zZUZvcm1hdHRpbmdBcmcoZGF0ZSwgbnVsbCwgY29udGV4dCwgdGhpcy5zZXBhcmF0b3IpKTtcbiAgICB9O1xuICAgIENtZEZvcm1hdHRlci5wcm90b3R5cGUuZm9ybWF0UmFuZ2UgPSBmdW5jdGlvbiAoc3RhcnQsIGVuZCwgY29udGV4dCkge1xuICAgICAgICByZXR1cm4gY29udGV4dC5jbWRGb3JtYXR0ZXIodGhpcy5jbWRTdHIsIGNyZWF0ZVZlcmJvc2VGb3JtYXR0aW5nQXJnKHN0YXJ0LCBlbmQsIGNvbnRleHQsIHRoaXMuc2VwYXJhdG9yKSk7XG4gICAgfTtcbiAgICByZXR1cm4gQ21kRm9ybWF0dGVyO1xufSgpKTtcblxudmFyIEZ1bmNGb3JtYXR0ZXIgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gRnVuY0Zvcm1hdHRlcihmdW5jKSB7XG4gICAgICAgIHRoaXMuZnVuYyA9IGZ1bmM7XG4gICAgfVxuICAgIEZ1bmNGb3JtYXR0ZXIucHJvdG90eXBlLmZvcm1hdCA9IGZ1bmN0aW9uIChkYXRlLCBjb250ZXh0KSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZ1bmMoY3JlYXRlVmVyYm9zZUZvcm1hdHRpbmdBcmcoZGF0ZSwgbnVsbCwgY29udGV4dCkpO1xuICAgIH07XG4gICAgRnVuY0Zvcm1hdHRlci5wcm90b3R5cGUuZm9ybWF0UmFuZ2UgPSBmdW5jdGlvbiAoc3RhcnQsIGVuZCwgY29udGV4dCkge1xuICAgICAgICByZXR1cm4gdGhpcy5mdW5jKGNyZWF0ZVZlcmJvc2VGb3JtYXR0aW5nQXJnKHN0YXJ0LCBlbmQsIGNvbnRleHQpKTtcbiAgICB9O1xuICAgIHJldHVybiBGdW5jRm9ybWF0dGVyO1xufSgpKTtcblxuLy8gRm9ybWF0dGVyIE9iamVjdCBDcmVhdGlvblxuZnVuY3Rpb24gY3JlYXRlRm9ybWF0dGVyKGlucHV0LCBkZWZhdWx0U2VwYXJhdG9yKSB7XG4gICAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ29iamVjdCcgJiYgaW5wdXQpIHsgLy8gbm9uLW51bGwgb2JqZWN0XG4gICAgICAgIGlmICh0eXBlb2YgZGVmYXVsdFNlcGFyYXRvciA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIGlucHV0ID0gX19hc3NpZ24oeyBzZXBhcmF0b3I6IGRlZmF1bHRTZXBhcmF0b3IgfSwgaW5wdXQpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgTmF0aXZlRm9ybWF0dGVyKGlucHV0KTtcbiAgICB9XG4gICAgZWxzZSBpZiAodHlwZW9mIGlucHV0ID09PSAnc3RyaW5nJykge1xuICAgICAgICByZXR1cm4gbmV3IENtZEZvcm1hdHRlcihpbnB1dCwgZGVmYXVsdFNlcGFyYXRvcik7XG4gICAgfVxuICAgIGVsc2UgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICByZXR1cm4gbmV3IEZ1bmNGb3JtYXR0ZXIoaW5wdXQpO1xuICAgIH1cbn1cbi8vIFN0cmluZyBVdGlsc1xuLy8gdGltZVpvbmVPZmZzZXQgaXMgaW4gbWludXRlc1xuZnVuY3Rpb24gYnVpbGRJc29TdHJpbmcobWFya2VyLCB0aW1lWm9uZU9mZnNldCwgc3RyaXBaZXJvVGltZSkge1xuICAgIGlmIChzdHJpcFplcm9UaW1lID09PSB2b2lkIDApIHsgc3RyaXBaZXJvVGltZSA9IGZhbHNlOyB9XG4gICAgdmFyIHMgPSBtYXJrZXIudG9JU09TdHJpbmcoKTtcbiAgICBzID0gcy5yZXBsYWNlKCcuMDAwJywgJycpO1xuICAgIGlmIChzdHJpcFplcm9UaW1lKSB7XG4gICAgICAgIHMgPSBzLnJlcGxhY2UoJ1QwMDowMDowMFonLCAnJyk7XG4gICAgfVxuICAgIGlmIChzLmxlbmd0aCA+IDEwKSB7IC8vIHRpbWUgcGFydCB3YXNuJ3Qgc3RyaXBwZWQsIGNhbiBhZGQgdGltZXpvbmUgaW5mb1xuICAgICAgICBpZiAodGltZVpvbmVPZmZzZXQgPT0gbnVsbCkge1xuICAgICAgICAgICAgcyA9IHMucmVwbGFjZSgnWicsICcnKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0aW1lWm9uZU9mZnNldCAhPT0gMCkge1xuICAgICAgICAgICAgcyA9IHMucmVwbGFjZSgnWicsIGZvcm1hdFRpbWVab25lT2Zmc2V0KHRpbWVab25lT2Zmc2V0LCB0cnVlKSk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gb3RoZXJ3aXNlLCBpdHMgVVRDLTAgYW5kIHdlIHdhbnQgdG8ga2VlcCB0aGUgWlxuICAgIH1cbiAgICByZXR1cm4gcztcbn1cbmZ1bmN0aW9uIGZvcm1hdElzb1RpbWVTdHJpbmcobWFya2VyKSB7XG4gICAgcmV0dXJuIHBhZFN0YXJ0KG1hcmtlci5nZXRVVENIb3VycygpLCAyKSArICc6JyArXG4gICAgICAgIHBhZFN0YXJ0KG1hcmtlci5nZXRVVENNaW51dGVzKCksIDIpICsgJzonICtcbiAgICAgICAgcGFkU3RhcnQobWFya2VyLmdldFVUQ1NlY29uZHMoKSwgMik7XG59XG5mdW5jdGlvbiBmb3JtYXRUaW1lWm9uZU9mZnNldChtaW51dGVzLCBkb0lzbykge1xuICAgIGlmIChkb0lzbyA9PT0gdm9pZCAwKSB7IGRvSXNvID0gZmFsc2U7IH1cbiAgICB2YXIgc2lnbiA9IG1pbnV0ZXMgPCAwID8gJy0nIDogJysnO1xuICAgIHZhciBhYnMgPSBNYXRoLmFicyhtaW51dGVzKTtcbiAgICB2YXIgaG91cnMgPSBNYXRoLmZsb29yKGFicyAvIDYwKTtcbiAgICB2YXIgbWlucyA9IE1hdGgucm91bmQoYWJzICUgNjApO1xuICAgIGlmIChkb0lzbykge1xuICAgICAgICByZXR1cm4gc2lnbiArIHBhZFN0YXJ0KGhvdXJzLCAyKSArICc6JyArIHBhZFN0YXJ0KG1pbnMsIDIpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmV0dXJuICdHTVQnICsgc2lnbiArIGhvdXJzICsgKG1pbnMgPyAnOicgKyBwYWRTdGFydChtaW5zLCAyKSA6ICcnKTtcbiAgICB9XG59XG4vLyBBcmcgVXRpbHNcbmZ1bmN0aW9uIGNyZWF0ZVZlcmJvc2VGb3JtYXR0aW5nQXJnKHN0YXJ0LCBlbmQsIGNvbnRleHQsIHNlcGFyYXRvcikge1xuICAgIHZhciBzdGFydEluZm8gPSBleHBhbmRab25lZE1hcmtlcihzdGFydCwgY29udGV4dC5jYWxlbmRhclN5c3RlbSk7XG4gICAgdmFyIGVuZEluZm8gPSBlbmQgPyBleHBhbmRab25lZE1hcmtlcihlbmQsIGNvbnRleHQuY2FsZW5kYXJTeXN0ZW0pIDogbnVsbDtcbiAgICByZXR1cm4ge1xuICAgICAgICBkYXRlOiBzdGFydEluZm8sXG4gICAgICAgIHN0YXJ0OiBzdGFydEluZm8sXG4gICAgICAgIGVuZDogZW5kSW5mbyxcbiAgICAgICAgdGltZVpvbmU6IGNvbnRleHQudGltZVpvbmUsXG4gICAgICAgIGxvY2FsZUNvZGVzOiBjb250ZXh0LmxvY2FsZS5jb2RlcyxcbiAgICAgICAgc2VwYXJhdG9yOiBzZXBhcmF0b3JcbiAgICB9O1xufVxuZnVuY3Rpb24gZXhwYW5kWm9uZWRNYXJrZXIoZGF0ZUluZm8sIGNhbGVuZGFyU3lzdGVtKSB7XG4gICAgdmFyIGEgPSBjYWxlbmRhclN5c3RlbS5tYXJrZXJUb0FycmF5KGRhdGVJbmZvLm1hcmtlcik7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgbWFya2VyOiBkYXRlSW5mby5tYXJrZXIsXG4gICAgICAgIHRpbWVab25lT2Zmc2V0OiBkYXRlSW5mby50aW1lWm9uZU9mZnNldCxcbiAgICAgICAgYXJyYXk6IGEsXG4gICAgICAgIHllYXI6IGFbMF0sXG4gICAgICAgIG1vbnRoOiBhWzFdLFxuICAgICAgICBkYXk6IGFbMl0sXG4gICAgICAgIGhvdXI6IGFbM10sXG4gICAgICAgIG1pbnV0ZTogYVs0XSxcbiAgICAgICAgc2Vjb25kOiBhWzVdLFxuICAgICAgICBtaWxsaXNlY29uZDogYVs2XVxuICAgIH07XG59XG5cbnZhciBFdmVudFNvdXJjZUFwaSA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBFdmVudFNvdXJjZUFwaShjYWxlbmRhciwgaW50ZXJuYWxFdmVudFNvdXJjZSkge1xuICAgICAgICB0aGlzLmNhbGVuZGFyID0gY2FsZW5kYXI7XG4gICAgICAgIHRoaXMuaW50ZXJuYWxFdmVudFNvdXJjZSA9IGludGVybmFsRXZlbnRTb3VyY2U7XG4gICAgfVxuICAgIEV2ZW50U291cmNlQXBpLnByb3RvdHlwZS5yZW1vdmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuY2FsZW5kYXIuZGlzcGF0Y2goe1xuICAgICAgICAgICAgdHlwZTogJ1JFTU9WRV9FVkVOVF9TT1VSQ0UnLFxuICAgICAgICAgICAgc291cmNlSWQ6IHRoaXMuaW50ZXJuYWxFdmVudFNvdXJjZS5zb3VyY2VJZFxuICAgICAgICB9KTtcbiAgICB9O1xuICAgIEV2ZW50U291cmNlQXBpLnByb3RvdHlwZS5yZWZldGNoID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLmNhbGVuZGFyLmRpc3BhdGNoKHtcbiAgICAgICAgICAgIHR5cGU6ICdGRVRDSF9FVkVOVF9TT1VSQ0VTJyxcbiAgICAgICAgICAgIHNvdXJjZUlkczogW3RoaXMuaW50ZXJuYWxFdmVudFNvdXJjZS5zb3VyY2VJZF1cbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRXZlbnRTb3VyY2VBcGkucHJvdG90eXBlLCBcImlkXCIsIHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5pbnRlcm5hbEV2ZW50U291cmNlLnB1YmxpY0lkO1xuICAgICAgICB9LFxuICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICB9KTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRXZlbnRTb3VyY2VBcGkucHJvdG90eXBlLCBcInVybFwiLCB7XG4gICAgICAgIC8vIG9ubHkgcmVsZXZhbnQgdG8ganNvbi1mZWVkIGV2ZW50IHNvdXJjZXNcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5pbnRlcm5hbEV2ZW50U291cmNlLm1ldGEudXJsO1xuICAgICAgICB9LFxuICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICB9KTtcbiAgICByZXR1cm4gRXZlbnRTb3VyY2VBcGk7XG59KCkpO1xuXG52YXIgRXZlbnRBcGkgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gRXZlbnRBcGkoY2FsZW5kYXIsIGRlZiwgaW5zdGFuY2UpIHtcbiAgICAgICAgdGhpcy5fY2FsZW5kYXIgPSBjYWxlbmRhcjtcbiAgICAgICAgdGhpcy5fZGVmID0gZGVmO1xuICAgICAgICB0aGlzLl9pbnN0YW5jZSA9IGluc3RhbmNlIHx8IG51bGw7XG4gICAgfVxuICAgIC8qXG4gICAgVE9ETzogbWFrZSBldmVudCBzdHJ1Y3QgbW9yZSByZXNwb25zaWJsZSBmb3IgdGhpc1xuICAgICovXG4gICAgRXZlbnRBcGkucHJvdG90eXBlLnNldFByb3AgPSBmdW5jdGlvbiAobmFtZSwgdmFsKSB7XG4gICAgICAgIHZhciBfYSwgX2I7XG4gICAgICAgIGlmIChuYW1lIGluIERBVEVfUFJPUFMpIDtcbiAgICAgICAgZWxzZSBpZiAobmFtZSBpbiBOT05fREFURV9QUk9QUykge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBOT05fREFURV9QUk9QU1tuYW1lXSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgIHZhbCA9IE5PTl9EQVRFX1BST1BTW25hbWVdKHZhbCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLm11dGF0ZSh7XG4gICAgICAgICAgICAgICAgc3RhbmRhcmRQcm9wczogKF9hID0ge30sIF9hW25hbWVdID0gdmFsLCBfYSlcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKG5hbWUgaW4gVU5TQ09QRURfRVZFTlRfVUlfUFJPUFMpIHtcbiAgICAgICAgICAgIHZhciB1aSA9IHZvaWQgMDtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgVU5TQ09QRURfRVZFTlRfVUlfUFJPUFNbbmFtZV0gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICB2YWwgPSBVTlNDT1BFRF9FVkVOVF9VSV9QUk9QU1tuYW1lXSh2YWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG5hbWUgPT09ICdjb2xvcicpIHtcbiAgICAgICAgICAgICAgICB1aSA9IHsgYmFja2dyb3VuZENvbG9yOiB2YWwsIGJvcmRlckNvbG9yOiB2YWwgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKG5hbWUgPT09ICdlZGl0YWJsZScpIHtcbiAgICAgICAgICAgICAgICB1aSA9IHsgc3RhcnRFZGl0YWJsZTogdmFsLCBkdXJhdGlvbkVkaXRhYmxlOiB2YWwgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHVpID0gKF9iID0ge30sIF9iW25hbWVdID0gdmFsLCBfYik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLm11dGF0ZSh7XG4gICAgICAgICAgICAgICAgc3RhbmRhcmRQcm9wczogeyB1aTogdWkgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIEV2ZW50QXBpLnByb3RvdHlwZS5zZXRFeHRlbmRlZFByb3AgPSBmdW5jdGlvbiAobmFtZSwgdmFsKSB7XG4gICAgICAgIHZhciBfYTtcbiAgICAgICAgdGhpcy5tdXRhdGUoe1xuICAgICAgICAgICAgZXh0ZW5kZWRQcm9wczogKF9hID0ge30sIF9hW25hbWVdID0gdmFsLCBfYSlcbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICBFdmVudEFwaS5wcm90b3R5cGUuc2V0U3RhcnQgPSBmdW5jdGlvbiAoc3RhcnRJbnB1dCwgb3B0aW9ucykge1xuICAgICAgICBpZiAob3B0aW9ucyA9PT0gdm9pZCAwKSB7IG9wdGlvbnMgPSB7fTsgfVxuICAgICAgICB2YXIgZGF0ZUVudiA9IHRoaXMuX2NhbGVuZGFyLmRhdGVFbnY7XG4gICAgICAgIHZhciBzdGFydCA9IGRhdGVFbnYuY3JlYXRlTWFya2VyKHN0YXJ0SW5wdXQpO1xuICAgICAgICBpZiAoc3RhcnQgJiYgdGhpcy5faW5zdGFuY2UpIHsgLy8gVE9ETzogd2FybmluZyBpZiBwYXJzZWQgYmFkXG4gICAgICAgICAgICB2YXIgaW5zdGFuY2VSYW5nZSA9IHRoaXMuX2luc3RhbmNlLnJhbmdlO1xuICAgICAgICAgICAgdmFyIHN0YXJ0RGVsdGEgPSBkaWZmRGF0ZXMoaW5zdGFuY2VSYW5nZS5zdGFydCwgc3RhcnQsIGRhdGVFbnYsIG9wdGlvbnMuZ3JhbnVsYXJpdHkpOyAvLyB3aGF0IGlmIHBhcnNlZCBiYWQhP1xuICAgICAgICAgICAgaWYgKG9wdGlvbnMubWFpbnRhaW5EdXJhdGlvbikge1xuICAgICAgICAgICAgICAgIHRoaXMubXV0YXRlKHsgZGF0ZXNEZWx0YTogc3RhcnREZWx0YSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMubXV0YXRlKHsgc3RhcnREZWx0YTogc3RhcnREZWx0YSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG4gICAgRXZlbnRBcGkucHJvdG90eXBlLnNldEVuZCA9IGZ1bmN0aW9uIChlbmRJbnB1dCwgb3B0aW9ucykge1xuICAgICAgICBpZiAob3B0aW9ucyA9PT0gdm9pZCAwKSB7IG9wdGlvbnMgPSB7fTsgfVxuICAgICAgICB2YXIgZGF0ZUVudiA9IHRoaXMuX2NhbGVuZGFyLmRhdGVFbnY7XG4gICAgICAgIHZhciBlbmQ7XG4gICAgICAgIGlmIChlbmRJbnB1dCAhPSBudWxsKSB7XG4gICAgICAgICAgICBlbmQgPSBkYXRlRW52LmNyZWF0ZU1hcmtlcihlbmRJbnB1dCk7XG4gICAgICAgICAgICBpZiAoIWVuZCkge1xuICAgICAgICAgICAgICAgIHJldHVybjsgLy8gVE9ETzogd2FybmluZyBpZiBwYXJzZWQgYmFkXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuX2luc3RhbmNlKSB7XG4gICAgICAgICAgICBpZiAoZW5kKSB7XG4gICAgICAgICAgICAgICAgdmFyIGVuZERlbHRhID0gZGlmZkRhdGVzKHRoaXMuX2luc3RhbmNlLnJhbmdlLmVuZCwgZW5kLCBkYXRlRW52LCBvcHRpb25zLmdyYW51bGFyaXR5KTtcbiAgICAgICAgICAgICAgICB0aGlzLm11dGF0ZSh7IGVuZERlbHRhOiBlbmREZWx0YSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMubXV0YXRlKHsgc3RhbmRhcmRQcm9wczogeyBoYXNFbmQ6IGZhbHNlIH0gfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuICAgIEV2ZW50QXBpLnByb3RvdHlwZS5zZXREYXRlcyA9IGZ1bmN0aW9uIChzdGFydElucHV0LCBlbmRJbnB1dCwgb3B0aW9ucykge1xuICAgICAgICBpZiAob3B0aW9ucyA9PT0gdm9pZCAwKSB7IG9wdGlvbnMgPSB7fTsgfVxuICAgICAgICB2YXIgZGF0ZUVudiA9IHRoaXMuX2NhbGVuZGFyLmRhdGVFbnY7XG4gICAgICAgIHZhciBzdGFuZGFyZFByb3BzID0geyBhbGxEYXk6IG9wdGlvbnMuYWxsRGF5IH07XG4gICAgICAgIHZhciBzdGFydCA9IGRhdGVFbnYuY3JlYXRlTWFya2VyKHN0YXJ0SW5wdXQpO1xuICAgICAgICB2YXIgZW5kO1xuICAgICAgICBpZiAoIXN0YXJ0KSB7XG4gICAgICAgICAgICByZXR1cm47IC8vIFRPRE86IHdhcm5pbmcgaWYgcGFyc2VkIGJhZFxuICAgICAgICB9XG4gICAgICAgIGlmIChlbmRJbnB1dCAhPSBudWxsKSB7XG4gICAgICAgICAgICBlbmQgPSBkYXRlRW52LmNyZWF0ZU1hcmtlcihlbmRJbnB1dCk7XG4gICAgICAgICAgICBpZiAoIWVuZCkgeyAvLyBUT0RPOiB3YXJuaW5nIGlmIHBhcnNlZCBiYWRcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuX2luc3RhbmNlKSB7XG4gICAgICAgICAgICB2YXIgaW5zdGFuY2VSYW5nZSA9IHRoaXMuX2luc3RhbmNlLnJhbmdlO1xuICAgICAgICAgICAgLy8gd2hlbiBjb21wdXRpbmcgdGhlIGRpZmYgZm9yIGFuIGV2ZW50IGJlaW5nIGNvbnZlcnRlZCB0byBhbGwtZGF5LFxuICAgICAgICAgICAgLy8gY29tcHV0ZSBkaWZmIG9mZiBvZiB0aGUgYWxsLWRheSB2YWx1ZXMgdGhlIHdheSBldmVudC1tdXRhdGlvbiBkb2VzLlxuICAgICAgICAgICAgaWYgKG9wdGlvbnMuYWxsRGF5ID09PSB0cnVlKSB7XG4gICAgICAgICAgICAgICAgaW5zdGFuY2VSYW5nZSA9IGNvbXB1dGVBbGlnbmVkRGF5UmFuZ2UoaW5zdGFuY2VSYW5nZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgc3RhcnREZWx0YSA9IGRpZmZEYXRlcyhpbnN0YW5jZVJhbmdlLnN0YXJ0LCBzdGFydCwgZGF0ZUVudiwgb3B0aW9ucy5ncmFudWxhcml0eSk7XG4gICAgICAgICAgICBpZiAoZW5kKSB7XG4gICAgICAgICAgICAgICAgdmFyIGVuZERlbHRhID0gZGlmZkRhdGVzKGluc3RhbmNlUmFuZ2UuZW5kLCBlbmQsIGRhdGVFbnYsIG9wdGlvbnMuZ3JhbnVsYXJpdHkpO1xuICAgICAgICAgICAgICAgIGlmIChkdXJhdGlvbnNFcXVhbChzdGFydERlbHRhLCBlbmREZWx0YSkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5tdXRhdGUoeyBkYXRlc0RlbHRhOiBzdGFydERlbHRhLCBzdGFuZGFyZFByb3BzOiBzdGFuZGFyZFByb3BzIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5tdXRhdGUoeyBzdGFydERlbHRhOiBzdGFydERlbHRhLCBlbmREZWx0YTogZW5kRGVsdGEsIHN0YW5kYXJkUHJvcHM6IHN0YW5kYXJkUHJvcHMgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7IC8vIG1lYW5zIFwiY2xlYXIgdGhlIGVuZFwiXG4gICAgICAgICAgICAgICAgc3RhbmRhcmRQcm9wcy5oYXNFbmQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB0aGlzLm11dGF0ZSh7IGRhdGVzRGVsdGE6IHN0YXJ0RGVsdGEsIHN0YW5kYXJkUHJvcHM6IHN0YW5kYXJkUHJvcHMgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuICAgIEV2ZW50QXBpLnByb3RvdHlwZS5tb3ZlU3RhcnQgPSBmdW5jdGlvbiAoZGVsdGFJbnB1dCkge1xuICAgICAgICB2YXIgZGVsdGEgPSBjcmVhdGVEdXJhdGlvbihkZWx0YUlucHV0KTtcbiAgICAgICAgaWYgKGRlbHRhKSB7IC8vIFRPRE86IHdhcm5pbmcgaWYgcGFyc2VkIGJhZFxuICAgICAgICAgICAgdGhpcy5tdXRhdGUoeyBzdGFydERlbHRhOiBkZWx0YSB9KTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgRXZlbnRBcGkucHJvdG90eXBlLm1vdmVFbmQgPSBmdW5jdGlvbiAoZGVsdGFJbnB1dCkge1xuICAgICAgICB2YXIgZGVsdGEgPSBjcmVhdGVEdXJhdGlvbihkZWx0YUlucHV0KTtcbiAgICAgICAgaWYgKGRlbHRhKSB7IC8vIFRPRE86IHdhcm5pbmcgaWYgcGFyc2VkIGJhZFxuICAgICAgICAgICAgdGhpcy5tdXRhdGUoeyBlbmREZWx0YTogZGVsdGEgfSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIEV2ZW50QXBpLnByb3RvdHlwZS5tb3ZlRGF0ZXMgPSBmdW5jdGlvbiAoZGVsdGFJbnB1dCkge1xuICAgICAgICB2YXIgZGVsdGEgPSBjcmVhdGVEdXJhdGlvbihkZWx0YUlucHV0KTtcbiAgICAgICAgaWYgKGRlbHRhKSB7IC8vIFRPRE86IHdhcm5pbmcgaWYgcGFyc2VkIGJhZFxuICAgICAgICAgICAgdGhpcy5tdXRhdGUoeyBkYXRlc0RlbHRhOiBkZWx0YSB9KTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgRXZlbnRBcGkucHJvdG90eXBlLnNldEFsbERheSA9IGZ1bmN0aW9uIChhbGxEYXksIG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMgPT09IHZvaWQgMCkgeyBvcHRpb25zID0ge307IH1cbiAgICAgICAgdmFyIHN0YW5kYXJkUHJvcHMgPSB7IGFsbERheTogYWxsRGF5IH07XG4gICAgICAgIHZhciBtYWludGFpbkR1cmF0aW9uID0gb3B0aW9ucy5tYWludGFpbkR1cmF0aW9uO1xuICAgICAgICBpZiAobWFpbnRhaW5EdXJhdGlvbiA9PSBudWxsKSB7XG4gICAgICAgICAgICBtYWludGFpbkR1cmF0aW9uID0gdGhpcy5fY2FsZW5kYXIub3B0KCdhbGxEYXlNYWludGFpbkR1cmF0aW9uJyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuX2RlZi5hbGxEYXkgIT09IGFsbERheSkge1xuICAgICAgICAgICAgc3RhbmRhcmRQcm9wcy5oYXNFbmQgPSBtYWludGFpbkR1cmF0aW9uO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMubXV0YXRlKHsgc3RhbmRhcmRQcm9wczogc3RhbmRhcmRQcm9wcyB9KTtcbiAgICB9O1xuICAgIEV2ZW50QXBpLnByb3RvdHlwZS5mb3JtYXRSYW5nZSA9IGZ1bmN0aW9uIChmb3JtYXRJbnB1dCkge1xuICAgICAgICB2YXIgZGF0ZUVudiA9IHRoaXMuX2NhbGVuZGFyLmRhdGVFbnY7XG4gICAgICAgIHZhciBpbnN0YW5jZSA9IHRoaXMuX2luc3RhbmNlO1xuICAgICAgICB2YXIgZm9ybWF0dGVyID0gY3JlYXRlRm9ybWF0dGVyKGZvcm1hdElucHV0LCB0aGlzLl9jYWxlbmRhci5vcHQoJ2RlZmF1bHRSYW5nZVNlcGFyYXRvcicpKTtcbiAgICAgICAgaWYgKHRoaXMuX2RlZi5oYXNFbmQpIHtcbiAgICAgICAgICAgIHJldHVybiBkYXRlRW52LmZvcm1hdFJhbmdlKGluc3RhbmNlLnJhbmdlLnN0YXJ0LCBpbnN0YW5jZS5yYW5nZS5lbmQsIGZvcm1hdHRlciwge1xuICAgICAgICAgICAgICAgIGZvcmNlZFN0YXJ0VHpvOiBpbnN0YW5jZS5mb3JjZWRTdGFydFR6byxcbiAgICAgICAgICAgICAgICBmb3JjZWRFbmRUem86IGluc3RhbmNlLmZvcmNlZEVuZFR6b1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gZGF0ZUVudi5mb3JtYXQoaW5zdGFuY2UucmFuZ2Uuc3RhcnQsIGZvcm1hdHRlciwge1xuICAgICAgICAgICAgICAgIGZvcmNlZFR6bzogaW5zdGFuY2UuZm9yY2VkU3RhcnRUem9cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBFdmVudEFwaS5wcm90b3R5cGUubXV0YXRlID0gZnVuY3Rpb24gKG11dGF0aW9uKSB7XG4gICAgICAgIHZhciBkZWYgPSB0aGlzLl9kZWY7XG4gICAgICAgIHZhciBpbnN0YW5jZSA9IHRoaXMuX2luc3RhbmNlO1xuICAgICAgICBpZiAoaW5zdGFuY2UpIHtcbiAgICAgICAgICAgIHRoaXMuX2NhbGVuZGFyLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICB0eXBlOiAnTVVUQVRFX0VWRU5UUycsXG4gICAgICAgICAgICAgICAgaW5zdGFuY2VJZDogaW5zdGFuY2UuaW5zdGFuY2VJZCxcbiAgICAgICAgICAgICAgICBtdXRhdGlvbjogbXV0YXRpb24sXG4gICAgICAgICAgICAgICAgZnJvbUFwaTogdHJ1ZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB2YXIgZXZlbnRTdG9yZSA9IHRoaXMuX2NhbGVuZGFyLnN0YXRlLmV2ZW50U3RvcmU7XG4gICAgICAgICAgICB0aGlzLl9kZWYgPSBldmVudFN0b3JlLmRlZnNbZGVmLmRlZklkXTtcbiAgICAgICAgICAgIHRoaXMuX2luc3RhbmNlID0gZXZlbnRTdG9yZS5pbnN0YW5jZXNbaW5zdGFuY2UuaW5zdGFuY2VJZF07XG4gICAgICAgIH1cbiAgICB9O1xuICAgIEV2ZW50QXBpLnByb3RvdHlwZS5yZW1vdmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuX2NhbGVuZGFyLmRpc3BhdGNoKHtcbiAgICAgICAgICAgIHR5cGU6ICdSRU1PVkVfRVZFTlRfREVGJyxcbiAgICAgICAgICAgIGRlZklkOiB0aGlzLl9kZWYuZGVmSWRcbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRXZlbnRBcGkucHJvdG90eXBlLCBcInNvdXJjZVwiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHNvdXJjZUlkID0gdGhpcy5fZGVmLnNvdXJjZUlkO1xuICAgICAgICAgICAgaWYgKHNvdXJjZUlkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBFdmVudFNvdXJjZUFwaSh0aGlzLl9jYWxlbmRhciwgdGhpcy5fY2FsZW5kYXIuc3RhdGUuZXZlbnRTb3VyY2VzW3NvdXJjZUlkXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfSxcbiAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlXG4gICAgfSk7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KEV2ZW50QXBpLnByb3RvdHlwZSwgXCJzdGFydFwiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2luc3RhbmNlID9cbiAgICAgICAgICAgICAgICB0aGlzLl9jYWxlbmRhci5kYXRlRW52LnRvRGF0ZSh0aGlzLl9pbnN0YW5jZS5yYW5nZS5zdGFydCkgOlxuICAgICAgICAgICAgICAgIG51bGw7XG4gICAgICAgIH0sXG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShFdmVudEFwaS5wcm90b3R5cGUsIFwiZW5kXCIsIHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gKHRoaXMuX2luc3RhbmNlICYmIHRoaXMuX2RlZi5oYXNFbmQpID9cbiAgICAgICAgICAgICAgICB0aGlzLl9jYWxlbmRhci5kYXRlRW52LnRvRGF0ZSh0aGlzLl9pbnN0YW5jZS5yYW5nZS5lbmQpIDpcbiAgICAgICAgICAgICAgICBudWxsO1xuICAgICAgICB9LFxuICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICB9KTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRXZlbnRBcGkucHJvdG90eXBlLCBcImlkXCIsIHtcbiAgICAgICAgLy8gY29tcHV0YWJsZSBwcm9wcyB0aGF0IGFsbCBhY2Nlc3MgdGhlIGRlZlxuICAgICAgICAvLyBUT0RPOiBmaW5kIGEgVHlwZVNjcmlwdC1jb21wYXRpYmxlIHdheSB0byBkbyB0aGlzIGF0IHNjYWxlXG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkgeyByZXR1cm4gdGhpcy5fZGVmLnB1YmxpY0lkOyB9LFxuICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICB9KTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRXZlbnRBcGkucHJvdG90eXBlLCBcImdyb3VwSWRcIiwge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMuX2RlZi5ncm91cElkOyB9LFxuICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICB9KTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRXZlbnRBcGkucHJvdG90eXBlLCBcImFsbERheVwiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkgeyByZXR1cm4gdGhpcy5fZGVmLmFsbERheTsgfSxcbiAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlXG4gICAgfSk7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KEV2ZW50QXBpLnByb3RvdHlwZSwgXCJ0aXRsZVwiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkgeyByZXR1cm4gdGhpcy5fZGVmLnRpdGxlOyB9LFxuICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICB9KTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRXZlbnRBcGkucHJvdG90eXBlLCBcInVybFwiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkgeyByZXR1cm4gdGhpcy5fZGVmLnVybDsgfSxcbiAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlXG4gICAgfSk7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KEV2ZW50QXBpLnByb3RvdHlwZSwgXCJyZW5kZXJpbmdcIiwge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMuX2RlZi5yZW5kZXJpbmc7IH0sXG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShFdmVudEFwaS5wcm90b3R5cGUsIFwic3RhcnRFZGl0YWJsZVwiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkgeyByZXR1cm4gdGhpcy5fZGVmLnVpLnN0YXJ0RWRpdGFibGU7IH0sXG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShFdmVudEFwaS5wcm90b3R5cGUsIFwiZHVyYXRpb25FZGl0YWJsZVwiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkgeyByZXR1cm4gdGhpcy5fZGVmLnVpLmR1cmF0aW9uRWRpdGFibGU7IH0sXG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShFdmVudEFwaS5wcm90b3R5cGUsIFwiY29uc3RyYWludFwiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkgeyByZXR1cm4gdGhpcy5fZGVmLnVpLmNvbnN0cmFpbnRzWzBdIHx8IG51bGw7IH0sXG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShFdmVudEFwaS5wcm90b3R5cGUsIFwib3ZlcmxhcFwiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkgeyByZXR1cm4gdGhpcy5fZGVmLnVpLm92ZXJsYXA7IH0sXG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShFdmVudEFwaS5wcm90b3R5cGUsIFwiYWxsb3dcIiwge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMuX2RlZi51aS5hbGxvd3NbMF0gfHwgbnVsbDsgfSxcbiAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlXG4gICAgfSk7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KEV2ZW50QXBpLnByb3RvdHlwZSwgXCJiYWNrZ3JvdW5kQ29sb3JcIiwge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMuX2RlZi51aS5iYWNrZ3JvdW5kQ29sb3I7IH0sXG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShFdmVudEFwaS5wcm90b3R5cGUsIFwiYm9yZGVyQ29sb3JcIiwge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMuX2RlZi51aS5ib3JkZXJDb2xvcjsgfSxcbiAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlXG4gICAgfSk7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KEV2ZW50QXBpLnByb3RvdHlwZSwgXCJ0ZXh0Q29sb3JcIiwge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMuX2RlZi51aS50ZXh0Q29sb3I7IH0sXG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShFdmVudEFwaS5wcm90b3R5cGUsIFwiY2xhc3NOYW1lc1wiLCB7XG4gICAgICAgIC8vIE5PVEU6IHVzZXIgY2FuJ3QgbW9kaWZ5IHRoZXNlIGJlY2F1c2UgT2JqZWN0LmZyZWV6ZSB3YXMgY2FsbGVkIGluIGV2ZW50LWRlZiBwYXJzaW5nXG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkgeyByZXR1cm4gdGhpcy5fZGVmLnVpLmNsYXNzTmFtZXM7IH0sXG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShFdmVudEFwaS5wcm90b3R5cGUsIFwiZXh0ZW5kZWRQcm9wc1wiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkgeyByZXR1cm4gdGhpcy5fZGVmLmV4dGVuZGVkUHJvcHM7IH0sXG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pO1xuICAgIHJldHVybiBFdmVudEFwaTtcbn0oKSk7XG5cbi8qXG5TcGVjaWZ5aW5nIG5leHREYXlUaHJlc2hvbGQgc2lnbmFscyB0aGF0IGFsbC1kYXkgcmFuZ2VzIHNob3VsZCBiZSBzbGljZWQuXG4qL1xuZnVuY3Rpb24gc2xpY2VFdmVudFN0b3JlKGV2ZW50U3RvcmUsIGV2ZW50VWlCYXNlcywgZnJhbWluZ1JhbmdlLCBuZXh0RGF5VGhyZXNob2xkKSB7XG4gICAgdmFyIGludmVyc2VCZ0J5R3JvdXBJZCA9IHt9O1xuICAgIHZhciBpbnZlcnNlQmdCeURlZklkID0ge307XG4gICAgdmFyIGRlZkJ5R3JvdXBJZCA9IHt9O1xuICAgIHZhciBiZ1JhbmdlcyA9IFtdO1xuICAgIHZhciBmZ1JhbmdlcyA9IFtdO1xuICAgIHZhciBldmVudFVpcyA9IGNvbXBpbGVFdmVudFVpcyhldmVudFN0b3JlLmRlZnMsIGV2ZW50VWlCYXNlcyk7XG4gICAgZm9yICh2YXIgZGVmSWQgaW4gZXZlbnRTdG9yZS5kZWZzKSB7XG4gICAgICAgIHZhciBkZWYgPSBldmVudFN0b3JlLmRlZnNbZGVmSWRdO1xuICAgICAgICBpZiAoZGVmLnJlbmRlcmluZyA9PT0gJ2ludmVyc2UtYmFja2dyb3VuZCcpIHtcbiAgICAgICAgICAgIGlmIChkZWYuZ3JvdXBJZCkge1xuICAgICAgICAgICAgICAgIGludmVyc2VCZ0J5R3JvdXBJZFtkZWYuZ3JvdXBJZF0gPSBbXTtcbiAgICAgICAgICAgICAgICBpZiAoIWRlZkJ5R3JvdXBJZFtkZWYuZ3JvdXBJZF0pIHtcbiAgICAgICAgICAgICAgICAgICAgZGVmQnlHcm91cElkW2RlZi5ncm91cElkXSA9IGRlZjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBpbnZlcnNlQmdCeURlZklkW2RlZklkXSA9IFtdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIGZvciAodmFyIGluc3RhbmNlSWQgaW4gZXZlbnRTdG9yZS5pbnN0YW5jZXMpIHtcbiAgICAgICAgdmFyIGluc3RhbmNlID0gZXZlbnRTdG9yZS5pbnN0YW5jZXNbaW5zdGFuY2VJZF07XG4gICAgICAgIHZhciBkZWYgPSBldmVudFN0b3JlLmRlZnNbaW5zdGFuY2UuZGVmSWRdO1xuICAgICAgICB2YXIgdWkgPSBldmVudFVpc1tkZWYuZGVmSWRdO1xuICAgICAgICB2YXIgb3JpZ1JhbmdlID0gaW5zdGFuY2UucmFuZ2U7XG4gICAgICAgIHZhciBub3JtYWxSYW5nZSA9ICghZGVmLmFsbERheSAmJiBuZXh0RGF5VGhyZXNob2xkKSA/XG4gICAgICAgICAgICBjb21wdXRlVmlzaWJsZURheVJhbmdlKG9yaWdSYW5nZSwgbmV4dERheVRocmVzaG9sZCkgOlxuICAgICAgICAgICAgb3JpZ1JhbmdlO1xuICAgICAgICB2YXIgc2xpY2VkUmFuZ2UgPSBpbnRlcnNlY3RSYW5nZXMobm9ybWFsUmFuZ2UsIGZyYW1pbmdSYW5nZSk7XG4gICAgICAgIGlmIChzbGljZWRSYW5nZSkge1xuICAgICAgICAgICAgaWYgKGRlZi5yZW5kZXJpbmcgPT09ICdpbnZlcnNlLWJhY2tncm91bmQnKSB7XG4gICAgICAgICAgICAgICAgaWYgKGRlZi5ncm91cElkKSB7XG4gICAgICAgICAgICAgICAgICAgIGludmVyc2VCZ0J5R3JvdXBJZFtkZWYuZ3JvdXBJZF0ucHVzaChzbGljZWRSYW5nZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBpbnZlcnNlQmdCeURlZklkW2luc3RhbmNlLmRlZklkXS5wdXNoKHNsaWNlZFJhbmdlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAoZGVmLnJlbmRlcmluZyA9PT0gJ2JhY2tncm91bmQnID8gYmdSYW5nZXMgOiBmZ1JhbmdlcykucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIGRlZjogZGVmLFxuICAgICAgICAgICAgICAgICAgICB1aTogdWksXG4gICAgICAgICAgICAgICAgICAgIGluc3RhbmNlOiBpbnN0YW5jZSxcbiAgICAgICAgICAgICAgICAgICAgcmFuZ2U6IHNsaWNlZFJhbmdlLFxuICAgICAgICAgICAgICAgICAgICBpc1N0YXJ0OiBub3JtYWxSYW5nZS5zdGFydCAmJiBub3JtYWxSYW5nZS5zdGFydC52YWx1ZU9mKCkgPT09IHNsaWNlZFJhbmdlLnN0YXJ0LnZhbHVlT2YoKSxcbiAgICAgICAgICAgICAgICAgICAgaXNFbmQ6IG5vcm1hbFJhbmdlLmVuZCAmJiBub3JtYWxSYW5nZS5lbmQudmFsdWVPZigpID09PSBzbGljZWRSYW5nZS5lbmQudmFsdWVPZigpXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgZm9yICh2YXIgZ3JvdXBJZCBpbiBpbnZlcnNlQmdCeUdyb3VwSWQpIHsgLy8gQlkgR1JPVVBcbiAgICAgICAgdmFyIHJhbmdlcyA9IGludmVyc2VCZ0J5R3JvdXBJZFtncm91cElkXTtcbiAgICAgICAgdmFyIGludmVydGVkUmFuZ2VzID0gaW52ZXJ0UmFuZ2VzKHJhbmdlcywgZnJhbWluZ1JhbmdlKTtcbiAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBpbnZlcnRlZFJhbmdlc18xID0gaW52ZXJ0ZWRSYW5nZXM7IF9pIDwgaW52ZXJ0ZWRSYW5nZXNfMS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIHZhciBpbnZlcnRlZFJhbmdlID0gaW52ZXJ0ZWRSYW5nZXNfMVtfaV07XG4gICAgICAgICAgICB2YXIgZGVmID0gZGVmQnlHcm91cElkW2dyb3VwSWRdO1xuICAgICAgICAgICAgdmFyIHVpID0gZXZlbnRVaXNbZGVmLmRlZklkXTtcbiAgICAgICAgICAgIGJnUmFuZ2VzLnB1c2goe1xuICAgICAgICAgICAgICAgIGRlZjogZGVmLFxuICAgICAgICAgICAgICAgIHVpOiB1aSxcbiAgICAgICAgICAgICAgICBpbnN0YW5jZTogbnVsbCxcbiAgICAgICAgICAgICAgICByYW5nZTogaW52ZXJ0ZWRSYW5nZSxcbiAgICAgICAgICAgICAgICBpc1N0YXJ0OiBmYWxzZSxcbiAgICAgICAgICAgICAgICBpc0VuZDogZmFsc2VcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIGZvciAodmFyIGRlZklkIGluIGludmVyc2VCZ0J5RGVmSWQpIHtcbiAgICAgICAgdmFyIHJhbmdlcyA9IGludmVyc2VCZ0J5RGVmSWRbZGVmSWRdO1xuICAgICAgICB2YXIgaW52ZXJ0ZWRSYW5nZXMgPSBpbnZlcnRSYW5nZXMocmFuZ2VzLCBmcmFtaW5nUmFuZ2UpO1xuICAgICAgICBmb3IgKHZhciBfYSA9IDAsIGludmVydGVkUmFuZ2VzXzIgPSBpbnZlcnRlZFJhbmdlczsgX2EgPCBpbnZlcnRlZFJhbmdlc18yLmxlbmd0aDsgX2ErKykge1xuICAgICAgICAgICAgdmFyIGludmVydGVkUmFuZ2UgPSBpbnZlcnRlZFJhbmdlc18yW19hXTtcbiAgICAgICAgICAgIGJnUmFuZ2VzLnB1c2goe1xuICAgICAgICAgICAgICAgIGRlZjogZXZlbnRTdG9yZS5kZWZzW2RlZklkXSxcbiAgICAgICAgICAgICAgICB1aTogZXZlbnRVaXNbZGVmSWRdLFxuICAgICAgICAgICAgICAgIGluc3RhbmNlOiBudWxsLFxuICAgICAgICAgICAgICAgIHJhbmdlOiBpbnZlcnRlZFJhbmdlLFxuICAgICAgICAgICAgICAgIGlzU3RhcnQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGlzRW5kOiBmYWxzZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgYmc6IGJnUmFuZ2VzLCBmZzogZmdSYW5nZXMgfTtcbn1cbmZ1bmN0aW9uIGhhc0JnUmVuZGVyaW5nKGRlZikge1xuICAgIHJldHVybiBkZWYucmVuZGVyaW5nID09PSAnYmFja2dyb3VuZCcgfHwgZGVmLnJlbmRlcmluZyA9PT0gJ2ludmVyc2UtYmFja2dyb3VuZCc7XG59XG5mdW5jdGlvbiBmaWx0ZXJTZWdzVmlhRWxzKGNvbnRleHQsIHNlZ3MsIGlzTWlycm9yKSB7XG4gICAgdmFyIGNhbGVuZGFyID0gY29udGV4dC5jYWxlbmRhciwgdmlldyA9IGNvbnRleHQudmlldztcbiAgICBpZiAoY2FsZW5kYXIuaGFzUHVibGljSGFuZGxlcnMoJ2V2ZW50UmVuZGVyJykpIHtcbiAgICAgICAgc2VncyA9IHNlZ3MuZmlsdGVyKGZ1bmN0aW9uIChzZWcpIHtcbiAgICAgICAgICAgIHZhciBjdXN0b20gPSBjYWxlbmRhci5wdWJsaWNseVRyaWdnZXIoJ2V2ZW50UmVuZGVyJywgW1xuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnQ6IG5ldyBFdmVudEFwaShjYWxlbmRhciwgc2VnLmV2ZW50UmFuZ2UuZGVmLCBzZWcuZXZlbnRSYW5nZS5pbnN0YW5jZSksXG4gICAgICAgICAgICAgICAgICAgIGlzTWlycm9yOiBpc01pcnJvcixcbiAgICAgICAgICAgICAgICAgICAgaXNTdGFydDogc2VnLmlzU3RhcnQsXG4gICAgICAgICAgICAgICAgICAgIGlzRW5kOiBzZWcuaXNFbmQsXG4gICAgICAgICAgICAgICAgICAgIC8vIFRPRE86IGluY2x1ZGUgc2VnLnJhbmdlIG9uY2UgYWxsIGNvbXBvbmVudHMgY29uc2lzdGVudGx5IGdlbmVyYXRlIGl0XG4gICAgICAgICAgICAgICAgICAgIGVsOiBzZWcuZWwsXG4gICAgICAgICAgICAgICAgICAgIHZpZXc6IHZpZXdcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICBdKTtcbiAgICAgICAgICAgIGlmIChjdXN0b20gPT09IGZhbHNlKSB7IC8vIG1lYW5zIGRvbid0IHJlbmRlciBhdCBhbGxcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmIChjdXN0b20gJiYgY3VzdG9tICE9PSB0cnVlKSB7XG4gICAgICAgICAgICAgICAgc2VnLmVsID0gY3VzdG9tO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBmb3IgKHZhciBfaSA9IDAsIHNlZ3NfMSA9IHNlZ3M7IF9pIDwgc2Vnc18xLmxlbmd0aDsgX2krKykge1xuICAgICAgICB2YXIgc2VnID0gc2Vnc18xW19pXTtcbiAgICAgICAgc2V0RWxTZWcoc2VnLmVsLCBzZWcpO1xuICAgIH1cbiAgICByZXR1cm4gc2Vncztcbn1cbmZ1bmN0aW9uIHNldEVsU2VnKGVsLCBzZWcpIHtcbiAgICBlbC5mY1NlZyA9IHNlZztcbn1cbmZ1bmN0aW9uIGdldEVsU2VnKGVsKSB7XG4gICAgcmV0dXJuIGVsLmZjU2VnIHx8IG51bGw7XG59XG4vLyBldmVudCB1aSBjb21wdXRhdGlvblxuZnVuY3Rpb24gY29tcGlsZUV2ZW50VWlzKGV2ZW50RGVmcywgZXZlbnRVaUJhc2VzKSB7XG4gICAgcmV0dXJuIG1hcEhhc2goZXZlbnREZWZzLCBmdW5jdGlvbiAoZXZlbnREZWYpIHtcbiAgICAgICAgcmV0dXJuIGNvbXBpbGVFdmVudFVpKGV2ZW50RGVmLCBldmVudFVpQmFzZXMpO1xuICAgIH0pO1xufVxuZnVuY3Rpb24gY29tcGlsZUV2ZW50VWkoZXZlbnREZWYsIGV2ZW50VWlCYXNlcykge1xuICAgIHZhciB1aXMgPSBbXTtcbiAgICBpZiAoZXZlbnRVaUJhc2VzWycnXSkge1xuICAgICAgICB1aXMucHVzaChldmVudFVpQmFzZXNbJyddKTtcbiAgICB9XG4gICAgaWYgKGV2ZW50VWlCYXNlc1tldmVudERlZi5kZWZJZF0pIHtcbiAgICAgICAgdWlzLnB1c2goZXZlbnRVaUJhc2VzW2V2ZW50RGVmLmRlZklkXSk7XG4gICAgfVxuICAgIHVpcy5wdXNoKGV2ZW50RGVmLnVpKTtcbiAgICByZXR1cm4gY29tYmluZUV2ZW50VWlzKHVpcyk7XG59XG4vLyB0cmlnZ2Vyc1xuZnVuY3Rpb24gdHJpZ2dlclJlbmRlcmVkU2Vncyhjb250ZXh0LCBzZWdzLCBpc01pcnJvcnMpIHtcbiAgICB2YXIgY2FsZW5kYXIgPSBjb250ZXh0LmNhbGVuZGFyLCB2aWV3ID0gY29udGV4dC52aWV3O1xuICAgIGlmIChjYWxlbmRhci5oYXNQdWJsaWNIYW5kbGVycygnZXZlbnRQb3NpdGlvbmVkJykpIHtcbiAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBzZWdzXzIgPSBzZWdzOyBfaSA8IHNlZ3NfMi5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIHZhciBzZWcgPSBzZWdzXzJbX2ldO1xuICAgICAgICAgICAgY2FsZW5kYXIucHVibGljbHlUcmlnZ2VyQWZ0ZXJTaXppbmcoJ2V2ZW50UG9zaXRpb25lZCcsIFtcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50OiBuZXcgRXZlbnRBcGkoY2FsZW5kYXIsIHNlZy5ldmVudFJhbmdlLmRlZiwgc2VnLmV2ZW50UmFuZ2UuaW5zdGFuY2UpLFxuICAgICAgICAgICAgICAgICAgICBpc01pcnJvcjogaXNNaXJyb3JzLFxuICAgICAgICAgICAgICAgICAgICBpc1N0YXJ0OiBzZWcuaXNTdGFydCxcbiAgICAgICAgICAgICAgICAgICAgaXNFbmQ6IHNlZy5pc0VuZCxcbiAgICAgICAgICAgICAgICAgICAgZWw6IHNlZy5lbCxcbiAgICAgICAgICAgICAgICAgICAgdmlldzogdmlld1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIF0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIGlmICghY2FsZW5kYXIuc3RhdGUubG9hZGluZ0xldmVsKSB7IC8vIGF2b2lkIGluaXRpYWwgZW1wdHkgc3RhdGUgd2hpbGUgcGVuZGluZ1xuICAgICAgICBjYWxlbmRhci5hZnRlclNpemluZ1RyaWdnZXJzLl9ldmVudHNQb3NpdGlvbmVkID0gW251bGxdOyAvLyBmaXJlIG9uY2VcbiAgICB9XG59XG5mdW5jdGlvbiB0cmlnZ2VyV2lsbFJlbW92ZVNlZ3MoY29udGV4dCwgc2VncywgaXNNaXJyb3JzKSB7XG4gICAgdmFyIGNhbGVuZGFyID0gY29udGV4dC5jYWxlbmRhciwgdmlldyA9IGNvbnRleHQudmlldztcbiAgICBmb3IgKHZhciBfaSA9IDAsIHNlZ3NfMyA9IHNlZ3M7IF9pIDwgc2Vnc18zLmxlbmd0aDsgX2krKykge1xuICAgICAgICB2YXIgc2VnID0gc2Vnc18zW19pXTtcbiAgICAgICAgY2FsZW5kYXIudHJpZ2dlcignZXZlbnRFbFJlbW92ZScsIHNlZy5lbCk7XG4gICAgfVxuICAgIGlmIChjYWxlbmRhci5oYXNQdWJsaWNIYW5kbGVycygnZXZlbnREZXN0cm95JykpIHtcbiAgICAgICAgZm9yICh2YXIgX2EgPSAwLCBzZWdzXzQgPSBzZWdzOyBfYSA8IHNlZ3NfNC5sZW5ndGg7IF9hKyspIHtcbiAgICAgICAgICAgIHZhciBzZWcgPSBzZWdzXzRbX2FdO1xuICAgICAgICAgICAgY2FsZW5kYXIucHVibGljbHlUcmlnZ2VyKCdldmVudERlc3Ryb3knLCBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBldmVudDogbmV3IEV2ZW50QXBpKGNhbGVuZGFyLCBzZWcuZXZlbnRSYW5nZS5kZWYsIHNlZy5ldmVudFJhbmdlLmluc3RhbmNlKSxcbiAgICAgICAgICAgICAgICAgICAgaXNNaXJyb3I6IGlzTWlycm9ycyxcbiAgICAgICAgICAgICAgICAgICAgZWw6IHNlZy5lbCxcbiAgICAgICAgICAgICAgICAgICAgdmlldzogdmlld1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIF0pO1xuICAgICAgICB9XG4gICAgfVxufVxuLy8gaXMtaW50ZXJhY3RhYmxlXG5mdW5jdGlvbiBjb21wdXRlRXZlbnREcmFnZ2FibGUoY29udGV4dCwgZXZlbnREZWYsIGV2ZW50VWkpIHtcbiAgICB2YXIgY2FsZW5kYXIgPSBjb250ZXh0LmNhbGVuZGFyLCB2aWV3ID0gY29udGV4dC52aWV3O1xuICAgIHZhciB0cmFuc2Zvcm1lcnMgPSBjYWxlbmRhci5wbHVnaW5TeXN0ZW0uaG9va3MuaXNEcmFnZ2FibGVUcmFuc2Zvcm1lcnM7XG4gICAgdmFyIHZhbCA9IGV2ZW50VWkuc3RhcnRFZGl0YWJsZTtcbiAgICBmb3IgKHZhciBfaSA9IDAsIHRyYW5zZm9ybWVyc18xID0gdHJhbnNmb3JtZXJzOyBfaSA8IHRyYW5zZm9ybWVyc18xLmxlbmd0aDsgX2krKykge1xuICAgICAgICB2YXIgdHJhbnNmb3JtZXIgPSB0cmFuc2Zvcm1lcnNfMVtfaV07XG4gICAgICAgIHZhbCA9IHRyYW5zZm9ybWVyKHZhbCwgZXZlbnREZWYsIGV2ZW50VWksIHZpZXcpO1xuICAgIH1cbiAgICByZXR1cm4gdmFsO1xufVxuZnVuY3Rpb24gY29tcHV0ZUV2ZW50U3RhcnRSZXNpemFibGUoY29udGV4dCwgZXZlbnREZWYsIGV2ZW50VWkpIHtcbiAgICByZXR1cm4gZXZlbnRVaS5kdXJhdGlvbkVkaXRhYmxlICYmIGNvbnRleHQub3B0aW9ucy5ldmVudFJlc2l6YWJsZUZyb21TdGFydDtcbn1cbmZ1bmN0aW9uIGNvbXB1dGVFdmVudEVuZFJlc2l6YWJsZShjb250ZXh0LCBldmVudERlZiwgZXZlbnRVaSkge1xuICAgIHJldHVybiBldmVudFVpLmR1cmF0aW9uRWRpdGFibGU7XG59XG5cbi8vIGFwcGxpZXMgdGhlIG11dGF0aW9uIHRvIEFMTCBkZWZzL2luc3RhbmNlcyB3aXRoaW4gdGhlIGV2ZW50IHN0b3JlXG5mdW5jdGlvbiBhcHBseU11dGF0aW9uVG9FdmVudFN0b3JlKGV2ZW50U3RvcmUsIGV2ZW50Q29uZmlnQmFzZSwgbXV0YXRpb24sIGNhbGVuZGFyKSB7XG4gICAgdmFyIGV2ZW50Q29uZmlncyA9IGNvbXBpbGVFdmVudFVpcyhldmVudFN0b3JlLmRlZnMsIGV2ZW50Q29uZmlnQmFzZSk7XG4gICAgdmFyIGRlc3QgPSBjcmVhdGVFbXB0eUV2ZW50U3RvcmUoKTtcbiAgICBmb3IgKHZhciBkZWZJZCBpbiBldmVudFN0b3JlLmRlZnMpIHtcbiAgICAgICAgdmFyIGRlZiA9IGV2ZW50U3RvcmUuZGVmc1tkZWZJZF07XG4gICAgICAgIGRlc3QuZGVmc1tkZWZJZF0gPSBhcHBseU11dGF0aW9uVG9FdmVudERlZihkZWYsIGV2ZW50Q29uZmlnc1tkZWZJZF0sIG11dGF0aW9uLCBjYWxlbmRhci5wbHVnaW5TeXN0ZW0uaG9va3MuZXZlbnREZWZNdXRhdGlvbkFwcGxpZXJzLCBjYWxlbmRhcik7XG4gICAgfVxuICAgIGZvciAodmFyIGluc3RhbmNlSWQgaW4gZXZlbnRTdG9yZS5pbnN0YW5jZXMpIHtcbiAgICAgICAgdmFyIGluc3RhbmNlID0gZXZlbnRTdG9yZS5pbnN0YW5jZXNbaW5zdGFuY2VJZF07XG4gICAgICAgIHZhciBkZWYgPSBkZXN0LmRlZnNbaW5zdGFuY2UuZGVmSWRdOyAvLyBpbXBvcnRhbnQgdG8gZ3JhYiB0aGUgbmV3bHkgbW9kaWZpZWQgZGVmXG4gICAgICAgIGRlc3QuaW5zdGFuY2VzW2luc3RhbmNlSWRdID0gYXBwbHlNdXRhdGlvblRvRXZlbnRJbnN0YW5jZShpbnN0YW5jZSwgZGVmLCBldmVudENvbmZpZ3NbaW5zdGFuY2UuZGVmSWRdLCBtdXRhdGlvbiwgY2FsZW5kYXIpO1xuICAgIH1cbiAgICByZXR1cm4gZGVzdDtcbn1cbmZ1bmN0aW9uIGFwcGx5TXV0YXRpb25Ub0V2ZW50RGVmKGV2ZW50RGVmLCBldmVudENvbmZpZywgbXV0YXRpb24sIGFwcGxpZXJzLCBjYWxlbmRhcikge1xuICAgIHZhciBzdGFuZGFyZFByb3BzID0gbXV0YXRpb24uc3RhbmRhcmRQcm9wcyB8fCB7fTtcbiAgICAvLyBpZiBoYXNFbmQgaGFzIG5vdCBiZWVuIHNwZWNpZmllZCwgZ3Vlc3MgYSBnb29kIHZhbHVlIGJhc2VkIG9uIGRlbHRhcy5cbiAgICAvLyBpZiBkdXJhdGlvbiB3aWxsIGNoYW5nZSwgdGhlcmUncyBubyB3YXkgdGhlIGRlZmF1bHQgZHVyYXRpb24gd2lsbCBwZXJzaXN0LFxuICAgIC8vIGFuZCB0aHVzLCB3ZSBuZWVkIHRvIG1hcmsgdGhlIGV2ZW50IGFzIGhhdmluZyBhIHJlYWwgZW5kXG4gICAgaWYgKHN0YW5kYXJkUHJvcHMuaGFzRW5kID09IG51bGwgJiZcbiAgICAgICAgZXZlbnRDb25maWcuZHVyYXRpb25FZGl0YWJsZSAmJlxuICAgICAgICAobXV0YXRpb24uc3RhcnREZWx0YSB8fCBtdXRhdGlvbi5lbmREZWx0YSkpIHtcbiAgICAgICAgc3RhbmRhcmRQcm9wcy5oYXNFbmQgPSB0cnVlOyAvLyBUT0RPOiBpcyB0aGlzIG11dGF0aW9uIG9rYXk/XG4gICAgfVxuICAgIHZhciBjb3B5ID0gX19hc3NpZ24oe30sIGV2ZW50RGVmLCBzdGFuZGFyZFByb3BzLCB7IHVpOiBfX2Fzc2lnbih7fSwgZXZlbnREZWYudWksIHN0YW5kYXJkUHJvcHMudWkpIH0pO1xuICAgIGlmIChtdXRhdGlvbi5leHRlbmRlZFByb3BzKSB7XG4gICAgICAgIGNvcHkuZXh0ZW5kZWRQcm9wcyA9IF9fYXNzaWduKHt9LCBjb3B5LmV4dGVuZGVkUHJvcHMsIG11dGF0aW9uLmV4dGVuZGVkUHJvcHMpO1xuICAgIH1cbiAgICBmb3IgKHZhciBfaSA9IDAsIGFwcGxpZXJzXzEgPSBhcHBsaWVyczsgX2kgPCBhcHBsaWVyc18xLmxlbmd0aDsgX2krKykge1xuICAgICAgICB2YXIgYXBwbGllciA9IGFwcGxpZXJzXzFbX2ldO1xuICAgICAgICBhcHBsaWVyKGNvcHksIG11dGF0aW9uLCBjYWxlbmRhcik7XG4gICAgfVxuICAgIGlmICghY29weS5oYXNFbmQgJiYgY2FsZW5kYXIub3B0KCdmb3JjZUV2ZW50RHVyYXRpb24nKSkge1xuICAgICAgICBjb3B5Lmhhc0VuZCA9IHRydWU7XG4gICAgfVxuICAgIHJldHVybiBjb3B5O1xufVxuZnVuY3Rpb24gYXBwbHlNdXRhdGlvblRvRXZlbnRJbnN0YW5jZShldmVudEluc3RhbmNlLCBldmVudERlZiwgLy8gbXVzdCBmaXJzdCBiZSBtb2RpZmllZCBieSBhcHBseU11dGF0aW9uVG9FdmVudERlZlxuZXZlbnRDb25maWcsIG11dGF0aW9uLCBjYWxlbmRhcikge1xuICAgIHZhciBkYXRlRW52ID0gY2FsZW5kYXIuZGF0ZUVudjtcbiAgICB2YXIgZm9yY2VBbGxEYXkgPSBtdXRhdGlvbi5zdGFuZGFyZFByb3BzICYmIG11dGF0aW9uLnN0YW5kYXJkUHJvcHMuYWxsRGF5ID09PSB0cnVlO1xuICAgIHZhciBjbGVhckVuZCA9IG11dGF0aW9uLnN0YW5kYXJkUHJvcHMgJiYgbXV0YXRpb24uc3RhbmRhcmRQcm9wcy5oYXNFbmQgPT09IGZhbHNlO1xuICAgIHZhciBjb3B5ID0gX19hc3NpZ24oe30sIGV2ZW50SW5zdGFuY2UpO1xuICAgIGlmIChmb3JjZUFsbERheSkge1xuICAgICAgICBjb3B5LnJhbmdlID0gY29tcHV0ZUFsaWduZWREYXlSYW5nZShjb3B5LnJhbmdlKTtcbiAgICB9XG4gICAgaWYgKG11dGF0aW9uLmRhdGVzRGVsdGEgJiYgZXZlbnRDb25maWcuc3RhcnRFZGl0YWJsZSkge1xuICAgICAgICBjb3B5LnJhbmdlID0ge1xuICAgICAgICAgICAgc3RhcnQ6IGRhdGVFbnYuYWRkKGNvcHkucmFuZ2Uuc3RhcnQsIG11dGF0aW9uLmRhdGVzRGVsdGEpLFxuICAgICAgICAgICAgZW5kOiBkYXRlRW52LmFkZChjb3B5LnJhbmdlLmVuZCwgbXV0YXRpb24uZGF0ZXNEZWx0YSlcbiAgICAgICAgfTtcbiAgICB9XG4gICAgaWYgKG11dGF0aW9uLnN0YXJ0RGVsdGEgJiYgZXZlbnRDb25maWcuZHVyYXRpb25FZGl0YWJsZSkge1xuICAgICAgICBjb3B5LnJhbmdlID0ge1xuICAgICAgICAgICAgc3RhcnQ6IGRhdGVFbnYuYWRkKGNvcHkucmFuZ2Uuc3RhcnQsIG11dGF0aW9uLnN0YXJ0RGVsdGEpLFxuICAgICAgICAgICAgZW5kOiBjb3B5LnJhbmdlLmVuZFxuICAgICAgICB9O1xuICAgIH1cbiAgICBpZiAobXV0YXRpb24uZW5kRGVsdGEgJiYgZXZlbnRDb25maWcuZHVyYXRpb25FZGl0YWJsZSkge1xuICAgICAgICBjb3B5LnJhbmdlID0ge1xuICAgICAgICAgICAgc3RhcnQ6IGNvcHkucmFuZ2Uuc3RhcnQsXG4gICAgICAgICAgICBlbmQ6IGRhdGVFbnYuYWRkKGNvcHkucmFuZ2UuZW5kLCBtdXRhdGlvbi5lbmREZWx0YSlcbiAgICAgICAgfTtcbiAgICB9XG4gICAgaWYgKGNsZWFyRW5kKSB7XG4gICAgICAgIGNvcHkucmFuZ2UgPSB7XG4gICAgICAgICAgICBzdGFydDogY29weS5yYW5nZS5zdGFydCxcbiAgICAgICAgICAgIGVuZDogY2FsZW5kYXIuZ2V0RGVmYXVsdEV2ZW50RW5kKGV2ZW50RGVmLmFsbERheSwgY29weS5yYW5nZS5zdGFydClcbiAgICAgICAgfTtcbiAgICB9XG4gICAgLy8gaW4gY2FzZSBldmVudCB3YXMgYWxsLWRheSBidXQgdGhlIHN1cHBsaWVkIGRlbHRhcyB3ZXJlIG5vdFxuICAgIC8vIGJldHRlciB1dGlsIGZvciB0aGlzP1xuICAgIGlmIChldmVudERlZi5hbGxEYXkpIHtcbiAgICAgICAgY29weS5yYW5nZSA9IHtcbiAgICAgICAgICAgIHN0YXJ0OiBzdGFydE9mRGF5KGNvcHkucmFuZ2Uuc3RhcnQpLFxuICAgICAgICAgICAgZW5kOiBzdGFydE9mRGF5KGNvcHkucmFuZ2UuZW5kKVxuICAgICAgICB9O1xuICAgIH1cbiAgICAvLyBoYW5kbGUgaW52YWxpZCBkdXJhdGlvbnNcbiAgICBpZiAoY29weS5yYW5nZS5lbmQgPCBjb3B5LnJhbmdlLnN0YXJ0KSB7XG4gICAgICAgIGNvcHkucmFuZ2UuZW5kID0gY2FsZW5kYXIuZ2V0RGVmYXVsdEV2ZW50RW5kKGV2ZW50RGVmLmFsbERheSwgY29weS5yYW5nZS5zdGFydCk7XG4gICAgfVxuICAgIHJldHVybiBjb3B5O1xufVxuXG5mdW5jdGlvbiByZWR1Y2VFdmVudFN0b3JlIChldmVudFN0b3JlLCBhY3Rpb24sIGV2ZW50U291cmNlcywgZGF0ZVByb2ZpbGUsIGNhbGVuZGFyKSB7XG4gICAgc3dpdGNoIChhY3Rpb24udHlwZSkge1xuICAgICAgICBjYXNlICdSRUNFSVZFX0VWRU5UUyc6IC8vIHJhd1xuICAgICAgICAgICAgcmV0dXJuIHJlY2VpdmVSYXdFdmVudHMoZXZlbnRTdG9yZSwgZXZlbnRTb3VyY2VzW2FjdGlvbi5zb3VyY2VJZF0sIGFjdGlvbi5mZXRjaElkLCBhY3Rpb24uZmV0Y2hSYW5nZSwgYWN0aW9uLnJhd0V2ZW50cywgY2FsZW5kYXIpO1xuICAgICAgICBjYXNlICdBRERfRVZFTlRTJzogLy8gYWxyZWFkeSBwYXJzZWQsIGJ1dCBub3QgZXhwYW5kZWRcbiAgICAgICAgICAgIHJldHVybiBhZGRFdmVudChldmVudFN0b3JlLCBhY3Rpb24uZXZlbnRTdG9yZSwgLy8gbmV3IG9uZXNcbiAgICAgICAgICAgIGRhdGVQcm9maWxlID8gZGF0ZVByb2ZpbGUuYWN0aXZlUmFuZ2UgOiBudWxsLCBjYWxlbmRhcik7XG4gICAgICAgIGNhc2UgJ01FUkdFX0VWRU5UUyc6IC8vIGFscmVhZHkgcGFyc2VkIGFuZCBleHBhbmRlZFxuICAgICAgICAgICAgcmV0dXJuIG1lcmdlRXZlbnRTdG9yZXMoZXZlbnRTdG9yZSwgYWN0aW9uLmV2ZW50U3RvcmUpO1xuICAgICAgICBjYXNlICdQUkVWJzogLy8gVE9ETzogaG93IGRvIHdlIHRyYWNrIGFsbCBhY3Rpb25zIHRoYXQgYWZmZWN0IGRhdGVQcm9maWxlIDooXG4gICAgICAgIGNhc2UgJ05FWFQnOlxuICAgICAgICBjYXNlICdTRVRfREFURSc6XG4gICAgICAgIGNhc2UgJ1NFVF9WSUVXX1RZUEUnOlxuICAgICAgICAgICAgaWYgKGRhdGVQcm9maWxlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGV4cGFuZFJlY3VycmluZyhldmVudFN0b3JlLCBkYXRlUHJvZmlsZS5hY3RpdmVSYW5nZSwgY2FsZW5kYXIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGV2ZW50U3RvcmU7XG4gICAgICAgICAgICB9XG4gICAgICAgIGNhc2UgJ0NIQU5HRV9USU1FWk9ORSc6XG4gICAgICAgICAgICByZXR1cm4gcmV6b25lRGF0ZXMoZXZlbnRTdG9yZSwgYWN0aW9uLm9sZERhdGVFbnYsIGNhbGVuZGFyLmRhdGVFbnYpO1xuICAgICAgICBjYXNlICdNVVRBVEVfRVZFTlRTJzpcbiAgICAgICAgICAgIHJldHVybiBhcHBseU11dGF0aW9uVG9SZWxhdGVkKGV2ZW50U3RvcmUsIGFjdGlvbi5pbnN0YW5jZUlkLCBhY3Rpb24ubXV0YXRpb24sIGFjdGlvbi5mcm9tQXBpLCBjYWxlbmRhcik7XG4gICAgICAgIGNhc2UgJ1JFTU9WRV9FVkVOVF9JTlNUQU5DRVMnOlxuICAgICAgICAgICAgcmV0dXJuIGV4Y2x1ZGVJbnN0YW5jZXMoZXZlbnRTdG9yZSwgYWN0aW9uLmluc3RhbmNlcyk7XG4gICAgICAgIGNhc2UgJ1JFTU9WRV9FVkVOVF9ERUYnOlxuICAgICAgICAgICAgcmV0dXJuIGZpbHRlckV2ZW50U3RvcmVEZWZzKGV2ZW50U3RvcmUsIGZ1bmN0aW9uIChldmVudERlZikge1xuICAgICAgICAgICAgICAgIHJldHVybiBldmVudERlZi5kZWZJZCAhPT0gYWN0aW9uLmRlZklkO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIGNhc2UgJ1JFTU9WRV9FVkVOVF9TT1VSQ0UnOlxuICAgICAgICAgICAgcmV0dXJuIGV4Y2x1ZGVFdmVudHNCeVNvdXJjZUlkKGV2ZW50U3RvcmUsIGFjdGlvbi5zb3VyY2VJZCk7XG4gICAgICAgIGNhc2UgJ1JFTU9WRV9BTExfRVZFTlRfU09VUkNFUyc6XG4gICAgICAgICAgICByZXR1cm4gZmlsdGVyRXZlbnRTdG9yZURlZnMoZXZlbnRTdG9yZSwgZnVuY3Rpb24gKGV2ZW50RGVmKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICFldmVudERlZi5zb3VyY2VJZDsgLy8gb25seSBrZWVwIGV2ZW50cyB3aXRoIG5vIHNvdXJjZSBpZFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIGNhc2UgJ1JFTU9WRV9BTExfRVZFTlRTJzpcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVFbXB0eUV2ZW50U3RvcmUoKTtcbiAgICAgICAgY2FzZSAnUkVTRVRfRVZFTlRTJzpcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgZGVmczogZXZlbnRTdG9yZS5kZWZzLFxuICAgICAgICAgICAgICAgIGluc3RhbmNlczogZXZlbnRTdG9yZS5pbnN0YW5jZXNcbiAgICAgICAgICAgIH07XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICByZXR1cm4gZXZlbnRTdG9yZTtcbiAgICB9XG59XG5mdW5jdGlvbiByZWNlaXZlUmF3RXZlbnRzKGV2ZW50U3RvcmUsIGV2ZW50U291cmNlLCBmZXRjaElkLCBmZXRjaFJhbmdlLCByYXdFdmVudHMsIGNhbGVuZGFyKSB7XG4gICAgaWYgKGV2ZW50U291cmNlICYmIC8vIG5vdCBhbHJlYWR5IHJlbW92ZWRcbiAgICAgICAgZmV0Y2hJZCA9PT0gZXZlbnRTb3VyY2UubGF0ZXN0RmV0Y2hJZCAvLyBUT0RPOiB3aXNoIHRoaXMgbG9naWMgd2FzIGFsd2F5cyBpbiBldmVudC1zb3VyY2VzXG4gICAgKSB7XG4gICAgICAgIHZhciBzdWJzZXQgPSBwYXJzZUV2ZW50cyh0cmFuc2Zvcm1SYXdFdmVudHMocmF3RXZlbnRzLCBldmVudFNvdXJjZSwgY2FsZW5kYXIpLCBldmVudFNvdXJjZS5zb3VyY2VJZCwgY2FsZW5kYXIpO1xuICAgICAgICBpZiAoZmV0Y2hSYW5nZSkge1xuICAgICAgICAgICAgc3Vic2V0ID0gZXhwYW5kUmVjdXJyaW5nKHN1YnNldCwgZmV0Y2hSYW5nZSwgY2FsZW5kYXIpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBtZXJnZUV2ZW50U3RvcmVzKGV4Y2x1ZGVFdmVudHNCeVNvdXJjZUlkKGV2ZW50U3RvcmUsIGV2ZW50U291cmNlLnNvdXJjZUlkKSwgc3Vic2V0KTtcbiAgICB9XG4gICAgcmV0dXJuIGV2ZW50U3RvcmU7XG59XG5mdW5jdGlvbiBhZGRFdmVudChldmVudFN0b3JlLCBzdWJzZXQsIGV4cGFuZFJhbmdlLCBjYWxlbmRhcikge1xuICAgIGlmIChleHBhbmRSYW5nZSkge1xuICAgICAgICBzdWJzZXQgPSBleHBhbmRSZWN1cnJpbmcoc3Vic2V0LCBleHBhbmRSYW5nZSwgY2FsZW5kYXIpO1xuICAgIH1cbiAgICByZXR1cm4gbWVyZ2VFdmVudFN0b3JlcyhldmVudFN0b3JlLCBzdWJzZXQpO1xufVxuZnVuY3Rpb24gcmV6b25lRGF0ZXMoZXZlbnRTdG9yZSwgb2xkRGF0ZUVudiwgbmV3RGF0ZUVudikge1xuICAgIHZhciBkZWZzID0gZXZlbnRTdG9yZS5kZWZzO1xuICAgIHZhciBpbnN0YW5jZXMgPSBtYXBIYXNoKGV2ZW50U3RvcmUuaW5zdGFuY2VzLCBmdW5jdGlvbiAoaW5zdGFuY2UpIHtcbiAgICAgICAgdmFyIGRlZiA9IGRlZnNbaW5zdGFuY2UuZGVmSWRdO1xuICAgICAgICBpZiAoZGVmLmFsbERheSB8fCBkZWYucmVjdXJyaW5nRGVmKSB7XG4gICAgICAgICAgICByZXR1cm4gaW5zdGFuY2U7IC8vIGlzbid0IGRlcGVuZGVudCBvbiB0aW1lem9uZVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIF9fYXNzaWduKHt9LCBpbnN0YW5jZSwgeyByYW5nZToge1xuICAgICAgICAgICAgICAgICAgICBzdGFydDogbmV3RGF0ZUVudi5jcmVhdGVNYXJrZXIob2xkRGF0ZUVudi50b0RhdGUoaW5zdGFuY2UucmFuZ2Uuc3RhcnQsIGluc3RhbmNlLmZvcmNlZFN0YXJ0VHpvKSksXG4gICAgICAgICAgICAgICAgICAgIGVuZDogbmV3RGF0ZUVudi5jcmVhdGVNYXJrZXIob2xkRGF0ZUVudi50b0RhdGUoaW5zdGFuY2UucmFuZ2UuZW5kLCBpbnN0YW5jZS5mb3JjZWRFbmRUem8pKVxuICAgICAgICAgICAgICAgIH0sIGZvcmNlZFN0YXJ0VHpvOiBuZXdEYXRlRW52LmNhbkNvbXB1dGVPZmZzZXQgPyBudWxsIDogaW5zdGFuY2UuZm9yY2VkU3RhcnRUem8sIGZvcmNlZEVuZFR6bzogbmV3RGF0ZUVudi5jYW5Db21wdXRlT2Zmc2V0ID8gbnVsbCA6IGluc3RhbmNlLmZvcmNlZEVuZFR6byB9KTtcbiAgICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiB7IGRlZnM6IGRlZnMsIGluc3RhbmNlczogaW5zdGFuY2VzIH07XG59XG5mdW5jdGlvbiBhcHBseU11dGF0aW9uVG9SZWxhdGVkKGV2ZW50U3RvcmUsIGluc3RhbmNlSWQsIG11dGF0aW9uLCBmcm9tQXBpLCBjYWxlbmRhcikge1xuICAgIHZhciByZWxldmFudCA9IGdldFJlbGV2YW50RXZlbnRzKGV2ZW50U3RvcmUsIGluc3RhbmNlSWQpO1xuICAgIHZhciBldmVudENvbmZpZ0Jhc2UgPSBmcm9tQXBpID9cbiAgICAgICAgeyAnJzoge1xuICAgICAgICAgICAgICAgIHN0YXJ0RWRpdGFibGU6IHRydWUsXG4gICAgICAgICAgICAgICAgZHVyYXRpb25FZGl0YWJsZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICBjb25zdHJhaW50czogW10sXG4gICAgICAgICAgICAgICAgb3ZlcmxhcDogbnVsbCxcbiAgICAgICAgICAgICAgICBhbGxvd3M6IFtdLFxuICAgICAgICAgICAgICAgIGJhY2tncm91bmRDb2xvcjogJycsXG4gICAgICAgICAgICAgICAgYm9yZGVyQ29sb3I6ICcnLFxuICAgICAgICAgICAgICAgIHRleHRDb2xvcjogJycsXG4gICAgICAgICAgICAgICAgY2xhc3NOYW1lczogW11cbiAgICAgICAgICAgIH0gfSA6XG4gICAgICAgIGNhbGVuZGFyLmV2ZW50VWlCYXNlcztcbiAgICByZWxldmFudCA9IGFwcGx5TXV0YXRpb25Ub0V2ZW50U3RvcmUocmVsZXZhbnQsIGV2ZW50Q29uZmlnQmFzZSwgbXV0YXRpb24sIGNhbGVuZGFyKTtcbiAgICByZXR1cm4gbWVyZ2VFdmVudFN0b3JlcyhldmVudFN0b3JlLCByZWxldmFudCk7XG59XG5mdW5jdGlvbiBleGNsdWRlRXZlbnRzQnlTb3VyY2VJZChldmVudFN0b3JlLCBzb3VyY2VJZCkge1xuICAgIHJldHVybiBmaWx0ZXJFdmVudFN0b3JlRGVmcyhldmVudFN0b3JlLCBmdW5jdGlvbiAoZXZlbnREZWYpIHtcbiAgICAgICAgcmV0dXJuIGV2ZW50RGVmLnNvdXJjZUlkICE9PSBzb3VyY2VJZDtcbiAgICB9KTtcbn1cbi8vIFFVRVNUSU9OOiB3aHkgbm90IGp1c3QgcmV0dXJuIGluc3RhbmNlcz8gZG8gYSBnZW5lcmFsIG9iamVjdC1wcm9wZXJ0eS1leGNsdXNpb24gdXRpbFxuZnVuY3Rpb24gZXhjbHVkZUluc3RhbmNlcyhldmVudFN0b3JlLCByZW1vdmFscykge1xuICAgIHJldHVybiB7XG4gICAgICAgIGRlZnM6IGV2ZW50U3RvcmUuZGVmcyxcbiAgICAgICAgaW5zdGFuY2VzOiBmaWx0ZXJIYXNoKGV2ZW50U3RvcmUuaW5zdGFuY2VzLCBmdW5jdGlvbiAoaW5zdGFuY2UpIHtcbiAgICAgICAgICAgIHJldHVybiAhcmVtb3ZhbHNbaW5zdGFuY2UuaW5zdGFuY2VJZF07XG4gICAgICAgIH0pXG4gICAgfTtcbn1cblxuLy8gaGlnaC1sZXZlbCBzZWdtZW50aW5nLWF3YXJlIHRlc3RlciBmdW5jdGlvbnNcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuZnVuY3Rpb24gaXNJbnRlcmFjdGlvblZhbGlkKGludGVyYWN0aW9uLCBjYWxlbmRhcikge1xuICAgIHJldHVybiBpc05ld1Byb3BzVmFsaWQoeyBldmVudERyYWc6IGludGVyYWN0aW9uIH0sIGNhbGVuZGFyKTsgLy8gSEFDSzogdGhlIGV2ZW50RHJhZyBwcm9wcyBpcyB1c2VkIGZvciBBTEwgaW50ZXJhY3Rpb25zXG59XG5mdW5jdGlvbiBpc0RhdGVTZWxlY3Rpb25WYWxpZChkYXRlU2VsZWN0aW9uLCBjYWxlbmRhcikge1xuICAgIHJldHVybiBpc05ld1Byb3BzVmFsaWQoeyBkYXRlU2VsZWN0aW9uOiBkYXRlU2VsZWN0aW9uIH0sIGNhbGVuZGFyKTtcbn1cbmZ1bmN0aW9uIGlzTmV3UHJvcHNWYWxpZChuZXdQcm9wcywgY2FsZW5kYXIpIHtcbiAgICB2YXIgdmlldyA9IGNhbGVuZGFyLnZpZXc7XG4gICAgdmFyIHByb3BzID0gX19hc3NpZ24oeyBidXNpbmVzc0hvdXJzOiB2aWV3ID8gdmlldy5wcm9wcy5idXNpbmVzc0hvdXJzIDogY3JlYXRlRW1wdHlFdmVudFN0b3JlKCksIGRhdGVTZWxlY3Rpb246ICcnLCBldmVudFN0b3JlOiBjYWxlbmRhci5zdGF0ZS5ldmVudFN0b3JlLCBldmVudFVpQmFzZXM6IGNhbGVuZGFyLmV2ZW50VWlCYXNlcywgZXZlbnRTZWxlY3Rpb246ICcnLCBldmVudERyYWc6IG51bGwsIGV2ZW50UmVzaXplOiBudWxsIH0sIG5ld1Byb3BzKTtcbiAgICByZXR1cm4gKGNhbGVuZGFyLnBsdWdpblN5c3RlbS5ob29rcy5pc1Byb3BzVmFsaWQgfHwgaXNQcm9wc1ZhbGlkKShwcm9wcywgY2FsZW5kYXIpO1xufVxuZnVuY3Rpb24gaXNQcm9wc1ZhbGlkKHN0YXRlLCBjYWxlbmRhciwgZGF0ZVNwYW5NZXRhLCBmaWx0ZXJDb25maWcpIHtcbiAgICBpZiAoZGF0ZVNwYW5NZXRhID09PSB2b2lkIDApIHsgZGF0ZVNwYW5NZXRhID0ge307IH1cbiAgICBpZiAoc3RhdGUuZXZlbnREcmFnICYmICFpc0ludGVyYWN0aW9uUHJvcHNWYWxpZChzdGF0ZSwgY2FsZW5kYXIsIGRhdGVTcGFuTWV0YSwgZmlsdGVyQ29uZmlnKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmIChzdGF0ZS5kYXRlU2VsZWN0aW9uICYmICFpc0RhdGVTZWxlY3Rpb25Qcm9wc1ZhbGlkKHN0YXRlLCBjYWxlbmRhciwgZGF0ZVNwYW5NZXRhLCBmaWx0ZXJDb25maWcpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG59XG4vLyBNb3ZpbmcgRXZlbnQgVmFsaWRhdGlvblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5mdW5jdGlvbiBpc0ludGVyYWN0aW9uUHJvcHNWYWxpZChzdGF0ZSwgY2FsZW5kYXIsIGRhdGVTcGFuTWV0YSwgZmlsdGVyQ29uZmlnKSB7XG4gICAgdmFyIGludGVyYWN0aW9uID0gc3RhdGUuZXZlbnREcmFnOyAvLyBIQUNLOiB0aGUgZXZlbnREcmFnIHByb3BzIGlzIHVzZWQgZm9yIEFMTCBpbnRlcmFjdGlvbnNcbiAgICB2YXIgc3ViamVjdEV2ZW50U3RvcmUgPSBpbnRlcmFjdGlvbi5tdXRhdGVkRXZlbnRzO1xuICAgIHZhciBzdWJqZWN0RGVmcyA9IHN1YmplY3RFdmVudFN0b3JlLmRlZnM7XG4gICAgdmFyIHN1YmplY3RJbnN0YW5jZXMgPSBzdWJqZWN0RXZlbnRTdG9yZS5pbnN0YW5jZXM7XG4gICAgdmFyIHN1YmplY3RDb25maWdzID0gY29tcGlsZUV2ZW50VWlzKHN1YmplY3REZWZzLCBpbnRlcmFjdGlvbi5pc0V2ZW50ID9cbiAgICAgICAgc3RhdGUuZXZlbnRVaUJhc2VzIDpcbiAgICAgICAgeyAnJzogY2FsZW5kYXIuc2VsZWN0aW9uQ29uZmlnIH0gLy8gaWYgbm90IGEgcmVhbCBldmVudCwgdmFsaWRhdGUgYXMgYSBzZWxlY3Rpb25cbiAgICApO1xuICAgIGlmIChmaWx0ZXJDb25maWcpIHtcbiAgICAgICAgc3ViamVjdENvbmZpZ3MgPSBtYXBIYXNoKHN1YmplY3RDb25maWdzLCBmaWx0ZXJDb25maWcpO1xuICAgIH1cbiAgICB2YXIgb3RoZXJFdmVudFN0b3JlID0gZXhjbHVkZUluc3RhbmNlcyhzdGF0ZS5ldmVudFN0b3JlLCBpbnRlcmFjdGlvbi5hZmZlY3RlZEV2ZW50cy5pbnN0YW5jZXMpOyAvLyBleGNsdWRlIHRoZSBzdWJqZWN0IGV2ZW50cy4gVE9ETzogZXhjbHVkZSBkZWZzIHRvbz9cbiAgICB2YXIgb3RoZXJEZWZzID0gb3RoZXJFdmVudFN0b3JlLmRlZnM7XG4gICAgdmFyIG90aGVySW5zdGFuY2VzID0gb3RoZXJFdmVudFN0b3JlLmluc3RhbmNlcztcbiAgICB2YXIgb3RoZXJDb25maWdzID0gY29tcGlsZUV2ZW50VWlzKG90aGVyRGVmcywgc3RhdGUuZXZlbnRVaUJhc2VzKTtcbiAgICBmb3IgKHZhciBzdWJqZWN0SW5zdGFuY2VJZCBpbiBzdWJqZWN0SW5zdGFuY2VzKSB7XG4gICAgICAgIHZhciBzdWJqZWN0SW5zdGFuY2UgPSBzdWJqZWN0SW5zdGFuY2VzW3N1YmplY3RJbnN0YW5jZUlkXTtcbiAgICAgICAgdmFyIHN1YmplY3RSYW5nZSA9IHN1YmplY3RJbnN0YW5jZS5yYW5nZTtcbiAgICAgICAgdmFyIHN1YmplY3RDb25maWcgPSBzdWJqZWN0Q29uZmlnc1tzdWJqZWN0SW5zdGFuY2UuZGVmSWRdO1xuICAgICAgICB2YXIgc3ViamVjdERlZiA9IHN1YmplY3REZWZzW3N1YmplY3RJbnN0YW5jZS5kZWZJZF07XG4gICAgICAgIC8vIGNvbnN0cmFpbnRcbiAgICAgICAgaWYgKCFhbGxDb25zdHJhaW50c1Bhc3Moc3ViamVjdENvbmZpZy5jb25zdHJhaW50cywgc3ViamVjdFJhbmdlLCBvdGhlckV2ZW50U3RvcmUsIHN0YXRlLmJ1c2luZXNzSG91cnMsIGNhbGVuZGFyKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIC8vIG92ZXJsYXBcbiAgICAgICAgdmFyIG92ZXJsYXBGdW5jID0gY2FsZW5kYXIub3B0KCdldmVudE92ZXJsYXAnKTtcbiAgICAgICAgaWYgKHR5cGVvZiBvdmVybGFwRnVuYyAhPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgb3ZlcmxhcEZ1bmMgPSBudWxsO1xuICAgICAgICB9XG4gICAgICAgIGZvciAodmFyIG90aGVySW5zdGFuY2VJZCBpbiBvdGhlckluc3RhbmNlcykge1xuICAgICAgICAgICAgdmFyIG90aGVySW5zdGFuY2UgPSBvdGhlckluc3RhbmNlc1tvdGhlckluc3RhbmNlSWRdO1xuICAgICAgICAgICAgLy8gaW50ZXJzZWN0ISBldmFsdWF0ZVxuICAgICAgICAgICAgaWYgKHJhbmdlc0ludGVyc2VjdChzdWJqZWN0UmFuZ2UsIG90aGVySW5zdGFuY2UucmFuZ2UpKSB7XG4gICAgICAgICAgICAgICAgdmFyIG90aGVyT3ZlcmxhcCA9IG90aGVyQ29uZmlnc1tvdGhlckluc3RhbmNlLmRlZklkXS5vdmVybGFwO1xuICAgICAgICAgICAgICAgIC8vIGNvbnNpZGVyIHRoZSBvdGhlciBldmVudCdzIG92ZXJsYXAuIG9ubHkgZG8gdGhpcyBpZiB0aGUgc3ViamVjdCBldmVudCBpcyBhIFwicmVhbFwiIGV2ZW50XG4gICAgICAgICAgICAgICAgaWYgKG90aGVyT3ZlcmxhcCA9PT0gZmFsc2UgJiYgaW50ZXJhY3Rpb24uaXNFdmVudCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChzdWJqZWN0Q29uZmlnLm92ZXJsYXAgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKG92ZXJsYXBGdW5jICYmICFvdmVybGFwRnVuYyhuZXcgRXZlbnRBcGkoY2FsZW5kYXIsIG90aGVyRGVmc1tvdGhlckluc3RhbmNlLmRlZklkXSwgb3RoZXJJbnN0YW5jZSksIC8vIHN0aWxsIGV2ZW50XG4gICAgICAgICAgICAgICAgbmV3IEV2ZW50QXBpKGNhbGVuZGFyLCBzdWJqZWN0RGVmLCBzdWJqZWN0SW5zdGFuY2UpIC8vIG1vdmluZyBldmVudFxuICAgICAgICAgICAgICAgICkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvLyBhbGxvdyAoYSBmdW5jdGlvbilcbiAgICAgICAgdmFyIGNhbGVuZGFyRXZlbnRTdG9yZSA9IGNhbGVuZGFyLnN0YXRlLmV2ZW50U3RvcmU7IC8vIG5lZWQgZ2xvYmFsLXRvLWNhbGVuZGFyLCBub3QgbG9jYWwgdG8gY29tcG9uZW50IChzcGxpdHRhYmxlKXN0YXRlXG4gICAgICAgIGZvciAodmFyIF9pID0gMCwgX2EgPSBzdWJqZWN0Q29uZmlnLmFsbG93czsgX2kgPCBfYS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIHZhciBzdWJqZWN0QWxsb3cgPSBfYVtfaV07XG4gICAgICAgICAgICB2YXIgc3ViamVjdERhdGVTcGFuID0gX19hc3NpZ24oe30sIGRhdGVTcGFuTWV0YSwgeyByYW5nZTogc3ViamVjdEluc3RhbmNlLnJhbmdlLCBhbGxEYXk6IHN1YmplY3REZWYuYWxsRGF5IH0pO1xuICAgICAgICAgICAgdmFyIG9yaWdEZWYgPSBjYWxlbmRhckV2ZW50U3RvcmUuZGVmc1tzdWJqZWN0RGVmLmRlZklkXTtcbiAgICAgICAgICAgIHZhciBvcmlnSW5zdGFuY2UgPSBjYWxlbmRhckV2ZW50U3RvcmUuaW5zdGFuY2VzW3N1YmplY3RJbnN0YW5jZUlkXTtcbiAgICAgICAgICAgIHZhciBldmVudEFwaSA9IHZvaWQgMDtcbiAgICAgICAgICAgIGlmIChvcmlnRGVmKSB7IC8vIHdhcyBwcmV2aW91c2x5IGluIHRoZSBjYWxlbmRhclxuICAgICAgICAgICAgICAgIGV2ZW50QXBpID0gbmV3IEV2ZW50QXBpKGNhbGVuZGFyLCBvcmlnRGVmLCBvcmlnSW5zdGFuY2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7IC8vIHdhcyBhbiBleHRlcm5hbCBldmVudFxuICAgICAgICAgICAgICAgIGV2ZW50QXBpID0gbmV3IEV2ZW50QXBpKGNhbGVuZGFyLCBzdWJqZWN0RGVmKTsgLy8gbm8gaW5zdGFuY2UsIGJlY2F1c2UgaGFkIG5vIGRhdGVzXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIXN1YmplY3RBbGxvdyhjYWxlbmRhci5idWlsZERhdGVTcGFuQXBpKHN1YmplY3REYXRlU3BhbiksIGV2ZW50QXBpKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn1cbi8vIERhdGUgU2VsZWN0aW9uIFZhbGlkYXRpb25cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuZnVuY3Rpb24gaXNEYXRlU2VsZWN0aW9uUHJvcHNWYWxpZChzdGF0ZSwgY2FsZW5kYXIsIGRhdGVTcGFuTWV0YSwgZmlsdGVyQ29uZmlnKSB7XG4gICAgdmFyIHJlbGV2YW50RXZlbnRTdG9yZSA9IHN0YXRlLmV2ZW50U3RvcmU7XG4gICAgdmFyIHJlbGV2YW50RGVmcyA9IHJlbGV2YW50RXZlbnRTdG9yZS5kZWZzO1xuICAgIHZhciByZWxldmFudEluc3RhbmNlcyA9IHJlbGV2YW50RXZlbnRTdG9yZS5pbnN0YW5jZXM7XG4gICAgdmFyIHNlbGVjdGlvbiA9IHN0YXRlLmRhdGVTZWxlY3Rpb247XG4gICAgdmFyIHNlbGVjdGlvblJhbmdlID0gc2VsZWN0aW9uLnJhbmdlO1xuICAgIHZhciBzZWxlY3Rpb25Db25maWcgPSBjYWxlbmRhci5zZWxlY3Rpb25Db25maWc7XG4gICAgaWYgKGZpbHRlckNvbmZpZykge1xuICAgICAgICBzZWxlY3Rpb25Db25maWcgPSBmaWx0ZXJDb25maWcoc2VsZWN0aW9uQ29uZmlnKTtcbiAgICB9XG4gICAgLy8gY29uc3RyYWludFxuICAgIGlmICghYWxsQ29uc3RyYWludHNQYXNzKHNlbGVjdGlvbkNvbmZpZy5jb25zdHJhaW50cywgc2VsZWN0aW9uUmFuZ2UsIHJlbGV2YW50RXZlbnRTdG9yZSwgc3RhdGUuYnVzaW5lc3NIb3VycywgY2FsZW5kYXIpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgLy8gb3ZlcmxhcFxuICAgIHZhciBvdmVybGFwRnVuYyA9IGNhbGVuZGFyLm9wdCgnc2VsZWN0T3ZlcmxhcCcpO1xuICAgIGlmICh0eXBlb2Ygb3ZlcmxhcEZ1bmMgIT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgb3ZlcmxhcEZ1bmMgPSBudWxsO1xuICAgIH1cbiAgICBmb3IgKHZhciByZWxldmFudEluc3RhbmNlSWQgaW4gcmVsZXZhbnRJbnN0YW5jZXMpIHtcbiAgICAgICAgdmFyIHJlbGV2YW50SW5zdGFuY2UgPSByZWxldmFudEluc3RhbmNlc1tyZWxldmFudEluc3RhbmNlSWRdO1xuICAgICAgICAvLyBpbnRlcnNlY3QhIGV2YWx1YXRlXG4gICAgICAgIGlmIChyYW5nZXNJbnRlcnNlY3Qoc2VsZWN0aW9uUmFuZ2UsIHJlbGV2YW50SW5zdGFuY2UucmFuZ2UpKSB7XG4gICAgICAgICAgICBpZiAoc2VsZWN0aW9uQ29uZmlnLm92ZXJsYXAgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG92ZXJsYXBGdW5jICYmICFvdmVybGFwRnVuYyhuZXcgRXZlbnRBcGkoY2FsZW5kYXIsIHJlbGV2YW50RGVmc1tyZWxldmFudEluc3RhbmNlLmRlZklkXSwgcmVsZXZhbnRJbnN0YW5jZSkpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIC8vIGFsbG93IChhIGZ1bmN0aW9uKVxuICAgIGZvciAodmFyIF9pID0gMCwgX2EgPSBzZWxlY3Rpb25Db25maWcuYWxsb3dzOyBfaSA8IF9hLmxlbmd0aDsgX2krKykge1xuICAgICAgICB2YXIgc2VsZWN0aW9uQWxsb3cgPSBfYVtfaV07XG4gICAgICAgIHZhciBmdWxsRGF0ZVNwYW4gPSBfX2Fzc2lnbih7fSwgZGF0ZVNwYW5NZXRhLCBzZWxlY3Rpb24pO1xuICAgICAgICBpZiAoIXNlbGVjdGlvbkFsbG93KGNhbGVuZGFyLmJ1aWxkRGF0ZVNwYW5BcGkoZnVsbERhdGVTcGFuKSwgbnVsbCkpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn1cbi8vIENvbnN0cmFpbnQgVXRpbHNcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuZnVuY3Rpb24gYWxsQ29uc3RyYWludHNQYXNzKGNvbnN0cmFpbnRzLCBzdWJqZWN0UmFuZ2UsIG90aGVyRXZlbnRTdG9yZSwgYnVzaW5lc3NIb3Vyc1VuZXhwYW5kZWQsIGNhbGVuZGFyKSB7XG4gICAgZm9yICh2YXIgX2kgPSAwLCBjb25zdHJhaW50c18xID0gY29uc3RyYWludHM7IF9pIDwgY29uc3RyYWludHNfMS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgdmFyIGNvbnN0cmFpbnQgPSBjb25zdHJhaW50c18xW19pXTtcbiAgICAgICAgaWYgKCFhbnlSYW5nZXNDb250YWluUmFuZ2UoY29uc3RyYWludFRvUmFuZ2VzKGNvbnN0cmFpbnQsIHN1YmplY3RSYW5nZSwgb3RoZXJFdmVudFN0b3JlLCBidXNpbmVzc0hvdXJzVW5leHBhbmRlZCwgY2FsZW5kYXIpLCBzdWJqZWN0UmFuZ2UpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG59XG5mdW5jdGlvbiBjb25zdHJhaW50VG9SYW5nZXMoY29uc3RyYWludCwgc3ViamVjdFJhbmdlLCAvLyBmb3IgZXhwYW5kaW5nIGEgcmVjdXJyaW5nIGNvbnN0cmFpbnQsIG9yIGV4cGFuZGluZyBidXNpbmVzcyBob3Vyc1xub3RoZXJFdmVudFN0b3JlLCAvLyBmb3IgaWYgY29uc3RyYWludCBpcyBhbiBldmVuIGdyb3VwIElEXG5idXNpbmVzc0hvdXJzVW5leHBhbmRlZCwgLy8gZm9yIGlmIGNvbnN0cmFpbnQgaXMgJ2J1c2luZXNzSG91cnMnXG5jYWxlbmRhciAvLyBmb3IgZXhwYW5kaW5nIGJ1c2luZXNzaG91cnNcbikge1xuICAgIGlmIChjb25zdHJhaW50ID09PSAnYnVzaW5lc3NIb3VycycpIHtcbiAgICAgICAgcmV0dXJuIGV2ZW50U3RvcmVUb1JhbmdlcyhleHBhbmRSZWN1cnJpbmcoYnVzaW5lc3NIb3Vyc1VuZXhwYW5kZWQsIHN1YmplY3RSYW5nZSwgY2FsZW5kYXIpKTtcbiAgICB9XG4gICAgZWxzZSBpZiAodHlwZW9mIGNvbnN0cmFpbnQgPT09ICdzdHJpbmcnKSB7IC8vIGFuIGdyb3VwIElEXG4gICAgICAgIHJldHVybiBldmVudFN0b3JlVG9SYW5nZXMoZmlsdGVyRXZlbnRTdG9yZURlZnMob3RoZXJFdmVudFN0b3JlLCBmdW5jdGlvbiAoZXZlbnREZWYpIHtcbiAgICAgICAgICAgIHJldHVybiBldmVudERlZi5ncm91cElkID09PSBjb25zdHJhaW50O1xuICAgICAgICB9KSk7XG4gICAgfVxuICAgIGVsc2UgaWYgKHR5cGVvZiBjb25zdHJhaW50ID09PSAnb2JqZWN0JyAmJiBjb25zdHJhaW50KSB7IC8vIG5vbi1udWxsIG9iamVjdFxuICAgICAgICByZXR1cm4gZXZlbnRTdG9yZVRvUmFuZ2VzKGV4cGFuZFJlY3VycmluZyhjb25zdHJhaW50LCBzdWJqZWN0UmFuZ2UsIGNhbGVuZGFyKSk7XG4gICAgfVxuICAgIHJldHVybiBbXTsgLy8gaWYgaXQncyBmYWxzZVxufVxuLy8gVE9ETzogbW92ZSB0byBldmVudC1zdG9yZSBmaWxlP1xuZnVuY3Rpb24gZXZlbnRTdG9yZVRvUmFuZ2VzKGV2ZW50U3RvcmUpIHtcbiAgICB2YXIgaW5zdGFuY2VzID0gZXZlbnRTdG9yZS5pbnN0YW5jZXM7XG4gICAgdmFyIHJhbmdlcyA9IFtdO1xuICAgIGZvciAodmFyIGluc3RhbmNlSWQgaW4gaW5zdGFuY2VzKSB7XG4gICAgICAgIHJhbmdlcy5wdXNoKGluc3RhbmNlc1tpbnN0YW5jZUlkXS5yYW5nZSk7XG4gICAgfVxuICAgIHJldHVybiByYW5nZXM7XG59XG4vLyBUT0RPOiBtb3ZlIHRvIGdlb20gZmlsZT9cbmZ1bmN0aW9uIGFueVJhbmdlc0NvbnRhaW5SYW5nZShvdXRlclJhbmdlcywgaW5uZXJSYW5nZSkge1xuICAgIGZvciAodmFyIF9pID0gMCwgb3V0ZXJSYW5nZXNfMSA9IG91dGVyUmFuZ2VzOyBfaSA8IG91dGVyUmFuZ2VzXzEubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgIHZhciBvdXRlclJhbmdlID0gb3V0ZXJSYW5nZXNfMVtfaV07XG4gICAgICAgIGlmIChyYW5nZUNvbnRhaW5zUmFuZ2Uob3V0ZXJSYW5nZSwgaW5uZXJSYW5nZSkpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbn1cbi8vIFBhcnNpbmdcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuZnVuY3Rpb24gbm9ybWFsaXplQ29uc3RyYWludChpbnB1dCwgY2FsZW5kYXIpIHtcbiAgICBpZiAoQXJyYXkuaXNBcnJheShpbnB1dCkpIHtcbiAgICAgICAgcmV0dXJuIHBhcnNlRXZlbnRzKGlucHV0LCAnJywgY2FsZW5kYXIsIHRydWUpOyAvLyBhbGxvd09wZW5SYW5nZT10cnVlXG4gICAgfVxuICAgIGVsc2UgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ29iamVjdCcgJiYgaW5wdXQpIHsgLy8gbm9uLW51bGwgb2JqZWN0XG4gICAgICAgIHJldHVybiBwYXJzZUV2ZW50cyhbaW5wdXRdLCAnJywgY2FsZW5kYXIsIHRydWUpOyAvLyBhbGxvd09wZW5SYW5nZT10cnVlXG4gICAgfVxuICAgIGVsc2UgaWYgKGlucHV0ICE9IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIFN0cmluZyhpbnB1dCk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGh0bWxFc2NhcGUocykge1xuICAgIHJldHVybiAocyArICcnKS5yZXBsYWNlKC8mL2csICcmYW1wOycpXG4gICAgICAgIC5yZXBsYWNlKC88L2csICcmbHQ7JylcbiAgICAgICAgLnJlcGxhY2UoLz4vZywgJyZndDsnKVxuICAgICAgICAucmVwbGFjZSgvJy9nLCAnJiMwMzk7JylcbiAgICAgICAgLnJlcGxhY2UoL1wiL2csICcmcXVvdDsnKVxuICAgICAgICAucmVwbGFjZSgvXFxuL2csICc8YnIgLz4nKTtcbn1cbi8vIEdpdmVuIGEgaGFzaCBvZiBDU1MgcHJvcGVydGllcywgcmV0dXJucyBhIHN0cmluZyBvZiBDU1MuXG4vLyBVc2VzIHByb3BlcnR5IG5hbWVzIGFzLWlzIChubyBjYW1lbC1jYXNlIGNvbnZlcnNpb24pLiBXaWxsIG5vdCBtYWtlIHN0YXRlbWVudHMgZm9yIG51bGwvdW5kZWZpbmVkIHZhbHVlcy5cbmZ1bmN0aW9uIGNzc1RvU3RyKGNzc1Byb3BzKSB7XG4gICAgdmFyIHN0YXRlbWVudHMgPSBbXTtcbiAgICBmb3IgKHZhciBuYW1lXzEgaW4gY3NzUHJvcHMpIHtcbiAgICAgICAgdmFyIHZhbCA9IGNzc1Byb3BzW25hbWVfMV07XG4gICAgICAgIGlmICh2YWwgIT0gbnVsbCAmJiB2YWwgIT09ICcnKSB7XG4gICAgICAgICAgICBzdGF0ZW1lbnRzLnB1c2gobmFtZV8xICsgJzonICsgdmFsKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gc3RhdGVtZW50cy5qb2luKCc7Jyk7XG59XG4vLyBHaXZlbiBhbiBvYmplY3QgaGFzaCBvZiBIVE1MIGF0dHJpYnV0ZSBuYW1lcyB0byB2YWx1ZXMsXG4vLyBnZW5lcmF0ZXMgYSBzdHJpbmcgdGhhdCBjYW4gYmUgaW5qZWN0ZWQgYmV0d2VlbiA8ID4gaW4gSFRNTFxuZnVuY3Rpb24gYXR0cnNUb1N0cihhdHRycykge1xuICAgIHZhciBwYXJ0cyA9IFtdO1xuICAgIGZvciAodmFyIG5hbWVfMiBpbiBhdHRycykge1xuICAgICAgICB2YXIgdmFsID0gYXR0cnNbbmFtZV8yXTtcbiAgICAgICAgaWYgKHZhbCAhPSBudWxsKSB7XG4gICAgICAgICAgICBwYXJ0cy5wdXNoKG5hbWVfMiArICc9XCInICsgaHRtbEVzY2FwZSh2YWwpICsgJ1wiJyk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHBhcnRzLmpvaW4oJyAnKTtcbn1cbmZ1bmN0aW9uIHBhcnNlQ2xhc3NOYW1lKHJhdykge1xuICAgIGlmIChBcnJheS5pc0FycmF5KHJhdykpIHtcbiAgICAgICAgcmV0dXJuIHJhdztcbiAgICB9XG4gICAgZWxzZSBpZiAodHlwZW9mIHJhdyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgcmV0dXJuIHJhdy5zcGxpdCgvXFxzKy8pO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbn1cblxudmFyIFVOU0NPUEVEX0VWRU5UX1VJX1BST1BTID0ge1xuICAgIGVkaXRhYmxlOiBCb29sZWFuLFxuICAgIHN0YXJ0RWRpdGFibGU6IEJvb2xlYW4sXG4gICAgZHVyYXRpb25FZGl0YWJsZTogQm9vbGVhbixcbiAgICBjb25zdHJhaW50OiBudWxsLFxuICAgIG92ZXJsYXA6IG51bGwsXG4gICAgYWxsb3c6IG51bGwsXG4gICAgY2xhc3NOYW1lOiBwYXJzZUNsYXNzTmFtZSxcbiAgICBjbGFzc05hbWVzOiBwYXJzZUNsYXNzTmFtZSxcbiAgICBjb2xvcjogU3RyaW5nLFxuICAgIGJhY2tncm91bmRDb2xvcjogU3RyaW5nLFxuICAgIGJvcmRlckNvbG9yOiBTdHJpbmcsXG4gICAgdGV4dENvbG9yOiBTdHJpbmdcbn07XG5mdW5jdGlvbiBwcm9jZXNzVW5zY29wZWRVaVByb3BzKHJhd1Byb3BzLCBjYWxlbmRhciwgbGVmdG92ZXJzKSB7XG4gICAgdmFyIHByb3BzID0gcmVmaW5lUHJvcHMocmF3UHJvcHMsIFVOU0NPUEVEX0VWRU5UX1VJX1BST1BTLCB7fSwgbGVmdG92ZXJzKTtcbiAgICB2YXIgY29uc3RyYWludCA9IG5vcm1hbGl6ZUNvbnN0cmFpbnQocHJvcHMuY29uc3RyYWludCwgY2FsZW5kYXIpO1xuICAgIHJldHVybiB7XG4gICAgICAgIHN0YXJ0RWRpdGFibGU6IHByb3BzLnN0YXJ0RWRpdGFibGUgIT0gbnVsbCA/IHByb3BzLnN0YXJ0RWRpdGFibGUgOiBwcm9wcy5lZGl0YWJsZSxcbiAgICAgICAgZHVyYXRpb25FZGl0YWJsZTogcHJvcHMuZHVyYXRpb25FZGl0YWJsZSAhPSBudWxsID8gcHJvcHMuZHVyYXRpb25FZGl0YWJsZSA6IHByb3BzLmVkaXRhYmxlLFxuICAgICAgICBjb25zdHJhaW50czogY29uc3RyYWludCAhPSBudWxsID8gW2NvbnN0cmFpbnRdIDogW10sXG4gICAgICAgIG92ZXJsYXA6IHByb3BzLm92ZXJsYXAsXG4gICAgICAgIGFsbG93czogcHJvcHMuYWxsb3cgIT0gbnVsbCA/IFtwcm9wcy5hbGxvd10gOiBbXSxcbiAgICAgICAgYmFja2dyb3VuZENvbG9yOiBwcm9wcy5iYWNrZ3JvdW5kQ29sb3IgfHwgcHJvcHMuY29sb3IsXG4gICAgICAgIGJvcmRlckNvbG9yOiBwcm9wcy5ib3JkZXJDb2xvciB8fCBwcm9wcy5jb2xvcixcbiAgICAgICAgdGV4dENvbG9yOiBwcm9wcy50ZXh0Q29sb3IsXG4gICAgICAgIGNsYXNzTmFtZXM6IHByb3BzLmNsYXNzTmFtZXMuY29uY2F0KHByb3BzLmNsYXNzTmFtZSlcbiAgICB9O1xufVxuZnVuY3Rpb24gcHJvY2Vzc1Njb3BlZFVpUHJvcHMocHJlZml4LCByYXdTY29wZWQsIGNhbGVuZGFyLCBsZWZ0b3ZlcnMpIHtcbiAgICB2YXIgcmF3VW5zY29wZWQgPSB7fTtcbiAgICB2YXIgd2FzRm91bmQgPSB7fTtcbiAgICBmb3IgKHZhciBrZXkgaW4gVU5TQ09QRURfRVZFTlRfVUlfUFJPUFMpIHtcbiAgICAgICAgdmFyIHNjb3BlZEtleSA9IHByZWZpeCArIGNhcGl0YWxpc2VGaXJzdExldHRlcihrZXkpO1xuICAgICAgICByYXdVbnNjb3BlZFtrZXldID0gcmF3U2NvcGVkW3Njb3BlZEtleV07XG4gICAgICAgIHdhc0ZvdW5kW3Njb3BlZEtleV0gPSB0cnVlO1xuICAgIH1cbiAgICBpZiAocHJlZml4ID09PSAnZXZlbnQnKSB7XG4gICAgICAgIHJhd1Vuc2NvcGVkLmVkaXRhYmxlID0gcmF3U2NvcGVkLmVkaXRhYmxlOyAvLyBzcGVjaWFsIGNhc2UuIHRoZXJlIGlzIG5vICdldmVudEVkaXRhYmxlJywganVzdCAnZWRpdGFibGUnXG4gICAgfVxuICAgIGlmIChsZWZ0b3ZlcnMpIHtcbiAgICAgICAgZm9yICh2YXIga2V5IGluIHJhd1Njb3BlZCkge1xuICAgICAgICAgICAgaWYgKCF3YXNGb3VuZFtrZXldKSB7XG4gICAgICAgICAgICAgICAgbGVmdG92ZXJzW2tleV0gPSByYXdTY29wZWRba2V5XTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcHJvY2Vzc1Vuc2NvcGVkVWlQcm9wcyhyYXdVbnNjb3BlZCwgY2FsZW5kYXIpO1xufVxudmFyIEVNUFRZX0VWRU5UX1VJID0ge1xuICAgIHN0YXJ0RWRpdGFibGU6IG51bGwsXG4gICAgZHVyYXRpb25FZGl0YWJsZTogbnVsbCxcbiAgICBjb25zdHJhaW50czogW10sXG4gICAgb3ZlcmxhcDogbnVsbCxcbiAgICBhbGxvd3M6IFtdLFxuICAgIGJhY2tncm91bmRDb2xvcjogJycsXG4gICAgYm9yZGVyQ29sb3I6ICcnLFxuICAgIHRleHRDb2xvcjogJycsXG4gICAgY2xhc3NOYW1lczogW11cbn07XG4vLyBwcmV2ZW50IGFnYWluc3QgcHJvYmxlbXMgd2l0aCA8MiBhcmdzIVxuZnVuY3Rpb24gY29tYmluZUV2ZW50VWlzKHVpcykge1xuICAgIHJldHVybiB1aXMucmVkdWNlKGNvbWJpbmVUd29FdmVudFVpcywgRU1QVFlfRVZFTlRfVUkpO1xufVxuZnVuY3Rpb24gY29tYmluZVR3b0V2ZW50VWlzKGl0ZW0wLCBpdGVtMSkge1xuICAgIHJldHVybiB7XG4gICAgICAgIHN0YXJ0RWRpdGFibGU6IGl0ZW0xLnN0YXJ0RWRpdGFibGUgIT0gbnVsbCA/IGl0ZW0xLnN0YXJ0RWRpdGFibGUgOiBpdGVtMC5zdGFydEVkaXRhYmxlLFxuICAgICAgICBkdXJhdGlvbkVkaXRhYmxlOiBpdGVtMS5kdXJhdGlvbkVkaXRhYmxlICE9IG51bGwgPyBpdGVtMS5kdXJhdGlvbkVkaXRhYmxlIDogaXRlbTAuZHVyYXRpb25FZGl0YWJsZSxcbiAgICAgICAgY29uc3RyYWludHM6IGl0ZW0wLmNvbnN0cmFpbnRzLmNvbmNhdChpdGVtMS5jb25zdHJhaW50cyksXG4gICAgICAgIG92ZXJsYXA6IHR5cGVvZiBpdGVtMS5vdmVybGFwID09PSAnYm9vbGVhbicgPyBpdGVtMS5vdmVybGFwIDogaXRlbTAub3ZlcmxhcCxcbiAgICAgICAgYWxsb3dzOiBpdGVtMC5hbGxvd3MuY29uY2F0KGl0ZW0xLmFsbG93cyksXG4gICAgICAgIGJhY2tncm91bmRDb2xvcjogaXRlbTEuYmFja2dyb3VuZENvbG9yIHx8IGl0ZW0wLmJhY2tncm91bmRDb2xvcixcbiAgICAgICAgYm9yZGVyQ29sb3I6IGl0ZW0xLmJvcmRlckNvbG9yIHx8IGl0ZW0wLmJvcmRlckNvbG9yLFxuICAgICAgICB0ZXh0Q29sb3I6IGl0ZW0xLnRleHRDb2xvciB8fCBpdGVtMC50ZXh0Q29sb3IsXG4gICAgICAgIGNsYXNzTmFtZXM6IGl0ZW0wLmNsYXNzTmFtZXMuY29uY2F0KGl0ZW0xLmNsYXNzTmFtZXMpXG4gICAgfTtcbn1cblxudmFyIE5PTl9EQVRFX1BST1BTID0ge1xuICAgIGlkOiBTdHJpbmcsXG4gICAgZ3JvdXBJZDogU3RyaW5nLFxuICAgIHRpdGxlOiBTdHJpbmcsXG4gICAgdXJsOiBTdHJpbmcsXG4gICAgcmVuZGVyaW5nOiBTdHJpbmcsXG4gICAgZXh0ZW5kZWRQcm9wczogbnVsbFxufTtcbnZhciBEQVRFX1BST1BTID0ge1xuICAgIHN0YXJ0OiBudWxsLFxuICAgIGRhdGU6IG51bGwsXG4gICAgZW5kOiBudWxsLFxuICAgIGFsbERheTogbnVsbFxufTtcbnZhciB1aWQgPSAwO1xuZnVuY3Rpb24gcGFyc2VFdmVudChyYXcsIHNvdXJjZUlkLCBjYWxlbmRhciwgYWxsb3dPcGVuUmFuZ2UpIHtcbiAgICB2YXIgYWxsRGF5RGVmYXVsdCA9IGNvbXB1dGVJc0FsbERheURlZmF1bHQoc291cmNlSWQsIGNhbGVuZGFyKTtcbiAgICB2YXIgbGVmdG92ZXJzMCA9IHt9O1xuICAgIHZhciByZWN1cnJpbmdSZXMgPSBwYXJzZVJlY3VycmluZyhyYXcsIC8vIHJhdywgYnV0IHdpdGggc2luZ2xlLWV2ZW50IHN0dWZmIHN0cmlwcGVkIG91dFxuICAgIGFsbERheURlZmF1bHQsIGNhbGVuZGFyLmRhdGVFbnYsIGNhbGVuZGFyLnBsdWdpblN5c3RlbS5ob29rcy5yZWN1cnJpbmdUeXBlcywgbGVmdG92ZXJzMCAvLyB3aWxsIHBvcHVsYXRlIHdpdGggbm9uLXJlY3VycmluZyBwcm9wc1xuICAgICk7XG4gICAgaWYgKHJlY3VycmluZ1Jlcykge1xuICAgICAgICB2YXIgZGVmID0gcGFyc2VFdmVudERlZihsZWZ0b3ZlcnMwLCBzb3VyY2VJZCwgcmVjdXJyaW5nUmVzLmFsbERheSwgQm9vbGVhbihyZWN1cnJpbmdSZXMuZHVyYXRpb24pLCBjYWxlbmRhcik7XG4gICAgICAgIGRlZi5yZWN1cnJpbmdEZWYgPSB7XG4gICAgICAgICAgICB0eXBlSWQ6IHJlY3VycmluZ1Jlcy50eXBlSWQsXG4gICAgICAgICAgICB0eXBlRGF0YTogcmVjdXJyaW5nUmVzLnR5cGVEYXRhLFxuICAgICAgICAgICAgZHVyYXRpb246IHJlY3VycmluZ1Jlcy5kdXJhdGlvblxuICAgICAgICB9O1xuICAgICAgICByZXR1cm4geyBkZWY6IGRlZiwgaW5zdGFuY2U6IG51bGwgfTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHZhciBsZWZ0b3ZlcnMxID0ge307XG4gICAgICAgIHZhciBzaW5nbGVSZXMgPSBwYXJzZVNpbmdsZShyYXcsIGFsbERheURlZmF1bHQsIGNhbGVuZGFyLCBsZWZ0b3ZlcnMxLCBhbGxvd09wZW5SYW5nZSk7XG4gICAgICAgIGlmIChzaW5nbGVSZXMpIHtcbiAgICAgICAgICAgIHZhciBkZWYgPSBwYXJzZUV2ZW50RGVmKGxlZnRvdmVyczEsIHNvdXJjZUlkLCBzaW5nbGVSZXMuYWxsRGF5LCBzaW5nbGVSZXMuaGFzRW5kLCBjYWxlbmRhcik7XG4gICAgICAgICAgICB2YXIgaW5zdGFuY2UgPSBjcmVhdGVFdmVudEluc3RhbmNlKGRlZi5kZWZJZCwgc2luZ2xlUmVzLnJhbmdlLCBzaW5nbGVSZXMuZm9yY2VkU3RhcnRUem8sIHNpbmdsZVJlcy5mb3JjZWRFbmRUem8pO1xuICAgICAgICAgICAgcmV0dXJuIHsgZGVmOiBkZWYsIGluc3RhbmNlOiBpbnN0YW5jZSB9O1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufVxuLypcbldpbGwgTk9UIHBvcHVsYXRlIGV4dGVuZGVkUHJvcHMgd2l0aCB0aGUgbGVmdG92ZXIgcHJvcGVydGllcy5cbldpbGwgTk9UIHBvcHVsYXRlIGRhdGUtcmVsYXRlZCBwcm9wcy5cblRoZSBFdmVudE5vbkRhdGVJbnB1dCBoYXMgYmVlbiBub3JtYWxpemVkIChpZCA9PiBwdWJsaWNJZCwgZXRjKS5cbiovXG5mdW5jdGlvbiBwYXJzZUV2ZW50RGVmKHJhdywgc291cmNlSWQsIGFsbERheSwgaGFzRW5kLCBjYWxlbmRhcikge1xuICAgIHZhciBsZWZ0b3ZlcnMgPSB7fTtcbiAgICB2YXIgZGVmID0gcGx1Y2tOb25EYXRlUHJvcHMocmF3LCBjYWxlbmRhciwgbGVmdG92ZXJzKTtcbiAgICBkZWYuZGVmSWQgPSBTdHJpbmcodWlkKyspO1xuICAgIGRlZi5zb3VyY2VJZCA9IHNvdXJjZUlkO1xuICAgIGRlZi5hbGxEYXkgPSBhbGxEYXk7XG4gICAgZGVmLmhhc0VuZCA9IGhhc0VuZDtcbiAgICBmb3IgKHZhciBfaSA9IDAsIF9hID0gY2FsZW5kYXIucGx1Z2luU3lzdGVtLmhvb2tzLmV2ZW50RGVmUGFyc2VyczsgX2kgPCBfYS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgdmFyIGV2ZW50RGVmUGFyc2VyID0gX2FbX2ldO1xuICAgICAgICB2YXIgbmV3TGVmdG92ZXJzID0ge307XG4gICAgICAgIGV2ZW50RGVmUGFyc2VyKGRlZiwgbGVmdG92ZXJzLCBuZXdMZWZ0b3ZlcnMpO1xuICAgICAgICBsZWZ0b3ZlcnMgPSBuZXdMZWZ0b3ZlcnM7XG4gICAgfVxuICAgIGRlZi5leHRlbmRlZFByb3BzID0gX19hc3NpZ24obGVmdG92ZXJzLCBkZWYuZXh0ZW5kZWRQcm9wcyB8fCB7fSk7XG4gICAgLy8gaGVscCBvdXQgRXZlbnRBcGkgZnJvbSBoYXZpbmcgdXNlciBtb2RpZnkgcHJvcHNcbiAgICBPYmplY3QuZnJlZXplKGRlZi51aS5jbGFzc05hbWVzKTtcbiAgICBPYmplY3QuZnJlZXplKGRlZi5leHRlbmRlZFByb3BzKTtcbiAgICByZXR1cm4gZGVmO1xufVxuZnVuY3Rpb24gY3JlYXRlRXZlbnRJbnN0YW5jZShkZWZJZCwgcmFuZ2UsIGZvcmNlZFN0YXJ0VHpvLCBmb3JjZWRFbmRUem8pIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBpbnN0YW5jZUlkOiBTdHJpbmcodWlkKyspLFxuICAgICAgICBkZWZJZDogZGVmSWQsXG4gICAgICAgIHJhbmdlOiByYW5nZSxcbiAgICAgICAgZm9yY2VkU3RhcnRUem86IGZvcmNlZFN0YXJ0VHpvID09IG51bGwgPyBudWxsIDogZm9yY2VkU3RhcnRUem8sXG4gICAgICAgIGZvcmNlZEVuZFR6bzogZm9yY2VkRW5kVHpvID09IG51bGwgPyBudWxsIDogZm9yY2VkRW5kVHpvXG4gICAgfTtcbn1cbmZ1bmN0aW9uIHBhcnNlU2luZ2xlKHJhdywgYWxsRGF5RGVmYXVsdCwgY2FsZW5kYXIsIGxlZnRvdmVycywgYWxsb3dPcGVuUmFuZ2UpIHtcbiAgICB2YXIgcHJvcHMgPSBwbHVja0RhdGVQcm9wcyhyYXcsIGxlZnRvdmVycyk7XG4gICAgdmFyIGFsbERheSA9IHByb3BzLmFsbERheTtcbiAgICB2YXIgc3RhcnRNZXRhO1xuICAgIHZhciBzdGFydE1hcmtlciA9IG51bGw7XG4gICAgdmFyIGhhc0VuZCA9IGZhbHNlO1xuICAgIHZhciBlbmRNZXRhO1xuICAgIHZhciBlbmRNYXJrZXIgPSBudWxsO1xuICAgIHN0YXJ0TWV0YSA9IGNhbGVuZGFyLmRhdGVFbnYuY3JlYXRlTWFya2VyTWV0YShwcm9wcy5zdGFydCk7XG4gICAgaWYgKHN0YXJ0TWV0YSkge1xuICAgICAgICBzdGFydE1hcmtlciA9IHN0YXJ0TWV0YS5tYXJrZXI7XG4gICAgfVxuICAgIGVsc2UgaWYgKCFhbGxvd09wZW5SYW5nZSkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgaWYgKHByb3BzLmVuZCAhPSBudWxsKSB7XG4gICAgICAgIGVuZE1ldGEgPSBjYWxlbmRhci5kYXRlRW52LmNyZWF0ZU1hcmtlck1ldGEocHJvcHMuZW5kKTtcbiAgICB9XG4gICAgaWYgKGFsbERheSA9PSBudWxsKSB7XG4gICAgICAgIGlmIChhbGxEYXlEZWZhdWx0ICE9IG51bGwpIHtcbiAgICAgICAgICAgIGFsbERheSA9IGFsbERheURlZmF1bHQ7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyBmYWxsIGJhY2sgdG8gdGhlIGRhdGUgcHJvcHMgTEFTVFxuICAgICAgICAgICAgYWxsRGF5ID0gKCFzdGFydE1ldGEgfHwgc3RhcnRNZXRhLmlzVGltZVVuc3BlY2lmaWVkKSAmJlxuICAgICAgICAgICAgICAgICghZW5kTWV0YSB8fCBlbmRNZXRhLmlzVGltZVVuc3BlY2lmaWVkKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAoYWxsRGF5ICYmIHN0YXJ0TWFya2VyKSB7XG4gICAgICAgIHN0YXJ0TWFya2VyID0gc3RhcnRPZkRheShzdGFydE1hcmtlcik7XG4gICAgfVxuICAgIGlmIChlbmRNZXRhKSB7XG4gICAgICAgIGVuZE1hcmtlciA9IGVuZE1ldGEubWFya2VyO1xuICAgICAgICBpZiAoYWxsRGF5KSB7XG4gICAgICAgICAgICBlbmRNYXJrZXIgPSBzdGFydE9mRGF5KGVuZE1hcmtlcik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHN0YXJ0TWFya2VyICYmIGVuZE1hcmtlciA8PSBzdGFydE1hcmtlcikge1xuICAgICAgICAgICAgZW5kTWFya2VyID0gbnVsbDtcbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAoZW5kTWFya2VyKSB7XG4gICAgICAgIGhhc0VuZCA9IHRydWU7XG4gICAgfVxuICAgIGVsc2UgaWYgKCFhbGxvd09wZW5SYW5nZSkge1xuICAgICAgICBoYXNFbmQgPSBjYWxlbmRhci5vcHQoJ2ZvcmNlRXZlbnREdXJhdGlvbicpIHx8IGZhbHNlO1xuICAgICAgICBlbmRNYXJrZXIgPSBjYWxlbmRhci5kYXRlRW52LmFkZChzdGFydE1hcmtlciwgYWxsRGF5ID9cbiAgICAgICAgICAgIGNhbGVuZGFyLmRlZmF1bHRBbGxEYXlFdmVudER1cmF0aW9uIDpcbiAgICAgICAgICAgIGNhbGVuZGFyLmRlZmF1bHRUaW1lZEV2ZW50RHVyYXRpb24pO1xuICAgIH1cbiAgICByZXR1cm4ge1xuICAgICAgICBhbGxEYXk6IGFsbERheSxcbiAgICAgICAgaGFzRW5kOiBoYXNFbmQsXG4gICAgICAgIHJhbmdlOiB7IHN0YXJ0OiBzdGFydE1hcmtlciwgZW5kOiBlbmRNYXJrZXIgfSxcbiAgICAgICAgZm9yY2VkU3RhcnRUem86IHN0YXJ0TWV0YSA/IHN0YXJ0TWV0YS5mb3JjZWRUem8gOiBudWxsLFxuICAgICAgICBmb3JjZWRFbmRUem86IGVuZE1ldGEgPyBlbmRNZXRhLmZvcmNlZFR6byA6IG51bGxcbiAgICB9O1xufVxuZnVuY3Rpb24gcGx1Y2tEYXRlUHJvcHMocmF3LCBsZWZ0b3ZlcnMpIHtcbiAgICB2YXIgcHJvcHMgPSByZWZpbmVQcm9wcyhyYXcsIERBVEVfUFJPUFMsIHt9LCBsZWZ0b3ZlcnMpO1xuICAgIHByb3BzLnN0YXJ0ID0gKHByb3BzLnN0YXJ0ICE9PSBudWxsKSA/IHByb3BzLnN0YXJ0IDogcHJvcHMuZGF0ZTtcbiAgICBkZWxldGUgcHJvcHMuZGF0ZTtcbiAgICByZXR1cm4gcHJvcHM7XG59XG5mdW5jdGlvbiBwbHVja05vbkRhdGVQcm9wcyhyYXcsIGNhbGVuZGFyLCBsZWZ0b3ZlcnMpIHtcbiAgICB2YXIgcHJlTGVmdG92ZXJzID0ge307XG4gICAgdmFyIHByb3BzID0gcmVmaW5lUHJvcHMocmF3LCBOT05fREFURV9QUk9QUywge30sIHByZUxlZnRvdmVycyk7XG4gICAgdmFyIHVpID0gcHJvY2Vzc1Vuc2NvcGVkVWlQcm9wcyhwcmVMZWZ0b3ZlcnMsIGNhbGVuZGFyLCBsZWZ0b3ZlcnMpO1xuICAgIHByb3BzLnB1YmxpY0lkID0gcHJvcHMuaWQ7XG4gICAgZGVsZXRlIHByb3BzLmlkO1xuICAgIHByb3BzLnVpID0gdWk7XG4gICAgcmV0dXJuIHByb3BzO1xufVxuZnVuY3Rpb24gY29tcHV0ZUlzQWxsRGF5RGVmYXVsdChzb3VyY2VJZCwgY2FsZW5kYXIpIHtcbiAgICB2YXIgcmVzID0gbnVsbDtcbiAgICBpZiAoc291cmNlSWQpIHtcbiAgICAgICAgdmFyIHNvdXJjZSA9IGNhbGVuZGFyLnN0YXRlLmV2ZW50U291cmNlc1tzb3VyY2VJZF07XG4gICAgICAgIHJlcyA9IHNvdXJjZS5hbGxEYXlEZWZhdWx0O1xuICAgIH1cbiAgICBpZiAocmVzID09IG51bGwpIHtcbiAgICAgICAgcmVzID0gY2FsZW5kYXIub3B0KCdhbGxEYXlEZWZhdWx0Jyk7XG4gICAgfVxuICAgIHJldHVybiByZXM7XG59XG5cbnZhciBERUZfREVGQVVMVFMgPSB7XG4gICAgc3RhcnRUaW1lOiAnMDk6MDAnLFxuICAgIGVuZFRpbWU6ICcxNzowMCcsXG4gICAgZGF5c09mV2VlazogWzEsIDIsIDMsIDQsIDVdLFxuICAgIHJlbmRlcmluZzogJ2ludmVyc2UtYmFja2dyb3VuZCcsXG4gICAgY2xhc3NOYW1lczogJ2ZjLW5vbmJ1c2luZXNzJyxcbiAgICBncm91cElkOiAnX2J1c2luZXNzSG91cnMnIC8vIHNvIG11bHRpcGxlIGRlZnMgZ2V0IGdyb3VwZWRcbn07XG4vKlxuVE9ETzogcGFzcyBhcm91bmQgYXMgRXZlbnREZWZIYXNoISEhXG4qL1xuZnVuY3Rpb24gcGFyc2VCdXNpbmVzc0hvdXJzKGlucHV0LCBjYWxlbmRhcikge1xuICAgIHJldHVybiBwYXJzZUV2ZW50cyhyZWZpbmVJbnB1dHMoaW5wdXQpLCAnJywgY2FsZW5kYXIpO1xufVxuZnVuY3Rpb24gcmVmaW5lSW5wdXRzKGlucHV0KSB7XG4gICAgdmFyIHJhd0RlZnM7XG4gICAgaWYgKGlucHV0ID09PSB0cnVlKSB7XG4gICAgICAgIHJhd0RlZnMgPSBbe31dOyAvLyB3aWxsIGdldCBERUZfREVGQVVMVFMgdmVyYmF0aW1cbiAgICB9XG4gICAgZWxzZSBpZiAoQXJyYXkuaXNBcnJheShpbnB1dCkpIHtcbiAgICAgICAgLy8gaWYgc3BlY2lmeWluZyBhbiBhcnJheSwgZXZlcnkgc3ViLWRlZmluaXRpb24gTkVFRFMgYSBkYXktb2Ytd2Vla1xuICAgICAgICByYXdEZWZzID0gaW5wdXQuZmlsdGVyKGZ1bmN0aW9uIChyYXdEZWYpIHtcbiAgICAgICAgICAgIHJldHVybiByYXdEZWYuZGF5c09mV2VlaztcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGVsc2UgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ29iamVjdCcgJiYgaW5wdXQpIHsgLy8gbm9uLW51bGwgb2JqZWN0XG4gICAgICAgIHJhd0RlZnMgPSBbaW5wdXRdO1xuICAgIH1cbiAgICBlbHNlIHsgLy8gaXMgcHJvYmFibHkgZmFsc2VcbiAgICAgICAgcmF3RGVmcyA9IFtdO1xuICAgIH1cbiAgICByYXdEZWZzID0gcmF3RGVmcy5tYXAoZnVuY3Rpb24gKHJhd0RlZikge1xuICAgICAgICByZXR1cm4gX19hc3NpZ24oe30sIERFRl9ERUZBVUxUUywgcmF3RGVmKTtcbiAgICB9KTtcbiAgICByZXR1cm4gcmF3RGVmcztcbn1cblxuZnVuY3Rpb24gbWVtb2l6ZVJlbmRlcmluZyhyZW5kZXJGdW5jLCB1bnJlbmRlckZ1bmMsIGRlcGVuZGVuY2llcykge1xuICAgIGlmIChkZXBlbmRlbmNpZXMgPT09IHZvaWQgMCkgeyBkZXBlbmRlbmNpZXMgPSBbXTsgfVxuICAgIHZhciBkZXBlbmRlbnRzID0gW107XG4gICAgdmFyIHRoaXNDb250ZXh0O1xuICAgIHZhciBwcmV2QXJncztcbiAgICBmdW5jdGlvbiB1bnJlbmRlcigpIHtcbiAgICAgICAgaWYgKHByZXZBcmdzKSB7XG4gICAgICAgICAgICBmb3IgKHZhciBfaSA9IDAsIGRlcGVuZGVudHNfMSA9IGRlcGVuZGVudHM7IF9pIDwgZGVwZW5kZW50c18xLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgICAgIHZhciBkZXBlbmRlbnQgPSBkZXBlbmRlbnRzXzFbX2ldO1xuICAgICAgICAgICAgICAgIGRlcGVuZGVudC51bnJlbmRlcigpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHVucmVuZGVyRnVuYykge1xuICAgICAgICAgICAgICAgIHVucmVuZGVyRnVuYy5hcHBseSh0aGlzQ29udGV4dCwgcHJldkFyZ3MpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcHJldkFyZ3MgPSBudWxsO1xuICAgICAgICB9XG4gICAgfVxuICAgIGZ1bmN0aW9uIHJlcygpIHtcbiAgICAgICAgaWYgKCFwcmV2QXJncyB8fCAhaXNBcnJheXNFcXVhbChwcmV2QXJncywgYXJndW1lbnRzKSkge1xuICAgICAgICAgICAgdW5yZW5kZXIoKTtcbiAgICAgICAgICAgIHRoaXNDb250ZXh0ID0gdGhpcztcbiAgICAgICAgICAgIHByZXZBcmdzID0gYXJndW1lbnRzO1xuICAgICAgICAgICAgcmVuZGVyRnVuYy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJlcy5kZXBlbmRlbnRzID0gZGVwZW5kZW50cztcbiAgICByZXMudW5yZW5kZXIgPSB1bnJlbmRlcjtcbiAgICBmb3IgKHZhciBfaSA9IDAsIGRlcGVuZGVuY2llc18xID0gZGVwZW5kZW5jaWVzOyBfaSA8IGRlcGVuZGVuY2llc18xLmxlbmd0aDsgX2krKykge1xuICAgICAgICB2YXIgZGVwZW5kZW5jeSA9IGRlcGVuZGVuY2llc18xW19pXTtcbiAgICAgICAgZGVwZW5kZW5jeS5kZXBlbmRlbnRzLnB1c2gocmVzKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlcztcbn1cblxudmFyIEVNUFRZX0VWRU5UX1NUT1JFID0gY3JlYXRlRW1wdHlFdmVudFN0b3JlKCk7IC8vIGZvciBwdXJlY29tcG9uZW50cy4gVE9ETzoga2VlcCBlbHNld2hlcmVcbnZhciBTcGxpdHRlciA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBTcGxpdHRlcigpIHtcbiAgICAgICAgdGhpcy5nZXRLZXlzRm9yRXZlbnREZWZzID0gbWVtb2l6ZSh0aGlzLl9nZXRLZXlzRm9yRXZlbnREZWZzKTtcbiAgICAgICAgdGhpcy5zcGxpdERhdGVTZWxlY3Rpb24gPSBtZW1vaXplKHRoaXMuX3NwbGl0RGF0ZVNwYW4pO1xuICAgICAgICB0aGlzLnNwbGl0RXZlbnRTdG9yZSA9IG1lbW9pemUodGhpcy5fc3BsaXRFdmVudFN0b3JlKTtcbiAgICAgICAgdGhpcy5zcGxpdEluZGl2aWR1YWxVaSA9IG1lbW9pemUodGhpcy5fc3BsaXRJbmRpdmlkdWFsVWkpO1xuICAgICAgICB0aGlzLnNwbGl0RXZlbnREcmFnID0gbWVtb2l6ZSh0aGlzLl9zcGxpdEludGVyYWN0aW9uKTtcbiAgICAgICAgdGhpcy5zcGxpdEV2ZW50UmVzaXplID0gbWVtb2l6ZSh0aGlzLl9zcGxpdEludGVyYWN0aW9uKTtcbiAgICAgICAgdGhpcy5ldmVudFVpQnVpbGRlcnMgPSB7fTsgLy8gVE9ETzogdHlwZXNjcmlwdCBwcm90ZWN0aW9uXG4gICAgfVxuICAgIFNwbGl0dGVyLnByb3RvdHlwZS5zcGxpdFByb3BzID0gZnVuY3Rpb24gKHByb3BzKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBrZXlJbmZvcyA9IHRoaXMuZ2V0S2V5SW5mbyhwcm9wcyk7XG4gICAgICAgIHZhciBkZWZLZXlzID0gdGhpcy5nZXRLZXlzRm9yRXZlbnREZWZzKHByb3BzLmV2ZW50U3RvcmUpO1xuICAgICAgICB2YXIgZGF0ZVNlbGVjdGlvbnMgPSB0aGlzLnNwbGl0RGF0ZVNlbGVjdGlvbihwcm9wcy5kYXRlU2VsZWN0aW9uKTtcbiAgICAgICAgdmFyIGluZGl2aWR1YWxVaSA9IHRoaXMuc3BsaXRJbmRpdmlkdWFsVWkocHJvcHMuZXZlbnRVaUJhc2VzLCBkZWZLZXlzKTsgLy8gdGhlIGluZGl2aWR1YWwgKmJhc2VzKlxuICAgICAgICB2YXIgZXZlbnRTdG9yZXMgPSB0aGlzLnNwbGl0RXZlbnRTdG9yZShwcm9wcy5ldmVudFN0b3JlLCBkZWZLZXlzKTtcbiAgICAgICAgdmFyIGV2ZW50RHJhZ3MgPSB0aGlzLnNwbGl0RXZlbnREcmFnKHByb3BzLmV2ZW50RHJhZyk7XG4gICAgICAgIHZhciBldmVudFJlc2l6ZXMgPSB0aGlzLnNwbGl0RXZlbnRSZXNpemUocHJvcHMuZXZlbnRSZXNpemUpO1xuICAgICAgICB2YXIgc3BsaXRQcm9wcyA9IHt9O1xuICAgICAgICB0aGlzLmV2ZW50VWlCdWlsZGVycyA9IG1hcEhhc2goa2V5SW5mb3MsIGZ1bmN0aW9uIChpbmZvLCBrZXkpIHtcbiAgICAgICAgICAgIHJldHVybiBfdGhpcy5ldmVudFVpQnVpbGRlcnNba2V5XSB8fCBtZW1vaXplKGJ1aWxkRXZlbnRVaUZvcktleSk7XG4gICAgICAgIH0pO1xuICAgICAgICBmb3IgKHZhciBrZXkgaW4ga2V5SW5mb3MpIHtcbiAgICAgICAgICAgIHZhciBrZXlJbmZvID0ga2V5SW5mb3Nba2V5XTtcbiAgICAgICAgICAgIHZhciBldmVudFN0b3JlID0gZXZlbnRTdG9yZXNba2V5XSB8fCBFTVBUWV9FVkVOVF9TVE9SRTtcbiAgICAgICAgICAgIHZhciBidWlsZEV2ZW50VWkgPSB0aGlzLmV2ZW50VWlCdWlsZGVyc1trZXldO1xuICAgICAgICAgICAgc3BsaXRQcm9wc1trZXldID0ge1xuICAgICAgICAgICAgICAgIGJ1c2luZXNzSG91cnM6IGtleUluZm8uYnVzaW5lc3NIb3VycyB8fCBwcm9wcy5idXNpbmVzc0hvdXJzLFxuICAgICAgICAgICAgICAgIGRhdGVTZWxlY3Rpb246IGRhdGVTZWxlY3Rpb25zW2tleV0gfHwgbnVsbCxcbiAgICAgICAgICAgICAgICBldmVudFN0b3JlOiBldmVudFN0b3JlLFxuICAgICAgICAgICAgICAgIGV2ZW50VWlCYXNlczogYnVpbGRFdmVudFVpKHByb3BzLmV2ZW50VWlCYXNlc1snJ10sIGtleUluZm8udWksIGluZGl2aWR1YWxVaVtrZXldKSxcbiAgICAgICAgICAgICAgICBldmVudFNlbGVjdGlvbjogZXZlbnRTdG9yZS5pbnN0YW5jZXNbcHJvcHMuZXZlbnRTZWxlY3Rpb25dID8gcHJvcHMuZXZlbnRTZWxlY3Rpb24gOiAnJyxcbiAgICAgICAgICAgICAgICBldmVudERyYWc6IGV2ZW50RHJhZ3Nba2V5XSB8fCBudWxsLFxuICAgICAgICAgICAgICAgIGV2ZW50UmVzaXplOiBldmVudFJlc2l6ZXNba2V5XSB8fCBudWxsXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzcGxpdFByb3BzO1xuICAgIH07XG4gICAgU3BsaXR0ZXIucHJvdG90eXBlLl9zcGxpdERhdGVTcGFuID0gZnVuY3Rpb24gKGRhdGVTcGFuKSB7XG4gICAgICAgIHZhciBkYXRlU3BhbnMgPSB7fTtcbiAgICAgICAgaWYgKGRhdGVTcGFuKSB7XG4gICAgICAgICAgICB2YXIga2V5cyA9IHRoaXMuZ2V0S2V5c0ZvckRhdGVTcGFuKGRhdGVTcGFuKTtcbiAgICAgICAgICAgIGZvciAodmFyIF9pID0gMCwga2V5c18xID0ga2V5czsgX2kgPCBrZXlzXzEubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIGtleSA9IGtleXNfMVtfaV07XG4gICAgICAgICAgICAgICAgZGF0ZVNwYW5zW2tleV0gPSBkYXRlU3BhbjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZGF0ZVNwYW5zO1xuICAgIH07XG4gICAgU3BsaXR0ZXIucHJvdG90eXBlLl9nZXRLZXlzRm9yRXZlbnREZWZzID0gZnVuY3Rpb24gKGV2ZW50U3RvcmUpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgcmV0dXJuIG1hcEhhc2goZXZlbnRTdG9yZS5kZWZzLCBmdW5jdGlvbiAoZXZlbnREZWYpIHtcbiAgICAgICAgICAgIHJldHVybiBfdGhpcy5nZXRLZXlzRm9yRXZlbnREZWYoZXZlbnREZWYpO1xuICAgICAgICB9KTtcbiAgICB9O1xuICAgIFNwbGl0dGVyLnByb3RvdHlwZS5fc3BsaXRFdmVudFN0b3JlID0gZnVuY3Rpb24gKGV2ZW50U3RvcmUsIGRlZktleXMpIHtcbiAgICAgICAgdmFyIGRlZnMgPSBldmVudFN0b3JlLmRlZnMsIGluc3RhbmNlcyA9IGV2ZW50U3RvcmUuaW5zdGFuY2VzO1xuICAgICAgICB2YXIgc3BsaXRTdG9yZXMgPSB7fTtcbiAgICAgICAgZm9yICh2YXIgZGVmSWQgaW4gZGVmcykge1xuICAgICAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBfYSA9IGRlZktleXNbZGVmSWRdOyBfaSA8IF9hLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgICAgIHZhciBrZXkgPSBfYVtfaV07XG4gICAgICAgICAgICAgICAgaWYgKCFzcGxpdFN0b3Jlc1trZXldKSB7XG4gICAgICAgICAgICAgICAgICAgIHNwbGl0U3RvcmVzW2tleV0gPSBjcmVhdGVFbXB0eUV2ZW50U3RvcmUoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgc3BsaXRTdG9yZXNba2V5XS5kZWZzW2RlZklkXSA9IGRlZnNbZGVmSWRdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGZvciAodmFyIGluc3RhbmNlSWQgaW4gaW5zdGFuY2VzKSB7XG4gICAgICAgICAgICB2YXIgaW5zdGFuY2UgPSBpbnN0YW5jZXNbaW5zdGFuY2VJZF07XG4gICAgICAgICAgICBmb3IgKHZhciBfYiA9IDAsIF9jID0gZGVmS2V5c1tpbnN0YW5jZS5kZWZJZF07IF9iIDwgX2MubGVuZ3RoOyBfYisrKSB7XG4gICAgICAgICAgICAgICAgdmFyIGtleSA9IF9jW19iXTtcbiAgICAgICAgICAgICAgICBpZiAoc3BsaXRTdG9yZXNba2V5XSkgeyAvLyBtdXN0IGhhdmUgYWxyZWFkeSBiZWVuIGNyZWF0ZWRcbiAgICAgICAgICAgICAgICAgICAgc3BsaXRTdG9yZXNba2V5XS5pbnN0YW5jZXNbaW5zdGFuY2VJZF0gPSBpbnN0YW5jZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNwbGl0U3RvcmVzO1xuICAgIH07XG4gICAgU3BsaXR0ZXIucHJvdG90eXBlLl9zcGxpdEluZGl2aWR1YWxVaSA9IGZ1bmN0aW9uIChldmVudFVpQmFzZXMsIGRlZktleXMpIHtcbiAgICAgICAgdmFyIHNwbGl0SGFzaGVzID0ge307XG4gICAgICAgIGZvciAodmFyIGRlZklkIGluIGV2ZW50VWlCYXNlcykge1xuICAgICAgICAgICAgaWYgKGRlZklkKSB7IC8vIG5vdCB0aGUgJycga2V5XG4gICAgICAgICAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBfYSA9IGRlZktleXNbZGVmSWRdOyBfaSA8IF9hLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgICAgICAgICB2YXIga2V5ID0gX2FbX2ldO1xuICAgICAgICAgICAgICAgICAgICBpZiAoIXNwbGl0SGFzaGVzW2tleV0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNwbGl0SGFzaGVzW2tleV0gPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBzcGxpdEhhc2hlc1trZXldW2RlZklkXSA9IGV2ZW50VWlCYXNlc1tkZWZJZF07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzcGxpdEhhc2hlcztcbiAgICB9O1xuICAgIFNwbGl0dGVyLnByb3RvdHlwZS5fc3BsaXRJbnRlcmFjdGlvbiA9IGZ1bmN0aW9uIChpbnRlcmFjdGlvbikge1xuICAgICAgICB2YXIgc3BsaXRTdGF0ZXMgPSB7fTtcbiAgICAgICAgaWYgKGludGVyYWN0aW9uKSB7XG4gICAgICAgICAgICB2YXIgYWZmZWN0ZWRTdG9yZXNfMSA9IHRoaXMuX3NwbGl0RXZlbnRTdG9yZShpbnRlcmFjdGlvbi5hZmZlY3RlZEV2ZW50cywgdGhpcy5fZ2V0S2V5c0ZvckV2ZW50RGVmcyhpbnRlcmFjdGlvbi5hZmZlY3RlZEV2ZW50cykgLy8gY2FuJ3QgdXNlIGNhY2hlZC4gbWlnaHQgYmUgZXZlbnRzIGZyb20gb3RoZXIgY2FsZW5kYXJcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICAvLyBjYW4ndCByZWx5IG9uIGRlZktleXMgYmVjYXVzZSBldmVudCBkYXRhIGlzIG11dGF0ZWRcbiAgICAgICAgICAgIHZhciBtdXRhdGVkS2V5c0J5RGVmSWQgPSB0aGlzLl9nZXRLZXlzRm9yRXZlbnREZWZzKGludGVyYWN0aW9uLm11dGF0ZWRFdmVudHMpO1xuICAgICAgICAgICAgdmFyIG11dGF0ZWRTdG9yZXNfMSA9IHRoaXMuX3NwbGl0RXZlbnRTdG9yZShpbnRlcmFjdGlvbi5tdXRhdGVkRXZlbnRzLCBtdXRhdGVkS2V5c0J5RGVmSWQpO1xuICAgICAgICAgICAgdmFyIHBvcHVsYXRlID0gZnVuY3Rpb24gKGtleSkge1xuICAgICAgICAgICAgICAgIGlmICghc3BsaXRTdGF0ZXNba2V5XSkge1xuICAgICAgICAgICAgICAgICAgICBzcGxpdFN0YXRlc1trZXldID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgYWZmZWN0ZWRFdmVudHM6IGFmZmVjdGVkU3RvcmVzXzFba2V5XSB8fCBFTVBUWV9FVkVOVF9TVE9SRSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZWRFdmVudHM6IG11dGF0ZWRTdG9yZXNfMVtrZXldIHx8IEVNUFRZX0VWRU5UX1NUT1JFLFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNFdmVudDogaW50ZXJhY3Rpb24uaXNFdmVudCxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9yaWdTZWc6IGludGVyYWN0aW9uLm9yaWdTZWdcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgZm9yICh2YXIga2V5IGluIGFmZmVjdGVkU3RvcmVzXzEpIHtcbiAgICAgICAgICAgICAgICBwb3B1bGF0ZShrZXkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yICh2YXIga2V5IGluIG11dGF0ZWRTdG9yZXNfMSkge1xuICAgICAgICAgICAgICAgIHBvcHVsYXRlKGtleSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNwbGl0U3RhdGVzO1xuICAgIH07XG4gICAgcmV0dXJuIFNwbGl0dGVyO1xufSgpKTtcbmZ1bmN0aW9uIGJ1aWxkRXZlbnRVaUZvcktleShhbGxVaSwgZXZlbnRVaUZvcktleSwgaW5kaXZpZHVhbFVpKSB7XG4gICAgdmFyIGJhc2VQYXJ0cyA9IFtdO1xuICAgIGlmIChhbGxVaSkge1xuICAgICAgICBiYXNlUGFydHMucHVzaChhbGxVaSk7XG4gICAgfVxuICAgIGlmIChldmVudFVpRm9yS2V5KSB7XG4gICAgICAgIGJhc2VQYXJ0cy5wdXNoKGV2ZW50VWlGb3JLZXkpO1xuICAgIH1cbiAgICB2YXIgc3R1ZmYgPSB7XG4gICAgICAgICcnOiBjb21iaW5lRXZlbnRVaXMoYmFzZVBhcnRzKVxuICAgIH07XG4gICAgaWYgKGluZGl2aWR1YWxVaSkge1xuICAgICAgICBfX2Fzc2lnbihzdHVmZiwgaW5kaXZpZHVhbFVpKTtcbiAgICB9XG4gICAgcmV0dXJuIHN0dWZmO1xufVxuXG4vLyBHZW5lcmF0ZXMgSFRNTCBmb3IgYW4gYW5jaG9yIHRvIGFub3RoZXIgdmlldyBpbnRvIHRoZSBjYWxlbmRhci5cbi8vIFdpbGwgZWl0aGVyIGdlbmVyYXRlIGFuIDxhPiB0YWcgb3IgYSBub24tY2xpY2thYmxlIDxzcGFuPiB0YWcsIGRlcGVuZGluZyBvbiBlbmFibGVkIHNldHRpbmdzLlxuLy8gYGdvdG9PcHRpb25zYCBjYW4gZWl0aGVyIGJlIGEgRGF0ZU1hcmtlciwgb3IgYW4gb2JqZWN0IHdpdGggdGhlIGZvcm06XG4vLyB7IGRhdGUsIHR5cGUsIGZvcmNlT2ZmIH1cbi8vIGB0eXBlYCBpcyBhIHZpZXctdHlwZSBsaWtlIFwiZGF5XCIgb3IgXCJ3ZWVrXCIuIGRlZmF1bHQgdmFsdWUgaXMgXCJkYXlcIi5cbi8vIGBhdHRyc2AgYW5kIGBpbm5lckh0bWxgIGFyZSB1c2UgdG8gZ2VuZXJhdGUgdGhlIHJlc3Qgb2YgdGhlIEhUTUwgdGFnLlxuZnVuY3Rpb24gYnVpbGRHb3RvQW5jaG9ySHRtbChhbGxPcHRpb25zLCBkYXRlRW52LCBnb3RvT3B0aW9ucywgYXR0cnMsIGlubmVySHRtbCkge1xuICAgIHZhciBkYXRlO1xuICAgIHZhciB0eXBlO1xuICAgIHZhciBmb3JjZU9mZjtcbiAgICB2YXIgZmluYWxPcHRpb25zO1xuICAgIGlmIChnb3RvT3B0aW9ucyBpbnN0YW5jZW9mIERhdGUpIHtcbiAgICAgICAgZGF0ZSA9IGdvdG9PcHRpb25zOyAvLyBhIHNpbmdsZSBkYXRlLWxpa2UgaW5wdXRcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGRhdGUgPSBnb3RvT3B0aW9ucy5kYXRlO1xuICAgICAgICB0eXBlID0gZ290b09wdGlvbnMudHlwZTtcbiAgICAgICAgZm9yY2VPZmYgPSBnb3RvT3B0aW9ucy5mb3JjZU9mZjtcbiAgICB9XG4gICAgZmluYWxPcHRpb25zID0ge1xuICAgICAgICBkYXRlOiBkYXRlRW52LmZvcm1hdElzbyhkYXRlLCB7IG9taXRUaW1lOiB0cnVlIH0pLFxuICAgICAgICB0eXBlOiB0eXBlIHx8ICdkYXknXG4gICAgfTtcbiAgICBpZiAodHlwZW9mIGF0dHJzID09PSAnc3RyaW5nJykge1xuICAgICAgICBpbm5lckh0bWwgPSBhdHRycztcbiAgICAgICAgYXR0cnMgPSBudWxsO1xuICAgIH1cbiAgICBhdHRycyA9IGF0dHJzID8gJyAnICsgYXR0cnNUb1N0cihhdHRycykgOiAnJzsgLy8gd2lsbCBoYXZlIGEgbGVhZGluZyBzcGFjZVxuICAgIGlubmVySHRtbCA9IGlubmVySHRtbCB8fCAnJztcbiAgICBpZiAoIWZvcmNlT2ZmICYmIGFsbE9wdGlvbnMubmF2TGlua3MpIHtcbiAgICAgICAgcmV0dXJuICc8YScgKyBhdHRycyArXG4gICAgICAgICAgICAnIGRhdGEtZ290bz1cIicgKyBodG1sRXNjYXBlKEpTT04uc3RyaW5naWZ5KGZpbmFsT3B0aW9ucykpICsgJ1wiPicgK1xuICAgICAgICAgICAgaW5uZXJIdG1sICtcbiAgICAgICAgICAgICc8L2E+JztcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHJldHVybiAnPHNwYW4nICsgYXR0cnMgKyAnPicgK1xuICAgICAgICAgICAgaW5uZXJIdG1sICtcbiAgICAgICAgICAgICc8L3NwYW4+JztcbiAgICB9XG59XG5mdW5jdGlvbiBnZXRBbGxEYXlIdG1sKGFsbE9wdGlvbnMpIHtcbiAgICByZXR1cm4gYWxsT3B0aW9ucy5hbGxEYXlIdG1sIHx8IGh0bWxFc2NhcGUoYWxsT3B0aW9ucy5hbGxEYXlUZXh0KTtcbn1cbi8vIENvbXB1dGVzIEhUTUwgY2xhc3NOYW1lcyBmb3IgYSBzaW5nbGUtZGF5IGVsZW1lbnRcbmZ1bmN0aW9uIGdldERheUNsYXNzZXMoZGF0ZSwgZGF0ZVByb2ZpbGUsIGNvbnRleHQsIG5vVGhlbWVIaWdobGlnaHQpIHtcbiAgICB2YXIgY2FsZW5kYXIgPSBjb250ZXh0LmNhbGVuZGFyLCBvcHRpb25zID0gY29udGV4dC5vcHRpb25zLCB0aGVtZSA9IGNvbnRleHQudGhlbWUsIGRhdGVFbnYgPSBjb250ZXh0LmRhdGVFbnY7XG4gICAgdmFyIGNsYXNzZXMgPSBbXTtcbiAgICB2YXIgdG9kYXlTdGFydDtcbiAgICB2YXIgdG9kYXlFbmQ7XG4gICAgaWYgKCFyYW5nZUNvbnRhaW5zTWFya2VyKGRhdGVQcm9maWxlLmFjdGl2ZVJhbmdlLCBkYXRlKSkge1xuICAgICAgICBjbGFzc2VzLnB1c2goJ2ZjLWRpc2FibGVkLWRheScpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgY2xhc3Nlcy5wdXNoKCdmYy0nICsgREFZX0lEU1tkYXRlLmdldFVUQ0RheSgpXSk7XG4gICAgICAgIGlmIChvcHRpb25zLm1vbnRoTW9kZSAmJlxuICAgICAgICAgICAgZGF0ZUVudi5nZXRNb250aChkYXRlKSAhPT0gZGF0ZUVudi5nZXRNb250aChkYXRlUHJvZmlsZS5jdXJyZW50UmFuZ2Uuc3RhcnQpKSB7XG4gICAgICAgICAgICBjbGFzc2VzLnB1c2goJ2ZjLW90aGVyLW1vbnRoJyk7XG4gICAgICAgIH1cbiAgICAgICAgdG9kYXlTdGFydCA9IHN0YXJ0T2ZEYXkoY2FsZW5kYXIuZ2V0Tm93KCkpO1xuICAgICAgICB0b2RheUVuZCA9IGFkZERheXModG9kYXlTdGFydCwgMSk7XG4gICAgICAgIGlmIChkYXRlIDwgdG9kYXlTdGFydCkge1xuICAgICAgICAgICAgY2xhc3Nlcy5wdXNoKCdmYy1wYXN0Jyk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZGF0ZSA+PSB0b2RheUVuZCkge1xuICAgICAgICAgICAgY2xhc3Nlcy5wdXNoKCdmYy1mdXR1cmUnKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNsYXNzZXMucHVzaCgnZmMtdG9kYXknKTtcbiAgICAgICAgICAgIGlmIChub1RoZW1lSGlnaGxpZ2h0ICE9PSB0cnVlKSB7XG4gICAgICAgICAgICAgICAgY2xhc3Nlcy5wdXNoKHRoZW1lLmdldENsYXNzKCd0b2RheScpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gY2xhc3Nlcztcbn1cblxuLy8gZ2l2ZW4gYSBmdW5jdGlvbiB0aGF0IHJlc29sdmVzIGEgcmVzdWx0IGFzeW5jaHJvbm91c2x5LlxuLy8gdGhlIGZ1bmN0aW9uIGNhbiBlaXRoZXIgY2FsbCBwYXNzZWQtaW4gc3VjY2VzcyBhbmQgZmFpbHVyZSBjYWxsYmFja3MsXG4vLyBvciBpdCBjYW4gcmV0dXJuIGEgcHJvbWlzZS5cbi8vIGlmIHlvdSBuZWVkIHRvIHBhc3MgYWRkaXRpb25hbCBwYXJhbXMgdG8gZnVuYywgYmluZCB0aGVtIGZpcnN0LlxuZnVuY3Rpb24gdW5wcm9taXNpZnkoZnVuYywgc3VjY2VzcywgZmFpbHVyZSkge1xuICAgIC8vIGd1YXJkIGFnYWluc3Qgc3VjY2Vzcy9mYWlsdXJlIGNhbGxiYWNrcyBiZWluZyBjYWxsZWQgbW9yZSB0aGFuIG9uY2VcbiAgICAvLyBhbmQgZ3VhcmQgYWdhaW5zdCBhIHByb21pc2UgQU5EIGNhbGxiYWNrIGJlaW5nIHVzZWQgdG9nZXRoZXIuXG4gICAgdmFyIGlzUmVzb2x2ZWQgPSBmYWxzZTtcbiAgICB2YXIgd3JhcHBlZFN1Y2Nlc3MgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghaXNSZXNvbHZlZCkge1xuICAgICAgICAgICAgaXNSZXNvbHZlZCA9IHRydWU7XG4gICAgICAgICAgICBzdWNjZXNzLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIHZhciB3cmFwcGVkRmFpbHVyZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCFpc1Jlc29sdmVkKSB7XG4gICAgICAgICAgICBpc1Jlc29sdmVkID0gdHJ1ZTtcbiAgICAgICAgICAgIGlmIChmYWlsdXJlKSB7XG4gICAgICAgICAgICAgICAgZmFpbHVyZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcbiAgICB2YXIgcmVzID0gZnVuYyh3cmFwcGVkU3VjY2Vzcywgd3JhcHBlZEZhaWx1cmUpO1xuICAgIGlmIChyZXMgJiYgdHlwZW9mIHJlcy50aGVuID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHJlcy50aGVuKHdyYXBwZWRTdWNjZXNzLCB3cmFwcGVkRmFpbHVyZSk7XG4gICAgfVxufVxuXG52YXIgTWl4aW4gPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gTWl4aW4oKSB7XG4gICAgfVxuICAgIC8vIG1peCBpbnRvIGEgQ0xBU1NcbiAgICBNaXhpbi5taXhJbnRvID0gZnVuY3Rpb24gKGRlc3RDbGFzcykge1xuICAgICAgICB0aGlzLm1peEludG9PYmooZGVzdENsYXNzLnByb3RvdHlwZSk7XG4gICAgfTtcbiAgICAvLyBtaXggaW50byBBTlkgb2JqZWN0XG4gICAgTWl4aW4ubWl4SW50b09iaiA9IGZ1bmN0aW9uIChkZXN0T2JqKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKHRoaXMucHJvdG90eXBlKS5mb3JFYWNoKGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgICAgICBpZiAoIWRlc3RPYmpbbmFtZV0pIHsgLy8gaWYgZGVzdGluYXRpb24gZG9lc24ndCBhbHJlYWR5IGRlZmluZSBpdFxuICAgICAgICAgICAgICAgIGRlc3RPYmpbbmFtZV0gPSBfdGhpcy5wcm90b3R5cGVbbmFtZV07XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH07XG4gICAgLypcbiAgICB3aWxsIG92ZXJyaWRlIGV4aXN0aW5nIG1ldGhvZHNcbiAgICBUT0RPOiByZW1vdmUhIG5vdCB1c2VkIGFueW1vcmVcbiAgICAqL1xuICAgIE1peGluLm1peE92ZXIgPSBmdW5jdGlvbiAoZGVzdENsYXNzKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKHRoaXMucHJvdG90eXBlKS5mb3JFYWNoKGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgICAgICBkZXN0Q2xhc3MucHJvdG90eXBlW25hbWVdID0gX3RoaXMucHJvdG90eXBlW25hbWVdO1xuICAgICAgICB9KTtcbiAgICB9O1xuICAgIHJldHVybiBNaXhpbjtcbn0oKSk7XG5cbi8qXG5VU0FHRTpcbiAgaW1wb3J0IHsgZGVmYXVsdCBhcyBFbWl0dGVyTWl4aW4sIEVtaXR0ZXJJbnRlcmZhY2UgfSBmcm9tICcuL0VtaXR0ZXJNaXhpbidcbmluIGNsYXNzOlxuICBvbjogRW1pdHRlckludGVyZmFjZVsnb24nXVxuICBvbmU6IEVtaXR0ZXJJbnRlcmZhY2VbJ29uZSddXG4gIG9mZjogRW1pdHRlckludGVyZmFjZVsnb2ZmJ11cbiAgdHJpZ2dlcjogRW1pdHRlckludGVyZmFjZVsndHJpZ2dlciddXG4gIHRyaWdnZXJXaXRoOiBFbWl0dGVySW50ZXJmYWNlWyd0cmlnZ2VyV2l0aCddXG4gIGhhc0hhbmRsZXJzOiBFbWl0dGVySW50ZXJmYWNlWydoYXNIYW5kbGVycyddXG5hZnRlciBjbGFzczpcbiAgRW1pdHRlck1peGluLm1peEludG8oVGhlQ2xhc3MpXG4qL1xudmFyIEVtaXR0ZXJNaXhpbiA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uIChfc3VwZXIpIHtcbiAgICBfX2V4dGVuZHMoRW1pdHRlck1peGluLCBfc3VwZXIpO1xuICAgIGZ1bmN0aW9uIEVtaXR0ZXJNaXhpbigpIHtcbiAgICAgICAgcmV0dXJuIF9zdXBlciAhPT0gbnVsbCAmJiBfc3VwZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKSB8fCB0aGlzO1xuICAgIH1cbiAgICBFbWl0dGVyTWl4aW4ucHJvdG90eXBlLm9uID0gZnVuY3Rpb24gKHR5cGUsIGhhbmRsZXIpIHtcbiAgICAgICAgYWRkVG9IYXNoKHRoaXMuX2hhbmRsZXJzIHx8ICh0aGlzLl9oYW5kbGVycyA9IHt9KSwgdHlwZSwgaGFuZGxlcik7XG4gICAgICAgIHJldHVybiB0aGlzOyAvLyBmb3IgY2hhaW5pbmdcbiAgICB9O1xuICAgIC8vIHRvZG86IGFkZCBjb21tZW50c1xuICAgIEVtaXR0ZXJNaXhpbi5wcm90b3R5cGUub25lID0gZnVuY3Rpb24gKHR5cGUsIGhhbmRsZXIpIHtcbiAgICAgICAgYWRkVG9IYXNoKHRoaXMuX29uZUhhbmRsZXJzIHx8ICh0aGlzLl9vbmVIYW5kbGVycyA9IHt9KSwgdHlwZSwgaGFuZGxlcik7XG4gICAgICAgIHJldHVybiB0aGlzOyAvLyBmb3IgY2hhaW5pbmdcbiAgICB9O1xuICAgIEVtaXR0ZXJNaXhpbi5wcm90b3R5cGUub2ZmID0gZnVuY3Rpb24gKHR5cGUsIGhhbmRsZXIpIHtcbiAgICAgICAgaWYgKHRoaXMuX2hhbmRsZXJzKSB7XG4gICAgICAgICAgICByZW1vdmVGcm9tSGFzaCh0aGlzLl9oYW5kbGVycywgdHlwZSwgaGFuZGxlcik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuX29uZUhhbmRsZXJzKSB7XG4gICAgICAgICAgICByZW1vdmVGcm9tSGFzaCh0aGlzLl9vbmVIYW5kbGVycywgdHlwZSwgaGFuZGxlcik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXM7IC8vIGZvciBjaGFpbmluZ1xuICAgIH07XG4gICAgRW1pdHRlck1peGluLnByb3RvdHlwZS50cmlnZ2VyID0gZnVuY3Rpb24gKHR5cGUpIHtcbiAgICAgICAgdmFyIGFyZ3MgPSBbXTtcbiAgICAgICAgZm9yICh2YXIgX2kgPSAxOyBfaSA8IGFyZ3VtZW50cy5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIGFyZ3NbX2kgLSAxXSA9IGFyZ3VtZW50c1tfaV07XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy50cmlnZ2VyV2l0aCh0eXBlLCB0aGlzLCBhcmdzKTtcbiAgICAgICAgcmV0dXJuIHRoaXM7IC8vIGZvciBjaGFpbmluZ1xuICAgIH07XG4gICAgRW1pdHRlck1peGluLnByb3RvdHlwZS50cmlnZ2VyV2l0aCA9IGZ1bmN0aW9uICh0eXBlLCBjb250ZXh0LCBhcmdzKSB7XG4gICAgICAgIGlmICh0aGlzLl9oYW5kbGVycykge1xuICAgICAgICAgICAgYXBwbHlBbGwodGhpcy5faGFuZGxlcnNbdHlwZV0sIGNvbnRleHQsIGFyZ3MpO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLl9vbmVIYW5kbGVycykge1xuICAgICAgICAgICAgYXBwbHlBbGwodGhpcy5fb25lSGFuZGxlcnNbdHlwZV0sIGNvbnRleHQsIGFyZ3MpO1xuICAgICAgICAgICAgZGVsZXRlIHRoaXMuX29uZUhhbmRsZXJzW3R5cGVdOyAvLyB3aWxsIG5ldmVyIGZpcmUgYWdhaW5cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpczsgLy8gZm9yIGNoYWluaW5nXG4gICAgfTtcbiAgICBFbWl0dGVyTWl4aW4ucHJvdG90eXBlLmhhc0hhbmRsZXJzID0gZnVuY3Rpb24gKHR5cGUpIHtcbiAgICAgICAgcmV0dXJuICh0aGlzLl9oYW5kbGVycyAmJiB0aGlzLl9oYW5kbGVyc1t0eXBlXSAmJiB0aGlzLl9oYW5kbGVyc1t0eXBlXS5sZW5ndGgpIHx8XG4gICAgICAgICAgICAodGhpcy5fb25lSGFuZGxlcnMgJiYgdGhpcy5fb25lSGFuZGxlcnNbdHlwZV0gJiYgdGhpcy5fb25lSGFuZGxlcnNbdHlwZV0ubGVuZ3RoKTtcbiAgICB9O1xuICAgIHJldHVybiBFbWl0dGVyTWl4aW47XG59KE1peGluKSk7XG5mdW5jdGlvbiBhZGRUb0hhc2goaGFzaCwgdHlwZSwgaGFuZGxlcikge1xuICAgIChoYXNoW3R5cGVdIHx8IChoYXNoW3R5cGVdID0gW10pKVxuICAgICAgICAucHVzaChoYW5kbGVyKTtcbn1cbmZ1bmN0aW9uIHJlbW92ZUZyb21IYXNoKGhhc2gsIHR5cGUsIGhhbmRsZXIpIHtcbiAgICBpZiAoaGFuZGxlcikge1xuICAgICAgICBpZiAoaGFzaFt0eXBlXSkge1xuICAgICAgICAgICAgaGFzaFt0eXBlXSA9IGhhc2hbdHlwZV0uZmlsdGVyKGZ1bmN0aW9uIChmdW5jKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZ1bmMgIT09IGhhbmRsZXI7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgZGVsZXRlIGhhc2hbdHlwZV07IC8vIHJlbW92ZSBhbGwgaGFuZGxlciBmdW5jcyBmb3IgdGhpcyB0eXBlXG4gICAgfVxufVxuXG4vKlxuUmVjb3JkcyBvZmZzZXQgaW5mb3JtYXRpb24gZm9yIGEgc2V0IG9mIGVsZW1lbnRzLCByZWxhdGl2ZSB0byBhbiBvcmlnaW4gZWxlbWVudC5cbkNhbiByZWNvcmQgdGhlIGxlZnQvcmlnaHQgT1IgdGhlIHRvcC9ib3R0b20gT1IgYm90aC5cblByb3ZpZGVzIG1ldGhvZHMgZm9yIHF1ZXJ5aW5nIHRoZSBjYWNoZSBieSBwb3NpdGlvbi5cbiovXG52YXIgUG9zaXRpb25DYWNoZSA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBQb3NpdGlvbkNhY2hlKG9yaWdpbkVsLCBlbHMsIGlzSG9yaXpvbnRhbCwgaXNWZXJ0aWNhbCkge1xuICAgICAgICB0aGlzLm9yaWdpbkVsID0gb3JpZ2luRWw7XG4gICAgICAgIHRoaXMuZWxzID0gZWxzO1xuICAgICAgICB0aGlzLmlzSG9yaXpvbnRhbCA9IGlzSG9yaXpvbnRhbDtcbiAgICAgICAgdGhpcy5pc1ZlcnRpY2FsID0gaXNWZXJ0aWNhbDtcbiAgICB9XG4gICAgLy8gUXVlcmllcyB0aGUgZWxzIGZvciBjb29yZGluYXRlcyBhbmQgc3RvcmVzIHRoZW0uXG4gICAgLy8gQ2FsbCB0aGlzIG1ldGhvZCBiZWZvcmUgdXNpbmcgYW5kIG9mIHRoZSBnZXQqIG1ldGhvZHMgYmVsb3cuXG4gICAgUG9zaXRpb25DYWNoZS5wcm90b3R5cGUuYnVpbGQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBvcmlnaW5FbCA9IHRoaXMub3JpZ2luRWw7XG4gICAgICAgIHZhciBvcmlnaW5DbGllbnRSZWN0ID0gdGhpcy5vcmlnaW5DbGllbnRSZWN0ID1cbiAgICAgICAgICAgIG9yaWdpbkVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOyAvLyByZWxhdGl2ZSB0byB2aWV3cG9ydCB0b3AtbGVmdFxuICAgICAgICBpZiAodGhpcy5pc0hvcml6b250YWwpIHtcbiAgICAgICAgICAgIHRoaXMuYnVpbGRFbEhvcml6b250YWxzKG9yaWdpbkNsaWVudFJlY3QubGVmdCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuaXNWZXJ0aWNhbCkge1xuICAgICAgICAgICAgdGhpcy5idWlsZEVsVmVydGljYWxzKG9yaWdpbkNsaWVudFJlY3QudG9wKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLy8gUG9wdWxhdGVzIHRoZSBsZWZ0L3JpZ2h0IGludGVybmFsIGNvb3JkaW5hdGUgYXJyYXlzXG4gICAgUG9zaXRpb25DYWNoZS5wcm90b3R5cGUuYnVpbGRFbEhvcml6b250YWxzID0gZnVuY3Rpb24gKG9yaWdpbkNsaWVudExlZnQpIHtcbiAgICAgICAgdmFyIGxlZnRzID0gW107XG4gICAgICAgIHZhciByaWdodHMgPSBbXTtcbiAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBfYSA9IHRoaXMuZWxzOyBfaSA8IF9hLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgdmFyIGVsID0gX2FbX2ldO1xuICAgICAgICAgICAgdmFyIHJlY3QgPSBlbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgICAgICAgIGxlZnRzLnB1c2gocmVjdC5sZWZ0IC0gb3JpZ2luQ2xpZW50TGVmdCk7XG4gICAgICAgICAgICByaWdodHMucHVzaChyZWN0LnJpZ2h0IC0gb3JpZ2luQ2xpZW50TGVmdCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5sZWZ0cyA9IGxlZnRzO1xuICAgICAgICB0aGlzLnJpZ2h0cyA9IHJpZ2h0cztcbiAgICB9O1xuICAgIC8vIFBvcHVsYXRlcyB0aGUgdG9wL2JvdHRvbSBpbnRlcm5hbCBjb29yZGluYXRlIGFycmF5c1xuICAgIFBvc2l0aW9uQ2FjaGUucHJvdG90eXBlLmJ1aWxkRWxWZXJ0aWNhbHMgPSBmdW5jdGlvbiAob3JpZ2luQ2xpZW50VG9wKSB7XG4gICAgICAgIHZhciB0b3BzID0gW107XG4gICAgICAgIHZhciBib3R0b21zID0gW107XG4gICAgICAgIGZvciAodmFyIF9pID0gMCwgX2EgPSB0aGlzLmVsczsgX2kgPCBfYS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIHZhciBlbCA9IF9hW19pXTtcbiAgICAgICAgICAgIHZhciByZWN0ID0gZWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgICB0b3BzLnB1c2gocmVjdC50b3AgLSBvcmlnaW5DbGllbnRUb3ApO1xuICAgICAgICAgICAgYm90dG9tcy5wdXNoKHJlY3QuYm90dG9tIC0gb3JpZ2luQ2xpZW50VG9wKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnRvcHMgPSB0b3BzO1xuICAgICAgICB0aGlzLmJvdHRvbXMgPSBib3R0b21zO1xuICAgIH07XG4gICAgLy8gR2l2ZW4gYSBsZWZ0IG9mZnNldCAoZnJvbSBkb2N1bWVudCBsZWZ0KSwgcmV0dXJucyB0aGUgaW5kZXggb2YgdGhlIGVsIHRoYXQgaXQgaG9yaXpvbnRhbGx5IGludGVyc2VjdHMuXG4gICAgLy8gSWYgbm8gaW50ZXJzZWN0aW9uIGlzIG1hZGUsIHJldHVybnMgdW5kZWZpbmVkLlxuICAgIFBvc2l0aW9uQ2FjaGUucHJvdG90eXBlLmxlZnRUb0luZGV4ID0gZnVuY3Rpb24gKGxlZnRQb3NpdGlvbikge1xuICAgICAgICB2YXIgbGVmdHMgPSB0aGlzLmxlZnRzO1xuICAgICAgICB2YXIgcmlnaHRzID0gdGhpcy5yaWdodHM7XG4gICAgICAgIHZhciBsZW4gPSBsZWZ0cy5sZW5ndGg7XG4gICAgICAgIHZhciBpO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChsZWZ0UG9zaXRpb24gPj0gbGVmdHNbaV0gJiYgbGVmdFBvc2l0aW9uIDwgcmlnaHRzW2ldKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8vIEdpdmVuIGEgdG9wIG9mZnNldCAoZnJvbSBkb2N1bWVudCB0b3ApLCByZXR1cm5zIHRoZSBpbmRleCBvZiB0aGUgZWwgdGhhdCBpdCB2ZXJ0aWNhbGx5IGludGVyc2VjdHMuXG4gICAgLy8gSWYgbm8gaW50ZXJzZWN0aW9uIGlzIG1hZGUsIHJldHVybnMgdW5kZWZpbmVkLlxuICAgIFBvc2l0aW9uQ2FjaGUucHJvdG90eXBlLnRvcFRvSW5kZXggPSBmdW5jdGlvbiAodG9wUG9zaXRpb24pIHtcbiAgICAgICAgdmFyIHRvcHMgPSB0aGlzLnRvcHM7XG4gICAgICAgIHZhciBib3R0b21zID0gdGhpcy5ib3R0b21zO1xuICAgICAgICB2YXIgbGVuID0gdG9wcy5sZW5ndGg7XG4gICAgICAgIHZhciBpO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgICAgICAgIGlmICh0b3BQb3NpdGlvbiA+PSB0b3BzW2ldICYmIHRvcFBvc2l0aW9uIDwgYm90dG9tc1tpXSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcbiAgICAvLyBHZXRzIHRoZSB3aWR0aCBvZiB0aGUgZWxlbWVudCBhdCB0aGUgZ2l2ZW4gaW5kZXhcbiAgICBQb3NpdGlvbkNhY2hlLnByb3RvdHlwZS5nZXRXaWR0aCA9IGZ1bmN0aW9uIChsZWZ0SW5kZXgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucmlnaHRzW2xlZnRJbmRleF0gLSB0aGlzLmxlZnRzW2xlZnRJbmRleF07XG4gICAgfTtcbiAgICAvLyBHZXRzIHRoZSBoZWlnaHQgb2YgdGhlIGVsZW1lbnQgYXQgdGhlIGdpdmVuIGluZGV4XG4gICAgUG9zaXRpb25DYWNoZS5wcm90b3R5cGUuZ2V0SGVpZ2h0ID0gZnVuY3Rpb24gKHRvcEluZGV4KSB7XG4gICAgICAgIHJldHVybiB0aGlzLmJvdHRvbXNbdG9wSW5kZXhdIC0gdGhpcy50b3BzW3RvcEluZGV4XTtcbiAgICB9O1xuICAgIHJldHVybiBQb3NpdGlvbkNhY2hlO1xufSgpKTtcblxuLypcbkFuIG9iamVjdCBmb3IgZ2V0dGluZy9zZXR0aW5nIHNjcm9sbC1yZWxhdGVkIGluZm9ybWF0aW9uIGZvciBhbiBlbGVtZW50LlxuSW50ZXJuYWxseSwgdGhpcyBpcyBkb25lIHZlcnkgZGlmZmVyZW50bHkgZm9yIHdpbmRvdyB2ZXJzdXMgRE9NIGVsZW1lbnQsXG5zbyB0aGlzIG9iamVjdCBzZXJ2ZXMgYXMgYSBjb21tb24gaW50ZXJmYWNlLlxuKi9cbnZhciBTY3JvbGxDb250cm9sbGVyID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIFNjcm9sbENvbnRyb2xsZXIoKSB7XG4gICAgfVxuICAgIFNjcm9sbENvbnRyb2xsZXIucHJvdG90eXBlLmdldE1heFNjcm9sbFRvcCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0U2Nyb2xsSGVpZ2h0KCkgLSB0aGlzLmdldENsaWVudEhlaWdodCgpO1xuICAgIH07XG4gICAgU2Nyb2xsQ29udHJvbGxlci5wcm90b3R5cGUuZ2V0TWF4U2Nyb2xsTGVmdCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0U2Nyb2xsV2lkdGgoKSAtIHRoaXMuZ2V0Q2xpZW50V2lkdGgoKTtcbiAgICB9O1xuICAgIFNjcm9sbENvbnRyb2xsZXIucHJvdG90eXBlLmNhblNjcm9sbFZlcnRpY2FsbHkgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldE1heFNjcm9sbFRvcCgpID4gMDtcbiAgICB9O1xuICAgIFNjcm9sbENvbnRyb2xsZXIucHJvdG90eXBlLmNhblNjcm9sbEhvcml6b250YWxseSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0TWF4U2Nyb2xsTGVmdCgpID4gMDtcbiAgICB9O1xuICAgIFNjcm9sbENvbnRyb2xsZXIucHJvdG90eXBlLmNhblNjcm9sbFVwID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRTY3JvbGxUb3AoKSA+IDA7XG4gICAgfTtcbiAgICBTY3JvbGxDb250cm9sbGVyLnByb3RvdHlwZS5jYW5TY3JvbGxEb3duID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRTY3JvbGxUb3AoKSA8IHRoaXMuZ2V0TWF4U2Nyb2xsVG9wKCk7XG4gICAgfTtcbiAgICBTY3JvbGxDb250cm9sbGVyLnByb3RvdHlwZS5jYW5TY3JvbGxMZWZ0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRTY3JvbGxMZWZ0KCkgPiAwO1xuICAgIH07XG4gICAgU2Nyb2xsQ29udHJvbGxlci5wcm90b3R5cGUuY2FuU2Nyb2xsUmlnaHQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFNjcm9sbExlZnQoKSA8IHRoaXMuZ2V0TWF4U2Nyb2xsTGVmdCgpO1xuICAgIH07XG4gICAgcmV0dXJuIFNjcm9sbENvbnRyb2xsZXI7XG59KCkpO1xudmFyIEVsZW1lbnRTY3JvbGxDb250cm9sbGVyID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKF9zdXBlcikge1xuICAgIF9fZXh0ZW5kcyhFbGVtZW50U2Nyb2xsQ29udHJvbGxlciwgX3N1cGVyKTtcbiAgICBmdW5jdGlvbiBFbGVtZW50U2Nyb2xsQ29udHJvbGxlcihlbCkge1xuICAgICAgICB2YXIgX3RoaXMgPSBfc3VwZXIuY2FsbCh0aGlzKSB8fCB0aGlzO1xuICAgICAgICBfdGhpcy5lbCA9IGVsO1xuICAgICAgICByZXR1cm4gX3RoaXM7XG4gICAgfVxuICAgIEVsZW1lbnRTY3JvbGxDb250cm9sbGVyLnByb3RvdHlwZS5nZXRTY3JvbGxUb3AgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmVsLnNjcm9sbFRvcDtcbiAgICB9O1xuICAgIEVsZW1lbnRTY3JvbGxDb250cm9sbGVyLnByb3RvdHlwZS5nZXRTY3JvbGxMZWZ0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5lbC5zY3JvbGxMZWZ0O1xuICAgIH07XG4gICAgRWxlbWVudFNjcm9sbENvbnRyb2xsZXIucHJvdG90eXBlLnNldFNjcm9sbFRvcCA9IGZ1bmN0aW9uICh0b3ApIHtcbiAgICAgICAgdGhpcy5lbC5zY3JvbGxUb3AgPSB0b3A7XG4gICAgfTtcbiAgICBFbGVtZW50U2Nyb2xsQ29udHJvbGxlci5wcm90b3R5cGUuc2V0U2Nyb2xsTGVmdCA9IGZ1bmN0aW9uIChsZWZ0KSB7XG4gICAgICAgIHRoaXMuZWwuc2Nyb2xsTGVmdCA9IGxlZnQ7XG4gICAgfTtcbiAgICBFbGVtZW50U2Nyb2xsQ29udHJvbGxlci5wcm90b3R5cGUuZ2V0U2Nyb2xsV2lkdGggPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmVsLnNjcm9sbFdpZHRoO1xuICAgIH07XG4gICAgRWxlbWVudFNjcm9sbENvbnRyb2xsZXIucHJvdG90eXBlLmdldFNjcm9sbEhlaWdodCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZWwuc2Nyb2xsSGVpZ2h0O1xuICAgIH07XG4gICAgRWxlbWVudFNjcm9sbENvbnRyb2xsZXIucHJvdG90eXBlLmdldENsaWVudEhlaWdodCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZWwuY2xpZW50SGVpZ2h0O1xuICAgIH07XG4gICAgRWxlbWVudFNjcm9sbENvbnRyb2xsZXIucHJvdG90eXBlLmdldENsaWVudFdpZHRoID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5lbC5jbGllbnRXaWR0aDtcbiAgICB9O1xuICAgIHJldHVybiBFbGVtZW50U2Nyb2xsQ29udHJvbGxlcjtcbn0oU2Nyb2xsQ29udHJvbGxlcikpO1xudmFyIFdpbmRvd1Njcm9sbENvbnRyb2xsZXIgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoX3N1cGVyKSB7XG4gICAgX19leHRlbmRzKFdpbmRvd1Njcm9sbENvbnRyb2xsZXIsIF9zdXBlcik7XG4gICAgZnVuY3Rpb24gV2luZG93U2Nyb2xsQ29udHJvbGxlcigpIHtcbiAgICAgICAgcmV0dXJuIF9zdXBlciAhPT0gbnVsbCAmJiBfc3VwZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKSB8fCB0aGlzO1xuICAgIH1cbiAgICBXaW5kb3dTY3JvbGxDb250cm9sbGVyLnByb3RvdHlwZS5nZXRTY3JvbGxUb3AgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB3aW5kb3cucGFnZVlPZmZzZXQ7XG4gICAgfTtcbiAgICBXaW5kb3dTY3JvbGxDb250cm9sbGVyLnByb3RvdHlwZS5nZXRTY3JvbGxMZWZ0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gd2luZG93LnBhZ2VYT2Zmc2V0O1xuICAgIH07XG4gICAgV2luZG93U2Nyb2xsQ29udHJvbGxlci5wcm90b3R5cGUuc2V0U2Nyb2xsVG9wID0gZnVuY3Rpb24gKG4pIHtcbiAgICAgICAgd2luZG93LnNjcm9sbCh3aW5kb3cucGFnZVhPZmZzZXQsIG4pO1xuICAgIH07XG4gICAgV2luZG93U2Nyb2xsQ29udHJvbGxlci5wcm90b3R5cGUuc2V0U2Nyb2xsTGVmdCA9IGZ1bmN0aW9uIChuKSB7XG4gICAgICAgIHdpbmRvdy5zY3JvbGwobiwgd2luZG93LnBhZ2VZT2Zmc2V0KTtcbiAgICB9O1xuICAgIFdpbmRvd1Njcm9sbENvbnRyb2xsZXIucHJvdG90eXBlLmdldFNjcm9sbFdpZHRoID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbFdpZHRoO1xuICAgIH07XG4gICAgV2luZG93U2Nyb2xsQ29udHJvbGxlci5wcm90b3R5cGUuZ2V0U2Nyb2xsSGVpZ2h0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbEhlaWdodDtcbiAgICB9O1xuICAgIFdpbmRvd1Njcm9sbENvbnRyb2xsZXIucHJvdG90eXBlLmdldENsaWVudEhlaWdodCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRIZWlnaHQ7XG4gICAgfTtcbiAgICBXaW5kb3dTY3JvbGxDb250cm9sbGVyLnByb3RvdHlwZS5nZXRDbGllbnRXaWR0aCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRXaWR0aDtcbiAgICB9O1xuICAgIHJldHVybiBXaW5kb3dTY3JvbGxDb250cm9sbGVyO1xufShTY3JvbGxDb250cm9sbGVyKSk7XG5cbi8qXG5FbWJvZGllcyBhIGRpdiB0aGF0IGhhcyBwb3RlbnRpYWwgc2Nyb2xsYmFyc1xuKi9cbnZhciBTY3JvbGxDb21wb25lbnQgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoX3N1cGVyKSB7XG4gICAgX19leHRlbmRzKFNjcm9sbENvbXBvbmVudCwgX3N1cGVyKTtcbiAgICBmdW5jdGlvbiBTY3JvbGxDb21wb25lbnQob3ZlcmZsb3dYLCBvdmVyZmxvd1kpIHtcbiAgICAgICAgdmFyIF90aGlzID0gX3N1cGVyLmNhbGwodGhpcywgY3JlYXRlRWxlbWVudCgnZGl2Jywge1xuICAgICAgICAgICAgY2xhc3NOYW1lOiAnZmMtc2Nyb2xsZXInXG4gICAgICAgIH0pKSB8fCB0aGlzO1xuICAgICAgICBfdGhpcy5vdmVyZmxvd1ggPSBvdmVyZmxvd1g7XG4gICAgICAgIF90aGlzLm92ZXJmbG93WSA9IG92ZXJmbG93WTtcbiAgICAgICAgX3RoaXMuYXBwbHlPdmVyZmxvdygpO1xuICAgICAgICByZXR1cm4gX3RoaXM7XG4gICAgfVxuICAgIC8vIHNldHMgdG8gbmF0dXJhbCBoZWlnaHQsIHVubG9ja3Mgb3ZlcmZsb3dcbiAgICBTY3JvbGxDb21wb25lbnQucHJvdG90eXBlLmNsZWFyID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnNldEhlaWdodCgnYXV0bycpO1xuICAgICAgICB0aGlzLmFwcGx5T3ZlcmZsb3coKTtcbiAgICB9O1xuICAgIFNjcm9sbENvbXBvbmVudC5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmVtb3ZlRWxlbWVudCh0aGlzLmVsKTtcbiAgICB9O1xuICAgIC8vIE92ZXJmbG93XG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBTY3JvbGxDb21wb25lbnQucHJvdG90eXBlLmFwcGx5T3ZlcmZsb3cgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGFwcGx5U3R5bGUodGhpcy5lbCwge1xuICAgICAgICAgICAgb3ZlcmZsb3dYOiB0aGlzLm92ZXJmbG93WCxcbiAgICAgICAgICAgIG92ZXJmbG93WTogdGhpcy5vdmVyZmxvd1lcbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICAvLyBDYXVzZXMgYW55ICdhdXRvJyBvdmVyZmxvdyB2YWx1ZXMgdG8gcmVzb2x2ZXMgdG8gJ3Njcm9sbCcgb3IgJ2hpZGRlbicuXG4gICAgLy8gVXNlZnVsIGZvciBwcmVzZXJ2aW5nIHNjcm9sbGJhciB3aWR0aHMgcmVnYXJkbGVzcyBvZiBmdXR1cmUgcmVzaXplcy5cbiAgICAvLyBDYW4gcGFzcyBpbiBzY3JvbGxiYXJXaWR0aHMgZm9yIG9wdGltaXphdGlvbi5cbiAgICBTY3JvbGxDb21wb25lbnQucHJvdG90eXBlLmxvY2tPdmVyZmxvdyA9IGZ1bmN0aW9uIChzY3JvbGxiYXJXaWR0aHMpIHtcbiAgICAgICAgdmFyIG92ZXJmbG93WCA9IHRoaXMub3ZlcmZsb3dYO1xuICAgICAgICB2YXIgb3ZlcmZsb3dZID0gdGhpcy5vdmVyZmxvd1k7XG4gICAgICAgIHNjcm9sbGJhcldpZHRocyA9IHNjcm9sbGJhcldpZHRocyB8fCB0aGlzLmdldFNjcm9sbGJhcldpZHRocygpO1xuICAgICAgICBpZiAob3ZlcmZsb3dYID09PSAnYXV0bycpIHtcbiAgICAgICAgICAgIG92ZXJmbG93WCA9IChzY3JvbGxiYXJXaWR0aHMuYm90dG9tIHx8IC8vIGhvcml6b250YWwgc2Nyb2xsYmFycz9cbiAgICAgICAgICAgICAgICB0aGlzLmNhblNjcm9sbEhvcml6b250YWxseSgpIC8vIE9SIHNjcm9sbGluZyBwYW5lIHdpdGggbWFzc2xlc3Mgc2Nyb2xsYmFycz9cbiAgICAgICAgICAgICkgPyAnc2Nyb2xsJyA6ICdoaWRkZW4nO1xuICAgICAgICB9XG4gICAgICAgIGlmIChvdmVyZmxvd1kgPT09ICdhdXRvJykge1xuICAgICAgICAgICAgb3ZlcmZsb3dZID0gKHNjcm9sbGJhcldpZHRocy5sZWZ0IHx8IHNjcm9sbGJhcldpZHRocy5yaWdodCB8fCAvLyBob3Jpem9udGFsIHNjcm9sbGJhcnM/XG4gICAgICAgICAgICAgICAgdGhpcy5jYW5TY3JvbGxWZXJ0aWNhbGx5KCkgLy8gT1Igc2Nyb2xsaW5nIHBhbmUgd2l0aCBtYXNzbGVzcyBzY3JvbGxiYXJzP1xuICAgICAgICAgICAgKSA/ICdzY3JvbGwnIDogJ2hpZGRlbic7XG4gICAgICAgIH1cbiAgICAgICAgYXBwbHlTdHlsZSh0aGlzLmVsLCB7IG92ZXJmbG93WDogb3ZlcmZsb3dYLCBvdmVyZmxvd1k6IG92ZXJmbG93WSB9KTtcbiAgICB9O1xuICAgIFNjcm9sbENvbXBvbmVudC5wcm90b3R5cGUuc2V0SGVpZ2h0ID0gZnVuY3Rpb24gKGhlaWdodCkge1xuICAgICAgICBhcHBseVN0eWxlUHJvcCh0aGlzLmVsLCAnaGVpZ2h0JywgaGVpZ2h0KTtcbiAgICB9O1xuICAgIFNjcm9sbENvbXBvbmVudC5wcm90b3R5cGUuZ2V0U2Nyb2xsYmFyV2lkdGhzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgZWRnZXMgPSBjb21wdXRlRWRnZXModGhpcy5lbCk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBsZWZ0OiBlZGdlcy5zY3JvbGxiYXJMZWZ0LFxuICAgICAgICAgICAgcmlnaHQ6IGVkZ2VzLnNjcm9sbGJhclJpZ2h0LFxuICAgICAgICAgICAgYm90dG9tOiBlZGdlcy5zY3JvbGxiYXJCb3R0b21cbiAgICAgICAgfTtcbiAgICB9O1xuICAgIHJldHVybiBTY3JvbGxDb21wb25lbnQ7XG59KEVsZW1lbnRTY3JvbGxDb250cm9sbGVyKSk7XG5cbnZhciBUaGVtZSA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBUaGVtZShjYWxlbmRhck9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5jYWxlbmRhck9wdGlvbnMgPSBjYWxlbmRhck9wdGlvbnM7XG4gICAgICAgIHRoaXMucHJvY2Vzc0ljb25PdmVycmlkZSgpO1xuICAgIH1cbiAgICBUaGVtZS5wcm90b3R5cGUucHJvY2Vzc0ljb25PdmVycmlkZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRoaXMuaWNvbk92ZXJyaWRlT3B0aW9uKSB7XG4gICAgICAgICAgICB0aGlzLnNldEljb25PdmVycmlkZSh0aGlzLmNhbGVuZGFyT3B0aW9uc1t0aGlzLmljb25PdmVycmlkZU9wdGlvbl0pO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBUaGVtZS5wcm90b3R5cGUuc2V0SWNvbk92ZXJyaWRlID0gZnVuY3Rpb24gKGljb25PdmVycmlkZUhhc2gpIHtcbiAgICAgICAgdmFyIGljb25DbGFzc2VzQ29weTtcbiAgICAgICAgdmFyIGJ1dHRvbk5hbWU7XG4gICAgICAgIGlmICh0eXBlb2YgaWNvbk92ZXJyaWRlSGFzaCA9PT0gJ29iamVjdCcgJiYgaWNvbk92ZXJyaWRlSGFzaCkgeyAvLyBub24tbnVsbCBvYmplY3RcbiAgICAgICAgICAgIGljb25DbGFzc2VzQ29weSA9IF9fYXNzaWduKHt9LCB0aGlzLmljb25DbGFzc2VzKTtcbiAgICAgICAgICAgIGZvciAoYnV0dG9uTmFtZSBpbiBpY29uT3ZlcnJpZGVIYXNoKSB7XG4gICAgICAgICAgICAgICAgaWNvbkNsYXNzZXNDb3B5W2J1dHRvbk5hbWVdID0gdGhpcy5hcHBseUljb25PdmVycmlkZVByZWZpeChpY29uT3ZlcnJpZGVIYXNoW2J1dHRvbk5hbWVdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuaWNvbkNsYXNzZXMgPSBpY29uQ2xhc3Nlc0NvcHk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoaWNvbk92ZXJyaWRlSGFzaCA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgIHRoaXMuaWNvbkNsYXNzZXMgPSB7fTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgVGhlbWUucHJvdG90eXBlLmFwcGx5SWNvbk92ZXJyaWRlUHJlZml4ID0gZnVuY3Rpb24gKGNsYXNzTmFtZSkge1xuICAgICAgICB2YXIgcHJlZml4ID0gdGhpcy5pY29uT3ZlcnJpZGVQcmVmaXg7XG4gICAgICAgIGlmIChwcmVmaXggJiYgY2xhc3NOYW1lLmluZGV4T2YocHJlZml4KSAhPT0gMCkgeyAvLyBpZiBub3QgYWxyZWFkeSBwcmVzZW50XG4gICAgICAgICAgICBjbGFzc05hbWUgPSBwcmVmaXggKyBjbGFzc05hbWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGNsYXNzTmFtZTtcbiAgICB9O1xuICAgIFRoZW1lLnByb3RvdHlwZS5nZXRDbGFzcyA9IGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2xhc3Nlc1trZXldIHx8ICcnO1xuICAgIH07XG4gICAgVGhlbWUucHJvdG90eXBlLmdldEljb25DbGFzcyA9IGZ1bmN0aW9uIChidXR0b25OYW1lKSB7XG4gICAgICAgIHZhciBjbGFzc05hbWUgPSB0aGlzLmljb25DbGFzc2VzW2J1dHRvbk5hbWVdO1xuICAgICAgICBpZiAoY2xhc3NOYW1lKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5iYXNlSWNvbkNsYXNzICsgJyAnICsgY2xhc3NOYW1lO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9O1xuICAgIFRoZW1lLnByb3RvdHlwZS5nZXRDdXN0b21CdXR0b25JY29uQ2xhc3MgPSBmdW5jdGlvbiAoY3VzdG9tQnV0dG9uUHJvcHMpIHtcbiAgICAgICAgdmFyIGNsYXNzTmFtZTtcbiAgICAgICAgaWYgKHRoaXMuaWNvbk92ZXJyaWRlQ3VzdG9tQnV0dG9uT3B0aW9uKSB7XG4gICAgICAgICAgICBjbGFzc05hbWUgPSBjdXN0b21CdXR0b25Qcm9wc1t0aGlzLmljb25PdmVycmlkZUN1c3RvbUJ1dHRvbk9wdGlvbl07XG4gICAgICAgICAgICBpZiAoY2xhc3NOYW1lKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuYmFzZUljb25DbGFzcyArICcgJyArIHRoaXMuYXBwbHlJY29uT3ZlcnJpZGVQcmVmaXgoY2xhc3NOYW1lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gJyc7XG4gICAgfTtcbiAgICByZXR1cm4gVGhlbWU7XG59KCkpO1xuVGhlbWUucHJvdG90eXBlLmNsYXNzZXMgPSB7fTtcblRoZW1lLnByb3RvdHlwZS5pY29uQ2xhc3NlcyA9IHt9O1xuVGhlbWUucHJvdG90eXBlLmJhc2VJY29uQ2xhc3MgPSAnJztcblRoZW1lLnByb3RvdHlwZS5pY29uT3ZlcnJpZGVQcmVmaXggPSAnJztcblxudmFyIGd1aWQgPSAwO1xudmFyIENvbXBvbmVudENvbnRleHQgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gQ29tcG9uZW50Q29udGV4dChjYWxlbmRhciwgdGhlbWUsIGRhdGVFbnYsIG9wdGlvbnMsIHZpZXcpIHtcbiAgICAgICAgdGhpcy5jYWxlbmRhciA9IGNhbGVuZGFyO1xuICAgICAgICB0aGlzLnRoZW1lID0gdGhlbWU7XG4gICAgICAgIHRoaXMuZGF0ZUVudiA9IGRhdGVFbnY7XG4gICAgICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgICAgIHRoaXMudmlldyA9IHZpZXc7XG4gICAgICAgIHRoaXMuaXNSdGwgPSBvcHRpb25zLmRpciA9PT0gJ3J0bCc7XG4gICAgICAgIHRoaXMuZXZlbnRPcmRlclNwZWNzID0gcGFyc2VGaWVsZFNwZWNzKG9wdGlvbnMuZXZlbnRPcmRlcik7XG4gICAgICAgIHRoaXMubmV4dERheVRocmVzaG9sZCA9IGNyZWF0ZUR1cmF0aW9uKG9wdGlvbnMubmV4dERheVRocmVzaG9sZCk7XG4gICAgfVxuICAgIENvbXBvbmVudENvbnRleHQucHJvdG90eXBlLmV4dGVuZCA9IGZ1bmN0aW9uIChvcHRpb25zLCB2aWV3KSB7XG4gICAgICAgIHJldHVybiBuZXcgQ29tcG9uZW50Q29udGV4dCh0aGlzLmNhbGVuZGFyLCB0aGlzLnRoZW1lLCB0aGlzLmRhdGVFbnYsIG9wdGlvbnMgfHwgdGhpcy5vcHRpb25zLCB2aWV3IHx8IHRoaXMudmlldyk7XG4gICAgfTtcbiAgICByZXR1cm4gQ29tcG9uZW50Q29udGV4dDtcbn0oKSk7XG52YXIgQ29tcG9uZW50ID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIENvbXBvbmVudCgpIHtcbiAgICAgICAgdGhpcy51aWQgPSBTdHJpbmcoZ3VpZCsrKTtcbiAgICB9XG4gICAgQ29tcG9uZW50LmFkZEVxdWFsaXR5RnVuY3MgPSBmdW5jdGlvbiAobmV3RnVuY3MpIHtcbiAgICAgICAgdGhpcy5wcm90b3R5cGUuZXF1YWxpdHlGdW5jcyA9IF9fYXNzaWduKHt9LCB0aGlzLnByb3RvdHlwZS5lcXVhbGl0eUZ1bmNzLCBuZXdGdW5jcyk7XG4gICAgfTtcbiAgICBDb21wb25lbnQucHJvdG90eXBlLnJlY2VpdmVQcm9wcyA9IGZ1bmN0aW9uIChwcm9wcywgY29udGV4dCkge1xuICAgICAgICB2YXIgb2xkQ29udGV4dCA9IHRoaXMuY29udGV4dDtcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gY29udGV4dDtcbiAgICAgICAgaWYgKCFvbGRDb250ZXh0KSB7XG4gICAgICAgICAgICB0aGlzLmZpcnN0Q29udGV4dChjb250ZXh0KTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgX2EgPSByZWN5Y2xlUHJvcHModGhpcy5wcm9wcyB8fCB7fSwgcHJvcHMsIHRoaXMuZXF1YWxpdHlGdW5jcyksIGFueUNoYW5nZXMgPSBfYS5hbnlDaGFuZ2VzLCBjb21ib1Byb3BzID0gX2EuY29tYm9Qcm9wcztcbiAgICAgICAgdGhpcy5wcm9wcyA9IGNvbWJvUHJvcHM7XG4gICAgICAgIGlmIChhbnlDaGFuZ2VzKSB7XG4gICAgICAgICAgICBpZiAob2xkQ29udGV4dCkge1xuICAgICAgICAgICAgICAgIHRoaXMuYmVmb3JlVXBkYXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnJlbmRlcihjb21ib1Byb3BzLCBjb250ZXh0KTtcbiAgICAgICAgICAgIGlmIChvbGRDb250ZXh0KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5hZnRlclVwZGF0ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcbiAgICBDb21wb25lbnQucHJvdG90eXBlLnJlbmRlciA9IGZ1bmN0aW9uIChwcm9wcywgY29udGV4dCkge1xuICAgIH07XG4gICAgQ29tcG9uZW50LnByb3RvdHlwZS5maXJzdENvbnRleHQgPSBmdW5jdGlvbiAoY29udGV4dCkge1xuICAgIH07XG4gICAgQ29tcG9uZW50LnByb3RvdHlwZS5iZWZvcmVVcGRhdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgfTtcbiAgICBDb21wb25lbnQucHJvdG90eXBlLmFmdGVyVXBkYXRlID0gZnVuY3Rpb24gKCkge1xuICAgIH07XG4gICAgLy8gYWZ0ZXIgZGVzdHJveSBpcyBjYWxsZWQsIHRoaXMgY29tcG9uZW50IHdvbid0IGV2ZXIgYmUgdXNlZCBhZ2FpblxuICAgIENvbXBvbmVudC5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICB9O1xuICAgIHJldHVybiBDb21wb25lbnQ7XG59KCkpO1xuQ29tcG9uZW50LnByb3RvdHlwZS5lcXVhbGl0eUZ1bmNzID0ge307XG4vKlxuUmV1c2VzIG9sZCB2YWx1ZXMgd2hlbiBlcXVhbC4gSWYgYW55dGhpbmcgaXMgdW5lcXVhbCwgcmV0dXJucyBuZXdQcm9wcyBhcy1pcy5cbkdyZWF0IGZvciBQdXJlQ29tcG9uZW50LCBidXQgd29uJ3QgYmUgZmVhc2libGUgd2l0aCBSZWFjdCwgc28ganVzdCBlbGltaW5hdGUgYW5kIHVzZSBSZWFjdCdzIERPTSBkaWZmaW5nLlxuKi9cbmZ1bmN0aW9uIHJlY3ljbGVQcm9wcyhvbGRQcm9wcywgbmV3UHJvcHMsIGVxdWFsaXR5RnVuY3MpIHtcbiAgICB2YXIgY29tYm9Qcm9wcyA9IHt9OyAvLyBzb21lIG9sZCwgc29tZSBuZXdcbiAgICB2YXIgYW55Q2hhbmdlcyA9IGZhbHNlO1xuICAgIGZvciAodmFyIGtleSBpbiBuZXdQcm9wcykge1xuICAgICAgICBpZiAoa2V5IGluIG9sZFByb3BzICYmIChvbGRQcm9wc1trZXldID09PSBuZXdQcm9wc1trZXldIHx8XG4gICAgICAgICAgICAoZXF1YWxpdHlGdW5jc1trZXldICYmIGVxdWFsaXR5RnVuY3Nba2V5XShvbGRQcm9wc1trZXldLCBuZXdQcm9wc1trZXldKSkpKSB7XG4gICAgICAgICAgICAvLyBlcXVhbCB0byBvbGQ/IHVzZSBvbGQgcHJvcFxuICAgICAgICAgICAgY29tYm9Qcm9wc1trZXldID0gb2xkUHJvcHNba2V5XTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNvbWJvUHJvcHNba2V5XSA9IG5ld1Byb3BzW2tleV07XG4gICAgICAgICAgICBhbnlDaGFuZ2VzID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBmb3IgKHZhciBrZXkgaW4gb2xkUHJvcHMpIHtcbiAgICAgICAgaWYgKCEoa2V5IGluIG5ld1Byb3BzKSkge1xuICAgICAgICAgICAgYW55Q2hhbmdlcyA9IHRydWU7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4geyBhbnlDaGFuZ2VzOiBhbnlDaGFuZ2VzLCBjb21ib1Byb3BzOiBjb21ib1Byb3BzIH07XG59XG5cbi8qXG5QVVJQT1NFUzpcbi0gaG9vayB1cCB0byBmZywgZmlsbCwgYW5kIG1pcnJvciByZW5kZXJlcnNcbi0gaW50ZXJmYWNlIGZvciBkcmFnZ2luZyBhbmQgaGl0c1xuKi9cbnZhciBEYXRlQ29tcG9uZW50ID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKF9zdXBlcikge1xuICAgIF9fZXh0ZW5kcyhEYXRlQ29tcG9uZW50LCBfc3VwZXIpO1xuICAgIGZ1bmN0aW9uIERhdGVDb21wb25lbnQoZWwpIHtcbiAgICAgICAgdmFyIF90aGlzID0gX3N1cGVyLmNhbGwodGhpcykgfHwgdGhpcztcbiAgICAgICAgX3RoaXMuZWwgPSBlbDtcbiAgICAgICAgcmV0dXJuIF90aGlzO1xuICAgIH1cbiAgICBEYXRlQ29tcG9uZW50LnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBfc3VwZXIucHJvdG90eXBlLmRlc3Ryb3kuY2FsbCh0aGlzKTtcbiAgICAgICAgcmVtb3ZlRWxlbWVudCh0aGlzLmVsKTtcbiAgICB9O1xuICAgIC8vIEhpdCBTeXN0ZW1cbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIERhdGVDb21wb25lbnQucHJvdG90eXBlLmJ1aWxkUG9zaXRpb25DYWNoZXMgPSBmdW5jdGlvbiAoKSB7XG4gICAgfTtcbiAgICBEYXRlQ29tcG9uZW50LnByb3RvdHlwZS5xdWVyeUhpdCA9IGZ1bmN0aW9uIChwb3NpdGlvbkxlZnQsIHBvc2l0aW9uVG9wLCBlbFdpZHRoLCBlbEhlaWdodCkge1xuICAgICAgICByZXR1cm4gbnVsbDsgLy8gdGhpcyBzaG91bGQgYmUgYWJzdHJhY3RcbiAgICB9O1xuICAgIC8vIFZhbGlkYXRpb25cbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIERhdGVDb21wb25lbnQucHJvdG90eXBlLmlzSW50ZXJhY3Rpb25WYWxpZCA9IGZ1bmN0aW9uIChpbnRlcmFjdGlvbikge1xuICAgICAgICB2YXIgY2FsZW5kYXIgPSB0aGlzLmNvbnRleHQuY2FsZW5kYXI7XG4gICAgICAgIHZhciBkYXRlUHJvZmlsZSA9IHRoaXMucHJvcHMuZGF0ZVByb2ZpbGU7IC8vIEhBQ0tcbiAgICAgICAgdmFyIGluc3RhbmNlcyA9IGludGVyYWN0aW9uLm11dGF0ZWRFdmVudHMuaW5zdGFuY2VzO1xuICAgICAgICBpZiAoZGF0ZVByb2ZpbGUpIHsgLy8gSEFDSyBmb3IgRGF5VGlsZVxuICAgICAgICAgICAgZm9yICh2YXIgaW5zdGFuY2VJZCBpbiBpbnN0YW5jZXMpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJhbmdlQ29udGFpbnNSYW5nZShkYXRlUHJvZmlsZS52YWxpZFJhbmdlLCBpbnN0YW5jZXNbaW5zdGFuY2VJZF0ucmFuZ2UpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGlzSW50ZXJhY3Rpb25WYWxpZChpbnRlcmFjdGlvbiwgY2FsZW5kYXIpO1xuICAgIH07XG4gICAgRGF0ZUNvbXBvbmVudC5wcm90b3R5cGUuaXNEYXRlU2VsZWN0aW9uVmFsaWQgPSBmdW5jdGlvbiAoc2VsZWN0aW9uKSB7XG4gICAgICAgIHZhciBjYWxlbmRhciA9IHRoaXMuY29udGV4dC5jYWxlbmRhcjtcbiAgICAgICAgdmFyIGRhdGVQcm9maWxlID0gdGhpcy5wcm9wcy5kYXRlUHJvZmlsZTsgLy8gSEFDS1xuICAgICAgICBpZiAoZGF0ZVByb2ZpbGUgJiYgLy8gSEFDSyBmb3IgRGF5VGlsZVxuICAgICAgICAgICAgIXJhbmdlQ29udGFpbnNSYW5nZShkYXRlUHJvZmlsZS52YWxpZFJhbmdlLCBzZWxlY3Rpb24ucmFuZ2UpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGlzRGF0ZVNlbGVjdGlvblZhbGlkKHNlbGVjdGlvbiwgY2FsZW5kYXIpO1xuICAgIH07XG4gICAgLy8gUG9pbnRlciBJbnRlcmFjdGlvbiBVdGlsc1xuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgRGF0ZUNvbXBvbmVudC5wcm90b3R5cGUuaXNWYWxpZFNlZ0Rvd25FbCA9IGZ1bmN0aW9uIChlbCkge1xuICAgICAgICByZXR1cm4gIXRoaXMucHJvcHMuZXZlbnREcmFnICYmIC8vIEhBQ0tcbiAgICAgICAgICAgICF0aGlzLnByb3BzLmV2ZW50UmVzaXplICYmIC8vIEhBQ0tcbiAgICAgICAgICAgICFlbGVtZW50Q2xvc2VzdChlbCwgJy5mYy1taXJyb3InKSAmJlxuICAgICAgICAgICAgKHRoaXMuaXNQb3BvdmVyKCkgfHwgIXRoaXMuaXNJblBvcG92ZXIoZWwpKTtcbiAgICAgICAgLy8gXmFib3ZlIGxpbmUgZW5zdXJlcyB3ZSBkb24ndCBkZXRlY3QgYSBzZWcgaW50ZXJhY3Rpb24gd2l0aGluIGEgbmVzdGVkIGNvbXBvbmVudC5cbiAgICAgICAgLy8gaXQncyBhIEhBQ0sgYmVjYXVzZSBpdCBvbmx5IHN1cHBvcnRzIGEgcG9wb3ZlciBhcyB0aGUgbmVzdGVkIGNvbXBvbmVudC5cbiAgICB9O1xuICAgIERhdGVDb21wb25lbnQucHJvdG90eXBlLmlzVmFsaWREYXRlRG93bkVsID0gZnVuY3Rpb24gKGVsKSB7XG4gICAgICAgIHZhciBzZWdFbCA9IGVsZW1lbnRDbG9zZXN0KGVsLCB0aGlzLmZnU2VnU2VsZWN0b3IpO1xuICAgICAgICByZXR1cm4gKCFzZWdFbCB8fCBzZWdFbC5jbGFzc0xpc3QuY29udGFpbnMoJ2ZjLW1pcnJvcicpKSAmJlxuICAgICAgICAgICAgIWVsZW1lbnRDbG9zZXN0KGVsLCAnLmZjLW1vcmUnKSAmJiAvLyBhIFwibW9yZS4uXCIgbGlua1xuICAgICAgICAgICAgIWVsZW1lbnRDbG9zZXN0KGVsLCAnYVtkYXRhLWdvdG9dJykgJiYgLy8gYSBjbGlja2FibGUgbmF2IGxpbmtcbiAgICAgICAgICAgICF0aGlzLmlzSW5Qb3BvdmVyKGVsKTtcbiAgICB9O1xuICAgIERhdGVDb21wb25lbnQucHJvdG90eXBlLmlzUG9wb3ZlciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZWwuY2xhc3NMaXN0LmNvbnRhaW5zKCdmYy1wb3BvdmVyJyk7XG4gICAgfTtcbiAgICBEYXRlQ29tcG9uZW50LnByb3RvdHlwZS5pc0luUG9wb3ZlciA9IGZ1bmN0aW9uIChlbCkge1xuICAgICAgICByZXR1cm4gQm9vbGVhbihlbGVtZW50Q2xvc2VzdChlbCwgJy5mYy1wb3BvdmVyJykpO1xuICAgIH07XG4gICAgcmV0dXJuIERhdGVDb21wb25lbnQ7XG59KENvbXBvbmVudCkpO1xuRGF0ZUNvbXBvbmVudC5wcm90b3R5cGUuZmdTZWdTZWxlY3RvciA9ICcuZmMtZXZlbnQtY29udGFpbmVyID4gKic7XG5EYXRlQ29tcG9uZW50LnByb3RvdHlwZS5iZ1NlZ1NlbGVjdG9yID0gJy5mYy1iZ2V2ZW50Om5vdCguZmMtbm9uYnVzaW5lc3MpJztcblxudmFyIHVpZCQxID0gMDtcbmZ1bmN0aW9uIGNyZWF0ZVBsdWdpbihpbnB1dCkge1xuICAgIHJldHVybiB7XG4gICAgICAgIGlkOiBTdHJpbmcodWlkJDErKyksXG4gICAgICAgIGRlcHM6IGlucHV0LmRlcHMgfHwgW10sXG4gICAgICAgIHJlZHVjZXJzOiBpbnB1dC5yZWR1Y2VycyB8fCBbXSxcbiAgICAgICAgZXZlbnREZWZQYXJzZXJzOiBpbnB1dC5ldmVudERlZlBhcnNlcnMgfHwgW10sXG4gICAgICAgIGlzRHJhZ2dhYmxlVHJhbnNmb3JtZXJzOiBpbnB1dC5pc0RyYWdnYWJsZVRyYW5zZm9ybWVycyB8fCBbXSxcbiAgICAgICAgZXZlbnREcmFnTXV0YXRpb25NYXNzYWdlcnM6IGlucHV0LmV2ZW50RHJhZ011dGF0aW9uTWFzc2FnZXJzIHx8IFtdLFxuICAgICAgICBldmVudERlZk11dGF0aW9uQXBwbGllcnM6IGlucHV0LmV2ZW50RGVmTXV0YXRpb25BcHBsaWVycyB8fCBbXSxcbiAgICAgICAgZGF0ZVNlbGVjdGlvblRyYW5zZm9ybWVyczogaW5wdXQuZGF0ZVNlbGVjdGlvblRyYW5zZm9ybWVycyB8fCBbXSxcbiAgICAgICAgZGF0ZVBvaW50VHJhbnNmb3JtczogaW5wdXQuZGF0ZVBvaW50VHJhbnNmb3JtcyB8fCBbXSxcbiAgICAgICAgZGF0ZVNwYW5UcmFuc2Zvcm1zOiBpbnB1dC5kYXRlU3BhblRyYW5zZm9ybXMgfHwgW10sXG4gICAgICAgIHZpZXdzOiBpbnB1dC52aWV3cyB8fCB7fSxcbiAgICAgICAgdmlld1Byb3BzVHJhbnNmb3JtZXJzOiBpbnB1dC52aWV3UHJvcHNUcmFuc2Zvcm1lcnMgfHwgW10sXG4gICAgICAgIGlzUHJvcHNWYWxpZDogaW5wdXQuaXNQcm9wc1ZhbGlkIHx8IG51bGwsXG4gICAgICAgIGV4dGVybmFsRGVmVHJhbnNmb3JtczogaW5wdXQuZXh0ZXJuYWxEZWZUcmFuc2Zvcm1zIHx8IFtdLFxuICAgICAgICBldmVudFJlc2l6ZUpvaW5UcmFuc2Zvcm1zOiBpbnB1dC5ldmVudFJlc2l6ZUpvaW5UcmFuc2Zvcm1zIHx8IFtdLFxuICAgICAgICB2aWV3Q29udGFpbmVyTW9kaWZpZXJzOiBpbnB1dC52aWV3Q29udGFpbmVyTW9kaWZpZXJzIHx8IFtdLFxuICAgICAgICBldmVudERyb3BUcmFuc2Zvcm1lcnM6IGlucHV0LmV2ZW50RHJvcFRyYW5zZm9ybWVycyB8fCBbXSxcbiAgICAgICAgY29tcG9uZW50SW50ZXJhY3Rpb25zOiBpbnB1dC5jb21wb25lbnRJbnRlcmFjdGlvbnMgfHwgW10sXG4gICAgICAgIGNhbGVuZGFySW50ZXJhY3Rpb25zOiBpbnB1dC5jYWxlbmRhckludGVyYWN0aW9ucyB8fCBbXSxcbiAgICAgICAgdGhlbWVDbGFzc2VzOiBpbnB1dC50aGVtZUNsYXNzZXMgfHwge30sXG4gICAgICAgIGV2ZW50U291cmNlRGVmczogaW5wdXQuZXZlbnRTb3VyY2VEZWZzIHx8IFtdLFxuICAgICAgICBjbWRGb3JtYXR0ZXI6IGlucHV0LmNtZEZvcm1hdHRlcixcbiAgICAgICAgcmVjdXJyaW5nVHlwZXM6IGlucHV0LnJlY3VycmluZ1R5cGVzIHx8IFtdLFxuICAgICAgICBuYW1lZFRpbWVab25lZEltcGw6IGlucHV0Lm5hbWVkVGltZVpvbmVkSW1wbCxcbiAgICAgICAgZGVmYXVsdFZpZXc6IGlucHV0LmRlZmF1bHRWaWV3IHx8ICcnLFxuICAgICAgICBlbGVtZW50RHJhZ2dpbmdJbXBsOiBpbnB1dC5lbGVtZW50RHJhZ2dpbmdJbXBsLFxuICAgICAgICBvcHRpb25DaGFuZ2VIYW5kbGVyczogaW5wdXQub3B0aW9uQ2hhbmdlSGFuZGxlcnMgfHwge31cbiAgICB9O1xufVxudmFyIFBsdWdpblN5c3RlbSA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBQbHVnaW5TeXN0ZW0oKSB7XG4gICAgICAgIHRoaXMuaG9va3MgPSB7XG4gICAgICAgICAgICByZWR1Y2VyczogW10sXG4gICAgICAgICAgICBldmVudERlZlBhcnNlcnM6IFtdLFxuICAgICAgICAgICAgaXNEcmFnZ2FibGVUcmFuc2Zvcm1lcnM6IFtdLFxuICAgICAgICAgICAgZXZlbnREcmFnTXV0YXRpb25NYXNzYWdlcnM6IFtdLFxuICAgICAgICAgICAgZXZlbnREZWZNdXRhdGlvbkFwcGxpZXJzOiBbXSxcbiAgICAgICAgICAgIGRhdGVTZWxlY3Rpb25UcmFuc2Zvcm1lcnM6IFtdLFxuICAgICAgICAgICAgZGF0ZVBvaW50VHJhbnNmb3JtczogW10sXG4gICAgICAgICAgICBkYXRlU3BhblRyYW5zZm9ybXM6IFtdLFxuICAgICAgICAgICAgdmlld3M6IHt9LFxuICAgICAgICAgICAgdmlld1Byb3BzVHJhbnNmb3JtZXJzOiBbXSxcbiAgICAgICAgICAgIGlzUHJvcHNWYWxpZDogbnVsbCxcbiAgICAgICAgICAgIGV4dGVybmFsRGVmVHJhbnNmb3JtczogW10sXG4gICAgICAgICAgICBldmVudFJlc2l6ZUpvaW5UcmFuc2Zvcm1zOiBbXSxcbiAgICAgICAgICAgIHZpZXdDb250YWluZXJNb2RpZmllcnM6IFtdLFxuICAgICAgICAgICAgZXZlbnREcm9wVHJhbnNmb3JtZXJzOiBbXSxcbiAgICAgICAgICAgIGNvbXBvbmVudEludGVyYWN0aW9uczogW10sXG4gICAgICAgICAgICBjYWxlbmRhckludGVyYWN0aW9uczogW10sXG4gICAgICAgICAgICB0aGVtZUNsYXNzZXM6IHt9LFxuICAgICAgICAgICAgZXZlbnRTb3VyY2VEZWZzOiBbXSxcbiAgICAgICAgICAgIGNtZEZvcm1hdHRlcjogbnVsbCxcbiAgICAgICAgICAgIHJlY3VycmluZ1R5cGVzOiBbXSxcbiAgICAgICAgICAgIG5hbWVkVGltZVpvbmVkSW1wbDogbnVsbCxcbiAgICAgICAgICAgIGRlZmF1bHRWaWV3OiAnJyxcbiAgICAgICAgICAgIGVsZW1lbnREcmFnZ2luZ0ltcGw6IG51bGwsXG4gICAgICAgICAgICBvcHRpb25DaGFuZ2VIYW5kbGVyczoge31cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5hZGRlZEhhc2ggPSB7fTtcbiAgICB9XG4gICAgUGx1Z2luU3lzdGVtLnByb3RvdHlwZS5hZGQgPSBmdW5jdGlvbiAocGx1Z2luKSB7XG4gICAgICAgIGlmICghdGhpcy5hZGRlZEhhc2hbcGx1Z2luLmlkXSkge1xuICAgICAgICAgICAgdGhpcy5hZGRlZEhhc2hbcGx1Z2luLmlkXSA9IHRydWU7XG4gICAgICAgICAgICBmb3IgKHZhciBfaSA9IDAsIF9hID0gcGx1Z2luLmRlcHM7IF9pIDwgX2EubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIGRlcCA9IF9hW19pXTtcbiAgICAgICAgICAgICAgICB0aGlzLmFkZChkZXApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5ob29rcyA9IGNvbWJpbmVIb29rcyh0aGlzLmhvb2tzLCBwbHVnaW4pO1xuICAgICAgICB9XG4gICAgfTtcbiAgICByZXR1cm4gUGx1Z2luU3lzdGVtO1xufSgpKTtcbmZ1bmN0aW9uIGNvbWJpbmVIb29rcyhob29rczAsIGhvb2tzMSkge1xuICAgIHJldHVybiB7XG4gICAgICAgIHJlZHVjZXJzOiBob29rczAucmVkdWNlcnMuY29uY2F0KGhvb2tzMS5yZWR1Y2VycyksXG4gICAgICAgIGV2ZW50RGVmUGFyc2VyczogaG9va3MwLmV2ZW50RGVmUGFyc2Vycy5jb25jYXQoaG9va3MxLmV2ZW50RGVmUGFyc2VycyksXG4gICAgICAgIGlzRHJhZ2dhYmxlVHJhbnNmb3JtZXJzOiBob29rczAuaXNEcmFnZ2FibGVUcmFuc2Zvcm1lcnMuY29uY2F0KGhvb2tzMS5pc0RyYWdnYWJsZVRyYW5zZm9ybWVycyksXG4gICAgICAgIGV2ZW50RHJhZ011dGF0aW9uTWFzc2FnZXJzOiBob29rczAuZXZlbnREcmFnTXV0YXRpb25NYXNzYWdlcnMuY29uY2F0KGhvb2tzMS5ldmVudERyYWdNdXRhdGlvbk1hc3NhZ2VycyksXG4gICAgICAgIGV2ZW50RGVmTXV0YXRpb25BcHBsaWVyczogaG9va3MwLmV2ZW50RGVmTXV0YXRpb25BcHBsaWVycy5jb25jYXQoaG9va3MxLmV2ZW50RGVmTXV0YXRpb25BcHBsaWVycyksXG4gICAgICAgIGRhdGVTZWxlY3Rpb25UcmFuc2Zvcm1lcnM6IGhvb2tzMC5kYXRlU2VsZWN0aW9uVHJhbnNmb3JtZXJzLmNvbmNhdChob29rczEuZGF0ZVNlbGVjdGlvblRyYW5zZm9ybWVycyksXG4gICAgICAgIGRhdGVQb2ludFRyYW5zZm9ybXM6IGhvb2tzMC5kYXRlUG9pbnRUcmFuc2Zvcm1zLmNvbmNhdChob29rczEuZGF0ZVBvaW50VHJhbnNmb3JtcyksXG4gICAgICAgIGRhdGVTcGFuVHJhbnNmb3JtczogaG9va3MwLmRhdGVTcGFuVHJhbnNmb3Jtcy5jb25jYXQoaG9va3MxLmRhdGVTcGFuVHJhbnNmb3JtcyksXG4gICAgICAgIHZpZXdzOiBfX2Fzc2lnbih7fSwgaG9va3MwLnZpZXdzLCBob29rczEudmlld3MpLFxuICAgICAgICB2aWV3UHJvcHNUcmFuc2Zvcm1lcnM6IGhvb2tzMC52aWV3UHJvcHNUcmFuc2Zvcm1lcnMuY29uY2F0KGhvb2tzMS52aWV3UHJvcHNUcmFuc2Zvcm1lcnMpLFxuICAgICAgICBpc1Byb3BzVmFsaWQ6IGhvb2tzMS5pc1Byb3BzVmFsaWQgfHwgaG9va3MwLmlzUHJvcHNWYWxpZCxcbiAgICAgICAgZXh0ZXJuYWxEZWZUcmFuc2Zvcm1zOiBob29rczAuZXh0ZXJuYWxEZWZUcmFuc2Zvcm1zLmNvbmNhdChob29rczEuZXh0ZXJuYWxEZWZUcmFuc2Zvcm1zKSxcbiAgICAgICAgZXZlbnRSZXNpemVKb2luVHJhbnNmb3JtczogaG9va3MwLmV2ZW50UmVzaXplSm9pblRyYW5zZm9ybXMuY29uY2F0KGhvb2tzMS5ldmVudFJlc2l6ZUpvaW5UcmFuc2Zvcm1zKSxcbiAgICAgICAgdmlld0NvbnRhaW5lck1vZGlmaWVyczogaG9va3MwLnZpZXdDb250YWluZXJNb2RpZmllcnMuY29uY2F0KGhvb2tzMS52aWV3Q29udGFpbmVyTW9kaWZpZXJzKSxcbiAgICAgICAgZXZlbnREcm9wVHJhbnNmb3JtZXJzOiBob29rczAuZXZlbnREcm9wVHJhbnNmb3JtZXJzLmNvbmNhdChob29rczEuZXZlbnREcm9wVHJhbnNmb3JtZXJzKSxcbiAgICAgICAgY2FsZW5kYXJJbnRlcmFjdGlvbnM6IGhvb2tzMC5jYWxlbmRhckludGVyYWN0aW9ucy5jb25jYXQoaG9va3MxLmNhbGVuZGFySW50ZXJhY3Rpb25zKSxcbiAgICAgICAgY29tcG9uZW50SW50ZXJhY3Rpb25zOiBob29rczAuY29tcG9uZW50SW50ZXJhY3Rpb25zLmNvbmNhdChob29rczEuY29tcG9uZW50SW50ZXJhY3Rpb25zKSxcbiAgICAgICAgdGhlbWVDbGFzc2VzOiBfX2Fzc2lnbih7fSwgaG9va3MwLnRoZW1lQ2xhc3NlcywgaG9va3MxLnRoZW1lQ2xhc3NlcyksXG4gICAgICAgIGV2ZW50U291cmNlRGVmczogaG9va3MwLmV2ZW50U291cmNlRGVmcy5jb25jYXQoaG9va3MxLmV2ZW50U291cmNlRGVmcyksXG4gICAgICAgIGNtZEZvcm1hdHRlcjogaG9va3MxLmNtZEZvcm1hdHRlciB8fCBob29rczAuY21kRm9ybWF0dGVyLFxuICAgICAgICByZWN1cnJpbmdUeXBlczogaG9va3MwLnJlY3VycmluZ1R5cGVzLmNvbmNhdChob29rczEucmVjdXJyaW5nVHlwZXMpLFxuICAgICAgICBuYW1lZFRpbWVab25lZEltcGw6IGhvb2tzMS5uYW1lZFRpbWVab25lZEltcGwgfHwgaG9va3MwLm5hbWVkVGltZVpvbmVkSW1wbCxcbiAgICAgICAgZGVmYXVsdFZpZXc6IGhvb2tzMC5kZWZhdWx0VmlldyB8fCBob29rczEuZGVmYXVsdFZpZXcsXG4gICAgICAgIGVsZW1lbnREcmFnZ2luZ0ltcGw6IGhvb2tzMC5lbGVtZW50RHJhZ2dpbmdJbXBsIHx8IGhvb2tzMS5lbGVtZW50RHJhZ2dpbmdJbXBsLFxuICAgICAgICBvcHRpb25DaGFuZ2VIYW5kbGVyczogX19hc3NpZ24oe30sIGhvb2tzMC5vcHRpb25DaGFuZ2VIYW5kbGVycywgaG9va3MxLm9wdGlvbkNoYW5nZUhhbmRsZXJzKVxuICAgIH07XG59XG5cbnZhciBldmVudFNvdXJjZURlZiA9IHtcbiAgICBpZ25vcmVSYW5nZTogdHJ1ZSxcbiAgICBwYXJzZU1ldGE6IGZ1bmN0aW9uIChyYXcpIHtcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkocmF3KSkgeyAvLyBzaG9ydCBmb3JtXG4gICAgICAgICAgICByZXR1cm4gcmF3O1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKEFycmF5LmlzQXJyYXkocmF3LmV2ZW50cykpIHtcbiAgICAgICAgICAgIHJldHVybiByYXcuZXZlbnRzO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH0sXG4gICAgZmV0Y2g6IGZ1bmN0aW9uIChhcmcsIHN1Y2Nlc3MpIHtcbiAgICAgICAgc3VjY2Vzcyh7XG4gICAgICAgICAgICByYXdFdmVudHM6IGFyZy5ldmVudFNvdXJjZS5tZXRhXG4gICAgICAgIH0pO1xuICAgIH1cbn07XG52YXIgQXJyYXlFdmVudFNvdXJjZVBsdWdpbiA9IGNyZWF0ZVBsdWdpbih7XG4gICAgZXZlbnRTb3VyY2VEZWZzOiBbZXZlbnRTb3VyY2VEZWZdXG59KTtcblxudmFyIGV2ZW50U291cmNlRGVmJDEgPSB7XG4gICAgcGFyc2VNZXRhOiBmdW5jdGlvbiAocmF3KSB7XG4gICAgICAgIGlmICh0eXBlb2YgcmF3ID09PSAnZnVuY3Rpb24nKSB7IC8vIHNob3J0IGZvcm1cbiAgICAgICAgICAgIHJldHVybiByYXc7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodHlwZW9mIHJhdy5ldmVudHMgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIHJldHVybiByYXcuZXZlbnRzO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH0sXG4gICAgZmV0Y2g6IGZ1bmN0aW9uIChhcmcsIHN1Y2Nlc3MsIGZhaWx1cmUpIHtcbiAgICAgICAgdmFyIGRhdGVFbnYgPSBhcmcuY2FsZW5kYXIuZGF0ZUVudjtcbiAgICAgICAgdmFyIGZ1bmMgPSBhcmcuZXZlbnRTb3VyY2UubWV0YTtcbiAgICAgICAgdW5wcm9taXNpZnkoZnVuYy5iaW5kKG51bGwsIHtcbiAgICAgICAgICAgIHN0YXJ0OiBkYXRlRW52LnRvRGF0ZShhcmcucmFuZ2Uuc3RhcnQpLFxuICAgICAgICAgICAgZW5kOiBkYXRlRW52LnRvRGF0ZShhcmcucmFuZ2UuZW5kKSxcbiAgICAgICAgICAgIHN0YXJ0U3RyOiBkYXRlRW52LmZvcm1hdElzbyhhcmcucmFuZ2Uuc3RhcnQpLFxuICAgICAgICAgICAgZW5kU3RyOiBkYXRlRW52LmZvcm1hdElzbyhhcmcucmFuZ2UuZW5kKSxcbiAgICAgICAgICAgIHRpbWVab25lOiBkYXRlRW52LnRpbWVab25lXG4gICAgICAgIH0pLCBmdW5jdGlvbiAocmF3RXZlbnRzKSB7XG4gICAgICAgICAgICBzdWNjZXNzKHsgcmF3RXZlbnRzOiByYXdFdmVudHMgfSk7IC8vIG5lZWRzIGFuIG9iamVjdCByZXNwb25zZVxuICAgICAgICB9LCBmYWlsdXJlIC8vIHNlbmQgZXJyb3JPYmogZGlyZWN0bHkgdG8gZmFpbHVyZSBjYWxsYmFja1xuICAgICAgICApO1xuICAgIH1cbn07XG52YXIgRnVuY0V2ZW50U291cmNlUGx1Z2luID0gY3JlYXRlUGx1Z2luKHtcbiAgICBldmVudFNvdXJjZURlZnM6IFtldmVudFNvdXJjZURlZiQxXVxufSk7XG5cbmZ1bmN0aW9uIHJlcXVlc3RKc29uKG1ldGhvZCwgdXJsLCBwYXJhbXMsIHN1Y2Nlc3NDYWxsYmFjaywgZmFpbHVyZUNhbGxiYWNrKSB7XG4gICAgbWV0aG9kID0gbWV0aG9kLnRvVXBwZXJDYXNlKCk7XG4gICAgdmFyIGJvZHkgPSBudWxsO1xuICAgIGlmIChtZXRob2QgPT09ICdHRVQnKSB7XG4gICAgICAgIHVybCA9IGluamVjdFF1ZXJ5U3RyaW5nUGFyYW1zKHVybCwgcGFyYW1zKTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGJvZHkgPSBlbmNvZGVQYXJhbXMocGFyYW1zKTtcbiAgICB9XG4gICAgdmFyIHhociA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpO1xuICAgIHhoci5vcGVuKG1ldGhvZCwgdXJsLCB0cnVlKTtcbiAgICBpZiAobWV0aG9kICE9PSAnR0VUJykge1xuICAgICAgICB4aHIuc2V0UmVxdWVzdEhlYWRlcignQ29udGVudC1UeXBlJywgJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCcpO1xuICAgIH1cbiAgICB4aHIub25sb2FkID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoeGhyLnN0YXR1cyA+PSAyMDAgJiYgeGhyLnN0YXR1cyA8IDQwMCkge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICB2YXIgcmVzID0gSlNPTi5wYXJzZSh4aHIucmVzcG9uc2VUZXh0KTtcbiAgICAgICAgICAgICAgICBzdWNjZXNzQ2FsbGJhY2socmVzLCB4aHIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgIGZhaWx1cmVDYWxsYmFjaygnRmFpbHVyZSBwYXJzaW5nIEpTT04nLCB4aHIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZmFpbHVyZUNhbGxiYWNrKCdSZXF1ZXN0IGZhaWxlZCcsIHhocik7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIHhoci5vbmVycm9yID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBmYWlsdXJlQ2FsbGJhY2soJ1JlcXVlc3QgZmFpbGVkJywgeGhyKTtcbiAgICB9O1xuICAgIHhoci5zZW5kKGJvZHkpO1xufVxuZnVuY3Rpb24gaW5qZWN0UXVlcnlTdHJpbmdQYXJhbXModXJsLCBwYXJhbXMpIHtcbiAgICByZXR1cm4gdXJsICtcbiAgICAgICAgKHVybC5pbmRleE9mKCc/JykgPT09IC0xID8gJz8nIDogJyYnKSArXG4gICAgICAgIGVuY29kZVBhcmFtcyhwYXJhbXMpO1xufVxuZnVuY3Rpb24gZW5jb2RlUGFyYW1zKHBhcmFtcykge1xuICAgIHZhciBwYXJ0cyA9IFtdO1xuICAgIGZvciAodmFyIGtleSBpbiBwYXJhbXMpIHtcbiAgICAgICAgcGFydHMucHVzaChlbmNvZGVVUklDb21wb25lbnQoa2V5KSArICc9JyArIGVuY29kZVVSSUNvbXBvbmVudChwYXJhbXNba2V5XSkpO1xuICAgIH1cbiAgICByZXR1cm4gcGFydHMuam9pbignJicpO1xufVxuXG52YXIgZXZlbnRTb3VyY2VEZWYkMiA9IHtcbiAgICBwYXJzZU1ldGE6IGZ1bmN0aW9uIChyYXcpIHtcbiAgICAgICAgaWYgKHR5cGVvZiByYXcgPT09ICdzdHJpbmcnKSB7IC8vIHNob3J0IGZvcm1cbiAgICAgICAgICAgIHJhdyA9IHsgdXJsOiByYXcgfTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICghcmF3IHx8IHR5cGVvZiByYXcgIT09ICdvYmplY3QnIHx8ICFyYXcudXJsKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgdXJsOiByYXcudXJsLFxuICAgICAgICAgICAgbWV0aG9kOiAocmF3Lm1ldGhvZCB8fCAnR0VUJykudG9VcHBlckNhc2UoKSxcbiAgICAgICAgICAgIGV4dHJhUGFyYW1zOiByYXcuZXh0cmFQYXJhbXMsXG4gICAgICAgICAgICBzdGFydFBhcmFtOiByYXcuc3RhcnRQYXJhbSxcbiAgICAgICAgICAgIGVuZFBhcmFtOiByYXcuZW5kUGFyYW0sXG4gICAgICAgICAgICB0aW1lWm9uZVBhcmFtOiByYXcudGltZVpvbmVQYXJhbVxuICAgICAgICB9O1xuICAgIH0sXG4gICAgZmV0Y2g6IGZ1bmN0aW9uIChhcmcsIHN1Y2Nlc3MsIGZhaWx1cmUpIHtcbiAgICAgICAgdmFyIG1ldGEgPSBhcmcuZXZlbnRTb3VyY2UubWV0YTtcbiAgICAgICAgdmFyIHJlcXVlc3RQYXJhbXMgPSBidWlsZFJlcXVlc3RQYXJhbXMobWV0YSwgYXJnLnJhbmdlLCBhcmcuY2FsZW5kYXIpO1xuICAgICAgICByZXF1ZXN0SnNvbihtZXRhLm1ldGhvZCwgbWV0YS51cmwsIHJlcXVlc3RQYXJhbXMsIGZ1bmN0aW9uIChyYXdFdmVudHMsIHhocikge1xuICAgICAgICAgICAgc3VjY2Vzcyh7IHJhd0V2ZW50czogcmF3RXZlbnRzLCB4aHI6IHhociB9KTtcbiAgICAgICAgfSwgZnVuY3Rpb24gKGVycm9yTWVzc2FnZSwgeGhyKSB7XG4gICAgICAgICAgICBmYWlsdXJlKHsgbWVzc2FnZTogZXJyb3JNZXNzYWdlLCB4aHI6IHhociB9KTtcbiAgICAgICAgfSk7XG4gICAgfVxufTtcbnZhciBKc29uRmVlZEV2ZW50U291cmNlUGx1Z2luID0gY3JlYXRlUGx1Z2luKHtcbiAgICBldmVudFNvdXJjZURlZnM6IFtldmVudFNvdXJjZURlZiQyXVxufSk7XG5mdW5jdGlvbiBidWlsZFJlcXVlc3RQYXJhbXMobWV0YSwgcmFuZ2UsIGNhbGVuZGFyKSB7XG4gICAgdmFyIGRhdGVFbnYgPSBjYWxlbmRhci5kYXRlRW52O1xuICAgIHZhciBzdGFydFBhcmFtO1xuICAgIHZhciBlbmRQYXJhbTtcbiAgICB2YXIgdGltZVpvbmVQYXJhbTtcbiAgICB2YXIgY3VzdG9tUmVxdWVzdFBhcmFtcztcbiAgICB2YXIgcGFyYW1zID0ge307XG4gICAgc3RhcnRQYXJhbSA9IG1ldGEuc3RhcnRQYXJhbTtcbiAgICBpZiAoc3RhcnRQYXJhbSA9PSBudWxsKSB7XG4gICAgICAgIHN0YXJ0UGFyYW0gPSBjYWxlbmRhci5vcHQoJ3N0YXJ0UGFyYW0nKTtcbiAgICB9XG4gICAgZW5kUGFyYW0gPSBtZXRhLmVuZFBhcmFtO1xuICAgIGlmIChlbmRQYXJhbSA9PSBudWxsKSB7XG4gICAgICAgIGVuZFBhcmFtID0gY2FsZW5kYXIub3B0KCdlbmRQYXJhbScpO1xuICAgIH1cbiAgICB0aW1lWm9uZVBhcmFtID0gbWV0YS50aW1lWm9uZVBhcmFtO1xuICAgIGlmICh0aW1lWm9uZVBhcmFtID09IG51bGwpIHtcbiAgICAgICAgdGltZVpvbmVQYXJhbSA9IGNhbGVuZGFyLm9wdCgndGltZVpvbmVQYXJhbScpO1xuICAgIH1cbiAgICAvLyByZXRyaWV2ZSBhbnkgb3V0Ym91bmQgR0VUL1BPU1QgZGF0YSBmcm9tIHRoZSBvcHRpb25zXG4gICAgaWYgKHR5cGVvZiBtZXRhLmV4dHJhUGFyYW1zID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIC8vIHN1cHBsaWVkIGFzIGEgZnVuY3Rpb24gdGhhdCByZXR1cm5zIGEga2V5L3ZhbHVlIG9iamVjdFxuICAgICAgICBjdXN0b21SZXF1ZXN0UGFyYW1zID0gbWV0YS5leHRyYVBhcmFtcygpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgLy8gcHJvYmFibHkgc3VwcGxpZWQgYXMgYSBzdHJhaWdodCBrZXkvdmFsdWUgb2JqZWN0XG4gICAgICAgIGN1c3RvbVJlcXVlc3RQYXJhbXMgPSBtZXRhLmV4dHJhUGFyYW1zIHx8IHt9O1xuICAgIH1cbiAgICBfX2Fzc2lnbihwYXJhbXMsIGN1c3RvbVJlcXVlc3RQYXJhbXMpO1xuICAgIHBhcmFtc1tzdGFydFBhcmFtXSA9IGRhdGVFbnYuZm9ybWF0SXNvKHJhbmdlLnN0YXJ0KTtcbiAgICBwYXJhbXNbZW5kUGFyYW1dID0gZGF0ZUVudi5mb3JtYXRJc28ocmFuZ2UuZW5kKTtcbiAgICBpZiAoZGF0ZUVudi50aW1lWm9uZSAhPT0gJ2xvY2FsJykge1xuICAgICAgICBwYXJhbXNbdGltZVpvbmVQYXJhbV0gPSBkYXRlRW52LnRpbWVab25lO1xuICAgIH1cbiAgICByZXR1cm4gcGFyYW1zO1xufVxuXG52YXIgcmVjdXJyaW5nID0ge1xuICAgIHBhcnNlOiBmdW5jdGlvbiAocmF3RXZlbnQsIGxlZnRvdmVyUHJvcHMsIGRhdGVFbnYpIHtcbiAgICAgICAgdmFyIGNyZWF0ZU1hcmtlciA9IGRhdGVFbnYuY3JlYXRlTWFya2VyLmJpbmQoZGF0ZUVudik7XG4gICAgICAgIHZhciBwcm9jZXNzb3JzID0ge1xuICAgICAgICAgICAgZGF5c09mV2VlazogbnVsbCxcbiAgICAgICAgICAgIHN0YXJ0VGltZTogY3JlYXRlRHVyYXRpb24sXG4gICAgICAgICAgICBlbmRUaW1lOiBjcmVhdGVEdXJhdGlvbixcbiAgICAgICAgICAgIHN0YXJ0UmVjdXI6IGNyZWF0ZU1hcmtlcixcbiAgICAgICAgICAgIGVuZFJlY3VyOiBjcmVhdGVNYXJrZXJcbiAgICAgICAgfTtcbiAgICAgICAgdmFyIHByb3BzID0gcmVmaW5lUHJvcHMocmF3RXZlbnQsIHByb2Nlc3NvcnMsIHt9LCBsZWZ0b3ZlclByb3BzKTtcbiAgICAgICAgdmFyIGFueVZhbGlkID0gZmFsc2U7XG4gICAgICAgIGZvciAodmFyIHByb3BOYW1lIGluIHByb3BzKSB7XG4gICAgICAgICAgICBpZiAocHJvcHNbcHJvcE5hbWVdICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICBhbnlWYWxpZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGFueVZhbGlkKSB7XG4gICAgICAgICAgICB2YXIgZHVyYXRpb24gPSBudWxsO1xuICAgICAgICAgICAgaWYgKCdkdXJhdGlvbicgaW4gbGVmdG92ZXJQcm9wcykge1xuICAgICAgICAgICAgICAgIGR1cmF0aW9uID0gY3JlYXRlRHVyYXRpb24obGVmdG92ZXJQcm9wcy5kdXJhdGlvbik7XG4gICAgICAgICAgICAgICAgZGVsZXRlIGxlZnRvdmVyUHJvcHMuZHVyYXRpb247XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWR1cmF0aW9uICYmIHByb3BzLnN0YXJ0VGltZSAmJiBwcm9wcy5lbmRUaW1lKSB7XG4gICAgICAgICAgICAgICAgZHVyYXRpb24gPSBzdWJ0cmFjdER1cmF0aW9ucyhwcm9wcy5lbmRUaW1lLCBwcm9wcy5zdGFydFRpbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBhbGxEYXlHdWVzczogQm9vbGVhbighcHJvcHMuc3RhcnRUaW1lICYmICFwcm9wcy5lbmRUaW1lKSxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogZHVyYXRpb24sXG4gICAgICAgICAgICAgICAgdHlwZURhdGE6IHByb3BzIC8vIGRvZXNuJ3QgbmVlZCBlbmRUaW1lIGFueW1vcmUgYnV0IG9oIHdlbGxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfSxcbiAgICBleHBhbmQ6IGZ1bmN0aW9uICh0eXBlRGF0YSwgZnJhbWluZ1JhbmdlLCBkYXRlRW52KSB7XG4gICAgICAgIHZhciBjbGlwcGVkRnJhbWluZ1JhbmdlID0gaW50ZXJzZWN0UmFuZ2VzKGZyYW1pbmdSYW5nZSwgeyBzdGFydDogdHlwZURhdGEuc3RhcnRSZWN1ciwgZW5kOiB0eXBlRGF0YS5lbmRSZWN1ciB9KTtcbiAgICAgICAgaWYgKGNsaXBwZWRGcmFtaW5nUmFuZ2UpIHtcbiAgICAgICAgICAgIHJldHVybiBleHBhbmRSYW5nZXModHlwZURhdGEuZGF5c09mV2VlaywgdHlwZURhdGEuc3RhcnRUaW1lLCBjbGlwcGVkRnJhbWluZ1JhbmdlLCBkYXRlRW52KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgfVxuICAgIH1cbn07XG52YXIgU2ltcGxlUmVjdXJyZW5jZVBsdWdpbiA9IGNyZWF0ZVBsdWdpbih7XG4gICAgcmVjdXJyaW5nVHlwZXM6IFtyZWN1cnJpbmddXG59KTtcbmZ1bmN0aW9uIGV4cGFuZFJhbmdlcyhkYXlzT2ZXZWVrLCBzdGFydFRpbWUsIGZyYW1pbmdSYW5nZSwgZGF0ZUVudikge1xuICAgIHZhciBkb3dIYXNoID0gZGF5c09mV2VlayA/IGFycmF5VG9IYXNoKGRheXNPZldlZWspIDogbnVsbDtcbiAgICB2YXIgZGF5TWFya2VyID0gc3RhcnRPZkRheShmcmFtaW5nUmFuZ2Uuc3RhcnQpO1xuICAgIHZhciBlbmRNYXJrZXIgPSBmcmFtaW5nUmFuZ2UuZW5kO1xuICAgIHZhciBpbnN0YW5jZVN0YXJ0cyA9IFtdO1xuICAgIHdoaWxlIChkYXlNYXJrZXIgPCBlbmRNYXJrZXIpIHtcbiAgICAgICAgdmFyIGluc3RhbmNlU3RhcnQgXG4gICAgICAgIC8vIGlmIGV2ZXJ5ZGF5LCBvciB0aGlzIHBhcnRpY3VsYXIgZGF5LW9mLXdlZWtcbiAgICAgICAgPSB2b2lkIDA7XG4gICAgICAgIC8vIGlmIGV2ZXJ5ZGF5LCBvciB0aGlzIHBhcnRpY3VsYXIgZGF5LW9mLXdlZWtcbiAgICAgICAgaWYgKCFkb3dIYXNoIHx8IGRvd0hhc2hbZGF5TWFya2VyLmdldFVUQ0RheSgpXSkge1xuICAgICAgICAgICAgaWYgKHN0YXJ0VGltZSkge1xuICAgICAgICAgICAgICAgIGluc3RhbmNlU3RhcnQgPSBkYXRlRW52LmFkZChkYXlNYXJrZXIsIHN0YXJ0VGltZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBpbnN0YW5jZVN0YXJ0ID0gZGF5TWFya2VyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaW5zdGFuY2VTdGFydHMucHVzaChpbnN0YW5jZVN0YXJ0KTtcbiAgICAgICAgfVxuICAgICAgICBkYXlNYXJrZXIgPSBhZGREYXlzKGRheU1hcmtlciwgMSk7XG4gICAgfVxuICAgIHJldHVybiBpbnN0YW5jZVN0YXJ0cztcbn1cblxudmFyIERlZmF1bHRPcHRpb25DaGFuZ2VIYW5kbGVycyA9IGNyZWF0ZVBsdWdpbih7XG4gICAgb3B0aW9uQ2hhbmdlSGFuZGxlcnM6IHtcbiAgICAgICAgZXZlbnRzOiBmdW5jdGlvbiAoZXZlbnRzLCBjYWxlbmRhciwgZGVlcEVxdWFsKSB7XG4gICAgICAgICAgICBoYW5kbGVFdmVudFNvdXJjZXMoW2V2ZW50c10sIGNhbGVuZGFyLCBkZWVwRXF1YWwpO1xuICAgICAgICB9LFxuICAgICAgICBldmVudFNvdXJjZXM6IGhhbmRsZUV2ZW50U291cmNlcyxcbiAgICAgICAgcGx1Z2luczogaGFuZGxlUGx1Z2luc1xuICAgIH1cbn0pO1xuZnVuY3Rpb24gaGFuZGxlRXZlbnRTb3VyY2VzKGlucHV0cywgY2FsZW5kYXIsIGRlZXBFcXVhbCkge1xuICAgIHZhciB1bmZvdW5kU291cmNlcyA9IGhhc2hWYWx1ZXNUb0FycmF5KGNhbGVuZGFyLnN0YXRlLmV2ZW50U291cmNlcyk7XG4gICAgdmFyIG5ld0lucHV0cyA9IFtdO1xuICAgIGZvciAodmFyIF9pID0gMCwgaW5wdXRzXzEgPSBpbnB1dHM7IF9pIDwgaW5wdXRzXzEubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgIHZhciBpbnB1dCA9IGlucHV0c18xW19pXTtcbiAgICAgICAgdmFyIGlucHV0Rm91bmQgPSBmYWxzZTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB1bmZvdW5kU291cmNlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKGRlZXBFcXVhbCh1bmZvdW5kU291cmNlc1tpXS5fcmF3LCBpbnB1dCkpIHtcbiAgICAgICAgICAgICAgICB1bmZvdW5kU291cmNlcy5zcGxpY2UoaSwgMSk7IC8vIGRlbGV0ZVxuICAgICAgICAgICAgICAgIGlucHV0Rm91bmQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICghaW5wdXRGb3VuZCkge1xuICAgICAgICAgICAgbmV3SW5wdXRzLnB1c2goaW5wdXQpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGZvciAodmFyIF9hID0gMCwgdW5mb3VuZFNvdXJjZXNfMSA9IHVuZm91bmRTb3VyY2VzOyBfYSA8IHVuZm91bmRTb3VyY2VzXzEubGVuZ3RoOyBfYSsrKSB7XG4gICAgICAgIHZhciB1bmZvdW5kU291cmNlID0gdW5mb3VuZFNvdXJjZXNfMVtfYV07XG4gICAgICAgIGNhbGVuZGFyLmRpc3BhdGNoKHtcbiAgICAgICAgICAgIHR5cGU6ICdSRU1PVkVfRVZFTlRfU09VUkNFJyxcbiAgICAgICAgICAgIHNvdXJjZUlkOiB1bmZvdW5kU291cmNlLnNvdXJjZUlkXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBmb3IgKHZhciBfYiA9IDAsIG5ld0lucHV0c18xID0gbmV3SW5wdXRzOyBfYiA8IG5ld0lucHV0c18xLmxlbmd0aDsgX2IrKykge1xuICAgICAgICB2YXIgbmV3SW5wdXQgPSBuZXdJbnB1dHNfMVtfYl07XG4gICAgICAgIGNhbGVuZGFyLmFkZEV2ZW50U291cmNlKG5ld0lucHV0KTtcbiAgICB9XG59XG4vLyBzaG9ydGNvbWluZzogd29uJ3QgcmVtb3ZlIHBsdWdpbnNcbmZ1bmN0aW9uIGhhbmRsZVBsdWdpbnMoaW5wdXRzLCBjYWxlbmRhcikge1xuICAgIGNhbGVuZGFyLmFkZFBsdWdpbklucHV0cyhpbnB1dHMpOyAvLyB3aWxsIGdyYWNlZnVsbHkgaGFuZGxlIGR1cGxpY2F0ZXNcbn1cblxudmFyIGNvbmZpZyA9IHt9OyAvLyBUT0RPOiBtYWtlIHRoZXNlIG9wdGlvbnNcbnZhciBnbG9iYWxEZWZhdWx0cyA9IHtcbiAgICBkZWZhdWx0UmFuZ2VTZXBhcmF0b3I6ICcgLSAnLFxuICAgIHRpdGxlUmFuZ2VTZXBhcmF0b3I6ICcgXFx1MjAxMyAnLFxuICAgIGRlZmF1bHRUaW1lZEV2ZW50RHVyYXRpb246ICcwMTowMDowMCcsXG4gICAgZGVmYXVsdEFsbERheUV2ZW50RHVyYXRpb246IHsgZGF5OiAxIH0sXG4gICAgZm9yY2VFdmVudER1cmF0aW9uOiBmYWxzZSxcbiAgICBuZXh0RGF5VGhyZXNob2xkOiAnMDA6MDA6MDAnLFxuICAgIC8vIGRpc3BsYXlcbiAgICBjb2x1bW5IZWFkZXI6IHRydWUsXG4gICAgZGVmYXVsdFZpZXc6ICcnLFxuICAgIGFzcGVjdFJhdGlvOiAxLjM1LFxuICAgIGhlYWRlcjoge1xuICAgICAgICBsZWZ0OiAndGl0bGUnLFxuICAgICAgICBjZW50ZXI6ICcnLFxuICAgICAgICByaWdodDogJ3RvZGF5IHByZXYsbmV4dCdcbiAgICB9LFxuICAgIHdlZWtlbmRzOiB0cnVlLFxuICAgIHdlZWtOdW1iZXJzOiBmYWxzZSxcbiAgICB3ZWVrTnVtYmVyQ2FsY3VsYXRpb246ICdsb2NhbCcsXG4gICAgZWRpdGFibGU6IGZhbHNlLFxuICAgIC8vIG5vd0luZGljYXRvcjogZmFsc2UsXG4gICAgc2Nyb2xsVGltZTogJzA2OjAwOjAwJyxcbiAgICBtaW5UaW1lOiAnMDA6MDA6MDAnLFxuICAgIG1heFRpbWU6ICcyNDowMDowMCcsXG4gICAgc2hvd05vbkN1cnJlbnREYXRlczogdHJ1ZSxcbiAgICAvLyBldmVudCBhamF4XG4gICAgbGF6eUZldGNoaW5nOiB0cnVlLFxuICAgIHN0YXJ0UGFyYW06ICdzdGFydCcsXG4gICAgZW5kUGFyYW06ICdlbmQnLFxuICAgIHRpbWVab25lUGFyYW06ICd0aW1lWm9uZScsXG4gICAgdGltZVpvbmU6ICdsb2NhbCcsXG4gICAgLy8gYWxsRGF5RGVmYXVsdDogdW5kZWZpbmVkLFxuICAgIC8vIGxvY2FsZVxuICAgIGxvY2FsZXM6IFtdLFxuICAgIGxvY2FsZTogJycsXG4gICAgLy8gZGlyOiB3aWxsIGdldCB0aGlzIGZyb20gdGhlIGRlZmF1bHQgbG9jYWxlXG4gICAgLy8gYnV0dG9uSWNvbnM6IG51bGwsXG4gICAgLy8gYWxsb3dzIHNldHRpbmcgYSBtaW4taGVpZ2h0IHRvIHRoZSBldmVudCBzZWdtZW50IHRvIHByZXZlbnQgc2hvcnQgZXZlbnRzIG92ZXJsYXBwaW5nIGVhY2ggb3RoZXJcbiAgICB0aW1lR3JpZEV2ZW50TWluSGVpZ2h0OiAwLFxuICAgIHRoZW1lU3lzdGVtOiAnc3RhbmRhcmQnLFxuICAgIC8vIGV2ZW50UmVzaXphYmxlRnJvbVN0YXJ0OiBmYWxzZSxcbiAgICBkcmFnUmV2ZXJ0RHVyYXRpb246IDUwMCxcbiAgICBkcmFnU2Nyb2xsOiB0cnVlLFxuICAgIGFsbERheU1haW50YWluRHVyYXRpb246IGZhbHNlLFxuICAgIC8vIHNlbGVjdGFibGU6IGZhbHNlLFxuICAgIHVuc2VsZWN0QXV0bzogdHJ1ZSxcbiAgICAvLyBzZWxlY3RNaW5EaXN0YW5jZTogMCxcbiAgICBkcm9wQWNjZXB0OiAnKicsXG4gICAgZXZlbnRPcmRlcjogJ3N0YXJ0LC1kdXJhdGlvbixhbGxEYXksdGl0bGUnLFxuICAgIC8vIF4gaWYgc3RhcnQgdGllLCBsb25nZXIgZXZlbnRzIGdvIGJlZm9yZSBzaG9ydGVyLiBmaW5hbCB0aWUtYnJlYWtlciBpcyB0aXRsZSB0ZXh0XG4gICAgLy8gcmVyZW5kZXJEZWxheTogbnVsbCxcbiAgICBldmVudExpbWl0OiBmYWxzZSxcbiAgICBldmVudExpbWl0Q2xpY2s6ICdwb3BvdmVyJyxcbiAgICBkYXlQb3BvdmVyRm9ybWF0OiB7IG1vbnRoOiAnbG9uZycsIGRheTogJ251bWVyaWMnLCB5ZWFyOiAnbnVtZXJpYycgfSxcbiAgICBoYW5kbGVXaW5kb3dSZXNpemU6IHRydWUsXG4gICAgd2luZG93UmVzaXplRGVsYXk6IDEwMCxcbiAgICBsb25nUHJlc3NEZWxheTogMTAwMCxcbiAgICBldmVudERyYWdNaW5EaXN0YW5jZTogNSAvLyBvbmx5IGFwcGxpZXMgdG8gbW91c2Vcbn07XG52YXIgcnRsRGVmYXVsdHMgPSB7XG4gICAgaGVhZGVyOiB7XG4gICAgICAgIGxlZnQ6ICduZXh0LHByZXYgdG9kYXknLFxuICAgICAgICBjZW50ZXI6ICcnLFxuICAgICAgICByaWdodDogJ3RpdGxlJ1xuICAgIH0sXG4gICAgYnV0dG9uSWNvbnM6IHtcbiAgICAgICAgLy8gVE9ETzogbWFrZSBSVEwgc3VwcG9ydCB0aGUgcmVzcG9uaWJpbGl0eSBvZiB0aGUgdGhlbWVcbiAgICAgICAgcHJldjogJ2ZjLWljb24tY2hldnJvbi1yaWdodCcsXG4gICAgICAgIG5leHQ6ICdmYy1pY29uLWNoZXZyb24tbGVmdCcsXG4gICAgICAgIHByZXZZZWFyOiAnZmMtaWNvbi1jaGV2cm9ucy1yaWdodCcsXG4gICAgICAgIG5leHRZZWFyOiAnZmMtaWNvbi1jaGV2cm9ucy1sZWZ0J1xuICAgIH1cbn07XG52YXIgY29tcGxleE9wdGlvbnMgPSBbXG4gICAgJ2hlYWRlcicsXG4gICAgJ2Zvb3RlcicsXG4gICAgJ2J1dHRvblRleHQnLFxuICAgICdidXR0b25JY29ucydcbl07XG4vLyBNZXJnZXMgYW4gYXJyYXkgb2Ygb3B0aW9uIG9iamVjdHMgaW50byBhIHNpbmdsZSBvYmplY3RcbmZ1bmN0aW9uIG1lcmdlT3B0aW9ucyhvcHRpb25PYmpzKSB7XG4gICAgcmV0dXJuIG1lcmdlUHJvcHMob3B0aW9uT2JqcywgY29tcGxleE9wdGlvbnMpO1xufVxuLy8gVE9ETzogbW92ZSB0aGlzIHN0dWZmIHRvIGEgXCJwbHVnaW5cIi1yZWxhdGVkIGZpbGUuLi5cbnZhciBJTlRFUk5BTF9QTFVHSU5TID0gW1xuICAgIEFycmF5RXZlbnRTb3VyY2VQbHVnaW4sXG4gICAgRnVuY0V2ZW50U291cmNlUGx1Z2luLFxuICAgIEpzb25GZWVkRXZlbnRTb3VyY2VQbHVnaW4sXG4gICAgU2ltcGxlUmVjdXJyZW5jZVBsdWdpbixcbiAgICBEZWZhdWx0T3B0aW9uQ2hhbmdlSGFuZGxlcnNcbl07XG5mdW5jdGlvbiByZWZpbmVQbHVnaW5EZWZzKHBsdWdpbklucHV0cykge1xuICAgIHZhciBwbHVnaW5zID0gW107XG4gICAgZm9yICh2YXIgX2kgPSAwLCBwbHVnaW5JbnB1dHNfMSA9IHBsdWdpbklucHV0czsgX2kgPCBwbHVnaW5JbnB1dHNfMS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgdmFyIHBsdWdpbklucHV0ID0gcGx1Z2luSW5wdXRzXzFbX2ldO1xuICAgICAgICBpZiAodHlwZW9mIHBsdWdpbklucHV0ID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgdmFyIGdsb2JhbE5hbWUgPSAnRnVsbENhbGVuZGFyJyArIGNhcGl0YWxpc2VGaXJzdExldHRlcihwbHVnaW5JbnB1dCk7XG4gICAgICAgICAgICBpZiAoIXdpbmRvd1tnbG9iYWxOYW1lXSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignUGx1Z2luIGZpbGUgbm90IGxvYWRlZCBmb3IgJyArIHBsdWdpbklucHV0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHBsdWdpbnMucHVzaCh3aW5kb3dbZ2xvYmFsTmFtZV0uZGVmYXVsdCk7IC8vIGlzIGFuIEVTNiBtb2R1bGVcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHBsdWdpbnMucHVzaChwbHVnaW5JbnB1dCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIElOVEVSTkFMX1BMVUdJTlMuY29uY2F0KHBsdWdpbnMpO1xufVxuXG52YXIgUkFXX0VOX0xPQ0FMRSA9IHtcbiAgICBjb2RlOiAnZW4nLFxuICAgIHdlZWs6IHtcbiAgICAgICAgZG93OiAwLFxuICAgICAgICBkb3k6IDQgLy8gNCBkYXlzIG5lZWQgdG8gYmUgd2l0aGluIHRoZSB5ZWFyIHRvIGJlIGNvbnNpZGVyZWQgdGhlIGZpcnN0IHdlZWtcbiAgICB9LFxuICAgIGRpcjogJ2x0cicsXG4gICAgYnV0dG9uVGV4dDoge1xuICAgICAgICBwcmV2OiAncHJldicsXG4gICAgICAgIG5leHQ6ICduZXh0JyxcbiAgICAgICAgcHJldlllYXI6ICdwcmV2IHllYXInLFxuICAgICAgICBuZXh0WWVhcjogJ25leHQgeWVhcicsXG4gICAgICAgIHllYXI6ICd5ZWFyJyxcbiAgICAgICAgdG9kYXk6ICd0b2RheScsXG4gICAgICAgIG1vbnRoOiAnbW9udGgnLFxuICAgICAgICB3ZWVrOiAnd2VlaycsXG4gICAgICAgIGRheTogJ2RheScsXG4gICAgICAgIGxpc3Q6ICdsaXN0J1xuICAgIH0sXG4gICAgd2Vla0xhYmVsOiAnVycsXG4gICAgYWxsRGF5VGV4dDogJ2FsbC1kYXknLFxuICAgIGV2ZW50TGltaXRUZXh0OiAnbW9yZScsXG4gICAgbm9FdmVudHNNZXNzYWdlOiAnTm8gZXZlbnRzIHRvIGRpc3BsYXknXG59O1xuZnVuY3Rpb24gcGFyc2VSYXdMb2NhbGVzKGV4cGxpY2l0UmF3TG9jYWxlcykge1xuICAgIHZhciBkZWZhdWx0Q29kZSA9IGV4cGxpY2l0UmF3TG9jYWxlcy5sZW5ndGggPiAwID8gZXhwbGljaXRSYXdMb2NhbGVzWzBdLmNvZGUgOiAnZW4nO1xuICAgIHZhciBnbG9iYWxBcnJheSA9IHdpbmRvd1snRnVsbENhbGVuZGFyTG9jYWxlc0FsbCddIHx8IFtdOyAvLyBmcm9tIGxvY2FsZXMtYWxsLmpzXG4gICAgdmFyIGdsb2JhbE9iamVjdCA9IHdpbmRvd1snRnVsbENhbGVuZGFyTG9jYWxlcyddIHx8IHt9OyAvLyBmcm9tIGxvY2FsZXMvKi5qcy4ga2V5cyBhcmUgbWVhbmluZ2xlc3NcbiAgICB2YXIgYWxsUmF3TG9jYWxlcyA9IGdsb2JhbEFycmF5LmNvbmNhdCgvLyBnbG9iYWxBcnJheSBpcyBsb3cgcHJpb1xuICAgIGhhc2hWYWx1ZXNUb0FycmF5KGdsb2JhbE9iamVjdCksIC8vIG1lZGl1bSBwcmlvXG4gICAgZXhwbGljaXRSYXdMb2NhbGVzIC8vIGhpZ2hlc3QgcHJpb1xuICAgICk7XG4gICAgdmFyIHJhd0xvY2FsZU1hcCA9IHtcbiAgICAgICAgZW46IFJBV19FTl9MT0NBTEUgLy8gbmVjZXNzYXJ5P1xuICAgIH07XG4gICAgZm9yICh2YXIgX2kgPSAwLCBhbGxSYXdMb2NhbGVzXzEgPSBhbGxSYXdMb2NhbGVzOyBfaSA8IGFsbFJhd0xvY2FsZXNfMS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgdmFyIHJhd0xvY2FsZSA9IGFsbFJhd0xvY2FsZXNfMVtfaV07XG4gICAgICAgIHJhd0xvY2FsZU1hcFtyYXdMb2NhbGUuY29kZV0gPSByYXdMb2NhbGU7XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICAgIG1hcDogcmF3TG9jYWxlTWFwLFxuICAgICAgICBkZWZhdWx0Q29kZTogZGVmYXVsdENvZGVcbiAgICB9O1xufVxuZnVuY3Rpb24gYnVpbGRMb2NhbGUoaW5wdXRTaW5ndWxhciwgYXZhaWxhYmxlKSB7XG4gICAgaWYgKHR5cGVvZiBpbnB1dFNpbmd1bGFyID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShpbnB1dFNpbmd1bGFyKSkge1xuICAgICAgICByZXR1cm4gcGFyc2VMb2NhbGUoaW5wdXRTaW5ndWxhci5jb2RlLCBbaW5wdXRTaW5ndWxhci5jb2RlXSwgaW5wdXRTaW5ndWxhcik7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICByZXR1cm4gcXVlcnlMb2NhbGUoaW5wdXRTaW5ndWxhciwgYXZhaWxhYmxlKTtcbiAgICB9XG59XG5mdW5jdGlvbiBxdWVyeUxvY2FsZShjb2RlQXJnLCBhdmFpbGFibGUpIHtcbiAgICB2YXIgY29kZXMgPSBbXS5jb25jYXQoY29kZUFyZyB8fCBbXSk7IC8vIHdpbGwgY29udmVydCB0byBhcnJheVxuICAgIHZhciByYXcgPSBxdWVyeVJhd0xvY2FsZShjb2RlcywgYXZhaWxhYmxlKSB8fCBSQVdfRU5fTE9DQUxFO1xuICAgIHJldHVybiBwYXJzZUxvY2FsZShjb2RlQXJnLCBjb2RlcywgcmF3KTtcbn1cbmZ1bmN0aW9uIHF1ZXJ5UmF3TG9jYWxlKGNvZGVzLCBhdmFpbGFibGUpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNvZGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBwYXJ0cyA9IGNvZGVzW2ldLnRvTG9jYWxlTG93ZXJDYXNlKCkuc3BsaXQoJy0nKTtcbiAgICAgICAgZm9yICh2YXIgaiA9IHBhcnRzLmxlbmd0aDsgaiA+IDA7IGotLSkge1xuICAgICAgICAgICAgdmFyIHNpbXBsZUlkID0gcGFydHMuc2xpY2UoMCwgaikuam9pbignLScpO1xuICAgICAgICAgICAgaWYgKGF2YWlsYWJsZVtzaW1wbGVJZF0pIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYXZhaWxhYmxlW3NpbXBsZUlkXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cbmZ1bmN0aW9uIHBhcnNlTG9jYWxlKGNvZGVBcmcsIGNvZGVzLCByYXcpIHtcbiAgICB2YXIgbWVyZ2VkID0gbWVyZ2VQcm9wcyhbUkFXX0VOX0xPQ0FMRSwgcmF3XSwgWydidXR0b25UZXh0J10pO1xuICAgIGRlbGV0ZSBtZXJnZWQuY29kZTsgLy8gZG9uJ3Qgd2FudCB0aGlzIHBhcnQgb2YgdGhlIG9wdGlvbnNcbiAgICB2YXIgd2VlayA9IG1lcmdlZC53ZWVrO1xuICAgIGRlbGV0ZSBtZXJnZWQud2VlaztcbiAgICByZXR1cm4ge1xuICAgICAgICBjb2RlQXJnOiBjb2RlQXJnLFxuICAgICAgICBjb2RlczogY29kZXMsXG4gICAgICAgIHdlZWs6IHdlZWssXG4gICAgICAgIHNpbXBsZU51bWJlckZvcm1hdDogbmV3IEludGwuTnVtYmVyRm9ybWF0KGNvZGVBcmcpLFxuICAgICAgICBvcHRpb25zOiBtZXJnZWRcbiAgICB9O1xufVxuXG52YXIgT3B0aW9uc01hbmFnZXIgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gT3B0aW9uc01hbmFnZXIob3ZlcnJpZGVzKSB7XG4gICAgICAgIHRoaXMub3ZlcnJpZGVzID0gX19hc3NpZ24oe30sIG92ZXJyaWRlcyk7IC8vIG1ha2UgYSBjb3B5XG4gICAgICAgIHRoaXMuZHluYW1pY092ZXJyaWRlcyA9IHt9O1xuICAgICAgICB0aGlzLmNvbXB1dGUoKTtcbiAgICB9XG4gICAgT3B0aW9uc01hbmFnZXIucHJvdG90eXBlLm11dGF0ZSA9IGZ1bmN0aW9uICh1cGRhdGVzLCByZW1vdmFscywgaXNEeW5hbWljKSB7XG4gICAgICAgIGlmICghT2JqZWN0LmtleXModXBkYXRlcykubGVuZ3RoICYmICFyZW1vdmFscy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB2YXIgb3ZlcnJpZGVIYXNoID0gaXNEeW5hbWljID8gdGhpcy5keW5hbWljT3ZlcnJpZGVzIDogdGhpcy5vdmVycmlkZXM7XG4gICAgICAgIF9fYXNzaWduKG92ZXJyaWRlSGFzaCwgdXBkYXRlcyk7XG4gICAgICAgIGZvciAodmFyIF9pID0gMCwgcmVtb3ZhbHNfMSA9IHJlbW92YWxzOyBfaSA8IHJlbW92YWxzXzEubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICB2YXIgcHJvcE5hbWUgPSByZW1vdmFsc18xW19pXTtcbiAgICAgICAgICAgIGRlbGV0ZSBvdmVycmlkZUhhc2hbcHJvcE5hbWVdO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuY29tcHV0ZSgpO1xuICAgIH07XG4gICAgLy8gQ29tcHV0ZXMgdGhlIGZsYXR0ZW5lZCBvcHRpb25zIGhhc2ggZm9yIHRoZSBjYWxlbmRhciBhbmQgYXNzaWducyB0byBgdGhpcy5vcHRpb25zYC5cbiAgICAvLyBBc3N1bWVzIHRoaXMub3ZlcnJpZGVzIGFuZCB0aGlzLmR5bmFtaWNPdmVycmlkZXMgaGF2ZSBhbHJlYWR5IGJlZW4gaW5pdGlhbGl6ZWQuXG4gICAgT3B0aW9uc01hbmFnZXIucHJvdG90eXBlLmNvbXB1dGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIFRPRE86IG5vdCBhIHZlcnkgZWZmaWNpZW50IHN5c3RlbVxuICAgICAgICB2YXIgbG9jYWxlcyA9IGZpcnN0RGVmaW5lZCgvLyBleHBsaWNpdCBsb2NhbGUgb3B0aW9uIGdpdmVuP1xuICAgICAgICB0aGlzLmR5bmFtaWNPdmVycmlkZXMubG9jYWxlcywgdGhpcy5vdmVycmlkZXMubG9jYWxlcywgZ2xvYmFsRGVmYXVsdHMubG9jYWxlcyk7XG4gICAgICAgIHZhciBsb2NhbGUgPSBmaXJzdERlZmluZWQoLy8gZXhwbGljaXQgbG9jYWxlcyBvcHRpb24gZ2l2ZW4/XG4gICAgICAgIHRoaXMuZHluYW1pY092ZXJyaWRlcy5sb2NhbGUsIHRoaXMub3ZlcnJpZGVzLmxvY2FsZSwgZ2xvYmFsRGVmYXVsdHMubG9jYWxlKTtcbiAgICAgICAgdmFyIGF2YWlsYWJsZSA9IHBhcnNlUmF3TG9jYWxlcyhsb2NhbGVzKTtcbiAgICAgICAgdmFyIGxvY2FsZURlZmF1bHRzID0gYnVpbGRMb2NhbGUobG9jYWxlIHx8IGF2YWlsYWJsZS5kZWZhdWx0Q29kZSwgYXZhaWxhYmxlLm1hcCkub3B0aW9ucztcbiAgICAgICAgdmFyIGRpciA9IGZpcnN0RGVmaW5lZCgvLyBiYXNlZCBvbiBvcHRpb25zIGNvbXB1dGVkIHNvIGZhciwgaXMgZGlyZWN0aW9uIFJUTD9cbiAgICAgICAgdGhpcy5keW5hbWljT3ZlcnJpZGVzLmRpciwgdGhpcy5vdmVycmlkZXMuZGlyLCBsb2NhbGVEZWZhdWx0cy5kaXIpO1xuICAgICAgICB2YXIgZGlyRGVmYXVsdHMgPSBkaXIgPT09ICdydGwnID8gcnRsRGVmYXVsdHMgOiB7fTtcbiAgICAgICAgdGhpcy5kaXJEZWZhdWx0cyA9IGRpckRlZmF1bHRzO1xuICAgICAgICB0aGlzLmxvY2FsZURlZmF1bHRzID0gbG9jYWxlRGVmYXVsdHM7XG4gICAgICAgIHRoaXMuY29tcHV0ZWQgPSBtZXJnZU9wdGlvbnMoW1xuICAgICAgICAgICAgZ2xvYmFsRGVmYXVsdHMsXG4gICAgICAgICAgICBkaXJEZWZhdWx0cyxcbiAgICAgICAgICAgIGxvY2FsZURlZmF1bHRzLFxuICAgICAgICAgICAgdGhpcy5vdmVycmlkZXMsXG4gICAgICAgICAgICB0aGlzLmR5bmFtaWNPdmVycmlkZXNcbiAgICAgICAgXSk7XG4gICAgfTtcbiAgICByZXR1cm4gT3B0aW9uc01hbmFnZXI7XG59KCkpO1xuXG52YXIgY2FsZW5kYXJTeXN0ZW1DbGFzc01hcCA9IHt9O1xuZnVuY3Rpb24gcmVnaXN0ZXJDYWxlbmRhclN5c3RlbShuYW1lLCB0aGVDbGFzcykge1xuICAgIGNhbGVuZGFyU3lzdGVtQ2xhc3NNYXBbbmFtZV0gPSB0aGVDbGFzcztcbn1cbmZ1bmN0aW9uIGNyZWF0ZUNhbGVuZGFyU3lzdGVtKG5hbWUpIHtcbiAgICByZXR1cm4gbmV3IGNhbGVuZGFyU3lzdGVtQ2xhc3NNYXBbbmFtZV0oKTtcbn1cbnZhciBHcmVnb3JpYW5DYWxlbmRhclN5c3RlbSA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBHcmVnb3JpYW5DYWxlbmRhclN5c3RlbSgpIHtcbiAgICB9XG4gICAgR3JlZ29yaWFuQ2FsZW5kYXJTeXN0ZW0ucHJvdG90eXBlLmdldE1hcmtlclllYXIgPSBmdW5jdGlvbiAoZCkge1xuICAgICAgICByZXR1cm4gZC5nZXRVVENGdWxsWWVhcigpO1xuICAgIH07XG4gICAgR3JlZ29yaWFuQ2FsZW5kYXJTeXN0ZW0ucHJvdG90eXBlLmdldE1hcmtlck1vbnRoID0gZnVuY3Rpb24gKGQpIHtcbiAgICAgICAgcmV0dXJuIGQuZ2V0VVRDTW9udGgoKTtcbiAgICB9O1xuICAgIEdyZWdvcmlhbkNhbGVuZGFyU3lzdGVtLnByb3RvdHlwZS5nZXRNYXJrZXJEYXkgPSBmdW5jdGlvbiAoZCkge1xuICAgICAgICByZXR1cm4gZC5nZXRVVENEYXRlKCk7XG4gICAgfTtcbiAgICBHcmVnb3JpYW5DYWxlbmRhclN5c3RlbS5wcm90b3R5cGUuYXJyYXlUb01hcmtlciA9IGZ1bmN0aW9uIChhcnIpIHtcbiAgICAgICAgcmV0dXJuIGFycmF5VG9VdGNEYXRlKGFycik7XG4gICAgfTtcbiAgICBHcmVnb3JpYW5DYWxlbmRhclN5c3RlbS5wcm90b3R5cGUubWFya2VyVG9BcnJheSA9IGZ1bmN0aW9uIChtYXJrZXIpIHtcbiAgICAgICAgcmV0dXJuIGRhdGVUb1V0Y0FycmF5KG1hcmtlcik7XG4gICAgfTtcbiAgICByZXR1cm4gR3JlZ29yaWFuQ2FsZW5kYXJTeXN0ZW07XG59KCkpO1xucmVnaXN0ZXJDYWxlbmRhclN5c3RlbSgnZ3JlZ29yeScsIEdyZWdvcmlhbkNhbGVuZGFyU3lzdGVtKTtcblxudmFyIElTT19SRSA9IC9eXFxzKihcXGR7NH0pKC0oXFxkezJ9KSgtKFxcZHsyfSkoW1QgXShcXGR7Mn0pOihcXGR7Mn0pKDooXFxkezJ9KShcXC4oXFxkKykpPyk/KFp8KChbLStdKShcXGR7Mn0pKDo/KFxcZHsyfSkpPykpPyk/KT8pPyQvO1xuZnVuY3Rpb24gcGFyc2Uoc3RyKSB7XG4gICAgdmFyIG0gPSBJU09fUkUuZXhlYyhzdHIpO1xuICAgIGlmIChtKSB7XG4gICAgICAgIHZhciBtYXJrZXIgPSBuZXcgRGF0ZShEYXRlLlVUQyhOdW1iZXIobVsxXSksIG1bM10gPyBOdW1iZXIobVszXSkgLSAxIDogMCwgTnVtYmVyKG1bNV0gfHwgMSksIE51bWJlcihtWzddIHx8IDApLCBOdW1iZXIobVs4XSB8fCAwKSwgTnVtYmVyKG1bMTBdIHx8IDApLCBtWzEyXSA/IE51bWJlcignMC4nICsgbVsxMl0pICogMTAwMCA6IDApKTtcbiAgICAgICAgaWYgKGlzVmFsaWREYXRlKG1hcmtlcikpIHtcbiAgICAgICAgICAgIHZhciB0aW1lWm9uZU9mZnNldCA9IG51bGw7XG4gICAgICAgICAgICBpZiAobVsxM10pIHtcbiAgICAgICAgICAgICAgICB0aW1lWm9uZU9mZnNldCA9IChtWzE1XSA9PT0gJy0nID8gLTEgOiAxKSAqIChOdW1iZXIobVsxNl0gfHwgMCkgKiA2MCArXG4gICAgICAgICAgICAgICAgICAgIE51bWJlcihtWzE4XSB8fCAwKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIG1hcmtlcjogbWFya2VyLFxuICAgICAgICAgICAgICAgIGlzVGltZVVuc3BlY2lmaWVkOiAhbVs2XSxcbiAgICAgICAgICAgICAgICB0aW1lWm9uZU9mZnNldDogdGltZVpvbmVPZmZzZXRcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG59XG5cbnZhciBEYXRlRW52ID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIERhdGVFbnYoc2V0dGluZ3MpIHtcbiAgICAgICAgdmFyIHRpbWVab25lID0gdGhpcy50aW1lWm9uZSA9IHNldHRpbmdzLnRpbWVab25lO1xuICAgICAgICB2YXIgaXNOYW1lZFRpbWVab25lID0gdGltZVpvbmUgIT09ICdsb2NhbCcgJiYgdGltZVpvbmUgIT09ICdVVEMnO1xuICAgICAgICBpZiAoc2V0dGluZ3MubmFtZWRUaW1lWm9uZUltcGwgJiYgaXNOYW1lZFRpbWVab25lKSB7XG4gICAgICAgICAgICB0aGlzLm5hbWVkVGltZVpvbmVJbXBsID0gbmV3IHNldHRpbmdzLm5hbWVkVGltZVpvbmVJbXBsKHRpbWVab25lKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmNhbkNvbXB1dGVPZmZzZXQgPSBCb29sZWFuKCFpc05hbWVkVGltZVpvbmUgfHwgdGhpcy5uYW1lZFRpbWVab25lSW1wbCk7XG4gICAgICAgIHRoaXMuY2FsZW5kYXJTeXN0ZW0gPSBjcmVhdGVDYWxlbmRhclN5c3RlbShzZXR0aW5ncy5jYWxlbmRhclN5c3RlbSk7XG4gICAgICAgIHRoaXMubG9jYWxlID0gc2V0dGluZ3MubG9jYWxlO1xuICAgICAgICB0aGlzLndlZWtEb3cgPSBzZXR0aW5ncy5sb2NhbGUud2Vlay5kb3c7XG4gICAgICAgIHRoaXMud2Vla0RveSA9IHNldHRpbmdzLmxvY2FsZS53ZWVrLmRveTtcbiAgICAgICAgaWYgKHNldHRpbmdzLndlZWtOdW1iZXJDYWxjdWxhdGlvbiA9PT0gJ0lTTycpIHtcbiAgICAgICAgICAgIHRoaXMud2Vla0RvdyA9IDE7XG4gICAgICAgICAgICB0aGlzLndlZWtEb3kgPSA0O1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlb2Ygc2V0dGluZ3MuZmlyc3REYXkgPT09ICdudW1iZXInKSB7XG4gICAgICAgICAgICB0aGlzLndlZWtEb3cgPSBzZXR0aW5ncy5maXJzdERheTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodHlwZW9mIHNldHRpbmdzLndlZWtOdW1iZXJDYWxjdWxhdGlvbiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgdGhpcy53ZWVrTnVtYmVyRnVuYyA9IHNldHRpbmdzLndlZWtOdW1iZXJDYWxjdWxhdGlvbjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLndlZWtMYWJlbCA9IHNldHRpbmdzLndlZWtMYWJlbCAhPSBudWxsID8gc2V0dGluZ3Mud2Vla0xhYmVsIDogc2V0dGluZ3MubG9jYWxlLm9wdGlvbnMud2Vla0xhYmVsO1xuICAgICAgICB0aGlzLmNtZEZvcm1hdHRlciA9IHNldHRpbmdzLmNtZEZvcm1hdHRlcjtcbiAgICB9XG4gICAgLy8gQ3JlYXRpbmcgLyBQYXJzaW5nXG4gICAgRGF0ZUVudi5wcm90b3R5cGUuY3JlYXRlTWFya2VyID0gZnVuY3Rpb24gKGlucHV0KSB7XG4gICAgICAgIHZhciBtZXRhID0gdGhpcy5jcmVhdGVNYXJrZXJNZXRhKGlucHV0KTtcbiAgICAgICAgaWYgKG1ldGEgPT09IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBtZXRhLm1hcmtlcjtcbiAgICB9O1xuICAgIERhdGVFbnYucHJvdG90eXBlLmNyZWF0ZU5vd01hcmtlciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRoaXMuY2FuQ29tcHV0ZU9mZnNldCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudGltZXN0YW1wVG9NYXJrZXIobmV3IERhdGUoKS52YWx1ZU9mKCkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgLy8gaWYgd2UgY2FuJ3QgY29tcHV0ZSB0aGUgY3VycmVudCBkYXRlIHZhbCBmb3IgYSB0aW1lem9uZSxcbiAgICAgICAgICAgIC8vIGJldHRlciB0byBnaXZlIHRoZSBjdXJyZW50IGxvY2FsIGRhdGUgdmFscyB0aGFuIFVUQ1xuICAgICAgICAgICAgcmV0dXJuIGFycmF5VG9VdGNEYXRlKGRhdGVUb0xvY2FsQXJyYXkobmV3IERhdGUoKSkpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBEYXRlRW52LnByb3RvdHlwZS5jcmVhdGVNYXJrZXJNZXRhID0gZnVuY3Rpb24gKGlucHV0KSB7XG4gICAgICAgIGlmICh0eXBlb2YgaW5wdXQgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wYXJzZShpbnB1dCk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIG1hcmtlciA9IG51bGw7XG4gICAgICAgIGlmICh0eXBlb2YgaW5wdXQgPT09ICdudW1iZXInKSB7XG4gICAgICAgICAgICBtYXJrZXIgPSB0aGlzLnRpbWVzdGFtcFRvTWFya2VyKGlucHV0KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChpbnB1dCBpbnN0YW5jZW9mIERhdGUpIHtcbiAgICAgICAgICAgIGlucHV0ID0gaW5wdXQudmFsdWVPZigpO1xuICAgICAgICAgICAgaWYgKCFpc05hTihpbnB1dCkpIHtcbiAgICAgICAgICAgICAgICBtYXJrZXIgPSB0aGlzLnRpbWVzdGFtcFRvTWFya2VyKGlucHV0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChBcnJheS5pc0FycmF5KGlucHV0KSkge1xuICAgICAgICAgICAgbWFya2VyID0gYXJyYXlUb1V0Y0RhdGUoaW5wdXQpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChtYXJrZXIgPT09IG51bGwgfHwgIWlzVmFsaWREYXRlKG1hcmtlcikpIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IG1hcmtlcjogbWFya2VyLCBpc1RpbWVVbnNwZWNpZmllZDogZmFsc2UsIGZvcmNlZFR6bzogbnVsbCB9O1xuICAgIH07XG4gICAgRGF0ZUVudi5wcm90b3R5cGUucGFyc2UgPSBmdW5jdGlvbiAocykge1xuICAgICAgICB2YXIgcGFydHMgPSBwYXJzZShzKTtcbiAgICAgICAgaWYgKHBhcnRzID09PSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICB2YXIgbWFya2VyID0gcGFydHMubWFya2VyO1xuICAgICAgICB2YXIgZm9yY2VkVHpvID0gbnVsbDtcbiAgICAgICAgaWYgKHBhcnRzLnRpbWVab25lT2Zmc2V0ICE9PSBudWxsKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5jYW5Db21wdXRlT2Zmc2V0KSB7XG4gICAgICAgICAgICAgICAgbWFya2VyID0gdGhpcy50aW1lc3RhbXBUb01hcmtlcihtYXJrZXIudmFsdWVPZigpIC0gcGFydHMudGltZVpvbmVPZmZzZXQgKiA2MCAqIDEwMDApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgZm9yY2VkVHpvID0gcGFydHMudGltZVpvbmVPZmZzZXQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHsgbWFya2VyOiBtYXJrZXIsIGlzVGltZVVuc3BlY2lmaWVkOiBwYXJ0cy5pc1RpbWVVbnNwZWNpZmllZCwgZm9yY2VkVHpvOiBmb3JjZWRUem8gfTtcbiAgICB9O1xuICAgIC8vIEFjY2Vzc29yc1xuICAgIERhdGVFbnYucHJvdG90eXBlLmdldFllYXIgPSBmdW5jdGlvbiAobWFya2VyKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmNhbGVuZGFyU3lzdGVtLmdldE1hcmtlclllYXIobWFya2VyKTtcbiAgICB9O1xuICAgIERhdGVFbnYucHJvdG90eXBlLmdldE1vbnRoID0gZnVuY3Rpb24gKG1hcmtlcikge1xuICAgICAgICByZXR1cm4gdGhpcy5jYWxlbmRhclN5c3RlbS5nZXRNYXJrZXJNb250aChtYXJrZXIpO1xuICAgIH07XG4gICAgLy8gQWRkaW5nIC8gU3VidHJhY3RpbmdcbiAgICBEYXRlRW52LnByb3RvdHlwZS5hZGQgPSBmdW5jdGlvbiAobWFya2VyLCBkdXIpIHtcbiAgICAgICAgdmFyIGEgPSB0aGlzLmNhbGVuZGFyU3lzdGVtLm1hcmtlclRvQXJyYXkobWFya2VyKTtcbiAgICAgICAgYVswXSArPSBkdXIueWVhcnM7XG4gICAgICAgIGFbMV0gKz0gZHVyLm1vbnRocztcbiAgICAgICAgYVsyXSArPSBkdXIuZGF5cztcbiAgICAgICAgYVs2XSArPSBkdXIubWlsbGlzZWNvbmRzO1xuICAgICAgICByZXR1cm4gdGhpcy5jYWxlbmRhclN5c3RlbS5hcnJheVRvTWFya2VyKGEpO1xuICAgIH07XG4gICAgRGF0ZUVudi5wcm90b3R5cGUuc3VidHJhY3QgPSBmdW5jdGlvbiAobWFya2VyLCBkdXIpIHtcbiAgICAgICAgdmFyIGEgPSB0aGlzLmNhbGVuZGFyU3lzdGVtLm1hcmtlclRvQXJyYXkobWFya2VyKTtcbiAgICAgICAgYVswXSAtPSBkdXIueWVhcnM7XG4gICAgICAgIGFbMV0gLT0gZHVyLm1vbnRocztcbiAgICAgICAgYVsyXSAtPSBkdXIuZGF5cztcbiAgICAgICAgYVs2XSAtPSBkdXIubWlsbGlzZWNvbmRzO1xuICAgICAgICByZXR1cm4gdGhpcy5jYWxlbmRhclN5c3RlbS5hcnJheVRvTWFya2VyKGEpO1xuICAgIH07XG4gICAgRGF0ZUVudi5wcm90b3R5cGUuYWRkWWVhcnMgPSBmdW5jdGlvbiAobWFya2VyLCBuKSB7XG4gICAgICAgIHZhciBhID0gdGhpcy5jYWxlbmRhclN5c3RlbS5tYXJrZXJUb0FycmF5KG1hcmtlcik7XG4gICAgICAgIGFbMF0gKz0gbjtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2FsZW5kYXJTeXN0ZW0uYXJyYXlUb01hcmtlcihhKTtcbiAgICB9O1xuICAgIERhdGVFbnYucHJvdG90eXBlLmFkZE1vbnRocyA9IGZ1bmN0aW9uIChtYXJrZXIsIG4pIHtcbiAgICAgICAgdmFyIGEgPSB0aGlzLmNhbGVuZGFyU3lzdGVtLm1hcmtlclRvQXJyYXkobWFya2VyKTtcbiAgICAgICAgYVsxXSArPSBuO1xuICAgICAgICByZXR1cm4gdGhpcy5jYWxlbmRhclN5c3RlbS5hcnJheVRvTWFya2VyKGEpO1xuICAgIH07XG4gICAgLy8gRGlmZmluZyBXaG9sZSBVbml0c1xuICAgIERhdGVFbnYucHJvdG90eXBlLmRpZmZXaG9sZVllYXJzID0gZnVuY3Rpb24gKG0wLCBtMSkge1xuICAgICAgICB2YXIgY2FsZW5kYXJTeXN0ZW0gPSB0aGlzLmNhbGVuZGFyU3lzdGVtO1xuICAgICAgICBpZiAodGltZUFzTXMobTApID09PSB0aW1lQXNNcyhtMSkgJiZcbiAgICAgICAgICAgIGNhbGVuZGFyU3lzdGVtLmdldE1hcmtlckRheShtMCkgPT09IGNhbGVuZGFyU3lzdGVtLmdldE1hcmtlckRheShtMSkgJiZcbiAgICAgICAgICAgIGNhbGVuZGFyU3lzdGVtLmdldE1hcmtlck1vbnRoKG0wKSA9PT0gY2FsZW5kYXJTeXN0ZW0uZ2V0TWFya2VyTW9udGgobTEpKSB7XG4gICAgICAgICAgICByZXR1cm4gY2FsZW5kYXJTeXN0ZW0uZ2V0TWFya2VyWWVhcihtMSkgLSBjYWxlbmRhclN5c3RlbS5nZXRNYXJrZXJZZWFyKG0wKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9O1xuICAgIERhdGVFbnYucHJvdG90eXBlLmRpZmZXaG9sZU1vbnRocyA9IGZ1bmN0aW9uIChtMCwgbTEpIHtcbiAgICAgICAgdmFyIGNhbGVuZGFyU3lzdGVtID0gdGhpcy5jYWxlbmRhclN5c3RlbTtcbiAgICAgICAgaWYgKHRpbWVBc01zKG0wKSA9PT0gdGltZUFzTXMobTEpICYmXG4gICAgICAgICAgICBjYWxlbmRhclN5c3RlbS5nZXRNYXJrZXJEYXkobTApID09PSBjYWxlbmRhclN5c3RlbS5nZXRNYXJrZXJEYXkobTEpKSB7XG4gICAgICAgICAgICByZXR1cm4gKGNhbGVuZGFyU3lzdGVtLmdldE1hcmtlck1vbnRoKG0xKSAtIGNhbGVuZGFyU3lzdGVtLmdldE1hcmtlck1vbnRoKG0wKSkgK1xuICAgICAgICAgICAgICAgIChjYWxlbmRhclN5c3RlbS5nZXRNYXJrZXJZZWFyKG0xKSAtIGNhbGVuZGFyU3lzdGVtLmdldE1hcmtlclllYXIobTApKSAqIDEyO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH07XG4gICAgLy8gUmFuZ2UgLyBEdXJhdGlvblxuICAgIERhdGVFbnYucHJvdG90eXBlLmdyZWF0ZXN0V2hvbGVVbml0ID0gZnVuY3Rpb24gKG0wLCBtMSkge1xuICAgICAgICB2YXIgbiA9IHRoaXMuZGlmZldob2xlWWVhcnMobTAsIG0xKTtcbiAgICAgICAgaWYgKG4gIT09IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHVuaXQ6ICd5ZWFyJywgdmFsdWU6IG4gfTtcbiAgICAgICAgfVxuICAgICAgICBuID0gdGhpcy5kaWZmV2hvbGVNb250aHMobTAsIG0xKTtcbiAgICAgICAgaWYgKG4gIT09IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHVuaXQ6ICdtb250aCcsIHZhbHVlOiBuIH07XG4gICAgICAgIH1cbiAgICAgICAgbiA9IGRpZmZXaG9sZVdlZWtzKG0wLCBtMSk7XG4gICAgICAgIGlmIChuICE9PSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm4geyB1bml0OiAnd2VlaycsIHZhbHVlOiBuIH07XG4gICAgICAgIH1cbiAgICAgICAgbiA9IGRpZmZXaG9sZURheXMobTAsIG0xKTtcbiAgICAgICAgaWYgKG4gIT09IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHVuaXQ6ICdkYXknLCB2YWx1ZTogbiB9O1xuICAgICAgICB9XG4gICAgICAgIG4gPSBkaWZmSG91cnMobTAsIG0xKTtcbiAgICAgICAgaWYgKGlzSW50KG4pKSB7XG4gICAgICAgICAgICByZXR1cm4geyB1bml0OiAnaG91cicsIHZhbHVlOiBuIH07XG4gICAgICAgIH1cbiAgICAgICAgbiA9IGRpZmZNaW51dGVzKG0wLCBtMSk7XG4gICAgICAgIGlmIChpc0ludChuKSkge1xuICAgICAgICAgICAgcmV0dXJuIHsgdW5pdDogJ21pbnV0ZScsIHZhbHVlOiBuIH07XG4gICAgICAgIH1cbiAgICAgICAgbiA9IGRpZmZTZWNvbmRzKG0wLCBtMSk7XG4gICAgICAgIGlmIChpc0ludChuKSkge1xuICAgICAgICAgICAgcmV0dXJuIHsgdW5pdDogJ3NlY29uZCcsIHZhbHVlOiBuIH07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHsgdW5pdDogJ21pbGxpc2Vjb25kJywgdmFsdWU6IG0xLnZhbHVlT2YoKSAtIG0wLnZhbHVlT2YoKSB9O1xuICAgIH07XG4gICAgRGF0ZUVudi5wcm90b3R5cGUuY291bnREdXJhdGlvbnNCZXR3ZWVuID0gZnVuY3Rpb24gKG0wLCBtMSwgZCkge1xuICAgICAgICAvLyBUT0RPOiBjYW4gdXNlIGdyZWF0ZXN0V2hvbGVVbml0XG4gICAgICAgIHZhciBkaWZmO1xuICAgICAgICBpZiAoZC55ZWFycykge1xuICAgICAgICAgICAgZGlmZiA9IHRoaXMuZGlmZldob2xlWWVhcnMobTAsIG0xKTtcbiAgICAgICAgICAgIGlmIChkaWZmICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGRpZmYgLyBhc1JvdWdoWWVhcnMoZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGQubW9udGhzKSB7XG4gICAgICAgICAgICBkaWZmID0gdGhpcy5kaWZmV2hvbGVNb250aHMobTAsIG0xKTtcbiAgICAgICAgICAgIGlmIChkaWZmICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGRpZmYgLyBhc1JvdWdoTW9udGhzKGQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChkLmRheXMpIHtcbiAgICAgICAgICAgIGRpZmYgPSBkaWZmV2hvbGVEYXlzKG0wLCBtMSk7XG4gICAgICAgICAgICBpZiAoZGlmZiAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBkaWZmIC8gYXNSb3VnaERheXMoZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIChtMS52YWx1ZU9mKCkgLSBtMC52YWx1ZU9mKCkpIC8gYXNSb3VnaE1zKGQpO1xuICAgIH07XG4gICAgLy8gU3RhcnQtT2ZcbiAgICBEYXRlRW52LnByb3RvdHlwZS5zdGFydE9mID0gZnVuY3Rpb24gKG0sIHVuaXQpIHtcbiAgICAgICAgaWYgKHVuaXQgPT09ICd5ZWFyJykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3RhcnRPZlllYXIobSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodW5pdCA9PT0gJ21vbnRoJykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3RhcnRPZk1vbnRoKG0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHVuaXQgPT09ICd3ZWVrJykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3RhcnRPZldlZWsobSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodW5pdCA9PT0gJ2RheScpIHtcbiAgICAgICAgICAgIHJldHVybiBzdGFydE9mRGF5KG0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHVuaXQgPT09ICdob3VyJykge1xuICAgICAgICAgICAgcmV0dXJuIHN0YXJ0T2ZIb3VyKG0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHVuaXQgPT09ICdtaW51dGUnKSB7XG4gICAgICAgICAgICByZXR1cm4gc3RhcnRPZk1pbnV0ZShtKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh1bml0ID09PSAnc2Vjb25kJykge1xuICAgICAgICAgICAgcmV0dXJuIHN0YXJ0T2ZTZWNvbmQobSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIERhdGVFbnYucHJvdG90eXBlLnN0YXJ0T2ZZZWFyID0gZnVuY3Rpb24gKG0pIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2FsZW5kYXJTeXN0ZW0uYXJyYXlUb01hcmtlcihbXG4gICAgICAgICAgICB0aGlzLmNhbGVuZGFyU3lzdGVtLmdldE1hcmtlclllYXIobSlcbiAgICAgICAgXSk7XG4gICAgfTtcbiAgICBEYXRlRW52LnByb3RvdHlwZS5zdGFydE9mTW9udGggPSBmdW5jdGlvbiAobSkge1xuICAgICAgICByZXR1cm4gdGhpcy5jYWxlbmRhclN5c3RlbS5hcnJheVRvTWFya2VyKFtcbiAgICAgICAgICAgIHRoaXMuY2FsZW5kYXJTeXN0ZW0uZ2V0TWFya2VyWWVhcihtKSxcbiAgICAgICAgICAgIHRoaXMuY2FsZW5kYXJTeXN0ZW0uZ2V0TWFya2VyTW9udGgobSlcbiAgICAgICAgXSk7XG4gICAgfTtcbiAgICBEYXRlRW52LnByb3RvdHlwZS5zdGFydE9mV2VlayA9IGZ1bmN0aW9uIChtKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmNhbGVuZGFyU3lzdGVtLmFycmF5VG9NYXJrZXIoW1xuICAgICAgICAgICAgdGhpcy5jYWxlbmRhclN5c3RlbS5nZXRNYXJrZXJZZWFyKG0pLFxuICAgICAgICAgICAgdGhpcy5jYWxlbmRhclN5c3RlbS5nZXRNYXJrZXJNb250aChtKSxcbiAgICAgICAgICAgIG0uZ2V0VVRDRGF0ZSgpIC0gKChtLmdldFVUQ0RheSgpIC0gdGhpcy53ZWVrRG93ICsgNykgJSA3KVxuICAgICAgICBdKTtcbiAgICB9O1xuICAgIC8vIFdlZWsgTnVtYmVyXG4gICAgRGF0ZUVudi5wcm90b3R5cGUuY29tcHV0ZVdlZWtOdW1iZXIgPSBmdW5jdGlvbiAobWFya2VyKSB7XG4gICAgICAgIGlmICh0aGlzLndlZWtOdW1iZXJGdW5jKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy53ZWVrTnVtYmVyRnVuYyh0aGlzLnRvRGF0ZShtYXJrZXIpKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB3ZWVrT2ZZZWFyKG1hcmtlciwgdGhpcy53ZWVrRG93LCB0aGlzLndlZWtEb3kpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvLyBUT0RPOiBjaG9rZSBvbiB0aW1lWm9uZU5hbWU6IGxvbmdcbiAgICBEYXRlRW52LnByb3RvdHlwZS5mb3JtYXQgPSBmdW5jdGlvbiAobWFya2VyLCBmb3JtYXR0ZXIsIGRhdGVPcHRpb25zKSB7XG4gICAgICAgIGlmIChkYXRlT3B0aW9ucyA9PT0gdm9pZCAwKSB7IGRhdGVPcHRpb25zID0ge307IH1cbiAgICAgICAgcmV0dXJuIGZvcm1hdHRlci5mb3JtYXQoe1xuICAgICAgICAgICAgbWFya2VyOiBtYXJrZXIsXG4gICAgICAgICAgICB0aW1lWm9uZU9mZnNldDogZGF0ZU9wdGlvbnMuZm9yY2VkVHpvICE9IG51bGwgP1xuICAgICAgICAgICAgICAgIGRhdGVPcHRpb25zLmZvcmNlZFR6byA6XG4gICAgICAgICAgICAgICAgdGhpcy5vZmZzZXRGb3JNYXJrZXIobWFya2VyKVxuICAgICAgICB9LCB0aGlzKTtcbiAgICB9O1xuICAgIERhdGVFbnYucHJvdG90eXBlLmZvcm1hdFJhbmdlID0gZnVuY3Rpb24gKHN0YXJ0LCBlbmQsIGZvcm1hdHRlciwgZGF0ZU9wdGlvbnMpIHtcbiAgICAgICAgaWYgKGRhdGVPcHRpb25zID09PSB2b2lkIDApIHsgZGF0ZU9wdGlvbnMgPSB7fTsgfVxuICAgICAgICBpZiAoZGF0ZU9wdGlvbnMuaXNFbmRFeGNsdXNpdmUpIHtcbiAgICAgICAgICAgIGVuZCA9IGFkZE1zKGVuZCwgLTEpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmb3JtYXR0ZXIuZm9ybWF0UmFuZ2Uoe1xuICAgICAgICAgICAgbWFya2VyOiBzdGFydCxcbiAgICAgICAgICAgIHRpbWVab25lT2Zmc2V0OiBkYXRlT3B0aW9ucy5mb3JjZWRTdGFydFR6byAhPSBudWxsID9cbiAgICAgICAgICAgICAgICBkYXRlT3B0aW9ucy5mb3JjZWRTdGFydFR6byA6XG4gICAgICAgICAgICAgICAgdGhpcy5vZmZzZXRGb3JNYXJrZXIoc3RhcnQpXG4gICAgICAgIH0sIHtcbiAgICAgICAgICAgIG1hcmtlcjogZW5kLFxuICAgICAgICAgICAgdGltZVpvbmVPZmZzZXQ6IGRhdGVPcHRpb25zLmZvcmNlZEVuZFR6byAhPSBudWxsID9cbiAgICAgICAgICAgICAgICBkYXRlT3B0aW9ucy5mb3JjZWRFbmRUem8gOlxuICAgICAgICAgICAgICAgIHRoaXMub2Zmc2V0Rm9yTWFya2VyKGVuZClcbiAgICAgICAgfSwgdGhpcyk7XG4gICAgfTtcbiAgICBEYXRlRW52LnByb3RvdHlwZS5mb3JtYXRJc28gPSBmdW5jdGlvbiAobWFya2VyLCBleHRyYU9wdGlvbnMpIHtcbiAgICAgICAgaWYgKGV4dHJhT3B0aW9ucyA9PT0gdm9pZCAwKSB7IGV4dHJhT3B0aW9ucyA9IHt9OyB9XG4gICAgICAgIHZhciB0aW1lWm9uZU9mZnNldCA9IG51bGw7XG4gICAgICAgIGlmICghZXh0cmFPcHRpb25zLm9taXRUaW1lWm9uZU9mZnNldCkge1xuICAgICAgICAgICAgaWYgKGV4dHJhT3B0aW9ucy5mb3JjZWRUem8gIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHRpbWVab25lT2Zmc2V0ID0gZXh0cmFPcHRpb25zLmZvcmNlZFR6bztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHRpbWVab25lT2Zmc2V0ID0gdGhpcy5vZmZzZXRGb3JNYXJrZXIobWFya2VyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYnVpbGRJc29TdHJpbmcobWFya2VyLCB0aW1lWm9uZU9mZnNldCwgZXh0cmFPcHRpb25zLm9taXRUaW1lKTtcbiAgICB9O1xuICAgIC8vIFRpbWVab25lXG4gICAgRGF0ZUVudi5wcm90b3R5cGUudGltZXN0YW1wVG9NYXJrZXIgPSBmdW5jdGlvbiAobXMpIHtcbiAgICAgICAgaWYgKHRoaXMudGltZVpvbmUgPT09ICdsb2NhbCcpIHtcbiAgICAgICAgICAgIHJldHVybiBhcnJheVRvVXRjRGF0ZShkYXRlVG9Mb2NhbEFycmF5KG5ldyBEYXRlKG1zKSkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHRoaXMudGltZVpvbmUgPT09ICdVVEMnIHx8ICF0aGlzLm5hbWVkVGltZVpvbmVJbXBsKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IERhdGUobXMpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIGFycmF5VG9VdGNEYXRlKHRoaXMubmFtZWRUaW1lWm9uZUltcGwudGltZXN0YW1wVG9BcnJheShtcykpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBEYXRlRW52LnByb3RvdHlwZS5vZmZzZXRGb3JNYXJrZXIgPSBmdW5jdGlvbiAobSkge1xuICAgICAgICBpZiAodGhpcy50aW1lWm9uZSA9PT0gJ2xvY2FsJykge1xuICAgICAgICAgICAgcmV0dXJuIC1hcnJheVRvTG9jYWxEYXRlKGRhdGVUb1V0Y0FycmF5KG0pKS5nZXRUaW1lem9uZU9mZnNldCgpOyAvLyBjb252ZXJ0IFwiaW52ZXJzZVwiIG9mZnNldCB0byBcIm5vcm1hbFwiIG9mZnNldFxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHRoaXMudGltZVpvbmUgPT09ICdVVEMnKSB7XG4gICAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0aGlzLm5hbWVkVGltZVpvbmVJbXBsKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5uYW1lZFRpbWVab25lSW1wbC5vZmZzZXRGb3JBcnJheShkYXRlVG9VdGNBcnJheShtKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfTtcbiAgICAvLyBDb252ZXJzaW9uXG4gICAgRGF0ZUVudi5wcm90b3R5cGUudG9EYXRlID0gZnVuY3Rpb24gKG0sIGZvcmNlZFR6bykge1xuICAgICAgICBpZiAodGhpcy50aW1lWm9uZSA9PT0gJ2xvY2FsJykge1xuICAgICAgICAgICAgcmV0dXJuIGFycmF5VG9Mb2NhbERhdGUoZGF0ZVRvVXRjQXJyYXkobSkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHRoaXMudGltZVpvbmUgPT09ICdVVEMnKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IERhdGUobS52YWx1ZU9mKCkpOyAvLyBtYWtlIHN1cmUgaXQncyBhIGNvcHlcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICghdGhpcy5uYW1lZFRpbWVab25lSW1wbCkge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBEYXRlKG0udmFsdWVPZigpIC0gKGZvcmNlZFR6byB8fCAwKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IERhdGUobS52YWx1ZU9mKCkgLVxuICAgICAgICAgICAgICAgIHRoaXMubmFtZWRUaW1lWm9uZUltcGwub2Zmc2V0Rm9yQXJyYXkoZGF0ZVRvVXRjQXJyYXkobSkpICogMTAwMCAqIDYwIC8vIGNvbnZlcnQgbWludXRlcyAtPiBtc1xuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgcmV0dXJuIERhdGVFbnY7XG59KCkpO1xuXG52YXIgU0lNUExFX1NPVVJDRV9QUk9QUyA9IHtcbiAgICBpZDogU3RyaW5nLFxuICAgIGFsbERheURlZmF1bHQ6IEJvb2xlYW4sXG4gICAgZXZlbnREYXRhVHJhbnNmb3JtOiBGdW5jdGlvbixcbiAgICBzdWNjZXNzOiBGdW5jdGlvbixcbiAgICBmYWlsdXJlOiBGdW5jdGlvblxufTtcbnZhciB1aWQkMiA9IDA7XG5mdW5jdGlvbiBkb2VzU291cmNlTmVlZFJhbmdlKGV2ZW50U291cmNlLCBjYWxlbmRhcikge1xuICAgIHZhciBkZWZzID0gY2FsZW5kYXIucGx1Z2luU3lzdGVtLmhvb2tzLmV2ZW50U291cmNlRGVmcztcbiAgICByZXR1cm4gIWRlZnNbZXZlbnRTb3VyY2Uuc291cmNlRGVmSWRdLmlnbm9yZVJhbmdlO1xufVxuZnVuY3Rpb24gcGFyc2VFdmVudFNvdXJjZShyYXcsIGNhbGVuZGFyKSB7XG4gICAgdmFyIGRlZnMgPSBjYWxlbmRhci5wbHVnaW5TeXN0ZW0uaG9va3MuZXZlbnRTb3VyY2VEZWZzO1xuICAgIGZvciAodmFyIGkgPSBkZWZzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7IC8vIGxhdGVyLWFkZGVkIHBsdWdpbnMgdGFrZSBwcmVjZWRlbmNlXG4gICAgICAgIHZhciBkZWYgPSBkZWZzW2ldO1xuICAgICAgICB2YXIgbWV0YSA9IGRlZi5wYXJzZU1ldGEocmF3KTtcbiAgICAgICAgaWYgKG1ldGEpIHtcbiAgICAgICAgICAgIHZhciByZXMgPSBwYXJzZUV2ZW50U291cmNlUHJvcHModHlwZW9mIHJhdyA9PT0gJ29iamVjdCcgPyByYXcgOiB7fSwgbWV0YSwgaSwgY2FsZW5kYXIpO1xuICAgICAgICAgICAgcmVzLl9yYXcgPSByYXc7XG4gICAgICAgICAgICByZXR1cm4gcmVzO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufVxuZnVuY3Rpb24gcGFyc2VFdmVudFNvdXJjZVByb3BzKHJhdywgbWV0YSwgc291cmNlRGVmSWQsIGNhbGVuZGFyKSB7XG4gICAgdmFyIGxlZnRvdmVyczAgPSB7fTtcbiAgICB2YXIgcHJvcHMgPSByZWZpbmVQcm9wcyhyYXcsIFNJTVBMRV9TT1VSQ0VfUFJPUFMsIHt9LCBsZWZ0b3ZlcnMwKTtcbiAgICB2YXIgbGVmdG92ZXJzMSA9IHt9O1xuICAgIHZhciB1aSA9IHByb2Nlc3NVbnNjb3BlZFVpUHJvcHMobGVmdG92ZXJzMCwgY2FsZW5kYXIsIGxlZnRvdmVyczEpO1xuICAgIHByb3BzLmlzRmV0Y2hpbmcgPSBmYWxzZTtcbiAgICBwcm9wcy5sYXRlc3RGZXRjaElkID0gJyc7XG4gICAgcHJvcHMuZmV0Y2hSYW5nZSA9IG51bGw7XG4gICAgcHJvcHMucHVibGljSWQgPSBTdHJpbmcocmF3LmlkIHx8ICcnKTtcbiAgICBwcm9wcy5zb3VyY2VJZCA9IFN0cmluZyh1aWQkMisrKTtcbiAgICBwcm9wcy5zb3VyY2VEZWZJZCA9IHNvdXJjZURlZklkO1xuICAgIHByb3BzLm1ldGEgPSBtZXRhO1xuICAgIHByb3BzLnVpID0gdWk7XG4gICAgcHJvcHMuZXh0ZW5kZWRQcm9wcyA9IGxlZnRvdmVyczE7XG4gICAgcmV0dXJuIHByb3BzO1xufVxuXG5mdW5jdGlvbiByZWR1Y2VFdmVudFNvdXJjZXMgKGV2ZW50U291cmNlcywgYWN0aW9uLCBkYXRlUHJvZmlsZSwgY2FsZW5kYXIpIHtcbiAgICBzd2l0Y2ggKGFjdGlvbi50eXBlKSB7XG4gICAgICAgIGNhc2UgJ0FERF9FVkVOVF9TT1VSQ0VTJzogLy8gYWxyZWFkeSBwYXJzZWRcbiAgICAgICAgICAgIHJldHVybiBhZGRTb3VyY2VzKGV2ZW50U291cmNlcywgYWN0aW9uLnNvdXJjZXMsIGRhdGVQcm9maWxlID8gZGF0ZVByb2ZpbGUuYWN0aXZlUmFuZ2UgOiBudWxsLCBjYWxlbmRhcik7XG4gICAgICAgIGNhc2UgJ1JFTU9WRV9FVkVOVF9TT1VSQ0UnOlxuICAgICAgICAgICAgcmV0dXJuIHJlbW92ZVNvdXJjZShldmVudFNvdXJjZXMsIGFjdGlvbi5zb3VyY2VJZCk7XG4gICAgICAgIGNhc2UgJ1BSRVYnOiAvLyBUT0RPOiBob3cgZG8gd2UgdHJhY2sgYWxsIGFjdGlvbnMgdGhhdCBhZmZlY3QgZGF0ZVByb2ZpbGUgOihcbiAgICAgICAgY2FzZSAnTkVYVCc6XG4gICAgICAgIGNhc2UgJ1NFVF9EQVRFJzpcbiAgICAgICAgY2FzZSAnU0VUX1ZJRVdfVFlQRSc6XG4gICAgICAgICAgICBpZiAoZGF0ZVByb2ZpbGUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmV0Y2hEaXJ0eVNvdXJjZXMoZXZlbnRTb3VyY2VzLCBkYXRlUHJvZmlsZS5hY3RpdmVSYW5nZSwgY2FsZW5kYXIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGV2ZW50U291cmNlcztcbiAgICAgICAgICAgIH1cbiAgICAgICAgY2FzZSAnRkVUQ0hfRVZFTlRfU09VUkNFUyc6XG4gICAgICAgIGNhc2UgJ0NIQU5HRV9USU1FWk9ORSc6XG4gICAgICAgICAgICByZXR1cm4gZmV0Y2hTb3VyY2VzQnlJZHMoZXZlbnRTb3VyY2VzLCBhY3Rpb24uc291cmNlSWRzID9cbiAgICAgICAgICAgICAgICBhcnJheVRvSGFzaChhY3Rpb24uc291cmNlSWRzKSA6XG4gICAgICAgICAgICAgICAgZXhjbHVkZVN0YXRpY1NvdXJjZXMoZXZlbnRTb3VyY2VzLCBjYWxlbmRhciksIGRhdGVQcm9maWxlID8gZGF0ZVByb2ZpbGUuYWN0aXZlUmFuZ2UgOiBudWxsLCBjYWxlbmRhcik7XG4gICAgICAgIGNhc2UgJ1JFQ0VJVkVfRVZFTlRTJzpcbiAgICAgICAgY2FzZSAnUkVDRUlWRV9FVkVOVF9FUlJPUic6XG4gICAgICAgICAgICByZXR1cm4gcmVjZWl2ZVJlc3BvbnNlKGV2ZW50U291cmNlcywgYWN0aW9uLnNvdXJjZUlkLCBhY3Rpb24uZmV0Y2hJZCwgYWN0aW9uLmZldGNoUmFuZ2UpO1xuICAgICAgICBjYXNlICdSRU1PVkVfQUxMX0VWRU5UX1NPVVJDRVMnOlxuICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgcmV0dXJuIGV2ZW50U291cmNlcztcbiAgICB9XG59XG52YXIgdWlkJDMgPSAwO1xuZnVuY3Rpb24gYWRkU291cmNlcyhldmVudFNvdXJjZUhhc2gsIHNvdXJjZXMsIGZldGNoUmFuZ2UsIGNhbGVuZGFyKSB7XG4gICAgdmFyIGhhc2ggPSB7fTtcbiAgICBmb3IgKHZhciBfaSA9IDAsIHNvdXJjZXNfMSA9IHNvdXJjZXM7IF9pIDwgc291cmNlc18xLmxlbmd0aDsgX2krKykge1xuICAgICAgICB2YXIgc291cmNlID0gc291cmNlc18xW19pXTtcbiAgICAgICAgaGFzaFtzb3VyY2Uuc291cmNlSWRdID0gc291cmNlO1xuICAgIH1cbiAgICBpZiAoZmV0Y2hSYW5nZSkge1xuICAgICAgICBoYXNoID0gZmV0Y2hEaXJ0eVNvdXJjZXMoaGFzaCwgZmV0Y2hSYW5nZSwgY2FsZW5kYXIpO1xuICAgIH1cbiAgICByZXR1cm4gX19hc3NpZ24oe30sIGV2ZW50U291cmNlSGFzaCwgaGFzaCk7XG59XG5mdW5jdGlvbiByZW1vdmVTb3VyY2UoZXZlbnRTb3VyY2VIYXNoLCBzb3VyY2VJZCkge1xuICAgIHJldHVybiBmaWx0ZXJIYXNoKGV2ZW50U291cmNlSGFzaCwgZnVuY3Rpb24gKGV2ZW50U291cmNlKSB7XG4gICAgICAgIHJldHVybiBldmVudFNvdXJjZS5zb3VyY2VJZCAhPT0gc291cmNlSWQ7XG4gICAgfSk7XG59XG5mdW5jdGlvbiBmZXRjaERpcnR5U291cmNlcyhzb3VyY2VIYXNoLCBmZXRjaFJhbmdlLCBjYWxlbmRhcikge1xuICAgIHJldHVybiBmZXRjaFNvdXJjZXNCeUlkcyhzb3VyY2VIYXNoLCBmaWx0ZXJIYXNoKHNvdXJjZUhhc2gsIGZ1bmN0aW9uIChldmVudFNvdXJjZSkge1xuICAgICAgICByZXR1cm4gaXNTb3VyY2VEaXJ0eShldmVudFNvdXJjZSwgZmV0Y2hSYW5nZSwgY2FsZW5kYXIpO1xuICAgIH0pLCBmZXRjaFJhbmdlLCBjYWxlbmRhcik7XG59XG5mdW5jdGlvbiBpc1NvdXJjZURpcnR5KGV2ZW50U291cmNlLCBmZXRjaFJhbmdlLCBjYWxlbmRhcikge1xuICAgIGlmICghZG9lc1NvdXJjZU5lZWRSYW5nZShldmVudFNvdXJjZSwgY2FsZW5kYXIpKSB7XG4gICAgICAgIHJldHVybiAhZXZlbnRTb3VyY2UubGF0ZXN0RmV0Y2hJZDtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHJldHVybiAhY2FsZW5kYXIub3B0KCdsYXp5RmV0Y2hpbmcnKSB8fFxuICAgICAgICAgICAgIWV2ZW50U291cmNlLmZldGNoUmFuZ2UgfHxcbiAgICAgICAgICAgIGV2ZW50U291cmNlLmlzRmV0Y2hpbmcgfHwgLy8gYWx3YXlzIGNhbmNlbCBvdXRkYXRlZCBpbi1wcm9ncmVzcyBmZXRjaGVzXG4gICAgICAgICAgICBmZXRjaFJhbmdlLnN0YXJ0IDwgZXZlbnRTb3VyY2UuZmV0Y2hSYW5nZS5zdGFydCB8fFxuICAgICAgICAgICAgZmV0Y2hSYW5nZS5lbmQgPiBldmVudFNvdXJjZS5mZXRjaFJhbmdlLmVuZDtcbiAgICB9XG59XG5mdW5jdGlvbiBmZXRjaFNvdXJjZXNCeUlkcyhwcmV2U291cmNlcywgc291cmNlSWRIYXNoLCBmZXRjaFJhbmdlLCBjYWxlbmRhcikge1xuICAgIHZhciBuZXh0U291cmNlcyA9IHt9O1xuICAgIGZvciAodmFyIHNvdXJjZUlkIGluIHByZXZTb3VyY2VzKSB7XG4gICAgICAgIHZhciBzb3VyY2UgPSBwcmV2U291cmNlc1tzb3VyY2VJZF07XG4gICAgICAgIGlmIChzb3VyY2VJZEhhc2hbc291cmNlSWRdKSB7XG4gICAgICAgICAgICBuZXh0U291cmNlc1tzb3VyY2VJZF0gPSBmZXRjaFNvdXJjZShzb3VyY2UsIGZldGNoUmFuZ2UsIGNhbGVuZGFyKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIG5leHRTb3VyY2VzW3NvdXJjZUlkXSA9IHNvdXJjZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gbmV4dFNvdXJjZXM7XG59XG5mdW5jdGlvbiBmZXRjaFNvdXJjZShldmVudFNvdXJjZSwgZmV0Y2hSYW5nZSwgY2FsZW5kYXIpIHtcbiAgICB2YXIgc291cmNlRGVmID0gY2FsZW5kYXIucGx1Z2luU3lzdGVtLmhvb2tzLmV2ZW50U291cmNlRGVmc1tldmVudFNvdXJjZS5zb3VyY2VEZWZJZF07XG4gICAgdmFyIGZldGNoSWQgPSBTdHJpbmcodWlkJDMrKyk7XG4gICAgc291cmNlRGVmLmZldGNoKHtcbiAgICAgICAgZXZlbnRTb3VyY2U6IGV2ZW50U291cmNlLFxuICAgICAgICBjYWxlbmRhcjogY2FsZW5kYXIsXG4gICAgICAgIHJhbmdlOiBmZXRjaFJhbmdlXG4gICAgfSwgZnVuY3Rpb24gKHJlcykge1xuICAgICAgICB2YXIgcmF3RXZlbnRzID0gcmVzLnJhd0V2ZW50cztcbiAgICAgICAgdmFyIGNhbFN1Y2Nlc3MgPSBjYWxlbmRhci5vcHQoJ2V2ZW50U291cmNlU3VjY2VzcycpO1xuICAgICAgICB2YXIgY2FsU3VjY2Vzc1JlcztcbiAgICAgICAgdmFyIHNvdXJjZVN1Y2Nlc3NSZXM7XG4gICAgICAgIGlmIChldmVudFNvdXJjZS5zdWNjZXNzKSB7XG4gICAgICAgICAgICBzb3VyY2VTdWNjZXNzUmVzID0gZXZlbnRTb3VyY2Uuc3VjY2VzcyhyYXdFdmVudHMsIHJlcy54aHIpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjYWxTdWNjZXNzKSB7XG4gICAgICAgICAgICBjYWxTdWNjZXNzUmVzID0gY2FsU3VjY2VzcyhyYXdFdmVudHMsIHJlcy54aHIpO1xuICAgICAgICB9XG4gICAgICAgIHJhd0V2ZW50cyA9IHNvdXJjZVN1Y2Nlc3NSZXMgfHwgY2FsU3VjY2Vzc1JlcyB8fCByYXdFdmVudHM7XG4gICAgICAgIGNhbGVuZGFyLmRpc3BhdGNoKHtcbiAgICAgICAgICAgIHR5cGU6ICdSRUNFSVZFX0VWRU5UUycsXG4gICAgICAgICAgICBzb3VyY2VJZDogZXZlbnRTb3VyY2Uuc291cmNlSWQsXG4gICAgICAgICAgICBmZXRjaElkOiBmZXRjaElkLFxuICAgICAgICAgICAgZmV0Y2hSYW5nZTogZmV0Y2hSYW5nZSxcbiAgICAgICAgICAgIHJhd0V2ZW50czogcmF3RXZlbnRzXG4gICAgICAgIH0pO1xuICAgIH0sIGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICB2YXIgY2FsbEZhaWx1cmUgPSBjYWxlbmRhci5vcHQoJ2V2ZW50U291cmNlRmFpbHVyZScpO1xuICAgICAgICBjb25zb2xlLndhcm4oZXJyb3IubWVzc2FnZSwgZXJyb3IpO1xuICAgICAgICBpZiAoZXZlbnRTb3VyY2UuZmFpbHVyZSkge1xuICAgICAgICAgICAgZXZlbnRTb3VyY2UuZmFpbHVyZShlcnJvcik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNhbGxGYWlsdXJlKSB7XG4gICAgICAgICAgICBjYWxsRmFpbHVyZShlcnJvcik7XG4gICAgICAgIH1cbiAgICAgICAgY2FsZW5kYXIuZGlzcGF0Y2goe1xuICAgICAgICAgICAgdHlwZTogJ1JFQ0VJVkVfRVZFTlRfRVJST1InLFxuICAgICAgICAgICAgc291cmNlSWQ6IGV2ZW50U291cmNlLnNvdXJjZUlkLFxuICAgICAgICAgICAgZmV0Y2hJZDogZmV0Y2hJZCxcbiAgICAgICAgICAgIGZldGNoUmFuZ2U6IGZldGNoUmFuZ2UsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3JcbiAgICAgICAgfSk7XG4gICAgfSk7XG4gICAgcmV0dXJuIF9fYXNzaWduKHt9LCBldmVudFNvdXJjZSwgeyBpc0ZldGNoaW5nOiB0cnVlLCBsYXRlc3RGZXRjaElkOiBmZXRjaElkIH0pO1xufVxuZnVuY3Rpb24gcmVjZWl2ZVJlc3BvbnNlKHNvdXJjZUhhc2gsIHNvdXJjZUlkLCBmZXRjaElkLCBmZXRjaFJhbmdlKSB7XG4gICAgdmFyIF9hO1xuICAgIHZhciBldmVudFNvdXJjZSA9IHNvdXJjZUhhc2hbc291cmNlSWRdO1xuICAgIGlmIChldmVudFNvdXJjZSAmJiAvLyBub3QgYWxyZWFkeSByZW1vdmVkXG4gICAgICAgIGZldGNoSWQgPT09IGV2ZW50U291cmNlLmxhdGVzdEZldGNoSWQpIHtcbiAgICAgICAgcmV0dXJuIF9fYXNzaWduKHt9LCBzb3VyY2VIYXNoLCAoX2EgPSB7fSwgX2Fbc291cmNlSWRdID0gX19hc3NpZ24oe30sIGV2ZW50U291cmNlLCB7IGlzRmV0Y2hpbmc6IGZhbHNlLCBmZXRjaFJhbmdlOiBmZXRjaFJhbmdlIC8vIGFsc28gc2VydmVzIGFzIGEgbWFya2VyIHRoYXQgYXQgbGVhc3Qgb25lIGZldGNoIGhhcyBjb21wbGV0ZWRcbiAgICAgICAgIH0pLCBfYSkpO1xuICAgIH1cbiAgICByZXR1cm4gc291cmNlSGFzaDtcbn1cbmZ1bmN0aW9uIGV4Y2x1ZGVTdGF0aWNTb3VyY2VzKGV2ZW50U291cmNlcywgY2FsZW5kYXIpIHtcbiAgICByZXR1cm4gZmlsdGVySGFzaChldmVudFNvdXJjZXMsIGZ1bmN0aW9uIChldmVudFNvdXJjZSkge1xuICAgICAgICByZXR1cm4gZG9lc1NvdXJjZU5lZWRSYW5nZShldmVudFNvdXJjZSwgY2FsZW5kYXIpO1xuICAgIH0pO1xufVxuXG52YXIgRGF0ZVByb2ZpbGVHZW5lcmF0b3IgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gRGF0ZVByb2ZpbGVHZW5lcmF0b3Iodmlld1NwZWMsIGNhbGVuZGFyKSB7XG4gICAgICAgIHRoaXMudmlld1NwZWMgPSB2aWV3U3BlYztcbiAgICAgICAgdGhpcy5vcHRpb25zID0gdmlld1NwZWMub3B0aW9ucztcbiAgICAgICAgdGhpcy5kYXRlRW52ID0gY2FsZW5kYXIuZGF0ZUVudjtcbiAgICAgICAgdGhpcy5jYWxlbmRhciA9IGNhbGVuZGFyO1xuICAgICAgICB0aGlzLmluaXRIaWRkZW5EYXlzKCk7XG4gICAgfVxuICAgIC8qIERhdGUgUmFuZ2UgQ29tcHV0YXRpb25cbiAgICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuICAgIC8vIEJ1aWxkcyBhIHN0cnVjdHVyZSB3aXRoIGluZm8gYWJvdXQgd2hhdCB0aGUgZGF0ZXMvcmFuZ2VzIHdpbGwgYmUgZm9yIHRoZSBcInByZXZcIiB2aWV3LlxuICAgIERhdGVQcm9maWxlR2VuZXJhdG9yLnByb3RvdHlwZS5idWlsZFByZXYgPSBmdW5jdGlvbiAoY3VycmVudERhdGVQcm9maWxlLCBjdXJyZW50RGF0ZSkge1xuICAgICAgICB2YXIgZGF0ZUVudiA9IHRoaXMuZGF0ZUVudjtcbiAgICAgICAgdmFyIHByZXZEYXRlID0gZGF0ZUVudi5zdWJ0cmFjdChkYXRlRW52LnN0YXJ0T2YoY3VycmVudERhdGUsIGN1cnJlbnREYXRlUHJvZmlsZS5jdXJyZW50UmFuZ2VVbml0KSwgLy8gaW1wb3J0YW50IGZvciBzdGFydC1vZi1tb250aFxuICAgICAgICBjdXJyZW50RGF0ZVByb2ZpbGUuZGF0ZUluY3JlbWVudCk7XG4gICAgICAgIHJldHVybiB0aGlzLmJ1aWxkKHByZXZEYXRlLCAtMSk7XG4gICAgfTtcbiAgICAvLyBCdWlsZHMgYSBzdHJ1Y3R1cmUgd2l0aCBpbmZvIGFib3V0IHdoYXQgdGhlIGRhdGVzL3JhbmdlcyB3aWxsIGJlIGZvciB0aGUgXCJuZXh0XCIgdmlldy5cbiAgICBEYXRlUHJvZmlsZUdlbmVyYXRvci5wcm90b3R5cGUuYnVpbGROZXh0ID0gZnVuY3Rpb24gKGN1cnJlbnREYXRlUHJvZmlsZSwgY3VycmVudERhdGUpIHtcbiAgICAgICAgdmFyIGRhdGVFbnYgPSB0aGlzLmRhdGVFbnY7XG4gICAgICAgIHZhciBuZXh0RGF0ZSA9IGRhdGVFbnYuYWRkKGRhdGVFbnYuc3RhcnRPZihjdXJyZW50RGF0ZSwgY3VycmVudERhdGVQcm9maWxlLmN1cnJlbnRSYW5nZVVuaXQpLCAvLyBpbXBvcnRhbnQgZm9yIHN0YXJ0LW9mLW1vbnRoXG4gICAgICAgIGN1cnJlbnREYXRlUHJvZmlsZS5kYXRlSW5jcmVtZW50KTtcbiAgICAgICAgcmV0dXJuIHRoaXMuYnVpbGQobmV4dERhdGUsIDEpO1xuICAgIH07XG4gICAgLy8gQnVpbGRzIGEgc3RydWN0dXJlIGhvbGRpbmcgZGF0ZXMvcmFuZ2VzIGZvciByZW5kZXJpbmcgYXJvdW5kIHRoZSBnaXZlbiBkYXRlLlxuICAgIC8vIE9wdGlvbmFsIGRpcmVjdGlvbiBwYXJhbSBpbmRpY2F0ZXMgd2hldGhlciB0aGUgZGF0ZSBpcyBiZWluZyBpbmNyZW1lbnRlZC9kZWNyZW1lbnRlZFxuICAgIC8vIGZyb20gaXRzIHByZXZpb3VzIHZhbHVlLiBkZWNyZW1lbnRlZCA9IC0xLCBpbmNyZW1lbnRlZCA9IDEgKGRlZmF1bHQpLlxuICAgIERhdGVQcm9maWxlR2VuZXJhdG9yLnByb3RvdHlwZS5idWlsZCA9IGZ1bmN0aW9uIChjdXJyZW50RGF0ZSwgZGlyZWN0aW9uLCBmb3JjZVRvVmFsaWQpIHtcbiAgICAgICAgaWYgKGZvcmNlVG9WYWxpZCA9PT0gdm9pZCAwKSB7IGZvcmNlVG9WYWxpZCA9IGZhbHNlOyB9XG4gICAgICAgIHZhciB2YWxpZFJhbmdlO1xuICAgICAgICB2YXIgbWluVGltZSA9IG51bGw7XG4gICAgICAgIHZhciBtYXhUaW1lID0gbnVsbDtcbiAgICAgICAgdmFyIGN1cnJlbnRJbmZvO1xuICAgICAgICB2YXIgaXNSYW5nZUFsbERheTtcbiAgICAgICAgdmFyIHJlbmRlclJhbmdlO1xuICAgICAgICB2YXIgYWN0aXZlUmFuZ2U7XG4gICAgICAgIHZhciBpc1ZhbGlkO1xuICAgICAgICB2YWxpZFJhbmdlID0gdGhpcy5idWlsZFZhbGlkUmFuZ2UoKTtcbiAgICAgICAgdmFsaWRSYW5nZSA9IHRoaXMudHJpbUhpZGRlbkRheXModmFsaWRSYW5nZSk7XG4gICAgICAgIGlmIChmb3JjZVRvVmFsaWQpIHtcbiAgICAgICAgICAgIGN1cnJlbnREYXRlID0gY29uc3RyYWluTWFya2VyVG9SYW5nZShjdXJyZW50RGF0ZSwgdmFsaWRSYW5nZSk7XG4gICAgICAgIH1cbiAgICAgICAgY3VycmVudEluZm8gPSB0aGlzLmJ1aWxkQ3VycmVudFJhbmdlSW5mbyhjdXJyZW50RGF0ZSwgZGlyZWN0aW9uKTtcbiAgICAgICAgaXNSYW5nZUFsbERheSA9IC9eKHllYXJ8bW9udGh8d2Vla3xkYXkpJC8udGVzdChjdXJyZW50SW5mby51bml0KTtcbiAgICAgICAgcmVuZGVyUmFuZ2UgPSB0aGlzLmJ1aWxkUmVuZGVyUmFuZ2UodGhpcy50cmltSGlkZGVuRGF5cyhjdXJyZW50SW5mby5yYW5nZSksIGN1cnJlbnRJbmZvLnVuaXQsIGlzUmFuZ2VBbGxEYXkpO1xuICAgICAgICByZW5kZXJSYW5nZSA9IHRoaXMudHJpbUhpZGRlbkRheXMocmVuZGVyUmFuZ2UpO1xuICAgICAgICBhY3RpdmVSYW5nZSA9IHJlbmRlclJhbmdlO1xuICAgICAgICBpZiAoIXRoaXMub3B0aW9ucy5zaG93Tm9uQ3VycmVudERhdGVzKSB7XG4gICAgICAgICAgICBhY3RpdmVSYW5nZSA9IGludGVyc2VjdFJhbmdlcyhhY3RpdmVSYW5nZSwgY3VycmVudEluZm8ucmFuZ2UpO1xuICAgICAgICB9XG4gICAgICAgIG1pblRpbWUgPSBjcmVhdGVEdXJhdGlvbih0aGlzLm9wdGlvbnMubWluVGltZSk7XG4gICAgICAgIG1heFRpbWUgPSBjcmVhdGVEdXJhdGlvbih0aGlzLm9wdGlvbnMubWF4VGltZSk7XG4gICAgICAgIGFjdGl2ZVJhbmdlID0gdGhpcy5hZGp1c3RBY3RpdmVSYW5nZShhY3RpdmVSYW5nZSwgbWluVGltZSwgbWF4VGltZSk7XG4gICAgICAgIGFjdGl2ZVJhbmdlID0gaW50ZXJzZWN0UmFuZ2VzKGFjdGl2ZVJhbmdlLCB2YWxpZFJhbmdlKTsgLy8gbWlnaHQgcmV0dXJuIG51bGxcbiAgICAgICAgLy8gaXQncyBpbnZhbGlkIGlmIHRoZSBvcmlnaW5hbGx5IHJlcXVlc3RlZCBkYXRlIGlzIG5vdCBjb250YWluZWQsXG4gICAgICAgIC8vIG9yIGlmIHRoZSByYW5nZSBpcyBjb21wbGV0ZWx5IG91dHNpZGUgb2YgdGhlIHZhbGlkIHJhbmdlLlxuICAgICAgICBpc1ZhbGlkID0gcmFuZ2VzSW50ZXJzZWN0KGN1cnJlbnRJbmZvLnJhbmdlLCB2YWxpZFJhbmdlKTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIC8vIGNvbnN0cmFpbnQgZm9yIHdoZXJlIHByZXYvbmV4dCBvcGVyYXRpb25zIGNhbiBnbyBhbmQgd2hlcmUgZXZlbnRzIGNhbiBiZSBkcmFnZ2VkL3Jlc2l6ZWQgdG8uXG4gICAgICAgICAgICAvLyBhbiBvYmplY3Qgd2l0aCBvcHRpb25hbCBzdGFydCBhbmQgZW5kIHByb3BlcnRpZXMuXG4gICAgICAgICAgICB2YWxpZFJhbmdlOiB2YWxpZFJhbmdlLFxuICAgICAgICAgICAgLy8gcmFuZ2UgdGhlIHZpZXcgaXMgZm9ybWFsbHkgcmVzcG9uc2libGUgZm9yLlxuICAgICAgICAgICAgLy8gZm9yIGV4YW1wbGUsIGEgbW9udGggdmlldyBtaWdodCBoYXZlIDFzdC0zMXN0LCBleGNsdWRpbmcgcGFkZGVkIGRhdGVzXG4gICAgICAgICAgICBjdXJyZW50UmFuZ2U6IGN1cnJlbnRJbmZvLnJhbmdlLFxuICAgICAgICAgICAgLy8gbmFtZSBvZiBsYXJnZXN0IHVuaXQgYmVpbmcgZGlzcGxheWVkLCBsaWtlIFwibW9udGhcIiBvciBcIndlZWtcIlxuICAgICAgICAgICAgY3VycmVudFJhbmdlVW5pdDogY3VycmVudEluZm8udW5pdCxcbiAgICAgICAgICAgIGlzUmFuZ2VBbGxEYXk6IGlzUmFuZ2VBbGxEYXksXG4gICAgICAgICAgICAvLyBkYXRlcyB0aGF0IGRpc3BsYXkgZXZlbnRzIGFuZCBhY2NlcHQgZHJhZy1uLWRyb3BcbiAgICAgICAgICAgIC8vIHdpbGwgYmUgYG51bGxgIGlmIG5vIGRhdGVzIGFjY2VwdCBldmVudHNcbiAgICAgICAgICAgIGFjdGl2ZVJhbmdlOiBhY3RpdmVSYW5nZSxcbiAgICAgICAgICAgIC8vIGRhdGUgcmFuZ2Ugd2l0aCBhIHJlbmRlcmVkIHNrZWxldG9uXG4gICAgICAgICAgICAvLyBpbmNsdWRlcyBub3QtYWN0aXZlIGRheXMgdGhhdCBuZWVkIHNvbWUgc29ydCBvZiBET01cbiAgICAgICAgICAgIHJlbmRlclJhbmdlOiByZW5kZXJSYW5nZSxcbiAgICAgICAgICAgIC8vIER1cmF0aW9uIG9iamVjdCB0aGF0IGRlbm90ZXMgdGhlIGZpcnN0IHZpc2libGUgdGltZSBvZiBhbnkgZ2l2ZW4gZGF5XG4gICAgICAgICAgICBtaW5UaW1lOiBtaW5UaW1lLFxuICAgICAgICAgICAgLy8gRHVyYXRpb24gb2JqZWN0IHRoYXQgZGVub3RlcyB0aGUgZXhjbHVzaXZlIHZpc2libGUgZW5kIHRpbWUgb2YgYW55IGdpdmVuIGRheVxuICAgICAgICAgICAgbWF4VGltZTogbWF4VGltZSxcbiAgICAgICAgICAgIGlzVmFsaWQ6IGlzVmFsaWQsXG4gICAgICAgICAgICAvLyBob3cgZmFyIHRoZSBjdXJyZW50IGRhdGUgd2lsbCBtb3ZlIGZvciBhIHByZXYvbmV4dCBvcGVyYXRpb25cbiAgICAgICAgICAgIGRhdGVJbmNyZW1lbnQ6IHRoaXMuYnVpbGREYXRlSW5jcmVtZW50KGN1cnJlbnRJbmZvLmR1cmF0aW9uKVxuICAgICAgICAgICAgLy8gcGFzcyBhIGZhbGxiYWNrIChtaWdodCBiZSBudWxsKSBeXG4gICAgICAgIH07XG4gICAgfTtcbiAgICAvLyBCdWlsZHMgYW4gb2JqZWN0IHdpdGggb3B0aW9uYWwgc3RhcnQvZW5kIHByb3BlcnRpZXMuXG4gICAgLy8gSW5kaWNhdGVzIHRoZSBtaW5pbXVtL21heGltdW0gZGF0ZXMgdG8gZGlzcGxheS5cbiAgICAvLyBub3QgcmVzcG9uc2libGUgZm9yIHRyaW1taW5nIGhpZGRlbiBkYXlzLlxuICAgIERhdGVQcm9maWxlR2VuZXJhdG9yLnByb3RvdHlwZS5idWlsZFZhbGlkUmFuZ2UgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFJhbmdlT3B0aW9uKCd2YWxpZFJhbmdlJywgdGhpcy5jYWxlbmRhci5nZXROb3coKSkgfHxcbiAgICAgICAgICAgIHsgc3RhcnQ6IG51bGwsIGVuZDogbnVsbCB9OyAvLyBjb21wbGV0ZWx5IG9wZW4tZW5kZWRcbiAgICB9O1xuICAgIC8vIEJ1aWxkcyBhIHN0cnVjdHVyZSB3aXRoIGluZm8gYWJvdXQgdGhlIFwiY3VycmVudFwiIHJhbmdlLCB0aGUgcmFuZ2UgdGhhdCBpc1xuICAgIC8vIGhpZ2hsaWdodGVkIGFzIGJlaW5nIHRoZSBjdXJyZW50IG1vbnRoIGZvciBleGFtcGxlLlxuICAgIC8vIFNlZSBidWlsZCgpIGZvciBhIGRlc2NyaXB0aW9uIG9mIGBkaXJlY3Rpb25gLlxuICAgIC8vIEd1YXJhbnRlZWQgdG8gaGF2ZSBgcmFuZ2VgIGFuZCBgdW5pdGAgcHJvcGVydGllcy4gYGR1cmF0aW9uYCBpcyBvcHRpb25hbC5cbiAgICBEYXRlUHJvZmlsZUdlbmVyYXRvci5wcm90b3R5cGUuYnVpbGRDdXJyZW50UmFuZ2VJbmZvID0gZnVuY3Rpb24gKGRhdGUsIGRpcmVjdGlvbikge1xuICAgICAgICB2YXIgX2EgPSB0aGlzLCB2aWV3U3BlYyA9IF9hLnZpZXdTcGVjLCBkYXRlRW52ID0gX2EuZGF0ZUVudjtcbiAgICAgICAgdmFyIGR1cmF0aW9uID0gbnVsbDtcbiAgICAgICAgdmFyIHVuaXQgPSBudWxsO1xuICAgICAgICB2YXIgcmFuZ2UgPSBudWxsO1xuICAgICAgICB2YXIgZGF5Q291bnQ7XG4gICAgICAgIGlmICh2aWV3U3BlYy5kdXJhdGlvbikge1xuICAgICAgICAgICAgZHVyYXRpb24gPSB2aWV3U3BlYy5kdXJhdGlvbjtcbiAgICAgICAgICAgIHVuaXQgPSB2aWV3U3BlYy5kdXJhdGlvblVuaXQ7XG4gICAgICAgICAgICByYW5nZSA9IHRoaXMuYnVpbGRSYW5nZUZyb21EdXJhdGlvbihkYXRlLCBkaXJlY3Rpb24sIGR1cmF0aW9uLCB1bml0KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICgoZGF5Q291bnQgPSB0aGlzLm9wdGlvbnMuZGF5Q291bnQpKSB7XG4gICAgICAgICAgICB1bml0ID0gJ2RheSc7XG4gICAgICAgICAgICByYW5nZSA9IHRoaXMuYnVpbGRSYW5nZUZyb21EYXlDb3VudChkYXRlLCBkaXJlY3Rpb24sIGRheUNvdW50KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICgocmFuZ2UgPSB0aGlzLmJ1aWxkQ3VzdG9tVmlzaWJsZVJhbmdlKGRhdGUpKSkge1xuICAgICAgICAgICAgdW5pdCA9IGRhdGVFbnYuZ3JlYXRlc3RXaG9sZVVuaXQocmFuZ2Uuc3RhcnQsIHJhbmdlLmVuZCkudW5pdDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGR1cmF0aW9uID0gdGhpcy5nZXRGYWxsYmFja0R1cmF0aW9uKCk7XG4gICAgICAgICAgICB1bml0ID0gZ3JlYXRlc3REdXJhdGlvbkRlbm9taW5hdG9yKGR1cmF0aW9uKS51bml0O1xuICAgICAgICAgICAgcmFuZ2UgPSB0aGlzLmJ1aWxkUmFuZ2VGcm9tRHVyYXRpb24oZGF0ZSwgZGlyZWN0aW9uLCBkdXJhdGlvbiwgdW5pdCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHsgZHVyYXRpb246IGR1cmF0aW9uLCB1bml0OiB1bml0LCByYW5nZTogcmFuZ2UgfTtcbiAgICB9O1xuICAgIERhdGVQcm9maWxlR2VuZXJhdG9yLnByb3RvdHlwZS5nZXRGYWxsYmFja0R1cmF0aW9uID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gY3JlYXRlRHVyYXRpb24oeyBkYXk6IDEgfSk7XG4gICAgfTtcbiAgICAvLyBSZXR1cm5zIGEgbmV3IGFjdGl2ZVJhbmdlIHRvIGhhdmUgdGltZSB2YWx1ZXMgKHVuLWFtYmlndWF0ZSlcbiAgICAvLyBtaW5UaW1lIG9yIG1heFRpbWUgY2F1c2VzIHRoZSByYW5nZSB0byBleHBhbmQuXG4gICAgRGF0ZVByb2ZpbGVHZW5lcmF0b3IucHJvdG90eXBlLmFkanVzdEFjdGl2ZVJhbmdlID0gZnVuY3Rpb24gKHJhbmdlLCBtaW5UaW1lLCBtYXhUaW1lKSB7XG4gICAgICAgIHZhciBkYXRlRW52ID0gdGhpcy5kYXRlRW52O1xuICAgICAgICB2YXIgc3RhcnQgPSByYW5nZS5zdGFydDtcbiAgICAgICAgdmFyIGVuZCA9IHJhbmdlLmVuZDtcbiAgICAgICAgaWYgKHRoaXMudmlld1NwZWMuY2xhc3MucHJvdG90eXBlLnVzZXNNaW5NYXhUaW1lKSB7XG4gICAgICAgICAgICAvLyBleHBhbmQgYWN0aXZlIHJhbmdlIGlmIG1pblRpbWUgaXMgbmVnYXRpdmUgKHdoeSBub3Qgd2hlbiBwb3NpdGl2ZT8pXG4gICAgICAgICAgICBpZiAoYXNSb3VnaERheXMobWluVGltZSkgPCAwKSB7XG4gICAgICAgICAgICAgICAgc3RhcnQgPSBzdGFydE9mRGF5KHN0YXJ0KTsgLy8gbmVjZXNzYXJ5P1xuICAgICAgICAgICAgICAgIHN0YXJ0ID0gZGF0ZUVudi5hZGQoc3RhcnQsIG1pblRpbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gZXhwYW5kIGFjdGl2ZSByYW5nZSBpZiBtYXhUaW1lIGlzIGJleW9uZCBvbmUgZGF5ICh3aHkgbm90IHdoZW4gcG9zaXRpdmU/KVxuICAgICAgICAgICAgaWYgKGFzUm91Z2hEYXlzKG1heFRpbWUpID4gMSkge1xuICAgICAgICAgICAgICAgIGVuZCA9IHN0YXJ0T2ZEYXkoZW5kKTsgLy8gbmVjZXNzYXJ5P1xuICAgICAgICAgICAgICAgIGVuZCA9IGFkZERheXMoZW5kLCAtMSk7XG4gICAgICAgICAgICAgICAgZW5kID0gZGF0ZUVudi5hZGQoZW5kLCBtYXhUaW1lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4geyBzdGFydDogc3RhcnQsIGVuZDogZW5kIH07XG4gICAgfTtcbiAgICAvLyBCdWlsZHMgdGhlIFwiY3VycmVudFwiIHJhbmdlIHdoZW4gaXQgaXMgc3BlY2lmaWVkIGFzIGFuIGV4cGxpY2l0IGR1cmF0aW9uLlxuICAgIC8vIGB1bml0YCBpcyB0aGUgYWxyZWFkeS1jb21wdXRlZCBncmVhdGVzdER1cmF0aW9uRGVub21pbmF0b3IgdW5pdCBvZiBkdXJhdGlvbi5cbiAgICBEYXRlUHJvZmlsZUdlbmVyYXRvci5wcm90b3R5cGUuYnVpbGRSYW5nZUZyb21EdXJhdGlvbiA9IGZ1bmN0aW9uIChkYXRlLCBkaXJlY3Rpb24sIGR1cmF0aW9uLCB1bml0KSB7XG4gICAgICAgIHZhciBkYXRlRW52ID0gdGhpcy5kYXRlRW52O1xuICAgICAgICB2YXIgYWxpZ25tZW50ID0gdGhpcy5vcHRpb25zLmRhdGVBbGlnbm1lbnQ7XG4gICAgICAgIHZhciBkYXRlSW5jcmVtZW50SW5wdXQ7XG4gICAgICAgIHZhciBkYXRlSW5jcmVtZW50RHVyYXRpb247XG4gICAgICAgIHZhciBzdGFydDtcbiAgICAgICAgdmFyIGVuZDtcbiAgICAgICAgdmFyIHJlcztcbiAgICAgICAgLy8gY29tcHV0ZSB3aGF0IHRoZSBhbGlnbm1lbnQgc2hvdWxkIGJlXG4gICAgICAgIGlmICghYWxpZ25tZW50KSB7XG4gICAgICAgICAgICBkYXRlSW5jcmVtZW50SW5wdXQgPSB0aGlzLm9wdGlvbnMuZGF0ZUluY3JlbWVudDtcbiAgICAgICAgICAgIGlmIChkYXRlSW5jcmVtZW50SW5wdXQpIHtcbiAgICAgICAgICAgICAgICBkYXRlSW5jcmVtZW50RHVyYXRpb24gPSBjcmVhdGVEdXJhdGlvbihkYXRlSW5jcmVtZW50SW5wdXQpO1xuICAgICAgICAgICAgICAgIC8vIHVzZSB0aGUgc21hbGxlciBvZiB0aGUgdHdvIHVuaXRzXG4gICAgICAgICAgICAgICAgaWYgKGFzUm91Z2hNcyhkYXRlSW5jcmVtZW50RHVyYXRpb24pIDwgYXNSb3VnaE1zKGR1cmF0aW9uKSkge1xuICAgICAgICAgICAgICAgICAgICBhbGlnbm1lbnQgPSBncmVhdGVzdER1cmF0aW9uRGVub21pbmF0b3IoZGF0ZUluY3JlbWVudER1cmF0aW9uLCAhZ2V0V2Vla3NGcm9tSW5wdXQoZGF0ZUluY3JlbWVudElucHV0KSkudW5pdDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGFsaWdubWVudCA9IHVuaXQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgYWxpZ25tZW50ID0gdW5pdDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvLyBpZiB0aGUgdmlldyBkaXNwbGF5cyBhIHNpbmdsZSBkYXkgb3Igc21hbGxlclxuICAgICAgICBpZiAoYXNSb3VnaERheXMoZHVyYXRpb24pIDw9IDEpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLmlzSGlkZGVuRGF5KHN0YXJ0KSkge1xuICAgICAgICAgICAgICAgIHN0YXJ0ID0gdGhpcy5za2lwSGlkZGVuRGF5cyhzdGFydCwgZGlyZWN0aW9uKTtcbiAgICAgICAgICAgICAgICBzdGFydCA9IHN0YXJ0T2ZEYXkoc3RhcnQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGZ1bmN0aW9uIGNvbXB1dGVSZXMoKSB7XG4gICAgICAgICAgICBzdGFydCA9IGRhdGVFbnYuc3RhcnRPZihkYXRlLCBhbGlnbm1lbnQpO1xuICAgICAgICAgICAgZW5kID0gZGF0ZUVudi5hZGQoc3RhcnQsIGR1cmF0aW9uKTtcbiAgICAgICAgICAgIHJlcyA9IHsgc3RhcnQ6IHN0YXJ0LCBlbmQ6IGVuZCB9O1xuICAgICAgICB9XG4gICAgICAgIGNvbXB1dGVSZXMoKTtcbiAgICAgICAgLy8gaWYgcmFuZ2UgaXMgY29tcGxldGVseSBlbnZlbG9wZWQgYnkgaGlkZGVuIGRheXMsIGdvIHBhc3QgdGhlIGhpZGRlbiBkYXlzXG4gICAgICAgIGlmICghdGhpcy50cmltSGlkZGVuRGF5cyhyZXMpKSB7XG4gICAgICAgICAgICBkYXRlID0gdGhpcy5za2lwSGlkZGVuRGF5cyhkYXRlLCBkaXJlY3Rpb24pO1xuICAgICAgICAgICAgY29tcHV0ZVJlcygpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfTtcbiAgICAvLyBCdWlsZHMgdGhlIFwiY3VycmVudFwiIHJhbmdlIHdoZW4gYSBkYXlDb3VudCBpcyBzcGVjaWZpZWQuXG4gICAgRGF0ZVByb2ZpbGVHZW5lcmF0b3IucHJvdG90eXBlLmJ1aWxkUmFuZ2VGcm9tRGF5Q291bnQgPSBmdW5jdGlvbiAoZGF0ZSwgZGlyZWN0aW9uLCBkYXlDb3VudCkge1xuICAgICAgICB2YXIgZGF0ZUVudiA9IHRoaXMuZGF0ZUVudjtcbiAgICAgICAgdmFyIGN1c3RvbUFsaWdubWVudCA9IHRoaXMub3B0aW9ucy5kYXRlQWxpZ25tZW50O1xuICAgICAgICB2YXIgcnVubmluZ0NvdW50ID0gMDtcbiAgICAgICAgdmFyIHN0YXJ0ID0gZGF0ZTtcbiAgICAgICAgdmFyIGVuZDtcbiAgICAgICAgaWYgKGN1c3RvbUFsaWdubWVudCkge1xuICAgICAgICAgICAgc3RhcnQgPSBkYXRlRW52LnN0YXJ0T2Yoc3RhcnQsIGN1c3RvbUFsaWdubWVudCk7XG4gICAgICAgIH1cbiAgICAgICAgc3RhcnQgPSBzdGFydE9mRGF5KHN0YXJ0KTtcbiAgICAgICAgc3RhcnQgPSB0aGlzLnNraXBIaWRkZW5EYXlzKHN0YXJ0LCBkaXJlY3Rpb24pO1xuICAgICAgICBlbmQgPSBzdGFydDtcbiAgICAgICAgZG8ge1xuICAgICAgICAgICAgZW5kID0gYWRkRGF5cyhlbmQsIDEpO1xuICAgICAgICAgICAgaWYgKCF0aGlzLmlzSGlkZGVuRGF5KGVuZCkpIHtcbiAgICAgICAgICAgICAgICBydW5uaW5nQ291bnQrKztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSB3aGlsZSAocnVubmluZ0NvdW50IDwgZGF5Q291bnQpO1xuICAgICAgICByZXR1cm4geyBzdGFydDogc3RhcnQsIGVuZDogZW5kIH07XG4gICAgfTtcbiAgICAvLyBCdWlsZHMgYSBub3JtYWxpemVkIHJhbmdlIG9iamVjdCBmb3IgdGhlIFwidmlzaWJsZVwiIHJhbmdlLFxuICAgIC8vIHdoaWNoIGlzIGEgd2F5IHRvIGRlZmluZSB0aGUgY3VycmVudFJhbmdlIGFuZCBhY3RpdmVSYW5nZSBhdCB0aGUgc2FtZSB0aW1lLlxuICAgIERhdGVQcm9maWxlR2VuZXJhdG9yLnByb3RvdHlwZS5idWlsZEN1c3RvbVZpc2libGVSYW5nZSA9IGZ1bmN0aW9uIChkYXRlKSB7XG4gICAgICAgIHZhciBkYXRlRW52ID0gdGhpcy5kYXRlRW52O1xuICAgICAgICB2YXIgdmlzaWJsZVJhbmdlID0gdGhpcy5nZXRSYW5nZU9wdGlvbigndmlzaWJsZVJhbmdlJywgZGF0ZUVudi50b0RhdGUoZGF0ZSkpO1xuICAgICAgICBpZiAodmlzaWJsZVJhbmdlICYmICh2aXNpYmxlUmFuZ2Uuc3RhcnQgPT0gbnVsbCB8fCB2aXNpYmxlUmFuZ2UuZW5kID09IG51bGwpKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdmlzaWJsZVJhbmdlO1xuICAgIH07XG4gICAgLy8gQ29tcHV0ZXMgdGhlIHJhbmdlIHRoYXQgd2lsbCByZXByZXNlbnQgdGhlIGVsZW1lbnQvY2VsbHMgZm9yICpyZW5kZXJpbmcqLFxuICAgIC8vIGJ1dCB3aGljaCBtYXkgaGF2ZSB2b2lkZWQgZGF5cy90aW1lcy5cbiAgICAvLyBub3QgcmVzcG9uc2libGUgZm9yIHRyaW1taW5nIGhpZGRlbiBkYXlzLlxuICAgIERhdGVQcm9maWxlR2VuZXJhdG9yLnByb3RvdHlwZS5idWlsZFJlbmRlclJhbmdlID0gZnVuY3Rpb24gKGN1cnJlbnRSYW5nZSwgY3VycmVudFJhbmdlVW5pdCwgaXNSYW5nZUFsbERheSkge1xuICAgICAgICByZXR1cm4gY3VycmVudFJhbmdlO1xuICAgIH07XG4gICAgLy8gQ29tcHV0ZSB0aGUgZHVyYXRpb24gdmFsdWUgdGhhdCBzaG91bGQgYmUgYWRkZWQvc3Vic3RyYWN0ZWQgdG8gdGhlIGN1cnJlbnQgZGF0ZVxuICAgIC8vIHdoZW4gYSBwcmV2L25leHQgb3BlcmF0aW9uIGhhcHBlbnMuXG4gICAgRGF0ZVByb2ZpbGVHZW5lcmF0b3IucHJvdG90eXBlLmJ1aWxkRGF0ZUluY3JlbWVudCA9IGZ1bmN0aW9uIChmYWxsYmFjaykge1xuICAgICAgICB2YXIgZGF0ZUluY3JlbWVudElucHV0ID0gdGhpcy5vcHRpb25zLmRhdGVJbmNyZW1lbnQ7XG4gICAgICAgIHZhciBjdXN0b21BbGlnbm1lbnQ7XG4gICAgICAgIGlmIChkYXRlSW5jcmVtZW50SW5wdXQpIHtcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVEdXJhdGlvbihkYXRlSW5jcmVtZW50SW5wdXQpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKChjdXN0b21BbGlnbm1lbnQgPSB0aGlzLm9wdGlvbnMuZGF0ZUFsaWdubWVudCkpIHtcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVEdXJhdGlvbigxLCBjdXN0b21BbGlnbm1lbnQpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGZhbGxiYWNrKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsbGJhY2s7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gY3JlYXRlRHVyYXRpb24oeyBkYXlzOiAxIH0pO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvLyBBcmd1bWVudHMgYWZ0ZXIgbmFtZSB3aWxsIGJlIGZvcndhcmRlZCB0byBhIGh5cG90aGV0aWNhbCBmdW5jdGlvbiB2YWx1ZVxuICAgIC8vIFdBUk5JTkc6IHBhc3NlZC1pbiBhcmd1bWVudHMgd2lsbCBiZSBnaXZlbiB0byBnZW5lcmF0b3IgZnVuY3Rpb25zIGFzLWlzIGFuZCBjYW4gY2F1c2Ugc2lkZS1lZmZlY3RzLlxuICAgIC8vIEFsd2F5cyBjbG9uZSB5b3VyIG9iamVjdHMgaWYgeW91IGZlYXIgbXV0YXRpb24uXG4gICAgRGF0ZVByb2ZpbGVHZW5lcmF0b3IucHJvdG90eXBlLmdldFJhbmdlT3B0aW9uID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgdmFyIG90aGVyQXJncyA9IFtdO1xuICAgICAgICBmb3IgKHZhciBfaSA9IDE7IF9pIDwgYXJndW1lbnRzLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgb3RoZXJBcmdzW19pIC0gMV0gPSBhcmd1bWVudHNbX2ldO1xuICAgICAgICB9XG4gICAgICAgIHZhciB2YWwgPSB0aGlzLm9wdGlvbnNbbmFtZV07XG4gICAgICAgIGlmICh0eXBlb2YgdmFsID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICB2YWwgPSB2YWwuYXBwbHkobnVsbCwgb3RoZXJBcmdzKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodmFsKSB7XG4gICAgICAgICAgICB2YWwgPSBwYXJzZVJhbmdlKHZhbCwgdGhpcy5kYXRlRW52KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodmFsKSB7XG4gICAgICAgICAgICB2YWwgPSBjb21wdXRlVmlzaWJsZURheVJhbmdlKHZhbCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHZhbDtcbiAgICB9O1xuICAgIC8qIEhpZGRlbiBEYXlzXG4gICAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbiAgICAvLyBJbml0aWFsaXplcyBpbnRlcm5hbCB2YXJpYWJsZXMgcmVsYXRlZCB0byBjYWxjdWxhdGluZyBoaWRkZW4gZGF5cy1vZi13ZWVrXG4gICAgRGF0ZVByb2ZpbGVHZW5lcmF0b3IucHJvdG90eXBlLmluaXRIaWRkZW5EYXlzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgaGlkZGVuRGF5cyA9IHRoaXMub3B0aW9ucy5oaWRkZW5EYXlzIHx8IFtdOyAvLyBhcnJheSBvZiBkYXktb2Ytd2VlayBpbmRpY2VzIHRoYXQgYXJlIGhpZGRlblxuICAgICAgICB2YXIgaXNIaWRkZW5EYXlIYXNoID0gW107IC8vIGlzIHRoZSBkYXktb2Ytd2VlayBoaWRkZW4/IChoYXNoIHdpdGggZGF5LW9mLXdlZWstaW5kZXggLT4gYm9vbClcbiAgICAgICAgdmFyIGRheUNudCA9IDA7XG4gICAgICAgIHZhciBpO1xuICAgICAgICBpZiAodGhpcy5vcHRpb25zLndlZWtlbmRzID09PSBmYWxzZSkge1xuICAgICAgICAgICAgaGlkZGVuRGF5cy5wdXNoKDAsIDYpOyAvLyAwPXN1bmRheSwgNj1zYXR1cmRheVxuICAgICAgICB9XG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCA3OyBpKyspIHtcbiAgICAgICAgICAgIGlmICghKGlzSGlkZGVuRGF5SGFzaFtpXSA9IGhpZGRlbkRheXMuaW5kZXhPZihpKSAhPT0gLTEpKSB7XG4gICAgICAgICAgICAgICAgZGF5Q250Kys7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFkYXlDbnQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBoaWRkZW5EYXlzJyk7IC8vIGFsbCBkYXlzIHdlcmUgaGlkZGVuPyBiYWQuXG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5pc0hpZGRlbkRheUhhc2ggPSBpc0hpZGRlbkRheUhhc2g7XG4gICAgfTtcbiAgICAvLyBSZW1vdmUgZGF5cyBmcm9tIHRoZSBiZWdpbm5pbmcgYW5kIGVuZCBvZiB0aGUgcmFuZ2UgdGhhdCBhcmUgY29tcHV0ZWQgYXMgaGlkZGVuLlxuICAgIC8vIElmIHRoZSB3aG9sZSByYW5nZSBpcyB0cmltbWVkIG9mZiwgcmV0dXJucyBudWxsXG4gICAgRGF0ZVByb2ZpbGVHZW5lcmF0b3IucHJvdG90eXBlLnRyaW1IaWRkZW5EYXlzID0gZnVuY3Rpb24gKHJhbmdlKSB7XG4gICAgICAgIHZhciBzdGFydCA9IHJhbmdlLnN0YXJ0O1xuICAgICAgICB2YXIgZW5kID0gcmFuZ2UuZW5kO1xuICAgICAgICBpZiAoc3RhcnQpIHtcbiAgICAgICAgICAgIHN0YXJ0ID0gdGhpcy5za2lwSGlkZGVuRGF5cyhzdGFydCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGVuZCkge1xuICAgICAgICAgICAgZW5kID0gdGhpcy5za2lwSGlkZGVuRGF5cyhlbmQsIC0xLCB0cnVlKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoc3RhcnQgPT0gbnVsbCB8fCBlbmQgPT0gbnVsbCB8fCBzdGFydCA8IGVuZCkge1xuICAgICAgICAgICAgcmV0dXJuIHsgc3RhcnQ6IHN0YXJ0LCBlbmQ6IGVuZCB9O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH07XG4gICAgLy8gSXMgdGhlIGN1cnJlbnQgZGF5IGhpZGRlbj9cbiAgICAvLyBgZGF5YCBpcyBhIGRheS1vZi13ZWVrIGluZGV4ICgwLTYpLCBvciBhIERhdGUgKHVzZWQgZm9yIFVUQylcbiAgICBEYXRlUHJvZmlsZUdlbmVyYXRvci5wcm90b3R5cGUuaXNIaWRkZW5EYXkgPSBmdW5jdGlvbiAoZGF5KSB7XG4gICAgICAgIGlmIChkYXkgaW5zdGFuY2VvZiBEYXRlKSB7XG4gICAgICAgICAgICBkYXkgPSBkYXkuZ2V0VVRDRGF5KCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuaXNIaWRkZW5EYXlIYXNoW2RheV07XG4gICAgfTtcbiAgICAvLyBJbmNyZW1lbnRpbmcgdGhlIGN1cnJlbnQgZGF5IHVudGlsIGl0IGlzIG5vIGxvbmdlciBhIGhpZGRlbiBkYXksIHJldHVybmluZyBhIGNvcHkuXG4gICAgLy8gRE9FUyBOT1QgQ09OU0lERVIgdmFsaWRSYW5nZSFcbiAgICAvLyBJZiB0aGUgaW5pdGlhbCB2YWx1ZSBvZiBgZGF0ZWAgaXMgbm90IGEgaGlkZGVuIGRheSwgZG9uJ3QgZG8gYW55dGhpbmcuXG4gICAgLy8gUGFzcyBgaXNFeGNsdXNpdmVgIGFzIGB0cnVlYCBpZiB5b3UgYXJlIGRlYWxpbmcgd2l0aCBhbiBlbmQgZGF0ZS5cbiAgICAvLyBgaW5jYCBkZWZhdWx0cyB0byBgMWAgKGluY3JlbWVudCBvbmUgZGF5IGZvcndhcmQgZWFjaCB0aW1lKVxuICAgIERhdGVQcm9maWxlR2VuZXJhdG9yLnByb3RvdHlwZS5za2lwSGlkZGVuRGF5cyA9IGZ1bmN0aW9uIChkYXRlLCBpbmMsIGlzRXhjbHVzaXZlKSB7XG4gICAgICAgIGlmIChpbmMgPT09IHZvaWQgMCkgeyBpbmMgPSAxOyB9XG4gICAgICAgIGlmIChpc0V4Y2x1c2l2ZSA9PT0gdm9pZCAwKSB7IGlzRXhjbHVzaXZlID0gZmFsc2U7IH1cbiAgICAgICAgd2hpbGUgKHRoaXMuaXNIaWRkZW5EYXlIYXNoWyhkYXRlLmdldFVUQ0RheSgpICsgKGlzRXhjbHVzaXZlID8gaW5jIDogMCkgKyA3KSAlIDddKSB7XG4gICAgICAgICAgICBkYXRlID0gYWRkRGF5cyhkYXRlLCBpbmMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBkYXRlO1xuICAgIH07XG4gICAgcmV0dXJuIERhdGVQcm9maWxlR2VuZXJhdG9yO1xufSgpKTtcbi8vIFRPRE86IGZpbmQgYSB3YXkgdG8gYXZvaWQgY29tcGFyaW5nIERhdGVQcm9maWxlcy4gaXQncyB0ZWRpb3VzXG5mdW5jdGlvbiBpc0RhdGVQcm9maWxlc0VxdWFsKHAwLCBwMSkge1xuICAgIHJldHVybiByYW5nZXNFcXVhbChwMC52YWxpZFJhbmdlLCBwMS52YWxpZFJhbmdlKSAmJlxuICAgICAgICByYW5nZXNFcXVhbChwMC5hY3RpdmVSYW5nZSwgcDEuYWN0aXZlUmFuZ2UpICYmXG4gICAgICAgIHJhbmdlc0VxdWFsKHAwLnJlbmRlclJhbmdlLCBwMS5yZW5kZXJSYW5nZSkgJiZcbiAgICAgICAgZHVyYXRpb25zRXF1YWwocDAubWluVGltZSwgcDEubWluVGltZSkgJiZcbiAgICAgICAgZHVyYXRpb25zRXF1YWwocDAubWF4VGltZSwgcDEubWF4VGltZSk7XG4gICAgLypcbiAgICBUT0RPOiBjb21wYXJlIG1vcmU/XG4gICAgICBjdXJyZW50UmFuZ2U6IERhdGVSYW5nZVxuICAgICAgY3VycmVudFJhbmdlVW5pdDogc3RyaW5nXG4gICAgICBpc1JhbmdlQWxsRGF5OiBib29sZWFuXG4gICAgICBpc1ZhbGlkOiBib29sZWFuXG4gICAgICBkYXRlSW5jcmVtZW50OiBEdXJhdGlvblxuICAgICovXG59XG5cbmZ1bmN0aW9uIHJlZHVjZSAoc3RhdGUsIGFjdGlvbiwgY2FsZW5kYXIpIHtcbiAgICB2YXIgdmlld1R5cGUgPSByZWR1Y2VWaWV3VHlwZShzdGF0ZS52aWV3VHlwZSwgYWN0aW9uKTtcbiAgICB2YXIgZGF0ZVByb2ZpbGUgPSByZWR1Y2VEYXRlUHJvZmlsZShzdGF0ZS5kYXRlUHJvZmlsZSwgYWN0aW9uLCBzdGF0ZS5jdXJyZW50RGF0ZSwgdmlld1R5cGUsIGNhbGVuZGFyKTtcbiAgICB2YXIgZXZlbnRTb3VyY2VzID0gcmVkdWNlRXZlbnRTb3VyY2VzKHN0YXRlLmV2ZW50U291cmNlcywgYWN0aW9uLCBkYXRlUHJvZmlsZSwgY2FsZW5kYXIpO1xuICAgIHZhciBuZXh0U3RhdGUgPSBfX2Fzc2lnbih7fSwgc3RhdGUsIHsgdmlld1R5cGU6IHZpZXdUeXBlLFxuICAgICAgICBkYXRlUHJvZmlsZTogZGF0ZVByb2ZpbGUsIGN1cnJlbnREYXRlOiByZWR1Y2VDdXJyZW50RGF0ZShzdGF0ZS5jdXJyZW50RGF0ZSwgYWN0aW9uLCBkYXRlUHJvZmlsZSksIGV2ZW50U291cmNlczogZXZlbnRTb3VyY2VzLCBldmVudFN0b3JlOiByZWR1Y2VFdmVudFN0b3JlKHN0YXRlLmV2ZW50U3RvcmUsIGFjdGlvbiwgZXZlbnRTb3VyY2VzLCBkYXRlUHJvZmlsZSwgY2FsZW5kYXIpLCBkYXRlU2VsZWN0aW9uOiByZWR1Y2VEYXRlU2VsZWN0aW9uKHN0YXRlLmRhdGVTZWxlY3Rpb24sIGFjdGlvbiwgY2FsZW5kYXIpLCBldmVudFNlbGVjdGlvbjogcmVkdWNlU2VsZWN0ZWRFdmVudChzdGF0ZS5ldmVudFNlbGVjdGlvbiwgYWN0aW9uKSwgZXZlbnREcmFnOiByZWR1Y2VFdmVudERyYWcoc3RhdGUuZXZlbnREcmFnLCBhY3Rpb24sIGV2ZW50U291cmNlcywgY2FsZW5kYXIpLCBldmVudFJlc2l6ZTogcmVkdWNlRXZlbnRSZXNpemUoc3RhdGUuZXZlbnRSZXNpemUsIGFjdGlvbiwgZXZlbnRTb3VyY2VzLCBjYWxlbmRhciksIGV2ZW50U291cmNlTG9hZGluZ0xldmVsOiBjb21wdXRlTG9hZGluZ0xldmVsKGV2ZW50U291cmNlcyksIGxvYWRpbmdMZXZlbDogY29tcHV0ZUxvYWRpbmdMZXZlbChldmVudFNvdXJjZXMpIH0pO1xuICAgIGZvciAodmFyIF9pID0gMCwgX2EgPSBjYWxlbmRhci5wbHVnaW5TeXN0ZW0uaG9va3MucmVkdWNlcnM7IF9pIDwgX2EubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgIHZhciByZWR1Y2VyRnVuYyA9IF9hW19pXTtcbiAgICAgICAgbmV4dFN0YXRlID0gcmVkdWNlckZ1bmMobmV4dFN0YXRlLCBhY3Rpb24sIGNhbGVuZGFyKTtcbiAgICB9XG4gICAgLy8gY29uc29sZS5sb2coYWN0aW9uLnR5cGUsIG5leHRTdGF0ZSlcbiAgICByZXR1cm4gbmV4dFN0YXRlO1xufVxuZnVuY3Rpb24gcmVkdWNlVmlld1R5cGUoY3VycmVudFZpZXdUeXBlLCBhY3Rpb24pIHtcbiAgICBzd2l0Y2ggKGFjdGlvbi50eXBlKSB7XG4gICAgICAgIGNhc2UgJ1NFVF9WSUVXX1RZUEUnOlxuICAgICAgICAgICAgcmV0dXJuIGFjdGlvbi52aWV3VHlwZTtcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIHJldHVybiBjdXJyZW50Vmlld1R5cGU7XG4gICAgfVxufVxuZnVuY3Rpb24gcmVkdWNlRGF0ZVByb2ZpbGUoY3VycmVudERhdGVQcm9maWxlLCBhY3Rpb24sIGN1cnJlbnREYXRlLCB2aWV3VHlwZSwgY2FsZW5kYXIpIHtcbiAgICB2YXIgbmV3RGF0ZVByb2ZpbGU7XG4gICAgc3dpdGNoIChhY3Rpb24udHlwZSkge1xuICAgICAgICBjYXNlICdQUkVWJzpcbiAgICAgICAgICAgIG5ld0RhdGVQcm9maWxlID0gY2FsZW5kYXIuZGF0ZVByb2ZpbGVHZW5lcmF0b3JzW3ZpZXdUeXBlXS5idWlsZFByZXYoY3VycmVudERhdGVQcm9maWxlLCBjdXJyZW50RGF0ZSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnTkVYVCc6XG4gICAgICAgICAgICBuZXdEYXRlUHJvZmlsZSA9IGNhbGVuZGFyLmRhdGVQcm9maWxlR2VuZXJhdG9yc1t2aWV3VHlwZV0uYnVpbGROZXh0KGN1cnJlbnREYXRlUHJvZmlsZSwgY3VycmVudERhdGUpO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ1NFVF9EQVRFJzpcbiAgICAgICAgICAgIGlmICghY3VycmVudERhdGVQcm9maWxlLmFjdGl2ZVJhbmdlIHx8XG4gICAgICAgICAgICAgICAgIXJhbmdlQ29udGFpbnNNYXJrZXIoY3VycmVudERhdGVQcm9maWxlLmN1cnJlbnRSYW5nZSwgYWN0aW9uLmRhdGVNYXJrZXIpKSB7XG4gICAgICAgICAgICAgICAgbmV3RGF0ZVByb2ZpbGUgPSBjYWxlbmRhci5kYXRlUHJvZmlsZUdlbmVyYXRvcnNbdmlld1R5cGVdLmJ1aWxkKGFjdGlvbi5kYXRlTWFya2VyLCB1bmRlZmluZWQsIHRydWUgLy8gZm9yY2VUb1ZhbGlkXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICdTRVRfVklFV19UWVBFJzpcbiAgICAgICAgICAgIHZhciBnZW5lcmF0b3IgPSBjYWxlbmRhci5kYXRlUHJvZmlsZUdlbmVyYXRvcnNbdmlld1R5cGVdO1xuICAgICAgICAgICAgaWYgKCFnZW5lcmF0b3IpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3Iodmlld1R5cGUgP1xuICAgICAgICAgICAgICAgICAgICAnVGhlIEZ1bGxDYWxlbmRhciB2aWV3IFwiJyArIHZpZXdUeXBlICsgJ1wiIGRvZXMgbm90IGV4aXN0LiBNYWtlIHN1cmUgeW91ciBwbHVnaW5zIGFyZSBsb2FkZWQgY29ycmVjdGx5LicgOlxuICAgICAgICAgICAgICAgICAgICAnTm8gYXZhaWxhYmxlIEZ1bGxDYWxlbmRhciB2aWV3IHBsdWdpbnMuJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBuZXdEYXRlUHJvZmlsZSA9IGdlbmVyYXRvci5idWlsZChhY3Rpb24uZGF0ZU1hcmtlciB8fCBjdXJyZW50RGF0ZSwgdW5kZWZpbmVkLCB0cnVlIC8vIGZvcmNlVG9WYWxpZFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgIH1cbiAgICBpZiAobmV3RGF0ZVByb2ZpbGUgJiZcbiAgICAgICAgbmV3RGF0ZVByb2ZpbGUuaXNWYWxpZCAmJlxuICAgICAgICAhKGN1cnJlbnREYXRlUHJvZmlsZSAmJiBpc0RhdGVQcm9maWxlc0VxdWFsKGN1cnJlbnREYXRlUHJvZmlsZSwgbmV3RGF0ZVByb2ZpbGUpKSkge1xuICAgICAgICByZXR1cm4gbmV3RGF0ZVByb2ZpbGU7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICByZXR1cm4gY3VycmVudERhdGVQcm9maWxlO1xuICAgIH1cbn1cbmZ1bmN0aW9uIHJlZHVjZUN1cnJlbnREYXRlKGN1cnJlbnREYXRlLCBhY3Rpb24sIGRhdGVQcm9maWxlKSB7XG4gICAgc3dpdGNoIChhY3Rpb24udHlwZSkge1xuICAgICAgICBjYXNlICdQUkVWJzpcbiAgICAgICAgY2FzZSAnTkVYVCc6XG4gICAgICAgICAgICBpZiAoIXJhbmdlQ29udGFpbnNNYXJrZXIoZGF0ZVByb2ZpbGUuY3VycmVudFJhbmdlLCBjdXJyZW50RGF0ZSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZGF0ZVByb2ZpbGUuY3VycmVudFJhbmdlLnN0YXJ0O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGN1cnJlbnREYXRlO1xuICAgICAgICAgICAgfVxuICAgICAgICBjYXNlICdTRVRfREFURSc6XG4gICAgICAgIGNhc2UgJ1NFVF9WSUVXX1RZUEUnOlxuICAgICAgICAgICAgdmFyIG5ld0RhdGUgPSBhY3Rpb24uZGF0ZU1hcmtlciB8fCBjdXJyZW50RGF0ZTtcbiAgICAgICAgICAgIGlmIChkYXRlUHJvZmlsZS5hY3RpdmVSYW5nZSAmJiAhcmFuZ2VDb250YWluc01hcmtlcihkYXRlUHJvZmlsZS5hY3RpdmVSYW5nZSwgbmV3RGF0ZSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZGF0ZVByb2ZpbGUuY3VycmVudFJhbmdlLnN0YXJ0O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ld0RhdGU7XG4gICAgICAgICAgICB9XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICByZXR1cm4gY3VycmVudERhdGU7XG4gICAgfVxufVxuZnVuY3Rpb24gcmVkdWNlRGF0ZVNlbGVjdGlvbihjdXJyZW50U2VsZWN0aW9uLCBhY3Rpb24sIGNhbGVuZGFyKSB7XG4gICAgc3dpdGNoIChhY3Rpb24udHlwZSkge1xuICAgICAgICBjYXNlICdTRUxFQ1RfREFURVMnOlxuICAgICAgICAgICAgcmV0dXJuIGFjdGlvbi5zZWxlY3Rpb247XG4gICAgICAgIGNhc2UgJ1VOU0VMRUNUX0RBVEVTJzpcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgcmV0dXJuIGN1cnJlbnRTZWxlY3Rpb247XG4gICAgfVxufVxuZnVuY3Rpb24gcmVkdWNlU2VsZWN0ZWRFdmVudChjdXJyZW50SW5zdGFuY2VJZCwgYWN0aW9uKSB7XG4gICAgc3dpdGNoIChhY3Rpb24udHlwZSkge1xuICAgICAgICBjYXNlICdTRUxFQ1RfRVZFTlQnOlxuICAgICAgICAgICAgcmV0dXJuIGFjdGlvbi5ldmVudEluc3RhbmNlSWQ7XG4gICAgICAgIGNhc2UgJ1VOU0VMRUNUX0VWRU5UJzpcbiAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIHJldHVybiBjdXJyZW50SW5zdGFuY2VJZDtcbiAgICB9XG59XG5mdW5jdGlvbiByZWR1Y2VFdmVudERyYWcoY3VycmVudERyYWcsIGFjdGlvbiwgc291cmNlcywgY2FsZW5kYXIpIHtcbiAgICBzd2l0Y2ggKGFjdGlvbi50eXBlKSB7XG4gICAgICAgIGNhc2UgJ1NFVF9FVkVOVF9EUkFHJzpcbiAgICAgICAgICAgIHZhciBuZXdEcmFnID0gYWN0aW9uLnN0YXRlO1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBhZmZlY3RlZEV2ZW50czogbmV3RHJhZy5hZmZlY3RlZEV2ZW50cyxcbiAgICAgICAgICAgICAgICBtdXRhdGVkRXZlbnRzOiBuZXdEcmFnLm11dGF0ZWRFdmVudHMsXG4gICAgICAgICAgICAgICAgaXNFdmVudDogbmV3RHJhZy5pc0V2ZW50LFxuICAgICAgICAgICAgICAgIG9yaWdTZWc6IG5ld0RyYWcub3JpZ1NlZ1xuICAgICAgICAgICAgfTtcbiAgICAgICAgY2FzZSAnVU5TRVRfRVZFTlRfRFJBRyc6XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIHJldHVybiBjdXJyZW50RHJhZztcbiAgICB9XG59XG5mdW5jdGlvbiByZWR1Y2VFdmVudFJlc2l6ZShjdXJyZW50UmVzaXplLCBhY3Rpb24sIHNvdXJjZXMsIGNhbGVuZGFyKSB7XG4gICAgc3dpdGNoIChhY3Rpb24udHlwZSkge1xuICAgICAgICBjYXNlICdTRVRfRVZFTlRfUkVTSVpFJzpcbiAgICAgICAgICAgIHZhciBuZXdSZXNpemUgPSBhY3Rpb24uc3RhdGU7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGFmZmVjdGVkRXZlbnRzOiBuZXdSZXNpemUuYWZmZWN0ZWRFdmVudHMsXG4gICAgICAgICAgICAgICAgbXV0YXRlZEV2ZW50czogbmV3UmVzaXplLm11dGF0ZWRFdmVudHMsXG4gICAgICAgICAgICAgICAgaXNFdmVudDogbmV3UmVzaXplLmlzRXZlbnQsXG4gICAgICAgICAgICAgICAgb3JpZ1NlZzogbmV3UmVzaXplLm9yaWdTZWdcbiAgICAgICAgICAgIH07XG4gICAgICAgIGNhc2UgJ1VOU0VUX0VWRU5UX1JFU0laRSc6XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIHJldHVybiBjdXJyZW50UmVzaXplO1xuICAgIH1cbn1cbmZ1bmN0aW9uIGNvbXB1dGVMb2FkaW5nTGV2ZWwoZXZlbnRTb3VyY2VzKSB7XG4gICAgdmFyIGNudCA9IDA7XG4gICAgZm9yICh2YXIgc291cmNlSWQgaW4gZXZlbnRTb3VyY2VzKSB7XG4gICAgICAgIGlmIChldmVudFNvdXJjZXNbc291cmNlSWRdLmlzRmV0Y2hpbmcpIHtcbiAgICAgICAgICAgIGNudCsrO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBjbnQ7XG59XG5cbnZhciBTVEFOREFSRF9QUk9QUyA9IHtcbiAgICBzdGFydDogbnVsbCxcbiAgICBlbmQ6IG51bGwsXG4gICAgYWxsRGF5OiBCb29sZWFuXG59O1xuZnVuY3Rpb24gcGFyc2VEYXRlU3BhbihyYXcsIGRhdGVFbnYsIGRlZmF1bHREdXJhdGlvbikge1xuICAgIHZhciBzcGFuID0gcGFyc2VPcGVuRGF0ZVNwYW4ocmF3LCBkYXRlRW52KTtcbiAgICB2YXIgcmFuZ2UgPSBzcGFuLnJhbmdlO1xuICAgIGlmICghcmFuZ2Uuc3RhcnQpIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIGlmICghcmFuZ2UuZW5kKSB7XG4gICAgICAgIGlmIChkZWZhdWx0RHVyYXRpb24gPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByYW5nZS5lbmQgPSBkYXRlRW52LmFkZChyYW5nZS5zdGFydCwgZGVmYXVsdER1cmF0aW9uKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gc3Bhbjtcbn1cbi8qXG5UT0RPOiBzb21laG93IGNvbWJpbmUgd2l0aCBwYXJzZVJhbmdlP1xuV2lsbCByZXR1cm4gbnVsbCBpZiB0aGUgc3RhcnQvZW5kIHByb3BzIHdlcmUgcHJlc2VudCBidXQgcGFyc2VkIGludmFsaWRseS5cbiovXG5mdW5jdGlvbiBwYXJzZU9wZW5EYXRlU3BhbihyYXcsIGRhdGVFbnYpIHtcbiAgICB2YXIgbGVmdG92ZXJzID0ge307XG4gICAgdmFyIHN0YW5kYXJkUHJvcHMgPSByZWZpbmVQcm9wcyhyYXcsIFNUQU5EQVJEX1BST1BTLCB7fSwgbGVmdG92ZXJzKTtcbiAgICB2YXIgc3RhcnRNZXRhID0gc3RhbmRhcmRQcm9wcy5zdGFydCA/IGRhdGVFbnYuY3JlYXRlTWFya2VyTWV0YShzdGFuZGFyZFByb3BzLnN0YXJ0KSA6IG51bGw7XG4gICAgdmFyIGVuZE1ldGEgPSBzdGFuZGFyZFByb3BzLmVuZCA/IGRhdGVFbnYuY3JlYXRlTWFya2VyTWV0YShzdGFuZGFyZFByb3BzLmVuZCkgOiBudWxsO1xuICAgIHZhciBhbGxEYXkgPSBzdGFuZGFyZFByb3BzLmFsbERheTtcbiAgICBpZiAoYWxsRGF5ID09IG51bGwpIHtcbiAgICAgICAgYWxsRGF5ID0gKHN0YXJ0TWV0YSAmJiBzdGFydE1ldGEuaXNUaW1lVW5zcGVjaWZpZWQpICYmXG4gICAgICAgICAgICAoIWVuZE1ldGEgfHwgZW5kTWV0YS5pc1RpbWVVbnNwZWNpZmllZCk7XG4gICAgfVxuICAgIC8vIHVzZSB0aGlzIGxlZnRvdmVyIG9iamVjdCBhcyB0aGUgc2VsZWN0aW9uIG9iamVjdFxuICAgIGxlZnRvdmVycy5yYW5nZSA9IHtcbiAgICAgICAgc3RhcnQ6IHN0YXJ0TWV0YSA/IHN0YXJ0TWV0YS5tYXJrZXIgOiBudWxsLFxuICAgICAgICBlbmQ6IGVuZE1ldGEgPyBlbmRNZXRhLm1hcmtlciA6IG51bGxcbiAgICB9O1xuICAgIGxlZnRvdmVycy5hbGxEYXkgPSBhbGxEYXk7XG4gICAgcmV0dXJuIGxlZnRvdmVycztcbn1cbmZ1bmN0aW9uIGlzRGF0ZVNwYW5zRXF1YWwoc3BhbjAsIHNwYW4xKSB7XG4gICAgcmV0dXJuIHJhbmdlc0VxdWFsKHNwYW4wLnJhbmdlLCBzcGFuMS5yYW5nZSkgJiZcbiAgICAgICAgc3BhbjAuYWxsRGF5ID09PSBzcGFuMS5hbGxEYXkgJiZcbiAgICAgICAgaXNTcGFuUHJvcHNFcXVhbChzcGFuMCwgc3BhbjEpO1xufVxuLy8gdGhlIE5PTi1EQVRFLVJFTEFURUQgcHJvcHNcbmZ1bmN0aW9uIGlzU3BhblByb3BzRXF1YWwoc3BhbjAsIHNwYW4xKSB7XG4gICAgZm9yICh2YXIgcHJvcE5hbWUgaW4gc3BhbjEpIHtcbiAgICAgICAgaWYgKHByb3BOYW1lICE9PSAncmFuZ2UnICYmIHByb3BOYW1lICE9PSAnYWxsRGF5Jykge1xuICAgICAgICAgICAgaWYgKHNwYW4wW3Byb3BOYW1lXSAhPT0gc3BhbjFbcHJvcE5hbWVdKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIC8vIGFyZSB0aGVyZSBhbnkgcHJvcHMgdGhhdCBzcGFuMCBoYXMgdGhhdCBzcGFuMSBET0VTTidUIGhhdmU/XG4gICAgLy8gYm90aCBoYXZlIHJhbmdlL2FsbERheSwgc28gbm8gbmVlZCB0byBzcGVjaWFsLWNhc2UuXG4gICAgZm9yICh2YXIgcHJvcE5hbWUgaW4gc3BhbjApIHtcbiAgICAgICAgaWYgKCEocHJvcE5hbWUgaW4gc3BhbjEpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG59XG5mdW5jdGlvbiBidWlsZERhdGVTcGFuQXBpKHNwYW4sIGRhdGVFbnYpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBzdGFydDogZGF0ZUVudi50b0RhdGUoc3Bhbi5yYW5nZS5zdGFydCksXG4gICAgICAgIGVuZDogZGF0ZUVudi50b0RhdGUoc3Bhbi5yYW5nZS5lbmQpLFxuICAgICAgICBzdGFydFN0cjogZGF0ZUVudi5mb3JtYXRJc28oc3Bhbi5yYW5nZS5zdGFydCwgeyBvbWl0VGltZTogc3Bhbi5hbGxEYXkgfSksXG4gICAgICAgIGVuZFN0cjogZGF0ZUVudi5mb3JtYXRJc28oc3Bhbi5yYW5nZS5lbmQsIHsgb21pdFRpbWU6IHNwYW4uYWxsRGF5IH0pLFxuICAgICAgICBhbGxEYXk6IHNwYW4uYWxsRGF5XG4gICAgfTtcbn1cbmZ1bmN0aW9uIGJ1aWxkRGF0ZVBvaW50QXBpKHNwYW4sIGRhdGVFbnYpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBkYXRlOiBkYXRlRW52LnRvRGF0ZShzcGFuLnJhbmdlLnN0YXJ0KSxcbiAgICAgICAgZGF0ZVN0cjogZGF0ZUVudi5mb3JtYXRJc28oc3Bhbi5yYW5nZS5zdGFydCwgeyBvbWl0VGltZTogc3Bhbi5hbGxEYXkgfSksXG4gICAgICAgIGFsbERheTogc3Bhbi5hbGxEYXlcbiAgICB9O1xufVxuZnVuY3Rpb24gZmFicmljYXRlRXZlbnRSYW5nZShkYXRlU3BhbiwgZXZlbnRVaUJhc2VzLCBjYWxlbmRhcikge1xuICAgIHZhciBkZWYgPSBwYXJzZUV2ZW50RGVmKHsgZWRpdGFibGU6IGZhbHNlIH0sICcnLCAvLyBzb3VyY2VJZFxuICAgIGRhdGVTcGFuLmFsbERheSwgdHJ1ZSwgLy8gaGFzRW5kXG4gICAgY2FsZW5kYXIpO1xuICAgIHJldHVybiB7XG4gICAgICAgIGRlZjogZGVmLFxuICAgICAgICB1aTogY29tcGlsZUV2ZW50VWkoZGVmLCBldmVudFVpQmFzZXMpLFxuICAgICAgICBpbnN0YW5jZTogY3JlYXRlRXZlbnRJbnN0YW5jZShkZWYuZGVmSWQsIGRhdGVTcGFuLnJhbmdlKSxcbiAgICAgICAgcmFuZ2U6IGRhdGVTcGFuLnJhbmdlLFxuICAgICAgICBpc1N0YXJ0OiB0cnVlLFxuICAgICAgICBpc0VuZDogdHJ1ZVxuICAgIH07XG59XG5cbmZ1bmN0aW9uIGNvbXBpbGVWaWV3RGVmcyhkZWZhdWx0Q29uZmlncywgb3ZlcnJpZGVDb25maWdzKSB7XG4gICAgdmFyIGhhc2ggPSB7fTtcbiAgICB2YXIgdmlld1R5cGU7XG4gICAgZm9yICh2aWV3VHlwZSBpbiBkZWZhdWx0Q29uZmlncykge1xuICAgICAgICBlbnN1cmVWaWV3RGVmKHZpZXdUeXBlLCBoYXNoLCBkZWZhdWx0Q29uZmlncywgb3ZlcnJpZGVDb25maWdzKTtcbiAgICB9XG4gICAgZm9yICh2aWV3VHlwZSBpbiBvdmVycmlkZUNvbmZpZ3MpIHtcbiAgICAgICAgZW5zdXJlVmlld0RlZih2aWV3VHlwZSwgaGFzaCwgZGVmYXVsdENvbmZpZ3MsIG92ZXJyaWRlQ29uZmlncyk7XG4gICAgfVxuICAgIHJldHVybiBoYXNoO1xufVxuZnVuY3Rpb24gZW5zdXJlVmlld0RlZih2aWV3VHlwZSwgaGFzaCwgZGVmYXVsdENvbmZpZ3MsIG92ZXJyaWRlQ29uZmlncykge1xuICAgIGlmIChoYXNoW3ZpZXdUeXBlXSkge1xuICAgICAgICByZXR1cm4gaGFzaFt2aWV3VHlwZV07XG4gICAgfVxuICAgIHZhciB2aWV3RGVmID0gYnVpbGRWaWV3RGVmKHZpZXdUeXBlLCBoYXNoLCBkZWZhdWx0Q29uZmlncywgb3ZlcnJpZGVDb25maWdzKTtcbiAgICBpZiAodmlld0RlZikge1xuICAgICAgICBoYXNoW3ZpZXdUeXBlXSA9IHZpZXdEZWY7XG4gICAgfVxuICAgIHJldHVybiB2aWV3RGVmO1xufVxuZnVuY3Rpb24gYnVpbGRWaWV3RGVmKHZpZXdUeXBlLCBoYXNoLCBkZWZhdWx0Q29uZmlncywgb3ZlcnJpZGVDb25maWdzKSB7XG4gICAgdmFyIGRlZmF1bHRDb25maWcgPSBkZWZhdWx0Q29uZmlnc1t2aWV3VHlwZV07XG4gICAgdmFyIG92ZXJyaWRlQ29uZmlnID0gb3ZlcnJpZGVDb25maWdzW3ZpZXdUeXBlXTtcbiAgICB2YXIgcXVlcnlQcm9wID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgcmV0dXJuIChkZWZhdWx0Q29uZmlnICYmIGRlZmF1bHRDb25maWdbbmFtZV0gIT09IG51bGwpID8gZGVmYXVsdENvbmZpZ1tuYW1lXSA6XG4gICAgICAgICAgICAoKG92ZXJyaWRlQ29uZmlnICYmIG92ZXJyaWRlQ29uZmlnW25hbWVdICE9PSBudWxsKSA/IG92ZXJyaWRlQ29uZmlnW25hbWVdIDogbnVsbCk7XG4gICAgfTtcbiAgICB2YXIgdGhlQ2xhc3MgPSBxdWVyeVByb3AoJ2NsYXNzJyk7XG4gICAgdmFyIHN1cGVyVHlwZSA9IHF1ZXJ5UHJvcCgnc3VwZXJUeXBlJyk7XG4gICAgaWYgKCFzdXBlclR5cGUgJiYgdGhlQ2xhc3MpIHtcbiAgICAgICAgc3VwZXJUeXBlID1cbiAgICAgICAgICAgIGZpbmRWaWV3TmFtZUJ5U3ViY2xhc3ModGhlQ2xhc3MsIG92ZXJyaWRlQ29uZmlncykgfHxcbiAgICAgICAgICAgICAgICBmaW5kVmlld05hbWVCeVN1YmNsYXNzKHRoZUNsYXNzLCBkZWZhdWx0Q29uZmlncyk7XG4gICAgfVxuICAgIHZhciBzdXBlckRlZiA9IG51bGw7XG4gICAgaWYgKHN1cGVyVHlwZSkge1xuICAgICAgICBpZiAoc3VwZXJUeXBlID09PSB2aWV3VHlwZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5cXCd0IGhhdmUgYSBjdXN0b20gdmlldyB0eXBlIHRoYXQgcmVmZXJlbmNlcyBpdHNlbGYnKTtcbiAgICAgICAgfVxuICAgICAgICBzdXBlckRlZiA9IGVuc3VyZVZpZXdEZWYoc3VwZXJUeXBlLCBoYXNoLCBkZWZhdWx0Q29uZmlncywgb3ZlcnJpZGVDb25maWdzKTtcbiAgICB9XG4gICAgaWYgKCF0aGVDbGFzcyAmJiBzdXBlckRlZikge1xuICAgICAgICB0aGVDbGFzcyA9IHN1cGVyRGVmLmNsYXNzO1xuICAgIH1cbiAgICBpZiAoIXRoZUNsYXNzKSB7XG4gICAgICAgIHJldHVybiBudWxsOyAvLyBkb24ndCB0aHJvdyBhIHdhcm5pbmcsIG1pZ2h0IGJlIHNldHRpbmdzIGZvciBhIHNpbmdsZS11bml0IHZpZXdcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgICAgdHlwZTogdmlld1R5cGUsXG4gICAgICAgIGNsYXNzOiB0aGVDbGFzcyxcbiAgICAgICAgZGVmYXVsdHM6IF9fYXNzaWduKHt9LCAoc3VwZXJEZWYgPyBzdXBlckRlZi5kZWZhdWx0cyA6IHt9KSwgKGRlZmF1bHRDb25maWcgPyBkZWZhdWx0Q29uZmlnLm9wdGlvbnMgOiB7fSkpLFxuICAgICAgICBvdmVycmlkZXM6IF9fYXNzaWduKHt9LCAoc3VwZXJEZWYgPyBzdXBlckRlZi5vdmVycmlkZXMgOiB7fSksIChvdmVycmlkZUNvbmZpZyA/IG92ZXJyaWRlQ29uZmlnLm9wdGlvbnMgOiB7fSkpXG4gICAgfTtcbn1cbmZ1bmN0aW9uIGZpbmRWaWV3TmFtZUJ5U3ViY2xhc3Modmlld1N1YmNsYXNzLCBjb25maWdzKSB7XG4gICAgdmFyIHN1cGVyUHJvdG8gPSBPYmplY3QuZ2V0UHJvdG90eXBlT2Yodmlld1N1YmNsYXNzLnByb3RvdHlwZSk7XG4gICAgZm9yICh2YXIgdmlld1R5cGUgaW4gY29uZmlncykge1xuICAgICAgICB2YXIgcGFyc2VkID0gY29uZmlnc1t2aWV3VHlwZV07XG4gICAgICAgIC8vIG5lZWQgRElSRUNUIHN1YmNsYXNzLCBzbyBpbnN0YW5jZW9mIHdvbid0IGRvIGl0XG4gICAgICAgIGlmIChwYXJzZWQuY2xhc3MgJiYgcGFyc2VkLmNsYXNzLnByb3RvdHlwZSA9PT0gc3VwZXJQcm90bykge1xuICAgICAgICAgICAgcmV0dXJuIHZpZXdUeXBlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiAnJztcbn1cblxuZnVuY3Rpb24gcGFyc2VWaWV3Q29uZmlncyhpbnB1dHMpIHtcbiAgICByZXR1cm4gbWFwSGFzaChpbnB1dHMsIHBhcnNlVmlld0NvbmZpZyk7XG59XG52YXIgVklFV19ERUZfUFJPUFMgPSB7XG4gICAgdHlwZTogU3RyaW5nLFxuICAgIGNsYXNzOiBudWxsXG59O1xuZnVuY3Rpb24gcGFyc2VWaWV3Q29uZmlnKGlucHV0KSB7XG4gICAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBpbnB1dCA9IHsgY2xhc3M6IGlucHV0IH07XG4gICAgfVxuICAgIHZhciBvcHRpb25zID0ge307XG4gICAgdmFyIHByb3BzID0gcmVmaW5lUHJvcHMoaW5wdXQsIFZJRVdfREVGX1BST1BTLCB7fSwgb3B0aW9ucyk7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgc3VwZXJUeXBlOiBwcm9wcy50eXBlLFxuICAgICAgICBjbGFzczogcHJvcHMuY2xhc3MsXG4gICAgICAgIG9wdGlvbnM6IG9wdGlvbnNcbiAgICB9O1xufVxuXG5mdW5jdGlvbiBidWlsZFZpZXdTcGVjcyhkZWZhdWx0SW5wdXRzLCBvcHRpb25zTWFuYWdlcikge1xuICAgIHZhciBkZWZhdWx0Q29uZmlncyA9IHBhcnNlVmlld0NvbmZpZ3MoZGVmYXVsdElucHV0cyk7XG4gICAgdmFyIG92ZXJyaWRlQ29uZmlncyA9IHBhcnNlVmlld0NvbmZpZ3Mob3B0aW9uc01hbmFnZXIub3ZlcnJpZGVzLnZpZXdzKTtcbiAgICB2YXIgdmlld0RlZnMgPSBjb21waWxlVmlld0RlZnMoZGVmYXVsdENvbmZpZ3MsIG92ZXJyaWRlQ29uZmlncyk7XG4gICAgcmV0dXJuIG1hcEhhc2godmlld0RlZnMsIGZ1bmN0aW9uICh2aWV3RGVmKSB7XG4gICAgICAgIHJldHVybiBidWlsZFZpZXdTcGVjKHZpZXdEZWYsIG92ZXJyaWRlQ29uZmlncywgb3B0aW9uc01hbmFnZXIpO1xuICAgIH0pO1xufVxuZnVuY3Rpb24gYnVpbGRWaWV3U3BlYyh2aWV3RGVmLCBvdmVycmlkZUNvbmZpZ3MsIG9wdGlvbnNNYW5hZ2VyKSB7XG4gICAgdmFyIGR1cmF0aW9uSW5wdXQgPSB2aWV3RGVmLm92ZXJyaWRlcy5kdXJhdGlvbiB8fFxuICAgICAgICB2aWV3RGVmLmRlZmF1bHRzLmR1cmF0aW9uIHx8XG4gICAgICAgIG9wdGlvbnNNYW5hZ2VyLmR5bmFtaWNPdmVycmlkZXMuZHVyYXRpb24gfHxcbiAgICAgICAgb3B0aW9uc01hbmFnZXIub3ZlcnJpZGVzLmR1cmF0aW9uO1xuICAgIHZhciBkdXJhdGlvbiA9IG51bGw7XG4gICAgdmFyIGR1cmF0aW9uVW5pdCA9ICcnO1xuICAgIHZhciBzaW5nbGVVbml0ID0gJyc7XG4gICAgdmFyIHNpbmdsZVVuaXRPdmVycmlkZXMgPSB7fTtcbiAgICBpZiAoZHVyYXRpb25JbnB1dCkge1xuICAgICAgICBkdXJhdGlvbiA9IGNyZWF0ZUR1cmF0aW9uKGR1cmF0aW9uSW5wdXQpO1xuICAgICAgICBpZiAoZHVyYXRpb24pIHsgLy8gdmFsaWQ/XG4gICAgICAgICAgICB2YXIgZGVub20gPSBncmVhdGVzdER1cmF0aW9uRGVub21pbmF0b3IoZHVyYXRpb24sICFnZXRXZWVrc0Zyb21JbnB1dChkdXJhdGlvbklucHV0KSk7XG4gICAgICAgICAgICBkdXJhdGlvblVuaXQgPSBkZW5vbS51bml0O1xuICAgICAgICAgICAgaWYgKGRlbm9tLnZhbHVlID09PSAxKSB7XG4gICAgICAgICAgICAgICAgc2luZ2xlVW5pdCA9IGR1cmF0aW9uVW5pdDtcbiAgICAgICAgICAgICAgICBzaW5nbGVVbml0T3ZlcnJpZGVzID0gb3ZlcnJpZGVDb25maWdzW2R1cmF0aW9uVW5pdF0gPyBvdmVycmlkZUNvbmZpZ3NbZHVyYXRpb25Vbml0XS5vcHRpb25zIDoge307XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgdmFyIHF1ZXJ5QnV0dG9uVGV4dCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBidXR0b25UZXh0TWFwID0gb3B0aW9ucy5idXR0b25UZXh0IHx8IHt9O1xuICAgICAgICB2YXIgYnV0dG9uVGV4dEtleSA9IHZpZXdEZWYuZGVmYXVsdHMuYnV0dG9uVGV4dEtleTtcbiAgICAgICAgaWYgKGJ1dHRvblRleHRLZXkgIT0gbnVsbCAmJiBidXR0b25UZXh0TWFwW2J1dHRvblRleHRLZXldICE9IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybiBidXR0b25UZXh0TWFwW2J1dHRvblRleHRLZXldO1xuICAgICAgICB9XG4gICAgICAgIGlmIChidXR0b25UZXh0TWFwW3ZpZXdEZWYudHlwZV0gIT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIGJ1dHRvblRleHRNYXBbdmlld0RlZi50eXBlXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoYnV0dG9uVGV4dE1hcFtzaW5nbGVVbml0XSAhPSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm4gYnV0dG9uVGV4dE1hcFtzaW5nbGVVbml0XTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgcmV0dXJuIHtcbiAgICAgICAgdHlwZTogdmlld0RlZi50eXBlLFxuICAgICAgICBjbGFzczogdmlld0RlZi5jbGFzcyxcbiAgICAgICAgZHVyYXRpb246IGR1cmF0aW9uLFxuICAgICAgICBkdXJhdGlvblVuaXQ6IGR1cmF0aW9uVW5pdCxcbiAgICAgICAgc2luZ2xlVW5pdDogc2luZ2xlVW5pdCxcbiAgICAgICAgb3B0aW9uczogX19hc3NpZ24oe30sIGdsb2JhbERlZmF1bHRzLCB2aWV3RGVmLmRlZmF1bHRzLCBvcHRpb25zTWFuYWdlci5kaXJEZWZhdWx0cywgb3B0aW9uc01hbmFnZXIubG9jYWxlRGVmYXVsdHMsIG9wdGlvbnNNYW5hZ2VyLm92ZXJyaWRlcywgc2luZ2xlVW5pdE92ZXJyaWRlcywgdmlld0RlZi5vdmVycmlkZXMsIG9wdGlvbnNNYW5hZ2VyLmR5bmFtaWNPdmVycmlkZXMpLFxuICAgICAgICBidXR0b25UZXh0T3ZlcnJpZGU6IHF1ZXJ5QnV0dG9uVGV4dChvcHRpb25zTWFuYWdlci5keW5hbWljT3ZlcnJpZGVzKSB8fFxuICAgICAgICAgICAgcXVlcnlCdXR0b25UZXh0KG9wdGlvbnNNYW5hZ2VyLm92ZXJyaWRlcykgfHwgLy8gY29uc3RydWN0b3Itc3BlY2lmaWVkIGJ1dHRvblRleHQgbG9va3VwIGhhc2ggdGFrZXMgcHJlY2VkZW5jZVxuICAgICAgICAgICAgdmlld0RlZi5vdmVycmlkZXMuYnV0dG9uVGV4dCxcbiAgICAgICAgYnV0dG9uVGV4dERlZmF1bHQ6IHF1ZXJ5QnV0dG9uVGV4dChvcHRpb25zTWFuYWdlci5sb2NhbGVEZWZhdWx0cykgfHxcbiAgICAgICAgICAgIHF1ZXJ5QnV0dG9uVGV4dChvcHRpb25zTWFuYWdlci5kaXJEZWZhdWx0cykgfHxcbiAgICAgICAgICAgIHZpZXdEZWYuZGVmYXVsdHMuYnV0dG9uVGV4dCB8fFxuICAgICAgICAgICAgcXVlcnlCdXR0b25UZXh0KGdsb2JhbERlZmF1bHRzKSB8fFxuICAgICAgICAgICAgdmlld0RlZi50eXBlIC8vIGZhbGwgYmFjayB0byBnaXZlbiB2aWV3IG5hbWVcbiAgICB9O1xufVxuXG52YXIgVG9vbGJhciA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uIChfc3VwZXIpIHtcbiAgICBfX2V4dGVuZHMoVG9vbGJhciwgX3N1cGVyKTtcbiAgICBmdW5jdGlvbiBUb29sYmFyKGV4dHJhQ2xhc3NOYW1lKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IF9zdXBlci5jYWxsKHRoaXMpIHx8IHRoaXM7XG4gICAgICAgIF90aGlzLl9yZW5kZXJMYXlvdXQgPSBtZW1vaXplUmVuZGVyaW5nKF90aGlzLnJlbmRlckxheW91dCwgX3RoaXMudW5yZW5kZXJMYXlvdXQpO1xuICAgICAgICBfdGhpcy5fdXBkYXRlVGl0bGUgPSBtZW1vaXplUmVuZGVyaW5nKF90aGlzLnVwZGF0ZVRpdGxlLCBudWxsLCBbX3RoaXMuX3JlbmRlckxheW91dF0pO1xuICAgICAgICBfdGhpcy5fdXBkYXRlQWN0aXZlQnV0dG9uID0gbWVtb2l6ZVJlbmRlcmluZyhfdGhpcy51cGRhdGVBY3RpdmVCdXR0b24sIG51bGwsIFtfdGhpcy5fcmVuZGVyTGF5b3V0XSk7XG4gICAgICAgIF90aGlzLl91cGRhdGVUb2RheSA9IG1lbW9pemVSZW5kZXJpbmcoX3RoaXMudXBkYXRlVG9kYXksIG51bGwsIFtfdGhpcy5fcmVuZGVyTGF5b3V0XSk7XG4gICAgICAgIF90aGlzLl91cGRhdGVQcmV2ID0gbWVtb2l6ZVJlbmRlcmluZyhfdGhpcy51cGRhdGVQcmV2LCBudWxsLCBbX3RoaXMuX3JlbmRlckxheW91dF0pO1xuICAgICAgICBfdGhpcy5fdXBkYXRlTmV4dCA9IG1lbW9pemVSZW5kZXJpbmcoX3RoaXMudXBkYXRlTmV4dCwgbnVsbCwgW190aGlzLl9yZW5kZXJMYXlvdXRdKTtcbiAgICAgICAgX3RoaXMuZWwgPSBjcmVhdGVFbGVtZW50KCdkaXYnLCB7IGNsYXNzTmFtZTogJ2ZjLXRvb2xiYXIgJyArIGV4dHJhQ2xhc3NOYW1lIH0pO1xuICAgICAgICByZXR1cm4gX3RoaXM7XG4gICAgfVxuICAgIFRvb2xiYXIucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIF9zdXBlci5wcm90b3R5cGUuZGVzdHJveS5jYWxsKHRoaXMpO1xuICAgICAgICB0aGlzLl9yZW5kZXJMYXlvdXQudW5yZW5kZXIoKTsgLy8gc2hvdWxkIHVucmVuZGVyIGV2ZXJ5dGhpbmcgZWxzZVxuICAgICAgICByZW1vdmVFbGVtZW50KHRoaXMuZWwpO1xuICAgIH07XG4gICAgVG9vbGJhci5wcm90b3R5cGUucmVuZGVyID0gZnVuY3Rpb24gKHByb3BzKSB7XG4gICAgICAgIHRoaXMuX3JlbmRlckxheW91dChwcm9wcy5sYXlvdXQpO1xuICAgICAgICB0aGlzLl91cGRhdGVUaXRsZShwcm9wcy50aXRsZSk7XG4gICAgICAgIHRoaXMuX3VwZGF0ZUFjdGl2ZUJ1dHRvbihwcm9wcy5hY3RpdmVCdXR0b24pO1xuICAgICAgICB0aGlzLl91cGRhdGVUb2RheShwcm9wcy5pc1RvZGF5RW5hYmxlZCk7XG4gICAgICAgIHRoaXMuX3VwZGF0ZVByZXYocHJvcHMuaXNQcmV2RW5hYmxlZCk7XG4gICAgICAgIHRoaXMuX3VwZGF0ZU5leHQocHJvcHMuaXNOZXh0RW5hYmxlZCk7XG4gICAgfTtcbiAgICBUb29sYmFyLnByb3RvdHlwZS5yZW5kZXJMYXlvdXQgPSBmdW5jdGlvbiAobGF5b3V0KSB7XG4gICAgICAgIHZhciBlbCA9IHRoaXMuZWw7XG4gICAgICAgIHRoaXMudmlld3NXaXRoQnV0dG9ucyA9IFtdO1xuICAgICAgICBhcHBlbmRUb0VsZW1lbnQoZWwsIHRoaXMucmVuZGVyU2VjdGlvbignbGVmdCcsIGxheW91dC5sZWZ0KSk7XG4gICAgICAgIGFwcGVuZFRvRWxlbWVudChlbCwgdGhpcy5yZW5kZXJTZWN0aW9uKCdjZW50ZXInLCBsYXlvdXQuY2VudGVyKSk7XG4gICAgICAgIGFwcGVuZFRvRWxlbWVudChlbCwgdGhpcy5yZW5kZXJTZWN0aW9uKCdyaWdodCcsIGxheW91dC5yaWdodCkpO1xuICAgIH07XG4gICAgVG9vbGJhci5wcm90b3R5cGUudW5yZW5kZXJMYXlvdXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuZWwuaW5uZXJIVE1MID0gJyc7XG4gICAgfTtcbiAgICBUb29sYmFyLnByb3RvdHlwZS5yZW5kZXJTZWN0aW9uID0gZnVuY3Rpb24gKHBvc2l0aW9uLCBidXR0b25TdHIpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIF9hID0gdGhpcy5jb250ZXh0LCB0aGVtZSA9IF9hLnRoZW1lLCBjYWxlbmRhciA9IF9hLmNhbGVuZGFyO1xuICAgICAgICB2YXIgb3B0aW9uc01hbmFnZXIgPSBjYWxlbmRhci5vcHRpb25zTWFuYWdlcjtcbiAgICAgICAgdmFyIHZpZXdTcGVjcyA9IGNhbGVuZGFyLnZpZXdTcGVjcztcbiAgICAgICAgdmFyIHNlY3Rpb25FbCA9IGNyZWF0ZUVsZW1lbnQoJ2RpdicsIHsgY2xhc3NOYW1lOiAnZmMtJyArIHBvc2l0aW9uIH0pO1xuICAgICAgICB2YXIgY2FsZW5kYXJDdXN0b21CdXR0b25zID0gb3B0aW9uc01hbmFnZXIuY29tcHV0ZWQuY3VzdG9tQnV0dG9ucyB8fCB7fTtcbiAgICAgICAgdmFyIGNhbGVuZGFyQnV0dG9uVGV4dE92ZXJyaWRlcyA9IG9wdGlvbnNNYW5hZ2VyLm92ZXJyaWRlcy5idXR0b25UZXh0IHx8IHt9O1xuICAgICAgICB2YXIgY2FsZW5kYXJCdXR0b25UZXh0ID0gb3B0aW9uc01hbmFnZXIuY29tcHV0ZWQuYnV0dG9uVGV4dCB8fCB7fTtcbiAgICAgICAgaWYgKGJ1dHRvblN0cikge1xuICAgICAgICAgICAgYnV0dG9uU3RyLnNwbGl0KCcgJykuZm9yRWFjaChmdW5jdGlvbiAoYnV0dG9uR3JvdXBTdHIsIGkpIHtcbiAgICAgICAgICAgICAgICB2YXIgZ3JvdXBDaGlsZHJlbiA9IFtdO1xuICAgICAgICAgICAgICAgIHZhciBpc09ubHlCdXR0b25zID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB2YXIgZ3JvdXBFbDtcbiAgICAgICAgICAgICAgICBidXR0b25Hcm91cFN0ci5zcGxpdCgnLCcpLmZvckVhY2goZnVuY3Rpb24gKGJ1dHRvbk5hbWUsIGopIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGN1c3RvbUJ1dHRvblByb3BzO1xuICAgICAgICAgICAgICAgICAgICB2YXIgdmlld1NwZWM7XG4gICAgICAgICAgICAgICAgICAgIHZhciBidXR0b25DbGljaztcbiAgICAgICAgICAgICAgICAgICAgdmFyIGJ1dHRvbkljb247IC8vIG9ubHkgb25lIG9mIHRoZXNlIHdpbGwgYmUgc2V0XG4gICAgICAgICAgICAgICAgICAgIHZhciBidXR0b25UZXh0OyAvLyBcIlxuICAgICAgICAgICAgICAgICAgICB2YXIgYnV0dG9uSW5uZXJIdG1sO1xuICAgICAgICAgICAgICAgICAgICB2YXIgYnV0dG9uQ2xhc3NlcztcbiAgICAgICAgICAgICAgICAgICAgdmFyIGJ1dHRvbkVsO1xuICAgICAgICAgICAgICAgICAgICB2YXIgYnV0dG9uQXJpYUF0dHI7XG4gICAgICAgICAgICAgICAgICAgIGlmIChidXR0b25OYW1lID09PSAndGl0bGUnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBncm91cENoaWxkcmVuLnB1c2goaHRtbFRvRWxlbWVudCgnPGgyPiZuYnNwOzwvaDI+JykpOyAvLyB3ZSBhbHdheXMgd2FudCBpdCB0byB0YWtlIHVwIGhlaWdodFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNPbmx5QnV0dG9ucyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKChjdXN0b21CdXR0b25Qcm9wcyA9IGNhbGVuZGFyQ3VzdG9tQnV0dG9uc1tidXR0b25OYW1lXSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b25DbGljayA9IGZ1bmN0aW9uIChldikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3VzdG9tQnV0dG9uUHJvcHMuY2xpY2spIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1c3RvbUJ1dHRvblByb3BzLmNsaWNrLmNhbGwoYnV0dG9uRWwsIGV2KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKGJ1dHRvbkljb24gPSB0aGVtZS5nZXRDdXN0b21CdXR0b25JY29uQ2xhc3MoY3VzdG9tQnV0dG9uUHJvcHMpKSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoYnV0dG9uSWNvbiA9IHRoZW1lLmdldEljb25DbGFzcyhidXR0b25OYW1lKSkgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGJ1dHRvblRleHQgPSBjdXN0b21CdXR0b25Qcm9wcy50ZXh0KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKCh2aWV3U3BlYyA9IHZpZXdTcGVjc1tidXR0b25OYW1lXSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBfdGhpcy52aWV3c1dpdGhCdXR0b25zLnB1c2goYnV0dG9uTmFtZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnV0dG9uQ2xpY2sgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhbGVuZGFyLmNoYW5nZVZpZXcoYnV0dG9uTmFtZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoYnV0dG9uVGV4dCA9IHZpZXdTcGVjLmJ1dHRvblRleHRPdmVycmlkZSkgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGJ1dHRvbkljb24gPSB0aGVtZS5nZXRJY29uQ2xhc3MoYnV0dG9uTmFtZSkpIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChidXR0b25UZXh0ID0gdmlld1NwZWMuYnV0dG9uVGV4dERlZmF1bHQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoY2FsZW5kYXJbYnV0dG9uTmFtZV0pIHsgLy8gYSBjYWxlbmRhciBtZXRob2RcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b25DbGljayA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FsZW5kYXJbYnV0dG9uTmFtZV0oKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChidXR0b25UZXh0ID0gY2FsZW5kYXJCdXR0b25UZXh0T3ZlcnJpZGVzW2J1dHRvbk5hbWVdKSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoYnV0dG9uSWNvbiA9IHRoZW1lLmdldEljb25DbGFzcyhidXR0b25OYW1lKSkgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGJ1dHRvblRleHQgPSBjYWxlbmRhckJ1dHRvblRleHRbYnV0dG9uTmFtZV0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICAgICAgICAgXiBldmVyeXRoaW5nIGVsc2UgaXMgY29uc2lkZXJlZCBkZWZhdWx0XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoYnV0dG9uQ2xpY2spIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b25DbGFzc2VzID0gW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnZmMtJyArIGJ1dHRvbk5hbWUgKyAnLWJ1dHRvbicsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lLmdldENsYXNzKCdidXR0b24nKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGJ1dHRvblRleHQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnV0dG9uSW5uZXJIdG1sID0gaHRtbEVzY2FwZShidXR0b25UZXh0KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnV0dG9uQXJpYUF0dHIgPSAnJztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoYnV0dG9uSWNvbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b25Jbm5lckh0bWwgPSBcIjxzcGFuIGNsYXNzPSdcIiArIGJ1dHRvbkljb24gKyBcIic+PC9zcGFuPlwiO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b25BcmlhQXR0ciA9ICcgYXJpYS1sYWJlbD1cIicgKyBidXR0b25OYW1lICsgJ1wiJztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnV0dG9uRWwgPSBodG1sVG9FbGVtZW50KC8vIHR5cGU9XCJidXR0b25cIiBzbyB0aGF0IGl0IGRvZXNuJ3Qgc3VibWl0IGEgZm9ybVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICc8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cIicgKyBidXR0b25DbGFzc2VzLmpvaW4oJyAnKSArICdcIicgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b25BcmlhQXR0ciArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICc+JyArIGJ1dHRvbklubmVySHRtbCArICc8L2J1dHRvbj4nKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b25FbC5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGJ1dHRvbkNsaWNrKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cENoaWxkcmVuLnB1c2goYnV0dG9uRWwpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgaWYgKGdyb3VwQ2hpbGRyZW4ubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgICAgICBncm91cEVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBidXR0b25Hcm91cENsYXNzTmFtZSA9IHRoZW1lLmdldENsYXNzKCdidXR0b25Hcm91cCcpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoaXNPbmx5QnV0dG9ucyAmJiBidXR0b25Hcm91cENsYXNzTmFtZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBFbC5jbGFzc0xpc3QuYWRkKGJ1dHRvbkdyb3VwQ2xhc3NOYW1lKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBhcHBlbmRUb0VsZW1lbnQoZ3JvdXBFbCwgZ3JvdXBDaGlsZHJlbik7XG4gICAgICAgICAgICAgICAgICAgIHNlY3Rpb25FbC5hcHBlbmRDaGlsZChncm91cEVsKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGFwcGVuZFRvRWxlbWVudChzZWN0aW9uRWwsIGdyb3VwQ2hpbGRyZW4pOyAvLyAxIG9yIDAgY2hpbGRyZW5cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2VjdGlvbkVsO1xuICAgIH07XG4gICAgVG9vbGJhci5wcm90b3R5cGUudXBkYXRlVG9kYXkgPSBmdW5jdGlvbiAoaXNUb2RheUVuYWJsZWQpIHtcbiAgICAgICAgdGhpcy50b2dnbGVCdXR0b25FbmFibGVkKCd0b2RheScsIGlzVG9kYXlFbmFibGVkKTtcbiAgICB9O1xuICAgIFRvb2xiYXIucHJvdG90eXBlLnVwZGF0ZVByZXYgPSBmdW5jdGlvbiAoaXNQcmV2RW5hYmxlZCkge1xuICAgICAgICB0aGlzLnRvZ2dsZUJ1dHRvbkVuYWJsZWQoJ3ByZXYnLCBpc1ByZXZFbmFibGVkKTtcbiAgICB9O1xuICAgIFRvb2xiYXIucHJvdG90eXBlLnVwZGF0ZU5leHQgPSBmdW5jdGlvbiAoaXNOZXh0RW5hYmxlZCkge1xuICAgICAgICB0aGlzLnRvZ2dsZUJ1dHRvbkVuYWJsZWQoJ25leHQnLCBpc05leHRFbmFibGVkKTtcbiAgICB9O1xuICAgIFRvb2xiYXIucHJvdG90eXBlLnVwZGF0ZVRpdGxlID0gZnVuY3Rpb24gKHRleHQpIHtcbiAgICAgICAgZmluZEVsZW1lbnRzKHRoaXMuZWwsICdoMicpLmZvckVhY2goZnVuY3Rpb24gKHRpdGxlRWwpIHtcbiAgICAgICAgICAgIHRpdGxlRWwuaW5uZXJUZXh0ID0gdGV4dDtcbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICBUb29sYmFyLnByb3RvdHlwZS51cGRhdGVBY3RpdmVCdXR0b24gPSBmdW5jdGlvbiAoYnV0dG9uTmFtZSkge1xuICAgICAgICB2YXIgdGhlbWUgPSB0aGlzLmNvbnRleHQudGhlbWU7XG4gICAgICAgIHZhciBjbGFzc05hbWUgPSB0aGVtZS5nZXRDbGFzcygnYnV0dG9uQWN0aXZlJyk7XG4gICAgICAgIGZpbmRFbGVtZW50cyh0aGlzLmVsLCAnYnV0dG9uJykuZm9yRWFjaChmdW5jdGlvbiAoYnV0dG9uRWwpIHtcbiAgICAgICAgICAgIGlmIChidXR0b25OYW1lICYmIGJ1dHRvbkVsLmNsYXNzTGlzdC5jb250YWlucygnZmMtJyArIGJ1dHRvbk5hbWUgKyAnLWJ1dHRvbicpKSB7XG4gICAgICAgICAgICAgICAgYnV0dG9uRWwuY2xhc3NMaXN0LmFkZChjbGFzc05hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgYnV0dG9uRWwuY2xhc3NMaXN0LnJlbW92ZShjbGFzc05hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9O1xuICAgIFRvb2xiYXIucHJvdG90eXBlLnRvZ2dsZUJ1dHRvbkVuYWJsZWQgPSBmdW5jdGlvbiAoYnV0dG9uTmFtZSwgYm9vbCkge1xuICAgICAgICBmaW5kRWxlbWVudHModGhpcy5lbCwgJy5mYy0nICsgYnV0dG9uTmFtZSArICctYnV0dG9uJykuZm9yRWFjaChmdW5jdGlvbiAoYnV0dG9uRWwpIHtcbiAgICAgICAgICAgIGJ1dHRvbkVsLmRpc2FibGVkID0gIWJvb2w7XG4gICAgICAgIH0pO1xuICAgIH07XG4gICAgcmV0dXJuIFRvb2xiYXI7XG59KENvbXBvbmVudCkpO1xuXG52YXIgQ2FsZW5kYXJDb21wb25lbnQgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoX3N1cGVyKSB7XG4gICAgX19leHRlbmRzKENhbGVuZGFyQ29tcG9uZW50LCBfc3VwZXIpO1xuICAgIGZ1bmN0aW9uIENhbGVuZGFyQ29tcG9uZW50KGVsKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IF9zdXBlci5jYWxsKHRoaXMpIHx8IHRoaXM7XG4gICAgICAgIF90aGlzLmVsQ2xhc3NOYW1lcyA9IFtdO1xuICAgICAgICBfdGhpcy5yZW5kZXJTa2VsZXRvbiA9IG1lbW9pemVSZW5kZXJpbmcoX3RoaXMuX3JlbmRlclNrZWxldG9uLCBfdGhpcy5fdW5yZW5kZXJTa2VsZXRvbik7XG4gICAgICAgIF90aGlzLnJlbmRlclRvb2xiYXJzID0gbWVtb2l6ZVJlbmRlcmluZyhfdGhpcy5fcmVuZGVyVG9vbGJhcnMsIF90aGlzLl91bnJlbmRlclRvb2xiYXJzLCBbX3RoaXMucmVuZGVyU2tlbGV0b25dKTtcbiAgICAgICAgX3RoaXMuYnVpbGRDb21wb25lbnRDb250ZXh0ID0gbWVtb2l6ZShidWlsZENvbXBvbmVudENvbnRleHQpO1xuICAgICAgICBfdGhpcy5idWlsZFZpZXdQcm9wVHJhbnNmb3JtZXJzID0gbWVtb2l6ZShidWlsZFZpZXdQcm9wVHJhbnNmb3JtZXJzKTtcbiAgICAgICAgX3RoaXMuZWwgPSBlbDtcbiAgICAgICAgX3RoaXMuY29tcHV0ZVRpdGxlID0gbWVtb2l6ZShjb21wdXRlVGl0bGUpO1xuICAgICAgICBfdGhpcy5wYXJzZUJ1c2luZXNzSG91cnMgPSBtZW1vaXplKGZ1bmN0aW9uIChpbnB1dCkge1xuICAgICAgICAgICAgcmV0dXJuIHBhcnNlQnVzaW5lc3NIb3VycyhpbnB1dCwgX3RoaXMuY29udGV4dC5jYWxlbmRhcik7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gX3RoaXM7XG4gICAgfVxuICAgIENhbGVuZGFyQ29tcG9uZW50LnByb3RvdHlwZS5yZW5kZXIgPSBmdW5jdGlvbiAocHJvcHMsIGNvbnRleHQpIHtcbiAgICAgICAgdGhpcy5mcmVlemVIZWlnaHQoKTtcbiAgICAgICAgdmFyIHRpdGxlID0gdGhpcy5jb21wdXRlVGl0bGUocHJvcHMuZGF0ZVByb2ZpbGUsIHByb3BzLnZpZXdTcGVjLm9wdGlvbnMpO1xuICAgICAgICB0aGlzLnJlbmRlclNrZWxldG9uKGNvbnRleHQpO1xuICAgICAgICB0aGlzLnJlbmRlclRvb2xiYXJzKHByb3BzLnZpZXdTcGVjLCBwcm9wcy5kYXRlUHJvZmlsZSwgcHJvcHMuY3VycmVudERhdGUsIHRpdGxlKTtcbiAgICAgICAgdGhpcy5yZW5kZXJWaWV3KHByb3BzLCB0aXRsZSk7XG4gICAgICAgIHRoaXMudXBkYXRlU2l6ZSgpO1xuICAgICAgICB0aGlzLnRoYXdIZWlnaHQoKTtcbiAgICB9O1xuICAgIENhbGVuZGFyQ29tcG9uZW50LnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGhpcy5oZWFkZXIpIHtcbiAgICAgICAgICAgIHRoaXMuaGVhZGVyLmRlc3Ryb3koKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5mb290ZXIpIHtcbiAgICAgICAgICAgIHRoaXMuZm9vdGVyLmRlc3Ryb3koKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnJlbmRlclNrZWxldG9uLnVucmVuZGVyKCk7IC8vIHdpbGwgY2FsbCBkZXN0cm95Vmlld1xuICAgICAgICBfc3VwZXIucHJvdG90eXBlLmRlc3Ryb3kuY2FsbCh0aGlzKTtcbiAgICB9O1xuICAgIENhbGVuZGFyQ29tcG9uZW50LnByb3RvdHlwZS5fcmVuZGVyU2tlbGV0b24gPSBmdW5jdGlvbiAoY29udGV4dCkge1xuICAgICAgICB0aGlzLnVwZGF0ZUVsQ2xhc3NOYW1lcyhjb250ZXh0KTtcbiAgICAgICAgcHJlcGVuZFRvRWxlbWVudCh0aGlzLmVsLCB0aGlzLmNvbnRlbnRFbCA9IGNyZWF0ZUVsZW1lbnQoJ2RpdicsIHsgY2xhc3NOYW1lOiAnZmMtdmlldy1jb250YWluZXInIH0pKTtcbiAgICAgICAgdmFyIGNhbGVuZGFyID0gY29udGV4dC5jYWxlbmRhcjtcbiAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBfYSA9IGNhbGVuZGFyLnBsdWdpblN5c3RlbS5ob29rcy52aWV3Q29udGFpbmVyTW9kaWZpZXJzOyBfaSA8IF9hLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgdmFyIG1vZGlmeVZpZXdDb250YWluZXIgPSBfYVtfaV07XG4gICAgICAgICAgICBtb2RpZnlWaWV3Q29udGFpbmVyKHRoaXMuY29udGVudEVsLCBjYWxlbmRhcik7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIENhbGVuZGFyQ29tcG9uZW50LnByb3RvdHlwZS5fdW5yZW5kZXJTa2VsZXRvbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLy8gd2VpcmQgdG8gaGF2ZSB0aGlzIGhlcmVcbiAgICAgICAgaWYgKHRoaXMudmlldykge1xuICAgICAgICAgICAgdGhpcy5zYXZlZFNjcm9sbCA9IHRoaXMudmlldy5xdWVyeVNjcm9sbCgpO1xuICAgICAgICAgICAgdGhpcy52aWV3LmRlc3Ryb3koKTtcbiAgICAgICAgICAgIHRoaXMudmlldyA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgcmVtb3ZlRWxlbWVudCh0aGlzLmNvbnRlbnRFbCk7XG4gICAgICAgIHRoaXMucmVtb3ZlRWxDbGFzc05hbWVzKCk7XG4gICAgfTtcbiAgICBDYWxlbmRhckNvbXBvbmVudC5wcm90b3R5cGUucmVtb3ZlRWxDbGFzc05hbWVzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgY2xhc3NMaXN0ID0gdGhpcy5lbC5jbGFzc0xpc3Q7XG4gICAgICAgIGZvciAodmFyIF9pID0gMCwgX2EgPSB0aGlzLmVsQ2xhc3NOYW1lczsgX2kgPCBfYS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIHZhciBjbGFzc05hbWUgPSBfYVtfaV07XG4gICAgICAgICAgICBjbGFzc0xpc3QucmVtb3ZlKGNsYXNzTmFtZSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5lbENsYXNzTmFtZXMgPSBbXTtcbiAgICB9O1xuICAgIENhbGVuZGFyQ29tcG9uZW50LnByb3RvdHlwZS51cGRhdGVFbENsYXNzTmFtZXMgPSBmdW5jdGlvbiAoY29udGV4dCkge1xuICAgICAgICB0aGlzLnJlbW92ZUVsQ2xhc3NOYW1lcygpO1xuICAgICAgICB2YXIgdGhlbWUgPSBjb250ZXh0LnRoZW1lLCBvcHRpb25zID0gY29udGV4dC5vcHRpb25zO1xuICAgICAgICB0aGlzLmVsQ2xhc3NOYW1lcyA9IFtcbiAgICAgICAgICAgICdmYycsXG4gICAgICAgICAgICAnZmMtJyArIG9wdGlvbnMuZGlyLFxuICAgICAgICAgICAgdGhlbWUuZ2V0Q2xhc3MoJ3dpZGdldCcpXG4gICAgICAgIF07XG4gICAgICAgIHZhciBjbGFzc0xpc3QgPSB0aGlzLmVsLmNsYXNzTGlzdDtcbiAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBfYSA9IHRoaXMuZWxDbGFzc05hbWVzOyBfaSA8IF9hLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgdmFyIGNsYXNzTmFtZSA9IF9hW19pXTtcbiAgICAgICAgICAgIGNsYXNzTGlzdC5hZGQoY2xhc3NOYW1lKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgQ2FsZW5kYXJDb21wb25lbnQucHJvdG90eXBlLl9yZW5kZXJUb29sYmFycyA9IGZ1bmN0aW9uICh2aWV3U3BlYywgZGF0ZVByb2ZpbGUsIGN1cnJlbnREYXRlLCB0aXRsZSkge1xuICAgICAgICB2YXIgX2EgPSB0aGlzLCBjb250ZXh0ID0gX2EuY29udGV4dCwgaGVhZGVyID0gX2EuaGVhZGVyLCBmb290ZXIgPSBfYS5mb290ZXI7XG4gICAgICAgIHZhciBvcHRpb25zID0gY29udGV4dC5vcHRpb25zLCBjYWxlbmRhciA9IGNvbnRleHQuY2FsZW5kYXI7XG4gICAgICAgIHZhciBoZWFkZXJMYXlvdXQgPSBvcHRpb25zLmhlYWRlcjtcbiAgICAgICAgdmFyIGZvb3RlckxheW91dCA9IG9wdGlvbnMuZm9vdGVyO1xuICAgICAgICB2YXIgZGF0ZVByb2ZpbGVHZW5lcmF0b3IgPSB0aGlzLnByb3BzLmRhdGVQcm9maWxlR2VuZXJhdG9yO1xuICAgICAgICB2YXIgbm93ID0gY2FsZW5kYXIuZ2V0Tm93KCk7XG4gICAgICAgIHZhciB0b2RheUluZm8gPSBkYXRlUHJvZmlsZUdlbmVyYXRvci5idWlsZChub3cpO1xuICAgICAgICB2YXIgcHJldkluZm8gPSBkYXRlUHJvZmlsZUdlbmVyYXRvci5idWlsZFByZXYoZGF0ZVByb2ZpbGUsIGN1cnJlbnREYXRlKTtcbiAgICAgICAgdmFyIG5leHRJbmZvID0gZGF0ZVByb2ZpbGVHZW5lcmF0b3IuYnVpbGROZXh0KGRhdGVQcm9maWxlLCBjdXJyZW50RGF0ZSk7XG4gICAgICAgIHZhciB0b29sYmFyUHJvcHMgPSB7XG4gICAgICAgICAgICB0aXRsZTogdGl0bGUsXG4gICAgICAgICAgICBhY3RpdmVCdXR0b246IHZpZXdTcGVjLnR5cGUsXG4gICAgICAgICAgICBpc1RvZGF5RW5hYmxlZDogdG9kYXlJbmZvLmlzVmFsaWQgJiYgIXJhbmdlQ29udGFpbnNNYXJrZXIoZGF0ZVByb2ZpbGUuY3VycmVudFJhbmdlLCBub3cpLFxuICAgICAgICAgICAgaXNQcmV2RW5hYmxlZDogcHJldkluZm8uaXNWYWxpZCxcbiAgICAgICAgICAgIGlzTmV4dEVuYWJsZWQ6IG5leHRJbmZvLmlzVmFsaWRcbiAgICAgICAgfTtcbiAgICAgICAgaWYgKGhlYWRlckxheW91dCkge1xuICAgICAgICAgICAgaWYgKCFoZWFkZXIpIHtcbiAgICAgICAgICAgICAgICBoZWFkZXIgPSB0aGlzLmhlYWRlciA9IG5ldyBUb29sYmFyKCdmYy1oZWFkZXItdG9vbGJhcicpO1xuICAgICAgICAgICAgICAgIHByZXBlbmRUb0VsZW1lbnQodGhpcy5lbCwgaGVhZGVyLmVsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGhlYWRlci5yZWNlaXZlUHJvcHMoX19hc3NpZ24oeyBsYXlvdXQ6IGhlYWRlckxheW91dCB9LCB0b29sYmFyUHJvcHMpLCBjb250ZXh0KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChoZWFkZXIpIHtcbiAgICAgICAgICAgIGhlYWRlci5kZXN0cm95KCk7XG4gICAgICAgICAgICBoZWFkZXIgPSB0aGlzLmhlYWRlciA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGZvb3RlckxheW91dCkge1xuICAgICAgICAgICAgaWYgKCFmb290ZXIpIHtcbiAgICAgICAgICAgICAgICBmb290ZXIgPSB0aGlzLmZvb3RlciA9IG5ldyBUb29sYmFyKCdmYy1mb290ZXItdG9vbGJhcicpO1xuICAgICAgICAgICAgICAgIGFwcGVuZFRvRWxlbWVudCh0aGlzLmVsLCBmb290ZXIuZWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9vdGVyLnJlY2VpdmVQcm9wcyhfX2Fzc2lnbih7IGxheW91dDogZm9vdGVyTGF5b3V0IH0sIHRvb2xiYXJQcm9wcyksIGNvbnRleHQpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGZvb3Rlcikge1xuICAgICAgICAgICAgZm9vdGVyLmRlc3Ryb3koKTtcbiAgICAgICAgICAgIGZvb3RlciA9IHRoaXMuZm9vdGVyID0gbnVsbDtcbiAgICAgICAgfVxuICAgIH07XG4gICAgQ2FsZW5kYXJDb21wb25lbnQucHJvdG90eXBlLl91bnJlbmRlclRvb2xiYXJzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGhpcy5oZWFkZXIpIHtcbiAgICAgICAgICAgIHRoaXMuaGVhZGVyLmRlc3Ryb3koKTtcbiAgICAgICAgICAgIHRoaXMuaGVhZGVyID0gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5mb290ZXIpIHtcbiAgICAgICAgICAgIHRoaXMuZm9vdGVyLmRlc3Ryb3koKTtcbiAgICAgICAgICAgIHRoaXMuZm9vdGVyID0gbnVsbDtcbiAgICAgICAgfVxuICAgIH07XG4gICAgQ2FsZW5kYXJDb21wb25lbnQucHJvdG90eXBlLnJlbmRlclZpZXcgPSBmdW5jdGlvbiAocHJvcHMsIHRpdGxlKSB7XG4gICAgICAgIHZhciB2aWV3ID0gdGhpcy52aWV3O1xuICAgICAgICB2YXIgX2EgPSB0aGlzLmNvbnRleHQsIGNhbGVuZGFyID0gX2EuY2FsZW5kYXIsIG9wdGlvbnMgPSBfYS5vcHRpb25zO1xuICAgICAgICB2YXIgdmlld1NwZWMgPSBwcm9wcy52aWV3U3BlYywgZGF0ZVByb2ZpbGVHZW5lcmF0b3IgPSBwcm9wcy5kYXRlUHJvZmlsZUdlbmVyYXRvcjtcbiAgICAgICAgaWYgKCF2aWV3IHx8IHZpZXcudmlld1NwZWMgIT09IHZpZXdTcGVjKSB7XG4gICAgICAgICAgICBpZiAodmlldykge1xuICAgICAgICAgICAgICAgIHZpZXcuZGVzdHJveSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmlldyA9IHRoaXMudmlldyA9IG5ldyB2aWV3U3BlY1snY2xhc3MnXSh2aWV3U3BlYywgdGhpcy5jb250ZW50RWwpO1xuICAgICAgICAgICAgaWYgKHRoaXMuc2F2ZWRTY3JvbGwpIHtcbiAgICAgICAgICAgICAgICB2aWV3LmFkZFNjcm9sbCh0aGlzLnNhdmVkU2Nyb2xsLCB0cnVlKTtcbiAgICAgICAgICAgICAgICB0aGlzLnNhdmVkU2Nyb2xsID0gbnVsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB2aWV3LnRpdGxlID0gdGl0bGU7IC8vIGZvciB0aGUgQVBJXG4gICAgICAgIHZhciB2aWV3UHJvcHMgPSB7XG4gICAgICAgICAgICBkYXRlUHJvZmlsZUdlbmVyYXRvcjogZGF0ZVByb2ZpbGVHZW5lcmF0b3IsXG4gICAgICAgICAgICBkYXRlUHJvZmlsZTogcHJvcHMuZGF0ZVByb2ZpbGUsXG4gICAgICAgICAgICBidXNpbmVzc0hvdXJzOiB0aGlzLnBhcnNlQnVzaW5lc3NIb3Vycyh2aWV3U3BlYy5vcHRpb25zLmJ1c2luZXNzSG91cnMpLFxuICAgICAgICAgICAgZXZlbnRTdG9yZTogcHJvcHMuZXZlbnRTdG9yZSxcbiAgICAgICAgICAgIGV2ZW50VWlCYXNlczogcHJvcHMuZXZlbnRVaUJhc2VzLFxuICAgICAgICAgICAgZGF0ZVNlbGVjdGlvbjogcHJvcHMuZGF0ZVNlbGVjdGlvbixcbiAgICAgICAgICAgIGV2ZW50U2VsZWN0aW9uOiBwcm9wcy5ldmVudFNlbGVjdGlvbixcbiAgICAgICAgICAgIGV2ZW50RHJhZzogcHJvcHMuZXZlbnREcmFnLFxuICAgICAgICAgICAgZXZlbnRSZXNpemU6IHByb3BzLmV2ZW50UmVzaXplXG4gICAgICAgIH07XG4gICAgICAgIHZhciB0cmFuc2Zvcm1lcnMgPSB0aGlzLmJ1aWxkVmlld1Byb3BUcmFuc2Zvcm1lcnMoY2FsZW5kYXIucGx1Z2luU3lzdGVtLmhvb2tzLnZpZXdQcm9wc1RyYW5zZm9ybWVycyk7XG4gICAgICAgIGZvciAodmFyIF9pID0gMCwgdHJhbnNmb3JtZXJzXzEgPSB0cmFuc2Zvcm1lcnM7IF9pIDwgdHJhbnNmb3JtZXJzXzEubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICB2YXIgdHJhbnNmb3JtZXIgPSB0cmFuc2Zvcm1lcnNfMVtfaV07XG4gICAgICAgICAgICBfX2Fzc2lnbih2aWV3UHJvcHMsIHRyYW5zZm9ybWVyLnRyYW5zZm9ybSh2aWV3UHJvcHMsIHZpZXdTcGVjLCBwcm9wcywgb3B0aW9ucykpO1xuICAgICAgICB9XG4gICAgICAgIHZpZXcucmVjZWl2ZVByb3BzKHZpZXdQcm9wcywgdGhpcy5idWlsZENvbXBvbmVudENvbnRleHQodGhpcy5jb250ZXh0LCB2aWV3U3BlYywgdmlldykpO1xuICAgIH07XG4gICAgLy8gU2l6aW5nXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBDYWxlbmRhckNvbXBvbmVudC5wcm90b3R5cGUudXBkYXRlU2l6ZSA9IGZ1bmN0aW9uIChpc1Jlc2l6ZSkge1xuICAgICAgICBpZiAoaXNSZXNpemUgPT09IHZvaWQgMCkgeyBpc1Jlc2l6ZSA9IGZhbHNlOyB9XG4gICAgICAgIHZhciB2aWV3ID0gdGhpcy52aWV3O1xuICAgICAgICBpZiAoIXZpZXcpIHtcbiAgICAgICAgICAgIHJldHVybjsgLy8gd2h5P1xuICAgICAgICB9XG4gICAgICAgIGlmIChpc1Jlc2l6ZSB8fCB0aGlzLmlzSGVpZ2h0QXV0byA9PSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLmNvbXB1dGVIZWlnaHRWYXJzKCk7XG4gICAgICAgIH1cbiAgICAgICAgdmlldy51cGRhdGVTaXplKGlzUmVzaXplLCB0aGlzLnZpZXdIZWlnaHQsIHRoaXMuaXNIZWlnaHRBdXRvKTtcbiAgICAgICAgdmlldy51cGRhdGVOb3dJbmRpY2F0b3IoKTsgLy8gd2UgbmVlZCB0byBndWFyYW50ZWUgdGhpcyB3aWxsIHJ1biBhZnRlciB1cGRhdGVTaXplXG4gICAgICAgIHZpZXcucG9wU2Nyb2xsKGlzUmVzaXplKTtcbiAgICB9O1xuICAgIENhbGVuZGFyQ29tcG9uZW50LnByb3RvdHlwZS5jb21wdXRlSGVpZ2h0VmFycyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGNhbGVuZGFyID0gdGhpcy5jb250ZXh0LmNhbGVuZGFyOyAvLyB5dWNrLiBuZWVkIHRvIGhhbmRsZSBkeW5hbWljIG9wdGlvbnNcbiAgICAgICAgdmFyIGhlaWdodElucHV0ID0gY2FsZW5kYXIub3B0KCdoZWlnaHQnKTtcbiAgICAgICAgdmFyIGNvbnRlbnRIZWlnaHRJbnB1dCA9IGNhbGVuZGFyLm9wdCgnY29udGVudEhlaWdodCcpO1xuICAgICAgICB0aGlzLmlzSGVpZ2h0QXV0byA9IGhlaWdodElucHV0ID09PSAnYXV0bycgfHwgY29udGVudEhlaWdodElucHV0ID09PSAnYXV0byc7XG4gICAgICAgIGlmICh0eXBlb2YgY29udGVudEhlaWdodElucHV0ID09PSAnbnVtYmVyJykgeyAvLyBleGlzdHMgYW5kIG5vdCAnYXV0bydcbiAgICAgICAgICAgIHRoaXMudmlld0hlaWdodCA9IGNvbnRlbnRIZWlnaHRJbnB1dDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0eXBlb2YgY29udGVudEhlaWdodElucHV0ID09PSAnZnVuY3Rpb24nKSB7IC8vIGV4aXN0cyBhbmQgaXMgYSBmdW5jdGlvblxuICAgICAgICAgICAgdGhpcy52aWV3SGVpZ2h0ID0gY29udGVudEhlaWdodElucHV0KCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodHlwZW9mIGhlaWdodElucHV0ID09PSAnbnVtYmVyJykgeyAvLyBleGlzdHMgYW5kIG5vdCAnYXV0bydcbiAgICAgICAgICAgIHRoaXMudmlld0hlaWdodCA9IGhlaWdodElucHV0IC0gdGhpcy5xdWVyeVRvb2xiYXJzSGVpZ2h0KCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodHlwZW9mIGhlaWdodElucHV0ID09PSAnZnVuY3Rpb24nKSB7IC8vIGV4aXN0cyBhbmQgaXMgYSBmdW5jdGlvblxuICAgICAgICAgICAgdGhpcy52aWV3SGVpZ2h0ID0gaGVpZ2h0SW5wdXQoKSAtIHRoaXMucXVlcnlUb29sYmFyc0hlaWdodCgpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGhlaWdodElucHV0ID09PSAncGFyZW50JykgeyAvLyBzZXQgdG8gaGVpZ2h0IG9mIHBhcmVudCBlbGVtZW50XG4gICAgICAgICAgICB2YXIgcGFyZW50RWwgPSB0aGlzLmVsLnBhcmVudE5vZGU7XG4gICAgICAgICAgICB0aGlzLnZpZXdIZWlnaHQgPSBwYXJlbnRFbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5oZWlnaHQgLSB0aGlzLnF1ZXJ5VG9vbGJhcnNIZWlnaHQoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMudmlld0hlaWdodCA9IE1hdGgucm91bmQodGhpcy5jb250ZW50RWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkud2lkdGggL1xuICAgICAgICAgICAgICAgIE1hdGgubWF4KGNhbGVuZGFyLm9wdCgnYXNwZWN0UmF0aW8nKSwgLjUpKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgQ2FsZW5kYXJDb21wb25lbnQucHJvdG90eXBlLnF1ZXJ5VG9vbGJhcnNIZWlnaHQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBoZWlnaHQgPSAwO1xuICAgICAgICBpZiAodGhpcy5oZWFkZXIpIHtcbiAgICAgICAgICAgIGhlaWdodCArPSBjb21wdXRlSGVpZ2h0QW5kTWFyZ2lucyh0aGlzLmhlYWRlci5lbCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuZm9vdGVyKSB7XG4gICAgICAgICAgICBoZWlnaHQgKz0gY29tcHV0ZUhlaWdodEFuZE1hcmdpbnModGhpcy5mb290ZXIuZWwpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBoZWlnaHQ7XG4gICAgfTtcbiAgICAvLyBIZWlnaHQgXCJGcmVlemluZ1wiXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBDYWxlbmRhckNvbXBvbmVudC5wcm90b3R5cGUuZnJlZXplSGVpZ2h0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBhcHBseVN0eWxlKHRoaXMuZWwsIHtcbiAgICAgICAgICAgIGhlaWdodDogdGhpcy5lbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5oZWlnaHQsXG4gICAgICAgICAgICBvdmVyZmxvdzogJ2hpZGRlbidcbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICBDYWxlbmRhckNvbXBvbmVudC5wcm90b3R5cGUudGhhd0hlaWdodCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYXBwbHlTdHlsZSh0aGlzLmVsLCB7XG4gICAgICAgICAgICBoZWlnaHQ6ICcnLFxuICAgICAgICAgICAgb3ZlcmZsb3c6ICcnXG4gICAgICAgIH0pO1xuICAgIH07XG4gICAgcmV0dXJuIENhbGVuZGFyQ29tcG9uZW50O1xufShDb21wb25lbnQpKTtcbi8vIFRpdGxlIGFuZCBEYXRlIEZvcm1hdHRpbmdcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBDb21wdXRlcyB3aGF0IHRoZSB0aXRsZSBhdCB0aGUgdG9wIG9mIHRoZSBjYWxlbmRhciBzaG91bGQgYmUgZm9yIHRoaXMgdmlld1xuZnVuY3Rpb24gY29tcHV0ZVRpdGxlKGRhdGVQcm9maWxlLCB2aWV3T3B0aW9ucykge1xuICAgIHZhciByYW5nZTtcbiAgICAvLyBmb3Igdmlld3MgdGhhdCBzcGFuIGEgbGFyZ2UgdW5pdCBvZiB0aW1lLCBzaG93IHRoZSBwcm9wZXIgaW50ZXJ2YWwsIGlnbm9yaW5nIHN0cmF5IGRheXMgYmVmb3JlIGFuZCBhZnRlclxuICAgIGlmICgvXih5ZWFyfG1vbnRoKSQvLnRlc3QoZGF0ZVByb2ZpbGUuY3VycmVudFJhbmdlVW5pdCkpIHtcbiAgICAgICAgcmFuZ2UgPSBkYXRlUHJvZmlsZS5jdXJyZW50UmFuZ2U7XG4gICAgfVxuICAgIGVsc2UgeyAvLyBmb3IgZGF5IHVuaXRzIG9yIHNtYWxsZXIsIHVzZSB0aGUgYWN0dWFsIGRheSByYW5nZVxuICAgICAgICByYW5nZSA9IGRhdGVQcm9maWxlLmFjdGl2ZVJhbmdlO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5jb250ZXh0LmRhdGVFbnYuZm9ybWF0UmFuZ2UocmFuZ2Uuc3RhcnQsIHJhbmdlLmVuZCwgY3JlYXRlRm9ybWF0dGVyKHZpZXdPcHRpb25zLnRpdGxlRm9ybWF0IHx8IGNvbXB1dGVUaXRsZUZvcm1hdChkYXRlUHJvZmlsZSksIHZpZXdPcHRpb25zLnRpdGxlUmFuZ2VTZXBhcmF0b3IpLCB7IGlzRW5kRXhjbHVzaXZlOiBkYXRlUHJvZmlsZS5pc1JhbmdlQWxsRGF5IH0pO1xufVxuLy8gR2VuZXJhdGVzIHRoZSBmb3JtYXQgc3RyaW5nIHRoYXQgc2hvdWxkIGJlIHVzZWQgdG8gZ2VuZXJhdGUgdGhlIHRpdGxlIGZvciB0aGUgY3VycmVudCBkYXRlIHJhbmdlLlxuLy8gQXR0ZW1wdHMgdG8gY29tcHV0ZSB0aGUgbW9zdCBhcHByb3ByaWF0ZSBmb3JtYXQgaWYgbm90IGV4cGxpY2l0bHkgc3BlY2lmaWVkIHdpdGggYHRpdGxlRm9ybWF0YC5cbmZ1bmN0aW9uIGNvbXB1dGVUaXRsZUZvcm1hdChkYXRlUHJvZmlsZSkge1xuICAgIHZhciBjdXJyZW50UmFuZ2VVbml0ID0gZGF0ZVByb2ZpbGUuY3VycmVudFJhbmdlVW5pdDtcbiAgICBpZiAoY3VycmVudFJhbmdlVW5pdCA9PT0gJ3llYXInKSB7XG4gICAgICAgIHJldHVybiB7IHllYXI6ICdudW1lcmljJyB9O1xuICAgIH1cbiAgICBlbHNlIGlmIChjdXJyZW50UmFuZ2VVbml0ID09PSAnbW9udGgnKSB7XG4gICAgICAgIHJldHVybiB7IHllYXI6ICdudW1lcmljJywgbW9udGg6ICdsb25nJyB9OyAvLyBsaWtlIFwiU2VwdGVtYmVyIDIwMTRcIlxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdmFyIGRheXMgPSBkaWZmV2hvbGVEYXlzKGRhdGVQcm9maWxlLmN1cnJlbnRSYW5nZS5zdGFydCwgZGF0ZVByb2ZpbGUuY3VycmVudFJhbmdlLmVuZCk7XG4gICAgICAgIGlmIChkYXlzICE9PSBudWxsICYmIGRheXMgPiAxKSB7XG4gICAgICAgICAgICAvLyBtdWx0aS1kYXkgcmFuZ2UuIHNob3J0ZXIsIGxpa2UgXCJTZXAgOSAtIDEwIDIwMTRcIlxuICAgICAgICAgICAgcmV0dXJuIHsgeWVhcjogJ251bWVyaWMnLCBtb250aDogJ3Nob3J0JywgZGF5OiAnbnVtZXJpYycgfTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIC8vIG9uZSBkYXkuIGxvbmdlciwgbGlrZSBcIlNlcHRlbWJlciA5IDIwMTRcIlxuICAgICAgICAgICAgcmV0dXJuIHsgeWVhcjogJ251bWVyaWMnLCBtb250aDogJ2xvbmcnLCBkYXk6ICdudW1lcmljJyB9O1xuICAgICAgICB9XG4gICAgfVxufVxuLy8gYnVpbGQgYSBjb250ZXh0IHNjb3BlZCB0byB0aGUgdmlld1xuZnVuY3Rpb24gYnVpbGRDb21wb25lbnRDb250ZXh0KGNvbnRleHQsIHZpZXdTcGVjLCB2aWV3KSB7XG4gICAgcmV0dXJuIGNvbnRleHQuZXh0ZW5kKHZpZXdTcGVjLm9wdGlvbnMsIHZpZXcpO1xufVxuLy8gUGx1Z2luXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuZnVuY3Rpb24gYnVpbGRWaWV3UHJvcFRyYW5zZm9ybWVycyh0aGVDbGFzc2VzKSB7XG4gICAgcmV0dXJuIHRoZUNsYXNzZXMubWFwKGZ1bmN0aW9uICh0aGVDbGFzcykge1xuICAgICAgICByZXR1cm4gbmV3IHRoZUNsYXNzKCk7XG4gICAgfSk7XG59XG5cbnZhciBJbnRlcmFjdGlvbiA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBJbnRlcmFjdGlvbihzZXR0aW5ncykge1xuICAgICAgICB0aGlzLmNvbXBvbmVudCA9IHNldHRpbmdzLmNvbXBvbmVudDtcbiAgICB9XG4gICAgSW50ZXJhY3Rpb24ucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgfTtcbiAgICByZXR1cm4gSW50ZXJhY3Rpb247XG59KCkpO1xuZnVuY3Rpb24gcGFyc2VJbnRlcmFjdGlvblNldHRpbmdzKGNvbXBvbmVudCwgaW5wdXQpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBjb21wb25lbnQ6IGNvbXBvbmVudCxcbiAgICAgICAgZWw6IGlucHV0LmVsLFxuICAgICAgICB1c2VFdmVudENlbnRlcjogaW5wdXQudXNlRXZlbnRDZW50ZXIgIT0gbnVsbCA/IGlucHV0LnVzZUV2ZW50Q2VudGVyIDogdHJ1ZVxuICAgIH07XG59XG5mdW5jdGlvbiBpbnRlcmFjdGlvblNldHRpbmdzVG9TdG9yZShzZXR0aW5ncykge1xuICAgIHZhciBfYTtcbiAgICByZXR1cm4gX2EgPSB7fSxcbiAgICAgICAgX2Fbc2V0dGluZ3MuY29tcG9uZW50LnVpZF0gPSBzZXR0aW5ncyxcbiAgICAgICAgX2E7XG59XG4vLyBnbG9iYWwgc3RhdGVcbnZhciBpbnRlcmFjdGlvblNldHRpbmdzU3RvcmUgPSB7fTtcblxuLypcbkRldGVjdHMgd2hlbiB0aGUgdXNlciBjbGlja3Mgb24gYW4gZXZlbnQgd2l0aGluIGEgRGF0ZUNvbXBvbmVudFxuKi9cbnZhciBFdmVudENsaWNraW5nID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKF9zdXBlcikge1xuICAgIF9fZXh0ZW5kcyhFdmVudENsaWNraW5nLCBfc3VwZXIpO1xuICAgIGZ1bmN0aW9uIEV2ZW50Q2xpY2tpbmcoc2V0dGluZ3MpIHtcbiAgICAgICAgdmFyIF90aGlzID0gX3N1cGVyLmNhbGwodGhpcywgc2V0dGluZ3MpIHx8IHRoaXM7XG4gICAgICAgIF90aGlzLmhhbmRsZVNlZ0NsaWNrID0gZnVuY3Rpb24gKGV2LCBzZWdFbCkge1xuICAgICAgICAgICAgdmFyIGNvbXBvbmVudCA9IF90aGlzLmNvbXBvbmVudDtcbiAgICAgICAgICAgIHZhciBfYSA9IGNvbXBvbmVudC5jb250ZXh0LCBjYWxlbmRhciA9IF9hLmNhbGVuZGFyLCB2aWV3ID0gX2EudmlldztcbiAgICAgICAgICAgIHZhciBzZWcgPSBnZXRFbFNlZyhzZWdFbCk7XG4gICAgICAgICAgICBpZiAoc2VnICYmIC8vIG1pZ2h0IGJlIHRoZSA8ZGl2PiBzdXJyb3VuZGluZyB0aGUgbW9yZSBsaW5rXG4gICAgICAgICAgICAgICAgY29tcG9uZW50LmlzVmFsaWRTZWdEb3duRWwoZXYudGFyZ2V0KSkge1xuICAgICAgICAgICAgICAgIC8vIG91ciB3YXkgdG8gc2ltdWxhdGUgYSBsaW5rIGNsaWNrIGZvciBlbGVtZW50cyB0aGF0IGNhbid0IGJlIDxhPiB0YWdzXG4gICAgICAgICAgICAgICAgLy8gZ3JhYiBiZWZvcmUgdHJpZ2dlciBmaXJlZCBpbiBjYXNlIHRyaWdnZXIgdHJhc2hlcyBET00gdGhydSByZXJlbmRlcmluZ1xuICAgICAgICAgICAgICAgIHZhciBoYXNVcmxDb250YWluZXIgPSBlbGVtZW50Q2xvc2VzdChldi50YXJnZXQsICcuZmMtaGFzLXVybCcpO1xuICAgICAgICAgICAgICAgIHZhciB1cmwgPSBoYXNVcmxDb250YWluZXIgPyBoYXNVcmxDb250YWluZXIucXVlcnlTZWxlY3RvcignYVtocmVmXScpLmhyZWYgOiAnJztcbiAgICAgICAgICAgICAgICBjYWxlbmRhci5wdWJsaWNseVRyaWdnZXIoJ2V2ZW50Q2xpY2snLCBbXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsOiBzZWdFbCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50OiBuZXcgRXZlbnRBcGkoY29tcG9uZW50LmNvbnRleHQuY2FsZW5kYXIsIHNlZy5ldmVudFJhbmdlLmRlZiwgc2VnLmV2ZW50UmFuZ2UuaW5zdGFuY2UpLFxuICAgICAgICAgICAgICAgICAgICAgICAganNFdmVudDogZXYsXG4gICAgICAgICAgICAgICAgICAgICAgICB2aWV3OiB2aWV3XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBdKTtcbiAgICAgICAgICAgICAgICBpZiAodXJsICYmICFldi5kZWZhdWx0UHJldmVudGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHdpbmRvdy5sb2NhdGlvbi5ocmVmID0gdXJsO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdmFyIGNvbXBvbmVudCA9IHNldHRpbmdzLmNvbXBvbmVudDtcbiAgICAgICAgX3RoaXMuZGVzdHJveSA9IGxpc3RlbkJ5U2VsZWN0b3IoY29tcG9uZW50LmVsLCAnY2xpY2snLCBjb21wb25lbnQuZmdTZWdTZWxlY3RvciArICcsJyArIGNvbXBvbmVudC5iZ1NlZ1NlbGVjdG9yLCBfdGhpcy5oYW5kbGVTZWdDbGljayk7XG4gICAgICAgIHJldHVybiBfdGhpcztcbiAgICB9XG4gICAgcmV0dXJuIEV2ZW50Q2xpY2tpbmc7XG59KEludGVyYWN0aW9uKSk7XG5cbi8qXG5UcmlnZ2VycyBldmVudHMgYW5kIGFkZHMvcmVtb3ZlcyBjb3JlIGNsYXNzTmFtZXMgd2hlbiB0aGUgdXNlcidzIHBvaW50ZXJcbmVudGVycy9sZWF2ZXMgZXZlbnQtZWxlbWVudHMgb2YgYSBjb21wb25lbnQuXG4qL1xudmFyIEV2ZW50SG92ZXJpbmcgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoX3N1cGVyKSB7XG4gICAgX19leHRlbmRzKEV2ZW50SG92ZXJpbmcsIF9zdXBlcik7XG4gICAgZnVuY3Rpb24gRXZlbnRIb3ZlcmluZyhzZXR0aW5ncykge1xuICAgICAgICB2YXIgX3RoaXMgPSBfc3VwZXIuY2FsbCh0aGlzLCBzZXR0aW5ncykgfHwgdGhpcztcbiAgICAgICAgLy8gZm9yIHNpbXVsYXRpbmcgYW4gZXZlbnRNb3VzZUxlYXZlIHdoZW4gdGhlIGV2ZW50IGVsIGlzIGRlc3Ryb3llZCB3aGlsZSBtb3VzZSBpcyBvdmVyIGl0XG4gICAgICAgIF90aGlzLmhhbmRsZUV2ZW50RWxSZW1vdmUgPSBmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgICAgIGlmIChlbCA9PT0gX3RoaXMuY3VycmVudFNlZ0VsKSB7XG4gICAgICAgICAgICAgICAgX3RoaXMuaGFuZGxlU2VnTGVhdmUobnVsbCwgX3RoaXMuY3VycmVudFNlZ0VsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgX3RoaXMuaGFuZGxlU2VnRW50ZXIgPSBmdW5jdGlvbiAoZXYsIHNlZ0VsKSB7XG4gICAgICAgICAgICBpZiAoZ2V0RWxTZWcoc2VnRWwpKSB7IC8vIFRPRE86IGJldHRlciB3YXkgdG8gbWFrZSBzdXJlIG5vdCBob3ZlcmluZyBvdmVyIG1vcmUrIGxpbmsgb3IgaXRzIHdyYXBwZXJcbiAgICAgICAgICAgICAgICBzZWdFbC5jbGFzc0xpc3QuYWRkKCdmYy1hbGxvdy1tb3VzZS1yZXNpemUnKTtcbiAgICAgICAgICAgICAgICBfdGhpcy5jdXJyZW50U2VnRWwgPSBzZWdFbDtcbiAgICAgICAgICAgICAgICBfdGhpcy50cmlnZ2VyRXZlbnQoJ2V2ZW50TW91c2VFbnRlcicsIGV2LCBzZWdFbCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIF90aGlzLmhhbmRsZVNlZ0xlYXZlID0gZnVuY3Rpb24gKGV2LCBzZWdFbCkge1xuICAgICAgICAgICAgaWYgKF90aGlzLmN1cnJlbnRTZWdFbCkge1xuICAgICAgICAgICAgICAgIHNlZ0VsLmNsYXNzTGlzdC5yZW1vdmUoJ2ZjLWFsbG93LW1vdXNlLXJlc2l6ZScpO1xuICAgICAgICAgICAgICAgIF90aGlzLmN1cnJlbnRTZWdFbCA9IG51bGw7XG4gICAgICAgICAgICAgICAgX3RoaXMudHJpZ2dlckV2ZW50KCdldmVudE1vdXNlTGVhdmUnLCBldiwgc2VnRWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICB2YXIgY29tcG9uZW50ID0gc2V0dGluZ3MuY29tcG9uZW50O1xuICAgICAgICBfdGhpcy5yZW1vdmVIb3Zlckxpc3RlbmVycyA9IGxpc3RlblRvSG92ZXJCeVNlbGVjdG9yKGNvbXBvbmVudC5lbCwgY29tcG9uZW50LmZnU2VnU2VsZWN0b3IgKyAnLCcgKyBjb21wb25lbnQuYmdTZWdTZWxlY3RvciwgX3RoaXMuaGFuZGxlU2VnRW50ZXIsIF90aGlzLmhhbmRsZVNlZ0xlYXZlKTtcbiAgICAgICAgLy8gaG93IHRvIG1ha2Ugc3VyZSBjb21wb25lbnQgYWxyZWFkeSBoYXMgY29udGV4dD9cbiAgICAgICAgY29tcG9uZW50LmNvbnRleHQuY2FsZW5kYXIub24oJ2V2ZW50RWxSZW1vdmUnLCBfdGhpcy5oYW5kbGVFdmVudEVsUmVtb3ZlKTtcbiAgICAgICAgcmV0dXJuIF90aGlzO1xuICAgIH1cbiAgICBFdmVudEhvdmVyaW5nLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnJlbW92ZUhvdmVyTGlzdGVuZXJzKCk7XG4gICAgICAgIHRoaXMuY29tcG9uZW50LmNvbnRleHQuY2FsZW5kYXIub2ZmKCdldmVudEVsUmVtb3ZlJywgdGhpcy5oYW5kbGVFdmVudEVsUmVtb3ZlKTtcbiAgICB9O1xuICAgIEV2ZW50SG92ZXJpbmcucHJvdG90eXBlLnRyaWdnZXJFdmVudCA9IGZ1bmN0aW9uIChwdWJsaWNFdk5hbWUsIGV2LCBzZWdFbCkge1xuICAgICAgICB2YXIgY29tcG9uZW50ID0gdGhpcy5jb21wb25lbnQ7XG4gICAgICAgIHZhciBfYSA9IGNvbXBvbmVudC5jb250ZXh0LCBjYWxlbmRhciA9IF9hLmNhbGVuZGFyLCB2aWV3ID0gX2EudmlldztcbiAgICAgICAgdmFyIHNlZyA9IGdldEVsU2VnKHNlZ0VsKTtcbiAgICAgICAgaWYgKCFldiB8fCBjb21wb25lbnQuaXNWYWxpZFNlZ0Rvd25FbChldi50YXJnZXQpKSB7XG4gICAgICAgICAgICBjYWxlbmRhci5wdWJsaWNseVRyaWdnZXIocHVibGljRXZOYW1lLCBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBlbDogc2VnRWwsXG4gICAgICAgICAgICAgICAgICAgIGV2ZW50OiBuZXcgRXZlbnRBcGkoY2FsZW5kYXIsIHNlZy5ldmVudFJhbmdlLmRlZiwgc2VnLmV2ZW50UmFuZ2UuaW5zdGFuY2UpLFxuICAgICAgICAgICAgICAgICAgICBqc0V2ZW50OiBldixcbiAgICAgICAgICAgICAgICAgICAgdmlldzogdmlld1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIF0pO1xuICAgICAgICB9XG4gICAgfTtcbiAgICByZXR1cm4gRXZlbnRIb3ZlcmluZztcbn0oSW50ZXJhY3Rpb24pKTtcblxudmFyIFN0YW5kYXJkVGhlbWUgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoX3N1cGVyKSB7XG4gICAgX19leHRlbmRzKFN0YW5kYXJkVGhlbWUsIF9zdXBlcik7XG4gICAgZnVuY3Rpb24gU3RhbmRhcmRUaGVtZSgpIHtcbiAgICAgICAgcmV0dXJuIF9zdXBlciAhPT0gbnVsbCAmJiBfc3VwZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKSB8fCB0aGlzO1xuICAgIH1cbiAgICByZXR1cm4gU3RhbmRhcmRUaGVtZTtcbn0oVGhlbWUpKTtcblN0YW5kYXJkVGhlbWUucHJvdG90eXBlLmNsYXNzZXMgPSB7XG4gICAgd2lkZ2V0OiAnZmMtdW50aGVtZWQnLFxuICAgIHdpZGdldEhlYWRlcjogJ2ZjLXdpZGdldC1oZWFkZXInLFxuICAgIHdpZGdldENvbnRlbnQ6ICdmYy13aWRnZXQtY29udGVudCcsXG4gICAgYnV0dG9uR3JvdXA6ICdmYy1idXR0b24tZ3JvdXAnLFxuICAgIGJ1dHRvbjogJ2ZjLWJ1dHRvbiBmYy1idXR0b24tcHJpbWFyeScsXG4gICAgYnV0dG9uQWN0aXZlOiAnZmMtYnV0dG9uLWFjdGl2ZScsXG4gICAgcG9wb3ZlckhlYWRlcjogJ2ZjLXdpZGdldC1oZWFkZXInLFxuICAgIHBvcG92ZXJDb250ZW50OiAnZmMtd2lkZ2V0LWNvbnRlbnQnLFxuICAgIC8vIGRheSBncmlkXG4gICAgaGVhZGVyUm93OiAnZmMtd2lkZ2V0LWhlYWRlcicsXG4gICAgZGF5Um93OiAnZmMtd2lkZ2V0LWNvbnRlbnQnLFxuICAgIC8vIGxpc3Qgdmlld1xuICAgIGxpc3RWaWV3OiAnZmMtd2lkZ2V0LWNvbnRlbnQnXG59O1xuU3RhbmRhcmRUaGVtZS5wcm90b3R5cGUuYmFzZUljb25DbGFzcyA9ICdmYy1pY29uJztcblN0YW5kYXJkVGhlbWUucHJvdG90eXBlLmljb25DbGFzc2VzID0ge1xuICAgIGNsb3NlOiAnZmMtaWNvbi14JyxcbiAgICBwcmV2OiAnZmMtaWNvbi1jaGV2cm9uLWxlZnQnLFxuICAgIG5leHQ6ICdmYy1pY29uLWNoZXZyb24tcmlnaHQnLFxuICAgIHByZXZZZWFyOiAnZmMtaWNvbi1jaGV2cm9ucy1sZWZ0JyxcbiAgICBuZXh0WWVhcjogJ2ZjLWljb24tY2hldnJvbnMtcmlnaHQnXG59O1xuU3RhbmRhcmRUaGVtZS5wcm90b3R5cGUuaWNvbk92ZXJyaWRlT3B0aW9uID0gJ2J1dHRvbkljb25zJztcblN0YW5kYXJkVGhlbWUucHJvdG90eXBlLmljb25PdmVycmlkZUN1c3RvbUJ1dHRvbk9wdGlvbiA9ICdpY29uJztcblN0YW5kYXJkVGhlbWUucHJvdG90eXBlLmljb25PdmVycmlkZVByZWZpeCA9ICdmYy1pY29uLSc7XG5cbnZhciBDYWxlbmRhciA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBDYWxlbmRhcihlbCwgb3ZlcnJpZGVzKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHRoaXMuYnVpbGRDb21wb25lbnRDb250ZXh0ID0gbWVtb2l6ZShidWlsZENvbXBvbmVudENvbnRleHQkMSk7XG4gICAgICAgIHRoaXMucGFyc2VSYXdMb2NhbGVzID0gbWVtb2l6ZShwYXJzZVJhd0xvY2FsZXMpO1xuICAgICAgICB0aGlzLmJ1aWxkTG9jYWxlID0gbWVtb2l6ZShidWlsZExvY2FsZSk7XG4gICAgICAgIHRoaXMuYnVpbGREYXRlRW52ID0gbWVtb2l6ZShidWlsZERhdGVFbnYpO1xuICAgICAgICB0aGlzLmJ1aWxkVGhlbWUgPSBtZW1vaXplKGJ1aWxkVGhlbWUpO1xuICAgICAgICB0aGlzLmJ1aWxkRXZlbnRVaVNpbmdsZUJhc2UgPSBtZW1vaXplKHRoaXMuX2J1aWxkRXZlbnRVaVNpbmdsZUJhc2UpO1xuICAgICAgICB0aGlzLmJ1aWxkU2VsZWN0aW9uQ29uZmlnID0gbWVtb2l6ZSh0aGlzLl9idWlsZFNlbGVjdGlvbkNvbmZpZyk7XG4gICAgICAgIHRoaXMuYnVpbGRFdmVudFVpQnlTb3VyY2UgPSBtZW1vaXplT3V0cHV0KGJ1aWxkRXZlbnRVaUJ5U291cmNlLCBpc1Byb3BzRXF1YWwpO1xuICAgICAgICB0aGlzLmJ1aWxkRXZlbnRVaUJhc2VzID0gbWVtb2l6ZShidWlsZEV2ZW50VWlCYXNlcyk7XG4gICAgICAgIHRoaXMuaW50ZXJhY3Rpb25zU3RvcmUgPSB7fTtcbiAgICAgICAgdGhpcy5hY3Rpb25RdWV1ZSA9IFtdO1xuICAgICAgICB0aGlzLmlzUmVkdWNpbmcgPSBmYWxzZTtcbiAgICAgICAgLy8gaXNEaXNwbGF5aW5nOiBib29sZWFuID0gZmFsc2UgLy8gaW5zdGFsbGVkIGluIERPTT8gYWNjZXB0aW5nIHJlbmRlcnM/XG4gICAgICAgIHRoaXMubmVlZHNSZXJlbmRlciA9IGZhbHNlOyAvLyBuZWVkcyBhIHJlbmRlcj9cbiAgICAgICAgdGhpcy5pc1JlbmRlcmluZyA9IGZhbHNlOyAvLyBjdXJyZW50bHkgaW4gdGhlIGV4ZWN1dGVSZW5kZXIgZnVuY3Rpb24/XG4gICAgICAgIHRoaXMucmVuZGVyaW5nUGF1c2VEZXB0aCA9IDA7XG4gICAgICAgIHRoaXMuYnVpbGREZWxheWVkUmVyZW5kZXIgPSBtZW1vaXplKGJ1aWxkRGVsYXllZFJlcmVuZGVyKTtcbiAgICAgICAgdGhpcy5hZnRlclNpemluZ1RyaWdnZXJzID0ge307XG4gICAgICAgIHRoaXMuaXNWaWV3VXBkYXRlZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLmlzRGF0ZXNVcGRhdGVkID0gZmFsc2U7XG4gICAgICAgIHRoaXMuaXNFdmVudHNVcGRhdGVkID0gZmFsc2U7XG4gICAgICAgIHRoaXMuZWwgPSBlbDtcbiAgICAgICAgdGhpcy5vcHRpb25zTWFuYWdlciA9IG5ldyBPcHRpb25zTWFuYWdlcihvdmVycmlkZXMgfHwge30pO1xuICAgICAgICB0aGlzLnBsdWdpblN5c3RlbSA9IG5ldyBQbHVnaW5TeXN0ZW0oKTtcbiAgICAgICAgLy8gb25seSBkbyBvbmNlLiBkb24ndCBkbyBpbiBoYW5kbGVPcHRpb25zLiBiZWNhdXNlIGNhbid0IHJlbW92ZSBwbHVnaW5zXG4gICAgICAgIHRoaXMuYWRkUGx1Z2luSW5wdXRzKHRoaXMub3B0aW9uc01hbmFnZXIuY29tcHV0ZWQucGx1Z2lucyB8fCBbXSk7XG4gICAgICAgIHRoaXMuaGFuZGxlT3B0aW9ucyh0aGlzLm9wdGlvbnNNYW5hZ2VyLmNvbXB1dGVkKTtcbiAgICAgICAgdGhpcy5wdWJsaWNseVRyaWdnZXIoJ19pbml0Jyk7IC8vIGZvciB0ZXN0c1xuICAgICAgICB0aGlzLmh5ZHJhdGUoKTtcbiAgICAgICAgdGhpcy5jYWxlbmRhckludGVyYWN0aW9ucyA9IHRoaXMucGx1Z2luU3lzdGVtLmhvb2tzLmNhbGVuZGFySW50ZXJhY3Rpb25zXG4gICAgICAgICAgICAubWFwKGZ1bmN0aW9uIChjYWxlbmRhckludGVyYWN0aW9uQ2xhc3MpIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgY2FsZW5kYXJJbnRlcmFjdGlvbkNsYXNzKF90aGlzKTtcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIENhbGVuZGFyLnByb3RvdHlwZS5hZGRQbHVnaW5JbnB1dHMgPSBmdW5jdGlvbiAocGx1Z2luSW5wdXRzKSB7XG4gICAgICAgIHZhciBwbHVnaW5EZWZzID0gcmVmaW5lUGx1Z2luRGVmcyhwbHVnaW5JbnB1dHMpO1xuICAgICAgICBmb3IgKHZhciBfaSA9IDAsIHBsdWdpbkRlZnNfMSA9IHBsdWdpbkRlZnM7IF9pIDwgcGx1Z2luRGVmc18xLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgdmFyIHBsdWdpbkRlZiA9IHBsdWdpbkRlZnNfMVtfaV07XG4gICAgICAgICAgICB0aGlzLnBsdWdpblN5c3RlbS5hZGQocGx1Z2luRGVmKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KENhbGVuZGFyLnByb3RvdHlwZSwgXCJ2aWV3XCIsIHtcbiAgICAgICAgLy8gcHVibGljIEFQSVxuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbXBvbmVudCA/IHRoaXMuY29tcG9uZW50LnZpZXcgOiBudWxsO1xuICAgICAgICB9LFxuICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICB9KTtcbiAgICAvLyBQdWJsaWMgQVBJIGZvciByZW5kZXJpbmdcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIENhbGVuZGFyLnByb3RvdHlwZS5yZW5kZXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghdGhpcy5jb21wb25lbnQpIHtcbiAgICAgICAgICAgIHRoaXMuY29tcG9uZW50ID0gbmV3IENhbGVuZGFyQ29tcG9uZW50KHRoaXMuZWwpO1xuICAgICAgICAgICAgdGhpcy5yZW5kZXJhYmxlRXZlbnRTdG9yZSA9IGNyZWF0ZUVtcHR5RXZlbnRTdG9yZSgpO1xuICAgICAgICAgICAgdGhpcy5iaW5kSGFuZGxlcnMoKTtcbiAgICAgICAgICAgIHRoaXMuZXhlY3V0ZVJlbmRlcigpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5yZXF1ZXN0UmVyZW5kZXIoKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh0aGlzLmNvbXBvbmVudCkge1xuICAgICAgICAgICAgdGhpcy51bmJpbmRIYW5kbGVycygpO1xuICAgICAgICAgICAgdGhpcy5jb21wb25lbnQuZGVzdHJveSgpOyAvLyBkb24ndCBudWxsLW91dC4gaW4gY2FzZSBBUEkgbmVlZHMgYWNjZXNzXG4gICAgICAgICAgICB0aGlzLmNvbXBvbmVudCA9IG51bGw7IC8vIHVtbSA/Pz9cbiAgICAgICAgICAgIGZvciAodmFyIF9pID0gMCwgX2EgPSB0aGlzLmNhbGVuZGFySW50ZXJhY3Rpb25zOyBfaSA8IF9hLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgICAgIHZhciBpbnRlcmFjdGlvbiA9IF9hW19pXTtcbiAgICAgICAgICAgICAgICBpbnRlcmFjdGlvbi5kZXN0cm95KCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnB1YmxpY2x5VHJpZ2dlcignX2Rlc3Ryb3llZCcpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvLyBIYW5kbGVyc1xuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLmJpbmRIYW5kbGVycyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgLy8gZXZlbnQgZGVsZWdhdGlvbiBmb3IgbmF2IGxpbmtzXG4gICAgICAgIHRoaXMucmVtb3ZlTmF2TGlua0xpc3RlbmVyID0gbGlzdGVuQnlTZWxlY3Rvcih0aGlzLmVsLCAnY2xpY2snLCAnYVtkYXRhLWdvdG9dJywgZnVuY3Rpb24gKGV2LCBhbmNob3JFbCkge1xuICAgICAgICAgICAgdmFyIGdvdG9PcHRpb25zID0gYW5jaG9yRWwuZ2V0QXR0cmlidXRlKCdkYXRhLWdvdG8nKTtcbiAgICAgICAgICAgIGdvdG9PcHRpb25zID0gZ290b09wdGlvbnMgPyBKU09OLnBhcnNlKGdvdG9PcHRpb25zKSA6IHt9O1xuICAgICAgICAgICAgdmFyIGRhdGVFbnYgPSBfdGhpcy5kYXRlRW52O1xuICAgICAgICAgICAgdmFyIGRhdGVNYXJrZXIgPSBkYXRlRW52LmNyZWF0ZU1hcmtlcihnb3RvT3B0aW9ucy5kYXRlKTtcbiAgICAgICAgICAgIHZhciB2aWV3VHlwZSA9IGdvdG9PcHRpb25zLnR5cGU7XG4gICAgICAgICAgICAvLyBwcm9wZXJ0eSBsaWtlIFwibmF2TGlua0RheUNsaWNrXCIuIG1pZ2h0IGJlIGEgc3RyaW5nIG9yIGEgZnVuY3Rpb25cbiAgICAgICAgICAgIHZhciBjdXN0b21BY3Rpb24gPSBfdGhpcy52aWV3T3B0KCduYXZMaW5rJyArIGNhcGl0YWxpc2VGaXJzdExldHRlcih2aWV3VHlwZSkgKyAnQ2xpY2snKTtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgY3VzdG9tQWN0aW9uID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgY3VzdG9tQWN0aW9uKGRhdGVFbnYudG9EYXRlKGRhdGVNYXJrZXIpLCBldik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGN1c3RvbUFjdGlvbiA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICAgICAgdmlld1R5cGUgPSBjdXN0b21BY3Rpb247XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIF90aGlzLnpvb21UbyhkYXRlTWFya2VyLCB2aWV3VHlwZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAodGhpcy5vcHQoJ2hhbmRsZVdpbmRvd1Jlc2l6ZScpKSB7XG4gICAgICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigncmVzaXplJywgdGhpcy53aW5kb3dSZXNpemVQcm94eSA9IGRlYm91bmNlKC8vIHByZXZlbnRzIHJhcGlkIGNhbGxzXG4gICAgICAgICAgICB0aGlzLndpbmRvd1Jlc2l6ZS5iaW5kKHRoaXMpLCB0aGlzLm9wdCgnd2luZG93UmVzaXplRGVsYXknKSkpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBDYWxlbmRhci5wcm90b3R5cGUudW5iaW5kSGFuZGxlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMucmVtb3ZlTmF2TGlua0xpc3RlbmVyKCk7XG4gICAgICAgIGlmICh0aGlzLndpbmRvd1Jlc2l6ZVByb3h5KSB7XG4gICAgICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcigncmVzaXplJywgdGhpcy53aW5kb3dSZXNpemVQcm94eSk7XG4gICAgICAgICAgICB0aGlzLndpbmRvd1Jlc2l6ZVByb3h5ID0gbnVsbDtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLy8gRGlzcGF0Y2hlclxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLmh5ZHJhdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHRoaXMuc3RhdGUgPSB0aGlzLmJ1aWxkSW5pdGlhbFN0YXRlKCk7XG4gICAgICAgIHZhciByYXdTb3VyY2VzID0gdGhpcy5vcHQoJ2V2ZW50U291cmNlcycpIHx8IFtdO1xuICAgICAgICB2YXIgc2luZ2xlUmF3U291cmNlID0gdGhpcy5vcHQoJ2V2ZW50cycpO1xuICAgICAgICB2YXIgc291cmNlcyA9IFtdOyAvLyBwYXJzZWRcbiAgICAgICAgaWYgKHNpbmdsZVJhd1NvdXJjZSkge1xuICAgICAgICAgICAgcmF3U291cmNlcy51bnNoaWZ0KHNpbmdsZVJhd1NvdXJjZSk7XG4gICAgICAgIH1cbiAgICAgICAgZm9yICh2YXIgX2kgPSAwLCByYXdTb3VyY2VzXzEgPSByYXdTb3VyY2VzOyBfaSA8IHJhd1NvdXJjZXNfMS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIHZhciByYXdTb3VyY2UgPSByYXdTb3VyY2VzXzFbX2ldO1xuICAgICAgICAgICAgdmFyIHNvdXJjZSA9IHBhcnNlRXZlbnRTb3VyY2UocmF3U291cmNlLCB0aGlzKTtcbiAgICAgICAgICAgIGlmIChzb3VyY2UpIHtcbiAgICAgICAgICAgICAgICBzb3VyY2VzLnB1c2goc291cmNlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLmJhdGNoUmVuZGVyaW5nKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIF90aGlzLmRpc3BhdGNoKHsgdHlwZTogJ0lOSVQnIH0pOyAvLyBwYXNzIGluIHNvdXJjZXMgaGVyZT9cbiAgICAgICAgICAgIF90aGlzLmRpc3BhdGNoKHsgdHlwZTogJ0FERF9FVkVOVF9TT1VSQ0VTJywgc291cmNlczogc291cmNlcyB9KTtcbiAgICAgICAgICAgIF90aGlzLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICB0eXBlOiAnU0VUX1ZJRVdfVFlQRScsXG4gICAgICAgICAgICAgICAgdmlld1R5cGU6IF90aGlzLm9wdCgnZGVmYXVsdFZpZXcnKSB8fCBfdGhpcy5wbHVnaW5TeXN0ZW0uaG9va3MuZGVmYXVsdFZpZXdcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5idWlsZEluaXRpYWxTdGF0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHZpZXdUeXBlOiBudWxsLFxuICAgICAgICAgICAgbG9hZGluZ0xldmVsOiAwLFxuICAgICAgICAgICAgZXZlbnRTb3VyY2VMb2FkaW5nTGV2ZWw6IDAsXG4gICAgICAgICAgICBjdXJyZW50RGF0ZTogdGhpcy5nZXRJbml0aWFsRGF0ZSgpLFxuICAgICAgICAgICAgZGF0ZVByb2ZpbGU6IG51bGwsXG4gICAgICAgICAgICBldmVudFNvdXJjZXM6IHt9LFxuICAgICAgICAgICAgZXZlbnRTdG9yZTogY3JlYXRlRW1wdHlFdmVudFN0b3JlKCksXG4gICAgICAgICAgICBkYXRlU2VsZWN0aW9uOiBudWxsLFxuICAgICAgICAgICAgZXZlbnRTZWxlY3Rpb246ICcnLFxuICAgICAgICAgICAgZXZlbnREcmFnOiBudWxsLFxuICAgICAgICAgICAgZXZlbnRSZXNpemU6IG51bGxcbiAgICAgICAgfTtcbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5kaXNwYXRjaCA9IGZ1bmN0aW9uIChhY3Rpb24pIHtcbiAgICAgICAgdGhpcy5hY3Rpb25RdWV1ZS5wdXNoKGFjdGlvbik7XG4gICAgICAgIGlmICghdGhpcy5pc1JlZHVjaW5nKSB7XG4gICAgICAgICAgICB0aGlzLmlzUmVkdWNpbmcgPSB0cnVlO1xuICAgICAgICAgICAgdmFyIG9sZFN0YXRlID0gdGhpcy5zdGF0ZTtcbiAgICAgICAgICAgIHdoaWxlICh0aGlzLmFjdGlvblF1ZXVlLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUgPSB0aGlzLnJlZHVjZSh0aGlzLnN0YXRlLCB0aGlzLmFjdGlvblF1ZXVlLnNoaWZ0KCksIHRoaXMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIG5ld1N0YXRlID0gdGhpcy5zdGF0ZTtcbiAgICAgICAgICAgIHRoaXMuaXNSZWR1Y2luZyA9IGZhbHNlO1xuICAgICAgICAgICAgaWYgKCFvbGRTdGF0ZS5sb2FkaW5nTGV2ZWwgJiYgbmV3U3RhdGUubG9hZGluZ0xldmVsKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5wdWJsaWNseVRyaWdnZXIoJ2xvYWRpbmcnLCBbdHJ1ZV0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAob2xkU3RhdGUubG9hZGluZ0xldmVsICYmICFuZXdTdGF0ZS5sb2FkaW5nTGV2ZWwpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnB1YmxpY2x5VHJpZ2dlcignbG9hZGluZycsIFtmYWxzZV0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHZpZXcgPSB0aGlzLmNvbXBvbmVudCAmJiB0aGlzLmNvbXBvbmVudC52aWV3O1xuICAgICAgICAgICAgaWYgKG9sZFN0YXRlLmV2ZW50U3RvcmUgIT09IG5ld1N0YXRlLmV2ZW50U3RvcmUpIHtcbiAgICAgICAgICAgICAgICBpZiAob2xkU3RhdGUuZXZlbnRTdG9yZSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmlzRXZlbnRzVXBkYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG9sZFN0YXRlLmRhdGVQcm9maWxlICE9PSBuZXdTdGF0ZS5kYXRlUHJvZmlsZSkge1xuICAgICAgICAgICAgICAgIGlmIChvbGRTdGF0ZS5kYXRlUHJvZmlsZSAmJiB2aWV3KSB7IC8vIHdoeSB3b3VsZCB2aWV3IGJlIG51bGwhP1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnB1YmxpY2x5VHJpZ2dlcignZGF0ZXNEZXN0cm95JywgW1xuICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZXc6IHZpZXcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWw6IHZpZXcuZWxcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMuaXNEYXRlc1VwZGF0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG9sZFN0YXRlLnZpZXdUeXBlICE9PSBuZXdTdGF0ZS52aWV3VHlwZSkge1xuICAgICAgICAgICAgICAgIGlmIChvbGRTdGF0ZS52aWV3VHlwZSAmJiB2aWV3KSB7IC8vIHdoeSB3b3VsZCB2aWV3IGJlIG51bGwhP1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnB1YmxpY2x5VHJpZ2dlcigndmlld1NrZWxldG9uRGVzdHJveScsIFtcbiAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWV3OiB2aWV3LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsOiB2aWV3LmVsXG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLmlzVmlld1VwZGF0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5yZXF1ZXN0UmVyZW5kZXIoKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLnJlZHVjZSA9IGZ1bmN0aW9uIChzdGF0ZSwgYWN0aW9uLCBjYWxlbmRhcikge1xuICAgICAgICByZXR1cm4gcmVkdWNlKHN0YXRlLCBhY3Rpb24sIGNhbGVuZGFyKTtcbiAgICB9O1xuICAgIC8vIFJlbmRlciBRdWV1ZVxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLnJlcXVlc3RSZXJlbmRlciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5uZWVkc1JlcmVuZGVyID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5kZWxheWVkUmVyZW5kZXIoKTsgLy8gd2lsbCBjYWxsIGEgZGVib3VuY2VkLXZlcnNpb24gb2YgdHJ5UmVyZW5kZXJcbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS50cnlSZXJlbmRlciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRoaXMuY29tcG9uZW50ICYmIC8vIG11c3QgYmUgYWNjZXB0aW5nIHJlbmRlcnNcbiAgICAgICAgICAgIHRoaXMubmVlZHNSZXJlbmRlciAmJiAvLyBpbmRpY2F0ZXMgdGhhdCBhIHJlcmVuZGVyIHdhcyByZXF1ZXN0ZWRcbiAgICAgICAgICAgICF0aGlzLnJlbmRlcmluZ1BhdXNlRGVwdGggJiYgLy8gbm90IHBhdXNlZFxuICAgICAgICAgICAgIXRoaXMuaXNSZW5kZXJpbmcgLy8gbm90IGN1cnJlbnRseSBpbiB0aGUgcmVuZGVyIGxvb3BcbiAgICAgICAgKSB7XG4gICAgICAgICAgICB0aGlzLmV4ZWN1dGVSZW5kZXIoKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLmJhdGNoUmVuZGVyaW5nID0gZnVuY3Rpb24gKGZ1bmMpIHtcbiAgICAgICAgdGhpcy5yZW5kZXJpbmdQYXVzZURlcHRoKys7XG4gICAgICAgIGZ1bmMoKTtcbiAgICAgICAgdGhpcy5yZW5kZXJpbmdQYXVzZURlcHRoLS07XG4gICAgICAgIGlmICh0aGlzLm5lZWRzUmVyZW5kZXIpIHtcbiAgICAgICAgICAgIHRoaXMucmVxdWVzdFJlcmVuZGVyKCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8vIFJlbmRlcmluZ1xuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLmV4ZWN1dGVSZW5kZXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIGNsZWFyIHRoZXNlIEJFRk9SRSB0aGUgcmVuZGVyIHNvIHRoYXQgbmV3IHZhbHVlcyB3aWxsIGFjY3VtdWxhdGUgZHVyaW5nIHJlbmRlclxuICAgICAgICB0aGlzLm5lZWRzUmVyZW5kZXIgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5pc1JlbmRlcmluZyA9IHRydWU7XG4gICAgICAgIHRoaXMucmVuZGVyQ29tcG9uZW50KCk7XG4gICAgICAgIHRoaXMuaXNSZW5kZXJpbmcgPSBmYWxzZTtcbiAgICAgICAgLy8gcmVjZWl2ZWQgYSByZXJlbmRlciByZXF1ZXN0IHdoaWxlIHJlbmRlcmluZ1xuICAgICAgICBpZiAodGhpcy5uZWVkc1JlcmVuZGVyKSB7XG4gICAgICAgICAgICB0aGlzLmRlbGF5ZWRSZXJlbmRlcigpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvKlxuICAgIGRvbid0IGNhbGwgdGhpcyBkaXJlY3RseS4gdXNlIGV4ZWN1dGVSZW5kZXIgaW5zdGVhZFxuICAgICovXG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLnJlbmRlckNvbXBvbmVudCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF9hID0gdGhpcywgc3RhdGUgPSBfYS5zdGF0ZSwgY29tcG9uZW50ID0gX2EuY29tcG9uZW50O1xuICAgICAgICB2YXIgdmlld1R5cGUgPSBzdGF0ZS52aWV3VHlwZTtcbiAgICAgICAgdmFyIHZpZXdTcGVjID0gdGhpcy52aWV3U3BlY3Nbdmlld1R5cGVdO1xuICAgICAgICBpZiAoIXZpZXdTcGVjKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJWaWV3IHR5cGUgXFxcIlwiICsgdmlld1R5cGUgKyBcIlxcXCIgaXMgbm90IHZhbGlkXCIpO1xuICAgICAgICB9XG4gICAgICAgIC8vIGlmIGV2ZW50IHNvdXJjZXMgYXJlIHN0aWxsIGxvYWRpbmcgYW5kIHByb2dyZXNzaXZlIHJlbmRlcmluZyBoYXNuJ3QgYmVlbiBlbmFibGVkLFxuICAgICAgICAvLyBrZWVwIHJlbmRlcmluZyB0aGUgbGFzdCBmdWxseSBsb2FkZWQgc2V0IG9mIGV2ZW50c1xuICAgICAgICB2YXIgcmVuZGVyYWJsZUV2ZW50U3RvcmUgPSB0aGlzLnJlbmRlcmFibGVFdmVudFN0b3JlID1cbiAgICAgICAgICAgIChzdGF0ZS5ldmVudFNvdXJjZUxvYWRpbmdMZXZlbCAmJiAhdGhpcy5vcHQoJ3Byb2dyZXNzaXZlRXZlbnRSZW5kZXJpbmcnKSkgP1xuICAgICAgICAgICAgICAgIHRoaXMucmVuZGVyYWJsZUV2ZW50U3RvcmUgOlxuICAgICAgICAgICAgICAgIHN0YXRlLmV2ZW50U3RvcmU7XG4gICAgICAgIHZhciBldmVudFVpU2luZ2xlQmFzZSA9IHRoaXMuYnVpbGRFdmVudFVpU2luZ2xlQmFzZSh2aWV3U3BlYy5vcHRpb25zKTtcbiAgICAgICAgdmFyIGV2ZW50VWlCeVNvdXJjZSA9IHRoaXMuYnVpbGRFdmVudFVpQnlTb3VyY2Uoc3RhdGUuZXZlbnRTb3VyY2VzKTtcbiAgICAgICAgdmFyIGV2ZW50VWlCYXNlcyA9IHRoaXMuZXZlbnRVaUJhc2VzID0gdGhpcy5idWlsZEV2ZW50VWlCYXNlcyhyZW5kZXJhYmxlRXZlbnRTdG9yZS5kZWZzLCBldmVudFVpU2luZ2xlQmFzZSwgZXZlbnRVaUJ5U291cmNlKTtcbiAgICAgICAgY29tcG9uZW50LnJlY2VpdmVQcm9wcyhfX2Fzc2lnbih7fSwgc3RhdGUsIHsgdmlld1NwZWM6IHZpZXdTcGVjLCBkYXRlUHJvZmlsZUdlbmVyYXRvcjogdGhpcy5kYXRlUHJvZmlsZUdlbmVyYXRvcnNbdmlld1R5cGVdLCBkYXRlUHJvZmlsZTogc3RhdGUuZGF0ZVByb2ZpbGUsIGV2ZW50U3RvcmU6IHJlbmRlcmFibGVFdmVudFN0b3JlLCBldmVudFVpQmFzZXM6IGV2ZW50VWlCYXNlcywgZGF0ZVNlbGVjdGlvbjogc3RhdGUuZGF0ZVNlbGVjdGlvbiwgZXZlbnRTZWxlY3Rpb246IHN0YXRlLmV2ZW50U2VsZWN0aW9uLCBldmVudERyYWc6IHN0YXRlLmV2ZW50RHJhZywgZXZlbnRSZXNpemU6IHN0YXRlLmV2ZW50UmVzaXplIH0pLCB0aGlzLmJ1aWxkQ29tcG9uZW50Q29udGV4dCh0aGlzLnRoZW1lLCB0aGlzLmRhdGVFbnYsIHRoaXMub3B0aW9uc01hbmFnZXIuY29tcHV0ZWQpKTtcbiAgICAgICAgaWYgKHRoaXMuaXNWaWV3VXBkYXRlZCkge1xuICAgICAgICAgICAgdGhpcy5pc1ZpZXdVcGRhdGVkID0gZmFsc2U7XG4gICAgICAgICAgICB0aGlzLnB1YmxpY2x5VHJpZ2dlcigndmlld1NrZWxldG9uUmVuZGVyJywgW1xuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdmlldzogY29tcG9uZW50LnZpZXcsXG4gICAgICAgICAgICAgICAgICAgIGVsOiBjb21wb25lbnQudmlldy5lbFxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIF0pO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLmlzRGF0ZXNVcGRhdGVkKSB7XG4gICAgICAgICAgICB0aGlzLmlzRGF0ZXNVcGRhdGVkID0gZmFsc2U7XG4gICAgICAgICAgICB0aGlzLnB1YmxpY2x5VHJpZ2dlcignZGF0ZXNSZW5kZXInLCBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB2aWV3OiBjb21wb25lbnQudmlldyxcbiAgICAgICAgICAgICAgICAgICAgZWw6IGNvbXBvbmVudC52aWV3LmVsXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgXSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuaXNFdmVudHNVcGRhdGVkKSB7XG4gICAgICAgICAgICB0aGlzLmlzRXZlbnRzVXBkYXRlZCA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucmVsZWFzZUFmdGVyU2l6aW5nVHJpZ2dlcnMoKTtcbiAgICB9O1xuICAgIC8vIE9wdGlvbnNcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIENhbGVuZGFyLnByb3RvdHlwZS5zZXRPcHRpb24gPSBmdW5jdGlvbiAobmFtZSwgdmFsKSB7XG4gICAgICAgIHZhciBfYTtcbiAgICAgICAgdGhpcy5tdXRhdGVPcHRpb25zKChfYSA9IHt9LCBfYVtuYW1lXSA9IHZhbCwgX2EpLCBbXSwgdHJ1ZSk7XG4gICAgfTtcbiAgICBDYWxlbmRhci5wcm90b3R5cGUuZ2V0T3B0aW9uID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3B0aW9uc01hbmFnZXIuY29tcHV0ZWRbbmFtZV07XG4gICAgfTtcbiAgICBDYWxlbmRhci5wcm90b3R5cGUub3B0ID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3B0aW9uc01hbmFnZXIuY29tcHV0ZWRbbmFtZV07XG4gICAgfTtcbiAgICBDYWxlbmRhci5wcm90b3R5cGUudmlld09wdCA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnZpZXdPcHRzKClbbmFtZV07XG4gICAgfTtcbiAgICBDYWxlbmRhci5wcm90b3R5cGUudmlld09wdHMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnZpZXdTcGVjc1t0aGlzLnN0YXRlLnZpZXdUeXBlXS5vcHRpb25zO1xuICAgIH07XG4gICAgLypcbiAgICBoYW5kbGVzIG9wdGlvbiBjaGFuZ2VzIChsaWtlIGEgZGlmZilcbiAgICAqL1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5tdXRhdGVPcHRpb25zID0gZnVuY3Rpb24gKHVwZGF0ZXMsIHJlbW92YWxzLCBpc0R5bmFtaWMsIGRlZXBFcXVhbCkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgY2hhbmdlSGFuZGxlcnMgPSB0aGlzLnBsdWdpblN5c3RlbS5ob29rcy5vcHRpb25DaGFuZ2VIYW5kbGVycztcbiAgICAgICAgdmFyIG5vcm1hbFVwZGF0ZXMgPSB7fTtcbiAgICAgICAgdmFyIHNwZWNpYWxVcGRhdGVzID0ge307XG4gICAgICAgIHZhciBvbGREYXRlRW52ID0gdGhpcy5kYXRlRW52OyAvLyBkbyB0aGlzIGJlZm9yZSBoYW5kbGVPcHRpb25zXG4gICAgICAgIHZhciBpc1RpbWVab25lRGlydHkgPSBmYWxzZTtcbiAgICAgICAgdmFyIGlzU2l6ZURpcnR5ID0gZmFsc2U7XG4gICAgICAgIHZhciBhbnlEaWZmaWN1bHRPcHRpb25zID0gQm9vbGVhbihyZW1vdmFscy5sZW5ndGgpO1xuICAgICAgICBmb3IgKHZhciBuYW1lXzEgaW4gdXBkYXRlcykge1xuICAgICAgICAgICAgaWYgKGNoYW5nZUhhbmRsZXJzW25hbWVfMV0pIHtcbiAgICAgICAgICAgICAgICBzcGVjaWFsVXBkYXRlc1tuYW1lXzFdID0gdXBkYXRlc1tuYW1lXzFdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgbm9ybWFsVXBkYXRlc1tuYW1lXzFdID0gdXBkYXRlc1tuYW1lXzFdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGZvciAodmFyIG5hbWVfMiBpbiBub3JtYWxVcGRhdGVzKSB7XG4gICAgICAgICAgICBpZiAoL14oaGVpZ2h0fGNvbnRlbnRIZWlnaHR8YXNwZWN0UmF0aW8pJC8udGVzdChuYW1lXzIpKSB7XG4gICAgICAgICAgICAgICAgaXNTaXplRGlydHkgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoL14oZGVmYXVsdERhdGV8ZGVmYXVsdFZpZXcpJC8udGVzdChuYW1lXzIpKSA7XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBhbnlEaWZmaWN1bHRPcHRpb25zID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBpZiAobmFtZV8yID09PSAndGltZVpvbmUnKSB7XG4gICAgICAgICAgICAgICAgICAgIGlzVGltZVpvbmVEaXJ0eSA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRoaXMub3B0aW9uc01hbmFnZXIubXV0YXRlKG5vcm1hbFVwZGF0ZXMsIHJlbW92YWxzLCBpc0R5bmFtaWMpO1xuICAgICAgICBpZiAoYW55RGlmZmljdWx0T3B0aW9ucykge1xuICAgICAgICAgICAgdGhpcy5oYW5kbGVPcHRpb25zKHRoaXMub3B0aW9uc01hbmFnZXIuY29tcHV0ZWQpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuYmF0Y2hSZW5kZXJpbmcoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKGFueURpZmZpY3VsdE9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICBpZiAoaXNUaW1lWm9uZURpcnR5KSB7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdDSEFOR0VfVElNRVpPTkUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgb2xkRGF0ZUVudjogb2xkRGF0ZUVudlxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLyogSEFDS1xuICAgICAgICAgICAgICAgIGhhcyB0aGUgc2FtZSBlZmZlY3QgYXMgY2FsbGluZyB0aGlzLnJlcXVlc3RSZXJlbmRlcigpXG4gICAgICAgICAgICAgICAgYnV0IHJlY29tcHV0ZXMgdGhlIHN0YXRlJ3MgZGF0ZVByb2ZpbGVcbiAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIF90aGlzLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogJ1NFVF9WSUVXX1RZUEUnLFxuICAgICAgICAgICAgICAgICAgICB2aWV3VHlwZTogX3RoaXMuc3RhdGUudmlld1R5cGVcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKGlzU2l6ZURpcnR5KSB7XG4gICAgICAgICAgICAgICAgX3RoaXMudXBkYXRlU2l6ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gc3BlY2lhbCB1cGRhdGVzXG4gICAgICAgICAgICBpZiAoZGVlcEVxdWFsKSB7XG4gICAgICAgICAgICAgICAgZm9yICh2YXIgbmFtZV8zIGluIHNwZWNpYWxVcGRhdGVzKSB7XG4gICAgICAgICAgICAgICAgICAgIGNoYW5nZUhhbmRsZXJzW25hbWVfM10oc3BlY2lhbFVwZGF0ZXNbbmFtZV8zXSwgX3RoaXMsIGRlZXBFcXVhbCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9O1xuICAgIC8qXG4gICAgcmVidWlsZHMgdGhpbmdzIGJhc2VkIG9mZiBvZiBhIGNvbXBsZXRlIHNldCBvZiByZWZpbmVkIG9wdGlvbnNcbiAgICAqL1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5oYW5kbGVPcHRpb25zID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIHBsdWdpbkhvb2tzID0gdGhpcy5wbHVnaW5TeXN0ZW0uaG9va3M7XG4gICAgICAgIHRoaXMuZGVmYXVsdEFsbERheUV2ZW50RHVyYXRpb24gPSBjcmVhdGVEdXJhdGlvbihvcHRpb25zLmRlZmF1bHRBbGxEYXlFdmVudER1cmF0aW9uKTtcbiAgICAgICAgdGhpcy5kZWZhdWx0VGltZWRFdmVudER1cmF0aW9uID0gY3JlYXRlRHVyYXRpb24ob3B0aW9ucy5kZWZhdWx0VGltZWRFdmVudER1cmF0aW9uKTtcbiAgICAgICAgdGhpcy5kZWxheWVkUmVyZW5kZXIgPSB0aGlzLmJ1aWxkRGVsYXllZFJlcmVuZGVyKG9wdGlvbnMucmVyZW5kZXJEZWxheSk7XG4gICAgICAgIHRoaXMudGhlbWUgPSB0aGlzLmJ1aWxkVGhlbWUob3B0aW9ucyk7XG4gICAgICAgIHZhciBhdmFpbGFibGUgPSB0aGlzLnBhcnNlUmF3TG9jYWxlcyhvcHRpb25zLmxvY2FsZXMpO1xuICAgICAgICB0aGlzLmF2YWlsYWJsZVJhd0xvY2FsZXMgPSBhdmFpbGFibGUubWFwO1xuICAgICAgICB2YXIgbG9jYWxlID0gdGhpcy5idWlsZExvY2FsZShvcHRpb25zLmxvY2FsZSB8fCBhdmFpbGFibGUuZGVmYXVsdENvZGUsIGF2YWlsYWJsZS5tYXApO1xuICAgICAgICB0aGlzLmRhdGVFbnYgPSB0aGlzLmJ1aWxkRGF0ZUVudihsb2NhbGUsIG9wdGlvbnMudGltZVpvbmUsIHBsdWdpbkhvb2tzLm5hbWVkVGltZVpvbmVkSW1wbCwgb3B0aW9ucy5maXJzdERheSwgb3B0aW9ucy53ZWVrTnVtYmVyQ2FsY3VsYXRpb24sIG9wdGlvbnMud2Vla0xhYmVsLCBwbHVnaW5Ib29rcy5jbWRGb3JtYXR0ZXIpO1xuICAgICAgICB0aGlzLnNlbGVjdGlvbkNvbmZpZyA9IHRoaXMuYnVpbGRTZWxlY3Rpb25Db25maWcob3B0aW9ucyk7IC8vIG5lZWRzIGRhdGVFbnYuIGRvIGFmdGVyIDooXG4gICAgICAgIC8vIGluZWZmZWNpZW50IHRvIGRvIGV2ZXJ5IHRpbWU/XG4gICAgICAgIHRoaXMudmlld1NwZWNzID0gYnVpbGRWaWV3U3BlY3MocGx1Z2luSG9va3Mudmlld3MsIHRoaXMub3B0aW9uc01hbmFnZXIpO1xuICAgICAgICAvLyBpbmVmZmVjaWVudCB0byBkbyBldmVyeSB0aW1lP1xuICAgICAgICB0aGlzLmRhdGVQcm9maWxlR2VuZXJhdG9ycyA9IG1hcEhhc2godGhpcy52aWV3U3BlY3MsIGZ1bmN0aW9uICh2aWV3U3BlYykge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyB2aWV3U3BlYy5jbGFzcy5wcm90b3R5cGUuZGF0ZVByb2ZpbGVHZW5lcmF0b3JDbGFzcyh2aWV3U3BlYywgX3RoaXMpO1xuICAgICAgICB9KTtcbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5nZXRBdmFpbGFibGVMb2NhbGVDb2RlcyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIE9iamVjdC5rZXlzKHRoaXMuYXZhaWxhYmxlUmF3TG9jYWxlcyk7XG4gICAgfTtcbiAgICBDYWxlbmRhci5wcm90b3R5cGUuX2J1aWxkU2VsZWN0aW9uQ29uZmlnID0gZnVuY3Rpb24gKHJhd09wdHMpIHtcbiAgICAgICAgcmV0dXJuIHByb2Nlc3NTY29wZWRVaVByb3BzKCdzZWxlY3QnLCByYXdPcHRzLCB0aGlzKTtcbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5fYnVpbGRFdmVudFVpU2luZ2xlQmFzZSA9IGZ1bmN0aW9uIChyYXdPcHRzKSB7XG4gICAgICAgIGlmIChyYXdPcHRzLmVkaXRhYmxlKSB7IC8vIHNvICdlZGl0YWJsZScgYWZmZWN0ZWQgZXZlbnRzXG4gICAgICAgICAgICByYXdPcHRzID0gX19hc3NpZ24oe30sIHJhd09wdHMsIHsgZXZlbnRFZGl0YWJsZTogdHJ1ZSB9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcHJvY2Vzc1Njb3BlZFVpUHJvcHMoJ2V2ZW50JywgcmF3T3B0cywgdGhpcyk7XG4gICAgfTtcbiAgICAvLyBUcmlnZ2VyXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBDYWxlbmRhci5wcm90b3R5cGUuaGFzUHVibGljSGFuZGxlcnMgPSBmdW5jdGlvbiAobmFtZSkge1xuICAgICAgICByZXR1cm4gdGhpcy5oYXNIYW5kbGVycyhuYW1lKSB8fFxuICAgICAgICAgICAgdGhpcy5vcHQobmFtZSk7IC8vIGhhbmRsZXIgc3BlY2lmaWVkIGluIG9wdGlvbnNcbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5wdWJsaWNseVRyaWdnZXIgPSBmdW5jdGlvbiAobmFtZSwgYXJncykge1xuICAgICAgICB2YXIgb3B0SGFuZGxlciA9IHRoaXMub3B0KG5hbWUpO1xuICAgICAgICB0aGlzLnRyaWdnZXJXaXRoKG5hbWUsIHRoaXMsIGFyZ3MpO1xuICAgICAgICBpZiAob3B0SGFuZGxlcikge1xuICAgICAgICAgICAgcmV0dXJuIG9wdEhhbmRsZXIuYXBwbHkodGhpcywgYXJncyk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5wdWJsaWNseVRyaWdnZXJBZnRlclNpemluZyA9IGZ1bmN0aW9uIChuYW1lLCBhcmdzKSB7XG4gICAgICAgIHZhciBhZnRlclNpemluZ1RyaWdnZXJzID0gdGhpcy5hZnRlclNpemluZ1RyaWdnZXJzO1xuICAgICAgICAoYWZ0ZXJTaXppbmdUcmlnZ2Vyc1tuYW1lXSB8fCAoYWZ0ZXJTaXppbmdUcmlnZ2Vyc1tuYW1lXSA9IFtdKSkucHVzaChhcmdzKTtcbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5yZWxlYXNlQWZ0ZXJTaXppbmdUcmlnZ2VycyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGFmdGVyU2l6aW5nVHJpZ2dlcnMgPSB0aGlzLmFmdGVyU2l6aW5nVHJpZ2dlcnM7XG4gICAgICAgIGZvciAodmFyIG5hbWVfNCBpbiBhZnRlclNpemluZ1RyaWdnZXJzKSB7XG4gICAgICAgICAgICBmb3IgKHZhciBfaSA9IDAsIF9hID0gYWZ0ZXJTaXppbmdUcmlnZ2Vyc1tuYW1lXzRdOyBfaSA8IF9hLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgICAgIHZhciBhcmdzID0gX2FbX2ldO1xuICAgICAgICAgICAgICAgIHRoaXMucHVibGljbHlUcmlnZ2VyKG5hbWVfNCwgYXJncyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5hZnRlclNpemluZ1RyaWdnZXJzID0ge307XG4gICAgfTtcbiAgICAvLyBWaWV3XG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAvLyBSZXR1cm5zIGEgYm9vbGVhbiBhYm91dCB3aGV0aGVyIHRoZSB2aWV3IGlzIG9rYXkgdG8gaW5zdGFudGlhdGUgYXQgc29tZSBwb2ludFxuICAgIENhbGVuZGFyLnByb3RvdHlwZS5pc1ZhbGlkVmlld1R5cGUgPSBmdW5jdGlvbiAodmlld1R5cGUpIHtcbiAgICAgICAgcmV0dXJuIEJvb2xlYW4odGhpcy52aWV3U3BlY3Nbdmlld1R5cGVdKTtcbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5jaGFuZ2VWaWV3ID0gZnVuY3Rpb24gKHZpZXdUeXBlLCBkYXRlT3JSYW5nZSkge1xuICAgICAgICB2YXIgZGF0ZU1hcmtlciA9IG51bGw7XG4gICAgICAgIGlmIChkYXRlT3JSYW5nZSkge1xuICAgICAgICAgICAgaWYgKGRhdGVPclJhbmdlLnN0YXJ0ICYmIGRhdGVPclJhbmdlLmVuZCkgeyAvLyBhIHJhbmdlXG4gICAgICAgICAgICAgICAgdGhpcy5vcHRpb25zTWFuYWdlci5tdXRhdGUoeyB2aXNpYmxlUmFuZ2U6IGRhdGVPclJhbmdlIH0sIFtdKTsgLy8gd2lsbCBub3QgcmVyZW5kZXJcbiAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZU9wdGlvbnModGhpcy5vcHRpb25zTWFuYWdlci5jb21wdXRlZCk7IC8vIC4uLmJ1dCB5dWNrXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHsgLy8gYSBkYXRlXG4gICAgICAgICAgICAgICAgZGF0ZU1hcmtlciA9IHRoaXMuZGF0ZUVudi5jcmVhdGVNYXJrZXIoZGF0ZU9yUmFuZ2UpOyAvLyBqdXN0IGxpa2UgZ290b0RhdGVcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLnVuc2VsZWN0KCk7XG4gICAgICAgIHRoaXMuZGlzcGF0Y2goe1xuICAgICAgICAgICAgdHlwZTogJ1NFVF9WSUVXX1RZUEUnLFxuICAgICAgICAgICAgdmlld1R5cGU6IHZpZXdUeXBlLFxuICAgICAgICAgICAgZGF0ZU1hcmtlcjogZGF0ZU1hcmtlclxuICAgICAgICB9KTtcbiAgICB9O1xuICAgIC8vIEZvcmNlcyBuYXZpZ2F0aW9uIHRvIGEgdmlldyBmb3IgdGhlIGdpdmVuIGRhdGUuXG4gICAgLy8gYHZpZXdUeXBlYCBjYW4gYmUgYSBzcGVjaWZpYyB2aWV3IG5hbWUgb3IgYSBnZW5lcmljIG9uZSBsaWtlIFwid2Vla1wiIG9yIFwiZGF5XCIuXG4gICAgLy8gbmVlZHMgdG8gY2hhbmdlXG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLnpvb21UbyA9IGZ1bmN0aW9uIChkYXRlTWFya2VyLCB2aWV3VHlwZSkge1xuICAgICAgICB2YXIgc3BlYztcbiAgICAgICAgdmlld1R5cGUgPSB2aWV3VHlwZSB8fCAnZGF5JzsgLy8gZGF5IGlzIGRlZmF1bHQgem9vbVxuICAgICAgICBzcGVjID0gdGhpcy52aWV3U3BlY3Nbdmlld1R5cGVdIHx8XG4gICAgICAgICAgICB0aGlzLmdldFVuaXRWaWV3U3BlYyh2aWV3VHlwZSk7XG4gICAgICAgIHRoaXMudW5zZWxlY3QoKTtcbiAgICAgICAgaWYgKHNwZWMpIHtcbiAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgIHR5cGU6ICdTRVRfVklFV19UWVBFJyxcbiAgICAgICAgICAgICAgICB2aWV3VHlwZTogc3BlYy50eXBlLFxuICAgICAgICAgICAgICAgIGRhdGVNYXJrZXI6IGRhdGVNYXJrZXJcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgdHlwZTogJ1NFVF9EQVRFJyxcbiAgICAgICAgICAgICAgICBkYXRlTWFya2VyOiBkYXRlTWFya2VyXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLy8gR2l2ZW4gYSBkdXJhdGlvbiBzaW5ndWxhciB1bml0LCBsaWtlIFwid2Vla1wiIG9yIFwiZGF5XCIsIGZpbmRzIGEgbWF0Y2hpbmcgdmlldyBzcGVjLlxuICAgIC8vIFByZWZlcmVuY2UgaXMgZ2l2ZW4gdG8gdmlld3MgdGhhdCBoYXZlIGNvcnJlc3BvbmRpbmcgYnV0dG9ucy5cbiAgICBDYWxlbmRhci5wcm90b3R5cGUuZ2V0VW5pdFZpZXdTcGVjID0gZnVuY3Rpb24gKHVuaXQpIHtcbiAgICAgICAgdmFyIGNvbXBvbmVudCA9IHRoaXMuY29tcG9uZW50O1xuICAgICAgICB2YXIgdmlld1R5cGVzID0gW107XG4gICAgICAgIHZhciBpO1xuICAgICAgICB2YXIgc3BlYztcbiAgICAgICAgLy8gcHV0IHZpZXdzIHRoYXQgaGF2ZSBidXR0b25zIGZpcnN0LiB0aGVyZSB3aWxsIGJlIGR1cGxpY2F0ZXMsIGJ1dCBvaFxuICAgICAgICBpZiAoY29tcG9uZW50LmhlYWRlcikge1xuICAgICAgICAgICAgdmlld1R5cGVzLnB1c2guYXBwbHkodmlld1R5cGVzLCBjb21wb25lbnQuaGVhZGVyLnZpZXdzV2l0aEJ1dHRvbnMpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjb21wb25lbnQuZm9vdGVyKSB7XG4gICAgICAgICAgICB2aWV3VHlwZXMucHVzaC5hcHBseSh2aWV3VHlwZXMsIGNvbXBvbmVudC5mb290ZXIudmlld3NXaXRoQnV0dG9ucyk7XG4gICAgICAgIH1cbiAgICAgICAgZm9yICh2YXIgdmlld1R5cGUgaW4gdGhpcy52aWV3U3BlY3MpIHtcbiAgICAgICAgICAgIHZpZXdUeXBlcy5wdXNoKHZpZXdUeXBlKTtcbiAgICAgICAgfVxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgdmlld1R5cGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBzcGVjID0gdGhpcy52aWV3U3BlY3Nbdmlld1R5cGVzW2ldXTtcbiAgICAgICAgICAgIGlmIChzcGVjKSB7XG4gICAgICAgICAgICAgICAgaWYgKHNwZWMuc2luZ2xlVW5pdCA9PT0gdW5pdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gc3BlYztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8vIEN1cnJlbnQgRGF0ZVxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLmdldEluaXRpYWxEYXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgZGVmYXVsdERhdGVJbnB1dCA9IHRoaXMub3B0KCdkZWZhdWx0RGF0ZScpO1xuICAgICAgICAvLyBjb21wdXRlIHRoZSBpbml0aWFsIGFtYmlnLXRpbWV6b25lIGRhdGVcbiAgICAgICAgaWYgKGRlZmF1bHREYXRlSW5wdXQgIT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZGF0ZUVudi5jcmVhdGVNYXJrZXIoZGVmYXVsdERhdGVJbnB1dCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5nZXROb3coKTsgLy8gZ2V0Tm93IGFscmVhZHkgcmV0dXJucyB1bnpvbmVkXG4gICAgICAgIH1cbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5wcmV2ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnVuc2VsZWN0KCk7XG4gICAgICAgIHRoaXMuZGlzcGF0Y2goeyB0eXBlOiAnUFJFVicgfSk7XG4gICAgfTtcbiAgICBDYWxlbmRhci5wcm90b3R5cGUubmV4dCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy51bnNlbGVjdCgpO1xuICAgICAgICB0aGlzLmRpc3BhdGNoKHsgdHlwZTogJ05FWFQnIH0pO1xuICAgIH07XG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLnByZXZZZWFyID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnVuc2VsZWN0KCk7XG4gICAgICAgIHRoaXMuZGlzcGF0Y2goe1xuICAgICAgICAgICAgdHlwZTogJ1NFVF9EQVRFJyxcbiAgICAgICAgICAgIGRhdGVNYXJrZXI6IHRoaXMuZGF0ZUVudi5hZGRZZWFycyh0aGlzLnN0YXRlLmN1cnJlbnREYXRlLCAtMSlcbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICBDYWxlbmRhci5wcm90b3R5cGUubmV4dFllYXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMudW5zZWxlY3QoKTtcbiAgICAgICAgdGhpcy5kaXNwYXRjaCh7XG4gICAgICAgICAgICB0eXBlOiAnU0VUX0RBVEUnLFxuICAgICAgICAgICAgZGF0ZU1hcmtlcjogdGhpcy5kYXRlRW52LmFkZFllYXJzKHRoaXMuc3RhdGUuY3VycmVudERhdGUsIDEpXG4gICAgICAgIH0pO1xuICAgIH07XG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLnRvZGF5ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnVuc2VsZWN0KCk7XG4gICAgICAgIHRoaXMuZGlzcGF0Y2goe1xuICAgICAgICAgICAgdHlwZTogJ1NFVF9EQVRFJyxcbiAgICAgICAgICAgIGRhdGVNYXJrZXI6IHRoaXMuZ2V0Tm93KClcbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICBDYWxlbmRhci5wcm90b3R5cGUuZ290b0RhdGUgPSBmdW5jdGlvbiAoem9uZWREYXRlSW5wdXQpIHtcbiAgICAgICAgdGhpcy51bnNlbGVjdCgpO1xuICAgICAgICB0aGlzLmRpc3BhdGNoKHtcbiAgICAgICAgICAgIHR5cGU6ICdTRVRfREFURScsXG4gICAgICAgICAgICBkYXRlTWFya2VyOiB0aGlzLmRhdGVFbnYuY3JlYXRlTWFya2VyKHpvbmVkRGF0ZUlucHV0KVxuICAgICAgICB9KTtcbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5pbmNyZW1lbnREYXRlID0gZnVuY3Rpb24gKGRlbHRhSW5wdXQpIHtcbiAgICAgICAgdmFyIGRlbHRhID0gY3JlYXRlRHVyYXRpb24oZGVsdGFJbnB1dCk7XG4gICAgICAgIGlmIChkZWx0YSkgeyAvLyBlbHNlLCB3YXJuIGFib3V0IGludmFsaWQgaW5wdXQ/XG4gICAgICAgICAgICB0aGlzLnVuc2VsZWN0KCk7XG4gICAgICAgICAgICB0aGlzLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICB0eXBlOiAnU0VUX0RBVEUnLFxuICAgICAgICAgICAgICAgIGRhdGVNYXJrZXI6IHRoaXMuZGF0ZUVudi5hZGQodGhpcy5zdGF0ZS5jdXJyZW50RGF0ZSwgZGVsdGEpXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLy8gZm9yIGV4dGVybmFsIEFQSVxuICAgIENhbGVuZGFyLnByb3RvdHlwZS5nZXREYXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5kYXRlRW52LnRvRGF0ZSh0aGlzLnN0YXRlLmN1cnJlbnREYXRlKTtcbiAgICB9O1xuICAgIC8vIERhdGUgRm9ybWF0dGluZyBVdGlsc1xuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLmZvcm1hdERhdGUgPSBmdW5jdGlvbiAoZCwgZm9ybWF0dGVyKSB7XG4gICAgICAgIHZhciBkYXRlRW52ID0gdGhpcy5kYXRlRW52O1xuICAgICAgICByZXR1cm4gZGF0ZUVudi5mb3JtYXQoZGF0ZUVudi5jcmVhdGVNYXJrZXIoZCksIGNyZWF0ZUZvcm1hdHRlcihmb3JtYXR0ZXIpKTtcbiAgICB9O1xuICAgIC8vIGBzZXR0aW5nc2AgaXMgZm9yIGZvcm1hdHRlciBBTkQgaXNFbmRFeGNsdXNpdmVcbiAgICBDYWxlbmRhci5wcm90b3R5cGUuZm9ybWF0UmFuZ2UgPSBmdW5jdGlvbiAoZDAsIGQxLCBzZXR0aW5ncykge1xuICAgICAgICB2YXIgZGF0ZUVudiA9IHRoaXMuZGF0ZUVudjtcbiAgICAgICAgcmV0dXJuIGRhdGVFbnYuZm9ybWF0UmFuZ2UoZGF0ZUVudi5jcmVhdGVNYXJrZXIoZDApLCBkYXRlRW52LmNyZWF0ZU1hcmtlcihkMSksIGNyZWF0ZUZvcm1hdHRlcihzZXR0aW5ncywgdGhpcy5vcHQoJ2RlZmF1bHRSYW5nZVNlcGFyYXRvcicpKSwgc2V0dGluZ3MpO1xuICAgIH07XG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLmZvcm1hdElzbyA9IGZ1bmN0aW9uIChkLCBvbWl0VGltZSkge1xuICAgICAgICB2YXIgZGF0ZUVudiA9IHRoaXMuZGF0ZUVudjtcbiAgICAgICAgcmV0dXJuIGRhdGVFbnYuZm9ybWF0SXNvKGRhdGVFbnYuY3JlYXRlTWFya2VyKGQpLCB7IG9taXRUaW1lOiBvbWl0VGltZSB9KTtcbiAgICB9O1xuICAgIC8vIFNpemluZ1xuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLndpbmRvd1Jlc2l6ZSA9IGZ1bmN0aW9uIChldikge1xuICAgICAgICBpZiAoIXRoaXMuaXNIYW5kbGluZ1dpbmRvd1Jlc2l6ZSAmJlxuICAgICAgICAgICAgdGhpcy5jb21wb25lbnQgJiYgLy8gd2h5P1xuICAgICAgICAgICAgZXYudGFyZ2V0ID09PSB3aW5kb3cgLy8gbm90IGEganF1aSByZXNpemUgZXZlbnRcbiAgICAgICAgKSB7XG4gICAgICAgICAgICB0aGlzLmlzSGFuZGxpbmdXaW5kb3dSZXNpemUgPSB0cnVlO1xuICAgICAgICAgICAgdGhpcy51cGRhdGVTaXplKCk7XG4gICAgICAgICAgICB0aGlzLnB1YmxpY2x5VHJpZ2dlcignd2luZG93UmVzaXplJywgW3RoaXMudmlld10pO1xuICAgICAgICAgICAgdGhpcy5pc0hhbmRsaW5nV2luZG93UmVzaXplID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS51cGRhdGVTaXplID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGhpcy5jb21wb25lbnQpIHsgLy8gd2hlbj9cbiAgICAgICAgICAgIHRoaXMuY29tcG9uZW50LnVwZGF0ZVNpemUodHJ1ZSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8vIENvbXBvbmVudCBSZWdpc3RyYXRpb25cbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIENhbGVuZGFyLnByb3RvdHlwZS5yZWdpc3RlckludGVyYWN0aXZlQ29tcG9uZW50ID0gZnVuY3Rpb24gKGNvbXBvbmVudCwgc2V0dGluZ3NJbnB1dCkge1xuICAgICAgICB2YXIgc2V0dGluZ3MgPSBwYXJzZUludGVyYWN0aW9uU2V0dGluZ3MoY29tcG9uZW50LCBzZXR0aW5nc0lucHV0KTtcbiAgICAgICAgdmFyIERFRkFVTFRfSU5URVJBQ1RJT05TID0gW1xuICAgICAgICAgICAgRXZlbnRDbGlja2luZyxcbiAgICAgICAgICAgIEV2ZW50SG92ZXJpbmdcbiAgICAgICAgXTtcbiAgICAgICAgdmFyIGludGVyYWN0aW9uQ2xhc3NlcyA9IERFRkFVTFRfSU5URVJBQ1RJT05TLmNvbmNhdCh0aGlzLnBsdWdpblN5c3RlbS5ob29rcy5jb21wb25lbnRJbnRlcmFjdGlvbnMpO1xuICAgICAgICB2YXIgaW50ZXJhY3Rpb25zID0gaW50ZXJhY3Rpb25DbGFzc2VzLm1hcChmdW5jdGlvbiAoaW50ZXJhY3Rpb25DbGFzcykge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBpbnRlcmFjdGlvbkNsYXNzKHNldHRpbmdzKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuaW50ZXJhY3Rpb25zU3RvcmVbY29tcG9uZW50LnVpZF0gPSBpbnRlcmFjdGlvbnM7XG4gICAgICAgIGludGVyYWN0aW9uU2V0dGluZ3NTdG9yZVtjb21wb25lbnQudWlkXSA9IHNldHRpbmdzO1xuICAgIH07XG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLnVucmVnaXN0ZXJJbnRlcmFjdGl2ZUNvbXBvbmVudCA9IGZ1bmN0aW9uIChjb21wb25lbnQpIHtcbiAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBfYSA9IHRoaXMuaW50ZXJhY3Rpb25zU3RvcmVbY29tcG9uZW50LnVpZF07IF9pIDwgX2EubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICB2YXIgbGlzdGVuZXIgPSBfYVtfaV07XG4gICAgICAgICAgICBsaXN0ZW5lci5kZXN0cm95KCk7XG4gICAgICAgIH1cbiAgICAgICAgZGVsZXRlIHRoaXMuaW50ZXJhY3Rpb25zU3RvcmVbY29tcG9uZW50LnVpZF07XG4gICAgICAgIGRlbGV0ZSBpbnRlcmFjdGlvblNldHRpbmdzU3RvcmVbY29tcG9uZW50LnVpZF07XG4gICAgfTtcbiAgICAvLyBEYXRlIFNlbGVjdGlvbiAvIEV2ZW50IFNlbGVjdGlvbiAvIERheUNsaWNrXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAvLyB0aGlzIHB1YmxpYyBtZXRob2QgcmVjZWl2ZXMgc3RhcnQvZW5kIGRhdGVzIGluIGFueSBmb3JtYXQsIHdpdGggYW55IHRpbWV6b25lXG4gICAgLy8gTk9URTogYXJncyB3ZXJlIGNoYW5nZWQgZnJvbSB2M1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5zZWxlY3QgPSBmdW5jdGlvbiAoZGF0ZU9yT2JqLCBlbmREYXRlKSB7XG4gICAgICAgIHZhciBzZWxlY3Rpb25JbnB1dDtcbiAgICAgICAgaWYgKGVuZERhdGUgPT0gbnVsbCkge1xuICAgICAgICAgICAgaWYgKGRhdGVPck9iai5zdGFydCAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgc2VsZWN0aW9uSW5wdXQgPSBkYXRlT3JPYmo7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBzZWxlY3Rpb25JbnB1dCA9IHtcbiAgICAgICAgICAgICAgICAgICAgc3RhcnQ6IGRhdGVPck9iaixcbiAgICAgICAgICAgICAgICAgICAgZW5kOiBudWxsXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHNlbGVjdGlvbklucHV0ID0ge1xuICAgICAgICAgICAgICAgIHN0YXJ0OiBkYXRlT3JPYmosXG4gICAgICAgICAgICAgICAgZW5kOiBlbmREYXRlXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHZhciBzZWxlY3Rpb24gPSBwYXJzZURhdGVTcGFuKHNlbGVjdGlvbklucHV0LCB0aGlzLmRhdGVFbnYsIGNyZWF0ZUR1cmF0aW9uKHsgZGF5czogMSB9KSAvLyBUT0RPOiBjYWNoZSB0aGlzP1xuICAgICAgICApO1xuICAgICAgICBpZiAoc2VsZWN0aW9uKSB7IC8vIHRocm93IHBhcnNlIGVycm9yIG90aGVyd2lzZT9cbiAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2goeyB0eXBlOiAnU0VMRUNUX0RBVEVTJywgc2VsZWN0aW9uOiBzZWxlY3Rpb24gfSk7XG4gICAgICAgICAgICB0aGlzLnRyaWdnZXJEYXRlU2VsZWN0KHNlbGVjdGlvbik7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8vIHB1YmxpYyBtZXRob2RcbiAgICBDYWxlbmRhci5wcm90b3R5cGUudW5zZWxlY3QgPSBmdW5jdGlvbiAocGV2KSB7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmRhdGVTZWxlY3Rpb24pIHtcbiAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2goeyB0eXBlOiAnVU5TRUxFQ1RfREFURVMnIH0pO1xuICAgICAgICAgICAgdGhpcy50cmlnZ2VyRGF0ZVVuc2VsZWN0KHBldik7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS50cmlnZ2VyRGF0ZVNlbGVjdCA9IGZ1bmN0aW9uIChzZWxlY3Rpb24sIHBldikge1xuICAgICAgICB2YXIgYXJnID0gX19hc3NpZ24oe30sIHRoaXMuYnVpbGREYXRlU3BhbkFwaShzZWxlY3Rpb24pLCB7IGpzRXZlbnQ6IHBldiA/IHBldi5vcmlnRXZlbnQgOiBudWxsLCB2aWV3OiB0aGlzLnZpZXcgfSk7XG4gICAgICAgIHRoaXMucHVibGljbHlUcmlnZ2VyKCdzZWxlY3QnLCBbYXJnXSk7XG4gICAgfTtcbiAgICBDYWxlbmRhci5wcm90b3R5cGUudHJpZ2dlckRhdGVVbnNlbGVjdCA9IGZ1bmN0aW9uIChwZXYpIHtcbiAgICAgICAgdGhpcy5wdWJsaWNseVRyaWdnZXIoJ3Vuc2VsZWN0JywgW1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGpzRXZlbnQ6IHBldiA/IHBldi5vcmlnRXZlbnQgOiBudWxsLFxuICAgICAgICAgICAgICAgIHZpZXc6IHRoaXMudmlld1xuICAgICAgICAgICAgfVxuICAgICAgICBdKTtcbiAgICB9O1xuICAgIC8vIFRPRE86IHJlY2VpdmUgcGV2P1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS50cmlnZ2VyRGF0ZUNsaWNrID0gZnVuY3Rpb24gKGRhdGVTcGFuLCBkYXlFbCwgdmlldywgZXYpIHtcbiAgICAgICAgdmFyIGFyZyA9IF9fYXNzaWduKHt9LCB0aGlzLmJ1aWxkRGF0ZVBvaW50QXBpKGRhdGVTcGFuKSwgeyBkYXlFbDogZGF5RWwsIGpzRXZlbnQ6IGV2LCAvLyBJcyB0aGlzIGFsd2F5cyBhIG1vdXNlIGV2ZW50PyBTZWUgIzQ2NTVcbiAgICAgICAgICAgIHZpZXc6IHZpZXcgfSk7XG4gICAgICAgIHRoaXMucHVibGljbHlUcmlnZ2VyKCdkYXRlQ2xpY2snLCBbYXJnXSk7XG4gICAgfTtcbiAgICBDYWxlbmRhci5wcm90b3R5cGUuYnVpbGREYXRlUG9pbnRBcGkgPSBmdW5jdGlvbiAoZGF0ZVNwYW4pIHtcbiAgICAgICAgdmFyIHByb3BzID0ge307XG4gICAgICAgIGZvciAodmFyIF9pID0gMCwgX2EgPSB0aGlzLnBsdWdpblN5c3RlbS5ob29rcy5kYXRlUG9pbnRUcmFuc2Zvcm1zOyBfaSA8IF9hLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgdmFyIHRyYW5zZm9ybSA9IF9hW19pXTtcbiAgICAgICAgICAgIF9fYXNzaWduKHByb3BzLCB0cmFuc2Zvcm0oZGF0ZVNwYW4sIHRoaXMpKTtcbiAgICAgICAgfVxuICAgICAgICBfX2Fzc2lnbihwcm9wcywgYnVpbGREYXRlUG9pbnRBcGkoZGF0ZVNwYW4sIHRoaXMuZGF0ZUVudikpO1xuICAgICAgICByZXR1cm4gcHJvcHM7XG4gICAgfTtcbiAgICBDYWxlbmRhci5wcm90b3R5cGUuYnVpbGREYXRlU3BhbkFwaSA9IGZ1bmN0aW9uIChkYXRlU3Bhbikge1xuICAgICAgICB2YXIgcHJvcHMgPSB7fTtcbiAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBfYSA9IHRoaXMucGx1Z2luU3lzdGVtLmhvb2tzLmRhdGVTcGFuVHJhbnNmb3JtczsgX2kgPCBfYS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIHZhciB0cmFuc2Zvcm0gPSBfYVtfaV07XG4gICAgICAgICAgICBfX2Fzc2lnbihwcm9wcywgdHJhbnNmb3JtKGRhdGVTcGFuLCB0aGlzKSk7XG4gICAgICAgIH1cbiAgICAgICAgX19hc3NpZ24ocHJvcHMsIGJ1aWxkRGF0ZVNwYW5BcGkoZGF0ZVNwYW4sIHRoaXMuZGF0ZUVudikpO1xuICAgICAgICByZXR1cm4gcHJvcHM7XG4gICAgfTtcbiAgICAvLyBEYXRlIFV0aWxzXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAvLyBSZXR1cm5zIGEgRGF0ZU1hcmtlciBmb3IgdGhlIGN1cnJlbnQgZGF0ZSwgYXMgZGVmaW5lZCBieSB0aGUgY2xpZW50J3MgY29tcHV0ZXIgb3IgZnJvbSB0aGUgYG5vd2Agb3B0aW9uXG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLmdldE5vdyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG5vdyA9IHRoaXMub3B0KCdub3cnKTtcbiAgICAgICAgaWYgKHR5cGVvZiBub3cgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIG5vdyA9IG5vdygpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChub3cgPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZGF0ZUVudi5jcmVhdGVOb3dNYXJrZXIoKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5kYXRlRW52LmNyZWF0ZU1hcmtlcihub3cpO1xuICAgIH07XG4gICAgLy8gRXZlbnQtRGF0ZSBVdGlsaXRpZXNcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIEdpdmVuIGFuIGV2ZW50J3MgYWxsRGF5IHN0YXR1cyBhbmQgc3RhcnQgZGF0ZSwgcmV0dXJuIHdoYXQgaXRzIGZhbGxiYWNrIGVuZCBkYXRlIHNob3VsZCBiZS5cbiAgICAvLyBUT0RPOiByZW5hbWUgdG8gY29tcHV0ZURlZmF1bHRFdmVudEVuZFxuICAgIENhbGVuZGFyLnByb3RvdHlwZS5nZXREZWZhdWx0RXZlbnRFbmQgPSBmdW5jdGlvbiAoYWxsRGF5LCBtYXJrZXIpIHtcbiAgICAgICAgdmFyIGVuZCA9IG1hcmtlcjtcbiAgICAgICAgaWYgKGFsbERheSkge1xuICAgICAgICAgICAgZW5kID0gc3RhcnRPZkRheShlbmQpO1xuICAgICAgICAgICAgZW5kID0gdGhpcy5kYXRlRW52LmFkZChlbmQsIHRoaXMuZGVmYXVsdEFsbERheUV2ZW50RHVyYXRpb24pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZW5kID0gdGhpcy5kYXRlRW52LmFkZChlbmQsIHRoaXMuZGVmYXVsdFRpbWVkRXZlbnREdXJhdGlvbik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGVuZDtcbiAgICB9O1xuICAgIC8vIFB1YmxpYyBFdmVudHMgQVBJXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBDYWxlbmRhci5wcm90b3R5cGUuYWRkRXZlbnQgPSBmdW5jdGlvbiAoZXZlbnRJbnB1dCwgc291cmNlSW5wdXQpIHtcbiAgICAgICAgaWYgKGV2ZW50SW5wdXQgaW5zdGFuY2VvZiBFdmVudEFwaSkge1xuICAgICAgICAgICAgdmFyIGRlZiA9IGV2ZW50SW5wdXQuX2RlZjtcbiAgICAgICAgICAgIHZhciBpbnN0YW5jZSA9IGV2ZW50SW5wdXQuX2luc3RhbmNlO1xuICAgICAgICAgICAgLy8gbm90IGFscmVhZHkgcHJlc2VudD8gZG9uJ3Qgd2FudCB0byBhZGQgYW4gb2xkIHNuYXBzaG90XG4gICAgICAgICAgICBpZiAoIXRoaXMuc3RhdGUuZXZlbnRTdG9yZS5kZWZzW2RlZi5kZWZJZF0pIHtcbiAgICAgICAgICAgICAgICB0aGlzLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogJ0FERF9FVkVOVFMnLFxuICAgICAgICAgICAgICAgICAgICBldmVudFN0b3JlOiBldmVudFR1cGxlVG9TdG9yZSh7IGRlZjogZGVmLCBpbnN0YW5jZTogaW5zdGFuY2UgfSkgLy8gVE9ETzogYmV0dGVyIHV0aWwgZm9yIHR3byBhcmdzP1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGV2ZW50SW5wdXQ7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHNvdXJjZUlkO1xuICAgICAgICBpZiAoc291cmNlSW5wdXQgaW5zdGFuY2VvZiBFdmVudFNvdXJjZUFwaSkge1xuICAgICAgICAgICAgc291cmNlSWQgPSBzb3VyY2VJbnB1dC5pbnRlcm5hbEV2ZW50U291cmNlLnNvdXJjZUlkO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHNvdXJjZUlucHV0ICE9IG51bGwpIHtcbiAgICAgICAgICAgIHZhciBzb3VyY2VBcGkgPSB0aGlzLmdldEV2ZW50U291cmNlQnlJZChzb3VyY2VJbnB1dCk7IC8vIFRPRE86IHVzZSBhbiBpbnRlcm5hbCBmdW5jdGlvblxuICAgICAgICAgICAgaWYgKCFzb3VyY2VBcGkpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ0NvdWxkIG5vdCBmaW5kIGFuIGV2ZW50IHNvdXJjZSB3aXRoIElEIFwiJyArIHNvdXJjZUlucHV0ICsgJ1wiJyk7IC8vIFRPRE86IHRlc3RcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHNvdXJjZUlkID0gc291cmNlQXBpLmludGVybmFsRXZlbnRTb3VyY2Uuc291cmNlSWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHR1cGxlID0gcGFyc2VFdmVudChldmVudElucHV0LCBzb3VyY2VJZCwgdGhpcyk7XG4gICAgICAgIGlmICh0dXBsZSkge1xuICAgICAgICAgICAgdGhpcy5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgdHlwZTogJ0FERF9FVkVOVFMnLFxuICAgICAgICAgICAgICAgIGV2ZW50U3RvcmU6IGV2ZW50VHVwbGVUb1N0b3JlKHR1cGxlKVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm4gbmV3IEV2ZW50QXBpKHRoaXMsIHR1cGxlLmRlZiwgdHVwbGUuZGVmLnJlY3VycmluZ0RlZiA/IG51bGwgOiB0dXBsZS5pbnN0YW5jZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfTtcbiAgICAvLyBUT0RPOiBvcHRpbWl6ZVxuICAgIENhbGVuZGFyLnByb3RvdHlwZS5nZXRFdmVudEJ5SWQgPSBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgdmFyIF9hID0gdGhpcy5zdGF0ZS5ldmVudFN0b3JlLCBkZWZzID0gX2EuZGVmcywgaW5zdGFuY2VzID0gX2EuaW5zdGFuY2VzO1xuICAgICAgICBpZCA9IFN0cmluZyhpZCk7XG4gICAgICAgIGZvciAodmFyIGRlZklkIGluIGRlZnMpIHtcbiAgICAgICAgICAgIHZhciBkZWYgPSBkZWZzW2RlZklkXTtcbiAgICAgICAgICAgIGlmIChkZWYucHVibGljSWQgPT09IGlkKSB7XG4gICAgICAgICAgICAgICAgaWYgKGRlZi5yZWN1cnJpbmdEZWYpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBFdmVudEFwaSh0aGlzLCBkZWYsIG51bGwpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZm9yICh2YXIgaW5zdGFuY2VJZCBpbiBpbnN0YW5jZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpbnN0YW5jZSA9IGluc3RhbmNlc1tpbnN0YW5jZUlkXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpbnN0YW5jZS5kZWZJZCA9PT0gZGVmLmRlZklkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBFdmVudEFwaSh0aGlzLCBkZWYsIGluc3RhbmNlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5nZXRFdmVudHMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBfYSA9IHRoaXMuc3RhdGUuZXZlbnRTdG9yZSwgZGVmcyA9IF9hLmRlZnMsIGluc3RhbmNlcyA9IF9hLmluc3RhbmNlcztcbiAgICAgICAgdmFyIGV2ZW50QXBpcyA9IFtdO1xuICAgICAgICBmb3IgKHZhciBpZCBpbiBpbnN0YW5jZXMpIHtcbiAgICAgICAgICAgIHZhciBpbnN0YW5jZSA9IGluc3RhbmNlc1tpZF07XG4gICAgICAgICAgICB2YXIgZGVmID0gZGVmc1tpbnN0YW5jZS5kZWZJZF07XG4gICAgICAgICAgICBldmVudEFwaXMucHVzaChuZXcgRXZlbnRBcGkodGhpcywgZGVmLCBpbnN0YW5jZSkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBldmVudEFwaXM7XG4gICAgfTtcbiAgICBDYWxlbmRhci5wcm90b3R5cGUucmVtb3ZlQWxsRXZlbnRzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLmRpc3BhdGNoKHsgdHlwZTogJ1JFTU9WRV9BTExfRVZFTlRTJyB9KTtcbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5yZXJlbmRlckV2ZW50cyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5kaXNwYXRjaCh7IHR5cGU6ICdSRVNFVF9FVkVOVFMnIH0pO1xuICAgIH07XG4gICAgLy8gUHVibGljIEV2ZW50IFNvdXJjZXMgQVBJXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBDYWxlbmRhci5wcm90b3R5cGUuZ2V0RXZlbnRTb3VyY2VzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc291cmNlSGFzaCA9IHRoaXMuc3RhdGUuZXZlbnRTb3VyY2VzO1xuICAgICAgICB2YXIgc291cmNlQXBpcyA9IFtdO1xuICAgICAgICBmb3IgKHZhciBpbnRlcm5hbElkIGluIHNvdXJjZUhhc2gpIHtcbiAgICAgICAgICAgIHNvdXJjZUFwaXMucHVzaChuZXcgRXZlbnRTb3VyY2VBcGkodGhpcywgc291cmNlSGFzaFtpbnRlcm5hbElkXSkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzb3VyY2VBcGlzO1xuICAgIH07XG4gICAgQ2FsZW5kYXIucHJvdG90eXBlLmdldEV2ZW50U291cmNlQnlJZCA9IGZ1bmN0aW9uIChpZCkge1xuICAgICAgICB2YXIgc291cmNlSGFzaCA9IHRoaXMuc3RhdGUuZXZlbnRTb3VyY2VzO1xuICAgICAgICBpZCA9IFN0cmluZyhpZCk7XG4gICAgICAgIGZvciAodmFyIHNvdXJjZUlkIGluIHNvdXJjZUhhc2gpIHtcbiAgICAgICAgICAgIGlmIChzb3VyY2VIYXNoW3NvdXJjZUlkXS5wdWJsaWNJZCA9PT0gaWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IEV2ZW50U291cmNlQXBpKHRoaXMsIHNvdXJjZUhhc2hbc291cmNlSWRdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5hZGRFdmVudFNvdXJjZSA9IGZ1bmN0aW9uIChzb3VyY2VJbnB1dCkge1xuICAgICAgICBpZiAoc291cmNlSW5wdXQgaW5zdGFuY2VvZiBFdmVudFNvdXJjZUFwaSkge1xuICAgICAgICAgICAgLy8gbm90IGFscmVhZHkgcHJlc2VudD8gZG9uJ3Qgd2FudCB0byBhZGQgYW4gb2xkIHNuYXBzaG90XG4gICAgICAgICAgICBpZiAoIXRoaXMuc3RhdGUuZXZlbnRTb3VyY2VzW3NvdXJjZUlucHV0LmludGVybmFsRXZlbnRTb3VyY2Uuc291cmNlSWRdKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdBRERfRVZFTlRfU09VUkNFUycsXG4gICAgICAgICAgICAgICAgICAgIHNvdXJjZXM6IFtzb3VyY2VJbnB1dC5pbnRlcm5hbEV2ZW50U291cmNlXVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHNvdXJjZUlucHV0O1xuICAgICAgICB9XG4gICAgICAgIHZhciBldmVudFNvdXJjZSA9IHBhcnNlRXZlbnRTb3VyY2Uoc291cmNlSW5wdXQsIHRoaXMpO1xuICAgICAgICBpZiAoZXZlbnRTb3VyY2UpIHsgLy8gVE9ETzogZXJyb3Igb3RoZXJ3aXNlP1xuICAgICAgICAgICAgdGhpcy5kaXNwYXRjaCh7IHR5cGU6ICdBRERfRVZFTlRfU09VUkNFUycsIHNvdXJjZXM6IFtldmVudFNvdXJjZV0gfSk7XG4gICAgICAgICAgICByZXR1cm4gbmV3IEV2ZW50U291cmNlQXBpKHRoaXMsIGV2ZW50U291cmNlKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5yZW1vdmVBbGxFdmVudFNvdXJjZXMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuZGlzcGF0Y2goeyB0eXBlOiAnUkVNT1ZFX0FMTF9FVkVOVF9TT1VSQ0VTJyB9KTtcbiAgICB9O1xuICAgIENhbGVuZGFyLnByb3RvdHlwZS5yZWZldGNoRXZlbnRzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLmRpc3BhdGNoKHsgdHlwZTogJ0ZFVENIX0VWRU5UX1NPVVJDRVMnIH0pO1xuICAgIH07XG4gICAgLy8gU2Nyb2xsXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBDYWxlbmRhci5wcm90b3R5cGUuc2Nyb2xsVG9UaW1lID0gZnVuY3Rpb24gKHRpbWVJbnB1dCkge1xuICAgICAgICB2YXIgZHVyYXRpb24gPSBjcmVhdGVEdXJhdGlvbih0aW1lSW5wdXQpO1xuICAgICAgICBpZiAoZHVyYXRpb24pIHtcbiAgICAgICAgICAgIHRoaXMuY29tcG9uZW50LnZpZXcuc2Nyb2xsVG9EdXJhdGlvbihkdXJhdGlvbik7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIHJldHVybiBDYWxlbmRhcjtcbn0oKSk7XG5FbWl0dGVyTWl4aW4ubWl4SW50byhDYWxlbmRhcik7XG4vLyBmb3IgbWVtb2l6ZXJzXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuZnVuY3Rpb24gYnVpbGRDb21wb25lbnRDb250ZXh0JDEodGhlbWUsIGRhdGVFbnYsIG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IENvbXBvbmVudENvbnRleHQodGhpcywgdGhlbWUsIGRhdGVFbnYsIG9wdGlvbnMsIG51bGwpO1xufVxuZnVuY3Rpb24gYnVpbGREYXRlRW52KGxvY2FsZSwgdGltZVpvbmUsIG5hbWVkVGltZVpvbmVJbXBsLCBmaXJzdERheSwgd2Vla051bWJlckNhbGN1bGF0aW9uLCB3ZWVrTGFiZWwsIGNtZEZvcm1hdHRlcikge1xuICAgIHJldHVybiBuZXcgRGF0ZUVudih7XG4gICAgICAgIGNhbGVuZGFyU3lzdGVtOiAnZ3JlZ29yeScsXG4gICAgICAgIHRpbWVab25lOiB0aW1lWm9uZSxcbiAgICAgICAgbmFtZWRUaW1lWm9uZUltcGw6IG5hbWVkVGltZVpvbmVJbXBsLFxuICAgICAgICBsb2NhbGU6IGxvY2FsZSxcbiAgICAgICAgd2Vla051bWJlckNhbGN1bGF0aW9uOiB3ZWVrTnVtYmVyQ2FsY3VsYXRpb24sXG4gICAgICAgIGZpcnN0RGF5OiBmaXJzdERheSxcbiAgICAgICAgd2Vla0xhYmVsOiB3ZWVrTGFiZWwsXG4gICAgICAgIGNtZEZvcm1hdHRlcjogY21kRm9ybWF0dGVyXG4gICAgfSk7XG59XG5mdW5jdGlvbiBidWlsZFRoZW1lKGNhbGVuZGFyT3B0aW9ucykge1xuICAgIHZhciB0aGVtZUNsYXNzID0gdGhpcy5wbHVnaW5TeXN0ZW0uaG9va3MudGhlbWVDbGFzc2VzW2NhbGVuZGFyT3B0aW9ucy50aGVtZVN5c3RlbV0gfHwgU3RhbmRhcmRUaGVtZTtcbiAgICByZXR1cm4gbmV3IHRoZW1lQ2xhc3MoY2FsZW5kYXJPcHRpb25zKTtcbn1cbmZ1bmN0aW9uIGJ1aWxkRGVsYXllZFJlcmVuZGVyKHdhaXQpIHtcbiAgICB2YXIgZnVuYyA9IHRoaXMudHJ5UmVyZW5kZXIuYmluZCh0aGlzKTtcbiAgICBpZiAod2FpdCAhPSBudWxsKSB7XG4gICAgICAgIGZ1bmMgPSBkZWJvdW5jZShmdW5jLCB3YWl0KTtcbiAgICB9XG4gICAgcmV0dXJuIGZ1bmM7XG59XG5mdW5jdGlvbiBidWlsZEV2ZW50VWlCeVNvdXJjZShldmVudFNvdXJjZXMpIHtcbiAgICByZXR1cm4gbWFwSGFzaChldmVudFNvdXJjZXMsIGZ1bmN0aW9uIChldmVudFNvdXJjZSkge1xuICAgICAgICByZXR1cm4gZXZlbnRTb3VyY2UudWk7XG4gICAgfSk7XG59XG5mdW5jdGlvbiBidWlsZEV2ZW50VWlCYXNlcyhldmVudERlZnMsIGV2ZW50VWlTaW5nbGVCYXNlLCBldmVudFVpQnlTb3VyY2UpIHtcbiAgICB2YXIgZXZlbnRVaUJhc2VzID0geyAnJzogZXZlbnRVaVNpbmdsZUJhc2UgfTtcbiAgICBmb3IgKHZhciBkZWZJZCBpbiBldmVudERlZnMpIHtcbiAgICAgICAgdmFyIGRlZiA9IGV2ZW50RGVmc1tkZWZJZF07XG4gICAgICAgIGlmIChkZWYuc291cmNlSWQgJiYgZXZlbnRVaUJ5U291cmNlW2RlZi5zb3VyY2VJZF0pIHtcbiAgICAgICAgICAgIGV2ZW50VWlCYXNlc1tkZWZJZF0gPSBldmVudFVpQnlTb3VyY2VbZGVmLnNvdXJjZUlkXTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZXZlbnRVaUJhc2VzO1xufVxuXG52YXIgVmlldyA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uIChfc3VwZXIpIHtcbiAgICBfX2V4dGVuZHMoVmlldywgX3N1cGVyKTtcbiAgICBmdW5jdGlvbiBWaWV3KHZpZXdTcGVjLCBwYXJlbnRFbCkge1xuICAgICAgICB2YXIgX3RoaXMgPSBfc3VwZXIuY2FsbCh0aGlzLCBjcmVhdGVFbGVtZW50KCdkaXYnLCB7IGNsYXNzTmFtZTogJ2ZjLXZpZXcgZmMtJyArIHZpZXdTcGVjLnR5cGUgKyAnLXZpZXcnIH0pKSB8fCB0aGlzO1xuICAgICAgICBfdGhpcy5yZW5kZXJEYXRlc01lbSA9IG1lbW9pemVSZW5kZXJpbmcoX3RoaXMucmVuZGVyRGF0ZXNXcmFwLCBfdGhpcy51bnJlbmRlckRhdGVzV3JhcCk7XG4gICAgICAgIF90aGlzLnJlbmRlckJ1c2luZXNzSG91cnNNZW0gPSBtZW1vaXplUmVuZGVyaW5nKF90aGlzLnJlbmRlckJ1c2luZXNzSG91cnMsIF90aGlzLnVucmVuZGVyQnVzaW5lc3NIb3VycywgW190aGlzLnJlbmRlckRhdGVzTWVtXSk7XG4gICAgICAgIF90aGlzLnJlbmRlckRhdGVTZWxlY3Rpb25NZW0gPSBtZW1vaXplUmVuZGVyaW5nKF90aGlzLnJlbmRlckRhdGVTZWxlY3Rpb25XcmFwLCBfdGhpcy51bnJlbmRlckRhdGVTZWxlY3Rpb25XcmFwLCBbX3RoaXMucmVuZGVyRGF0ZXNNZW1dKTtcbiAgICAgICAgX3RoaXMucmVuZGVyRXZlbnRzTWVtID0gbWVtb2l6ZVJlbmRlcmluZyhfdGhpcy5yZW5kZXJFdmVudHMsIF90aGlzLnVucmVuZGVyRXZlbnRzLCBbX3RoaXMucmVuZGVyRGF0ZXNNZW1dKTtcbiAgICAgICAgX3RoaXMucmVuZGVyRXZlbnRTZWxlY3Rpb25NZW0gPSBtZW1vaXplUmVuZGVyaW5nKF90aGlzLnJlbmRlckV2ZW50U2VsZWN0aW9uV3JhcCwgX3RoaXMudW5yZW5kZXJFdmVudFNlbGVjdGlvbldyYXAsIFtfdGhpcy5yZW5kZXJFdmVudHNNZW1dKTtcbiAgICAgICAgX3RoaXMucmVuZGVyRXZlbnREcmFnTWVtID0gbWVtb2l6ZVJlbmRlcmluZyhfdGhpcy5yZW5kZXJFdmVudERyYWdXcmFwLCBfdGhpcy51bnJlbmRlckV2ZW50RHJhZ1dyYXAsIFtfdGhpcy5yZW5kZXJEYXRlc01lbV0pO1xuICAgICAgICBfdGhpcy5yZW5kZXJFdmVudFJlc2l6ZU1lbSA9IG1lbW9pemVSZW5kZXJpbmcoX3RoaXMucmVuZGVyRXZlbnRSZXNpemVXcmFwLCBfdGhpcy51bnJlbmRlckV2ZW50UmVzaXplV3JhcCwgW190aGlzLnJlbmRlckRhdGVzTWVtXSk7XG4gICAgICAgIF90aGlzLnZpZXdTcGVjID0gdmlld1NwZWM7XG4gICAgICAgIF90aGlzLnR5cGUgPSB2aWV3U3BlYy50eXBlO1xuICAgICAgICBwYXJlbnRFbC5hcHBlbmRDaGlsZChfdGhpcy5lbCk7XG4gICAgICAgIF90aGlzLmluaXRpYWxpemUoKTtcbiAgICAgICAgcmV0dXJuIF90aGlzO1xuICAgIH1cbiAgICBWaWV3LnByb3RvdHlwZS5pbml0aWFsaXplID0gZnVuY3Rpb24gKCkge1xuICAgIH07XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFZpZXcucHJvdG90eXBlLCBcImFjdGl2ZVN0YXJ0XCIsIHtcbiAgICAgICAgLy8gRGF0ZSBTZXR0aW5nL1Vuc2V0dGluZ1xuICAgICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbnRleHQuZGF0ZUVudi50b0RhdGUodGhpcy5wcm9wcy5kYXRlUHJvZmlsZS5hY3RpdmVSYW5nZS5zdGFydCk7XG4gICAgICAgIH0sXG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShWaWV3LnByb3RvdHlwZSwgXCJhY3RpdmVFbmRcIiwge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbnRleHQuZGF0ZUVudi50b0RhdGUodGhpcy5wcm9wcy5kYXRlUHJvZmlsZS5hY3RpdmVSYW5nZS5lbmQpO1xuICAgICAgICB9LFxuICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICB9KTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoVmlldy5wcm90b3R5cGUsIFwiY3VycmVudFN0YXJ0XCIsIHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jb250ZXh0LmRhdGVFbnYudG9EYXRlKHRoaXMucHJvcHMuZGF0ZVByb2ZpbGUuY3VycmVudFJhbmdlLnN0YXJ0KTtcbiAgICAgICAgfSxcbiAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlXG4gICAgfSk7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFZpZXcucHJvdG90eXBlLCBcImN1cnJlbnRFbmRcIiwge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbnRleHQuZGF0ZUVudi50b0RhdGUodGhpcy5wcm9wcy5kYXRlUHJvZmlsZS5jdXJyZW50UmFuZ2UuZW5kKTtcbiAgICAgICAgfSxcbiAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlXG4gICAgfSk7XG4gICAgLy8gR2VuZXJhbCBSZW5kZXJpbmdcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIFZpZXcucHJvdG90eXBlLnJlbmRlciA9IGZ1bmN0aW9uIChwcm9wcywgY29udGV4dCkge1xuICAgICAgICB0aGlzLnJlbmRlckRhdGVzTWVtKHByb3BzLmRhdGVQcm9maWxlKTtcbiAgICAgICAgdGhpcy5yZW5kZXJCdXNpbmVzc0hvdXJzTWVtKHByb3BzLmJ1c2luZXNzSG91cnMpO1xuICAgICAgICB0aGlzLnJlbmRlckRhdGVTZWxlY3Rpb25NZW0ocHJvcHMuZGF0ZVNlbGVjdGlvbik7XG4gICAgICAgIHRoaXMucmVuZGVyRXZlbnRzTWVtKHByb3BzLmV2ZW50U3RvcmUpO1xuICAgICAgICB0aGlzLnJlbmRlckV2ZW50U2VsZWN0aW9uTWVtKHByb3BzLmV2ZW50U2VsZWN0aW9uKTtcbiAgICAgICAgdGhpcy5yZW5kZXJFdmVudERyYWdNZW0ocHJvcHMuZXZlbnREcmFnKTtcbiAgICAgICAgdGhpcy5yZW5kZXJFdmVudFJlc2l6ZU1lbShwcm9wcy5ldmVudFJlc2l6ZSk7XG4gICAgfTtcbiAgICBWaWV3LnByb3RvdHlwZS5iZWZvcmVVcGRhdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuYWRkU2Nyb2xsKHRoaXMucXVlcnlTY3JvbGwoKSk7XG4gICAgfTtcbiAgICBWaWV3LnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBfc3VwZXIucHJvdG90eXBlLmRlc3Ryb3kuY2FsbCh0aGlzKTtcbiAgICAgICAgdGhpcy5yZW5kZXJEYXRlc01lbS51bnJlbmRlcigpOyAvLyBzaG91bGQgdW5yZW5kZXIgZXZlcnl0aGluZyBlbHNlXG4gICAgfTtcbiAgICAvLyBTaXppbmdcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIFZpZXcucHJvdG90eXBlLnVwZGF0ZVNpemUgPSBmdW5jdGlvbiAoaXNSZXNpemUsIHZpZXdIZWlnaHQsIGlzQXV0bykge1xuICAgICAgICB2YXIgY2FsZW5kYXIgPSB0aGlzLmNvbnRleHQuY2FsZW5kYXI7XG4gICAgICAgIGlmIChpc1Jlc2l6ZSkge1xuICAgICAgICAgICAgdGhpcy5hZGRTY3JvbGwodGhpcy5xdWVyeVNjcm9sbCgpKTsgLy8gTk9URTogc2FtZSBjb2RlIGFzIGluIGJlZm9yZVVwZGF0ZVxuICAgICAgICB9XG4gICAgICAgIGlmIChpc1Jlc2l6ZSB8fCAvLyBIQUNLUy4uLlxuICAgICAgICAgICAgY2FsZW5kYXIuaXNWaWV3VXBkYXRlZCB8fFxuICAgICAgICAgICAgY2FsZW5kYXIuaXNEYXRlc1VwZGF0ZWQgfHxcbiAgICAgICAgICAgIGNhbGVuZGFyLmlzRXZlbnRzVXBkYXRlZCkge1xuICAgICAgICAgICAgLy8gc29ydCBvZiB0aGUgY2F0Y2gtYWxsIHNpemluZ1xuICAgICAgICAgICAgLy8gYW55dGhpbmcgdGhhdCBtaWdodCBjYXVzZSBkaW1lbnNpb24gY2hhbmdlc1xuICAgICAgICAgICAgdGhpcy51cGRhdGVCYXNlU2l6ZShpc1Jlc2l6ZSwgdmlld0hlaWdodCwgaXNBdXRvKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBOT1RFOiBwb3BTY3JvbGwgaXMgY2FsbGVkIGJ5IENhbGVuZGFyQ29tcG9uZW50XG4gICAgfTtcbiAgICBWaWV3LnByb3RvdHlwZS51cGRhdGVCYXNlU2l6ZSA9IGZ1bmN0aW9uIChpc1Jlc2l6ZSwgdmlld0hlaWdodCwgaXNBdXRvKSB7XG4gICAgfTtcbiAgICAvLyBEYXRlIFJlbmRlcmluZ1xuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgVmlldy5wcm90b3R5cGUucmVuZGVyRGF0ZXNXcmFwID0gZnVuY3Rpb24gKGRhdGVQcm9maWxlKSB7XG4gICAgICAgIHRoaXMucmVuZGVyRGF0ZXMoZGF0ZVByb2ZpbGUpO1xuICAgICAgICB0aGlzLmFkZFNjcm9sbCh7XG4gICAgICAgICAgICBkdXJhdGlvbjogY3JlYXRlRHVyYXRpb24odGhpcy5jb250ZXh0Lm9wdGlvbnMuc2Nyb2xsVGltZSlcbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICBWaWV3LnByb3RvdHlwZS51bnJlbmRlckRhdGVzV3JhcCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5zdG9wTm93SW5kaWNhdG9yKCk7XG4gICAgICAgIHRoaXMudW5yZW5kZXJEYXRlcygpO1xuICAgIH07XG4gICAgVmlldy5wcm90b3R5cGUucmVuZGVyRGF0ZXMgPSBmdW5jdGlvbiAoZGF0ZVByb2ZpbGUpIHsgfTtcbiAgICBWaWV3LnByb3RvdHlwZS51bnJlbmRlckRhdGVzID0gZnVuY3Rpb24gKCkgeyB9O1xuICAgIC8vIEJ1c2luZXNzIEhvdXJzXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBWaWV3LnByb3RvdHlwZS5yZW5kZXJCdXNpbmVzc0hvdXJzID0gZnVuY3Rpb24gKGJ1c2luZXNzSG91cnMpIHsgfTtcbiAgICBWaWV3LnByb3RvdHlwZS51bnJlbmRlckJ1c2luZXNzSG91cnMgPSBmdW5jdGlvbiAoKSB7IH07XG4gICAgLy8gRGF0ZSBTZWxlY3Rpb25cbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIFZpZXcucHJvdG90eXBlLnJlbmRlckRhdGVTZWxlY3Rpb25XcmFwID0gZnVuY3Rpb24gKHNlbGVjdGlvbikge1xuICAgICAgICBpZiAoc2VsZWN0aW9uKSB7XG4gICAgICAgICAgICB0aGlzLnJlbmRlckRhdGVTZWxlY3Rpb24oc2VsZWN0aW9uKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgVmlldy5wcm90b3R5cGUudW5yZW5kZXJEYXRlU2VsZWN0aW9uV3JhcCA9IGZ1bmN0aW9uIChzZWxlY3Rpb24pIHtcbiAgICAgICAgaWYgKHNlbGVjdGlvbikge1xuICAgICAgICAgICAgdGhpcy51bnJlbmRlckRhdGVTZWxlY3Rpb24oc2VsZWN0aW9uKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgVmlldy5wcm90b3R5cGUucmVuZGVyRGF0ZVNlbGVjdGlvbiA9IGZ1bmN0aW9uIChzZWxlY3Rpb24pIHsgfTtcbiAgICBWaWV3LnByb3RvdHlwZS51bnJlbmRlckRhdGVTZWxlY3Rpb24gPSBmdW5jdGlvbiAoc2VsZWN0aW9uKSB7IH07XG4gICAgLy8gRXZlbnQgUmVuZGVyaW5nXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBWaWV3LnByb3RvdHlwZS5yZW5kZXJFdmVudHMgPSBmdW5jdGlvbiAoZXZlbnRTdG9yZSkgeyB9O1xuICAgIFZpZXcucHJvdG90eXBlLnVucmVuZGVyRXZlbnRzID0gZnVuY3Rpb24gKCkgeyB9O1xuICAgIC8vIHV0aWwgZm9yIHN1YmNsYXNzZXNcbiAgICBWaWV3LnByb3RvdHlwZS5zbGljZUV2ZW50cyA9IGZ1bmN0aW9uIChldmVudFN0b3JlLCBhbGxEYXkpIHtcbiAgICAgICAgdmFyIHByb3BzID0gdGhpcy5wcm9wcztcbiAgICAgICAgcmV0dXJuIHNsaWNlRXZlbnRTdG9yZShldmVudFN0b3JlLCBwcm9wcy5ldmVudFVpQmFzZXMsIHByb3BzLmRhdGVQcm9maWxlLmFjdGl2ZVJhbmdlLCBhbGxEYXkgPyB0aGlzLmNvbnRleHQubmV4dERheVRocmVzaG9sZCA6IG51bGwpLmZnO1xuICAgIH07XG4gICAgLy8gRXZlbnQgU2VsZWN0aW9uXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBWaWV3LnByb3RvdHlwZS5yZW5kZXJFdmVudFNlbGVjdGlvbldyYXAgPSBmdW5jdGlvbiAoaW5zdGFuY2VJZCkge1xuICAgICAgICBpZiAoaW5zdGFuY2VJZCkge1xuICAgICAgICAgICAgdGhpcy5yZW5kZXJFdmVudFNlbGVjdGlvbihpbnN0YW5jZUlkKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgVmlldy5wcm90b3R5cGUudW5yZW5kZXJFdmVudFNlbGVjdGlvbldyYXAgPSBmdW5jdGlvbiAoaW5zdGFuY2VJZCkge1xuICAgICAgICBpZiAoaW5zdGFuY2VJZCkge1xuICAgICAgICAgICAgdGhpcy51bnJlbmRlckV2ZW50U2VsZWN0aW9uKGluc3RhbmNlSWQpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBWaWV3LnByb3RvdHlwZS5yZW5kZXJFdmVudFNlbGVjdGlvbiA9IGZ1bmN0aW9uIChpbnN0YW5jZUlkKSB7IH07XG4gICAgVmlldy5wcm90b3R5cGUudW5yZW5kZXJFdmVudFNlbGVjdGlvbiA9IGZ1bmN0aW9uIChpbnN0YW5jZUlkKSB7IH07XG4gICAgLy8gRXZlbnQgRHJhZ1xuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgVmlldy5wcm90b3R5cGUucmVuZGVyRXZlbnREcmFnV3JhcCA9IGZ1bmN0aW9uIChzdGF0ZSkge1xuICAgICAgICBpZiAoc3RhdGUpIHtcbiAgICAgICAgICAgIHRoaXMucmVuZGVyRXZlbnREcmFnKHN0YXRlKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgVmlldy5wcm90b3R5cGUudW5yZW5kZXJFdmVudERyYWdXcmFwID0gZnVuY3Rpb24gKHN0YXRlKSB7XG4gICAgICAgIGlmIChzdGF0ZSkge1xuICAgICAgICAgICAgdGhpcy51bnJlbmRlckV2ZW50RHJhZyhzdGF0ZSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIFZpZXcucHJvdG90eXBlLnJlbmRlckV2ZW50RHJhZyA9IGZ1bmN0aW9uIChzdGF0ZSkgeyB9O1xuICAgIFZpZXcucHJvdG90eXBlLnVucmVuZGVyRXZlbnREcmFnID0gZnVuY3Rpb24gKHN0YXRlKSB7IH07XG4gICAgLy8gRXZlbnQgUmVzaXplXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBWaWV3LnByb3RvdHlwZS5yZW5kZXJFdmVudFJlc2l6ZVdyYXAgPSBmdW5jdGlvbiAoc3RhdGUpIHtcbiAgICAgICAgaWYgKHN0YXRlKSB7XG4gICAgICAgICAgICB0aGlzLnJlbmRlckV2ZW50UmVzaXplKHN0YXRlKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgVmlldy5wcm90b3R5cGUudW5yZW5kZXJFdmVudFJlc2l6ZVdyYXAgPSBmdW5jdGlvbiAoc3RhdGUpIHtcbiAgICAgICAgaWYgKHN0YXRlKSB7XG4gICAgICAgICAgICB0aGlzLnVucmVuZGVyRXZlbnRSZXNpemUoc3RhdGUpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBWaWV3LnByb3RvdHlwZS5yZW5kZXJFdmVudFJlc2l6ZSA9IGZ1bmN0aW9uIChzdGF0ZSkgeyB9O1xuICAgIFZpZXcucHJvdG90eXBlLnVucmVuZGVyRXZlbnRSZXNpemUgPSBmdW5jdGlvbiAoc3RhdGUpIHsgfTtcbiAgICAvKiBOb3cgSW5kaWNhdG9yXG4gICAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbiAgICAvLyBJbW1lZGlhdGVseSByZW5kZXIgdGhlIGN1cnJlbnQgdGltZSBpbmRpY2F0b3IgYW5kIGJlZ2lucyByZS1yZW5kZXJpbmcgaXQgYXQgYW4gaW50ZXJ2YWwsXG4gICAgLy8gd2hpY2ggaXMgZGVmaW5lZCBieSB0aGlzLmdldE5vd0luZGljYXRvclVuaXQoKS5cbiAgICAvLyBUT0RPOiBzb21laG93IGRvIHRoaXMgZm9yIHRoZSBjdXJyZW50IHdob2xlIGRheSdzIGJhY2tncm91bmQgdG9vXG4gICAgLy8gVVNBR0U6IG11c3QgYmUgY2FsbGVkIG1hbnVhbGx5IGZyb20gc3ViY2xhc3NlcycgcmVuZGVyIG1ldGhvZHMhIGRvbid0IG5lZWQgdG8gY2FsbCBzdG9wTm93SW5kaWNhdG9yIHRob1xuICAgIFZpZXcucHJvdG90eXBlLnN0YXJ0Tm93SW5kaWNhdG9yID0gZnVuY3Rpb24gKGRhdGVQcm9maWxlLCBkYXRlUHJvZmlsZUdlbmVyYXRvcikge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgX2EgPSB0aGlzLmNvbnRleHQsIGNhbGVuZGFyID0gX2EuY2FsZW5kYXIsIGRhdGVFbnYgPSBfYS5kYXRlRW52LCBvcHRpb25zID0gX2Eub3B0aW9ucztcbiAgICAgICAgdmFyIHVuaXQ7XG4gICAgICAgIHZhciB1cGRhdGU7XG4gICAgICAgIHZhciBkZWxheTsgLy8gbXMgd2FpdCB2YWx1ZVxuICAgICAgICBpZiAob3B0aW9ucy5ub3dJbmRpY2F0b3IgJiYgIXRoaXMuaW5pdGlhbE5vd0RhdGUpIHtcbiAgICAgICAgICAgIHVuaXQgPSB0aGlzLmdldE5vd0luZGljYXRvclVuaXQoZGF0ZVByb2ZpbGUsIGRhdGVQcm9maWxlR2VuZXJhdG9yKTtcbiAgICAgICAgICAgIGlmICh1bml0KSB7XG4gICAgICAgICAgICAgICAgdXBkYXRlID0gdGhpcy51cGRhdGVOb3dJbmRpY2F0b3IuYmluZCh0aGlzKTtcbiAgICAgICAgICAgICAgICB0aGlzLmluaXRpYWxOb3dEYXRlID0gY2FsZW5kYXIuZ2V0Tm93KCk7XG4gICAgICAgICAgICAgICAgdGhpcy5pbml0aWFsTm93UXVlcmllZE1zID0gbmV3IERhdGUoKS52YWx1ZU9mKCk7XG4gICAgICAgICAgICAgICAgLy8gd2FpdCB1bnRpbCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBuZXh0IGludGVydmFsXG4gICAgICAgICAgICAgICAgZGVsYXkgPSBkYXRlRW52LmFkZChkYXRlRW52LnN0YXJ0T2YodGhpcy5pbml0aWFsTm93RGF0ZSwgdW5pdCksIGNyZWF0ZUR1cmF0aW9uKDEsIHVuaXQpKS52YWx1ZU9mKCkgLSB0aGlzLmluaXRpYWxOb3dEYXRlLnZhbHVlT2YoKTtcbiAgICAgICAgICAgICAgICAvLyBUT0RPOiBtYXliZSBhbHdheXMgdXNlIHNldFRpbWVvdXQsIHdhaXRpbmcgdW50aWwgc3RhcnQgb2YgbmV4dCB1bml0XG4gICAgICAgICAgICAgICAgdGhpcy5ub3dJbmRpY2F0b3JUaW1lb3V0SUQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgX3RoaXMubm93SW5kaWNhdG9yVGltZW91dElEID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgdXBkYXRlKCk7XG4gICAgICAgICAgICAgICAgICAgIGlmICh1bml0ID09PSAnc2Vjb25kJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGVsYXkgPSAxMDAwOyAvLyBldmVyeSBzZWNvbmRcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGF5ID0gMTAwMCAqIDYwOyAvLyBvdGhlcndpc2UsIGV2ZXJ5IG1pbnV0ZVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLm5vd0luZGljYXRvckludGVydmFsSUQgPSBzZXRJbnRlcnZhbCh1cGRhdGUsIGRlbGF5KTsgLy8gdXBkYXRlIGV2ZXJ5IGludGVydmFsXG4gICAgICAgICAgICAgICAgfSwgZGVsYXkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gcmVuZGVyaW5nIHdpbGwgYmUgaW5pdGlhdGVkIGluIHVwZGF0ZVNpemVcbiAgICAgICAgfVxuICAgIH07XG4gICAgLy8gcmVyZW5kZXJzIHRoZSBub3cgaW5kaWNhdG9yLCBjb21wdXRpbmcgdGhlIG5ldyBjdXJyZW50IHRpbWUgZnJvbSB0aGUgYW1vdW50IG9mIHRpbWUgdGhhdCBoYXMgcGFzc2VkXG4gICAgLy8gc2luY2UgdGhlIGluaXRpYWwgZ2V0Tm93IGNhbGwuXG4gICAgVmlldy5wcm90b3R5cGUudXBkYXRlTm93SW5kaWNhdG9yID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGhpcy5wcm9wcy5kYXRlUHJvZmlsZSAmJiAvLyBhIHdheSB0byBkZXRlcm1pbmUgaWYgZGF0ZXMgd2VyZSByZW5kZXJlZCB5ZXRcbiAgICAgICAgICAgIHRoaXMuaW5pdGlhbE5vd0RhdGUgLy8gYWN0aXZhdGVkIGJlZm9yZT9cbiAgICAgICAgKSB7XG4gICAgICAgICAgICB0aGlzLnVucmVuZGVyTm93SW5kaWNhdG9yKCk7IC8vIHdvbid0IHVucmVuZGVyIGlmIHVubmVjZXNzYXJ5XG4gICAgICAgICAgICB0aGlzLnJlbmRlck5vd0luZGljYXRvcihhZGRNcyh0aGlzLmluaXRpYWxOb3dEYXRlLCBuZXcgRGF0ZSgpLnZhbHVlT2YoKSAtIHRoaXMuaW5pdGlhbE5vd1F1ZXJpZWRNcykpO1xuICAgICAgICAgICAgdGhpcy5pc05vd0luZGljYXRvclJlbmRlcmVkID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLy8gSW1tZWRpYXRlbHkgdW5yZW5kZXJzIHRoZSB2aWV3J3MgY3VycmVudCB0aW1lIGluZGljYXRvciBhbmQgc3RvcHMgYW55IHJlLXJlbmRlcmluZyB0aW1lcnMuXG4gICAgLy8gV29uJ3QgY2F1c2Ugc2lkZSBlZmZlY3RzIGlmIGluZGljYXRvciBpc24ndCByZW5kZXJlZC5cbiAgICBWaWV3LnByb3RvdHlwZS5zdG9wTm93SW5kaWNhdG9yID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGhpcy5ub3dJbmRpY2F0b3JUaW1lb3V0SUQpIHtcbiAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aGlzLm5vd0luZGljYXRvclRpbWVvdXRJRCk7XG4gICAgICAgICAgICB0aGlzLm5vd0luZGljYXRvclRpbWVvdXRJRCA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMubm93SW5kaWNhdG9ySW50ZXJ2YWxJRCkge1xuICAgICAgICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLm5vd0luZGljYXRvckludGVydmFsSUQpO1xuICAgICAgICAgICAgdGhpcy5ub3dJbmRpY2F0b3JJbnRlcnZhbElEID0gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5pc05vd0luZGljYXRvclJlbmRlcmVkKSB7XG4gICAgICAgICAgICB0aGlzLnVucmVuZGVyTm93SW5kaWNhdG9yKCk7XG4gICAgICAgICAgICB0aGlzLmlzTm93SW5kaWNhdG9yUmVuZGVyZWQgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgVmlldy5wcm90b3R5cGUuZ2V0Tm93SW5kaWNhdG9yVW5pdCA9IGZ1bmN0aW9uIChkYXRlUHJvZmlsZSwgZGF0ZVByb2ZpbGVHZW5lcmF0b3IpIHtcbiAgICAgICAgLy8gc3ViY2xhc3NlcyBzaG91bGQgaW1wbGVtZW50XG4gICAgfTtcbiAgICAvLyBSZW5kZXJzIGEgY3VycmVudCB0aW1lIGluZGljYXRvciBhdCB0aGUgZ2l2ZW4gZGF0ZXRpbWVcbiAgICBWaWV3LnByb3RvdHlwZS5yZW5kZXJOb3dJbmRpY2F0b3IgPSBmdW5jdGlvbiAoZGF0ZSkge1xuICAgICAgICAvLyBTVUJDTEFTU0VTIE1VU1QgUEFTUyBUTyBDSElMRFJFTiFcbiAgICB9O1xuICAgIC8vIFVuZG9lcyB0aGUgcmVuZGVyaW5nIGFjdGlvbnMgZnJvbSByZW5kZXJOb3dJbmRpY2F0b3JcbiAgICBWaWV3LnByb3RvdHlwZS51bnJlbmRlck5vd0luZGljYXRvciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLy8gU1VCQ0xBU1NFUyBNVVNUIFBBU1MgVE8gQ0hJTERSRU4hXG4gICAgfTtcbiAgICAvKiBTY3JvbGxlclxuICAgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG4gICAgVmlldy5wcm90b3R5cGUuYWRkU2Nyb2xsID0gZnVuY3Rpb24gKHNjcm9sbCwgaXNGb3JjZWQpIHtcbiAgICAgICAgaWYgKGlzRm9yY2VkKSB7XG4gICAgICAgICAgICBzY3JvbGwuaXNGb3JjZWQgPSBpc0ZvcmNlZDtcbiAgICAgICAgfVxuICAgICAgICBfX2Fzc2lnbih0aGlzLnF1ZXVlZFNjcm9sbCB8fCAodGhpcy5xdWV1ZWRTY3JvbGwgPSB7fSksIHNjcm9sbCk7XG4gICAgfTtcbiAgICBWaWV3LnByb3RvdHlwZS5wb3BTY3JvbGwgPSBmdW5jdGlvbiAoaXNSZXNpemUpIHtcbiAgICAgICAgdGhpcy5hcHBseVF1ZXVlZFNjcm9sbChpc1Jlc2l6ZSk7XG4gICAgICAgIHRoaXMucXVldWVkU2Nyb2xsID0gbnVsbDtcbiAgICB9O1xuICAgIFZpZXcucHJvdG90eXBlLmFwcGx5UXVldWVkU2Nyb2xsID0gZnVuY3Rpb24gKGlzUmVzaXplKSB7XG4gICAgICAgIGlmICh0aGlzLnF1ZXVlZFNjcm9sbCkge1xuICAgICAgICAgICAgdGhpcy5hcHBseVNjcm9sbCh0aGlzLnF1ZXVlZFNjcm9sbCwgaXNSZXNpemUpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBWaWV3LnByb3RvdHlwZS5xdWVyeVNjcm9sbCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNjcm9sbCA9IHt9O1xuICAgICAgICBpZiAodGhpcy5wcm9wcy5kYXRlUHJvZmlsZSkgeyAvLyBkYXRlcyByZW5kZXJlZCB5ZXQ/XG4gICAgICAgICAgICBfX2Fzc2lnbihzY3JvbGwsIHRoaXMucXVlcnlEYXRlU2Nyb2xsKCkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzY3JvbGw7XG4gICAgfTtcbiAgICBWaWV3LnByb3RvdHlwZS5hcHBseVNjcm9sbCA9IGZ1bmN0aW9uIChzY3JvbGwsIGlzUmVzaXplKSB7XG4gICAgICAgIHZhciBkdXJhdGlvbiA9IHNjcm9sbC5kdXJhdGlvbiwgaXNGb3JjZWQgPSBzY3JvbGwuaXNGb3JjZWQ7XG4gICAgICAgIGlmIChkdXJhdGlvbiAhPSBudWxsICYmICFpc0ZvcmNlZCkge1xuICAgICAgICAgICAgZGVsZXRlIHNjcm9sbC5kdXJhdGlvbjtcbiAgICAgICAgICAgIGlmICh0aGlzLnByb3BzLmRhdGVQcm9maWxlKSB7IC8vIGRhdGVzIHJlbmRlcmVkIHlldD9cbiAgICAgICAgICAgICAgICBfX2Fzc2lnbihzY3JvbGwsIHRoaXMuY29tcHV0ZURhdGVTY3JvbGwoZHVyYXRpb24pKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5wcm9wcy5kYXRlUHJvZmlsZSkgeyAvLyBkYXRlcyByZW5kZXJlZCB5ZXQ/XG4gICAgICAgICAgICB0aGlzLmFwcGx5RGF0ZVNjcm9sbChzY3JvbGwpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBWaWV3LnByb3RvdHlwZS5jb21wdXRlRGF0ZVNjcm9sbCA9IGZ1bmN0aW9uIChkdXJhdGlvbikge1xuICAgICAgICByZXR1cm4ge307IC8vIHN1YmNsYXNzZXMgbXVzdCBpbXBsZW1lbnRcbiAgICB9O1xuICAgIFZpZXcucHJvdG90eXBlLnF1ZXJ5RGF0ZVNjcm9sbCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHt9OyAvLyBzdWJjbGFzc2VzIG11c3QgaW1wbGVtZW50XG4gICAgfTtcbiAgICBWaWV3LnByb3RvdHlwZS5hcHBseURhdGVTY3JvbGwgPSBmdW5jdGlvbiAoc2Nyb2xsKSB7XG4gICAgICAgIC8vIHN1YmNsYXNzZXMgbXVzdCBpbXBsZW1lbnRcbiAgICB9O1xuICAgIC8vIGZvciBBUElcbiAgICBWaWV3LnByb3RvdHlwZS5zY3JvbGxUb0R1cmF0aW9uID0gZnVuY3Rpb24gKGR1cmF0aW9uKSB7XG4gICAgICAgIHRoaXMuYXBwbHlTY3JvbGwoeyBkdXJhdGlvbjogZHVyYXRpb24gfSwgZmFsc2UpO1xuICAgIH07XG4gICAgcmV0dXJuIFZpZXc7XG59KERhdGVDb21wb25lbnQpKTtcbkVtaXR0ZXJNaXhpbi5taXhJbnRvKFZpZXcpO1xuVmlldy5wcm90b3R5cGUudXNlc01pbk1heFRpbWUgPSBmYWxzZTtcblZpZXcucHJvdG90eXBlLmRhdGVQcm9maWxlR2VuZXJhdG9yQ2xhc3MgPSBEYXRlUHJvZmlsZUdlbmVyYXRvcjtcblxudmFyIEZnRXZlbnRSZW5kZXJlciA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBGZ0V2ZW50UmVuZGVyZXIoKSB7XG4gICAgICAgIHRoaXMuc2VncyA9IFtdO1xuICAgICAgICB0aGlzLmlzU2l6ZURpcnR5ID0gZmFsc2U7XG4gICAgfVxuICAgIEZnRXZlbnRSZW5kZXJlci5wcm90b3R5cGUucmVuZGVyU2VncyA9IGZ1bmN0aW9uIChjb250ZXh0LCBzZWdzLCBtaXJyb3JJbmZvKSB7XG4gICAgICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XG4gICAgICAgIHRoaXMucmFuZ2VVcGRhdGVkKCk7IC8vIGNhbGxlZCB0b28gZnJlcXVlbnRseSA6KFxuICAgICAgICAvLyByZW5kZXIgYW4gYC5lbGAgb24gZWFjaCBzZWdcbiAgICAgICAgLy8gcmV0dXJucyBhIHN1YnNldCBvZiB0aGUgc2Vncy4gc2VncyB0aGF0IHdlcmUgYWN0dWFsbHkgcmVuZGVyZWRcbiAgICAgICAgc2VncyA9IHRoaXMucmVuZGVyU2VnRWxzKHNlZ3MsIG1pcnJvckluZm8pO1xuICAgICAgICB0aGlzLnNlZ3MgPSBzZWdzO1xuICAgICAgICB0aGlzLmF0dGFjaFNlZ3Moc2VncywgbWlycm9ySW5mbyk7XG4gICAgICAgIHRoaXMuaXNTaXplRGlydHkgPSB0cnVlO1xuICAgICAgICB0cmlnZ2VyUmVuZGVyZWRTZWdzKHRoaXMuY29udGV4dCwgdGhpcy5zZWdzLCBCb29sZWFuKG1pcnJvckluZm8pKTtcbiAgICB9O1xuICAgIEZnRXZlbnRSZW5kZXJlci5wcm90b3R5cGUudW5yZW5kZXIgPSBmdW5jdGlvbiAoY29udGV4dCwgX3NlZ3MsIG1pcnJvckluZm8pIHtcbiAgICAgICAgdHJpZ2dlcldpbGxSZW1vdmVTZWdzKHRoaXMuY29udGV4dCwgdGhpcy5zZWdzLCBCb29sZWFuKG1pcnJvckluZm8pKTtcbiAgICAgICAgdGhpcy5kZXRhY2hTZWdzKHRoaXMuc2Vncyk7XG4gICAgICAgIHRoaXMuc2VncyA9IFtdO1xuICAgIH07XG4gICAgLy8gVXBkYXRlcyB2YWx1ZXMgdGhhdCByZWx5IG9uIG9wdGlvbnMgYW5kIGFsc28gcmVsYXRlIHRvIHJhbmdlXG4gICAgRmdFdmVudFJlbmRlcmVyLnByb3RvdHlwZS5yYW5nZVVwZGF0ZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBvcHRpb25zID0gdGhpcy5jb250ZXh0Lm9wdGlvbnM7XG4gICAgICAgIHZhciBkaXNwbGF5RXZlbnRUaW1lO1xuICAgICAgICB2YXIgZGlzcGxheUV2ZW50RW5kO1xuICAgICAgICB0aGlzLmV2ZW50VGltZUZvcm1hdCA9IGNyZWF0ZUZvcm1hdHRlcihvcHRpb25zLmV2ZW50VGltZUZvcm1hdCB8fCB0aGlzLmNvbXB1dGVFdmVudFRpbWVGb3JtYXQoKSwgb3B0aW9ucy5kZWZhdWx0UmFuZ2VTZXBhcmF0b3IpO1xuICAgICAgICBkaXNwbGF5RXZlbnRUaW1lID0gb3B0aW9ucy5kaXNwbGF5RXZlbnRUaW1lO1xuICAgICAgICBpZiAoZGlzcGxheUV2ZW50VGltZSA9PSBudWxsKSB7XG4gICAgICAgICAgICBkaXNwbGF5RXZlbnRUaW1lID0gdGhpcy5jb21wdXRlRGlzcGxheUV2ZW50VGltZSgpOyAvLyBtaWdodCBiZSBiYXNlZCBvZmYgb2YgcmFuZ2VcbiAgICAgICAgfVxuICAgICAgICBkaXNwbGF5RXZlbnRFbmQgPSBvcHRpb25zLmRpc3BsYXlFdmVudEVuZDtcbiAgICAgICAgaWYgKGRpc3BsYXlFdmVudEVuZCA9PSBudWxsKSB7XG4gICAgICAgICAgICBkaXNwbGF5RXZlbnRFbmQgPSB0aGlzLmNvbXB1dGVEaXNwbGF5RXZlbnRFbmQoKTsgLy8gbWlnaHQgYmUgYmFzZWQgb2ZmIG9mIHJhbmdlXG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5kaXNwbGF5RXZlbnRUaW1lID0gZGlzcGxheUV2ZW50VGltZTtcbiAgICAgICAgdGhpcy5kaXNwbGF5RXZlbnRFbmQgPSBkaXNwbGF5RXZlbnRFbmQ7XG4gICAgfTtcbiAgICAvLyBSZW5kZXJzIGFuZCBhc3NpZ25zIGFuIGBlbGAgcHJvcGVydHkgZm9yIGVhY2ggZm9yZWdyb3VuZCBldmVudCBzZWdtZW50LlxuICAgIC8vIE9ubHkgcmV0dXJucyBzZWdtZW50cyB0aGF0IHN1Y2Nlc3NmdWxseSByZW5kZXJlZC5cbiAgICBGZ0V2ZW50UmVuZGVyZXIucHJvdG90eXBlLnJlbmRlclNlZ0VscyA9IGZ1bmN0aW9uIChzZWdzLCBtaXJyb3JJbmZvKSB7XG4gICAgICAgIHZhciBodG1sID0gJyc7XG4gICAgICAgIHZhciBpO1xuICAgICAgICBpZiAoc2Vncy5sZW5ndGgpIHsgLy8gZG9uJ3QgYnVpbGQgYW4gZW1wdHkgaHRtbCBzdHJpbmdcbiAgICAgICAgICAgIC8vIGJ1aWxkIGEgbGFyZ2UgY29uY2F0ZW5hdGlvbiBvZiBldmVudCBzZWdtZW50IEhUTUxcbiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBzZWdzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgaHRtbCArPSB0aGlzLnJlbmRlclNlZ0h0bWwoc2Vnc1tpXSwgbWlycm9ySW5mbyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBHcmFiIGluZGl2aWR1YWwgZWxlbWVudHMgZnJvbSB0aGUgY29tYmluZWQgSFRNTCBzdHJpbmcuIFVzZSBlYWNoIGFzIHRoZSBkZWZhdWx0IHJlbmRlcmluZy5cbiAgICAgICAgICAgIC8vIFRoZW4sIGNvbXB1dGUgdGhlICdlbCcgZm9yIGVhY2ggc2VnbWVudC4gQW4gZWwgbWlnaHQgYmUgbnVsbCBpZiB0aGUgZXZlbnRSZW5kZXIgY2FsbGJhY2sgcmV0dXJuZWQgZmFsc2UuXG4gICAgICAgICAgICBodG1sVG9FbGVtZW50cyhodG1sKS5mb3JFYWNoKGZ1bmN0aW9uIChlbCwgaSkge1xuICAgICAgICAgICAgICAgIHZhciBzZWcgPSBzZWdzW2ldO1xuICAgICAgICAgICAgICAgIGlmIChlbCkge1xuICAgICAgICAgICAgICAgICAgICBzZWcuZWwgPSBlbDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHNlZ3MgPSBmaWx0ZXJTZWdzVmlhRWxzKHRoaXMuY29udGV4dCwgc2VncywgQm9vbGVhbihtaXJyb3JJbmZvKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlZ3M7XG4gICAgfTtcbiAgICAvLyBHZW5lcmljIHV0aWxpdHkgZm9yIGdlbmVyYXRpbmcgdGhlIEhUTUwgY2xhc3NOYW1lcyBmb3IgYW4gZXZlbnQgc2VnbWVudCdzIGVsZW1lbnRcbiAgICBGZ0V2ZW50UmVuZGVyZXIucHJvdG90eXBlLmdldFNlZ0NsYXNzZXMgPSBmdW5jdGlvbiAoc2VnLCBpc0RyYWdnYWJsZSwgaXNSZXNpemFibGUsIG1pcnJvckluZm8pIHtcbiAgICAgICAgdmFyIGNsYXNzZXMgPSBbXG4gICAgICAgICAgICAnZmMtZXZlbnQnLFxuICAgICAgICAgICAgc2VnLmlzU3RhcnQgPyAnZmMtc3RhcnQnIDogJ2ZjLW5vdC1zdGFydCcsXG4gICAgICAgICAgICBzZWcuaXNFbmQgPyAnZmMtZW5kJyA6ICdmYy1ub3QtZW5kJ1xuICAgICAgICBdLmNvbmNhdChzZWcuZXZlbnRSYW5nZS51aS5jbGFzc05hbWVzKTtcbiAgICAgICAgaWYgKGlzRHJhZ2dhYmxlKSB7XG4gICAgICAgICAgICBjbGFzc2VzLnB1c2goJ2ZjLWRyYWdnYWJsZScpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChpc1Jlc2l6YWJsZSkge1xuICAgICAgICAgICAgY2xhc3Nlcy5wdXNoKCdmYy1yZXNpemFibGUnKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobWlycm9ySW5mbykge1xuICAgICAgICAgICAgY2xhc3Nlcy5wdXNoKCdmYy1taXJyb3InKTtcbiAgICAgICAgICAgIGlmIChtaXJyb3JJbmZvLmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgICAgICAgICBjbGFzc2VzLnB1c2goJ2ZjLWRyYWdnaW5nJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobWlycm9ySW5mby5pc1Jlc2l6aW5nKSB7XG4gICAgICAgICAgICAgICAgY2xhc3Nlcy5wdXNoKCdmYy1yZXNpemluZycpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBjbGFzc2VzO1xuICAgIH07XG4gICAgLy8gQ29tcHV0ZSB0aGUgdGV4dCB0aGF0IHNob3VsZCBiZSBkaXNwbGF5ZWQgb24gYW4gZXZlbnQncyBlbGVtZW50LlxuICAgIC8vIGByYW5nZWAgY2FuIGJlIHRoZSBFdmVudCBvYmplY3QgaXRzZWxmLCBvciBzb21ldGhpbmcgcmFuZ2UtbGlrZSwgd2l0aCBhdCBsZWFzdCBhIGBzdGFydGAuXG4gICAgLy8gSWYgZXZlbnQgdGltZXMgYXJlIGRpc2FibGVkLCBvciB0aGUgZXZlbnQgaGFzIG5vIHRpbWUsIHdpbGwgcmV0dXJuIGEgYmxhbmsgc3RyaW5nLlxuICAgIC8vIElmIG5vdCBzcGVjaWZpZWQsIGZvcm1hdHRlciB3aWxsIGRlZmF1bHQgdG8gdGhlIGV2ZW50VGltZUZvcm1hdCBzZXR0aW5nLFxuICAgIC8vIGFuZCBkaXNwbGF5RW5kIHdpbGwgZGVmYXVsdCB0byB0aGUgZGlzcGxheUV2ZW50RW5kIHNldHRpbmcuXG4gICAgRmdFdmVudFJlbmRlcmVyLnByb3RvdHlwZS5nZXRUaW1lVGV4dCA9IGZ1bmN0aW9uIChldmVudFJhbmdlLCBmb3JtYXR0ZXIsIGRpc3BsYXlFbmQpIHtcbiAgICAgICAgdmFyIGRlZiA9IGV2ZW50UmFuZ2UuZGVmLCBpbnN0YW5jZSA9IGV2ZW50UmFuZ2UuaW5zdGFuY2U7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRUaW1lVGV4dChpbnN0YW5jZS5yYW5nZS5zdGFydCwgZGVmLmhhc0VuZCA/IGluc3RhbmNlLnJhbmdlLmVuZCA6IG51bGwsIGRlZi5hbGxEYXksIGZvcm1hdHRlciwgZGlzcGxheUVuZCwgaW5zdGFuY2UuZm9yY2VkU3RhcnRUem8sIGluc3RhbmNlLmZvcmNlZEVuZFR6byk7XG4gICAgfTtcbiAgICBGZ0V2ZW50UmVuZGVyZXIucHJvdG90eXBlLl9nZXRUaW1lVGV4dCA9IGZ1bmN0aW9uIChzdGFydCwgZW5kLCBhbGxEYXksIGZvcm1hdHRlciwgZGlzcGxheUVuZCwgZm9yY2VkU3RhcnRUem8sIGZvcmNlZEVuZFR6bykge1xuICAgICAgICB2YXIgZGF0ZUVudiA9IHRoaXMuY29udGV4dC5kYXRlRW52O1xuICAgICAgICBpZiAoZm9ybWF0dGVyID09IG51bGwpIHtcbiAgICAgICAgICAgIGZvcm1hdHRlciA9IHRoaXMuZXZlbnRUaW1lRm9ybWF0O1xuICAgICAgICB9XG4gICAgICAgIGlmIChkaXNwbGF5RW5kID09IG51bGwpIHtcbiAgICAgICAgICAgIGRpc3BsYXlFbmQgPSB0aGlzLmRpc3BsYXlFdmVudEVuZDtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5kaXNwbGF5RXZlbnRUaW1lICYmICFhbGxEYXkpIHtcbiAgICAgICAgICAgIGlmIChkaXNwbGF5RW5kICYmIGVuZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBkYXRlRW52LmZvcm1hdFJhbmdlKHN0YXJ0LCBlbmQsIGZvcm1hdHRlciwge1xuICAgICAgICAgICAgICAgICAgICBmb3JjZWRTdGFydFR6bzogZm9yY2VkU3RhcnRUem8sXG4gICAgICAgICAgICAgICAgICAgIGZvcmNlZEVuZFR6bzogZm9yY2VkRW5kVHpvXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZGF0ZUVudi5mb3JtYXQoc3RhcnQsIGZvcm1hdHRlciwge1xuICAgICAgICAgICAgICAgICAgICBmb3JjZWRUem86IGZvcmNlZFN0YXJ0VHpvXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH07XG4gICAgRmdFdmVudFJlbmRlcmVyLnByb3RvdHlwZS5jb21wdXRlRXZlbnRUaW1lRm9ybWF0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgaG91cjogJ251bWVyaWMnLFxuICAgICAgICAgICAgbWludXRlOiAnMi1kaWdpdCcsXG4gICAgICAgICAgICBvbWl0WmVyb01pbnV0ZTogdHJ1ZVxuICAgICAgICB9O1xuICAgIH07XG4gICAgRmdFdmVudFJlbmRlcmVyLnByb3RvdHlwZS5jb21wdXRlRGlzcGxheUV2ZW50VGltZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfTtcbiAgICBGZ0V2ZW50UmVuZGVyZXIucHJvdG90eXBlLmNvbXB1dGVEaXNwbGF5RXZlbnRFbmQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH07XG4gICAgLy8gVXRpbGl0eSBmb3IgZ2VuZXJhdGluZyBldmVudCBza2luLXJlbGF0ZWQgQ1NTIHByb3BlcnRpZXNcbiAgICBGZ0V2ZW50UmVuZGVyZXIucHJvdG90eXBlLmdldFNraW5Dc3MgPSBmdW5jdGlvbiAodWkpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICdiYWNrZ3JvdW5kLWNvbG9yJzogdWkuYmFja2dyb3VuZENvbG9yLFxuICAgICAgICAgICAgJ2JvcmRlci1jb2xvcic6IHVpLmJvcmRlckNvbG9yLFxuICAgICAgICAgICAgY29sb3I6IHVpLnRleHRDb2xvclxuICAgICAgICB9O1xuICAgIH07XG4gICAgRmdFdmVudFJlbmRlcmVyLnByb3RvdHlwZS5zb3J0RXZlbnRTZWdzID0gZnVuY3Rpb24gKHNlZ3MpIHtcbiAgICAgICAgdmFyIHNwZWNzID0gdGhpcy5jb250ZXh0LmV2ZW50T3JkZXJTcGVjcztcbiAgICAgICAgdmFyIG9ianMgPSBzZWdzLm1hcChidWlsZFNlZ0NvbXBhcmVPYmopO1xuICAgICAgICBvYmpzLnNvcnQoZnVuY3Rpb24gKG9iajAsIG9iajEpIHtcbiAgICAgICAgICAgIHJldHVybiBjb21wYXJlQnlGaWVsZFNwZWNzKG9iajAsIG9iajEsIHNwZWNzKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBvYmpzLm1hcChmdW5jdGlvbiAoYykge1xuICAgICAgICAgICAgcmV0dXJuIGMuX3NlZztcbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICBGZ0V2ZW50UmVuZGVyZXIucHJvdG90eXBlLmNvbXB1dGVTaXplcyA9IGZ1bmN0aW9uIChmb3JjZSkge1xuICAgICAgICBpZiAoZm9yY2UgfHwgdGhpcy5pc1NpemVEaXJ0eSkge1xuICAgICAgICAgICAgdGhpcy5jb21wdXRlU2VnU2l6ZXModGhpcy5zZWdzKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgRmdFdmVudFJlbmRlcmVyLnByb3RvdHlwZS5hc3NpZ25TaXplcyA9IGZ1bmN0aW9uIChmb3JjZSkge1xuICAgICAgICBpZiAoZm9yY2UgfHwgdGhpcy5pc1NpemVEaXJ0eSkge1xuICAgICAgICAgICAgdGhpcy5hc3NpZ25TZWdTaXplcyh0aGlzLnNlZ3MpO1xuICAgICAgICAgICAgdGhpcy5pc1NpemVEaXJ0eSA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBGZ0V2ZW50UmVuZGVyZXIucHJvdG90eXBlLmNvbXB1dGVTZWdTaXplcyA9IGZ1bmN0aW9uIChzZWdzKSB7XG4gICAgfTtcbiAgICBGZ0V2ZW50UmVuZGVyZXIucHJvdG90eXBlLmFzc2lnblNlZ1NpemVzID0gZnVuY3Rpb24gKHNlZ3MpIHtcbiAgICB9O1xuICAgIC8vIE1hbmlwdWxhdGlvbiBvbiByZW5kZXJlZCBzZWdzXG4gICAgRmdFdmVudFJlbmRlcmVyLnByb3RvdHlwZS5oaWRlQnlIYXNoID0gZnVuY3Rpb24gKGhhc2gpIHtcbiAgICAgICAgaWYgKGhhc2gpIHtcbiAgICAgICAgICAgIGZvciAodmFyIF9pID0gMCwgX2EgPSB0aGlzLnNlZ3M7IF9pIDwgX2EubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIHNlZyA9IF9hW19pXTtcbiAgICAgICAgICAgICAgICBpZiAoaGFzaFtzZWcuZXZlbnRSYW5nZS5pbnN0YW5jZS5pbnN0YW5jZUlkXSkge1xuICAgICAgICAgICAgICAgICAgICBzZWcuZWwuc3R5bGUudmlzaWJpbGl0eSA9ICdoaWRkZW4nO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG4gICAgRmdFdmVudFJlbmRlcmVyLnByb3RvdHlwZS5zaG93QnlIYXNoID0gZnVuY3Rpb24gKGhhc2gpIHtcbiAgICAgICAgaWYgKGhhc2gpIHtcbiAgICAgICAgICAgIGZvciAodmFyIF9pID0gMCwgX2EgPSB0aGlzLnNlZ3M7IF9pIDwgX2EubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIHNlZyA9IF9hW19pXTtcbiAgICAgICAgICAgICAgICBpZiAoaGFzaFtzZWcuZXZlbnRSYW5nZS5pbnN0YW5jZS5pbnN0YW5jZUlkXSkge1xuICAgICAgICAgICAgICAgICAgICBzZWcuZWwuc3R5bGUudmlzaWJpbGl0eSA9ICcnO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG4gICAgRmdFdmVudFJlbmRlcmVyLnByb3RvdHlwZS5zZWxlY3RCeUluc3RhbmNlSWQgPSBmdW5jdGlvbiAoaW5zdGFuY2VJZCkge1xuICAgICAgICBpZiAoaW5zdGFuY2VJZCkge1xuICAgICAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBfYSA9IHRoaXMuc2VnczsgX2kgPCBfYS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgc2VnID0gX2FbX2ldO1xuICAgICAgICAgICAgICAgIHZhciBldmVudEluc3RhbmNlID0gc2VnLmV2ZW50UmFuZ2UuaW5zdGFuY2U7XG4gICAgICAgICAgICAgICAgaWYgKGV2ZW50SW5zdGFuY2UgJiYgZXZlbnRJbnN0YW5jZS5pbnN0YW5jZUlkID09PSBpbnN0YW5jZUlkICYmXG4gICAgICAgICAgICAgICAgICAgIHNlZy5lbCAvLyBuZWNlc3Nhcnk/XG4gICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgIHNlZy5lbC5jbGFzc0xpc3QuYWRkKCdmYy1zZWxlY3RlZCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG4gICAgRmdFdmVudFJlbmRlcmVyLnByb3RvdHlwZS51bnNlbGVjdEJ5SW5zdGFuY2VJZCA9IGZ1bmN0aW9uIChpbnN0YW5jZUlkKSB7XG4gICAgICAgIGlmIChpbnN0YW5jZUlkKSB7XG4gICAgICAgICAgICBmb3IgKHZhciBfaSA9IDAsIF9hID0gdGhpcy5zZWdzOyBfaSA8IF9hLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgICAgIHZhciBzZWcgPSBfYVtfaV07XG4gICAgICAgICAgICAgICAgaWYgKHNlZy5lbCkgeyAvLyBuZWNlc3Nhcnk/XG4gICAgICAgICAgICAgICAgICAgIHNlZy5lbC5jbGFzc0xpc3QucmVtb3ZlKCdmYy1zZWxlY3RlZCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG4gICAgcmV0dXJuIEZnRXZlbnRSZW5kZXJlcjtcbn0oKSk7XG4vLyByZXR1cm5zIGEgb2JqZWN0IHdpdGggYWxsIHByaW1pdGl2ZSBwcm9wcyB0aGF0IGNhbiBiZSBjb21wYXJlZFxuZnVuY3Rpb24gYnVpbGRTZWdDb21wYXJlT2JqKHNlZykge1xuICAgIHZhciBldmVudERlZiA9IHNlZy5ldmVudFJhbmdlLmRlZjtcbiAgICB2YXIgcmFuZ2UgPSBzZWcuZXZlbnRSYW5nZS5pbnN0YW5jZS5yYW5nZTtcbiAgICB2YXIgc3RhcnQgPSByYW5nZS5zdGFydCA/IHJhbmdlLnN0YXJ0LnZhbHVlT2YoKSA6IDA7IC8vIFRPRE86IGJldHRlciBzdXBwb3J0IGZvciBvcGVuLXJhbmdlIGV2ZW50c1xuICAgIHZhciBlbmQgPSByYW5nZS5lbmQgPyByYW5nZS5lbmQudmFsdWVPZigpIDogMDsgLy8gXCJcbiAgICByZXR1cm4gX19hc3NpZ24oe30sIGV2ZW50RGVmLmV4dGVuZGVkUHJvcHMsIGV2ZW50RGVmLCB7IGlkOiBldmVudERlZi5wdWJsaWNJZCwgc3RhcnQ6IHN0YXJ0LFxuICAgICAgICBlbmQ6IGVuZCwgZHVyYXRpb246IGVuZCAtIHN0YXJ0LCBhbGxEYXk6IE51bWJlcihldmVudERlZi5hbGxEYXkpLCBfc2VnOiBzZWcgLy8gZm9yIGxhdGVyIHJldHJpZXZhbFxuICAgICB9KTtcbn1cblxuLypcblRPRE86IHdoZW4gcmVmYWN0b3JpbmcgdGhpcyBjbGFzcywgbWFrZSBhIG5ldyBGaWxsUmVuZGVyZXIgaW5zdGFuY2UgZm9yIGVhY2ggYHR5cGVgXG4qL1xudmFyIEZpbGxSZW5kZXJlciA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBGaWxsUmVuZGVyZXIoKSB7XG4gICAgICAgIHRoaXMuZmlsbFNlZ1RhZyA9ICdkaXYnO1xuICAgICAgICB0aGlzLmRpcnR5U2l6ZUZsYWdzID0ge307XG4gICAgICAgIHRoaXMuY29udGFpbmVyRWxzQnlUeXBlID0ge307XG4gICAgICAgIHRoaXMuc2Vnc0J5VHlwZSA9IHt9O1xuICAgIH1cbiAgICBGaWxsUmVuZGVyZXIucHJvdG90eXBlLmdldFNlZ3NCeVR5cGUgPSBmdW5jdGlvbiAodHlwZSkge1xuICAgICAgICByZXR1cm4gdGhpcy5zZWdzQnlUeXBlW3R5cGVdIHx8IFtdO1xuICAgIH07XG4gICAgRmlsbFJlbmRlcmVyLnByb3RvdHlwZS5yZW5kZXJTZWdzID0gZnVuY3Rpb24gKHR5cGUsIGNvbnRleHQsIHNlZ3MpIHtcbiAgICAgICAgdmFyIF9hO1xuICAgICAgICB0aGlzLmNvbnRleHQgPSBjb250ZXh0O1xuICAgICAgICB2YXIgcmVuZGVyZWRTZWdzID0gdGhpcy5yZW5kZXJTZWdFbHModHlwZSwgc2Vncyk7IC8vIGFzc2lnbmVzIGAuZWxgIHRvIGVhY2ggc2VnLiByZXR1cm5zIHN1Y2Nlc3NmdWxseSByZW5kZXJlZCBzZWdzXG4gICAgICAgIHZhciBjb250YWluZXJFbHMgPSB0aGlzLmF0dGFjaFNlZ3ModHlwZSwgcmVuZGVyZWRTZWdzKTtcbiAgICAgICAgaWYgKGNvbnRhaW5lckVscykge1xuICAgICAgICAgICAgKF9hID0gKHRoaXMuY29udGFpbmVyRWxzQnlUeXBlW3R5cGVdIHx8ICh0aGlzLmNvbnRhaW5lckVsc0J5VHlwZVt0eXBlXSA9IFtdKSkpLnB1c2guYXBwbHkoX2EsIGNvbnRhaW5lckVscyk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zZWdzQnlUeXBlW3R5cGVdID0gcmVuZGVyZWRTZWdzO1xuICAgICAgICBpZiAodHlwZSA9PT0gJ2JnRXZlbnQnKSB7XG4gICAgICAgICAgICB0cmlnZ2VyUmVuZGVyZWRTZWdzKGNvbnRleHQsIHJlbmRlcmVkU2VncywgZmFsc2UpOyAvLyBpc01pcnJvcj1mYWxzZVxuICAgICAgICB9XG4gICAgICAgIHRoaXMuZGlydHlTaXplRmxhZ3NbdHlwZV0gPSB0cnVlO1xuICAgIH07XG4gICAgLy8gVW5yZW5kZXJzIGEgc3BlY2lmaWMgdHlwZSBvZiBmaWxsIHRoYXQgaXMgY3VycmVudGx5IHJlbmRlcmVkIG9uIHRoZSBncmlkXG4gICAgRmlsbFJlbmRlcmVyLnByb3RvdHlwZS51bnJlbmRlciA9IGZ1bmN0aW9uICh0eXBlLCBjb250ZXh0KSB7XG4gICAgICAgIHZhciBzZWdzID0gdGhpcy5zZWdzQnlUeXBlW3R5cGVdO1xuICAgICAgICBpZiAoc2Vncykge1xuICAgICAgICAgICAgaWYgKHR5cGUgPT09ICdiZ0V2ZW50Jykge1xuICAgICAgICAgICAgICAgIHRyaWdnZXJXaWxsUmVtb3ZlU2Vncyhjb250ZXh0LCBzZWdzLCBmYWxzZSk7IC8vIGlzTWlycm9yPWZhbHNlXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmRldGFjaFNlZ3ModHlwZSwgc2Vncyk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8vIFJlbmRlcnMgYW5kIGFzc2lnbnMgYW4gYGVsYCBwcm9wZXJ0eSBmb3IgZWFjaCBmaWxsIHNlZ21lbnQuIEdlbmVyaWMgZW5vdWdoIHRvIHdvcmsgd2l0aCBkaWZmZXJlbnQgdHlwZXMuXG4gICAgLy8gT25seSByZXR1cm5zIHNlZ21lbnRzIHRoYXQgc3VjY2Vzc2Z1bGx5IHJlbmRlcmVkLlxuICAgIEZpbGxSZW5kZXJlci5wcm90b3R5cGUucmVuZGVyU2VnRWxzID0gZnVuY3Rpb24gKHR5cGUsIHNlZ3MpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGh0bWwgPSAnJztcbiAgICAgICAgdmFyIGk7XG4gICAgICAgIGlmIChzZWdzLmxlbmd0aCkge1xuICAgICAgICAgICAgLy8gYnVpbGQgYSBsYXJnZSBjb25jYXRlbmF0aW9uIG9mIHNlZ21lbnQgSFRNTFxuICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IHNlZ3MubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBodG1sICs9IHRoaXMucmVuZGVyU2VnSHRtbCh0eXBlLCBzZWdzW2ldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEdyYWIgaW5kaXZpZHVhbCBlbGVtZW50cyBmcm9tIHRoZSBjb21iaW5lZCBIVE1MIHN0cmluZy4gVXNlIGVhY2ggYXMgdGhlIGRlZmF1bHQgcmVuZGVyaW5nLlxuICAgICAgICAgICAgLy8gVGhlbiwgY29tcHV0ZSB0aGUgJ2VsJyBmb3IgZWFjaCBzZWdtZW50LlxuICAgICAgICAgICAgaHRtbFRvRWxlbWVudHMoaHRtbCkuZm9yRWFjaChmdW5jdGlvbiAoZWwsIGkpIHtcbiAgICAgICAgICAgICAgICB2YXIgc2VnID0gc2Vnc1tpXTtcbiAgICAgICAgICAgICAgICBpZiAoZWwpIHtcbiAgICAgICAgICAgICAgICAgICAgc2VnLmVsID0gZWw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBpZiAodHlwZSA9PT0gJ2JnRXZlbnQnKSB7XG4gICAgICAgICAgICAgICAgc2VncyA9IGZpbHRlclNlZ3NWaWFFbHModGhpcy5jb250ZXh0LCBzZWdzLCBmYWxzZSAvLyBpc01pcnJvci4gYmFja2dyb3VuZCBldmVudHMgY2FuIG5ldmVyIGJlIG1pcnJvciBlbGVtZW50c1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBjb3JyZWN0IGVsZW1lbnQgdHlwZT8gKHdvdWxkIGJlIGJhZCBpZiBhIG5vbi1URCB3ZXJlIGluc2VydGVkIGludG8gYSB0YWJsZSBmb3IgZXhhbXBsZSlcbiAgICAgICAgICAgIHNlZ3MgPSBzZWdzLmZpbHRlcihmdW5jdGlvbiAoc2VnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGVsZW1lbnRNYXRjaGVzKHNlZy5lbCwgX3RoaXMuZmlsbFNlZ1RhZyk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2VncztcbiAgICB9O1xuICAgIC8vIEJ1aWxkcyB0aGUgSFRNTCBuZWVkZWQgZm9yIG9uZSBmaWxsIHNlZ21lbnQuIEdlbmVyaWMgZW5vdWdoIHRvIHdvcmsgd2l0aCBkaWZmZXJlbnQgdHlwZXMuXG4gICAgRmlsbFJlbmRlcmVyLnByb3RvdHlwZS5yZW5kZXJTZWdIdG1sID0gZnVuY3Rpb24gKHR5cGUsIHNlZykge1xuICAgICAgICB2YXIgY3NzID0gbnVsbDtcbiAgICAgICAgdmFyIGNsYXNzTmFtZXMgPSBbXTtcbiAgICAgICAgaWYgKHR5cGUgIT09ICdoaWdobGlnaHQnICYmIHR5cGUgIT09ICdidXNpbmVzc0hvdXJzJykge1xuICAgICAgICAgICAgY3NzID0ge1xuICAgICAgICAgICAgICAgICdiYWNrZ3JvdW5kLWNvbG9yJzogc2VnLmV2ZW50UmFuZ2UudWkuYmFja2dyb3VuZENvbG9yXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlICE9PSAnaGlnaGxpZ2h0Jykge1xuICAgICAgICAgICAgY2xhc3NOYW1lcyA9IGNsYXNzTmFtZXMuY29uY2F0KHNlZy5ldmVudFJhbmdlLnVpLmNsYXNzTmFtZXMpO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlID09PSAnYnVzaW5lc3NIb3VycycpIHtcbiAgICAgICAgICAgIGNsYXNzTmFtZXMucHVzaCgnZmMtYmdldmVudCcpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgY2xhc3NOYW1lcy5wdXNoKCdmYy0nICsgdHlwZS50b0xvd2VyQ2FzZSgpKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gJzwnICsgdGhpcy5maWxsU2VnVGFnICtcbiAgICAgICAgICAgIChjbGFzc05hbWVzLmxlbmd0aCA/ICcgY2xhc3M9XCInICsgY2xhc3NOYW1lcy5qb2luKCcgJykgKyAnXCInIDogJycpICtcbiAgICAgICAgICAgIChjc3MgPyAnIHN0eWxlPVwiJyArIGNzc1RvU3RyKGNzcykgKyAnXCInIDogJycpICtcbiAgICAgICAgICAgICc+PC8nICsgdGhpcy5maWxsU2VnVGFnICsgJz4nO1xuICAgIH07XG4gICAgRmlsbFJlbmRlcmVyLnByb3RvdHlwZS5kZXRhY2hTZWdzID0gZnVuY3Rpb24gKHR5cGUsIHNlZ3MpIHtcbiAgICAgICAgdmFyIGNvbnRhaW5lckVscyA9IHRoaXMuY29udGFpbmVyRWxzQnlUeXBlW3R5cGVdO1xuICAgICAgICBpZiAoY29udGFpbmVyRWxzKSB7XG4gICAgICAgICAgICBjb250YWluZXJFbHMuZm9yRWFjaChyZW1vdmVFbGVtZW50KTtcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLmNvbnRhaW5lckVsc0J5VHlwZVt0eXBlXTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgRmlsbFJlbmRlcmVyLnByb3RvdHlwZS5jb21wdXRlU2l6ZXMgPSBmdW5jdGlvbiAoZm9yY2UpIHtcbiAgICAgICAgZm9yICh2YXIgdHlwZSBpbiB0aGlzLnNlZ3NCeVR5cGUpIHtcbiAgICAgICAgICAgIGlmIChmb3JjZSB8fCB0aGlzLmRpcnR5U2l6ZUZsYWdzW3R5cGVdKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jb21wdXRlU2VnU2l6ZXModGhpcy5zZWdzQnlUeXBlW3R5cGVdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG4gICAgRmlsbFJlbmRlcmVyLnByb3RvdHlwZS5hc3NpZ25TaXplcyA9IGZ1bmN0aW9uIChmb3JjZSkge1xuICAgICAgICBmb3IgKHZhciB0eXBlIGluIHRoaXMuc2Vnc0J5VHlwZSkge1xuICAgICAgICAgICAgaWYgKGZvcmNlIHx8IHRoaXMuZGlydHlTaXplRmxhZ3NbdHlwZV0pIHtcbiAgICAgICAgICAgICAgICB0aGlzLmFzc2lnblNlZ1NpemVzKHRoaXMuc2Vnc0J5VHlwZVt0eXBlXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5kaXJ0eVNpemVGbGFncyA9IHt9O1xuICAgIH07XG4gICAgRmlsbFJlbmRlcmVyLnByb3RvdHlwZS5jb21wdXRlU2VnU2l6ZXMgPSBmdW5jdGlvbiAoc2Vncykge1xuICAgIH07XG4gICAgRmlsbFJlbmRlcmVyLnByb3RvdHlwZS5hc3NpZ25TZWdTaXplcyA9IGZ1bmN0aW9uIChzZWdzKSB7XG4gICAgfTtcbiAgICByZXR1cm4gRmlsbFJlbmRlcmVyO1xufSgpKTtcblxudmFyIE5hbWVkVGltZVpvbmVJbXBsID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIE5hbWVkVGltZVpvbmVJbXBsKHRpbWVab25lTmFtZSkge1xuICAgICAgICB0aGlzLnRpbWVab25lTmFtZSA9IHRpbWVab25lTmFtZTtcbiAgICB9XG4gICAgcmV0dXJuIE5hbWVkVGltZVpvbmVJbXBsO1xufSgpKTtcblxuLypcbkFuIGFic3RyYWN0aW9uIGZvciBhIGRyYWdnaW5nIGludGVyYWN0aW9uIG9yaWdpbmF0aW5nIG9uIGFuIGV2ZW50LlxuRG9lcyBoaWdoZXItbGV2ZWwgdGhpbmdzIHRoYW4gUG9pbnRlckRyYWdnZXIsIHN1Y2ggYXMgcG9zc2libHk6XG4tIGEgXCJtaXJyb3JcIiB0aGF0IG1vdmVzIHdpdGggdGhlIHBvaW50ZXJcbi0gYSBtaW5pbXVtIG51bWJlciBvZiBwaXhlbHMgb3Igb3RoZXIgY3JpdGVyaWEgZm9yIGEgdHJ1ZSBkcmFnIHRvIGJlZ2luXG5cbnN1YmNsYXNzZXMgbXVzdCBlbWl0OlxuLSBwb2ludGVyZG93blxuLSBkcmFnc3RhcnRcbi0gZHJhZ21vdmVcbi0gcG9pbnRlcnVwXG4tIGRyYWdlbmRcbiovXG52YXIgRWxlbWVudERyYWdnaW5nID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIEVsZW1lbnREcmFnZ2luZyhlbCkge1xuICAgICAgICB0aGlzLmVtaXR0ZXIgPSBuZXcgRW1pdHRlck1peGluKCk7XG4gICAgfVxuICAgIEVsZW1lbnREcmFnZ2luZy5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICB9O1xuICAgIEVsZW1lbnREcmFnZ2luZy5wcm90b3R5cGUuc2V0TWlycm9ySXNWaXNpYmxlID0gZnVuY3Rpb24gKGJvb2wpIHtcbiAgICAgICAgLy8gb3B0aW9uYWwgaWYgc3ViY2xhc3MgZG9lc24ndCB3YW50IHRvIHN1cHBvcnQgYSBtaXJyb3JcbiAgICB9O1xuICAgIEVsZW1lbnREcmFnZ2luZy5wcm90b3R5cGUuc2V0TWlycm9yTmVlZHNSZXZlcnQgPSBmdW5jdGlvbiAoYm9vbCkge1xuICAgICAgICAvLyBvcHRpb25hbCBpZiBzdWJjbGFzcyBkb2Vzbid0IHdhbnQgdG8gc3VwcG9ydCBhIG1pcnJvclxuICAgIH07XG4gICAgRWxlbWVudERyYWdnaW5nLnByb3RvdHlwZS5zZXRBdXRvU2Nyb2xsRW5hYmxlZCA9IGZ1bmN0aW9uIChib29sKSB7XG4gICAgICAgIC8vIG9wdGlvbmFsXG4gICAgfTtcbiAgICByZXR1cm4gRWxlbWVudERyYWdnaW5nO1xufSgpKTtcblxuZnVuY3Rpb24gZm9ybWF0RGF0ZShkYXRlSW5wdXQsIHNldHRpbmdzKSB7XG4gICAgaWYgKHNldHRpbmdzID09PSB2b2lkIDApIHsgc2V0dGluZ3MgPSB7fTsgfVxuICAgIHZhciBkYXRlRW52ID0gYnVpbGREYXRlRW52JDEoc2V0dGluZ3MpO1xuICAgIHZhciBmb3JtYXR0ZXIgPSBjcmVhdGVGb3JtYXR0ZXIoc2V0dGluZ3MpO1xuICAgIHZhciBkYXRlTWV0YSA9IGRhdGVFbnYuY3JlYXRlTWFya2VyTWV0YShkYXRlSW5wdXQpO1xuICAgIGlmICghZGF0ZU1ldGEpIHsgLy8gVE9ETzogd2FybmluZz9cbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH1cbiAgICByZXR1cm4gZGF0ZUVudi5mb3JtYXQoZGF0ZU1ldGEubWFya2VyLCBmb3JtYXR0ZXIsIHtcbiAgICAgICAgZm9yY2VkVHpvOiBkYXRlTWV0YS5mb3JjZWRUem9cbiAgICB9KTtcbn1cbmZ1bmN0aW9uIGZvcm1hdFJhbmdlKHN0YXJ0SW5wdXQsIGVuZElucHV0LCBzZXR0aW5ncyAvLyBtaXh0dXJlIG9mIGVudiBhbmQgZm9ybWF0dGVyIHNldHRpbmdzXG4pIHtcbiAgICB2YXIgZGF0ZUVudiA9IGJ1aWxkRGF0ZUVudiQxKHR5cGVvZiBzZXR0aW5ncyA9PT0gJ29iamVjdCcgJiYgc2V0dGluZ3MgPyBzZXR0aW5ncyA6IHt9KTsgLy8gcGFzcyBpbiBpZiBub24tbnVsbCBvYmplY3RcbiAgICB2YXIgZm9ybWF0dGVyID0gY3JlYXRlRm9ybWF0dGVyKHNldHRpbmdzLCBnbG9iYWxEZWZhdWx0cy5kZWZhdWx0UmFuZ2VTZXBhcmF0b3IpO1xuICAgIHZhciBzdGFydE1ldGEgPSBkYXRlRW52LmNyZWF0ZU1hcmtlck1ldGEoc3RhcnRJbnB1dCk7XG4gICAgdmFyIGVuZE1ldGEgPSBkYXRlRW52LmNyZWF0ZU1hcmtlck1ldGEoZW5kSW5wdXQpO1xuICAgIGlmICghc3RhcnRNZXRhIHx8ICFlbmRNZXRhKSB7IC8vIFRPRE86IHdhcm5pbmc/XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9XG4gICAgcmV0dXJuIGRhdGVFbnYuZm9ybWF0UmFuZ2Uoc3RhcnRNZXRhLm1hcmtlciwgZW5kTWV0YS5tYXJrZXIsIGZvcm1hdHRlciwge1xuICAgICAgICBmb3JjZWRTdGFydFR6bzogc3RhcnRNZXRhLmZvcmNlZFR6byxcbiAgICAgICAgZm9yY2VkRW5kVHpvOiBlbmRNZXRhLmZvcmNlZFR6byxcbiAgICAgICAgaXNFbmRFeGNsdXNpdmU6IHNldHRpbmdzLmlzRW5kRXhjbHVzaXZlXG4gICAgfSk7XG59XG4vLyBUT0RPOiBtb3JlIERSWSBhbmQgb3B0aW1pemVkXG5mdW5jdGlvbiBidWlsZERhdGVFbnYkMShzZXR0aW5ncykge1xuICAgIHZhciBsb2NhbGUgPSBidWlsZExvY2FsZShzZXR0aW5ncy5sb2NhbGUgfHwgJ2VuJywgcGFyc2VSYXdMb2NhbGVzKFtdKS5tYXApOyAvLyBUT0RPOiBkb24ndCBoYXJkY29kZSAnZW4nIGV2ZXJ5d2hlcmVcbiAgICAvLyBlbnN1cmUgcmVxdWlyZWQgc2V0dGluZ3NcbiAgICBzZXR0aW5ncyA9IF9fYXNzaWduKHsgdGltZVpvbmU6IGdsb2JhbERlZmF1bHRzLnRpbWVab25lLCBjYWxlbmRhclN5c3RlbTogJ2dyZWdvcnknIH0sIHNldHRpbmdzLCB7IGxvY2FsZTogbG9jYWxlIH0pO1xuICAgIHJldHVybiBuZXcgRGF0ZUVudihzZXR0aW5ncyk7XG59XG5cbnZhciBEUkFHX01FVEFfUFJPUFMgPSB7XG4gICAgc3RhcnRUaW1lOiBjcmVhdGVEdXJhdGlvbixcbiAgICBkdXJhdGlvbjogY3JlYXRlRHVyYXRpb24sXG4gICAgY3JlYXRlOiBCb29sZWFuLFxuICAgIHNvdXJjZUlkOiBTdHJpbmdcbn07XG52YXIgRFJBR19NRVRBX0RFRkFVTFRTID0ge1xuICAgIGNyZWF0ZTogdHJ1ZVxufTtcbmZ1bmN0aW9uIHBhcnNlRHJhZ01ldGEocmF3KSB7XG4gICAgdmFyIGxlZnRvdmVyUHJvcHMgPSB7fTtcbiAgICB2YXIgcmVmaW5lZCA9IHJlZmluZVByb3BzKHJhdywgRFJBR19NRVRBX1BST1BTLCBEUkFHX01FVEFfREVGQVVMVFMsIGxlZnRvdmVyUHJvcHMpO1xuICAgIHJlZmluZWQubGVmdG92ZXJQcm9wcyA9IGxlZnRvdmVyUHJvcHM7XG4gICAgcmV0dXJuIHJlZmluZWQ7XG59XG5cbi8vIENvbXB1dGVzIGEgZGVmYXVsdCBjb2x1bW4gaGVhZGVyIGZvcm1hdHRpbmcgc3RyaW5nIGlmIGBjb2xGb3JtYXRgIGlzIG5vdCBleHBsaWNpdGx5IGRlZmluZWRcbmZ1bmN0aW9uIGNvbXB1dGVGYWxsYmFja0hlYWRlckZvcm1hdChkYXRlc1JlcERpc3RpbmN0RGF5cywgZGF5Q250KSB7XG4gICAgLy8gaWYgbW9yZSB0aGFuIG9uZSB3ZWVrIHJvdywgb3IgaWYgdGhlcmUgYXJlIGEgbG90IG9mIGNvbHVtbnMgd2l0aCBub3QgbXVjaCBzcGFjZSxcbiAgICAvLyBwdXQganVzdCB0aGUgZGF5IG51bWJlcnMgd2lsbCBiZSBpbiBlYWNoIGNlbGxcbiAgICBpZiAoIWRhdGVzUmVwRGlzdGluY3REYXlzIHx8IGRheUNudCA+IDEwKSB7XG4gICAgICAgIHJldHVybiB7IHdlZWtkYXk6ICdzaG9ydCcgfTsgLy8gXCJTYXRcIlxuICAgIH1cbiAgICBlbHNlIGlmIChkYXlDbnQgPiAxKSB7XG4gICAgICAgIHJldHVybiB7IHdlZWtkYXk6ICdzaG9ydCcsIG1vbnRoOiAnbnVtZXJpYycsIGRheTogJ251bWVyaWMnLCBvbWl0Q29tbWFzOiB0cnVlIH07IC8vIFwiU2F0IDExLzEyXCJcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHJldHVybiB7IHdlZWtkYXk6ICdsb25nJyB9OyAvLyBcIlNhdHVyZGF5XCJcbiAgICB9XG59XG5mdW5jdGlvbiByZW5kZXJEYXRlQ2VsbChkYXRlTWFya2VyLCBkYXRlUHJvZmlsZSwgZGF0ZXNSZXBEaXN0aW5jdERheXMsIGNvbENudCwgY29sSGVhZEZvcm1hdCwgY29udGV4dCwgY29sc3Bhbiwgb3RoZXJBdHRycykge1xuICAgIHZhciBkYXRlRW52ID0gY29udGV4dC5kYXRlRW52LCB0aGVtZSA9IGNvbnRleHQudGhlbWUsIG9wdGlvbnMgPSBjb250ZXh0Lm9wdGlvbnM7XG4gICAgdmFyIGlzRGF0ZVZhbGlkID0gcmFuZ2VDb250YWluc01hcmtlcihkYXRlUHJvZmlsZS5hY3RpdmVSYW5nZSwgZGF0ZU1hcmtlcik7IC8vIFRPRE86IGNhbGxlZCB0b28gZnJlcXVlbnRseS4gY2FjaGUgc29tZWhvdy5cbiAgICB2YXIgY2xhc3NOYW1lcyA9IFtcbiAgICAgICAgJ2ZjLWRheS1oZWFkZXInLFxuICAgICAgICB0aGVtZS5nZXRDbGFzcygnd2lkZ2V0SGVhZGVyJylcbiAgICBdO1xuICAgIHZhciBpbm5lckh0bWw7XG4gICAgaWYgKHR5cGVvZiBvcHRpb25zLmNvbHVtbkhlYWRlckh0bWwgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgaW5uZXJIdG1sID0gb3B0aW9ucy5jb2x1bW5IZWFkZXJIdG1sKGRhdGVFbnYudG9EYXRlKGRhdGVNYXJrZXIpKTtcbiAgICB9XG4gICAgZWxzZSBpZiAodHlwZW9mIG9wdGlvbnMuY29sdW1uSGVhZGVyVGV4dCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBpbm5lckh0bWwgPSBodG1sRXNjYXBlKG9wdGlvbnMuY29sdW1uSGVhZGVyVGV4dChkYXRlRW52LnRvRGF0ZShkYXRlTWFya2VyKSkpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgaW5uZXJIdG1sID0gaHRtbEVzY2FwZShkYXRlRW52LmZvcm1hdChkYXRlTWFya2VyLCBjb2xIZWFkRm9ybWF0KSk7XG4gICAgfVxuICAgIC8vIGlmIG9ubHkgb25lIHJvdyBvZiBkYXlzLCB0aGUgY2xhc3NOYW1lcyBvbiB0aGUgaGVhZGVyIGNhbiByZXByZXNlbnQgdGhlIHNwZWNpZmljIGRheXMgYmVuZWF0aFxuICAgIGlmIChkYXRlc1JlcERpc3RpbmN0RGF5cykge1xuICAgICAgICBjbGFzc05hbWVzID0gY2xhc3NOYW1lcy5jb25jYXQoXG4gICAgICAgIC8vIGluY2x1ZGVzIHRoZSBkYXktb2Ytd2VlayBjbGFzc1xuICAgICAgICAvLyBub1RoZW1lSGlnaGxpZ2h0PXRydWUgKGRvbid0IGhpZ2hsaWdodCB0aGUgaGVhZGVyKVxuICAgICAgICBnZXREYXlDbGFzc2VzKGRhdGVNYXJrZXIsIGRhdGVQcm9maWxlLCBjb250ZXh0LCB0cnVlKSk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBjbGFzc05hbWVzLnB1c2goJ2ZjLScgKyBEQVlfSURTW2RhdGVNYXJrZXIuZ2V0VVRDRGF5KCldKTsgLy8gb25seSBhZGQgdGhlIGRheS1vZi13ZWVrIGNsYXNzXG4gICAgfVxuICAgIHJldHVybiAnJyArXG4gICAgICAgICc8dGggY2xhc3M9XCInICsgY2xhc3NOYW1lcy5qb2luKCcgJykgKyAnXCInICtcbiAgICAgICAgKChpc0RhdGVWYWxpZCAmJiBkYXRlc1JlcERpc3RpbmN0RGF5cykgP1xuICAgICAgICAgICAgJyBkYXRhLWRhdGU9XCInICsgZGF0ZUVudi5mb3JtYXRJc28oZGF0ZU1hcmtlciwgeyBvbWl0VGltZTogdHJ1ZSB9KSArICdcIicgOlxuICAgICAgICAgICAgJycpICtcbiAgICAgICAgKGNvbHNwYW4gPiAxID9cbiAgICAgICAgICAgICcgY29sc3Bhbj1cIicgKyBjb2xzcGFuICsgJ1wiJyA6XG4gICAgICAgICAgICAnJykgK1xuICAgICAgICAob3RoZXJBdHRycyA/XG4gICAgICAgICAgICAnICcgKyBvdGhlckF0dHJzIDpcbiAgICAgICAgICAgICcnKSArXG4gICAgICAgICc+JyArXG4gICAgICAgIChpc0RhdGVWYWxpZCA/XG4gICAgICAgICAgICAvLyBkb24ndCBtYWtlIGEgbGluayBpZiB0aGUgaGVhZGluZyBjb3VsZCByZXByZXNlbnQgbXVsdGlwbGUgZGF5cywgb3IgaWYgdGhlcmUncyBvbmx5IG9uZSBkYXkgKGZvcmNlT2ZmKVxuICAgICAgICAgICAgYnVpbGRHb3RvQW5jaG9ySHRtbChvcHRpb25zLCBkYXRlRW52LCB7IGRhdGU6IGRhdGVNYXJrZXIsIGZvcmNlT2ZmOiAhZGF0ZXNSZXBEaXN0aW5jdERheXMgfHwgY29sQ250ID09PSAxIH0sIGlubmVySHRtbCkgOlxuICAgICAgICAgICAgLy8gaWYgbm90IHZhbGlkLCBkaXNwbGF5IHRleHQsIGJ1dCBubyBsaW5rXG4gICAgICAgICAgICBpbm5lckh0bWwpICtcbiAgICAgICAgJzwvdGg+Jztcbn1cblxudmFyIERheUhlYWRlciA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uIChfc3VwZXIpIHtcbiAgICBfX2V4dGVuZHMoRGF5SGVhZGVyLCBfc3VwZXIpO1xuICAgIGZ1bmN0aW9uIERheUhlYWRlcihwYXJlbnRFbCkge1xuICAgICAgICB2YXIgX3RoaXMgPSBfc3VwZXIuY2FsbCh0aGlzKSB8fCB0aGlzO1xuICAgICAgICBfdGhpcy5yZW5kZXJTa2VsZXRvbiA9IG1lbW9pemVSZW5kZXJpbmcoX3RoaXMuX3JlbmRlclNrZWxldG9uLCBfdGhpcy5fdW5yZW5kZXJTa2VsZXRvbik7XG4gICAgICAgIF90aGlzLnBhcmVudEVsID0gcGFyZW50RWw7XG4gICAgICAgIHJldHVybiBfdGhpcztcbiAgICB9XG4gICAgRGF5SGVhZGVyLnByb3RvdHlwZS5yZW5kZXIgPSBmdW5jdGlvbiAocHJvcHMsIGNvbnRleHQpIHtcbiAgICAgICAgdmFyIGRhdGVzID0gcHJvcHMuZGF0ZXMsIGRhdGVzUmVwRGlzdGluY3REYXlzID0gcHJvcHMuZGF0ZXNSZXBEaXN0aW5jdERheXM7XG4gICAgICAgIHZhciBwYXJ0cyA9IFtdO1xuICAgICAgICB0aGlzLnJlbmRlclNrZWxldG9uKGNvbnRleHQpO1xuICAgICAgICBpZiAocHJvcHMucmVuZGVySW50cm9IdG1sKSB7XG4gICAgICAgICAgICBwYXJ0cy5wdXNoKHByb3BzLnJlbmRlckludHJvSHRtbCgpKTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgY29sSGVhZEZvcm1hdCA9IGNyZWF0ZUZvcm1hdHRlcihjb250ZXh0Lm9wdGlvbnMuY29sdW1uSGVhZGVyRm9ybWF0IHx8XG4gICAgICAgICAgICBjb21wdXRlRmFsbGJhY2tIZWFkZXJGb3JtYXQoZGF0ZXNSZXBEaXN0aW5jdERheXMsIGRhdGVzLmxlbmd0aCkpO1xuICAgICAgICBmb3IgKHZhciBfaSA9IDAsIGRhdGVzXzEgPSBkYXRlczsgX2kgPCBkYXRlc18xLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgdmFyIGRhdGUgPSBkYXRlc18xW19pXTtcbiAgICAgICAgICAgIHBhcnRzLnB1c2gocmVuZGVyRGF0ZUNlbGwoZGF0ZSwgcHJvcHMuZGF0ZVByb2ZpbGUsIGRhdGVzUmVwRGlzdGluY3REYXlzLCBkYXRlcy5sZW5ndGgsIGNvbEhlYWRGb3JtYXQsIGNvbnRleHQpKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoY29udGV4dC5pc1J0bCkge1xuICAgICAgICAgICAgcGFydHMucmV2ZXJzZSgpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMudGhlYWQuaW5uZXJIVE1MID0gJzx0cj4nICsgcGFydHMuam9pbignJykgKyAnPC90cj4nO1xuICAgIH07XG4gICAgRGF5SGVhZGVyLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBfc3VwZXIucHJvdG90eXBlLmRlc3Ryb3kuY2FsbCh0aGlzKTtcbiAgICAgICAgdGhpcy5yZW5kZXJTa2VsZXRvbi51bnJlbmRlcigpO1xuICAgIH07XG4gICAgRGF5SGVhZGVyLnByb3RvdHlwZS5fcmVuZGVyU2tlbGV0b24gPSBmdW5jdGlvbiAoY29udGV4dCkge1xuICAgICAgICB2YXIgdGhlbWUgPSBjb250ZXh0LnRoZW1lO1xuICAgICAgICB2YXIgcGFyZW50RWwgPSB0aGlzLnBhcmVudEVsO1xuICAgICAgICBwYXJlbnRFbC5pbm5lckhUTUwgPSAnJzsgLy8gYmVjYXVzZSBtaWdodCBiZSBuYnNwXG4gICAgICAgIHBhcmVudEVsLmFwcGVuZENoaWxkKHRoaXMuZWwgPSBodG1sVG9FbGVtZW50KCc8ZGl2IGNsYXNzPVwiZmMtcm93ICcgKyB0aGVtZS5nZXRDbGFzcygnaGVhZGVyUm93JykgKyAnXCI+JyArXG4gICAgICAgICAgICAnPHRhYmxlIGNsYXNzPVwiJyArIHRoZW1lLmdldENsYXNzKCd0YWJsZUdyaWQnKSArICdcIj4nICtcbiAgICAgICAgICAgICc8dGhlYWQ+PC90aGVhZD4nICtcbiAgICAgICAgICAgICc8L3RhYmxlPicgK1xuICAgICAgICAgICAgJzwvZGl2PicpKTtcbiAgICAgICAgdGhpcy50aGVhZCA9IHRoaXMuZWwucXVlcnlTZWxlY3RvcigndGhlYWQnKTtcbiAgICB9O1xuICAgIERheUhlYWRlci5wcm90b3R5cGUuX3VucmVuZGVyU2tlbGV0b24gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJlbW92ZUVsZW1lbnQodGhpcy5lbCk7XG4gICAgfTtcbiAgICByZXR1cm4gRGF5SGVhZGVyO1xufShDb21wb25lbnQpKTtcblxudmFyIERheVNlcmllcyA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBEYXlTZXJpZXMocmFuZ2UsIGRhdGVQcm9maWxlR2VuZXJhdG9yKSB7XG4gICAgICAgIHZhciBkYXRlID0gcmFuZ2Uuc3RhcnQ7XG4gICAgICAgIHZhciBlbmQgPSByYW5nZS5lbmQ7XG4gICAgICAgIHZhciBpbmRpY2VzID0gW107XG4gICAgICAgIHZhciBkYXRlcyA9IFtdO1xuICAgICAgICB2YXIgZGF5SW5kZXggPSAtMTtcbiAgICAgICAgd2hpbGUgKGRhdGUgPCBlbmQpIHsgLy8gbG9vcCBlYWNoIGRheSBmcm9tIHN0YXJ0IHRvIGVuZFxuICAgICAgICAgICAgaWYgKGRhdGVQcm9maWxlR2VuZXJhdG9yLmlzSGlkZGVuRGF5KGRhdGUpKSB7XG4gICAgICAgICAgICAgICAgaW5kaWNlcy5wdXNoKGRheUluZGV4ICsgMC41KTsgLy8gbWFyayB0aGF0IGl0J3MgYmV0d2VlbiBpbmRpY2VzXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBkYXlJbmRleCsrO1xuICAgICAgICAgICAgICAgIGluZGljZXMucHVzaChkYXlJbmRleCk7XG4gICAgICAgICAgICAgICAgZGF0ZXMucHVzaChkYXRlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRhdGUgPSBhZGREYXlzKGRhdGUsIDEpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuZGF0ZXMgPSBkYXRlcztcbiAgICAgICAgdGhpcy5pbmRpY2VzID0gaW5kaWNlcztcbiAgICAgICAgdGhpcy5jbnQgPSBkYXRlcy5sZW5ndGg7XG4gICAgfVxuICAgIERheVNlcmllcy5wcm90b3R5cGUuc2xpY2VSYW5nZSA9IGZ1bmN0aW9uIChyYW5nZSkge1xuICAgICAgICB2YXIgZmlyc3RJbmRleCA9IHRoaXMuZ2V0RGF0ZURheUluZGV4KHJhbmdlLnN0YXJ0KTsgLy8gaW5jbHVzaXZlIGZpcnN0IGluZGV4XG4gICAgICAgIHZhciBsYXN0SW5kZXggPSB0aGlzLmdldERhdGVEYXlJbmRleChhZGREYXlzKHJhbmdlLmVuZCwgLTEpKTsgLy8gaW5jbHVzaXZlIGxhc3QgaW5kZXhcbiAgICAgICAgdmFyIGNsaXBwZWRGaXJzdEluZGV4ID0gTWF0aC5tYXgoMCwgZmlyc3RJbmRleCk7XG4gICAgICAgIHZhciBjbGlwcGVkTGFzdEluZGV4ID0gTWF0aC5taW4odGhpcy5jbnQgLSAxLCBsYXN0SW5kZXgpO1xuICAgICAgICAvLyBkZWFsIHdpdGggaW4tYmV0d2VlbiBpbmRpY2VzXG4gICAgICAgIGNsaXBwZWRGaXJzdEluZGV4ID0gTWF0aC5jZWlsKGNsaXBwZWRGaXJzdEluZGV4KTsgLy8gaW4tYmV0d2VlbiBzdGFydHMgcm91bmQgdG8gbmV4dCBjZWxsXG4gICAgICAgIGNsaXBwZWRMYXN0SW5kZXggPSBNYXRoLmZsb29yKGNsaXBwZWRMYXN0SW5kZXgpOyAvLyBpbi1iZXR3ZWVuIGVuZHMgcm91bmQgdG8gcHJldiBjZWxsXG4gICAgICAgIGlmIChjbGlwcGVkRmlyc3RJbmRleCA8PSBjbGlwcGVkTGFzdEluZGV4KSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGZpcnN0SW5kZXg6IGNsaXBwZWRGaXJzdEluZGV4LFxuICAgICAgICAgICAgICAgIGxhc3RJbmRleDogY2xpcHBlZExhc3RJbmRleCxcbiAgICAgICAgICAgICAgICBpc1N0YXJ0OiBmaXJzdEluZGV4ID09PSBjbGlwcGVkRmlyc3RJbmRleCxcbiAgICAgICAgICAgICAgICBpc0VuZDogbGFzdEluZGV4ID09PSBjbGlwcGVkTGFzdEluZGV4XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8vIEdpdmVuIGEgZGF0ZSwgcmV0dXJucyBpdHMgY2hyb25vbG9jaWFsIGNlbGwtaW5kZXggZnJvbSB0aGUgZmlyc3QgY2VsbCBvZiB0aGUgZ3JpZC5cbiAgICAvLyBJZiB0aGUgZGF0ZSBsaWVzIGJldHdlZW4gY2VsbHMgKGJlY2F1c2Ugb2YgaGlkZGVuRGF5cyksIHJldHVybnMgYSBmbG9hdGluZy1wb2ludCB2YWx1ZSBiZXR3ZWVuIG9mZnNldHMuXG4gICAgLy8gSWYgYmVmb3JlIHRoZSBmaXJzdCBvZmZzZXQsIHJldHVybnMgYSBuZWdhdGl2ZSBudW1iZXIuXG4gICAgLy8gSWYgYWZ0ZXIgdGhlIGxhc3Qgb2Zmc2V0LCByZXR1cm5zIGFuIG9mZnNldCBwYXN0IHRoZSBsYXN0IGNlbGwgb2Zmc2V0LlxuICAgIC8vIE9ubHkgd29ya3MgZm9yICpzdGFydCogZGF0ZXMgb2YgY2VsbHMuIFdpbGwgbm90IHdvcmsgZm9yIGV4Y2x1c2l2ZSBlbmQgZGF0ZXMgZm9yIGNlbGxzLlxuICAgIERheVNlcmllcy5wcm90b3R5cGUuZ2V0RGF0ZURheUluZGV4ID0gZnVuY3Rpb24gKGRhdGUpIHtcbiAgICAgICAgdmFyIGluZGljZXMgPSB0aGlzLmluZGljZXM7XG4gICAgICAgIHZhciBkYXlPZmZzZXQgPSBNYXRoLmZsb29yKGRpZmZEYXlzKHRoaXMuZGF0ZXNbMF0sIGRhdGUpKTtcbiAgICAgICAgaWYgKGRheU9mZnNldCA8IDApIHtcbiAgICAgICAgICAgIHJldHVybiBpbmRpY2VzWzBdIC0gMTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChkYXlPZmZzZXQgPj0gaW5kaWNlcy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybiBpbmRpY2VzW2luZGljZXMubGVuZ3RoIC0gMV0gKyAxO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIGluZGljZXNbZGF5T2Zmc2V0XTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgcmV0dXJuIERheVNlcmllcztcbn0oKSk7XG5cbnZhciBEYXlUYWJsZSA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBEYXlUYWJsZShkYXlTZXJpZXMsIGJyZWFrT25XZWVrcykge1xuICAgICAgICB2YXIgZGF0ZXMgPSBkYXlTZXJpZXMuZGF0ZXM7XG4gICAgICAgIHZhciBkYXlzUGVyUm93O1xuICAgICAgICB2YXIgZmlyc3REYXk7XG4gICAgICAgIHZhciByb3dDbnQ7XG4gICAgICAgIGlmIChicmVha09uV2Vla3MpIHtcbiAgICAgICAgICAgIC8vIGNvdW50IGNvbHVtbnMgdW50aWwgdGhlIGRheS1vZi13ZWVrIHJlcGVhdHNcbiAgICAgICAgICAgIGZpcnN0RGF5ID0gZGF0ZXNbMF0uZ2V0VVRDRGF5KCk7XG4gICAgICAgICAgICBmb3IgKGRheXNQZXJSb3cgPSAxOyBkYXlzUGVyUm93IDwgZGF0ZXMubGVuZ3RoOyBkYXlzUGVyUm93KyspIHtcbiAgICAgICAgICAgICAgICBpZiAoZGF0ZXNbZGF5c1BlclJvd10uZ2V0VVRDRGF5KCkgPT09IGZpcnN0RGF5KSB7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJvd0NudCA9IE1hdGguY2VpbChkYXRlcy5sZW5ndGggLyBkYXlzUGVyUm93KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJvd0NudCA9IDE7XG4gICAgICAgICAgICBkYXlzUGVyUm93ID0gZGF0ZXMubGVuZ3RoO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucm93Q250ID0gcm93Q250O1xuICAgICAgICB0aGlzLmNvbENudCA9IGRheXNQZXJSb3c7XG4gICAgICAgIHRoaXMuZGF5U2VyaWVzID0gZGF5U2VyaWVzO1xuICAgICAgICB0aGlzLmNlbGxzID0gdGhpcy5idWlsZENlbGxzKCk7XG4gICAgICAgIHRoaXMuaGVhZGVyRGF0ZXMgPSB0aGlzLmJ1aWxkSGVhZGVyRGF0ZXMoKTtcbiAgICB9XG4gICAgRGF5VGFibGUucHJvdG90eXBlLmJ1aWxkQ2VsbHMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciByb3dzID0gW107XG4gICAgICAgIGZvciAodmFyIHJvdyA9IDA7IHJvdyA8IHRoaXMucm93Q250OyByb3crKykge1xuICAgICAgICAgICAgdmFyIGNlbGxzID0gW107XG4gICAgICAgICAgICBmb3IgKHZhciBjb2wgPSAwOyBjb2wgPCB0aGlzLmNvbENudDsgY29sKyspIHtcbiAgICAgICAgICAgICAgICBjZWxscy5wdXNoKHRoaXMuYnVpbGRDZWxsKHJvdywgY29sKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByb3dzLnB1c2goY2VsbHMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByb3dzO1xuICAgIH07XG4gICAgRGF5VGFibGUucHJvdG90eXBlLmJ1aWxkQ2VsbCA9IGZ1bmN0aW9uIChyb3csIGNvbCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgZGF0ZTogdGhpcy5kYXlTZXJpZXMuZGF0ZXNbcm93ICogdGhpcy5jb2xDbnQgKyBjb2xdXG4gICAgICAgIH07XG4gICAgfTtcbiAgICBEYXlUYWJsZS5wcm90b3R5cGUuYnVpbGRIZWFkZXJEYXRlcyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGRhdGVzID0gW107XG4gICAgICAgIGZvciAodmFyIGNvbCA9IDA7IGNvbCA8IHRoaXMuY29sQ250OyBjb2wrKykge1xuICAgICAgICAgICAgZGF0ZXMucHVzaCh0aGlzLmNlbGxzWzBdW2NvbF0uZGF0ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGRhdGVzO1xuICAgIH07XG4gICAgRGF5VGFibGUucHJvdG90eXBlLnNsaWNlUmFuZ2UgPSBmdW5jdGlvbiAocmFuZ2UpIHtcbiAgICAgICAgdmFyIGNvbENudCA9IHRoaXMuY29sQ250O1xuICAgICAgICB2YXIgc2VyaWVzU2VnID0gdGhpcy5kYXlTZXJpZXMuc2xpY2VSYW5nZShyYW5nZSk7XG4gICAgICAgIHZhciBzZWdzID0gW107XG4gICAgICAgIGlmIChzZXJpZXNTZWcpIHtcbiAgICAgICAgICAgIHZhciBmaXJzdEluZGV4ID0gc2VyaWVzU2VnLmZpcnN0SW5kZXgsIGxhc3RJbmRleCA9IHNlcmllc1NlZy5sYXN0SW5kZXg7XG4gICAgICAgICAgICB2YXIgaW5kZXggPSBmaXJzdEluZGV4O1xuICAgICAgICAgICAgd2hpbGUgKGluZGV4IDw9IGxhc3RJbmRleCkge1xuICAgICAgICAgICAgICAgIHZhciByb3cgPSBNYXRoLmZsb29yKGluZGV4IC8gY29sQ250KTtcbiAgICAgICAgICAgICAgICB2YXIgbmV4dEluZGV4ID0gTWF0aC5taW4oKHJvdyArIDEpICogY29sQ250LCBsYXN0SW5kZXggKyAxKTtcbiAgICAgICAgICAgICAgICBzZWdzLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICByb3c6IHJvdyxcbiAgICAgICAgICAgICAgICAgICAgZmlyc3RDb2w6IGluZGV4ICUgY29sQ250LFxuICAgICAgICAgICAgICAgICAgICBsYXN0Q29sOiAobmV4dEluZGV4IC0gMSkgJSBjb2xDbnQsXG4gICAgICAgICAgICAgICAgICAgIGlzU3RhcnQ6IHNlcmllc1NlZy5pc1N0YXJ0ICYmIGluZGV4ID09PSBmaXJzdEluZGV4LFxuICAgICAgICAgICAgICAgICAgICBpc0VuZDogc2VyaWVzU2VnLmlzRW5kICYmIChuZXh0SW5kZXggLSAxKSA9PT0gbGFzdEluZGV4XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgaW5kZXggPSBuZXh0SW5kZXg7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlZ3M7XG4gICAgfTtcbiAgICByZXR1cm4gRGF5VGFibGU7XG59KCkpO1xuXG52YXIgU2xpY2VyID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIFNsaWNlcigpIHtcbiAgICAgICAgdGhpcy5zbGljZUJ1c2luZXNzSG91cnMgPSBtZW1vaXplKHRoaXMuX3NsaWNlQnVzaW5lc3NIb3Vycyk7XG4gICAgICAgIHRoaXMuc2xpY2VEYXRlU2VsZWN0aW9uID0gbWVtb2l6ZSh0aGlzLl9zbGljZURhdGVTcGFuKTtcbiAgICAgICAgdGhpcy5zbGljZUV2ZW50U3RvcmUgPSBtZW1vaXplKHRoaXMuX3NsaWNlRXZlbnRTdG9yZSk7XG4gICAgICAgIHRoaXMuc2xpY2VFdmVudERyYWcgPSBtZW1vaXplKHRoaXMuX3NsaWNlSW50ZXJhY3Rpb24pO1xuICAgICAgICB0aGlzLnNsaWNlRXZlbnRSZXNpemUgPSBtZW1vaXplKHRoaXMuX3NsaWNlSW50ZXJhY3Rpb24pO1xuICAgIH1cbiAgICBTbGljZXIucHJvdG90eXBlLnNsaWNlUHJvcHMgPSBmdW5jdGlvbiAocHJvcHMsIGRhdGVQcm9maWxlLCBuZXh0RGF5VGhyZXNob2xkLCBjYWxlbmRhciwgY29tcG9uZW50KSB7XG4gICAgICAgIHZhciBleHRyYUFyZ3MgPSBbXTtcbiAgICAgICAgZm9yICh2YXIgX2kgPSA1OyBfaSA8IGFyZ3VtZW50cy5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIGV4dHJhQXJnc1tfaSAtIDVdID0gYXJndW1lbnRzW19pXTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgZXZlbnRVaUJhc2VzID0gcHJvcHMuZXZlbnRVaUJhc2VzO1xuICAgICAgICB2YXIgZXZlbnRTZWdzID0gdGhpcy5zbGljZUV2ZW50U3RvcmUuYXBwbHkodGhpcywgW3Byb3BzLmV2ZW50U3RvcmUsIGV2ZW50VWlCYXNlcywgZGF0ZVByb2ZpbGUsIG5leHREYXlUaHJlc2hvbGQsIGNvbXBvbmVudF0uY29uY2F0KGV4dHJhQXJncykpO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgZGF0ZVNlbGVjdGlvblNlZ3M6IHRoaXMuc2xpY2VEYXRlU2VsZWN0aW9uLmFwcGx5KHRoaXMsIFtwcm9wcy5kYXRlU2VsZWN0aW9uLCBldmVudFVpQmFzZXMsIGNvbXBvbmVudF0uY29uY2F0KGV4dHJhQXJncykpLFxuICAgICAgICAgICAgYnVzaW5lc3NIb3VyU2VnczogdGhpcy5zbGljZUJ1c2luZXNzSG91cnMuYXBwbHkodGhpcywgW3Byb3BzLmJ1c2luZXNzSG91cnMsIGRhdGVQcm9maWxlLCBuZXh0RGF5VGhyZXNob2xkLCBjYWxlbmRhciwgY29tcG9uZW50XS5jb25jYXQoZXh0cmFBcmdzKSksXG4gICAgICAgICAgICBmZ0V2ZW50U2VnczogZXZlbnRTZWdzLmZnLFxuICAgICAgICAgICAgYmdFdmVudFNlZ3M6IGV2ZW50U2Vncy5iZyxcbiAgICAgICAgICAgIGV2ZW50RHJhZzogdGhpcy5zbGljZUV2ZW50RHJhZy5hcHBseSh0aGlzLCBbcHJvcHMuZXZlbnREcmFnLCBldmVudFVpQmFzZXMsIGRhdGVQcm9maWxlLCBuZXh0RGF5VGhyZXNob2xkLCBjb21wb25lbnRdLmNvbmNhdChleHRyYUFyZ3MpKSxcbiAgICAgICAgICAgIGV2ZW50UmVzaXplOiB0aGlzLnNsaWNlRXZlbnRSZXNpemUuYXBwbHkodGhpcywgW3Byb3BzLmV2ZW50UmVzaXplLCBldmVudFVpQmFzZXMsIGRhdGVQcm9maWxlLCBuZXh0RGF5VGhyZXNob2xkLCBjb21wb25lbnRdLmNvbmNhdChleHRyYUFyZ3MpKSxcbiAgICAgICAgICAgIGV2ZW50U2VsZWN0aW9uOiBwcm9wcy5ldmVudFNlbGVjdGlvblxuICAgICAgICB9OyAvLyBUT0RPOiBnaXZlIGludGVyYWN0aW9uU2Vncz9cbiAgICB9O1xuICAgIFNsaWNlci5wcm90b3R5cGUuc2xpY2VOb3dEYXRlID0gZnVuY3Rpb24gKC8vIGRvZXMgbm90IG1lbW9pemVcbiAgICBkYXRlLCBjb21wb25lbnQpIHtcbiAgICAgICAgdmFyIGV4dHJhQXJncyA9IFtdO1xuICAgICAgICBmb3IgKHZhciBfaSA9IDI7IF9pIDwgYXJndW1lbnRzLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgZXh0cmFBcmdzW19pIC0gMl0gPSBhcmd1bWVudHNbX2ldO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLl9zbGljZURhdGVTcGFuLmFwcGx5KHRoaXMsIFt7IHJhbmdlOiB7IHN0YXJ0OiBkYXRlLCBlbmQ6IGFkZE1zKGRhdGUsIDEpIH0sIGFsbERheTogZmFsc2UgfSxcbiAgICAgICAgICAgIHt9LFxuICAgICAgICAgICAgY29tcG9uZW50XS5jb25jYXQoZXh0cmFBcmdzKSk7XG4gICAgfTtcbiAgICBTbGljZXIucHJvdG90eXBlLl9zbGljZUJ1c2luZXNzSG91cnMgPSBmdW5jdGlvbiAoYnVzaW5lc3NIb3VycywgZGF0ZVByb2ZpbGUsIG5leHREYXlUaHJlc2hvbGQsIGNhbGVuZGFyLCBjb21wb25lbnQpIHtcbiAgICAgICAgdmFyIGV4dHJhQXJncyA9IFtdO1xuICAgICAgICBmb3IgKHZhciBfaSA9IDU7IF9pIDwgYXJndW1lbnRzLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgZXh0cmFBcmdzW19pIC0gNV0gPSBhcmd1bWVudHNbX2ldO1xuICAgICAgICB9XG4gICAgICAgIGlmICghYnVzaW5lc3NIb3Vycykge1xuICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLl9zbGljZUV2ZW50U3RvcmUuYXBwbHkodGhpcywgW2V4cGFuZFJlY3VycmluZyhidXNpbmVzc0hvdXJzLCBjb21wdXRlQWN0aXZlUmFuZ2UoZGF0ZVByb2ZpbGUsIEJvb2xlYW4obmV4dERheVRocmVzaG9sZCkpLCBjYWxlbmRhciksXG4gICAgICAgICAgICB7fSxcbiAgICAgICAgICAgIGRhdGVQcm9maWxlLFxuICAgICAgICAgICAgbmV4dERheVRocmVzaG9sZCxcbiAgICAgICAgICAgIGNvbXBvbmVudF0uY29uY2F0KGV4dHJhQXJncykpLmJnO1xuICAgIH07XG4gICAgU2xpY2VyLnByb3RvdHlwZS5fc2xpY2VFdmVudFN0b3JlID0gZnVuY3Rpb24gKGV2ZW50U3RvcmUsIGV2ZW50VWlCYXNlcywgZGF0ZVByb2ZpbGUsIG5leHREYXlUaHJlc2hvbGQsIGNvbXBvbmVudCkge1xuICAgICAgICB2YXIgZXh0cmFBcmdzID0gW107XG4gICAgICAgIGZvciAodmFyIF9pID0gNTsgX2kgPCBhcmd1bWVudHMubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICBleHRyYUFyZ3NbX2kgLSA1XSA9IGFyZ3VtZW50c1tfaV07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGV2ZW50U3RvcmUpIHtcbiAgICAgICAgICAgIHZhciByYW5nZVJlcyA9IHNsaWNlRXZlbnRTdG9yZShldmVudFN0b3JlLCBldmVudFVpQmFzZXMsIGNvbXB1dGVBY3RpdmVSYW5nZShkYXRlUHJvZmlsZSwgQm9vbGVhbihuZXh0RGF5VGhyZXNob2xkKSksIG5leHREYXlUaHJlc2hvbGQpO1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBiZzogdGhpcy5zbGljZUV2ZW50UmFuZ2VzKHJhbmdlUmVzLmJnLCBjb21wb25lbnQsIGV4dHJhQXJncyksXG4gICAgICAgICAgICAgICAgZmc6IHRoaXMuc2xpY2VFdmVudFJhbmdlcyhyYW5nZVJlcy5mZywgY29tcG9uZW50LCBleHRyYUFyZ3MpXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHsgYmc6IFtdLCBmZzogW10gfTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgU2xpY2VyLnByb3RvdHlwZS5fc2xpY2VJbnRlcmFjdGlvbiA9IGZ1bmN0aW9uIChpbnRlcmFjdGlvbiwgZXZlbnRVaUJhc2VzLCBkYXRlUHJvZmlsZSwgbmV4dERheVRocmVzaG9sZCwgY29tcG9uZW50KSB7XG4gICAgICAgIHZhciBleHRyYUFyZ3MgPSBbXTtcbiAgICAgICAgZm9yICh2YXIgX2kgPSA1OyBfaSA8IGFyZ3VtZW50cy5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIGV4dHJhQXJnc1tfaSAtIDVdID0gYXJndW1lbnRzW19pXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWludGVyYWN0aW9uKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICB2YXIgcmFuZ2VSZXMgPSBzbGljZUV2ZW50U3RvcmUoaW50ZXJhY3Rpb24ubXV0YXRlZEV2ZW50cywgZXZlbnRVaUJhc2VzLCBjb21wdXRlQWN0aXZlUmFuZ2UoZGF0ZVByb2ZpbGUsIEJvb2xlYW4obmV4dERheVRocmVzaG9sZCkpLCBuZXh0RGF5VGhyZXNob2xkKTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHNlZ3M6IHRoaXMuc2xpY2VFdmVudFJhbmdlcyhyYW5nZVJlcy5mZywgY29tcG9uZW50LCBleHRyYUFyZ3MpLFxuICAgICAgICAgICAgYWZmZWN0ZWRJbnN0YW5jZXM6IGludGVyYWN0aW9uLmFmZmVjdGVkRXZlbnRzLmluc3RhbmNlcyxcbiAgICAgICAgICAgIGlzRXZlbnQ6IGludGVyYWN0aW9uLmlzRXZlbnQsXG4gICAgICAgICAgICBzb3VyY2VTZWc6IGludGVyYWN0aW9uLm9yaWdTZWdcbiAgICAgICAgfTtcbiAgICB9O1xuICAgIFNsaWNlci5wcm90b3R5cGUuX3NsaWNlRGF0ZVNwYW4gPSBmdW5jdGlvbiAoZGF0ZVNwYW4sIGV2ZW50VWlCYXNlcywgY29tcG9uZW50KSB7XG4gICAgICAgIHZhciBleHRyYUFyZ3MgPSBbXTtcbiAgICAgICAgZm9yICh2YXIgX2kgPSAzOyBfaSA8IGFyZ3VtZW50cy5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIGV4dHJhQXJnc1tfaSAtIDNdID0gYXJndW1lbnRzW19pXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWRhdGVTcGFuKSB7XG4gICAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGV2ZW50UmFuZ2UgPSBmYWJyaWNhdGVFdmVudFJhbmdlKGRhdGVTcGFuLCBldmVudFVpQmFzZXMsIGNvbXBvbmVudC5jb250ZXh0LmNhbGVuZGFyKTtcbiAgICAgICAgdmFyIHNlZ3MgPSB0aGlzLnNsaWNlUmFuZ2UuYXBwbHkodGhpcywgW2RhdGVTcGFuLnJhbmdlXS5jb25jYXQoZXh0cmFBcmdzKSk7XG4gICAgICAgIGZvciAodmFyIF9hID0gMCwgc2Vnc18xID0gc2VnczsgX2EgPCBzZWdzXzEubGVuZ3RoOyBfYSsrKSB7XG4gICAgICAgICAgICB2YXIgc2VnID0gc2Vnc18xW19hXTtcbiAgICAgICAgICAgIHNlZy5jb21wb25lbnQgPSBjb21wb25lbnQ7XG4gICAgICAgICAgICBzZWcuZXZlbnRSYW5nZSA9IGV2ZW50UmFuZ2U7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlZ3M7XG4gICAgfTtcbiAgICAvKlxuICAgIFwiY29tcGxldGVcIiBzZWcgbWVhbnMgaXQgaGFzIGNvbXBvbmVudCBhbmQgZXZlbnRSYW5nZVxuICAgICovXG4gICAgU2xpY2VyLnByb3RvdHlwZS5zbGljZUV2ZW50UmFuZ2VzID0gZnVuY3Rpb24gKGV2ZW50UmFuZ2VzLCBjb21wb25lbnQsIC8vIFRPRE86IGtpbGxcbiAgICBleHRyYUFyZ3MpIHtcbiAgICAgICAgdmFyIHNlZ3MgPSBbXTtcbiAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBldmVudFJhbmdlc18xID0gZXZlbnRSYW5nZXM7IF9pIDwgZXZlbnRSYW5nZXNfMS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIHZhciBldmVudFJhbmdlID0gZXZlbnRSYW5nZXNfMVtfaV07XG4gICAgICAgICAgICBzZWdzLnB1c2guYXBwbHkoc2VncywgdGhpcy5zbGljZUV2ZW50UmFuZ2UoZXZlbnRSYW5nZSwgY29tcG9uZW50LCBleHRyYUFyZ3MpKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2VncztcbiAgICB9O1xuICAgIC8qXG4gICAgXCJjb21wbGV0ZVwiIHNlZyBtZWFucyBpdCBoYXMgY29tcG9uZW50IGFuZCBldmVudFJhbmdlXG4gICAgKi9cbiAgICBTbGljZXIucHJvdG90eXBlLnNsaWNlRXZlbnRSYW5nZSA9IGZ1bmN0aW9uIChldmVudFJhbmdlLCBjb21wb25lbnQsIC8vIFRPRE86IGtpbGxcbiAgICBleHRyYUFyZ3MpIHtcbiAgICAgICAgdmFyIHNlZ3MgPSB0aGlzLnNsaWNlUmFuZ2UuYXBwbHkodGhpcywgW2V2ZW50UmFuZ2UucmFuZ2VdLmNvbmNhdChleHRyYUFyZ3MpKTtcbiAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBzZWdzXzIgPSBzZWdzOyBfaSA8IHNlZ3NfMi5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIHZhciBzZWcgPSBzZWdzXzJbX2ldO1xuICAgICAgICAgICAgc2VnLmNvbXBvbmVudCA9IGNvbXBvbmVudDtcbiAgICAgICAgICAgIHNlZy5ldmVudFJhbmdlID0gZXZlbnRSYW5nZTtcbiAgICAgICAgICAgIHNlZy5pc1N0YXJ0ID0gZXZlbnRSYW5nZS5pc1N0YXJ0ICYmIHNlZy5pc1N0YXJ0O1xuICAgICAgICAgICAgc2VnLmlzRW5kID0gZXZlbnRSYW5nZS5pc0VuZCAmJiBzZWcuaXNFbmQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlZ3M7XG4gICAgfTtcbiAgICByZXR1cm4gU2xpY2VyO1xufSgpKTtcbi8qXG5mb3IgaW5jb3Jwb3JhdGluZyBtaW5UaW1lL21heFRpbWUgaWYgYXBwcm9wcmlhdGVcblRPRE86IHNob3VsZCBiZSBwYXJ0IG9mIERhdGVQcm9maWxlIVxuVGltZWxpbmVEYXRlUHJvZmlsZSBhbHJlYWR5IGRvZXMgdGhpcyBidHdcbiovXG5mdW5jdGlvbiBjb21wdXRlQWN0aXZlUmFuZ2UoZGF0ZVByb2ZpbGUsIGlzQ29tcG9uZW50QWxsRGF5KSB7XG4gICAgdmFyIHJhbmdlID0gZGF0ZVByb2ZpbGUuYWN0aXZlUmFuZ2U7XG4gICAgaWYgKGlzQ29tcG9uZW50QWxsRGF5KSB7XG4gICAgICAgIHJldHVybiByYW5nZTtcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgICAgc3RhcnQ6IGFkZE1zKHJhbmdlLnN0YXJ0LCBkYXRlUHJvZmlsZS5taW5UaW1lLm1pbGxpc2Vjb25kcyksXG4gICAgICAgIGVuZDogYWRkTXMocmFuZ2UuZW5kLCBkYXRlUHJvZmlsZS5tYXhUaW1lLm1pbGxpc2Vjb25kcyAtIDg2NGU1KSAvLyA4NjRlNSA9IG1zIGluIGEgZGF5XG4gICAgfTtcbn1cblxuLy8gZXhwb3J0c1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbnZhciB2ZXJzaW9uID0gJzQuNC4wJztcblxuZXhwb3J0IHsgQ2FsZW5kYXIsIENvbXBvbmVudCwgQ29tcG9uZW50Q29udGV4dCwgRGF0ZUNvbXBvbmVudCwgRGF0ZUVudiwgRGF0ZVByb2ZpbGVHZW5lcmF0b3IsIERheUhlYWRlciwgRGF5U2VyaWVzLCBEYXlUYWJsZSwgRWxlbWVudERyYWdnaW5nLCBFbGVtZW50U2Nyb2xsQ29udHJvbGxlciwgRW1pdHRlck1peGluLCBFdmVudEFwaSwgRmdFdmVudFJlbmRlcmVyLCBGaWxsUmVuZGVyZXIsIEludGVyYWN0aW9uLCBNaXhpbiwgTmFtZWRUaW1lWm9uZUltcGwsIFBvc2l0aW9uQ2FjaGUsIFNjcm9sbENvbXBvbmVudCwgU2Nyb2xsQ29udHJvbGxlciwgU2xpY2VyLCBTcGxpdHRlciwgVGhlbWUsIFZpZXcsIFdpbmRvd1Njcm9sbENvbnRyb2xsZXIsIGFkZERheXMsIGFkZER1cmF0aW9ucywgYWRkTXMsIGFkZFdlZWtzLCBhbGxvd0NvbnRleHRNZW51LCBhbGxvd1NlbGVjdGlvbiwgYXBwZW5kVG9FbGVtZW50LCBhcHBseUFsbCwgYXBwbHlNdXRhdGlvblRvRXZlbnRTdG9yZSwgYXBwbHlTdHlsZSwgYXBwbHlTdHlsZVByb3AsIGFzUm91Z2hNaW51dGVzLCBhc1JvdWdoTXMsIGFzUm91Z2hTZWNvbmRzLCBidWlsZEdvdG9BbmNob3JIdG1sLCBidWlsZFNlZ0NvbXBhcmVPYmosIGNhcGl0YWxpc2VGaXJzdExldHRlciwgY29tYmluZUV2ZW50VWlzLCBjb21wYXJlQnlGaWVsZFNwZWMsIGNvbXBhcmVCeUZpZWxkU3BlY3MsIGNvbXBhcmVOdW1iZXJzLCBjb21wZW5zYXRlU2Nyb2xsLCBjb21wdXRlQ2xpcHBpbmdSZWN0LCBjb21wdXRlRWRnZXMsIGNvbXB1dGVFdmVudERyYWdnYWJsZSwgY29tcHV0ZUV2ZW50RW5kUmVzaXphYmxlLCBjb21wdXRlRXZlbnRTdGFydFJlc2l6YWJsZSwgY29tcHV0ZUZhbGxiYWNrSGVhZGVyRm9ybWF0LCBjb21wdXRlSGVpZ2h0QW5kTWFyZ2lucywgY29tcHV0ZUlubmVyUmVjdCwgY29tcHV0ZVJlY3QsIGNvbXB1dGVWaXNpYmxlRGF5UmFuZ2UsIGNvbmZpZywgY29uc3RyYWluUG9pbnQsIGNyZWF0ZUR1cmF0aW9uLCBjcmVhdGVFbGVtZW50LCBjcmVhdGVFbXB0eUV2ZW50U3RvcmUsIGNyZWF0ZUV2ZW50SW5zdGFuY2UsIGNyZWF0ZUZvcm1hdHRlciwgY3JlYXRlUGx1Z2luLCBjc3NUb1N0ciwgZGVib3VuY2UsIGRpZmZEYXRlcywgZGlmZkRheUFuZFRpbWUsIGRpZmZEYXlzLCBkaWZmUG9pbnRzLCBkaWZmV2Vla3MsIGRpZmZXaG9sZURheXMsIGRpZmZXaG9sZVdlZWtzLCBkaXNhYmxlQ3Vyc29yLCBkaXN0cmlidXRlSGVpZ2h0LCBlbGVtZW50Q2xvc2VzdCwgZWxlbWVudE1hdGNoZXMsIGVuYWJsZUN1cnNvciwgZXZlbnRUdXBsZVRvU3RvcmUsIGZpbHRlckV2ZW50U3RvcmVEZWZzLCBmaWx0ZXJIYXNoLCBmaW5kQ2hpbGRyZW4sIGZpbmRFbGVtZW50cywgZmxleGlibGVDb21wYXJlLCBmb3JjZUNsYXNzTmFtZSwgZm9ybWF0RGF0ZSwgZm9ybWF0SXNvVGltZVN0cmluZywgZm9ybWF0UmFuZ2UsIGdldEFsbERheUh0bWwsIGdldENsaXBwaW5nUGFyZW50cywgZ2V0RGF5Q2xhc3NlcywgZ2V0RWxTZWcsIGdldFJlY3RDZW50ZXIsIGdldFJlbGV2YW50RXZlbnRzLCBnbG9iYWxEZWZhdWx0cywgZ3JlYXRlc3REdXJhdGlvbkRlbm9taW5hdG9yLCBoYXNCZ1JlbmRlcmluZywgaHRtbEVzY2FwZSwgaHRtbFRvRWxlbWVudCwgaW5zZXJ0QWZ0ZXJFbGVtZW50LCBpbnRlcmFjdGlvblNldHRpbmdzU3RvcmUsIGludGVyYWN0aW9uU2V0dGluZ3NUb1N0b3JlLCBpbnRlcnNlY3RSYW5nZXMsIGludGVyc2VjdFJlY3RzLCBpc0FycmF5c0VxdWFsLCBpc0RhdGVTcGFuc0VxdWFsLCBpc0ludCwgaXNJbnRlcmFjdGlvblZhbGlkLCBpc011bHRpRGF5UmFuZ2UsIGlzUHJvcHNFcXVhbCwgaXNQcm9wc1ZhbGlkLCBpc1NpbmdsZURheSwgaXNWYWxpZERhdGUsIGxpc3RlbkJ5U2VsZWN0b3IsIG1hcEhhc2gsIG1hdGNoQ2VsbFdpZHRocywgbWVtb2l6ZSwgbWVtb2l6ZU91dHB1dCwgbWVtb2l6ZVJlbmRlcmluZywgbWVyZ2VFdmVudFN0b3JlcywgbXVsdGlwbHlEdXJhdGlvbiwgcGFkU3RhcnQsIHBhcnNlQnVzaW5lc3NIb3VycywgcGFyc2VEcmFnTWV0YSwgcGFyc2VFdmVudERlZiwgcGFyc2VGaWVsZFNwZWNzLCBwYXJzZSBhcyBwYXJzZU1hcmtlciwgcG9pbnRJbnNpZGVSZWN0LCBwcmVwZW5kVG9FbGVtZW50LCBwcmV2ZW50Q29udGV4dE1lbnUsIHByZXZlbnREZWZhdWx0LCBwcmV2ZW50U2VsZWN0aW9uLCBwcm9jZXNzU2NvcGVkVWlQcm9wcywgcmFuZ2VDb250YWluc01hcmtlciwgcmFuZ2VDb250YWluc1JhbmdlLCByYW5nZXNFcXVhbCwgcmFuZ2VzSW50ZXJzZWN0LCByZWZpbmVQcm9wcywgcmVtb3ZlRWxlbWVudCwgcmVtb3ZlRXhhY3QsIHJlbmRlckRhdGVDZWxsLCByZXF1ZXN0SnNvbiwgc2xpY2VFdmVudFN0b3JlLCBzdGFydE9mRGF5LCBzdWJ0cmFjdElubmVyRWxIZWlnaHQsIHRyYW5zbGF0ZVJlY3QsIHVuY29tcGVuc2F0ZVNjcm9sbCwgdW5kaXN0cmlidXRlSGVpZ2h0LCB1bnByb21pc2lmeSwgdmVyc2lvbiwgd2hlblRyYW5zaXRpb25Eb25lLCB3aG9sZURpdmlkZUR1cmF0aW9ucyB9O1xuIiwiLy8gZXh0cmFjdGVkIGJ5IG1pbmktY3NzLWV4dHJhY3QtcGx1Z2luIiwiLyohXG5GdWxsQ2FsZW5kYXIgRGF5IEdyaWQgUGx1Z2luIHY0LjQuMFxuRG9jcyAmIExpY2Vuc2U6IGh0dHBzOi8vZnVsbGNhbGVuZGFyLmlvL1xuKGMpIDIwMTkgQWRhbSBTaGF3XG4qL1xuXG5pbXBvcnQgeyBhZGRXZWVrcywgZGlmZldlZWtzLCBEYXRlUHJvZmlsZUdlbmVyYXRvciwgY3JlYXRlRWxlbWVudCwgbGlzdGVuQnlTZWxlY3RvciwgcmVtb3ZlRWxlbWVudCwgY29tcHV0ZVJlY3QsIGNvbXB1dGVDbGlwcGluZ1JlY3QsIGFwcGx5U3R5bGUsIGNvbXB1dGVFdmVudERyYWdnYWJsZSwgY29tcHV0ZUV2ZW50U3RhcnRSZXNpemFibGUsIGNvbXB1dGVFdmVudEVuZFJlc2l6YWJsZSwgY3NzVG9TdHIsIGh0bWxFc2NhcGUsIEZnRXZlbnRSZW5kZXJlciwgYXBwZW5kVG9FbGVtZW50LCBwcmVwZW5kVG9FbGVtZW50LCBodG1sVG9FbGVtZW50LCBGaWxsUmVuZGVyZXIsIG1lbW9pemVSZW5kZXJpbmcsIGNyZWF0ZUZvcm1hdHRlciwgYWRkRGF5cywgRGF0ZUNvbXBvbmVudCwgcmFuZ2VDb250YWluc01hcmtlciwgZ2V0RGF5Q2xhc3NlcywgZmluZEVsZW1lbnRzLCBQb3NpdGlvbkNhY2hlLCBidWlsZEdvdG9BbmNob3JIdG1sLCBmaW5kQ2hpbGRyZW4sIGluc2VydEFmdGVyRWxlbWVudCwgaW50ZXJzZWN0UmFuZ2VzLCBtZW1vaXplLCBTY3JvbGxDb21wb25lbnQsIG1hdGNoQ2VsbFdpZHRocywgdW5jb21wZW5zYXRlU2Nyb2xsLCBjb21wZW5zYXRlU2Nyb2xsLCBzdWJ0cmFjdElubmVyRWxIZWlnaHQsIGRpc3RyaWJ1dGVIZWlnaHQsIHVuZGlzdHJpYnV0ZUhlaWdodCwgVmlldywgU2xpY2VyLCBEYXlIZWFkZXIsIERheVNlcmllcywgRGF5VGFibGUsIGNyZWF0ZVBsdWdpbiB9IGZyb20gJ0BmdWxsY2FsZW5kYXIvY29yZSc7XG5cbi8qISAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5Db3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cclxuTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTsgeW91IG1heSBub3QgdXNlXHJcbnRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlXHJcbkxpY2Vuc2UgYXQgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXHJcblxyXG5USElTIENPREUgSVMgUFJPVklERUQgT04gQU4gKkFTIElTKiBCQVNJUywgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZXHJcbktJTkQsIEVJVEhFUiBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBXSVRIT1VUIExJTUlUQVRJT04gQU5ZIElNUExJRURcclxuV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIFRJVExFLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSxcclxuTUVSQ0hBTlRBQkxJVFkgT1IgTk9OLUlORlJJTkdFTUVOVC5cclxuXHJcblNlZSB0aGUgQXBhY2hlIFZlcnNpb24gMi4wIExpY2Vuc2UgZm9yIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9uc1xyXG5hbmQgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXHJcbi8qIGdsb2JhbCBSZWZsZWN0LCBQcm9taXNlICovXHJcblxyXG52YXIgZXh0ZW5kU3RhdGljcyA9IGZ1bmN0aW9uKGQsIGIpIHtcclxuICAgIGV4dGVuZFN0YXRpY3MgPSBPYmplY3Quc2V0UHJvdG90eXBlT2YgfHxcclxuICAgICAgICAoeyBfX3Byb3RvX186IFtdIH0gaW5zdGFuY2VvZiBBcnJheSAmJiBmdW5jdGlvbiAoZCwgYikgeyBkLl9fcHJvdG9fXyA9IGI7IH0pIHx8XHJcbiAgICAgICAgZnVuY3Rpb24gKGQsIGIpIHsgZm9yICh2YXIgcCBpbiBiKSBpZiAoYi5oYXNPd25Qcm9wZXJ0eShwKSkgZFtwXSA9IGJbcF07IH07XHJcbiAgICByZXR1cm4gZXh0ZW5kU3RhdGljcyhkLCBiKTtcclxufTtcclxuXHJcbmZ1bmN0aW9uIF9fZXh0ZW5kcyhkLCBiKSB7XHJcbiAgICBleHRlbmRTdGF0aWNzKGQsIGIpO1xyXG4gICAgZnVuY3Rpb24gX18oKSB7IHRoaXMuY29uc3RydWN0b3IgPSBkOyB9XHJcbiAgICBkLnByb3RvdHlwZSA9IGIgPT09IG51bGwgPyBPYmplY3QuY3JlYXRlKGIpIDogKF9fLnByb3RvdHlwZSA9IGIucHJvdG90eXBlLCBuZXcgX18oKSk7XHJcbn1cclxuXHJcbnZhciBfX2Fzc2lnbiA9IGZ1bmN0aW9uKCkge1xyXG4gICAgX19hc3NpZ24gPSBPYmplY3QuYXNzaWduIHx8IGZ1bmN0aW9uIF9fYXNzaWduKHQpIHtcclxuICAgICAgICBmb3IgKHZhciBzLCBpID0gMSwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcclxuICAgICAgICAgICAgcyA9IGFyZ3VtZW50c1tpXTtcclxuICAgICAgICAgICAgZm9yICh2YXIgcCBpbiBzKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHMsIHApKSB0W3BdID0gc1twXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHQ7XHJcbiAgICB9O1xyXG4gICAgcmV0dXJuIF9fYXNzaWduLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XHJcbn07XG5cbnZhciBEYXlHcmlkRGF0ZVByb2ZpbGVHZW5lcmF0b3IgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoX3N1cGVyKSB7XG4gICAgX19leHRlbmRzKERheUdyaWREYXRlUHJvZmlsZUdlbmVyYXRvciwgX3N1cGVyKTtcbiAgICBmdW5jdGlvbiBEYXlHcmlkRGF0ZVByb2ZpbGVHZW5lcmF0b3IoKSB7XG4gICAgICAgIHJldHVybiBfc3VwZXIgIT09IG51bGwgJiYgX3N1cGVyLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykgfHwgdGhpcztcbiAgICB9XG4gICAgLy8gQ29tcHV0ZXMgdGhlIGRhdGUgcmFuZ2UgdGhhdCB3aWxsIGJlIHJlbmRlcmVkLlxuICAgIERheUdyaWREYXRlUHJvZmlsZUdlbmVyYXRvci5wcm90b3R5cGUuYnVpbGRSZW5kZXJSYW5nZSA9IGZ1bmN0aW9uIChjdXJyZW50UmFuZ2UsIGN1cnJlbnRSYW5nZVVuaXQsIGlzUmFuZ2VBbGxEYXkpIHtcbiAgICAgICAgdmFyIGRhdGVFbnYgPSB0aGlzLmRhdGVFbnY7XG4gICAgICAgIHZhciByZW5kZXJSYW5nZSA9IF9zdXBlci5wcm90b3R5cGUuYnVpbGRSZW5kZXJSYW5nZS5jYWxsKHRoaXMsIGN1cnJlbnRSYW5nZSwgY3VycmVudFJhbmdlVW5pdCwgaXNSYW5nZUFsbERheSk7XG4gICAgICAgIHZhciBzdGFydCA9IHJlbmRlclJhbmdlLnN0YXJ0O1xuICAgICAgICB2YXIgZW5kID0gcmVuZGVyUmFuZ2UuZW5kO1xuICAgICAgICB2YXIgZW5kT2ZXZWVrO1xuICAgICAgICAvLyB5ZWFyIGFuZCBtb250aCB2aWV3cyBzaG91bGQgYmUgYWxpZ25lZCB3aXRoIHdlZWtzLiB0aGlzIGlzIGFscmVhZHkgZG9uZSBmb3Igd2Vla1xuICAgICAgICBpZiAoL14oeWVhcnxtb250aCkkLy50ZXN0KGN1cnJlbnRSYW5nZVVuaXQpKSB7XG4gICAgICAgICAgICBzdGFydCA9IGRhdGVFbnYuc3RhcnRPZldlZWsoc3RhcnQpO1xuICAgICAgICAgICAgLy8gbWFrZSBlbmQtb2Ytd2VlayBpZiBub3QgYWxyZWFkeVxuICAgICAgICAgICAgZW5kT2ZXZWVrID0gZGF0ZUVudi5zdGFydE9mV2VlayhlbmQpO1xuICAgICAgICAgICAgaWYgKGVuZE9mV2Vlay52YWx1ZU9mKCkgIT09IGVuZC52YWx1ZU9mKCkpIHtcbiAgICAgICAgICAgICAgICBlbmQgPSBhZGRXZWVrcyhlbmRPZldlZWssIDEpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIGVuc3VyZSA2IHdlZWtzXG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMubW9udGhNb2RlICYmXG4gICAgICAgICAgICB0aGlzLm9wdGlvbnMuZml4ZWRXZWVrQ291bnQpIHtcbiAgICAgICAgICAgIHZhciByb3dDbnQgPSBNYXRoLmNlaWwoLy8gY291bGQgYmUgcGFydGlhbCB3ZWVrcyBkdWUgdG8gaGlkZGVuRGF5c1xuICAgICAgICAgICAgZGlmZldlZWtzKHN0YXJ0LCBlbmQpKTtcbiAgICAgICAgICAgIGVuZCA9IGFkZFdlZWtzKGVuZCwgNiAtIHJvd0NudCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHsgc3RhcnQ6IHN0YXJ0LCBlbmQ6IGVuZCB9O1xuICAgIH07XG4gICAgcmV0dXJuIERheUdyaWREYXRlUHJvZmlsZUdlbmVyYXRvcjtcbn0oRGF0ZVByb2ZpbGVHZW5lcmF0b3IpKTtcblxuLyogQSByZWN0YW5ndWxhciBwYW5lbCB0aGF0IGlzIGFic29sdXRlbHkgcG9zaXRpb25lZCBvdmVyIG90aGVyIGNvbnRlbnRcbi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuT3B0aW9uczpcbiAgLSBjbGFzc05hbWUgKHN0cmluZylcbiAgLSBjb250ZW50IChIVE1MIHN0cmluZywgZWxlbWVudCwgb3IgZWxlbWVudCBhcnJheSlcbiAgLSBwYXJlbnRFbFxuICAtIHRvcFxuICAtIGxlZnRcbiAgLSByaWdodCAodGhlIHggY29vcmQgb2Ygd2hlcmUgdGhlIHJpZ2h0IGVkZ2Ugc2hvdWxkIGJlLiBub3QgYSBcIkNTU1wiIHJpZ2h0KVxuICAtIGF1dG9IaWRlIChib29sZWFuKVxuICAtIHNob3cgKGNhbGxiYWNrKVxuICAtIGhpZGUgKGNhbGxiYWNrKVxuKi9cbnZhciBQb3BvdmVyID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIFBvcG92ZXIob3B0aW9ucykge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB0aGlzLmlzSGlkZGVuID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5tYXJnaW4gPSAxMDsgLy8gdGhlIHNwYWNlIHJlcXVpcmVkIGJldHdlZW4gdGhlIHBvcG92ZXIgYW5kIHRoZSBlZGdlcyBvZiB0aGUgc2Nyb2xsIGNvbnRhaW5lclxuICAgICAgICAvLyBUcmlnZ2VyZWQgd2hlbiB0aGUgdXNlciBjbGlja3MgKmFueXdoZXJlKiBpbiB0aGUgZG9jdW1lbnQsIGZvciB0aGUgYXV0b0hpZGUgZmVhdHVyZVxuICAgICAgICB0aGlzLmRvY3VtZW50TW91c2Vkb3duID0gZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICAvLyBvbmx5IGhpZGUgdGhlIHBvcG92ZXIgaWYgdGhlIGNsaWNrIGhhcHBlbmVkIG91dHNpZGUgdGhlIHBvcG92ZXJcbiAgICAgICAgICAgIGlmIChfdGhpcy5lbCAmJiAhX3RoaXMuZWwuY29udGFpbnMoZXYudGFyZ2V0KSkge1xuICAgICAgICAgICAgICAgIF90aGlzLmhpZGUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcbiAgICB9XG4gICAgLy8gU2hvd3MgdGhlIHBvcG92ZXIgb24gdGhlIHNwZWNpZmllZCBwb3NpdGlvbi4gUmVuZGVycyBpdCBpZiBub3QgYWxyZWFkeVxuICAgIFBvcG92ZXIucHJvdG90eXBlLnNob3cgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh0aGlzLmlzSGlkZGVuKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuZWwpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5lbC5zdHlsZS5kaXNwbGF5ID0gJyc7XG4gICAgICAgICAgICB0aGlzLnBvc2l0aW9uKCk7XG4gICAgICAgICAgICB0aGlzLmlzSGlkZGVuID0gZmFsc2U7XG4gICAgICAgICAgICB0aGlzLnRyaWdnZXIoJ3Nob3cnKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLy8gSGlkZXMgdGhlIHBvcG92ZXIsIHRocm91Z2ggQ1NTLCBidXQgZG9lcyBub3QgcmVtb3ZlIGl0IGZyb20gdGhlIERPTVxuICAgIFBvcG92ZXIucHJvdG90eXBlLmhpZGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghdGhpcy5pc0hpZGRlbikge1xuICAgICAgICAgICAgdGhpcy5lbC5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgICAgICAgICAgdGhpcy5pc0hpZGRlbiA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLnRyaWdnZXIoJ2hpZGUnKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLy8gQ3JlYXRlcyBgdGhpcy5lbGAgYW5kIHJlbmRlcnMgY29udGVudCBpbnNpZGUgb2YgaXRcbiAgICBQb3BvdmVyLnByb3RvdHlwZS5yZW5kZXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuICAgICAgICB2YXIgZWwgPSB0aGlzLmVsID0gY3JlYXRlRWxlbWVudCgnZGl2Jywge1xuICAgICAgICAgICAgY2xhc3NOYW1lOiAnZmMtcG9wb3ZlciAnICsgKG9wdGlvbnMuY2xhc3NOYW1lIHx8ICcnKSxcbiAgICAgICAgICAgIHN0eWxlOiB7XG4gICAgICAgICAgICAgICAgdG9wOiAnMCcsXG4gICAgICAgICAgICAgICAgbGVmdDogJzAnXG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAodHlwZW9mIG9wdGlvbnMuY29udGVudCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgb3B0aW9ucy5jb250ZW50KGVsKTtcbiAgICAgICAgfVxuICAgICAgICBvcHRpb25zLnBhcmVudEVsLmFwcGVuZENoaWxkKGVsKTtcbiAgICAgICAgLy8gd2hlbiBhIGNsaWNrIGhhcHBlbnMgb24gYW55dGhpbmcgaW5zaWRlIHdpdGggYSAnZmMtY2xvc2UnIGNsYXNzTmFtZSwgaGlkZSB0aGUgcG9wb3ZlclxuICAgICAgICBsaXN0ZW5CeVNlbGVjdG9yKGVsLCAnY2xpY2snLCAnLmZjLWNsb3NlJywgZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICBfdGhpcy5oaWRlKCk7XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAob3B0aW9ucy5hdXRvSGlkZSkge1xuICAgICAgICAgICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgdGhpcy5kb2N1bWVudE1vdXNlZG93bik7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8vIEhpZGVzIGFuZCB1bnJlZ2lzdGVycyBhbnkgaGFuZGxlcnNcbiAgICBQb3BvdmVyLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLmhpZGUoKTtcbiAgICAgICAgaWYgKHRoaXMuZWwpIHtcbiAgICAgICAgICAgIHJlbW92ZUVsZW1lbnQodGhpcy5lbCk7XG4gICAgICAgICAgICB0aGlzLmVsID0gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdtb3VzZWRvd24nLCB0aGlzLmRvY3VtZW50TW91c2Vkb3duKTtcbiAgICB9O1xuICAgIC8vIFBvc2l0aW9ucyB0aGUgcG9wb3ZlciBvcHRpbWFsbHksIHVzaW5nIHRoZSB0b3AvbGVmdC9yaWdodCBvcHRpb25zXG4gICAgUG9wb3Zlci5wcm90b3R5cGUucG9zaXRpb24gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuICAgICAgICB2YXIgZWwgPSB0aGlzLmVsO1xuICAgICAgICB2YXIgZWxEaW1zID0gZWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7IC8vIG9ubHkgdXNlZCBmb3Igd2lkdGgsaGVpZ2h0XG4gICAgICAgIHZhciBvcmlnaW4gPSBjb21wdXRlUmVjdChlbC5vZmZzZXRQYXJlbnQpO1xuICAgICAgICB2YXIgY2xpcHBpbmdSZWN0ID0gY29tcHV0ZUNsaXBwaW5nUmVjdChvcHRpb25zLnBhcmVudEVsKTtcbiAgICAgICAgdmFyIHRvcDsgLy8gdGhlIFwicG9zaXRpb25cIiAobm90IFwib2Zmc2V0XCIpIHZhbHVlcyBmb3IgdGhlIHBvcG92ZXJcbiAgICAgICAgdmFyIGxlZnQ7IC8vXG4gICAgICAgIC8vIGNvbXB1dGUgdG9wIGFuZCBsZWZ0XG4gICAgICAgIHRvcCA9IG9wdGlvbnMudG9wIHx8IDA7XG4gICAgICAgIGlmIChvcHRpb25zLmxlZnQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgbGVmdCA9IG9wdGlvbnMubGVmdDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChvcHRpb25zLnJpZ2h0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGxlZnQgPSBvcHRpb25zLnJpZ2h0IC0gZWxEaW1zLndpZHRoOyAvLyBkZXJpdmUgdGhlIGxlZnQgdmFsdWUgZnJvbSB0aGUgcmlnaHQgdmFsdWVcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGxlZnQgPSAwO1xuICAgICAgICB9XG4gICAgICAgIC8vIGNvbnN0cmFpbiB0byB0aGUgdmlldyBwb3J0LiBpZiBjb25zdHJhaW5lZCBieSB0d28gZWRnZXMsIGdpdmUgcHJlY2VkZW5jZSB0byB0b3AvbGVmdFxuICAgICAgICB0b3AgPSBNYXRoLm1pbih0b3AsIGNsaXBwaW5nUmVjdC5ib3R0b20gLSBlbERpbXMuaGVpZ2h0IC0gdGhpcy5tYXJnaW4pO1xuICAgICAgICB0b3AgPSBNYXRoLm1heCh0b3AsIGNsaXBwaW5nUmVjdC50b3AgKyB0aGlzLm1hcmdpbik7XG4gICAgICAgIGxlZnQgPSBNYXRoLm1pbihsZWZ0LCBjbGlwcGluZ1JlY3QucmlnaHQgLSBlbERpbXMud2lkdGggLSB0aGlzLm1hcmdpbik7XG4gICAgICAgIGxlZnQgPSBNYXRoLm1heChsZWZ0LCBjbGlwcGluZ1JlY3QubGVmdCArIHRoaXMubWFyZ2luKTtcbiAgICAgICAgYXBwbHlTdHlsZShlbCwge1xuICAgICAgICAgICAgdG9wOiB0b3AgLSBvcmlnaW4udG9wLFxuICAgICAgICAgICAgbGVmdDogbGVmdCAtIG9yaWdpbi5sZWZ0XG4gICAgICAgIH0pO1xuICAgIH07XG4gICAgLy8gVHJpZ2dlcnMgYSBjYWxsYmFjay4gQ2FsbHMgYSBmdW5jdGlvbiBpbiB0aGUgb3B0aW9uIGhhc2ggb2YgdGhlIHNhbWUgbmFtZS5cbiAgICAvLyBBcmd1bWVudHMgYmV5b25kIHRoZSBmaXJzdCBgbmFtZWAgYXJlIGZvcndhcmRlZCBvbi5cbiAgICAvLyBUT0RPOiBiZXR0ZXIgY29kZSByZXVzZSBmb3IgdGhpcy4gUmVwZWF0IGNvZGVcbiAgICAvLyBjYW4ga2lsbCB0aGlzPz8/XG4gICAgUG9wb3Zlci5wcm90b3R5cGUudHJpZ2dlciA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnNbbmFtZV0pIHtcbiAgICAgICAgICAgIHRoaXMub3B0aW9uc1tuYW1lXS5hcHBseSh0aGlzLCBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgcmV0dXJuIFBvcG92ZXI7XG59KCkpO1xuXG4vKiBFdmVudC1yZW5kZXJpbmcgbWV0aG9kcyBmb3IgdGhlIERheUdyaWQgY2xhc3Ncbi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuLy8gXCJTaW1wbGVcIiBpcyBiYWQgYSBuYW1lLiBoYXMgbm90aGluZyB0byBkbyB3aXRoIFNpbXBsZURheUdyaWRcbnZhciBTaW1wbGVEYXlHcmlkRXZlbnRSZW5kZXJlciA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uIChfc3VwZXIpIHtcbiAgICBfX2V4dGVuZHMoU2ltcGxlRGF5R3JpZEV2ZW50UmVuZGVyZXIsIF9zdXBlcik7XG4gICAgZnVuY3Rpb24gU2ltcGxlRGF5R3JpZEV2ZW50UmVuZGVyZXIoKSB7XG4gICAgICAgIHJldHVybiBfc3VwZXIgIT09IG51bGwgJiYgX3N1cGVyLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykgfHwgdGhpcztcbiAgICB9XG4gICAgLy8gQnVpbGRzIHRoZSBIVE1MIHRvIGJlIHVzZWQgZm9yIHRoZSBkZWZhdWx0IGVsZW1lbnQgZm9yIGFuIGluZGl2aWR1YWwgc2VnbWVudFxuICAgIFNpbXBsZURheUdyaWRFdmVudFJlbmRlcmVyLnByb3RvdHlwZS5yZW5kZXJTZWdIdG1sID0gZnVuY3Rpb24gKHNlZywgbWlycm9ySW5mbykge1xuICAgICAgICB2YXIgY29udGV4dCA9IHRoaXMuY29udGV4dDtcbiAgICAgICAgdmFyIGV2ZW50UmFuZ2UgPSBzZWcuZXZlbnRSYW5nZTtcbiAgICAgICAgdmFyIGV2ZW50RGVmID0gZXZlbnRSYW5nZS5kZWY7XG4gICAgICAgIHZhciBldmVudFVpID0gZXZlbnRSYW5nZS51aTtcbiAgICAgICAgdmFyIGFsbERheSA9IGV2ZW50RGVmLmFsbERheTtcbiAgICAgICAgdmFyIGlzRHJhZ2dhYmxlID0gY29tcHV0ZUV2ZW50RHJhZ2dhYmxlKGNvbnRleHQsIGV2ZW50RGVmLCBldmVudFVpKTtcbiAgICAgICAgdmFyIGlzUmVzaXphYmxlRnJvbVN0YXJ0ID0gYWxsRGF5ICYmIHNlZy5pc1N0YXJ0ICYmIGNvbXB1dGVFdmVudFN0YXJ0UmVzaXphYmxlKGNvbnRleHQsIGV2ZW50RGVmLCBldmVudFVpKTtcbiAgICAgICAgdmFyIGlzUmVzaXphYmxlRnJvbUVuZCA9IGFsbERheSAmJiBzZWcuaXNFbmQgJiYgY29tcHV0ZUV2ZW50RW5kUmVzaXphYmxlKGNvbnRleHQsIGV2ZW50RGVmLCBldmVudFVpKTtcbiAgICAgICAgdmFyIGNsYXNzZXMgPSB0aGlzLmdldFNlZ0NsYXNzZXMoc2VnLCBpc0RyYWdnYWJsZSwgaXNSZXNpemFibGVGcm9tU3RhcnQgfHwgaXNSZXNpemFibGVGcm9tRW5kLCBtaXJyb3JJbmZvKTtcbiAgICAgICAgdmFyIHNraW5Dc3MgPSBjc3NUb1N0cih0aGlzLmdldFNraW5Dc3MoZXZlbnRVaSkpO1xuICAgICAgICB2YXIgdGltZUh0bWwgPSAnJztcbiAgICAgICAgdmFyIHRpbWVUZXh0O1xuICAgICAgICB2YXIgdGl0bGVIdG1sO1xuICAgICAgICBjbGFzc2VzLnVuc2hpZnQoJ2ZjLWRheS1ncmlkLWV2ZW50JywgJ2ZjLWgtZXZlbnQnKTtcbiAgICAgICAgLy8gT25seSBkaXNwbGF5IGEgdGltZWQgZXZlbnRzIHRpbWUgaWYgaXQgaXMgdGhlIHN0YXJ0aW5nIHNlZ21lbnRcbiAgICAgICAgaWYgKHNlZy5pc1N0YXJ0KSB7XG4gICAgICAgICAgICB0aW1lVGV4dCA9IHRoaXMuZ2V0VGltZVRleHQoZXZlbnRSYW5nZSk7XG4gICAgICAgICAgICBpZiAodGltZVRleHQpIHtcbiAgICAgICAgICAgICAgICB0aW1lSHRtbCA9ICc8c3BhbiBjbGFzcz1cImZjLXRpbWVcIj4nICsgaHRtbEVzY2FwZSh0aW1lVGV4dCkgKyAnPC9zcGFuPic7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGl0bGVIdG1sID1cbiAgICAgICAgICAgICc8c3BhbiBjbGFzcz1cImZjLXRpdGxlXCI+JyArXG4gICAgICAgICAgICAgICAgKGh0bWxFc2NhcGUoZXZlbnREZWYudGl0bGUgfHwgJycpIHx8ICcmbmJzcDsnKSArIC8vIHdlIGFsd2F5cyB3YW50IG9uZSBsaW5lIG9mIGhlaWdodFxuICAgICAgICAgICAgICAgICc8L3NwYW4+JztcbiAgICAgICAgcmV0dXJuICc8YSBjbGFzcz1cIicgKyBjbGFzc2VzLmpvaW4oJyAnKSArICdcIicgK1xuICAgICAgICAgICAgKGV2ZW50RGVmLnVybCA/XG4gICAgICAgICAgICAgICAgJyBocmVmPVwiJyArIGh0bWxFc2NhcGUoZXZlbnREZWYudXJsKSArICdcIicgOlxuICAgICAgICAgICAgICAgICcnKSArXG4gICAgICAgICAgICAoc2tpbkNzcyA/XG4gICAgICAgICAgICAgICAgJyBzdHlsZT1cIicgKyBza2luQ3NzICsgJ1wiJyA6XG4gICAgICAgICAgICAgICAgJycpICtcbiAgICAgICAgICAgICc+JyArXG4gICAgICAgICAgICAnPGRpdiBjbGFzcz1cImZjLWNvbnRlbnRcIj4nICtcbiAgICAgICAgICAgIChjb250ZXh0Lm9wdGlvbnMuZGlyID09PSAncnRsJyA/XG4gICAgICAgICAgICAgICAgdGl0bGVIdG1sICsgJyAnICsgdGltZUh0bWwgOiAvLyBwdXQgYSBuYXR1cmFsIHNwYWNlIGluIGJldHdlZW5cbiAgICAgICAgICAgICAgICB0aW1lSHRtbCArICcgJyArIHRpdGxlSHRtbCAvL1xuICAgICAgICAgICAgKSArXG4gICAgICAgICAgICAnPC9kaXY+JyArXG4gICAgICAgICAgICAoaXNSZXNpemFibGVGcm9tU3RhcnQgP1xuICAgICAgICAgICAgICAgICc8ZGl2IGNsYXNzPVwiZmMtcmVzaXplciBmYy1zdGFydC1yZXNpemVyXCI+PC9kaXY+JyA6XG4gICAgICAgICAgICAgICAgJycpICtcbiAgICAgICAgICAgIChpc1Jlc2l6YWJsZUZyb21FbmQgP1xuICAgICAgICAgICAgICAgICc8ZGl2IGNsYXNzPVwiZmMtcmVzaXplciBmYy1lbmQtcmVzaXplclwiPjwvZGl2PicgOlxuICAgICAgICAgICAgICAgICcnKSArXG4gICAgICAgICAgICAnPC9hPic7XG4gICAgfTtcbiAgICAvLyBDb21wdXRlcyBhIGRlZmF1bHQgZXZlbnQgdGltZSBmb3JtYXR0aW5nIHN0cmluZyBpZiBgZXZlbnRUaW1lRm9ybWF0YCBpcyBub3QgZXhwbGljaXRseSBkZWZpbmVkXG4gICAgU2ltcGxlRGF5R3JpZEV2ZW50UmVuZGVyZXIucHJvdG90eXBlLmNvbXB1dGVFdmVudFRpbWVGb3JtYXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBob3VyOiAnbnVtZXJpYycsXG4gICAgICAgICAgICBtaW51dGU6ICcyLWRpZ2l0JyxcbiAgICAgICAgICAgIG9taXRaZXJvTWludXRlOiB0cnVlLFxuICAgICAgICAgICAgbWVyaWRpZW06ICduYXJyb3cnXG4gICAgICAgIH07XG4gICAgfTtcbiAgICBTaW1wbGVEYXlHcmlkRXZlbnRSZW5kZXJlci5wcm90b3R5cGUuY29tcHV0ZURpc3BsYXlFdmVudEVuZCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlOyAvLyBUT0RPOiBzb21laG93IGNvbnNpZGVyIHRoZSBvcmlnaW5hdGluZyBEYXlHcmlkJ3MgY29sdW1uIGNvdW50XG4gICAgfTtcbiAgICByZXR1cm4gU2ltcGxlRGF5R3JpZEV2ZW50UmVuZGVyZXI7XG59KEZnRXZlbnRSZW5kZXJlcikpO1xuXG4vKiBFdmVudC1yZW5kZXJpbmcgbWV0aG9kcyBmb3IgdGhlIERheUdyaWQgY2xhc3Ncbi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xudmFyIERheUdyaWRFdmVudFJlbmRlcmVyID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKF9zdXBlcikge1xuICAgIF9fZXh0ZW5kcyhEYXlHcmlkRXZlbnRSZW5kZXJlciwgX3N1cGVyKTtcbiAgICBmdW5jdGlvbiBEYXlHcmlkRXZlbnRSZW5kZXJlcihkYXlHcmlkKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IF9zdXBlci5jYWxsKHRoaXMpIHx8IHRoaXM7XG4gICAgICAgIF90aGlzLmRheUdyaWQgPSBkYXlHcmlkO1xuICAgICAgICByZXR1cm4gX3RoaXM7XG4gICAgfVxuICAgIC8vIFJlbmRlcnMgdGhlIGdpdmVuIGZvcmVncm91bmQgZXZlbnQgc2VnbWVudHMgb250byB0aGUgZ3JpZFxuICAgIERheUdyaWRFdmVudFJlbmRlcmVyLnByb3RvdHlwZS5hdHRhY2hTZWdzID0gZnVuY3Rpb24gKHNlZ3MsIG1pcnJvckluZm8pIHtcbiAgICAgICAgdmFyIHJvd1N0cnVjdHMgPSB0aGlzLnJvd1N0cnVjdHMgPSB0aGlzLnJlbmRlclNlZ1Jvd3Moc2Vncyk7XG4gICAgICAgIC8vIGFwcGVuZCB0byBlYWNoIHJvdydzIGNvbnRlbnQgc2tlbGV0b25cbiAgICAgICAgdGhpcy5kYXlHcmlkLnJvd0Vscy5mb3JFYWNoKGZ1bmN0aW9uIChyb3dOb2RlLCBpKSB7XG4gICAgICAgICAgICByb3dOb2RlLnF1ZXJ5U2VsZWN0b3IoJy5mYy1jb250ZW50LXNrZWxldG9uID4gdGFibGUnKS5hcHBlbmRDaGlsZChyb3dTdHJ1Y3RzW2ldLnRib2R5RWwpO1xuICAgICAgICB9KTtcbiAgICAgICAgLy8gcmVtb3ZlcyB0aGUgXCJtb3JlLi5cIiBldmVudHMgcG9wb3ZlclxuICAgICAgICBpZiAoIW1pcnJvckluZm8pIHtcbiAgICAgICAgICAgIHRoaXMuZGF5R3JpZC5yZW1vdmVTZWdQb3BvdmVyKCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8vIFVucmVuZGVycyBhbGwgY3VycmVudGx5IHJlbmRlcmVkIGZvcmVncm91bmQgZXZlbnQgc2VnbWVudHNcbiAgICBEYXlHcmlkRXZlbnRSZW5kZXJlci5wcm90b3R5cGUuZGV0YWNoU2VncyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHJvd1N0cnVjdHMgPSB0aGlzLnJvd1N0cnVjdHMgfHwgW107XG4gICAgICAgIHZhciByb3dTdHJ1Y3Q7XG4gICAgICAgIHdoaWxlICgocm93U3RydWN0ID0gcm93U3RydWN0cy5wb3AoKSkpIHtcbiAgICAgICAgICAgIHJlbW92ZUVsZW1lbnQocm93U3RydWN0LnRib2R5RWwpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucm93U3RydWN0cyA9IG51bGw7XG4gICAgfTtcbiAgICAvLyBVc2VzIHRoZSBnaXZlbiBldmVudHMgYXJyYXkgdG8gZ2VuZXJhdGUgPHRib2R5PiBlbGVtZW50cyB0aGF0IHNob3VsZCBiZSBhcHBlbmRlZCB0byBlYWNoIHJvdydzIGNvbnRlbnQgc2tlbGV0b24uXG4gICAgLy8gUmV0dXJucyBhbiBhcnJheSBvZiByb3dTdHJ1Y3Qgb2JqZWN0cyAoc2VlIHRoZSBib3R0b20gb2YgYHJlbmRlclNlZ1Jvd2ApLlxuICAgIC8vIFBSRUNPTkRJVElPTjogZWFjaCBzZWdtZW50IHNob3VkIGFscmVhZHkgaGF2ZSBhIHJlbmRlcmVkIGFuZCBhc3NpZ25lZCBgLmVsYFxuICAgIERheUdyaWRFdmVudFJlbmRlcmVyLnByb3RvdHlwZS5yZW5kZXJTZWdSb3dzID0gZnVuY3Rpb24gKHNlZ3MpIHtcbiAgICAgICAgdmFyIHJvd1N0cnVjdHMgPSBbXTtcbiAgICAgICAgdmFyIHNlZ1Jvd3M7XG4gICAgICAgIHZhciByb3c7XG4gICAgICAgIHNlZ1Jvd3MgPSB0aGlzLmdyb3VwU2VnUm93cyhzZWdzKTsgLy8gZ3JvdXAgaW50byBuZXN0ZWQgYXJyYXlzXG4gICAgICAgIC8vIGl0ZXJhdGUgZWFjaCByb3cgb2Ygc2VnbWVudCBncm91cGluZ3NcbiAgICAgICAgZm9yIChyb3cgPSAwOyByb3cgPCBzZWdSb3dzLmxlbmd0aDsgcm93KyspIHtcbiAgICAgICAgICAgIHJvd1N0cnVjdHMucHVzaCh0aGlzLnJlbmRlclNlZ1Jvdyhyb3csIHNlZ1Jvd3Nbcm93XSkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByb3dTdHJ1Y3RzO1xuICAgIH07XG4gICAgLy8gR2l2ZW4gYSByb3cgIyBhbmQgYW4gYXJyYXkgb2Ygc2VnbWVudHMgYWxsIGluIHRoZSBzYW1lIHJvdywgcmVuZGVyIGEgPHRib2R5PiBlbGVtZW50LCBhIHNrZWxldG9uIHRoYXQgY29udGFpbnNcbiAgICAvLyB0aGUgc2VnbWVudHMuIFJldHVybnMgb2JqZWN0IHdpdGggYSBidW5jaCBvZiBpbnRlcm5hbCBkYXRhIGFib3V0IGhvdyB0aGUgcmVuZGVyIHdhcyBjYWxjdWxhdGVkLlxuICAgIC8vIE5PVEU6IG1vZGlmaWVzIHJvd1NlZ3NcbiAgICBEYXlHcmlkRXZlbnRSZW5kZXJlci5wcm90b3R5cGUucmVuZGVyU2VnUm93ID0gZnVuY3Rpb24gKHJvdywgcm93U2Vncykge1xuICAgICAgICB2YXIgaXNSdGwgPSB0aGlzLmNvbnRleHQuaXNSdGw7XG4gICAgICAgIHZhciBkYXlHcmlkID0gdGhpcy5kYXlHcmlkO1xuICAgICAgICB2YXIgY29sQ250ID0gZGF5R3JpZC5jb2xDbnQ7XG4gICAgICAgIHZhciBzZWdMZXZlbHMgPSB0aGlzLmJ1aWxkU2VnTGV2ZWxzKHJvd1NlZ3MpOyAvLyBncm91cCBpbnRvIHN1Yi1hcnJheXMgb2YgbGV2ZWxzXG4gICAgICAgIHZhciBsZXZlbENudCA9IE1hdGgubWF4KDEsIHNlZ0xldmVscy5sZW5ndGgpOyAvLyBlbnN1cmUgYXQgbGVhc3Qgb25lIGxldmVsXG4gICAgICAgIHZhciB0Ym9keSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3Rib2R5Jyk7XG4gICAgICAgIHZhciBzZWdNYXRyaXggPSBbXTsgLy8gbG9va3VwIGZvciB3aGljaCBzZWdtZW50cyBhcmUgcmVuZGVyZWQgaW50byB3aGljaCBsZXZlbCtjb2wgY2VsbHNcbiAgICAgICAgdmFyIGNlbGxNYXRyaXggPSBbXTsgLy8gbG9va3VwIGZvciBhbGwgPHRkPiBlbGVtZW50cyBvZiB0aGUgbGV2ZWwrY29sIG1hdHJpeFxuICAgICAgICB2YXIgbG9uZUNlbGxNYXRyaXggPSBbXTsgLy8gbG9va3VwIGZvciA8dGQ+IGVsZW1lbnRzIHRoYXQgb25seSB0YWtlIHVwIGEgc2luZ2xlIGNvbHVtblxuICAgICAgICB2YXIgaTtcbiAgICAgICAgdmFyIGxldmVsU2VncztcbiAgICAgICAgdmFyIGNvbDtcbiAgICAgICAgdmFyIHRyO1xuICAgICAgICB2YXIgajtcbiAgICAgICAgdmFyIHNlZztcbiAgICAgICAgdmFyIHRkO1xuICAgICAgICAvLyBwb3B1bGF0ZXMgZW1wdHkgY2VsbHMgZnJvbSB0aGUgY3VycmVudCBjb2x1bW4gKGBjb2xgKSB0byBgZW5kQ29sYFxuICAgICAgICBmdW5jdGlvbiBlbXB0eUNlbGxzVW50aWwoZW5kQ29sKSB7XG4gICAgICAgICAgICB3aGlsZSAoY29sIDwgZW5kQ29sKSB7XG4gICAgICAgICAgICAgICAgLy8gdHJ5IHRvIGdyYWIgYSBjZWxsIGZyb20gdGhlIGxldmVsIGFib3ZlIGFuZCBleHRlbmQgaXRzIHJvd3NwYW4uIG90aGVyd2lzZSwgY3JlYXRlIGEgZnJlc2ggY2VsbFxuICAgICAgICAgICAgICAgIHRkID0gKGxvbmVDZWxsTWF0cml4W2kgLSAxXSB8fCBbXSlbY29sXTtcbiAgICAgICAgICAgICAgICBpZiAodGQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGQucm93U3BhbiA9ICh0ZC5yb3dTcGFuIHx8IDEpICsgMTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRkID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndGQnKTtcbiAgICAgICAgICAgICAgICAgICAgdHIuYXBwZW5kQ2hpbGQodGQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjZWxsTWF0cml4W2ldW2NvbF0gPSB0ZDtcbiAgICAgICAgICAgICAgICBsb25lQ2VsbE1hdHJpeFtpXVtjb2xdID0gdGQ7XG4gICAgICAgICAgICAgICAgY29sKys7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGxldmVsQ250OyBpKyspIHsgLy8gaXRlcmF0ZSB0aHJvdWdoIGFsbCBsZXZlbHNcbiAgICAgICAgICAgIGxldmVsU2VncyA9IHNlZ0xldmVsc1tpXTtcbiAgICAgICAgICAgIGNvbCA9IDA7XG4gICAgICAgICAgICB0ciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3RyJyk7XG4gICAgICAgICAgICBzZWdNYXRyaXgucHVzaChbXSk7XG4gICAgICAgICAgICBjZWxsTWF0cml4LnB1c2goW10pO1xuICAgICAgICAgICAgbG9uZUNlbGxNYXRyaXgucHVzaChbXSk7XG4gICAgICAgICAgICAvLyBsZXZlbENudCBtaWdodCBiZSAxIGV2ZW4gdGhvdWdoIHRoZXJlIGFyZSBubyBhY3R1YWwgbGV2ZWxzLiBwcm90ZWN0IGFnYWluc3QgdGhpcy5cbiAgICAgICAgICAgIC8vIHRoaXMgc2luZ2xlIGVtcHR5IHJvdyBpcyB1c2VmdWwgZm9yIHN0eWxpbmcuXG4gICAgICAgICAgICBpZiAobGV2ZWxTZWdzKSB7XG4gICAgICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IGxldmVsU2Vncy5sZW5ndGg7IGorKykgeyAvLyBpdGVyYXRlIHRocm91Z2ggc2VnbWVudHMgaW4gbGV2ZWxcbiAgICAgICAgICAgICAgICAgICAgc2VnID0gbGV2ZWxTZWdzW2pdO1xuICAgICAgICAgICAgICAgICAgICB2YXIgbGVmdENvbCA9IGlzUnRsID8gKGNvbENudCAtIDEgLSBzZWcubGFzdENvbCkgOiBzZWcuZmlyc3RDb2w7XG4gICAgICAgICAgICAgICAgICAgIHZhciByaWdodENvbCA9IGlzUnRsID8gKGNvbENudCAtIDEgLSBzZWcuZmlyc3RDb2wpIDogc2VnLmxhc3RDb2w7XG4gICAgICAgICAgICAgICAgICAgIGVtcHR5Q2VsbHNVbnRpbChsZWZ0Q29sKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gY3JlYXRlIGEgY29udGFpbmVyIHRoYXQgb2NjdXBpZXMgb3IgbW9yZSBjb2x1bW5zLiBhcHBlbmQgdGhlIGV2ZW50IGVsZW1lbnQuXG4gICAgICAgICAgICAgICAgICAgIHRkID0gY3JlYXRlRWxlbWVudCgndGQnLCB7IGNsYXNzTmFtZTogJ2ZjLWV2ZW50LWNvbnRhaW5lcicgfSwgc2VnLmVsKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGxlZnRDb2wgIT09IHJpZ2h0Q29sKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0ZC5jb2xTcGFuID0gcmlnaHRDb2wgLSBsZWZ0Q29sICsgMTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIHsgLy8gYSBzaW5nbGUtY29sdW1uIHNlZ21lbnRcbiAgICAgICAgICAgICAgICAgICAgICAgIGxvbmVDZWxsTWF0cml4W2ldW2NvbF0gPSB0ZDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB3aGlsZSAoY29sIDw9IHJpZ2h0Q29sKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjZWxsTWF0cml4W2ldW2NvbF0gPSB0ZDtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlZ01hdHJpeFtpXVtjb2xdID0gc2VnO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29sKys7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgdHIuYXBwZW5kQ2hpbGQodGQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVtcHR5Q2VsbHNVbnRpbChjb2xDbnQpOyAvLyBmaW5pc2ggb2ZmIHRoZSByb3dcbiAgICAgICAgICAgIHZhciBpbnRyb0h0bWwgPSBkYXlHcmlkLnJlbmRlclByb3BzLnJlbmRlckludHJvSHRtbCgpO1xuICAgICAgICAgICAgaWYgKGludHJvSHRtbCkge1xuICAgICAgICAgICAgICAgIGlmIChpc1J0bCkge1xuICAgICAgICAgICAgICAgICAgICBhcHBlbmRUb0VsZW1lbnQodHIsIGludHJvSHRtbCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBwcmVwZW5kVG9FbGVtZW50KHRyLCBpbnRyb0h0bWwpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRib2R5LmFwcGVuZENoaWxkKHRyKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgcm93OiByb3csXG4gICAgICAgICAgICB0Ym9keUVsOiB0Ym9keSxcbiAgICAgICAgICAgIGNlbGxNYXRyaXg6IGNlbGxNYXRyaXgsXG4gICAgICAgICAgICBzZWdNYXRyaXg6IHNlZ01hdHJpeCxcbiAgICAgICAgICAgIHNlZ0xldmVsczogc2VnTGV2ZWxzLFxuICAgICAgICAgICAgc2Vnczogcm93U2Vnc1xuICAgICAgICB9O1xuICAgIH07XG4gICAgLy8gU3RhY2tzIGEgZmxhdCBhcnJheSBvZiBzZWdtZW50cywgd2hpY2ggYXJlIGFsbCBhc3N1bWVkIHRvIGJlIGluIHRoZSBzYW1lIHJvdywgaW50byBzdWJhcnJheXMgb2YgdmVydGljYWwgbGV2ZWxzLlxuICAgIC8vIE5PVEU6IG1vZGlmaWVzIHNlZ3NcbiAgICBEYXlHcmlkRXZlbnRSZW5kZXJlci5wcm90b3R5cGUuYnVpbGRTZWdMZXZlbHMgPSBmdW5jdGlvbiAoc2Vncykge1xuICAgICAgICB2YXIgaXNSdGwgPSB0aGlzLmNvbnRleHQuaXNSdGw7XG4gICAgICAgIHZhciBjb2xDbnQgPSB0aGlzLmRheUdyaWQuY29sQ250O1xuICAgICAgICB2YXIgbGV2ZWxzID0gW107XG4gICAgICAgIHZhciBpO1xuICAgICAgICB2YXIgc2VnO1xuICAgICAgICB2YXIgajtcbiAgICAgICAgLy8gR2l2ZSBwcmVmZXJlbmNlIHRvIGVsZW1lbnRzIHdpdGggY2VydGFpbiBjcml0ZXJpYSwgc28gdGhleSBoYXZlXG4gICAgICAgIC8vIGEgY2hhbmNlIHRvIGJlIGNsb3NlciB0byB0aGUgdG9wLlxuICAgICAgICBzZWdzID0gdGhpcy5zb3J0RXZlbnRTZWdzKHNlZ3MpO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgc2Vncy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgc2VnID0gc2Vnc1tpXTtcbiAgICAgICAgICAgIC8vIGxvb3AgdGhyb3VnaCBsZXZlbHMsIHN0YXJ0aW5nIHdpdGggdGhlIHRvcG1vc3QsIHVudGlsIHRoZSBzZWdtZW50IGRvZXNuJ3QgY29sbGlkZSB3aXRoIG90aGVyIHNlZ21lbnRzXG4gICAgICAgICAgICBmb3IgKGogPSAwOyBqIDwgbGV2ZWxzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFpc0RheVNlZ0NvbGxpc2lvbihzZWcsIGxldmVsc1tqXSkpIHtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gYGpgIG5vdyBob2xkcyB0aGUgZGVzaXJlZCBzdWJyb3cgaW5kZXhcbiAgICAgICAgICAgIHNlZy5sZXZlbCA9IGo7XG4gICAgICAgICAgICBzZWcubGVmdENvbCA9IGlzUnRsID8gKGNvbENudCAtIDEgLSBzZWcubGFzdENvbCkgOiBzZWcuZmlyc3RDb2w7IC8vIGZvciBzb3J0aW5nIG9ubHlcbiAgICAgICAgICAgIHNlZy5yaWdodENvbCA9IGlzUnRsID8gKGNvbENudCAtIDEgLSBzZWcuZmlyc3RDb2wpIDogc2VnLmxhc3RDb2wgLy8gZm9yIHNvcnRpbmcgb25seVxuICAgICAgICAgICAgO1xuICAgICAgICAgICAgKGxldmVsc1tqXSB8fCAobGV2ZWxzW2pdID0gW10pKS5wdXNoKHNlZyk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gb3JkZXIgc2VnbWVudHMgbGVmdC10by1yaWdodC4gdmVyeSBpbXBvcnRhbnQgaWYgY2FsZW5kYXIgaXMgUlRMXG4gICAgICAgIGZvciAoaiA9IDA7IGogPCBsZXZlbHMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgIGxldmVsc1tqXS5zb3J0KGNvbXBhcmVEYXlTZWdDb2xzKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbGV2ZWxzO1xuICAgIH07XG4gICAgLy8gR2l2ZW4gYSBmbGF0IGFycmF5IG9mIHNlZ21lbnRzLCByZXR1cm4gYW4gYXJyYXkgb2Ygc3ViLWFycmF5cywgZ3JvdXBlZCBieSBlYWNoIHNlZ21lbnQncyByb3dcbiAgICBEYXlHcmlkRXZlbnRSZW5kZXJlci5wcm90b3R5cGUuZ3JvdXBTZWdSb3dzID0gZnVuY3Rpb24gKHNlZ3MpIHtcbiAgICAgICAgdmFyIHNlZ1Jvd3MgPSBbXTtcbiAgICAgICAgdmFyIGk7XG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCB0aGlzLmRheUdyaWQucm93Q250OyBpKyspIHtcbiAgICAgICAgICAgIHNlZ1Jvd3MucHVzaChbXSk7XG4gICAgICAgIH1cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHNlZ3MubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHNlZ1Jvd3Nbc2Vnc1tpXS5yb3ddLnB1c2goc2Vnc1tpXSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlZ1Jvd3M7XG4gICAgfTtcbiAgICAvLyBDb21wdXRlcyBhIGRlZmF1bHQgYGRpc3BsYXlFdmVudEVuZGAgdmFsdWUgaWYgb25lIGlzIG5vdCBleHBsaWNsdHkgZGVmaW5lZFxuICAgIERheUdyaWRFdmVudFJlbmRlcmVyLnByb3RvdHlwZS5jb21wdXRlRGlzcGxheUV2ZW50RW5kID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5kYXlHcmlkLmNvbENudCA9PT0gMTsgLy8gd2UnbGwgbGlrZWx5IGhhdmUgc3BhY2UgaWYgdGhlcmUncyBvbmx5IG9uZSBkYXlcbiAgICB9O1xuICAgIHJldHVybiBEYXlHcmlkRXZlbnRSZW5kZXJlcjtcbn0oU2ltcGxlRGF5R3JpZEV2ZW50UmVuZGVyZXIpKTtcbi8vIENvbXB1dGVzIHdoZXRoZXIgdHdvIHNlZ21lbnRzJyBjb2x1bW5zIGNvbGxpZGUuIFRoZXkgYXJlIGFzc3VtZWQgdG8gYmUgaW4gdGhlIHNhbWUgcm93LlxuZnVuY3Rpb24gaXNEYXlTZWdDb2xsaXNpb24oc2VnLCBvdGhlclNlZ3MpIHtcbiAgICB2YXIgaTtcbiAgICB2YXIgb3RoZXJTZWc7XG4gICAgZm9yIChpID0gMDsgaSA8IG90aGVyU2Vncy5sZW5ndGg7IGkrKykge1xuICAgICAgICBvdGhlclNlZyA9IG90aGVyU2Vnc1tpXTtcbiAgICAgICAgaWYgKG90aGVyU2VnLmZpcnN0Q29sIDw9IHNlZy5sYXN0Q29sICYmXG4gICAgICAgICAgICBvdGhlclNlZy5sYXN0Q29sID49IHNlZy5maXJzdENvbCkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xufVxuLy8gQSBjbXAgZnVuY3Rpb24gZm9yIGRldGVybWluaW5nIHRoZSBsZWZ0bW9zdCBldmVudFxuZnVuY3Rpb24gY29tcGFyZURheVNlZ0NvbHMoYSwgYikge1xuICAgIHJldHVybiBhLmxlZnRDb2wgLSBiLmxlZnRDb2w7XG59XG5cbnZhciBEYXlHcmlkTWlycm9yUmVuZGVyZXIgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoX3N1cGVyKSB7XG4gICAgX19leHRlbmRzKERheUdyaWRNaXJyb3JSZW5kZXJlciwgX3N1cGVyKTtcbiAgICBmdW5jdGlvbiBEYXlHcmlkTWlycm9yUmVuZGVyZXIoKSB7XG4gICAgICAgIHJldHVybiBfc3VwZXIgIT09IG51bGwgJiYgX3N1cGVyLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykgfHwgdGhpcztcbiAgICB9XG4gICAgRGF5R3JpZE1pcnJvclJlbmRlcmVyLnByb3RvdHlwZS5hdHRhY2hTZWdzID0gZnVuY3Rpb24gKHNlZ3MsIG1pcnJvckluZm8pIHtcbiAgICAgICAgdmFyIHNvdXJjZVNlZyA9IG1pcnJvckluZm8uc291cmNlU2VnO1xuICAgICAgICB2YXIgcm93U3RydWN0cyA9IHRoaXMucm93U3RydWN0cyA9IHRoaXMucmVuZGVyU2VnUm93cyhzZWdzKTtcbiAgICAgICAgLy8gaW5qZWN0IGVhY2ggbmV3IGV2ZW50IHNrZWxldG9uIGludG8gZWFjaCBhc3NvY2lhdGVkIHJvd1xuICAgICAgICB0aGlzLmRheUdyaWQucm93RWxzLmZvckVhY2goZnVuY3Rpb24gKHJvd05vZGUsIHJvdykge1xuICAgICAgICAgICAgdmFyIHNrZWxldG9uRWwgPSBodG1sVG9FbGVtZW50KCc8ZGl2IGNsYXNzPVwiZmMtbWlycm9yLXNrZWxldG9uXCI+PHRhYmxlPjwvdGFibGU+PC9kaXY+Jyk7IC8vIHdpbGwgYmUgYWJzb2x1dGVseSBwb3NpdGlvbmVkXG4gICAgICAgICAgICB2YXIgc2tlbGV0b25Ub3BFbDtcbiAgICAgICAgICAgIHZhciBza2VsZXRvblRvcDtcbiAgICAgICAgICAgIC8vIElmIHRoZXJlIGlzIGFuIG9yaWdpbmFsIHNlZ21lbnQsIG1hdGNoIHRoZSB0b3AgcG9zaXRpb24uIE90aGVyd2lzZSwgcHV0IGl0IGF0IHRoZSByb3cncyB0b3AgbGV2ZWxcbiAgICAgICAgICAgIGlmIChzb3VyY2VTZWcgJiYgc291cmNlU2VnLnJvdyA9PT0gcm93KSB7XG4gICAgICAgICAgICAgICAgc2tlbGV0b25Ub3BFbCA9IHNvdXJjZVNlZy5lbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHNrZWxldG9uVG9wRWwgPSByb3dOb2RlLnF1ZXJ5U2VsZWN0b3IoJy5mYy1jb250ZW50LXNrZWxldG9uIHRib2R5Jyk7XG4gICAgICAgICAgICAgICAgaWYgKCFza2VsZXRvblRvcEVsKSB7IC8vIHdoZW4gbm8gZXZlbnRzXG4gICAgICAgICAgICAgICAgICAgIHNrZWxldG9uVG9wRWwgPSByb3dOb2RlLnF1ZXJ5U2VsZWN0b3IoJy5mYy1jb250ZW50LXNrZWxldG9uIHRhYmxlJyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc2tlbGV0b25Ub3AgPSBza2VsZXRvblRvcEVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCAtXG4gICAgICAgICAgICAgICAgcm93Tm9kZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS50b3A7IC8vIHRoZSBvZmZzZXRQYXJlbnQgb3JpZ2luXG4gICAgICAgICAgICBza2VsZXRvbkVsLnN0eWxlLnRvcCA9IHNrZWxldG9uVG9wICsgJ3B4JztcbiAgICAgICAgICAgIHNrZWxldG9uRWwucXVlcnlTZWxlY3RvcigndGFibGUnKS5hcHBlbmRDaGlsZChyb3dTdHJ1Y3RzW3Jvd10udGJvZHlFbCk7XG4gICAgICAgICAgICByb3dOb2RlLmFwcGVuZENoaWxkKHNrZWxldG9uRWwpO1xuICAgICAgICB9KTtcbiAgICB9O1xuICAgIHJldHVybiBEYXlHcmlkTWlycm9yUmVuZGVyZXI7XG59KERheUdyaWRFdmVudFJlbmRlcmVyKSk7XG5cbnZhciBFTVBUWV9DRUxMX0hUTUwgPSAnPHRkIHN0eWxlPVwicG9pbnRlci1ldmVudHM6bm9uZVwiPjwvdGQ+JztcbnZhciBEYXlHcmlkRmlsbFJlbmRlcmVyID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKF9zdXBlcikge1xuICAgIF9fZXh0ZW5kcyhEYXlHcmlkRmlsbFJlbmRlcmVyLCBfc3VwZXIpO1xuICAgIGZ1bmN0aW9uIERheUdyaWRGaWxsUmVuZGVyZXIoZGF5R3JpZCkge1xuICAgICAgICB2YXIgX3RoaXMgPSBfc3VwZXIuY2FsbCh0aGlzKSB8fCB0aGlzO1xuICAgICAgICBfdGhpcy5maWxsU2VnVGFnID0gJ3RkJzsgLy8gb3ZlcnJpZGUgdGhlIGRlZmF1bHQgdGFnIG5hbWVcbiAgICAgICAgX3RoaXMuZGF5R3JpZCA9IGRheUdyaWQ7XG4gICAgICAgIHJldHVybiBfdGhpcztcbiAgICB9XG4gICAgRGF5R3JpZEZpbGxSZW5kZXJlci5wcm90b3R5cGUucmVuZGVyU2VncyA9IGZ1bmN0aW9uICh0eXBlLCBjb250ZXh0LCBzZWdzKSB7XG4gICAgICAgIC8vIGRvbid0IHJlbmRlciB0aW1lZCBiYWNrZ3JvdW5kIGV2ZW50c1xuICAgICAgICBpZiAodHlwZSA9PT0gJ2JnRXZlbnQnKSB7XG4gICAgICAgICAgICBzZWdzID0gc2Vncy5maWx0ZXIoZnVuY3Rpb24gKHNlZykge1xuICAgICAgICAgICAgICAgIHJldHVybiBzZWcuZXZlbnRSYW5nZS5kZWYuYWxsRGF5O1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgX3N1cGVyLnByb3RvdHlwZS5yZW5kZXJTZWdzLmNhbGwodGhpcywgdHlwZSwgY29udGV4dCwgc2Vncyk7XG4gICAgfTtcbiAgICBEYXlHcmlkRmlsbFJlbmRlcmVyLnByb3RvdHlwZS5hdHRhY2hTZWdzID0gZnVuY3Rpb24gKHR5cGUsIHNlZ3MpIHtcbiAgICAgICAgdmFyIGVscyA9IFtdO1xuICAgICAgICB2YXIgaTtcbiAgICAgICAgdmFyIHNlZztcbiAgICAgICAgdmFyIHNrZWxldG9uRWw7XG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBzZWdzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBzZWcgPSBzZWdzW2ldO1xuICAgICAgICAgICAgc2tlbGV0b25FbCA9IHRoaXMucmVuZGVyRmlsbFJvdyh0eXBlLCBzZWcpO1xuICAgICAgICAgICAgdGhpcy5kYXlHcmlkLnJvd0Vsc1tzZWcucm93XS5hcHBlbmRDaGlsZChza2VsZXRvbkVsKTtcbiAgICAgICAgICAgIGVscy5wdXNoKHNrZWxldG9uRWwpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBlbHM7XG4gICAgfTtcbiAgICAvLyBHZW5lcmF0ZXMgdGhlIEhUTUwgbmVlZGVkIGZvciBvbmUgcm93IG9mIGEgZmlsbC4gUmVxdWlyZXMgdGhlIHNlZydzIGVsIHRvIGJlIHJlbmRlcmVkLlxuICAgIERheUdyaWRGaWxsUmVuZGVyZXIucHJvdG90eXBlLnJlbmRlckZpbGxSb3cgPSBmdW5jdGlvbiAodHlwZSwgc2VnKSB7XG4gICAgICAgIHZhciBkYXlHcmlkID0gdGhpcy5kYXlHcmlkO1xuICAgICAgICB2YXIgaXNSdGwgPSB0aGlzLmNvbnRleHQuaXNSdGw7XG4gICAgICAgIHZhciBjb2xDbnQgPSBkYXlHcmlkLmNvbENudDtcbiAgICAgICAgdmFyIGxlZnRDb2wgPSBpc1J0bCA/IChjb2xDbnQgLSAxIC0gc2VnLmxhc3RDb2wpIDogc2VnLmZpcnN0Q29sO1xuICAgICAgICB2YXIgcmlnaHRDb2wgPSBpc1J0bCA/IChjb2xDbnQgLSAxIC0gc2VnLmZpcnN0Q29sKSA6IHNlZy5sYXN0Q29sO1xuICAgICAgICB2YXIgc3RhcnRDb2wgPSBsZWZ0Q29sO1xuICAgICAgICB2YXIgZW5kQ29sID0gcmlnaHRDb2wgKyAxO1xuICAgICAgICB2YXIgY2xhc3NOYW1lO1xuICAgICAgICB2YXIgc2tlbGV0b25FbDtcbiAgICAgICAgdmFyIHRyRWw7XG4gICAgICAgIGlmICh0eXBlID09PSAnYnVzaW5lc3NIb3VycycpIHtcbiAgICAgICAgICAgIGNsYXNzTmFtZSA9ICdiZ2V2ZW50JztcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNsYXNzTmFtZSA9IHR5cGUudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgfVxuICAgICAgICBza2VsZXRvbkVsID0gaHRtbFRvRWxlbWVudCgnPGRpdiBjbGFzcz1cImZjLScgKyBjbGFzc05hbWUgKyAnLXNrZWxldG9uXCI+JyArXG4gICAgICAgICAgICAnPHRhYmxlPjx0cj48L3RyPjwvdGFibGU+JyArXG4gICAgICAgICAgICAnPC9kaXY+Jyk7XG4gICAgICAgIHRyRWwgPSBza2VsZXRvbkVsLmdldEVsZW1lbnRzQnlUYWdOYW1lKCd0cicpWzBdO1xuICAgICAgICBpZiAoc3RhcnRDb2wgPiAwKSB7XG4gICAgICAgICAgICBhcHBlbmRUb0VsZW1lbnQodHJFbCwgXG4gICAgICAgICAgICAvLyB3aWxsIGNyZWF0ZSAoc3RhcnRDb2wgKyAxKSB0ZCdzXG4gICAgICAgICAgICBuZXcgQXJyYXkoc3RhcnRDb2wgKyAxKS5qb2luKEVNUFRZX0NFTExfSFRNTCkpO1xuICAgICAgICB9XG4gICAgICAgIHNlZy5lbC5jb2xTcGFuID0gZW5kQ29sIC0gc3RhcnRDb2w7XG4gICAgICAgIHRyRWwuYXBwZW5kQ2hpbGQoc2VnLmVsKTtcbiAgICAgICAgaWYgKGVuZENvbCA8IGNvbENudCkge1xuICAgICAgICAgICAgYXBwZW5kVG9FbGVtZW50KHRyRWwsIFxuICAgICAgICAgICAgLy8gd2lsbCBjcmVhdGUgKGNvbENudCAtIGVuZENvbCkgdGQnc1xuICAgICAgICAgICAgbmV3IEFycmF5KGNvbENudCAtIGVuZENvbCArIDEpLmpvaW4oRU1QVFlfQ0VMTF9IVE1MKSk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGludHJvSHRtbCA9IGRheUdyaWQucmVuZGVyUHJvcHMucmVuZGVySW50cm9IdG1sKCk7XG4gICAgICAgIGlmIChpbnRyb0h0bWwpIHtcbiAgICAgICAgICAgIGlmIChpc1J0bCkge1xuICAgICAgICAgICAgICAgIGFwcGVuZFRvRWxlbWVudCh0ckVsLCBpbnRyb0h0bWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgcHJlcGVuZFRvRWxlbWVudCh0ckVsLCBpbnRyb0h0bWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBza2VsZXRvbkVsO1xuICAgIH07XG4gICAgcmV0dXJuIERheUdyaWRGaWxsUmVuZGVyZXI7XG59KEZpbGxSZW5kZXJlcikpO1xuXG52YXIgRGF5VGlsZSA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uIChfc3VwZXIpIHtcbiAgICBfX2V4dGVuZHMoRGF5VGlsZSwgX3N1cGVyKTtcbiAgICBmdW5jdGlvbiBEYXlUaWxlKGVsKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IF9zdXBlci5jYWxsKHRoaXMsIGVsKSB8fCB0aGlzO1xuICAgICAgICB2YXIgZXZlbnRSZW5kZXJlciA9IF90aGlzLmV2ZW50UmVuZGVyZXIgPSBuZXcgRGF5VGlsZUV2ZW50UmVuZGVyZXIoX3RoaXMpO1xuICAgICAgICB2YXIgcmVuZGVyRnJhbWUgPSBfdGhpcy5yZW5kZXJGcmFtZSA9IG1lbW9pemVSZW5kZXJpbmcoX3RoaXMuX3JlbmRlckZyYW1lKTtcbiAgICAgICAgX3RoaXMucmVuZGVyRmdFdmVudHMgPSBtZW1vaXplUmVuZGVyaW5nKGV2ZW50UmVuZGVyZXIucmVuZGVyU2Vncy5iaW5kKGV2ZW50UmVuZGVyZXIpLCBldmVudFJlbmRlcmVyLnVucmVuZGVyLmJpbmQoZXZlbnRSZW5kZXJlciksIFtyZW5kZXJGcmFtZV0pO1xuICAgICAgICBfdGhpcy5yZW5kZXJFdmVudFNlbGVjdGlvbiA9IG1lbW9pemVSZW5kZXJpbmcoZXZlbnRSZW5kZXJlci5zZWxlY3RCeUluc3RhbmNlSWQuYmluZChldmVudFJlbmRlcmVyKSwgZXZlbnRSZW5kZXJlci51bnNlbGVjdEJ5SW5zdGFuY2VJZC5iaW5kKGV2ZW50UmVuZGVyZXIpLCBbX3RoaXMucmVuZGVyRmdFdmVudHNdKTtcbiAgICAgICAgX3RoaXMucmVuZGVyRXZlbnREcmFnID0gbWVtb2l6ZVJlbmRlcmluZyhldmVudFJlbmRlcmVyLmhpZGVCeUhhc2guYmluZChldmVudFJlbmRlcmVyKSwgZXZlbnRSZW5kZXJlci5zaG93QnlIYXNoLmJpbmQoZXZlbnRSZW5kZXJlciksIFtyZW5kZXJGcmFtZV0pO1xuICAgICAgICBfdGhpcy5yZW5kZXJFdmVudFJlc2l6ZSA9IG1lbW9pemVSZW5kZXJpbmcoZXZlbnRSZW5kZXJlci5oaWRlQnlIYXNoLmJpbmQoZXZlbnRSZW5kZXJlciksIGV2ZW50UmVuZGVyZXIuc2hvd0J5SGFzaC5iaW5kKGV2ZW50UmVuZGVyZXIpLCBbcmVuZGVyRnJhbWVdKTtcbiAgICAgICAgcmV0dXJuIF90aGlzO1xuICAgIH1cbiAgICBEYXlUaWxlLnByb3RvdHlwZS5maXJzdENvbnRleHQgPSBmdW5jdGlvbiAoY29udGV4dCkge1xuICAgICAgICBjb250ZXh0LmNhbGVuZGFyLnJlZ2lzdGVySW50ZXJhY3RpdmVDb21wb25lbnQodGhpcywge1xuICAgICAgICAgICAgZWw6IHRoaXMuZWwsXG4gICAgICAgICAgICB1c2VFdmVudENlbnRlcjogZmFsc2VcbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICBEYXlUaWxlLnByb3RvdHlwZS5yZW5kZXIgPSBmdW5jdGlvbiAocHJvcHMsIGNvbnRleHQpIHtcbiAgICAgICAgdGhpcy5yZW5kZXJGcmFtZShwcm9wcy5kYXRlKTtcbiAgICAgICAgdGhpcy5yZW5kZXJGZ0V2ZW50cyhjb250ZXh0LCBwcm9wcy5mZ1NlZ3MpO1xuICAgICAgICB0aGlzLnJlbmRlckV2ZW50U2VsZWN0aW9uKHByb3BzLmV2ZW50U2VsZWN0aW9uKTtcbiAgICAgICAgdGhpcy5yZW5kZXJFdmVudERyYWcocHJvcHMuZXZlbnREcmFnSW5zdGFuY2VzKTtcbiAgICAgICAgdGhpcy5yZW5kZXJFdmVudFJlc2l6ZShwcm9wcy5ldmVudFJlc2l6ZUluc3RhbmNlcyk7XG4gICAgfTtcbiAgICBEYXlUaWxlLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBfc3VwZXIucHJvdG90eXBlLmRlc3Ryb3kuY2FsbCh0aGlzKTtcbiAgICAgICAgdGhpcy5yZW5kZXJGcmFtZS51bnJlbmRlcigpOyAvLyBzaG91bGQgdW5yZW5kZXIgZXZlcnl0aGluZyBlbHNlXG4gICAgICAgIHRoaXMuY29udGV4dC5jYWxlbmRhci51bnJlZ2lzdGVySW50ZXJhY3RpdmVDb21wb25lbnQodGhpcyk7XG4gICAgfTtcbiAgICBEYXlUaWxlLnByb3RvdHlwZS5fcmVuZGVyRnJhbWUgPSBmdW5jdGlvbiAoZGF0ZSkge1xuICAgICAgICB2YXIgX2EgPSB0aGlzLmNvbnRleHQsIHRoZW1lID0gX2EudGhlbWUsIGRhdGVFbnYgPSBfYS5kYXRlRW52LCBvcHRpb25zID0gX2Eub3B0aW9ucztcbiAgICAgICAgdmFyIHRpdGxlID0gZGF0ZUVudi5mb3JtYXQoZGF0ZSwgY3JlYXRlRm9ybWF0dGVyKG9wdGlvbnMuZGF5UG9wb3ZlckZvcm1hdCkgLy8gVE9ETzogY2FjaGVcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5lbC5pbm5lckhUTUwgPVxuICAgICAgICAgICAgJzxkaXYgY2xhc3M9XCJmYy1oZWFkZXIgJyArIHRoZW1lLmdldENsYXNzKCdwb3BvdmVySGVhZGVyJykgKyAnXCI+JyArXG4gICAgICAgICAgICAgICAgJzxzcGFuIGNsYXNzPVwiZmMtdGl0bGVcIj4nICtcbiAgICAgICAgICAgICAgICBodG1sRXNjYXBlKHRpdGxlKSArXG4gICAgICAgICAgICAgICAgJzwvc3Bhbj4nICtcbiAgICAgICAgICAgICAgICAnPHNwYW4gY2xhc3M9XCJmYy1jbG9zZSAnICsgdGhlbWUuZ2V0SWNvbkNsYXNzKCdjbG9zZScpICsgJ1wiPjwvc3Bhbj4nICtcbiAgICAgICAgICAgICAgICAnPC9kaXY+JyArXG4gICAgICAgICAgICAgICAgJzxkaXYgY2xhc3M9XCJmYy1ib2R5ICcgKyB0aGVtZS5nZXRDbGFzcygncG9wb3ZlckNvbnRlbnQnKSArICdcIj4nICtcbiAgICAgICAgICAgICAgICAnPGRpdiBjbGFzcz1cImZjLWV2ZW50LWNvbnRhaW5lclwiPjwvZGl2PicgK1xuICAgICAgICAgICAgICAgICc8L2Rpdj4nO1xuICAgICAgICB0aGlzLnNlZ0NvbnRhaW5lckVsID0gdGhpcy5lbC5xdWVyeVNlbGVjdG9yKCcuZmMtZXZlbnQtY29udGFpbmVyJyk7XG4gICAgfTtcbiAgICBEYXlUaWxlLnByb3RvdHlwZS5xdWVyeUhpdCA9IGZ1bmN0aW9uIChwb3NpdGlvbkxlZnQsIHBvc2l0aW9uVG9wLCBlbFdpZHRoLCBlbEhlaWdodCkge1xuICAgICAgICB2YXIgZGF0ZSA9IHRoaXMucHJvcHMuZGF0ZTsgLy8gSEFDS1xuICAgICAgICBpZiAocG9zaXRpb25MZWZ0IDwgZWxXaWR0aCAmJiBwb3NpdGlvblRvcCA8IGVsSGVpZ2h0KSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGNvbXBvbmVudDogdGhpcyxcbiAgICAgICAgICAgICAgICBkYXRlU3Bhbjoge1xuICAgICAgICAgICAgICAgICAgICBhbGxEYXk6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgIHJhbmdlOiB7IHN0YXJ0OiBkYXRlLCBlbmQ6IGFkZERheXMoZGF0ZSwgMSkgfVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZGF5RWw6IHRoaXMuZWwsXG4gICAgICAgICAgICAgICAgcmVjdDoge1xuICAgICAgICAgICAgICAgICAgICBsZWZ0OiAwLFxuICAgICAgICAgICAgICAgICAgICB0b3A6IDAsXG4gICAgICAgICAgICAgICAgICAgIHJpZ2h0OiBlbFdpZHRoLFxuICAgICAgICAgICAgICAgICAgICBib3R0b206IGVsSGVpZ2h0XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBsYXllcjogMVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgcmV0dXJuIERheVRpbGU7XG59KERhdGVDb21wb25lbnQpKTtcbnZhciBEYXlUaWxlRXZlbnRSZW5kZXJlciA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uIChfc3VwZXIpIHtcbiAgICBfX2V4dGVuZHMoRGF5VGlsZUV2ZW50UmVuZGVyZXIsIF9zdXBlcik7XG4gICAgZnVuY3Rpb24gRGF5VGlsZUV2ZW50UmVuZGVyZXIoZGF5VGlsZSkge1xuICAgICAgICB2YXIgX3RoaXMgPSBfc3VwZXIuY2FsbCh0aGlzKSB8fCB0aGlzO1xuICAgICAgICBfdGhpcy5kYXlUaWxlID0gZGF5VGlsZTtcbiAgICAgICAgcmV0dXJuIF90aGlzO1xuICAgIH1cbiAgICBEYXlUaWxlRXZlbnRSZW5kZXJlci5wcm90b3R5cGUuYXR0YWNoU2VncyA9IGZ1bmN0aW9uIChzZWdzKSB7XG4gICAgICAgIGZvciAodmFyIF9pID0gMCwgc2Vnc18xID0gc2VnczsgX2kgPCBzZWdzXzEubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICB2YXIgc2VnID0gc2Vnc18xW19pXTtcbiAgICAgICAgICAgIHRoaXMuZGF5VGlsZS5zZWdDb250YWluZXJFbC5hcHBlbmRDaGlsZChzZWcuZWwpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBEYXlUaWxlRXZlbnRSZW5kZXJlci5wcm90b3R5cGUuZGV0YWNoU2VncyA9IGZ1bmN0aW9uIChzZWdzKSB7XG4gICAgICAgIGZvciAodmFyIF9pID0gMCwgc2Vnc18yID0gc2VnczsgX2kgPCBzZWdzXzIubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICB2YXIgc2VnID0gc2Vnc18yW19pXTtcbiAgICAgICAgICAgIHJlbW92ZUVsZW1lbnQoc2VnLmVsKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgcmV0dXJuIERheVRpbGVFdmVudFJlbmRlcmVyO1xufShTaW1wbGVEYXlHcmlkRXZlbnRSZW5kZXJlcikpO1xuXG52YXIgRGF5QmdSb3cgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gRGF5QmdSb3coY29udGV4dCkge1xuICAgICAgICB0aGlzLmNvbnRleHQgPSBjb250ZXh0O1xuICAgIH1cbiAgICBEYXlCZ1Jvdy5wcm90b3R5cGUucmVuZGVySHRtbCA9IGZ1bmN0aW9uIChwcm9wcykge1xuICAgICAgICB2YXIgcGFydHMgPSBbXTtcbiAgICAgICAgaWYgKHByb3BzLnJlbmRlckludHJvSHRtbCkge1xuICAgICAgICAgICAgcGFydHMucHVzaChwcm9wcy5yZW5kZXJJbnRyb0h0bWwoKSk7XG4gICAgICAgIH1cbiAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBfYSA9IHByb3BzLmNlbGxzOyBfaSA8IF9hLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgdmFyIGNlbGwgPSBfYVtfaV07XG4gICAgICAgICAgICBwYXJ0cy5wdXNoKHJlbmRlckNlbGxIdG1sKGNlbGwuZGF0ZSwgcHJvcHMuZGF0ZVByb2ZpbGUsIHRoaXMuY29udGV4dCwgY2VsbC5odG1sQXR0cnMpKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXByb3BzLmNlbGxzLmxlbmd0aCkge1xuICAgICAgICAgICAgcGFydHMucHVzaCgnPHRkIGNsYXNzPVwiZmMtZGF5ICcgKyB0aGlzLmNvbnRleHQudGhlbWUuZ2V0Q2xhc3MoJ3dpZGdldENvbnRlbnQnKSArICdcIj48L3RkPicpO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLmNvbnRleHQub3B0aW9ucy5kaXIgPT09ICdydGwnKSB7XG4gICAgICAgICAgICBwYXJ0cy5yZXZlcnNlKCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICc8dHI+JyArIHBhcnRzLmpvaW4oJycpICsgJzwvdHI+JztcbiAgICB9O1xuICAgIHJldHVybiBEYXlCZ1Jvdztcbn0oKSk7XG5mdW5jdGlvbiByZW5kZXJDZWxsSHRtbChkYXRlLCBkYXRlUHJvZmlsZSwgY29udGV4dCwgb3RoZXJBdHRycykge1xuICAgIHZhciBkYXRlRW52ID0gY29udGV4dC5kYXRlRW52LCB0aGVtZSA9IGNvbnRleHQudGhlbWU7XG4gICAgdmFyIGlzRGF0ZVZhbGlkID0gcmFuZ2VDb250YWluc01hcmtlcihkYXRlUHJvZmlsZS5hY3RpdmVSYW5nZSwgZGF0ZSk7IC8vIFRPRE86IGNhbGxlZCB0b28gZnJlcXVlbnRseS4gY2FjaGUgc29tZWhvdy5cbiAgICB2YXIgY2xhc3NlcyA9IGdldERheUNsYXNzZXMoZGF0ZSwgZGF0ZVByb2ZpbGUsIGNvbnRleHQpO1xuICAgIGNsYXNzZXMudW5zaGlmdCgnZmMtZGF5JywgdGhlbWUuZ2V0Q2xhc3MoJ3dpZGdldENvbnRlbnQnKSk7XG4gICAgcmV0dXJuICc8dGQgY2xhc3M9XCInICsgY2xhc3Nlcy5qb2luKCcgJykgKyAnXCInICtcbiAgICAgICAgKGlzRGF0ZVZhbGlkID9cbiAgICAgICAgICAgICcgZGF0YS1kYXRlPVwiJyArIGRhdGVFbnYuZm9ybWF0SXNvKGRhdGUsIHsgb21pdFRpbWU6IHRydWUgfSkgKyAnXCInIDpcbiAgICAgICAgICAgICcnKSArXG4gICAgICAgIChvdGhlckF0dHJzID9cbiAgICAgICAgICAgICcgJyArIG90aGVyQXR0cnMgOlxuICAgICAgICAgICAgJycpICtcbiAgICAgICAgJz48L3RkPic7XG59XG5cbnZhciBEQVlfTlVNX0ZPUk1BVCA9IGNyZWF0ZUZvcm1hdHRlcih7IGRheTogJ251bWVyaWMnIH0pO1xudmFyIFdFRUtfTlVNX0ZPUk1BVCA9IGNyZWF0ZUZvcm1hdHRlcih7IHdlZWs6ICdudW1lcmljJyB9KTtcbnZhciBEYXlHcmlkID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKF9zdXBlcikge1xuICAgIF9fZXh0ZW5kcyhEYXlHcmlkLCBfc3VwZXIpO1xuICAgIGZ1bmN0aW9uIERheUdyaWQoZWwsIHJlbmRlclByb3BzKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IF9zdXBlci5jYWxsKHRoaXMsIGVsKSB8fCB0aGlzO1xuICAgICAgICBfdGhpcy5ib3R0b21Db29yZFBhZGRpbmcgPSAwOyAvLyBoYWNrIGZvciBleHRlbmRpbmcgdGhlIGhpdCBhcmVhIGZvciB0aGUgbGFzdCByb3cgb2YgdGhlIGNvb3JkaW5hdGUgZ3JpZFxuICAgICAgICBfdGhpcy5pc0NlbGxTaXplc0RpcnR5ID0gZmFsc2U7XG4gICAgICAgIF90aGlzLnJlbmRlclByb3BzID0gcmVuZGVyUHJvcHM7XG4gICAgICAgIHZhciBldmVudFJlbmRlcmVyID0gX3RoaXMuZXZlbnRSZW5kZXJlciA9IG5ldyBEYXlHcmlkRXZlbnRSZW5kZXJlcihfdGhpcyk7XG4gICAgICAgIHZhciBmaWxsUmVuZGVyZXIgPSBfdGhpcy5maWxsUmVuZGVyZXIgPSBuZXcgRGF5R3JpZEZpbGxSZW5kZXJlcihfdGhpcyk7XG4gICAgICAgIF90aGlzLm1pcnJvclJlbmRlcmVyID0gbmV3IERheUdyaWRNaXJyb3JSZW5kZXJlcihfdGhpcyk7XG4gICAgICAgIHZhciByZW5kZXJDZWxscyA9IF90aGlzLnJlbmRlckNlbGxzID0gbWVtb2l6ZVJlbmRlcmluZyhfdGhpcy5fcmVuZGVyQ2VsbHMsIF90aGlzLl91bnJlbmRlckNlbGxzKTtcbiAgICAgICAgX3RoaXMucmVuZGVyQnVzaW5lc3NIb3VycyA9IG1lbW9pemVSZW5kZXJpbmcoZmlsbFJlbmRlcmVyLnJlbmRlclNlZ3MuYmluZChmaWxsUmVuZGVyZXIsICdidXNpbmVzc0hvdXJzJyksIGZpbGxSZW5kZXJlci51bnJlbmRlci5iaW5kKGZpbGxSZW5kZXJlciwgJ2J1c2luZXNzSG91cnMnKSwgW3JlbmRlckNlbGxzXSk7XG4gICAgICAgIF90aGlzLnJlbmRlckRhdGVTZWxlY3Rpb24gPSBtZW1vaXplUmVuZGVyaW5nKGZpbGxSZW5kZXJlci5yZW5kZXJTZWdzLmJpbmQoZmlsbFJlbmRlcmVyLCAnaGlnaGxpZ2h0JyksIGZpbGxSZW5kZXJlci51bnJlbmRlci5iaW5kKGZpbGxSZW5kZXJlciwgJ2hpZ2hsaWdodCcpLCBbcmVuZGVyQ2VsbHNdKTtcbiAgICAgICAgX3RoaXMucmVuZGVyQmdFdmVudHMgPSBtZW1vaXplUmVuZGVyaW5nKGZpbGxSZW5kZXJlci5yZW5kZXJTZWdzLmJpbmQoZmlsbFJlbmRlcmVyLCAnYmdFdmVudCcpLCBmaWxsUmVuZGVyZXIudW5yZW5kZXIuYmluZChmaWxsUmVuZGVyZXIsICdiZ0V2ZW50JyksIFtyZW5kZXJDZWxsc10pO1xuICAgICAgICBfdGhpcy5yZW5kZXJGZ0V2ZW50cyA9IG1lbW9pemVSZW5kZXJpbmcoZXZlbnRSZW5kZXJlci5yZW5kZXJTZWdzLmJpbmQoZXZlbnRSZW5kZXJlciksIGV2ZW50UmVuZGVyZXIudW5yZW5kZXIuYmluZChldmVudFJlbmRlcmVyKSwgW3JlbmRlckNlbGxzXSk7XG4gICAgICAgIF90aGlzLnJlbmRlckV2ZW50U2VsZWN0aW9uID0gbWVtb2l6ZVJlbmRlcmluZyhldmVudFJlbmRlcmVyLnNlbGVjdEJ5SW5zdGFuY2VJZC5iaW5kKGV2ZW50UmVuZGVyZXIpLCBldmVudFJlbmRlcmVyLnVuc2VsZWN0QnlJbnN0YW5jZUlkLmJpbmQoZXZlbnRSZW5kZXJlciksIFtfdGhpcy5yZW5kZXJGZ0V2ZW50c10pO1xuICAgICAgICBfdGhpcy5yZW5kZXJFdmVudERyYWcgPSBtZW1vaXplUmVuZGVyaW5nKF90aGlzLl9yZW5kZXJFdmVudERyYWcsIF90aGlzLl91bnJlbmRlckV2ZW50RHJhZywgW3JlbmRlckNlbGxzXSk7XG4gICAgICAgIF90aGlzLnJlbmRlckV2ZW50UmVzaXplID0gbWVtb2l6ZVJlbmRlcmluZyhfdGhpcy5fcmVuZGVyRXZlbnRSZXNpemUsIF90aGlzLl91bnJlbmRlckV2ZW50UmVzaXplLCBbcmVuZGVyQ2VsbHNdKTtcbiAgICAgICAgcmV0dXJuIF90aGlzO1xuICAgIH1cbiAgICBEYXlHcmlkLnByb3RvdHlwZS5yZW5kZXIgPSBmdW5jdGlvbiAocHJvcHMsIGNvbnRleHQpIHtcbiAgICAgICAgdmFyIGNlbGxzID0gcHJvcHMuY2VsbHM7XG4gICAgICAgIHRoaXMucm93Q250ID0gY2VsbHMubGVuZ3RoO1xuICAgICAgICB0aGlzLmNvbENudCA9IGNlbGxzWzBdLmxlbmd0aDtcbiAgICAgICAgdGhpcy5yZW5kZXJDZWxscyhjZWxscywgcHJvcHMuaXNSaWdpZCk7XG4gICAgICAgIHRoaXMucmVuZGVyQnVzaW5lc3NIb3Vycyhjb250ZXh0LCBwcm9wcy5idXNpbmVzc0hvdXJTZWdzKTtcbiAgICAgICAgdGhpcy5yZW5kZXJEYXRlU2VsZWN0aW9uKGNvbnRleHQsIHByb3BzLmRhdGVTZWxlY3Rpb25TZWdzKTtcbiAgICAgICAgdGhpcy5yZW5kZXJCZ0V2ZW50cyhjb250ZXh0LCBwcm9wcy5iZ0V2ZW50U2Vncyk7XG4gICAgICAgIHRoaXMucmVuZGVyRmdFdmVudHMoY29udGV4dCwgcHJvcHMuZmdFdmVudFNlZ3MpO1xuICAgICAgICB0aGlzLnJlbmRlckV2ZW50U2VsZWN0aW9uKHByb3BzLmV2ZW50U2VsZWN0aW9uKTtcbiAgICAgICAgdGhpcy5yZW5kZXJFdmVudERyYWcocHJvcHMuZXZlbnREcmFnKTtcbiAgICAgICAgdGhpcy5yZW5kZXJFdmVudFJlc2l6ZShwcm9wcy5ldmVudFJlc2l6ZSk7XG4gICAgICAgIGlmICh0aGlzLnNlZ1BvcG92ZXJUaWxlKSB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVNlZ1BvcG92ZXJUaWxlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIERheUdyaWQucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIF9zdXBlci5wcm90b3R5cGUuZGVzdHJveS5jYWxsKHRoaXMpO1xuICAgICAgICB0aGlzLnJlbmRlckNlbGxzLnVucmVuZGVyKCk7IC8vIHdpbGwgdW5yZW5kZXIgZXZlcnl0aGluZyBlbHNlXG4gICAgfTtcbiAgICBEYXlHcmlkLnByb3RvdHlwZS5nZXRDZWxsUmFuZ2UgPSBmdW5jdGlvbiAocm93LCBjb2wpIHtcbiAgICAgICAgdmFyIHN0YXJ0ID0gdGhpcy5wcm9wcy5jZWxsc1tyb3ddW2NvbF0uZGF0ZTtcbiAgICAgICAgdmFyIGVuZCA9IGFkZERheXMoc3RhcnQsIDEpO1xuICAgICAgICByZXR1cm4geyBzdGFydDogc3RhcnQsIGVuZDogZW5kIH07XG4gICAgfTtcbiAgICBEYXlHcmlkLnByb3RvdHlwZS51cGRhdGVTZWdQb3BvdmVyVGlsZSA9IGZ1bmN0aW9uIChkYXRlLCBzZWdzKSB7XG4gICAgICAgIHZhciBvd25Qcm9wcyA9IHRoaXMucHJvcHM7XG4gICAgICAgIHRoaXMuc2VnUG9wb3ZlclRpbGUucmVjZWl2ZVByb3BzKHtcbiAgICAgICAgICAgIGRhdGU6IGRhdGUgfHwgdGhpcy5zZWdQb3BvdmVyVGlsZS5wcm9wcy5kYXRlLFxuICAgICAgICAgICAgZmdTZWdzOiBzZWdzIHx8IHRoaXMuc2VnUG9wb3ZlclRpbGUucHJvcHMuZmdTZWdzLFxuICAgICAgICAgICAgZXZlbnRTZWxlY3Rpb246IG93blByb3BzLmV2ZW50U2VsZWN0aW9uLFxuICAgICAgICAgICAgZXZlbnREcmFnSW5zdGFuY2VzOiBvd25Qcm9wcy5ldmVudERyYWcgPyBvd25Qcm9wcy5ldmVudERyYWcuYWZmZWN0ZWRJbnN0YW5jZXMgOiBudWxsLFxuICAgICAgICAgICAgZXZlbnRSZXNpemVJbnN0YW5jZXM6IG93blByb3BzLmV2ZW50UmVzaXplID8gb3duUHJvcHMuZXZlbnRSZXNpemUuYWZmZWN0ZWRJbnN0YW5jZXMgOiBudWxsXG4gICAgICAgIH0sIHRoaXMuY29udGV4dCk7XG4gICAgfTtcbiAgICAvKiBEYXRlIFJlbmRlcmluZ1xuICAgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG4gICAgRGF5R3JpZC5wcm90b3R5cGUuX3JlbmRlckNlbGxzID0gZnVuY3Rpb24gKGNlbGxzLCBpc1JpZ2lkKSB7XG4gICAgICAgIHZhciBfYSA9IHRoaXMuY29udGV4dCwgY2FsZW5kYXIgPSBfYS5jYWxlbmRhciwgdmlldyA9IF9hLnZpZXcsIGlzUnRsID0gX2EuaXNSdGwsIGRhdGVFbnYgPSBfYS5kYXRlRW52O1xuICAgICAgICB2YXIgX2IgPSB0aGlzLCByb3dDbnQgPSBfYi5yb3dDbnQsIGNvbENudCA9IF9iLmNvbENudDtcbiAgICAgICAgdmFyIGh0bWwgPSAnJztcbiAgICAgICAgdmFyIHJvdztcbiAgICAgICAgdmFyIGNvbDtcbiAgICAgICAgZm9yIChyb3cgPSAwOyByb3cgPCByb3dDbnQ7IHJvdysrKSB7XG4gICAgICAgICAgICBodG1sICs9IHRoaXMucmVuZGVyRGF5Um93SHRtbChyb3csIGlzUmlnaWQpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuZWwuaW5uZXJIVE1MID0gaHRtbDtcbiAgICAgICAgdGhpcy5yb3dFbHMgPSBmaW5kRWxlbWVudHModGhpcy5lbCwgJy5mYy1yb3cnKTtcbiAgICAgICAgdGhpcy5jZWxsRWxzID0gZmluZEVsZW1lbnRzKHRoaXMuZWwsICcuZmMtZGF5LCAuZmMtZGlzYWJsZWQtZGF5Jyk7XG4gICAgICAgIGlmIChpc1J0bCkge1xuICAgICAgICAgICAgdGhpcy5jZWxsRWxzLnJldmVyc2UoKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnJvd1Bvc2l0aW9ucyA9IG5ldyBQb3NpdGlvbkNhY2hlKHRoaXMuZWwsIHRoaXMucm93RWxzLCBmYWxzZSwgdHJ1ZSAvLyB2ZXJ0aWNhbFxuICAgICAgICApO1xuICAgICAgICB0aGlzLmNvbFBvc2l0aW9ucyA9IG5ldyBQb3NpdGlvbkNhY2hlKHRoaXMuZWwsIHRoaXMuY2VsbEVscy5zbGljZSgwLCBjb2xDbnQpLCAvLyBvbmx5IHRoZSBmaXJzdCByb3dcbiAgICAgICAgdHJ1ZSwgZmFsc2UgLy8gaG9yaXpvbnRhbFxuICAgICAgICApO1xuICAgICAgICAvLyB0cmlnZ2VyIGRheVJlbmRlciB3aXRoIGVhY2ggY2VsbCdzIGVsZW1lbnRcbiAgICAgICAgZm9yIChyb3cgPSAwOyByb3cgPCByb3dDbnQ7IHJvdysrKSB7XG4gICAgICAgICAgICBmb3IgKGNvbCA9IDA7IGNvbCA8IGNvbENudDsgY29sKyspIHtcbiAgICAgICAgICAgICAgICBjYWxlbmRhci5wdWJsaWNseVRyaWdnZXIoJ2RheVJlbmRlcicsIFtcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGF0ZTogZGF0ZUVudi50b0RhdGUoY2VsbHNbcm93XVtjb2xdLmRhdGUpLFxuICAgICAgICAgICAgICAgICAgICAgICAgZWw6IHRoaXMuZ2V0Q2VsbEVsKHJvdywgY29sKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZpZXc6IHZpZXdcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRoaXMuaXNDZWxsU2l6ZXNEaXJ0eSA9IHRydWU7XG4gICAgfTtcbiAgICBEYXlHcmlkLnByb3RvdHlwZS5fdW5yZW5kZXJDZWxscyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVTZWdQb3BvdmVyKCk7XG4gICAgfTtcbiAgICAvLyBHZW5lcmF0ZXMgdGhlIEhUTUwgZm9yIGEgc2luZ2xlIHJvdywgd2hpY2ggaXMgYSBkaXYgdGhhdCB3cmFwcyBhIHRhYmxlLlxuICAgIC8vIGByb3dgIGlzIHRoZSByb3cgbnVtYmVyLlxuICAgIERheUdyaWQucHJvdG90eXBlLnJlbmRlckRheVJvd0h0bWwgPSBmdW5jdGlvbiAocm93LCBpc1JpZ2lkKSB7XG4gICAgICAgIHZhciB0aGVtZSA9IHRoaXMuY29udGV4dC50aGVtZTtcbiAgICAgICAgdmFyIGNsYXNzZXMgPSBbJ2ZjLXJvdycsICdmYy13ZWVrJywgdGhlbWUuZ2V0Q2xhc3MoJ2RheVJvdycpXTtcbiAgICAgICAgaWYgKGlzUmlnaWQpIHtcbiAgICAgICAgICAgIGNsYXNzZXMucHVzaCgnZmMtcmlnaWQnKTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgYmdSb3cgPSBuZXcgRGF5QmdSb3codGhpcy5jb250ZXh0KTtcbiAgICAgICAgcmV0dXJuICcnICtcbiAgICAgICAgICAgICc8ZGl2IGNsYXNzPVwiJyArIGNsYXNzZXMuam9pbignICcpICsgJ1wiPicgK1xuICAgICAgICAgICAgJzxkaXYgY2xhc3M9XCJmYy1iZ1wiPicgK1xuICAgICAgICAgICAgJzx0YWJsZSBjbGFzcz1cIicgKyB0aGVtZS5nZXRDbGFzcygndGFibGVHcmlkJykgKyAnXCI+JyArXG4gICAgICAgICAgICBiZ1Jvdy5yZW5kZXJIdG1sKHtcbiAgICAgICAgICAgICAgICBjZWxsczogdGhpcy5wcm9wcy5jZWxsc1tyb3ddLFxuICAgICAgICAgICAgICAgIGRhdGVQcm9maWxlOiB0aGlzLnByb3BzLmRhdGVQcm9maWxlLFxuICAgICAgICAgICAgICAgIHJlbmRlckludHJvSHRtbDogdGhpcy5yZW5kZXJQcm9wcy5yZW5kZXJCZ0ludHJvSHRtbFxuICAgICAgICAgICAgfSkgK1xuICAgICAgICAgICAgJzwvdGFibGU+JyArXG4gICAgICAgICAgICAnPC9kaXY+JyArXG4gICAgICAgICAgICAnPGRpdiBjbGFzcz1cImZjLWNvbnRlbnQtc2tlbGV0b25cIj4nICtcbiAgICAgICAgICAgICc8dGFibGU+JyArXG4gICAgICAgICAgICAodGhpcy5nZXRJc051bWJlcnNWaXNpYmxlKCkgP1xuICAgICAgICAgICAgICAgICc8dGhlYWQ+JyArXG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVuZGVyTnVtYmVyVHJIdG1sKHJvdykgK1xuICAgICAgICAgICAgICAgICAgICAnPC90aGVhZD4nIDpcbiAgICAgICAgICAgICAgICAnJykgK1xuICAgICAgICAgICAgJzwvdGFibGU+JyArXG4gICAgICAgICAgICAnPC9kaXY+JyArXG4gICAgICAgICAgICAnPC9kaXY+JztcbiAgICB9O1xuICAgIERheUdyaWQucHJvdG90eXBlLmdldElzTnVtYmVyc1Zpc2libGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldElzRGF5TnVtYmVyc1Zpc2libGUoKSB8fFxuICAgICAgICAgICAgdGhpcy5yZW5kZXJQcm9wcy5jZWxsV2Vla051bWJlcnNWaXNpYmxlIHx8XG4gICAgICAgICAgICB0aGlzLnJlbmRlclByb3BzLmNvbFdlZWtOdW1iZXJzVmlzaWJsZTtcbiAgICB9O1xuICAgIERheUdyaWQucHJvdG90eXBlLmdldElzRGF5TnVtYmVyc1Zpc2libGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJvd0NudCA+IDE7XG4gICAgfTtcbiAgICAvKiBHcmlkIE51bWJlciBSZW5kZXJpbmdcbiAgICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuICAgIERheUdyaWQucHJvdG90eXBlLnJlbmRlck51bWJlclRySHRtbCA9IGZ1bmN0aW9uIChyb3cpIHtcbiAgICAgICAgdmFyIGlzUnRsID0gdGhpcy5jb250ZXh0LmlzUnRsO1xuICAgICAgICB2YXIgaW50cm8gPSB0aGlzLnJlbmRlclByb3BzLnJlbmRlck51bWJlckludHJvSHRtbChyb3csIHRoaXMpO1xuICAgICAgICByZXR1cm4gJycgK1xuICAgICAgICAgICAgJzx0cj4nICtcbiAgICAgICAgICAgIChpc1J0bCA/ICcnIDogaW50cm8pICtcbiAgICAgICAgICAgIHRoaXMucmVuZGVyTnVtYmVyQ2VsbHNIdG1sKHJvdykgK1xuICAgICAgICAgICAgKGlzUnRsID8gaW50cm8gOiAnJykgK1xuICAgICAgICAgICAgJzwvdHI+JztcbiAgICB9O1xuICAgIERheUdyaWQucHJvdG90eXBlLnJlbmRlck51bWJlckNlbGxzSHRtbCA9IGZ1bmN0aW9uIChyb3cpIHtcbiAgICAgICAgdmFyIGh0bWxzID0gW107XG4gICAgICAgIHZhciBjb2w7XG4gICAgICAgIHZhciBkYXRlO1xuICAgICAgICBmb3IgKGNvbCA9IDA7IGNvbCA8IHRoaXMuY29sQ250OyBjb2wrKykge1xuICAgICAgICAgICAgZGF0ZSA9IHRoaXMucHJvcHMuY2VsbHNbcm93XVtjb2xdLmRhdGU7XG4gICAgICAgICAgICBodG1scy5wdXNoKHRoaXMucmVuZGVyTnVtYmVyQ2VsbEh0bWwoZGF0ZSkpO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLmNvbnRleHQuaXNSdGwpIHtcbiAgICAgICAgICAgIGh0bWxzLnJldmVyc2UoKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gaHRtbHMuam9pbignJyk7XG4gICAgfTtcbiAgICAvLyBHZW5lcmF0ZXMgdGhlIEhUTUwgZm9yIHRoZSA8dGQ+cyBvZiB0aGUgXCJudW1iZXJcIiByb3cgaW4gdGhlIERheUdyaWQncyBjb250ZW50IHNrZWxldG9uLlxuICAgIC8vIFRoZSBudW1iZXIgcm93IHdpbGwgb25seSBleGlzdCBpZiBlaXRoZXIgZGF5IG51bWJlcnMgb3Igd2VlayBudW1iZXJzIGFyZSB0dXJuZWQgb24uXG4gICAgRGF5R3JpZC5wcm90b3R5cGUucmVuZGVyTnVtYmVyQ2VsbEh0bWwgPSBmdW5jdGlvbiAoZGF0ZSkge1xuICAgICAgICB2YXIgX2EgPSB0aGlzLmNvbnRleHQsIGRhdGVFbnYgPSBfYS5kYXRlRW52LCBvcHRpb25zID0gX2Eub3B0aW9ucztcbiAgICAgICAgdmFyIGh0bWwgPSAnJztcbiAgICAgICAgdmFyIGlzRGF0ZVZhbGlkID0gcmFuZ2VDb250YWluc01hcmtlcih0aGlzLnByb3BzLmRhdGVQcm9maWxlLmFjdGl2ZVJhbmdlLCBkYXRlKTsgLy8gVE9ETzogY2FsbGVkIHRvbyBmcmVxdWVudGx5LiBjYWNoZSBzb21laG93LlxuICAgICAgICB2YXIgaXNEYXlOdW1iZXJWaXNpYmxlID0gdGhpcy5nZXRJc0RheU51bWJlcnNWaXNpYmxlKCkgJiYgaXNEYXRlVmFsaWQ7XG4gICAgICAgIHZhciBjbGFzc2VzO1xuICAgICAgICB2YXIgd2Vla0NhbGNGaXJzdERvdztcbiAgICAgICAgaWYgKCFpc0RheU51bWJlclZpc2libGUgJiYgIXRoaXMucmVuZGVyUHJvcHMuY2VsbFdlZWtOdW1iZXJzVmlzaWJsZSkge1xuICAgICAgICAgICAgLy8gbm8gbnVtYmVycyBpbiBkYXkgY2VsbCAod2VlayBudW1iZXIgbXVzdCBiZSBhbG9uZyB0aGUgc2lkZSlcbiAgICAgICAgICAgIHJldHVybiAnPHRkPjwvdGQ+JzsgLy8gIHdpbGwgY3JlYXRlIGFuIGVtcHR5IHNwYWNlIGFib3ZlIGV2ZW50cyA6KFxuICAgICAgICB9XG4gICAgICAgIGNsYXNzZXMgPSBnZXREYXlDbGFzc2VzKGRhdGUsIHRoaXMucHJvcHMuZGF0ZVByb2ZpbGUsIHRoaXMuY29udGV4dCk7XG4gICAgICAgIGNsYXNzZXMudW5zaGlmdCgnZmMtZGF5LXRvcCcpO1xuICAgICAgICBpZiAodGhpcy5yZW5kZXJQcm9wcy5jZWxsV2Vla051bWJlcnNWaXNpYmxlKSB7XG4gICAgICAgICAgICB3ZWVrQ2FsY0ZpcnN0RG93ID0gZGF0ZUVudi53ZWVrRG93O1xuICAgICAgICB9XG4gICAgICAgIGh0bWwgKz0gJzx0ZCBjbGFzcz1cIicgKyBjbGFzc2VzLmpvaW4oJyAnKSArICdcIicgK1xuICAgICAgICAgICAgKGlzRGF0ZVZhbGlkID9cbiAgICAgICAgICAgICAgICAnIGRhdGEtZGF0ZT1cIicgKyBkYXRlRW52LmZvcm1hdElzbyhkYXRlLCB7IG9taXRUaW1lOiB0cnVlIH0pICsgJ1wiJyA6XG4gICAgICAgICAgICAgICAgJycpICtcbiAgICAgICAgICAgICc+JztcbiAgICAgICAgaWYgKHRoaXMucmVuZGVyUHJvcHMuY2VsbFdlZWtOdW1iZXJzVmlzaWJsZSAmJiAoZGF0ZS5nZXRVVENEYXkoKSA9PT0gd2Vla0NhbGNGaXJzdERvdykpIHtcbiAgICAgICAgICAgIGh0bWwgKz0gYnVpbGRHb3RvQW5jaG9ySHRtbChvcHRpb25zLCBkYXRlRW52LCB7IGRhdGU6IGRhdGUsIHR5cGU6ICd3ZWVrJyB9LCB7ICdjbGFzcyc6ICdmYy13ZWVrLW51bWJlcicgfSwgZGF0ZUVudi5mb3JtYXQoZGF0ZSwgV0VFS19OVU1fRk9STUFUKSAvLyBpbm5lciBIVE1MXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGlmIChpc0RheU51bWJlclZpc2libGUpIHtcbiAgICAgICAgICAgIGh0bWwgKz0gYnVpbGRHb3RvQW5jaG9ySHRtbChvcHRpb25zLCBkYXRlRW52LCBkYXRlLCB7ICdjbGFzcyc6ICdmYy1kYXktbnVtYmVyJyB9LCBkYXRlRW52LmZvcm1hdChkYXRlLCBEQVlfTlVNX0ZPUk1BVCkgLy8gaW5uZXIgSFRNTFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBodG1sICs9ICc8L3RkPic7XG4gICAgICAgIHJldHVybiBodG1sO1xuICAgIH07XG4gICAgLyogU2l6aW5nXG4gICAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbiAgICBEYXlHcmlkLnByb3RvdHlwZS51cGRhdGVTaXplID0gZnVuY3Rpb24gKGlzUmVzaXplKSB7XG4gICAgICAgIHZhciBjYWxlbmRhciA9IHRoaXMuY29udGV4dC5jYWxlbmRhcjtcbiAgICAgICAgdmFyIF9hID0gdGhpcywgZmlsbFJlbmRlcmVyID0gX2EuZmlsbFJlbmRlcmVyLCBldmVudFJlbmRlcmVyID0gX2EuZXZlbnRSZW5kZXJlciwgbWlycm9yUmVuZGVyZXIgPSBfYS5taXJyb3JSZW5kZXJlcjtcbiAgICAgICAgaWYgKGlzUmVzaXplIHx8XG4gICAgICAgICAgICB0aGlzLmlzQ2VsbFNpemVzRGlydHkgfHxcbiAgICAgICAgICAgIGNhbGVuZGFyLmlzRXZlbnRzVXBkYXRlZCAvLyBoYWNrXG4gICAgICAgICkge1xuICAgICAgICAgICAgdGhpcy5idWlsZFBvc2l0aW9uQ2FjaGVzKCk7XG4gICAgICAgICAgICB0aGlzLmlzQ2VsbFNpemVzRGlydHkgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBmaWxsUmVuZGVyZXIuY29tcHV0ZVNpemVzKGlzUmVzaXplKTtcbiAgICAgICAgZXZlbnRSZW5kZXJlci5jb21wdXRlU2l6ZXMoaXNSZXNpemUpO1xuICAgICAgICBtaXJyb3JSZW5kZXJlci5jb21wdXRlU2l6ZXMoaXNSZXNpemUpO1xuICAgICAgICBmaWxsUmVuZGVyZXIuYXNzaWduU2l6ZXMoaXNSZXNpemUpO1xuICAgICAgICBldmVudFJlbmRlcmVyLmFzc2lnblNpemVzKGlzUmVzaXplKTtcbiAgICAgICAgbWlycm9yUmVuZGVyZXIuYXNzaWduU2l6ZXMoaXNSZXNpemUpO1xuICAgIH07XG4gICAgRGF5R3JpZC5wcm90b3R5cGUuYnVpbGRQb3NpdGlvbkNhY2hlcyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5idWlsZENvbFBvc2l0aW9ucygpO1xuICAgICAgICB0aGlzLmJ1aWxkUm93UG9zaXRpb25zKCk7XG4gICAgfTtcbiAgICBEYXlHcmlkLnByb3RvdHlwZS5idWlsZENvbFBvc2l0aW9ucyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5jb2xQb3NpdGlvbnMuYnVpbGQoKTtcbiAgICB9O1xuICAgIERheUdyaWQucHJvdG90eXBlLmJ1aWxkUm93UG9zaXRpb25zID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnJvd1Bvc2l0aW9ucy5idWlsZCgpO1xuICAgICAgICB0aGlzLnJvd1Bvc2l0aW9ucy5ib3R0b21zW3RoaXMucm93Q250IC0gMV0gKz0gdGhpcy5ib3R0b21Db29yZFBhZGRpbmc7IC8vIGhhY2tcbiAgICB9O1xuICAgIC8qIEhpdCBTeXN0ZW1cbiAgICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuICAgIERheUdyaWQucHJvdG90eXBlLnBvc2l0aW9uVG9IaXQgPSBmdW5jdGlvbiAobGVmdFBvc2l0aW9uLCB0b3BQb3NpdGlvbikge1xuICAgICAgICB2YXIgX2EgPSB0aGlzLCBjb2xQb3NpdGlvbnMgPSBfYS5jb2xQb3NpdGlvbnMsIHJvd1Bvc2l0aW9ucyA9IF9hLnJvd1Bvc2l0aW9ucztcbiAgICAgICAgdmFyIGNvbCA9IGNvbFBvc2l0aW9ucy5sZWZ0VG9JbmRleChsZWZ0UG9zaXRpb24pO1xuICAgICAgICB2YXIgcm93ID0gcm93UG9zaXRpb25zLnRvcFRvSW5kZXgodG9wUG9zaXRpb24pO1xuICAgICAgICBpZiAocm93ICE9IG51bGwgJiYgY29sICE9IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgcm93OiByb3csXG4gICAgICAgICAgICAgICAgY29sOiBjb2wsXG4gICAgICAgICAgICAgICAgZGF0ZVNwYW46IHtcbiAgICAgICAgICAgICAgICAgICAgcmFuZ2U6IHRoaXMuZ2V0Q2VsbFJhbmdlKHJvdywgY29sKSxcbiAgICAgICAgICAgICAgICAgICAgYWxsRGF5OiB0cnVlXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBkYXlFbDogdGhpcy5nZXRDZWxsRWwocm93LCBjb2wpLFxuICAgICAgICAgICAgICAgIHJlbGF0aXZlUmVjdDoge1xuICAgICAgICAgICAgICAgICAgICBsZWZ0OiBjb2xQb3NpdGlvbnMubGVmdHNbY29sXSxcbiAgICAgICAgICAgICAgICAgICAgcmlnaHQ6IGNvbFBvc2l0aW9ucy5yaWdodHNbY29sXSxcbiAgICAgICAgICAgICAgICAgICAgdG9wOiByb3dQb3NpdGlvbnMudG9wc1tyb3ddLFxuICAgICAgICAgICAgICAgICAgICBib3R0b206IHJvd1Bvc2l0aW9ucy5ib3R0b21zW3Jvd11cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvKiBDZWxsIFN5c3RlbVxuICAgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG4gICAgLy8gRllJOiB0aGUgZmlyc3QgY29sdW1uIGlzIHRoZSBsZWZ0bW9zdCBjb2x1bW4sIHJlZ2FyZGxlc3Mgb2YgZGF0ZVxuICAgIERheUdyaWQucHJvdG90eXBlLmdldENlbGxFbCA9IGZ1bmN0aW9uIChyb3csIGNvbCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jZWxsRWxzW3JvdyAqIHRoaXMuY29sQ250ICsgY29sXTtcbiAgICB9O1xuICAgIC8qIEV2ZW50IERyYWcgVmlzdWFsaXphdGlvblxuICAgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG4gICAgRGF5R3JpZC5wcm90b3R5cGUuX3JlbmRlckV2ZW50RHJhZyA9IGZ1bmN0aW9uIChzdGF0ZSkge1xuICAgICAgICBpZiAoc3RhdGUpIHtcbiAgICAgICAgICAgIHRoaXMuZXZlbnRSZW5kZXJlci5oaWRlQnlIYXNoKHN0YXRlLmFmZmVjdGVkSW5zdGFuY2VzKTtcbiAgICAgICAgICAgIHRoaXMuZmlsbFJlbmRlcmVyLnJlbmRlclNlZ3MoJ2hpZ2hsaWdodCcsIHRoaXMuY29udGV4dCwgc3RhdGUuc2Vncyk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIERheUdyaWQucHJvdG90eXBlLl91bnJlbmRlckV2ZW50RHJhZyA9IGZ1bmN0aW9uIChzdGF0ZSkge1xuICAgICAgICBpZiAoc3RhdGUpIHtcbiAgICAgICAgICAgIHRoaXMuZXZlbnRSZW5kZXJlci5zaG93QnlIYXNoKHN0YXRlLmFmZmVjdGVkSW5zdGFuY2VzKTtcbiAgICAgICAgICAgIHRoaXMuZmlsbFJlbmRlcmVyLnVucmVuZGVyKCdoaWdobGlnaHQnLCB0aGlzLmNvbnRleHQpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvKiBFdmVudCBSZXNpemUgVmlzdWFsaXphdGlvblxuICAgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG4gICAgRGF5R3JpZC5wcm90b3R5cGUuX3JlbmRlckV2ZW50UmVzaXplID0gZnVuY3Rpb24gKHN0YXRlKSB7XG4gICAgICAgIGlmIChzdGF0ZSkge1xuICAgICAgICAgICAgdGhpcy5ldmVudFJlbmRlcmVyLmhpZGVCeUhhc2goc3RhdGUuYWZmZWN0ZWRJbnN0YW5jZXMpO1xuICAgICAgICAgICAgdGhpcy5maWxsUmVuZGVyZXIucmVuZGVyU2VncygnaGlnaGxpZ2h0JywgdGhpcy5jb250ZXh0LCBzdGF0ZS5zZWdzKTtcbiAgICAgICAgICAgIHRoaXMubWlycm9yUmVuZGVyZXIucmVuZGVyU2Vncyh0aGlzLmNvbnRleHQsIHN0YXRlLnNlZ3MsIHsgaXNSZXNpemluZzogdHJ1ZSwgc291cmNlU2VnOiBzdGF0ZS5zb3VyY2VTZWcgfSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIERheUdyaWQucHJvdG90eXBlLl91bnJlbmRlckV2ZW50UmVzaXplID0gZnVuY3Rpb24gKHN0YXRlKSB7XG4gICAgICAgIGlmIChzdGF0ZSkge1xuICAgICAgICAgICAgdGhpcy5ldmVudFJlbmRlcmVyLnNob3dCeUhhc2goc3RhdGUuYWZmZWN0ZWRJbnN0YW5jZXMpO1xuICAgICAgICAgICAgdGhpcy5maWxsUmVuZGVyZXIudW5yZW5kZXIoJ2hpZ2hsaWdodCcsIHRoaXMuY29udGV4dCk7XG4gICAgICAgICAgICB0aGlzLm1pcnJvclJlbmRlcmVyLnVucmVuZGVyKHRoaXMuY29udGV4dCwgc3RhdGUuc2VncywgeyBpc1Jlc2l6aW5nOiB0cnVlLCBzb3VyY2VTZWc6IHN0YXRlLnNvdXJjZVNlZyB9KTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLyogTW9yZSsgTGluayBQb3BvdmVyXG4gICAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbiAgICBEYXlHcmlkLnByb3RvdHlwZS5yZW1vdmVTZWdQb3BvdmVyID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGhpcy5zZWdQb3BvdmVyKSB7XG4gICAgICAgICAgICB0aGlzLnNlZ1BvcG92ZXIuaGlkZSgpOyAvLyBpbiBoYW5kbGVyLCB3aWxsIGNhbGwgc2VnUG9wb3ZlcidzIHJlbW92ZUVsZW1lbnRcbiAgICAgICAgfVxuICAgIH07XG4gICAgLy8gTGltaXRzIHRoZSBudW1iZXIgb2YgXCJsZXZlbHNcIiAodmVydGljYWxseSBzdGFja2luZyBsYXllcnMgb2YgZXZlbnRzKSBmb3IgZWFjaCByb3cgb2YgdGhlIGdyaWQuXG4gICAgLy8gYGxldmVsTGltaXRgIGNhbiBiZSBmYWxzZSAoZG9uJ3QgbGltaXQpLCBhIG51bWJlciwgb3IgdHJ1ZSAoc2hvdWxkIGJlIGNvbXB1dGVkKS5cbiAgICBEYXlHcmlkLnByb3RvdHlwZS5saW1pdFJvd3MgPSBmdW5jdGlvbiAobGV2ZWxMaW1pdCkge1xuICAgICAgICB2YXIgcm93U3RydWN0cyA9IHRoaXMuZXZlbnRSZW5kZXJlci5yb3dTdHJ1Y3RzIHx8IFtdO1xuICAgICAgICB2YXIgcm93OyAvLyByb3cgI1xuICAgICAgICB2YXIgcm93TGV2ZWxMaW1pdDtcbiAgICAgICAgZm9yIChyb3cgPSAwOyByb3cgPCByb3dTdHJ1Y3RzLmxlbmd0aDsgcm93KyspIHtcbiAgICAgICAgICAgIHRoaXMudW5saW1pdFJvdyhyb3cpO1xuICAgICAgICAgICAgaWYgKCFsZXZlbExpbWl0KSB7XG4gICAgICAgICAgICAgICAgcm93TGV2ZWxMaW1pdCA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAodHlwZW9mIGxldmVsTGltaXQgPT09ICdudW1iZXInKSB7XG4gICAgICAgICAgICAgICAgcm93TGV2ZWxMaW1pdCA9IGxldmVsTGltaXQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICByb3dMZXZlbExpbWl0ID0gdGhpcy5jb21wdXRlUm93TGV2ZWxMaW1pdChyb3cpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHJvd0xldmVsTGltaXQgIT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5saW1pdFJvdyhyb3csIHJvd0xldmVsTGltaXQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcbiAgICAvLyBDb21wdXRlcyB0aGUgbnVtYmVyIG9mIGxldmVscyBhIHJvdyB3aWxsIGFjY29tb2RhdGUgd2l0aG91dCBnb2luZyBvdXRzaWRlIGl0cyBib3VuZHMuXG4gICAgLy8gQXNzdW1lcyB0aGUgcm93IGlzIFwicmlnaWRcIiAobWFpbnRhaW5zIGEgY29uc3RhbnQgaGVpZ2h0IHJlZ2FyZGxlc3Mgb2Ygd2hhdCBpcyBpbnNpZGUpLlxuICAgIC8vIGByb3dgIGlzIHRoZSByb3cgbnVtYmVyLlxuICAgIERheUdyaWQucHJvdG90eXBlLmNvbXB1dGVSb3dMZXZlbExpbWl0ID0gZnVuY3Rpb24gKHJvdykge1xuICAgICAgICB2YXIgcm93RWwgPSB0aGlzLnJvd0Vsc1tyb3ddOyAvLyB0aGUgY29udGFpbmluZyBcImZha2VcIiByb3cgZGl2XG4gICAgICAgIHZhciByb3dCb3R0b20gPSByb3dFbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5ib3R0b207IC8vIHJlbGF0aXZlIHRvIHZpZXdwb3J0IVxuICAgICAgICB2YXIgdHJFbHMgPSBmaW5kQ2hpbGRyZW4odGhpcy5ldmVudFJlbmRlcmVyLnJvd1N0cnVjdHNbcm93XS50Ym9keUVsKTtcbiAgICAgICAgdmFyIGk7XG4gICAgICAgIHZhciB0ckVsO1xuICAgICAgICAvLyBSZXZlYWwgb25lIGxldmVsIDx0cj4gYXQgYSB0aW1lIGFuZCBzdG9wIHdoZW4gd2UgZmluZCBvbmUgb3V0IG9mIGJvdW5kc1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgdHJFbHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHRyRWwgPSB0ckVsc1tpXTtcbiAgICAgICAgICAgIHRyRWwuY2xhc3NMaXN0LnJlbW92ZSgnZmMtbGltaXRlZCcpOyAvLyByZXNldCB0byBvcmlnaW5hbCBzdGF0ZSAocmV2ZWFsKVxuICAgICAgICAgICAgaWYgKHRyRWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuYm90dG9tID4gcm93Qm90dG9tKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlOyAvLyBzaG91bGQgbm90IGxpbWl0IGF0IGFsbFxuICAgIH07XG4gICAgLy8gTGltaXRzIHRoZSBnaXZlbiBncmlkIHJvdyB0byB0aGUgbWF4aW11bSBudW1iZXIgb2YgbGV2ZWxzIGFuZCBpbmplY3RzIFwibW9yZVwiIGxpbmtzIGlmIG5lY2Vzc2FyeS5cbiAgICAvLyBgcm93YCBpcyB0aGUgcm93IG51bWJlci5cbiAgICAvLyBgbGV2ZWxMaW1pdGAgaXMgYSBudW1iZXIgZm9yIHRoZSBtYXhpbXVtIChpbmNsdXNpdmUpIG51bWJlciBvZiBsZXZlbHMgYWxsb3dlZC5cbiAgICBEYXlHcmlkLnByb3RvdHlwZS5saW1pdFJvdyA9IGZ1bmN0aW9uIChyb3csIGxldmVsTGltaXQpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGNvbENudCA9IHRoaXMuY29sQ250O1xuICAgICAgICB2YXIgaXNSdGwgPSB0aGlzLmNvbnRleHQuaXNSdGw7XG4gICAgICAgIHZhciByb3dTdHJ1Y3QgPSB0aGlzLmV2ZW50UmVuZGVyZXIucm93U3RydWN0c1tyb3ddO1xuICAgICAgICB2YXIgbW9yZU5vZGVzID0gW107IC8vIGFycmF5IG9mIFwibW9yZVwiIDxhPiBsaW5rcyBhbmQgPHRkPiBET00gbm9kZXNcbiAgICAgICAgdmFyIGNvbCA9IDA7IC8vIGNvbCAjLCBsZWZ0LXRvLXJpZ2h0IChub3QgY2hyb25vbG9naWNhbGx5KVxuICAgICAgICB2YXIgbGV2ZWxTZWdzOyAvLyBhcnJheSBvZiBzZWdtZW50IG9iamVjdHMgaW4gdGhlIGxhc3QgYWxsb3dhYmxlIGxldmVsLCBvcmRlcmVkIGxlZnQtdG8tcmlnaHRcbiAgICAgICAgdmFyIGNlbGxNYXRyaXg7IC8vIGEgbWF0cml4IChieSBsZXZlbCwgdGhlbiBjb2x1bW4pIG9mIGFsbCA8dGQ+IGVsZW1lbnRzIGluIHRoZSByb3dcbiAgICAgICAgdmFyIGxpbWl0ZWROb2RlczsgLy8gYXJyYXkgb2YgdGVtcG9yYXJpbHkgaGlkZGVuIGxldmVsIDx0cj4gYW5kIHNlZ21lbnQgPHRkPiBET00gbm9kZXNcbiAgICAgICAgdmFyIGk7XG4gICAgICAgIHZhciBzZWc7XG4gICAgICAgIHZhciBzZWdzQmVsb3c7IC8vIGFycmF5IG9mIHNlZ21lbnQgb2JqZWN0cyBiZWxvdyBgc2VnYCBpbiB0aGUgY3VycmVudCBgY29sYFxuICAgICAgICB2YXIgdG90YWxTZWdzQmVsb3c7IC8vIHRvdGFsIG51bWJlciBvZiBzZWdtZW50cyBiZWxvdyBgc2VnYCBpbiBhbnkgb2YgdGhlIGNvbHVtbnMgYHNlZ2Agb2NjdXBpZXNcbiAgICAgICAgdmFyIGNvbFNlZ3NCZWxvdzsgLy8gYXJyYXkgb2Ygc2VnbWVudCBhcnJheXMsIGJlbG93IHNlZywgb25lIGZvciBlYWNoIGNvbHVtbiAob2Zmc2V0IGZyb20gc2VncydzIGZpcnN0IGNvbHVtbilcbiAgICAgICAgdmFyIHRkO1xuICAgICAgICB2YXIgcm93U3BhbjtcbiAgICAgICAgdmFyIHNlZ01vcmVOb2RlczsgLy8gYXJyYXkgb2YgXCJtb3JlXCIgPHRkPiBjZWxscyB0aGF0IHdpbGwgc3RhbmQtaW4gZm9yIHRoZSBjdXJyZW50IHNlZydzIGNlbGxcbiAgICAgICAgdmFyIGo7XG4gICAgICAgIHZhciBtb3JlVGQ7XG4gICAgICAgIHZhciBtb3JlV3JhcDtcbiAgICAgICAgdmFyIG1vcmVMaW5rO1xuICAgICAgICAvLyBJdGVyYXRlcyB0aHJvdWdoIGVtcHR5IGxldmVsIGNlbGxzIGFuZCBwbGFjZXMgXCJtb3JlXCIgbGlua3MgaW5zaWRlIGlmIG5lZWQgYmVcbiAgICAgICAgdmFyIGVtcHR5Q2VsbHNVbnRpbCA9IGZ1bmN0aW9uIChlbmRDb2wpIHtcbiAgICAgICAgICAgIHdoaWxlIChjb2wgPCBlbmRDb2wpIHtcbiAgICAgICAgICAgICAgICBzZWdzQmVsb3cgPSBfdGhpcy5nZXRDZWxsU2Vncyhyb3csIGNvbCwgbGV2ZWxMaW1pdCk7XG4gICAgICAgICAgICAgICAgaWYgKHNlZ3NCZWxvdy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgdGQgPSBjZWxsTWF0cml4W2xldmVsTGltaXQgLSAxXVtjb2xdO1xuICAgICAgICAgICAgICAgICAgICBtb3JlTGluayA9IF90aGlzLnJlbmRlck1vcmVMaW5rKHJvdywgY29sLCBzZWdzQmVsb3cpO1xuICAgICAgICAgICAgICAgICAgICBtb3JlV3JhcCA9IGNyZWF0ZUVsZW1lbnQoJ2RpdicsIG51bGwsIG1vcmVMaW5rKTtcbiAgICAgICAgICAgICAgICAgICAgdGQuYXBwZW5kQ2hpbGQobW9yZVdyYXApO1xuICAgICAgICAgICAgICAgICAgICBtb3JlTm9kZXMucHVzaChtb3JlV3JhcCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbCsrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICBpZiAobGV2ZWxMaW1pdCAmJiBsZXZlbExpbWl0IDwgcm93U3RydWN0LnNlZ0xldmVscy5sZW5ndGgpIHsgLy8gaXMgaXQgYWN0dWFsbHkgb3ZlciB0aGUgbGltaXQ/XG4gICAgICAgICAgICBsZXZlbFNlZ3MgPSByb3dTdHJ1Y3Quc2VnTGV2ZWxzW2xldmVsTGltaXQgLSAxXTtcbiAgICAgICAgICAgIGNlbGxNYXRyaXggPSByb3dTdHJ1Y3QuY2VsbE1hdHJpeDtcbiAgICAgICAgICAgIGxpbWl0ZWROb2RlcyA9IGZpbmRDaGlsZHJlbihyb3dTdHJ1Y3QudGJvZHlFbCkuc2xpY2UobGV2ZWxMaW1pdCk7IC8vIGdldCBsZXZlbCA8dHI+IGVsZW1lbnRzIHBhc3QgdGhlIGxpbWl0XG4gICAgICAgICAgICBsaW1pdGVkTm9kZXMuZm9yRWFjaChmdW5jdGlvbiAobm9kZSkge1xuICAgICAgICAgICAgICAgIG5vZGUuY2xhc3NMaXN0LmFkZCgnZmMtbGltaXRlZCcpOyAvLyBoaWRlIGVsZW1lbnRzIGFuZCBnZXQgYSBzaW1wbGUgRE9NLW5vZGVzIGFycmF5XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIC8vIGl0ZXJhdGUgdGhvdWdoIHNlZ21lbnRzIGluIHRoZSBsYXN0IGFsbG93YWJsZSBsZXZlbFxuICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IGxldmVsU2Vncy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHNlZyA9IGxldmVsU2Vnc1tpXTtcbiAgICAgICAgICAgICAgICB2YXIgbGVmdENvbCA9IGlzUnRsID8gKGNvbENudCAtIDEgLSBzZWcubGFzdENvbCkgOiBzZWcuZmlyc3RDb2w7XG4gICAgICAgICAgICAgICAgdmFyIHJpZ2h0Q29sID0gaXNSdGwgPyAoY29sQ250IC0gMSAtIHNlZy5maXJzdENvbCkgOiBzZWcubGFzdENvbDtcbiAgICAgICAgICAgICAgICBlbXB0eUNlbGxzVW50aWwobGVmdENvbCk7IC8vIHByb2Nlc3MgZW1wdHkgY2VsbHMgYmVmb3JlIHRoZSBzZWdtZW50XG4gICAgICAgICAgICAgICAgLy8gZGV0ZXJtaW5lICphbGwqIHNlZ21lbnRzIGJlbG93IGBzZWdgIHRoYXQgb2NjdXB5IHRoZSBzYW1lIGNvbHVtbnNcbiAgICAgICAgICAgICAgICBjb2xTZWdzQmVsb3cgPSBbXTtcbiAgICAgICAgICAgICAgICB0b3RhbFNlZ3NCZWxvdyA9IDA7XG4gICAgICAgICAgICAgICAgd2hpbGUgKGNvbCA8PSByaWdodENvbCkge1xuICAgICAgICAgICAgICAgICAgICBzZWdzQmVsb3cgPSB0aGlzLmdldENlbGxTZWdzKHJvdywgY29sLCBsZXZlbExpbWl0KTtcbiAgICAgICAgICAgICAgICAgICAgY29sU2Vnc0JlbG93LnB1c2goc2Vnc0JlbG93KTtcbiAgICAgICAgICAgICAgICAgICAgdG90YWxTZWdzQmVsb3cgKz0gc2Vnc0JlbG93Lmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgY29sKys7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICh0b3RhbFNlZ3NCZWxvdykgeyAvLyBkbyB3ZSBuZWVkIHRvIHJlcGxhY2UgdGhpcyBzZWdtZW50IHdpdGggb25lIG9yIG1hbnkgXCJtb3JlXCIgbGlua3M/XG4gICAgICAgICAgICAgICAgICAgIHRkID0gY2VsbE1hdHJpeFtsZXZlbExpbWl0IC0gMV1bbGVmdENvbF07IC8vIHRoZSBzZWdtZW50J3MgcGFyZW50IGNlbGxcbiAgICAgICAgICAgICAgICAgICAgcm93U3BhbiA9IHRkLnJvd1NwYW4gfHwgMTtcbiAgICAgICAgICAgICAgICAgICAgc2VnTW9yZU5vZGVzID0gW107XG4gICAgICAgICAgICAgICAgICAgIC8vIG1ha2UgYSByZXBsYWNlbWVudCA8dGQ+IGZvciBlYWNoIGNvbHVtbiB0aGUgc2VnbWVudCBvY2N1cGllcy4gd2lsbCBiZSBvbmUgZm9yIGVhY2ggY29sc3BhblxuICAgICAgICAgICAgICAgICAgICBmb3IgKGogPSAwOyBqIDwgY29sU2Vnc0JlbG93Lmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtb3JlVGQgPSBjcmVhdGVFbGVtZW50KCd0ZCcsIHsgY2xhc3NOYW1lOiAnZmMtbW9yZS1jZWxsJywgcm93U3Bhbjogcm93U3BhbiB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlZ3NCZWxvdyA9IGNvbFNlZ3NCZWxvd1tqXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1vcmVMaW5rID0gdGhpcy5yZW5kZXJNb3JlTGluayhyb3csIGxlZnRDb2wgKyBqLCBbc2VnXS5jb25jYXQoc2Vnc0JlbG93KSAvLyBjb3VudCBzZWcgYXMgaGlkZGVuIHRvb1xuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1vcmVXcmFwID0gY3JlYXRlRWxlbWVudCgnZGl2JywgbnVsbCwgbW9yZUxpbmspO1xuICAgICAgICAgICAgICAgICAgICAgICAgbW9yZVRkLmFwcGVuZENoaWxkKG1vcmVXcmFwKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlZ01vcmVOb2Rlcy5wdXNoKG1vcmVUZCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBtb3JlTm9kZXMucHVzaChtb3JlVGQpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHRkLmNsYXNzTGlzdC5hZGQoJ2ZjLWxpbWl0ZWQnKTtcbiAgICAgICAgICAgICAgICAgICAgaW5zZXJ0QWZ0ZXJFbGVtZW50KHRkLCBzZWdNb3JlTm9kZXMpO1xuICAgICAgICAgICAgICAgICAgICBsaW1pdGVkTm9kZXMucHVzaCh0ZCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZW1wdHlDZWxsc1VudGlsKHRoaXMuY29sQ250KTsgLy8gZmluaXNoIG9mZiB0aGUgbGV2ZWxcbiAgICAgICAgICAgIHJvd1N0cnVjdC5tb3JlRWxzID0gbW9yZU5vZGVzOyAvLyBmb3IgZWFzeSB1bmRvaW5nIGxhdGVyXG4gICAgICAgICAgICByb3dTdHJ1Y3QubGltaXRlZEVscyA9IGxpbWl0ZWROb2RlczsgLy8gZm9yIGVhc3kgdW5kb2luZyBsYXRlclxuICAgICAgICB9XG4gICAgfTtcbiAgICAvLyBSZXZlYWxzIGFsbCBsZXZlbHMgYW5kIHJlbW92ZXMgYWxsIFwibW9yZVwiLXJlbGF0ZWQgZWxlbWVudHMgZm9yIGEgZ3JpZCdzIHJvdy5cbiAgICAvLyBgcm93YCBpcyBhIHJvdyBudW1iZXIuXG4gICAgRGF5R3JpZC5wcm90b3R5cGUudW5saW1pdFJvdyA9IGZ1bmN0aW9uIChyb3cpIHtcbiAgICAgICAgdmFyIHJvd1N0cnVjdCA9IHRoaXMuZXZlbnRSZW5kZXJlci5yb3dTdHJ1Y3RzW3Jvd107XG4gICAgICAgIGlmIChyb3dTdHJ1Y3QubW9yZUVscykge1xuICAgICAgICAgICAgcm93U3RydWN0Lm1vcmVFbHMuZm9yRWFjaChyZW1vdmVFbGVtZW50KTtcbiAgICAgICAgICAgIHJvd1N0cnVjdC5tb3JlRWxzID0gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICBpZiAocm93U3RydWN0LmxpbWl0ZWRFbHMpIHtcbiAgICAgICAgICAgIHJvd1N0cnVjdC5saW1pdGVkRWxzLmZvckVhY2goZnVuY3Rpb24gKGxpbWl0ZWRFbCkge1xuICAgICAgICAgICAgICAgIGxpbWl0ZWRFbC5jbGFzc0xpc3QucmVtb3ZlKCdmYy1saW1pdGVkJyk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJvd1N0cnVjdC5saW1pdGVkRWxzID0gbnVsbDtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLy8gUmVuZGVycyBhbiA8YT4gZWxlbWVudCB0aGF0IHJlcHJlc2VudHMgaGlkZGVuIGV2ZW50IGVsZW1lbnQgZm9yIGEgY2VsbC5cbiAgICAvLyBSZXNwb25zaWJsZSBmb3IgYXR0YWNoaW5nIGNsaWNrIGhhbmRsZXIgYXMgd2VsbC5cbiAgICBEYXlHcmlkLnByb3RvdHlwZS5yZW5kZXJNb3JlTGluayA9IGZ1bmN0aW9uIChyb3csIGNvbCwgaGlkZGVuU2Vncykge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgX2EgPSB0aGlzLmNvbnRleHQsIGNhbGVuZGFyID0gX2EuY2FsZW5kYXIsIHZpZXcgPSBfYS52aWV3LCBkYXRlRW52ID0gX2EuZGF0ZUVudiwgb3B0aW9ucyA9IF9hLm9wdGlvbnMsIGlzUnRsID0gX2EuaXNSdGw7XG4gICAgICAgIHZhciBhID0gY3JlYXRlRWxlbWVudCgnYScsIHsgY2xhc3NOYW1lOiAnZmMtbW9yZScgfSk7XG4gICAgICAgIGEuaW5uZXJUZXh0ID0gdGhpcy5nZXRNb3JlTGlua1RleHQoaGlkZGVuU2Vncy5sZW5ndGgpO1xuICAgICAgICBhLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICB2YXIgY2xpY2tPcHRpb24gPSBvcHRpb25zLmV2ZW50TGltaXRDbGljaztcbiAgICAgICAgICAgIHZhciBfY29sID0gaXNSdGwgPyBfdGhpcy5jb2xDbnQgLSBjb2wgLSAxIDogY29sOyAvLyBIQUNLOiBwcm9wcy5jZWxscyBoYXMgZGlmZmVyZW50IGRpciBzeXN0ZW0/XG4gICAgICAgICAgICB2YXIgZGF0ZSA9IF90aGlzLnByb3BzLmNlbGxzW3Jvd11bX2NvbF0uZGF0ZTtcbiAgICAgICAgICAgIHZhciBtb3JlRWwgPSBldi5jdXJyZW50VGFyZ2V0O1xuICAgICAgICAgICAgdmFyIGRheUVsID0gX3RoaXMuZ2V0Q2VsbEVsKHJvdywgY29sKTtcbiAgICAgICAgICAgIHZhciBhbGxTZWdzID0gX3RoaXMuZ2V0Q2VsbFNlZ3Mocm93LCBjb2wpO1xuICAgICAgICAgICAgLy8gcmVzY29wZSB0aGUgc2VnbWVudHMgdG8gYmUgd2l0aGluIHRoZSBjZWxsJ3MgZGF0ZVxuICAgICAgICAgICAgdmFyIHJlc2xpY2VkQWxsU2VncyA9IF90aGlzLnJlc2xpY2VEYXlTZWdzKGFsbFNlZ3MsIGRhdGUpO1xuICAgICAgICAgICAgdmFyIHJlc2xpY2VkSGlkZGVuU2VncyA9IF90aGlzLnJlc2xpY2VEYXlTZWdzKGhpZGRlblNlZ3MsIGRhdGUpO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBjbGlja09wdGlvbiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgIC8vIHRoZSByZXR1cm5lZCB2YWx1ZSBjYW4gYmUgYW4gYXRvbWljIG9wdGlvblxuICAgICAgICAgICAgICAgIGNsaWNrT3B0aW9uID0gY2FsZW5kYXIucHVibGljbHlUcmlnZ2VyKCdldmVudExpbWl0Q2xpY2snLCBbXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGU6IGRhdGVFbnYudG9EYXRlKGRhdGUpLFxuICAgICAgICAgICAgICAgICAgICAgICAgYWxsRGF5OiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgZGF5RWw6IGRheUVsLFxuICAgICAgICAgICAgICAgICAgICAgICAgbW9yZUVsOiBtb3JlRWwsXG4gICAgICAgICAgICAgICAgICAgICAgICBzZWdzOiByZXNsaWNlZEFsbFNlZ3MsXG4gICAgICAgICAgICAgICAgICAgICAgICBoaWRkZW5TZWdzOiByZXNsaWNlZEhpZGRlblNlZ3MsXG4gICAgICAgICAgICAgICAgICAgICAgICBqc0V2ZW50OiBldixcbiAgICAgICAgICAgICAgICAgICAgICAgIHZpZXc6IHZpZXdcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGNsaWNrT3B0aW9uID09PSAncG9wb3ZlcicpIHtcbiAgICAgICAgICAgICAgICBfdGhpcy5zaG93U2VnUG9wb3Zlcihyb3csIGNvbCwgbW9yZUVsLCByZXNsaWNlZEFsbFNlZ3MpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAodHlwZW9mIGNsaWNrT3B0aW9uID09PSAnc3RyaW5nJykgeyAvLyBhIHZpZXcgbmFtZVxuICAgICAgICAgICAgICAgIGNhbGVuZGFyLnpvb21UbyhkYXRlLCBjbGlja09wdGlvbik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gYTtcbiAgICB9O1xuICAgIC8vIFJldmVhbHMgdGhlIHBvcG92ZXIgdGhhdCBkaXNwbGF5cyBhbGwgZXZlbnRzIHdpdGhpbiBhIGNlbGxcbiAgICBEYXlHcmlkLnByb3RvdHlwZS5zaG93U2VnUG9wb3ZlciA9IGZ1bmN0aW9uIChyb3csIGNvbCwgbW9yZUxpbmssIHNlZ3MpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIF9hID0gdGhpcy5jb250ZXh0LCBjYWxlbmRhciA9IF9hLmNhbGVuZGFyLCB2aWV3ID0gX2EudmlldywgdGhlbWUgPSBfYS50aGVtZSwgaXNSdGwgPSBfYS5pc1J0bDtcbiAgICAgICAgdmFyIF9jb2wgPSBpc1J0bCA/IHRoaXMuY29sQ250IC0gY29sIC0gMSA6IGNvbDsgLy8gSEFDSzogcHJvcHMuY2VsbHMgaGFzIGRpZmZlcmVudCBkaXIgc3lzdGVtP1xuICAgICAgICB2YXIgbW9yZVdyYXAgPSBtb3JlTGluay5wYXJlbnROb2RlOyAvLyB0aGUgPGRpdj4gd3JhcHBlciBhcm91bmQgdGhlIDxhPlxuICAgICAgICB2YXIgdG9wRWw7IC8vIHRoZSBlbGVtZW50IHdlIHdhbnQgdG8gbWF0Y2ggdGhlIHRvcCBjb29yZGluYXRlIG9mXG4gICAgICAgIHZhciBvcHRpb25zO1xuICAgICAgICBpZiAodGhpcy5yb3dDbnQgPT09IDEpIHtcbiAgICAgICAgICAgIHRvcEVsID0gdmlldy5lbDsgLy8gd2lsbCBjYXVzZSB0aGUgcG9wb3ZlciB0byBjb3ZlciBhbnkgc29ydCBvZiBoZWFkZXJcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRvcEVsID0gdGhpcy5yb3dFbHNbcm93XTsgLy8gd2lsbCBhbGlnbiB3aXRoIHRvcCBvZiByb3dcbiAgICAgICAgfVxuICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgICAgY2xhc3NOYW1lOiAnZmMtbW9yZS1wb3BvdmVyICcgKyB0aGVtZS5nZXRDbGFzcygncG9wb3ZlcicpLFxuICAgICAgICAgICAgcGFyZW50RWw6IHZpZXcuZWwsXG4gICAgICAgICAgICB0b3A6IGNvbXB1dGVSZWN0KHRvcEVsKS50b3AsXG4gICAgICAgICAgICBhdXRvSGlkZTogdHJ1ZSxcbiAgICAgICAgICAgIGNvbnRlbnQ6IGZ1bmN0aW9uIChlbCkge1xuICAgICAgICAgICAgICAgIF90aGlzLnNlZ1BvcG92ZXJUaWxlID0gbmV3IERheVRpbGUoZWwpO1xuICAgICAgICAgICAgICAgIF90aGlzLnVwZGF0ZVNlZ1BvcG92ZXJUaWxlKF90aGlzLnByb3BzLmNlbGxzW3Jvd11bX2NvbF0uZGF0ZSwgc2Vncyk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgaGlkZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIF90aGlzLnNlZ1BvcG92ZXJUaWxlLmRlc3Ryb3koKTtcbiAgICAgICAgICAgICAgICBfdGhpcy5zZWdQb3BvdmVyVGlsZSA9IG51bGw7XG4gICAgICAgICAgICAgICAgX3RoaXMuc2VnUG9wb3Zlci5kZXN0cm95KCk7XG4gICAgICAgICAgICAgICAgX3RoaXMuc2VnUG9wb3ZlciA9IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIC8vIERldGVybWluZSBob3Jpem9udGFsIGNvb3JkaW5hdGUuXG4gICAgICAgIC8vIFdlIHVzZSB0aGUgbW9yZVdyYXAgaW5zdGVhZCBvZiB0aGUgPHRkPiB0byBhdm9pZCBib3JkZXIgY29uZnVzaW9uLlxuICAgICAgICBpZiAoaXNSdGwpIHtcbiAgICAgICAgICAgIG9wdGlvbnMucmlnaHQgPSBjb21wdXRlUmVjdChtb3JlV3JhcCkucmlnaHQgKyAxOyAvLyArMSB0byBiZSBvdmVyIGNlbGwgYm9yZGVyXG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBvcHRpb25zLmxlZnQgPSBjb21wdXRlUmVjdChtb3JlV3JhcCkubGVmdCAtIDE7IC8vIC0xIHRvIGJlIG92ZXIgY2VsbCBib3JkZXJcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnNlZ1BvcG92ZXIgPSBuZXcgUG9wb3ZlcihvcHRpb25zKTtcbiAgICAgICAgdGhpcy5zZWdQb3BvdmVyLnNob3coKTtcbiAgICAgICAgY2FsZW5kYXIucmVsZWFzZUFmdGVyU2l6aW5nVHJpZ2dlcnMoKTsgLy8gaGFjayBmb3IgZXZlbnRQb3NpdGlvbmVkXG4gICAgfTtcbiAgICAvLyBHaXZlbiB0aGUgZXZlbnRzIHdpdGhpbiBhbiBhcnJheSBvZiBzZWdtZW50IG9iamVjdHMsIHJlc2xpY2UgdGhlbSB0byBiZSBpbiBhIHNpbmdsZSBkYXlcbiAgICBEYXlHcmlkLnByb3RvdHlwZS5yZXNsaWNlRGF5U2VncyA9IGZ1bmN0aW9uIChzZWdzLCBkYXlEYXRlKSB7XG4gICAgICAgIHZhciBkYXlTdGFydCA9IGRheURhdGU7XG4gICAgICAgIHZhciBkYXlFbmQgPSBhZGREYXlzKGRheVN0YXJ0LCAxKTtcbiAgICAgICAgdmFyIGRheVJhbmdlID0geyBzdGFydDogZGF5U3RhcnQsIGVuZDogZGF5RW5kIH07XG4gICAgICAgIHZhciBuZXdTZWdzID0gW107XG4gICAgICAgIGZvciAodmFyIF9pID0gMCwgc2Vnc18xID0gc2VnczsgX2kgPCBzZWdzXzEubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICB2YXIgc2VnID0gc2Vnc18xW19pXTtcbiAgICAgICAgICAgIHZhciBldmVudFJhbmdlID0gc2VnLmV2ZW50UmFuZ2U7XG4gICAgICAgICAgICB2YXIgb3JpZ1JhbmdlID0gZXZlbnRSYW5nZS5yYW5nZTtcbiAgICAgICAgICAgIHZhciBzbGljZWRSYW5nZSA9IGludGVyc2VjdFJhbmdlcyhvcmlnUmFuZ2UsIGRheVJhbmdlKTtcbiAgICAgICAgICAgIGlmIChzbGljZWRSYW5nZSkge1xuICAgICAgICAgICAgICAgIG5ld1NlZ3MucHVzaChfX2Fzc2lnbih7fSwgc2VnLCB7IGV2ZW50UmFuZ2U6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlZjogZXZlbnRSYW5nZS5kZWYsXG4gICAgICAgICAgICAgICAgICAgICAgICB1aTogX19hc3NpZ24oe30sIGV2ZW50UmFuZ2UudWksIHsgZHVyYXRpb25FZGl0YWJsZTogZmFsc2UgfSksXG4gICAgICAgICAgICAgICAgICAgICAgICBpbnN0YW5jZTogZXZlbnRSYW5nZS5pbnN0YW5jZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJhbmdlOiBzbGljZWRSYW5nZVxuICAgICAgICAgICAgICAgICAgICB9LCBpc1N0YXJ0OiBzZWcuaXNTdGFydCAmJiBzbGljZWRSYW5nZS5zdGFydC52YWx1ZU9mKCkgPT09IG9yaWdSYW5nZS5zdGFydC52YWx1ZU9mKCksIGlzRW5kOiBzZWcuaXNFbmQgJiYgc2xpY2VkUmFuZ2UuZW5kLnZhbHVlT2YoKSA9PT0gb3JpZ1JhbmdlLmVuZC52YWx1ZU9mKCkgfSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXdTZWdzO1xuICAgIH07XG4gICAgLy8gR2VuZXJhdGVzIHRoZSB0ZXh0IHRoYXQgc2hvdWxkIGJlIGluc2lkZSBhIFwibW9yZVwiIGxpbmssIGdpdmVuIHRoZSBudW1iZXIgb2YgZXZlbnRzIGl0IHJlcHJlc2VudHNcbiAgICBEYXlHcmlkLnByb3RvdHlwZS5nZXRNb3JlTGlua1RleHQgPSBmdW5jdGlvbiAobnVtKSB7XG4gICAgICAgIHZhciBvcHQgPSB0aGlzLmNvbnRleHQub3B0aW9ucy5ldmVudExpbWl0VGV4dDtcbiAgICAgICAgaWYgKHR5cGVvZiBvcHQgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIHJldHVybiBvcHQobnVtKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiAnKycgKyBudW0gKyAnICcgKyBvcHQ7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8vIFJldHVybnMgc2VnbWVudHMgd2l0aGluIGEgZ2l2ZW4gY2VsbC5cbiAgICAvLyBJZiBgc3RhcnRMZXZlbGAgaXMgc3BlY2lmaWVkLCByZXR1cm5zIG9ubHkgZXZlbnRzIGluY2x1ZGluZyBhbmQgYmVsb3cgdGhhdCBsZXZlbC4gT3RoZXJ3aXNlIHJldHVybnMgYWxsIHNlZ3MuXG4gICAgRGF5R3JpZC5wcm90b3R5cGUuZ2V0Q2VsbFNlZ3MgPSBmdW5jdGlvbiAocm93LCBjb2wsIHN0YXJ0TGV2ZWwpIHtcbiAgICAgICAgdmFyIHNlZ01hdHJpeCA9IHRoaXMuZXZlbnRSZW5kZXJlci5yb3dTdHJ1Y3RzW3Jvd10uc2VnTWF0cml4O1xuICAgICAgICB2YXIgbGV2ZWwgPSBzdGFydExldmVsIHx8IDA7XG4gICAgICAgIHZhciBzZWdzID0gW107XG4gICAgICAgIHZhciBzZWc7XG4gICAgICAgIHdoaWxlIChsZXZlbCA8IHNlZ01hdHJpeC5sZW5ndGgpIHtcbiAgICAgICAgICAgIHNlZyA9IHNlZ01hdHJpeFtsZXZlbF1bY29sXTtcbiAgICAgICAgICAgIGlmIChzZWcpIHtcbiAgICAgICAgICAgICAgICBzZWdzLnB1c2goc2VnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldmVsKys7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlZ3M7XG4gICAgfTtcbiAgICByZXR1cm4gRGF5R3JpZDtcbn0oRGF0ZUNvbXBvbmVudCkpO1xuXG52YXIgV0VFS19OVU1fRk9STUFUJDEgPSBjcmVhdGVGb3JtYXR0ZXIoeyB3ZWVrOiAnbnVtZXJpYycgfSk7XG4vKiBBbiBhYnN0cmFjdCBjbGFzcyBmb3IgdGhlIGRheWdyaWQgdmlld3MsIGFzIHdlbGwgYXMgbW9udGggdmlldy4gUmVuZGVycyBvbmUgb3IgbW9yZSByb3dzIG9mIGRheSBjZWxscy5cbi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuLy8gSXQgaXMgYSBtYW5hZ2VyIGZvciBhIERheUdyaWQgc3ViY29tcG9uZW50LCB3aGljaCBkb2VzIG1vc3Qgb2YgdGhlIGhlYXZ5IGxpZnRpbmcuXG4vLyBJdCBpcyByZXNwb25zaWJsZSBmb3IgbWFuYWdpbmcgd2lkdGgvaGVpZ2h0LlxudmFyIEFic3RyYWN0RGF5R3JpZFZpZXcgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoX3N1cGVyKSB7XG4gICAgX19leHRlbmRzKEFic3RyYWN0RGF5R3JpZFZpZXcsIF9zdXBlcik7XG4gICAgZnVuY3Rpb24gQWJzdHJhY3REYXlHcmlkVmlldygpIHtcbiAgICAgICAgdmFyIF90aGlzID0gX3N1cGVyICE9PSBudWxsICYmIF9zdXBlci5hcHBseSh0aGlzLCBhcmd1bWVudHMpIHx8IHRoaXM7XG4gICAgICAgIF90aGlzLnByb2Nlc3NPcHRpb25zID0gbWVtb2l6ZShfdGhpcy5fcHJvY2Vzc09wdGlvbnMpO1xuICAgICAgICBfdGhpcy5yZW5kZXJTa2VsZXRvbiA9IG1lbW9pemVSZW5kZXJpbmcoX3RoaXMuX3JlbmRlclNrZWxldG9uLCBfdGhpcy5fdW5yZW5kZXJTa2VsZXRvbik7XG4gICAgICAgIC8qIEhlYWRlciBSZW5kZXJpbmdcbiAgICAgICAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbiAgICAgICAgLy8gR2VuZXJhdGVzIHRoZSBIVE1MIHRoYXQgd2lsbCBnbyBiZWZvcmUgdGhlIGRheS1vZiB3ZWVrIGhlYWRlciBjZWxsc1xuICAgICAgICBfdGhpcy5yZW5kZXJIZWFkSW50cm9IdG1sID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIF9hID0gX3RoaXMuY29udGV4dCwgdGhlbWUgPSBfYS50aGVtZSwgb3B0aW9ucyA9IF9hLm9wdGlvbnM7XG4gICAgICAgICAgICBpZiAoX3RoaXMuY29sV2Vla051bWJlcnNWaXNpYmxlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcnICtcbiAgICAgICAgICAgICAgICAgICAgJzx0aCBjbGFzcz1cImZjLXdlZWstbnVtYmVyICcgKyB0aGVtZS5nZXRDbGFzcygnd2lkZ2V0SGVhZGVyJykgKyAnXCIgJyArIF90aGlzLndlZWtOdW1iZXJTdHlsZUF0dHIoKSArICc+JyArXG4gICAgICAgICAgICAgICAgICAgICc8c3Bhbj4nICsgLy8gbmVlZGVkIGZvciBtYXRjaENlbGxXaWR0aHNcbiAgICAgICAgICAgICAgICAgICAgaHRtbEVzY2FwZShvcHRpb25zLndlZWtMYWJlbCkgK1xuICAgICAgICAgICAgICAgICAgICAnPC9zcGFuPicgK1xuICAgICAgICAgICAgICAgICAgICAnPC90aD4nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICB9O1xuICAgICAgICAvKiBEYXkgR3JpZCBSZW5kZXJpbmdcbiAgICAgICAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbiAgICAgICAgLy8gR2VuZXJhdGVzIHRoZSBIVE1MIHRoYXQgd2lsbCBnbyBiZWZvcmUgY29udGVudC1za2VsZXRvbiBjZWxscyB0aGF0IGRpc3BsYXkgdGhlIGRheS93ZWVrIG51bWJlcnNcbiAgICAgICAgX3RoaXMucmVuZGVyRGF5R3JpZE51bWJlckludHJvSHRtbCA9IGZ1bmN0aW9uIChyb3csIGRheUdyaWQpIHtcbiAgICAgICAgICAgIHZhciBfYSA9IF90aGlzLmNvbnRleHQsIG9wdGlvbnMgPSBfYS5vcHRpb25zLCBkYXRlRW52ID0gX2EuZGF0ZUVudjtcbiAgICAgICAgICAgIHZhciB3ZWVrU3RhcnQgPSBkYXlHcmlkLnByb3BzLmNlbGxzW3Jvd11bMF0uZGF0ZTtcbiAgICAgICAgICAgIGlmIChfdGhpcy5jb2xXZWVrTnVtYmVyc1Zpc2libGUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJycgK1xuICAgICAgICAgICAgICAgICAgICAnPHRkIGNsYXNzPVwiZmMtd2Vlay1udW1iZXJcIiAnICsgX3RoaXMud2Vla051bWJlclN0eWxlQXR0cigpICsgJz4nICtcbiAgICAgICAgICAgICAgICAgICAgYnVpbGRHb3RvQW5jaG9ySHRtbCgvLyBhc2lkZSBmcm9tIGxpbmssIGltcG9ydGFudCBmb3IgbWF0Y2hDZWxsV2lkdGhzXG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMsIGRhdGVFbnYsIHsgZGF0ZTogd2Vla1N0YXJ0LCB0eXBlOiAnd2VlaycsIGZvcmNlT2ZmOiBkYXlHcmlkLmNvbENudCA9PT0gMSB9LCBkYXRlRW52LmZvcm1hdCh3ZWVrU3RhcnQsIFdFRUtfTlVNX0ZPUk1BVCQxKSAvLyBpbm5lciBIVE1MXG4gICAgICAgICAgICAgICAgICAgICkgK1xuICAgICAgICAgICAgICAgICAgICAnPC90ZD4nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICB9O1xuICAgICAgICAvLyBHZW5lcmF0ZXMgdGhlIEhUTUwgdGhhdCBnb2VzIGJlZm9yZSB0aGUgZGF5IGJnIGNlbGxzIGZvciBlYWNoIGRheS1yb3dcbiAgICAgICAgX3RoaXMucmVuZGVyRGF5R3JpZEJnSW50cm9IdG1sID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHRoZW1lID0gX3RoaXMuY29udGV4dC50aGVtZTtcbiAgICAgICAgICAgIGlmIChfdGhpcy5jb2xXZWVrTnVtYmVyc1Zpc2libGUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJzx0ZCBjbGFzcz1cImZjLXdlZWstbnVtYmVyICcgKyB0aGVtZS5nZXRDbGFzcygnd2lkZ2V0Q29udGVudCcpICsgJ1wiICcgKyBfdGhpcy53ZWVrTnVtYmVyU3R5bGVBdHRyKCkgKyAnPjwvdGQ+JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgfTtcbiAgICAgICAgLy8gR2VuZXJhdGVzIHRoZSBIVE1MIHRoYXQgZ29lcyBiZWZvcmUgZXZlcnkgb3RoZXIgdHlwZSBvZiByb3cgZ2VuZXJhdGVkIGJ5IERheUdyaWQuXG4gICAgICAgIC8vIEFmZmVjdHMgbWlycm9yLXNrZWxldG9uIGFuZCBoaWdobGlnaHQtc2tlbGV0b24gcm93cy5cbiAgICAgICAgX3RoaXMucmVuZGVyRGF5R3JpZEludHJvSHRtbCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmIChfdGhpcy5jb2xXZWVrTnVtYmVyc1Zpc2libGUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJzx0ZCBjbGFzcz1cImZjLXdlZWstbnVtYmVyXCIgJyArIF90aGlzLndlZWtOdW1iZXJTdHlsZUF0dHIoKSArICc+PC90ZD4nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gX3RoaXM7XG4gICAgfVxuICAgIEFic3RyYWN0RGF5R3JpZFZpZXcucHJvdG90eXBlLl9wcm9jZXNzT3B0aW9ucyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zLndlZWtOdW1iZXJzKSB7XG4gICAgICAgICAgICBpZiAob3B0aW9ucy53ZWVrTnVtYmVyc1dpdGhpbkRheXMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNlbGxXZWVrTnVtYmVyc1Zpc2libGUgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHRoaXMuY29sV2Vla051bWJlcnNWaXNpYmxlID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNlbGxXZWVrTnVtYmVyc1Zpc2libGUgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbFdlZWtOdW1iZXJzVmlzaWJsZSA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmNvbFdlZWtOdW1iZXJzVmlzaWJsZSA9IGZhbHNlO1xuICAgICAgICAgICAgdGhpcy5jZWxsV2Vla051bWJlcnNWaXNpYmxlID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIEFic3RyYWN0RGF5R3JpZFZpZXcucHJvdG90eXBlLnJlbmRlciA9IGZ1bmN0aW9uIChwcm9wcywgY29udGV4dCkge1xuICAgICAgICBfc3VwZXIucHJvdG90eXBlLnJlbmRlci5jYWxsKHRoaXMsIHByb3BzLCBjb250ZXh0KTtcbiAgICAgICAgdGhpcy5wcm9jZXNzT3B0aW9ucyhjb250ZXh0Lm9wdGlvbnMpO1xuICAgICAgICB0aGlzLnJlbmRlclNrZWxldG9uKGNvbnRleHQpO1xuICAgIH07XG4gICAgQWJzdHJhY3REYXlHcmlkVmlldy5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgX3N1cGVyLnByb3RvdHlwZS5kZXN0cm95LmNhbGwodGhpcyk7XG4gICAgICAgIHRoaXMucmVuZGVyU2tlbGV0b24udW5yZW5kZXIoKTtcbiAgICB9O1xuICAgIEFic3RyYWN0RGF5R3JpZFZpZXcucHJvdG90eXBlLl9yZW5kZXJTa2VsZXRvbiA9IGZ1bmN0aW9uIChjb250ZXh0KSB7XG4gICAgICAgIHRoaXMuZWwuY2xhc3NMaXN0LmFkZCgnZmMtZGF5R3JpZC12aWV3Jyk7XG4gICAgICAgIHRoaXMuZWwuaW5uZXJIVE1MID0gdGhpcy5yZW5kZXJTa2VsZXRvbkh0bWwoKTtcbiAgICAgICAgdGhpcy5zY3JvbGxlciA9IG5ldyBTY3JvbGxDb21wb25lbnQoJ2hpZGRlbicsIC8vIG92ZXJmbG93IHhcbiAgICAgICAgJ2F1dG8nIC8vIG92ZXJmbG93IHlcbiAgICAgICAgKTtcbiAgICAgICAgdmFyIGRheUdyaWRDb250YWluZXJFbCA9IHRoaXMuc2Nyb2xsZXIuZWw7XG4gICAgICAgIHRoaXMuZWwucXVlcnlTZWxlY3RvcignLmZjLWJvZHkgPiB0ciA+IHRkJykuYXBwZW5kQ2hpbGQoZGF5R3JpZENvbnRhaW5lckVsKTtcbiAgICAgICAgZGF5R3JpZENvbnRhaW5lckVsLmNsYXNzTGlzdC5hZGQoJ2ZjLWRheS1ncmlkLWNvbnRhaW5lcicpO1xuICAgICAgICB2YXIgZGF5R3JpZEVsID0gY3JlYXRlRWxlbWVudCgnZGl2JywgeyBjbGFzc05hbWU6ICdmYy1kYXktZ3JpZCcgfSk7XG4gICAgICAgIGRheUdyaWRDb250YWluZXJFbC5hcHBlbmRDaGlsZChkYXlHcmlkRWwpO1xuICAgICAgICB0aGlzLmRheUdyaWQgPSBuZXcgRGF5R3JpZChkYXlHcmlkRWwsIHtcbiAgICAgICAgICAgIHJlbmRlck51bWJlckludHJvSHRtbDogdGhpcy5yZW5kZXJEYXlHcmlkTnVtYmVySW50cm9IdG1sLFxuICAgICAgICAgICAgcmVuZGVyQmdJbnRyb0h0bWw6IHRoaXMucmVuZGVyRGF5R3JpZEJnSW50cm9IdG1sLFxuICAgICAgICAgICAgcmVuZGVySW50cm9IdG1sOiB0aGlzLnJlbmRlckRheUdyaWRJbnRyb0h0bWwsXG4gICAgICAgICAgICBjb2xXZWVrTnVtYmVyc1Zpc2libGU6IHRoaXMuY29sV2Vla051bWJlcnNWaXNpYmxlLFxuICAgICAgICAgICAgY2VsbFdlZWtOdW1iZXJzVmlzaWJsZTogdGhpcy5jZWxsV2Vla051bWJlcnNWaXNpYmxlXG4gICAgICAgIH0pO1xuICAgIH07XG4gICAgQWJzdHJhY3REYXlHcmlkVmlldy5wcm90b3R5cGUuX3VucmVuZGVyU2tlbGV0b24gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuZWwuY2xhc3NMaXN0LnJlbW92ZSgnZmMtZGF5R3JpZC12aWV3Jyk7XG4gICAgICAgIHRoaXMuZGF5R3JpZC5kZXN0cm95KCk7XG4gICAgICAgIHRoaXMuc2Nyb2xsZXIuZGVzdHJveSgpO1xuICAgIH07XG4gICAgLy8gQnVpbGRzIHRoZSBIVE1MIHNrZWxldG9uIGZvciB0aGUgdmlldy5cbiAgICAvLyBUaGUgZGF5LWdyaWQgY29tcG9uZW50IHdpbGwgcmVuZGVyIGluc2lkZSBvZiBhIGNvbnRhaW5lciBkZWZpbmVkIGJ5IHRoaXMgSFRNTC5cbiAgICBBYnN0cmFjdERheUdyaWRWaWV3LnByb3RvdHlwZS5yZW5kZXJTa2VsZXRvbkh0bWwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBfYSA9IHRoaXMuY29udGV4dCwgdGhlbWUgPSBfYS50aGVtZSwgb3B0aW9ucyA9IF9hLm9wdGlvbnM7XG4gICAgICAgIHJldHVybiAnJyArXG4gICAgICAgICAgICAnPHRhYmxlIGNsYXNzPVwiJyArIHRoZW1lLmdldENsYXNzKCd0YWJsZUdyaWQnKSArICdcIj4nICtcbiAgICAgICAgICAgIChvcHRpb25zLmNvbHVtbkhlYWRlciA/XG4gICAgICAgICAgICAgICAgJzx0aGVhZCBjbGFzcz1cImZjLWhlYWRcIj4nICtcbiAgICAgICAgICAgICAgICAgICAgJzx0cj4nICtcbiAgICAgICAgICAgICAgICAgICAgJzx0ZCBjbGFzcz1cImZjLWhlYWQtY29udGFpbmVyICcgKyB0aGVtZS5nZXRDbGFzcygnd2lkZ2V0SGVhZGVyJykgKyAnXCI+Jm5ic3A7PC90ZD4nICtcbiAgICAgICAgICAgICAgICAgICAgJzwvdHI+JyArXG4gICAgICAgICAgICAgICAgICAgICc8L3RoZWFkPicgOlxuICAgICAgICAgICAgICAgICcnKSArXG4gICAgICAgICAgICAnPHRib2R5IGNsYXNzPVwiZmMtYm9keVwiPicgK1xuICAgICAgICAgICAgJzx0cj4nICtcbiAgICAgICAgICAgICc8dGQgY2xhc3M9XCInICsgdGhlbWUuZ2V0Q2xhc3MoJ3dpZGdldENvbnRlbnQnKSArICdcIj48L3RkPicgK1xuICAgICAgICAgICAgJzwvdHI+JyArXG4gICAgICAgICAgICAnPC90Ym9keT4nICtcbiAgICAgICAgICAgICc8L3RhYmxlPic7XG4gICAgfTtcbiAgICAvLyBHZW5lcmF0ZXMgYW4gSFRNTCBhdHRyaWJ1dGUgc3RyaW5nIGZvciBzZXR0aW5nIHRoZSB3aWR0aCBvZiB0aGUgd2VlayBudW1iZXIgY29sdW1uLCBpZiBpdCBpcyBrbm93blxuICAgIEFic3RyYWN0RGF5R3JpZFZpZXcucHJvdG90eXBlLndlZWtOdW1iZXJTdHlsZUF0dHIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh0aGlzLndlZWtOdW1iZXJXaWR0aCAhPSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm4gJ3N0eWxlPVwid2lkdGg6JyArIHRoaXMud2Vla051bWJlcldpZHRoICsgJ3B4XCInO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9O1xuICAgIC8vIERldGVybWluZXMgd2hldGhlciBlYWNoIHJvdyBzaG91bGQgaGF2ZSBhIGNvbnN0YW50IGhlaWdodFxuICAgIEFic3RyYWN0RGF5R3JpZFZpZXcucHJvdG90eXBlLmhhc1JpZ2lkUm93cyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGV2ZW50TGltaXQgPSB0aGlzLmNvbnRleHQub3B0aW9ucy5ldmVudExpbWl0O1xuICAgICAgICByZXR1cm4gZXZlbnRMaW1pdCAmJiB0eXBlb2YgZXZlbnRMaW1pdCAhPT0gJ251bWJlcic7XG4gICAgfTtcbiAgICAvKiBEaW1lbnNpb25zXG4gICAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbiAgICBBYnN0cmFjdERheUdyaWRWaWV3LnByb3RvdHlwZS51cGRhdGVTaXplID0gZnVuY3Rpb24gKGlzUmVzaXplLCB2aWV3SGVpZ2h0LCBpc0F1dG8pIHtcbiAgICAgICAgX3N1cGVyLnByb3RvdHlwZS51cGRhdGVTaXplLmNhbGwodGhpcywgaXNSZXNpemUsIHZpZXdIZWlnaHQsIGlzQXV0byk7IC8vIHdpbGwgY2FsbCB1cGRhdGVCYXNlU2l6ZS4gaW1wb3J0YW50IHRoYXQgZXhlY3V0ZXMgZmlyc3RcbiAgICAgICAgdGhpcy5kYXlHcmlkLnVwZGF0ZVNpemUoaXNSZXNpemUpO1xuICAgIH07XG4gICAgLy8gUmVmcmVzaGVzIHRoZSBob3Jpem9udGFsIGRpbWVuc2lvbnMgb2YgdGhlIHZpZXdcbiAgICBBYnN0cmFjdERheUdyaWRWaWV3LnByb3RvdHlwZS51cGRhdGVCYXNlU2l6ZSA9IGZ1bmN0aW9uIChpc1Jlc2l6ZSwgdmlld0hlaWdodCwgaXNBdXRvKSB7XG4gICAgICAgIHZhciBkYXlHcmlkID0gdGhpcy5kYXlHcmlkO1xuICAgICAgICB2YXIgZXZlbnRMaW1pdCA9IHRoaXMuY29udGV4dC5vcHRpb25zLmV2ZW50TGltaXQ7XG4gICAgICAgIHZhciBoZWFkUm93RWwgPSB0aGlzLmhlYWRlciA/IHRoaXMuaGVhZGVyLmVsIDogbnVsbDsgLy8gSEFDS1xuICAgICAgICB2YXIgc2Nyb2xsZXJIZWlnaHQ7XG4gICAgICAgIHZhciBzY3JvbGxiYXJXaWR0aHM7XG4gICAgICAgIC8vIGhhY2sgdG8gZ2l2ZSB0aGUgdmlldyBzb21lIGhlaWdodCBwcmlvciB0byBkYXlHcmlkJ3MgY29sdW1ucyBiZWluZyByZW5kZXJlZFxuICAgICAgICAvLyBUT0RPOiBzZXBhcmF0ZSBzZXR0aW5nIGhlaWdodCBmcm9tIHNjcm9sbGVyIFZTIGRheUdyaWQuXG4gICAgICAgIGlmICghZGF5R3JpZC5yb3dFbHMpIHtcbiAgICAgICAgICAgIGlmICghaXNBdXRvKSB7XG4gICAgICAgICAgICAgICAgc2Nyb2xsZXJIZWlnaHQgPSB0aGlzLmNvbXB1dGVTY3JvbGxlckhlaWdodCh2aWV3SGVpZ2h0KTtcbiAgICAgICAgICAgICAgICB0aGlzLnNjcm9sbGVyLnNldEhlaWdodChzY3JvbGxlckhlaWdodCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuY29sV2Vla051bWJlcnNWaXNpYmxlKSB7XG4gICAgICAgICAgICAvLyBNYWtlIHN1cmUgYWxsIHdlZWsgbnVtYmVyIGNlbGxzIHJ1bm5pbmcgZG93biB0aGUgc2lkZSBoYXZlIHRoZSBzYW1lIHdpZHRoLlxuICAgICAgICAgICAgdGhpcy53ZWVrTnVtYmVyV2lkdGggPSBtYXRjaENlbGxXaWR0aHMoZmluZEVsZW1lbnRzKHRoaXMuZWwsICcuZmMtd2Vlay1udW1iZXInKSk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gcmVzZXQgYWxsIGhlaWdodHMgdG8gYmUgbmF0dXJhbFxuICAgICAgICB0aGlzLnNjcm9sbGVyLmNsZWFyKCk7XG4gICAgICAgIGlmIChoZWFkUm93RWwpIHtcbiAgICAgICAgICAgIHVuY29tcGVuc2F0ZVNjcm9sbChoZWFkUm93RWwpO1xuICAgICAgICB9XG4gICAgICAgIGRheUdyaWQucmVtb3ZlU2VnUG9wb3ZlcigpOyAvLyBraWxsIHRoZSBcIm1vcmVcIiBwb3BvdmVyIGlmIGRpc3BsYXllZFxuICAgICAgICAvLyBpcyB0aGUgZXZlbnQgbGltaXQgYSBjb25zdGFudCBsZXZlbCBudW1iZXI/XG4gICAgICAgIGlmIChldmVudExpbWl0ICYmIHR5cGVvZiBldmVudExpbWl0ID09PSAnbnVtYmVyJykge1xuICAgICAgICAgICAgZGF5R3JpZC5saW1pdFJvd3MoZXZlbnRMaW1pdCk7IC8vIGxpbWl0IHRoZSBsZXZlbHMgZmlyc3Qgc28gdGhlIGhlaWdodCBjYW4gcmVkaXN0cmlidXRlIGFmdGVyXG4gICAgICAgIH1cbiAgICAgICAgLy8gZGlzdHJpYnV0ZSB0aGUgaGVpZ2h0IHRvIHRoZSByb3dzXG4gICAgICAgIC8vICh2aWV3SGVpZ2h0IGlzIGEgXCJyZWNvbW1lbmRlZFwiIHZhbHVlIGlmIGlzQXV0bylcbiAgICAgICAgc2Nyb2xsZXJIZWlnaHQgPSB0aGlzLmNvbXB1dGVTY3JvbGxlckhlaWdodCh2aWV3SGVpZ2h0KTtcbiAgICAgICAgdGhpcy5zZXRHcmlkSGVpZ2h0KHNjcm9sbGVySGVpZ2h0LCBpc0F1dG8pO1xuICAgICAgICAvLyBpcyB0aGUgZXZlbnQgbGltaXQgZHluYW1pY2FsbHkgY2FsY3VsYXRlZD9cbiAgICAgICAgaWYgKGV2ZW50TGltaXQgJiYgdHlwZW9mIGV2ZW50TGltaXQgIT09ICdudW1iZXInKSB7XG4gICAgICAgICAgICBkYXlHcmlkLmxpbWl0Um93cyhldmVudExpbWl0KTsgLy8gbGltaXQgdGhlIGxldmVscyBhZnRlciB0aGUgZ3JpZCdzIHJvdyBoZWlnaHRzIGhhdmUgYmVlbiBzZXRcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWlzQXV0bykgeyAvLyBzaG91bGQgd2UgZm9yY2UgZGltZW5zaW9ucyBvZiB0aGUgc2Nyb2xsIGNvbnRhaW5lcj9cbiAgICAgICAgICAgIHRoaXMuc2Nyb2xsZXIuc2V0SGVpZ2h0KHNjcm9sbGVySGVpZ2h0KTtcbiAgICAgICAgICAgIHNjcm9sbGJhcldpZHRocyA9IHRoaXMuc2Nyb2xsZXIuZ2V0U2Nyb2xsYmFyV2lkdGhzKCk7XG4gICAgICAgICAgICBpZiAoc2Nyb2xsYmFyV2lkdGhzLmxlZnQgfHwgc2Nyb2xsYmFyV2lkdGhzLnJpZ2h0KSB7IC8vIHVzaW5nIHNjcm9sbGJhcnM/XG4gICAgICAgICAgICAgICAgaWYgKGhlYWRSb3dFbCkge1xuICAgICAgICAgICAgICAgICAgICBjb21wZW5zYXRlU2Nyb2xsKGhlYWRSb3dFbCwgc2Nyb2xsYmFyV2lkdGhzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gZG9pbmcgdGhlIHNjcm9sbGJhciBjb21wZW5zYXRpb24gbWlnaHQgaGF2ZSBjcmVhdGVkIHRleHQgb3ZlcmZsb3cgd2hpY2ggY3JlYXRlZCBtb3JlIGhlaWdodC4gcmVkb1xuICAgICAgICAgICAgICAgIHNjcm9sbGVySGVpZ2h0ID0gdGhpcy5jb21wdXRlU2Nyb2xsZXJIZWlnaHQodmlld0hlaWdodCk7XG4gICAgICAgICAgICAgICAgdGhpcy5zY3JvbGxlci5zZXRIZWlnaHQoc2Nyb2xsZXJIZWlnaHQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gZ3VhcmFudGVlcyB0aGUgc2FtZSBzY3JvbGxiYXIgd2lkdGhzXG4gICAgICAgICAgICB0aGlzLnNjcm9sbGVyLmxvY2tPdmVyZmxvdyhzY3JvbGxiYXJXaWR0aHMpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvLyBnaXZlbiBhIGRlc2lyZWQgdG90YWwgaGVpZ2h0IG9mIHRoZSB2aWV3LCByZXR1cm5zIHdoYXQgdGhlIGhlaWdodCBvZiB0aGUgc2Nyb2xsZXIgc2hvdWxkIGJlXG4gICAgQWJzdHJhY3REYXlHcmlkVmlldy5wcm90b3R5cGUuY29tcHV0ZVNjcm9sbGVySGVpZ2h0ID0gZnVuY3Rpb24gKHZpZXdIZWlnaHQpIHtcbiAgICAgICAgcmV0dXJuIHZpZXdIZWlnaHQgLVxuICAgICAgICAgICAgc3VidHJhY3RJbm5lckVsSGVpZ2h0KHRoaXMuZWwsIHRoaXMuc2Nyb2xsZXIuZWwpOyAvLyBldmVyeXRoaW5nIHRoYXQncyBOT1QgdGhlIHNjcm9sbGVyXG4gICAgfTtcbiAgICAvLyBTZXRzIHRoZSBoZWlnaHQgb2YganVzdCB0aGUgRGF5R3JpZCBjb21wb25lbnQgaW4gdGhpcyB2aWV3XG4gICAgQWJzdHJhY3REYXlHcmlkVmlldy5wcm90b3R5cGUuc2V0R3JpZEhlaWdodCA9IGZ1bmN0aW9uIChoZWlnaHQsIGlzQXV0bykge1xuICAgICAgICBpZiAodGhpcy5jb250ZXh0Lm9wdGlvbnMubW9udGhNb2RlKSB7XG4gICAgICAgICAgICAvLyBpZiBhdXRvLCBtYWtlIHRoZSBoZWlnaHQgb2YgZWFjaCByb3cgdGhlIGhlaWdodCB0aGF0IGl0IHdvdWxkIGJlIGlmIHRoZXJlIHdlcmUgNiB3ZWVrc1xuICAgICAgICAgICAgaWYgKGlzQXV0bykge1xuICAgICAgICAgICAgICAgIGhlaWdodCAqPSB0aGlzLmRheUdyaWQucm93Q250IC8gNjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRpc3RyaWJ1dGVIZWlnaHQodGhpcy5kYXlHcmlkLnJvd0VscywgaGVpZ2h0LCAhaXNBdXRvKTsgLy8gaWYgYXV0bywgZG9uJ3QgY29tcGVuc2F0ZSBmb3IgaGVpZ2h0LWhvZ2dpbmcgcm93c1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgaWYgKGlzQXV0bykge1xuICAgICAgICAgICAgICAgIHVuZGlzdHJpYnV0ZUhlaWdodCh0aGlzLmRheUdyaWQucm93RWxzKTsgLy8gbGV0IHRoZSByb3dzIGJlIHRoZWlyIG5hdHVyYWwgaGVpZ2h0IHdpdGggbm8gZXhwYW5kaW5nXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBkaXN0cmlidXRlSGVpZ2h0KHRoaXMuZGF5R3JpZC5yb3dFbHMsIGhlaWdodCwgdHJ1ZSk7IC8vIHRydWUgPSBjb21wZW5zYXRlIGZvciBoZWlnaHQtaG9nZ2luZyByb3dzXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qIFNjcm9sbFxuICAgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG4gICAgQWJzdHJhY3REYXlHcmlkVmlldy5wcm90b3R5cGUuY29tcHV0ZURhdGVTY3JvbGwgPSBmdW5jdGlvbiAoZHVyYXRpb24pIHtcbiAgICAgICAgcmV0dXJuIHsgdG9wOiAwIH07XG4gICAgfTtcbiAgICBBYnN0cmFjdERheUdyaWRWaWV3LnByb3RvdHlwZS5xdWVyeURhdGVTY3JvbGwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB7IHRvcDogdGhpcy5zY3JvbGxlci5nZXRTY3JvbGxUb3AoKSB9O1xuICAgIH07XG4gICAgQWJzdHJhY3REYXlHcmlkVmlldy5wcm90b3R5cGUuYXBwbHlEYXRlU2Nyb2xsID0gZnVuY3Rpb24gKHNjcm9sbCkge1xuICAgICAgICBpZiAoc2Nyb2xsLnRvcCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICB0aGlzLnNjcm9sbGVyLnNldFNjcm9sbFRvcChzY3JvbGwudG9wKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgcmV0dXJuIEFic3RyYWN0RGF5R3JpZFZpZXc7XG59KFZpZXcpKTtcbkFic3RyYWN0RGF5R3JpZFZpZXcucHJvdG90eXBlLmRhdGVQcm9maWxlR2VuZXJhdG9yQ2xhc3MgPSBEYXlHcmlkRGF0ZVByb2ZpbGVHZW5lcmF0b3I7XG5cbnZhciBTaW1wbGVEYXlHcmlkID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKF9zdXBlcikge1xuICAgIF9fZXh0ZW5kcyhTaW1wbGVEYXlHcmlkLCBfc3VwZXIpO1xuICAgIGZ1bmN0aW9uIFNpbXBsZURheUdyaWQoZGF5R3JpZCkge1xuICAgICAgICB2YXIgX3RoaXMgPSBfc3VwZXIuY2FsbCh0aGlzLCBkYXlHcmlkLmVsKSB8fCB0aGlzO1xuICAgICAgICBfdGhpcy5zbGljZXIgPSBuZXcgRGF5R3JpZFNsaWNlcigpO1xuICAgICAgICBfdGhpcy5kYXlHcmlkID0gZGF5R3JpZDtcbiAgICAgICAgcmV0dXJuIF90aGlzO1xuICAgIH1cbiAgICBTaW1wbGVEYXlHcmlkLnByb3RvdHlwZS5maXJzdENvbnRleHQgPSBmdW5jdGlvbiAoY29udGV4dCkge1xuICAgICAgICBjb250ZXh0LmNhbGVuZGFyLnJlZ2lzdGVySW50ZXJhY3RpdmVDb21wb25lbnQodGhpcywgeyBlbDogdGhpcy5kYXlHcmlkLmVsIH0pO1xuICAgIH07XG4gICAgU2ltcGxlRGF5R3JpZC5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgX3N1cGVyLnByb3RvdHlwZS5kZXN0cm95LmNhbGwodGhpcyk7XG4gICAgICAgIHRoaXMuY29udGV4dC5jYWxlbmRhci51bnJlZ2lzdGVySW50ZXJhY3RpdmVDb21wb25lbnQodGhpcyk7XG4gICAgfTtcbiAgICBTaW1wbGVEYXlHcmlkLnByb3RvdHlwZS5yZW5kZXIgPSBmdW5jdGlvbiAocHJvcHMsIGNvbnRleHQpIHtcbiAgICAgICAgdmFyIGRheUdyaWQgPSB0aGlzLmRheUdyaWQ7XG4gICAgICAgIHZhciBkYXRlUHJvZmlsZSA9IHByb3BzLmRhdGVQcm9maWxlLCBkYXlUYWJsZSA9IHByb3BzLmRheVRhYmxlO1xuICAgICAgICBkYXlHcmlkLnJlY2VpdmVQcm9wcyhfX2Fzc2lnbih7fSwgdGhpcy5zbGljZXIuc2xpY2VQcm9wcyhwcm9wcywgZGF0ZVByb2ZpbGUsIHByb3BzLm5leHREYXlUaHJlc2hvbGQsIGNvbnRleHQuY2FsZW5kYXIsIGRheUdyaWQsIGRheVRhYmxlKSwgeyBkYXRlUHJvZmlsZTogZGF0ZVByb2ZpbGUsIGNlbGxzOiBkYXlUYWJsZS5jZWxscywgaXNSaWdpZDogcHJvcHMuaXNSaWdpZCB9KSwgY29udGV4dCk7XG4gICAgfTtcbiAgICBTaW1wbGVEYXlHcmlkLnByb3RvdHlwZS5idWlsZFBvc2l0aW9uQ2FjaGVzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLmRheUdyaWQuYnVpbGRQb3NpdGlvbkNhY2hlcygpO1xuICAgIH07XG4gICAgU2ltcGxlRGF5R3JpZC5wcm90b3R5cGUucXVlcnlIaXQgPSBmdW5jdGlvbiAocG9zaXRpb25MZWZ0LCBwb3NpdGlvblRvcCkge1xuICAgICAgICB2YXIgcmF3SGl0ID0gdGhpcy5kYXlHcmlkLnBvc2l0aW9uVG9IaXQocG9zaXRpb25MZWZ0LCBwb3NpdGlvblRvcCk7XG4gICAgICAgIGlmIChyYXdIaXQpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgY29tcG9uZW50OiB0aGlzLmRheUdyaWQsXG4gICAgICAgICAgICAgICAgZGF0ZVNwYW46IHJhd0hpdC5kYXRlU3BhbixcbiAgICAgICAgICAgICAgICBkYXlFbDogcmF3SGl0LmRheUVsLFxuICAgICAgICAgICAgICAgIHJlY3Q6IHtcbiAgICAgICAgICAgICAgICAgICAgbGVmdDogcmF3SGl0LnJlbGF0aXZlUmVjdC5sZWZ0LFxuICAgICAgICAgICAgICAgICAgICByaWdodDogcmF3SGl0LnJlbGF0aXZlUmVjdC5yaWdodCxcbiAgICAgICAgICAgICAgICAgICAgdG9wOiByYXdIaXQucmVsYXRpdmVSZWN0LnRvcCxcbiAgICAgICAgICAgICAgICAgICAgYm90dG9tOiByYXdIaXQucmVsYXRpdmVSZWN0LmJvdHRvbVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgbGF5ZXI6IDBcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9O1xuICAgIHJldHVybiBTaW1wbGVEYXlHcmlkO1xufShEYXRlQ29tcG9uZW50KSk7XG52YXIgRGF5R3JpZFNsaWNlciA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uIChfc3VwZXIpIHtcbiAgICBfX2V4dGVuZHMoRGF5R3JpZFNsaWNlciwgX3N1cGVyKTtcbiAgICBmdW5jdGlvbiBEYXlHcmlkU2xpY2VyKCkge1xuICAgICAgICByZXR1cm4gX3N1cGVyICE9PSBudWxsICYmIF9zdXBlci5hcHBseSh0aGlzLCBhcmd1bWVudHMpIHx8IHRoaXM7XG4gICAgfVxuICAgIERheUdyaWRTbGljZXIucHJvdG90eXBlLnNsaWNlUmFuZ2UgPSBmdW5jdGlvbiAoZGF0ZVJhbmdlLCBkYXlUYWJsZSkge1xuICAgICAgICByZXR1cm4gZGF5VGFibGUuc2xpY2VSYW5nZShkYXRlUmFuZ2UpO1xuICAgIH07XG4gICAgcmV0dXJuIERheUdyaWRTbGljZXI7XG59KFNsaWNlcikpO1xuXG52YXIgRGF5R3JpZFZpZXcgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoX3N1cGVyKSB7XG4gICAgX19leHRlbmRzKERheUdyaWRWaWV3LCBfc3VwZXIpO1xuICAgIGZ1bmN0aW9uIERheUdyaWRWaWV3KCkge1xuICAgICAgICB2YXIgX3RoaXMgPSBfc3VwZXIgIT09IG51bGwgJiYgX3N1cGVyLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykgfHwgdGhpcztcbiAgICAgICAgX3RoaXMuYnVpbGREYXlUYWJsZSA9IG1lbW9pemUoYnVpbGREYXlUYWJsZSk7XG4gICAgICAgIHJldHVybiBfdGhpcztcbiAgICB9XG4gICAgRGF5R3JpZFZpZXcucHJvdG90eXBlLnJlbmRlciA9IGZ1bmN0aW9uIChwcm9wcywgY29udGV4dCkge1xuICAgICAgICBfc3VwZXIucHJvdG90eXBlLnJlbmRlci5jYWxsKHRoaXMsIHByb3BzLCBjb250ZXh0KTsgLy8gd2lsbCBjYWxsIF9yZW5kZXJTa2VsZXRvbi9fdW5yZW5kZXJTa2VsZXRvblxuICAgICAgICB2YXIgZGF0ZVByb2ZpbGUgPSB0aGlzLnByb3BzLmRhdGVQcm9maWxlO1xuICAgICAgICB2YXIgZGF5VGFibGUgPSB0aGlzLmRheVRhYmxlID1cbiAgICAgICAgICAgIHRoaXMuYnVpbGREYXlUYWJsZShkYXRlUHJvZmlsZSwgcHJvcHMuZGF0ZVByb2ZpbGVHZW5lcmF0b3IpO1xuICAgICAgICBpZiAodGhpcy5oZWFkZXIpIHtcbiAgICAgICAgICAgIHRoaXMuaGVhZGVyLnJlY2VpdmVQcm9wcyh7XG4gICAgICAgICAgICAgICAgZGF0ZVByb2ZpbGU6IGRhdGVQcm9maWxlLFxuICAgICAgICAgICAgICAgIGRhdGVzOiBkYXlUYWJsZS5oZWFkZXJEYXRlcyxcbiAgICAgICAgICAgICAgICBkYXRlc1JlcERpc3RpbmN0RGF5czogZGF5VGFibGUucm93Q250ID09PSAxLFxuICAgICAgICAgICAgICAgIHJlbmRlckludHJvSHRtbDogdGhpcy5yZW5kZXJIZWFkSW50cm9IdG1sXG4gICAgICAgICAgICB9LCBjb250ZXh0KTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnNpbXBsZURheUdyaWQucmVjZWl2ZVByb3BzKHtcbiAgICAgICAgICAgIGRhdGVQcm9maWxlOiBkYXRlUHJvZmlsZSxcbiAgICAgICAgICAgIGRheVRhYmxlOiBkYXlUYWJsZSxcbiAgICAgICAgICAgIGJ1c2luZXNzSG91cnM6IHByb3BzLmJ1c2luZXNzSG91cnMsXG4gICAgICAgICAgICBkYXRlU2VsZWN0aW9uOiBwcm9wcy5kYXRlU2VsZWN0aW9uLFxuICAgICAgICAgICAgZXZlbnRTdG9yZTogcHJvcHMuZXZlbnRTdG9yZSxcbiAgICAgICAgICAgIGV2ZW50VWlCYXNlczogcHJvcHMuZXZlbnRVaUJhc2VzLFxuICAgICAgICAgICAgZXZlbnRTZWxlY3Rpb246IHByb3BzLmV2ZW50U2VsZWN0aW9uLFxuICAgICAgICAgICAgZXZlbnREcmFnOiBwcm9wcy5ldmVudERyYWcsXG4gICAgICAgICAgICBldmVudFJlc2l6ZTogcHJvcHMuZXZlbnRSZXNpemUsXG4gICAgICAgICAgICBpc1JpZ2lkOiB0aGlzLmhhc1JpZ2lkUm93cygpLFxuICAgICAgICAgICAgbmV4dERheVRocmVzaG9sZDogdGhpcy5jb250ZXh0Lm5leHREYXlUaHJlc2hvbGRcbiAgICAgICAgfSwgY29udGV4dCk7XG4gICAgfTtcbiAgICBEYXlHcmlkVmlldy5wcm90b3R5cGUuX3JlbmRlclNrZWxldG9uID0gZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICAgICAgX3N1cGVyLnByb3RvdHlwZS5fcmVuZGVyU2tlbGV0b24uY2FsbCh0aGlzLCBjb250ZXh0KTtcbiAgICAgICAgaWYgKGNvbnRleHQub3B0aW9ucy5jb2x1bW5IZWFkZXIpIHtcbiAgICAgICAgICAgIHRoaXMuaGVhZGVyID0gbmV3IERheUhlYWRlcih0aGlzLmVsLnF1ZXJ5U2VsZWN0b3IoJy5mYy1oZWFkLWNvbnRhaW5lcicpKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnNpbXBsZURheUdyaWQgPSBuZXcgU2ltcGxlRGF5R3JpZCh0aGlzLmRheUdyaWQpO1xuICAgIH07XG4gICAgRGF5R3JpZFZpZXcucHJvdG90eXBlLl91bnJlbmRlclNrZWxldG9uID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBfc3VwZXIucHJvdG90eXBlLl91bnJlbmRlclNrZWxldG9uLmNhbGwodGhpcyk7XG4gICAgICAgIGlmICh0aGlzLmhlYWRlcikge1xuICAgICAgICAgICAgdGhpcy5oZWFkZXIuZGVzdHJveSgpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuc2ltcGxlRGF5R3JpZC5kZXN0cm95KCk7XG4gICAgfTtcbiAgICByZXR1cm4gRGF5R3JpZFZpZXc7XG59KEFic3RyYWN0RGF5R3JpZFZpZXcpKTtcbmZ1bmN0aW9uIGJ1aWxkRGF5VGFibGUoZGF0ZVByb2ZpbGUsIGRhdGVQcm9maWxlR2VuZXJhdG9yKSB7XG4gICAgdmFyIGRheVNlcmllcyA9IG5ldyBEYXlTZXJpZXMoZGF0ZVByb2ZpbGUucmVuZGVyUmFuZ2UsIGRhdGVQcm9maWxlR2VuZXJhdG9yKTtcbiAgICByZXR1cm4gbmV3IERheVRhYmxlKGRheVNlcmllcywgL3llYXJ8bW9udGh8d2Vlay8udGVzdChkYXRlUHJvZmlsZS5jdXJyZW50UmFuZ2VVbml0KSk7XG59XG5cbnZhciBtYWluID0gY3JlYXRlUGx1Z2luKHtcbiAgICBkZWZhdWx0VmlldzogJ2RheUdyaWRNb250aCcsXG4gICAgdmlld3M6IHtcbiAgICAgICAgZGF5R3JpZDogRGF5R3JpZFZpZXcsXG4gICAgICAgIGRheUdyaWREYXk6IHtcbiAgICAgICAgICAgIHR5cGU6ICdkYXlHcmlkJyxcbiAgICAgICAgICAgIGR1cmF0aW9uOiB7IGRheXM6IDEgfVxuICAgICAgICB9LFxuICAgICAgICBkYXlHcmlkV2Vlazoge1xuICAgICAgICAgICAgdHlwZTogJ2RheUdyaWQnLFxuICAgICAgICAgICAgZHVyYXRpb246IHsgd2Vla3M6IDEgfVxuICAgICAgICB9LFxuICAgICAgICBkYXlHcmlkTW9udGg6IHtcbiAgICAgICAgICAgIHR5cGU6ICdkYXlHcmlkJyxcbiAgICAgICAgICAgIGR1cmF0aW9uOiB7IG1vbnRoczogMSB9LFxuICAgICAgICAgICAgbW9udGhNb2RlOiB0cnVlLFxuICAgICAgICAgICAgZml4ZWRXZWVrQ291bnQ6IHRydWVcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG5leHBvcnQgZGVmYXVsdCBtYWluO1xuZXhwb3J0IHsgQWJzdHJhY3REYXlHcmlkVmlldywgRGF5QmdSb3csIERheUdyaWQsIERheUdyaWRTbGljZXIsIERheUdyaWRWaWV3LCBTaW1wbGVEYXlHcmlkLCBidWlsZERheVRhYmxlIGFzIGJ1aWxkQmFzaWNEYXlUYWJsZSB9O1xuIiwiLyohXG5GdWxsQ2FsZW5kYXIgSW50ZXJhY3Rpb24gUGx1Z2luIHY0LjQuMFxuRG9jcyAmIExpY2Vuc2U6IGh0dHBzOi8vZnVsbGNhbGVuZGFyLmlvL1xuKGMpIDIwMTkgQWRhbSBTaGF3XG4qL1xuXG5pbXBvcnQgeyBjb25maWcsIGVsZW1lbnRDbG9zZXN0LCBFbWl0dGVyTWl4aW4sIGFwcGx5U3R5bGUsIHdoZW5UcmFuc2l0aW9uRG9uZSwgcmVtb3ZlRWxlbWVudCwgU2Nyb2xsQ29udHJvbGxlciwgRWxlbWVudFNjcm9sbENvbnRyb2xsZXIsIGNvbXB1dGVJbm5lclJlY3QsIFdpbmRvd1Njcm9sbENvbnRyb2xsZXIsIHByZXZlbnRTZWxlY3Rpb24sIHByZXZlbnRDb250ZXh0TWVudSwgYWxsb3dTZWxlY3Rpb24sIGFsbG93Q29udGV4dE1lbnUsIEVsZW1lbnREcmFnZ2luZywgY29tcHV0ZVJlY3QsIGdldENsaXBwaW5nUGFyZW50cywgcG9pbnRJbnNpZGVSZWN0LCBpc0RhdGVTcGFuc0VxdWFsLCBjb25zdHJhaW5Qb2ludCwgaW50ZXJzZWN0UmVjdHMsIGdldFJlY3RDZW50ZXIsIGRpZmZQb2ludHMsIG1hcEhhc2gsIHJhbmdlQ29udGFpbnNSYW5nZSwgaW50ZXJhY3Rpb25TZXR0aW5nc1RvU3RvcmUsIEludGVyYWN0aW9uLCBlbmFibGVDdXJzb3IsIGRpc2FibGVDdXJzb3IsIGNvbXBhcmVOdW1iZXJzLCBnZXRFbFNlZywgZ2V0UmVsZXZhbnRFdmVudHMsIEV2ZW50QXBpLCBjcmVhdGVFbXB0eUV2ZW50U3RvcmUsIGFwcGx5TXV0YXRpb25Ub0V2ZW50U3RvcmUsIGludGVyYWN0aW9uU2V0dGluZ3NTdG9yZSwgc3RhcnRPZkRheSwgZGlmZkRhdGVzLCBjcmVhdGVEdXJhdGlvbiwgZXZlbnRUdXBsZVRvU3RvcmUsIGlzSW50ZXJhY3Rpb25WYWxpZCwgcGFyc2VEcmFnTWV0YSwgZWxlbWVudE1hdGNoZXMsIHBhcnNlRXZlbnREZWYsIGNyZWF0ZUV2ZW50SW5zdGFuY2UsIGdsb2JhbERlZmF1bHRzLCBjcmVhdGVQbHVnaW4gfSBmcm9tICdAZnVsbGNhbGVuZGFyL2NvcmUnO1xuXG4vKiEgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXHJcbkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7IHlvdSBtYXkgbm90IHVzZVxyXG50aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4gWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZVxyXG5MaWNlbnNlIGF0IGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxyXG5cclxuVEhJUyBDT0RFIElTIFBST1ZJREVEIE9OIEFOICpBUyBJUyogQkFTSVMsIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWVxyXG5LSU5ELCBFSVRIRVIgRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJTkcgV0lUSE9VVCBMSU1JVEFUSU9OIEFOWSBJTVBMSUVEXHJcbldBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBUSVRMRSwgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UsXHJcbk1FUkNIQU5UQUJMSVRZIE9SIE5PTi1JTkZSSU5HRU1FTlQuXHJcblxyXG5TZWUgdGhlIEFwYWNoZSBWZXJzaW9uIDIuMCBMaWNlbnNlIGZvciBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnNcclxuYW5kIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiAqL1xyXG4vKiBnbG9iYWwgUmVmbGVjdCwgUHJvbWlzZSAqL1xyXG5cclxudmFyIGV4dGVuZFN0YXRpY3MgPSBmdW5jdGlvbihkLCBiKSB7XHJcbiAgICBleHRlbmRTdGF0aWNzID0gT2JqZWN0LnNldFByb3RvdHlwZU9mIHx8XHJcbiAgICAgICAgKHsgX19wcm90b19fOiBbXSB9IGluc3RhbmNlb2YgQXJyYXkgJiYgZnVuY3Rpb24gKGQsIGIpIHsgZC5fX3Byb3RvX18gPSBiOyB9KSB8fFxyXG4gICAgICAgIGZ1bmN0aW9uIChkLCBiKSB7IGZvciAodmFyIHAgaW4gYikgaWYgKGIuaGFzT3duUHJvcGVydHkocCkpIGRbcF0gPSBiW3BdOyB9O1xyXG4gICAgcmV0dXJuIGV4dGVuZFN0YXRpY3MoZCwgYik7XHJcbn07XHJcblxyXG5mdW5jdGlvbiBfX2V4dGVuZHMoZCwgYikge1xyXG4gICAgZXh0ZW5kU3RhdGljcyhkLCBiKTtcclxuICAgIGZ1bmN0aW9uIF9fKCkgeyB0aGlzLmNvbnN0cnVjdG9yID0gZDsgfVxyXG4gICAgZC5wcm90b3R5cGUgPSBiID09PSBudWxsID8gT2JqZWN0LmNyZWF0ZShiKSA6IChfXy5wcm90b3R5cGUgPSBiLnByb3RvdHlwZSwgbmV3IF9fKCkpO1xyXG59XHJcblxyXG52YXIgX19hc3NpZ24gPSBmdW5jdGlvbigpIHtcclxuICAgIF9fYXNzaWduID0gT2JqZWN0LmFzc2lnbiB8fCBmdW5jdGlvbiBfX2Fzc2lnbih0KSB7XHJcbiAgICAgICAgZm9yICh2YXIgcywgaSA9IDEsIG4gPSBhcmd1bWVudHMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XHJcbiAgICAgICAgICAgIHMgPSBhcmd1bWVudHNbaV07XHJcbiAgICAgICAgICAgIGZvciAodmFyIHAgaW4gcykgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzLCBwKSkgdFtwXSA9IHNbcF07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0O1xyXG4gICAgfTtcclxuICAgIHJldHVybiBfX2Fzc2lnbi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xyXG59O1xuXG5jb25maWcudG91Y2hNb3VzZUlnbm9yZVdhaXQgPSA1MDA7XG52YXIgaWdub3JlTW91c2VEZXB0aCA9IDA7XG52YXIgbGlzdGVuZXJDbnQgPSAwO1xudmFyIGlzV2luZG93VG91Y2hNb3ZlQ2FuY2VsbGVkID0gZmFsc2U7XG4vKlxuVXNlcyBhIFwicG9pbnRlclwiIGFic3RyYWN0aW9uLCB3aGljaCBtb25pdG9ycyBVSSBldmVudHMgZm9yIGJvdGggbW91c2UgYW5kIHRvdWNoLlxuVHJhY2tzIHdoZW4gdGhlIHBvaW50ZXIgXCJkcmFnc1wiIG9uIGEgY2VydGFpbiBlbGVtZW50LCBtZWFuaW5nIGRvd24rbW92ZSt1cC5cblxuQWxzbywgdHJhY2tzIGlmIHRoZXJlIHdhcyB0b3VjaC1zY3JvbGxpbmcuXG5BbHNvLCBjYW4gcHJldmVudCB0b3VjaC1zY3JvbGxpbmcgZnJvbSBoYXBwZW5pbmcuXG5BbHNvLCBjYW4gZmlyZSBwb2ludGVybW92ZSBldmVudHMgd2hlbiBzY3JvbGxpbmcgaGFwcGVucyB1bmRlcm5lYXRoLCBldmVuIHdoZW4gbm8gcmVhbCBwb2ludGVyIG1vdmVtZW50LlxuXG5lbWl0czpcbi0gcG9pbnRlcmRvd25cbi0gcG9pbnRlcm1vdmVcbi0gcG9pbnRlcnVwXG4qL1xudmFyIFBvaW50ZXJEcmFnZ2luZyA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBQb2ludGVyRHJhZ2dpbmcoY29udGFpbmVyRWwpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdGhpcy5zdWJqZWN0RWwgPSBudWxsO1xuICAgICAgICB0aGlzLmRvd25FbCA9IG51bGw7XG4gICAgICAgIC8vIG9wdGlvbnMgdGhhdCBjYW4gYmUgZGlyZWN0bHkgYXNzaWduZWQgYnkgY2FsbGVyXG4gICAgICAgIHRoaXMuc2VsZWN0b3IgPSAnJzsgLy8gd2lsbCBjYXVzZSBzdWJqZWN0RWwgaW4gYWxsIGVtaXR0ZWQgZXZlbnRzIHRvIGJlIHRoaXMgZWxlbWVudFxuICAgICAgICB0aGlzLmhhbmRsZVNlbGVjdG9yID0gJyc7XG4gICAgICAgIHRoaXMuc2hvdWxkSWdub3JlTW92ZSA9IGZhbHNlO1xuICAgICAgICB0aGlzLnNob3VsZFdhdGNoU2Nyb2xsID0gdHJ1ZTsgLy8gZm9yIHNpbXVsYXRpbmcgcG9pbnRlcm1vdmUgb24gc2Nyb2xsXG4gICAgICAgIC8vIGludGVybmFsIHN0YXRlc1xuICAgICAgICB0aGlzLmlzRHJhZ2dpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5pc1RvdWNoRHJhZ2dpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy53YXNUb3VjaFNjcm9sbCA9IGZhbHNlO1xuICAgICAgICAvLyBNb3VzZVxuICAgICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgICAgIHRoaXMuaGFuZGxlTW91c2VEb3duID0gZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICBpZiAoIV90aGlzLnNob3VsZElnbm9yZU1vdXNlKCkgJiZcbiAgICAgICAgICAgICAgICBpc1ByaW1hcnlNb3VzZUJ1dHRvbihldikgJiZcbiAgICAgICAgICAgICAgICBfdGhpcy50cnlTdGFydChldikpIHtcbiAgICAgICAgICAgICAgICB2YXIgcGV2ID0gX3RoaXMuY3JlYXRlRXZlbnRGcm9tTW91c2UoZXYsIHRydWUpO1xuICAgICAgICAgICAgICAgIF90aGlzLmVtaXR0ZXIudHJpZ2dlcigncG9pbnRlcmRvd24nLCBwZXYpO1xuICAgICAgICAgICAgICAgIF90aGlzLmluaXRTY3JvbGxXYXRjaChwZXYpO1xuICAgICAgICAgICAgICAgIGlmICghX3RoaXMuc2hvdWxkSWdub3JlTW92ZSkge1xuICAgICAgICAgICAgICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZW1vdmUnLCBfdGhpcy5oYW5kbGVNb3VzZU1vdmUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgX3RoaXMuaGFuZGxlTW91c2VVcCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlTW91c2VNb3ZlID0gZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICB2YXIgcGV2ID0gX3RoaXMuY3JlYXRlRXZlbnRGcm9tTW91c2UoZXYpO1xuICAgICAgICAgICAgX3RoaXMucmVjb3JkQ29vcmRzKHBldik7XG4gICAgICAgICAgICBfdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ3BvaW50ZXJtb3ZlJywgcGV2KTtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVNb3VzZVVwID0gZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdtb3VzZW1vdmUnLCBfdGhpcy5oYW5kbGVNb3VzZU1vdmUpO1xuICAgICAgICAgICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsIF90aGlzLmhhbmRsZU1vdXNlVXApO1xuICAgICAgICAgICAgX3RoaXMuZW1pdHRlci50cmlnZ2VyKCdwb2ludGVydXAnLCBfdGhpcy5jcmVhdGVFdmVudEZyb21Nb3VzZShldikpO1xuICAgICAgICAgICAgX3RoaXMuY2xlYW51cCgpOyAvLyBjYWxsIGxhc3Qgc28gdGhhdCBwb2ludGVydXAgaGFzIGFjY2VzcyB0byBwcm9wc1xuICAgICAgICB9O1xuICAgICAgICAvLyBUb3VjaFxuICAgICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgICAgIHRoaXMuaGFuZGxlVG91Y2hTdGFydCA9IGZ1bmN0aW9uIChldikge1xuICAgICAgICAgICAgaWYgKF90aGlzLnRyeVN0YXJ0KGV2KSkge1xuICAgICAgICAgICAgICAgIF90aGlzLmlzVG91Y2hEcmFnZ2luZyA9IHRydWU7XG4gICAgICAgICAgICAgICAgdmFyIHBldiA9IF90aGlzLmNyZWF0ZUV2ZW50RnJvbVRvdWNoKGV2LCB0cnVlKTtcbiAgICAgICAgICAgICAgICBfdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ3BvaW50ZXJkb3duJywgcGV2KTtcbiAgICAgICAgICAgICAgICBfdGhpcy5pbml0U2Nyb2xsV2F0Y2gocGV2KTtcbiAgICAgICAgICAgICAgICAvLyB1bmxpa2UgbW91c2UsIG5lZWQgdG8gYXR0YWNoIHRvIHRhcmdldCwgbm90IGRvY3VtZW50XG4gICAgICAgICAgICAgICAgLy8gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9hLzQ1NzYwMDE0XG4gICAgICAgICAgICAgICAgdmFyIHRhcmdldCA9IGV2LnRhcmdldDtcbiAgICAgICAgICAgICAgICBpZiAoIV90aGlzLnNob3VsZElnbm9yZU1vdmUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGFyZ2V0LmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNobW92ZScsIF90aGlzLmhhbmRsZVRvdWNoTW92ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRhcmdldC5hZGRFdmVudExpc3RlbmVyKCd0b3VjaGVuZCcsIF90aGlzLmhhbmRsZVRvdWNoRW5kKTtcbiAgICAgICAgICAgICAgICB0YXJnZXQuYWRkRXZlbnRMaXN0ZW5lcigndG91Y2hjYW5jZWwnLCBfdGhpcy5oYW5kbGVUb3VjaEVuZCk7IC8vIHRyZWF0IGl0IGFzIGEgdG91Y2ggZW5kXG4gICAgICAgICAgICAgICAgLy8gYXR0YWNoIGEgaGFuZGxlciB0byBnZXQgY2FsbGVkIHdoZW4gQU5ZIHNjcm9sbCBhY3Rpb24gaGFwcGVucyBvbiB0aGUgcGFnZS5cbiAgICAgICAgICAgICAgICAvLyB0aGlzIHdhcyBpbXBvc3NpYmxlIHRvIGRvIHdpdGggbm9ybWFsIG9uL29mZiBiZWNhdXNlICdzY3JvbGwnIGRvZXNuJ3QgYnViYmxlLlxuICAgICAgICAgICAgICAgIC8vIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9hLzMyOTU0NTY1Lzk2MzQyXG4gICAgICAgICAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Njcm9sbCcsIF90aGlzLmhhbmRsZVRvdWNoU2Nyb2xsLCB0cnVlIC8vIHVzZUNhcHR1cmVcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZVRvdWNoTW92ZSA9IGZ1bmN0aW9uIChldikge1xuICAgICAgICAgICAgdmFyIHBldiA9IF90aGlzLmNyZWF0ZUV2ZW50RnJvbVRvdWNoKGV2KTtcbiAgICAgICAgICAgIF90aGlzLnJlY29yZENvb3JkcyhwZXYpO1xuICAgICAgICAgICAgX3RoaXMuZW1pdHRlci50cmlnZ2VyKCdwb2ludGVybW92ZScsIHBldik7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlVG91Y2hFbmQgPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgICAgIGlmIChfdGhpcy5pc0RyYWdnaW5nKSB7IC8vIGRvbmUgdG8gZ3VhcmQgYWdhaW5zdCB0b3VjaGVuZCBmb2xsb3dlZCBieSB0b3VjaGNhbmNlbFxuICAgICAgICAgICAgICAgIHZhciB0YXJnZXQgPSBldi50YXJnZXQ7XG4gICAgICAgICAgICAgICAgdGFyZ2V0LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNobW92ZScsIF90aGlzLmhhbmRsZVRvdWNoTW92ZSk7XG4gICAgICAgICAgICAgICAgdGFyZ2V0LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNoZW5kJywgX3RoaXMuaGFuZGxlVG91Y2hFbmQpO1xuICAgICAgICAgICAgICAgIHRhcmdldC5yZW1vdmVFdmVudExpc3RlbmVyKCd0b3VjaGNhbmNlbCcsIF90aGlzLmhhbmRsZVRvdWNoRW5kKTtcbiAgICAgICAgICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcignc2Nyb2xsJywgX3RoaXMuaGFuZGxlVG91Y2hTY3JvbGwsIHRydWUpOyAvLyB1c2VDYXB0dXJlZD10cnVlXG4gICAgICAgICAgICAgICAgX3RoaXMuZW1pdHRlci50cmlnZ2VyKCdwb2ludGVydXAnLCBfdGhpcy5jcmVhdGVFdmVudEZyb21Ub3VjaChldikpO1xuICAgICAgICAgICAgICAgIF90aGlzLmNsZWFudXAoKTsgLy8gY2FsbCBsYXN0IHNvIHRoYXQgcG9pbnRlcnVwIGhhcyBhY2Nlc3MgdG8gcHJvcHNcbiAgICAgICAgICAgICAgICBfdGhpcy5pc1RvdWNoRHJhZ2dpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBzdGFydElnbm9yaW5nTW91c2UoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVUb3VjaFNjcm9sbCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIF90aGlzLndhc1RvdWNoU2Nyb2xsID0gdHJ1ZTtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVTY3JvbGwgPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgICAgIGlmICghX3RoaXMuc2hvdWxkSWdub3JlTW92ZSkge1xuICAgICAgICAgICAgICAgIHZhciBwYWdlWCA9ICh3aW5kb3cucGFnZVhPZmZzZXQgLSBfdGhpcy5wcmV2U2Nyb2xsWCkgKyBfdGhpcy5wcmV2UGFnZVg7XG4gICAgICAgICAgICAgICAgdmFyIHBhZ2VZID0gKHdpbmRvdy5wYWdlWU9mZnNldCAtIF90aGlzLnByZXZTY3JvbGxZKSArIF90aGlzLnByZXZQYWdlWTtcbiAgICAgICAgICAgICAgICBfdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ3BvaW50ZXJtb3ZlJywge1xuICAgICAgICAgICAgICAgICAgICBvcmlnRXZlbnQ6IGV2LFxuICAgICAgICAgICAgICAgICAgICBpc1RvdWNoOiBfdGhpcy5pc1RvdWNoRHJhZ2dpbmcsXG4gICAgICAgICAgICAgICAgICAgIHN1YmplY3RFbDogX3RoaXMuc3ViamVjdEVsLFxuICAgICAgICAgICAgICAgICAgICBwYWdlWDogcGFnZVgsXG4gICAgICAgICAgICAgICAgICAgIHBhZ2VZOiBwYWdlWSxcbiAgICAgICAgICAgICAgICAgICAgZGVsdGFYOiBwYWdlWCAtIF90aGlzLm9yaWdQYWdlWCxcbiAgICAgICAgICAgICAgICAgICAgZGVsdGFZOiBwYWdlWSAtIF90aGlzLm9yaWdQYWdlWVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICB0aGlzLmNvbnRhaW5lckVsID0gY29udGFpbmVyRWw7XG4gICAgICAgIHRoaXMuZW1pdHRlciA9IG5ldyBFbWl0dGVyTWl4aW4oKTtcbiAgICAgICAgY29udGFpbmVyRWwuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgdGhpcy5oYW5kbGVNb3VzZURvd24pO1xuICAgICAgICBjb250YWluZXJFbC5hZGRFdmVudExpc3RlbmVyKCd0b3VjaHN0YXJ0JywgdGhpcy5oYW5kbGVUb3VjaFN0YXJ0LCB7IHBhc3NpdmU6IHRydWUgfSk7XG4gICAgICAgIGxpc3RlbmVyQ3JlYXRlZCgpO1xuICAgIH1cbiAgICBQb2ludGVyRHJhZ2dpbmcucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuY29udGFpbmVyRWwucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgdGhpcy5oYW5kbGVNb3VzZURvd24pO1xuICAgICAgICB0aGlzLmNvbnRhaW5lckVsLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNoc3RhcnQnLCB0aGlzLmhhbmRsZVRvdWNoU3RhcnQsIHsgcGFzc2l2ZTogdHJ1ZSB9KTtcbiAgICAgICAgbGlzdGVuZXJEZXN0cm95ZWQoKTtcbiAgICB9O1xuICAgIFBvaW50ZXJEcmFnZ2luZy5wcm90b3R5cGUudHJ5U3RhcnQgPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgdmFyIHN1YmplY3RFbCA9IHRoaXMucXVlcnlTdWJqZWN0RWwoZXYpO1xuICAgICAgICB2YXIgZG93bkVsID0gZXYudGFyZ2V0O1xuICAgICAgICBpZiAoc3ViamVjdEVsICYmXG4gICAgICAgICAgICAoIXRoaXMuaGFuZGxlU2VsZWN0b3IgfHwgZWxlbWVudENsb3Nlc3QoZG93bkVsLCB0aGlzLmhhbmRsZVNlbGVjdG9yKSkpIHtcbiAgICAgICAgICAgIHRoaXMuc3ViamVjdEVsID0gc3ViamVjdEVsO1xuICAgICAgICAgICAgdGhpcy5kb3duRWwgPSBkb3duRWw7XG4gICAgICAgICAgICB0aGlzLmlzRHJhZ2dpbmcgPSB0cnVlOyAvLyBkbyB0aGlzIGZpcnN0IHNvIGNhbmNlbFRvdWNoU2Nyb2xsIHdpbGwgd29ya1xuICAgICAgICAgICAgdGhpcy53YXNUb3VjaFNjcm9sbCA9IGZhbHNlO1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH07XG4gICAgUG9pbnRlckRyYWdnaW5nLnByb3RvdHlwZS5jbGVhbnVwID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpc1dpbmRvd1RvdWNoTW92ZUNhbmNlbGxlZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLmlzRHJhZ2dpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5zdWJqZWN0RWwgPSBudWxsO1xuICAgICAgICB0aGlzLmRvd25FbCA9IG51bGw7XG4gICAgICAgIC8vIGtlZXAgd2FzVG91Y2hTY3JvbGwgYXJvdW5kIGZvciBsYXRlciBhY2Nlc3NcbiAgICAgICAgdGhpcy5kZXN0cm95U2Nyb2xsV2F0Y2goKTtcbiAgICB9O1xuICAgIFBvaW50ZXJEcmFnZ2luZy5wcm90b3R5cGUucXVlcnlTdWJqZWN0RWwgPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgaWYgKHRoaXMuc2VsZWN0b3IpIHtcbiAgICAgICAgICAgIHJldHVybiBlbGVtZW50Q2xvc2VzdChldi50YXJnZXQsIHRoaXMuc2VsZWN0b3IpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY29udGFpbmVyRWw7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIFBvaW50ZXJEcmFnZ2luZy5wcm90b3R5cGUuc2hvdWxkSWdub3JlTW91c2UgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBpZ25vcmVNb3VzZURlcHRoIHx8IHRoaXMuaXNUb3VjaERyYWdnaW5nO1xuICAgIH07XG4gICAgLy8gY2FuIGJlIGNhbGxlZCBieSB1c2VyIG9mIHRoaXMgY2xhc3MsIHRvIGNhbmNlbCB0b3VjaC1iYXNlZCBzY3JvbGxpbmcgZm9yIHRoZSBjdXJyZW50IGRyYWdcbiAgICBQb2ludGVyRHJhZ2dpbmcucHJvdG90eXBlLmNhbmNlbFRvdWNoU2Nyb2xsID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGhpcy5pc0RyYWdnaW5nKSB7XG4gICAgICAgICAgICBpc1dpbmRvd1RvdWNoTW92ZUNhbmNlbGxlZCA9IHRydWU7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8vIFNjcm9sbGluZyB0aGF0IHNpbXVsYXRlcyBwb2ludGVybW92ZXNcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgUG9pbnRlckRyYWdnaW5nLnByb3RvdHlwZS5pbml0U2Nyb2xsV2F0Y2ggPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgaWYgKHRoaXMuc2hvdWxkV2F0Y2hTY3JvbGwpIHtcbiAgICAgICAgICAgIHRoaXMucmVjb3JkQ29vcmRzKGV2KTtcbiAgICAgICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdzY3JvbGwnLCB0aGlzLmhhbmRsZVNjcm9sbCwgdHJ1ZSk7IC8vIHVzZUNhcHR1cmU9dHJ1ZVxuICAgICAgICB9XG4gICAgfTtcbiAgICBQb2ludGVyRHJhZ2dpbmcucHJvdG90eXBlLnJlY29yZENvb3JkcyA9IGZ1bmN0aW9uIChldikge1xuICAgICAgICBpZiAodGhpcy5zaG91bGRXYXRjaFNjcm9sbCkge1xuICAgICAgICAgICAgdGhpcy5wcmV2UGFnZVggPSBldi5wYWdlWDtcbiAgICAgICAgICAgIHRoaXMucHJldlBhZ2VZID0gZXYucGFnZVk7XG4gICAgICAgICAgICB0aGlzLnByZXZTY3JvbGxYID0gd2luZG93LnBhZ2VYT2Zmc2V0O1xuICAgICAgICAgICAgdGhpcy5wcmV2U2Nyb2xsWSA9IHdpbmRvdy5wYWdlWU9mZnNldDtcbiAgICAgICAgfVxuICAgIH07XG4gICAgUG9pbnRlckRyYWdnaW5nLnByb3RvdHlwZS5kZXN0cm95U2Nyb2xsV2F0Y2ggPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh0aGlzLnNob3VsZFdhdGNoU2Nyb2xsKSB7XG4gICAgICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcignc2Nyb2xsJywgdGhpcy5oYW5kbGVTY3JvbGwsIHRydWUpOyAvLyB1c2VDYXB0dXJlZD10cnVlXG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8vIEV2ZW50IE5vcm1hbGl6YXRpb25cbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgUG9pbnRlckRyYWdnaW5nLnByb3RvdHlwZS5jcmVhdGVFdmVudEZyb21Nb3VzZSA9IGZ1bmN0aW9uIChldiwgaXNGaXJzdCkge1xuICAgICAgICB2YXIgZGVsdGFYID0gMDtcbiAgICAgICAgdmFyIGRlbHRhWSA9IDA7XG4gICAgICAgIC8vIFRPRE86IHJlcGVhdCBjb2RlXG4gICAgICAgIGlmIChpc0ZpcnN0KSB7XG4gICAgICAgICAgICB0aGlzLm9yaWdQYWdlWCA9IGV2LnBhZ2VYO1xuICAgICAgICAgICAgdGhpcy5vcmlnUGFnZVkgPSBldi5wYWdlWTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGRlbHRhWCA9IGV2LnBhZ2VYIC0gdGhpcy5vcmlnUGFnZVg7XG4gICAgICAgICAgICBkZWx0YVkgPSBldi5wYWdlWSAtIHRoaXMub3JpZ1BhZ2VZO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBvcmlnRXZlbnQ6IGV2LFxuICAgICAgICAgICAgaXNUb3VjaDogZmFsc2UsXG4gICAgICAgICAgICBzdWJqZWN0RWw6IHRoaXMuc3ViamVjdEVsLFxuICAgICAgICAgICAgcGFnZVg6IGV2LnBhZ2VYLFxuICAgICAgICAgICAgcGFnZVk6IGV2LnBhZ2VZLFxuICAgICAgICAgICAgZGVsdGFYOiBkZWx0YVgsXG4gICAgICAgICAgICBkZWx0YVk6IGRlbHRhWVxuICAgICAgICB9O1xuICAgIH07XG4gICAgUG9pbnRlckRyYWdnaW5nLnByb3RvdHlwZS5jcmVhdGVFdmVudEZyb21Ub3VjaCA9IGZ1bmN0aW9uIChldiwgaXNGaXJzdCkge1xuICAgICAgICB2YXIgdG91Y2hlcyA9IGV2LnRvdWNoZXM7XG4gICAgICAgIHZhciBwYWdlWDtcbiAgICAgICAgdmFyIHBhZ2VZO1xuICAgICAgICB2YXIgZGVsdGFYID0gMDtcbiAgICAgICAgdmFyIGRlbHRhWSA9IDA7XG4gICAgICAgIC8vIGlmIHRvdWNoIGNvb3JkcyBhdmFpbGFibGUsIHByZWZlcixcbiAgICAgICAgLy8gYmVjYXVzZSBGRiB3b3VsZCBnaXZlIGJhZCBldi5wYWdlWCBldi5wYWdlWVxuICAgICAgICBpZiAodG91Y2hlcyAmJiB0b3VjaGVzLmxlbmd0aCkge1xuICAgICAgICAgICAgcGFnZVggPSB0b3VjaGVzWzBdLnBhZ2VYO1xuICAgICAgICAgICAgcGFnZVkgPSB0b3VjaGVzWzBdLnBhZ2VZO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcGFnZVggPSBldi5wYWdlWDtcbiAgICAgICAgICAgIHBhZ2VZID0gZXYucGFnZVk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gVE9ETzogcmVwZWF0IGNvZGVcbiAgICAgICAgaWYgKGlzRmlyc3QpIHtcbiAgICAgICAgICAgIHRoaXMub3JpZ1BhZ2VYID0gcGFnZVg7XG4gICAgICAgICAgICB0aGlzLm9yaWdQYWdlWSA9IHBhZ2VZO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZGVsdGFYID0gcGFnZVggLSB0aGlzLm9yaWdQYWdlWDtcbiAgICAgICAgICAgIGRlbHRhWSA9IHBhZ2VZIC0gdGhpcy5vcmlnUGFnZVk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIG9yaWdFdmVudDogZXYsXG4gICAgICAgICAgICBpc1RvdWNoOiB0cnVlLFxuICAgICAgICAgICAgc3ViamVjdEVsOiB0aGlzLnN1YmplY3RFbCxcbiAgICAgICAgICAgIHBhZ2VYOiBwYWdlWCxcbiAgICAgICAgICAgIHBhZ2VZOiBwYWdlWSxcbiAgICAgICAgICAgIGRlbHRhWDogZGVsdGFYLFxuICAgICAgICAgICAgZGVsdGFZOiBkZWx0YVlcbiAgICAgICAgfTtcbiAgICB9O1xuICAgIHJldHVybiBQb2ludGVyRHJhZ2dpbmc7XG59KCkpO1xuLy8gUmV0dXJucyBhIGJvb2xlYW4gd2hldGhlciB0aGlzIHdhcyBhIGxlZnQgbW91c2UgY2xpY2sgYW5kIG5vIGN0cmwga2V5ICh3aGljaCBtZWFucyByaWdodCBjbGljayBvbiBNYWMpXG5mdW5jdGlvbiBpc1ByaW1hcnlNb3VzZUJ1dHRvbihldikge1xuICAgIHJldHVybiBldi5idXR0b24gPT09IDAgJiYgIWV2LmN0cmxLZXk7XG59XG4vLyBJZ25vcmluZyBmYWtlIG1vdXNlIGV2ZW50cyBnZW5lcmF0ZWQgYnkgdG91Y2hcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbmZ1bmN0aW9uIHN0YXJ0SWdub3JpbmdNb3VzZSgpIHtcbiAgICBpZ25vcmVNb3VzZURlcHRoKys7XG4gICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlnbm9yZU1vdXNlRGVwdGgtLTtcbiAgICB9LCBjb25maWcudG91Y2hNb3VzZUlnbm9yZVdhaXQpO1xufVxuLy8gV2Ugd2FudCB0byBhdHRhY2ggdG91Y2htb3ZlIGFzIGVhcmx5IGFzIHBvc3NpYmxlIGZvciBTYWZhcmlcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbmZ1bmN0aW9uIGxpc3RlbmVyQ3JlYXRlZCgpIHtcbiAgICBpZiAoIShsaXN0ZW5lckNudCsrKSkge1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigndG91Y2htb3ZlJywgb25XaW5kb3dUb3VjaE1vdmUsIHsgcGFzc2l2ZTogZmFsc2UgfSk7XG4gICAgfVxufVxuZnVuY3Rpb24gbGlzdGVuZXJEZXN0cm95ZWQoKSB7XG4gICAgaWYgKCEoLS1saXN0ZW5lckNudCkpIHtcbiAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNobW92ZScsIG9uV2luZG93VG91Y2hNb3ZlLCB7IHBhc3NpdmU6IGZhbHNlIH0pO1xuICAgIH1cbn1cbmZ1bmN0aW9uIG9uV2luZG93VG91Y2hNb3ZlKGV2KSB7XG4gICAgaWYgKGlzV2luZG93VG91Y2hNb3ZlQ2FuY2VsbGVkKSB7XG4gICAgICAgIGV2LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxufVxuXG4vKlxuQW4gZWZmZWN0IGluIHdoaWNoIGFuIGVsZW1lbnQgZm9sbG93cyB0aGUgbW92ZW1lbnQgb2YgYSBwb2ludGVyIGFjcm9zcyB0aGUgc2NyZWVuLlxuVGhlIG1vdmluZyBlbGVtZW50IGlzIGEgY2xvbmUgb2Ygc29tZSBvdGhlciBlbGVtZW50LlxuTXVzdCBjYWxsIHN0YXJ0ICsgaGFuZGxlTW92ZSArIHN0b3AuXG4qL1xudmFyIEVsZW1lbnRNaXJyb3IgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gRWxlbWVudE1pcnJvcigpIHtcbiAgICAgICAgdGhpcy5pc1Zpc2libGUgPSBmYWxzZTsgLy8gbXVzdCBiZSBleHBsaWNpdGx5IGVuYWJsZWRcbiAgICAgICAgdGhpcy5zb3VyY2VFbCA9IG51bGw7XG4gICAgICAgIHRoaXMubWlycm9yRWwgPSBudWxsO1xuICAgICAgICB0aGlzLnNvdXJjZUVsUmVjdCA9IG51bGw7IC8vIHNjcmVlbiBjb29yZHMgcmVsYXRpdmUgdG8gdmlld3BvcnRcbiAgICAgICAgLy8gb3B0aW9ucyB0aGF0IGNhbiBiZSBzZXQgZGlyZWN0bHkgYnkgY2FsbGVyXG4gICAgICAgIHRoaXMucGFyZW50Tm9kZSA9IGRvY3VtZW50LmJvZHk7XG4gICAgICAgIHRoaXMuekluZGV4ID0gOTk5OTtcbiAgICAgICAgdGhpcy5yZXZlcnREdXJhdGlvbiA9IDA7XG4gICAgfVxuICAgIEVsZW1lbnRNaXJyb3IucHJvdG90eXBlLnN0YXJ0ID0gZnVuY3Rpb24gKHNvdXJjZUVsLCBwYWdlWCwgcGFnZVkpIHtcbiAgICAgICAgdGhpcy5zb3VyY2VFbCA9IHNvdXJjZUVsO1xuICAgICAgICB0aGlzLnNvdXJjZUVsUmVjdCA9IHRoaXMuc291cmNlRWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgIHRoaXMub3JpZ1NjcmVlblggPSBwYWdlWCAtIHdpbmRvdy5wYWdlWE9mZnNldDtcbiAgICAgICAgdGhpcy5vcmlnU2NyZWVuWSA9IHBhZ2VZIC0gd2luZG93LnBhZ2VZT2Zmc2V0O1xuICAgICAgICB0aGlzLmRlbHRhWCA9IDA7XG4gICAgICAgIHRoaXMuZGVsdGFZID0gMDtcbiAgICAgICAgdGhpcy51cGRhdGVFbFBvc2l0aW9uKCk7XG4gICAgfTtcbiAgICBFbGVtZW50TWlycm9yLnByb3RvdHlwZS5oYW5kbGVNb3ZlID0gZnVuY3Rpb24gKHBhZ2VYLCBwYWdlWSkge1xuICAgICAgICB0aGlzLmRlbHRhWCA9IChwYWdlWCAtIHdpbmRvdy5wYWdlWE9mZnNldCkgLSB0aGlzLm9yaWdTY3JlZW5YO1xuICAgICAgICB0aGlzLmRlbHRhWSA9IChwYWdlWSAtIHdpbmRvdy5wYWdlWU9mZnNldCkgLSB0aGlzLm9yaWdTY3JlZW5ZO1xuICAgICAgICB0aGlzLnVwZGF0ZUVsUG9zaXRpb24oKTtcbiAgICB9O1xuICAgIC8vIGNhbiBiZSBjYWxsZWQgYmVmb3JlIHN0YXJ0XG4gICAgRWxlbWVudE1pcnJvci5wcm90b3R5cGUuc2V0SXNWaXNpYmxlID0gZnVuY3Rpb24gKGJvb2wpIHtcbiAgICAgICAgaWYgKGJvb2wpIHtcbiAgICAgICAgICAgIGlmICghdGhpcy5pc1Zpc2libGUpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5taXJyb3JFbCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm1pcnJvckVsLnN0eWxlLmRpc3BsYXkgPSAnJztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy5pc1Zpc2libGUgPSBib29sOyAvLyBuZWVkcyB0byBoYXBwZW4gYmVmb3JlIHVwZGF0ZUVsUG9zaXRpb25cbiAgICAgICAgICAgICAgICB0aGlzLnVwZGF0ZUVsUG9zaXRpb24oKTsgLy8gYmVjYXVzZSB3YXMgbm90IHVwZGF0aW5nIHRoZSBwb3NpdGlvbiB3aGlsZSBpbnZpc2libGVcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGlmICh0aGlzLmlzVmlzaWJsZSkge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLm1pcnJvckVsKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubWlycm9yRWwuc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy5pc1Zpc2libGUgPSBib29sO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcbiAgICAvLyBhbHdheXMgYXN5bmNcbiAgICBFbGVtZW50TWlycm9yLnByb3RvdHlwZS5zdG9wID0gZnVuY3Rpb24gKG5lZWRzUmV2ZXJ0QW5pbWF0aW9uLCBjYWxsYmFjaykge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgZG9uZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIF90aGlzLmNsZWFudXAoKTtcbiAgICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgIH07XG4gICAgICAgIGlmIChuZWVkc1JldmVydEFuaW1hdGlvbiAmJlxuICAgICAgICAgICAgdGhpcy5taXJyb3JFbCAmJlxuICAgICAgICAgICAgdGhpcy5pc1Zpc2libGUgJiZcbiAgICAgICAgICAgIHRoaXMucmV2ZXJ0RHVyYXRpb24gJiYgLy8gaWYgMCwgdHJhbnNpdGlvbiB3b24ndCB3b3JrXG4gICAgICAgICAgICAodGhpcy5kZWx0YVggfHwgdGhpcy5kZWx0YVkpIC8vIGlmIHNhbWUgY29vcmRzLCB0cmFuc2l0aW9uIHdvbid0IHdvcmtcbiAgICAgICAgKSB7XG4gICAgICAgICAgICB0aGlzLmRvUmV2ZXJ0QW5pbWF0aW9uKGRvbmUsIHRoaXMucmV2ZXJ0RHVyYXRpb24pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgc2V0VGltZW91dChkb25lLCAwKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgRWxlbWVudE1pcnJvci5wcm90b3R5cGUuZG9SZXZlcnRBbmltYXRpb24gPSBmdW5jdGlvbiAoY2FsbGJhY2ssIHJldmVydER1cmF0aW9uKSB7XG4gICAgICAgIHZhciBtaXJyb3JFbCA9IHRoaXMubWlycm9yRWw7XG4gICAgICAgIHZhciBmaW5hbFNvdXJjZUVsUmVjdCA9IHRoaXMuc291cmNlRWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7IC8vIGJlY2F1c2UgYXV0b3Njcm9sbGluZyBtaWdodCBoYXZlIGhhcHBlbmVkXG4gICAgICAgIG1pcnJvckVsLnN0eWxlLnRyYW5zaXRpb24gPVxuICAgICAgICAgICAgJ3RvcCAnICsgcmV2ZXJ0RHVyYXRpb24gKyAnbXMsJyArXG4gICAgICAgICAgICAgICAgJ2xlZnQgJyArIHJldmVydER1cmF0aW9uICsgJ21zJztcbiAgICAgICAgYXBwbHlTdHlsZShtaXJyb3JFbCwge1xuICAgICAgICAgICAgbGVmdDogZmluYWxTb3VyY2VFbFJlY3QubGVmdCxcbiAgICAgICAgICAgIHRvcDogZmluYWxTb3VyY2VFbFJlY3QudG9wXG4gICAgICAgIH0pO1xuICAgICAgICB3aGVuVHJhbnNpdGlvbkRvbmUobWlycm9yRWwsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIG1pcnJvckVsLnN0eWxlLnRyYW5zaXRpb24gPSAnJztcbiAgICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgIH0pO1xuICAgIH07XG4gICAgRWxlbWVudE1pcnJvci5wcm90b3R5cGUuY2xlYW51cCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRoaXMubWlycm9yRWwpIHtcbiAgICAgICAgICAgIHJlbW92ZUVsZW1lbnQodGhpcy5taXJyb3JFbCk7XG4gICAgICAgICAgICB0aGlzLm1pcnJvckVsID0gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnNvdXJjZUVsID0gbnVsbDtcbiAgICB9O1xuICAgIEVsZW1lbnRNaXJyb3IucHJvdG90eXBlLnVwZGF0ZUVsUG9zaXRpb24gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh0aGlzLnNvdXJjZUVsICYmIHRoaXMuaXNWaXNpYmxlKSB7XG4gICAgICAgICAgICBhcHBseVN0eWxlKHRoaXMuZ2V0TWlycm9yRWwoKSwge1xuICAgICAgICAgICAgICAgIGxlZnQ6IHRoaXMuc291cmNlRWxSZWN0LmxlZnQgKyB0aGlzLmRlbHRhWCxcbiAgICAgICAgICAgICAgICB0b3A6IHRoaXMuc291cmNlRWxSZWN0LnRvcCArIHRoaXMuZGVsdGFZXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgRWxlbWVudE1pcnJvci5wcm90b3R5cGUuZ2V0TWlycm9yRWwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBzb3VyY2VFbFJlY3QgPSB0aGlzLnNvdXJjZUVsUmVjdDtcbiAgICAgICAgdmFyIG1pcnJvckVsID0gdGhpcy5taXJyb3JFbDtcbiAgICAgICAgaWYgKCFtaXJyb3JFbCkge1xuICAgICAgICAgICAgbWlycm9yRWwgPSB0aGlzLm1pcnJvckVsID0gdGhpcy5zb3VyY2VFbC5jbG9uZU5vZGUodHJ1ZSk7IC8vIGNsb25lQ2hpbGRyZW49dHJ1ZVxuICAgICAgICAgICAgLy8gd2UgZG9uJ3Qgd2FudCBsb25nIHRhcHMgb3IgYW55IG1vdXNlIGludGVyYWN0aW9uIGNhdXNpbmcgc2VsZWN0aW9uL21lbnVzLlxuICAgICAgICAgICAgLy8gd291bGQgdXNlIHByZXZlbnRTZWxlY3Rpb24oKSwgYnV0IHRoYXQgcHJldmVudHMgc2VsZWN0c3RhcnQsIGNhdXNpbmcgcHJvYmxlbXMuXG4gICAgICAgICAgICBtaXJyb3JFbC5jbGFzc0xpc3QuYWRkKCdmYy11bnNlbGVjdGFibGUnKTtcbiAgICAgICAgICAgIG1pcnJvckVsLmNsYXNzTGlzdC5hZGQoJ2ZjLWRyYWdnaW5nJyk7XG4gICAgICAgICAgICBhcHBseVN0eWxlKG1pcnJvckVsLCB7XG4gICAgICAgICAgICAgICAgcG9zaXRpb246ICdmaXhlZCcsXG4gICAgICAgICAgICAgICAgekluZGV4OiB0aGlzLnpJbmRleCxcbiAgICAgICAgICAgICAgICB2aXNpYmlsaXR5OiAnJyxcbiAgICAgICAgICAgICAgICBib3hTaXppbmc6ICdib3JkZXItYm94JyxcbiAgICAgICAgICAgICAgICB3aWR0aDogc291cmNlRWxSZWN0LnJpZ2h0IC0gc291cmNlRWxSZWN0LmxlZnQsXG4gICAgICAgICAgICAgICAgaGVpZ2h0OiBzb3VyY2VFbFJlY3QuYm90dG9tIC0gc291cmNlRWxSZWN0LnRvcCxcbiAgICAgICAgICAgICAgICByaWdodDogJ2F1dG8nLFxuICAgICAgICAgICAgICAgIGJvdHRvbTogJ2F1dG8nLFxuICAgICAgICAgICAgICAgIG1hcmdpbjogMFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB0aGlzLnBhcmVudE5vZGUuYXBwZW5kQ2hpbGQobWlycm9yRWwpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBtaXJyb3JFbDtcbiAgICB9O1xuICAgIHJldHVybiBFbGVtZW50TWlycm9yO1xufSgpKTtcblxuLypcbklzIGEgY2FjaGUgZm9yIGEgZ2l2ZW4gZWxlbWVudCdzIHNjcm9sbCBpbmZvcm1hdGlvbiAoYWxsIHRoZSBpbmZvIHRoYXQgU2Nyb2xsQ29udHJvbGxlciBzdG9yZXMpXG5pbiBhZGRpdGlvbiB0aGUgXCJjbGllbnQgcmVjdGFuZ2xlXCIgb2YgdGhlIGVsZW1lbnQuLiB0aGUgYXJlYSB3aXRoaW4gdGhlIHNjcm9sbGJhcnMuXG5cblRoZSBjYWNoZSBjYW4gYmUgaW4gb25lIG9mIHR3byBtb2Rlczpcbi0gZG9lc0xpc3RlbmluZzpmYWxzZSAtIGlnbm9yZXMgd2hlbiB0aGUgY29udGFpbmVyIGlzIHNjcm9sbGVkIGJ5IHNvbWVvbmUgZWxzZVxuLSBkb2VzTGlzdGVuaW5nOnRydWUgLSB3YXRjaCBmb3Igc2Nyb2xsaW5nIGFuZCB1cGRhdGUgdGhlIGNhY2hlXG4qL1xudmFyIFNjcm9sbEdlb21DYWNoZSA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uIChfc3VwZXIpIHtcbiAgICBfX2V4dGVuZHMoU2Nyb2xsR2VvbUNhY2hlLCBfc3VwZXIpO1xuICAgIGZ1bmN0aW9uIFNjcm9sbEdlb21DYWNoZShzY3JvbGxDb250cm9sbGVyLCBkb2VzTGlzdGVuaW5nKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IF9zdXBlci5jYWxsKHRoaXMpIHx8IHRoaXM7XG4gICAgICAgIF90aGlzLmhhbmRsZVNjcm9sbCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIF90aGlzLnNjcm9sbFRvcCA9IF90aGlzLnNjcm9sbENvbnRyb2xsZXIuZ2V0U2Nyb2xsVG9wKCk7XG4gICAgICAgICAgICBfdGhpcy5zY3JvbGxMZWZ0ID0gX3RoaXMuc2Nyb2xsQ29udHJvbGxlci5nZXRTY3JvbGxMZWZ0KCk7XG4gICAgICAgICAgICBfdGhpcy5oYW5kbGVTY3JvbGxDaGFuZ2UoKTtcbiAgICAgICAgfTtcbiAgICAgICAgX3RoaXMuc2Nyb2xsQ29udHJvbGxlciA9IHNjcm9sbENvbnRyb2xsZXI7XG4gICAgICAgIF90aGlzLmRvZXNMaXN0ZW5pbmcgPSBkb2VzTGlzdGVuaW5nO1xuICAgICAgICBfdGhpcy5zY3JvbGxUb3AgPSBfdGhpcy5vcmlnU2Nyb2xsVG9wID0gc2Nyb2xsQ29udHJvbGxlci5nZXRTY3JvbGxUb3AoKTtcbiAgICAgICAgX3RoaXMuc2Nyb2xsTGVmdCA9IF90aGlzLm9yaWdTY3JvbGxMZWZ0ID0gc2Nyb2xsQ29udHJvbGxlci5nZXRTY3JvbGxMZWZ0KCk7XG4gICAgICAgIF90aGlzLnNjcm9sbFdpZHRoID0gc2Nyb2xsQ29udHJvbGxlci5nZXRTY3JvbGxXaWR0aCgpO1xuICAgICAgICBfdGhpcy5zY3JvbGxIZWlnaHQgPSBzY3JvbGxDb250cm9sbGVyLmdldFNjcm9sbEhlaWdodCgpO1xuICAgICAgICBfdGhpcy5jbGllbnRXaWR0aCA9IHNjcm9sbENvbnRyb2xsZXIuZ2V0Q2xpZW50V2lkdGgoKTtcbiAgICAgICAgX3RoaXMuY2xpZW50SGVpZ2h0ID0gc2Nyb2xsQ29udHJvbGxlci5nZXRDbGllbnRIZWlnaHQoKTtcbiAgICAgICAgX3RoaXMuY2xpZW50UmVjdCA9IF90aGlzLmNvbXB1dGVDbGllbnRSZWN0KCk7IC8vIGRvIGxhc3QgaW4gY2FzZSBpdCBuZWVkcyBjYWNoZWQgdmFsdWVzXG4gICAgICAgIGlmIChfdGhpcy5kb2VzTGlzdGVuaW5nKSB7XG4gICAgICAgICAgICBfdGhpcy5nZXRFdmVudFRhcmdldCgpLmFkZEV2ZW50TGlzdGVuZXIoJ3Njcm9sbCcsIF90aGlzLmhhbmRsZVNjcm9sbCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIF90aGlzO1xuICAgIH1cbiAgICBTY3JvbGxHZW9tQ2FjaGUucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh0aGlzLmRvZXNMaXN0ZW5pbmcpIHtcbiAgICAgICAgICAgIHRoaXMuZ2V0RXZlbnRUYXJnZXQoKS5yZW1vdmVFdmVudExpc3RlbmVyKCdzY3JvbGwnLCB0aGlzLmhhbmRsZVNjcm9sbCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIFNjcm9sbEdlb21DYWNoZS5wcm90b3R5cGUuZ2V0U2Nyb2xsVG9wID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zY3JvbGxUb3A7XG4gICAgfTtcbiAgICBTY3JvbGxHZW9tQ2FjaGUucHJvdG90eXBlLmdldFNjcm9sbExlZnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNjcm9sbExlZnQ7XG4gICAgfTtcbiAgICBTY3JvbGxHZW9tQ2FjaGUucHJvdG90eXBlLnNldFNjcm9sbFRvcCA9IGZ1bmN0aW9uICh0b3ApIHtcbiAgICAgICAgdGhpcy5zY3JvbGxDb250cm9sbGVyLnNldFNjcm9sbFRvcCh0b3ApO1xuICAgICAgICBpZiAoIXRoaXMuZG9lc0xpc3RlbmluZykge1xuICAgICAgICAgICAgLy8gd2UgYXJlIG5vdCByZWx5aW5nIG9uIHRoZSBlbGVtZW50IHRvIG5vcm1hbGl6ZSBvdXQtb2YtYm91bmRzIHNjcm9sbCB2YWx1ZXNcbiAgICAgICAgICAgIC8vIHNvIHdlIG5lZWQgdG8gc2FuaXRpemUgb3Vyc2VsdmVzXG4gICAgICAgICAgICB0aGlzLnNjcm9sbFRvcCA9IE1hdGgubWF4KE1hdGgubWluKHRvcCwgdGhpcy5nZXRNYXhTY3JvbGxUb3AoKSksIDApO1xuICAgICAgICAgICAgdGhpcy5oYW5kbGVTY3JvbGxDaGFuZ2UoKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgU2Nyb2xsR2VvbUNhY2hlLnByb3RvdHlwZS5zZXRTY3JvbGxMZWZ0ID0gZnVuY3Rpb24gKHRvcCkge1xuICAgICAgICB0aGlzLnNjcm9sbENvbnRyb2xsZXIuc2V0U2Nyb2xsTGVmdCh0b3ApO1xuICAgICAgICBpZiAoIXRoaXMuZG9lc0xpc3RlbmluZykge1xuICAgICAgICAgICAgLy8gd2UgYXJlIG5vdCByZWx5aW5nIG9uIHRoZSBlbGVtZW50IHRvIG5vcm1hbGl6ZSBvdXQtb2YtYm91bmRzIHNjcm9sbCB2YWx1ZXNcbiAgICAgICAgICAgIC8vIHNvIHdlIG5lZWQgdG8gc2FuaXRpemUgb3Vyc2VsdmVzXG4gICAgICAgICAgICB0aGlzLnNjcm9sbExlZnQgPSBNYXRoLm1heChNYXRoLm1pbih0b3AsIHRoaXMuZ2V0TWF4U2Nyb2xsTGVmdCgpKSwgMCk7XG4gICAgICAgICAgICB0aGlzLmhhbmRsZVNjcm9sbENoYW5nZSgpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBTY3JvbGxHZW9tQ2FjaGUucHJvdG90eXBlLmdldENsaWVudFdpZHRoID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jbGllbnRXaWR0aDtcbiAgICB9O1xuICAgIFNjcm9sbEdlb21DYWNoZS5wcm90b3R5cGUuZ2V0Q2xpZW50SGVpZ2h0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jbGllbnRIZWlnaHQ7XG4gICAgfTtcbiAgICBTY3JvbGxHZW9tQ2FjaGUucHJvdG90eXBlLmdldFNjcm9sbFdpZHRoID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zY3JvbGxXaWR0aDtcbiAgICB9O1xuICAgIFNjcm9sbEdlb21DYWNoZS5wcm90b3R5cGUuZ2V0U2Nyb2xsSGVpZ2h0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zY3JvbGxIZWlnaHQ7XG4gICAgfTtcbiAgICBTY3JvbGxHZW9tQ2FjaGUucHJvdG90eXBlLmhhbmRsZVNjcm9sbENoYW5nZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB9O1xuICAgIHJldHVybiBTY3JvbGxHZW9tQ2FjaGU7XG59KFNjcm9sbENvbnRyb2xsZXIpKTtcbnZhciBFbGVtZW50U2Nyb2xsR2VvbUNhY2hlID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKF9zdXBlcikge1xuICAgIF9fZXh0ZW5kcyhFbGVtZW50U2Nyb2xsR2VvbUNhY2hlLCBfc3VwZXIpO1xuICAgIGZ1bmN0aW9uIEVsZW1lbnRTY3JvbGxHZW9tQ2FjaGUoZWwsIGRvZXNMaXN0ZW5pbmcpIHtcbiAgICAgICAgcmV0dXJuIF9zdXBlci5jYWxsKHRoaXMsIG5ldyBFbGVtZW50U2Nyb2xsQ29udHJvbGxlcihlbCksIGRvZXNMaXN0ZW5pbmcpIHx8IHRoaXM7XG4gICAgfVxuICAgIEVsZW1lbnRTY3JvbGxHZW9tQ2FjaGUucHJvdG90eXBlLmdldEV2ZW50VGFyZ2V0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zY3JvbGxDb250cm9sbGVyLmVsO1xuICAgIH07XG4gICAgRWxlbWVudFNjcm9sbEdlb21DYWNoZS5wcm90b3R5cGUuY29tcHV0ZUNsaWVudFJlY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBjb21wdXRlSW5uZXJSZWN0KHRoaXMuc2Nyb2xsQ29udHJvbGxlci5lbCk7XG4gICAgfTtcbiAgICByZXR1cm4gRWxlbWVudFNjcm9sbEdlb21DYWNoZTtcbn0oU2Nyb2xsR2VvbUNhY2hlKSk7XG52YXIgV2luZG93U2Nyb2xsR2VvbUNhY2hlID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKF9zdXBlcikge1xuICAgIF9fZXh0ZW5kcyhXaW5kb3dTY3JvbGxHZW9tQ2FjaGUsIF9zdXBlcik7XG4gICAgZnVuY3Rpb24gV2luZG93U2Nyb2xsR2VvbUNhY2hlKGRvZXNMaXN0ZW5pbmcpIHtcbiAgICAgICAgcmV0dXJuIF9zdXBlci5jYWxsKHRoaXMsIG5ldyBXaW5kb3dTY3JvbGxDb250cm9sbGVyKCksIGRvZXNMaXN0ZW5pbmcpIHx8IHRoaXM7XG4gICAgfVxuICAgIFdpbmRvd1Njcm9sbEdlb21DYWNoZS5wcm90b3R5cGUuZ2V0RXZlbnRUYXJnZXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB3aW5kb3c7XG4gICAgfTtcbiAgICBXaW5kb3dTY3JvbGxHZW9tQ2FjaGUucHJvdG90eXBlLmNvbXB1dGVDbGllbnRSZWN0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgbGVmdDogdGhpcy5zY3JvbGxMZWZ0LFxuICAgICAgICAgICAgcmlnaHQ6IHRoaXMuc2Nyb2xsTGVmdCArIHRoaXMuY2xpZW50V2lkdGgsXG4gICAgICAgICAgICB0b3A6IHRoaXMuc2Nyb2xsVG9wLFxuICAgICAgICAgICAgYm90dG9tOiB0aGlzLnNjcm9sbFRvcCArIHRoaXMuY2xpZW50SGVpZ2h0XG4gICAgICAgIH07XG4gICAgfTtcbiAgICAvLyB0aGUgd2luZG93IGlzIHRoZSBvbmx5IHNjcm9sbCBvYmplY3QgdGhhdCBjaGFuZ2VzIGl0J3MgcmVjdGFuZ2xlIHJlbGF0aXZlXG4gICAgLy8gdG8gdGhlIGRvY3VtZW50J3MgdG9wbGVmdCBhcyBpdCBzY3JvbGxzXG4gICAgV2luZG93U2Nyb2xsR2VvbUNhY2hlLnByb3RvdHlwZS5oYW5kbGVTY3JvbGxDaGFuZ2UgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuY2xpZW50UmVjdCA9IHRoaXMuY29tcHV0ZUNsaWVudFJlY3QoKTtcbiAgICB9O1xuICAgIHJldHVybiBXaW5kb3dTY3JvbGxHZW9tQ2FjaGU7XG59KFNjcm9sbEdlb21DYWNoZSkpO1xuXG4vLyBJZiBhdmFpbGFibGUgd2UgYXJlIHVzaW5nIG5hdGl2ZSBcInBlcmZvcm1hbmNlXCIgQVBJIGluc3RlYWQgb2YgXCJEYXRlXCJcbi8vIFJlYWQgbW9yZSBhYm91dCBpdCBvbiBNRE46XG4vLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9BUEkvUGVyZm9ybWFuY2VcbnZhciBnZXRUaW1lID0gdHlwZW9mIHBlcmZvcm1hbmNlID09PSAnZnVuY3Rpb24nID8gcGVyZm9ybWFuY2Uubm93IDogRGF0ZS5ub3c7XG4vKlxuRm9yIGEgcG9pbnRlciBpbnRlcmFjdGlvbiwgYXV0b21hdGljYWxseSBzY3JvbGxzIGNlcnRhaW4gc2Nyb2xsIGNvbnRhaW5lcnMgd2hlbiB0aGUgcG9pbnRlclxuYXBwcm9hY2hlcyB0aGUgZWRnZS5cblxuVGhlIGNhbGxlciBtdXN0IGNhbGwgc3RhcnQgKyBoYW5kbGVNb3ZlICsgc3RvcC5cbiovXG52YXIgQXV0b1Njcm9sbGVyID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIEF1dG9TY3JvbGxlcigpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgLy8gb3B0aW9ucyB0aGF0IGNhbiBiZSBzZXQgYnkgY2FsbGVyXG4gICAgICAgIHRoaXMuaXNFbmFibGVkID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5zY3JvbGxRdWVyeSA9IFt3aW5kb3csICcuZmMtc2Nyb2xsZXInXTtcbiAgICAgICAgdGhpcy5lZGdlVGhyZXNob2xkID0gNTA7IC8vIHBpeGVsc1xuICAgICAgICB0aGlzLm1heFZlbG9jaXR5ID0gMzAwOyAvLyBwaXhlbHMgcGVyIHNlY29uZFxuICAgICAgICAvLyBpbnRlcm5hbCBzdGF0ZVxuICAgICAgICB0aGlzLnBvaW50ZXJTY3JlZW5YID0gbnVsbDtcbiAgICAgICAgdGhpcy5wb2ludGVyU2NyZWVuWSA9IG51bGw7XG4gICAgICAgIHRoaXMuaXNBbmltYXRpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5zY3JvbGxDYWNoZXMgPSBudWxsO1xuICAgICAgICAvLyBwcm90ZWN0IGFnYWluc3QgdGhlIGluaXRpYWwgcG9pbnRlcmRvd24gYmVpbmcgdG9vIGNsb3NlIHRvIGFuIGVkZ2UgYW5kIHN0YXJ0aW5nIHRoZSBzY3JvbGxcbiAgICAgICAgdGhpcy5ldmVyTW92ZWRVcCA9IGZhbHNlO1xuICAgICAgICB0aGlzLmV2ZXJNb3ZlZERvd24gPSBmYWxzZTtcbiAgICAgICAgdGhpcy5ldmVyTW92ZWRMZWZ0ID0gZmFsc2U7XG4gICAgICAgIHRoaXMuZXZlck1vdmVkUmlnaHQgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5hbmltYXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKF90aGlzLmlzQW5pbWF0aW5nKSB7IC8vIHdhc24ndCBjYW5jZWxsZWQgYmV0d2VlbiBhbmltYXRpb24gY2FsbHNcbiAgICAgICAgICAgICAgICB2YXIgZWRnZSA9IF90aGlzLmNvbXB1dGVCZXN0RWRnZShfdGhpcy5wb2ludGVyU2NyZWVuWCArIHdpbmRvdy5wYWdlWE9mZnNldCwgX3RoaXMucG9pbnRlclNjcmVlblkgKyB3aW5kb3cucGFnZVlPZmZzZXQpO1xuICAgICAgICAgICAgICAgIGlmIChlZGdlKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBub3cgPSBnZXRUaW1lKCk7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLmhhbmRsZVNpZGUoZWRnZSwgKG5vdyAtIF90aGlzLm1zU2luY2VSZXF1ZXN0KSAvIDEwMDApO1xuICAgICAgICAgICAgICAgICAgICBfdGhpcy5yZXF1ZXN0QW5pbWF0aW9uKG5vdyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBfdGhpcy5pc0FuaW1hdGluZyA9IGZhbHNlOyAvLyB3aWxsIHN0b3AgYW5pbWF0aW9uXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgIH1cbiAgICBBdXRvU2Nyb2xsZXIucHJvdG90eXBlLnN0YXJ0ID0gZnVuY3Rpb24gKHBhZ2VYLCBwYWdlWSkge1xuICAgICAgICBpZiAodGhpcy5pc0VuYWJsZWQpIHtcbiAgICAgICAgICAgIHRoaXMuc2Nyb2xsQ2FjaGVzID0gdGhpcy5idWlsZENhY2hlcygpO1xuICAgICAgICAgICAgdGhpcy5wb2ludGVyU2NyZWVuWCA9IG51bGw7XG4gICAgICAgICAgICB0aGlzLnBvaW50ZXJTY3JlZW5ZID0gbnVsbDtcbiAgICAgICAgICAgIHRoaXMuZXZlck1vdmVkVXAgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMuZXZlck1vdmVkRG93biA9IGZhbHNlO1xuICAgICAgICAgICAgdGhpcy5ldmVyTW92ZWRMZWZ0ID0gZmFsc2U7XG4gICAgICAgICAgICB0aGlzLmV2ZXJNb3ZlZFJpZ2h0ID0gZmFsc2U7XG4gICAgICAgICAgICB0aGlzLmhhbmRsZU1vdmUocGFnZVgsIHBhZ2VZKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgQXV0b1Njcm9sbGVyLnByb3RvdHlwZS5oYW5kbGVNb3ZlID0gZnVuY3Rpb24gKHBhZ2VYLCBwYWdlWSkge1xuICAgICAgICBpZiAodGhpcy5pc0VuYWJsZWQpIHtcbiAgICAgICAgICAgIHZhciBwb2ludGVyU2NyZWVuWCA9IHBhZ2VYIC0gd2luZG93LnBhZ2VYT2Zmc2V0O1xuICAgICAgICAgICAgdmFyIHBvaW50ZXJTY3JlZW5ZID0gcGFnZVkgLSB3aW5kb3cucGFnZVlPZmZzZXQ7XG4gICAgICAgICAgICB2YXIgeURlbHRhID0gdGhpcy5wb2ludGVyU2NyZWVuWSA9PT0gbnVsbCA/IDAgOiBwb2ludGVyU2NyZWVuWSAtIHRoaXMucG9pbnRlclNjcmVlblk7XG4gICAgICAgICAgICB2YXIgeERlbHRhID0gdGhpcy5wb2ludGVyU2NyZWVuWCA9PT0gbnVsbCA/IDAgOiBwb2ludGVyU2NyZWVuWCAtIHRoaXMucG9pbnRlclNjcmVlblg7XG4gICAgICAgICAgICBpZiAoeURlbHRhIDwgMCkge1xuICAgICAgICAgICAgICAgIHRoaXMuZXZlck1vdmVkVXAgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoeURlbHRhID4gMCkge1xuICAgICAgICAgICAgICAgIHRoaXMuZXZlck1vdmVkRG93biA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoeERlbHRhIDwgMCkge1xuICAgICAgICAgICAgICAgIHRoaXMuZXZlck1vdmVkTGVmdCA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICh4RGVsdGEgPiAwKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5ldmVyTW92ZWRSaWdodCA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnBvaW50ZXJTY3JlZW5YID0gcG9pbnRlclNjcmVlblg7XG4gICAgICAgICAgICB0aGlzLnBvaW50ZXJTY3JlZW5ZID0gcG9pbnRlclNjcmVlblk7XG4gICAgICAgICAgICBpZiAoIXRoaXMuaXNBbmltYXRpbmcpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmlzQW5pbWF0aW5nID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlcXVlc3RBbmltYXRpb24oZ2V0VGltZSgpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG4gICAgQXV0b1Njcm9sbGVyLnByb3RvdHlwZS5zdG9wID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGhpcy5pc0VuYWJsZWQpIHtcbiAgICAgICAgICAgIHRoaXMuaXNBbmltYXRpbmcgPSBmYWxzZTsgLy8gd2lsbCBzdG9wIGFuaW1hdGlvblxuICAgICAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBfYSA9IHRoaXMuc2Nyb2xsQ2FjaGVzOyBfaSA8IF9hLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgICAgIHZhciBzY3JvbGxDYWNoZSA9IF9hW19pXTtcbiAgICAgICAgICAgICAgICBzY3JvbGxDYWNoZS5kZXN0cm95KCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnNjcm9sbENhY2hlcyA9IG51bGw7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIEF1dG9TY3JvbGxlci5wcm90b3R5cGUucmVxdWVzdEFuaW1hdGlvbiA9IGZ1bmN0aW9uIChub3cpIHtcbiAgICAgICAgdGhpcy5tc1NpbmNlUmVxdWVzdCA9IG5vdztcbiAgICAgICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKHRoaXMuYW5pbWF0ZSk7XG4gICAgfTtcbiAgICBBdXRvU2Nyb2xsZXIucHJvdG90eXBlLmhhbmRsZVNpZGUgPSBmdW5jdGlvbiAoZWRnZSwgc2Vjb25kcykge1xuICAgICAgICB2YXIgc2Nyb2xsQ2FjaGUgPSBlZGdlLnNjcm9sbENhY2hlO1xuICAgICAgICB2YXIgZWRnZVRocmVzaG9sZCA9IHRoaXMuZWRnZVRocmVzaG9sZDtcbiAgICAgICAgdmFyIGludkRpc3RhbmNlID0gZWRnZVRocmVzaG9sZCAtIGVkZ2UuZGlzdGFuY2U7XG4gICAgICAgIHZhciB2ZWxvY2l0eSA9IC8vIHRoZSBjbG9zZXIgdG8gdGhlIGVkZ2UsIHRoZSBmYXN0ZXIgd2Ugc2Nyb2xsXG4gICAgICAgICAoaW52RGlzdGFuY2UgKiBpbnZEaXN0YW5jZSkgLyAoZWRnZVRocmVzaG9sZCAqIGVkZ2VUaHJlc2hvbGQpICogLy8gcXVhZHJhdGljXG4gICAgICAgICAgICB0aGlzLm1heFZlbG9jaXR5ICogc2Vjb25kcztcbiAgICAgICAgdmFyIHNpZ24gPSAxO1xuICAgICAgICBzd2l0Y2ggKGVkZ2UubmFtZSkge1xuICAgICAgICAgICAgY2FzZSAnbGVmdCc6XG4gICAgICAgICAgICAgICAgc2lnbiA9IC0xO1xuICAgICAgICAgICAgLy8gZmFsbHMgdGhyb3VnaFxuICAgICAgICAgICAgY2FzZSAncmlnaHQnOlxuICAgICAgICAgICAgICAgIHNjcm9sbENhY2hlLnNldFNjcm9sbExlZnQoc2Nyb2xsQ2FjaGUuZ2V0U2Nyb2xsTGVmdCgpICsgdmVsb2NpdHkgKiBzaWduKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ3RvcCc6XG4gICAgICAgICAgICAgICAgc2lnbiA9IC0xO1xuICAgICAgICAgICAgLy8gZmFsbHMgdGhyb3VnaFxuICAgICAgICAgICAgY2FzZSAnYm90dG9tJzpcbiAgICAgICAgICAgICAgICBzY3JvbGxDYWNoZS5zZXRTY3JvbGxUb3Aoc2Nyb2xsQ2FjaGUuZ2V0U2Nyb2xsVG9wKCkgKyB2ZWxvY2l0eSAqIHNpZ24pO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvLyBsZWZ0L3RvcCBhcmUgcmVsYXRpdmUgdG8gZG9jdW1lbnQgdG9wbGVmdFxuICAgIEF1dG9TY3JvbGxlci5wcm90b3R5cGUuY29tcHV0ZUJlc3RFZGdlID0gZnVuY3Rpb24gKGxlZnQsIHRvcCkge1xuICAgICAgICB2YXIgZWRnZVRocmVzaG9sZCA9IHRoaXMuZWRnZVRocmVzaG9sZDtcbiAgICAgICAgdmFyIGJlc3RTaWRlID0gbnVsbDtcbiAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBfYSA9IHRoaXMuc2Nyb2xsQ2FjaGVzOyBfaSA8IF9hLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgdmFyIHNjcm9sbENhY2hlID0gX2FbX2ldO1xuICAgICAgICAgICAgdmFyIHJlY3QgPSBzY3JvbGxDYWNoZS5jbGllbnRSZWN0O1xuICAgICAgICAgICAgdmFyIGxlZnREaXN0ID0gbGVmdCAtIHJlY3QubGVmdDtcbiAgICAgICAgICAgIHZhciByaWdodERpc3QgPSByZWN0LnJpZ2h0IC0gbGVmdDtcbiAgICAgICAgICAgIHZhciB0b3BEaXN0ID0gdG9wIC0gcmVjdC50b3A7XG4gICAgICAgICAgICB2YXIgYm90dG9tRGlzdCA9IHJlY3QuYm90dG9tIC0gdG9wO1xuICAgICAgICAgICAgLy8gY29tcGxldGVseSB3aXRoaW4gdGhlIHJlY3Q/XG4gICAgICAgICAgICBpZiAobGVmdERpc3QgPj0gMCAmJiByaWdodERpc3QgPj0gMCAmJiB0b3BEaXN0ID49IDAgJiYgYm90dG9tRGlzdCA+PSAwKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRvcERpc3QgPD0gZWRnZVRocmVzaG9sZCAmJiB0aGlzLmV2ZXJNb3ZlZFVwICYmIHNjcm9sbENhY2hlLmNhblNjcm9sbFVwKCkgJiZcbiAgICAgICAgICAgICAgICAgICAgKCFiZXN0U2lkZSB8fCBiZXN0U2lkZS5kaXN0YW5jZSA+IHRvcERpc3QpKSB7XG4gICAgICAgICAgICAgICAgICAgIGJlc3RTaWRlID0geyBzY3JvbGxDYWNoZTogc2Nyb2xsQ2FjaGUsIG5hbWU6ICd0b3AnLCBkaXN0YW5jZTogdG9wRGlzdCB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoYm90dG9tRGlzdCA8PSBlZGdlVGhyZXNob2xkICYmIHRoaXMuZXZlck1vdmVkRG93biAmJiBzY3JvbGxDYWNoZS5jYW5TY3JvbGxEb3duKCkgJiZcbiAgICAgICAgICAgICAgICAgICAgKCFiZXN0U2lkZSB8fCBiZXN0U2lkZS5kaXN0YW5jZSA+IGJvdHRvbURpc3QpKSB7XG4gICAgICAgICAgICAgICAgICAgIGJlc3RTaWRlID0geyBzY3JvbGxDYWNoZTogc2Nyb2xsQ2FjaGUsIG5hbWU6ICdib3R0b20nLCBkaXN0YW5jZTogYm90dG9tRGlzdCB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAobGVmdERpc3QgPD0gZWRnZVRocmVzaG9sZCAmJiB0aGlzLmV2ZXJNb3ZlZExlZnQgJiYgc2Nyb2xsQ2FjaGUuY2FuU2Nyb2xsTGVmdCgpICYmXG4gICAgICAgICAgICAgICAgICAgICghYmVzdFNpZGUgfHwgYmVzdFNpZGUuZGlzdGFuY2UgPiBsZWZ0RGlzdCkpIHtcbiAgICAgICAgICAgICAgICAgICAgYmVzdFNpZGUgPSB7IHNjcm9sbENhY2hlOiBzY3JvbGxDYWNoZSwgbmFtZTogJ2xlZnQnLCBkaXN0YW5jZTogbGVmdERpc3QgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHJpZ2h0RGlzdCA8PSBlZGdlVGhyZXNob2xkICYmIHRoaXMuZXZlck1vdmVkUmlnaHQgJiYgc2Nyb2xsQ2FjaGUuY2FuU2Nyb2xsUmlnaHQoKSAmJlxuICAgICAgICAgICAgICAgICAgICAoIWJlc3RTaWRlIHx8IGJlc3RTaWRlLmRpc3RhbmNlID4gcmlnaHREaXN0KSkge1xuICAgICAgICAgICAgICAgICAgICBiZXN0U2lkZSA9IHsgc2Nyb2xsQ2FjaGU6IHNjcm9sbENhY2hlLCBuYW1lOiAncmlnaHQnLCBkaXN0YW5jZTogcmlnaHREaXN0IH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBiZXN0U2lkZTtcbiAgICB9O1xuICAgIEF1dG9TY3JvbGxlci5wcm90b3R5cGUuYnVpbGRDYWNoZXMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnF1ZXJ5U2Nyb2xsRWxzKCkubWFwKGZ1bmN0aW9uIChlbCkge1xuICAgICAgICAgICAgaWYgKGVsID09PSB3aW5kb3cpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IFdpbmRvd1Njcm9sbEdlb21DYWNoZShmYWxzZSk7IC8vIGZhbHNlID0gZG9uJ3QgbGlzdGVuIHRvIHVzZXItZ2VuZXJhdGVkIHNjcm9sbHNcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgRWxlbWVudFNjcm9sbEdlb21DYWNoZShlbCwgZmFsc2UpOyAvLyBmYWxzZSA9IGRvbid0IGxpc3RlbiB0byB1c2VyLWdlbmVyYXRlZCBzY3JvbGxzXG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH07XG4gICAgQXV0b1Njcm9sbGVyLnByb3RvdHlwZS5xdWVyeVNjcm9sbEVscyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGVscyA9IFtdO1xuICAgICAgICBmb3IgKHZhciBfaSA9IDAsIF9hID0gdGhpcy5zY3JvbGxRdWVyeTsgX2kgPCBfYS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIHZhciBxdWVyeSA9IF9hW19pXTtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgcXVlcnkgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAgICAgZWxzLnB1c2gocXVlcnkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgZWxzLnB1c2guYXBwbHkoZWxzLCBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKHF1ZXJ5KSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBlbHM7XG4gICAgfTtcbiAgICByZXR1cm4gQXV0b1Njcm9sbGVyO1xufSgpKTtcblxuLypcbk1vbml0b3JzIGRyYWdnaW5nIG9uIGFuIGVsZW1lbnQuIEhhcyBhIG51bWJlciBvZiBoaWdoLWxldmVsIGZlYXR1cmVzOlxuLSBtaW5pbXVtIGRpc3RhbmNlIHJlcXVpcmVkIGJlZm9yZSBkcmFnZ2luZ1xuLSBtaW5pbXVtIHdhaXQgdGltZSAoXCJkZWxheVwiKSBiZWZvcmUgZHJhZ2dpbmdcbi0gYSBtaXJyb3IgZWxlbWVudCB0aGF0IGZvbGxvd3MgdGhlIHBvaW50ZXJcbiovXG52YXIgRmVhdHVyZWZ1bEVsZW1lbnREcmFnZ2luZyA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uIChfc3VwZXIpIHtcbiAgICBfX2V4dGVuZHMoRmVhdHVyZWZ1bEVsZW1lbnREcmFnZ2luZywgX3N1cGVyKTtcbiAgICBmdW5jdGlvbiBGZWF0dXJlZnVsRWxlbWVudERyYWdnaW5nKGNvbnRhaW5lckVsKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IF9zdXBlci5jYWxsKHRoaXMsIGNvbnRhaW5lckVsKSB8fCB0aGlzO1xuICAgICAgICAvLyBvcHRpb25zIHRoYXQgY2FuIGJlIGRpcmVjdGx5IHNldCBieSBjYWxsZXJcbiAgICAgICAgLy8gdGhlIGNhbGxlciBjYW4gYWxzbyBzZXQgdGhlIFBvaW50ZXJEcmFnZ2luZydzIG9wdGlvbnMgYXMgd2VsbFxuICAgICAgICBfdGhpcy5kZWxheSA9IG51bGw7XG4gICAgICAgIF90aGlzLm1pbkRpc3RhbmNlID0gMDtcbiAgICAgICAgX3RoaXMudG91Y2hTY3JvbGxBbGxvd2VkID0gdHJ1ZTsgLy8gcHJldmVudHMgZHJhZyBmcm9tIHN0YXJ0aW5nIGFuZCBibG9ja3Mgc2Nyb2xsaW5nIGR1cmluZyBkcmFnXG4gICAgICAgIF90aGlzLm1pcnJvck5lZWRzUmV2ZXJ0ID0gZmFsc2U7XG4gICAgICAgIF90aGlzLmlzSW50ZXJhY3RpbmcgPSBmYWxzZTsgLy8gaXMgdGhlIHVzZXIgdmFsaWRseSBtb3ZpbmcgdGhlIHBvaW50ZXI/IGxhc3RzIHVudGlsIHBvaW50ZXJ1cFxuICAgICAgICBfdGhpcy5pc0RyYWdnaW5nID0gZmFsc2U7IC8vIGlzIGl0IElOVEVOVEZVTExZIGRyYWdnaW5nPyBsYXN0cyB1bnRpbCBhZnRlciByZXZlcnQgYW5pbWF0aW9uXG4gICAgICAgIF90aGlzLmlzRGVsYXlFbmRlZCA9IGZhbHNlO1xuICAgICAgICBfdGhpcy5pc0Rpc3RhbmNlU3VycGFzc2VkID0gZmFsc2U7XG4gICAgICAgIF90aGlzLmRlbGF5VGltZW91dElkID0gbnVsbDtcbiAgICAgICAgX3RoaXMub25Qb2ludGVyRG93biA9IGZ1bmN0aW9uIChldikge1xuICAgICAgICAgICAgaWYgKCFfdGhpcy5pc0RyYWdnaW5nKSB7IC8vIHNvIG5ldyBkcmFnIGRvZXNuJ3QgaGFwcGVuIHdoaWxlIHJldmVydCBhbmltYXRpb24gaXMgZ29pbmdcbiAgICAgICAgICAgICAgICBfdGhpcy5pc0ludGVyYWN0aW5nID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBfdGhpcy5pc0RlbGF5RW5kZWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBfdGhpcy5pc0Rpc3RhbmNlU3VycGFzc2VkID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgcHJldmVudFNlbGVjdGlvbihkb2N1bWVudC5ib2R5KTtcbiAgICAgICAgICAgICAgICBwcmV2ZW50Q29udGV4dE1lbnUoZG9jdW1lbnQuYm9keSk7XG4gICAgICAgICAgICAgICAgLy8gcHJldmVudCBsaW5rcyBmcm9tIGJlaW5nIHZpc2l0ZWQgaWYgdGhlcmUncyBhbiBldmVudHVhbCBkcmFnLlxuICAgICAgICAgICAgICAgIC8vIGFsc28gcHJldmVudHMgc2VsZWN0aW9uIGluIG9sZGVyIGJyb3dzZXJzIChtYXliZT8pLlxuICAgICAgICAgICAgICAgIC8vIG5vdCBuZWNlc3NhcnkgZm9yIHRvdWNoLCBiZXNpZGVzLCBicm93c2VyIHdvdWxkIGNvbXBsYWluIGFib3V0IHBhc3NpdmVuZXNzLlxuICAgICAgICAgICAgICAgIGlmICghZXYuaXNUb3VjaCkge1xuICAgICAgICAgICAgICAgICAgICBldi5vcmlnRXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgX3RoaXMuZW1pdHRlci50cmlnZ2VyKCdwb2ludGVyZG93bicsIGV2KTtcbiAgICAgICAgICAgICAgICBpZiAoIV90aGlzLnBvaW50ZXIuc2hvdWxkSWdub3JlTW92ZSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBhY3Rpb25zIHJlbGF0ZWQgdG8gaW5pdGlhdGluZyBkcmFnc3RhcnQrZHJhZ21vdmUrZHJhZ2VuZC4uLlxuICAgICAgICAgICAgICAgICAgICBfdGhpcy5taXJyb3Iuc2V0SXNWaXNpYmxlKGZhbHNlKTsgLy8gcmVzZXQuIGNhbGxlciBtdXN0IHNldC12aXNpYmxlXG4gICAgICAgICAgICAgICAgICAgIF90aGlzLm1pcnJvci5zdGFydChldi5zdWJqZWN0RWwsIGV2LnBhZ2VYLCBldi5wYWdlWSk7IC8vIG11c3QgaGFwcGVuIG9uIGZpcnN0IHBvaW50ZXIgZG93blxuICAgICAgICAgICAgICAgICAgICBfdGhpcy5zdGFydERlbGF5KGV2KTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFfdGhpcy5taW5EaXN0YW5jZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgX3RoaXMuaGFuZGxlRGlzdGFuY2VTdXJwYXNzZWQoZXYpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICBfdGhpcy5vblBvaW50ZXJNb3ZlID0gZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICBpZiAoX3RoaXMuaXNJbnRlcmFjdGluZykgeyAvLyBpZiBmYWxzZSwgc3RpbGwgd2FpdGluZyBmb3IgcHJldmlvdXMgZHJhZydzIHJldmVydFxuICAgICAgICAgICAgICAgIF90aGlzLmVtaXR0ZXIudHJpZ2dlcigncG9pbnRlcm1vdmUnLCBldik7XG4gICAgICAgICAgICAgICAgaWYgKCFfdGhpcy5pc0Rpc3RhbmNlU3VycGFzc2VkKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBtaW5EaXN0YW5jZSA9IF90aGlzLm1pbkRpc3RhbmNlO1xuICAgICAgICAgICAgICAgICAgICB2YXIgZGlzdGFuY2VTcSA9IHZvaWQgMDsgLy8gY3VycmVudCBkaXN0YW5jZSBmcm9tIHRoZSBvcmlnaW4sIHNxdWFyZWRcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRlbHRhWCA9IGV2LmRlbHRhWCwgZGVsdGFZID0gZXYuZGVsdGFZO1xuICAgICAgICAgICAgICAgICAgICBkaXN0YW5jZVNxID0gZGVsdGFYICogZGVsdGFYICsgZGVsdGFZICogZGVsdGFZO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZGlzdGFuY2VTcSA+PSBtaW5EaXN0YW5jZSAqIG1pbkRpc3RhbmNlKSB7IC8vIHVzZSBweXRoYWdvcmVhbiB0aGVvcmVtXG4gICAgICAgICAgICAgICAgICAgICAgICBfdGhpcy5oYW5kbGVEaXN0YW5jZVN1cnBhc3NlZChldik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKF90aGlzLmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gYSByZWFsIHBvaW50ZXIgbW92ZT8gKG5vdCBvbmUgc2ltdWxhdGVkIGJ5IHNjcm9sbGluZylcbiAgICAgICAgICAgICAgICAgICAgaWYgKGV2Lm9yaWdFdmVudC50eXBlICE9PSAnc2Nyb2xsJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgX3RoaXMubWlycm9yLmhhbmRsZU1vdmUoZXYucGFnZVgsIGV2LnBhZ2VZKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIF90aGlzLmF1dG9TY3JvbGxlci5oYW5kbGVNb3ZlKGV2LnBhZ2VYLCBldi5wYWdlWSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgX3RoaXMuZW1pdHRlci50cmlnZ2VyKCdkcmFnbW92ZScsIGV2KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIF90aGlzLm9uUG9pbnRlclVwID0gZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICBpZiAoX3RoaXMuaXNJbnRlcmFjdGluZykgeyAvLyBpZiBmYWxzZSwgc3RpbGwgd2FpdGluZyBmb3IgcHJldmlvdXMgZHJhZydzIHJldmVydFxuICAgICAgICAgICAgICAgIF90aGlzLmlzSW50ZXJhY3RpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBhbGxvd1NlbGVjdGlvbihkb2N1bWVudC5ib2R5KTtcbiAgICAgICAgICAgICAgICBhbGxvd0NvbnRleHRNZW51KGRvY3VtZW50LmJvZHkpO1xuICAgICAgICAgICAgICAgIF90aGlzLmVtaXR0ZXIudHJpZ2dlcigncG9pbnRlcnVwJywgZXYpOyAvLyBjYW4gcG90ZW50aWFsbHkgc2V0IG1pcnJvck5lZWRzUmV2ZXJ0XG4gICAgICAgICAgICAgICAgaWYgKF90aGlzLmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgICAgICAgICAgICAgX3RoaXMuYXV0b1Njcm9sbGVyLnN0b3AoKTtcbiAgICAgICAgICAgICAgICAgICAgX3RoaXMudHJ5U3RvcERyYWcoZXYpOyAvLyB3aGljaCB3aWxsIHN0b3AgdGhlIG1pcnJvclxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoX3RoaXMuZGVsYXlUaW1lb3V0SWQpIHtcbiAgICAgICAgICAgICAgICAgICAgY2xlYXJUaW1lb3V0KF90aGlzLmRlbGF5VGltZW91dElkKTtcbiAgICAgICAgICAgICAgICAgICAgX3RoaXMuZGVsYXlUaW1lb3V0SWQgPSBudWxsO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdmFyIHBvaW50ZXIgPSBfdGhpcy5wb2ludGVyID0gbmV3IFBvaW50ZXJEcmFnZ2luZyhjb250YWluZXJFbCk7XG4gICAgICAgIHBvaW50ZXIuZW1pdHRlci5vbigncG9pbnRlcmRvd24nLCBfdGhpcy5vblBvaW50ZXJEb3duKTtcbiAgICAgICAgcG9pbnRlci5lbWl0dGVyLm9uKCdwb2ludGVybW92ZScsIF90aGlzLm9uUG9pbnRlck1vdmUpO1xuICAgICAgICBwb2ludGVyLmVtaXR0ZXIub24oJ3BvaW50ZXJ1cCcsIF90aGlzLm9uUG9pbnRlclVwKTtcbiAgICAgICAgX3RoaXMubWlycm9yID0gbmV3IEVsZW1lbnRNaXJyb3IoKTtcbiAgICAgICAgX3RoaXMuYXV0b1Njcm9sbGVyID0gbmV3IEF1dG9TY3JvbGxlcigpO1xuICAgICAgICByZXR1cm4gX3RoaXM7XG4gICAgfVxuICAgIEZlYXR1cmVmdWxFbGVtZW50RHJhZ2dpbmcucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMucG9pbnRlci5kZXN0cm95KCk7XG4gICAgfTtcbiAgICBGZWF0dXJlZnVsRWxlbWVudERyYWdnaW5nLnByb3RvdHlwZS5zdGFydERlbGF5ID0gZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5kZWxheSA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgICAgIHRoaXMuZGVsYXlUaW1lb3V0SWQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBfdGhpcy5kZWxheVRpbWVvdXRJZCA9IG51bGw7XG4gICAgICAgICAgICAgICAgX3RoaXMuaGFuZGxlRGVsYXlFbmQoZXYpO1xuICAgICAgICAgICAgfSwgdGhpcy5kZWxheSk7IC8vIG5vdCBhc3NpZ25hYmxlIHRvIG51bWJlciFcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuaGFuZGxlRGVsYXlFbmQoZXYpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBGZWF0dXJlZnVsRWxlbWVudERyYWdnaW5nLnByb3RvdHlwZS5oYW5kbGVEZWxheUVuZCA9IGZ1bmN0aW9uIChldikge1xuICAgICAgICB0aGlzLmlzRGVsYXlFbmRlZCA9IHRydWU7XG4gICAgICAgIHRoaXMudHJ5U3RhcnREcmFnKGV2KTtcbiAgICB9O1xuICAgIEZlYXR1cmVmdWxFbGVtZW50RHJhZ2dpbmcucHJvdG90eXBlLmhhbmRsZURpc3RhbmNlU3VycGFzc2VkID0gZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgIHRoaXMuaXNEaXN0YW5jZVN1cnBhc3NlZCA9IHRydWU7XG4gICAgICAgIHRoaXMudHJ5U3RhcnREcmFnKGV2KTtcbiAgICB9O1xuICAgIEZlYXR1cmVmdWxFbGVtZW50RHJhZ2dpbmcucHJvdG90eXBlLnRyeVN0YXJ0RHJhZyA9IGZ1bmN0aW9uIChldikge1xuICAgICAgICBpZiAodGhpcy5pc0RlbGF5RW5kZWQgJiYgdGhpcy5pc0Rpc3RhbmNlU3VycGFzc2VkKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMucG9pbnRlci53YXNUb3VjaFNjcm9sbCB8fCB0aGlzLnRvdWNoU2Nyb2xsQWxsb3dlZCkge1xuICAgICAgICAgICAgICAgIHRoaXMuaXNEcmFnZ2luZyA9IHRydWU7XG4gICAgICAgICAgICAgICAgdGhpcy5taXJyb3JOZWVkc1JldmVydCA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIHRoaXMuYXV0b1Njcm9sbGVyLnN0YXJ0KGV2LnBhZ2VYLCBldi5wYWdlWSk7XG4gICAgICAgICAgICAgICAgdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ2RyYWdzdGFydCcsIGV2KTtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy50b3VjaFNjcm9sbEFsbG93ZWQgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucG9pbnRlci5jYW5jZWxUb3VjaFNjcm9sbCgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG4gICAgRmVhdHVyZWZ1bEVsZW1lbnREcmFnZ2luZy5wcm90b3R5cGUudHJ5U3RvcERyYWcgPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgLy8gLnN0b3AoKSBpcyBBTFdBWVMgYXN5bmNocm9ub3VzLCB3aGljaCB3ZSBORUVEIGJlY2F1c2Ugd2Ugd2FudCBhbGwgcG9pbnRlcnVwIGV2ZW50c1xuICAgICAgICAvLyB0aGF0IGNvbWUgZnJvbSB0aGUgZG9jdW1lbnQgdG8gZmlyZSBiZWZvcmVoYW5kLiBtdWNoIG1vcmUgY29udmVuaWVudCB0aGlzIHdheS5cbiAgICAgICAgdGhpcy5taXJyb3Iuc3RvcCh0aGlzLm1pcnJvck5lZWRzUmV2ZXJ0LCB0aGlzLnN0b3BEcmFnLmJpbmQodGhpcywgZXYpIC8vIGJvdW5kIHdpdGggYXJnc1xuICAgICAgICApO1xuICAgIH07XG4gICAgRmVhdHVyZWZ1bEVsZW1lbnREcmFnZ2luZy5wcm90b3R5cGUuc3RvcERyYWcgPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgdGhpcy5pc0RyYWdnaW5nID0gZmFsc2U7XG4gICAgICAgIHRoaXMuZW1pdHRlci50cmlnZ2VyKCdkcmFnZW5kJywgZXYpO1xuICAgIH07XG4gICAgLy8gZmlsbCBpbiB0aGUgaW1wbGVtZW50YXRpb25zLi4uXG4gICAgRmVhdHVyZWZ1bEVsZW1lbnREcmFnZ2luZy5wcm90b3R5cGUuc2V0SWdub3JlTW92ZSA9IGZ1bmN0aW9uIChib29sKSB7XG4gICAgICAgIHRoaXMucG9pbnRlci5zaG91bGRJZ25vcmVNb3ZlID0gYm9vbDtcbiAgICB9O1xuICAgIEZlYXR1cmVmdWxFbGVtZW50RHJhZ2dpbmcucHJvdG90eXBlLnNldE1pcnJvcklzVmlzaWJsZSA9IGZ1bmN0aW9uIChib29sKSB7XG4gICAgICAgIHRoaXMubWlycm9yLnNldElzVmlzaWJsZShib29sKTtcbiAgICB9O1xuICAgIEZlYXR1cmVmdWxFbGVtZW50RHJhZ2dpbmcucHJvdG90eXBlLnNldE1pcnJvck5lZWRzUmV2ZXJ0ID0gZnVuY3Rpb24gKGJvb2wpIHtcbiAgICAgICAgdGhpcy5taXJyb3JOZWVkc1JldmVydCA9IGJvb2w7XG4gICAgfTtcbiAgICBGZWF0dXJlZnVsRWxlbWVudERyYWdnaW5nLnByb3RvdHlwZS5zZXRBdXRvU2Nyb2xsRW5hYmxlZCA9IGZ1bmN0aW9uIChib29sKSB7XG4gICAgICAgIHRoaXMuYXV0b1Njcm9sbGVyLmlzRW5hYmxlZCA9IGJvb2w7XG4gICAgfTtcbiAgICByZXR1cm4gRmVhdHVyZWZ1bEVsZW1lbnREcmFnZ2luZztcbn0oRWxlbWVudERyYWdnaW5nKSk7XG5cbi8qXG5XaGVuIHRoaXMgY2xhc3MgaXMgaW5zdGFudGlhdGVkLCBpdCByZWNvcmRzIHRoZSBvZmZzZXQgb2YgYW4gZWxlbWVudCAocmVsYXRpdmUgdG8gdGhlIGRvY3VtZW50IHRvcGxlZnQpLFxuYW5kIGNvbnRpbnVlcyB0byBtb25pdG9yIHNjcm9sbGluZywgdXBkYXRpbmcgdGhlIGNhY2hlZCBjb29yZGluYXRlcyBpZiBpdCBuZWVkcyB0by5cbkRvZXMgbm90IGFjY2VzcyB0aGUgRE9NIGFmdGVyIGluc3RhbnRpYXRpb24sIHNvIGhpZ2hseSBwZXJmb3JtYW50LlxuXG5BbHNvIGtlZXBzIHRyYWNrIG9mIGFsbCBzY3JvbGxpbmcvb3ZlcmZsb3c6aGlkZGVuIGNvbnRhaW5lcnMgdGhhdCBhcmUgcGFyZW50cyBvZiB0aGUgZ2l2ZW4gZWxlbWVudFxuYW5kIGFuIGRldGVybWluZSBpZiBhIGdpdmVuIHBvaW50IGlzIGluc2lkZSB0aGUgY29tYmluZWQgY2xpcHBpbmcgcmVjdGFuZ2xlLlxuKi9cbnZhciBPZmZzZXRUcmFja2VyID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIE9mZnNldFRyYWNrZXIoZWwpIHtcbiAgICAgICAgdGhpcy5vcmlnUmVjdCA9IGNvbXB1dGVSZWN0KGVsKTtcbiAgICAgICAgLy8gd2lsbCB3b3JrIGZpbmUgZm9yIGRpdnMgdGhhdCBoYXZlIG92ZXJmbG93OmhpZGRlblxuICAgICAgICB0aGlzLnNjcm9sbENhY2hlcyA9IGdldENsaXBwaW5nUGFyZW50cyhlbCkubWFwKGZ1bmN0aW9uIChlbCkge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBFbGVtZW50U2Nyb2xsR2VvbUNhY2hlKGVsLCB0cnVlKTsgLy8gbGlzdGVuPXRydWVcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIE9mZnNldFRyYWNrZXIucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGZvciAodmFyIF9pID0gMCwgX2EgPSB0aGlzLnNjcm9sbENhY2hlczsgX2kgPCBfYS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIHZhciBzY3JvbGxDYWNoZSA9IF9hW19pXTtcbiAgICAgICAgICAgIHNjcm9sbENhY2hlLmRlc3Ryb3koKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgT2Zmc2V0VHJhY2tlci5wcm90b3R5cGUuY29tcHV0ZUxlZnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBsZWZ0ID0gdGhpcy5vcmlnUmVjdC5sZWZ0O1xuICAgICAgICBmb3IgKHZhciBfaSA9IDAsIF9hID0gdGhpcy5zY3JvbGxDYWNoZXM7IF9pIDwgX2EubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICB2YXIgc2Nyb2xsQ2FjaGUgPSBfYVtfaV07XG4gICAgICAgICAgICBsZWZ0ICs9IHNjcm9sbENhY2hlLm9yaWdTY3JvbGxMZWZ0IC0gc2Nyb2xsQ2FjaGUuZ2V0U2Nyb2xsTGVmdCgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBsZWZ0O1xuICAgIH07XG4gICAgT2Zmc2V0VHJhY2tlci5wcm90b3R5cGUuY29tcHV0ZVRvcCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHRvcCA9IHRoaXMub3JpZ1JlY3QudG9wO1xuICAgICAgICBmb3IgKHZhciBfaSA9IDAsIF9hID0gdGhpcy5zY3JvbGxDYWNoZXM7IF9pIDwgX2EubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICB2YXIgc2Nyb2xsQ2FjaGUgPSBfYVtfaV07XG4gICAgICAgICAgICB0b3AgKz0gc2Nyb2xsQ2FjaGUub3JpZ1Njcm9sbFRvcCAtIHNjcm9sbENhY2hlLmdldFNjcm9sbFRvcCgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0b3A7XG4gICAgfTtcbiAgICBPZmZzZXRUcmFja2VyLnByb3RvdHlwZS5pc1dpdGhpbkNsaXBwaW5nID0gZnVuY3Rpb24gKHBhZ2VYLCBwYWdlWSkge1xuICAgICAgICB2YXIgcG9pbnQgPSB7IGxlZnQ6IHBhZ2VYLCB0b3A6IHBhZ2VZIH07XG4gICAgICAgIGZvciAodmFyIF9pID0gMCwgX2EgPSB0aGlzLnNjcm9sbENhY2hlczsgX2kgPCBfYS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIHZhciBzY3JvbGxDYWNoZSA9IF9hW19pXTtcbiAgICAgICAgICAgIGlmICghaXNJZ25vcmVkQ2xpcHBpbmcoc2Nyb2xsQ2FjaGUuZ2V0RXZlbnRUYXJnZXQoKSkgJiZcbiAgICAgICAgICAgICAgICAhcG9pbnRJbnNpZGVSZWN0KHBvaW50LCBzY3JvbGxDYWNoZS5jbGllbnRSZWN0KSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9O1xuICAgIHJldHVybiBPZmZzZXRUcmFja2VyO1xufSgpKTtcbi8vIGNlcnRhaW4gY2xpcHBpbmcgY29udGFpbmVycyBzaG91bGQgbmV2ZXIgY29uc3RyYWluIGludGVyYWN0aW9ucywgbGlrZSA8aHRtbD4gYW5kIDxib2R5PlxuLy8gaHR0cHM6Ly9naXRodWIuY29tL2Z1bGxjYWxlbmRhci9mdWxsY2FsZW5kYXIvaXNzdWVzLzM2MTVcbmZ1bmN0aW9uIGlzSWdub3JlZENsaXBwaW5nKG5vZGUpIHtcbiAgICB2YXIgdGFnTmFtZSA9IG5vZGUudGFnTmFtZTtcbiAgICByZXR1cm4gdGFnTmFtZSA9PT0gJ0hUTUwnIHx8IHRhZ05hbWUgPT09ICdCT0RZJztcbn1cblxuLypcblRyYWNrcyBtb3ZlbWVudCBvdmVyIG11bHRpcGxlIGRyb3BwYWJsZSBhcmVhcyAoYWthIFwiaGl0c1wiKVxudGhhdCBleGlzdCBpbiBvbmUgb3IgbW9yZSBEYXRlQ29tcG9uZW50cy5cblJlbGllcyBvbiBhbiBleGlzdGluZyBkcmFnZ2FibGUuXG5cbmVtaXRzOlxuLSBwb2ludGVyZG93blxuLSBkcmFnc3RhcnRcbi0gaGl0Y2hhbmdlIC0gZmlyZXMgaW5pdGlhbGx5LCBldmVuIGlmIG5vdCBvdmVyIGEgaGl0XG4tIHBvaW50ZXJ1cFxuLSAoaGl0Y2hhbmdlIC0gYWdhaW4sIHRvIG51bGwsIGlmIGVuZGVkIG92ZXIgYSBoaXQpXG4tIGRyYWdlbmRcbiovXG52YXIgSGl0RHJhZ2dpbmcgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gSGl0RHJhZ2dpbmcoZHJhZ2dpbmcsIGRyb3BwYWJsZVN0b3JlKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIC8vIG9wdGlvbnMgdGhhdCBjYW4gYmUgc2V0IGJ5IGNhbGxlclxuICAgICAgICB0aGlzLnVzZVN1YmplY3RDZW50ZXIgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5yZXF1aXJlSW5pdGlhbCA9IHRydWU7IC8vIGlmIGRvZXNuJ3Qgc3RhcnQgb3V0IG9uIGEgaGl0LCB3b24ndCBlbWl0IGFueSBldmVudHNcbiAgICAgICAgdGhpcy5pbml0aWFsSGl0ID0gbnVsbDtcbiAgICAgICAgdGhpcy5tb3ZpbmdIaXQgPSBudWxsO1xuICAgICAgICB0aGlzLmZpbmFsSGl0ID0gbnVsbDsgLy8gd29uJ3QgZXZlciBiZSBwb3B1bGF0ZWQgaWYgc2hvdWxkSWdub3JlTW92ZVxuICAgICAgICB0aGlzLmhhbmRsZVBvaW50ZXJEb3duID0gZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICB2YXIgZHJhZ2dpbmcgPSBfdGhpcy5kcmFnZ2luZztcbiAgICAgICAgICAgIF90aGlzLmluaXRpYWxIaXQgPSBudWxsO1xuICAgICAgICAgICAgX3RoaXMubW92aW5nSGl0ID0gbnVsbDtcbiAgICAgICAgICAgIF90aGlzLmZpbmFsSGl0ID0gbnVsbDtcbiAgICAgICAgICAgIF90aGlzLnByZXBhcmVIaXRzKCk7XG4gICAgICAgICAgICBfdGhpcy5wcm9jZXNzRmlyc3RDb29yZChldik7XG4gICAgICAgICAgICBpZiAoX3RoaXMuaW5pdGlhbEhpdCB8fCAhX3RoaXMucmVxdWlyZUluaXRpYWwpIHtcbiAgICAgICAgICAgICAgICBkcmFnZ2luZy5zZXRJZ25vcmVNb3ZlKGZhbHNlKTtcbiAgICAgICAgICAgICAgICBfdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ3BvaW50ZXJkb3duJywgZXYpOyAvLyBUT0RPOiBmaXJlIHRoaXMgYmVmb3JlIGNvbXB1dGluZyBwcm9jZXNzRmlyc3RDb29yZCwgc28gbGlzdGVuZXJzIGNhbiBjYW5jZWwuIHRoaXMgZ2V0cyBmaXJlZCBieSBhbG1vc3QgZXZlcnkgaGFuZGxlciA6KFxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgZHJhZ2dpbmcuc2V0SWdub3JlTW92ZSh0cnVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVEcmFnU3RhcnQgPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgICAgIF90aGlzLmVtaXR0ZXIudHJpZ2dlcignZHJhZ3N0YXJ0JywgZXYpO1xuICAgICAgICAgICAgX3RoaXMuaGFuZGxlTW92ZShldiwgdHJ1ZSk7IC8vIGZvcmNlID0gZmlyZSBldmVuIGlmIGluaXRpYWxseSBudWxsXG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlRHJhZ01vdmUgPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgICAgIF90aGlzLmVtaXR0ZXIudHJpZ2dlcignZHJhZ21vdmUnLCBldik7XG4gICAgICAgICAgICBfdGhpcy5oYW5kbGVNb3ZlKGV2KTtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVQb2ludGVyVXAgPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgICAgIF90aGlzLnJlbGVhc2VIaXRzKCk7XG4gICAgICAgICAgICBfdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ3BvaW50ZXJ1cCcsIGV2KTtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVEcmFnRW5kID0gZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICBpZiAoX3RoaXMubW92aW5nSGl0KSB7XG4gICAgICAgICAgICAgICAgX3RoaXMuZW1pdHRlci50cmlnZ2VyKCdoaXR1cGRhdGUnLCBudWxsLCB0cnVlLCBldik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBfdGhpcy5maW5hbEhpdCA9IF90aGlzLm1vdmluZ0hpdDtcbiAgICAgICAgICAgIF90aGlzLm1vdmluZ0hpdCA9IG51bGw7XG4gICAgICAgICAgICBfdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ2RyYWdlbmQnLCBldik7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuZHJvcHBhYmxlU3RvcmUgPSBkcm9wcGFibGVTdG9yZTtcbiAgICAgICAgZHJhZ2dpbmcuZW1pdHRlci5vbigncG9pbnRlcmRvd24nLCB0aGlzLmhhbmRsZVBvaW50ZXJEb3duKTtcbiAgICAgICAgZHJhZ2dpbmcuZW1pdHRlci5vbignZHJhZ3N0YXJ0JywgdGhpcy5oYW5kbGVEcmFnU3RhcnQpO1xuICAgICAgICBkcmFnZ2luZy5lbWl0dGVyLm9uKCdkcmFnbW92ZScsIHRoaXMuaGFuZGxlRHJhZ01vdmUpO1xuICAgICAgICBkcmFnZ2luZy5lbWl0dGVyLm9uKCdwb2ludGVydXAnLCB0aGlzLmhhbmRsZVBvaW50ZXJVcCk7XG4gICAgICAgIGRyYWdnaW5nLmVtaXR0ZXIub24oJ2RyYWdlbmQnLCB0aGlzLmhhbmRsZURyYWdFbmQpO1xuICAgICAgICB0aGlzLmRyYWdnaW5nID0gZHJhZ2dpbmc7XG4gICAgICAgIHRoaXMuZW1pdHRlciA9IG5ldyBFbWl0dGVyTWl4aW4oKTtcbiAgICB9XG4gICAgLy8gc2V0cyBpbml0aWFsSGl0XG4gICAgLy8gc2V0cyBjb29yZEFkanVzdFxuICAgIEhpdERyYWdnaW5nLnByb3RvdHlwZS5wcm9jZXNzRmlyc3RDb29yZCA9IGZ1bmN0aW9uIChldikge1xuICAgICAgICB2YXIgb3JpZ1BvaW50ID0geyBsZWZ0OiBldi5wYWdlWCwgdG9wOiBldi5wYWdlWSB9O1xuICAgICAgICB2YXIgYWRqdXN0ZWRQb2ludCA9IG9yaWdQb2ludDtcbiAgICAgICAgdmFyIHN1YmplY3RFbCA9IGV2LnN1YmplY3RFbDtcbiAgICAgICAgdmFyIHN1YmplY3RSZWN0O1xuICAgICAgICBpZiAoc3ViamVjdEVsICE9PSBkb2N1bWVudCkge1xuICAgICAgICAgICAgc3ViamVjdFJlY3QgPSBjb21wdXRlUmVjdChzdWJqZWN0RWwpO1xuICAgICAgICAgICAgYWRqdXN0ZWRQb2ludCA9IGNvbnN0cmFpblBvaW50KGFkanVzdGVkUG9pbnQsIHN1YmplY3RSZWN0KTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgaW5pdGlhbEhpdCA9IHRoaXMuaW5pdGlhbEhpdCA9IHRoaXMucXVlcnlIaXRGb3JPZmZzZXQoYWRqdXN0ZWRQb2ludC5sZWZ0LCBhZGp1c3RlZFBvaW50LnRvcCk7XG4gICAgICAgIGlmIChpbml0aWFsSGl0KSB7XG4gICAgICAgICAgICBpZiAodGhpcy51c2VTdWJqZWN0Q2VudGVyICYmIHN1YmplY3RSZWN0KSB7XG4gICAgICAgICAgICAgICAgdmFyIHNsaWNlZFN1YmplY3RSZWN0ID0gaW50ZXJzZWN0UmVjdHMoc3ViamVjdFJlY3QsIGluaXRpYWxIaXQucmVjdCk7XG4gICAgICAgICAgICAgICAgaWYgKHNsaWNlZFN1YmplY3RSZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgIGFkanVzdGVkUG9pbnQgPSBnZXRSZWN0Q2VudGVyKHNsaWNlZFN1YmplY3RSZWN0KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmNvb3JkQWRqdXN0ID0gZGlmZlBvaW50cyhhZGp1c3RlZFBvaW50LCBvcmlnUG9pbnQpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5jb29yZEFkanVzdCA9IHsgbGVmdDogMCwgdG9wOiAwIH07XG4gICAgICAgIH1cbiAgICB9O1xuICAgIEhpdERyYWdnaW5nLnByb3RvdHlwZS5oYW5kbGVNb3ZlID0gZnVuY3Rpb24gKGV2LCBmb3JjZUhhbmRsZSkge1xuICAgICAgICB2YXIgaGl0ID0gdGhpcy5xdWVyeUhpdEZvck9mZnNldChldi5wYWdlWCArIHRoaXMuY29vcmRBZGp1c3QubGVmdCwgZXYucGFnZVkgKyB0aGlzLmNvb3JkQWRqdXN0LnRvcCk7XG4gICAgICAgIGlmIChmb3JjZUhhbmRsZSB8fCAhaXNIaXRzRXF1YWwodGhpcy5tb3ZpbmdIaXQsIGhpdCkpIHtcbiAgICAgICAgICAgIHRoaXMubW92aW5nSGl0ID0gaGl0O1xuICAgICAgICAgICAgdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ2hpdHVwZGF0ZScsIGhpdCwgZmFsc2UsIGV2KTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgSGl0RHJhZ2dpbmcucHJvdG90eXBlLnByZXBhcmVIaXRzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLm9mZnNldFRyYWNrZXJzID0gbWFwSGFzaCh0aGlzLmRyb3BwYWJsZVN0b3JlLCBmdW5jdGlvbiAoaW50ZXJhY3Rpb25TZXR0aW5ncykge1xuICAgICAgICAgICAgaW50ZXJhY3Rpb25TZXR0aW5ncy5jb21wb25lbnQuYnVpbGRQb3NpdGlvbkNhY2hlcygpO1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBPZmZzZXRUcmFja2VyKGludGVyYWN0aW9uU2V0dGluZ3MuZWwpO1xuICAgICAgICB9KTtcbiAgICB9O1xuICAgIEhpdERyYWdnaW5nLnByb3RvdHlwZS5yZWxlYXNlSGl0cyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG9mZnNldFRyYWNrZXJzID0gdGhpcy5vZmZzZXRUcmFja2VycztcbiAgICAgICAgZm9yICh2YXIgaWQgaW4gb2Zmc2V0VHJhY2tlcnMpIHtcbiAgICAgICAgICAgIG9mZnNldFRyYWNrZXJzW2lkXS5kZXN0cm95KCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5vZmZzZXRUcmFja2VycyA9IHt9O1xuICAgIH07XG4gICAgSGl0RHJhZ2dpbmcucHJvdG90eXBlLnF1ZXJ5SGl0Rm9yT2Zmc2V0ID0gZnVuY3Rpb24gKG9mZnNldExlZnQsIG9mZnNldFRvcCkge1xuICAgICAgICB2YXIgX2EgPSB0aGlzLCBkcm9wcGFibGVTdG9yZSA9IF9hLmRyb3BwYWJsZVN0b3JlLCBvZmZzZXRUcmFja2VycyA9IF9hLm9mZnNldFRyYWNrZXJzO1xuICAgICAgICB2YXIgYmVzdEhpdCA9IG51bGw7XG4gICAgICAgIGZvciAodmFyIGlkIGluIGRyb3BwYWJsZVN0b3JlKSB7XG4gICAgICAgICAgICB2YXIgY29tcG9uZW50ID0gZHJvcHBhYmxlU3RvcmVbaWRdLmNvbXBvbmVudDtcbiAgICAgICAgICAgIHZhciBvZmZzZXRUcmFja2VyID0gb2Zmc2V0VHJhY2tlcnNbaWRdO1xuICAgICAgICAgICAgaWYgKG9mZnNldFRyYWNrZXIuaXNXaXRoaW5DbGlwcGluZyhvZmZzZXRMZWZ0LCBvZmZzZXRUb3ApKSB7XG4gICAgICAgICAgICAgICAgdmFyIG9yaWdpbkxlZnQgPSBvZmZzZXRUcmFja2VyLmNvbXB1dGVMZWZ0KCk7XG4gICAgICAgICAgICAgICAgdmFyIG9yaWdpblRvcCA9IG9mZnNldFRyYWNrZXIuY29tcHV0ZVRvcCgpO1xuICAgICAgICAgICAgICAgIHZhciBwb3NpdGlvbkxlZnQgPSBvZmZzZXRMZWZ0IC0gb3JpZ2luTGVmdDtcbiAgICAgICAgICAgICAgICB2YXIgcG9zaXRpb25Ub3AgPSBvZmZzZXRUb3AgLSBvcmlnaW5Ub3A7XG4gICAgICAgICAgICAgICAgdmFyIG9yaWdSZWN0ID0gb2Zmc2V0VHJhY2tlci5vcmlnUmVjdDtcbiAgICAgICAgICAgICAgICB2YXIgd2lkdGggPSBvcmlnUmVjdC5yaWdodCAtIG9yaWdSZWN0LmxlZnQ7XG4gICAgICAgICAgICAgICAgdmFyIGhlaWdodCA9IG9yaWdSZWN0LmJvdHRvbSAtIG9yaWdSZWN0LnRvcDtcbiAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgLy8gbXVzdCBiZSB3aXRoaW4gdGhlIGVsZW1lbnQncyBib3VuZHNcbiAgICAgICAgICAgICAgICBwb3NpdGlvbkxlZnQgPj0gMCAmJiBwb3NpdGlvbkxlZnQgPCB3aWR0aCAmJlxuICAgICAgICAgICAgICAgICAgICBwb3NpdGlvblRvcCA+PSAwICYmIHBvc2l0aW9uVG9wIDwgaGVpZ2h0KSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBoaXQgPSBjb21wb25lbnQucXVlcnlIaXQocG9zaXRpb25MZWZ0LCBwb3NpdGlvblRvcCwgd2lkdGgsIGhlaWdodCk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChoaXQgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIChcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1ha2Ugc3VyZSB0aGUgaGl0IGlzIHdpdGhpbiBhY3RpdmVSYW5nZSwgbWVhbmluZyBpdCdzIG5vdCBhIGRlYWwgY2VsbFxuICAgICAgICAgICAgICAgICAgICAgICAgIWNvbXBvbmVudC5wcm9wcy5kYXRlUHJvZmlsZSB8fCAvLyBoYWNrIGZvciBEYXlUaWxlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZ2VDb250YWluc1JhbmdlKGNvbXBvbmVudC5wcm9wcy5kYXRlUHJvZmlsZS5hY3RpdmVSYW5nZSwgaGl0LmRhdGVTcGFuLnJhbmdlKSkgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICghYmVzdEhpdCB8fCBoaXQubGF5ZXIgPiBiZXN0SGl0LmxheWVyKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVE9ETzogYmV0dGVyIHdheSB0byByZS1vcmllbnQgcmVjdGFuZ2xlXG4gICAgICAgICAgICAgICAgICAgICAgICBoaXQucmVjdC5sZWZ0ICs9IG9yaWdpbkxlZnQ7XG4gICAgICAgICAgICAgICAgICAgICAgICBoaXQucmVjdC5yaWdodCArPSBvcmlnaW5MZWZ0O1xuICAgICAgICAgICAgICAgICAgICAgICAgaGl0LnJlY3QudG9wICs9IG9yaWdpblRvcDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGhpdC5yZWN0LmJvdHRvbSArPSBvcmlnaW5Ub3A7XG4gICAgICAgICAgICAgICAgICAgICAgICBiZXN0SGl0ID0gaGl0O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBiZXN0SGl0O1xuICAgIH07XG4gICAgcmV0dXJuIEhpdERyYWdnaW5nO1xufSgpKTtcbmZ1bmN0aW9uIGlzSGl0c0VxdWFsKGhpdDAsIGhpdDEpIHtcbiAgICBpZiAoIWhpdDAgJiYgIWhpdDEpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGlmIChCb29sZWFuKGhpdDApICE9PSBCb29sZWFuKGhpdDEpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIGlzRGF0ZVNwYW5zRXF1YWwoaGl0MC5kYXRlU3BhbiwgaGl0MS5kYXRlU3Bhbik7XG59XG5cbi8qXG5Nb25pdG9ycyB3aGVuIHRoZSB1c2VyIGNsaWNrcyBvbiBhIHNwZWNpZmljIGRhdGUvdGltZSBvZiBhIGNvbXBvbmVudC5cbkEgcG9pbnRlcmRvd24rcG9pbnRlcnVwIG9uIHRoZSBzYW1lIFwiaGl0XCIgY29uc3RpdHV0ZXMgYSBjbGljay5cbiovXG52YXIgRGF0ZUNsaWNraW5nID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKF9zdXBlcikge1xuICAgIF9fZXh0ZW5kcyhEYXRlQ2xpY2tpbmcsIF9zdXBlcik7XG4gICAgZnVuY3Rpb24gRGF0ZUNsaWNraW5nKHNldHRpbmdzKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IF9zdXBlci5jYWxsKHRoaXMsIHNldHRpbmdzKSB8fCB0aGlzO1xuICAgICAgICBfdGhpcy5oYW5kbGVQb2ludGVyRG93biA9IGZ1bmN0aW9uIChldikge1xuICAgICAgICAgICAgdmFyIGRyYWdnaW5nID0gX3RoaXMuZHJhZ2dpbmc7XG4gICAgICAgICAgICAvLyBkbyB0aGlzIGluIHBvaW50ZXJkb3duIChub3QgZHJhZ2VuZCkgYmVjYXVzZSBET00gbWlnaHQgYmUgbXV0YXRlZCBieSB0aGUgdGltZSBkcmFnZW5kIGlzIGZpcmVkXG4gICAgICAgICAgICBkcmFnZ2luZy5zZXRJZ25vcmVNb3ZlKCFfdGhpcy5jb21wb25lbnQuaXNWYWxpZERhdGVEb3duRWwoZHJhZ2dpbmcucG9pbnRlci5kb3duRWwpKTtcbiAgICAgICAgfTtcbiAgICAgICAgLy8gd29uJ3QgZXZlbiBmaXJlIGlmIG1vdmluZyB3YXMgaWdub3JlZFxuICAgICAgICBfdGhpcy5oYW5kbGVEcmFnRW5kID0gZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICB2YXIgY29tcG9uZW50ID0gX3RoaXMuY29tcG9uZW50O1xuICAgICAgICAgICAgdmFyIF9hID0gY29tcG9uZW50LmNvbnRleHQsIGNhbGVuZGFyID0gX2EuY2FsZW5kYXIsIHZpZXcgPSBfYS52aWV3O1xuICAgICAgICAgICAgdmFyIHBvaW50ZXIgPSBfdGhpcy5kcmFnZ2luZy5wb2ludGVyO1xuICAgICAgICAgICAgaWYgKCFwb2ludGVyLndhc1RvdWNoU2Nyb2xsKSB7XG4gICAgICAgICAgICAgICAgdmFyIF9iID0gX3RoaXMuaGl0RHJhZ2dpbmcsIGluaXRpYWxIaXQgPSBfYi5pbml0aWFsSGl0LCBmaW5hbEhpdCA9IF9iLmZpbmFsSGl0O1xuICAgICAgICAgICAgICAgIGlmIChpbml0aWFsSGl0ICYmIGZpbmFsSGl0ICYmIGlzSGl0c0VxdWFsKGluaXRpYWxIaXQsIGZpbmFsSGl0KSkge1xuICAgICAgICAgICAgICAgICAgICBjYWxlbmRhci50cmlnZ2VyRGF0ZUNsaWNrKGluaXRpYWxIaXQuZGF0ZVNwYW4sIGluaXRpYWxIaXQuZGF5RWwsIHZpZXcsIGV2Lm9yaWdFdmVudCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICB2YXIgY29tcG9uZW50ID0gc2V0dGluZ3MuY29tcG9uZW50O1xuICAgICAgICAvLyB3ZSBETyB3YW50IHRvIHdhdGNoIHBvaW50ZXIgbW92ZXMgYmVjYXVzZSBvdGhlcndpc2UgZmluYWxIaXQgd29uJ3QgZ2V0IHBvcHVsYXRlZFxuICAgICAgICBfdGhpcy5kcmFnZ2luZyA9IG5ldyBGZWF0dXJlZnVsRWxlbWVudERyYWdnaW5nKGNvbXBvbmVudC5lbCk7XG4gICAgICAgIF90aGlzLmRyYWdnaW5nLmF1dG9TY3JvbGxlci5pc0VuYWJsZWQgPSBmYWxzZTtcbiAgICAgICAgdmFyIGhpdERyYWdnaW5nID0gX3RoaXMuaGl0RHJhZ2dpbmcgPSBuZXcgSGl0RHJhZ2dpbmcoX3RoaXMuZHJhZ2dpbmcsIGludGVyYWN0aW9uU2V0dGluZ3NUb1N0b3JlKHNldHRpbmdzKSk7XG4gICAgICAgIGhpdERyYWdnaW5nLmVtaXR0ZXIub24oJ3BvaW50ZXJkb3duJywgX3RoaXMuaGFuZGxlUG9pbnRlckRvd24pO1xuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdkcmFnZW5kJywgX3RoaXMuaGFuZGxlRHJhZ0VuZCk7XG4gICAgICAgIHJldHVybiBfdGhpcztcbiAgICB9XG4gICAgRGF0ZUNsaWNraW5nLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLmRyYWdnaW5nLmRlc3Ryb3koKTtcbiAgICB9O1xuICAgIHJldHVybiBEYXRlQ2xpY2tpbmc7XG59KEludGVyYWN0aW9uKSk7XG5cbi8qXG5UcmFja3Mgd2hlbiB0aGUgdXNlciBzZWxlY3RzIGEgcG9ydGlvbiBvZiB0aW1lIG9mIGEgY29tcG9uZW50LFxuY29uc3RpdHV0ZWQgYnkgYSBkcmFnIG92ZXIgZGF0ZSBjZWxscywgd2l0aCBhIHBvc3NpYmxlIGRlbGF5IGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIGRyYWcuXG4qL1xudmFyIERhdGVTZWxlY3RpbmcgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoX3N1cGVyKSB7XG4gICAgX19leHRlbmRzKERhdGVTZWxlY3RpbmcsIF9zdXBlcik7XG4gICAgZnVuY3Rpb24gRGF0ZVNlbGVjdGluZyhzZXR0aW5ncykge1xuICAgICAgICB2YXIgX3RoaXMgPSBfc3VwZXIuY2FsbCh0aGlzLCBzZXR0aW5ncykgfHwgdGhpcztcbiAgICAgICAgX3RoaXMuZHJhZ1NlbGVjdGlvbiA9IG51bGw7XG4gICAgICAgIF90aGlzLmhhbmRsZVBvaW50ZXJEb3duID0gZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICB2YXIgX2EgPSBfdGhpcywgY29tcG9uZW50ID0gX2EuY29tcG9uZW50LCBkcmFnZ2luZyA9IF9hLmRyYWdnaW5nO1xuICAgICAgICAgICAgdmFyIG9wdGlvbnMgPSBjb21wb25lbnQuY29udGV4dC5vcHRpb25zO1xuICAgICAgICAgICAgdmFyIGNhblNlbGVjdCA9IG9wdGlvbnMuc2VsZWN0YWJsZSAmJlxuICAgICAgICAgICAgICAgIGNvbXBvbmVudC5pc1ZhbGlkRGF0ZURvd25FbChldi5vcmlnRXZlbnQudGFyZ2V0KTtcbiAgICAgICAgICAgIC8vIGRvbid0IGJvdGhlciB0byB3YXRjaCBleHBlbnNpdmUgbW92ZXMgaWYgY29tcG9uZW50IHdvbid0IGRvIHNlbGVjdGlvblxuICAgICAgICAgICAgZHJhZ2dpbmcuc2V0SWdub3JlTW92ZSghY2FuU2VsZWN0KTtcbiAgICAgICAgICAgIC8vIGlmIHRvdWNoLCByZXF1aXJlIHVzZXIgdG8gaG9sZCBkb3duXG4gICAgICAgICAgICBkcmFnZ2luZy5kZWxheSA9IGV2LmlzVG91Y2ggPyBnZXRDb21wb25lbnRUb3VjaERlbGF5KGNvbXBvbmVudCkgOiBudWxsO1xuICAgICAgICB9O1xuICAgICAgICBfdGhpcy5oYW5kbGVEcmFnU3RhcnQgPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgICAgIF90aGlzLmNvbXBvbmVudC5jb250ZXh0LmNhbGVuZGFyLnVuc2VsZWN0KGV2KTsgLy8gdW5zZWxlY3QgcHJldmlvdXMgc2VsZWN0aW9uc1xuICAgICAgICB9O1xuICAgICAgICBfdGhpcy5oYW5kbGVIaXRVcGRhdGUgPSBmdW5jdGlvbiAoaGl0LCBpc0ZpbmFsKSB7XG4gICAgICAgICAgICB2YXIgY2FsZW5kYXIgPSBfdGhpcy5jb21wb25lbnQuY29udGV4dC5jYWxlbmRhcjtcbiAgICAgICAgICAgIHZhciBkcmFnU2VsZWN0aW9uID0gbnVsbDtcbiAgICAgICAgICAgIHZhciBpc0ludmFsaWQgPSBmYWxzZTtcbiAgICAgICAgICAgIGlmIChoaXQpIHtcbiAgICAgICAgICAgICAgICBkcmFnU2VsZWN0aW9uID0gam9pbkhpdHNJbnRvU2VsZWN0aW9uKF90aGlzLmhpdERyYWdnaW5nLmluaXRpYWxIaXQsIGhpdCwgY2FsZW5kYXIucGx1Z2luU3lzdGVtLmhvb2tzLmRhdGVTZWxlY3Rpb25UcmFuc2Zvcm1lcnMpO1xuICAgICAgICAgICAgICAgIGlmICghZHJhZ1NlbGVjdGlvbiB8fCAhX3RoaXMuY29tcG9uZW50LmlzRGF0ZVNlbGVjdGlvblZhbGlkKGRyYWdTZWxlY3Rpb24pKSB7XG4gICAgICAgICAgICAgICAgICAgIGlzSW52YWxpZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIGRyYWdTZWxlY3Rpb24gPSBudWxsO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChkcmFnU2VsZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgY2FsZW5kYXIuZGlzcGF0Y2goeyB0eXBlOiAnU0VMRUNUX0RBVEVTJywgc2VsZWN0aW9uOiBkcmFnU2VsZWN0aW9uIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoIWlzRmluYWwpIHsgLy8gb25seSB1bnNlbGVjdCBpZiBtb3ZlZCBhd2F5IHdoaWxlIGRyYWdnaW5nXG4gICAgICAgICAgICAgICAgY2FsZW5kYXIuZGlzcGF0Y2goeyB0eXBlOiAnVU5TRUxFQ1RfREFURVMnIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFpc0ludmFsaWQpIHtcbiAgICAgICAgICAgICAgICBlbmFibGVDdXJzb3IoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGRpc2FibGVDdXJzb3IoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghaXNGaW5hbCkge1xuICAgICAgICAgICAgICAgIF90aGlzLmRyYWdTZWxlY3Rpb24gPSBkcmFnU2VsZWN0aW9uOyAvLyBvbmx5IGNsZWFyIGlmIG1vdmVkIGF3YXkgZnJvbSBhbGwgaGl0cyB3aGlsZSBkcmFnZ2luZ1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICBfdGhpcy5oYW5kbGVQb2ludGVyVXAgPSBmdW5jdGlvbiAocGV2KSB7XG4gICAgICAgICAgICBpZiAoX3RoaXMuZHJhZ1NlbGVjdGlvbikge1xuICAgICAgICAgICAgICAgIC8vIHNlbGVjdGlvbiBpcyBhbHJlYWR5IHJlbmRlcmVkLCBzbyBqdXN0IG5lZWQgdG8gcmVwb3J0IHNlbGVjdGlvblxuICAgICAgICAgICAgICAgIF90aGlzLmNvbXBvbmVudC5jb250ZXh0LmNhbGVuZGFyLnRyaWdnZXJEYXRlU2VsZWN0KF90aGlzLmRyYWdTZWxlY3Rpb24sIHBldik7XG4gICAgICAgICAgICAgICAgX3RoaXMuZHJhZ1NlbGVjdGlvbiA9IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIHZhciBjb21wb25lbnQgPSBzZXR0aW5ncy5jb21wb25lbnQ7XG4gICAgICAgIHZhciBvcHRpb25zID0gY29tcG9uZW50LmNvbnRleHQub3B0aW9ucztcbiAgICAgICAgdmFyIGRyYWdnaW5nID0gX3RoaXMuZHJhZ2dpbmcgPSBuZXcgRmVhdHVyZWZ1bEVsZW1lbnREcmFnZ2luZyhjb21wb25lbnQuZWwpO1xuICAgICAgICBkcmFnZ2luZy50b3VjaFNjcm9sbEFsbG93ZWQgPSBmYWxzZTtcbiAgICAgICAgZHJhZ2dpbmcubWluRGlzdGFuY2UgPSBvcHRpb25zLnNlbGVjdE1pbkRpc3RhbmNlIHx8IDA7XG4gICAgICAgIGRyYWdnaW5nLmF1dG9TY3JvbGxlci5pc0VuYWJsZWQgPSBvcHRpb25zLmRyYWdTY3JvbGw7XG4gICAgICAgIHZhciBoaXREcmFnZ2luZyA9IF90aGlzLmhpdERyYWdnaW5nID0gbmV3IEhpdERyYWdnaW5nKF90aGlzLmRyYWdnaW5nLCBpbnRlcmFjdGlvblNldHRpbmdzVG9TdG9yZShzZXR0aW5ncykpO1xuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdwb2ludGVyZG93bicsIF90aGlzLmhhbmRsZVBvaW50ZXJEb3duKTtcbiAgICAgICAgaGl0RHJhZ2dpbmcuZW1pdHRlci5vbignZHJhZ3N0YXJ0JywgX3RoaXMuaGFuZGxlRHJhZ1N0YXJ0KTtcbiAgICAgICAgaGl0RHJhZ2dpbmcuZW1pdHRlci5vbignaGl0dXBkYXRlJywgX3RoaXMuaGFuZGxlSGl0VXBkYXRlKTtcbiAgICAgICAgaGl0RHJhZ2dpbmcuZW1pdHRlci5vbigncG9pbnRlcnVwJywgX3RoaXMuaGFuZGxlUG9pbnRlclVwKTtcbiAgICAgICAgcmV0dXJuIF90aGlzO1xuICAgIH1cbiAgICBEYXRlU2VsZWN0aW5nLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLmRyYWdnaW5nLmRlc3Ryb3koKTtcbiAgICB9O1xuICAgIHJldHVybiBEYXRlU2VsZWN0aW5nO1xufShJbnRlcmFjdGlvbikpO1xuZnVuY3Rpb24gZ2V0Q29tcG9uZW50VG91Y2hEZWxheShjb21wb25lbnQpIHtcbiAgICB2YXIgb3B0aW9ucyA9IGNvbXBvbmVudC5jb250ZXh0Lm9wdGlvbnM7XG4gICAgdmFyIGRlbGF5ID0gb3B0aW9ucy5zZWxlY3RMb25nUHJlc3NEZWxheTtcbiAgICBpZiAoZGVsYXkgPT0gbnVsbCkge1xuICAgICAgICBkZWxheSA9IG9wdGlvbnMubG9uZ1ByZXNzRGVsYXk7XG4gICAgfVxuICAgIHJldHVybiBkZWxheTtcbn1cbmZ1bmN0aW9uIGpvaW5IaXRzSW50b1NlbGVjdGlvbihoaXQwLCBoaXQxLCBkYXRlU2VsZWN0aW9uVHJhbnNmb3JtZXJzKSB7XG4gICAgdmFyIGRhdGVTcGFuMCA9IGhpdDAuZGF0ZVNwYW47XG4gICAgdmFyIGRhdGVTcGFuMSA9IGhpdDEuZGF0ZVNwYW47XG4gICAgdmFyIG1zID0gW1xuICAgICAgICBkYXRlU3BhbjAucmFuZ2Uuc3RhcnQsXG4gICAgICAgIGRhdGVTcGFuMC5yYW5nZS5lbmQsXG4gICAgICAgIGRhdGVTcGFuMS5yYW5nZS5zdGFydCxcbiAgICAgICAgZGF0ZVNwYW4xLnJhbmdlLmVuZFxuICAgIF07XG4gICAgbXMuc29ydChjb21wYXJlTnVtYmVycyk7XG4gICAgdmFyIHByb3BzID0ge307XG4gICAgZm9yICh2YXIgX2kgPSAwLCBkYXRlU2VsZWN0aW9uVHJhbnNmb3JtZXJzXzEgPSBkYXRlU2VsZWN0aW9uVHJhbnNmb3JtZXJzOyBfaSA8IGRhdGVTZWxlY3Rpb25UcmFuc2Zvcm1lcnNfMS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgdmFyIHRyYW5zZm9ybWVyID0gZGF0ZVNlbGVjdGlvblRyYW5zZm9ybWVyc18xW19pXTtcbiAgICAgICAgdmFyIHJlcyA9IHRyYW5zZm9ybWVyKGhpdDAsIGhpdDEpO1xuICAgICAgICBpZiAocmVzID09PSBmYWxzZSkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAocmVzKSB7XG4gICAgICAgICAgICBfX2Fzc2lnbihwcm9wcywgcmVzKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBwcm9wcy5yYW5nZSA9IHsgc3RhcnQ6IG1zWzBdLCBlbmQ6IG1zWzNdIH07XG4gICAgcHJvcHMuYWxsRGF5ID0gZGF0ZVNwYW4wLmFsbERheTtcbiAgICByZXR1cm4gcHJvcHM7XG59XG5cbnZhciBFdmVudERyYWdnaW5nID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKF9zdXBlcikge1xuICAgIF9fZXh0ZW5kcyhFdmVudERyYWdnaW5nLCBfc3VwZXIpO1xuICAgIGZ1bmN0aW9uIEV2ZW50RHJhZ2dpbmcoc2V0dGluZ3MpIHtcbiAgICAgICAgdmFyIF90aGlzID0gX3N1cGVyLmNhbGwodGhpcywgc2V0dGluZ3MpIHx8IHRoaXM7XG4gICAgICAgIC8vIGludGVybmFsIHN0YXRlXG4gICAgICAgIF90aGlzLnN1YmplY3RTZWcgPSBudWxsOyAvLyB0aGUgc2VnIGJlaW5nIHNlbGVjdGVkL2RyYWdnZWRcbiAgICAgICAgX3RoaXMuaXNEcmFnZ2luZyA9IGZhbHNlO1xuICAgICAgICBfdGhpcy5ldmVudFJhbmdlID0gbnVsbDtcbiAgICAgICAgX3RoaXMucmVsZXZhbnRFdmVudHMgPSBudWxsOyAvLyB0aGUgZXZlbnRzIGJlaW5nIGRyYWdnZWRcbiAgICAgICAgX3RoaXMucmVjZWl2aW5nQ2FsZW5kYXIgPSBudWxsO1xuICAgICAgICBfdGhpcy52YWxpZE11dGF0aW9uID0gbnVsbDtcbiAgICAgICAgX3RoaXMubXV0YXRlZFJlbGV2YW50RXZlbnRzID0gbnVsbDtcbiAgICAgICAgX3RoaXMuaGFuZGxlUG9pbnRlckRvd24gPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgICAgIHZhciBvcmlnVGFyZ2V0ID0gZXYub3JpZ0V2ZW50LnRhcmdldDtcbiAgICAgICAgICAgIHZhciBfYSA9IF90aGlzLCBjb21wb25lbnQgPSBfYS5jb21wb25lbnQsIGRyYWdnaW5nID0gX2EuZHJhZ2dpbmc7XG4gICAgICAgICAgICB2YXIgbWlycm9yID0gZHJhZ2dpbmcubWlycm9yO1xuICAgICAgICAgICAgdmFyIG9wdGlvbnMgPSBjb21wb25lbnQuY29udGV4dC5vcHRpb25zO1xuICAgICAgICAgICAgdmFyIGluaXRpYWxDYWxlbmRhciA9IGNvbXBvbmVudC5jb250ZXh0LmNhbGVuZGFyO1xuICAgICAgICAgICAgdmFyIHN1YmplY3RTZWcgPSBfdGhpcy5zdWJqZWN0U2VnID0gZ2V0RWxTZWcoZXYuc3ViamVjdEVsKTtcbiAgICAgICAgICAgIHZhciBldmVudFJhbmdlID0gX3RoaXMuZXZlbnRSYW5nZSA9IHN1YmplY3RTZWcuZXZlbnRSYW5nZTtcbiAgICAgICAgICAgIHZhciBldmVudEluc3RhbmNlSWQgPSBldmVudFJhbmdlLmluc3RhbmNlLmluc3RhbmNlSWQ7XG4gICAgICAgICAgICBfdGhpcy5yZWxldmFudEV2ZW50cyA9IGdldFJlbGV2YW50RXZlbnRzKGluaXRpYWxDYWxlbmRhci5zdGF0ZS5ldmVudFN0b3JlLCBldmVudEluc3RhbmNlSWQpO1xuICAgICAgICAgICAgZHJhZ2dpbmcubWluRGlzdGFuY2UgPSBldi5pc1RvdWNoID8gMCA6IG9wdGlvbnMuZXZlbnREcmFnTWluRGlzdGFuY2U7XG4gICAgICAgICAgICBkcmFnZ2luZy5kZWxheSA9XG4gICAgICAgICAgICAgICAgLy8gb25seSBkbyBhIHRvdWNoIGRlbGF5IGlmIHRvdWNoIGFuZCB0aGlzIGV2ZW50IGhhc24ndCBiZWVuIHNlbGVjdGVkIHlldFxuICAgICAgICAgICAgICAgIChldi5pc1RvdWNoICYmIGV2ZW50SW5zdGFuY2VJZCAhPT0gY29tcG9uZW50LnByb3BzLmV2ZW50U2VsZWN0aW9uKSA/XG4gICAgICAgICAgICAgICAgICAgIGdldENvbXBvbmVudFRvdWNoRGVsYXkkMShjb21wb25lbnQpIDpcbiAgICAgICAgICAgICAgICAgICAgbnVsbDtcbiAgICAgICAgICAgIG1pcnJvci5wYXJlbnROb2RlID0gaW5pdGlhbENhbGVuZGFyLmVsO1xuICAgICAgICAgICAgbWlycm9yLnJldmVydER1cmF0aW9uID0gb3B0aW9ucy5kcmFnUmV2ZXJ0RHVyYXRpb247XG4gICAgICAgICAgICB2YXIgaXNWYWxpZCA9IGNvbXBvbmVudC5pc1ZhbGlkU2VnRG93bkVsKG9yaWdUYXJnZXQpICYmXG4gICAgICAgICAgICAgICAgIWVsZW1lbnRDbG9zZXN0KG9yaWdUYXJnZXQsICcuZmMtcmVzaXplcicpOyAvLyBOT1Qgb24gYSByZXNpemVyXG4gICAgICAgICAgICBkcmFnZ2luZy5zZXRJZ25vcmVNb3ZlKCFpc1ZhbGlkKTtcbiAgICAgICAgICAgIC8vIGRpc2FibGUgZHJhZ2dpbmcgZm9yIGVsZW1lbnRzIHRoYXQgYXJlIHJlc2l6YWJsZSAoaWUsIHNlbGVjdGFibGUpXG4gICAgICAgICAgICAvLyBidXQgYXJlIG5vdCBkcmFnZ2FibGVcbiAgICAgICAgICAgIF90aGlzLmlzRHJhZ2dpbmcgPSBpc1ZhbGlkICYmXG4gICAgICAgICAgICAgICAgZXYuc3ViamVjdEVsLmNsYXNzTGlzdC5jb250YWlucygnZmMtZHJhZ2dhYmxlJyk7XG4gICAgICAgIH07XG4gICAgICAgIF90aGlzLmhhbmRsZURyYWdTdGFydCA9IGZ1bmN0aW9uIChldikge1xuICAgICAgICAgICAgdmFyIGNvbnRleHQgPSBfdGhpcy5jb21wb25lbnQuY29udGV4dDtcbiAgICAgICAgICAgIHZhciBpbml0aWFsQ2FsZW5kYXIgPSBjb250ZXh0LmNhbGVuZGFyO1xuICAgICAgICAgICAgdmFyIGV2ZW50UmFuZ2UgPSBfdGhpcy5ldmVudFJhbmdlO1xuICAgICAgICAgICAgdmFyIGV2ZW50SW5zdGFuY2VJZCA9IGV2ZW50UmFuZ2UuaW5zdGFuY2UuaW5zdGFuY2VJZDtcbiAgICAgICAgICAgIGlmIChldi5pc1RvdWNoKSB7XG4gICAgICAgICAgICAgICAgLy8gbmVlZCB0byBzZWxlY3QgYSBkaWZmZXJlbnQgZXZlbnQ/XG4gICAgICAgICAgICAgICAgaWYgKGV2ZW50SW5zdGFuY2VJZCAhPT0gX3RoaXMuY29tcG9uZW50LnByb3BzLmV2ZW50U2VsZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIGluaXRpYWxDYWxlbmRhci5kaXNwYXRjaCh7IHR5cGU6ICdTRUxFQ1RfRVZFTlQnLCBldmVudEluc3RhbmNlSWQ6IGV2ZW50SW5zdGFuY2VJZCB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBpZiBub3cgdXNpbmcgbW91c2UsIGJ1dCB3YXMgcHJldmlvdXMgdG91Y2ggaW50ZXJhY3Rpb24sIGNsZWFyIHNlbGVjdGVkIGV2ZW50XG4gICAgICAgICAgICAgICAgaW5pdGlhbENhbGVuZGFyLmRpc3BhdGNoKHsgdHlwZTogJ1VOU0VMRUNUX0VWRU5UJyB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChfdGhpcy5pc0RyYWdnaW5nKSB7XG4gICAgICAgICAgICAgICAgaW5pdGlhbENhbGVuZGFyLnVuc2VsZWN0KGV2KTsgLy8gdW5zZWxlY3QgKmRhdGUqIHNlbGVjdGlvblxuICAgICAgICAgICAgICAgIGluaXRpYWxDYWxlbmRhci5wdWJsaWNseVRyaWdnZXIoJ2V2ZW50RHJhZ1N0YXJ0JywgW1xuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbDogX3RoaXMuc3ViamVjdFNlZy5lbCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50OiBuZXcgRXZlbnRBcGkoaW5pdGlhbENhbGVuZGFyLCBldmVudFJhbmdlLmRlZiwgZXZlbnRSYW5nZS5pbnN0YW5jZSksXG4gICAgICAgICAgICAgICAgICAgICAgICBqc0V2ZW50OiBldi5vcmlnRXZlbnQsXG4gICAgICAgICAgICAgICAgICAgICAgICB2aWV3OiBjb250ZXh0LnZpZXdcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICBfdGhpcy5oYW5kbGVIaXRVcGRhdGUgPSBmdW5jdGlvbiAoaGl0LCBpc0ZpbmFsKSB7XG4gICAgICAgICAgICBpZiAoIV90aGlzLmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgcmVsZXZhbnRFdmVudHMgPSBfdGhpcy5yZWxldmFudEV2ZW50cztcbiAgICAgICAgICAgIHZhciBpbml0aWFsSGl0ID0gX3RoaXMuaGl0RHJhZ2dpbmcuaW5pdGlhbEhpdDtcbiAgICAgICAgICAgIHZhciBpbml0aWFsQ2FsZW5kYXIgPSBfdGhpcy5jb21wb25lbnQuY29udGV4dC5jYWxlbmRhcjtcbiAgICAgICAgICAgIC8vIHN0YXRlcyBiYXNlZCBvbiBuZXcgaGl0XG4gICAgICAgICAgICB2YXIgcmVjZWl2aW5nQ2FsZW5kYXIgPSBudWxsO1xuICAgICAgICAgICAgdmFyIG11dGF0aW9uID0gbnVsbDtcbiAgICAgICAgICAgIHZhciBtdXRhdGVkUmVsZXZhbnRFdmVudHMgPSBudWxsO1xuICAgICAgICAgICAgdmFyIGlzSW52YWxpZCA9IGZhbHNlO1xuICAgICAgICAgICAgdmFyIGludGVyYWN0aW9uID0ge1xuICAgICAgICAgICAgICAgIGFmZmVjdGVkRXZlbnRzOiByZWxldmFudEV2ZW50cyxcbiAgICAgICAgICAgICAgICBtdXRhdGVkRXZlbnRzOiBjcmVhdGVFbXB0eUV2ZW50U3RvcmUoKSxcbiAgICAgICAgICAgICAgICBpc0V2ZW50OiB0cnVlLFxuICAgICAgICAgICAgICAgIG9yaWdTZWc6IF90aGlzLnN1YmplY3RTZWdcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAoaGl0KSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlY2VpdmluZ0NvbXBvbmVudCA9IGhpdC5jb21wb25lbnQ7XG4gICAgICAgICAgICAgICAgcmVjZWl2aW5nQ2FsZW5kYXIgPSByZWNlaXZpbmdDb21wb25lbnQuY29udGV4dC5jYWxlbmRhcjtcbiAgICAgICAgICAgICAgICB2YXIgcmVjZWl2aW5nT3B0aW9ucyA9IHJlY2VpdmluZ0NvbXBvbmVudC5jb250ZXh0Lm9wdGlvbnM7XG4gICAgICAgICAgICAgICAgaWYgKGluaXRpYWxDYWxlbmRhciA9PT0gcmVjZWl2aW5nQ2FsZW5kYXIgfHxcbiAgICAgICAgICAgICAgICAgICAgcmVjZWl2aW5nT3B0aW9ucy5lZGl0YWJsZSAmJiByZWNlaXZpbmdPcHRpb25zLmRyb3BwYWJsZSkge1xuICAgICAgICAgICAgICAgICAgICBtdXRhdGlvbiA9IGNvbXB1dGVFdmVudE11dGF0aW9uKGluaXRpYWxIaXQsIGhpdCwgcmVjZWl2aW5nQ2FsZW5kYXIucGx1Z2luU3lzdGVtLmhvb2tzLmV2ZW50RHJhZ011dGF0aW9uTWFzc2FnZXJzKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKG11dGF0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGVkUmVsZXZhbnRFdmVudHMgPSBhcHBseU11dGF0aW9uVG9FdmVudFN0b3JlKHJlbGV2YW50RXZlbnRzLCByZWNlaXZpbmdDYWxlbmRhci5ldmVudFVpQmFzZXMsIG11dGF0aW9uLCByZWNlaXZpbmdDYWxlbmRhcik7XG4gICAgICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGlvbi5tdXRhdGVkRXZlbnRzID0gbXV0YXRlZFJlbGV2YW50RXZlbnRzO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFyZWNlaXZpbmdDb21wb25lbnQuaXNJbnRlcmFjdGlvblZhbGlkKGludGVyYWN0aW9uKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzSW52YWxpZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRpb24gPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZWRSZWxldmFudEV2ZW50cyA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3Rpb24ubXV0YXRlZEV2ZW50cyA9IGNyZWF0ZUVtcHR5RXZlbnRTdG9yZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZWNlaXZpbmdDYWxlbmRhciA9IG51bGw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgX3RoaXMuZGlzcGxheURyYWcocmVjZWl2aW5nQ2FsZW5kYXIsIGludGVyYWN0aW9uKTtcbiAgICAgICAgICAgIGlmICghaXNJbnZhbGlkKSB7XG4gICAgICAgICAgICAgICAgZW5hYmxlQ3Vyc29yKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBkaXNhYmxlQ3Vyc29yKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWlzRmluYWwpIHtcbiAgICAgICAgICAgICAgICBpZiAoaW5pdGlhbENhbGVuZGFyID09PSByZWNlaXZpbmdDYWxlbmRhciAmJiAvLyBUT0RPOiB3cml0ZSB0ZXN0IGZvciB0aGlzXG4gICAgICAgICAgICAgICAgICAgIGlzSGl0c0VxdWFsKGluaXRpYWxIaXQsIGhpdCkpIHtcbiAgICAgICAgICAgICAgICAgICAgbXV0YXRpb24gPSBudWxsO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBfdGhpcy5kcmFnZ2luZy5zZXRNaXJyb3JOZWVkc1JldmVydCghbXV0YXRpb24pO1xuICAgICAgICAgICAgICAgIC8vIHJlbmRlciB0aGUgbWlycm9yIGlmIG5vIGFscmVhZHktcmVuZGVyZWQgbWlycm9yXG4gICAgICAgICAgICAgICAgLy8gVE9ETzogd2lzaCB3ZSBjb3VsZCBzb21laG93IHdhaXQgZm9yIGRpc3BhdGNoIHRvIGd1YXJhbnRlZSByZW5kZXJcbiAgICAgICAgICAgICAgICBfdGhpcy5kcmFnZ2luZy5zZXRNaXJyb3JJc1Zpc2libGUoIWhpdCB8fCAhZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmZjLW1pcnJvcicpKTtcbiAgICAgICAgICAgICAgICAvLyBhc3NpZ24gc3RhdGVzIGJhc2VkIG9uIG5ldyBoaXRcbiAgICAgICAgICAgICAgICBfdGhpcy5yZWNlaXZpbmdDYWxlbmRhciA9IHJlY2VpdmluZ0NhbGVuZGFyO1xuICAgICAgICAgICAgICAgIF90aGlzLnZhbGlkTXV0YXRpb24gPSBtdXRhdGlvbjtcbiAgICAgICAgICAgICAgICBfdGhpcy5tdXRhdGVkUmVsZXZhbnRFdmVudHMgPSBtdXRhdGVkUmVsZXZhbnRFdmVudHM7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIF90aGlzLmhhbmRsZVBvaW50ZXJVcCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmICghX3RoaXMuaXNEcmFnZ2luZykge1xuICAgICAgICAgICAgICAgIF90aGlzLmNsZWFudXAoKTsgLy8gYmVjYXVzZSBoYW5kbGVEcmFnRW5kIHdvbid0IGZpcmVcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgX3RoaXMuaGFuZGxlRHJhZ0VuZCA9IGZ1bmN0aW9uIChldikge1xuICAgICAgICAgICAgaWYgKF90aGlzLmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgICAgICAgICB2YXIgY29udGV4dCA9IF90aGlzLmNvbXBvbmVudC5jb250ZXh0O1xuICAgICAgICAgICAgICAgIHZhciBpbml0aWFsQ2FsZW5kYXJfMSA9IGNvbnRleHQuY2FsZW5kYXI7XG4gICAgICAgICAgICAgICAgdmFyIGluaXRpYWxWaWV3ID0gY29udGV4dC52aWV3O1xuICAgICAgICAgICAgICAgIHZhciBfYSA9IF90aGlzLCByZWNlaXZpbmdDYWxlbmRhciA9IF9hLnJlY2VpdmluZ0NhbGVuZGFyLCB2YWxpZE11dGF0aW9uID0gX2EudmFsaWRNdXRhdGlvbjtcbiAgICAgICAgICAgICAgICB2YXIgZXZlbnREZWYgPSBfdGhpcy5ldmVudFJhbmdlLmRlZjtcbiAgICAgICAgICAgICAgICB2YXIgZXZlbnRJbnN0YW5jZSA9IF90aGlzLmV2ZW50UmFuZ2UuaW5zdGFuY2U7XG4gICAgICAgICAgICAgICAgdmFyIGV2ZW50QXBpID0gbmV3IEV2ZW50QXBpKGluaXRpYWxDYWxlbmRhcl8xLCBldmVudERlZiwgZXZlbnRJbnN0YW5jZSk7XG4gICAgICAgICAgICAgICAgdmFyIHJlbGV2YW50RXZlbnRzXzEgPSBfdGhpcy5yZWxldmFudEV2ZW50cztcbiAgICAgICAgICAgICAgICB2YXIgbXV0YXRlZFJlbGV2YW50RXZlbnRzID0gX3RoaXMubXV0YXRlZFJlbGV2YW50RXZlbnRzO1xuICAgICAgICAgICAgICAgIHZhciBmaW5hbEhpdCA9IF90aGlzLmhpdERyYWdnaW5nLmZpbmFsSGl0O1xuICAgICAgICAgICAgICAgIF90aGlzLmNsZWFyRHJhZygpOyAvLyBtdXN0IGhhcHBlbiBhZnRlciByZXZlcnQgYW5pbWF0aW9uXG4gICAgICAgICAgICAgICAgaW5pdGlhbENhbGVuZGFyXzEucHVibGljbHlUcmlnZ2VyKCdldmVudERyYWdTdG9wJywgW1xuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbDogX3RoaXMuc3ViamVjdFNlZy5lbCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50OiBldmVudEFwaSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGpzRXZlbnQ6IGV2Lm9yaWdFdmVudCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZpZXc6IGluaXRpYWxWaWV3XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBdKTtcbiAgICAgICAgICAgICAgICBpZiAodmFsaWRNdXRhdGlvbikge1xuICAgICAgICAgICAgICAgICAgICAvLyBkcm9wcGVkIHdpdGhpbiBzYW1lIGNhbGVuZGFyXG4gICAgICAgICAgICAgICAgICAgIGlmIChyZWNlaXZpbmdDYWxlbmRhciA9PT0gaW5pdGlhbENhbGVuZGFyXzEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGluaXRpYWxDYWxlbmRhcl8xLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnTUVSR0VfRVZFTlRTJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudFN0b3JlOiBtdXRhdGVkUmVsZXZhbnRFdmVudHNcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHRyYW5zZm9ybWVkID0ge307XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKHZhciBfaSA9IDAsIF9iID0gaW5pdGlhbENhbGVuZGFyXzEucGx1Z2luU3lzdGVtLmhvb2tzLmV2ZW50RHJvcFRyYW5zZm9ybWVyczsgX2kgPCBfYi5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgdHJhbnNmb3JtZXIgPSBfYltfaV07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgX19hc3NpZ24odHJhbnNmb3JtZWQsIHRyYW5zZm9ybWVyKHZhbGlkTXV0YXRpb24sIGluaXRpYWxDYWxlbmRhcl8xKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZXZlbnREcm9wQXJnID0gX19hc3NpZ24oe30sIHRyYW5zZm9ybWVkLCB7IGVsOiBldi5zdWJqZWN0RWwsIGRlbHRhOiB2YWxpZE11dGF0aW9uLmRhdGVzRGVsdGEsIG9sZEV2ZW50OiBldmVudEFwaSwgZXZlbnQ6IG5ldyBFdmVudEFwaSgvLyB0aGUgZGF0YSBBRlRFUiB0aGUgbXV0YXRpb25cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0aWFsQ2FsZW5kYXJfMSwgbXV0YXRlZFJlbGV2YW50RXZlbnRzLmRlZnNbZXZlbnREZWYuZGVmSWRdLCBldmVudEluc3RhbmNlID8gbXV0YXRlZFJlbGV2YW50RXZlbnRzLmluc3RhbmNlc1tldmVudEluc3RhbmNlLmluc3RhbmNlSWRdIDogbnVsbCksIHJldmVydDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0aWFsQ2FsZW5kYXJfMS5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnTUVSR0VfRVZFTlRTJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50U3RvcmU6IHJlbGV2YW50RXZlbnRzXzFcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSwganNFdmVudDogZXYub3JpZ0V2ZW50LCB2aWV3OiBpbml0aWFsVmlldyB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGluaXRpYWxDYWxlbmRhcl8xLnB1YmxpY2x5VHJpZ2dlcignZXZlbnREcm9wJywgW2V2ZW50RHJvcEFyZ10pO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZHJvcHBlZCBpbiBkaWZmZXJlbnQgY2FsZW5kYXJcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChyZWNlaXZpbmdDYWxlbmRhcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgaW5pdGlhbENhbGVuZGFyXzEucHVibGljbHlUcmlnZ2VyKCdldmVudExlYXZlJywgW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHJhZ2dlZEVsOiBldi5zdWJqZWN0RWwsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50OiBldmVudEFwaSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlldzogaW5pdGlhbFZpZXdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGluaXRpYWxDYWxlbmRhcl8xLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnUkVNT1ZFX0VWRU5UX0lOU1RBTkNFUycsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5zdGFuY2VzOiBfdGhpcy5tdXRhdGVkUmVsZXZhbnRFdmVudHMuaW5zdGFuY2VzXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlY2VpdmluZ0NhbGVuZGFyLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnTUVSR0VfRVZFTlRTJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudFN0b3JlOiBfdGhpcy5tdXRhdGVkUmVsZXZhbnRFdmVudHNcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGV2LmlzVG91Y2gpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNlaXZpbmdDYWxlbmRhci5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdTRUxFQ1RfRVZFTlQnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudEluc3RhbmNlSWQ6IGV2ZW50SW5zdGFuY2UuaW5zdGFuY2VJZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGRyb3BBcmcgPSBfX2Fzc2lnbih7fSwgcmVjZWl2aW5nQ2FsZW5kYXIuYnVpbGREYXRlUG9pbnRBcGkoZmluYWxIaXQuZGF0ZVNwYW4pLCB7IGRyYWdnZWRFbDogZXYuc3ViamVjdEVsLCBqc0V2ZW50OiBldi5vcmlnRXZlbnQsIHZpZXc6IGZpbmFsSGl0LmNvbXBvbmVudCAvLyBzaG91bGQgdGhpcyBiZSBmaW5hbEhpdC5jb21wb25lbnQudmlldz8gU2VlICM0NjQ0XG4gICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZWNlaXZpbmdDYWxlbmRhci5wdWJsaWNseVRyaWdnZXIoJ2Ryb3AnLCBbZHJvcEFyZ10pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2aW5nQ2FsZW5kYXIucHVibGljbHlUcmlnZ2VyKCdldmVudFJlY2VpdmUnLCBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcmFnZ2VkRWw6IGV2LnN1YmplY3RFbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnQ6IG5ldyBFdmVudEFwaSgvLyB0aGUgZGF0YSBBRlRFUiB0aGUgbXV0YXRpb25cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2aW5nQ2FsZW5kYXIsIG11dGF0ZWRSZWxldmFudEV2ZW50cy5kZWZzW2V2ZW50RGVmLmRlZklkXSwgbXV0YXRlZFJlbGV2YW50RXZlbnRzLmluc3RhbmNlc1tldmVudEluc3RhbmNlLmluc3RhbmNlSWRdKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlldzogZmluYWxIaXQuY29tcG9uZW50IC8vIHNob3VsZCB0aGlzIGJlIGZpbmFsSGl0LmNvbXBvbmVudC52aWV3PyBTZWUgIzQ2NDRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBdKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgaW5pdGlhbENhbGVuZGFyXzEucHVibGljbHlUcmlnZ2VyKCdfbm9FdmVudERyb3AnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBfdGhpcy5jbGVhbnVwKCk7XG4gICAgICAgIH07XG4gICAgICAgIHZhciBjb21wb25lbnQgPSBfdGhpcy5jb21wb25lbnQ7XG4gICAgICAgIHZhciBvcHRpb25zID0gY29tcG9uZW50LmNvbnRleHQub3B0aW9ucztcbiAgICAgICAgdmFyIGRyYWdnaW5nID0gX3RoaXMuZHJhZ2dpbmcgPSBuZXcgRmVhdHVyZWZ1bEVsZW1lbnREcmFnZ2luZyhjb21wb25lbnQuZWwpO1xuICAgICAgICBkcmFnZ2luZy5wb2ludGVyLnNlbGVjdG9yID0gRXZlbnREcmFnZ2luZy5TRUxFQ1RPUjtcbiAgICAgICAgZHJhZ2dpbmcudG91Y2hTY3JvbGxBbGxvd2VkID0gZmFsc2U7XG4gICAgICAgIGRyYWdnaW5nLmF1dG9TY3JvbGxlci5pc0VuYWJsZWQgPSBvcHRpb25zLmRyYWdTY3JvbGw7XG4gICAgICAgIHZhciBoaXREcmFnZ2luZyA9IF90aGlzLmhpdERyYWdnaW5nID0gbmV3IEhpdERyYWdnaW5nKF90aGlzLmRyYWdnaW5nLCBpbnRlcmFjdGlvblNldHRpbmdzU3RvcmUpO1xuICAgICAgICBoaXREcmFnZ2luZy51c2VTdWJqZWN0Q2VudGVyID0gc2V0dGluZ3MudXNlRXZlbnRDZW50ZXI7XG4gICAgICAgIGhpdERyYWdnaW5nLmVtaXR0ZXIub24oJ3BvaW50ZXJkb3duJywgX3RoaXMuaGFuZGxlUG9pbnRlckRvd24pO1xuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdkcmFnc3RhcnQnLCBfdGhpcy5oYW5kbGVEcmFnU3RhcnQpO1xuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdoaXR1cGRhdGUnLCBfdGhpcy5oYW5kbGVIaXRVcGRhdGUpO1xuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdwb2ludGVydXAnLCBfdGhpcy5oYW5kbGVQb2ludGVyVXApO1xuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdkcmFnZW5kJywgX3RoaXMuaGFuZGxlRHJhZ0VuZCk7XG4gICAgICAgIHJldHVybiBfdGhpcztcbiAgICB9XG4gICAgRXZlbnREcmFnZ2luZy5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5kcmFnZ2luZy5kZXN0cm95KCk7XG4gICAgfTtcbiAgICAvLyByZW5kZXIgYSBkcmFnIHN0YXRlIG9uIHRoZSBuZXh0IHJlY2VpdmluZ0NhbGVuZGFyXG4gICAgRXZlbnREcmFnZ2luZy5wcm90b3R5cGUuZGlzcGxheURyYWcgPSBmdW5jdGlvbiAobmV4dENhbGVuZGFyLCBzdGF0ZSkge1xuICAgICAgICB2YXIgaW5pdGlhbENhbGVuZGFyID0gdGhpcy5jb21wb25lbnQuY29udGV4dC5jYWxlbmRhcjtcbiAgICAgICAgdmFyIHByZXZDYWxlbmRhciA9IHRoaXMucmVjZWl2aW5nQ2FsZW5kYXI7XG4gICAgICAgIC8vIGRvZXMgdGhlIHByZXZpb3VzIGNhbGVuZGFyIG5lZWQgdG8gYmUgY2xlYXJlZD9cbiAgICAgICAgaWYgKHByZXZDYWxlbmRhciAmJiBwcmV2Q2FsZW5kYXIgIT09IG5leHRDYWxlbmRhcikge1xuICAgICAgICAgICAgLy8gZG9lcyB0aGUgaW5pdGlhbCBjYWxlbmRhciBuZWVkIHRvIGJlIGNsZWFyZWQ/XG4gICAgICAgICAgICAvLyBpZiBzbywgZG9uJ3QgY2xlYXIgYWxsIHRoZSB3YXkuIHdlIHN0aWxsIG5lZWQgdG8gdG8gaGlkZSB0aGUgYWZmZWN0ZWRFdmVudHNcbiAgICAgICAgICAgIGlmIChwcmV2Q2FsZW5kYXIgPT09IGluaXRpYWxDYWxlbmRhcikge1xuICAgICAgICAgICAgICAgIHByZXZDYWxlbmRhci5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdTRVRfRVZFTlRfRFJBRycsXG4gICAgICAgICAgICAgICAgICAgIHN0YXRlOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhZmZlY3RlZEV2ZW50czogc3RhdGUuYWZmZWN0ZWRFdmVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGVkRXZlbnRzOiBjcmVhdGVFbXB0eUV2ZW50U3RvcmUoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzRXZlbnQ6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvcmlnU2VnOiBzdGF0ZS5vcmlnU2VnXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAvLyBjb21wbGV0ZWx5IGNsZWFyIHRoZSBvbGQgY2FsZW5kYXIgaWYgaXQgd2Fzbid0IHRoZSBpbml0aWFsXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBwcmV2Q2FsZW5kYXIuZGlzcGF0Y2goeyB0eXBlOiAnVU5TRVRfRVZFTlRfRFJBRycgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG5leHRDYWxlbmRhcikge1xuICAgICAgICAgICAgbmV4dENhbGVuZGFyLmRpc3BhdGNoKHsgdHlwZTogJ1NFVF9FVkVOVF9EUkFHJywgc3RhdGU6IHN0YXRlIH0pO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBFdmVudERyYWdnaW5nLnByb3RvdHlwZS5jbGVhckRyYWcgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBpbml0aWFsQ2FsZW5kYXIgPSB0aGlzLmNvbXBvbmVudC5jb250ZXh0LmNhbGVuZGFyO1xuICAgICAgICB2YXIgcmVjZWl2aW5nQ2FsZW5kYXIgPSB0aGlzLnJlY2VpdmluZ0NhbGVuZGFyO1xuICAgICAgICBpZiAocmVjZWl2aW5nQ2FsZW5kYXIpIHtcbiAgICAgICAgICAgIHJlY2VpdmluZ0NhbGVuZGFyLmRpc3BhdGNoKHsgdHlwZTogJ1VOU0VUX0VWRU5UX0RSQUcnIH0pO1xuICAgICAgICB9XG4gICAgICAgIC8vIHRoZSBpbml0aWFsIGNhbGVuZGFyIG1pZ2h0IGhhdmUgYW4gZHVtbXkgZHJhZyBzdGF0ZSBmcm9tIGRpc3BsYXlEcmFnXG4gICAgICAgIGlmIChpbml0aWFsQ2FsZW5kYXIgIT09IHJlY2VpdmluZ0NhbGVuZGFyKSB7XG4gICAgICAgICAgICBpbml0aWFsQ2FsZW5kYXIuZGlzcGF0Y2goeyB0eXBlOiAnVU5TRVRfRVZFTlRfRFJBRycgfSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIEV2ZW50RHJhZ2dpbmcucHJvdG90eXBlLmNsZWFudXAgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuc3ViamVjdFNlZyA9IG51bGw7XG4gICAgICAgIHRoaXMuaXNEcmFnZ2luZyA9IGZhbHNlO1xuICAgICAgICB0aGlzLmV2ZW50UmFuZ2UgPSBudWxsO1xuICAgICAgICB0aGlzLnJlbGV2YW50RXZlbnRzID0gbnVsbDtcbiAgICAgICAgdGhpcy5yZWNlaXZpbmdDYWxlbmRhciA9IG51bGw7XG4gICAgICAgIHRoaXMudmFsaWRNdXRhdGlvbiA9IG51bGw7XG4gICAgICAgIHRoaXMubXV0YXRlZFJlbGV2YW50RXZlbnRzID0gbnVsbDtcbiAgICB9O1xuICAgIEV2ZW50RHJhZ2dpbmcuU0VMRUNUT1IgPSAnLmZjLWRyYWdnYWJsZSwgLmZjLXJlc2l6YWJsZSc7IC8vIFRPRE86IHRlc3QgdGhpcyBpbiBJRTExXG4gICAgcmV0dXJuIEV2ZW50RHJhZ2dpbmc7XG59KEludGVyYWN0aW9uKSk7XG5mdW5jdGlvbiBjb21wdXRlRXZlbnRNdXRhdGlvbihoaXQwLCBoaXQxLCBtYXNzYWdlcnMpIHtcbiAgICB2YXIgZGF0ZVNwYW4wID0gaGl0MC5kYXRlU3BhbjtcbiAgICB2YXIgZGF0ZVNwYW4xID0gaGl0MS5kYXRlU3BhbjtcbiAgICB2YXIgZGF0ZTAgPSBkYXRlU3BhbjAucmFuZ2Uuc3RhcnQ7XG4gICAgdmFyIGRhdGUxID0gZGF0ZVNwYW4xLnJhbmdlLnN0YXJ0O1xuICAgIHZhciBzdGFuZGFyZFByb3BzID0ge307XG4gICAgaWYgKGRhdGVTcGFuMC5hbGxEYXkgIT09IGRhdGVTcGFuMS5hbGxEYXkpIHtcbiAgICAgICAgc3RhbmRhcmRQcm9wcy5hbGxEYXkgPSBkYXRlU3BhbjEuYWxsRGF5O1xuICAgICAgICBzdGFuZGFyZFByb3BzLmhhc0VuZCA9IGhpdDEuY29tcG9uZW50LmNvbnRleHQub3B0aW9ucy5hbGxEYXlNYWludGFpbkR1cmF0aW9uO1xuICAgICAgICBpZiAoZGF0ZVNwYW4xLmFsbERheSkge1xuICAgICAgICAgICAgLy8gbWVhbnMgZGF0ZTEgaXMgYWxyZWFkeSBzdGFydC1vZi1kYXksXG4gICAgICAgICAgICAvLyBidXQgZGF0ZTAgbmVlZHMgdG8gYmUgY29udmVydGVkXG4gICAgICAgICAgICBkYXRlMCA9IHN0YXJ0T2ZEYXkoZGF0ZTApO1xuICAgICAgICB9XG4gICAgfVxuICAgIHZhciBkZWx0YSA9IGRpZmZEYXRlcyhkYXRlMCwgZGF0ZTEsIGhpdDAuY29tcG9uZW50LmNvbnRleHQuZGF0ZUVudiwgaGl0MC5jb21wb25lbnQgPT09IGhpdDEuY29tcG9uZW50ID9cbiAgICAgICAgaGl0MC5jb21wb25lbnQubGFyZ2VVbml0IDpcbiAgICAgICAgbnVsbCk7XG4gICAgaWYgKGRlbHRhLm1pbGxpc2Vjb25kcykgeyAvLyBoYXMgaG91cnMvbWludXRlcy9zZWNvbmRzXG4gICAgICAgIHN0YW5kYXJkUHJvcHMuYWxsRGF5ID0gZmFsc2U7XG4gICAgfVxuICAgIHZhciBtdXRhdGlvbiA9IHtcbiAgICAgICAgZGF0ZXNEZWx0YTogZGVsdGEsXG4gICAgICAgIHN0YW5kYXJkUHJvcHM6IHN0YW5kYXJkUHJvcHNcbiAgICB9O1xuICAgIGZvciAodmFyIF9pID0gMCwgbWFzc2FnZXJzXzEgPSBtYXNzYWdlcnM7IF9pIDwgbWFzc2FnZXJzXzEubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgIHZhciBtYXNzYWdlciA9IG1hc3NhZ2Vyc18xW19pXTtcbiAgICAgICAgbWFzc2FnZXIobXV0YXRpb24sIGhpdDAsIGhpdDEpO1xuICAgIH1cbiAgICByZXR1cm4gbXV0YXRpb247XG59XG5mdW5jdGlvbiBnZXRDb21wb25lbnRUb3VjaERlbGF5JDEoY29tcG9uZW50KSB7XG4gICAgdmFyIG9wdGlvbnMgPSBjb21wb25lbnQuY29udGV4dC5vcHRpb25zO1xuICAgIHZhciBkZWxheSA9IG9wdGlvbnMuZXZlbnRMb25nUHJlc3NEZWxheTtcbiAgICBpZiAoZGVsYXkgPT0gbnVsbCkge1xuICAgICAgICBkZWxheSA9IG9wdGlvbnMubG9uZ1ByZXNzRGVsYXk7XG4gICAgfVxuICAgIHJldHVybiBkZWxheTtcbn1cblxudmFyIEV2ZW50RHJhZ2dpbmckMSA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uIChfc3VwZXIpIHtcbiAgICBfX2V4dGVuZHMoRXZlbnREcmFnZ2luZywgX3N1cGVyKTtcbiAgICBmdW5jdGlvbiBFdmVudERyYWdnaW5nKHNldHRpbmdzKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IF9zdXBlci5jYWxsKHRoaXMsIHNldHRpbmdzKSB8fCB0aGlzO1xuICAgICAgICAvLyBpbnRlcm5hbCBzdGF0ZVxuICAgICAgICBfdGhpcy5kcmFnZ2luZ1NlZyA9IG51bGw7IC8vIFRPRE86IHJlbmFtZSB0byByZXNpemluZ1NlZz8gc3ViamVjdFNlZz9cbiAgICAgICAgX3RoaXMuZXZlbnRSYW5nZSA9IG51bGw7XG4gICAgICAgIF90aGlzLnJlbGV2YW50RXZlbnRzID0gbnVsbDtcbiAgICAgICAgX3RoaXMudmFsaWRNdXRhdGlvbiA9IG51bGw7XG4gICAgICAgIF90aGlzLm11dGF0ZWRSZWxldmFudEV2ZW50cyA9IG51bGw7XG4gICAgICAgIF90aGlzLmhhbmRsZVBvaW50ZXJEb3duID0gZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICB2YXIgY29tcG9uZW50ID0gX3RoaXMuY29tcG9uZW50O1xuICAgICAgICAgICAgdmFyIHNlZyA9IF90aGlzLnF1ZXJ5U2VnKGV2KTtcbiAgICAgICAgICAgIHZhciBldmVudFJhbmdlID0gX3RoaXMuZXZlbnRSYW5nZSA9IHNlZy5ldmVudFJhbmdlO1xuICAgICAgICAgICAgX3RoaXMuZHJhZ2dpbmcubWluRGlzdGFuY2UgPSBjb21wb25lbnQuY29udGV4dC5vcHRpb25zLmV2ZW50RHJhZ01pbkRpc3RhbmNlO1xuICAgICAgICAgICAgLy8gaWYgdG91Y2gsIG5lZWQgdG8gYmUgd29ya2luZyB3aXRoIGEgc2VsZWN0ZWQgZXZlbnRcbiAgICAgICAgICAgIF90aGlzLmRyYWdnaW5nLnNldElnbm9yZU1vdmUoIV90aGlzLmNvbXBvbmVudC5pc1ZhbGlkU2VnRG93bkVsKGV2Lm9yaWdFdmVudC50YXJnZXQpIHx8XG4gICAgICAgICAgICAgICAgKGV2LmlzVG91Y2ggJiYgX3RoaXMuY29tcG9uZW50LnByb3BzLmV2ZW50U2VsZWN0aW9uICE9PSBldmVudFJhbmdlLmluc3RhbmNlLmluc3RhbmNlSWQpKTtcbiAgICAgICAgfTtcbiAgICAgICAgX3RoaXMuaGFuZGxlRHJhZ1N0YXJ0ID0gZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICB2YXIgX2EgPSBfdGhpcy5jb21wb25lbnQuY29udGV4dCwgY2FsZW5kYXIgPSBfYS5jYWxlbmRhciwgdmlldyA9IF9hLnZpZXc7XG4gICAgICAgICAgICB2YXIgZXZlbnRSYW5nZSA9IF90aGlzLmV2ZW50UmFuZ2U7XG4gICAgICAgICAgICBfdGhpcy5yZWxldmFudEV2ZW50cyA9IGdldFJlbGV2YW50RXZlbnRzKGNhbGVuZGFyLnN0YXRlLmV2ZW50U3RvcmUsIF90aGlzLmV2ZW50UmFuZ2UuaW5zdGFuY2UuaW5zdGFuY2VJZCk7XG4gICAgICAgICAgICBfdGhpcy5kcmFnZ2luZ1NlZyA9IF90aGlzLnF1ZXJ5U2VnKGV2KTtcbiAgICAgICAgICAgIGNhbGVuZGFyLnVuc2VsZWN0KCk7XG4gICAgICAgICAgICBjYWxlbmRhci5wdWJsaWNseVRyaWdnZXIoJ2V2ZW50UmVzaXplU3RhcnQnLCBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBlbDogX3RoaXMuZHJhZ2dpbmdTZWcuZWwsXG4gICAgICAgICAgICAgICAgICAgIGV2ZW50OiBuZXcgRXZlbnRBcGkoY2FsZW5kYXIsIGV2ZW50UmFuZ2UuZGVmLCBldmVudFJhbmdlLmluc3RhbmNlKSxcbiAgICAgICAgICAgICAgICAgICAganNFdmVudDogZXYub3JpZ0V2ZW50LFxuICAgICAgICAgICAgICAgICAgICB2aWV3OiB2aWV3XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgXSk7XG4gICAgICAgIH07XG4gICAgICAgIF90aGlzLmhhbmRsZUhpdFVwZGF0ZSA9IGZ1bmN0aW9uIChoaXQsIGlzRmluYWwsIGV2KSB7XG4gICAgICAgICAgICB2YXIgY2FsZW5kYXIgPSBfdGhpcy5jb21wb25lbnQuY29udGV4dC5jYWxlbmRhcjtcbiAgICAgICAgICAgIHZhciByZWxldmFudEV2ZW50cyA9IF90aGlzLnJlbGV2YW50RXZlbnRzO1xuICAgICAgICAgICAgdmFyIGluaXRpYWxIaXQgPSBfdGhpcy5oaXREcmFnZ2luZy5pbml0aWFsSGl0O1xuICAgICAgICAgICAgdmFyIGV2ZW50SW5zdGFuY2UgPSBfdGhpcy5ldmVudFJhbmdlLmluc3RhbmNlO1xuICAgICAgICAgICAgdmFyIG11dGF0aW9uID0gbnVsbDtcbiAgICAgICAgICAgIHZhciBtdXRhdGVkUmVsZXZhbnRFdmVudHMgPSBudWxsO1xuICAgICAgICAgICAgdmFyIGlzSW52YWxpZCA9IGZhbHNlO1xuICAgICAgICAgICAgdmFyIGludGVyYWN0aW9uID0ge1xuICAgICAgICAgICAgICAgIGFmZmVjdGVkRXZlbnRzOiByZWxldmFudEV2ZW50cyxcbiAgICAgICAgICAgICAgICBtdXRhdGVkRXZlbnRzOiBjcmVhdGVFbXB0eUV2ZW50U3RvcmUoKSxcbiAgICAgICAgICAgICAgICBpc0V2ZW50OiB0cnVlLFxuICAgICAgICAgICAgICAgIG9yaWdTZWc6IF90aGlzLmRyYWdnaW5nU2VnXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKGhpdCkge1xuICAgICAgICAgICAgICAgIG11dGF0aW9uID0gY29tcHV0ZU11dGF0aW9uKGluaXRpYWxIaXQsIGhpdCwgZXYuc3ViamVjdEVsLmNsYXNzTGlzdC5jb250YWlucygnZmMtc3RhcnQtcmVzaXplcicpLCBldmVudEluc3RhbmNlLnJhbmdlLCBjYWxlbmRhci5wbHVnaW5TeXN0ZW0uaG9va3MuZXZlbnRSZXNpemVKb2luVHJhbnNmb3Jtcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobXV0YXRpb24pIHtcbiAgICAgICAgICAgICAgICBtdXRhdGVkUmVsZXZhbnRFdmVudHMgPSBhcHBseU11dGF0aW9uVG9FdmVudFN0b3JlKHJlbGV2YW50RXZlbnRzLCBjYWxlbmRhci5ldmVudFVpQmFzZXMsIG11dGF0aW9uLCBjYWxlbmRhcik7XG4gICAgICAgICAgICAgICAgaW50ZXJhY3Rpb24ubXV0YXRlZEV2ZW50cyA9IG11dGF0ZWRSZWxldmFudEV2ZW50cztcbiAgICAgICAgICAgICAgICBpZiAoIV90aGlzLmNvbXBvbmVudC5pc0ludGVyYWN0aW9uVmFsaWQoaW50ZXJhY3Rpb24pKSB7XG4gICAgICAgICAgICAgICAgICAgIGlzSW52YWxpZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIG11dGF0aW9uID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgbXV0YXRlZFJlbGV2YW50RXZlbnRzID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3Rpb24ubXV0YXRlZEV2ZW50cyA9IG51bGw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG11dGF0ZWRSZWxldmFudEV2ZW50cykge1xuICAgICAgICAgICAgICAgIGNhbGVuZGFyLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogJ1NFVF9FVkVOVF9SRVNJWkUnLFxuICAgICAgICAgICAgICAgICAgICBzdGF0ZTogaW50ZXJhY3Rpb25cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGNhbGVuZGFyLmRpc3BhdGNoKHsgdHlwZTogJ1VOU0VUX0VWRU5UX1JFU0laRScgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWlzSW52YWxpZCkge1xuICAgICAgICAgICAgICAgIGVuYWJsZUN1cnNvcigpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgZGlzYWJsZUN1cnNvcigpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFpc0ZpbmFsKSB7XG4gICAgICAgICAgICAgICAgaWYgKG11dGF0aW9uICYmIGlzSGl0c0VxdWFsKGluaXRpYWxIaXQsIGhpdCkpIHtcbiAgICAgICAgICAgICAgICAgICAgbXV0YXRpb24gPSBudWxsO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBfdGhpcy52YWxpZE11dGF0aW9uID0gbXV0YXRpb247XG4gICAgICAgICAgICAgICAgX3RoaXMubXV0YXRlZFJlbGV2YW50RXZlbnRzID0gbXV0YXRlZFJlbGV2YW50RXZlbnRzO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICBfdGhpcy5oYW5kbGVEcmFnRW5kID0gZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICB2YXIgX2EgPSBfdGhpcy5jb21wb25lbnQuY29udGV4dCwgY2FsZW5kYXIgPSBfYS5jYWxlbmRhciwgdmlldyA9IF9hLnZpZXc7XG4gICAgICAgICAgICB2YXIgZXZlbnREZWYgPSBfdGhpcy5ldmVudFJhbmdlLmRlZjtcbiAgICAgICAgICAgIHZhciBldmVudEluc3RhbmNlID0gX3RoaXMuZXZlbnRSYW5nZS5pbnN0YW5jZTtcbiAgICAgICAgICAgIHZhciBldmVudEFwaSA9IG5ldyBFdmVudEFwaShjYWxlbmRhciwgZXZlbnREZWYsIGV2ZW50SW5zdGFuY2UpO1xuICAgICAgICAgICAgdmFyIHJlbGV2YW50RXZlbnRzID0gX3RoaXMucmVsZXZhbnRFdmVudHM7XG4gICAgICAgICAgICB2YXIgbXV0YXRlZFJlbGV2YW50RXZlbnRzID0gX3RoaXMubXV0YXRlZFJlbGV2YW50RXZlbnRzO1xuICAgICAgICAgICAgY2FsZW5kYXIucHVibGljbHlUcmlnZ2VyKCdldmVudFJlc2l6ZVN0b3AnLCBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBlbDogX3RoaXMuZHJhZ2dpbmdTZWcuZWwsXG4gICAgICAgICAgICAgICAgICAgIGV2ZW50OiBldmVudEFwaSxcbiAgICAgICAgICAgICAgICAgICAganNFdmVudDogZXYub3JpZ0V2ZW50LFxuICAgICAgICAgICAgICAgICAgICB2aWV3OiB2aWV3XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgXSk7XG4gICAgICAgICAgICBpZiAoX3RoaXMudmFsaWRNdXRhdGlvbikge1xuICAgICAgICAgICAgICAgIGNhbGVuZGFyLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogJ01FUkdFX0VWRU5UUycsXG4gICAgICAgICAgICAgICAgICAgIGV2ZW50U3RvcmU6IG11dGF0ZWRSZWxldmFudEV2ZW50c1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGNhbGVuZGFyLnB1YmxpY2x5VHJpZ2dlcignZXZlbnRSZXNpemUnLCBbXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsOiBfdGhpcy5kcmFnZ2luZ1NlZy5lbCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0RGVsdGE6IF90aGlzLnZhbGlkTXV0YXRpb24uc3RhcnREZWx0YSB8fCBjcmVhdGVEdXJhdGlvbigwKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVuZERlbHRhOiBfdGhpcy52YWxpZE11dGF0aW9uLmVuZERlbHRhIHx8IGNyZWF0ZUR1cmF0aW9uKDApLFxuICAgICAgICAgICAgICAgICAgICAgICAgcHJldkV2ZW50OiBldmVudEFwaSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50OiBuZXcgRXZlbnRBcGkoLy8gdGhlIGRhdGEgQUZURVIgdGhlIG11dGF0aW9uXG4gICAgICAgICAgICAgICAgICAgICAgICBjYWxlbmRhciwgbXV0YXRlZFJlbGV2YW50RXZlbnRzLmRlZnNbZXZlbnREZWYuZGVmSWRdLCBldmVudEluc3RhbmNlID8gbXV0YXRlZFJlbGV2YW50RXZlbnRzLmluc3RhbmNlc1tldmVudEluc3RhbmNlLmluc3RhbmNlSWRdIDogbnVsbCksXG4gICAgICAgICAgICAgICAgICAgICAgICByZXZlcnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYWxlbmRhci5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdNRVJHRV9FVkVOVFMnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudFN0b3JlOiByZWxldmFudEV2ZW50c1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGpzRXZlbnQ6IGV2Lm9yaWdFdmVudCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZpZXc6IHZpZXdcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgY2FsZW5kYXIucHVibGljbHlUcmlnZ2VyKCdfbm9FdmVudFJlc2l6ZScpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gcmVzZXQgYWxsIGludGVybmFsIHN0YXRlXG4gICAgICAgICAgICBfdGhpcy5kcmFnZ2luZ1NlZyA9IG51bGw7XG4gICAgICAgICAgICBfdGhpcy5yZWxldmFudEV2ZW50cyA9IG51bGw7XG4gICAgICAgICAgICBfdGhpcy52YWxpZE11dGF0aW9uID0gbnVsbDtcbiAgICAgICAgICAgIC8vIG9rYXkgdG8ga2VlcCBldmVudEluc3RhbmNlIGFyb3VuZC4gdXNlZnVsIHRvIHNldCBpdCBpbiBoYW5kbGVQb2ludGVyRG93blxuICAgICAgICB9O1xuICAgICAgICB2YXIgY29tcG9uZW50ID0gc2V0dGluZ3MuY29tcG9uZW50O1xuICAgICAgICB2YXIgZHJhZ2dpbmcgPSBfdGhpcy5kcmFnZ2luZyA9IG5ldyBGZWF0dXJlZnVsRWxlbWVudERyYWdnaW5nKGNvbXBvbmVudC5lbCk7XG4gICAgICAgIGRyYWdnaW5nLnBvaW50ZXIuc2VsZWN0b3IgPSAnLmZjLXJlc2l6ZXInO1xuICAgICAgICBkcmFnZ2luZy50b3VjaFNjcm9sbEFsbG93ZWQgPSBmYWxzZTtcbiAgICAgICAgZHJhZ2dpbmcuYXV0b1Njcm9sbGVyLmlzRW5hYmxlZCA9IGNvbXBvbmVudC5jb250ZXh0Lm9wdGlvbnMuZHJhZ1Njcm9sbDtcbiAgICAgICAgdmFyIGhpdERyYWdnaW5nID0gX3RoaXMuaGl0RHJhZ2dpbmcgPSBuZXcgSGl0RHJhZ2dpbmcoX3RoaXMuZHJhZ2dpbmcsIGludGVyYWN0aW9uU2V0dGluZ3NUb1N0b3JlKHNldHRpbmdzKSk7XG4gICAgICAgIGhpdERyYWdnaW5nLmVtaXR0ZXIub24oJ3BvaW50ZXJkb3duJywgX3RoaXMuaGFuZGxlUG9pbnRlckRvd24pO1xuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdkcmFnc3RhcnQnLCBfdGhpcy5oYW5kbGVEcmFnU3RhcnQpO1xuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdoaXR1cGRhdGUnLCBfdGhpcy5oYW5kbGVIaXRVcGRhdGUpO1xuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdkcmFnZW5kJywgX3RoaXMuaGFuZGxlRHJhZ0VuZCk7XG4gICAgICAgIHJldHVybiBfdGhpcztcbiAgICB9XG4gICAgRXZlbnREcmFnZ2luZy5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5kcmFnZ2luZy5kZXN0cm95KCk7XG4gICAgfTtcbiAgICBFdmVudERyYWdnaW5nLnByb3RvdHlwZS5xdWVyeVNlZyA9IGZ1bmN0aW9uIChldikge1xuICAgICAgICByZXR1cm4gZ2V0RWxTZWcoZWxlbWVudENsb3Nlc3QoZXYuc3ViamVjdEVsLCB0aGlzLmNvbXBvbmVudC5mZ1NlZ1NlbGVjdG9yKSk7XG4gICAgfTtcbiAgICByZXR1cm4gRXZlbnREcmFnZ2luZztcbn0oSW50ZXJhY3Rpb24pKTtcbmZ1bmN0aW9uIGNvbXB1dGVNdXRhdGlvbihoaXQwLCBoaXQxLCBpc0Zyb21TdGFydCwgaW5zdGFuY2VSYW5nZSwgdHJhbnNmb3Jtcykge1xuICAgIHZhciBkYXRlRW52ID0gaGl0MC5jb21wb25lbnQuY29udGV4dC5kYXRlRW52O1xuICAgIHZhciBkYXRlMCA9IGhpdDAuZGF0ZVNwYW4ucmFuZ2Uuc3RhcnQ7XG4gICAgdmFyIGRhdGUxID0gaGl0MS5kYXRlU3Bhbi5yYW5nZS5zdGFydDtcbiAgICB2YXIgZGVsdGEgPSBkaWZmRGF0ZXMoZGF0ZTAsIGRhdGUxLCBkYXRlRW52LCBoaXQwLmNvbXBvbmVudC5sYXJnZVVuaXQpO1xuICAgIHZhciBwcm9wcyA9IHt9O1xuICAgIGZvciAodmFyIF9pID0gMCwgdHJhbnNmb3Jtc18xID0gdHJhbnNmb3JtczsgX2kgPCB0cmFuc2Zvcm1zXzEubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgIHZhciB0cmFuc2Zvcm0gPSB0cmFuc2Zvcm1zXzFbX2ldO1xuICAgICAgICB2YXIgcmVzID0gdHJhbnNmb3JtKGhpdDAsIGhpdDEpO1xuICAgICAgICBpZiAocmVzID09PSBmYWxzZSkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAocmVzKSB7XG4gICAgICAgICAgICBfX2Fzc2lnbihwcm9wcywgcmVzKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAoaXNGcm9tU3RhcnQpIHtcbiAgICAgICAgaWYgKGRhdGVFbnYuYWRkKGluc3RhbmNlUmFuZ2Uuc3RhcnQsIGRlbHRhKSA8IGluc3RhbmNlUmFuZ2UuZW5kKSB7XG4gICAgICAgICAgICBwcm9wcy5zdGFydERlbHRhID0gZGVsdGE7XG4gICAgICAgICAgICByZXR1cm4gcHJvcHM7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGlmIChkYXRlRW52LmFkZChpbnN0YW5jZVJhbmdlLmVuZCwgZGVsdGEpID4gaW5zdGFuY2VSYW5nZS5zdGFydCkge1xuICAgICAgICAgICAgcHJvcHMuZW5kRGVsdGEgPSBkZWx0YTtcbiAgICAgICAgICAgIHJldHVybiBwcm9wcztcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cblxudmFyIFVuc2VsZWN0QXV0byA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBVbnNlbGVjdEF1dG8oY2FsZW5kYXIpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdGhpcy5pc1JlY2VudFBvaW50ZXJEYXRlU2VsZWN0ID0gZmFsc2U7IC8vIHdpc2ggd2UgY291bGQgdXNlIGEgc2VsZWN0b3IgdG8gZGV0ZWN0IGRhdGUgc2VsZWN0aW9uLCBidXQgdXNlcyBoaXQgc3lzdGVtXG4gICAgICAgIHRoaXMub25TZWxlY3QgPSBmdW5jdGlvbiAoc2VsZWN0SW5mbykge1xuICAgICAgICAgICAgaWYgKHNlbGVjdEluZm8uanNFdmVudCkge1xuICAgICAgICAgICAgICAgIF90aGlzLmlzUmVjZW50UG9pbnRlckRhdGVTZWxlY3QgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICB0aGlzLm9uRG9jdW1lbnRQb2ludGVyVXAgPSBmdW5jdGlvbiAocGV2KSB7XG4gICAgICAgICAgICB2YXIgX2EgPSBfdGhpcywgY2FsZW5kYXIgPSBfYS5jYWxlbmRhciwgZG9jdW1lbnRQb2ludGVyID0gX2EuZG9jdW1lbnRQb2ludGVyO1xuICAgICAgICAgICAgdmFyIHN0YXRlID0gY2FsZW5kYXIuc3RhdGU7XG4gICAgICAgICAgICAvLyB0b3VjaC1zY3JvbGxpbmcgc2hvdWxkIG5ldmVyIHVuZm9jdXMgYW55IHR5cGUgb2Ygc2VsZWN0aW9uXG4gICAgICAgICAgICBpZiAoIWRvY3VtZW50UG9pbnRlci53YXNUb3VjaFNjcm9sbCkge1xuICAgICAgICAgICAgICAgIGlmIChzdGF0ZS5kYXRlU2VsZWN0aW9uICYmIC8vIGFuIGV4aXN0aW5nIGRhdGUgc2VsZWN0aW9uP1xuICAgICAgICAgICAgICAgICAgICAhX3RoaXMuaXNSZWNlbnRQb2ludGVyRGF0ZVNlbGVjdCAvLyBhIG5ldyBwb2ludGVyLWluaXRpYXRlZCBkYXRlIHNlbGVjdGlvbiBzaW5jZSBsYXN0IG9uRG9jdW1lbnRQb2ludGVyVXA/XG4gICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB1bnNlbGVjdEF1dG8gPSBjYWxlbmRhci52aWV3T3B0KCd1bnNlbGVjdEF1dG8nKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVuc2VsZWN0Q2FuY2VsID0gY2FsZW5kYXIudmlld09wdCgndW5zZWxlY3RDYW5jZWwnKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHVuc2VsZWN0QXV0byAmJiAoIXVuc2VsZWN0QXV0byB8fCAhZWxlbWVudENsb3Nlc3QoZG9jdW1lbnRQb2ludGVyLmRvd25FbCwgdW5zZWxlY3RDYW5jZWwpKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FsZW5kYXIudW5zZWxlY3QocGV2KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoc3RhdGUuZXZlbnRTZWxlY3Rpb24gJiYgLy8gYW4gZXhpc3RpbmcgZXZlbnQgc2VsZWN0ZWQ/XG4gICAgICAgICAgICAgICAgICAgICFlbGVtZW50Q2xvc2VzdChkb2N1bWVudFBvaW50ZXIuZG93bkVsLCBFdmVudERyYWdnaW5nLlNFTEVDVE9SKSAvLyBpbnRlcmFjdGlvbiBESUROJ1Qgc3RhcnQgb24gYW4gZXZlbnRcbiAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgY2FsZW5kYXIuZGlzcGF0Y2goeyB0eXBlOiAnVU5TRUxFQ1RfRVZFTlQnIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIF90aGlzLmlzUmVjZW50UG9pbnRlckRhdGVTZWxlY3QgPSBmYWxzZTtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5jYWxlbmRhciA9IGNhbGVuZGFyO1xuICAgICAgICB2YXIgZG9jdW1lbnRQb2ludGVyID0gdGhpcy5kb2N1bWVudFBvaW50ZXIgPSBuZXcgUG9pbnRlckRyYWdnaW5nKGRvY3VtZW50KTtcbiAgICAgICAgZG9jdW1lbnRQb2ludGVyLnNob3VsZElnbm9yZU1vdmUgPSB0cnVlO1xuICAgICAgICBkb2N1bWVudFBvaW50ZXIuc2hvdWxkV2F0Y2hTY3JvbGwgPSBmYWxzZTtcbiAgICAgICAgZG9jdW1lbnRQb2ludGVyLmVtaXR0ZXIub24oJ3BvaW50ZXJ1cCcsIHRoaXMub25Eb2N1bWVudFBvaW50ZXJVcCk7XG4gICAgICAgIC8qXG4gICAgICAgIFRPRE86IGJldHRlciB3YXkgdG8ga25vdyBhYm91dCB3aGV0aGVyIHRoZXJlIHdhcyBhIHNlbGVjdGlvbiB3aXRoIHRoZSBwb2ludGVyXG4gICAgICAgICovXG4gICAgICAgIGNhbGVuZGFyLm9uKCdzZWxlY3QnLCB0aGlzLm9uU2VsZWN0KTtcbiAgICB9XG4gICAgVW5zZWxlY3RBdXRvLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLmNhbGVuZGFyLm9mZignc2VsZWN0JywgdGhpcy5vblNlbGVjdCk7XG4gICAgICAgIHRoaXMuZG9jdW1lbnRQb2ludGVyLmRlc3Ryb3koKTtcbiAgICB9O1xuICAgIHJldHVybiBVbnNlbGVjdEF1dG87XG59KCkpO1xuXG4vKlxuR2l2ZW4gYW4gYWxyZWFkeSBpbnN0YW50aWF0ZWQgZHJhZ2dhYmxlIG9iamVjdCBmb3Igb25lLW9yLW1vcmUgZWxlbWVudHMsXG5JbnRlcnByZXRzIGFueSBkcmFnZ2luZyBhcyBhbiBhdHRlbXB0IHRvIGRyYWcgYW4gZXZlbnRzIHRoYXQgbGl2ZXMgb3V0c2lkZVxub2YgYSBjYWxlbmRhciBvbnRvIGEgY2FsZW5kYXIuXG4qL1xudmFyIEV4dGVybmFsRWxlbWVudERyYWdnaW5nID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIEV4dGVybmFsRWxlbWVudERyYWdnaW5nKGRyYWdnaW5nLCBzdXBwbGllZERyYWdNZXRhKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHRoaXMucmVjZWl2aW5nQ2FsZW5kYXIgPSBudWxsO1xuICAgICAgICB0aGlzLmRyb3BwYWJsZUV2ZW50ID0gbnVsbDsgLy8gd2lsbCBleGlzdCBmb3IgYWxsIGRyYWdzLCBldmVuIGlmIGNyZWF0ZTpmYWxzZVxuICAgICAgICB0aGlzLnN1cHBsaWVkRHJhZ01ldGEgPSBudWxsO1xuICAgICAgICB0aGlzLmRyYWdNZXRhID0gbnVsbDtcbiAgICAgICAgdGhpcy5oYW5kbGVEcmFnU3RhcnQgPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgICAgIF90aGlzLmRyYWdNZXRhID0gX3RoaXMuYnVpbGREcmFnTWV0YShldi5zdWJqZWN0RWwpO1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZUhpdFVwZGF0ZSA9IGZ1bmN0aW9uIChoaXQsIGlzRmluYWwsIGV2KSB7XG4gICAgICAgICAgICB2YXIgZHJhZ2dpbmcgPSBfdGhpcy5oaXREcmFnZ2luZy5kcmFnZ2luZztcbiAgICAgICAgICAgIHZhciByZWNlaXZpbmdDYWxlbmRhciA9IG51bGw7XG4gICAgICAgICAgICB2YXIgZHJvcHBhYmxlRXZlbnQgPSBudWxsO1xuICAgICAgICAgICAgdmFyIGlzSW52YWxpZCA9IGZhbHNlO1xuICAgICAgICAgICAgdmFyIGludGVyYWN0aW9uID0ge1xuICAgICAgICAgICAgICAgIGFmZmVjdGVkRXZlbnRzOiBjcmVhdGVFbXB0eUV2ZW50U3RvcmUoKSxcbiAgICAgICAgICAgICAgICBtdXRhdGVkRXZlbnRzOiBjcmVhdGVFbXB0eUV2ZW50U3RvcmUoKSxcbiAgICAgICAgICAgICAgICBpc0V2ZW50OiBfdGhpcy5kcmFnTWV0YS5jcmVhdGUsXG4gICAgICAgICAgICAgICAgb3JpZ1NlZzogbnVsbFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGlmIChoaXQpIHtcbiAgICAgICAgICAgICAgICByZWNlaXZpbmdDYWxlbmRhciA9IGhpdC5jb21wb25lbnQuY29udGV4dC5jYWxlbmRhcjtcbiAgICAgICAgICAgICAgICBpZiAoX3RoaXMuY2FuRHJvcEVsT25DYWxlbmRhcihldi5zdWJqZWN0RWwsIHJlY2VpdmluZ0NhbGVuZGFyKSkge1xuICAgICAgICAgICAgICAgICAgICBkcm9wcGFibGVFdmVudCA9IGNvbXB1dGVFdmVudEZvckRhdGVTcGFuKGhpdC5kYXRlU3BhbiwgX3RoaXMuZHJhZ01ldGEsIHJlY2VpdmluZ0NhbGVuZGFyKTtcbiAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3Rpb24ubXV0YXRlZEV2ZW50cyA9IGV2ZW50VHVwbGVUb1N0b3JlKGRyb3BwYWJsZUV2ZW50KTtcbiAgICAgICAgICAgICAgICAgICAgaXNJbnZhbGlkID0gIWlzSW50ZXJhY3Rpb25WYWxpZChpbnRlcmFjdGlvbiwgcmVjZWl2aW5nQ2FsZW5kYXIpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoaXNJbnZhbGlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGlvbi5tdXRhdGVkRXZlbnRzID0gY3JlYXRlRW1wdHlFdmVudFN0b3JlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBkcm9wcGFibGVFdmVudCA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBfdGhpcy5kaXNwbGF5RHJhZyhyZWNlaXZpbmdDYWxlbmRhciwgaW50ZXJhY3Rpb24pO1xuICAgICAgICAgICAgLy8gc2hvdyBtaXJyb3IgaWYgbm8gYWxyZWFkeS1yZW5kZXJlZCBtaXJyb3IgZWxlbWVudCBPUiBpZiB3ZSBhcmUgc2h1dHRpbmcgZG93biB0aGUgbWlycm9yICg/KVxuICAgICAgICAgICAgLy8gVE9ETzogd2lzaCB3ZSBjb3VsZCBzb21laG93IHdhaXQgZm9yIGRpc3BhdGNoIHRvIGd1YXJhbnRlZSByZW5kZXJcbiAgICAgICAgICAgIGRyYWdnaW5nLnNldE1pcnJvcklzVmlzaWJsZShpc0ZpbmFsIHx8ICFkcm9wcGFibGVFdmVudCB8fCAhZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmZjLW1pcnJvcicpKTtcbiAgICAgICAgICAgIGlmICghaXNJbnZhbGlkKSB7XG4gICAgICAgICAgICAgICAgZW5hYmxlQ3Vyc29yKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBkaXNhYmxlQ3Vyc29yKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWlzRmluYWwpIHtcbiAgICAgICAgICAgICAgICBkcmFnZ2luZy5zZXRNaXJyb3JOZWVkc1JldmVydCghZHJvcHBhYmxlRXZlbnQpO1xuICAgICAgICAgICAgICAgIF90aGlzLnJlY2VpdmluZ0NhbGVuZGFyID0gcmVjZWl2aW5nQ2FsZW5kYXI7XG4gICAgICAgICAgICAgICAgX3RoaXMuZHJvcHBhYmxlRXZlbnQgPSBkcm9wcGFibGVFdmVudDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVEcmFnRW5kID0gZnVuY3Rpb24gKHBldikge1xuICAgICAgICAgICAgdmFyIF9hID0gX3RoaXMsIHJlY2VpdmluZ0NhbGVuZGFyID0gX2EucmVjZWl2aW5nQ2FsZW5kYXIsIGRyb3BwYWJsZUV2ZW50ID0gX2EuZHJvcHBhYmxlRXZlbnQ7XG4gICAgICAgICAgICBfdGhpcy5jbGVhckRyYWcoKTtcbiAgICAgICAgICAgIGlmIChyZWNlaXZpbmdDYWxlbmRhciAmJiBkcm9wcGFibGVFdmVudCkge1xuICAgICAgICAgICAgICAgIHZhciBmaW5hbEhpdCA9IF90aGlzLmhpdERyYWdnaW5nLmZpbmFsSGl0O1xuICAgICAgICAgICAgICAgIHZhciBmaW5hbFZpZXcgPSBmaW5hbEhpdC5jb21wb25lbnQuY29udGV4dC52aWV3O1xuICAgICAgICAgICAgICAgIHZhciBkcmFnTWV0YSA9IF90aGlzLmRyYWdNZXRhO1xuICAgICAgICAgICAgICAgIHZhciBhcmcgPSBfX2Fzc2lnbih7fSwgcmVjZWl2aW5nQ2FsZW5kYXIuYnVpbGREYXRlUG9pbnRBcGkoZmluYWxIaXQuZGF0ZVNwYW4pLCB7IGRyYWdnZWRFbDogcGV2LnN1YmplY3RFbCwganNFdmVudDogcGV2Lm9yaWdFdmVudCwgdmlldzogZmluYWxWaWV3IH0pO1xuICAgICAgICAgICAgICAgIHJlY2VpdmluZ0NhbGVuZGFyLnB1YmxpY2x5VHJpZ2dlcignZHJvcCcsIFthcmddKTtcbiAgICAgICAgICAgICAgICBpZiAoZHJhZ01ldGEuY3JlYXRlKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlY2VpdmluZ0NhbGVuZGFyLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdNRVJHRV9FVkVOVFMnLFxuICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRTdG9yZTogZXZlbnRUdXBsZVRvU3RvcmUoZHJvcHBhYmxlRXZlbnQpXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBpZiAocGV2LmlzVG91Y2gpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlY2VpdmluZ0NhbGVuZGFyLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnU0VMRUNUX0VWRU5UJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudEluc3RhbmNlSWQ6IGRyb3BwYWJsZUV2ZW50Lmluc3RhbmNlLmluc3RhbmNlSWRcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIC8vIHNpZ25hbCB0aGF0IGFuIGV4dGVybmFsIGV2ZW50IGxhbmRlZFxuICAgICAgICAgICAgICAgICAgICByZWNlaXZpbmdDYWxlbmRhci5wdWJsaWNseVRyaWdnZXIoJ2V2ZW50UmVjZWl2ZScsIFtcbiAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcmFnZ2VkRWw6IHBldi5zdWJqZWN0RWwsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnQ6IG5ldyBFdmVudEFwaShyZWNlaXZpbmdDYWxlbmRhciwgZHJvcHBhYmxlRXZlbnQuZGVmLCBkcm9wcGFibGVFdmVudC5pbnN0YW5jZSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlldzogZmluYWxWaWV3XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIF90aGlzLnJlY2VpdmluZ0NhbGVuZGFyID0gbnVsbDtcbiAgICAgICAgICAgIF90aGlzLmRyb3BwYWJsZUV2ZW50ID0gbnVsbDtcbiAgICAgICAgfTtcbiAgICAgICAgdmFyIGhpdERyYWdnaW5nID0gdGhpcy5oaXREcmFnZ2luZyA9IG5ldyBIaXREcmFnZ2luZyhkcmFnZ2luZywgaW50ZXJhY3Rpb25TZXR0aW5nc1N0b3JlKTtcbiAgICAgICAgaGl0RHJhZ2dpbmcucmVxdWlyZUluaXRpYWwgPSBmYWxzZTsgLy8gd2lsbCBzdGFydCBvdXRzaWRlIG9mIGEgY29tcG9uZW50XG4gICAgICAgIGhpdERyYWdnaW5nLmVtaXR0ZXIub24oJ2RyYWdzdGFydCcsIHRoaXMuaGFuZGxlRHJhZ1N0YXJ0KTtcbiAgICAgICAgaGl0RHJhZ2dpbmcuZW1pdHRlci5vbignaGl0dXBkYXRlJywgdGhpcy5oYW5kbGVIaXRVcGRhdGUpO1xuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdkcmFnZW5kJywgdGhpcy5oYW5kbGVEcmFnRW5kKTtcbiAgICAgICAgdGhpcy5zdXBwbGllZERyYWdNZXRhID0gc3VwcGxpZWREcmFnTWV0YTtcbiAgICB9XG4gICAgRXh0ZXJuYWxFbGVtZW50RHJhZ2dpbmcucHJvdG90eXBlLmJ1aWxkRHJhZ01ldGEgPSBmdW5jdGlvbiAoc3ViamVjdEVsKSB7XG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5zdXBwbGllZERyYWdNZXRhID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgcmV0dXJuIHBhcnNlRHJhZ01ldGEodGhpcy5zdXBwbGllZERyYWdNZXRhKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0eXBlb2YgdGhpcy5zdXBwbGllZERyYWdNZXRhID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICByZXR1cm4gcGFyc2VEcmFnTWV0YSh0aGlzLnN1cHBsaWVkRHJhZ01ldGEoc3ViamVjdEVsKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gZ2V0RHJhZ01ldGFGcm9tRWwoc3ViamVjdEVsKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgRXh0ZXJuYWxFbGVtZW50RHJhZ2dpbmcucHJvdG90eXBlLmRpc3BsYXlEcmFnID0gZnVuY3Rpb24gKG5leHRDYWxlbmRhciwgc3RhdGUpIHtcbiAgICAgICAgdmFyIHByZXZDYWxlbmRhciA9IHRoaXMucmVjZWl2aW5nQ2FsZW5kYXI7XG4gICAgICAgIGlmIChwcmV2Q2FsZW5kYXIgJiYgcHJldkNhbGVuZGFyICE9PSBuZXh0Q2FsZW5kYXIpIHtcbiAgICAgICAgICAgIHByZXZDYWxlbmRhci5kaXNwYXRjaCh7IHR5cGU6ICdVTlNFVF9FVkVOVF9EUkFHJyB9KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobmV4dENhbGVuZGFyKSB7XG4gICAgICAgICAgICBuZXh0Q2FsZW5kYXIuZGlzcGF0Y2goeyB0eXBlOiAnU0VUX0VWRU5UX0RSQUcnLCBzdGF0ZTogc3RhdGUgfSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIEV4dGVybmFsRWxlbWVudERyYWdnaW5nLnByb3RvdHlwZS5jbGVhckRyYWcgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh0aGlzLnJlY2VpdmluZ0NhbGVuZGFyKSB7XG4gICAgICAgICAgICB0aGlzLnJlY2VpdmluZ0NhbGVuZGFyLmRpc3BhdGNoKHsgdHlwZTogJ1VOU0VUX0VWRU5UX0RSQUcnIH0pO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBFeHRlcm5hbEVsZW1lbnREcmFnZ2luZy5wcm90b3R5cGUuY2FuRHJvcEVsT25DYWxlbmRhciA9IGZ1bmN0aW9uIChlbCwgcmVjZWl2aW5nQ2FsZW5kYXIpIHtcbiAgICAgICAgdmFyIGRyb3BBY2NlcHQgPSByZWNlaXZpbmdDYWxlbmRhci5vcHQoJ2Ryb3BBY2NlcHQnKTtcbiAgICAgICAgaWYgKHR5cGVvZiBkcm9wQWNjZXB0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICByZXR1cm4gZHJvcEFjY2VwdChlbCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodHlwZW9mIGRyb3BBY2NlcHQgPT09ICdzdHJpbmcnICYmIGRyb3BBY2NlcHQpIHtcbiAgICAgICAgICAgIHJldHVybiBCb29sZWFuKGVsZW1lbnRNYXRjaGVzKGVsLCBkcm9wQWNjZXB0KSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfTtcbiAgICByZXR1cm4gRXh0ZXJuYWxFbGVtZW50RHJhZ2dpbmc7XG59KCkpO1xuLy8gVXRpbHMgZm9yIGNvbXB1dGluZyBldmVudCBzdG9yZSBmcm9tIHRoZSBEcmFnTWV0YVxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuZnVuY3Rpb24gY29tcHV0ZUV2ZW50Rm9yRGF0ZVNwYW4oZGF0ZVNwYW4sIGRyYWdNZXRhLCBjYWxlbmRhcikge1xuICAgIHZhciBkZWZQcm9wcyA9IF9fYXNzaWduKHt9LCBkcmFnTWV0YS5sZWZ0b3ZlclByb3BzKTtcbiAgICBmb3IgKHZhciBfaSA9IDAsIF9hID0gY2FsZW5kYXIucGx1Z2luU3lzdGVtLmhvb2tzLmV4dGVybmFsRGVmVHJhbnNmb3JtczsgX2kgPCBfYS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgdmFyIHRyYW5zZm9ybSA9IF9hW19pXTtcbiAgICAgICAgX19hc3NpZ24oZGVmUHJvcHMsIHRyYW5zZm9ybShkYXRlU3BhbiwgZHJhZ01ldGEpKTtcbiAgICB9XG4gICAgdmFyIGRlZiA9IHBhcnNlRXZlbnREZWYoZGVmUHJvcHMsIGRyYWdNZXRhLnNvdXJjZUlkLCBkYXRlU3Bhbi5hbGxEYXksIGNhbGVuZGFyLm9wdCgnZm9yY2VFdmVudER1cmF0aW9uJykgfHwgQm9vbGVhbihkcmFnTWV0YS5kdXJhdGlvbiksIC8vIGhhc0VuZFxuICAgIGNhbGVuZGFyKTtcbiAgICB2YXIgc3RhcnQgPSBkYXRlU3Bhbi5yYW5nZS5zdGFydDtcbiAgICAvLyBvbmx5IHJlbHkgb24gdGltZSBpbmZvIGlmIGRyb3Agem9uZSBpcyBhbGwtZGF5LFxuICAgIC8vIG90aGVyd2lzZSwgd2UgYWxyZWFkeSBrbm93IHRoZSB0aW1lXG4gICAgaWYgKGRhdGVTcGFuLmFsbERheSAmJiBkcmFnTWV0YS5zdGFydFRpbWUpIHtcbiAgICAgICAgc3RhcnQgPSBjYWxlbmRhci5kYXRlRW52LmFkZChzdGFydCwgZHJhZ01ldGEuc3RhcnRUaW1lKTtcbiAgICB9XG4gICAgdmFyIGVuZCA9IGRyYWdNZXRhLmR1cmF0aW9uID9cbiAgICAgICAgY2FsZW5kYXIuZGF0ZUVudi5hZGQoc3RhcnQsIGRyYWdNZXRhLmR1cmF0aW9uKSA6XG4gICAgICAgIGNhbGVuZGFyLmdldERlZmF1bHRFdmVudEVuZChkYXRlU3Bhbi5hbGxEYXksIHN0YXJ0KTtcbiAgICB2YXIgaW5zdGFuY2UgPSBjcmVhdGVFdmVudEluc3RhbmNlKGRlZi5kZWZJZCwgeyBzdGFydDogc3RhcnQsIGVuZDogZW5kIH0pO1xuICAgIHJldHVybiB7IGRlZjogZGVmLCBpbnN0YW5jZTogaW5zdGFuY2UgfTtcbn1cbi8vIFV0aWxzIGZvciBleHRyYWN0aW5nIGRhdGEgZnJvbSBlbGVtZW50XG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5mdW5jdGlvbiBnZXREcmFnTWV0YUZyb21FbChlbCkge1xuICAgIHZhciBzdHIgPSBnZXRFbWJlZGRlZEVsRGF0YShlbCwgJ2V2ZW50Jyk7XG4gICAgdmFyIG9iaiA9IHN0ciA/XG4gICAgICAgIEpTT04ucGFyc2Uoc3RyKSA6XG4gICAgICAgIHsgY3JlYXRlOiBmYWxzZSB9OyAvLyBpZiBubyBlbWJlZGRlZCBkYXRhLCBhc3N1bWUgbm8gZXZlbnQgY3JlYXRpb25cbiAgICByZXR1cm4gcGFyc2VEcmFnTWV0YShvYmopO1xufVxuY29uZmlnLmRhdGFBdHRyUHJlZml4ID0gJyc7XG5mdW5jdGlvbiBnZXRFbWJlZGRlZEVsRGF0YShlbCwgbmFtZSkge1xuICAgIHZhciBwcmVmaXggPSBjb25maWcuZGF0YUF0dHJQcmVmaXg7XG4gICAgdmFyIHByZWZpeGVkTmFtZSA9IChwcmVmaXggPyBwcmVmaXggKyAnLScgOiAnJykgKyBuYW1lO1xuICAgIHJldHVybiBlbC5nZXRBdHRyaWJ1dGUoJ2RhdGEtJyArIHByZWZpeGVkTmFtZSkgfHwgJyc7XG59XG5cbi8qXG5NYWtlcyBhbiBlbGVtZW50ICh0aGF0IGlzICpleHRlcm5hbCogdG8gYW55IGNhbGVuZGFyKSBkcmFnZ2FibGUuXG5DYW4gcGFzcyBpbiBkYXRhIHRoYXQgZGV0ZXJtaW5lcyBob3cgYW4gZXZlbnQgd2lsbCBiZSBjcmVhdGVkIHdoZW4gZHJvcHBlZCBvbnRvIGEgY2FsZW5kYXIuXG5MZXZlcmFnZXMgRnVsbENhbGVuZGFyJ3MgaW50ZXJuYWwgZHJhZy1uLWRyb3AgZnVuY3Rpb25hbGl0eSBXSVRIT1VUIGEgdGhpcmQtcGFydHkgZHJhZyBzeXN0ZW0uXG4qL1xudmFyIEV4dGVybmFsRHJhZ2dhYmxlID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIEV4dGVybmFsRHJhZ2dhYmxlKGVsLCBzZXR0aW5ncykge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICBpZiAoc2V0dGluZ3MgPT09IHZvaWQgMCkgeyBzZXR0aW5ncyA9IHt9OyB9XG4gICAgICAgIHRoaXMuaGFuZGxlUG9pbnRlckRvd24gPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgICAgIHZhciBkcmFnZ2luZyA9IF90aGlzLmRyYWdnaW5nO1xuICAgICAgICAgICAgdmFyIF9hID0gX3RoaXMuc2V0dGluZ3MsIG1pbkRpc3RhbmNlID0gX2EubWluRGlzdGFuY2UsIGxvbmdQcmVzc0RlbGF5ID0gX2EubG9uZ1ByZXNzRGVsYXk7XG4gICAgICAgICAgICBkcmFnZ2luZy5taW5EaXN0YW5jZSA9XG4gICAgICAgICAgICAgICAgbWluRGlzdGFuY2UgIT0gbnVsbCA/XG4gICAgICAgICAgICAgICAgICAgIG1pbkRpc3RhbmNlIDpcbiAgICAgICAgICAgICAgICAgICAgKGV2LmlzVG91Y2ggPyAwIDogZ2xvYmFsRGVmYXVsdHMuZXZlbnREcmFnTWluRGlzdGFuY2UpO1xuICAgICAgICAgICAgZHJhZ2dpbmcuZGVsYXkgPVxuICAgICAgICAgICAgICAgIGV2LmlzVG91Y2ggPyAvLyBUT0RPOiBldmVudHVhbGx5IHJlYWQgZXZlbnRMb25nUHJlc3NEZWxheSBpbnN0ZWFkIHZ2dlxuICAgICAgICAgICAgICAgICAgICAobG9uZ1ByZXNzRGVsYXkgIT0gbnVsbCA/IGxvbmdQcmVzc0RlbGF5IDogZ2xvYmFsRGVmYXVsdHMubG9uZ1ByZXNzRGVsYXkpIDpcbiAgICAgICAgICAgICAgICAgICAgMDtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVEcmFnU3RhcnQgPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgICAgIGlmIChldi5pc1RvdWNoICYmXG4gICAgICAgICAgICAgICAgX3RoaXMuZHJhZ2dpbmcuZGVsYXkgJiZcbiAgICAgICAgICAgICAgICBldi5zdWJqZWN0RWwuY2xhc3NMaXN0LmNvbnRhaW5zKCdmYy1ldmVudCcpKSB7XG4gICAgICAgICAgICAgICAgX3RoaXMuZHJhZ2dpbmcubWlycm9yLmdldE1pcnJvckVsKCkuY2xhc3NMaXN0LmFkZCgnZmMtc2VsZWN0ZWQnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5zZXR0aW5ncyA9IHNldHRpbmdzO1xuICAgICAgICB2YXIgZHJhZ2dpbmcgPSB0aGlzLmRyYWdnaW5nID0gbmV3IEZlYXR1cmVmdWxFbGVtZW50RHJhZ2dpbmcoZWwpO1xuICAgICAgICBkcmFnZ2luZy50b3VjaFNjcm9sbEFsbG93ZWQgPSBmYWxzZTtcbiAgICAgICAgaWYgKHNldHRpbmdzLml0ZW1TZWxlY3RvciAhPSBudWxsKSB7XG4gICAgICAgICAgICBkcmFnZ2luZy5wb2ludGVyLnNlbGVjdG9yID0gc2V0dGluZ3MuaXRlbVNlbGVjdG9yO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzZXR0aW5ncy5hcHBlbmRUbyAhPSBudWxsKSB7XG4gICAgICAgICAgICBkcmFnZ2luZy5taXJyb3IucGFyZW50Tm9kZSA9IHNldHRpbmdzLmFwcGVuZFRvOyAvLyBUT0RPOiB3cml0ZSB0ZXN0c1xuICAgICAgICB9XG4gICAgICAgIGRyYWdnaW5nLmVtaXR0ZXIub24oJ3BvaW50ZXJkb3duJywgdGhpcy5oYW5kbGVQb2ludGVyRG93bik7XG4gICAgICAgIGRyYWdnaW5nLmVtaXR0ZXIub24oJ2RyYWdzdGFydCcsIHRoaXMuaGFuZGxlRHJhZ1N0YXJ0KTtcbiAgICAgICAgbmV3IEV4dGVybmFsRWxlbWVudERyYWdnaW5nKGRyYWdnaW5nLCBzZXR0aW5ncy5ldmVudERhdGEpO1xuICAgIH1cbiAgICBFeHRlcm5hbERyYWdnYWJsZS5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5kcmFnZ2luZy5kZXN0cm95KCk7XG4gICAgfTtcbiAgICByZXR1cm4gRXh0ZXJuYWxEcmFnZ2FibGU7XG59KCkpO1xuXG4vKlxuRGV0ZWN0cyB3aGVuIGEgKlRISVJELVBBUlRZKiBkcmFnLW4tZHJvcCBzeXN0ZW0gaW50ZXJhY3RzIHdpdGggZWxlbWVudHMuXG5UaGUgdGhpcmQtcGFydHkgc3lzdGVtIGlzIHJlc3BvbnNpYmxlIGZvciBkcmF3aW5nIHRoZSB2aXN1YWxzIGVmZmVjdHMgb2YgdGhlIGRyYWcuXG5UaGlzIGNsYXNzIHNpbXBseSBtb25pdG9ycyBmb3IgcG9pbnRlciBtb3ZlbWVudHMgYW5kIGZpcmVzIGV2ZW50cy5cbkl0IGFsc28gaGFzIHRoZSBhYmlsaXR5IHRvIGhpZGUgdGhlIG1vdmluZyBlbGVtZW50ICh0aGUgXCJtaXJyb3JcIikgZHVyaW5nIHRoZSBkcmFnLlxuKi9cbnZhciBJbmZlcnJlZEVsZW1lbnREcmFnZ2luZyA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uIChfc3VwZXIpIHtcbiAgICBfX2V4dGVuZHMoSW5mZXJyZWRFbGVtZW50RHJhZ2dpbmcsIF9zdXBlcik7XG4gICAgZnVuY3Rpb24gSW5mZXJyZWRFbGVtZW50RHJhZ2dpbmcoY29udGFpbmVyRWwpIHtcbiAgICAgICAgdmFyIF90aGlzID0gX3N1cGVyLmNhbGwodGhpcywgY29udGFpbmVyRWwpIHx8IHRoaXM7XG4gICAgICAgIF90aGlzLnNob3VsZElnbm9yZU1vdmUgPSBmYWxzZTtcbiAgICAgICAgX3RoaXMubWlycm9yU2VsZWN0b3IgPSAnJztcbiAgICAgICAgX3RoaXMuY3VycmVudE1pcnJvckVsID0gbnVsbDtcbiAgICAgICAgX3RoaXMuaGFuZGxlUG9pbnRlckRvd24gPSBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgICAgIF90aGlzLmVtaXR0ZXIudHJpZ2dlcigncG9pbnRlcmRvd24nLCBldik7XG4gICAgICAgICAgICBpZiAoIV90aGlzLnNob3VsZElnbm9yZU1vdmUpIHtcbiAgICAgICAgICAgICAgICAvLyBmaXJlIGRyYWdzdGFydCByaWdodCBhd2F5LiBkb2VzIG5vdCBzdXBwb3J0IGRlbGF5IG9yIG1pbi1kaXN0YW5jZVxuICAgICAgICAgICAgICAgIF90aGlzLmVtaXR0ZXIudHJpZ2dlcignZHJhZ3N0YXJ0JywgZXYpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICBfdGhpcy5oYW5kbGVQb2ludGVyTW92ZSA9IGZ1bmN0aW9uIChldikge1xuICAgICAgICAgICAgaWYgKCFfdGhpcy5zaG91bGRJZ25vcmVNb3ZlKSB7XG4gICAgICAgICAgICAgICAgX3RoaXMuZW1pdHRlci50cmlnZ2VyKCdkcmFnbW92ZScsIGV2KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgX3RoaXMuaGFuZGxlUG9pbnRlclVwID0gZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICBfdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ3BvaW50ZXJ1cCcsIGV2KTtcbiAgICAgICAgICAgIGlmICghX3RoaXMuc2hvdWxkSWdub3JlTW92ZSkge1xuICAgICAgICAgICAgICAgIC8vIGZpcmUgZHJhZ2VuZCByaWdodCBhd2F5LiBkb2VzIG5vdCBzdXBwb3J0IGEgcmV2ZXJ0IGFuaW1hdGlvblxuICAgICAgICAgICAgICAgIF90aGlzLmVtaXR0ZXIudHJpZ2dlcignZHJhZ2VuZCcsIGV2KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdmFyIHBvaW50ZXIgPSBfdGhpcy5wb2ludGVyID0gbmV3IFBvaW50ZXJEcmFnZ2luZyhjb250YWluZXJFbCk7XG4gICAgICAgIHBvaW50ZXIuZW1pdHRlci5vbigncG9pbnRlcmRvd24nLCBfdGhpcy5oYW5kbGVQb2ludGVyRG93bik7XG4gICAgICAgIHBvaW50ZXIuZW1pdHRlci5vbigncG9pbnRlcm1vdmUnLCBfdGhpcy5oYW5kbGVQb2ludGVyTW92ZSk7XG4gICAgICAgIHBvaW50ZXIuZW1pdHRlci5vbigncG9pbnRlcnVwJywgX3RoaXMuaGFuZGxlUG9pbnRlclVwKTtcbiAgICAgICAgcmV0dXJuIF90aGlzO1xuICAgIH1cbiAgICBJbmZlcnJlZEVsZW1lbnREcmFnZ2luZy5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5wb2ludGVyLmRlc3Ryb3koKTtcbiAgICB9O1xuICAgIEluZmVycmVkRWxlbWVudERyYWdnaW5nLnByb3RvdHlwZS5zZXRJZ25vcmVNb3ZlID0gZnVuY3Rpb24gKGJvb2wpIHtcbiAgICAgICAgdGhpcy5zaG91bGRJZ25vcmVNb3ZlID0gYm9vbDtcbiAgICB9O1xuICAgIEluZmVycmVkRWxlbWVudERyYWdnaW5nLnByb3RvdHlwZS5zZXRNaXJyb3JJc1Zpc2libGUgPSBmdW5jdGlvbiAoYm9vbCkge1xuICAgICAgICBpZiAoYm9vbCkge1xuICAgICAgICAgICAgLy8gcmVzdG9yZSBhIHByZXZpb3VzbHkgaGlkZGVuIGVsZW1lbnQuXG4gICAgICAgICAgICAvLyB1c2UgdGhlIHJlZmVyZW5jZSBpbiBjYXNlIHRoZSBzZWxlY3RvciBjbGFzcyBoYXMgYWxyZWFkeSBiZWVuIHJlbW92ZWQuXG4gICAgICAgICAgICBpZiAodGhpcy5jdXJyZW50TWlycm9yRWwpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmN1cnJlbnRNaXJyb3JFbC5zdHlsZS52aXNpYmlsaXR5ID0gJyc7XG4gICAgICAgICAgICAgICAgdGhpcy5jdXJyZW50TWlycm9yRWwgPSBudWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdmFyIG1pcnJvckVsID0gdGhpcy5taXJyb3JTZWxlY3RvciA/XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLm1pcnJvclNlbGVjdG9yKSA6XG4gICAgICAgICAgICAgICAgbnVsbDtcbiAgICAgICAgICAgIGlmIChtaXJyb3JFbCkge1xuICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudE1pcnJvckVsID0gbWlycm9yRWw7XG4gICAgICAgICAgICAgICAgbWlycm9yRWwuc3R5bGUudmlzaWJpbGl0eSA9ICdoaWRkZW4nO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcbiAgICByZXR1cm4gSW5mZXJyZWRFbGVtZW50RHJhZ2dpbmc7XG59KEVsZW1lbnREcmFnZ2luZykpO1xuXG4vKlxuQnJpZGdlcyB0aGlyZC1wYXJ0eSBkcmFnLW4tZHJvcCBzeXN0ZW1zIHdpdGggRnVsbENhbGVuZGFyLlxuTXVzdCBiZSBpbnN0YW50aWF0ZWQgYW5kIGRlc3Ryb3llZCBieSBjYWxsZXIuXG4qL1xudmFyIFRoaXJkUGFydHlEcmFnZ2FibGUgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gVGhpcmRQYXJ0eURyYWdnYWJsZShjb250YWluZXJPclNldHRpbmdzLCBzZXR0aW5ncykge1xuICAgICAgICB2YXIgY29udGFpbmVyRWwgPSBkb2N1bWVudDtcbiAgICAgICAgaWYgKFxuICAgICAgICAvLyB3aXNoIHdlIGNvdWxkIGp1c3QgdGVzdCBpbnN0YW5jZW9mIEV2ZW50VGFyZ2V0LCBidXQgZG9lc24ndCB3b3JrIGluIElFMTFcbiAgICAgICAgY29udGFpbmVyT3JTZXR0aW5ncyA9PT0gZG9jdW1lbnQgfHxcbiAgICAgICAgICAgIGNvbnRhaW5lck9yU2V0dGluZ3MgaW5zdGFuY2VvZiBFbGVtZW50KSB7XG4gICAgICAgICAgICBjb250YWluZXJFbCA9IGNvbnRhaW5lck9yU2V0dGluZ3M7XG4gICAgICAgICAgICBzZXR0aW5ncyA9IHNldHRpbmdzIHx8IHt9O1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgc2V0dGluZ3MgPSAoY29udGFpbmVyT3JTZXR0aW5ncyB8fCB7fSk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGRyYWdnaW5nID0gdGhpcy5kcmFnZ2luZyA9IG5ldyBJbmZlcnJlZEVsZW1lbnREcmFnZ2luZyhjb250YWluZXJFbCk7XG4gICAgICAgIGlmICh0eXBlb2Ygc2V0dGluZ3MuaXRlbVNlbGVjdG9yID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgZHJhZ2dpbmcucG9pbnRlci5zZWxlY3RvciA9IHNldHRpbmdzLml0ZW1TZWxlY3RvcjtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChjb250YWluZXJFbCA9PT0gZG9jdW1lbnQpIHtcbiAgICAgICAgICAgIGRyYWdnaW5nLnBvaW50ZXIuc2VsZWN0b3IgPSAnW2RhdGEtZXZlbnRdJztcbiAgICAgICAgfVxuICAgICAgICBpZiAodHlwZW9mIHNldHRpbmdzLm1pcnJvclNlbGVjdG9yID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgZHJhZ2dpbmcubWlycm9yU2VsZWN0b3IgPSBzZXR0aW5ncy5taXJyb3JTZWxlY3RvcjtcbiAgICAgICAgfVxuICAgICAgICBuZXcgRXh0ZXJuYWxFbGVtZW50RHJhZ2dpbmcoZHJhZ2dpbmcsIHNldHRpbmdzLmV2ZW50RGF0YSk7XG4gICAgfVxuICAgIFRoaXJkUGFydHlEcmFnZ2FibGUucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuZHJhZ2dpbmcuZGVzdHJveSgpO1xuICAgIH07XG4gICAgcmV0dXJuIFRoaXJkUGFydHlEcmFnZ2FibGU7XG59KCkpO1xuXG52YXIgbWFpbiA9IGNyZWF0ZVBsdWdpbih7XG4gICAgY29tcG9uZW50SW50ZXJhY3Rpb25zOiBbRGF0ZUNsaWNraW5nLCBEYXRlU2VsZWN0aW5nLCBFdmVudERyYWdnaW5nLCBFdmVudERyYWdnaW5nJDFdLFxuICAgIGNhbGVuZGFySW50ZXJhY3Rpb25zOiBbVW5zZWxlY3RBdXRvXSxcbiAgICBlbGVtZW50RHJhZ2dpbmdJbXBsOiBGZWF0dXJlZnVsRWxlbWVudERyYWdnaW5nXG59KTtcblxuZXhwb3J0IGRlZmF1bHQgbWFpbjtcbmV4cG9ydCB7IEV4dGVybmFsRHJhZ2dhYmxlIGFzIERyYWdnYWJsZSwgRmVhdHVyZWZ1bEVsZW1lbnREcmFnZ2luZywgUG9pbnRlckRyYWdnaW5nLCBUaGlyZFBhcnR5RHJhZ2dhYmxlIH07XG4iLCJ2YXIgaXNPYmplY3QgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvaXMtb2JqZWN0Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGl0KSB7XG4gIGlmICghaXNPYmplY3QoaXQpKSB7XG4gICAgdGhyb3cgVHlwZUVycm9yKFN0cmluZyhpdCkgKyAnIGlzIG5vdCBhbiBvYmplY3QnKTtcbiAgfSByZXR1cm4gaXQ7XG59O1xuIiwidmFyIHRvU3RyaW5nID0ge30udG9TdHJpbmc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGl0KSB7XG4gIHJldHVybiB0b1N0cmluZy5jYWxsKGl0KS5zbGljZSg4LCAtMSk7XG59O1xuIiwidmFyIFRPX1NUUklOR19UQUdfU1VQUE9SVCA9IHJlcXVpcmUoJy4uL2ludGVybmFscy90by1zdHJpbmctdGFnLXN1cHBvcnQnKTtcbnZhciBjbGFzc29mUmF3ID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL2NsYXNzb2YtcmF3Jyk7XG52YXIgd2VsbEtub3duU3ltYm9sID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL3dlbGwta25vd24tc3ltYm9sJyk7XG5cbnZhciBUT19TVFJJTkdfVEFHID0gd2VsbEtub3duU3ltYm9sKCd0b1N0cmluZ1RhZycpO1xuLy8gRVMzIHdyb25nIGhlcmVcbnZhciBDT1JSRUNUX0FSR1VNRU5UUyA9IGNsYXNzb2ZSYXcoZnVuY3Rpb24gKCkgeyByZXR1cm4gYXJndW1lbnRzOyB9KCkpID09ICdBcmd1bWVudHMnO1xuXG4vLyBmYWxsYmFjayBmb3IgSUUxMSBTY3JpcHQgQWNjZXNzIERlbmllZCBlcnJvclxudmFyIHRyeUdldCA9IGZ1bmN0aW9uIChpdCwga2V5KSB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIGl0W2tleV07XG4gIH0gY2F0Y2ggKGVycm9yKSB7IC8qIGVtcHR5ICovIH1cbn07XG5cbi8vIGdldHRpbmcgdGFnIGZyb20gRVM2KyBgT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZ2Bcbm1vZHVsZS5leHBvcnRzID0gVE9fU1RSSU5HX1RBR19TVVBQT1JUID8gY2xhc3NvZlJhdyA6IGZ1bmN0aW9uIChpdCkge1xuICB2YXIgTywgdGFnLCByZXN1bHQ7XG4gIHJldHVybiBpdCA9PT0gdW5kZWZpbmVkID8gJ1VuZGVmaW5lZCcgOiBpdCA9PT0gbnVsbCA/ICdOdWxsJ1xuICAgIC8vIEBAdG9TdHJpbmdUYWcgY2FzZVxuICAgIDogdHlwZW9mICh0YWcgPSB0cnlHZXQoTyA9IE9iamVjdChpdCksIFRPX1NUUklOR19UQUcpKSA9PSAnc3RyaW5nJyA/IHRhZ1xuICAgIC8vIGJ1aWx0aW5UYWcgY2FzZVxuICAgIDogQ09SUkVDVF9BUkdVTUVOVFMgPyBjbGFzc29mUmF3KE8pXG4gICAgLy8gRVMzIGFyZ3VtZW50cyBmYWxsYmFja1xuICAgIDogKHJlc3VsdCA9IGNsYXNzb2ZSYXcoTykpID09ICdPYmplY3QnICYmIHR5cGVvZiBPLmNhbGxlZSA9PSAnZnVuY3Rpb24nID8gJ0FyZ3VtZW50cycgOiByZXN1bHQ7XG59O1xuIiwidmFyIERFU0NSSVBUT1JTID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL2Rlc2NyaXB0b3JzJyk7XG52YXIgZGVmaW5lUHJvcGVydHlNb2R1bGUgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvb2JqZWN0LWRlZmluZS1wcm9wZXJ0eScpO1xudmFyIGNyZWF0ZVByb3BlcnR5RGVzY3JpcHRvciA9IHJlcXVpcmUoJy4uL2ludGVybmFscy9jcmVhdGUtcHJvcGVydHktZGVzY3JpcHRvcicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IERFU0NSSVBUT1JTID8gZnVuY3Rpb24gKG9iamVjdCwga2V5LCB2YWx1ZSkge1xuICByZXR1cm4gZGVmaW5lUHJvcGVydHlNb2R1bGUuZihvYmplY3QsIGtleSwgY3JlYXRlUHJvcGVydHlEZXNjcmlwdG9yKDEsIHZhbHVlKSk7XG59IDogZnVuY3Rpb24gKG9iamVjdCwga2V5LCB2YWx1ZSkge1xuICBvYmplY3Rba2V5XSA9IHZhbHVlO1xuICByZXR1cm4gb2JqZWN0O1xufTtcbiIsIm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGJpdG1hcCwgdmFsdWUpIHtcbiAgcmV0dXJuIHtcbiAgICBlbnVtZXJhYmxlOiAhKGJpdG1hcCAmIDEpLFxuICAgIGNvbmZpZ3VyYWJsZTogIShiaXRtYXAgJiAyKSxcbiAgICB3cml0YWJsZTogIShiaXRtYXAgJiA0KSxcbiAgICB2YWx1ZTogdmFsdWVcbiAgfTtcbn07XG4iLCJ2YXIgZmFpbHMgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvZmFpbHMnKTtcblxuLy8gVGhhbmsncyBJRTggZm9yIGhpcyBmdW5ueSBkZWZpbmVQcm9wZXJ0eVxubW9kdWxlLmV4cG9ydHMgPSAhZmFpbHMoZnVuY3Rpb24gKCkge1xuICByZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5KHt9LCAxLCB7IGdldDogZnVuY3Rpb24gKCkgeyByZXR1cm4gNzsgfSB9KVsxXSAhPSA3O1xufSk7XG4iLCJ2YXIgZ2xvYmFsID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL2dsb2JhbCcpO1xudmFyIGlzT2JqZWN0ID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL2lzLW9iamVjdCcpO1xuXG52YXIgZG9jdW1lbnQgPSBnbG9iYWwuZG9jdW1lbnQ7XG4vLyB0eXBlb2YgZG9jdW1lbnQuY3JlYXRlRWxlbWVudCBpcyAnb2JqZWN0JyBpbiBvbGQgSUVcbnZhciBFWElTVFMgPSBpc09iamVjdChkb2N1bWVudCkgJiYgaXNPYmplY3QoZG9jdW1lbnQuY3JlYXRlRWxlbWVudCk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGl0KSB7XG4gIHJldHVybiBFWElTVFMgPyBkb2N1bWVudC5jcmVhdGVFbGVtZW50KGl0KSA6IHt9O1xufTtcbiIsIm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGV4ZWMpIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gISFleGVjKCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbn07XG4iLCJ2YXIgY2hlY2sgPSBmdW5jdGlvbiAoaXQpIHtcbiAgcmV0dXJuIGl0ICYmIGl0Lk1hdGggPT0gTWF0aCAmJiBpdDtcbn07XG5cbi8vIGh0dHBzOi8vZ2l0aHViLmNvbS96bG9pcm9jay9jb3JlLWpzL2lzc3Vlcy84NiNpc3N1ZWNvbW1lbnQtMTE1NzU5MDI4XG5tb2R1bGUuZXhwb3J0cyA9XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICBjaGVjayh0eXBlb2YgZ2xvYmFsVGhpcyA9PSAnb2JqZWN0JyAmJiBnbG9iYWxUaGlzKSB8fFxuICBjaGVjayh0eXBlb2Ygd2luZG93ID09ICdvYmplY3QnICYmIHdpbmRvdykgfHxcbiAgY2hlY2sodHlwZW9mIHNlbGYgPT0gJ29iamVjdCcgJiYgc2VsZikgfHxcbiAgY2hlY2sodHlwZW9mIGdsb2JhbCA9PSAnb2JqZWN0JyAmJiBnbG9iYWwpIHx8XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1uZXctZnVuY1xuICBGdW5jdGlvbigncmV0dXJuIHRoaXMnKSgpO1xuIiwidmFyIGhhc093blByb3BlcnR5ID0ge30uaGFzT3duUHJvcGVydHk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGl0LCBrZXkpIHtcbiAgcmV0dXJuIGhhc093blByb3BlcnR5LmNhbGwoaXQsIGtleSk7XG59O1xuIiwibW9kdWxlLmV4cG9ydHMgPSB7fTtcbiIsInZhciBERVNDUklQVE9SUyA9IHJlcXVpcmUoJy4uL2ludGVybmFscy9kZXNjcmlwdG9ycycpO1xudmFyIGZhaWxzID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL2ZhaWxzJyk7XG52YXIgY3JlYXRlRWxlbWVudCA9IHJlcXVpcmUoJy4uL2ludGVybmFscy9kb2N1bWVudC1jcmVhdGUtZWxlbWVudCcpO1xuXG4vLyBUaGFuaydzIElFOCBmb3IgaGlzIGZ1bm55IGRlZmluZVByb3BlcnR5XG5tb2R1bGUuZXhwb3J0cyA9ICFERVNDUklQVE9SUyAmJiAhZmFpbHMoZnVuY3Rpb24gKCkge1xuICByZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5KGNyZWF0ZUVsZW1lbnQoJ2RpdicpLCAnYScsIHtcbiAgICBnZXQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIDc7IH1cbiAgfSkuYSAhPSA3O1xufSk7XG4iLCJ2YXIgc3RvcmUgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvc2hhcmVkLXN0b3JlJyk7XG5cbnZhciBmdW5jdGlvblRvU3RyaW5nID0gRnVuY3Rpb24udG9TdHJpbmc7XG5cbi8vIHRoaXMgaGVscGVyIGJyb2tlbiBpbiBgMy40LjEtMy40LjRgLCBzbyB3ZSBjYW4ndCB1c2UgYHNoYXJlZGAgaGVscGVyXG5pZiAodHlwZW9mIHN0b3JlLmluc3BlY3RTb3VyY2UgIT0gJ2Z1bmN0aW9uJykge1xuICBzdG9yZS5pbnNwZWN0U291cmNlID0gZnVuY3Rpb24gKGl0KSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uVG9TdHJpbmcuY2FsbChpdCk7XG4gIH07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gc3RvcmUuaW5zcGVjdFNvdXJjZTtcbiIsInZhciBOQVRJVkVfV0VBS19NQVAgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvbmF0aXZlLXdlYWstbWFwJyk7XG52YXIgZ2xvYmFsID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL2dsb2JhbCcpO1xudmFyIGlzT2JqZWN0ID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL2lzLW9iamVjdCcpO1xudmFyIGNyZWF0ZU5vbkVudW1lcmFibGVQcm9wZXJ0eSA9IHJlcXVpcmUoJy4uL2ludGVybmFscy9jcmVhdGUtbm9uLWVudW1lcmFibGUtcHJvcGVydHknKTtcbnZhciBvYmplY3RIYXMgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvaGFzJyk7XG52YXIgc2hhcmVkS2V5ID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL3NoYXJlZC1rZXknKTtcbnZhciBoaWRkZW5LZXlzID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL2hpZGRlbi1rZXlzJyk7XG5cbnZhciBXZWFrTWFwID0gZ2xvYmFsLldlYWtNYXA7XG52YXIgc2V0LCBnZXQsIGhhcztcblxudmFyIGVuZm9yY2UgPSBmdW5jdGlvbiAoaXQpIHtcbiAgcmV0dXJuIGhhcyhpdCkgPyBnZXQoaXQpIDogc2V0KGl0LCB7fSk7XG59O1xuXG52YXIgZ2V0dGVyRm9yID0gZnVuY3Rpb24gKFRZUEUpIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIChpdCkge1xuICAgIHZhciBzdGF0ZTtcbiAgICBpZiAoIWlzT2JqZWN0KGl0KSB8fCAoc3RhdGUgPSBnZXQoaXQpKS50eXBlICE9PSBUWVBFKSB7XG4gICAgICB0aHJvdyBUeXBlRXJyb3IoJ0luY29tcGF0aWJsZSByZWNlaXZlciwgJyArIFRZUEUgKyAnIHJlcXVpcmVkJyk7XG4gICAgfSByZXR1cm4gc3RhdGU7XG4gIH07XG59O1xuXG5pZiAoTkFUSVZFX1dFQUtfTUFQKSB7XG4gIHZhciBzdG9yZSA9IG5ldyBXZWFrTWFwKCk7XG4gIHZhciB3bWdldCA9IHN0b3JlLmdldDtcbiAgdmFyIHdtaGFzID0gc3RvcmUuaGFzO1xuICB2YXIgd21zZXQgPSBzdG9yZS5zZXQ7XG4gIHNldCA9IGZ1bmN0aW9uIChpdCwgbWV0YWRhdGEpIHtcbiAgICB3bXNldC5jYWxsKHN0b3JlLCBpdCwgbWV0YWRhdGEpO1xuICAgIHJldHVybiBtZXRhZGF0YTtcbiAgfTtcbiAgZ2V0ID0gZnVuY3Rpb24gKGl0KSB7XG4gICAgcmV0dXJuIHdtZ2V0LmNhbGwoc3RvcmUsIGl0KSB8fCB7fTtcbiAgfTtcbiAgaGFzID0gZnVuY3Rpb24gKGl0KSB7XG4gICAgcmV0dXJuIHdtaGFzLmNhbGwoc3RvcmUsIGl0KTtcbiAgfTtcbn0gZWxzZSB7XG4gIHZhciBTVEFURSA9IHNoYXJlZEtleSgnc3RhdGUnKTtcbiAgaGlkZGVuS2V5c1tTVEFURV0gPSB0cnVlO1xuICBzZXQgPSBmdW5jdGlvbiAoaXQsIG1ldGFkYXRhKSB7XG4gICAgY3JlYXRlTm9uRW51bWVyYWJsZVByb3BlcnR5KGl0LCBTVEFURSwgbWV0YWRhdGEpO1xuICAgIHJldHVybiBtZXRhZGF0YTtcbiAgfTtcbiAgZ2V0ID0gZnVuY3Rpb24gKGl0KSB7XG4gICAgcmV0dXJuIG9iamVjdEhhcyhpdCwgU1RBVEUpID8gaXRbU1RBVEVdIDoge307XG4gIH07XG4gIGhhcyA9IGZ1bmN0aW9uIChpdCkge1xuICAgIHJldHVybiBvYmplY3RIYXMoaXQsIFNUQVRFKTtcbiAgfTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIHNldDogc2V0LFxuICBnZXQ6IGdldCxcbiAgaGFzOiBoYXMsXG4gIGVuZm9yY2U6IGVuZm9yY2UsXG4gIGdldHRlckZvcjogZ2V0dGVyRm9yXG59O1xuIiwibW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoaXQpIHtcbiAgcmV0dXJuIHR5cGVvZiBpdCA9PT0gJ29iamVjdCcgPyBpdCAhPT0gbnVsbCA6IHR5cGVvZiBpdCA9PT0gJ2Z1bmN0aW9uJztcbn07XG4iLCJtb2R1bGUuZXhwb3J0cyA9IGZhbHNlO1xuIiwidmFyIGZhaWxzID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL2ZhaWxzJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gISFPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzICYmICFmYWlscyhmdW5jdGlvbiAoKSB7XG4gIC8vIENocm9tZSAzOCBTeW1ib2wgaGFzIGluY29ycmVjdCB0b1N0cmluZyBjb252ZXJzaW9uXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICByZXR1cm4gIVN0cmluZyhTeW1ib2woKSk7XG59KTtcbiIsInZhciBnbG9iYWwgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvZ2xvYmFsJyk7XG52YXIgaW5zcGVjdFNvdXJjZSA9IHJlcXVpcmUoJy4uL2ludGVybmFscy9pbnNwZWN0LXNvdXJjZScpO1xuXG52YXIgV2Vha01hcCA9IGdsb2JhbC5XZWFrTWFwO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHR5cGVvZiBXZWFrTWFwID09PSAnZnVuY3Rpb24nICYmIC9uYXRpdmUgY29kZS8udGVzdChpbnNwZWN0U291cmNlKFdlYWtNYXApKTtcbiIsInZhciBERVNDUklQVE9SUyA9IHJlcXVpcmUoJy4uL2ludGVybmFscy9kZXNjcmlwdG9ycycpO1xudmFyIElFOF9ET01fREVGSU5FID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL2llOC1kb20tZGVmaW5lJyk7XG52YXIgYW5PYmplY3QgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvYW4tb2JqZWN0Jyk7XG52YXIgdG9QcmltaXRpdmUgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvdG8tcHJpbWl0aXZlJyk7XG5cbnZhciBuYXRpdmVEZWZpbmVQcm9wZXJ0eSA9IE9iamVjdC5kZWZpbmVQcm9wZXJ0eTtcblxuLy8gYE9iamVjdC5kZWZpbmVQcm9wZXJ0eWAgbWV0aG9kXG4vLyBodHRwczovL3RjMzkuZ2l0aHViLmlvL2VjbWEyNjIvI3NlYy1vYmplY3QuZGVmaW5lcHJvcGVydHlcbmV4cG9ydHMuZiA9IERFU0NSSVBUT1JTID8gbmF0aXZlRGVmaW5lUHJvcGVydHkgOiBmdW5jdGlvbiBkZWZpbmVQcm9wZXJ0eShPLCBQLCBBdHRyaWJ1dGVzKSB7XG4gIGFuT2JqZWN0KE8pO1xuICBQID0gdG9QcmltaXRpdmUoUCwgdHJ1ZSk7XG4gIGFuT2JqZWN0KEF0dHJpYnV0ZXMpO1xuICBpZiAoSUU4X0RPTV9ERUZJTkUpIHRyeSB7XG4gICAgcmV0dXJuIG5hdGl2ZURlZmluZVByb3BlcnR5KE8sIFAsIEF0dHJpYnV0ZXMpO1xuICB9IGNhdGNoIChlcnJvcikgeyAvKiBlbXB0eSAqLyB9XG4gIGlmICgnZ2V0JyBpbiBBdHRyaWJ1dGVzIHx8ICdzZXQnIGluIEF0dHJpYnV0ZXMpIHRocm93IFR5cGVFcnJvcignQWNjZXNzb3JzIG5vdCBzdXBwb3J0ZWQnKTtcbiAgaWYgKCd2YWx1ZScgaW4gQXR0cmlidXRlcykgT1tQXSA9IEF0dHJpYnV0ZXMudmFsdWU7XG4gIHJldHVybiBPO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcbnZhciBUT19TVFJJTkdfVEFHX1NVUFBPUlQgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvdG8tc3RyaW5nLXRhZy1zdXBwb3J0Jyk7XG52YXIgY2xhc3NvZiA9IHJlcXVpcmUoJy4uL2ludGVybmFscy9jbGFzc29mJyk7XG5cbi8vIGBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nYCBtZXRob2QgaW1wbGVtZW50YXRpb25cbi8vIGh0dHBzOi8vdGMzOS5naXRodWIuaW8vZWNtYTI2Mi8jc2VjLW9iamVjdC5wcm90b3R5cGUudG9zdHJpbmdcbm1vZHVsZS5leHBvcnRzID0gVE9fU1RSSU5HX1RBR19TVVBQT1JUID8ge30udG9TdHJpbmcgOiBmdW5jdGlvbiB0b1N0cmluZygpIHtcbiAgcmV0dXJuICdbb2JqZWN0ICcgKyBjbGFzc29mKHRoaXMpICsgJ10nO1xufTtcbiIsInZhciBnbG9iYWwgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvZ2xvYmFsJyk7XG52YXIgY3JlYXRlTm9uRW51bWVyYWJsZVByb3BlcnR5ID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL2NyZWF0ZS1ub24tZW51bWVyYWJsZS1wcm9wZXJ0eScpO1xudmFyIGhhcyA9IHJlcXVpcmUoJy4uL2ludGVybmFscy9oYXMnKTtcbnZhciBzZXRHbG9iYWwgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvc2V0LWdsb2JhbCcpO1xudmFyIGluc3BlY3RTb3VyY2UgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvaW5zcGVjdC1zb3VyY2UnKTtcbnZhciBJbnRlcm5hbFN0YXRlTW9kdWxlID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL2ludGVybmFsLXN0YXRlJyk7XG5cbnZhciBnZXRJbnRlcm5hbFN0YXRlID0gSW50ZXJuYWxTdGF0ZU1vZHVsZS5nZXQ7XG52YXIgZW5mb3JjZUludGVybmFsU3RhdGUgPSBJbnRlcm5hbFN0YXRlTW9kdWxlLmVuZm9yY2U7XG52YXIgVEVNUExBVEUgPSBTdHJpbmcoU3RyaW5nKS5zcGxpdCgnU3RyaW5nJyk7XG5cbihtb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChPLCBrZXksIHZhbHVlLCBvcHRpb25zKSB7XG4gIHZhciB1bnNhZmUgPSBvcHRpb25zID8gISFvcHRpb25zLnVuc2FmZSA6IGZhbHNlO1xuICB2YXIgc2ltcGxlID0gb3B0aW9ucyA/ICEhb3B0aW9ucy5lbnVtZXJhYmxlIDogZmFsc2U7XG4gIHZhciBub1RhcmdldEdldCA9IG9wdGlvbnMgPyAhIW9wdGlvbnMubm9UYXJnZXRHZXQgOiBmYWxzZTtcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PSAnZnVuY3Rpb24nKSB7XG4gICAgaWYgKHR5cGVvZiBrZXkgPT0gJ3N0cmluZycgJiYgIWhhcyh2YWx1ZSwgJ25hbWUnKSkgY3JlYXRlTm9uRW51bWVyYWJsZVByb3BlcnR5KHZhbHVlLCAnbmFtZScsIGtleSk7XG4gICAgZW5mb3JjZUludGVybmFsU3RhdGUodmFsdWUpLnNvdXJjZSA9IFRFTVBMQVRFLmpvaW4odHlwZW9mIGtleSA9PSAnc3RyaW5nJyA/IGtleSA6ICcnKTtcbiAgfVxuICBpZiAoTyA9PT0gZ2xvYmFsKSB7XG4gICAgaWYgKHNpbXBsZSkgT1trZXldID0gdmFsdWU7XG4gICAgZWxzZSBzZXRHbG9iYWwoa2V5LCB2YWx1ZSk7XG4gICAgcmV0dXJuO1xuICB9IGVsc2UgaWYgKCF1bnNhZmUpIHtcbiAgICBkZWxldGUgT1trZXldO1xuICB9IGVsc2UgaWYgKCFub1RhcmdldEdldCAmJiBPW2tleV0pIHtcbiAgICBzaW1wbGUgPSB0cnVlO1xuICB9XG4gIGlmIChzaW1wbGUpIE9ba2V5XSA9IHZhbHVlO1xuICBlbHNlIGNyZWF0ZU5vbkVudW1lcmFibGVQcm9wZXJ0eShPLCBrZXksIHZhbHVlKTtcbi8vIGFkZCBmYWtlIEZ1bmN0aW9uI3RvU3RyaW5nIGZvciBjb3JyZWN0IHdvcmsgd3JhcHBlZCBtZXRob2RzIC8gY29uc3RydWN0b3JzIHdpdGggbWV0aG9kcyBsaWtlIExvRGFzaCBpc05hdGl2ZVxufSkoRnVuY3Rpb24ucHJvdG90eXBlLCAndG9TdHJpbmcnLCBmdW5jdGlvbiB0b1N0cmluZygpIHtcbiAgcmV0dXJuIHR5cGVvZiB0aGlzID09ICdmdW5jdGlvbicgJiYgZ2V0SW50ZXJuYWxTdGF0ZSh0aGlzKS5zb3VyY2UgfHwgaW5zcGVjdFNvdXJjZSh0aGlzKTtcbn0pO1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIGFuT2JqZWN0ID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL2FuLW9iamVjdCcpO1xuXG4vLyBgUmVnRXhwLnByb3RvdHlwZS5mbGFnc2AgZ2V0dGVyIGltcGxlbWVudGF0aW9uXG4vLyBodHRwczovL3RjMzkuZ2l0aHViLmlvL2VjbWEyNjIvI3NlYy1nZXQtcmVnZXhwLnByb3RvdHlwZS5mbGFnc1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoKSB7XG4gIHZhciB0aGF0ID0gYW5PYmplY3QodGhpcyk7XG4gIHZhciByZXN1bHQgPSAnJztcbiAgaWYgKHRoYXQuZ2xvYmFsKSByZXN1bHQgKz0gJ2cnO1xuICBpZiAodGhhdC5pZ25vcmVDYXNlKSByZXN1bHQgKz0gJ2knO1xuICBpZiAodGhhdC5tdWx0aWxpbmUpIHJlc3VsdCArPSAnbSc7XG4gIGlmICh0aGF0LmRvdEFsbCkgcmVzdWx0ICs9ICdzJztcbiAgaWYgKHRoYXQudW5pY29kZSkgcmVzdWx0ICs9ICd1JztcbiAgaWYgKHRoYXQuc3RpY2t5KSByZXN1bHQgKz0gJ3knO1xuICByZXR1cm4gcmVzdWx0O1xufTtcbiIsInZhciBnbG9iYWwgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvZ2xvYmFsJyk7XG52YXIgY3JlYXRlTm9uRW51bWVyYWJsZVByb3BlcnR5ID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL2NyZWF0ZS1ub24tZW51bWVyYWJsZS1wcm9wZXJ0eScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gIHRyeSB7XG4gICAgY3JlYXRlTm9uRW51bWVyYWJsZVByb3BlcnR5KGdsb2JhbCwga2V5LCB2YWx1ZSk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgZ2xvYmFsW2tleV0gPSB2YWx1ZTtcbiAgfSByZXR1cm4gdmFsdWU7XG59O1xuIiwidmFyIHNoYXJlZCA9IHJlcXVpcmUoJy4uL2ludGVybmFscy9zaGFyZWQnKTtcbnZhciB1aWQgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvdWlkJyk7XG5cbnZhciBrZXlzID0gc2hhcmVkKCdrZXlzJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGtleSkge1xuICByZXR1cm4ga2V5c1trZXldIHx8IChrZXlzW2tleV0gPSB1aWQoa2V5KSk7XG59O1xuIiwidmFyIGdsb2JhbCA9IHJlcXVpcmUoJy4uL2ludGVybmFscy9nbG9iYWwnKTtcbnZhciBzZXRHbG9iYWwgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvc2V0LWdsb2JhbCcpO1xuXG52YXIgU0hBUkVEID0gJ19fY29yZS1qc19zaGFyZWRfXyc7XG52YXIgc3RvcmUgPSBnbG9iYWxbU0hBUkVEXSB8fCBzZXRHbG9iYWwoU0hBUkVELCB7fSk7XG5cbm1vZHVsZS5leHBvcnRzID0gc3RvcmU7XG4iLCJ2YXIgSVNfUFVSRSA9IHJlcXVpcmUoJy4uL2ludGVybmFscy9pcy1wdXJlJyk7XG52YXIgc3RvcmUgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvc2hhcmVkLXN0b3JlJyk7XG5cbihtb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gIHJldHVybiBzdG9yZVtrZXldIHx8IChzdG9yZVtrZXldID0gdmFsdWUgIT09IHVuZGVmaW5lZCA/IHZhbHVlIDoge30pO1xufSkoJ3ZlcnNpb25zJywgW10pLnB1c2goe1xuICB2ZXJzaW9uOiAnMy42LjQnLFxuICBtb2RlOiBJU19QVVJFID8gJ3B1cmUnIDogJ2dsb2JhbCcsXG4gIGNvcHlyaWdodDogJ8KpIDIwMjAgRGVuaXMgUHVzaGthcmV2ICh6bG9pcm9jay5ydSknXG59KTtcbiIsInZhciBpc09iamVjdCA9IHJlcXVpcmUoJy4uL2ludGVybmFscy9pcy1vYmplY3QnKTtcblxuLy8gYFRvUHJpbWl0aXZlYCBhYnN0cmFjdCBvcGVyYXRpb25cbi8vIGh0dHBzOi8vdGMzOS5naXRodWIuaW8vZWNtYTI2Mi8jc2VjLXRvcHJpbWl0aXZlXG4vLyBpbnN0ZWFkIG9mIHRoZSBFUzYgc3BlYyB2ZXJzaW9uLCB3ZSBkaWRuJ3QgaW1wbGVtZW50IEBAdG9QcmltaXRpdmUgY2FzZVxuLy8gYW5kIHRoZSBzZWNvbmQgYXJndW1lbnQgLSBmbGFnIC0gcHJlZmVycmVkIHR5cGUgaXMgYSBzdHJpbmdcbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGlucHV0LCBQUkVGRVJSRURfU1RSSU5HKSB7XG4gIGlmICghaXNPYmplY3QoaW5wdXQpKSByZXR1cm4gaW5wdXQ7XG4gIHZhciBmbiwgdmFsO1xuICBpZiAoUFJFRkVSUkVEX1NUUklORyAmJiB0eXBlb2YgKGZuID0gaW5wdXQudG9TdHJpbmcpID09ICdmdW5jdGlvbicgJiYgIWlzT2JqZWN0KHZhbCA9IGZuLmNhbGwoaW5wdXQpKSkgcmV0dXJuIHZhbDtcbiAgaWYgKHR5cGVvZiAoZm4gPSBpbnB1dC52YWx1ZU9mKSA9PSAnZnVuY3Rpb24nICYmICFpc09iamVjdCh2YWwgPSBmbi5jYWxsKGlucHV0KSkpIHJldHVybiB2YWw7XG4gIGlmICghUFJFRkVSUkVEX1NUUklORyAmJiB0eXBlb2YgKGZuID0gaW5wdXQudG9TdHJpbmcpID09ICdmdW5jdGlvbicgJiYgIWlzT2JqZWN0KHZhbCA9IGZuLmNhbGwoaW5wdXQpKSkgcmV0dXJuIHZhbDtcbiAgdGhyb3cgVHlwZUVycm9yKFwiQ2FuJ3QgY29udmVydCBvYmplY3QgdG8gcHJpbWl0aXZlIHZhbHVlXCIpO1xufTtcbiIsInZhciB3ZWxsS25vd25TeW1ib2wgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvd2VsbC1rbm93bi1zeW1ib2wnKTtcblxudmFyIFRPX1NUUklOR19UQUcgPSB3ZWxsS25vd25TeW1ib2woJ3RvU3RyaW5nVGFnJyk7XG52YXIgdGVzdCA9IHt9O1xuXG50ZXN0W1RPX1NUUklOR19UQUddID0gJ3onO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmluZyh0ZXN0KSA9PT0gJ1tvYmplY3Qgel0nO1xuIiwidmFyIGlkID0gMDtcbnZhciBwb3N0Zml4ID0gTWF0aC5yYW5kb20oKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoa2V5KSB7XG4gIHJldHVybiAnU3ltYm9sKCcgKyBTdHJpbmcoa2V5ID09PSB1bmRlZmluZWQgPyAnJyA6IGtleSkgKyAnKV8nICsgKCsraWQgKyBwb3N0Zml4KS50b1N0cmluZygzNik7XG59O1xuIiwidmFyIE5BVElWRV9TWU1CT0wgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvbmF0aXZlLXN5bWJvbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE5BVElWRV9TWU1CT0xcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICYmICFTeW1ib2wuc2hhbVxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgJiYgdHlwZW9mIFN5bWJvbC5pdGVyYXRvciA9PSAnc3ltYm9sJztcbiIsInZhciBnbG9iYWwgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvZ2xvYmFsJyk7XG52YXIgc2hhcmVkID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL3NoYXJlZCcpO1xudmFyIGhhcyA9IHJlcXVpcmUoJy4uL2ludGVybmFscy9oYXMnKTtcbnZhciB1aWQgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvdWlkJyk7XG52YXIgTkFUSVZFX1NZTUJPTCA9IHJlcXVpcmUoJy4uL2ludGVybmFscy9uYXRpdmUtc3ltYm9sJyk7XG52YXIgVVNFX1NZTUJPTF9BU19VSUQgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvdXNlLXN5bWJvbC1hcy11aWQnKTtcblxudmFyIFdlbGxLbm93blN5bWJvbHNTdG9yZSA9IHNoYXJlZCgnd2tzJyk7XG52YXIgU3ltYm9sID0gZ2xvYmFsLlN5bWJvbDtcbnZhciBjcmVhdGVXZWxsS25vd25TeW1ib2wgPSBVU0VfU1lNQk9MX0FTX1VJRCA/IFN5bWJvbCA6IFN5bWJvbCAmJiBTeW1ib2wud2l0aG91dFNldHRlciB8fCB1aWQ7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgaWYgKCFoYXMoV2VsbEtub3duU3ltYm9sc1N0b3JlLCBuYW1lKSkge1xuICAgIGlmIChOQVRJVkVfU1lNQk9MICYmIGhhcyhTeW1ib2wsIG5hbWUpKSBXZWxsS25vd25TeW1ib2xzU3RvcmVbbmFtZV0gPSBTeW1ib2xbbmFtZV07XG4gICAgZWxzZSBXZWxsS25vd25TeW1ib2xzU3RvcmVbbmFtZV0gPSBjcmVhdGVXZWxsS25vd25TeW1ib2woJ1N5bWJvbC4nICsgbmFtZSk7XG4gIH0gcmV0dXJuIFdlbGxLbm93blN5bWJvbHNTdG9yZVtuYW1lXTtcbn07XG4iLCJ2YXIgcmVkZWZpbmUgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvcmVkZWZpbmUnKTtcblxudmFyIERhdGVQcm90b3R5cGUgPSBEYXRlLnByb3RvdHlwZTtcbnZhciBJTlZBTElEX0RBVEUgPSAnSW52YWxpZCBEYXRlJztcbnZhciBUT19TVFJJTkcgPSAndG9TdHJpbmcnO1xudmFyIG5hdGl2ZURhdGVUb1N0cmluZyA9IERhdGVQcm90b3R5cGVbVE9fU1RSSU5HXTtcbnZhciBnZXRUaW1lID0gRGF0ZVByb3RvdHlwZS5nZXRUaW1lO1xuXG4vLyBgRGF0ZS5wcm90b3R5cGUudG9TdHJpbmdgIG1ldGhvZFxuLy8gaHR0cHM6Ly90YzM5LmdpdGh1Yi5pby9lY21hMjYyLyNzZWMtZGF0ZS5wcm90b3R5cGUudG9zdHJpbmdcbmlmIChuZXcgRGF0ZShOYU4pICsgJycgIT0gSU5WQUxJRF9EQVRFKSB7XG4gIHJlZGVmaW5lKERhdGVQcm90b3R5cGUsIFRPX1NUUklORywgZnVuY3Rpb24gdG9TdHJpbmcoKSB7XG4gICAgdmFyIHZhbHVlID0gZ2V0VGltZS5jYWxsKHRoaXMpO1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1zZWxmLWNvbXBhcmVcbiAgICByZXR1cm4gdmFsdWUgPT09IHZhbHVlID8gbmF0aXZlRGF0ZVRvU3RyaW5nLmNhbGwodGhpcykgOiBJTlZBTElEX0RBVEU7XG4gIH0pO1xufVxuIiwidmFyIFRPX1NUUklOR19UQUdfU1VQUE9SVCA9IHJlcXVpcmUoJy4uL2ludGVybmFscy90by1zdHJpbmctdGFnLXN1cHBvcnQnKTtcbnZhciByZWRlZmluZSA9IHJlcXVpcmUoJy4uL2ludGVybmFscy9yZWRlZmluZScpO1xudmFyIHRvU3RyaW5nID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL29iamVjdC10by1zdHJpbmcnKTtcblxuLy8gYE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmdgIG1ldGhvZFxuLy8gaHR0cHM6Ly90YzM5LmdpdGh1Yi5pby9lY21hMjYyLyNzZWMtb2JqZWN0LnByb3RvdHlwZS50b3N0cmluZ1xuaWYgKCFUT19TVFJJTkdfVEFHX1NVUFBPUlQpIHtcbiAgcmVkZWZpbmUoT2JqZWN0LnByb3RvdHlwZSwgJ3RvU3RyaW5nJywgdG9TdHJpbmcsIHsgdW5zYWZlOiB0cnVlIH0pO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIHJlZGVmaW5lID0gcmVxdWlyZSgnLi4vaW50ZXJuYWxzL3JlZGVmaW5lJyk7XG52YXIgYW5PYmplY3QgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvYW4tb2JqZWN0Jyk7XG52YXIgZmFpbHMgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvZmFpbHMnKTtcbnZhciBmbGFncyA9IHJlcXVpcmUoJy4uL2ludGVybmFscy9yZWdleHAtZmxhZ3MnKTtcblxudmFyIFRPX1NUUklORyA9ICd0b1N0cmluZyc7XG52YXIgUmVnRXhwUHJvdG90eXBlID0gUmVnRXhwLnByb3RvdHlwZTtcbnZhciBuYXRpdmVUb1N0cmluZyA9IFJlZ0V4cFByb3RvdHlwZVtUT19TVFJJTkddO1xuXG52YXIgTk9UX0dFTkVSSUMgPSBmYWlscyhmdW5jdGlvbiAoKSB7IHJldHVybiBuYXRpdmVUb1N0cmluZy5jYWxsKHsgc291cmNlOiAnYScsIGZsYWdzOiAnYicgfSkgIT0gJy9hL2InOyB9KTtcbi8vIEZGNDQtIFJlZ0V4cCN0b1N0cmluZyBoYXMgYSB3cm9uZyBuYW1lXG52YXIgSU5DT1JSRUNUX05BTUUgPSBuYXRpdmVUb1N0cmluZy5uYW1lICE9IFRPX1NUUklORztcblxuLy8gYFJlZ0V4cC5wcm90b3R5cGUudG9TdHJpbmdgIG1ldGhvZFxuLy8gaHR0cHM6Ly90YzM5LmdpdGh1Yi5pby9lY21hMjYyLyNzZWMtcmVnZXhwLnByb3RvdHlwZS50b3N0cmluZ1xuaWYgKE5PVF9HRU5FUklDIHx8IElOQ09SUkVDVF9OQU1FKSB7XG4gIHJlZGVmaW5lKFJlZ0V4cC5wcm90b3R5cGUsIFRPX1NUUklORywgZnVuY3Rpb24gdG9TdHJpbmcoKSB7XG4gICAgdmFyIFIgPSBhbk9iamVjdCh0aGlzKTtcbiAgICB2YXIgcCA9IFN0cmluZyhSLnNvdXJjZSk7XG4gICAgdmFyIHJmID0gUi5mbGFncztcbiAgICB2YXIgZiA9IFN0cmluZyhyZiA9PT0gdW5kZWZpbmVkICYmIFIgaW5zdGFuY2VvZiBSZWdFeHAgJiYgISgnZmxhZ3MnIGluIFJlZ0V4cFByb3RvdHlwZSkgPyBmbGFncy5jYWxsKFIpIDogcmYpO1xuICAgIHJldHVybiAnLycgKyBwICsgJy8nICsgZjtcbiAgfSwgeyB1bnNhZmU6IHRydWUgfSk7XG59XG4iLCJ2YXIgZztcblxuLy8gVGhpcyB3b3JrcyBpbiBub24tc3RyaWN0IG1vZGVcbmcgPSAoZnVuY3Rpb24oKSB7XG5cdHJldHVybiB0aGlzO1xufSkoKTtcblxudHJ5IHtcblx0Ly8gVGhpcyB3b3JrcyBpZiBldmFsIGlzIGFsbG93ZWQgKHNlZSBDU1ApXG5cdGcgPSBnIHx8IG5ldyBGdW5jdGlvbihcInJldHVybiB0aGlzXCIpKCk7XG59IGNhdGNoIChlKSB7XG5cdC8vIFRoaXMgd29ya3MgaWYgdGhlIHdpbmRvdyByZWZlcmVuY2UgaXMgYXZhaWxhYmxlXG5cdGlmICh0eXBlb2Ygd2luZG93ID09PSBcIm9iamVjdFwiKSBnID0gd2luZG93O1xufVxuXG4vLyBnIGNhbiBzdGlsbCBiZSB1bmRlZmluZWQsIGJ1dCBub3RoaW5nIHRvIGRvIGFib3V0IGl0Li4uXG4vLyBXZSByZXR1cm4gdW5kZWZpbmVkLCBpbnN0ZWFkIG9mIG5vdGhpbmcgaGVyZSwgc28gaXQnc1xuLy8gZWFzaWVyIHRvIGhhbmRsZSB0aGlzIGNhc2UuIGlmKCFnbG9iYWwpIHsgLi4ufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGc7XG4iXSwic291cmNlUm9vdCI6IiJ9