95 lines
1.5 MiB
Plaintext
95 lines
1.5 MiB
Plaintext
"use strict";
|
|
/*
|
|
* ATTENTION: An "eval-source-map" devtool has been used.
|
|
* This devtool is neither made for production nor for readable output files.
|
|
* It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
|
|
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
|
|
* or disable the default devtool with "devtool: false".
|
|
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
|
|
*/
|
|
exports.id = "vendor-chunks/@fullcalendar";
|
|
exports.ids = ["vendor-chunks/@fullcalendar"];
|
|
exports.modules = {
|
|
|
|
/***/ "(ssr)/./node_modules/@fullcalendar/core/index.js":
|
|
/*!**************************************************!*\
|
|
!*** ./node_modules/@fullcalendar/core/index.js ***!
|
|
\**************************************************/
|
|
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
|
|
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ Calendar: () => (/* binding */ Calendar),\n/* harmony export */ JsonRequestError: () => (/* reexport safe */ _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.ae),\n/* harmony export */ createPlugin: () => (/* binding */ createPlugin),\n/* harmony export */ formatDate: () => (/* binding */ formatDate),\n/* harmony export */ formatRange: () => (/* binding */ formatRange),\n/* harmony export */ globalLocales: () => (/* binding */ globalLocales),\n/* harmony export */ globalPlugins: () => (/* binding */ globalPlugins),\n/* harmony export */ sliceEvents: () => (/* binding */ sliceEvents),\n/* harmony export */ version: () => (/* binding */ version)\n/* harmony export */ });\n/* harmony import */ var _internal_common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./internal-common.js */ \"(ssr)/./node_modules/@fullcalendar/core/internal-common.js\");\n/* harmony import */ var preact__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! preact */ \"(ssr)/./node_modules/preact/dist/preact.mjs\");\n/* harmony import */ var preact_compat__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! preact/compat */ \"(ssr)/./node_modules/preact/compat/dist/compat.mjs\");\n\n\n\n\n\nconst globalLocales = [];\n\nconst MINIMAL_RAW_EN_LOCALE = {\n code: 'en',\n week: {\n dow: 0,\n doy: 4, // 4 days need to be within the year to be considered the first week\n },\n direction: 'ltr',\n buttonText: {\n prev: 'prev',\n next: 'next',\n prevYear: 'prev year',\n nextYear: 'next year',\n year: 'year',\n today: 'today',\n month: 'month',\n week: 'week',\n day: 'day',\n list: 'list',\n },\n weekText: 'W',\n weekTextLong: 'Week',\n closeHint: 'Close',\n timeHint: 'Time',\n eventHint: 'Event',\n allDayText: 'all-day',\n moreLinkText: 'more',\n noEventsText: 'No events to display',\n};\nconst RAW_EN_LOCALE = Object.assign(Object.assign({}, MINIMAL_RAW_EN_LOCALE), { \n // Includes things we don't want other locales to inherit,\n // things that derive from other translatable strings.\n buttonHints: {\n prev: 'Previous $0',\n next: 'Next $0',\n today(buttonText, unit) {\n return (unit === 'day')\n ? 'Today'\n : `This ${buttonText}`;\n },\n }, viewHint: '$0 view', navLinkHint: 'Go to $0', moreLinkHint(eventCnt) {\n return `Show ${eventCnt} more event${eventCnt === 1 ? '' : 's'}`;\n } });\nfunction organizeRawLocales(explicitRawLocales) {\n let defaultCode = explicitRawLocales.length > 0 ? explicitRawLocales[0].code : 'en';\n let allRawLocales = globalLocales.concat(explicitRawLocales);\n let rawLocaleMap = {\n en: RAW_EN_LOCALE,\n };\n for (let rawLocale of allRawLocales) {\n rawLocaleMap[rawLocale.code] = rawLocale;\n }\n return {\n map: rawLocaleMap,\n defaultCode,\n };\n}\nfunction buildLocale(inputSingular, available) {\n if (typeof inputSingular === 'object' && !Array.isArray(inputSingular)) {\n return parseLocale(inputSingular.code, [inputSingular.code], inputSingular);\n }\n return queryLocale(inputSingular, available);\n}\nfunction queryLocale(codeArg, available) {\n let codes = [].concat(codeArg || []); // will convert to array\n let raw = queryRawLocale(codes, available) || RAW_EN_LOCALE;\n return parseLocale(codeArg, codes, raw);\n}\nfunction queryRawLocale(codes, available) {\n for (let i = 0; i < codes.length; i += 1) {\n let parts = codes[i].toLocaleLowerCase().split('-');\n for (let j = parts.length; j > 0; j -= 1) {\n let simpleId = parts.slice(0, j).join('-');\n if (available[simpleId]) {\n return available[simpleId];\n }\n }\n }\n return null;\n}\nfunction parseLocale(codeArg, codes, raw) {\n let merged = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.m)([MINIMAL_RAW_EN_LOCALE, raw], ['buttonText']);\n delete merged.code; // don't want this part of the options\n let { week } = merged;\n delete merged.week;\n return {\n codeArg,\n codes,\n week,\n simpleNumberFormat: new Intl.NumberFormat(codeArg),\n options: merged,\n };\n}\n\n// TODO: easier way to add new hooks? need to update a million things\nfunction createPlugin(input) {\n return {\n id: (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.g)(),\n name: input.name,\n premiumReleaseDate: input.premiumReleaseDate ? new Date(input.premiumReleaseDate) : undefined,\n deps: input.deps || [],\n reducers: input.reducers || [],\n isLoadingFuncs: input.isLoadingFuncs || [],\n contextInit: [].concat(input.contextInit || []),\n eventRefiners: input.eventRefiners || {},\n eventDefMemberAdders: input.eventDefMemberAdders || [],\n eventSourceRefiners: input.eventSourceRefiners || {},\n isDraggableTransformers: input.isDraggableTransformers || [],\n eventDragMutationMassagers: input.eventDragMutationMassagers || [],\n eventDefMutationAppliers: input.eventDefMutationAppliers || [],\n dateSelectionTransformers: input.dateSelectionTransformers || [],\n datePointTransforms: input.datePointTransforms || [],\n dateSpanTransforms: input.dateSpanTransforms || [],\n views: input.views || {},\n viewPropsTransformers: input.viewPropsTransformers || [],\n isPropsValid: input.isPropsValid || null,\n externalDefTransforms: input.externalDefTransforms || [],\n viewContainerAppends: input.viewContainerAppends || [],\n eventDropTransformers: input.eventDropTransformers || [],\n componentInteractions: input.componentInteractions || [],\n calendarInteractions: input.calendarInteractions || [],\n themeClasses: input.themeClasses || {},\n eventSourceDefs: input.eventSourceDefs || [],\n cmdFormatter: input.cmdFormatter,\n recurringTypes: input.recurringTypes || [],\n namedTimeZonedImpl: input.namedTimeZonedImpl,\n initialView: input.initialView || '',\n elementDraggingImpl: input.elementDraggingImpl,\n optionChangeHandlers: input.optionChangeHandlers || {},\n scrollGridImpl: input.scrollGridImpl || null,\n listenerRefiners: input.listenerRefiners || {},\n optionRefiners: input.optionRefiners || {},\n propSetHandlers: input.propSetHandlers || {},\n };\n}\nfunction buildPluginHooks(pluginDefs, globalDefs) {\n let currentPluginIds = {};\n let hooks = {\n premiumReleaseDate: undefined,\n reducers: [],\n isLoadingFuncs: [],\n contextInit: [],\n eventRefiners: {},\n eventDefMemberAdders: [],\n eventSourceRefiners: {},\n isDraggableTransformers: [],\n eventDragMutationMassagers: [],\n eventDefMutationAppliers: [],\n dateSelectionTransformers: [],\n datePointTransforms: [],\n dateSpanTransforms: [],\n views: {},\n viewPropsTransformers: [],\n isPropsValid: null,\n externalDefTransforms: [],\n viewContainerAppends: [],\n eventDropTransformers: [],\n componentInteractions: [],\n calendarInteractions: [],\n themeClasses: {},\n eventSourceDefs: [],\n cmdFormatter: null,\n recurringTypes: [],\n namedTimeZonedImpl: null,\n initialView: '',\n elementDraggingImpl: null,\n optionChangeHandlers: {},\n scrollGridImpl: null,\n listenerRefiners: {},\n optionRefiners: {},\n propSetHandlers: {},\n };\n function addDefs(defs) {\n for (let def of defs) {\n const pluginName = def.name;\n const currentId = currentPluginIds[pluginName];\n if (currentId === undefined) {\n currentPluginIds[pluginName] = def.id;\n addDefs(def.deps);\n hooks = combineHooks(hooks, def);\n }\n else if (currentId !== def.id) {\n // different ID than the one already added\n console.warn(`Duplicate plugin '${pluginName}'`);\n }\n }\n }\n if (pluginDefs) {\n addDefs(pluginDefs);\n }\n addDefs(globalDefs);\n return hooks;\n}\nfunction buildBuildPluginHooks() {\n let currentOverrideDefs = [];\n let currentGlobalDefs = [];\n let currentHooks;\n return (overrideDefs, globalDefs) => {\n if (!currentHooks || !(0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.i)(overrideDefs, currentOverrideDefs) || !(0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.i)(globalDefs, currentGlobalDefs)) {\n currentHooks = buildPluginHooks(overrideDefs, globalDefs);\n }\n currentOverrideDefs = overrideDefs;\n currentGlobalDefs = globalDefs;\n return currentHooks;\n };\n}\nfunction combineHooks(hooks0, hooks1) {\n return {\n premiumReleaseDate: compareOptionalDates(hooks0.premiumReleaseDate, hooks1.premiumReleaseDate),\n reducers: hooks0.reducers.concat(hooks1.reducers),\n isLoadingFuncs: hooks0.isLoadingFuncs.concat(hooks1.isLoadingFuncs),\n contextInit: hooks0.contextInit.concat(hooks1.contextInit),\n eventRefiners: Object.assign(Object.assign({}, hooks0.eventRefiners), hooks1.eventRefiners),\n eventDefMemberAdders: hooks0.eventDefMemberAdders.concat(hooks1.eventDefMemberAdders),\n eventSourceRefiners: Object.assign(Object.assign({}, hooks0.eventSourceRefiners), hooks1.eventSourceRefiners),\n isDraggableTransformers: hooks0.isDraggableTransformers.concat(hooks1.isDraggableTransformers),\n eventDragMutationMassagers: hooks0.eventDragMutationMassagers.concat(hooks1.eventDragMutationMassagers),\n eventDefMutationAppliers: hooks0.eventDefMutationAppliers.concat(hooks1.eventDefMutationAppliers),\n dateSelectionTransformers: hooks0.dateSelectionTransformers.concat(hooks1.dateSelectionTransformers),\n datePointTransforms: hooks0.datePointTransforms.concat(hooks1.datePointTransforms),\n dateSpanTransforms: hooks0.dateSpanTransforms.concat(hooks1.dateSpanTransforms),\n views: Object.assign(Object.assign({}, hooks0.views), hooks1.views),\n viewPropsTransformers: hooks0.viewPropsTransformers.concat(hooks1.viewPropsTransformers),\n isPropsValid: hooks1.isPropsValid || hooks0.isPropsValid,\n externalDefTransforms: hooks0.externalDefTransforms.concat(hooks1.externalDefTransforms),\n viewContainerAppends: hooks0.viewContainerAppends.concat(hooks1.viewContainerAppends),\n eventDropTransformers: hooks0.eventDropTransformers.concat(hooks1.eventDropTransformers),\n calendarInteractions: hooks0.calendarInteractions.concat(hooks1.calendarInteractions),\n componentInteractions: hooks0.componentInteractions.concat(hooks1.componentInteractions),\n themeClasses: Object.assign(Object.assign({}, hooks0.themeClasses), hooks1.themeClasses),\n eventSourceDefs: hooks0.eventSourceDefs.concat(hooks1.eventSourceDefs),\n cmdFormatter: hooks1.cmdFormatter || hooks0.cmdFormatter,\n recurringTypes: hooks0.recurringTypes.concat(hooks1.recurringTypes),\n namedTimeZonedImpl: hooks1.namedTimeZonedImpl || hooks0.namedTimeZonedImpl,\n initialView: hooks0.initialView || hooks1.initialView,\n elementDraggingImpl: hooks0.elementDraggingImpl || hooks1.elementDraggingImpl,\n optionChangeHandlers: Object.assign(Object.assign({}, hooks0.optionChangeHandlers), hooks1.optionChangeHandlers),\n scrollGridImpl: hooks1.scrollGridImpl || hooks0.scrollGridImpl,\n listenerRefiners: Object.assign(Object.assign({}, hooks0.listenerRefiners), hooks1.listenerRefiners),\n optionRefiners: Object.assign(Object.assign({}, hooks0.optionRefiners), hooks1.optionRefiners),\n propSetHandlers: Object.assign(Object.assign({}, hooks0.propSetHandlers), hooks1.propSetHandlers),\n };\n}\nfunction compareOptionalDates(date0, date1) {\n if (date0 === undefined) {\n return date1;\n }\n if (date1 === undefined) {\n return date0;\n }\n return new Date(Math.max(date0.valueOf(), date1.valueOf()));\n}\n\nclass StandardTheme extends _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.T {\n}\nStandardTheme.prototype.classes = {\n root: 'fc-theme-standard',\n tableCellShaded: 'fc-cell-shaded',\n buttonGroup: 'fc-button-group',\n button: 'fc-button fc-button-primary',\n buttonActive: 'fc-button-active',\n};\nStandardTheme.prototype.baseIconClass = 'fc-icon';\nStandardTheme.prototype.iconClasses = {\n close: 'fc-icon-x',\n prev: 'fc-icon-chevron-left',\n next: 'fc-icon-chevron-right',\n prevYear: 'fc-icon-chevrons-left',\n nextYear: 'fc-icon-chevrons-right',\n};\nStandardTheme.prototype.rtlIconClasses = {\n prev: 'fc-icon-chevron-right',\n next: 'fc-icon-chevron-left',\n prevYear: 'fc-icon-chevrons-right',\n nextYear: 'fc-icon-chevrons-left',\n};\nStandardTheme.prototype.iconOverrideOption = 'buttonIcons'; // TODO: make TS-friendly\nStandardTheme.prototype.iconOverrideCustomButtonOption = 'icon';\nStandardTheme.prototype.iconOverridePrefix = 'fc-icon-';\n\nfunction compileViewDefs(defaultConfigs, overrideConfigs) {\n let hash = {};\n let viewType;\n for (viewType in defaultConfigs) {\n ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs);\n }\n for (viewType in overrideConfigs) {\n ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs);\n }\n return hash;\n}\nfunction ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs) {\n if (hash[viewType]) {\n return hash[viewType];\n }\n let viewDef = buildViewDef(viewType, hash, defaultConfigs, overrideConfigs);\n if (viewDef) {\n hash[viewType] = viewDef;\n }\n return viewDef;\n}\nfunction buildViewDef(viewType, hash, defaultConfigs, overrideConfigs) {\n let defaultConfig = defaultConfigs[viewType];\n let overrideConfig = overrideConfigs[viewType];\n let queryProp = (name) => ((defaultConfig && defaultConfig[name] !== null) ? defaultConfig[name] :\n ((overrideConfig && overrideConfig[name] !== null) ? overrideConfig[name] : null));\n let theComponent = queryProp('component');\n let superType = queryProp('superType');\n let superDef = null;\n if (superType) {\n if (superType === viewType) {\n throw new Error('Can\\'t have a custom view type that references itself');\n }\n superDef = ensureViewDef(superType, hash, defaultConfigs, overrideConfigs);\n }\n if (!theComponent && superDef) {\n theComponent = superDef.component;\n }\n if (!theComponent) {\n return null; // don't throw a warning, might be settings for a single-unit view\n }\n return {\n type: viewType,\n component: theComponent,\n defaults: Object.assign(Object.assign({}, (superDef ? superDef.defaults : {})), (defaultConfig ? defaultConfig.rawOptions : {})),\n overrides: Object.assign(Object.assign({}, (superDef ? superDef.overrides : {})), (overrideConfig ? overrideConfig.rawOptions : {})),\n };\n}\n\nfunction parseViewConfigs(inputs) {\n return (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.a)(inputs, parseViewConfig);\n}\nfunction parseViewConfig(input) {\n let rawOptions = typeof input === 'function' ?\n { component: input } :\n input;\n let { component } = rawOptions;\n if (rawOptions.content) {\n // TODO: remove content/classNames/didMount/etc from options?\n component = createViewHookComponent(rawOptions);\n }\n else if (component && !(component.prototype instanceof _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.B)) {\n // WHY?: people were using `component` property for `content`\n // TODO: converge on one setting name\n component = createViewHookComponent(Object.assign(Object.assign({}, rawOptions), { content: component }));\n }\n return {\n superType: rawOptions.type,\n component: component,\n rawOptions, // includes type and component too :(\n };\n}\nfunction createViewHookComponent(options) {\n return (viewProps) => ((0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.V.Consumer, null, (context) => ((0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.C, { elTag: \"div\", elClasses: (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.b)(context.viewSpec), renderProps: Object.assign(Object.assign({}, viewProps), { nextDayThreshold: context.options.nextDayThreshold }), generatorName: undefined, customGenerator: options.content, classNameGenerator: options.classNames, didMount: options.didMount, willUnmount: options.willUnmount }))));\n}\n\nfunction buildViewSpecs(defaultInputs, optionOverrides, dynamicOptionOverrides, localeDefaults) {\n let defaultConfigs = parseViewConfigs(defaultInputs);\n let overrideConfigs = parseViewConfigs(optionOverrides.views);\n let viewDefs = compileViewDefs(defaultConfigs, overrideConfigs);\n return (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.a)(viewDefs, (viewDef) => buildViewSpec(viewDef, overrideConfigs, optionOverrides, dynamicOptionOverrides, localeDefaults));\n}\nfunction buildViewSpec(viewDef, overrideConfigs, optionOverrides, dynamicOptionOverrides, localeDefaults) {\n let durationInput = viewDef.overrides.duration ||\n viewDef.defaults.duration ||\n dynamicOptionOverrides.duration ||\n optionOverrides.duration;\n let duration = null;\n let durationUnit = '';\n let singleUnit = '';\n let singleUnitOverrides = {};\n if (durationInput) {\n duration = createDurationCached(durationInput);\n if (duration) { // valid?\n let denom = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.c)(duration);\n durationUnit = denom.unit;\n if (denom.value === 1) {\n singleUnit = durationUnit;\n singleUnitOverrides = overrideConfigs[durationUnit] ? overrideConfigs[durationUnit].rawOptions : {};\n }\n }\n }\n let queryButtonText = (optionsSubset) => {\n let buttonTextMap = optionsSubset.buttonText || {};\n let buttonTextKey = viewDef.defaults.buttonTextKey;\n if (buttonTextKey != null && buttonTextMap[buttonTextKey] != null) {\n return buttonTextMap[buttonTextKey];\n }\n if (buttonTextMap[viewDef.type] != null) {\n return buttonTextMap[viewDef.type];\n }\n if (buttonTextMap[singleUnit] != null) {\n return buttonTextMap[singleUnit];\n }\n return null;\n };\n let queryButtonTitle = (optionsSubset) => {\n let buttonHints = optionsSubset.buttonHints || {};\n let buttonKey = viewDef.defaults.buttonTextKey; // use same key as text\n if (buttonKey != null && buttonHints[buttonKey] != null) {\n return buttonHints[buttonKey];\n }\n if (buttonHints[viewDef.type] != null) {\n return buttonHints[viewDef.type];\n }\n if (buttonHints[singleUnit] != null) {\n return buttonHints[singleUnit];\n }\n return null;\n };\n return {\n type: viewDef.type,\n component: viewDef.component,\n duration,\n durationUnit,\n singleUnit,\n optionDefaults: viewDef.defaults,\n optionOverrides: Object.assign(Object.assign({}, singleUnitOverrides), viewDef.overrides),\n buttonTextOverride: queryButtonText(dynamicOptionOverrides) ||\n queryButtonText(optionOverrides) || // constructor-specified buttonText lookup hash takes precedence\n viewDef.overrides.buttonText,\n buttonTextDefault: queryButtonText(localeDefaults) ||\n viewDef.defaults.buttonText ||\n queryButtonText(_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.e) ||\n viewDef.type,\n // not DRY\n buttonTitleOverride: queryButtonTitle(dynamicOptionOverrides) ||\n queryButtonTitle(optionOverrides) ||\n viewDef.overrides.buttonHint,\n buttonTitleDefault: queryButtonTitle(localeDefaults) ||\n viewDef.defaults.buttonHint ||\n queryButtonTitle(_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.e),\n // will eventually fall back to buttonText\n };\n}\n// hack to get memoization working\nlet durationInputMap = {};\nfunction createDurationCached(durationInput) {\n let json = JSON.stringify(durationInput);\n let res = durationInputMap[json];\n if (res === undefined) {\n res = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.d)(durationInput);\n durationInputMap[json] = res;\n }\n return res;\n}\n\nfunction reduceViewType(viewType, action) {\n switch (action.type) {\n case 'CHANGE_VIEW_TYPE':\n viewType = action.viewType;\n }\n return viewType;\n}\n\nfunction reduceCurrentDate(currentDate, action) {\n switch (action.type) {\n case 'CHANGE_DATE':\n return action.dateMarker;\n default:\n return currentDate;\n }\n}\n// should be initialized once and stay constant\n// this will change too\nfunction getInitialDate(options, dateEnv, nowManager) {\n let initialDateInput = options.initialDate;\n // compute the initial ambig-timezone date\n if (initialDateInput != null) {\n return dateEnv.createMarker(initialDateInput);\n }\n return nowManager.getDateMarker();\n}\n\nfunction reduceDynamicOptionOverrides(dynamicOptionOverrides, action) {\n switch (action.type) {\n case 'SET_OPTION':\n return Object.assign(Object.assign({}, dynamicOptionOverrides), { [action.optionName]: action.rawOptionValue });\n default:\n return dynamicOptionOverrides;\n }\n}\n\nfunction reduceDateProfile(currentDateProfile, action, currentDate, dateProfileGenerator) {\n let dp;\n switch (action.type) {\n case 'CHANGE_VIEW_TYPE':\n return dateProfileGenerator.build(action.dateMarker || currentDate);\n case 'CHANGE_DATE':\n return dateProfileGenerator.build(action.dateMarker);\n case 'PREV':\n dp = dateProfileGenerator.buildPrev(currentDateProfile, currentDate);\n if (dp.isValid) {\n return dp;\n }\n break;\n case 'NEXT':\n dp = dateProfileGenerator.buildNext(currentDateProfile, currentDate);\n if (dp.isValid) {\n return dp;\n }\n break;\n }\n return currentDateProfile;\n}\n\nfunction initEventSources(calendarOptions, dateProfile, context) {\n let activeRange = dateProfile ? dateProfile.activeRange : null;\n return addSources({}, parseInitialSources(calendarOptions, context), activeRange, context);\n}\nfunction reduceEventSources(eventSources, action, dateProfile, context) {\n let activeRange = dateProfile ? dateProfile.activeRange : null; // need this check?\n switch (action.type) {\n case 'ADD_EVENT_SOURCES': // already parsed\n return addSources(eventSources, action.sources, activeRange, context);\n case 'REMOVE_EVENT_SOURCE':\n return removeSource(eventSources, action.sourceId);\n case 'PREV': // TODO: how do we track all actions that affect dateProfile :(\n case 'NEXT':\n case 'CHANGE_DATE':\n case 'CHANGE_VIEW_TYPE':\n if (dateProfile) {\n return fetchDirtySources(eventSources, activeRange, context);\n }\n return eventSources;\n case 'FETCH_EVENT_SOURCES':\n return fetchSourcesByIds(eventSources, action.sourceIds ? // why no type?\n (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.f)(action.sourceIds) :\n excludeStaticSources(eventSources, context), activeRange, action.isRefetch || false, context);\n case 'RECEIVE_EVENTS':\n case 'RECEIVE_EVENT_ERROR':\n return receiveResponse(eventSources, action.sourceId, action.fetchId, action.fetchRange);\n case 'REMOVE_ALL_EVENT_SOURCES':\n return {};\n default:\n return eventSources;\n }\n}\nfunction reduceEventSourcesNewTimeZone(eventSources, dateProfile, context) {\n let activeRange = dateProfile ? dateProfile.activeRange : null; // need this check?\n return fetchSourcesByIds(eventSources, excludeStaticSources(eventSources, context), activeRange, true, context);\n}\nfunction computeEventSourcesLoading(eventSources) {\n for (let sourceId in eventSources) {\n if (eventSources[sourceId].isFetching) {\n return true;\n }\n }\n return false;\n}\nfunction addSources(eventSourceHash, sources, fetchRange, context) {\n let hash = {};\n for (let source of sources) {\n hash[source.sourceId] = source;\n }\n if (fetchRange) {\n hash = fetchDirtySources(hash, fetchRange, context);\n }\n return Object.assign(Object.assign({}, eventSourceHash), hash);\n}\nfunction removeSource(eventSourceHash, sourceId) {\n return (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.h)(eventSourceHash, (eventSource) => eventSource.sourceId !== sourceId);\n}\nfunction fetchDirtySources(sourceHash, fetchRange, context) {\n return fetchSourcesByIds(sourceHash, (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.h)(sourceHash, (eventSource) => isSourceDirty(eventSource, fetchRange, context)), fetchRange, false, context);\n}\nfunction isSourceDirty(eventSource, fetchRange, context) {\n if (!doesSourceNeedRange(eventSource, context)) {\n return !eventSource.latestFetchId;\n }\n return !context.options.lazyFetching ||\n !eventSource.fetchRange ||\n eventSource.isFetching || // always cancel outdated in-progress fetches\n fetchRange.start < eventSource.fetchRange.start ||\n fetchRange.end > eventSource.fetchRange.end;\n}\nfunction fetchSourcesByIds(prevSources, sourceIdHash, fetchRange, isRefetch, context) {\n let nextSources = {};\n for (let sourceId in prevSources) {\n let source = prevSources[sourceId];\n if (sourceIdHash[sourceId]) {\n nextSources[sourceId] = fetchSource(source, fetchRange, isRefetch, context);\n }\n else {\n nextSources[sourceId] = source;\n }\n }\n return nextSources;\n}\nfunction fetchSource(eventSource, fetchRange, isRefetch, context) {\n let { options, calendarApi } = context;\n let sourceDef = context.pluginHooks.eventSourceDefs[eventSource.sourceDefId];\n let fetchId = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.g)();\n sourceDef.fetch({\n eventSource,\n range: fetchRange,\n isRefetch,\n context,\n }, (res) => {\n let { rawEvents } = res;\n if (options.eventSourceSuccess) {\n rawEvents = options.eventSourceSuccess.call(calendarApi, rawEvents, res.response) || rawEvents;\n }\n if (eventSource.success) {\n rawEvents = eventSource.success.call(calendarApi, rawEvents, res.response) || rawEvents;\n }\n context.dispatch({\n type: 'RECEIVE_EVENTS',\n sourceId: eventSource.sourceId,\n fetchId,\n fetchRange,\n rawEvents,\n });\n }, (error) => {\n let errorHandled = false;\n if (options.eventSourceFailure) {\n options.eventSourceFailure.call(calendarApi, error);\n errorHandled = true;\n }\n if (eventSource.failure) {\n eventSource.failure(error);\n errorHandled = true;\n }\n if (!errorHandled) {\n console.warn(error.message, error);\n }\n context.dispatch({\n type: 'RECEIVE_EVENT_ERROR',\n sourceId: eventSource.sourceId,\n fetchId,\n fetchRange,\n error,\n });\n });\n return Object.assign(Object.assign({}, eventSource), { isFetching: true, latestFetchId: fetchId });\n}\nfunction receiveResponse(sourceHash, sourceId, fetchId, fetchRange) {\n let eventSource = sourceHash[sourceId];\n if (eventSource && // not already removed\n fetchId === eventSource.latestFetchId) {\n return Object.assign(Object.assign({}, sourceHash), { [sourceId]: Object.assign(Object.assign({}, eventSource), { isFetching: false, fetchRange }) });\n }\n return sourceHash;\n}\nfunction excludeStaticSources(eventSources, context) {\n return (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.h)(eventSources, (eventSource) => doesSourceNeedRange(eventSource, context));\n}\nfunction parseInitialSources(rawOptions, context) {\n let refiners = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.j)(context);\n let rawSources = [].concat(rawOptions.eventSources || []);\n let sources = []; // parsed\n if (rawOptions.initialEvents) {\n rawSources.unshift(rawOptions.initialEvents);\n }\n if (rawOptions.events) {\n rawSources.unshift(rawOptions.events);\n }\n for (let rawSource of rawSources) {\n let source = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.p)(rawSource, context, refiners);\n if (source) {\n sources.push(source);\n }\n }\n return sources;\n}\nfunction doesSourceNeedRange(eventSource, context) {\n let defs = context.pluginHooks.eventSourceDefs;\n return !defs[eventSource.sourceDefId].ignoreRange;\n}\n\nfunction reduceDateSelection(currentSelection, action) {\n switch (action.type) {\n case 'UNSELECT_DATES':\n return null;\n case 'SELECT_DATES':\n return action.selection;\n default:\n return currentSelection;\n }\n}\n\nfunction reduceSelectedEvent(currentInstanceId, action) {\n switch (action.type) {\n case 'UNSELECT_EVENT':\n return '';\n case 'SELECT_EVENT':\n return action.eventInstanceId;\n default:\n return currentInstanceId;\n }\n}\n\nfunction reduceEventDrag(currentDrag, action) {\n let newDrag;\n switch (action.type) {\n case 'UNSET_EVENT_DRAG':\n return null;\n case 'SET_EVENT_DRAG':\n newDrag = action.state;\n return {\n affectedEvents: newDrag.affectedEvents,\n mutatedEvents: newDrag.mutatedEvents,\n isEvent: newDrag.isEvent,\n };\n default:\n return currentDrag;\n }\n}\n\nfunction reduceEventResize(currentResize, action) {\n let newResize;\n switch (action.type) {\n case 'UNSET_EVENT_RESIZE':\n return null;\n case 'SET_EVENT_RESIZE':\n newResize = action.state;\n return {\n affectedEvents: newResize.affectedEvents,\n mutatedEvents: newResize.mutatedEvents,\n isEvent: newResize.isEvent,\n };\n default:\n return currentResize;\n }\n}\n\nfunction parseToolbars(calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) {\n let header = calendarOptions.headerToolbar ? parseToolbar(calendarOptions.headerToolbar, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) : null;\n let footer = calendarOptions.footerToolbar ? parseToolbar(calendarOptions.footerToolbar, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) : null;\n return { header, footer };\n}\nfunction parseToolbar(sectionStrHash, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) {\n let sectionWidgets = {};\n let viewsWithButtons = [];\n let hasTitle = false;\n for (let sectionName in sectionStrHash) {\n let sectionStr = sectionStrHash[sectionName];\n let sectionRes = parseSection(sectionStr, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi);\n sectionWidgets[sectionName] = sectionRes.widgets;\n viewsWithButtons.push(...sectionRes.viewsWithButtons);\n hasTitle = hasTitle || sectionRes.hasTitle;\n }\n return { sectionWidgets, viewsWithButtons, hasTitle };\n}\n/*\nBAD: querying icons and text here. should be done at render time\n*/\nfunction parseSection(sectionStr, calendarOptions, // defaults+overrides, then refined\ncalendarOptionOverrides, // overrides only!, unrefined :(\ntheme, viewSpecs, calendarApi) {\n let isRtl = calendarOptions.direction === 'rtl';\n let calendarCustomButtons = calendarOptions.customButtons || {};\n let calendarButtonTextOverrides = calendarOptionOverrides.buttonText || {};\n let calendarButtonText = calendarOptions.buttonText || {};\n let calendarButtonHintOverrides = calendarOptionOverrides.buttonHints || {};\n let calendarButtonHints = calendarOptions.buttonHints || {};\n let sectionSubstrs = sectionStr ? sectionStr.split(' ') : [];\n let viewsWithButtons = [];\n let hasTitle = false;\n let widgets = sectionSubstrs.map((buttonGroupStr) => (buttonGroupStr.split(',').map((buttonName) => {\n if (buttonName === 'title') {\n hasTitle = true;\n return { buttonName };\n }\n let customButtonProps;\n let viewSpec;\n let buttonClick;\n let buttonIcon; // only one of these will be set\n let buttonText; // \"\n let buttonHint;\n // ^ for the title=\"\" attribute, for accessibility\n if ((customButtonProps = calendarCustomButtons[buttonName])) {\n buttonClick = (ev) => {\n if (customButtonProps.click) {\n customButtonProps.click.call(ev.target, ev, ev.target); // TODO: use Calendar this context?\n }\n };\n (buttonIcon = theme.getCustomButtonIconClass(customButtonProps)) ||\n (buttonIcon = theme.getIconClass(buttonName, isRtl)) ||\n (buttonText = customButtonProps.text);\n buttonHint = customButtonProps.hint || customButtonProps.text;\n }\n else if ((viewSpec = viewSpecs[buttonName])) {\n viewsWithButtons.push(buttonName);\n buttonClick = () => {\n calendarApi.changeView(buttonName);\n };\n (buttonText = viewSpec.buttonTextOverride) ||\n (buttonIcon = theme.getIconClass(buttonName, isRtl)) ||\n (buttonText = viewSpec.buttonTextDefault);\n let textFallback = viewSpec.buttonTextOverride ||\n viewSpec.buttonTextDefault;\n buttonHint = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.k)(viewSpec.buttonTitleOverride ||\n viewSpec.buttonTitleDefault ||\n calendarOptions.viewHint, [textFallback, buttonName], // view-name = buttonName\n textFallback);\n }\n else if (calendarApi[buttonName]) { // a calendarApi method\n buttonClick = () => {\n calendarApi[buttonName]();\n };\n (buttonText = calendarButtonTextOverrides[buttonName]) ||\n (buttonIcon = theme.getIconClass(buttonName, isRtl)) ||\n (buttonText = calendarButtonText[buttonName]); // everything else is considered default\n if (buttonName === 'prevYear' || buttonName === 'nextYear') {\n let prevOrNext = buttonName === 'prevYear' ? 'prev' : 'next';\n buttonHint = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.k)(calendarButtonHintOverrides[prevOrNext] ||\n calendarButtonHints[prevOrNext], [\n calendarButtonText.year || 'year',\n 'year',\n ], calendarButtonText[buttonName]);\n }\n else {\n buttonHint = (navUnit) => (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.k)(calendarButtonHintOverrides[buttonName] ||\n calendarButtonHints[buttonName], [\n calendarButtonText[navUnit] || navUnit,\n navUnit,\n ], calendarButtonText[buttonName]);\n }\n }\n return { buttonName, buttonClick, buttonIcon, buttonText, buttonHint };\n })));\n return { widgets, viewsWithButtons, hasTitle };\n}\n\n// always represents the current view. otherwise, it'd need to change value every time date changes\nclass ViewImpl {\n constructor(type, getCurrentData, dateEnv) {\n this.type = type;\n this.getCurrentData = getCurrentData;\n this.dateEnv = dateEnv;\n }\n get calendar() {\n return this.getCurrentData().calendarApi;\n }\n get title() {\n return this.getCurrentData().viewTitle;\n }\n get activeStart() {\n return this.dateEnv.toDate(this.getCurrentData().dateProfile.activeRange.start);\n }\n get activeEnd() {\n return this.dateEnv.toDate(this.getCurrentData().dateProfile.activeRange.end);\n }\n get currentStart() {\n return this.dateEnv.toDate(this.getCurrentData().dateProfile.currentRange.start);\n }\n get currentEnd() {\n return this.dateEnv.toDate(this.getCurrentData().dateProfile.currentRange.end);\n }\n getOption(name) {\n return this.getCurrentData().options[name]; // are the view-specific options\n }\n}\n\nlet eventSourceDef$2 = {\n ignoreRange: true,\n parseMeta(refined) {\n if (Array.isArray(refined.events)) {\n return refined.events;\n }\n return null;\n },\n fetch(arg, successCallback) {\n successCallback({\n rawEvents: arg.eventSource.meta,\n });\n },\n};\nconst arrayEventSourcePlugin = createPlugin({\n name: 'array-event-source',\n eventSourceDefs: [eventSourceDef$2],\n});\n\nlet eventSourceDef$1 = {\n parseMeta(refined) {\n if (typeof refined.events === 'function') {\n return refined.events;\n }\n return null;\n },\n fetch(arg, successCallback, errorCallback) {\n const { dateEnv } = arg.context;\n const func = arg.eventSource.meta;\n (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.u)(func.bind(null, (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.l)(arg.range, dateEnv)), (rawEvents) => successCallback({ rawEvents }), errorCallback);\n },\n};\nconst funcEventSourcePlugin = createPlugin({\n name: 'func-event-source',\n eventSourceDefs: [eventSourceDef$1],\n});\n\nconst JSON_FEED_EVENT_SOURCE_REFINERS = {\n method: String,\n extraParams: _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.n,\n startParam: String,\n endParam: String,\n timeZoneParam: String,\n};\n\nlet eventSourceDef = {\n parseMeta(refined) {\n if (refined.url && (refined.format === 'json' || !refined.format)) {\n return {\n url: refined.url,\n format: 'json',\n method: (refined.method || 'GET').toUpperCase(),\n extraParams: refined.extraParams,\n startParam: refined.startParam,\n endParam: refined.endParam,\n timeZoneParam: refined.timeZoneParam,\n };\n }\n return null;\n },\n fetch(arg, successCallback, errorCallback) {\n const { meta } = arg.eventSource;\n const requestParams = buildRequestParams(meta, arg.range, arg.context);\n (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.r)(meta.method, meta.url, requestParams).then(([rawEvents, response]) => {\n successCallback({ rawEvents, response });\n }, errorCallback);\n },\n};\nconst jsonFeedEventSourcePlugin = createPlugin({\n name: 'json-event-source',\n eventSourceRefiners: JSON_FEED_EVENT_SOURCE_REFINERS,\n eventSourceDefs: [eventSourceDef],\n});\nfunction buildRequestParams(meta, range, context) {\n let { dateEnv, options } = context;\n let startParam;\n let endParam;\n let timeZoneParam;\n let customRequestParams;\n let params = {};\n startParam = meta.startParam;\n if (startParam == null) {\n startParam = options.startParam;\n }\n endParam = meta.endParam;\n if (endParam == null) {\n endParam = options.endParam;\n }\n timeZoneParam = meta.timeZoneParam;\n if (timeZoneParam == null) {\n timeZoneParam = options.timeZoneParam;\n }\n // retrieve any outbound GET/POST data from the options\n if (typeof meta.extraParams === 'function') {\n // supplied as a function that returns a key/value object\n customRequestParams = meta.extraParams();\n }\n else {\n // probably supplied as a straight key/value object\n customRequestParams = meta.extraParams || {};\n }\n Object.assign(params, customRequestParams);\n params[startParam] = dateEnv.formatIso(range.start);\n params[endParam] = dateEnv.formatIso(range.end);\n if (dateEnv.timeZone !== 'local') {\n params[timeZoneParam] = dateEnv.timeZone;\n }\n return params;\n}\n\nconst SIMPLE_RECURRING_REFINERS = {\n daysOfWeek: _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.n,\n startTime: _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.d,\n endTime: _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.d,\n duration: _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.d,\n startRecur: _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.n,\n endRecur: _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.n,\n};\n\nlet recurring = {\n parse(refined, dateEnv) {\n if (refined.daysOfWeek || refined.startTime || refined.endTime || refined.startRecur || refined.endRecur) {\n let recurringData = {\n daysOfWeek: refined.daysOfWeek || null,\n startTime: refined.startTime || null,\n endTime: refined.endTime || null,\n startRecur: refined.startRecur ? dateEnv.createMarker(refined.startRecur) : null,\n endRecur: refined.endRecur ? dateEnv.createMarker(refined.endRecur) : null,\n dateEnv,\n };\n let duration;\n if (refined.duration) {\n duration = refined.duration;\n }\n if (!duration && refined.startTime && refined.endTime) {\n duration = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.s)(refined.endTime, refined.startTime);\n }\n return {\n allDayGuess: Boolean(!refined.startTime && !refined.endTime),\n duration,\n typeData: recurringData, // doesn't need endTime anymore but oh well\n };\n }\n return null;\n },\n expand(typeData, framingRange, dateEnv) {\n let clippedFramingRange = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.o)(framingRange, { start: typeData.startRecur, end: typeData.endRecur });\n if (clippedFramingRange) {\n return expandRanges(typeData.daysOfWeek, typeData.startTime, typeData.dateEnv, dateEnv, clippedFramingRange);\n }\n return [];\n },\n};\nconst simpleRecurringEventsPlugin = createPlugin({\n name: 'simple-recurring-event',\n recurringTypes: [recurring],\n eventRefiners: SIMPLE_RECURRING_REFINERS,\n});\nfunction expandRanges(daysOfWeek, startTime, eventDateEnv, calendarDateEnv, framingRange) {\n let dowHash = daysOfWeek ? (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.f)(daysOfWeek) : null;\n let dayMarker = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.q)(framingRange.start);\n let endMarker = framingRange.end;\n let instanceStarts = [];\n // https://github.com/fullcalendar/fullcalendar/issues/7934\n if (startTime) {\n if (startTime.milliseconds < 0) {\n // possible for next-day to have negative business hours that go into current day\n endMarker = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.t)(endMarker, 1);\n }\n else if (startTime.milliseconds >= 1000 * 60 * 60 * 24) {\n // possible for prev-day to have >24hr business hours that go into current day\n dayMarker = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.t)(dayMarker, -1);\n }\n }\n while (dayMarker < endMarker) {\n let instanceStart;\n // if everyday, or this particular day-of-week\n if (!dowHash || dowHash[dayMarker.getUTCDay()]) {\n if (startTime) {\n instanceStart = calendarDateEnv.add(dayMarker, startTime);\n }\n else {\n instanceStart = dayMarker;\n }\n instanceStarts.push(calendarDateEnv.createMarker(eventDateEnv.toDate(instanceStart)));\n }\n dayMarker = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.t)(dayMarker, 1);\n }\n return instanceStarts;\n}\n\nconst changeHandlerPlugin = createPlugin({\n name: 'change-handler',\n optionChangeHandlers: {\n events(events, context) {\n handleEventSources([events], context);\n },\n eventSources: handleEventSources,\n },\n});\n/*\nBUG: if `event` was supplied, all previously-given `eventSources` will be wiped out\n*/\nfunction handleEventSources(inputs, context) {\n let unfoundSources = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.v)(context.getCurrentData().eventSources);\n if (unfoundSources.length === 1 &&\n inputs.length === 1 &&\n Array.isArray(unfoundSources[0]._raw) &&\n Array.isArray(inputs[0])) {\n context.dispatch({\n type: 'RESET_RAW_EVENTS',\n sourceId: unfoundSources[0].sourceId,\n rawEvents: inputs[0],\n });\n return;\n }\n let newInputs = [];\n for (let input of inputs) {\n let inputFound = false;\n for (let i = 0; i < unfoundSources.length; i += 1) {\n if (unfoundSources[i]._raw === input) {\n unfoundSources.splice(i, 1); // delete\n inputFound = true;\n break;\n }\n }\n if (!inputFound) {\n newInputs.push(input);\n }\n }\n for (let unfoundSource of unfoundSources) {\n context.dispatch({\n type: 'REMOVE_EVENT_SOURCE',\n sourceId: unfoundSource.sourceId,\n });\n }\n for (let newInput of newInputs) {\n context.calendarApi.addEventSource(newInput);\n }\n}\n\nfunction handleDateProfile(dateProfile, context) {\n context.emitter.trigger('datesSet', Object.assign(Object.assign({}, (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.l)(dateProfile.activeRange, context.dateEnv)), { view: context.viewApi }));\n}\n\nfunction handleEventStore(eventStore, context) {\n let { emitter } = context;\n if (emitter.hasHandlers('eventsSet')) {\n emitter.trigger('eventsSet', (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.w)(eventStore, context));\n }\n}\n\n/*\nthis array is exposed on the root namespace so that UMD plugins can add to it.\nsee the rollup-bundles script.\n*/\nconst globalPlugins = [\n arrayEventSourcePlugin,\n funcEventSourcePlugin,\n jsonFeedEventSourcePlugin,\n simpleRecurringEventsPlugin,\n changeHandlerPlugin,\n createPlugin({\n name: 'misc',\n isLoadingFuncs: [\n (state) => computeEventSourcesLoading(state.eventSources),\n ],\n propSetHandlers: {\n dateProfile: handleDateProfile,\n eventStore: handleEventStore,\n },\n }),\n];\n\nclass TaskRunner {\n constructor(runTaskOption, drainedOption) {\n this.runTaskOption = runTaskOption;\n this.drainedOption = drainedOption;\n this.queue = [];\n this.delayedRunner = new _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.D(this.drain.bind(this));\n }\n request(task, delay) {\n this.queue.push(task);\n this.delayedRunner.request(delay);\n }\n pause(scope) {\n this.delayedRunner.pause(scope);\n }\n resume(scope, force) {\n this.delayedRunner.resume(scope, force);\n }\n drain() {\n let { queue } = this;\n while (queue.length) {\n let completedTasks = [];\n let task;\n while ((task = queue.shift())) {\n this.runTask(task);\n completedTasks.push(task);\n }\n this.drained(completedTasks);\n } // keep going, in case new tasks were added in the drained handler\n }\n runTask(task) {\n if (this.runTaskOption) {\n this.runTaskOption(task);\n }\n }\n drained(completedTasks) {\n if (this.drainedOption) {\n this.drainedOption(completedTasks);\n }\n }\n}\n\n// Computes what the title at the top of the calendarApi should be for this view\nfunction buildTitle(dateProfile, viewOptions, dateEnv) {\n let range;\n // for views that span a large unit of time, show the proper interval, ignoring stray days before and after\n if (/^(year|month)$/.test(dateProfile.currentRangeUnit)) {\n range = dateProfile.currentRange;\n }\n else { // for day units or smaller, use the actual day range\n range = dateProfile.activeRange;\n }\n return dateEnv.formatRange(range.start, range.end, (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.x)(viewOptions.titleFormat || buildTitleFormat(dateProfile)), {\n isEndExclusive: dateProfile.isRangeAllDay,\n defaultSeparator: viewOptions.titleRangeSeparator,\n });\n}\n// Generates the format string that should be used to generate the title for the current date range.\n// Attempts to compute the most appropriate format if not explicitly specified with `titleFormat`.\nfunction buildTitleFormat(dateProfile) {\n let { currentRangeUnit } = dateProfile;\n if (currentRangeUnit === 'year') {\n return { year: 'numeric' };\n }\n if (currentRangeUnit === 'month') {\n return { year: 'numeric', month: 'long' }; // like \"September 2014\"\n }\n let days = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.y)(dateProfile.currentRange.start, dateProfile.currentRange.end);\n if (days !== null && days > 1) {\n // multi-day range. shorter, like \"Sep 9 - 10 2014\"\n return { year: 'numeric', month: 'short', day: 'numeric' };\n }\n // one day. longer, like \"September 9 2014\"\n return { year: 'numeric', month: 'long', day: 'numeric' };\n}\n\n/*\nTODO: test switching timezones when NO timezone plugin\n*/\nclass CalendarNowManager {\n constructor() {\n this.resetListeners = new Set();\n }\n handleInput(dateEnv, // will change if timezone setup changed\n nowInput) {\n const oldDateEnv = this.dateEnv;\n if (dateEnv !== oldDateEnv) {\n if (typeof nowInput === 'function') {\n this.nowFn = nowInput;\n }\n else if (!oldDateEnv) { // first time?\n this.nowAnchorDate = dateEnv.toDate(nowInput\n ? dateEnv.createMarker(nowInput)\n : dateEnv.createNowMarker());\n this.nowAnchorQueried = Date.now();\n }\n this.dateEnv = dateEnv;\n // not first time? fire reset handlers\n if (oldDateEnv) {\n for (const resetListener of this.resetListeners.values()) {\n resetListener();\n }\n }\n }\n }\n getDateMarker() {\n return this.nowAnchorDate\n ? this.dateEnv.timestampToMarker(this.nowAnchorDate.valueOf() +\n (Date.now() - this.nowAnchorQueried))\n : this.dateEnv.createMarker(this.nowFn());\n }\n addResetListener(handler) {\n this.resetListeners.add(handler);\n }\n removeResetListener(handler) {\n this.resetListeners.delete(handler);\n }\n}\n\n// in future refactor, do the redux-style function(state=initial) for initial-state\n// also, whatever is happening in constructor, have it happen in action queue too\nclass CalendarDataManager {\n constructor(props) {\n this.computeCurrentViewData = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.z)(this._computeCurrentViewData);\n this.organizeRawLocales = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.z)(organizeRawLocales);\n this.buildLocale = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.z)(buildLocale);\n this.buildPluginHooks = buildBuildPluginHooks();\n this.buildDateEnv = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.z)(buildDateEnv$1);\n this.buildTheme = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.z)(buildTheme);\n this.parseToolbars = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.z)(parseToolbars);\n this.buildViewSpecs = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.z)(buildViewSpecs);\n this.buildDateProfileGenerator = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.A)(buildDateProfileGenerator);\n this.buildViewApi = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.z)(buildViewApi);\n this.buildViewUiProps = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.A)(buildViewUiProps);\n this.buildEventUiBySource = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.z)(buildEventUiBySource, _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.E);\n this.buildEventUiBases = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.z)(buildEventUiBases);\n this.parseContextBusinessHours = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.A)(parseContextBusinessHours);\n this.buildTitle = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.z)(buildTitle);\n this.nowManager = new CalendarNowManager();\n this.emitter = new _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.F();\n this.actionRunner = new TaskRunner(this._handleAction.bind(this), this.updateData.bind(this));\n this.currentCalendarOptionsInput = {};\n this.currentCalendarOptionsRefined = {};\n this.currentViewOptionsInput = {};\n this.currentViewOptionsRefined = {};\n this.currentCalendarOptionsRefiners = {};\n this.optionsForRefining = [];\n this.optionsForHandling = [];\n this.getCurrentData = () => this.data;\n this.dispatch = (action) => {\n this.actionRunner.request(action); // protects against recursive calls to _handleAction\n };\n this.props = props;\n this.actionRunner.pause();\n this.nowManager = new CalendarNowManager();\n let dynamicOptionOverrides = {};\n let optionsData = this.computeOptionsData(props.optionOverrides, dynamicOptionOverrides, props.calendarApi);\n let currentViewType = optionsData.calendarOptions.initialView || optionsData.pluginHooks.initialView;\n let currentViewData = this.computeCurrentViewData(currentViewType, optionsData, props.optionOverrides, dynamicOptionOverrides);\n // wire things up\n // TODO: not DRY\n props.calendarApi.currentDataManager = this;\n this.emitter.setThisContext(props.calendarApi);\n this.emitter.setOptions(currentViewData.options);\n let calendarContext = {\n nowManager: this.nowManager,\n dateEnv: optionsData.dateEnv,\n options: optionsData.calendarOptions,\n pluginHooks: optionsData.pluginHooks,\n calendarApi: props.calendarApi,\n dispatch: this.dispatch,\n emitter: this.emitter,\n getCurrentData: this.getCurrentData,\n };\n let currentDate = getInitialDate(optionsData.calendarOptions, optionsData.dateEnv, this.nowManager);\n let dateProfile = currentViewData.dateProfileGenerator.build(currentDate);\n if (!(0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.G)(dateProfile.activeRange, currentDate)) {\n currentDate = dateProfile.currentRange.start;\n }\n // needs to be after setThisContext\n for (let callback of optionsData.pluginHooks.contextInit) {\n callback(calendarContext);\n }\n // NOT DRY\n let eventSources = initEventSources(optionsData.calendarOptions, dateProfile, calendarContext);\n let initialState = {\n dynamicOptionOverrides,\n currentViewType,\n currentDate,\n dateProfile,\n businessHours: this.parseContextBusinessHours(calendarContext),\n eventSources,\n eventUiBases: {},\n eventStore: (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.H)(),\n renderableEventStore: (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.H)(),\n dateSelection: null,\n eventSelection: '',\n eventDrag: null,\n eventResize: null,\n selectionConfig: this.buildViewUiProps(calendarContext).selectionConfig,\n };\n let contextAndState = Object.assign(Object.assign({}, calendarContext), initialState);\n for (let reducer of optionsData.pluginHooks.reducers) {\n Object.assign(initialState, reducer(null, null, contextAndState));\n }\n if (computeIsLoading(initialState, calendarContext)) {\n this.emitter.trigger('loading', true); // NOT DRY\n }\n this.state = initialState;\n this.updateData();\n this.actionRunner.resume();\n }\n resetOptions(optionOverrides, changedOptionNames) {\n let { props } = this;\n if (changedOptionNames === undefined) {\n props.optionOverrides = optionOverrides;\n }\n else {\n props.optionOverrides = Object.assign(Object.assign({}, (props.optionOverrides || {})), optionOverrides);\n this.optionsForRefining.push(...changedOptionNames);\n }\n if (changedOptionNames === undefined || changedOptionNames.length) {\n this.actionRunner.request({\n type: 'NOTHING',\n });\n }\n }\n _handleAction(action) {\n let { props, state, emitter } = this;\n let dynamicOptionOverrides = reduceDynamicOptionOverrides(state.dynamicOptionOverrides, action);\n let optionsData = this.computeOptionsData(props.optionOverrides, dynamicOptionOverrides, props.calendarApi);\n let currentViewType = reduceViewType(state.currentViewType, action);\n let currentViewData = this.computeCurrentViewData(currentViewType, optionsData, props.optionOverrides, dynamicOptionOverrides);\n // wire things up\n // TODO: not DRY\n props.calendarApi.currentDataManager = this;\n emitter.setThisContext(props.calendarApi);\n emitter.setOptions(currentViewData.options);\n let calendarContext = {\n nowManager: this.nowManager,\n dateEnv: optionsData.dateEnv,\n options: optionsData.calendarOptions,\n pluginHooks: optionsData.pluginHooks,\n calendarApi: props.calendarApi,\n dispatch: this.dispatch,\n emitter,\n getCurrentData: this.getCurrentData,\n };\n let { currentDate, dateProfile } = state;\n if (this.data && this.data.dateProfileGenerator !== currentViewData.dateProfileGenerator) { // hack\n dateProfile = currentViewData.dateProfileGenerator.build(currentDate);\n }\n currentDate = reduceCurrentDate(currentDate, action);\n dateProfile = reduceDateProfile(dateProfile, action, currentDate, currentViewData.dateProfileGenerator);\n if (action.type === 'PREV' || // TODO: move this logic into DateProfileGenerator\n action.type === 'NEXT' || // \"\n !(0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.G)(dateProfile.currentRange, currentDate)) {\n currentDate = dateProfile.currentRange.start;\n }\n let eventSources = reduceEventSources(state.eventSources, action, dateProfile, calendarContext);\n let eventStore = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.I)(state.eventStore, action, eventSources, dateProfile, calendarContext);\n let isEventsLoading = computeEventSourcesLoading(eventSources); // BAD. also called in this func in computeIsLoading\n let renderableEventStore = (isEventsLoading && !currentViewData.options.progressiveEventRendering) ?\n (state.renderableEventStore || eventStore) : // try from previous state\n eventStore;\n let { eventUiSingleBase, selectionConfig } = this.buildViewUiProps(calendarContext); // will memoize obj\n let eventUiBySource = this.buildEventUiBySource(eventSources);\n let eventUiBases = this.buildEventUiBases(renderableEventStore.defs, eventUiSingleBase, eventUiBySource);\n let newState = {\n dynamicOptionOverrides,\n currentViewType,\n currentDate,\n dateProfile,\n eventSources,\n eventStore,\n renderableEventStore,\n selectionConfig,\n eventUiBases,\n businessHours: this.parseContextBusinessHours(calendarContext),\n dateSelection: reduceDateSelection(state.dateSelection, action),\n eventSelection: reduceSelectedEvent(state.eventSelection, action),\n eventDrag: reduceEventDrag(state.eventDrag, action),\n eventResize: reduceEventResize(state.eventResize, action),\n };\n let contextAndState = Object.assign(Object.assign({}, calendarContext), newState);\n for (let reducer of optionsData.pluginHooks.reducers) {\n Object.assign(newState, reducer(state, action, contextAndState)); // give the OLD state, for old value\n }\n let wasLoading = computeIsLoading(state, calendarContext);\n let isLoading = computeIsLoading(newState, calendarContext);\n // TODO: use propSetHandlers in plugin system\n if (!wasLoading && isLoading) {\n emitter.trigger('loading', true);\n }\n else if (wasLoading && !isLoading) {\n emitter.trigger('loading', false);\n }\n this.state = newState;\n if (props.onAction) {\n props.onAction(action);\n }\n }\n updateData() {\n let { props, state } = this;\n let oldData = this.data;\n let optionsData = this.computeOptionsData(props.optionOverrides, state.dynamicOptionOverrides, props.calendarApi);\n let currentViewData = this.computeCurrentViewData(state.currentViewType, optionsData, props.optionOverrides, state.dynamicOptionOverrides);\n let data = this.data = Object.assign(Object.assign(Object.assign({ nowManager: this.nowManager, viewTitle: this.buildTitle(state.dateProfile, currentViewData.options, optionsData.dateEnv), calendarApi: props.calendarApi, dispatch: this.dispatch, emitter: this.emitter, getCurrentData: this.getCurrentData }, optionsData), currentViewData), state);\n let changeHandlers = optionsData.pluginHooks.optionChangeHandlers;\n let oldCalendarOptions = oldData && oldData.calendarOptions;\n let newCalendarOptions = optionsData.calendarOptions;\n if (oldCalendarOptions && oldCalendarOptions !== newCalendarOptions) {\n if (oldCalendarOptions.timeZone !== newCalendarOptions.timeZone) {\n // hack\n state.eventSources = data.eventSources = reduceEventSourcesNewTimeZone(data.eventSources, state.dateProfile, data);\n state.eventStore = data.eventStore = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.J)(data.eventStore, oldData.dateEnv, data.dateEnv);\n state.renderableEventStore = data.renderableEventStore = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.J)(data.renderableEventStore, oldData.dateEnv, data.dateEnv);\n }\n for (let optionName in changeHandlers) {\n if (this.optionsForHandling.indexOf(optionName) !== -1 ||\n oldCalendarOptions[optionName] !== newCalendarOptions[optionName]) {\n changeHandlers[optionName](newCalendarOptions[optionName], data);\n }\n }\n }\n this.optionsForHandling = [];\n if (props.onData) {\n props.onData(data);\n }\n }\n computeOptionsData(optionOverrides, dynamicOptionOverrides, calendarApi) {\n // TODO: blacklist options that are handled by optionChangeHandlers\n if (!this.optionsForRefining.length &&\n optionOverrides === this.stableOptionOverrides &&\n dynamicOptionOverrides === this.stableDynamicOptionOverrides) {\n return this.stableCalendarOptionsData;\n }\n let { refinedOptions, pluginHooks, localeDefaults, availableLocaleData, extra, } = this.processRawCalendarOptions(optionOverrides, dynamicOptionOverrides);\n warnUnknownOptions(extra);\n let dateEnv = this.buildDateEnv(refinedOptions.timeZone, refinedOptions.locale, refinedOptions.weekNumberCalculation, refinedOptions.firstDay, refinedOptions.weekText, pluginHooks, availableLocaleData, refinedOptions.defaultRangeSeparator);\n let viewSpecs = this.buildViewSpecs(pluginHooks.views, this.stableOptionOverrides, this.stableDynamicOptionOverrides, localeDefaults);\n let theme = this.buildTheme(refinedOptions, pluginHooks);\n let toolbarConfig = this.parseToolbars(refinedOptions, this.stableOptionOverrides, theme, viewSpecs, calendarApi);\n return this.stableCalendarOptionsData = {\n calendarOptions: refinedOptions,\n pluginHooks,\n dateEnv,\n viewSpecs,\n theme,\n toolbarConfig,\n localeDefaults,\n availableRawLocales: availableLocaleData.map,\n };\n }\n // always called from behind a memoizer\n processRawCalendarOptions(optionOverrides, dynamicOptionOverrides) {\n let { locales, locale } = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.K)([\n _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.e,\n optionOverrides,\n dynamicOptionOverrides,\n ]);\n let availableLocaleData = this.organizeRawLocales(locales);\n let availableRawLocales = availableLocaleData.map;\n let localeDefaults = this.buildLocale(locale || availableLocaleData.defaultCode, availableRawLocales).options;\n let pluginHooks = this.buildPluginHooks(optionOverrides.plugins || [], globalPlugins);\n let refiners = this.currentCalendarOptionsRefiners = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.L), _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.M), _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.N), pluginHooks.listenerRefiners), pluginHooks.optionRefiners);\n let extra = {};\n let raw = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.K)([\n _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.e,\n localeDefaults,\n optionOverrides,\n dynamicOptionOverrides,\n ]);\n let refined = {};\n let currentRaw = this.currentCalendarOptionsInput;\n let currentRefined = this.currentCalendarOptionsRefined;\n let anyChanges = false;\n for (let optionName in raw) {\n if (this.optionsForRefining.indexOf(optionName) === -1 && (raw[optionName] === currentRaw[optionName] || (_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.O[optionName] &&\n (optionName in currentRaw) &&\n _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.O[optionName](currentRaw[optionName], raw[optionName])))) {\n refined[optionName] = currentRefined[optionName];\n }\n else if (refiners[optionName]) {\n refined[optionName] = refiners[optionName](raw[optionName]);\n anyChanges = true;\n }\n else {\n extra[optionName] = currentRaw[optionName];\n }\n }\n if (anyChanges) {\n this.currentCalendarOptionsInput = raw;\n this.currentCalendarOptionsRefined = refined;\n this.stableOptionOverrides = optionOverrides;\n this.stableDynamicOptionOverrides = dynamicOptionOverrides;\n }\n this.optionsForHandling.push(...this.optionsForRefining);\n this.optionsForRefining = [];\n return {\n rawOptions: this.currentCalendarOptionsInput,\n refinedOptions: this.currentCalendarOptionsRefined,\n pluginHooks,\n availableLocaleData,\n localeDefaults,\n extra,\n };\n }\n _computeCurrentViewData(viewType, optionsData, optionOverrides, dynamicOptionOverrides) {\n let viewSpec = optionsData.viewSpecs[viewType];\n if (!viewSpec) {\n throw new Error(`viewType \"${viewType}\" is not available. Please make sure you've loaded all neccessary plugins`);\n }\n let { refinedOptions, extra } = this.processRawViewOptions(viewSpec, optionsData.pluginHooks, optionsData.localeDefaults, optionOverrides, dynamicOptionOverrides);\n warnUnknownOptions(extra);\n this.nowManager.handleInput(optionsData.dateEnv, refinedOptions.now);\n let dateProfileGenerator = this.buildDateProfileGenerator({\n dateProfileGeneratorClass: viewSpec.optionDefaults.dateProfileGeneratorClass,\n nowManager: this.nowManager,\n duration: viewSpec.duration,\n durationUnit: viewSpec.durationUnit,\n usesMinMaxTime: viewSpec.optionDefaults.usesMinMaxTime,\n dateEnv: optionsData.dateEnv,\n calendarApi: this.props.calendarApi,\n slotMinTime: refinedOptions.slotMinTime,\n slotMaxTime: refinedOptions.slotMaxTime,\n showNonCurrentDates: refinedOptions.showNonCurrentDates,\n dayCount: refinedOptions.dayCount,\n dateAlignment: refinedOptions.dateAlignment,\n dateIncrement: refinedOptions.dateIncrement,\n hiddenDays: refinedOptions.hiddenDays,\n weekends: refinedOptions.weekends,\n validRangeInput: refinedOptions.validRange,\n visibleRangeInput: refinedOptions.visibleRange,\n fixedWeekCount: refinedOptions.fixedWeekCount,\n });\n let viewApi = this.buildViewApi(viewType, this.getCurrentData, optionsData.dateEnv);\n return { viewSpec, options: refinedOptions, dateProfileGenerator, viewApi };\n }\n processRawViewOptions(viewSpec, pluginHooks, localeDefaults, optionOverrides, dynamicOptionOverrides) {\n let raw = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.K)([\n _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.e,\n viewSpec.optionDefaults,\n localeDefaults,\n optionOverrides,\n viewSpec.optionOverrides,\n dynamicOptionOverrides,\n ]);\n let refiners = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.L), _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.M), _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.N), _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.P), pluginHooks.listenerRefiners), pluginHooks.optionRefiners);\n let refined = {};\n let currentRaw = this.currentViewOptionsInput;\n let currentRefined = this.currentViewOptionsRefined;\n let anyChanges = false;\n let extra = {};\n for (let optionName in raw) {\n if (raw[optionName] === currentRaw[optionName] ||\n (_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.O[optionName] &&\n _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.O[optionName](raw[optionName], currentRaw[optionName]))) {\n refined[optionName] = currentRefined[optionName];\n }\n else {\n if (raw[optionName] === this.currentCalendarOptionsInput[optionName] ||\n (_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.O[optionName] &&\n _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.O[optionName](raw[optionName], this.currentCalendarOptionsInput[optionName]))) {\n if (optionName in this.currentCalendarOptionsRefined) { // might be an \"extra\" prop\n refined[optionName] = this.currentCalendarOptionsRefined[optionName];\n }\n }\n else if (refiners[optionName]) {\n refined[optionName] = refiners[optionName](raw[optionName]);\n }\n else {\n extra[optionName] = raw[optionName];\n }\n anyChanges = true;\n }\n }\n if (anyChanges) {\n this.currentViewOptionsInput = raw;\n this.currentViewOptionsRefined = refined;\n }\n return {\n rawOptions: this.currentViewOptionsInput,\n refinedOptions: this.currentViewOptionsRefined,\n extra,\n };\n }\n}\nfunction buildDateEnv$1(timeZone, explicitLocale, weekNumberCalculation, firstDay, weekText, pluginHooks, availableLocaleData, defaultSeparator) {\n let locale = buildLocale(explicitLocale || availableLocaleData.defaultCode, availableLocaleData.map);\n return new _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.Q({\n calendarSystem: 'gregory',\n timeZone,\n namedTimeZoneImpl: pluginHooks.namedTimeZonedImpl,\n locale,\n weekNumberCalculation,\n firstDay,\n weekText,\n cmdFormatter: pluginHooks.cmdFormatter,\n defaultSeparator,\n });\n}\nfunction buildTheme(options, pluginHooks) {\n let ThemeClass = pluginHooks.themeClasses[options.themeSystem] || StandardTheme;\n return new ThemeClass(options);\n}\nfunction buildDateProfileGenerator(props) {\n let DateProfileGeneratorClass = props.dateProfileGeneratorClass || _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.R;\n return new DateProfileGeneratorClass(props);\n}\nfunction buildViewApi(type, getCurrentData, dateEnv) {\n return new ViewImpl(type, getCurrentData, dateEnv);\n}\nfunction buildEventUiBySource(eventSources) {\n return (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.a)(eventSources, (eventSource) => eventSource.ui);\n}\nfunction buildEventUiBases(eventDefs, eventUiSingleBase, eventUiBySource) {\n let eventUiBases = { '': eventUiSingleBase };\n for (let defId in eventDefs) {\n let def = eventDefs[defId];\n if (def.sourceId && eventUiBySource[def.sourceId]) {\n eventUiBases[defId] = eventUiBySource[def.sourceId];\n }\n }\n return eventUiBases;\n}\nfunction buildViewUiProps(calendarContext) {\n let { options } = calendarContext;\n return {\n eventUiSingleBase: (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.S)({\n display: options.eventDisplay,\n editable: options.editable,\n startEditable: options.eventStartEditable,\n durationEditable: options.eventDurationEditable,\n constraint: options.eventConstraint,\n overlap: typeof options.eventOverlap === 'boolean' ? options.eventOverlap : undefined,\n allow: options.eventAllow,\n backgroundColor: options.eventBackgroundColor,\n borderColor: options.eventBorderColor,\n textColor: options.eventTextColor,\n color: options.eventColor,\n // classNames: options.eventClassNames // render hook will handle this\n }, calendarContext),\n selectionConfig: (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.S)({\n constraint: options.selectConstraint,\n overlap: typeof options.selectOverlap === 'boolean' ? options.selectOverlap : undefined,\n allow: options.selectAllow,\n }, calendarContext),\n };\n}\nfunction computeIsLoading(state, context) {\n for (let isLoadingFunc of context.pluginHooks.isLoadingFuncs) {\n if (isLoadingFunc(state)) {\n return true;\n }\n }\n return false;\n}\nfunction parseContextBusinessHours(calendarContext) {\n return (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.U)(calendarContext.options.businessHours, calendarContext);\n}\nfunction warnUnknownOptions(options, viewName) {\n for (let optionName in options) {\n console.warn(`Unknown option '${optionName}'` +\n (viewName ? ` for view '${viewName}'` : ''));\n }\n}\n\nclass ToolbarSection extends _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.B {\n render() {\n let children = this.props.widgetGroups.map((widgetGroup) => this.renderWidgetGroup(widgetGroup));\n return (0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)('div', { className: 'fc-toolbar-chunk' }, ...children);\n }\n renderWidgetGroup(widgetGroup) {\n let { props } = this;\n let { theme } = this.context;\n let children = [];\n let isOnlyButtons = true;\n for (let widget of widgetGroup) {\n let { buttonName, buttonClick, buttonText, buttonIcon, buttonHint } = widget;\n if (buttonName === 'title') {\n isOnlyButtons = false;\n children.push((0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"h2\", { className: \"fc-toolbar-title\", id: props.titleId }, props.title));\n }\n else {\n let isPressed = buttonName === props.activeButton;\n let isDisabled = (!props.isTodayEnabled && buttonName === 'today') ||\n (!props.isPrevEnabled && buttonName === 'prev') ||\n (!props.isNextEnabled && buttonName === 'next');\n let buttonClasses = [`fc-${buttonName}-button`, theme.getClass('button')];\n if (isPressed) {\n buttonClasses.push(theme.getClass('buttonActive'));\n }\n children.push((0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"button\", { type: \"button\", title: typeof buttonHint === 'function' ? buttonHint(props.navUnit) : buttonHint, disabled: isDisabled, \"aria-pressed\": isPressed, className: buttonClasses.join(' '), onClick: buttonClick }, buttonText || (buttonIcon ? (0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"span\", { className: buttonIcon, role: \"img\" }) : '')));\n }\n }\n if (children.length > 1) {\n let groupClassName = (isOnlyButtons && theme.getClass('buttonGroup')) || '';\n return (0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)('div', { className: groupClassName }, ...children);\n }\n return children[0];\n }\n}\n\nclass Toolbar extends _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.B {\n render() {\n let { model, extraClassName } = this.props;\n let forceLtr = false;\n let startContent;\n let endContent;\n let sectionWidgets = model.sectionWidgets;\n let centerContent = sectionWidgets.center;\n if (sectionWidgets.left) {\n forceLtr = true;\n startContent = sectionWidgets.left;\n }\n else {\n startContent = sectionWidgets.start;\n }\n if (sectionWidgets.right) {\n forceLtr = true;\n endContent = sectionWidgets.right;\n }\n else {\n endContent = sectionWidgets.end;\n }\n let classNames = [\n extraClassName || '',\n 'fc-toolbar',\n forceLtr ? 'fc-toolbar-ltr' : '',\n ];\n return ((0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: classNames.join(' ') },\n this.renderSection('start', startContent || []),\n this.renderSection('center', centerContent || []),\n this.renderSection('end', endContent || [])));\n }\n renderSection(key, widgetGroups) {\n let { props } = this;\n return ((0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(ToolbarSection, { key: key, widgetGroups: widgetGroups, title: props.title, navUnit: props.navUnit, activeButton: props.activeButton, isTodayEnabled: props.isTodayEnabled, isPrevEnabled: props.isPrevEnabled, isNextEnabled: props.isNextEnabled, titleId: props.titleId }));\n }\n}\n\nclass ViewHarness extends _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.B {\n constructor() {\n super(...arguments);\n this.state = {\n availableWidth: null,\n };\n this.handleEl = (el) => {\n this.el = el;\n (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.W)(this.props.elRef, el);\n this.updateAvailableWidth();\n };\n this.handleResize = () => {\n this.updateAvailableWidth();\n };\n }\n render() {\n let { props, state } = this;\n let { aspectRatio } = props;\n let classNames = [\n 'fc-view-harness',\n (aspectRatio || props.liquid || props.height)\n ? 'fc-view-harness-active' // harness controls the height\n : 'fc-view-harness-passive', // let the view do the height\n ];\n let height = '';\n let paddingBottom = '';\n if (aspectRatio) {\n if (state.availableWidth !== null) {\n height = state.availableWidth / aspectRatio;\n }\n else {\n // while waiting to know availableWidth, we can't set height to *zero*\n // because will cause lots of unnecessary scrollbars within scrollgrid.\n // BETTER: don't start rendering ANYTHING yet until we know container width\n // NOTE: why not always use paddingBottom? Causes height oscillation (issue 5606)\n paddingBottom = `${(1 / aspectRatio) * 100}%`;\n }\n }\n else {\n height = props.height || '';\n }\n return ((0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { \"aria-labelledby\": props.labeledById, ref: this.handleEl, className: classNames.join(' '), style: { height, paddingBottom } }, props.children));\n }\n componentDidMount() {\n this.context.addResizeHandler(this.handleResize);\n }\n componentWillUnmount() {\n this.context.removeResizeHandler(this.handleResize);\n }\n updateAvailableWidth() {\n if (this.el && // needed. but why?\n this.props.aspectRatio // aspectRatio is the only height setting that needs availableWidth\n ) {\n this.setState({ availableWidth: this.el.offsetWidth });\n }\n }\n}\n\n/*\nDetects when the user clicks on an event within a DateComponent\n*/\nclass EventClicking extends _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.X {\n constructor(settings) {\n super(settings);\n this.handleSegClick = (ev, segEl) => {\n let { component } = this;\n let { context } = component;\n let seg = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.Y)(segEl);\n if (seg && // might be the <div> surrounding the more link\n component.isValidSegDownEl(ev.target)) {\n // our way to simulate a link click for elements that can't be <a> tags\n // grab before trigger fired in case trigger trashes DOM thru rerendering\n let hasUrlContainer = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ev.target, '.fc-event-forced-url');\n let url = hasUrlContainer ? hasUrlContainer.querySelector('a[href]').href : '';\n context.emitter.trigger('eventClick', {\n el: segEl,\n event: new _internal_common_js__WEBPACK_IMPORTED_MODULE_0__._(component.context, seg.eventRange.def, seg.eventRange.instance),\n jsEvent: ev,\n view: context.viewApi,\n });\n if (url && !ev.defaultPrevented) {\n window.location.href = url;\n }\n }\n };\n this.destroy = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.$)(settings.el, 'click', '.fc-event', // on both fg and bg events\n this.handleSegClick);\n }\n}\n\n/*\nTriggers events and adds/removes core classNames when the user's pointer\nenters/leaves event-elements of a component.\n*/\nclass EventHovering extends _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.X {\n constructor(settings) {\n super(settings);\n // for simulating an eventMouseLeave when the event el is destroyed while mouse is over it\n this.handleEventElRemove = (el) => {\n if (el === this.currentSegEl) {\n this.handleSegLeave(null, this.currentSegEl);\n }\n };\n this.handleSegEnter = (ev, segEl) => {\n if ((0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.Y)(segEl)) { // TODO: better way to make sure not hovering over more+ link or its wrapper\n this.currentSegEl = segEl;\n this.triggerEvent('eventMouseEnter', ev, segEl);\n }\n };\n this.handleSegLeave = (ev, segEl) => {\n if (this.currentSegEl) {\n this.currentSegEl = null;\n this.triggerEvent('eventMouseLeave', ev, segEl);\n }\n };\n this.removeHoverListeners = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.a0)(settings.el, '.fc-event', // on both fg and bg events\n this.handleSegEnter, this.handleSegLeave);\n }\n destroy() {\n this.removeHoverListeners();\n }\n triggerEvent(publicEvName, ev, segEl) {\n let { component } = this;\n let { context } = component;\n let seg = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.Y)(segEl);\n if (!ev || component.isValidSegDownEl(ev.target)) {\n context.emitter.trigger(publicEvName, {\n el: segEl,\n event: new _internal_common_js__WEBPACK_IMPORTED_MODULE_0__._(context, seg.eventRange.def, seg.eventRange.instance),\n jsEvent: ev,\n view: context.viewApi,\n });\n }\n }\n}\n\nclass CalendarContent extends _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.a1 {\n constructor() {\n super(...arguments);\n this.buildViewContext = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.z)(_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.a2);\n this.buildViewPropTransformers = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.z)(buildViewPropTransformers);\n this.buildToolbarProps = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.z)(buildToolbarProps);\n this.headerRef = (0,preact__WEBPACK_IMPORTED_MODULE_1__.createRef)();\n this.footerRef = (0,preact__WEBPACK_IMPORTED_MODULE_1__.createRef)();\n this.interactionsStore = {};\n // eslint-disable-next-line\n this.state = {\n viewLabelId: (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.a3)(),\n };\n // Component Registration\n // -----------------------------------------------------------------------------------------------------------------\n this.registerInteractiveComponent = (component, settingsInput) => {\n let settings = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.a4)(component, settingsInput);\n let DEFAULT_INTERACTIONS = [\n EventClicking,\n EventHovering,\n ];\n let interactionClasses = DEFAULT_INTERACTIONS.concat(this.props.pluginHooks.componentInteractions);\n let interactions = interactionClasses.map((TheInteractionClass) => new TheInteractionClass(settings));\n this.interactionsStore[component.uid] = interactions;\n _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.a5[component.uid] = settings;\n };\n this.unregisterInteractiveComponent = (component) => {\n let listeners = this.interactionsStore[component.uid];\n if (listeners) {\n for (let listener of listeners) {\n listener.destroy();\n }\n delete this.interactionsStore[component.uid];\n }\n delete _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.a5[component.uid];\n };\n // Resizing\n // -----------------------------------------------------------------------------------------------------------------\n this.resizeRunner = new _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.D(() => {\n this.props.emitter.trigger('_resize', true); // should window resizes be considered \"forced\" ?\n this.props.emitter.trigger('windowResize', { view: this.props.viewApi });\n });\n this.handleWindowResize = (ev) => {\n let { options } = this.props;\n if (options.handleWindowResize &&\n ev.target === window // avoid jqui events\n ) {\n this.resizeRunner.request(options.windowResizeDelay);\n }\n };\n }\n /*\n renders INSIDE of an outer div\n */\n render() {\n let { props } = this;\n let { toolbarConfig, options } = props;\n let viewVGrow = false;\n let viewHeight = '';\n let viewAspectRatio;\n if (props.isHeightAuto || props.forPrint) {\n viewHeight = '';\n }\n else if (options.height != null) {\n viewVGrow = true;\n }\n else if (options.contentHeight != null) {\n viewHeight = options.contentHeight;\n }\n else {\n viewAspectRatio = Math.max(options.aspectRatio, 0.5); // prevent from getting too tall\n }\n let viewContext = this.buildViewContext(props.viewSpec, props.viewApi, props.options, props.dateProfileGenerator, props.dateEnv, props.nowManager, props.theme, props.pluginHooks, props.dispatch, props.getCurrentData, props.emitter, props.calendarApi, this.registerInteractiveComponent, this.unregisterInteractiveComponent);\n let viewLabelId = (toolbarConfig.header && toolbarConfig.header.hasTitle)\n ? this.state.viewLabelId\n : undefined;\n return ((0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.V.Provider, { value: viewContext },\n (0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.a6, { unit: \"day\" }, (nowDate) => {\n let toolbarProps = this.buildToolbarProps(props.viewSpec, props.dateProfile, props.dateProfileGenerator, props.currentDate, nowDate, props.viewTitle);\n return ((0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(preact__WEBPACK_IMPORTED_MODULE_1__.Fragment, null,\n toolbarConfig.header && ((0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(Toolbar, Object.assign({ ref: this.headerRef, extraClassName: \"fc-header-toolbar\", model: toolbarConfig.header, titleId: viewLabelId }, toolbarProps))),\n (0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(ViewHarness, { liquid: viewVGrow, height: viewHeight, aspectRatio: viewAspectRatio, labeledById: viewLabelId },\n this.renderView(props),\n this.buildAppendContent()),\n toolbarConfig.footer && ((0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(Toolbar, Object.assign({ ref: this.footerRef, extraClassName: \"fc-footer-toolbar\", model: toolbarConfig.footer, titleId: \"\" }, toolbarProps)))));\n })));\n }\n componentDidMount() {\n let { props } = this;\n this.calendarInteractions = props.pluginHooks.calendarInteractions\n .map((CalendarInteractionClass) => new CalendarInteractionClass(props));\n window.addEventListener('resize', this.handleWindowResize);\n let { propSetHandlers } = props.pluginHooks;\n for (let propName in propSetHandlers) {\n propSetHandlers[propName](props[propName], props);\n }\n }\n componentDidUpdate(prevProps) {\n let { props } = this;\n let { propSetHandlers } = props.pluginHooks;\n for (let propName in propSetHandlers) {\n if (props[propName] !== prevProps[propName]) {\n propSetHandlers[propName](props[propName], props);\n }\n }\n }\n componentWillUnmount() {\n window.removeEventListener('resize', this.handleWindowResize);\n this.resizeRunner.clear();\n for (let interaction of this.calendarInteractions) {\n interaction.destroy();\n }\n this.props.emitter.trigger('_unmount');\n }\n buildAppendContent() {\n let { props } = this;\n let children = props.pluginHooks.viewContainerAppends.map((buildAppendContent) => buildAppendContent(props));\n return (0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(preact__WEBPACK_IMPORTED_MODULE_1__.Fragment, {}, ...children);\n }\n renderView(props) {\n let { pluginHooks } = props;\n let { viewSpec } = props;\n let viewProps = {\n dateProfile: props.dateProfile,\n businessHours: props.businessHours,\n eventStore: props.renderableEventStore,\n eventUiBases: props.eventUiBases,\n dateSelection: props.dateSelection,\n eventSelection: props.eventSelection,\n eventDrag: props.eventDrag,\n eventResize: props.eventResize,\n isHeightAuto: props.isHeightAuto,\n forPrint: props.forPrint,\n };\n let transformers = this.buildViewPropTransformers(pluginHooks.viewPropsTransformers);\n for (let transformer of transformers) {\n Object.assign(viewProps, transformer.transform(viewProps, props));\n }\n let ViewComponent = viewSpec.component;\n return ((0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(ViewComponent, Object.assign({}, viewProps)));\n }\n}\nfunction buildToolbarProps(viewSpec, dateProfile, dateProfileGenerator, currentDate, now, title) {\n // don't force any date-profiles to valid date profiles (the `false`) so that we can tell if it's invalid\n let todayInfo = dateProfileGenerator.build(now, undefined, false); // TODO: need `undefined` or else INFINITE LOOP for some reason\n let prevInfo = dateProfileGenerator.buildPrev(dateProfile, currentDate, false);\n let nextInfo = dateProfileGenerator.buildNext(dateProfile, currentDate, false);\n return {\n title,\n activeButton: viewSpec.type,\n navUnit: viewSpec.singleUnit,\n isTodayEnabled: todayInfo.isValid && !(0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.G)(dateProfile.currentRange, now),\n isPrevEnabled: prevInfo.isValid,\n isNextEnabled: nextInfo.isValid,\n };\n}\n// Plugin\n// -----------------------------------------------------------------------------------------------------------------\nfunction buildViewPropTransformers(theClasses) {\n return theClasses.map((TheClass) => new TheClass());\n}\n\nclass Calendar extends _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.a7 {\n constructor(el, optionOverrides = {}) {\n super();\n this.isRendering = false;\n this.isRendered = false;\n this.currentClassNames = [];\n this.customContentRenderId = 0;\n this.handleAction = (action) => {\n // actions we know we want to render immediately\n switch (action.type) {\n case 'SET_EVENT_DRAG':\n case 'SET_EVENT_RESIZE':\n this.renderRunner.tryDrain();\n }\n };\n this.handleData = (data) => {\n this.currentData = data;\n this.renderRunner.request(data.calendarOptions.rerenderDelay);\n };\n this.handleRenderRequest = () => {\n if (this.isRendering) {\n this.isRendered = true;\n let { currentData } = this;\n (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.a8)(() => {\n (0,preact__WEBPACK_IMPORTED_MODULE_1__.render)((0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.a9, { options: currentData.calendarOptions, theme: currentData.theme, emitter: currentData.emitter }, (classNames, height, isHeightAuto, forPrint) => {\n this.setClassNames(classNames);\n this.setHeight(height);\n return ((0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.aa.Provider, { value: this.customContentRenderId },\n (0,preact__WEBPACK_IMPORTED_MODULE_1__.createElement)(CalendarContent, Object.assign({ isHeightAuto: isHeightAuto, forPrint: forPrint }, currentData))));\n }), this.el);\n });\n }\n else if (this.isRendered) {\n this.isRendered = false;\n (0,preact__WEBPACK_IMPORTED_MODULE_1__.render)(null, this.el);\n this.setClassNames([]);\n this.setHeight('');\n }\n };\n (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.ab)(el);\n this.el = el;\n this.renderRunner = new _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.D(this.handleRenderRequest);\n new CalendarDataManager({\n optionOverrides,\n calendarApi: this,\n onAction: this.handleAction,\n onData: this.handleData,\n });\n }\n render() {\n let wasRendering = this.isRendering;\n if (!wasRendering) {\n this.isRendering = true;\n }\n else {\n this.customContentRenderId += 1;\n }\n this.renderRunner.request();\n if (wasRendering) {\n this.updateSize();\n }\n }\n destroy() {\n if (this.isRendering) {\n this.isRendering = false;\n this.renderRunner.request();\n }\n }\n updateSize() {\n (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.a8)(() => {\n super.updateSize();\n });\n }\n batchRendering(func) {\n this.renderRunner.pause('batchRendering');\n func();\n this.renderRunner.resume('batchRendering');\n }\n pauseRendering() {\n this.renderRunner.pause('pauseRendering');\n }\n resumeRendering() {\n this.renderRunner.resume('pauseRendering', true);\n }\n resetOptions(optionOverrides, changedOptionNames) {\n this.currentDataManager.resetOptions(optionOverrides, changedOptionNames);\n }\n setClassNames(classNames) {\n if (!(0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.i)(classNames, this.currentClassNames)) {\n let { classList } = this.el;\n for (let className of this.currentClassNames) {\n classList.remove(className);\n }\n for (let className of classNames) {\n classList.add(className);\n }\n this.currentClassNames = classNames;\n }\n }\n setHeight(height) {\n (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.ac)(this.el, 'height', height);\n }\n}\n\nfunction formatDate(dateInput, options = {}) {\n let dateEnv = buildDateEnv(options);\n let formatter = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.x)(options);\n let dateMeta = dateEnv.createMarkerMeta(dateInput);\n if (!dateMeta) { // TODO: warning?\n return '';\n }\n return dateEnv.format(dateMeta.marker, formatter, {\n forcedTzo: dateMeta.forcedTzo,\n });\n}\nfunction formatRange(startInput, endInput, options) {\n let dateEnv = buildDateEnv(typeof options === 'object' && options ? options : {}); // pass in if non-null object\n let formatter = (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.x)(options);\n let startMeta = dateEnv.createMarkerMeta(startInput);\n let endMeta = dateEnv.createMarkerMeta(endInput);\n if (!startMeta || !endMeta) { // TODO: warning?\n return '';\n }\n return dateEnv.formatRange(startMeta.marker, endMeta.marker, formatter, {\n forcedStartTzo: startMeta.forcedTzo,\n forcedEndTzo: endMeta.forcedTzo,\n isEndExclusive: options.isEndExclusive,\n defaultSeparator: _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.e.defaultRangeSeparator,\n });\n}\n// TODO: more DRY and optimized\nfunction buildDateEnv(settings) {\n let locale = buildLocale(settings.locale || 'en', organizeRawLocales([]).map); // TODO: don't hardcode 'en' everywhere\n return new _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.Q(Object.assign(Object.assign({ timeZone: _internal_common_js__WEBPACK_IMPORTED_MODULE_0__.e.timeZone, calendarSystem: 'gregory' }, settings), { locale }));\n}\n\n// HELPERS\n/*\nif nextDayThreshold is specified, slicing is done in an all-day fashion.\nyou can get nextDayThreshold from context.nextDayThreshold\n*/\nfunction sliceEvents(props, allDay) {\n return (0,_internal_common_js__WEBPACK_IMPORTED_MODULE_0__.ad)(props.eventStore, props.eventUiBases, props.dateProfile.activeRange, allDay ? props.nextDayThreshold : null).fg;\n}\n\nconst version = '6.1.20';\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKHNzcikvLi9ub2RlX21vZHVsZXMvQGZ1bGxjYWxlbmRhci9jb3JlL2luZGV4LmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7OztBQUFvL0M7QUFDdDdDO0FBQ007QUFDN0M7O0FBRXZCOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9EQUFvRDtBQUNwRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMEJBQTBCLFdBQVc7QUFDckMsU0FBUztBQUNULEtBQUs7QUFDTCx1QkFBdUIsVUFBVSxZQUFZLDBCQUEwQjtBQUN2RSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMENBQTBDO0FBQzFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CLGtCQUFrQjtBQUN0QztBQUNBLG1DQUFtQyxPQUFPO0FBQzFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQixzREFBVTtBQUMzQix3QkFBd0I7QUFDeEIsVUFBVSxPQUFPO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLHNEQUFJO0FBQ2hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdEQUFnRDtBQUNoRDtBQUNBLDREQUE0RDtBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0M7QUFDaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEM7QUFDOUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOERBQThEO0FBQzlEO0FBQ0Esc0RBQXNEO0FBQ3RELGtEQUFrRDtBQUNsRCxvREFBb0Q7QUFDcEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCO0FBQ3pCO0FBQ0EsK0JBQStCO0FBQy9CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3QjtBQUN4QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0M7QUFDaEM7QUFDQSw0QkFBNEI7QUFDNUIsMEJBQTBCO0FBQzFCLDJCQUEyQjtBQUMzQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrREFBa0QsV0FBVztBQUM3RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOEJBQThCLHNEQUFhLHdDQUF3QyxzREFBYTtBQUNoRztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFEQUFxRDtBQUNyRDtBQUNBLDJEQUEyRDtBQUMzRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw2Q0FBNkM7QUFDN0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvREFBb0Q7QUFDcEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNERBQTREO0FBQzVEO0FBQ0Esd0RBQXdEO0FBQ3hELHNEQUFzRDtBQUN0RCx1REFBdUQ7QUFDdkQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSw0QkFBNEIsa0RBQUs7QUFDakM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0REFBNEQ7QUFDNUQ7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUI7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnREFBZ0Qsb0NBQW9DLGtEQUFrRDtBQUN0SSxpREFBaUQscUNBQXFDLG9EQUFvRDtBQUMxSTtBQUNBOztBQUVBO0FBQ0EsV0FBVyxzREFBTztBQUNsQjtBQUNBO0FBQ0E7QUFDQSxVQUFVLG1CQUFtQjtBQUM3QjtBQUNBLFVBQVUsWUFBWTtBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJEQUEyRCxrREFBYTtBQUN4RTtBQUNBO0FBQ0EsMEVBQTBFLGlCQUFpQixvQkFBb0I7QUFDL0c7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQixxREFBYSxDQUFDLGtEQUFlLCtCQUErQixxREFBYSxDQUFDLGtEQUFnQixJQUFJLHlCQUF5QixzREFBbUIsK0RBQStELGdCQUFnQixvREFBb0QscUtBQXFLO0FBQzdjOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxzREFBTztBQUNsQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0I7QUFDeEIsd0JBQXdCLHNEQUEyQjtBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0RBQXdEO0FBQ3hEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVEQUF1RDtBQUN2RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCLGtEQUFvQjtBQUNoRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDZCQUE2QixrREFBb0I7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxzREFBYztBQUM1QjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsaURBQWlELDZCQUE2Qiw0Q0FBNEM7QUFDMUg7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLHdCQUF3QjtBQUN4QjtBQUNBO0FBQ0Esb0VBQW9FO0FBQ3BFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixzREFBVztBQUMzQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0VBQW9FO0FBQ3BFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlDQUF5QztBQUN6QztBQUNBO0FBQ0EsV0FBVyxzREFBVTtBQUNyQjtBQUNBO0FBQ0EseUNBQXlDLHNEQUFVO0FBQ25EO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSx1QkFBdUI7QUFDakM7QUFDQSxrQkFBa0Isc0RBQUk7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxjQUFjLFlBQVk7QUFDMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNULEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsS0FBSztBQUNMLHlDQUF5QyxrQkFBa0IsMENBQTBDO0FBQ3JHO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw2Q0FBNkMsaUJBQWlCLDBDQUEwQyxrQkFBa0IsK0JBQStCLEdBQUc7QUFDNUo7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLHNEQUFVO0FBQ3JCO0FBQ0E7QUFDQSxtQkFBbUIsc0RBQXdCO0FBQzNDO0FBQ0Esc0JBQXNCO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCLHNEQUFnQjtBQUNyQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCO0FBQ3hCLHdCQUF3QjtBQUN4QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEVBQTRFO0FBQzVFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUIsc0RBQWtCO0FBQzNDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNENBQTRDO0FBQzVDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrREFBK0Q7QUFDL0Q7QUFDQTtBQUNBLDZCQUE2QixzREFBa0I7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMENBQTBDLHNEQUFrQjtBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakIsS0FBSztBQUNMLGFBQWE7QUFDYjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0RBQW9EO0FBQ3BEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNULEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0EsZ0JBQWdCLFVBQVU7QUFDMUI7QUFDQSxRQUFRLHNEQUFXLGlCQUFpQixzREFBeUIsd0RBQXdELFdBQVc7QUFDaEksS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0EsaUJBQWlCLGtEQUFRO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQSxnQkFBZ0IsT0FBTztBQUN2QjtBQUNBLFFBQVEsc0RBQVc7QUFDbkIsOEJBQThCLHFCQUFxQjtBQUNuRCxTQUFTO0FBQ1QsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDO0FBQ0Q7QUFDQSxVQUFVLG1CQUFtQjtBQUM3QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGdCQUFnQixrREFBUTtBQUN4QixlQUFlLGtEQUFjO0FBQzdCLGFBQWEsa0RBQWM7QUFDM0IsY0FBYyxrREFBYztBQUM1QixnQkFBZ0Isa0RBQVE7QUFDeEIsY0FBYyxrREFBUTtBQUN0Qjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQixzREFBaUI7QUFDNUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBLGtDQUFrQyxzREFBZSxpQkFBaUIsb0RBQW9EO0FBQ3RIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDO0FBQ0Q7QUFDQSwrQkFBK0Isc0RBQVc7QUFDMUMsb0JBQW9CLHNEQUFVO0FBQzlCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3QixzREFBTztBQUMvQjtBQUNBO0FBQ0E7QUFDQSx3QkFBd0Isc0RBQU87QUFDL0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQixzREFBTztBQUMzQjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBLEtBQUs7QUFDTCxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUIsc0RBQWlCO0FBQzFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3QiwyQkFBMkI7QUFDbkQ7QUFDQSw2Q0FBNkM7QUFDN0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxzRUFBc0UsRUFBRSxzREFBeUIsK0NBQStDLHVCQUF1QjtBQUN2Szs7QUFFQTtBQUNBLFVBQVUsVUFBVTtBQUNwQjtBQUNBLHFDQUFxQyxzREFBYztBQUNuRDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlDQUFpQyxrREFBYTtBQUM5QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBLHVEQUF1RCxzREFBZTtBQUN0RTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSxtQkFBbUI7QUFDN0I7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBLGlCQUFpQixrQ0FBa0M7QUFDbkQ7QUFDQSxlQUFlLHNEQUFhO0FBQzVCO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBLGFBQWE7QUFDYjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0NBQW9DO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNDQUFzQyxzREFBTztBQUM3QyxrQ0FBa0Msc0RBQU87QUFDekMsMkJBQTJCLHNEQUFPO0FBQ2xDO0FBQ0EsNEJBQTRCLHNEQUFPO0FBQ25DLDBCQUEwQixzREFBTztBQUNqQyw2QkFBNkIsc0RBQU87QUFDcEMsOEJBQThCLHNEQUFPO0FBQ3JDLHlDQUF5QyxzREFBYTtBQUN0RCw0QkFBNEIsc0RBQU87QUFDbkMsZ0NBQWdDLHNEQUFhO0FBQzdDLG9DQUFvQyxzREFBTyx1QkFBdUIsa0RBQVk7QUFDOUUsaUNBQWlDLHNEQUFPO0FBQ3hDLHlDQUF5QyxzREFBYTtBQUN0RCwwQkFBMEIsc0RBQU87QUFDakM7QUFDQSwyQkFBMkIsa0RBQU87QUFDbEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQ0FBK0M7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLHNEQUFtQjtBQUNoQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0QkFBNEI7QUFDNUIsd0JBQXdCLHNEQUFxQjtBQUM3QyxrQ0FBa0Msc0RBQXFCO0FBQ3ZEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDREQUE0RDtBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1EQUFtRDtBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrRUFBa0UsOEJBQThCO0FBQ2hHO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0EsY0FBYyx3QkFBd0I7QUFDdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLDJCQUEyQjtBQUN6QyxvR0FBb0c7QUFDcEc7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxzREFBbUI7QUFDaEM7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLHNEQUFnQjtBQUN6Qyx3RUFBd0U7QUFDeEU7QUFDQTtBQUNBO0FBQ0EsY0FBYyxxQ0FBcUMsMENBQTBDO0FBQzdGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDREQUE0RDtBQUM1RDtBQUNBLDhFQUE4RTtBQUM5RTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsZUFBZTtBQUM3QjtBQUNBO0FBQ0E7QUFDQSwyRUFBMkUsK09BQStPO0FBQzFUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscURBQXFELHNEQUFxQjtBQUMxRSx5RUFBeUUsc0RBQXFCO0FBQzlGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLDJFQUEyRTtBQUN6RjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLGtCQUFrQixFQUFFLHNEQUFlO0FBQ2pELFlBQVksa0RBQW9CO0FBQ2hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUlBQXFJLEVBQUUsa0RBQW9CLEdBQUcsa0RBQTBCLEdBQUcsa0RBQXdCO0FBQ25OO0FBQ0Esa0JBQWtCLHNEQUFlO0FBQ2pDLFlBQVksa0RBQW9CO0FBQ2hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNIQUFzSCxrREFBMEI7QUFDaEo7QUFDQSxnQkFBZ0Isa0RBQTBCO0FBQzFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlDQUF5QyxTQUFTO0FBQ2xEO0FBQ0EsY0FBYyx3QkFBd0I7QUFDdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQSxrQkFBa0Isc0RBQWU7QUFDakMsWUFBWSxrREFBb0I7QUFDaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkdBQTZHLEVBQUUsa0RBQW9CLEdBQUcsa0RBQTBCLEdBQUcsa0RBQXdCLEdBQUcsa0RBQW9CO0FBQ2xOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCLGtEQUEwQjtBQUMzQyxvQkFBb0Isa0RBQTBCO0FBQzlDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCLGtEQUEwQjtBQUMvQyx3QkFBd0Isa0RBQTBCO0FBQ2xELDRFQUE0RTtBQUM1RTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWUsa0RBQU87QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVFQUF1RSxrREFBb0I7QUFDM0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxzREFBTztBQUNsQjtBQUNBO0FBQ0EseUJBQXlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsVUFBVTtBQUNwQjtBQUNBLDJCQUEyQixzREFBYTtBQUN4QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QseUJBQXlCLHNEQUFhO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxzREFBa0I7QUFDN0I7QUFDQTtBQUNBO0FBQ0Esd0NBQXdDLFdBQVc7QUFDbkQsc0NBQXNDLFNBQVM7QUFDL0M7QUFDQTs7QUFFQSw2QkFBNkIsa0RBQWE7QUFDMUM7QUFDQTtBQUNBLGVBQWUscURBQWEsVUFBVSwrQkFBK0I7QUFDckU7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixjQUFjLFFBQVE7QUFDdEI7QUFDQTtBQUNBO0FBQ0Esa0JBQWtCLDhEQUE4RDtBQUNoRjtBQUNBO0FBQ0EsOEJBQThCLHFEQUFhLFNBQVMsa0RBQWtEO0FBQ3RHO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJDQUEyQyxXQUFXO0FBQ3REO0FBQ0E7QUFDQTtBQUNBLDhCQUE4QixxREFBYSxhQUFhLDZNQUE2TSw4QkFBOEIscURBQWEsV0FBVyxvQ0FBb0M7QUFDL1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQkFBbUIscURBQWEsVUFBVSwyQkFBMkI7QUFDckU7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsc0JBQXNCLGtEQUFhO0FBQ25DO0FBQ0EsY0FBYyx3QkFBd0I7QUFDdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLHFEQUFhLFVBQVUsaUNBQWlDO0FBQ3hFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEIsZ0JBQWdCLHFEQUFhLG1CQUFtQiwwUEFBMFA7QUFDMVM7QUFDQTs7QUFFQSwwQkFBMEIsa0RBQWE7QUFDdkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLHNEQUFNO0FBQ2xCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxlQUFlO0FBQzdCLGNBQWMsY0FBYztBQUM1QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DLHdCQUF3QjtBQUMzRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLHFEQUFhLFVBQVUsb0dBQW9HLHlCQUF5QjtBQUNwSztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCLHFDQUFxQztBQUNqRTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCLGtEQUFXO0FBQ3ZDO0FBQ0E7QUFDQTtBQUNBLGtCQUFrQixZQUFZO0FBQzlCLGtCQUFrQixVQUFVO0FBQzVCLHNCQUFzQixzREFBUTtBQUM5QjtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNDQUFzQyxzREFBYztBQUNwRDtBQUNBO0FBQ0E7QUFDQSwrQkFBK0Isa0RBQVM7QUFDeEM7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLHNEQUFnQjtBQUN2QztBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0QkFBNEIsa0RBQVc7QUFDdkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLHNEQUFRLFdBQVc7QUFDbkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQ0FBb0MsdURBQXVCO0FBQzNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsWUFBWTtBQUMxQixjQUFjLFVBQVU7QUFDeEIsa0JBQWtCLHNEQUFRO0FBQzFCO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQixrREFBUztBQUNwQztBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTs7QUFFQSw4QkFBOEIsbURBQWE7QUFDM0M7QUFDQTtBQUNBLGdDQUFnQyxzREFBTyxDQUFDLG1EQUFnQjtBQUN4RCx5Q0FBeUMsc0RBQU87QUFDaEQsaUNBQWlDLHNEQUFPO0FBQ3hDLHlCQUF5QixpREFBUztBQUNsQyx5QkFBeUIsaURBQVM7QUFDbEM7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLHVEQUFjO0FBQ3ZDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMkJBQTJCLHVEQUF3QjtBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksbURBQXdCO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQixtREFBd0I7QUFDM0M7QUFDQTtBQUNBO0FBQ0EsZ0NBQWdDLGtEQUFhO0FBQzdDLHlEQUF5RDtBQUN6RCx5REFBeUQsMEJBQTBCO0FBQ25GLFNBQVM7QUFDVDtBQUNBLGtCQUFrQixVQUFVO0FBQzVCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEIsY0FBYyx5QkFBeUI7QUFDdkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrRUFBa0U7QUFDbEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixxREFBYSxDQUFDLGtEQUFlLGFBQWEsb0JBQW9CO0FBQzlFLFlBQVkscURBQWEsQ0FBQyxtREFBUSxJQUFJLGFBQWE7QUFDbkQ7QUFDQSx3QkFBd0IscURBQWEsQ0FBQyw0Q0FBUTtBQUM5Qyw2Q0FBNkMscURBQWEsMEJBQTBCLDZHQUE2RztBQUNqTSxvQkFBb0IscURBQWEsZ0JBQWdCLCtGQUErRjtBQUNoSjtBQUNBO0FBQ0EsNkNBQTZDLHFEQUFhLDBCQUEwQixvR0FBb0c7QUFDeEwsYUFBYTtBQUNiO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEI7QUFDQTtBQUNBO0FBQ0EsY0FBYyxrQkFBa0I7QUFDaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixjQUFjLGtCQUFrQjtBQUNoQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEI7QUFDQSxlQUFlLHFEQUFhLENBQUMsNENBQVEsSUFBSTtBQUN6QztBQUNBO0FBQ0EsY0FBYyxjQUFjO0FBQzVCLGNBQWMsV0FBVztBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLHFEQUFhLGdDQUFnQztBQUM3RDtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVFQUF1RTtBQUN2RTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsc0RBQW1CO0FBQ2pFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSx1QkFBdUIsbURBQVk7QUFDbkMsd0NBQXdDO0FBQ3hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0IsY0FBYztBQUNwQyxnQkFBZ0IsdURBQVM7QUFDekIsb0JBQW9CLDhDQUFNLENBQUMscURBQWEsQ0FBQyxtREFBWSxJQUFJLDhGQUE4RjtBQUN2SjtBQUNBO0FBQ0EsZ0NBQWdDLHFEQUFhLENBQUMsbURBQVEsYUFBYSxtQ0FBbUM7QUFDdEcsNEJBQTRCLHFEQUFhLGtDQUFrQyxnREFBZ0Q7QUFDM0gscUJBQXFCO0FBQ3JCLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsOENBQU07QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRLHVEQUFpQjtBQUN6QjtBQUNBLGdDQUFnQyxrREFBYTtBQUM3QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVEsdURBQVM7QUFDakI7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLHNEQUFhO0FBQzFCLGtCQUFrQixZQUFZO0FBQzlCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUSx1REFBYztBQUN0QjtBQUNBOztBQUVBLDJDQUEyQztBQUMzQztBQUNBLG9CQUFvQixzREFBZTtBQUNuQztBQUNBLHFCQUFxQjtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0Esb0ZBQW9GLEdBQUc7QUFDdkYsb0JBQW9CLHNEQUFlO0FBQ25DO0FBQ0E7QUFDQSxrQ0FBa0M7QUFDbEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMEJBQTBCLGtEQUFvQjtBQUM5QyxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsbUZBQW1GO0FBQ25GLGVBQWUsa0RBQU8sK0JBQStCLFVBQVUsa0RBQW9CLHNDQUFzQyxlQUFlLFFBQVE7QUFDaEo7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyx1REFBZTtBQUMxQjs7QUFFQTs7QUFFK0ciLCJzb3VyY2VzIjpbIi9ob21lL3NpbHZpby9EZXZlbG9wL0NJUlVYLUFQUC9ub2RlX21vZHVsZXMvQGZ1bGxjYWxlbmRhci9jb3JlL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IG0gYXMgbWVyZ2VQcm9wcywgZyBhcyBndWlkLCBpIGFzIGlzQXJyYXlzRXF1YWwsIFQgYXMgVGhlbWUsIGEgYXMgbWFwSGFzaCwgQiBhcyBCYXNlQ29tcG9uZW50LCBWIGFzIFZpZXdDb250ZXh0VHlwZSwgQyBhcyBDb250ZW50Q29udGFpbmVyLCBiIGFzIGJ1aWxkVmlld0NsYXNzTmFtZXMsIGMgYXMgZ3JlYXRlc3REdXJhdGlvbkRlbm9taW5hdG9yLCBkIGFzIGNyZWF0ZUR1cmF0aW9uLCBlIGFzIEJBU0VfT1BUSU9OX0RFRkFVTFRTLCBmIGFzIGFycmF5VG9IYXNoLCBoIGFzIGZpbHRlckhhc2gsIGogYXMgYnVpbGRFdmVudFNvdXJjZVJlZmluZXJzLCBwIGFzIHBhcnNlRXZlbnRTb3VyY2UsIGsgYXMgZm9ybWF0V2l0aE9yZGluYWxzLCB1IGFzIHVucHJvbWlzaWZ5LCBsIGFzIGJ1aWxkUmFuZ2VBcGlXaXRoVGltZVpvbmUsIG4gYXMgaWRlbnRpdHksIHIgYXMgcmVxdWVzdEpzb24sIHMgYXMgc3VidHJhY3REdXJhdGlvbnMsIG8gYXMgaW50ZXJzZWN0UmFuZ2VzLCBxIGFzIHN0YXJ0T2ZEYXksIHQgYXMgYWRkRGF5cywgdiBhcyBoYXNoVmFsdWVzVG9BcnJheSwgdyBhcyBidWlsZEV2ZW50QXBpcywgRCBhcyBEZWxheWVkUnVubmVyLCB4IGFzIGNyZWF0ZUZvcm1hdHRlciwgeSBhcyBkaWZmV2hvbGVEYXlzLCB6IGFzIG1lbW9pemUsIEEgYXMgbWVtb2l6ZU9iakFyZywgRSBhcyBpc1Byb3BzRXF1YWwsIEYgYXMgRW1pdHRlciwgRyBhcyByYW5nZUNvbnRhaW5zTWFya2VyLCBIIGFzIGNyZWF0ZUVtcHR5RXZlbnRTdG9yZSwgSSBhcyByZWR1Y2VFdmVudFN0b3JlLCBKIGFzIHJlem9uZUV2ZW50U3RvcmVEYXRlcywgSyBhcyBtZXJnZVJhd09wdGlvbnMsIEwgYXMgQkFTRV9PUFRJT05fUkVGSU5FUlMsIE0gYXMgQ0FMRU5EQVJfTElTVEVORVJfUkVGSU5FUlMsIE4gYXMgQ0FMRU5EQVJfT1BUSU9OX1JFRklORVJTLCBPIGFzIENPTVBMRVhfT1BUSU9OX0NPTVBBUkFUT1JTLCBQIGFzIFZJRVdfT1BUSU9OX1JFRklORVJTLCBRIGFzIERhdGVFbnYsIFIgYXMgRGF0ZVByb2ZpbGVHZW5lcmF0b3IsIFMgYXMgY3JlYXRlRXZlbnRVaSwgVSBhcyBwYXJzZUJ1c2luZXNzSG91cnMsIFcgYXMgc2V0UmVmLCBYIGFzIEludGVyYWN0aW9uLCBZIGFzIGdldEVsU2VnLCBaIGFzIGVsZW1lbnRDbG9zZXN0LCBfIGFzIEV2ZW50SW1wbCwgJCBhcyBsaXN0ZW5CeVNlbGVjdG9yLCBhMCBhcyBsaXN0ZW5Ub0hvdmVyQnlTZWxlY3RvciwgYTEgYXMgUHVyZUNvbXBvbmVudCwgYTIgYXMgYnVpbGRWaWV3Q29udGV4dCwgYTMgYXMgZ2V0VW5pcXVlRG9tSWQsIGE0IGFzIHBhcnNlSW50ZXJhY3Rpb25TZXR0aW5ncywgYTUgYXMgaW50ZXJhY3Rpb25TZXR0aW5nc1N0b3JlLCBhNiBhcyBOb3dUaW1lciwgYTcgYXMgQ2FsZW5kYXJJbXBsLCBhOCBhcyBmbHVzaFN5bmMsIGE5IGFzIENhbGVuZGFyUm9vdCwgYWEgYXMgUmVuZGVySWQsIGFiIGFzIGVuc3VyZUVsSGFzU3R5bGVzLCBhYyBhcyBhcHBseVN0eWxlUHJvcCwgYWQgYXMgc2xpY2VFdmVudFN0b3JlIH0gZnJvbSAnLi9pbnRlcm5hbC1jb21tb24uanMnO1xuZXhwb3J0IHsgYWUgYXMgSnNvblJlcXVlc3RFcnJvciB9IGZyb20gJy4vaW50ZXJuYWwtY29tbW9uLmpzJztcbmltcG9ydCB7IGNyZWF0ZUVsZW1lbnQsIGNyZWF0ZVJlZiwgRnJhZ21lbnQsIHJlbmRlciB9IGZyb20gJ3ByZWFjdCc7XG5pbXBvcnQgJ3ByZWFjdC9jb21wYXQnO1xuXG5jb25zdCBnbG9iYWxMb2NhbGVzID0gW107XG5cbmNvbnN0IE1JTklNQUxfUkFXX0VOX0xPQ0FMRSA9IHtcbiAgICBjb2RlOiAnZW4nLFxuICAgIHdlZWs6IHtcbiAgICAgICAgZG93OiAwLFxuICAgICAgICBkb3k6IDQsIC8vIDQgZGF5cyBuZWVkIHRvIGJlIHdpdGhpbiB0aGUgeWVhciB0byBiZSBjb25zaWRlcmVkIHRoZSBmaXJzdCB3ZWVrXG4gICAgfSxcbiAgICBkaXJlY3Rpb246ICdsdHInLFxuICAgIGJ1dHRvblRleHQ6IHtcbiAgICAgICAgcHJldjogJ3ByZXYnLFxuICAgICAgICBuZXh0OiAnbmV4dCcsXG4gICAgICAgIHByZXZZZWFyOiAncHJldiB5ZWFyJyxcbiAgICAgICAgbmV4dFllYXI6ICduZXh0IHllYXInLFxuICAgICAgICB5ZWFyOiAneWVhcicsXG4gICAgICAgIHRvZGF5OiAndG9kYXknLFxuICAgICAgICBtb250aDogJ21vbnRoJyxcbiAgICAgICAgd2VlazogJ3dlZWsnLFxuICAgICAgICBkYXk6ICdkYXknLFxuICAgICAgICBsaXN0OiAnbGlzdCcsXG4gICAgfSxcbiAgICB3ZWVrVGV4dDogJ1cnLFxuICAgIHdlZWtUZXh0TG9uZzogJ1dlZWsnLFxuICAgIGNsb3NlSGludDogJ0Nsb3NlJyxcbiAgICB0aW1lSGludDogJ1RpbWUnLFxuICAgIGV2ZW50SGludDogJ0V2ZW50JyxcbiAgICBhbGxEYXlUZXh0OiAnYWxsLWRheScsXG4gICAgbW9yZUxpbmtUZXh0OiAnbW9yZScsXG4gICAgbm9FdmVudHNUZXh0OiAnTm8gZXZlbnRzIHRvIGRpc3BsYXknLFxufTtcbmNvbnN0IFJBV19FTl9MT0NBTEUgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIE1JTklNQUxfUkFXX0VOX0xPQ0FMRSksIHsgXG4gICAgLy8gSW5jbHVkZXMgdGhpbmdzIHdlIGRvbid0IHdhbnQgb3RoZXIgbG9jYWxlcyB0byBpbmhlcml0LFxuICAgIC8vIHRoaW5ncyB0aGF0IGRlcml2ZSBmcm9tIG90aGVyIHRyYW5zbGF0YWJsZSBzdHJpbmdzLlxuICAgIGJ1dHRvbkhpbnRzOiB7XG4gICAgICAgIHByZXY6ICdQcmV2aW91cyAkMCcsXG4gICAgICAgIG5leHQ6ICdOZXh0ICQwJyxcbiAgICAgICAgdG9kYXkoYnV0dG9uVGV4dCwgdW5pdCkge1xuICAgICAgICAgICAgcmV0dXJuICh1bml0ID09PSAnZGF5JylcbiAgICAgICAgICAgICAgICA/ICdUb2RheSdcbiAgICAgICAgICAgICAgICA6IGBUaGlzICR7YnV0dG9uVGV4dH1gO1xuICAgICAgICB9LFxuICAgIH0sIHZpZXdIaW50OiAnJDAgdmlldycsIG5hdkxpbmtIaW50OiAnR28gdG8gJDAnLCBtb3JlTGlua0hpbnQoZXZlbnRDbnQpIHtcbiAgICAgICAgcmV0dXJuIGBTaG93ICR7ZXZlbnRDbnR9IG1vcmUgZXZlbnQke2V2ZW50Q250ID09PSAxID8gJycgOiAncyd9YDtcbiAgICB9IH0pO1xuZnVuY3Rpb24gb3JnYW5pemVSYXdMb2NhbGVzKGV4cGxpY2l0UmF3TG9jYWxlcykge1xuICAgIGxldCBkZWZhdWx0Q29kZSA9IGV4cGxpY2l0UmF3TG9jYWxlcy5sZW5ndGggPiAwID8gZXhwbGljaXRSYXdMb2NhbGVzWzBdLmNvZGUgOiAnZW4nO1xuICAgIGxldCBhbGxSYXdMb2NhbGVzID0gZ2xvYmFsTG9jYWxlcy5jb25jYXQoZXhwbGljaXRSYXdMb2NhbGVzKTtcbiAgICBsZXQgcmF3TG9jYWxlTWFwID0ge1xuICAgICAgICBlbjogUkFXX0VOX0xPQ0FMRSxcbiAgICB9O1xuICAgIGZvciAobGV0IHJhd0xvY2FsZSBvZiBhbGxSYXdMb2NhbGVzKSB7XG4gICAgICAgIHJhd0xvY2FsZU1hcFtyYXdMb2NhbGUuY29kZV0gPSByYXdMb2NhbGU7XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICAgIG1hcDogcmF3TG9jYWxlTWFwLFxuICAgICAgICBkZWZhdWx0Q29kZSxcbiAgICB9O1xufVxuZnVuY3Rpb24gYnVpbGRMb2NhbGUoaW5wdXRTaW5ndWxhciwgYXZhaWxhYmxlKSB7XG4gICAgaWYgKHR5cGVvZiBpbnB1dFNpbmd1bGFyID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShpbnB1dFNpbmd1bGFyKSkge1xuICAgICAgICByZXR1cm4gcGFyc2VMb2NhbGUoaW5wdXRTaW5ndWxhci5jb2RlLCBbaW5wdXRTaW5ndWxhci5jb2RlXSwgaW5wdXRTaW5ndWxhcik7XG4gICAgfVxuICAgIHJldHVybiBxdWVyeUxvY2FsZShpbnB1dFNpbmd1bGFyLCBhdmFpbGFibGUpO1xufVxuZnVuY3Rpb24gcXVlcnlMb2NhbGUoY29kZUFyZywgYXZhaWxhYmxlKSB7XG4gICAgbGV0IGNvZGVzID0gW10uY29uY2F0KGNvZGVBcmcgfHwgW10pOyAvLyB3aWxsIGNvbnZlcnQgdG8gYXJyYXlcbiAgICBsZXQgcmF3ID0gcXVlcnlSYXdMb2NhbGUoY29kZXMsIGF2YWlsYWJsZSkgfHwgUkFXX0VOX0xPQ0FMRTtcbiAgICByZXR1cm4gcGFyc2VMb2NhbGUoY29kZUFyZywgY29kZXMsIHJhdyk7XG59XG5mdW5jdGlvbiBxdWVyeVJhd0xvY2FsZShjb2RlcywgYXZhaWxhYmxlKSB7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjb2Rlcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICBsZXQgcGFydHMgPSBjb2Rlc1tpXS50b0xvY2FsZUxvd2VyQ2FzZSgpLnNwbGl0KCctJyk7XG4gICAgICAgIGZvciAobGV0IGogPSBwYXJ0cy5sZW5ndGg7IGogPiAwOyBqIC09IDEpIHtcbiAgICAgICAgICAgIGxldCBzaW1wbGVJZCA9IHBhcnRzLnNsaWNlKDAsIGopLmpvaW4oJy0nKTtcbiAgICAgICAgICAgIGlmIChhdmFpbGFibGVbc2ltcGxlSWRdKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGF2YWlsYWJsZVtzaW1wbGVJZF07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG59XG5mdW5jdGlvbiBwYXJzZUxvY2FsZShjb2RlQXJnLCBjb2RlcywgcmF3KSB7XG4gICAgbGV0IG1lcmdlZCA9IG1lcmdlUHJvcHMoW01JTklNQUxfUkFXX0VOX0xPQ0FMRSwgcmF3XSwgWydidXR0b25UZXh0J10pO1xuICAgIGRlbGV0ZSBtZXJnZWQuY29kZTsgLy8gZG9uJ3Qgd2FudCB0aGlzIHBhcnQgb2YgdGhlIG9wdGlvbnNcbiAgICBsZXQgeyB3ZWVrIH0gPSBtZXJnZWQ7XG4gICAgZGVsZXRlIG1lcmdlZC53ZWVrO1xuICAgIHJldHVybiB7XG4gICAgICAgIGNvZGVBcmcsXG4gICAgICAgIGNvZGVzLFxuICAgICAgICB3ZWVrLFxuICAgICAgICBzaW1wbGVOdW1iZXJGb3JtYXQ6IG5ldyBJbnRsLk51bWJlckZvcm1hdChjb2RlQXJnKSxcbiAgICAgICAgb3B0aW9uczogbWVyZ2VkLFxuICAgIH07XG59XG5cbi8vIFRPRE86IGVhc2llciB3YXkgdG8gYWRkIG5ldyBob29rcz8gbmVlZCB0byB1cGRhdGUgYSBtaWxsaW9uIHRoaW5nc1xuZnVuY3Rpb24gY3JlYXRlUGx1Z2luKGlucHV0KSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgaWQ6IGd1aWQoKSxcbiAgICAgICAgbmFtZTogaW5wdXQubmFtZSxcbiAgICAgICAgcHJlbWl1bVJlbGVhc2VEYXRlOiBpbnB1dC5wcmVtaXVtUmVsZWFzZURhdGUgPyBuZXcgRGF0ZShpbnB1dC5wcmVtaXVtUmVsZWFzZURhdGUpIDogdW5kZWZpbmVkLFxuICAgICAgICBkZXBzOiBpbnB1dC5kZXBzIHx8IFtdLFxuICAgICAgICByZWR1Y2VyczogaW5wdXQucmVkdWNlcnMgfHwgW10sXG4gICAgICAgIGlzTG9hZGluZ0Z1bmNzOiBpbnB1dC5pc0xvYWRpbmdGdW5jcyB8fCBbXSxcbiAgICAgICAgY29udGV4dEluaXQ6IFtdLmNvbmNhdChpbnB1dC5jb250ZXh0SW5pdCB8fCBbXSksXG4gICAgICAgIGV2ZW50UmVmaW5lcnM6IGlucHV0LmV2ZW50UmVmaW5lcnMgfHwge30sXG4gICAgICAgIGV2ZW50RGVmTWVtYmVyQWRkZXJzOiBpbnB1dC5ldmVudERlZk1lbWJlckFkZGVycyB8fCBbXSxcbiAgICAgICAgZXZlbnRTb3VyY2VSZWZpbmVyczogaW5wdXQuZXZlbnRTb3VyY2VSZWZpbmVycyB8fCB7fSxcbiAgICAgICAgaXNEcmFnZ2FibGVUcmFuc2Zvcm1lcnM6IGlucHV0LmlzRHJhZ2dhYmxlVHJhbnNmb3JtZXJzIHx8IFtdLFxuICAgICAgICBldmVudERyYWdNdXRhdGlvbk1hc3NhZ2VyczogaW5wdXQuZXZlbnREcmFnTXV0YXRpb25NYXNzYWdlcnMgfHwgW10sXG4gICAgICAgIGV2ZW50RGVmTXV0YXRpb25BcHBsaWVyczogaW5wdXQuZXZlbnREZWZNdXRhdGlvbkFwcGxpZXJzIHx8IFtdLFxuICAgICAgICBkYXRlU2VsZWN0aW9uVHJhbnNmb3JtZXJzOiBpbnB1dC5kYXRlU2VsZWN0aW9uVHJhbnNmb3JtZXJzIHx8IFtdLFxuICAgICAgICBkYXRlUG9pbnRUcmFuc2Zvcm1zOiBpbnB1dC5kYXRlUG9pbnRUcmFuc2Zvcm1zIHx8IFtdLFxuICAgICAgICBkYXRlU3BhblRyYW5zZm9ybXM6IGlucHV0LmRhdGVTcGFuVHJhbnNmb3JtcyB8fCBbXSxcbiAgICAgICAgdmlld3M6IGlucHV0LnZpZXdzIHx8IHt9LFxuICAgICAgICB2aWV3UHJvcHNUcmFuc2Zvcm1lcnM6IGlucHV0LnZpZXdQcm9wc1RyYW5zZm9ybWVycyB8fCBbXSxcbiAgICAgICAgaXNQcm9wc1ZhbGlkOiBpbnB1dC5pc1Byb3BzVmFsaWQgfHwgbnVsbCxcbiAgICAgICAgZXh0ZXJuYWxEZWZUcmFuc2Zvcm1zOiBpbnB1dC5leHRlcm5hbERlZlRyYW5zZm9ybXMgfHwgW10sXG4gICAgICAgIHZpZXdDb250YWluZXJBcHBlbmRzOiBpbnB1dC52aWV3Q29udGFpbmVyQXBwZW5kcyB8fCBbXSxcbiAgICAgICAgZXZlbnREcm9wVHJhbnNmb3JtZXJzOiBpbnB1dC5ldmVudERyb3BUcmFuc2Zvcm1lcnMgfHwgW10sXG4gICAgICAgIGNvbXBvbmVudEludGVyYWN0aW9uczogaW5wdXQuY29tcG9uZW50SW50ZXJhY3Rpb25zIHx8IFtdLFxuICAgICAgICBjYWxlbmRhckludGVyYWN0aW9uczogaW5wdXQuY2FsZW5kYXJJbnRlcmFjdGlvbnMgfHwgW10sXG4gICAgICAgIHRoZW1lQ2xhc3NlczogaW5wdXQudGhlbWVDbGFzc2VzIHx8IHt9LFxuICAgICAgICBldmVudFNvdXJjZURlZnM6IGlucHV0LmV2ZW50U291cmNlRGVmcyB8fCBbXSxcbiAgICAgICAgY21kRm9ybWF0dGVyOiBpbnB1dC5jbWRGb3JtYXR0ZXIsXG4gICAgICAgIHJlY3VycmluZ1R5cGVzOiBpbnB1dC5yZWN1cnJpbmdUeXBlcyB8fCBbXSxcbiAgICAgICAgbmFtZWRUaW1lWm9uZWRJbXBsOiBpbnB1dC5uYW1lZFRpbWVab25lZEltcGwsXG4gICAgICAgIGluaXRpYWxWaWV3OiBpbnB1dC5pbml0aWFsVmlldyB8fCAnJyxcbiAgICAgICAgZWxlbWVudERyYWdnaW5nSW1wbDogaW5wdXQuZWxlbWVudERyYWdnaW5nSW1wbCxcbiAgICAgICAgb3B0aW9uQ2hhbmdlSGFuZGxlcnM6IGlucHV0Lm9wdGlvbkNoYW5nZUhhbmRsZXJzIHx8IHt9LFxuICAgICAgICBzY3JvbGxHcmlkSW1wbDogaW5wdXQuc2Nyb2xsR3JpZEltcGwgfHwgbnVsbCxcbiAgICAgICAgbGlzdGVuZXJSZWZpbmVyczogaW5wdXQubGlzdGVuZXJSZWZpbmVycyB8fCB7fSxcbiAgICAgICAgb3B0aW9uUmVmaW5lcnM6IGlucHV0Lm9wdGlvblJlZmluZXJzIHx8IHt9LFxuICAgICAgICBwcm9wU2V0SGFuZGxlcnM6IGlucHV0LnByb3BTZXRIYW5kbGVycyB8fCB7fSxcbiAgICB9O1xufVxuZnVuY3Rpb24gYnVpbGRQbHVnaW5Ib29rcyhwbHVnaW5EZWZzLCBnbG9iYWxEZWZzKSB7XG4gICAgbGV0IGN1cnJlbnRQbHVnaW5JZHMgPSB7fTtcbiAgICBsZXQgaG9va3MgPSB7XG4gICAgICAgIHByZW1pdW1SZWxlYXNlRGF0ZTogdW5kZWZpbmVkLFxuICAgICAgICByZWR1Y2VyczogW10sXG4gICAgICAgIGlzTG9hZGluZ0Z1bmNzOiBbXSxcbiAgICAgICAgY29udGV4dEluaXQ6IFtdLFxuICAgICAgICBldmVudFJlZmluZXJzOiB7fSxcbiAgICAgICAgZXZlbnREZWZNZW1iZXJBZGRlcnM6IFtdLFxuICAgICAgICBldmVudFNvdXJjZVJlZmluZXJzOiB7fSxcbiAgICAgICAgaXNEcmFnZ2FibGVUcmFuc2Zvcm1lcnM6IFtdLFxuICAgICAgICBldmVudERyYWdNdXRhdGlvbk1hc3NhZ2VyczogW10sXG4gICAgICAgIGV2ZW50RGVmTXV0YXRpb25BcHBsaWVyczogW10sXG4gICAgICAgIGRhdGVTZWxlY3Rpb25UcmFuc2Zvcm1lcnM6IFtdLFxuICAgICAgICBkYXRlUG9pbnRUcmFuc2Zvcm1zOiBbXSxcbiAgICAgICAgZGF0ZVNwYW5UcmFuc2Zvcm1zOiBbXSxcbiAgICAgICAgdmlld3M6IHt9LFxuICAgICAgICB2aWV3UHJvcHNUcmFuc2Zvcm1lcnM6IFtdLFxuICAgICAgICBpc1Byb3BzVmFsaWQ6IG51bGwsXG4gICAgICAgIGV4dGVybmFsRGVmVHJhbnNmb3JtczogW10sXG4gICAgICAgIHZpZXdDb250YWluZXJBcHBlbmRzOiBbXSxcbiAgICAgICAgZXZlbnREcm9wVHJhbnNmb3JtZXJzOiBbXSxcbiAgICAgICAgY29tcG9uZW50SW50ZXJhY3Rpb25zOiBbXSxcbiAgICAgICAgY2FsZW5kYXJJbnRlcmFjdGlvbnM6IFtdLFxuICAgICAgICB0aGVtZUNsYXNzZXM6IHt9LFxuICAgICAgICBldmVudFNvdXJjZURlZnM6IFtdLFxuICAgICAgICBjbWRGb3JtYXR0ZXI6IG51bGwsXG4gICAgICAgIHJlY3VycmluZ1R5cGVzOiBbXSxcbiAgICAgICAgbmFtZWRUaW1lWm9uZWRJbXBsOiBudWxsLFxuICAgICAgICBpbml0aWFsVmlldzogJycsXG4gICAgICAgIGVsZW1lbnREcmFnZ2luZ0ltcGw6IG51bGwsXG4gICAgICAgIG9wdGlvbkNoYW5nZUhhbmRsZXJzOiB7fSxcbiAgICAgICAgc2Nyb2xsR3JpZEltcGw6IG51bGwsXG4gICAgICAgIGxpc3RlbmVyUmVmaW5lcnM6IHt9LFxuICAgICAgICBvcHRpb25SZWZpbmVyczoge30sXG4gICAgICAgIHByb3BTZXRIYW5kbGVyczoge30sXG4gICAgfTtcbiAgICBmdW5jdGlvbiBhZGREZWZzKGRlZnMpIHtcbiAgICAgICAgZm9yIChsZXQgZGVmIG9mIGRlZnMpIHtcbiAgICAgICAgICAgIGNvbnN0IHBsdWdpbk5hbWUgPSBkZWYubmFtZTtcbiAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRJZCA9IGN1cnJlbnRQbHVnaW5JZHNbcGx1Z2luTmFtZV07XG4gICAgICAgICAgICBpZiAoY3VycmVudElkID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBjdXJyZW50UGx1Z2luSWRzW3BsdWdpbk5hbWVdID0gZGVmLmlkO1xuICAgICAgICAgICAgICAgIGFkZERlZnMoZGVmLmRlcHMpO1xuICAgICAgICAgICAgICAgIGhvb2tzID0gY29tYmluZUhvb2tzKGhvb2tzLCBkZWYpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoY3VycmVudElkICE9PSBkZWYuaWQpIHtcbiAgICAgICAgICAgICAgICAvLyBkaWZmZXJlbnQgSUQgdGhhbiB0aGUgb25lIGFscmVhZHkgYWRkZWRcbiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oYER1cGxpY2F0ZSBwbHVnaW4gJyR7cGx1Z2luTmFtZX0nYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgaWYgKHBsdWdpbkRlZnMpIHtcbiAgICAgICAgYWRkRGVmcyhwbHVnaW5EZWZzKTtcbiAgICB9XG4gICAgYWRkRGVmcyhnbG9iYWxEZWZzKTtcbiAgICByZXR1cm4gaG9va3M7XG59XG5mdW5jdGlvbiBidWlsZEJ1aWxkUGx1Z2luSG9va3MoKSB7XG4gICAgbGV0IGN1cnJlbnRPdmVycmlkZURlZnMgPSBbXTtcbiAgICBsZXQgY3VycmVudEdsb2JhbERlZnMgPSBbXTtcbiAgICBsZXQgY3VycmVudEhvb2tzO1xuICAgIHJldHVybiAob3ZlcnJpZGVEZWZzLCBnbG9iYWxEZWZzKSA9PiB7XG4gICAgICAgIGlmICghY3VycmVudEhvb2tzIHx8ICFpc0FycmF5c0VxdWFsKG92ZXJyaWRlRGVmcywgY3VycmVudE92ZXJyaWRlRGVmcykgfHwgIWlzQXJyYXlzRXF1YWwoZ2xvYmFsRGVmcywgY3VycmVudEdsb2JhbERlZnMpKSB7XG4gICAgICAgICAgICBjdXJyZW50SG9va3MgPSBidWlsZFBsdWdpbkhvb2tzKG92ZXJyaWRlRGVmcywgZ2xvYmFsRGVmcyk7XG4gICAgICAgIH1cbiAgICAgICAgY3VycmVudE92ZXJyaWRlRGVmcyA9IG92ZXJyaWRlRGVmcztcbiAgICAgICAgY3VycmVudEdsb2JhbERlZnMgPSBnbG9iYWxEZWZzO1xuICAgICAgICByZXR1cm4gY3VycmVudEhvb2tzO1xuICAgIH07XG59XG5mdW5jdGlvbiBjb21iaW5lSG9va3MoaG9va3MwLCBob29rczEpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBwcmVtaXVtUmVsZWFzZURhdGU6IGNvbXBhcmVPcHRpb25hbERhdGVzKGhvb2tzMC5wcmVtaXVtUmVsZWFzZURhdGUsIGhvb2tzMS5wcmVtaXVtUmVsZWFzZURhdGUpLFxuICAgICAgICByZWR1Y2VyczogaG9va3MwLnJlZHVjZXJzLmNvbmNhdChob29rczEucmVkdWNlcnMpLFxuICAgICAgICBpc0xvYWRpbmdGdW5jczogaG9va3MwLmlzTG9hZGluZ0Z1bmNzLmNvbmNhdChob29rczEuaXNMb2FkaW5nRnVuY3MpLFxuICAgICAgICBjb250ZXh0SW5pdDogaG9va3MwLmNvbnRleHRJbml0LmNvbmNhdChob29rczEuY29udGV4dEluaXQpLFxuICAgICAgICBldmVudFJlZmluZXJzOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGhvb2tzMC5ldmVudFJlZmluZXJzKSwgaG9va3MxLmV2ZW50UmVmaW5lcnMpLFxuICAgICAgICBldmVudERlZk1lbWJlckFkZGVyczogaG9va3MwLmV2ZW50RGVmTWVtYmVyQWRkZXJzLmNvbmNhdChob29rczEuZXZlbnREZWZNZW1iZXJBZGRlcnMpLFxuICAgICAgICBldmVudFNvdXJjZVJlZmluZXJzOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGhvb2tzMC5ldmVudFNvdXJjZVJlZmluZXJzKSwgaG9va3MxLmV2ZW50U291cmNlUmVmaW5lcnMpLFxuICAgICAgICBpc0RyYWdnYWJsZVRyYW5zZm9ybWVyczogaG9va3MwLmlzRHJhZ2dhYmxlVHJhbnNmb3JtZXJzLmNvbmNhdChob29rczEuaXNEcmFnZ2FibGVUcmFuc2Zvcm1lcnMpLFxuICAgICAgICBldmVudERyYWdNdXRhdGlvbk1hc3NhZ2VyczogaG9va3MwLmV2ZW50RHJhZ011dGF0aW9uTWFzc2FnZXJzLmNvbmNhdChob29rczEuZXZlbnREcmFnTXV0YXRpb25NYXNzYWdlcnMpLFxuICAgICAgICBldmVudERlZk11dGF0aW9uQXBwbGllcnM6IGhvb2tzMC5ldmVudERlZk11dGF0aW9uQXBwbGllcnMuY29uY2F0KGhvb2tzMS5ldmVudERlZk11dGF0aW9uQXBwbGllcnMpLFxuICAgICAgICBkYXRlU2VsZWN0aW9uVHJhbnNmb3JtZXJzOiBob29rczAuZGF0ZVNlbGVjdGlvblRyYW5zZm9ybWVycy5jb25jYXQoaG9va3MxLmRhdGVTZWxlY3Rpb25UcmFuc2Zvcm1lcnMpLFxuICAgICAgICBkYXRlUG9pbnRUcmFuc2Zvcm1zOiBob29rczAuZGF0ZVBvaW50VHJhbnNmb3Jtcy5jb25jYXQoaG9va3MxLmRhdGVQb2ludFRyYW5zZm9ybXMpLFxuICAgICAgICBkYXRlU3BhblRyYW5zZm9ybXM6IGhvb2tzMC5kYXRlU3BhblRyYW5zZm9ybXMuY29uY2F0KGhvb2tzMS5kYXRlU3BhblRyYW5zZm9ybXMpLFxuICAgICAgICB2aWV3czogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBob29rczAudmlld3MpLCBob29rczEudmlld3MpLFxuICAgICAgICB2aWV3UHJvcHNUcmFuc2Zvcm1lcnM6IGhvb2tzMC52aWV3UHJvcHNUcmFuc2Zvcm1lcnMuY29uY2F0KGhvb2tzMS52aWV3UHJvcHNUcmFuc2Zvcm1lcnMpLFxuICAgICAgICBpc1Byb3BzVmFsaWQ6IGhvb2tzMS5pc1Byb3BzVmFsaWQgfHwgaG9va3MwLmlzUHJvcHNWYWxpZCxcbiAgICAgICAgZXh0ZXJuYWxEZWZUcmFuc2Zvcm1zOiBob29rczAuZXh0ZXJuYWxEZWZUcmFuc2Zvcm1zLmNvbmNhdChob29rczEuZXh0ZXJuYWxEZWZUcmFuc2Zvcm1zKSxcbiAgICAgICAgdmlld0NvbnRhaW5lckFwcGVuZHM6IGhvb2tzMC52aWV3Q29udGFpbmVyQXBwZW5kcy5jb25jYXQoaG9va3MxLnZpZXdDb250YWluZXJBcHBlbmRzKSxcbiAgICAgICAgZXZlbnREcm9wVHJhbnNmb3JtZXJzOiBob29rczAuZXZlbnREcm9wVHJhbnNmb3JtZXJzLmNvbmNhdChob29rczEuZXZlbnREcm9wVHJhbnNmb3JtZXJzKSxcbiAgICAgICAgY2FsZW5kYXJJbnRlcmFjdGlvbnM6IGhvb2tzMC5jYWxlbmRhckludGVyYWN0aW9ucy5jb25jYXQoaG9va3MxLmNhbGVuZGFySW50ZXJhY3Rpb25zKSxcbiAgICAgICAgY29tcG9uZW50SW50ZXJhY3Rpb25zOiBob29rczAuY29tcG9uZW50SW50ZXJhY3Rpb25zLmNvbmNhdChob29rczEuY29tcG9uZW50SW50ZXJhY3Rpb25zKSxcbiAgICAgICAgdGhlbWVDbGFzc2VzOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGhvb2tzMC50aGVtZUNsYXNzZXMpLCBob29rczEudGhlbWVDbGFzc2VzKSxcbiAgICAgICAgZXZlbnRTb3VyY2VEZWZzOiBob29rczAuZXZlbnRTb3VyY2VEZWZzLmNvbmNhdChob29rczEuZXZlbnRTb3VyY2VEZWZzKSxcbiAgICAgICAgY21kRm9ybWF0dGVyOiBob29rczEuY21kRm9ybWF0dGVyIHx8IGhvb2tzMC5jbWRGb3JtYXR0ZXIsXG4gICAgICAgIHJlY3VycmluZ1R5cGVzOiBob29rczAucmVjdXJyaW5nVHlwZXMuY29uY2F0KGhvb2tzMS5yZWN1cnJpbmdUeXBlcyksXG4gICAgICAgIG5hbWVkVGltZVpvbmVkSW1wbDogaG9va3MxLm5hbWVkVGltZVpvbmVkSW1wbCB8fCBob29rczAubmFtZWRUaW1lWm9uZWRJbXBsLFxuICAgICAgICBpbml0aWFsVmlldzogaG9va3MwLmluaXRpYWxWaWV3IHx8IGhvb2tzMS5pbml0aWFsVmlldyxcbiAgICAgICAgZWxlbWVudERyYWdnaW5nSW1wbDogaG9va3MwLmVsZW1lbnREcmFnZ2luZ0ltcGwgfHwgaG9va3MxLmVsZW1lbnREcmFnZ2luZ0ltcGwsXG4gICAgICAgIG9wdGlvbkNoYW5nZUhhbmRsZXJzOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGhvb2tzMC5vcHRpb25DaGFuZ2VIYW5kbGVycyksIGhvb2tzMS5vcHRpb25DaGFuZ2VIYW5kbGVycyksXG4gICAgICAgIHNjcm9sbEdyaWRJbXBsOiBob29rczEuc2Nyb2xsR3JpZEltcGwgfHwgaG9va3MwLnNjcm9sbEdyaWRJbXBsLFxuICAgICAgICBsaXN0ZW5lclJlZmluZXJzOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGhvb2tzMC5saXN0ZW5lclJlZmluZXJzKSwgaG9va3MxLmxpc3RlbmVyUmVmaW5lcnMpLFxuICAgICAgICBvcHRpb25SZWZpbmVyczogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBob29rczAub3B0aW9uUmVmaW5lcnMpLCBob29rczEub3B0aW9uUmVmaW5lcnMpLFxuICAgICAgICBwcm9wU2V0SGFuZGxlcnM6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgaG9va3MwLnByb3BTZXRIYW5kbGVycyksIGhvb2tzMS5wcm9wU2V0SGFuZGxlcnMpLFxuICAgIH07XG59XG5mdW5jdGlvbiBjb21wYXJlT3B0aW9uYWxEYXRlcyhkYXRlMCwgZGF0ZTEpIHtcbiAgICBpZiAoZGF0ZTAgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm4gZGF0ZTE7XG4gICAgfVxuICAgIGlmIChkYXRlMSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBkYXRlMDtcbiAgICB9XG4gICAgcmV0dXJuIG5ldyBEYXRlKE1hdGgubWF4KGRhdGUwLnZhbHVlT2YoKSwgZGF0ZTEudmFsdWVPZigpKSk7XG59XG5cbmNsYXNzIFN0YW5kYXJkVGhlbWUgZXh0ZW5kcyBUaGVtZSB7XG59XG5TdGFuZGFyZFRoZW1lLnByb3RvdHlwZS5jbGFzc2VzID0ge1xuICAgIHJvb3Q6ICdmYy10aGVtZS1zdGFuZGFyZCcsXG4gICAgdGFibGVDZWxsU2hhZGVkOiAnZmMtY2VsbC1zaGFkZWQnLFxuICAgIGJ1dHRvbkdyb3VwOiAnZmMtYnV0dG9uLWdyb3VwJyxcbiAgICBidXR0b246ICdmYy1idXR0b24gZmMtYnV0dG9uLXByaW1hcnknLFxuICAgIGJ1dHRvbkFjdGl2ZTogJ2ZjLWJ1dHRvbi1hY3RpdmUnLFxufTtcblN0YW5kYXJkVGhlbWUucHJvdG90eXBlLmJhc2VJY29uQ2xhc3MgPSAnZmMtaWNvbic7XG5TdGFuZGFyZFRoZW1lLnByb3RvdHlwZS5pY29uQ2xhc3NlcyA9IHtcbiAgICBjbG9zZTogJ2ZjLWljb24teCcsXG4gICAgcHJldjogJ2ZjLWljb24tY2hldnJvbi1sZWZ0JyxcbiAgICBuZXh0OiAnZmMtaWNvbi1jaGV2cm9uLXJpZ2h0JyxcbiAgICBwcmV2WWVhcjogJ2ZjLWljb24tY2hldnJvbnMtbGVmdCcsXG4gICAgbmV4dFllYXI6ICdmYy1pY29uLWNoZXZyb25zLXJpZ2h0Jyxcbn07XG5TdGFuZGFyZFRoZW1lLnByb3RvdHlwZS5ydGxJY29uQ2xhc3NlcyA9IHtcbiAgICBwcmV2OiAnZmMtaWNvbi1jaGV2cm9uLXJpZ2h0JyxcbiAgICBuZXh0OiAnZmMtaWNvbi1jaGV2cm9uLWxlZnQnLFxuICAgIHByZXZZZWFyOiAnZmMtaWNvbi1jaGV2cm9ucy1yaWdodCcsXG4gICAgbmV4dFllYXI6ICdmYy1pY29uLWNoZXZyb25zLWxlZnQnLFxufTtcblN0YW5kYXJkVGhlbWUucHJvdG90eXBlLmljb25PdmVycmlkZU9wdGlvbiA9ICdidXR0b25JY29ucyc7IC8vIFRPRE86IG1ha2UgVFMtZnJpZW5kbHlcblN0YW5kYXJkVGhlbWUucHJvdG90eXBlLmljb25PdmVycmlkZUN1c3RvbUJ1dHRvbk9wdGlvbiA9ICdpY29uJztcblN0YW5kYXJkVGhlbWUucHJvdG90eXBlLmljb25PdmVycmlkZVByZWZpeCA9ICdmYy1pY29uLSc7XG5cbmZ1bmN0aW9uIGNvbXBpbGVWaWV3RGVmcyhkZWZhdWx0Q29uZmlncywgb3ZlcnJpZGVDb25maWdzKSB7XG4gICAgbGV0IGhhc2ggPSB7fTtcbiAgICBsZXQgdmlld1R5cGU7XG4gICAgZm9yICh2aWV3VHlwZSBpbiBkZWZhdWx0Q29uZmlncykge1xuICAgICAgICBlbnN1cmVWaWV3RGVmKHZpZXdUeXBlLCBoYXNoLCBkZWZhdWx0Q29uZmlncywgb3ZlcnJpZGVDb25maWdzKTtcbiAgICB9XG4gICAgZm9yICh2aWV3VHlwZSBpbiBvdmVycmlkZUNvbmZpZ3MpIHtcbiAgICAgICAgZW5zdXJlVmlld0RlZih2aWV3VHlwZSwgaGFzaCwgZGVmYXVsdENvbmZpZ3MsIG92ZXJyaWRlQ29uZmlncyk7XG4gICAgfVxuICAgIHJldHVybiBoYXNoO1xufVxuZnVuY3Rpb24gZW5zdXJlVmlld0RlZih2aWV3VHlwZSwgaGFzaCwgZGVmYXVsdENvbmZpZ3MsIG92ZXJyaWRlQ29uZmlncykge1xuICAgIGlmIChoYXNoW3ZpZXdUeXBlXSkge1xuICAgICAgICByZXR1cm4gaGFzaFt2aWV3VHlwZV07XG4gICAgfVxuICAgIGxldCB2aWV3RGVmID0gYnVpbGRWaWV3RGVmKHZpZXdUeXBlLCBoYXNoLCBkZWZhdWx0Q29uZmlncywgb3ZlcnJpZGVDb25maWdzKTtcbiAgICBpZiAodmlld0RlZikge1xuICAgICAgICBoYXNoW3ZpZXdUeXBlXSA9IHZpZXdEZWY7XG4gICAgfVxuICAgIHJldHVybiB2aWV3RGVmO1xufVxuZnVuY3Rpb24gYnVpbGRWaWV3RGVmKHZpZXdUeXBlLCBoYXNoLCBkZWZhdWx0Q29uZmlncywgb3ZlcnJpZGVDb25maWdzKSB7XG4gICAgbGV0IGRlZmF1bHRDb25maWcgPSBkZWZhdWx0Q29uZmlnc1t2aWV3VHlwZV07XG4gICAgbGV0IG92ZXJyaWRlQ29uZmlnID0gb3ZlcnJpZGVDb25maWdzW3ZpZXdUeXBlXTtcbiAgICBsZXQgcXVlcnlQcm9wID0gKG5hbWUpID0+ICgoZGVmYXVsdENvbmZpZyAmJiBkZWZhdWx0Q29uZmlnW25hbWVdICE9PSBudWxsKSA/IGRlZmF1bHRDb25maWdbbmFtZV0gOlxuICAgICAgICAoKG92ZXJyaWRlQ29uZmlnICYmIG92ZXJyaWRlQ29uZmlnW25hbWVdICE9PSBudWxsKSA/IG92ZXJyaWRlQ29uZmlnW25hbWVdIDogbnVsbCkpO1xuICAgIGxldCB0aGVDb21wb25lbnQgPSBxdWVyeVByb3AoJ2NvbXBvbmVudCcpO1xuICAgIGxldCBzdXBlclR5cGUgPSBxdWVyeVByb3AoJ3N1cGVyVHlwZScpO1xuICAgIGxldCBzdXBlckRlZiA9IG51bGw7XG4gICAgaWYgKHN1cGVyVHlwZSkge1xuICAgICAgICBpZiAoc3VwZXJUeXBlID09PSB2aWV3VHlwZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5cXCd0IGhhdmUgYSBjdXN0b20gdmlldyB0eXBlIHRoYXQgcmVmZXJlbmNlcyBpdHNlbGYnKTtcbiAgICAgICAgfVxuICAgICAgICBzdXBlckRlZiA9IGVuc3VyZVZpZXdEZWYoc3VwZXJUeXBlLCBoYXNoLCBkZWZhdWx0Q29uZmlncywgb3ZlcnJpZGVDb25maWdzKTtcbiAgICB9XG4gICAgaWYgKCF0aGVDb21wb25lbnQgJiYgc3VwZXJEZWYpIHtcbiAgICAgICAgdGhlQ29tcG9uZW50ID0gc3VwZXJEZWYuY29tcG9uZW50O1xuICAgIH1cbiAgICBpZiAoIXRoZUNvbXBvbmVudCkge1xuICAgICAgICByZXR1cm4gbnVsbDsgLy8gZG9uJ3QgdGhyb3cgYSB3YXJuaW5nLCBtaWdodCBiZSBzZXR0aW5ncyBmb3IgYSBzaW5nbGUtdW5pdCB2aWV3XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICAgIHR5cGU6IHZpZXdUeXBlLFxuICAgICAgICBjb21wb25lbnQ6IHRoZUNvbXBvbmVudCxcbiAgICAgICAgZGVmYXVsdHM6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgKHN1cGVyRGVmID8gc3VwZXJEZWYuZGVmYXVsdHMgOiB7fSkpLCAoZGVmYXVsdENvbmZpZyA/IGRlZmF1bHRDb25maWcucmF3T3B0aW9ucyA6IHt9KSksXG4gICAgICAgIG92ZXJyaWRlczogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCAoc3VwZXJEZWYgPyBzdXBlckRlZi5vdmVycmlkZXMgOiB7fSkpLCAob3ZlcnJpZGVDb25maWcgPyBvdmVycmlkZUNvbmZpZy5yYXdPcHRpb25zIDoge30pKSxcbiAgICB9O1xufVxuXG5mdW5jdGlvbiBwYXJzZVZpZXdDb25maWdzKGlucHV0cykge1xuICAgIHJldHVybiBtYXBIYXNoKGlucHV0cywgcGFyc2VWaWV3Q29uZmlnKTtcbn1cbmZ1bmN0aW9uIHBhcnNlVmlld0NvbmZpZyhpbnB1dCkge1xuICAgIGxldCByYXdPcHRpb25zID0gdHlwZW9mIGlucHV0ID09PSAnZnVuY3Rpb24nID9cbiAgICAgICAgeyBjb21wb25lbnQ6IGlucHV0IH0gOlxuICAgICAgICBpbnB1dDtcbiAgICBsZXQgeyBjb21wb25lbnQgfSA9IHJhd09wdGlvbnM7XG4gICAgaWYgKHJhd09wdGlvbnMuY29udGVudCkge1xuICAgICAgICAvLyBUT0RPOiByZW1vdmUgY29udGVudC9jbGFzc05hbWVzL2RpZE1vdW50L2V0YyBmcm9tIG9wdGlvbnM/XG4gICAgICAgIGNvbXBvbmVudCA9IGNyZWF0ZVZpZXdIb29rQ29tcG9uZW50KHJhd09wdGlvbnMpO1xuICAgIH1cbiAgICBlbHNlIGlmIChjb21wb25lbnQgJiYgIShjb21wb25lbnQucHJvdG90eXBlIGluc3RhbmNlb2YgQmFzZUNvbXBvbmVudCkpIHtcbiAgICAgICAgLy8gV0hZPzogcGVvcGxlIHdlcmUgdXNpbmcgYGNvbXBvbmVudGAgcHJvcGVydHkgZm9yIGBjb250ZW50YFxuICAgICAgICAvLyBUT0RPOiBjb252ZXJnZSBvbiBvbmUgc2V0dGluZyBuYW1lXG4gICAgICAgIGNvbXBvbmVudCA9IGNyZWF0ZVZpZXdIb29rQ29tcG9uZW50KE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcmF3T3B0aW9ucyksIHsgY29udGVudDogY29tcG9uZW50IH0pKTtcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgICAgc3VwZXJUeXBlOiByYXdPcHRpb25zLnR5cGUsXG4gICAgICAgIGNvbXBvbmVudDogY29tcG9uZW50LFxuICAgICAgICByYXdPcHRpb25zLCAvLyBpbmNsdWRlcyB0eXBlIGFuZCBjb21wb25lbnQgdG9vIDooXG4gICAgfTtcbn1cbmZ1bmN0aW9uIGNyZWF0ZVZpZXdIb29rQ29tcG9uZW50KG9wdGlvbnMpIHtcbiAgICByZXR1cm4gKHZpZXdQcm9wcykgPT4gKGNyZWF0ZUVsZW1lbnQoVmlld0NvbnRleHRUeXBlLkNvbnN1bWVyLCBudWxsLCAoY29udGV4dCkgPT4gKGNyZWF0ZUVsZW1lbnQoQ29udGVudENvbnRhaW5lciwgeyBlbFRhZzogXCJkaXZcIiwgZWxDbGFzc2VzOiBidWlsZFZpZXdDbGFzc05hbWVzKGNvbnRleHQudmlld1NwZWMpLCByZW5kZXJQcm9wczogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB2aWV3UHJvcHMpLCB7IG5leHREYXlUaHJlc2hvbGQ6IGNvbnRleHQub3B0aW9ucy5uZXh0RGF5VGhyZXNob2xkIH0pLCBnZW5lcmF0b3JOYW1lOiB1bmRlZmluZWQsIGN1c3RvbUdlbmVyYXRvcjogb3B0aW9ucy5jb250ZW50LCBjbGFzc05hbWVHZW5lcmF0b3I6IG9wdGlvbnMuY2xhc3NOYW1lcywgZGlkTW91bnQ6IG9wdGlvbnMuZGlkTW91bnQsIHdpbGxVbm1vdW50OiBvcHRpb25zLndpbGxVbm1vdW50IH0pKSkpO1xufVxuXG5mdW5jdGlvbiBidWlsZFZpZXdTcGVjcyhkZWZhdWx0SW5wdXRzLCBvcHRpb25PdmVycmlkZXMsIGR5bmFtaWNPcHRpb25PdmVycmlkZXMsIGxvY2FsZURlZmF1bHRzKSB7XG4gICAgbGV0IGRlZmF1bHRDb25maWdzID0gcGFyc2VWaWV3Q29uZmlncyhkZWZhdWx0SW5wdXRzKTtcbiAgICBsZXQgb3ZlcnJpZGVDb25maWdzID0gcGFyc2VWaWV3Q29uZmlncyhvcHRpb25PdmVycmlkZXMudmlld3MpO1xuICAgIGxldCB2aWV3RGVmcyA9IGNvbXBpbGVWaWV3RGVmcyhkZWZhdWx0Q29uZmlncywgb3ZlcnJpZGVDb25maWdzKTtcbiAgICByZXR1cm4gbWFwSGFzaCh2aWV3RGVmcywgKHZpZXdEZWYpID0+IGJ1aWxkVmlld1NwZWModmlld0RlZiwgb3ZlcnJpZGVDb25maWdzLCBvcHRpb25PdmVycmlkZXMsIGR5bmFtaWNPcHRpb25PdmVycmlkZXMsIGxvY2FsZURlZmF1bHRzKSk7XG59XG5mdW5jdGlvbiBidWlsZFZpZXdTcGVjKHZpZXdEZWYsIG92ZXJyaWRlQ29uZmlncywgb3B0aW9uT3ZlcnJpZGVzLCBkeW5hbWljT3B0aW9uT3ZlcnJpZGVzLCBsb2NhbGVEZWZhdWx0cykge1xuICAgIGxldCBkdXJhdGlvbklucHV0ID0gdmlld0RlZi5vdmVycmlkZXMuZHVyYXRpb24gfHxcbiAgICAgICAgdmlld0RlZi5kZWZhdWx0cy5kdXJhdGlvbiB8fFxuICAgICAgICBkeW5hbWljT3B0aW9uT3ZlcnJpZGVzLmR1cmF0aW9uIHx8XG4gICAgICAgIG9wdGlvbk92ZXJyaWRlcy5kdXJhdGlvbjtcbiAgICBsZXQgZHVyYXRpb24gPSBudWxsO1xuICAgIGxldCBkdXJhdGlvblVuaXQgPSAnJztcbiAgICBsZXQgc2luZ2xlVW5pdCA9ICcnO1xuICAgIGxldCBzaW5nbGVVbml0T3ZlcnJpZGVzID0ge307XG4gICAgaWYgKGR1cmF0aW9uSW5wdXQpIHtcbiAgICAgICAgZHVyYXRpb24gPSBjcmVhdGVEdXJhdGlvbkNhY2hlZChkdXJhdGlvbklucHV0KTtcbiAgICAgICAgaWYgKGR1cmF0aW9uKSB7IC8vIHZhbGlkP1xuICAgICAgICAgICAgbGV0IGRlbm9tID0gZ3JlYXRlc3REdXJhdGlvbkRlbm9taW5hdG9yKGR1cmF0aW9uKTtcbiAgICAgICAgICAgIGR1cmF0aW9uVW5pdCA9IGRlbm9tLnVuaXQ7XG4gICAgICAgICAgICBpZiAoZGVub20udmFsdWUgPT09IDEpIHtcbiAgICAgICAgICAgICAgICBzaW5nbGVVbml0ID0gZHVyYXRpb25Vbml0O1xuICAgICAgICAgICAgICAgIHNpbmdsZVVuaXRPdmVycmlkZXMgPSBvdmVycmlkZUNvbmZpZ3NbZHVyYXRpb25Vbml0XSA/IG92ZXJyaWRlQ29uZmlnc1tkdXJhdGlvblVuaXRdLnJhd09wdGlvbnMgOiB7fTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICBsZXQgcXVlcnlCdXR0b25UZXh0ID0gKG9wdGlvbnNTdWJzZXQpID0+IHtcbiAgICAgICAgbGV0IGJ1dHRvblRleHRNYXAgPSBvcHRpb25zU3Vic2V0LmJ1dHRvblRleHQgfHwge307XG4gICAgICAgIGxldCBidXR0b25UZXh0S2V5ID0gdmlld0RlZi5kZWZhdWx0cy5idXR0b25UZXh0S2V5O1xuICAgICAgICBpZiAoYnV0dG9uVGV4dEtleSAhPSBudWxsICYmIGJ1dHRvblRleHRNYXBbYnV0dG9uVGV4dEtleV0gIT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIGJ1dHRvblRleHRNYXBbYnV0dG9uVGV4dEtleV07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGJ1dHRvblRleHRNYXBbdmlld0RlZi50eXBlXSAhPSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm4gYnV0dG9uVGV4dE1hcFt2aWV3RGVmLnR5cGVdO1xuICAgICAgICB9XG4gICAgICAgIGlmIChidXR0b25UZXh0TWFwW3NpbmdsZVVuaXRdICE9IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybiBidXR0b25UZXh0TWFwW3NpbmdsZVVuaXRdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH07XG4gICAgbGV0IHF1ZXJ5QnV0dG9uVGl0bGUgPSAob3B0aW9uc1N1YnNldCkgPT4ge1xuICAgICAgICBsZXQgYnV0dG9uSGludHMgPSBvcHRpb25zU3Vic2V0LmJ1dHRvbkhpbnRzIHx8IHt9O1xuICAgICAgICBsZXQgYnV0dG9uS2V5ID0gdmlld0RlZi5kZWZhdWx0cy5idXR0b25UZXh0S2V5OyAvLyB1c2Ugc2FtZSBrZXkgYXMgdGV4dFxuICAgICAgICBpZiAoYnV0dG9uS2V5ICE9IG51bGwgJiYgYnV0dG9uSGludHNbYnV0dG9uS2V5XSAhPSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm4gYnV0dG9uSGludHNbYnV0dG9uS2V5XTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoYnV0dG9uSGludHNbdmlld0RlZi50eXBlXSAhPSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm4gYnV0dG9uSGludHNbdmlld0RlZi50eXBlXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoYnV0dG9uSGludHNbc2luZ2xlVW5pdF0gIT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIGJ1dHRvbkhpbnRzW3NpbmdsZVVuaXRdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH07XG4gICAgcmV0dXJuIHtcbiAgICAgICAgdHlwZTogdmlld0RlZi50eXBlLFxuICAgICAgICBjb21wb25lbnQ6IHZpZXdEZWYuY29tcG9uZW50LFxuICAgICAgICBkdXJhdGlvbixcbiAgICAgICAgZHVyYXRpb25Vbml0LFxuICAgICAgICBzaW5nbGVVbml0LFxuICAgICAgICBvcHRpb25EZWZhdWx0czogdmlld0RlZi5kZWZhdWx0cyxcbiAgICAgICAgb3B0aW9uT3ZlcnJpZGVzOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNpbmdsZVVuaXRPdmVycmlkZXMpLCB2aWV3RGVmLm92ZXJyaWRlcyksXG4gICAgICAgIGJ1dHRvblRleHRPdmVycmlkZTogcXVlcnlCdXR0b25UZXh0KGR5bmFtaWNPcHRpb25PdmVycmlkZXMpIHx8XG4gICAgICAgICAgICBxdWVyeUJ1dHRvblRleHQob3B0aW9uT3ZlcnJpZGVzKSB8fCAvLyBjb25zdHJ1Y3Rvci1zcGVjaWZpZWQgYnV0dG9uVGV4dCBsb29rdXAgaGFzaCB0YWtlcyBwcmVjZWRlbmNlXG4gICAgICAgICAgICB2aWV3RGVmLm92ZXJyaWRlcy5idXR0b25UZXh0LFxuICAgICAgICBidXR0b25UZXh0RGVmYXVsdDogcXVlcnlCdXR0b25UZXh0KGxvY2FsZURlZmF1bHRzKSB8fFxuICAgICAgICAgICAgdmlld0RlZi5kZWZhdWx0cy5idXR0b25UZXh0IHx8XG4gICAgICAgICAgICBxdWVyeUJ1dHRvblRleHQoQkFTRV9PUFRJT05fREVGQVVMVFMpIHx8XG4gICAgICAgICAgICB2aWV3RGVmLnR5cGUsXG4gICAgICAgIC8vIG5vdCBEUllcbiAgICAgICAgYnV0dG9uVGl0bGVPdmVycmlkZTogcXVlcnlCdXR0b25UaXRsZShkeW5hbWljT3B0aW9uT3ZlcnJpZGVzKSB8fFxuICAgICAgICAgICAgcXVlcnlCdXR0b25UaXRsZShvcHRpb25PdmVycmlkZXMpIHx8XG4gICAgICAgICAgICB2aWV3RGVmLm92ZXJyaWRlcy5idXR0b25IaW50LFxuICAgICAgICBidXR0b25UaXRsZURlZmF1bHQ6IHF1ZXJ5QnV0dG9uVGl0bGUobG9jYWxlRGVmYXVsdHMpIHx8XG4gICAgICAgICAgICB2aWV3RGVmLmRlZmF1bHRzLmJ1dHRvbkhpbnQgfHxcbiAgICAgICAgICAgIHF1ZXJ5QnV0dG9uVGl0bGUoQkFTRV9PUFRJT05fREVGQVVMVFMpLFxuICAgICAgICAvLyB3aWxsIGV2ZW50dWFsbHkgZmFsbCBiYWNrIHRvIGJ1dHRvblRleHRcbiAgICB9O1xufVxuLy8gaGFjayB0byBnZXQgbWVtb2l6YXRpb24gd29ya2luZ1xubGV0IGR1cmF0aW9uSW5wdXRNYXAgPSB7fTtcbmZ1bmN0aW9uIGNyZWF0ZUR1cmF0aW9uQ2FjaGVkKGR1cmF0aW9uSW5wdXQpIHtcbiAgICBsZXQganNvbiA9IEpTT04uc3RyaW5naWZ5KGR1cmF0aW9uSW5wdXQpO1xuICAgIGxldCByZXMgPSBkdXJhdGlvbklucHV0TWFwW2pzb25dO1xuICAgIGlmIChyZXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXMgPSBjcmVhdGVEdXJhdGlvbihkdXJhdGlvbklucHV0KTtcbiAgICAgICAgZHVyYXRpb25JbnB1dE1hcFtqc29uXSA9IHJlcztcbiAgICB9XG4gICAgcmV0dXJuIHJlcztcbn1cblxuZnVuY3Rpb24gcmVkdWNlVmlld1R5cGUodmlld1R5cGUsIGFjdGlvbikge1xuICAgIHN3aXRjaCAoYWN0aW9uLnR5cGUpIHtcbiAgICAgICAgY2FzZSAnQ0hBTkdFX1ZJRVdfVFlQRSc6XG4gICAgICAgICAgICB2aWV3VHlwZSA9IGFjdGlvbi52aWV3VHlwZTtcbiAgICB9XG4gICAgcmV0dXJuIHZpZXdUeXBlO1xufVxuXG5mdW5jdGlvbiByZWR1Y2VDdXJyZW50RGF0ZShjdXJyZW50RGF0ZSwgYWN0aW9uKSB7XG4gICAgc3dpdGNoIChhY3Rpb24udHlwZSkge1xuICAgICAgICBjYXNlICdDSEFOR0VfREFURSc6XG4gICAgICAgICAgICByZXR1cm4gYWN0aW9uLmRhdGVNYXJrZXI7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICByZXR1cm4gY3VycmVudERhdGU7XG4gICAgfVxufVxuLy8gc2hvdWxkIGJlIGluaXRpYWxpemVkIG9uY2UgYW5kIHN0YXkgY29uc3RhbnRcbi8vIHRoaXMgd2lsbCBjaGFuZ2UgdG9vXG5mdW5jdGlvbiBnZXRJbml0aWFsRGF0ZShvcHRpb25zLCBkYXRlRW52LCBub3dNYW5hZ2VyKSB7XG4gICAgbGV0IGluaXRpYWxEYXRlSW5wdXQgPSBvcHRpb25zLmluaXRpYWxEYXRlO1xuICAgIC8vIGNvbXB1dGUgdGhlIGluaXRpYWwgYW1iaWctdGltZXpvbmUgZGF0ZVxuICAgIGlmIChpbml0aWFsRGF0ZUlucHV0ICE9IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIGRhdGVFbnYuY3JlYXRlTWFya2VyKGluaXRpYWxEYXRlSW5wdXQpO1xuICAgIH1cbiAgICByZXR1cm4gbm93TWFuYWdlci5nZXREYXRlTWFya2VyKCk7XG59XG5cbmZ1bmN0aW9uIHJlZHVjZUR5bmFtaWNPcHRpb25PdmVycmlkZXMoZHluYW1pY09wdGlvbk92ZXJyaWRlcywgYWN0aW9uKSB7XG4gICAgc3dpdGNoIChhY3Rpb24udHlwZSkge1xuICAgICAgICBjYXNlICdTRVRfT1BUSU9OJzpcbiAgICAgICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGR5bmFtaWNPcHRpb25PdmVycmlkZXMpLCB7IFthY3Rpb24ub3B0aW9uTmFtZV06IGFjdGlvbi5yYXdPcHRpb25WYWx1ZSB9KTtcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIHJldHVybiBkeW5hbWljT3B0aW9uT3ZlcnJpZGVzO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gcmVkdWNlRGF0ZVByb2ZpbGUoY3VycmVudERhdGVQcm9maWxlLCBhY3Rpb24sIGN1cnJlbnREYXRlLCBkYXRlUHJvZmlsZUdlbmVyYXRvcikge1xuICAgIGxldCBkcDtcbiAgICBzd2l0Y2ggKGFjdGlvbi50eXBlKSB7XG4gICAgICAgIGNhc2UgJ0NIQU5HRV9WSUVXX1RZUEUnOlxuICAgICAgICAgICAgcmV0dXJuIGRhdGVQcm9maWxlR2VuZXJhdG9yLmJ1aWxkKGFjdGlvbi5kYXRlTWFya2VyIHx8IGN1cnJlbnREYXRlKTtcbiAgICAgICAgY2FzZSAnQ0hBTkdFX0RBVEUnOlxuICAgICAgICAgICAgcmV0dXJuIGRhdGVQcm9maWxlR2VuZXJhdG9yLmJ1aWxkKGFjdGlvbi5kYXRlTWFya2VyKTtcbiAgICAgICAgY2FzZSAnUFJFVic6XG4gICAgICAgICAgICBkcCA9IGRhdGVQcm9maWxlR2VuZXJhdG9yLmJ1aWxkUHJldihjdXJyZW50RGF0ZVByb2ZpbGUsIGN1cnJlbnREYXRlKTtcbiAgICAgICAgICAgIGlmIChkcC5pc1ZhbGlkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGRwO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ05FWFQnOlxuICAgICAgICAgICAgZHAgPSBkYXRlUHJvZmlsZUdlbmVyYXRvci5idWlsZE5leHQoY3VycmVudERhdGVQcm9maWxlLCBjdXJyZW50RGF0ZSk7XG4gICAgICAgICAgICBpZiAoZHAuaXNWYWxpZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBkcDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrO1xuICAgIH1cbiAgICByZXR1cm4gY3VycmVudERhdGVQcm9maWxlO1xufVxuXG5mdW5jdGlvbiBpbml0RXZlbnRTb3VyY2VzKGNhbGVuZGFyT3B0aW9ucywgZGF0ZVByb2ZpbGUsIGNvbnRleHQpIHtcbiAgICBsZXQgYWN0aXZlUmFuZ2UgPSBkYXRlUHJvZmlsZSA/IGRhdGVQcm9maWxlLmFjdGl2ZVJhbmdlIDogbnVsbDtcbiAgICByZXR1cm4gYWRkU291cmNlcyh7fSwgcGFyc2VJbml0aWFsU291cmNlcyhjYWxlbmRhck9wdGlvbnMsIGNvbnRleHQpLCBhY3RpdmVSYW5nZSwgY29udGV4dCk7XG59XG5mdW5jdGlvbiByZWR1Y2VFdmVudFNvdXJjZXMoZXZlbnRTb3VyY2VzLCBhY3Rpb24sIGRhdGVQcm9maWxlLCBjb250ZXh0KSB7XG4gICAgbGV0IGFjdGl2ZVJhbmdlID0gZGF0ZVByb2ZpbGUgPyBkYXRlUHJvZmlsZS5hY3RpdmVSYW5nZSA6IG51bGw7IC8vIG5lZWQgdGhpcyBjaGVjaz9cbiAgICBzd2l0Y2ggKGFjdGlvbi50eXBlKSB7XG4gICAgICAgIGNhc2UgJ0FERF9FVkVOVF9TT1VSQ0VTJzogLy8gYWxyZWFkeSBwYXJzZWRcbiAgICAgICAgICAgIHJldHVybiBhZGRTb3VyY2VzKGV2ZW50U291cmNlcywgYWN0aW9uLnNvdXJjZXMsIGFjdGl2ZVJhbmdlLCBjb250ZXh0KTtcbiAgICAgICAgY2FzZSAnUkVNT1ZFX0VWRU5UX1NPVVJDRSc6XG4gICAgICAgICAgICByZXR1cm4gcmVtb3ZlU291cmNlKGV2ZW50U291cmNlcywgYWN0aW9uLnNvdXJjZUlkKTtcbiAgICAgICAgY2FzZSAnUFJFVic6IC8vIFRPRE86IGhvdyBkbyB3ZSB0cmFjayBhbGwgYWN0aW9ucyB0aGF0IGFmZmVjdCBkYXRlUHJvZmlsZSA6KFxuICAgICAgICBjYXNlICdORVhUJzpcbiAgICAgICAgY2FzZSAnQ0hBTkdFX0RBVEUnOlxuICAgICAgICBjYXNlICdDSEFOR0VfVklFV19UWVBFJzpcbiAgICAgICAgICAgIGlmIChkYXRlUHJvZmlsZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmZXRjaERpcnR5U291cmNlcyhldmVudFNvdXJjZXMsIGFjdGl2ZVJhbmdlLCBjb250ZXh0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBldmVudFNvdXJjZXM7XG4gICAgICAgIGNhc2UgJ0ZFVENIX0VWRU5UX1NPVVJDRVMnOlxuICAgICAgICAgICAgcmV0dXJuIGZldGNoU291cmNlc0J5SWRzKGV2ZW50U291cmNlcywgYWN0aW9uLnNvdXJjZUlkcyA/IC8vIHdoeSBubyB0eXBlP1xuICAgICAgICAgICAgICAgIGFycmF5VG9IYXNoKGFjdGlvbi5zb3VyY2VJZHMpIDpcbiAgICAgICAgICAgICAgICBleGNsdWRlU3RhdGljU291cmNlcyhldmVudFNvdXJjZXMsIGNvbnRleHQpLCBhY3RpdmVSYW5nZSwgYWN0aW9uLmlzUmVmZXRjaCB8fCBmYWxzZSwgY29udGV4dCk7XG4gICAgICAgIGNhc2UgJ1JFQ0VJVkVfRVZFTlRTJzpcbiAgICAgICAgY2FzZSAnUkVDRUlWRV9FVkVOVF9FUlJPUic6XG4gICAgICAgICAgICByZXR1cm4gcmVjZWl2ZVJlc3BvbnNlKGV2ZW50U291cmNlcywgYWN0aW9uLnNvdXJjZUlkLCBhY3Rpb24uZmV0Y2hJZCwgYWN0aW9uLmZldGNoUmFuZ2UpO1xuICAgICAgICBjYXNlICdSRU1PVkVfQUxMX0VWRU5UX1NPVVJDRVMnOlxuICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgcmV0dXJuIGV2ZW50U291cmNlcztcbiAgICB9XG59XG5mdW5jdGlvbiByZWR1Y2VFdmVudFNvdXJjZXNOZXdUaW1lWm9uZShldmVudFNvdXJjZXMsIGRhdGVQcm9maWxlLCBjb250ZXh0KSB7XG4gICAgbGV0IGFjdGl2ZVJhbmdlID0gZGF0ZVByb2ZpbGUgPyBkYXRlUHJvZmlsZS5hY3RpdmVSYW5nZSA6IG51bGw7IC8vIG5lZWQgdGhpcyBjaGVjaz9cbiAgICByZXR1cm4gZmV0Y2hTb3VyY2VzQnlJZHMoZXZlbnRTb3VyY2VzLCBleGNsdWRlU3RhdGljU291cmNlcyhldmVudFNvdXJjZXMsIGNvbnRleHQpLCBhY3RpdmVSYW5nZSwgdHJ1ZSwgY29udGV4dCk7XG59XG5mdW5jdGlvbiBjb21wdXRlRXZlbnRTb3VyY2VzTG9hZGluZyhldmVudFNvdXJjZXMpIHtcbiAgICBmb3IgKGxldCBzb3VyY2VJZCBpbiBldmVudFNvdXJjZXMpIHtcbiAgICAgICAgaWYgKGV2ZW50U291cmNlc1tzb3VyY2VJZF0uaXNGZXRjaGluZykge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xufVxuZnVuY3Rpb24gYWRkU291cmNlcyhldmVudFNvdXJjZUhhc2gsIHNvdXJjZXMsIGZldGNoUmFuZ2UsIGNvbnRleHQpIHtcbiAgICBsZXQgaGFzaCA9IHt9O1xuICAgIGZvciAobGV0IHNvdXJjZSBvZiBzb3VyY2VzKSB7XG4gICAgICAgIGhhc2hbc291cmNlLnNvdXJjZUlkXSA9IHNvdXJjZTtcbiAgICB9XG4gICAgaWYgKGZldGNoUmFuZ2UpIHtcbiAgICAgICAgaGFzaCA9IGZldGNoRGlydHlTb3VyY2VzKGhhc2gsIGZldGNoUmFuZ2UsIGNvbnRleHQpO1xuICAgIH1cbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBldmVudFNvdXJjZUhhc2gpLCBoYXNoKTtcbn1cbmZ1bmN0aW9uIHJlbW92ZVNvdXJjZShldmVudFNvdXJjZUhhc2gsIHNvdXJjZUlkKSB7XG4gICAgcmV0dXJuIGZpbHRlckhhc2goZXZlbnRTb3VyY2VIYXNoLCAoZXZlbnRTb3VyY2UpID0+IGV2ZW50U291cmNlLnNvdXJjZUlkICE9PSBzb3VyY2VJZCk7XG59XG5mdW5jdGlvbiBmZXRjaERpcnR5U291cmNlcyhzb3VyY2VIYXNoLCBmZXRjaFJhbmdlLCBjb250ZXh0KSB7XG4gICAgcmV0dXJuIGZldGNoU291cmNlc0J5SWRzKHNvdXJjZUhhc2gsIGZpbHRlckhhc2goc291cmNlSGFzaCwgKGV2ZW50U291cmNlKSA9PiBpc1NvdXJjZURpcnR5KGV2ZW50U291cmNlLCBmZXRjaFJhbmdlLCBjb250ZXh0KSksIGZldGNoUmFuZ2UsIGZhbHNlLCBjb250ZXh0KTtcbn1cbmZ1bmN0aW9uIGlzU291cmNlRGlydHkoZXZlbnRTb3VyY2UsIGZldGNoUmFuZ2UsIGNvbnRleHQpIHtcbiAgICBpZiAoIWRvZXNTb3VyY2VOZWVkUmFuZ2UoZXZlbnRTb3VyY2UsIGNvbnRleHQpKSB7XG4gICAgICAgIHJldHVybiAhZXZlbnRTb3VyY2UubGF0ZXN0RmV0Y2hJZDtcbiAgICB9XG4gICAgcmV0dXJuICFjb250ZXh0Lm9wdGlvbnMubGF6eUZldGNoaW5nIHx8XG4gICAgICAgICFldmVudFNvdXJjZS5mZXRjaFJhbmdlIHx8XG4gICAgICAgIGV2ZW50U291cmNlLmlzRmV0Y2hpbmcgfHwgLy8gYWx3YXlzIGNhbmNlbCBvdXRkYXRlZCBpbi1wcm9ncmVzcyBmZXRjaGVzXG4gICAgICAgIGZldGNoUmFuZ2Uuc3RhcnQgPCBldmVudFNvdXJjZS5mZXRjaFJhbmdlLnN0YXJ0IHx8XG4gICAgICAgIGZldGNoUmFuZ2UuZW5kID4gZXZlbnRTb3VyY2UuZmV0Y2hSYW5nZS5lbmQ7XG59XG5mdW5jdGlvbiBmZXRjaFNvdXJjZXNCeUlkcyhwcmV2U291cmNlcywgc291cmNlSWRIYXNoLCBmZXRjaFJhbmdlLCBpc1JlZmV0Y2gsIGNvbnRleHQpIHtcbiAgICBsZXQgbmV4dFNvdXJjZXMgPSB7fTtcbiAgICBmb3IgKGxldCBzb3VyY2VJZCBpbiBwcmV2U291cmNlcykge1xuICAgICAgICBsZXQgc291cmNlID0gcHJldlNvdXJjZXNbc291cmNlSWRdO1xuICAgICAgICBpZiAoc291cmNlSWRIYXNoW3NvdXJjZUlkXSkge1xuICAgICAgICAgICAgbmV4dFNvdXJjZXNbc291cmNlSWRdID0gZmV0Y2hTb3VyY2Uoc291cmNlLCBmZXRjaFJhbmdlLCBpc1JlZmV0Y2gsIGNvbnRleHQpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgbmV4dFNvdXJjZXNbc291cmNlSWRdID0gc291cmNlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBuZXh0U291cmNlcztcbn1cbmZ1bmN0aW9uIGZldGNoU291cmNlKGV2ZW50U291cmNlLCBmZXRjaFJhbmdlLCBpc1JlZmV0Y2gsIGNvbnRleHQpIHtcbiAgICBsZXQgeyBvcHRpb25zLCBjYWxlbmRhckFwaSB9ID0gY29udGV4dDtcbiAgICBsZXQgc291cmNlRGVmID0gY29udGV4dC5wbHVnaW5Ib29rcy5ldmVudFNvdXJjZURlZnNbZXZlbnRTb3VyY2Uuc291cmNlRGVmSWRdO1xuICAgIGxldCBmZXRjaElkID0gZ3VpZCgpO1xuICAgIHNvdXJjZURlZi5mZXRjaCh7XG4gICAgICAgIGV2ZW50U291cmNlLFxuICAgICAgICByYW5nZTogZmV0Y2hSYW5nZSxcbiAgICAgICAgaXNSZWZldGNoLFxuICAgICAgICBjb250ZXh0LFxuICAgIH0sIChyZXMpID0+IHtcbiAgICAgICAgbGV0IHsgcmF3RXZlbnRzIH0gPSByZXM7XG4gICAgICAgIGlmIChvcHRpb25zLmV2ZW50U291cmNlU3VjY2Vzcykge1xuICAgICAgICAgICAgcmF3RXZlbnRzID0gb3B0aW9ucy5ldmVudFNvdXJjZVN1Y2Nlc3MuY2FsbChjYWxlbmRhckFwaSwgcmF3RXZlbnRzLCByZXMucmVzcG9uc2UpIHx8IHJhd0V2ZW50cztcbiAgICAgICAgfVxuICAgICAgICBpZiAoZXZlbnRTb3VyY2Uuc3VjY2Vzcykge1xuICAgICAgICAgICAgcmF3RXZlbnRzID0gZXZlbnRTb3VyY2Uuc3VjY2Vzcy5jYWxsKGNhbGVuZGFyQXBpLCByYXdFdmVudHMsIHJlcy5yZXNwb25zZSkgfHwgcmF3RXZlbnRzO1xuICAgICAgICB9XG4gICAgICAgIGNvbnRleHQuZGlzcGF0Y2goe1xuICAgICAgICAgICAgdHlwZTogJ1JFQ0VJVkVfRVZFTlRTJyxcbiAgICAgICAgICAgIHNvdXJjZUlkOiBldmVudFNvdXJjZS5zb3VyY2VJZCxcbiAgICAgICAgICAgIGZldGNoSWQsXG4gICAgICAgICAgICBmZXRjaFJhbmdlLFxuICAgICAgICAgICAgcmF3RXZlbnRzLFxuICAgICAgICB9KTtcbiAgICB9LCAoZXJyb3IpID0+IHtcbiAgICAgICAgbGV0IGVycm9ySGFuZGxlZCA9IGZhbHNlO1xuICAgICAgICBpZiAob3B0aW9ucy5ldmVudFNvdXJjZUZhaWx1cmUpIHtcbiAgICAgICAgICAgIG9wdGlvbnMuZXZlbnRTb3VyY2VGYWlsdXJlLmNhbGwoY2FsZW5kYXJBcGksIGVycm9yKTtcbiAgICAgICAgICAgIGVycm9ySGFuZGxlZCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGV2ZW50U291cmNlLmZhaWx1cmUpIHtcbiAgICAgICAgICAgIGV2ZW50U291cmNlLmZhaWx1cmUoZXJyb3IpO1xuICAgICAgICAgICAgZXJyb3JIYW5kbGVkID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWVycm9ySGFuZGxlZCkge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKGVycm9yLm1lc3NhZ2UsIGVycm9yKTtcbiAgICAgICAgfVxuICAgICAgICBjb250ZXh0LmRpc3BhdGNoKHtcbiAgICAgICAgICAgIHR5cGU6ICdSRUNFSVZFX0VWRU5UX0VSUk9SJyxcbiAgICAgICAgICAgIHNvdXJjZUlkOiBldmVudFNvdXJjZS5zb3VyY2VJZCxcbiAgICAgICAgICAgIGZldGNoSWQsXG4gICAgICAgICAgICBmZXRjaFJhbmdlLFxuICAgICAgICAgICAgZXJyb3IsXG4gICAgICAgIH0pO1xuICAgIH0pO1xuICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGV2ZW50U291cmNlKSwgeyBpc0ZldGNoaW5nOiB0cnVlLCBsYXRlc3RGZXRjaElkOiBmZXRjaElkIH0pO1xufVxuZnVuY3Rpb24gcmVjZWl2ZVJlc3BvbnNlKHNvdXJjZUhhc2gsIHNvdXJjZUlkLCBmZXRjaElkLCBmZXRjaFJhbmdlKSB7XG4gICAgbGV0IGV2ZW50U291cmNlID0gc291cmNlSGFzaFtzb3VyY2VJZF07XG4gICAgaWYgKGV2ZW50U291cmNlICYmIC8vIG5vdCBhbHJlYWR5IHJlbW92ZWRcbiAgICAgICAgZmV0Y2hJZCA9PT0gZXZlbnRTb3VyY2UubGF0ZXN0RmV0Y2hJZCkge1xuICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzb3VyY2VIYXNoKSwgeyBbc291cmNlSWRdOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGV2ZW50U291cmNlKSwgeyBpc0ZldGNoaW5nOiBmYWxzZSwgZmV0Y2hSYW5nZSB9KSB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHNvdXJjZUhhc2g7XG59XG5mdW5jdGlvbiBleGNsdWRlU3RhdGljU291cmNlcyhldmVudFNvdXJjZXMsIGNvbnRleHQpIHtcbiAgICByZXR1cm4gZmlsdGVySGFzaChldmVudFNvdXJjZXMsIChldmVudFNvdXJjZSkgPT4gZG9lc1NvdXJjZU5lZWRSYW5nZShldmVudFNvdXJjZSwgY29udGV4dCkpO1xufVxuZnVuY3Rpb24gcGFyc2VJbml0aWFsU291cmNlcyhyYXdPcHRpb25zLCBjb250ZXh0KSB7XG4gICAgbGV0IHJlZmluZXJzID0gYnVpbGRFdmVudFNvdXJjZVJlZmluZXJzKGNvbnRleHQpO1xuICAgIGxldCByYXdTb3VyY2VzID0gW10uY29uY2F0KHJhd09wdGlvbnMuZXZlbnRTb3VyY2VzIHx8IFtdKTtcbiAgICBsZXQgc291cmNlcyA9IFtdOyAvLyBwYXJzZWRcbiAgICBpZiAocmF3T3B0aW9ucy5pbml0aWFsRXZlbnRzKSB7XG4gICAgICAgIHJhd1NvdXJjZXMudW5zaGlmdChyYXdPcHRpb25zLmluaXRpYWxFdmVudHMpO1xuICAgIH1cbiAgICBpZiAocmF3T3B0aW9ucy5ldmVudHMpIHtcbiAgICAgICAgcmF3U291cmNlcy51bnNoaWZ0KHJhd09wdGlvbnMuZXZlbnRzKTtcbiAgICB9XG4gICAgZm9yIChsZXQgcmF3U291cmNlIG9mIHJhd1NvdXJjZXMpIHtcbiAgICAgICAgbGV0IHNvdXJjZSA9IHBhcnNlRXZlbnRTb3VyY2UocmF3U291cmNlLCBjb250ZXh0LCByZWZpbmVycyk7XG4gICAgICAgIGlmIChzb3VyY2UpIHtcbiAgICAgICAgICAgIHNvdXJjZXMucHVzaChzb3VyY2UpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBzb3VyY2VzO1xufVxuZnVuY3Rpb24gZG9lc1NvdXJjZU5lZWRSYW5nZShldmVudFNvdXJjZSwgY29udGV4dCkge1xuICAgIGxldCBkZWZzID0gY29udGV4dC5wbHVnaW5Ib29rcy5ldmVudFNvdXJjZURlZnM7XG4gICAgcmV0dXJuICFkZWZzW2V2ZW50U291cmNlLnNvdXJjZURlZklkXS5pZ25vcmVSYW5nZTtcbn1cblxuZnVuY3Rpb24gcmVkdWNlRGF0ZVNlbGVjdGlvbihjdXJyZW50U2VsZWN0aW9uLCBhY3Rpb24pIHtcbiAgICBzd2l0Y2ggKGFjdGlvbi50eXBlKSB7XG4gICAgICAgIGNhc2UgJ1VOU0VMRUNUX0RBVEVTJzpcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICBjYXNlICdTRUxFQ1RfREFURVMnOlxuICAgICAgICAgICAgcmV0dXJuIGFjdGlvbi5zZWxlY3Rpb247XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICByZXR1cm4gY3VycmVudFNlbGVjdGlvbjtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIHJlZHVjZVNlbGVjdGVkRXZlbnQoY3VycmVudEluc3RhbmNlSWQsIGFjdGlvbikge1xuICAgIHN3aXRjaCAoYWN0aW9uLnR5cGUpIHtcbiAgICAgICAgY2FzZSAnVU5TRUxFQ1RfRVZFTlQnOlxuICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICBjYXNlICdTRUxFQ1RfRVZFTlQnOlxuICAgICAgICAgICAgcmV0dXJuIGFjdGlvbi5ldmVudEluc3RhbmNlSWQ7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICByZXR1cm4gY3VycmVudEluc3RhbmNlSWQ7XG4gICAgfVxufVxuXG5mdW5jdGlvbiByZWR1Y2VFdmVudERyYWcoY3VycmVudERyYWcsIGFjdGlvbikge1xuICAgIGxldCBuZXdEcmFnO1xuICAgIHN3aXRjaCAoYWN0aW9uLnR5cGUpIHtcbiAgICAgICAgY2FzZSAnVU5TRVRfRVZFTlRfRFJBRyc6XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgY2FzZSAnU0VUX0VWRU5UX0RSQUcnOlxuICAgICAgICAgICAgbmV3RHJhZyA9IGFjdGlvbi5zdGF0ZTtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgYWZmZWN0ZWRFdmVudHM6IG5ld0RyYWcuYWZmZWN0ZWRFdmVudHMsXG4gICAgICAgICAgICAgICAgbXV0YXRlZEV2ZW50czogbmV3RHJhZy5tdXRhdGVkRXZlbnRzLFxuICAgICAgICAgICAgICAgIGlzRXZlbnQ6IG5ld0RyYWcuaXNFdmVudCxcbiAgICAgICAgICAgIH07XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICByZXR1cm4gY3VycmVudERyYWc7XG4gICAgfVxufVxuXG5mdW5jdGlvbiByZWR1Y2VFdmVudFJlc2l6ZShjdXJyZW50UmVzaXplLCBhY3Rpb24pIHtcbiAgICBsZXQgbmV3UmVzaXplO1xuICAgIHN3aXRjaCAoYWN0aW9uLnR5cGUpIHtcbiAgICAgICAgY2FzZSAnVU5TRVRfRVZFTlRfUkVTSVpFJzpcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICBjYXNlICdTRVRfRVZFTlRfUkVTSVpFJzpcbiAgICAgICAgICAgIG5ld1Jlc2l6ZSA9IGFjdGlvbi5zdGF0ZTtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgYWZmZWN0ZWRFdmVudHM6IG5ld1Jlc2l6ZS5hZmZlY3RlZEV2ZW50cyxcbiAgICAgICAgICAgICAgICBtdXRhdGVkRXZlbnRzOiBuZXdSZXNpemUubXV0YXRlZEV2ZW50cyxcbiAgICAgICAgICAgICAgICBpc0V2ZW50OiBuZXdSZXNpemUuaXNFdmVudCxcbiAgICAgICAgICAgIH07XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICByZXR1cm4gY3VycmVudFJlc2l6ZTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIHBhcnNlVG9vbGJhcnMoY2FsZW5kYXJPcHRpb25zLCBjYWxlbmRhck9wdGlvbk92ZXJyaWRlcywgdGhlbWUsIHZpZXdTcGVjcywgY2FsZW5kYXJBcGkpIHtcbiAgICBsZXQgaGVhZGVyID0gY2FsZW5kYXJPcHRpb25zLmhlYWRlclRvb2xiYXIgPyBwYXJzZVRvb2xiYXIoY2FsZW5kYXJPcHRpb25zLmhlYWRlclRvb2xiYXIsIGNhbGVuZGFyT3B0aW9ucywgY2FsZW5kYXJPcHRpb25PdmVycmlkZXMsIHRoZW1lLCB2aWV3U3BlY3MsIGNhbGVuZGFyQXBpKSA6IG51bGw7XG4gICAgbGV0IGZvb3RlciA9IGNhbGVuZGFyT3B0aW9ucy5mb290ZXJUb29sYmFyID8gcGFyc2VUb29sYmFyKGNhbGVuZGFyT3B0aW9ucy5mb290ZXJUb29sYmFyLCBjYWxlbmRhck9wdGlvbnMsIGNhbGVuZGFyT3B0aW9uT3ZlcnJpZGVzLCB0aGVtZSwgdmlld1NwZWNzLCBjYWxlbmRhckFwaSkgOiBudWxsO1xuICAgIHJldHVybiB7IGhlYWRlciwgZm9vdGVyIH07XG59XG5mdW5jdGlvbiBwYXJzZVRvb2xiYXIoc2VjdGlvblN0ckhhc2gsIGNhbGVuZGFyT3B0aW9ucywgY2FsZW5kYXJPcHRpb25PdmVycmlkZXMsIHRoZW1lLCB2aWV3U3BlY3MsIGNhbGVuZGFyQXBpKSB7XG4gICAgbGV0IHNlY3Rpb25XaWRnZXRzID0ge307XG4gICAgbGV0IHZpZXdzV2l0aEJ1dHRvbnMgPSBbXTtcbiAgICBsZXQgaGFzVGl0bGUgPSBmYWxzZTtcbiAgICBmb3IgKGxldCBzZWN0aW9uTmFtZSBpbiBzZWN0aW9uU3RySGFzaCkge1xuICAgICAgICBsZXQgc2VjdGlvblN0ciA9IHNlY3Rpb25TdHJIYXNoW3NlY3Rpb25OYW1lXTtcbiAgICAgICAgbGV0IHNlY3Rpb25SZXMgPSBwYXJzZVNlY3Rpb24oc2VjdGlvblN0ciwgY2FsZW5kYXJPcHRpb25zLCBjYWxlbmRhck9wdGlvbk92ZXJyaWRlcywgdGhlbWUsIHZpZXdTcGVjcywgY2FsZW5kYXJBcGkpO1xuICAgICAgICBzZWN0aW9uV2lkZ2V0c1tzZWN0aW9uTmFtZV0gPSBzZWN0aW9uUmVzLndpZGdldHM7XG4gICAgICAgIHZpZXdzV2l0aEJ1dHRvbnMucHVzaCguLi5zZWN0aW9uUmVzLnZpZXdzV2l0aEJ1dHRvbnMpO1xuICAgICAgICBoYXNUaXRsZSA9IGhhc1RpdGxlIHx8IHNlY3Rpb25SZXMuaGFzVGl0bGU7XG4gICAgfVxuICAgIHJldHVybiB7IHNlY3Rpb25XaWRnZXRzLCB2aWV3c1dpdGhCdXR0b25zLCBoYXNUaXRsZSB9O1xufVxuLypcbkJBRDogcXVlcnlpbmcgaWNvbnMgYW5kIHRleHQgaGVyZS4gc2hvdWxkIGJlIGRvbmUgYXQgcmVuZGVyIHRpbWVcbiovXG5mdW5jdGlvbiBwYXJzZVNlY3Rpb24oc2VjdGlvblN0ciwgY2FsZW5kYXJPcHRpb25zLCAvLyBkZWZhdWx0cytvdmVycmlkZXMsIHRoZW4gcmVmaW5lZFxuY2FsZW5kYXJPcHRpb25PdmVycmlkZXMsIC8vIG92ZXJyaWRlcyBvbmx5ISwgdW5yZWZpbmVkIDooXG50aGVtZSwgdmlld1NwZWNzLCBjYWxlbmRhckFwaSkge1xuICAgIGxldCBpc1J0bCA9IGNhbGVuZGFyT3B0aW9ucy5kaXJlY3Rpb24gPT09ICdydGwnO1xuICAgIGxldCBjYWxlbmRhckN1c3RvbUJ1dHRvbnMgPSBjYWxlbmRhck9wdGlvbnMuY3VzdG9tQnV0dG9ucyB8fCB7fTtcbiAgICBsZXQgY2FsZW5kYXJCdXR0b25UZXh0T3ZlcnJpZGVzID0gY2FsZW5kYXJPcHRpb25PdmVycmlkZXMuYnV0dG9uVGV4dCB8fCB7fTtcbiAgICBsZXQgY2FsZW5kYXJCdXR0b25UZXh0ID0gY2FsZW5kYXJPcHRpb25zLmJ1dHRvblRleHQgfHwge307XG4gICAgbGV0IGNhbGVuZGFyQnV0dG9uSGludE92ZXJyaWRlcyA9IGNhbGVuZGFyT3B0aW9uT3ZlcnJpZGVzLmJ1dHRvbkhpbnRzIHx8IHt9O1xuICAgIGxldCBjYWxlbmRhckJ1dHRvbkhpbnRzID0gY2FsZW5kYXJPcHRpb25zLmJ1dHRvbkhpbnRzIHx8IHt9O1xuICAgIGxldCBzZWN0aW9uU3Vic3RycyA9IHNlY3Rpb25TdHIgPyBzZWN0aW9uU3RyLnNwbGl0KCcgJykgOiBbXTtcbiAgICBsZXQgdmlld3NXaXRoQnV0dG9ucyA9IFtdO1xuICAgIGxldCBoYXNUaXRsZSA9IGZhbHNlO1xuICAgIGxldCB3aWRnZXRzID0gc2VjdGlvblN1YnN0cnMubWFwKChidXR0b25Hcm91cFN0cikgPT4gKGJ1dHRvbkdyb3VwU3RyLnNwbGl0KCcsJykubWFwKChidXR0b25OYW1lKSA9PiB7XG4gICAgICAgIGlmIChidXR0b25OYW1lID09PSAndGl0bGUnKSB7XG4gICAgICAgICAgICBoYXNUaXRsZSA9IHRydWU7XG4gICAgICAgICAgICByZXR1cm4geyBidXR0b25OYW1lIH07XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGN1c3RvbUJ1dHRvblByb3BzO1xuICAgICAgICBsZXQgdmlld1NwZWM7XG4gICAgICAgIGxldCBidXR0b25DbGljaztcbiAgICAgICAgbGV0IGJ1dHRvbkljb247IC8vIG9ubHkgb25lIG9mIHRoZXNlIHdpbGwgYmUgc2V0XG4gICAgICAgIGxldCBidXR0b25UZXh0OyAvLyBcIlxuICAgICAgICBsZXQgYnV0dG9uSGludDtcbiAgICAgICAgLy8gXiBmb3IgdGhlIHRpdGxlPVwiXCIgYXR0cmlidXRlLCBmb3IgYWNjZXNzaWJpbGl0eVxuICAgICAgICBpZiAoKGN1c3RvbUJ1dHRvblByb3BzID0gY2FsZW5kYXJDdXN0b21CdXR0b25zW2J1dHRvbk5hbWVdKSkge1xuICAgICAgICAgICAgYnV0dG9uQ2xpY2sgPSAoZXYpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoY3VzdG9tQnV0dG9uUHJvcHMuY2xpY2spIHtcbiAgICAgICAgICAgICAgICAgICAgY3VzdG9tQnV0dG9uUHJvcHMuY2xpY2suY2FsbChldi50YXJnZXQsIGV2LCBldi50YXJnZXQpOyAvLyBUT0RPOiB1c2UgQ2FsZW5kYXIgdGhpcyBjb250ZXh0P1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICAoYnV0dG9uSWNvbiA9IHRoZW1lLmdldEN1c3RvbUJ1dHRvbkljb25DbGFzcyhjdXN0b21CdXR0b25Qcm9wcykpIHx8XG4gICAgICAgICAgICAgICAgKGJ1dHRvbkljb24gPSB0aGVtZS5nZXRJY29uQ2xhc3MoYnV0dG9uTmFtZSwgaXNSdGwpKSB8fFxuICAgICAgICAgICAgICAgIChidXR0b25UZXh0ID0gY3VzdG9tQnV0dG9uUHJvcHMudGV4dCk7XG4gICAgICAgICAgICBidXR0b25IaW50ID0gY3VzdG9tQnV0dG9uUHJvcHMuaGludCB8fCBjdXN0b21CdXR0b25Qcm9wcy50ZXh0O1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKCh2aWV3U3BlYyA9IHZpZXdTcGVjc1tidXR0b25OYW1lXSkpIHtcbiAgICAgICAgICAgIHZpZXdzV2l0aEJ1dHRvbnMucHVzaChidXR0b25OYW1lKTtcbiAgICAgICAgICAgIGJ1dHRvbkNsaWNrID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgIGNhbGVuZGFyQXBpLmNoYW5nZVZpZXcoYnV0dG9uTmFtZSk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgKGJ1dHRvblRleHQgPSB2aWV3U3BlYy5idXR0b25UZXh0T3ZlcnJpZGUpIHx8XG4gICAgICAgICAgICAgICAgKGJ1dHRvbkljb24gPSB0aGVtZS5nZXRJY29uQ2xhc3MoYnV0dG9uTmFtZSwgaXNSdGwpKSB8fFxuICAgICAgICAgICAgICAgIChidXR0b25UZXh0ID0gdmlld1NwZWMuYnV0dG9uVGV4dERlZmF1bHQpO1xuICAgICAgICAgICAgbGV0IHRleHRGYWxsYmFjayA9IHZpZXdTcGVjLmJ1dHRvblRleHRPdmVycmlkZSB8fFxuICAgICAgICAgICAgICAgIHZpZXdTcGVjLmJ1dHRvblRleHREZWZhdWx0O1xuICAgICAgICAgICAgYnV0dG9uSGludCA9IGZvcm1hdFdpdGhPcmRpbmFscyh2aWV3U3BlYy5idXR0b25UaXRsZU92ZXJyaWRlIHx8XG4gICAgICAgICAgICAgICAgdmlld1NwZWMuYnV0dG9uVGl0bGVEZWZhdWx0IHx8XG4gICAgICAgICAgICAgICAgY2FsZW5kYXJPcHRpb25zLnZpZXdIaW50LCBbdGV4dEZhbGxiYWNrLCBidXR0b25OYW1lXSwgLy8gdmlldy1uYW1lID0gYnV0dG9uTmFtZVxuICAgICAgICAgICAgdGV4dEZhbGxiYWNrKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChjYWxlbmRhckFwaVtidXR0b25OYW1lXSkgeyAvLyBhIGNhbGVuZGFyQXBpIG1ldGhvZFxuICAgICAgICAgICAgYnV0dG9uQ2xpY2sgPSAoKSA9PiB7XG4gICAgICAgICAgICAgICAgY2FsZW5kYXJBcGlbYnV0dG9uTmFtZV0oKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICAoYnV0dG9uVGV4dCA9IGNhbGVuZGFyQnV0dG9uVGV4dE92ZXJyaWRlc1tidXR0b25OYW1lXSkgfHxcbiAgICAgICAgICAgICAgICAoYnV0dG9uSWNvbiA9IHRoZW1lLmdldEljb25DbGFzcyhidXR0b25OYW1lLCBpc1J0bCkpIHx8XG4gICAgICAgICAgICAgICAgKGJ1dHRvblRleHQgPSBjYWxlbmRhckJ1dHRvblRleHRbYnV0dG9uTmFtZV0pOyAvLyBldmVyeXRoaW5nIGVsc2UgaXMgY29uc2lkZXJlZCBkZWZhdWx0XG4gICAgICAgICAgICBpZiAoYnV0dG9uTmFtZSA9PT0gJ3ByZXZZZWFyJyB8fCBidXR0b25OYW1lID09PSAnbmV4dFllYXInKSB7XG4gICAgICAgICAgICAgICAgbGV0IHByZXZPck5leHQgPSBidXR0b25OYW1lID09PSAncHJldlllYXInID8gJ3ByZXYnIDogJ25leHQnO1xuICAgICAgICAgICAgICAgIGJ1dHRvbkhpbnQgPSBmb3JtYXRXaXRoT3JkaW5hbHMoY2FsZW5kYXJCdXR0b25IaW50T3ZlcnJpZGVzW3ByZXZPck5leHRdIHx8XG4gICAgICAgICAgICAgICAgICAgIGNhbGVuZGFyQnV0dG9uSGludHNbcHJldk9yTmV4dF0sIFtcbiAgICAgICAgICAgICAgICAgICAgY2FsZW5kYXJCdXR0b25UZXh0LnllYXIgfHwgJ3llYXInLFxuICAgICAgICAgICAgICAgICAgICAneWVhcicsXG4gICAgICAgICAgICAgICAgXSwgY2FsZW5kYXJCdXR0b25UZXh0W2J1dHRvbk5hbWVdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGJ1dHRvbkhpbnQgPSAobmF2VW5pdCkgPT4gZm9ybWF0V2l0aE9yZGluYWxzKGNhbGVuZGFyQnV0dG9uSGludE92ZXJyaWRlc1tidXR0b25OYW1lXSB8fFxuICAgICAgICAgICAgICAgICAgICBjYWxlbmRhckJ1dHRvbkhpbnRzW2J1dHRvbk5hbWVdLCBbXG4gICAgICAgICAgICAgICAgICAgIGNhbGVuZGFyQnV0dG9uVGV4dFtuYXZVbml0XSB8fCBuYXZVbml0LFxuICAgICAgICAgICAgICAgICAgICBuYXZVbml0LFxuICAgICAgICAgICAgICAgIF0sIGNhbGVuZGFyQnV0dG9uVGV4dFtidXR0b25OYW1lXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHsgYnV0dG9uTmFtZSwgYnV0dG9uQ2xpY2ssIGJ1dHRvbkljb24sIGJ1dHRvblRleHQsIGJ1dHRvbkhpbnQgfTtcbiAgICB9KSkpO1xuICAgIHJldHVybiB7IHdpZGdldHMsIHZpZXdzV2l0aEJ1dHRvbnMsIGhhc1RpdGxlIH07XG59XG5cbi8vIGFsd2F5cyByZXByZXNlbnRzIHRoZSBjdXJyZW50IHZpZXcuIG90aGVyd2lzZSwgaXQnZCBuZWVkIHRvIGNoYW5nZSB2YWx1ZSBldmVyeSB0aW1lIGRhdGUgY2hhbmdlc1xuY2xhc3MgVmlld0ltcGwge1xuICAgIGNvbnN0cnVjdG9yKHR5cGUsIGdldEN1cnJlbnREYXRhLCBkYXRlRW52KSB7XG4gICAgICAgIHRoaXMudHlwZSA9IHR5cGU7XG4gICAgICAgIHRoaXMuZ2V0Q3VycmVudERhdGEgPSBnZXRDdXJyZW50RGF0YTtcbiAgICAgICAgdGhpcy5kYXRlRW52ID0gZGF0ZUVudjtcbiAgICB9XG4gICAgZ2V0IGNhbGVuZGFyKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRDdXJyZW50RGF0YSgpLmNhbGVuZGFyQXBpO1xuICAgIH1cbiAgICBnZXQgdGl0bGUoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldEN1cnJlbnREYXRhKCkudmlld1RpdGxlO1xuICAgIH1cbiAgICBnZXQgYWN0aXZlU3RhcnQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRhdGVFbnYudG9EYXRlKHRoaXMuZ2V0Q3VycmVudERhdGEoKS5kYXRlUHJvZmlsZS5hY3RpdmVSYW5nZS5zdGFydCk7XG4gICAgfVxuICAgIGdldCBhY3RpdmVFbmQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRhdGVFbnYudG9EYXRlKHRoaXMuZ2V0Q3VycmVudERhdGEoKS5kYXRlUHJvZmlsZS5hY3RpdmVSYW5nZS5lbmQpO1xuICAgIH1cbiAgICBnZXQgY3VycmVudFN0YXJ0KCkge1xuICAgICAgICByZXR1cm4gdGhpcy5kYXRlRW52LnRvRGF0ZSh0aGlzLmdldEN1cnJlbnREYXRhKCkuZGF0ZVByb2ZpbGUuY3VycmVudFJhbmdlLnN0YXJ0KTtcbiAgICB9XG4gICAgZ2V0IGN1cnJlbnRFbmQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRhdGVFbnYudG9EYXRlKHRoaXMuZ2V0Q3VycmVudERhdGEoKS5kYXRlUHJvZmlsZS5jdXJyZW50UmFuZ2UuZW5kKTtcbiAgICB9XG4gICAgZ2V0T3B0aW9uKG5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0Q3VycmVudERhdGEoKS5vcHRpb25zW25hbWVdOyAvLyBhcmUgdGhlIHZpZXctc3BlY2lmaWMgb3B0aW9uc1xuICAgIH1cbn1cblxubGV0IGV2ZW50U291cmNlRGVmJDIgPSB7XG4gICAgaWdub3JlUmFuZ2U6IHRydWUsXG4gICAgcGFyc2VNZXRhKHJlZmluZWQpIHtcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkocmVmaW5lZC5ldmVudHMpKSB7XG4gICAgICAgICAgICByZXR1cm4gcmVmaW5lZC5ldmVudHM7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfSxcbiAgICBmZXRjaChhcmcsIHN1Y2Nlc3NDYWxsYmFjaykge1xuICAgICAgICBzdWNjZXNzQ2FsbGJhY2soe1xuICAgICAgICAgICAgcmF3RXZlbnRzOiBhcmcuZXZlbnRTb3VyY2UubWV0YSxcbiAgICAgICAgfSk7XG4gICAgfSxcbn07XG5jb25zdCBhcnJheUV2ZW50U291cmNlUGx1Z2luID0gY3JlYXRlUGx1Z2luKHtcbiAgICBuYW1lOiAnYXJyYXktZXZlbnQtc291cmNlJyxcbiAgICBldmVudFNvdXJjZURlZnM6IFtldmVudFNvdXJjZURlZiQyXSxcbn0pO1xuXG5sZXQgZXZlbnRTb3VyY2VEZWYkMSA9IHtcbiAgICBwYXJzZU1ldGEocmVmaW5lZCkge1xuICAgICAgICBpZiAodHlwZW9mIHJlZmluZWQuZXZlbnRzID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICByZXR1cm4gcmVmaW5lZC5ldmVudHM7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfSxcbiAgICBmZXRjaChhcmcsIHN1Y2Nlc3NDYWxsYmFjaywgZXJyb3JDYWxsYmFjaykge1xuICAgICAgICBjb25zdCB7IGRhdGVFbnYgfSA9IGFyZy5jb250ZXh0O1xuICAgICAgICBjb25zdCBmdW5jID0gYXJnLmV2ZW50U291cmNlLm1ldGE7XG4gICAgICAgIHVucHJvbWlzaWZ5KGZ1bmMuYmluZChudWxsLCBidWlsZFJhbmdlQXBpV2l0aFRpbWVab25lKGFyZy5yYW5nZSwgZGF0ZUVudikpLCAocmF3RXZlbnRzKSA9PiBzdWNjZXNzQ2FsbGJhY2soeyByYXdFdmVudHMgfSksIGVycm9yQ2FsbGJhY2spO1xuICAgIH0sXG59O1xuY29uc3QgZnVuY0V2ZW50U291cmNlUGx1Z2luID0gY3JlYXRlUGx1Z2luKHtcbiAgICBuYW1lOiAnZnVuYy1ldmVudC1zb3VyY2UnLFxuICAgIGV2ZW50U291cmNlRGVmczogW2V2ZW50U291cmNlRGVmJDFdLFxufSk7XG5cbmNvbnN0IEpTT05fRkVFRF9FVkVOVF9TT1VSQ0VfUkVGSU5FUlMgPSB7XG4gICAgbWV0aG9kOiBTdHJpbmcsXG4gICAgZXh0cmFQYXJhbXM6IGlkZW50aXR5LFxuICAgIHN0YXJ0UGFyYW06IFN0cmluZyxcbiAgICBlbmRQYXJhbTogU3RyaW5nLFxuICAgIHRpbWVab25lUGFyYW06IFN0cmluZyxcbn07XG5cbmxldCBldmVudFNvdXJjZURlZiA9IHtcbiAgICBwYXJzZU1ldGEocmVmaW5lZCkge1xuICAgICAgICBpZiAocmVmaW5lZC51cmwgJiYgKHJlZmluZWQuZm9ybWF0ID09PSAnanNvbicgfHwgIXJlZmluZWQuZm9ybWF0KSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICB1cmw6IHJlZmluZWQudXJsLFxuICAgICAgICAgICAgICAgIGZvcm1hdDogJ2pzb24nLFxuICAgICAgICAgICAgICAgIG1ldGhvZDogKHJlZmluZWQubWV0aG9kIHx8ICdHRVQnKS50b1VwcGVyQ2FzZSgpLFxuICAgICAgICAgICAgICAgIGV4dHJhUGFyYW1zOiByZWZpbmVkLmV4dHJhUGFyYW1zLFxuICAgICAgICAgICAgICAgIHN0YXJ0UGFyYW06IHJlZmluZWQuc3RhcnRQYXJhbSxcbiAgICAgICAgICAgICAgICBlbmRQYXJhbTogcmVmaW5lZC5lbmRQYXJhbSxcbiAgICAgICAgICAgICAgICB0aW1lWm9uZVBhcmFtOiByZWZpbmVkLnRpbWVab25lUGFyYW0sXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH0sXG4gICAgZmV0Y2goYXJnLCBzdWNjZXNzQ2FsbGJhY2ssIGVycm9yQ2FsbGJhY2spIHtcbiAgICAgICAgY29uc3QgeyBtZXRhIH0gPSBhcmcuZXZlbnRTb3VyY2U7XG4gICAgICAgIGNvbnN0IHJlcXVlc3RQYXJhbXMgPSBidWlsZFJlcXVlc3RQYXJhbXMobWV0YSwgYXJnLnJhbmdlLCBhcmcuY29udGV4dCk7XG4gICAgICAgIHJlcXVlc3RKc29uKG1ldGEubWV0aG9kLCBtZXRhLnVybCwgcmVxdWVzdFBhcmFtcykudGhlbigoW3Jhd0V2ZW50cywgcmVzcG9uc2VdKSA9PiB7XG4gICAgICAgICAgICBzdWNjZXNzQ2FsbGJhY2soeyByYXdFdmVudHMsIHJlc3BvbnNlIH0pO1xuICAgICAgICB9LCBlcnJvckNhbGxiYWNrKTtcbiAgICB9LFxufTtcbmNvbnN0IGpzb25GZWVkRXZlbnRTb3VyY2VQbHVnaW4gPSBjcmVhdGVQbHVnaW4oe1xuICAgIG5hbWU6ICdqc29uLWV2ZW50LXNvdXJjZScsXG4gICAgZXZlbnRTb3VyY2VSZWZpbmVyczogSlNPTl9GRUVEX0VWRU5UX1NPVVJDRV9SRUZJTkVSUyxcbiAgICBldmVudFNvdXJjZURlZnM6IFtldmVudFNvdXJjZURlZl0sXG59KTtcbmZ1bmN0aW9uIGJ1aWxkUmVxdWVzdFBhcmFtcyhtZXRhLCByYW5nZSwgY29udGV4dCkge1xuICAgIGxldCB7IGRhdGVFbnYsIG9wdGlvbnMgfSA9IGNvbnRleHQ7XG4gICAgbGV0IHN0YXJ0UGFyYW07XG4gICAgbGV0IGVuZFBhcmFtO1xuICAgIGxldCB0aW1lWm9uZVBhcmFtO1xuICAgIGxldCBjdXN0b21SZXF1ZXN0UGFyYW1zO1xuICAgIGxldCBwYXJhbXMgPSB7fTtcbiAgICBzdGFydFBhcmFtID0gbWV0YS5zdGFydFBhcmFtO1xuICAgIGlmIChzdGFydFBhcmFtID09IG51bGwpIHtcbiAgICAgICAgc3RhcnRQYXJhbSA9IG9wdGlvbnMuc3RhcnRQYXJhbTtcbiAgICB9XG4gICAgZW5kUGFyYW0gPSBtZXRhLmVuZFBhcmFtO1xuICAgIGlmIChlbmRQYXJhbSA9PSBudWxsKSB7XG4gICAgICAgIGVuZFBhcmFtID0gb3B0aW9ucy5lbmRQYXJhbTtcbiAgICB9XG4gICAgdGltZVpvbmVQYXJhbSA9IG1ldGEudGltZVpvbmVQYXJhbTtcbiAgICBpZiAodGltZVpvbmVQYXJhbSA9PSBudWxsKSB7XG4gICAgICAgIHRpbWVab25lUGFyYW0gPSBvcHRpb25zLnRpbWVab25lUGFyYW07XG4gICAgfVxuICAgIC8vIHJldHJpZXZlIGFueSBvdXRib3VuZCBHRVQvUE9TVCBkYXRhIGZyb20gdGhlIG9wdGlvbnNcbiAgICBpZiAodHlwZW9mIG1ldGEuZXh0cmFQYXJhbXMgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgLy8gc3VwcGxpZWQgYXMgYSBmdW5jdGlvbiB0aGF0IHJldHVybnMgYSBrZXkvdmFsdWUgb2JqZWN0XG4gICAgICAgIGN1c3RvbVJlcXVlc3RQYXJhbXMgPSBtZXRhLmV4dHJhUGFyYW1zKCk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICAvLyBwcm9iYWJseSBzdXBwbGllZCBhcyBhIHN0cmFpZ2h0IGtleS92YWx1ZSBvYmplY3RcbiAgICAgICAgY3VzdG9tUmVxdWVzdFBhcmFtcyA9IG1ldGEuZXh0cmFQYXJhbXMgfHwge307XG4gICAgfVxuICAgIE9iamVjdC5hc3NpZ24ocGFyYW1zLCBjdXN0b21SZXF1ZXN0UGFyYW1zKTtcbiAgICBwYXJhbXNbc3RhcnRQYXJhbV0gPSBkYXRlRW52LmZvcm1hdElzbyhyYW5nZS5zdGFydCk7XG4gICAgcGFyYW1zW2VuZFBhcmFtXSA9IGRhdGVFbnYuZm9ybWF0SXNvKHJhbmdlLmVuZCk7XG4gICAgaWYgKGRhdGVFbnYudGltZVpvbmUgIT09ICdsb2NhbCcpIHtcbiAgICAgICAgcGFyYW1zW3RpbWVab25lUGFyYW1dID0gZGF0ZUVudi50aW1lWm9uZTtcbiAgICB9XG4gICAgcmV0dXJuIHBhcmFtcztcbn1cblxuY29uc3QgU0lNUExFX1JFQ1VSUklOR19SRUZJTkVSUyA9IHtcbiAgICBkYXlzT2ZXZWVrOiBpZGVudGl0eSxcbiAgICBzdGFydFRpbWU6IGNyZWF0ZUR1cmF0aW9uLFxuICAgIGVuZFRpbWU6IGNyZWF0ZUR1cmF0aW9uLFxuICAgIGR1cmF0aW9uOiBjcmVhdGVEdXJhdGlvbixcbiAgICBzdGFydFJlY3VyOiBpZGVudGl0eSxcbiAgICBlbmRSZWN1cjogaWRlbnRpdHksXG59O1xuXG5sZXQgcmVjdXJyaW5nID0ge1xuICAgIHBhcnNlKHJlZmluZWQsIGRhdGVFbnYpIHtcbiAgICAgICAgaWYgKHJlZmluZWQuZGF5c09mV2VlayB8fCByZWZpbmVkLnN0YXJ0VGltZSB8fCByZWZpbmVkLmVuZFRpbWUgfHwgcmVmaW5lZC5zdGFydFJlY3VyIHx8IHJlZmluZWQuZW5kUmVjdXIpIHtcbiAgICAgICAgICAgIGxldCByZWN1cnJpbmdEYXRhID0ge1xuICAgICAgICAgICAgICAgIGRheXNPZldlZWs6IHJlZmluZWQuZGF5c09mV2VlayB8fCBudWxsLFxuICAgICAgICAgICAgICAgIHN0YXJ0VGltZTogcmVmaW5lZC5zdGFydFRpbWUgfHwgbnVsbCxcbiAgICAgICAgICAgICAgICBlbmRUaW1lOiByZWZpbmVkLmVuZFRpbWUgfHwgbnVsbCxcbiAgICAgICAgICAgICAgICBzdGFydFJlY3VyOiByZWZpbmVkLnN0YXJ0UmVjdXIgPyBkYXRlRW52LmNyZWF0ZU1hcmtlcihyZWZpbmVkLnN0YXJ0UmVjdXIpIDogbnVsbCxcbiAgICAgICAgICAgICAgICBlbmRSZWN1cjogcmVmaW5lZC5lbmRSZWN1ciA/IGRhdGVFbnYuY3JlYXRlTWFya2VyKHJlZmluZWQuZW5kUmVjdXIpIDogbnVsbCxcbiAgICAgICAgICAgICAgICBkYXRlRW52LFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGxldCBkdXJhdGlvbjtcbiAgICAgICAgICAgIGlmIChyZWZpbmVkLmR1cmF0aW9uKSB7XG4gICAgICAgICAgICAgICAgZHVyYXRpb24gPSByZWZpbmVkLmR1cmF0aW9uO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFkdXJhdGlvbiAmJiByZWZpbmVkLnN0YXJ0VGltZSAmJiByZWZpbmVkLmVuZFRpbWUpIHtcbiAgICAgICAgICAgICAgICBkdXJhdGlvbiA9IHN1YnRyYWN0RHVyYXRpb25zKHJlZmluZWQuZW5kVGltZSwgcmVmaW5lZC5zdGFydFRpbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBhbGxEYXlHdWVzczogQm9vbGVhbighcmVmaW5lZC5zdGFydFRpbWUgJiYgIXJlZmluZWQuZW5kVGltZSksXG4gICAgICAgICAgICAgICAgZHVyYXRpb24sXG4gICAgICAgICAgICAgICAgdHlwZURhdGE6IHJlY3VycmluZ0RhdGEsIC8vIGRvZXNuJ3QgbmVlZCBlbmRUaW1lIGFueW1vcmUgYnV0IG9oIHdlbGxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfSxcbiAgICBleHBhbmQodHlwZURhdGEsIGZyYW1pbmdSYW5nZSwgZGF0ZUVudikge1xuICAgICAgICBsZXQgY2xpcHBlZEZyYW1pbmdSYW5nZSA9IGludGVyc2VjdFJhbmdlcyhmcmFtaW5nUmFuZ2UsIHsgc3RhcnQ6IHR5cGVEYXRhLnN0YXJ0UmVjdXIsIGVuZDogdHlwZURhdGEuZW5kUmVjdXIgfSk7XG4gICAgICAgIGlmIChjbGlwcGVkRnJhbWluZ1JhbmdlKSB7XG4gICAgICAgICAgICByZXR1cm4gZXhwYW5kUmFuZ2VzKHR5cGVEYXRhLmRheXNPZldlZWssIHR5cGVEYXRhLnN0YXJ0VGltZSwgdHlwZURhdGEuZGF0ZUVudiwgZGF0ZUVudiwgY2xpcHBlZEZyYW1pbmdSYW5nZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFtdO1xuICAgIH0sXG59O1xuY29uc3Qgc2ltcGxlUmVjdXJyaW5nRXZlbnRzUGx1Z2luID0gY3JlYXRlUGx1Z2luKHtcbiAgICBuYW1lOiAnc2ltcGxlLXJlY3VycmluZy1ldmVudCcsXG4gICAgcmVjdXJyaW5nVHlwZXM6IFtyZWN1cnJpbmddLFxuICAgIGV2ZW50UmVmaW5lcnM6IFNJTVBMRV9SRUNVUlJJTkdfUkVGSU5FUlMsXG59KTtcbmZ1bmN0aW9uIGV4cGFuZFJhbmdlcyhkYXlzT2ZXZWVrLCBzdGFydFRpbWUsIGV2ZW50RGF0ZUVudiwgY2FsZW5kYXJEYXRlRW52LCBmcmFtaW5nUmFuZ2UpIHtcbiAgICBsZXQgZG93SGFzaCA9IGRheXNPZldlZWsgPyBhcnJheVRvSGFzaChkYXlzT2ZXZWVrKSA6IG51bGw7XG4gICAgbGV0IGRheU1hcmtlciA9IHN0YXJ0T2ZEYXkoZnJhbWluZ1JhbmdlLnN0YXJ0KTtcbiAgICBsZXQgZW5kTWFya2VyID0gZnJhbWluZ1JhbmdlLmVuZDtcbiAgICBsZXQgaW5zdGFuY2VTdGFydHMgPSBbXTtcbiAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vZnVsbGNhbGVuZGFyL2Z1bGxjYWxlbmRhci9pc3N1ZXMvNzkzNFxuICAgIGlmIChzdGFydFRpbWUpIHtcbiAgICAgICAgaWYgKHN0YXJ0VGltZS5taWxsaXNlY29uZHMgPCAwKSB7XG4gICAgICAgICAgICAvLyBwb3NzaWJsZSBmb3IgbmV4dC1kYXkgdG8gaGF2ZSBuZWdhdGl2ZSBidXNpbmVzcyBob3VycyB0aGF0IGdvIGludG8gY3VycmVudCBkYXlcbiAgICAgICAgICAgIGVuZE1hcmtlciA9IGFkZERheXMoZW5kTWFya2VyLCAxKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChzdGFydFRpbWUubWlsbGlzZWNvbmRzID49IDEwMDAgKiA2MCAqIDYwICogMjQpIHtcbiAgICAgICAgICAgIC8vIHBvc3NpYmxlIGZvciBwcmV2LWRheSB0byBoYXZlID4yNGhyIGJ1c2luZXNzIGhvdXJzIHRoYXQgZ28gaW50byBjdXJyZW50IGRheVxuICAgICAgICAgICAgZGF5TWFya2VyID0gYWRkRGF5cyhkYXlNYXJrZXIsIC0xKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICB3aGlsZSAoZGF5TWFya2VyIDwgZW5kTWFya2VyKSB7XG4gICAgICAgIGxldCBpbnN0YW5jZVN0YXJ0O1xuICAgICAgICAvLyBpZiBldmVyeWRheSwgb3IgdGhpcyBwYXJ0aWN1bGFyIGRheS1vZi13ZWVrXG4gICAgICAgIGlmICghZG93SGFzaCB8fCBkb3dIYXNoW2RheU1hcmtlci5nZXRVVENEYXkoKV0pIHtcbiAgICAgICAgICAgIGlmIChzdGFydFRpbWUpIHtcbiAgICAgICAgICAgICAgICBpbnN0YW5jZVN0YXJ0ID0gY2FsZW5kYXJEYXRlRW52LmFkZChkYXlNYXJrZXIsIHN0YXJ0VGltZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBpbnN0YW5jZVN0YXJ0ID0gZGF5TWFya2VyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaW5zdGFuY2VTdGFydHMucHVzaChjYWxlbmRhckRhdGVFbnYuY3JlYXRlTWFya2VyKGV2ZW50RGF0ZUVudi50b0RhdGUoaW5zdGFuY2VTdGFydCkpKTtcbiAgICAgICAgfVxuICAgICAgICBkYXlNYXJrZXIgPSBhZGREYXlzKGRheU1hcmtlciwgMSk7XG4gICAgfVxuICAgIHJldHVybiBpbnN0YW5jZVN0YXJ0cztcbn1cblxuY29uc3QgY2hhbmdlSGFuZGxlclBsdWdpbiA9IGNyZWF0ZVBsdWdpbih7XG4gICAgbmFtZTogJ2NoYW5nZS1oYW5kbGVyJyxcbiAgICBvcHRpb25DaGFuZ2VIYW5kbGVyczoge1xuICAgICAgICBldmVudHMoZXZlbnRzLCBjb250ZXh0KSB7XG4gICAgICAgICAgICBoYW5kbGVFdmVudFNvdXJjZXMoW2V2ZW50c10sIGNvbnRleHQpO1xuICAgICAgICB9LFxuICAgICAgICBldmVudFNvdXJjZXM6IGhhbmRsZUV2ZW50U291cmNlcyxcbiAgICB9LFxufSk7XG4vKlxuQlVHOiBpZiBgZXZlbnRgIHdhcyBzdXBwbGllZCwgYWxsIHByZXZpb3VzbHktZ2l2ZW4gYGV2ZW50U291cmNlc2Agd2lsbCBiZSB3aXBlZCBvdXRcbiovXG5mdW5jdGlvbiBoYW5kbGVFdmVudFNvdXJjZXMoaW5wdXRzLCBjb250ZXh0KSB7XG4gICAgbGV0IHVuZm91bmRTb3VyY2VzID0gaGFzaFZhbHVlc1RvQXJyYXkoY29udGV4dC5nZXRDdXJyZW50RGF0YSgpLmV2ZW50U291cmNlcyk7XG4gICAgaWYgKHVuZm91bmRTb3VyY2VzLmxlbmd0aCA9PT0gMSAmJlxuICAgICAgICBpbnB1dHMubGVuZ3RoID09PSAxICYmXG4gICAgICAgIEFycmF5LmlzQXJyYXkodW5mb3VuZFNvdXJjZXNbMF0uX3JhdykgJiZcbiAgICAgICAgQXJyYXkuaXNBcnJheShpbnB1dHNbMF0pKSB7XG4gICAgICAgIGNvbnRleHQuZGlzcGF0Y2goe1xuICAgICAgICAgICAgdHlwZTogJ1JFU0VUX1JBV19FVkVOVFMnLFxuICAgICAgICAgICAgc291cmNlSWQ6IHVuZm91bmRTb3VyY2VzWzBdLnNvdXJjZUlkLFxuICAgICAgICAgICAgcmF3RXZlbnRzOiBpbnB1dHNbMF0sXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGxldCBuZXdJbnB1dHMgPSBbXTtcbiAgICBmb3IgKGxldCBpbnB1dCBvZiBpbnB1dHMpIHtcbiAgICAgICAgbGV0IGlucHV0Rm91bmQgPSBmYWxzZTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB1bmZvdW5kU291cmNlcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICAgICAgaWYgKHVuZm91bmRTb3VyY2VzW2ldLl9yYXcgPT09IGlucHV0KSB7XG4gICAgICAgICAgICAgICAgdW5mb3VuZFNvdXJjZXMuc3BsaWNlKGksIDEpOyAvLyBkZWxldGVcbiAgICAgICAgICAgICAgICBpbnB1dEZvdW5kID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoIWlucHV0Rm91bmQpIHtcbiAgICAgICAgICAgIG5ld0lucHV0cy5wdXNoKGlucHV0KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBmb3IgKGxldCB1bmZvdW5kU291cmNlIG9mIHVuZm91bmRTb3VyY2VzKSB7XG4gICAgICAgIGNvbnRleHQuZGlzcGF0Y2goe1xuICAgICAgICAgICAgdHlwZTogJ1JFTU9WRV9FVkVOVF9TT1VSQ0UnLFxuICAgICAgICAgICAgc291cmNlSWQ6IHVuZm91bmRTb3VyY2Uuc291cmNlSWQsXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBmb3IgKGxldCBuZXdJbnB1dCBvZiBuZXdJbnB1dHMpIHtcbiAgICAgICAgY29udGV4dC5jYWxlbmRhckFwaS5hZGRFdmVudFNvdXJjZShuZXdJbnB1dCk7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBoYW5kbGVEYXRlUHJvZmlsZShkYXRlUHJvZmlsZSwgY29udGV4dCkge1xuICAgIGNvbnRleHQuZW1pdHRlci50cmlnZ2VyKCdkYXRlc1NldCcsIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgYnVpbGRSYW5nZUFwaVdpdGhUaW1lWm9uZShkYXRlUHJvZmlsZS5hY3RpdmVSYW5nZSwgY29udGV4dC5kYXRlRW52KSksIHsgdmlldzogY29udGV4dC52aWV3QXBpIH0pKTtcbn1cblxuZnVuY3Rpb24gaGFuZGxlRXZlbnRTdG9yZShldmVudFN0b3JlLCBjb250ZXh0KSB7XG4gICAgbGV0IHsgZW1pdHRlciB9ID0gY29udGV4dDtcbiAgICBpZiAoZW1pdHRlci5oYXNIYW5kbGVycygnZXZlbnRzU2V0JykpIHtcbiAgICAgICAgZW1pdHRlci50cmlnZ2VyKCdldmVudHNTZXQnLCBidWlsZEV2ZW50QXBpcyhldmVudFN0b3JlLCBjb250ZXh0KSk7XG4gICAgfVxufVxuXG4vKlxudGhpcyBhcnJheSBpcyBleHBvc2VkIG9uIHRoZSByb290IG5hbWVzcGFjZSBzbyB0aGF0IFVNRCBwbHVnaW5zIGNhbiBhZGQgdG8gaXQuXG5zZWUgdGhlIHJvbGx1cC1idW5kbGVzIHNjcmlwdC5cbiovXG5jb25zdCBnbG9iYWxQbHVnaW5zID0gW1xuICAgIGFycmF5RXZlbnRTb3VyY2VQbHVnaW4sXG4gICAgZnVuY0V2ZW50U291cmNlUGx1Z2luLFxuICAgIGpzb25GZWVkRXZlbnRTb3VyY2VQbHVnaW4sXG4gICAgc2ltcGxlUmVjdXJyaW5nRXZlbnRzUGx1Z2luLFxuICAgIGNoYW5nZUhhbmRsZXJQbHVnaW4sXG4gICAgY3JlYXRlUGx1Z2luKHtcbiAgICAgICAgbmFtZTogJ21pc2MnLFxuICAgICAgICBpc0xvYWRpbmdGdW5jczogW1xuICAgICAgICAgICAgKHN0YXRlKSA9PiBjb21wdXRlRXZlbnRTb3VyY2VzTG9hZGluZyhzdGF0ZS5ldmVudFNvdXJjZXMpLFxuICAgICAgICBdLFxuICAgICAgICBwcm9wU2V0SGFuZGxlcnM6IHtcbiAgICAgICAgICAgIGRhdGVQcm9maWxlOiBoYW5kbGVEYXRlUHJvZmlsZSxcbiAgICAgICAgICAgIGV2ZW50U3RvcmU6IGhhbmRsZUV2ZW50U3RvcmUsXG4gICAgICAgIH0sXG4gICAgfSksXG5dO1xuXG5jbGFzcyBUYXNrUnVubmVyIHtcbiAgICBjb25zdHJ1Y3RvcihydW5UYXNrT3B0aW9uLCBkcmFpbmVkT3B0aW9uKSB7XG4gICAgICAgIHRoaXMucnVuVGFza09wdGlvbiA9IHJ1blRhc2tPcHRpb247XG4gICAgICAgIHRoaXMuZHJhaW5lZE9wdGlvbiA9IGRyYWluZWRPcHRpb247XG4gICAgICAgIHRoaXMucXVldWUgPSBbXTtcbiAgICAgICAgdGhpcy5kZWxheWVkUnVubmVyID0gbmV3IERlbGF5ZWRSdW5uZXIodGhpcy5kcmFpbi5iaW5kKHRoaXMpKTtcbiAgICB9XG4gICAgcmVxdWVzdCh0YXNrLCBkZWxheSkge1xuICAgICAgICB0aGlzLnF1ZXVlLnB1c2godGFzayk7XG4gICAgICAgIHRoaXMuZGVsYXllZFJ1bm5lci5yZXF1ZXN0KGRlbGF5KTtcbiAgICB9XG4gICAgcGF1c2Uoc2NvcGUpIHtcbiAgICAgICAgdGhpcy5kZWxheWVkUnVubmVyLnBhdXNlKHNjb3BlKTtcbiAgICB9XG4gICAgcmVzdW1lKHNjb3BlLCBmb3JjZSkge1xuICAgICAgICB0aGlzLmRlbGF5ZWRSdW5uZXIucmVzdW1lKHNjb3BlLCBmb3JjZSk7XG4gICAgfVxuICAgIGRyYWluKCkge1xuICAgICAgICBsZXQgeyBxdWV1ZSB9ID0gdGhpcztcbiAgICAgICAgd2hpbGUgKHF1ZXVlLmxlbmd0aCkge1xuICAgICAgICAgICAgbGV0IGNvbXBsZXRlZFRhc2tzID0gW107XG4gICAgICAgICAgICBsZXQgdGFzaztcbiAgICAgICAgICAgIHdoaWxlICgodGFzayA9IHF1ZXVlLnNoaWZ0KCkpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5ydW5UYXNrKHRhc2spO1xuICAgICAgICAgICAgICAgIGNvbXBsZXRlZFRhc2tzLnB1c2godGFzayk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmRyYWluZWQoY29tcGxldGVkVGFza3MpO1xuICAgICAgICB9IC8vIGtlZXAgZ29pbmcsIGluIGNhc2UgbmV3IHRhc2tzIHdlcmUgYWRkZWQgaW4gdGhlIGRyYWluZWQgaGFuZGxlclxuICAgIH1cbiAgICBydW5UYXNrKHRhc2spIHtcbiAgICAgICAgaWYgKHRoaXMucnVuVGFza09wdGlvbikge1xuICAgICAgICAgICAgdGhpcy5ydW5UYXNrT3B0aW9uKHRhc2spO1xuICAgICAgICB9XG4gICAgfVxuICAgIGRyYWluZWQoY29tcGxldGVkVGFza3MpIHtcbiAgICAgICAgaWYgKHRoaXMuZHJhaW5lZE9wdGlvbikge1xuICAgICAgICAgICAgdGhpcy5kcmFpbmVkT3B0aW9uKGNvbXBsZXRlZFRhc2tzKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuLy8gQ29tcHV0ZXMgd2hhdCB0aGUgdGl0bGUgYXQgdGhlIHRvcCBvZiB0aGUgY2FsZW5kYXJBcGkgc2hvdWxkIGJlIGZvciB0aGlzIHZpZXdcbmZ1bmN0aW9uIGJ1aWxkVGl0bGUoZGF0ZVByb2ZpbGUsIHZpZXdPcHRpb25zLCBkYXRlRW52KSB7XG4gICAgbGV0IHJhbmdlO1xuICAgIC8vIGZvciB2aWV3cyB0aGF0IHNwYW4gYSBsYXJnZSB1bml0IG9mIHRpbWUsIHNob3cgdGhlIHByb3BlciBpbnRlcnZhbCwgaWdub3Jpbmcgc3RyYXkgZGF5cyBiZWZvcmUgYW5kIGFmdGVyXG4gICAgaWYgKC9eKHllYXJ8bW9udGgpJC8udGVzdChkYXRlUHJvZmlsZS5jdXJyZW50UmFuZ2VVbml0KSkge1xuICAgICAgICByYW5nZSA9IGRhdGVQcm9maWxlLmN1cnJlbnRSYW5nZTtcbiAgICB9XG4gICAgZWxzZSB7IC8vIGZvciBkYXkgdW5pdHMgb3Igc21hbGxlciwgdXNlIHRoZSBhY3R1YWwgZGF5IHJhbmdlXG4gICAgICAgIHJhbmdlID0gZGF0ZVByb2ZpbGUuYWN0aXZlUmFuZ2U7XG4gICAgfVxuICAgIHJldHVybiBkYXRlRW52LmZvcm1hdFJhbmdlKHJhbmdlLnN0YXJ0LCByYW5nZS5lbmQsIGNyZWF0ZUZvcm1hdHRlcih2aWV3T3B0aW9ucy50aXRsZUZvcm1hdCB8fCBidWlsZFRpdGxlRm9ybWF0KGRhdGVQcm9maWxlKSksIHtcbiAgICAgICAgaXNFbmRFeGNsdXNpdmU6IGRhdGVQcm9maWxlLmlzUmFuZ2VBbGxEYXksXG4gICAgICAgIGRlZmF1bHRTZXBhcmF0b3I6IHZpZXdPcHRpb25zLnRpdGxlUmFuZ2VTZXBhcmF0b3IsXG4gICAgfSk7XG59XG4vLyBHZW5lcmF0ZXMgdGhlIGZvcm1hdCBzdHJpbmcgdGhhdCBzaG91bGQgYmUgdXNlZCB0byBnZW5lcmF0ZSB0aGUgdGl0bGUgZm9yIHRoZSBjdXJyZW50IGRhdGUgcmFuZ2UuXG4vLyBBdHRlbXB0cyB0byBjb21wdXRlIHRoZSBtb3N0IGFwcHJvcHJpYXRlIGZvcm1hdCBpZiBub3QgZXhwbGljaXRseSBzcGVjaWZpZWQgd2l0aCBgdGl0bGVGb3JtYXRgLlxuZnVuY3Rpb24gYnVpbGRUaXRsZUZvcm1hdChkYXRlUHJvZmlsZSkge1xuICAgIGxldCB7IGN1cnJlbnRSYW5nZVVuaXQgfSA9IGRhdGVQcm9maWxlO1xuICAgIGlmIChjdXJyZW50UmFuZ2VVbml0ID09PSAneWVhcicpIHtcbiAgICAgICAgcmV0dXJuIHsgeWVhcjogJ251bWVyaWMnIH07XG4gICAgfVxuICAgIGlmIChjdXJyZW50UmFuZ2VVbml0ID09PSAnbW9udGgnKSB7XG4gICAgICAgIHJldHVybiB7IHllYXI6ICdudW1lcmljJywgbW9udGg6ICdsb25nJyB9OyAvLyBsaWtlIFwiU2VwdGVtYmVyIDIwMTRcIlxuICAgIH1cbiAgICBsZXQgZGF5cyA9IGRpZmZXaG9sZURheXMoZGF0ZVByb2ZpbGUuY3VycmVudFJhbmdlLnN0YXJ0LCBkYXRlUHJvZmlsZS5jdXJyZW50UmFuZ2UuZW5kKTtcbiAgICBpZiAoZGF5cyAhPT0gbnVsbCAmJiBkYXlzID4gMSkge1xuICAgICAgICAvLyBtdWx0aS1kYXkgcmFuZ2UuIHNob3J0ZXIsIGxpa2UgXCJTZXAgOSAtIDEwIDIwMTRcIlxuICAgICAgICByZXR1cm4geyB5ZWFyOiAnbnVtZXJpYycsIG1vbnRoOiAnc2hvcnQnLCBkYXk6ICdudW1lcmljJyB9O1xuICAgIH1cbiAgICAvLyBvbmUgZGF5LiBsb25nZXIsIGxpa2UgXCJTZXB0ZW1iZXIgOSAyMDE0XCJcbiAgICByZXR1cm4geyB5ZWFyOiAnbnVtZXJpYycsIG1vbnRoOiAnbG9uZycsIGRheTogJ251bWVyaWMnIH07XG59XG5cbi8qXG5UT0RPOiB0ZXN0IHN3aXRjaGluZyB0aW1lem9uZXMgd2hlbiBOTyB0aW1lem9uZSBwbHVnaW5cbiovXG5jbGFzcyBDYWxlbmRhck5vd01hbmFnZXIge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLnJlc2V0TGlzdGVuZXJzID0gbmV3IFNldCgpO1xuICAgIH1cbiAgICBoYW5kbGVJbnB1dChkYXRlRW52LCAvLyB3aWxsIGNoYW5nZSBpZiB0aW1lem9uZSBzZXR1cCBjaGFuZ2VkXG4gICAgbm93SW5wdXQpIHtcbiAgICAgICAgY29uc3Qgb2xkRGF0ZUVudiA9IHRoaXMuZGF0ZUVudjtcbiAgICAgICAgaWYgKGRhdGVFbnYgIT09IG9sZERhdGVFbnYpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygbm93SW5wdXQgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICB0aGlzLm5vd0ZuID0gbm93SW5wdXQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICghb2xkRGF0ZUVudikgeyAvLyBmaXJzdCB0aW1lP1xuICAgICAgICAgICAgICAgIHRoaXMubm93QW5jaG9yRGF0ZSA9IGRhdGVFbnYudG9EYXRlKG5vd0lucHV0XG4gICAgICAgICAgICAgICAgICAgID8gZGF0ZUVudi5jcmVhdGVNYXJrZXIobm93SW5wdXQpXG4gICAgICAgICAgICAgICAgICAgIDogZGF0ZUVudi5jcmVhdGVOb3dNYXJrZXIoKSk7XG4gICAgICAgICAgICAgICAgdGhpcy5ub3dBbmNob3JRdWVyaWVkID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuZGF0ZUVudiA9IGRhdGVFbnY7XG4gICAgICAgICAgICAvLyBub3QgZmlyc3QgdGltZT8gZmlyZSByZXNldCBoYW5kbGVyc1xuICAgICAgICAgICAgaWYgKG9sZERhdGVFbnYpIHtcbiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IHJlc2V0TGlzdGVuZXIgb2YgdGhpcy5yZXNldExpc3RlbmVycy52YWx1ZXMoKSkge1xuICAgICAgICAgICAgICAgICAgICByZXNldExpc3RlbmVyKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIGdldERhdGVNYXJrZXIoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm5vd0FuY2hvckRhdGVcbiAgICAgICAgICAgID8gdGhpcy5kYXRlRW52LnRpbWVzdGFtcFRvTWFya2VyKHRoaXMubm93QW5jaG9yRGF0ZS52YWx1ZU9mKCkgK1xuICAgICAgICAgICAgICAgIChEYXRlLm5vdygpIC0gdGhpcy5ub3dBbmNob3JRdWVyaWVkKSlcbiAgICAgICAgICAgIDogdGhpcy5kYXRlRW52LmNyZWF0ZU1hcmtlcih0aGlzLm5vd0ZuKCkpO1xuICAgIH1cbiAgICBhZGRSZXNldExpc3RlbmVyKGhhbmRsZXIpIHtcbiAgICAgICAgdGhpcy5yZXNldExpc3RlbmVycy5hZGQoaGFuZGxlcik7XG4gICAgfVxuICAgIHJlbW92ZVJlc2V0TGlzdGVuZXIoaGFuZGxlcikge1xuICAgICAgICB0aGlzLnJlc2V0TGlzdGVuZXJzLmRlbGV0ZShoYW5kbGVyKTtcbiAgICB9XG59XG5cbi8vIGluIGZ1dHVyZSByZWZhY3RvciwgZG8gdGhlIHJlZHV4LXN0eWxlIGZ1bmN0aW9uKHN0YXRlPWluaXRpYWwpIGZvciBpbml0aWFsLXN0YXRlXG4vLyBhbHNvLCB3aGF0ZXZlciBpcyBoYXBwZW5pbmcgaW4gY29uc3RydWN0b3IsIGhhdmUgaXQgaGFwcGVuIGluIGFjdGlvbiBxdWV1ZSB0b29cbmNsYXNzIENhbGVuZGFyRGF0YU1hbmFnZXIge1xuICAgIGNvbnN0cnVjdG9yKHByb3BzKSB7XG4gICAgICAgIHRoaXMuY29tcHV0ZUN1cnJlbnRWaWV3RGF0YSA9IG1lbW9pemUodGhpcy5fY29tcHV0ZUN1cnJlbnRWaWV3RGF0YSk7XG4gICAgICAgIHRoaXMub3JnYW5pemVSYXdMb2NhbGVzID0gbWVtb2l6ZShvcmdhbml6ZVJhd0xvY2FsZXMpO1xuICAgICAgICB0aGlzLmJ1aWxkTG9jYWxlID0gbWVtb2l6ZShidWlsZExvY2FsZSk7XG4gICAgICAgIHRoaXMuYnVpbGRQbHVnaW5Ib29rcyA9IGJ1aWxkQnVpbGRQbHVnaW5Ib29rcygpO1xuICAgICAgICB0aGlzLmJ1aWxkRGF0ZUVudiA9IG1lbW9pemUoYnVpbGREYXRlRW52JDEpO1xuICAgICAgICB0aGlzLmJ1aWxkVGhlbWUgPSBtZW1vaXplKGJ1aWxkVGhlbWUpO1xuICAgICAgICB0aGlzLnBhcnNlVG9vbGJhcnMgPSBtZW1vaXplKHBhcnNlVG9vbGJhcnMpO1xuICAgICAgICB0aGlzLmJ1aWxkVmlld1NwZWNzID0gbWVtb2l6ZShidWlsZFZpZXdTcGVjcyk7XG4gICAgICAgIHRoaXMuYnVpbGREYXRlUHJvZmlsZUdlbmVyYXRvciA9IG1lbW9pemVPYmpBcmcoYnVpbGREYXRlUHJvZmlsZUdlbmVyYXRvcik7XG4gICAgICAgIHRoaXMuYnVpbGRWaWV3QXBpID0gbWVtb2l6ZShidWlsZFZpZXdBcGkpO1xuICAgICAgICB0aGlzLmJ1aWxkVmlld1VpUHJvcHMgPSBtZW1vaXplT2JqQXJnKGJ1aWxkVmlld1VpUHJvcHMpO1xuICAgICAgICB0aGlzLmJ1aWxkRXZlbnRVaUJ5U291cmNlID0gbWVtb2l6ZShidWlsZEV2ZW50VWlCeVNvdXJjZSwgaXNQcm9wc0VxdWFsKTtcbiAgICAgICAgdGhpcy5idWlsZEV2ZW50VWlCYXNlcyA9IG1lbW9pemUoYnVpbGRFdmVudFVpQmFzZXMpO1xuICAgICAgICB0aGlzLnBhcnNlQ29udGV4dEJ1c2luZXNzSG91cnMgPSBtZW1vaXplT2JqQXJnKHBhcnNlQ29udGV4dEJ1c2luZXNzSG91cnMpO1xuICAgICAgICB0aGlzLmJ1aWxkVGl0bGUgPSBtZW1vaXplKGJ1aWxkVGl0bGUpO1xuICAgICAgICB0aGlzLm5vd01hbmFnZXIgPSBuZXcgQ2FsZW5kYXJOb3dNYW5hZ2VyKCk7XG4gICAgICAgIHRoaXMuZW1pdHRlciA9IG5ldyBFbWl0dGVyKCk7XG4gICAgICAgIHRoaXMuYWN0aW9uUnVubmVyID0gbmV3IFRhc2tSdW5uZXIodGhpcy5faGFuZGxlQWN0aW9uLmJpbmQodGhpcyksIHRoaXMudXBkYXRlRGF0YS5iaW5kKHRoaXMpKTtcbiAgICAgICAgdGhpcy5jdXJyZW50Q2FsZW5kYXJPcHRpb25zSW5wdXQgPSB7fTtcbiAgICAgICAgdGhpcy5jdXJyZW50Q2FsZW5kYXJPcHRpb25zUmVmaW5lZCA9IHt9O1xuICAgICAgICB0aGlzLmN1cnJlbnRWaWV3T3B0aW9uc0lucHV0ID0ge307XG4gICAgICAgIHRoaXMuY3VycmVudFZpZXdPcHRpb25zUmVmaW5lZCA9IHt9O1xuICAgICAgICB0aGlzLmN1cnJlbnRDYWxlbmRhck9wdGlvbnNSZWZpbmVycyA9IHt9O1xuICAgICAgICB0aGlzLm9wdGlvbnNGb3JSZWZpbmluZyA9IFtdO1xuICAgICAgICB0aGlzLm9wdGlvbnNGb3JIYW5kbGluZyA9IFtdO1xuICAgICAgICB0aGlzLmdldEN1cnJlbnREYXRhID0gKCkgPT4gdGhpcy5kYXRhO1xuICAgICAgICB0aGlzLmRpc3BhdGNoID0gKGFjdGlvbikgPT4ge1xuICAgICAgICAgICAgdGhpcy5hY3Rpb25SdW5uZXIucmVxdWVzdChhY3Rpb24pOyAvLyBwcm90ZWN0cyBhZ2FpbnN0IHJlY3Vyc2l2ZSBjYWxscyB0byBfaGFuZGxlQWN0aW9uXG4gICAgICAgIH07XG4gICAgICAgIHRoaXMucHJvcHMgPSBwcm9wcztcbiAgICAgICAgdGhpcy5hY3Rpb25SdW5uZXIucGF1c2UoKTtcbiAgICAgICAgdGhpcy5ub3dNYW5hZ2VyID0gbmV3IENhbGVuZGFyTm93TWFuYWdlcigpO1xuICAgICAgICBsZXQgZHluYW1pY09wdGlvbk92ZXJyaWRlcyA9IHt9O1xuICAgICAgICBsZXQgb3B0aW9uc0RhdGEgPSB0aGlzLmNvbXB1dGVPcHRpb25zRGF0YShwcm9wcy5vcHRpb25PdmVycmlkZXMsIGR5bmFtaWNPcHRpb25PdmVycmlkZXMsIHByb3BzLmNhbGVuZGFyQXBpKTtcbiAgICAgICAgbGV0IGN1cnJlbnRWaWV3VHlwZSA9IG9wdGlvbnNEYXRhLmNhbGVuZGFyT3B0aW9ucy5pbml0aWFsVmlldyB8fCBvcHRpb25zRGF0YS5wbHVnaW5Ib29rcy5pbml0aWFsVmlldztcbiAgICAgICAgbGV0IGN1cnJlbnRWaWV3RGF0YSA9IHRoaXMuY29tcHV0ZUN1cnJlbnRWaWV3RGF0YShjdXJyZW50Vmlld1R5cGUsIG9wdGlvbnNEYXRhLCBwcm9wcy5vcHRpb25PdmVycmlkZXMsIGR5bmFtaWNPcHRpb25PdmVycmlkZXMpO1xuICAgICAgICAvLyB3aXJlIHRoaW5ncyB1cFxuICAgICAgICAvLyBUT0RPOiBub3QgRFJZXG4gICAgICAgIHByb3BzLmNhbGVuZGFyQXBpLmN1cnJlbnREYXRhTWFuYWdlciA9IHRoaXM7XG4gICAgICAgIHRoaXMuZW1pdHRlci5zZXRUaGlzQ29udGV4dChwcm9wcy5jYWxlbmRhckFwaSk7XG4gICAgICAgIHRoaXMuZW1pdHRlci5zZXRPcHRpb25zKGN1cnJlbnRWaWV3RGF0YS5vcHRpb25zKTtcbiAgICAgICAgbGV0IGNhbGVuZGFyQ29udGV4dCA9IHtcbiAgICAgICAgICAgIG5vd01hbmFnZXI6IHRoaXMubm93TWFuYWdlcixcbiAgICAgICAgICAgIGRhdGVFbnY6IG9wdGlvbnNEYXRhLmRhdGVFbnYsXG4gICAgICAgICAgICBvcHRpb25zOiBvcHRpb25zRGF0YS5jYWxlbmRhck9wdGlvbnMsXG4gICAgICAgICAgICBwbHVnaW5Ib29rczogb3B0aW9uc0RhdGEucGx1Z2luSG9va3MsXG4gICAgICAgICAgICBjYWxlbmRhckFwaTogcHJvcHMuY2FsZW5kYXJBcGksXG4gICAgICAgICAgICBkaXNwYXRjaDogdGhpcy5kaXNwYXRjaCxcbiAgICAgICAgICAgIGVtaXR0ZXI6IHRoaXMuZW1pdHRlcixcbiAgICAgICAgICAgIGdldEN1cnJlbnREYXRhOiB0aGlzLmdldEN1cnJlbnREYXRhLFxuICAgICAgICB9O1xuICAgICAgICBsZXQgY3VycmVudERhdGUgPSBnZXRJbml0aWFsRGF0ZShvcHRpb25zRGF0YS5jYWxlbmRhck9wdGlvbnMsIG9wdGlvbnNEYXRhLmRhdGVFbnYsIHRoaXMubm93TWFuYWdlcik7XG4gICAgICAgIGxldCBkYXRlUHJvZmlsZSA9IGN1cnJlbnRWaWV3RGF0YS5kYXRlUHJvZmlsZUdlbmVyYXRvci5idWlsZChjdXJyZW50RGF0ZSk7XG4gICAgICAgIGlmICghcmFuZ2VDb250YWluc01hcmtlcihkYXRlUHJvZmlsZS5hY3RpdmVSYW5nZSwgY3VycmVudERhdGUpKSB7XG4gICAgICAgICAgICBjdXJyZW50RGF0ZSA9IGRhdGVQcm9maWxlLmN1cnJlbnRSYW5nZS5zdGFydDtcbiAgICAgICAgfVxuICAgICAgICAvLyBuZWVkcyB0byBiZSBhZnRlciBzZXRUaGlzQ29udGV4dFxuICAgICAgICBmb3IgKGxldCBjYWxsYmFjayBvZiBvcHRpb25zRGF0YS5wbHVnaW5Ib29rcy5jb250ZXh0SW5pdCkge1xuICAgICAgICAgICAgY2FsbGJhY2soY2FsZW5kYXJDb250ZXh0KTtcbiAgICAgICAgfVxuICAgICAgICAvLyBOT1QgRFJZXG4gICAgICAgIGxldCBldmVudFNvdXJjZXMgPSBpbml0RXZlbnRTb3VyY2VzKG9wdGlvbnNEYXRhLmNhbGVuZGFyT3B0aW9ucywgZGF0ZVByb2ZpbGUsIGNhbGVuZGFyQ29udGV4dCk7XG4gICAgICAgIGxldCBpbml0aWFsU3RhdGUgPSB7XG4gICAgICAgICAgICBkeW5hbWljT3B0aW9uT3ZlcnJpZGVzLFxuICAgICAgICAgICAgY3VycmVudFZpZXdUeXBlLFxuICAgICAgICAgICAgY3VycmVudERhdGUsXG4gICAgICAgICAgICBkYXRlUHJvZmlsZSxcbiAgICAgICAgICAgIGJ1c2luZXNzSG91cnM6IHRoaXMucGFyc2VDb250ZXh0QnVzaW5lc3NIb3VycyhjYWxlbmRhckNvbnRleHQpLFxuICAgICAgICAgICAgZXZlbnRTb3VyY2VzLFxuICAgICAgICAgICAgZXZlbnRVaUJhc2VzOiB7fSxcbiAgICAgICAgICAgIGV2ZW50U3RvcmU6IGNyZWF0ZUVtcHR5RXZlbnRTdG9yZSgpLFxuICAgICAgICAgICAgcmVuZGVyYWJsZUV2ZW50U3RvcmU6IGNyZWF0ZUVtcHR5RXZlbnRTdG9yZSgpLFxuICAgICAgICAgICAgZGF0ZVNlbGVjdGlvbjogbnVsbCxcbiAgICAgICAgICAgIGV2ZW50U2VsZWN0aW9uOiAnJyxcbiAgICAgICAgICAgIGV2ZW50RHJhZzogbnVsbCxcbiAgICAgICAgICAgIGV2ZW50UmVzaXplOiBudWxsLFxuICAgICAgICAgICAgc2VsZWN0aW9uQ29uZmlnOiB0aGlzLmJ1aWxkVmlld1VpUHJvcHMoY2FsZW5kYXJDb250ZXh0KS5zZWxlY3Rpb25Db25maWcsXG4gICAgICAgIH07XG4gICAgICAgIGxldCBjb250ZXh0QW5kU3RhdGUgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGNhbGVuZGFyQ29udGV4dCksIGluaXRpYWxTdGF0ZSk7XG4gICAgICAgIGZvciAobGV0IHJlZHVjZXIgb2Ygb3B0aW9uc0RhdGEucGx1Z2luSG9va3MucmVkdWNlcnMpIHtcbiAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oaW5pdGlhbFN0YXRlLCByZWR1Y2VyKG51bGwsIG51bGwsIGNvbnRleHRBbmRTdGF0ZSkpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjb21wdXRlSXNMb2FkaW5nKGluaXRpYWxTdGF0ZSwgY2FsZW5kYXJDb250ZXh0KSkge1xuICAgICAgICAgICAgdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ2xvYWRpbmcnLCB0cnVlKTsgLy8gTk9UIERSWVxuICAgICAgICB9XG4gICAgICAgIHRoaXMuc3RhdGUgPSBpbml0aWFsU3RhdGU7XG4gICAgICAgIHRoaXMudXBkYXRlRGF0YSgpO1xuICAgICAgICB0aGlzLmFjdGlvblJ1bm5lci5yZXN1bWUoKTtcbiAgICB9XG4gICAgcmVzZXRPcHRpb25zKG9wdGlvbk92ZXJyaWRlcywgY2hhbmdlZE9wdGlvbk5hbWVzKSB7XG4gICAgICAgIGxldCB7IHByb3BzIH0gPSB0aGlzO1xuICAgICAgICBpZiAoY2hhbmdlZE9wdGlvbk5hbWVzID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHByb3BzLm9wdGlvbk92ZXJyaWRlcyA9IG9wdGlvbk92ZXJyaWRlcztcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHByb3BzLm9wdGlvbk92ZXJyaWRlcyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgKHByb3BzLm9wdGlvbk92ZXJyaWRlcyB8fCB7fSkpLCBvcHRpb25PdmVycmlkZXMpO1xuICAgICAgICAgICAgdGhpcy5vcHRpb25zRm9yUmVmaW5pbmcucHVzaCguLi5jaGFuZ2VkT3B0aW9uTmFtZXMpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjaGFuZ2VkT3B0aW9uTmFtZXMgPT09IHVuZGVmaW5lZCB8fCBjaGFuZ2VkT3B0aW9uTmFtZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLmFjdGlvblJ1bm5lci5yZXF1ZXN0KHtcbiAgICAgICAgICAgICAgICB0eXBlOiAnTk9USElORycsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBfaGFuZGxlQWN0aW9uKGFjdGlvbikge1xuICAgICAgICBsZXQgeyBwcm9wcywgc3RhdGUsIGVtaXR0ZXIgfSA9IHRoaXM7XG4gICAgICAgIGxldCBkeW5hbWljT3B0aW9uT3ZlcnJpZGVzID0gcmVkdWNlRHluYW1pY09wdGlvbk92ZXJyaWRlcyhzdGF0ZS5keW5hbWljT3B0aW9uT3ZlcnJpZGVzLCBhY3Rpb24pO1xuICAgICAgICBsZXQgb3B0aW9uc0RhdGEgPSB0aGlzLmNvbXB1dGVPcHRpb25zRGF0YShwcm9wcy5vcHRpb25PdmVycmlkZXMsIGR5bmFtaWNPcHRpb25PdmVycmlkZXMsIHByb3BzLmNhbGVuZGFyQXBpKTtcbiAgICAgICAgbGV0IGN1cnJlbnRWaWV3VHlwZSA9IHJlZHVjZVZpZXdUeXBlKHN0YXRlLmN1cnJlbnRWaWV3VHlwZSwgYWN0aW9uKTtcbiAgICAgICAgbGV0IGN1cnJlbnRWaWV3RGF0YSA9IHRoaXMuY29tcHV0ZUN1cnJlbnRWaWV3RGF0YShjdXJyZW50Vmlld1R5cGUsIG9wdGlvbnNEYXRhLCBwcm9wcy5vcHRpb25PdmVycmlkZXMsIGR5bmFtaWNPcHRpb25PdmVycmlkZXMpO1xuICAgICAgICAvLyB3aXJlIHRoaW5ncyB1cFxuICAgICAgICAvLyBUT0RPOiBub3QgRFJZXG4gICAgICAgIHByb3BzLmNhbGVuZGFyQXBpLmN1cnJlbnREYXRhTWFuYWdlciA9IHRoaXM7XG4gICAgICAgIGVtaXR0ZXIuc2V0VGhpc0NvbnRleHQocHJvcHMuY2FsZW5kYXJBcGkpO1xuICAgICAgICBlbWl0dGVyLnNldE9wdGlvbnMoY3VycmVudFZpZXdEYXRhLm9wdGlvbnMpO1xuICAgICAgICBsZXQgY2FsZW5kYXJDb250ZXh0ID0ge1xuICAgICAgICAgICAgbm93TWFuYWdlcjogdGhpcy5ub3dNYW5hZ2VyLFxuICAgICAgICAgICAgZGF0ZUVudjogb3B0aW9uc0RhdGEuZGF0ZUVudixcbiAgICAgICAgICAgIG9wdGlvbnM6IG9wdGlvbnNEYXRhLmNhbGVuZGFyT3B0aW9ucyxcbiAgICAgICAgICAgIHBsdWdpbkhvb2tzOiBvcHRpb25zRGF0YS5wbHVnaW5Ib29rcyxcbiAgICAgICAgICAgIGNhbGVuZGFyQXBpOiBwcm9wcy5jYWxlbmRhckFwaSxcbiAgICAgICAgICAgIGRpc3BhdGNoOiB0aGlzLmRpc3BhdGNoLFxuICAgICAgICAgICAgZW1pdHRlcixcbiAgICAgICAgICAgIGdldEN1cnJlbnREYXRhOiB0aGlzLmdldEN1cnJlbnREYXRhLFxuICAgICAgICB9O1xuICAgICAgICBsZXQgeyBjdXJyZW50RGF0ZSwgZGF0ZVByb2ZpbGUgfSA9IHN0YXRlO1xuICAgICAgICBpZiAodGhpcy5kYXRhICYmIHRoaXMuZGF0YS5kYXRlUHJvZmlsZUdlbmVyYXRvciAhPT0gY3VycmVudFZpZXdEYXRhLmRhdGVQcm9maWxlR2VuZXJhdG9yKSB7IC8vIGhhY2tcbiAgICAgICAgICAgIGRhdGVQcm9maWxlID0gY3VycmVudFZpZXdEYXRhLmRhdGVQcm9maWxlR2VuZXJhdG9yLmJ1aWxkKGN1cnJlbnREYXRlKTtcbiAgICAgICAgfVxuICAgICAgICBjdXJyZW50RGF0ZSA9IHJlZHVjZUN1cnJlbnREYXRlKGN1cnJlbnREYXRlLCBhY3Rpb24pO1xuICAgICAgICBkYXRlUHJvZmlsZSA9IHJlZHVjZURhdGVQcm9maWxlKGRhdGVQcm9maWxlLCBhY3Rpb24sIGN1cnJlbnREYXRlLCBjdXJyZW50Vmlld0RhdGEuZGF0ZVByb2ZpbGVHZW5lcmF0b3IpO1xuICAgICAgICBpZiAoYWN0aW9uLnR5cGUgPT09ICdQUkVWJyB8fCAvLyBUT0RPOiBtb3ZlIHRoaXMgbG9naWMgaW50byBEYXRlUHJvZmlsZUdlbmVyYXRvclxuICAgICAgICAgICAgYWN0aW9uLnR5cGUgPT09ICdORVhUJyB8fCAvLyBcIlxuICAgICAgICAgICAgIXJhbmdlQ29udGFpbnNNYXJrZXIoZGF0ZVByb2ZpbGUuY3VycmVudFJhbmdlLCBjdXJyZW50RGF0ZSkpIHtcbiAgICAgICAgICAgIGN1cnJlbnREYXRlID0gZGF0ZVByb2ZpbGUuY3VycmVudFJhbmdlLnN0YXJ0O1xuICAgICAgICB9XG4gICAgICAgIGxldCBldmVudFNvdXJjZXMgPSByZWR1Y2VFdmVudFNvdXJjZXMoc3RhdGUuZXZlbnRTb3VyY2VzLCBhY3Rpb24sIGRhdGVQcm9maWxlLCBjYWxlbmRhckNvbnRleHQpO1xuICAgICAgICBsZXQgZXZlbnRTdG9yZSA9IHJlZHVjZUV2ZW50U3RvcmUoc3RhdGUuZXZlbnRTdG9yZSwgYWN0aW9uLCBldmVudFNvdXJjZXMsIGRhdGVQcm9maWxlLCBjYWxlbmRhckNvbnRleHQpO1xuICAgICAgICBsZXQgaXNFdmVudHNMb2FkaW5nID0gY29tcHV0ZUV2ZW50U291cmNlc0xvYWRpbmcoZXZlbnRTb3VyY2VzKTsgLy8gQkFELiBhbHNvIGNhbGxlZCBpbiB0aGlzIGZ1bmMgaW4gY29tcHV0ZUlzTG9hZGluZ1xuICAgICAgICBsZXQgcmVuZGVyYWJsZUV2ZW50U3RvcmUgPSAoaXNFdmVudHNMb2FkaW5nICYmICFjdXJyZW50Vmlld0RhdGEub3B0aW9ucy5wcm9ncmVzc2l2ZUV2ZW50UmVuZGVyaW5nKSA/XG4gICAgICAgICAgICAoc3RhdGUucmVuZGVyYWJsZUV2ZW50U3RvcmUgfHwgZXZlbnRTdG9yZSkgOiAvLyB0cnkgZnJvbSBwcmV2aW91cyBzdGF0ZVxuICAgICAgICAgICAgZXZlbnRTdG9yZTtcbiAgICAgICAgbGV0IHsgZXZlbnRVaVNpbmdsZUJhc2UsIHNlbGVjdGlvbkNvbmZpZyB9ID0gdGhpcy5idWlsZFZpZXdVaVByb3BzKGNhbGVuZGFyQ29udGV4dCk7IC8vIHdpbGwgbWVtb2l6ZSBvYmpcbiAgICAgICAgbGV0IGV2ZW50VWlCeVNvdXJjZSA9IHRoaXMuYnVpbGRFdmVudFVpQnlTb3VyY2UoZXZlbnRTb3VyY2VzKTtcbiAgICAgICAgbGV0IGV2ZW50VWlCYXNlcyA9IHRoaXMuYnVpbGRFdmVudFVpQmFzZXMocmVuZGVyYWJsZUV2ZW50U3RvcmUuZGVmcywgZXZlbnRVaVNpbmdsZUJhc2UsIGV2ZW50VWlCeVNvdXJjZSk7XG4gICAgICAgIGxldCBuZXdTdGF0ZSA9IHtcbiAgICAgICAgICAgIGR5bmFtaWNPcHRpb25PdmVycmlkZXMsXG4gICAgICAgICAgICBjdXJyZW50Vmlld1R5cGUsXG4gICAgICAgICAgICBjdXJyZW50RGF0ZSxcbiAgICAgICAgICAgIGRhdGVQcm9maWxlLFxuICAgICAgICAgICAgZXZlbnRTb3VyY2VzLFxuICAgICAgICAgICAgZXZlbnRTdG9yZSxcbiAgICAgICAgICAgIHJlbmRlcmFibGVFdmVudFN0b3JlLFxuICAgICAgICAgICAgc2VsZWN0aW9uQ29uZmlnLFxuICAgICAgICAgICAgZXZlbnRVaUJhc2VzLFxuICAgICAgICAgICAgYnVzaW5lc3NIb3VyczogdGhpcy5wYXJzZUNvbnRleHRCdXNpbmVzc0hvdXJzKGNhbGVuZGFyQ29udGV4dCksXG4gICAgICAgICAgICBkYXRlU2VsZWN0aW9uOiByZWR1Y2VEYXRlU2VsZWN0aW9uKHN0YXRlLmRhdGVTZWxlY3Rpb24sIGFjdGlvbiksXG4gICAgICAgICAgICBldmVudFNlbGVjdGlvbjogcmVkdWNlU2VsZWN0ZWRFdmVudChzdGF0ZS5ldmVudFNlbGVjdGlvbiwgYWN0aW9uKSxcbiAgICAgICAgICAgIGV2ZW50RHJhZzogcmVkdWNlRXZlbnREcmFnKHN0YXRlLmV2ZW50RHJhZywgYWN0aW9uKSxcbiAgICAgICAgICAgIGV2ZW50UmVzaXplOiByZWR1Y2VFdmVudFJlc2l6ZShzdGF0ZS5ldmVudFJlc2l6ZSwgYWN0aW9uKSxcbiAgICAgICAgfTtcbiAgICAgICAgbGV0IGNvbnRleHRBbmRTdGF0ZSA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgY2FsZW5kYXJDb250ZXh0KSwgbmV3U3RhdGUpO1xuICAgICAgICBmb3IgKGxldCByZWR1Y2VyIG9mIG9wdGlvbnNEYXRhLnBsdWdpbkhvb2tzLnJlZHVjZXJzKSB7XG4gICAgICAgICAgICBPYmplY3QuYXNzaWduKG5ld1N0YXRlLCByZWR1Y2VyKHN0YXRlLCBhY3Rpb24sIGNvbnRleHRBbmRTdGF0ZSkpOyAvLyBnaXZlIHRoZSBPTEQgc3RhdGUsIGZvciBvbGQgdmFsdWVcbiAgICAgICAgfVxuICAgICAgICBsZXQgd2FzTG9hZGluZyA9IGNvbXB1dGVJc0xvYWRpbmcoc3RhdGUsIGNhbGVuZGFyQ29udGV4dCk7XG4gICAgICAgIGxldCBpc0xvYWRpbmcgPSBjb21wdXRlSXNMb2FkaW5nKG5ld1N0YXRlLCBjYWxlbmRhckNvbnRleHQpO1xuICAgICAgICAvLyBUT0RPOiB1c2UgcHJvcFNldEhhbmRsZXJzIGluIHBsdWdpbiBzeXN0ZW1cbiAgICAgICAgaWYgKCF3YXNMb2FkaW5nICYmIGlzTG9hZGluZykge1xuICAgICAgICAgICAgZW1pdHRlci50cmlnZ2VyKCdsb2FkaW5nJywgdHJ1ZSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAod2FzTG9hZGluZyAmJiAhaXNMb2FkaW5nKSB7XG4gICAgICAgICAgICBlbWl0dGVyLnRyaWdnZXIoJ2xvYWRpbmcnLCBmYWxzZSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zdGF0ZSA9IG5ld1N0YXRlO1xuICAgICAgICBpZiAocHJvcHMub25BY3Rpb24pIHtcbiAgICAgICAgICAgIHByb3BzLm9uQWN0aW9uKGFjdGlvbik7XG4gICAgICAgIH1cbiAgICB9XG4gICAgdXBkYXRlRGF0YSgpIHtcbiAgICAgICAgbGV0IHsgcHJvcHMsIHN0YXRlIH0gPSB0aGlzO1xuICAgICAgICBsZXQgb2xkRGF0YSA9IHRoaXMuZGF0YTtcbiAgICAgICAgbGV0IG9wdGlvbnNEYXRhID0gdGhpcy5jb21wdXRlT3B0aW9uc0RhdGEocHJvcHMub3B0aW9uT3ZlcnJpZGVzLCBzdGF0ZS5keW5hbWljT3B0aW9uT3ZlcnJpZGVzLCBwcm9wcy5jYWxlbmRhckFwaSk7XG4gICAgICAgIGxldCBjdXJyZW50Vmlld0RhdGEgPSB0aGlzLmNvbXB1dGVDdXJyZW50Vmlld0RhdGEoc3RhdGUuY3VycmVudFZpZXdUeXBlLCBvcHRpb25zRGF0YSwgcHJvcHMub3B0aW9uT3ZlcnJpZGVzLCBzdGF0ZS5keW5hbWljT3B0aW9uT3ZlcnJpZGVzKTtcbiAgICAgICAgbGV0IGRhdGEgPSB0aGlzLmRhdGEgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7IG5vd01hbmFnZXI6IHRoaXMubm93TWFuYWdlciwgdmlld1RpdGxlOiB0aGlzLmJ1aWxkVGl0bGUoc3RhdGUuZGF0ZVByb2ZpbGUsIGN1cnJlbnRWaWV3RGF0YS5vcHRpb25zLCBvcHRpb25zRGF0YS5kYXRlRW52KSwgY2FsZW5kYXJBcGk6IHByb3BzLmNhbGVuZGFyQXBpLCBkaXNwYXRjaDogdGhpcy5kaXNwYXRjaCwgZW1pdHRlcjogdGhpcy5lbWl0dGVyLCBnZXRDdXJyZW50RGF0YTogdGhpcy5nZXRDdXJyZW50RGF0YSB9LCBvcHRpb25zRGF0YSksIGN1cnJlbnRWaWV3RGF0YSksIHN0YXRlKTtcbiAgICAgICAgbGV0IGNoYW5nZUhhbmRsZXJzID0gb3B0aW9uc0RhdGEucGx1Z2luSG9va3Mub3B0aW9uQ2hhbmdlSGFuZGxlcnM7XG4gICAgICAgIGxldCBvbGRDYWxlbmRhck9wdGlvbnMgPSBvbGREYXRhICYmIG9sZERhdGEuY2FsZW5kYXJPcHRpb25zO1xuICAgICAgICBsZXQgbmV3Q2FsZW5kYXJPcHRpb25zID0gb3B0aW9uc0RhdGEuY2FsZW5kYXJPcHRpb25zO1xuICAgICAgICBpZiAob2xkQ2FsZW5kYXJPcHRpb25zICYmIG9sZENhbGVuZGFyT3B0aW9ucyAhPT0gbmV3Q2FsZW5kYXJPcHRpb25zKSB7XG4gICAgICAgICAgICBpZiAob2xkQ2FsZW5kYXJPcHRpb25zLnRpbWVab25lICE9PSBuZXdDYWxlbmRhck9wdGlvbnMudGltZVpvbmUpIHtcbiAgICAgICAgICAgICAgICAvLyBoYWNrXG4gICAgICAgICAgICAgICAgc3RhdGUuZXZlbnRTb3VyY2VzID0gZGF0YS5ldmVudFNvdXJjZXMgPSByZWR1Y2VFdmVudFNvdXJjZXNOZXdUaW1lWm9uZShkYXRhLmV2ZW50U291cmNlcywgc3RhdGUuZGF0ZVByb2ZpbGUsIGRhdGEpO1xuICAgICAgICAgICAgICAgIHN0YXRlLmV2ZW50U3RvcmUgPSBkYXRhLmV2ZW50U3RvcmUgPSByZXpvbmVFdmVudFN0b3JlRGF0ZXMoZGF0YS5ldmVudFN0b3JlLCBvbGREYXRhLmRhdGVFbnYsIGRhdGEuZGF0ZUVudik7XG4gICAgICAgICAgICAgICAgc3RhdGUucmVuZGVyYWJsZUV2ZW50U3RvcmUgPSBkYXRhLnJlbmRlcmFibGVFdmVudFN0b3JlID0gcmV6b25lRXZlbnRTdG9yZURhdGVzKGRhdGEucmVuZGVyYWJsZUV2ZW50U3RvcmUsIG9sZERhdGEuZGF0ZUVudiwgZGF0YS5kYXRlRW52KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZvciAobGV0IG9wdGlvbk5hbWUgaW4gY2hhbmdlSGFuZGxlcnMpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5vcHRpb25zRm9ySGFuZGxpbmcuaW5kZXhPZihvcHRpb25OYW1lKSAhPT0gLTEgfHxcbiAgICAgICAgICAgICAgICAgICAgb2xkQ2FsZW5kYXJPcHRpb25zW29wdGlvbk5hbWVdICE9PSBuZXdDYWxlbmRhck9wdGlvbnNbb3B0aW9uTmFtZV0pIHtcbiAgICAgICAgICAgICAgICAgICAgY2hhbmdlSGFuZGxlcnNbb3B0aW9uTmFtZV0obmV3Q2FsZW5kYXJPcHRpb25zW29wdGlvbk5hbWVdLCBkYXRhKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5vcHRpb25zRm9ySGFuZGxpbmcgPSBbXTtcbiAgICAgICAgaWYgKHByb3BzLm9uRGF0YSkge1xuICAgICAgICAgICAgcHJvcHMub25EYXRhKGRhdGEpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbXB1dGVPcHRpb25zRGF0YShvcHRpb25PdmVycmlkZXMsIGR5bmFtaWNPcHRpb25PdmVycmlkZXMsIGNhbGVuZGFyQXBpKSB7XG4gICAgICAgIC8vIFRPRE86IGJsYWNrbGlzdCBvcHRpb25zIHRoYXQgYXJlIGhhbmRsZWQgYnkgb3B0aW9uQ2hhbmdlSGFuZGxlcnNcbiAgICAgICAgaWYgKCF0aGlzLm9wdGlvbnNGb3JSZWZpbmluZy5sZW5ndGggJiZcbiAgICAgICAgICAgIG9wdGlvbk92ZXJyaWRlcyA9PT0gdGhpcy5zdGFibGVPcHRpb25PdmVycmlkZXMgJiZcbiAgICAgICAgICAgIGR5bmFtaWNPcHRpb25PdmVycmlkZXMgPT09IHRoaXMuc3RhYmxlRHluYW1pY09wdGlvbk92ZXJyaWRlcykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3RhYmxlQ2FsZW5kYXJPcHRpb25zRGF0YTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgeyByZWZpbmVkT3B0aW9ucywgcGx1Z2luSG9va3MsIGxvY2FsZURlZmF1bHRzLCBhdmFpbGFibGVMb2NhbGVEYXRhLCBleHRyYSwgfSA9IHRoaXMucHJvY2Vzc1Jhd0NhbGVuZGFyT3B0aW9ucyhvcHRpb25PdmVycmlkZXMsIGR5bmFtaWNPcHRpb25PdmVycmlkZXMpO1xuICAgICAgICB3YXJuVW5rbm93bk9wdGlvbnMoZXh0cmEpO1xuICAgICAgICBsZXQgZGF0ZUVudiA9IHRoaXMuYnVpbGREYXRlRW52KHJlZmluZWRPcHRpb25zLnRpbWVab25lLCByZWZpbmVkT3B0aW9ucy5sb2NhbGUsIHJlZmluZWRPcHRpb25zLndlZWtOdW1iZXJDYWxjdWxhdGlvbiwgcmVmaW5lZE9wdGlvbnMuZmlyc3REYXksIHJlZmluZWRPcHRpb25zLndlZWtUZXh0LCBwbHVnaW5Ib29rcywgYXZhaWxhYmxlTG9jYWxlRGF0YSwgcmVmaW5lZE9wdGlvbnMuZGVmYXVsdFJhbmdlU2VwYXJhdG9yKTtcbiAgICAgICAgbGV0IHZpZXdTcGVjcyA9IHRoaXMuYnVpbGRWaWV3U3BlY3MocGx1Z2luSG9va3Mudmlld3MsIHRoaXMuc3RhYmxlT3B0aW9uT3ZlcnJpZGVzLCB0aGlzLnN0YWJsZUR5bmFtaWNPcHRpb25PdmVycmlkZXMsIGxvY2FsZURlZmF1bHRzKTtcbiAgICAgICAgbGV0IHRoZW1lID0gdGhpcy5idWlsZFRoZW1lKHJlZmluZWRPcHRpb25zLCBwbHVnaW5Ib29rcyk7XG4gICAgICAgIGxldCB0b29sYmFyQ29uZmlnID0gdGhpcy5wYXJzZVRvb2xiYXJzKHJlZmluZWRPcHRpb25zLCB0aGlzLnN0YWJsZU9wdGlvbk92ZXJyaWRlcywgdGhlbWUsIHZpZXdTcGVjcywgY2FsZW5kYXJBcGkpO1xuICAgICAgICByZXR1cm4gdGhpcy5zdGFibGVDYWxlbmRhck9wdGlvbnNEYXRhID0ge1xuICAgICAgICAgICAgY2FsZW5kYXJPcHRpb25zOiByZWZpbmVkT3B0aW9ucyxcbiAgICAgICAgICAgIHBsdWdpbkhvb2tzLFxuICAgICAgICAgICAgZGF0ZUVudixcbiAgICAgICAgICAgIHZpZXdTcGVjcyxcbiAgICAgICAgICAgIHRoZW1lLFxuICAgICAgICAgICAgdG9vbGJhckNvbmZpZyxcbiAgICAgICAgICAgIGxvY2FsZURlZmF1bHRzLFxuICAgICAgICAgICAgYXZhaWxhYmxlUmF3TG9jYWxlczogYXZhaWxhYmxlTG9jYWxlRGF0YS5tYXAsXG4gICAgICAgIH07XG4gICAgfVxuICAgIC8vIGFsd2F5cyBjYWxsZWQgZnJvbSBiZWhpbmQgYSBtZW1vaXplclxuICAgIHByb2Nlc3NSYXdDYWxlbmRhck9wdGlvbnMob3B0aW9uT3ZlcnJpZGVzLCBkeW5hbWljT3B0aW9uT3ZlcnJpZGVzKSB7XG4gICAgICAgIGxldCB7IGxvY2FsZXMsIGxvY2FsZSB9ID0gbWVyZ2VSYXdPcHRpb25zKFtcbiAgICAgICAgICAgIEJBU0VfT1BUSU9OX0RFRkFVTFRTLFxuICAgICAgICAgICAgb3B0aW9uT3ZlcnJpZGVzLFxuICAgICAgICAgICAgZHluYW1pY09wdGlvbk92ZXJyaWRlcyxcbiAgICAgICAgXSk7XG4gICAgICAgIGxldCBhdmFpbGFibGVMb2NhbGVEYXRhID0gdGhpcy5vcmdhbml6ZVJhd0xvY2FsZXMobG9jYWxlcyk7XG4gICAgICAgIGxldCBhdmFpbGFibGVSYXdMb2NhbGVzID0gYXZhaWxhYmxlTG9jYWxlRGF0YS5tYXA7XG4gICAgICAgIGxldCBsb2NhbGVEZWZhdWx0cyA9IHRoaXMuYnVpbGRMb2NhbGUobG9jYWxlIHx8IGF2YWlsYWJsZUxvY2FsZURhdGEuZGVmYXVsdENvZGUsIGF2YWlsYWJsZVJhd0xvY2FsZXMpLm9wdGlvbnM7XG4gICAgICAgIGxldCBwbHVnaW5Ib29rcyA9IHRoaXMuYnVpbGRQbHVnaW5Ib29rcyhvcHRpb25PdmVycmlkZXMucGx1Z2lucyB8fCBbXSwgZ2xvYmFsUGx1Z2lucyk7XG4gICAgICAgIGxldCByZWZpbmVycyA9IHRoaXMuY3VycmVudENhbGVuZGFyT3B0aW9uc1JlZmluZXJzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBCQVNFX09QVElPTl9SRUZJTkVSUyksIENBTEVOREFSX0xJU1RFTkVSX1JFRklORVJTKSwgQ0FMRU5EQVJfT1BUSU9OX1JFRklORVJTKSwgcGx1Z2luSG9va3MubGlzdGVuZXJSZWZpbmVycyksIHBsdWdpbkhvb2tzLm9wdGlvblJlZmluZXJzKTtcbiAgICAgICAgbGV0IGV4dHJhID0ge307XG4gICAgICAgIGxldCByYXcgPSBtZXJnZVJhd09wdGlvbnMoW1xuICAgICAgICAgICAgQkFTRV9PUFRJT05fREVGQVVMVFMsXG4gICAgICAgICAgICBsb2NhbGVEZWZhdWx0cyxcbiAgICAgICAgICAgIG9wdGlvbk92ZXJyaWRlcyxcbiAgICAgICAgICAgIGR5bmFtaWNPcHRpb25PdmVycmlkZXMsXG4gICAgICAgIF0pO1xuICAgICAgICBsZXQgcmVmaW5lZCA9IHt9O1xuICAgICAgICBsZXQgY3VycmVudFJhdyA9IHRoaXMuY3VycmVudENhbGVuZGFyT3B0aW9uc0lucHV0O1xuICAgICAgICBsZXQgY3VycmVudFJlZmluZWQgPSB0aGlzLmN1cnJlbnRDYWxlbmRhck9wdGlvbnNSZWZpbmVkO1xuICAgICAgICBsZXQgYW55Q2hhbmdlcyA9IGZhbHNlO1xuICAgICAgICBmb3IgKGxldCBvcHRpb25OYW1lIGluIHJhdykge1xuICAgICAgICAgICAgaWYgKHRoaXMub3B0aW9uc0ZvclJlZmluaW5nLmluZGV4T2Yob3B0aW9uTmFtZSkgPT09IC0xICYmIChyYXdbb3B0aW9uTmFtZV0gPT09IGN1cnJlbnRSYXdbb3B0aW9uTmFtZV0gfHwgKENPTVBMRVhfT1BUSU9OX0NPTVBBUkFUT1JTW29wdGlvbk5hbWVdICYmXG4gICAgICAgICAgICAgICAgKG9wdGlvbk5hbWUgaW4gY3VycmVudFJhdykgJiZcbiAgICAgICAgICAgICAgICBDT01QTEVYX09QVElPTl9DT01QQVJBVE9SU1tvcHRpb25OYW1lXShjdXJyZW50UmF3W29wdGlvbk5hbWVdLCByYXdbb3B0aW9uTmFtZV0pKSkpIHtcbiAgICAgICAgICAgICAgICByZWZpbmVkW29wdGlvbk5hbWVdID0gY3VycmVudFJlZmluZWRbb3B0aW9uTmFtZV07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmIChyZWZpbmVyc1tvcHRpb25OYW1lXSkge1xuICAgICAgICAgICAgICAgIHJlZmluZWRbb3B0aW9uTmFtZV0gPSByZWZpbmVyc1tvcHRpb25OYW1lXShyYXdbb3B0aW9uTmFtZV0pO1xuICAgICAgICAgICAgICAgIGFueUNoYW5nZXMgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgZXh0cmFbb3B0aW9uTmFtZV0gPSBjdXJyZW50UmF3W29wdGlvbk5hbWVdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChhbnlDaGFuZ2VzKSB7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRDYWxlbmRhck9wdGlvbnNJbnB1dCA9IHJhdztcbiAgICAgICAgICAgIHRoaXMuY3VycmVudENhbGVuZGFyT3B0aW9uc1JlZmluZWQgPSByZWZpbmVkO1xuICAgICAgICAgICAgdGhpcy5zdGFibGVPcHRpb25PdmVycmlkZXMgPSBvcHRpb25PdmVycmlkZXM7XG4gICAgICAgICAgICB0aGlzLnN0YWJsZUR5bmFtaWNPcHRpb25PdmVycmlkZXMgPSBkeW5hbWljT3B0aW9uT3ZlcnJpZGVzO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMub3B0aW9uc0ZvckhhbmRsaW5nLnB1c2goLi4udGhpcy5vcHRpb25zRm9yUmVmaW5pbmcpO1xuICAgICAgICB0aGlzLm9wdGlvbnNGb3JSZWZpbmluZyA9IFtdO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgcmF3T3B0aW9uczogdGhpcy5jdXJyZW50Q2FsZW5kYXJPcHRpb25zSW5wdXQsXG4gICAgICAgICAgICByZWZpbmVkT3B0aW9uczogdGhpcy5jdXJyZW50Q2FsZW5kYXJPcHRpb25zUmVmaW5lZCxcbiAgICAgICAgICAgIHBsdWdpbkhvb2tzLFxuICAgICAgICAgICAgYXZhaWxhYmxlTG9jYWxlRGF0YSxcbiAgICAgICAgICAgIGxvY2FsZURlZmF1bHRzLFxuICAgICAgICAgICAgZXh0cmEsXG4gICAgICAgIH07XG4gICAgfVxuICAgIF9jb21wdXRlQ3VycmVudFZpZXdEYXRhKHZpZXdUeXBlLCBvcHRpb25zRGF0YSwgb3B0aW9uT3ZlcnJpZGVzLCBkeW5hbWljT3B0aW9uT3ZlcnJpZGVzKSB7XG4gICAgICAgIGxldCB2aWV3U3BlYyA9IG9wdGlvbnNEYXRhLnZpZXdTcGVjc1t2aWV3VHlwZV07XG4gICAgICAgIGlmICghdmlld1NwZWMpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgdmlld1R5cGUgXCIke3ZpZXdUeXBlfVwiIGlzIG5vdCBhdmFpbGFibGUuIFBsZWFzZSBtYWtlIHN1cmUgeW91J3ZlIGxvYWRlZCBhbGwgbmVjY2Vzc2FyeSBwbHVnaW5zYCk7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHsgcmVmaW5lZE9wdGlvbnMsIGV4dHJhIH0gPSB0aGlzLnByb2Nlc3NSYXdWaWV3T3B0aW9ucyh2aWV3U3BlYywgb3B0aW9uc0RhdGEucGx1Z2luSG9va3MsIG9wdGlvbnNEYXRhLmxvY2FsZURlZmF1bHRzLCBvcHRpb25PdmVycmlkZXMsIGR5bmFtaWNPcHRpb25PdmVycmlkZXMpO1xuICAgICAgICB3YXJuVW5rbm93bk9wdGlvbnMoZXh0cmEpO1xuICAgICAgICB0aGlzLm5vd01hbmFnZXIuaGFuZGxlSW5wdXQob3B0aW9uc0RhdGEuZGF0ZUVudiwgcmVmaW5lZE9wdGlvbnMubm93KTtcbiAgICAgICAgbGV0IGRhdGVQcm9maWxlR2VuZXJhdG9yID0gdGhpcy5idWlsZERhdGVQcm9maWxlR2VuZXJhdG9yKHtcbiAgICAgICAgICAgIGRhdGVQcm9maWxlR2VuZXJhdG9yQ2xhc3M6IHZpZXdTcGVjLm9wdGlvbkRlZmF1bHRzLmRhdGVQcm9maWxlR2VuZXJhdG9yQ2xhc3MsXG4gICAgICAgICAgICBub3dNYW5hZ2VyOiB0aGlzLm5vd01hbmFnZXIsXG4gICAgICAgICAgICBkdXJhdGlvbjogdmlld1NwZWMuZHVyYXRpb24sXG4gICAgICAgICAgICBkdXJhdGlvblVuaXQ6IHZpZXdTcGVjLmR1cmF0aW9uVW5pdCxcbiAgICAgICAgICAgIHVzZXNNaW5NYXhUaW1lOiB2aWV3U3BlYy5vcHRpb25EZWZhdWx0cy51c2VzTWluTWF4VGltZSxcbiAgICAgICAgICAgIGRhdGVFbnY6IG9wdGlvbnNEYXRhLmRhdGVFbnYsXG4gICAgICAgICAgICBjYWxlbmRhckFwaTogdGhpcy5wcm9wcy5jYWxlbmRhckFwaSxcbiAgICAgICAgICAgIHNsb3RNaW5UaW1lOiByZWZpbmVkT3B0aW9ucy5zbG90TWluVGltZSxcbiAgICAgICAgICAgIHNsb3RNYXhUaW1lOiByZWZpbmVkT3B0aW9ucy5zbG90TWF4VGltZSxcbiAgICAgICAgICAgIHNob3dOb25DdXJyZW50RGF0ZXM6IHJlZmluZWRPcHRpb25zLnNob3dOb25DdXJyZW50RGF0ZXMsXG4gICAgICAgICAgICBkYXlDb3VudDogcmVmaW5lZE9wdGlvbnMuZGF5Q291bnQsXG4gICAgICAgICAgICBkYXRlQWxpZ25tZW50OiByZWZpbmVkT3B0aW9ucy5kYXRlQWxpZ25tZW50LFxuICAgICAgICAgICAgZGF0ZUluY3JlbWVudDogcmVmaW5lZE9wdGlvbnMuZGF0ZUluY3JlbWVudCxcbiAgICAgICAgICAgIGhpZGRlbkRheXM6IHJlZmluZWRPcHRpb25zLmhpZGRlbkRheXMsXG4gICAgICAgICAgICB3ZWVrZW5kczogcmVmaW5lZE9wdGlvbnMud2Vla2VuZHMsXG4gICAgICAgICAgICB2YWxpZFJhbmdlSW5wdXQ6IHJlZmluZWRPcHRpb25zLnZhbGlkUmFuZ2UsXG4gICAgICAgICAgICB2aXNpYmxlUmFuZ2VJbnB1dDogcmVmaW5lZE9wdGlvbnMudmlzaWJsZVJhbmdlLFxuICAgICAgICAgICAgZml4ZWRXZWVrQ291bnQ6IHJlZmluZWRPcHRpb25zLmZpeGVkV2Vla0NvdW50LFxuICAgICAgICB9KTtcbiAgICAgICAgbGV0IHZpZXdBcGkgPSB0aGlzLmJ1aWxkVmlld0FwaSh2aWV3VHlwZSwgdGhpcy5nZXRDdXJyZW50RGF0YSwgb3B0aW9uc0RhdGEuZGF0ZUVudik7XG4gICAgICAgIHJldHVybiB7IHZpZXdTcGVjLCBvcHRpb25zOiByZWZpbmVkT3B0aW9ucywgZGF0ZVByb2ZpbGVHZW5lcmF0b3IsIHZpZXdBcGkgfTtcbiAgICB9XG4gICAgcHJvY2Vzc1Jhd1ZpZXdPcHRpb25zKHZpZXdTcGVjLCBwbHVnaW5Ib29rcywgbG9jYWxlRGVmYXVsdHMsIG9wdGlvbk92ZXJyaWRlcywgZHluYW1pY09wdGlvbk92ZXJyaWRlcykge1xuICAgICAgICBsZXQgcmF3ID0gbWVyZ2VSYXdPcHRpb25zKFtcbiAgICAgICAgICAgIEJBU0VfT1BUSU9OX0RFRkFVTFRTLFxuICAgICAgICAgICAgdmlld1NwZWMub3B0aW9uRGVmYXVsdHMsXG4gICAgICAgICAgICBsb2NhbGVEZWZhdWx0cyxcbiAgICAgICAgICAgIG9wdGlvbk92ZXJyaWRlcyxcbiAgICAgICAgICAgIHZpZXdTcGVjLm9wdGlvbk92ZXJyaWRlcyxcbiAgICAgICAgICAgIGR5bmFtaWNPcHRpb25PdmVycmlkZXMsXG4gICAgICAgIF0pO1xuICAgICAgICBsZXQgcmVmaW5lcnMgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgQkFTRV9PUFRJT05fUkVGSU5FUlMpLCBDQUxFTkRBUl9MSVNURU5FUl9SRUZJTkVSUyksIENBTEVOREFSX09QVElPTl9SRUZJTkVSUyksIFZJRVdfT1BUSU9OX1JFRklORVJTKSwgcGx1Z2luSG9va3MubGlzdGVuZXJSZWZpbmVycyksIHBsdWdpbkhvb2tzLm9wdGlvblJlZmluZXJzKTtcbiAgICAgICAgbGV0IHJlZmluZWQgPSB7fTtcbiAgICAgICAgbGV0IGN1cnJlbnRSYXcgPSB0aGlzLmN1cnJlbnRWaWV3T3B0aW9uc0lucHV0O1xuICAgICAgICBsZXQgY3VycmVudFJlZmluZWQgPSB0aGlzLmN1cnJlbnRWaWV3T3B0aW9uc1JlZmluZWQ7XG4gICAgICAgIGxldCBhbnlDaGFuZ2VzID0gZmFsc2U7XG4gICAgICAgIGxldCBleHRyYSA9IHt9O1xuICAgICAgICBmb3IgKGxldCBvcHRpb25OYW1lIGluIHJhdykge1xuICAgICAgICAgICAgaWYgKHJhd1tvcHRpb25OYW1lXSA9PT0gY3VycmVudFJhd1tvcHRpb25OYW1lXSB8fFxuICAgICAgICAgICAgICAgIChDT01QTEVYX09QVElPTl9DT01QQVJBVE9SU1tvcHRpb25OYW1lXSAmJlxuICAgICAgICAgICAgICAgICAgICBDT01QTEVYX09QVElPTl9DT01QQVJBVE9SU1tvcHRpb25OYW1lXShyYXdbb3B0aW9uTmFtZV0sIGN1cnJlbnRSYXdbb3B0aW9uTmFtZV0pKSkge1xuICAgICAgICAgICAgICAgIHJlZmluZWRbb3B0aW9uTmFtZV0gPSBjdXJyZW50UmVmaW5lZFtvcHRpb25OYW1lXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmIChyYXdbb3B0aW9uTmFtZV0gPT09IHRoaXMuY3VycmVudENhbGVuZGFyT3B0aW9uc0lucHV0W29wdGlvbk5hbWVdIHx8XG4gICAgICAgICAgICAgICAgICAgIChDT01QTEVYX09QVElPTl9DT01QQVJBVE9SU1tvcHRpb25OYW1lXSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgQ09NUExFWF9PUFRJT05fQ09NUEFSQVRPUlNbb3B0aW9uTmFtZV0ocmF3W29wdGlvbk5hbWVdLCB0aGlzLmN1cnJlbnRDYWxlbmRhck9wdGlvbnNJbnB1dFtvcHRpb25OYW1lXSkpKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChvcHRpb25OYW1lIGluIHRoaXMuY3VycmVudENhbGVuZGFyT3B0aW9uc1JlZmluZWQpIHsgLy8gbWlnaHQgYmUgYW4gXCJleHRyYVwiIHByb3BcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlZmluZWRbb3B0aW9uTmFtZV0gPSB0aGlzLmN1cnJlbnRDYWxlbmRhck9wdGlvbnNSZWZpbmVkW29wdGlvbk5hbWVdO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKHJlZmluZXJzW29wdGlvbk5hbWVdKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlZmluZWRbb3B0aW9uTmFtZV0gPSByZWZpbmVyc1tvcHRpb25OYW1lXShyYXdbb3B0aW9uTmFtZV0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZXh0cmFbb3B0aW9uTmFtZV0gPSByYXdbb3B0aW9uTmFtZV07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGFueUNoYW5nZXMgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChhbnlDaGFuZ2VzKSB7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRWaWV3T3B0aW9uc0lucHV0ID0gcmF3O1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50Vmlld09wdGlvbnNSZWZpbmVkID0gcmVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgcmF3T3B0aW9uczogdGhpcy5jdXJyZW50Vmlld09wdGlvbnNJbnB1dCxcbiAgICAgICAgICAgIHJlZmluZWRPcHRpb25zOiB0aGlzLmN1cnJlbnRWaWV3T3B0aW9uc1JlZmluZWQsXG4gICAgICAgICAgICBleHRyYSxcbiAgICAgICAgfTtcbiAgICB9XG59XG5mdW5jdGlvbiBidWlsZERhdGVFbnYkMSh0aW1lWm9uZSwgZXhwbGljaXRMb2NhbGUsIHdlZWtOdW1iZXJDYWxjdWxhdGlvbiwgZmlyc3REYXksIHdlZWtUZXh0LCBwbHVnaW5Ib29rcywgYXZhaWxhYmxlTG9jYWxlRGF0YSwgZGVmYXVsdFNlcGFyYXRvcikge1xuICAgIGxldCBsb2NhbGUgPSBidWlsZExvY2FsZShleHBsaWNpdExvY2FsZSB8fCBhdmFpbGFibGVMb2NhbGVEYXRhLmRlZmF1bHRDb2RlLCBhdmFpbGFibGVMb2NhbGVEYXRhLm1hcCk7XG4gICAgcmV0dXJuIG5ldyBEYXRlRW52KHtcbiAgICAgICAgY2FsZW5kYXJTeXN0ZW06ICdncmVnb3J5JyxcbiAgICAgICAgdGltZVpvbmUsXG4gICAgICAgIG5hbWVkVGltZVpvbmVJbXBsOiBwbHVnaW5Ib29rcy5uYW1lZFRpbWVab25lZEltcGwsXG4gICAgICAgIGxvY2FsZSxcbiAgICAgICAgd2Vla051bWJlckNhbGN1bGF0aW9uLFxuICAgICAgICBmaXJzdERheSxcbiAgICAgICAgd2Vla1RleHQsXG4gICAgICAgIGNtZEZvcm1hdHRlcjogcGx1Z2luSG9va3MuY21kRm9ybWF0dGVyLFxuICAgICAgICBkZWZhdWx0U2VwYXJhdG9yLFxuICAgIH0pO1xufVxuZnVuY3Rpb24gYnVpbGRUaGVtZShvcHRpb25zLCBwbHVnaW5Ib29rcykge1xuICAgIGxldCBUaGVtZUNsYXNzID0gcGx1Z2luSG9va3MudGhlbWVDbGFzc2VzW29wdGlvbnMudGhlbWVTeXN0ZW1dIHx8IFN0YW5kYXJkVGhlbWU7XG4gICAgcmV0dXJuIG5ldyBUaGVtZUNsYXNzKG9wdGlvbnMpO1xufVxuZnVuY3Rpb24gYnVpbGREYXRlUHJvZmlsZUdlbmVyYXRvcihwcm9wcykge1xuICAgIGxldCBEYXRlUHJvZmlsZUdlbmVyYXRvckNsYXNzID0gcHJvcHMuZGF0ZVByb2ZpbGVHZW5lcmF0b3JDbGFzcyB8fCBEYXRlUHJvZmlsZUdlbmVyYXRvcjtcbiAgICByZXR1cm4gbmV3IERhdGVQcm9maWxlR2VuZXJhdG9yQ2xhc3MocHJvcHMpO1xufVxuZnVuY3Rpb24gYnVpbGRWaWV3QXBpKHR5cGUsIGdldEN1cnJlbnREYXRhLCBkYXRlRW52KSB7XG4gICAgcmV0dXJuIG5ldyBWaWV3SW1wbCh0eXBlLCBnZXRDdXJyZW50RGF0YSwgZGF0ZUVudik7XG59XG5mdW5jdGlvbiBidWlsZEV2ZW50VWlCeVNvdXJjZShldmVudFNvdXJjZXMpIHtcbiAgICByZXR1cm4gbWFwSGFzaChldmVudFNvdXJjZXMsIChldmVudFNvdXJjZSkgPT4gZXZlbnRTb3VyY2UudWkpO1xufVxuZnVuY3Rpb24gYnVpbGRFdmVudFVpQmFzZXMoZXZlbnREZWZzLCBldmVudFVpU2luZ2xlQmFzZSwgZXZlbnRVaUJ5U291cmNlKSB7XG4gICAgbGV0IGV2ZW50VWlCYXNlcyA9IHsgJyc6IGV2ZW50VWlTaW5nbGVCYXNlIH07XG4gICAgZm9yIChsZXQgZGVmSWQgaW4gZXZlbnREZWZzKSB7XG4gICAgICAgIGxldCBkZWYgPSBldmVudERlZnNbZGVmSWRdO1xuICAgICAgICBpZiAoZGVmLnNvdXJjZUlkICYmIGV2ZW50VWlCeVNvdXJjZVtkZWYuc291cmNlSWRdKSB7XG4gICAgICAgICAgICBldmVudFVpQmFzZXNbZGVmSWRdID0gZXZlbnRVaUJ5U291cmNlW2RlZi5zb3VyY2VJZF07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGV2ZW50VWlCYXNlcztcbn1cbmZ1bmN0aW9uIGJ1aWxkVmlld1VpUHJvcHMoY2FsZW5kYXJDb250ZXh0KSB7XG4gICAgbGV0IHsgb3B0aW9ucyB9ID0gY2FsZW5kYXJDb250ZXh0O1xuICAgIHJldHVybiB7XG4gICAgICAgIGV2ZW50VWlTaW5nbGVCYXNlOiBjcmVhdGVFdmVudFVpKHtcbiAgICAgICAgICAgIGRpc3BsYXk6IG9wdGlvbnMuZXZlbnREaXNwbGF5LFxuICAgICAgICAgICAgZWRpdGFibGU6IG9wdGlvbnMuZWRpdGFibGUsXG4gICAgICAgICAgICBzdGFydEVkaXRhYmxlOiBvcHRpb25zLmV2ZW50U3RhcnRFZGl0YWJsZSxcbiAgICAgICAgICAgIGR1cmF0aW9uRWRpdGFibGU6IG9wdGlvbnMuZXZlbnREdXJhdGlvbkVkaXRhYmxlLFxuICAgICAgICAgICAgY29uc3RyYWludDogb3B0aW9ucy5ldmVudENvbnN0cmFpbnQsXG4gICAgICAgICAgICBvdmVybGFwOiB0eXBlb2Ygb3B0aW9ucy5ldmVudE92ZXJsYXAgPT09ICdib29sZWFuJyA/IG9wdGlvbnMuZXZlbnRPdmVybGFwIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgYWxsb3c6IG9wdGlvbnMuZXZlbnRBbGxvdyxcbiAgICAgICAgICAgIGJhY2tncm91bmRDb2xvcjogb3B0aW9ucy5ldmVudEJhY2tncm91bmRDb2xvcixcbiAgICAgICAgICAgIGJvcmRlckNvbG9yOiBvcHRpb25zLmV2ZW50Qm9yZGVyQ29sb3IsXG4gICAgICAgICAgICB0ZXh0Q29sb3I6IG9wdGlvbnMuZXZlbnRUZXh0Q29sb3IsXG4gICAgICAgICAgICBjb2xvcjogb3B0aW9ucy5ldmVudENvbG9yLFxuICAgICAgICAgICAgLy8gY2xhc3NOYW1lczogb3B0aW9ucy5ldmVudENsYXNzTmFtZXMgLy8gcmVuZGVyIGhvb2sgd2lsbCBoYW5kbGUgdGhpc1xuICAgICAgICB9LCBjYWxlbmRhckNvbnRleHQpLFxuICAgICAgICBzZWxlY3Rpb25Db25maWc6IGNyZWF0ZUV2ZW50VWkoe1xuICAgICAgICAgICAgY29uc3RyYWludDogb3B0aW9ucy5zZWxlY3RDb25zdHJhaW50LFxuICAgICAgICAgICAgb3ZlcmxhcDogdHlwZW9mIG9wdGlvbnMuc2VsZWN0T3ZlcmxhcCA9PT0gJ2Jvb2xlYW4nID8gb3B0aW9ucy5zZWxlY3RPdmVybGFwIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgYWxsb3c6IG9wdGlvbnMuc2VsZWN0QWxsb3csXG4gICAgICAgIH0sIGNhbGVuZGFyQ29udGV4dCksXG4gICAgfTtcbn1cbmZ1bmN0aW9uIGNvbXB1dGVJc0xvYWRpbmcoc3RhdGUsIGNvbnRleHQpIHtcbiAgICBmb3IgKGxldCBpc0xvYWRpbmdGdW5jIG9mIGNvbnRleHQucGx1Z2luSG9va3MuaXNMb2FkaW5nRnVuY3MpIHtcbiAgICAgICAgaWYgKGlzTG9hZGluZ0Z1bmMoc3RhdGUpKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG59XG5mdW5jdGlvbiBwYXJzZUNvbnRleHRCdXNpbmVzc0hvdXJzKGNhbGVuZGFyQ29udGV4dCkge1xuICAgIHJldHVybiBwYXJzZUJ1c2luZXNzSG91cnMoY2FsZW5kYXJDb250ZXh0Lm9wdGlvbnMuYnVzaW5lc3NIb3VycywgY2FsZW5kYXJDb250ZXh0KTtcbn1cbmZ1bmN0aW9uIHdhcm5Vbmtub3duT3B0aW9ucyhvcHRpb25zLCB2aWV3TmFtZSkge1xuICAgIGZvciAobGV0IG9wdGlvbk5hbWUgaW4gb3B0aW9ucykge1xuICAgICAgICBjb25zb2xlLndhcm4oYFVua25vd24gb3B0aW9uICcke29wdGlvbk5hbWV9J2AgK1xuICAgICAgICAgICAgKHZpZXdOYW1lID8gYCBmb3IgdmlldyAnJHt2aWV3TmFtZX0nYCA6ICcnKSk7XG4gICAgfVxufVxuXG5jbGFzcyBUb29sYmFyU2VjdGlvbiBleHRlbmRzIEJhc2VDb21wb25lbnQge1xuICAgIHJlbmRlcigpIHtcbiAgICAgICAgbGV0IGNoaWxkcmVuID0gdGhpcy5wcm9wcy53aWRnZXRHcm91cHMubWFwKCh3aWRnZXRHcm91cCkgPT4gdGhpcy5yZW5kZXJXaWRnZXRHcm91cCh3aWRnZXRHcm91cCkpO1xuICAgICAgICByZXR1cm4gY3JlYXRlRWxlbWVudCgnZGl2JywgeyBjbGFzc05hbWU6ICdmYy10b29sYmFyLWNodW5rJyB9LCAuLi5jaGlsZHJlbik7XG4gICAgfVxuICAgIHJlbmRlcldpZGdldEdyb3VwKHdpZGdldEdyb3VwKSB7XG4gICAgICAgIGxldCB7IHByb3BzIH0gPSB0aGlzO1xuICAgICAgICBsZXQgeyB0aGVtZSB9ID0gdGhpcy5jb250ZXh0O1xuICAgICAgICBsZXQgY2hpbGRyZW4gPSBbXTtcbiAgICAgICAgbGV0IGlzT25seUJ1dHRvbnMgPSB0cnVlO1xuICAgICAgICBmb3IgKGxldCB3aWRnZXQgb2Ygd2lkZ2V0R3JvdXApIHtcbiAgICAgICAgICAgIGxldCB7IGJ1dHRvbk5hbWUsIGJ1dHRvbkNsaWNrLCBidXR0b25UZXh0LCBidXR0b25JY29uLCBidXR0b25IaW50IH0gPSB3aWRnZXQ7XG4gICAgICAgICAgICBpZiAoYnV0dG9uTmFtZSA9PT0gJ3RpdGxlJykge1xuICAgICAgICAgICAgICAgIGlzT25seUJ1dHRvbnMgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBjaGlsZHJlbi5wdXNoKGNyZWF0ZUVsZW1lbnQoXCJoMlwiLCB7IGNsYXNzTmFtZTogXCJmYy10b29sYmFyLXRpdGxlXCIsIGlkOiBwcm9wcy50aXRsZUlkIH0sIHByb3BzLnRpdGxlKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBsZXQgaXNQcmVzc2VkID0gYnV0dG9uTmFtZSA9PT0gcHJvcHMuYWN0aXZlQnV0dG9uO1xuICAgICAgICAgICAgICAgIGxldCBpc0Rpc2FibGVkID0gKCFwcm9wcy5pc1RvZGF5RW5hYmxlZCAmJiBidXR0b25OYW1lID09PSAndG9kYXknKSB8fFxuICAgICAgICAgICAgICAgICAgICAoIXByb3BzLmlzUHJldkVuYWJsZWQgJiYgYnV0dG9uTmFtZSA9PT0gJ3ByZXYnKSB8fFxuICAgICAgICAgICAgICAgICAgICAoIXByb3BzLmlzTmV4dEVuYWJsZWQgJiYgYnV0dG9uTmFtZSA9PT0gJ25leHQnKTtcbiAgICAgICAgICAgICAgICBsZXQgYnV0dG9uQ2xhc3NlcyA9IFtgZmMtJHtidXR0b25OYW1lfS1idXR0b25gLCB0aGVtZS5nZXRDbGFzcygnYnV0dG9uJyldO1xuICAgICAgICAgICAgICAgIGlmIChpc1ByZXNzZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgYnV0dG9uQ2xhc3Nlcy5wdXNoKHRoZW1lLmdldENsYXNzKCdidXR0b25BY3RpdmUnKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNoaWxkcmVuLnB1c2goY3JlYXRlRWxlbWVudChcImJ1dHRvblwiLCB7IHR5cGU6IFwiYnV0dG9uXCIsIHRpdGxlOiB0eXBlb2YgYnV0dG9uSGludCA9PT0gJ2Z1bmN0aW9uJyA/IGJ1dHRvbkhpbnQocHJvcHMubmF2VW5pdCkgOiBidXR0b25IaW50LCBkaXNhYmxlZDogaXNEaXNhYmxlZCwgXCJhcmlhLXByZXNzZWRcIjogaXNQcmVzc2VkLCBjbGFzc05hbWU6IGJ1dHRvbkNsYXNzZXMuam9pbignICcpLCBvbkNsaWNrOiBidXR0b25DbGljayB9LCBidXR0b25UZXh0IHx8IChidXR0b25JY29uID8gY3JlYXRlRWxlbWVudChcInNwYW5cIiwgeyBjbGFzc05hbWU6IGJ1dHRvbkljb24sIHJvbGU6IFwiaW1nXCIgfSkgOiAnJykpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoY2hpbGRyZW4ubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgbGV0IGdyb3VwQ2xhc3NOYW1lID0gKGlzT25seUJ1dHRvbnMgJiYgdGhlbWUuZ2V0Q2xhc3MoJ2J1dHRvbkdyb3VwJykpIHx8ICcnO1xuICAgICAgICAgICAgcmV0dXJuIGNyZWF0ZUVsZW1lbnQoJ2RpdicsIHsgY2xhc3NOYW1lOiBncm91cENsYXNzTmFtZSB9LCAuLi5jaGlsZHJlbik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGNoaWxkcmVuWzBdO1xuICAgIH1cbn1cblxuY2xhc3MgVG9vbGJhciBleHRlbmRzIEJhc2VDb21wb25lbnQge1xuICAgIHJlbmRlcigpIHtcbiAgICAgICAgbGV0IHsgbW9kZWwsIGV4dHJhQ2xhc3NOYW1lIH0gPSB0aGlzLnByb3BzO1xuICAgICAgICBsZXQgZm9yY2VMdHIgPSBmYWxzZTtcbiAgICAgICAgbGV0IHN0YXJ0Q29udGVudDtcbiAgICAgICAgbGV0IGVuZENvbnRlbnQ7XG4gICAgICAgIGxldCBzZWN0aW9uV2lkZ2V0cyA9IG1vZGVsLnNlY3Rpb25XaWRnZXRzO1xuICAgICAgICBsZXQgY2VudGVyQ29udGVudCA9IHNlY3Rpb25XaWRnZXRzLmNlbnRlcjtcbiAgICAgICAgaWYgKHNlY3Rpb25XaWRnZXRzLmxlZnQpIHtcbiAgICAgICAgICAgIGZvcmNlTHRyID0gdHJ1ZTtcbiAgICAgICAgICAgIHN0YXJ0Q29udGVudCA9IHNlY3Rpb25XaWRnZXRzLmxlZnQ7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBzdGFydENvbnRlbnQgPSBzZWN0aW9uV2lkZ2V0cy5zdGFydDtcbiAgICAgICAgfVxuICAgICAgICBpZiAoc2VjdGlvbldpZGdldHMucmlnaHQpIHtcbiAgICAgICAgICAgIGZvcmNlTHRyID0gdHJ1ZTtcbiAgICAgICAgICAgIGVuZENvbnRlbnQgPSBzZWN0aW9uV2lkZ2V0cy5yaWdodDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGVuZENvbnRlbnQgPSBzZWN0aW9uV2lkZ2V0cy5lbmQ7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGNsYXNzTmFtZXMgPSBbXG4gICAgICAgICAgICBleHRyYUNsYXNzTmFtZSB8fCAnJyxcbiAgICAgICAgICAgICdmYy10b29sYmFyJyxcbiAgICAgICAgICAgIGZvcmNlTHRyID8gJ2ZjLXRvb2xiYXItbHRyJyA6ICcnLFxuICAgICAgICBdO1xuICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IGNsYXNzTmFtZXMuam9pbignICcpIH0sXG4gICAgICAgICAgICB0aGlzLnJlbmRlclNlY3Rpb24oJ3N0YXJ0Jywgc3RhcnRDb250ZW50IHx8IFtdKSxcbiAgICAgICAgICAgIHRoaXMucmVuZGVyU2VjdGlvbignY2VudGVyJywgY2VudGVyQ29udGVudCB8fCBbXSksXG4gICAgICAgICAgICB0aGlzLnJlbmRlclNlY3Rpb24oJ2VuZCcsIGVuZENvbnRlbnQgfHwgW10pKSk7XG4gICAgfVxuICAgIHJlbmRlclNlY3Rpb24oa2V5LCB3aWRnZXRHcm91cHMpIHtcbiAgICAgICAgbGV0IHsgcHJvcHMgfSA9IHRoaXM7XG4gICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChUb29sYmFyU2VjdGlvbiwgeyBrZXk6IGtleSwgd2lkZ2V0R3JvdXBzOiB3aWRnZXRHcm91cHMsIHRpdGxlOiBwcm9wcy50aXRsZSwgbmF2VW5pdDogcHJvcHMubmF2VW5pdCwgYWN0aXZlQnV0dG9uOiBwcm9wcy5hY3RpdmVCdXR0b24sIGlzVG9kYXlFbmFibGVkOiBwcm9wcy5pc1RvZGF5RW5hYmxlZCwgaXNQcmV2RW5hYmxlZDogcHJvcHMuaXNQcmV2RW5hYmxlZCwgaXNOZXh0RW5hYmxlZDogcHJvcHMuaXNOZXh0RW5hYmxlZCwgdGl0bGVJZDogcHJvcHMudGl0bGVJZCB9KSk7XG4gICAgfVxufVxuXG5jbGFzcyBWaWV3SGFybmVzcyBleHRlbmRzIEJhc2VDb21wb25lbnQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICB0aGlzLnN0YXRlID0ge1xuICAgICAgICAgICAgYXZhaWxhYmxlV2lkdGg6IG51bGwsXG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlRWwgPSAoZWwpID0+IHtcbiAgICAgICAgICAgIHRoaXMuZWwgPSBlbDtcbiAgICAgICAgICAgIHNldFJlZih0aGlzLnByb3BzLmVsUmVmLCBlbCk7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZUF2YWlsYWJsZVdpZHRoKCk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlUmVzaXplID0gKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy51cGRhdGVBdmFpbGFibGVXaWR0aCgpO1xuICAgICAgICB9O1xuICAgIH1cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGxldCB7IHByb3BzLCBzdGF0ZSB9ID0gdGhpcztcbiAgICAgICAgbGV0IHsgYXNwZWN0UmF0aW8gfSA9IHByb3BzO1xuICAgICAgICBsZXQgY2xhc3NOYW1lcyA9IFtcbiAgICAgICAgICAgICdmYy12aWV3LWhhcm5lc3MnLFxuICAgICAgICAgICAgKGFzcGVjdFJhdGlvIHx8IHByb3BzLmxpcXVpZCB8fCBwcm9wcy5oZWlnaHQpXG4gICAgICAgICAgICAgICAgPyAnZmMtdmlldy1oYXJuZXNzLWFjdGl2ZScgLy8gaGFybmVzcyBjb250cm9scyB0aGUgaGVpZ2h0XG4gICAgICAgICAgICAgICAgOiAnZmMtdmlldy1oYXJuZXNzLXBhc3NpdmUnLCAvLyBsZXQgdGhlIHZpZXcgZG8gdGhlIGhlaWdodFxuICAgICAgICBdO1xuICAgICAgICBsZXQgaGVpZ2h0ID0gJyc7XG4gICAgICAgIGxldCBwYWRkaW5nQm90dG9tID0gJyc7XG4gICAgICAgIGlmIChhc3BlY3RSYXRpbykge1xuICAgICAgICAgICAgaWYgKHN0YXRlLmF2YWlsYWJsZVdpZHRoICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgaGVpZ2h0ID0gc3RhdGUuYXZhaWxhYmxlV2lkdGggLyBhc3BlY3RSYXRpbztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIHdoaWxlIHdhaXRpbmcgdG8ga25vdyBhdmFpbGFibGVXaWR0aCwgd2UgY2FuJ3Qgc2V0IGhlaWdodCB0byAqemVybypcbiAgICAgICAgICAgICAgICAvLyBiZWNhdXNlIHdpbGwgY2F1c2UgbG90cyBvZiB1bm5lY2Vzc2FyeSBzY3JvbGxiYXJzIHdpdGhpbiBzY3JvbGxncmlkLlxuICAgICAgICAgICAgICAgIC8vIEJFVFRFUjogZG9uJ3Qgc3RhcnQgcmVuZGVyaW5nIEFOWVRISU5HIHlldCB1bnRpbCB3ZSBrbm93IGNvbnRhaW5lciB3aWR0aFxuICAgICAgICAgICAgICAgIC8vIE5PVEU6IHdoeSBub3QgYWx3YXlzIHVzZSBwYWRkaW5nQm90dG9tPyBDYXVzZXMgaGVpZ2h0IG9zY2lsbGF0aW9uIChpc3N1ZSA1NjA2KVxuICAgICAgICAgICAgICAgIHBhZGRpbmdCb3R0b20gPSBgJHsoMSAvIGFzcGVjdFJhdGlvKSAqIDEwMH0lYDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGhlaWdodCA9IHByb3BzLmhlaWdodCB8fCAnJztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBcImFyaWEtbGFiZWxsZWRieVwiOiBwcm9wcy5sYWJlbGVkQnlJZCwgcmVmOiB0aGlzLmhhbmRsZUVsLCBjbGFzc05hbWU6IGNsYXNzTmFtZXMuam9pbignICcpLCBzdHlsZTogeyBoZWlnaHQsIHBhZGRpbmdCb3R0b20gfSB9LCBwcm9wcy5jaGlsZHJlbikpO1xuICAgIH1cbiAgICBjb21wb25lbnREaWRNb3VudCgpIHtcbiAgICAgICAgdGhpcy5jb250ZXh0LmFkZFJlc2l6ZUhhbmRsZXIodGhpcy5oYW5kbGVSZXNpemUpO1xuICAgIH1cbiAgICBjb21wb25lbnRXaWxsVW5tb3VudCgpIHtcbiAgICAgICAgdGhpcy5jb250ZXh0LnJlbW92ZVJlc2l6ZUhhbmRsZXIodGhpcy5oYW5kbGVSZXNpemUpO1xuICAgIH1cbiAgICB1cGRhdGVBdmFpbGFibGVXaWR0aCgpIHtcbiAgICAgICAgaWYgKHRoaXMuZWwgJiYgLy8gbmVlZGVkLiBidXQgd2h5P1xuICAgICAgICAgICAgdGhpcy5wcm9wcy5hc3BlY3RSYXRpbyAvLyBhc3BlY3RSYXRpbyBpcyB0aGUgb25seSBoZWlnaHQgc2V0dGluZyB0aGF0IG5lZWRzIGF2YWlsYWJsZVdpZHRoXG4gICAgICAgICkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IGF2YWlsYWJsZVdpZHRoOiB0aGlzLmVsLm9mZnNldFdpZHRoIH0pO1xuICAgICAgICB9XG4gICAgfVxufVxuXG4vKlxuRGV0ZWN0cyB3aGVuIHRoZSB1c2VyIGNsaWNrcyBvbiBhbiBldmVudCB3aXRoaW4gYSBEYXRlQ29tcG9uZW50XG4qL1xuY2xhc3MgRXZlbnRDbGlja2luZyBleHRlbmRzIEludGVyYWN0aW9uIHtcbiAgICBjb25zdHJ1Y3RvcihzZXR0aW5ncykge1xuICAgICAgICBzdXBlcihzZXR0aW5ncyk7XG4gICAgICAgIHRoaXMuaGFuZGxlU2VnQ2xpY2sgPSAoZXYsIHNlZ0VsKSA9PiB7XG4gICAgICAgICAgICBsZXQgeyBjb21wb25lbnQgfSA9IHRoaXM7XG4gICAgICAgICAgICBsZXQgeyBjb250ZXh0IH0gPSBjb21wb25lbnQ7XG4gICAgICAgICAgICBsZXQgc2VnID0gZ2V0RWxTZWcoc2VnRWwpO1xuICAgICAgICAgICAgaWYgKHNlZyAmJiAvLyBtaWdodCBiZSB0aGUgPGRpdj4gc3Vycm91bmRpbmcgdGhlIG1vcmUgbGlua1xuICAgICAgICAgICAgICAgIGNvbXBvbmVudC5pc1ZhbGlkU2VnRG93bkVsKGV2LnRhcmdldCkpIHtcbiAgICAgICAgICAgICAgICAvLyBvdXIgd2F5IHRvIHNpbXVsYXRlIGEgbGluayBjbGljayBmb3IgZWxlbWVudHMgdGhhdCBjYW4ndCBiZSA8YT4gdGFnc1xuICAgICAgICAgICAgICAgIC8vIGdyYWIgYmVmb3JlIHRyaWdnZXIgZmlyZWQgaW4gY2FzZSB0cmlnZ2VyIHRyYXNoZXMgRE9NIHRocnUgcmVyZW5kZXJpbmdcbiAgICAgICAgICAgICAgICBsZXQgaGFzVXJsQ29udGFpbmVyID0gZWxlbWVudENsb3Nlc3QoZXYudGFyZ2V0LCAnLmZjLWV2ZW50LWZvcmNlZC11cmwnKTtcbiAgICAgICAgICAgICAgICBsZXQgdXJsID0gaGFzVXJsQ29udGFpbmVyID8gaGFzVXJsQ29udGFpbmVyLnF1ZXJ5U2VsZWN0b3IoJ2FbaHJlZl0nKS5ocmVmIDogJyc7XG4gICAgICAgICAgICAgICAgY29udGV4dC5lbWl0dGVyLnRyaWdnZXIoJ2V2ZW50Q2xpY2snLCB7XG4gICAgICAgICAgICAgICAgICAgIGVsOiBzZWdFbCxcbiAgICAgICAgICAgICAgICAgICAgZXZlbnQ6IG5ldyBFdmVudEltcGwoY29tcG9uZW50LmNvbnRleHQsIHNlZy5ldmVudFJhbmdlLmRlZiwgc2VnLmV2ZW50UmFuZ2UuaW5zdGFuY2UpLFxuICAgICAgICAgICAgICAgICAgICBqc0V2ZW50OiBldixcbiAgICAgICAgICAgICAgICAgICAgdmlldzogY29udGV4dC52aWV3QXBpLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGlmICh1cmwgJiYgIWV2LmRlZmF1bHRQcmV2ZW50ZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgd2luZG93LmxvY2F0aW9uLmhyZWYgPSB1cmw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICB0aGlzLmRlc3Ryb3kgPSBsaXN0ZW5CeVNlbGVjdG9yKHNldHRpbmdzLmVsLCAnY2xpY2snLCAnLmZjLWV2ZW50JywgLy8gb24gYm90aCBmZyBhbmQgYmcgZXZlbnRzXG4gICAgICAgIHRoaXMuaGFuZGxlU2VnQ2xpY2spO1xuICAgIH1cbn1cblxuLypcblRyaWdnZXJzIGV2ZW50cyBhbmQgYWRkcy9yZW1vdmVzIGNvcmUgY2xhc3NOYW1lcyB3aGVuIHRoZSB1c2VyJ3MgcG9pbnRlclxuZW50ZXJzL2xlYXZlcyBldmVudC1lbGVtZW50cyBvZiBhIGNvbXBvbmVudC5cbiovXG5jbGFzcyBFdmVudEhvdmVyaW5nIGV4dGVuZHMgSW50ZXJhY3Rpb24ge1xuICAgIGNvbnN0cnVjdG9yKHNldHRpbmdzKSB7XG4gICAgICAgIHN1cGVyKHNldHRpbmdzKTtcbiAgICAgICAgLy8gZm9yIHNpbXVsYXRpbmcgYW4gZXZlbnRNb3VzZUxlYXZlIHdoZW4gdGhlIGV2ZW50IGVsIGlzIGRlc3Ryb3llZCB3aGlsZSBtb3VzZSBpcyBvdmVyIGl0XG4gICAgICAgIHRoaXMuaGFuZGxlRXZlbnRFbFJlbW92ZSA9IChlbCkgPT4ge1xuICAgICAgICAgICAgaWYgKGVsID09PSB0aGlzLmN1cnJlbnRTZWdFbCkge1xuICAgICAgICAgICAgICAgIHRoaXMuaGFuZGxlU2VnTGVhdmUobnVsbCwgdGhpcy5jdXJyZW50U2VnRWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZVNlZ0VudGVyID0gKGV2LCBzZWdFbCkgPT4ge1xuICAgICAgICAgICAgaWYgKGdldEVsU2VnKHNlZ0VsKSkgeyAvLyBUT0RPOiBiZXR0ZXIgd2F5IHRvIG1ha2Ugc3VyZSBub3QgaG92ZXJpbmcgb3ZlciBtb3JlKyBsaW5rIG9yIGl0cyB3cmFwcGVyXG4gICAgICAgICAgICAgICAgdGhpcy5jdXJyZW50U2VnRWwgPSBzZWdFbDtcbiAgICAgICAgICAgICAgICB0aGlzLnRyaWdnZXJFdmVudCgnZXZlbnRNb3VzZUVudGVyJywgZXYsIHNlZ0VsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVTZWdMZWF2ZSA9IChldiwgc2VnRWwpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLmN1cnJlbnRTZWdFbCkge1xuICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudFNlZ0VsID0gbnVsbDtcbiAgICAgICAgICAgICAgICB0aGlzLnRyaWdnZXJFdmVudCgnZXZlbnRNb3VzZUxlYXZlJywgZXYsIHNlZ0VsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5yZW1vdmVIb3Zlckxpc3RlbmVycyA9IGxpc3RlblRvSG92ZXJCeVNlbGVjdG9yKHNldHRpbmdzLmVsLCAnLmZjLWV2ZW50JywgLy8gb24gYm90aCBmZyBhbmQgYmcgZXZlbnRzXG4gICAgICAgIHRoaXMuaGFuZGxlU2VnRW50ZXIsIHRoaXMuaGFuZGxlU2VnTGVhdmUpO1xuICAgIH1cbiAgICBkZXN0cm95KCkge1xuICAgICAgICB0aGlzLnJlbW92ZUhvdmVyTGlzdGVuZXJzKCk7XG4gICAgfVxuICAgIHRyaWdnZXJFdmVudChwdWJsaWNFdk5hbWUsIGV2LCBzZWdFbCkge1xuICAgICAgICBsZXQgeyBjb21wb25lbnQgfSA9IHRoaXM7XG4gICAgICAgIGxldCB7IGNvbnRleHQgfSA9IGNvbXBvbmVudDtcbiAgICAgICAgbGV0IHNlZyA9IGdldEVsU2VnKHNlZ0VsKTtcbiAgICAgICAgaWYgKCFldiB8fCBjb21wb25lbnQuaXNWYWxpZFNlZ0Rvd25FbChldi50YXJnZXQpKSB7XG4gICAgICAgICAgICBjb250ZXh0LmVtaXR0ZXIudHJpZ2dlcihwdWJsaWNFdk5hbWUsIHtcbiAgICAgICAgICAgICAgICBlbDogc2VnRWwsXG4gICAgICAgICAgICAgICAgZXZlbnQ6IG5ldyBFdmVudEltcGwoY29udGV4dCwgc2VnLmV2ZW50UmFuZ2UuZGVmLCBzZWcuZXZlbnRSYW5nZS5pbnN0YW5jZSksXG4gICAgICAgICAgICAgICAganNFdmVudDogZXYsXG4gICAgICAgICAgICAgICAgdmlldzogY29udGV4dC52aWV3QXBpLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmNsYXNzIENhbGVuZGFyQ29udGVudCBleHRlbmRzIFB1cmVDb21wb25lbnQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICB0aGlzLmJ1aWxkVmlld0NvbnRleHQgPSBtZW1vaXplKGJ1aWxkVmlld0NvbnRleHQpO1xuICAgICAgICB0aGlzLmJ1aWxkVmlld1Byb3BUcmFuc2Zvcm1lcnMgPSBtZW1vaXplKGJ1aWxkVmlld1Byb3BUcmFuc2Zvcm1lcnMpO1xuICAgICAgICB0aGlzLmJ1aWxkVG9vbGJhclByb3BzID0gbWVtb2l6ZShidWlsZFRvb2xiYXJQcm9wcyk7XG4gICAgICAgIHRoaXMuaGVhZGVyUmVmID0gY3JlYXRlUmVmKCk7XG4gICAgICAgIHRoaXMuZm9vdGVyUmVmID0gY3JlYXRlUmVmKCk7XG4gICAgICAgIHRoaXMuaW50ZXJhY3Rpb25zU3RvcmUgPSB7fTtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXG4gICAgICAgIHRoaXMuc3RhdGUgPSB7XG4gICAgICAgICAgICB2aWV3TGFiZWxJZDogZ2V0VW5pcXVlRG9tSWQoKSxcbiAgICAgICAgfTtcbiAgICAgICAgLy8gQ29tcG9uZW50IFJlZ2lzdHJhdGlvblxuICAgICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgICAgICB0aGlzLnJlZ2lzdGVySW50ZXJhY3RpdmVDb21wb25lbnQgPSAoY29tcG9uZW50LCBzZXR0aW5nc0lucHV0KSA9PiB7XG4gICAgICAgICAgICBsZXQgc2V0dGluZ3MgPSBwYXJzZUludGVyYWN0aW9uU2V0dGluZ3MoY29tcG9uZW50LCBzZXR0aW5nc0lucHV0KTtcbiAgICAgICAgICAgIGxldCBERUZBVUxUX0lOVEVSQUNUSU9OUyA9IFtcbiAgICAgICAgICAgICAgICBFdmVudENsaWNraW5nLFxuICAgICAgICAgICAgICAgIEV2ZW50SG92ZXJpbmcsXG4gICAgICAgICAgICBdO1xuICAgICAgICAgICAgbGV0IGludGVyYWN0aW9uQ2xhc3NlcyA9IERFRkFVTFRfSU5URVJBQ1RJT05TLmNvbmNhdCh0aGlzLnByb3BzLnBsdWdpbkhvb2tzLmNvbXBvbmVudEludGVyYWN0aW9ucyk7XG4gICAgICAgICAgICBsZXQgaW50ZXJhY3Rpb25zID0gaW50ZXJhY3Rpb25DbGFzc2VzLm1hcCgoVGhlSW50ZXJhY3Rpb25DbGFzcykgPT4gbmV3IFRoZUludGVyYWN0aW9uQ2xhc3Moc2V0dGluZ3MpKTtcbiAgICAgICAgICAgIHRoaXMuaW50ZXJhY3Rpb25zU3RvcmVbY29tcG9uZW50LnVpZF0gPSBpbnRlcmFjdGlvbnM7XG4gICAgICAgICAgICBpbnRlcmFjdGlvblNldHRpbmdzU3RvcmVbY29tcG9uZW50LnVpZF0gPSBzZXR0aW5ncztcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy51bnJlZ2lzdGVySW50ZXJhY3RpdmVDb21wb25lbnQgPSAoY29tcG9uZW50KSA9PiB7XG4gICAgICAgICAgICBsZXQgbGlzdGVuZXJzID0gdGhpcy5pbnRlcmFjdGlvbnNTdG9yZVtjb21wb25lbnQudWlkXTtcbiAgICAgICAgICAgIGlmIChsaXN0ZW5lcnMpIHtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBsaXN0ZW5lciBvZiBsaXN0ZW5lcnMpIHtcbiAgICAgICAgICAgICAgICAgICAgbGlzdGVuZXIuZGVzdHJveSgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5pbnRlcmFjdGlvbnNTdG9yZVtjb21wb25lbnQudWlkXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRlbGV0ZSBpbnRlcmFjdGlvblNldHRpbmdzU3RvcmVbY29tcG9uZW50LnVpZF07XG4gICAgICAgIH07XG4gICAgICAgIC8vIFJlc2l6aW5nXG4gICAgICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgICAgIHRoaXMucmVzaXplUnVubmVyID0gbmV3IERlbGF5ZWRSdW5uZXIoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5wcm9wcy5lbWl0dGVyLnRyaWdnZXIoJ19yZXNpemUnLCB0cnVlKTsgLy8gc2hvdWxkIHdpbmRvdyByZXNpemVzIGJlIGNvbnNpZGVyZWQgXCJmb3JjZWRcIiA/XG4gICAgICAgICAgICB0aGlzLnByb3BzLmVtaXR0ZXIudHJpZ2dlcignd2luZG93UmVzaXplJywgeyB2aWV3OiB0aGlzLnByb3BzLnZpZXdBcGkgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmhhbmRsZVdpbmRvd1Jlc2l6ZSA9IChldikgPT4ge1xuICAgICAgICAgICAgbGV0IHsgb3B0aW9ucyB9ID0gdGhpcy5wcm9wcztcbiAgICAgICAgICAgIGlmIChvcHRpb25zLmhhbmRsZVdpbmRvd1Jlc2l6ZSAmJlxuICAgICAgICAgICAgICAgIGV2LnRhcmdldCA9PT0gd2luZG93IC8vIGF2b2lkIGpxdWkgZXZlbnRzXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlc2l6ZVJ1bm5lci5yZXF1ZXN0KG9wdGlvbnMud2luZG93UmVzaXplRGVsYXkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgIH1cbiAgICAvKlxuICAgIHJlbmRlcnMgSU5TSURFIG9mIGFuIG91dGVyIGRpdlxuICAgICovXG4gICAgcmVuZGVyKCkge1xuICAgICAgICBsZXQgeyBwcm9wcyB9ID0gdGhpcztcbiAgICAgICAgbGV0IHsgdG9vbGJhckNvbmZpZywgb3B0aW9ucyB9ID0gcHJvcHM7XG4gICAgICAgIGxldCB2aWV3Vkdyb3cgPSBmYWxzZTtcbiAgICAgICAgbGV0IHZpZXdIZWlnaHQgPSAnJztcbiAgICAgICAgbGV0IHZpZXdBc3BlY3RSYXRpbztcbiAgICAgICAgaWYgKHByb3BzLmlzSGVpZ2h0QXV0byB8fCBwcm9wcy5mb3JQcmludCkge1xuICAgICAgICAgICAgdmlld0hlaWdodCA9ICcnO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKG9wdGlvbnMuaGVpZ2h0ICE9IG51bGwpIHtcbiAgICAgICAgICAgIHZpZXdWR3JvdyA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAob3B0aW9ucy5jb250ZW50SGVpZ2h0ICE9IG51bGwpIHtcbiAgICAgICAgICAgIHZpZXdIZWlnaHQgPSBvcHRpb25zLmNvbnRlbnRIZWlnaHQ7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB2aWV3QXNwZWN0UmF0aW8gPSBNYXRoLm1heChvcHRpb25zLmFzcGVjdFJhdGlvLCAwLjUpOyAvLyBwcmV2ZW50IGZyb20gZ2V0dGluZyB0b28gdGFsbFxuICAgICAgICB9XG4gICAgICAgIGxldCB2aWV3Q29udGV4dCA9IHRoaXMuYnVpbGRWaWV3Q29udGV4dChwcm9wcy52aWV3U3BlYywgcHJvcHMudmlld0FwaSwgcHJvcHMub3B0aW9ucywgcHJvcHMuZGF0ZVByb2ZpbGVHZW5lcmF0b3IsIHByb3BzLmRhdGVFbnYsIHByb3BzLm5vd01hbmFnZXIsIHByb3BzLnRoZW1lLCBwcm9wcy5wbHVnaW5Ib29rcywgcHJvcHMuZGlzcGF0Y2gsIHByb3BzLmdldEN1cnJlbnREYXRhLCBwcm9wcy5lbWl0dGVyLCBwcm9wcy5jYWxlbmRhckFwaSwgdGhpcy5yZWdpc3RlckludGVyYWN0aXZlQ29tcG9uZW50LCB0aGlzLnVucmVnaXN0ZXJJbnRlcmFjdGl2ZUNvbXBvbmVudCk7XG4gICAgICAgIGxldCB2aWV3TGFiZWxJZCA9ICh0b29sYmFyQ29uZmlnLmhlYWRlciAmJiB0b29sYmFyQ29uZmlnLmhlYWRlci5oYXNUaXRsZSlcbiAgICAgICAgICAgID8gdGhpcy5zdGF0ZS52aWV3TGFiZWxJZFxuICAgICAgICAgICAgOiB1bmRlZmluZWQ7XG4gICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChWaWV3Q29udGV4dFR5cGUuUHJvdmlkZXIsIHsgdmFsdWU6IHZpZXdDb250ZXh0IH0sXG4gICAgICAgICAgICBjcmVhdGVFbGVtZW50KE5vd1RpbWVyLCB7IHVuaXQ6IFwiZGF5XCIgfSwgKG5vd0RhdGUpID0+IHtcbiAgICAgICAgICAgICAgICBsZXQgdG9vbGJhclByb3BzID0gdGhpcy5idWlsZFRvb2xiYXJQcm9wcyhwcm9wcy52aWV3U3BlYywgcHJvcHMuZGF0ZVByb2ZpbGUsIHByb3BzLmRhdGVQcm9maWxlR2VuZXJhdG9yLCBwcm9wcy5jdXJyZW50RGF0ZSwgbm93RGF0ZSwgcHJvcHMudmlld1RpdGxlKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoRnJhZ21lbnQsIG51bGwsXG4gICAgICAgICAgICAgICAgICAgIHRvb2xiYXJDb25maWcuaGVhZGVyICYmIChjcmVhdGVFbGVtZW50KFRvb2xiYXIsIE9iamVjdC5hc3NpZ24oeyByZWY6IHRoaXMuaGVhZGVyUmVmLCBleHRyYUNsYXNzTmFtZTogXCJmYy1oZWFkZXItdG9vbGJhclwiLCBtb2RlbDogdG9vbGJhckNvbmZpZy5oZWFkZXIsIHRpdGxlSWQ6IHZpZXdMYWJlbElkIH0sIHRvb2xiYXJQcm9wcykpKSxcbiAgICAgICAgICAgICAgICAgICAgY3JlYXRlRWxlbWVudChWaWV3SGFybmVzcywgeyBsaXF1aWQ6IHZpZXdWR3JvdywgaGVpZ2h0OiB2aWV3SGVpZ2h0LCBhc3BlY3RSYXRpbzogdmlld0FzcGVjdFJhdGlvLCBsYWJlbGVkQnlJZDogdmlld0xhYmVsSWQgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmVuZGVyVmlldyhwcm9wcyksXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmJ1aWxkQXBwZW5kQ29udGVudCgpKSxcbiAgICAgICAgICAgICAgICAgICAgdG9vbGJhckNvbmZpZy5mb290ZXIgJiYgKGNyZWF0ZUVsZW1lbnQoVG9vbGJhciwgT2JqZWN0LmFzc2lnbih7IHJlZjogdGhpcy5mb290ZXJSZWYsIGV4dHJhQ2xhc3NOYW1lOiBcImZjLWZvb3Rlci10b29sYmFyXCIsIG1vZGVsOiB0b29sYmFyQ29uZmlnLmZvb3RlciwgdGl0bGVJZDogXCJcIiB9LCB0b29sYmFyUHJvcHMpKSkpKTtcbiAgICAgICAgICAgIH0pKSk7XG4gICAgfVxuICAgIGNvbXBvbmVudERpZE1vdW50KCkge1xuICAgICAgICBsZXQgeyBwcm9wcyB9ID0gdGhpcztcbiAgICAgICAgdGhpcy5jYWxlbmRhckludGVyYWN0aW9ucyA9IHByb3BzLnBsdWdpbkhvb2tzLmNhbGVuZGFySW50ZXJhY3Rpb25zXG4gICAgICAgICAgICAubWFwKChDYWxlbmRhckludGVyYWN0aW9uQ2xhc3MpID0+IG5ldyBDYWxlbmRhckludGVyYWN0aW9uQ2xhc3MocHJvcHMpKTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsIHRoaXMuaGFuZGxlV2luZG93UmVzaXplKTtcbiAgICAgICAgbGV0IHsgcHJvcFNldEhhbmRsZXJzIH0gPSBwcm9wcy5wbHVnaW5Ib29rcztcbiAgICAgICAgZm9yIChsZXQgcHJvcE5hbWUgaW4gcHJvcFNldEhhbmRsZXJzKSB7XG4gICAgICAgICAgICBwcm9wU2V0SGFuZGxlcnNbcHJvcE5hbWVdKHByb3BzW3Byb3BOYW1lXSwgcHJvcHMpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbXBvbmVudERpZFVwZGF0ZShwcmV2UHJvcHMpIHtcbiAgICAgICAgbGV0IHsgcHJvcHMgfSA9IHRoaXM7XG4gICAgICAgIGxldCB7IHByb3BTZXRIYW5kbGVycyB9ID0gcHJvcHMucGx1Z2luSG9va3M7XG4gICAgICAgIGZvciAobGV0IHByb3BOYW1lIGluIHByb3BTZXRIYW5kbGVycykge1xuICAgICAgICAgICAgaWYgKHByb3BzW3Byb3BOYW1lXSAhPT0gcHJldlByb3BzW3Byb3BOYW1lXSkge1xuICAgICAgICAgICAgICAgIHByb3BTZXRIYW5kbGVyc1twcm9wTmFtZV0ocHJvcHNbcHJvcE5hbWVdLCBwcm9wcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgY29tcG9uZW50V2lsbFVubW91bnQoKSB7XG4gICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdyZXNpemUnLCB0aGlzLmhhbmRsZVdpbmRvd1Jlc2l6ZSk7XG4gICAgICAgIHRoaXMucmVzaXplUnVubmVyLmNsZWFyKCk7XG4gICAgICAgIGZvciAobGV0IGludGVyYWN0aW9uIG9mIHRoaXMuY2FsZW5kYXJJbnRlcmFjdGlvbnMpIHtcbiAgICAgICAgICAgIGludGVyYWN0aW9uLmRlc3Ryb3koKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnByb3BzLmVtaXR0ZXIudHJpZ2dlcignX3VubW91bnQnKTtcbiAgICB9XG4gICAgYnVpbGRBcHBlbmRDb250ZW50KCkge1xuICAgICAgICBsZXQgeyBwcm9wcyB9ID0gdGhpcztcbiAgICAgICAgbGV0IGNoaWxkcmVuID0gcHJvcHMucGx1Z2luSG9va3Mudmlld0NvbnRhaW5lckFwcGVuZHMubWFwKChidWlsZEFwcGVuZENvbnRlbnQpID0+IGJ1aWxkQXBwZW5kQ29udGVudChwcm9wcykpO1xuICAgICAgICByZXR1cm4gY3JlYXRlRWxlbWVudChGcmFnbWVudCwge30sIC4uLmNoaWxkcmVuKTtcbiAgICB9XG4gICAgcmVuZGVyVmlldyhwcm9wcykge1xuICAgICAgICBsZXQgeyBwbHVnaW5Ib29rcyB9ID0gcHJvcHM7XG4gICAgICAgIGxldCB7IHZpZXdTcGVjIH0gPSBwcm9wcztcbiAgICAgICAgbGV0IHZpZXdQcm9wcyA9IHtcbiAgICAgICAgICAgIGRhdGVQcm9maWxlOiBwcm9wcy5kYXRlUHJvZmlsZSxcbiAgICAgICAgICAgIGJ1c2luZXNzSG91cnM6IHByb3BzLmJ1c2luZXNzSG91cnMsXG4gICAgICAgICAgICBldmVudFN0b3JlOiBwcm9wcy5yZW5kZXJhYmxlRXZlbnRTdG9yZSxcbiAgICAgICAgICAgIGV2ZW50VWlCYXNlczogcHJvcHMuZXZlbnRVaUJhc2VzLFxuICAgICAgICAgICAgZGF0ZVNlbGVjdGlvbjogcHJvcHMuZGF0ZVNlbGVjdGlvbixcbiAgICAgICAgICAgIGV2ZW50U2VsZWN0aW9uOiBwcm9wcy5ldmVudFNlbGVjdGlvbixcbiAgICAgICAgICAgIGV2ZW50RHJhZzogcHJvcHMuZXZlbnREcmFnLFxuICAgICAgICAgICAgZXZlbnRSZXNpemU6IHByb3BzLmV2ZW50UmVzaXplLFxuICAgICAgICAgICAgaXNIZWlnaHRBdXRvOiBwcm9wcy5pc0hlaWdodEF1dG8sXG4gICAgICAgICAgICBmb3JQcmludDogcHJvcHMuZm9yUHJpbnQsXG4gICAgICAgIH07XG4gICAgICAgIGxldCB0cmFuc2Zvcm1lcnMgPSB0aGlzLmJ1aWxkVmlld1Byb3BUcmFuc2Zvcm1lcnMocGx1Z2luSG9va3Mudmlld1Byb3BzVHJhbnNmb3JtZXJzKTtcbiAgICAgICAgZm9yIChsZXQgdHJhbnNmb3JtZXIgb2YgdHJhbnNmb3JtZXJzKSB7XG4gICAgICAgICAgICBPYmplY3QuYXNzaWduKHZpZXdQcm9wcywgdHJhbnNmb3JtZXIudHJhbnNmb3JtKHZpZXdQcm9wcywgcHJvcHMpKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgVmlld0NvbXBvbmVudCA9IHZpZXdTcGVjLmNvbXBvbmVudDtcbiAgICAgICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KFZpZXdDb21wb25lbnQsIE9iamVjdC5hc3NpZ24oe30sIHZpZXdQcm9wcykpKTtcbiAgICB9XG59XG5mdW5jdGlvbiBidWlsZFRvb2xiYXJQcm9wcyh2aWV3U3BlYywgZGF0ZVByb2ZpbGUsIGRhdGVQcm9maWxlR2VuZXJhdG9yLCBjdXJyZW50RGF0ZSwgbm93LCB0aXRsZSkge1xuICAgIC8vIGRvbid0IGZvcmNlIGFueSBkYXRlLXByb2ZpbGVzIHRvIHZhbGlkIGRhdGUgcHJvZmlsZXMgKHRoZSBgZmFsc2VgKSBzbyB0aGF0IHdlIGNhbiB0ZWxsIGlmIGl0J3MgaW52YWxpZFxuICAgIGxldCB0b2RheUluZm8gPSBkYXRlUHJvZmlsZUdlbmVyYXRvci5idWlsZChub3csIHVuZGVmaW5lZCwgZmFsc2UpOyAvLyBUT0RPOiBuZWVkIGB1bmRlZmluZWRgIG9yIGVsc2UgSU5GSU5JVEUgTE9PUCBmb3Igc29tZSByZWFzb25cbiAgICBsZXQgcHJldkluZm8gPSBkYXRlUHJvZmlsZUdlbmVyYXRvci5idWlsZFByZXYoZGF0ZVByb2ZpbGUsIGN1cnJlbnREYXRlLCBmYWxzZSk7XG4gICAgbGV0IG5leHRJbmZvID0gZGF0ZVByb2ZpbGVHZW5lcmF0b3IuYnVpbGROZXh0KGRhdGVQcm9maWxlLCBjdXJyZW50RGF0ZSwgZmFsc2UpO1xuICAgIHJldHVybiB7XG4gICAgICAgIHRpdGxlLFxuICAgICAgICBhY3RpdmVCdXR0b246IHZpZXdTcGVjLnR5cGUsXG4gICAgICAgIG5hdlVuaXQ6IHZpZXdTcGVjLnNpbmdsZVVuaXQsXG4gICAgICAgIGlzVG9kYXlFbmFibGVkOiB0b2RheUluZm8uaXNWYWxpZCAmJiAhcmFuZ2VDb250YWluc01hcmtlcihkYXRlUHJvZmlsZS5jdXJyZW50UmFuZ2UsIG5vdyksXG4gICAgICAgIGlzUHJldkVuYWJsZWQ6IHByZXZJbmZvLmlzVmFsaWQsXG4gICAgICAgIGlzTmV4dEVuYWJsZWQ6IG5leHRJbmZvLmlzVmFsaWQsXG4gICAgfTtcbn1cbi8vIFBsdWdpblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbmZ1bmN0aW9uIGJ1aWxkVmlld1Byb3BUcmFuc2Zvcm1lcnModGhlQ2xhc3Nlcykge1xuICAgIHJldHVybiB0aGVDbGFzc2VzLm1hcCgoVGhlQ2xhc3MpID0+IG5ldyBUaGVDbGFzcygpKTtcbn1cblxuY2xhc3MgQ2FsZW5kYXIgZXh0ZW5kcyBDYWxlbmRhckltcGwge1xuICAgIGNvbnN0cnVjdG9yKGVsLCBvcHRpb25PdmVycmlkZXMgPSB7fSkge1xuICAgICAgICBzdXBlcigpO1xuICAgICAgICB0aGlzLmlzUmVuZGVyaW5nID0gZmFsc2U7XG4gICAgICAgIHRoaXMuaXNSZW5kZXJlZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLmN1cnJlbnRDbGFzc05hbWVzID0gW107XG4gICAgICAgIHRoaXMuY3VzdG9tQ29udGVudFJlbmRlcklkID0gMDtcbiAgICAgICAgdGhpcy5oYW5kbGVBY3Rpb24gPSAoYWN0aW9uKSA9PiB7XG4gICAgICAgICAgICAvLyBhY3Rpb25zIHdlIGtub3cgd2Ugd2FudCB0byByZW5kZXIgaW1tZWRpYXRlbHlcbiAgICAgICAgICAgIHN3aXRjaCAoYWN0aW9uLnR5cGUpIHtcbiAgICAgICAgICAgICAgICBjYXNlICdTRVRfRVZFTlRfRFJBRyc6XG4gICAgICAgICAgICAgICAgY2FzZSAnU0VUX0VWRU5UX1JFU0laRSc6XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVuZGVyUnVubmVyLnRyeURyYWluKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlRGF0YSA9IChkYXRhKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnREYXRhID0gZGF0YTtcbiAgICAgICAgICAgIHRoaXMucmVuZGVyUnVubmVyLnJlcXVlc3QoZGF0YS5jYWxlbmRhck9wdGlvbnMucmVyZW5kZXJEZWxheSk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlUmVuZGVyUmVxdWVzdCA9ICgpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLmlzUmVuZGVyaW5nKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5pc1JlbmRlcmVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBsZXQgeyBjdXJyZW50RGF0YSB9ID0gdGhpcztcbiAgICAgICAgICAgICAgICBmbHVzaFN5bmMoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICByZW5kZXIoY3JlYXRlRWxlbWVudChDYWxlbmRhclJvb3QsIHsgb3B0aW9uczogY3VycmVudERhdGEuY2FsZW5kYXJPcHRpb25zLCB0aGVtZTogY3VycmVudERhdGEudGhlbWUsIGVtaXR0ZXI6IGN1cnJlbnREYXRhLmVtaXR0ZXIgfSwgKGNsYXNzTmFtZXMsIGhlaWdodCwgaXNIZWlnaHRBdXRvLCBmb3JQcmludCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXRDbGFzc05hbWVzKGNsYXNzTmFtZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXRIZWlnaHQoaGVpZ2h0KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChSZW5kZXJJZC5Qcm92aWRlciwgeyB2YWx1ZTogdGhpcy5jdXN0b21Db250ZW50UmVuZGVySWQgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcmVhdGVFbGVtZW50KENhbGVuZGFyQ29udGVudCwgT2JqZWN0LmFzc2lnbih7IGlzSGVpZ2h0QXV0bzogaXNIZWlnaHRBdXRvLCBmb3JQcmludDogZm9yUHJpbnQgfSwgY3VycmVudERhdGEpKSkpO1xuICAgICAgICAgICAgICAgICAgICB9KSwgdGhpcy5lbCk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICh0aGlzLmlzUmVuZGVyZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmlzUmVuZGVyZWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICByZW5kZXIobnVsbCwgdGhpcy5lbCk7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRDbGFzc05hbWVzKFtdKTtcbiAgICAgICAgICAgICAgICB0aGlzLnNldEhlaWdodCgnJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIGVuc3VyZUVsSGFzU3R5bGVzKGVsKTtcbiAgICAgICAgdGhpcy5lbCA9IGVsO1xuICAgICAgICB0aGlzLnJlbmRlclJ1bm5lciA9IG5ldyBEZWxheWVkUnVubmVyKHRoaXMuaGFuZGxlUmVuZGVyUmVxdWVzdCk7XG4gICAgICAgIG5ldyBDYWxlbmRhckRhdGFNYW5hZ2VyKHtcbiAgICAgICAgICAgIG9wdGlvbk92ZXJyaWRlcyxcbiAgICAgICAgICAgIGNhbGVuZGFyQXBpOiB0aGlzLFxuICAgICAgICAgICAgb25BY3Rpb246IHRoaXMuaGFuZGxlQWN0aW9uLFxuICAgICAgICAgICAgb25EYXRhOiB0aGlzLmhhbmRsZURhdGEsXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGxldCB3YXNSZW5kZXJpbmcgPSB0aGlzLmlzUmVuZGVyaW5nO1xuICAgICAgICBpZiAoIXdhc1JlbmRlcmluZykge1xuICAgICAgICAgICAgdGhpcy5pc1JlbmRlcmluZyA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmN1c3RvbUNvbnRlbnRSZW5kZXJJZCArPSAxO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucmVuZGVyUnVubmVyLnJlcXVlc3QoKTtcbiAgICAgICAgaWYgKHdhc1JlbmRlcmluZykge1xuICAgICAgICAgICAgdGhpcy51cGRhdGVTaXplKCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZGVzdHJveSgpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNSZW5kZXJpbmcpIHtcbiAgICAgICAgICAgIHRoaXMuaXNSZW5kZXJpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMucmVuZGVyUnVubmVyLnJlcXVlc3QoKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICB1cGRhdGVTaXplKCkge1xuICAgICAgICBmbHVzaFN5bmMoKCkgPT4ge1xuICAgICAgICAgICAgc3VwZXIudXBkYXRlU2l6ZSgpO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgYmF0Y2hSZW5kZXJpbmcoZnVuYykge1xuICAgICAgICB0aGlzLnJlbmRlclJ1bm5lci5wYXVzZSgnYmF0Y2hSZW5kZXJpbmcnKTtcbiAgICAgICAgZnVuYygpO1xuICAgICAgICB0aGlzLnJlbmRlclJ1bm5lci5yZXN1bWUoJ2JhdGNoUmVuZGVyaW5nJyk7XG4gICAgfVxuICAgIHBhdXNlUmVuZGVyaW5nKCkge1xuICAgICAgICB0aGlzLnJlbmRlclJ1bm5lci5wYXVzZSgncGF1c2VSZW5kZXJpbmcnKTtcbiAgICB9XG4gICAgcmVzdW1lUmVuZGVyaW5nKCkge1xuICAgICAgICB0aGlzLnJlbmRlclJ1bm5lci5yZXN1bWUoJ3BhdXNlUmVuZGVyaW5nJywgdHJ1ZSk7XG4gICAgfVxuICAgIHJlc2V0T3B0aW9ucyhvcHRpb25PdmVycmlkZXMsIGNoYW5nZWRPcHRpb25OYW1lcykge1xuICAgICAgICB0aGlzLmN1cnJlbnREYXRhTWFuYWdlci5yZXNldE9wdGlvbnMob3B0aW9uT3ZlcnJpZGVzLCBjaGFuZ2VkT3B0aW9uTmFtZXMpO1xuICAgIH1cbiAgICBzZXRDbGFzc05hbWVzKGNsYXNzTmFtZXMpIHtcbiAgICAgICAgaWYgKCFpc0FycmF5c0VxdWFsKGNsYXNzTmFtZXMsIHRoaXMuY3VycmVudENsYXNzTmFtZXMpKSB7XG4gICAgICAgICAgICBsZXQgeyBjbGFzc0xpc3QgfSA9IHRoaXMuZWw7XG4gICAgICAgICAgICBmb3IgKGxldCBjbGFzc05hbWUgb2YgdGhpcy5jdXJyZW50Q2xhc3NOYW1lcykge1xuICAgICAgICAgICAgICAgIGNsYXNzTGlzdC5yZW1vdmUoY2xhc3NOYW1lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZvciAobGV0IGNsYXNzTmFtZSBvZiBjbGFzc05hbWVzKSB7XG4gICAgICAgICAgICAgICAgY2xhc3NMaXN0LmFkZChjbGFzc05hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5jdXJyZW50Q2xhc3NOYW1lcyA9IGNsYXNzTmFtZXM7XG4gICAgICAgIH1cbiAgICB9XG4gICAgc2V0SGVpZ2h0KGhlaWdodCkge1xuICAgICAgICBhcHBseVN0eWxlUHJvcCh0aGlzLmVsLCAnaGVpZ2h0JywgaGVpZ2h0KTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGZvcm1hdERhdGUoZGF0ZUlucHV0LCBvcHRpb25zID0ge30pIHtcbiAgICBsZXQgZGF0ZUVudiA9IGJ1aWxkRGF0ZUVudihvcHRpb25zKTtcbiAgICBsZXQgZm9ybWF0dGVyID0gY3JlYXRlRm9ybWF0dGVyKG9wdGlvbnMpO1xuICAgIGxldCBkYXRlTWV0YSA9IGRhdGVFbnYuY3JlYXRlTWFya2VyTWV0YShkYXRlSW5wdXQpO1xuICAgIGlmICghZGF0ZU1ldGEpIHsgLy8gVE9ETzogd2FybmluZz9cbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH1cbiAgICByZXR1cm4gZGF0ZUVudi5mb3JtYXQoZGF0ZU1ldGEubWFya2VyLCBmb3JtYXR0ZXIsIHtcbiAgICAgICAgZm9yY2VkVHpvOiBkYXRlTWV0YS5mb3JjZWRUem8sXG4gICAgfSk7XG59XG5mdW5jdGlvbiBmb3JtYXRSYW5nZShzdGFydElucHV0LCBlbmRJbnB1dCwgb3B0aW9ucykge1xuICAgIGxldCBkYXRlRW52ID0gYnVpbGREYXRlRW52KHR5cGVvZiBvcHRpb25zID09PSAnb2JqZWN0JyAmJiBvcHRpb25zID8gb3B0aW9ucyA6IHt9KTsgLy8gcGFzcyBpbiBpZiBub24tbnVsbCBvYmplY3RcbiAgICBsZXQgZm9ybWF0dGVyID0gY3JlYXRlRm9ybWF0dGVyKG9wdGlvbnMpO1xuICAgIGxldCBzdGFydE1ldGEgPSBkYXRlRW52LmNyZWF0ZU1hcmtlck1ldGEoc3RhcnRJbnB1dCk7XG4gICAgbGV0IGVuZE1ldGEgPSBkYXRlRW52LmNyZWF0ZU1hcmtlck1ldGEoZW5kSW5wdXQpO1xuICAgIGlmICghc3RhcnRNZXRhIHx8ICFlbmRNZXRhKSB7IC8vIFRPRE86IHdhcm5pbmc/XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9XG4gICAgcmV0dXJuIGRhdGVFbnYuZm9ybWF0UmFuZ2Uoc3RhcnRNZXRhLm1hcmtlciwgZW5kTWV0YS5tYXJrZXIsIGZvcm1hdHRlciwge1xuICAgICAgICBmb3JjZWRTdGFydFR6bzogc3RhcnRNZXRhLmZvcmNlZFR6byxcbiAgICAgICAgZm9yY2VkRW5kVHpvOiBlbmRNZXRhLmZvcmNlZFR6byxcbiAgICAgICAgaXNFbmRFeGNsdXNpdmU6IG9wdGlvbnMuaXNFbmRFeGNsdXNpdmUsXG4gICAgICAgIGRlZmF1bHRTZXBhcmF0b3I6IEJBU0VfT1BUSU9OX0RFRkFVTFRTLmRlZmF1bHRSYW5nZVNlcGFyYXRvcixcbiAgICB9KTtcbn1cbi8vIFRPRE86IG1vcmUgRFJZIGFuZCBvcHRpbWl6ZWRcbmZ1bmN0aW9uIGJ1aWxkRGF0ZUVudihzZXR0aW5ncykge1xuICAgIGxldCBsb2NhbGUgPSBidWlsZExvY2FsZShzZXR0aW5ncy5sb2NhbGUgfHwgJ2VuJywgb3JnYW5pemVSYXdMb2NhbGVzKFtdKS5tYXApOyAvLyBUT0RPOiBkb24ndCBoYXJkY29kZSAnZW4nIGV2ZXJ5d2hlcmVcbiAgICByZXR1cm4gbmV3IERhdGVFbnYoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHsgdGltZVpvbmU6IEJBU0VfT1BUSU9OX0RFRkFVTFRTLnRpbWVab25lLCBjYWxlbmRhclN5c3RlbTogJ2dyZWdvcnknIH0sIHNldHRpbmdzKSwgeyBsb2NhbGUgfSkpO1xufVxuXG4vLyBIRUxQRVJTXG4vKlxuaWYgbmV4dERheVRocmVzaG9sZCBpcyBzcGVjaWZpZWQsIHNsaWNpbmcgaXMgZG9uZSBpbiBhbiBhbGwtZGF5IGZhc2hpb24uXG55b3UgY2FuIGdldCBuZXh0RGF5VGhyZXNob2xkIGZyb20gY29udGV4dC5uZXh0RGF5VGhyZXNob2xkXG4qL1xuZnVuY3Rpb24gc2xpY2VFdmVudHMocHJvcHMsIGFsbERheSkge1xuICAgIHJldHVybiBzbGljZUV2ZW50U3RvcmUocHJvcHMuZXZlbnRTdG9yZSwgcHJvcHMuZXZlbnRVaUJhc2VzLCBwcm9wcy5kYXRlUHJvZmlsZS5hY3RpdmVSYW5nZSwgYWxsRGF5ID8gcHJvcHMubmV4dERheVRocmVzaG9sZCA6IG51bGwpLmZnO1xufVxuXG5jb25zdCB2ZXJzaW9uID0gJzYuMS4yMCc7XG5cbmV4cG9ydCB7IENhbGVuZGFyLCBjcmVhdGVQbHVnaW4sIGZvcm1hdERhdGUsIGZvcm1hdFJhbmdlLCBnbG9iYWxMb2NhbGVzLCBnbG9iYWxQbHVnaW5zLCBzbGljZUV2ZW50cywgdmVyc2lvbiB9O1xuIl0sIm5hbWVzIjpbXSwiaWdub3JlTGlzdCI6WzBdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///(ssr)/./node_modules/@fullcalendar/core/index.js\n");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "(ssr)/./node_modules/@fullcalendar/core/internal-common.js":
|
|
/*!************************************************************!*\
|
|
!*** ./node_modules/@fullcalendar/core/internal-common.js ***!
|
|
\************************************************************/
|
|
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
|
|
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ $: () => (/* binding */ listenBySelector),\n/* harmony export */ A: () => (/* binding */ memoizeObjArg),\n/* harmony export */ B: () => (/* binding */ BaseComponent),\n/* harmony export */ C: () => (/* binding */ ContentContainer),\n/* harmony export */ D: () => (/* binding */ DelayedRunner),\n/* harmony export */ E: () => (/* binding */ isPropsEqual),\n/* harmony export */ F: () => (/* binding */ Emitter),\n/* harmony export */ G: () => (/* binding */ rangeContainsMarker),\n/* harmony export */ H: () => (/* binding */ createEmptyEventStore),\n/* harmony export */ I: () => (/* binding */ reduceEventStore),\n/* harmony export */ J: () => (/* binding */ rezoneEventStoreDates),\n/* harmony export */ K: () => (/* binding */ mergeRawOptions),\n/* harmony export */ L: () => (/* binding */ BASE_OPTION_REFINERS),\n/* harmony export */ M: () => (/* binding */ CALENDAR_LISTENER_REFINERS),\n/* harmony export */ N: () => (/* binding */ CALENDAR_OPTION_REFINERS),\n/* harmony export */ O: () => (/* binding */ COMPLEX_OPTION_COMPARATORS),\n/* harmony export */ P: () => (/* binding */ VIEW_OPTION_REFINERS),\n/* harmony export */ Q: () => (/* binding */ DateEnv),\n/* harmony export */ R: () => (/* binding */ DateProfileGenerator),\n/* harmony export */ S: () => (/* binding */ createEventUi),\n/* harmony export */ T: () => (/* binding */ Theme),\n/* harmony export */ U: () => (/* binding */ parseBusinessHours),\n/* harmony export */ V: () => (/* binding */ ViewContextType),\n/* harmony export */ W: () => (/* binding */ setRef),\n/* harmony export */ X: () => (/* binding */ Interaction),\n/* harmony export */ Y: () => (/* binding */ getElSeg),\n/* harmony export */ Z: () => (/* binding */ elementClosest),\n/* harmony export */ _: () => (/* binding */ EventImpl),\n/* harmony export */ a: () => (/* binding */ mapHash),\n/* harmony export */ a$: () => (/* binding */ preventDefault),\n/* harmony export */ a0: () => (/* binding */ listenToHoverBySelector),\n/* harmony export */ a1: () => (/* binding */ PureComponent),\n/* harmony export */ a2: () => (/* binding */ buildViewContext),\n/* harmony export */ a3: () => (/* binding */ getUniqueDomId),\n/* harmony export */ a4: () => (/* binding */ parseInteractionSettings),\n/* harmony export */ a5: () => (/* binding */ interactionSettingsStore),\n/* harmony export */ a6: () => (/* binding */ NowTimer),\n/* harmony export */ a7: () => (/* binding */ CalendarImpl),\n/* harmony export */ a8: () => (/* binding */ flushSync),\n/* harmony export */ a9: () => (/* binding */ CalendarRoot),\n/* harmony export */ aA: () => (/* binding */ memoizeArraylike),\n/* harmony export */ aB: () => (/* binding */ memoizeHashlike),\n/* harmony export */ aC: () => (/* binding */ intersectRects),\n/* harmony export */ aD: () => (/* binding */ pointInsideRect),\n/* harmony export */ aE: () => (/* binding */ constrainPoint),\n/* harmony export */ aF: () => (/* binding */ getRectCenter),\n/* harmony export */ aG: () => (/* binding */ diffPoints),\n/* harmony export */ aH: () => (/* binding */ translateRect),\n/* harmony export */ aI: () => (/* binding */ compareObjs),\n/* harmony export */ aJ: () => (/* binding */ collectFromHash),\n/* harmony export */ aK: () => (/* binding */ findElements),\n/* harmony export */ aL: () => (/* binding */ findDirectChildren),\n/* harmony export */ aM: () => (/* binding */ removeElement),\n/* harmony export */ aN: () => (/* binding */ applyStyle),\n/* harmony export */ aO: () => (/* binding */ elementMatches),\n/* harmony export */ aP: () => (/* binding */ getEventTargetViaRoot),\n/* harmony export */ aQ: () => (/* binding */ parseClassNames),\n/* harmony export */ aR: () => (/* binding */ getCanVGrowWithinCell),\n/* harmony export */ aS: () => (/* binding */ mergeEventStores),\n/* harmony export */ aT: () => (/* binding */ getRelevantEvents),\n/* harmony export */ aU: () => (/* binding */ eventTupleToStore),\n/* harmony export */ aV: () => (/* binding */ combineEventUis),\n/* harmony export */ aW: () => (/* binding */ Splitter),\n/* harmony export */ aX: () => (/* binding */ getDayClassNames),\n/* harmony export */ aY: () => (/* binding */ getDateMeta),\n/* harmony export */ aZ: () => (/* binding */ getSlotClassNames),\n/* harmony export */ a_: () => (/* binding */ buildNavLinkAttrs),\n/* harmony export */ aa: () => (/* binding */ RenderId),\n/* harmony export */ ab: () => (/* binding */ ensureElHasStyles),\n/* harmony export */ ac: () => (/* binding */ applyStyleProp),\n/* harmony export */ ad: () => (/* binding */ sliceEventStore),\n/* harmony export */ ae: () => (/* binding */ JsonRequestError),\n/* harmony export */ af: () => (/* binding */ createContext),\n/* harmony export */ ag: () => (/* binding */ refineProps),\n/* harmony export */ ah: () => (/* binding */ createEventInstance),\n/* harmony export */ ai: () => (/* binding */ parseEventDef),\n/* harmony export */ aj: () => (/* binding */ refineEventDef),\n/* harmony export */ ak: () => (/* binding */ padStart),\n/* harmony export */ al: () => (/* binding */ isInt),\n/* harmony export */ am: () => (/* binding */ parseFieldSpecs),\n/* harmony export */ an: () => (/* binding */ compareByFieldSpecs),\n/* harmony export */ ao: () => (/* binding */ flexibleCompare),\n/* harmony export */ ap: () => (/* binding */ preventSelection),\n/* harmony export */ aq: () => (/* binding */ allowSelection),\n/* harmony export */ ar: () => (/* binding */ preventContextMenu),\n/* harmony export */ as: () => (/* binding */ allowContextMenu),\n/* harmony export */ at: () => (/* binding */ compareNumbers),\n/* harmony export */ au: () => (/* binding */ enableCursor),\n/* harmony export */ av: () => (/* binding */ disableCursor),\n/* harmony export */ aw: () => (/* binding */ computeVisibleDayRange),\n/* harmony export */ ax: () => (/* binding */ isMultiDayRange),\n/* harmony export */ ay: () => (/* binding */ diffDates),\n/* harmony export */ az: () => (/* binding */ removeExact),\n/* harmony export */ b: () => (/* binding */ buildViewClassNames),\n/* harmony export */ b$: () => (/* binding */ renderMicroColGroup),\n/* harmony export */ b0: () => (/* binding */ whenTransitionDone),\n/* harmony export */ b1: () => (/* binding */ computeInnerRect),\n/* harmony export */ b2: () => (/* binding */ computeEdges),\n/* harmony export */ b3: () => (/* binding */ getClippingParents),\n/* harmony export */ b4: () => (/* binding */ computeRect),\n/* harmony export */ b5: () => (/* binding */ rangesEqual),\n/* harmony export */ b6: () => (/* binding */ rangesIntersect),\n/* harmony export */ b7: () => (/* binding */ rangeContainsRange),\n/* harmony export */ b8: () => (/* binding */ PositionCache),\n/* harmony export */ b9: () => (/* binding */ ScrollController),\n/* harmony export */ bA: () => (/* binding */ getEntrySpanEnd),\n/* harmony export */ bB: () => (/* binding */ binarySearch),\n/* harmony export */ bC: () => (/* binding */ groupIntersectingEntries),\n/* harmony export */ bD: () => (/* binding */ intersectSpans),\n/* harmony export */ bE: () => (/* binding */ interactionSettingsToStore),\n/* harmony export */ bF: () => (/* binding */ ElementDragging),\n/* harmony export */ bG: () => (/* binding */ config),\n/* harmony export */ bH: () => (/* binding */ parseDragMeta),\n/* harmony export */ bI: () => (/* binding */ DayHeader),\n/* harmony export */ bJ: () => (/* binding */ computeFallbackHeaderFormat),\n/* harmony export */ bK: () => (/* binding */ TableDateCell),\n/* harmony export */ bL: () => (/* binding */ TableDowCell),\n/* harmony export */ bM: () => (/* binding */ DaySeriesModel),\n/* harmony export */ bN: () => (/* binding */ hasBgRendering),\n/* harmony export */ bO: () => (/* binding */ buildSegTimeText),\n/* harmony export */ bP: () => (/* binding */ sortEventSegs),\n/* harmony export */ bQ: () => (/* binding */ getSegMeta),\n/* harmony export */ bR: () => (/* binding */ buildEventRangeKey),\n/* harmony export */ bS: () => (/* binding */ getSegAnchorAttrs),\n/* harmony export */ bT: () => (/* binding */ DayTableModel),\n/* harmony export */ bU: () => (/* binding */ Slicer),\n/* harmony export */ bV: () => (/* binding */ applyMutationToEventStore),\n/* harmony export */ bW: () => (/* binding */ isPropsValid),\n/* harmony export */ bX: () => (/* binding */ isInteractionValid),\n/* harmony export */ bY: () => (/* binding */ isDateSelectionValid),\n/* harmony export */ bZ: () => (/* binding */ SimpleScrollGrid),\n/* harmony export */ b_: () => (/* binding */ hasShrinkWidth),\n/* harmony export */ ba: () => (/* binding */ ElementScrollController),\n/* harmony export */ bb: () => (/* binding */ WindowScrollController),\n/* harmony export */ bc: () => (/* binding */ DateComponent),\n/* harmony export */ bd: () => (/* binding */ isDateSpansEqual),\n/* harmony export */ be: () => (/* binding */ addMs),\n/* harmony export */ bf: () => (/* binding */ addWeeks),\n/* harmony export */ bg: () => (/* binding */ diffWeeks),\n/* harmony export */ bh: () => (/* binding */ diffWholeWeeks),\n/* harmony export */ bi: () => (/* binding */ diffDayAndTime),\n/* harmony export */ bj: () => (/* binding */ diffDays),\n/* harmony export */ bk: () => (/* binding */ isValidDate),\n/* harmony export */ bl: () => (/* binding */ asCleanDays),\n/* harmony export */ bm: () => (/* binding */ multiplyDuration),\n/* harmony export */ bn: () => (/* binding */ addDurations),\n/* harmony export */ bo: () => (/* binding */ asRoughMinutes),\n/* harmony export */ bp: () => (/* binding */ asRoughSeconds),\n/* harmony export */ bq: () => (/* binding */ asRoughMs),\n/* harmony export */ br: () => (/* binding */ wholeDivideDurations),\n/* harmony export */ bs: () => (/* binding */ formatIsoTimeString),\n/* harmony export */ bt: () => (/* binding */ formatDayString),\n/* harmony export */ bu: () => (/* binding */ buildIsoString),\n/* harmony export */ bv: () => (/* binding */ formatIsoMonthStr),\n/* harmony export */ bw: () => (/* binding */ NamedTimeZoneImpl),\n/* harmony export */ bx: () => (/* binding */ parse),\n/* harmony export */ by: () => (/* binding */ SegHierarchy),\n/* harmony export */ bz: () => (/* binding */ buildEntryKey),\n/* harmony export */ c: () => (/* binding */ greatestDurationDenominator),\n/* harmony export */ c0: () => (/* binding */ getScrollGridClassNames),\n/* harmony export */ c1: () => (/* binding */ getSectionClassNames),\n/* harmony export */ c2: () => (/* binding */ getSectionHasLiquidHeight),\n/* harmony export */ c3: () => (/* binding */ getAllowYScrolling),\n/* harmony export */ c4: () => (/* binding */ renderChunkContent),\n/* harmony export */ c5: () => (/* binding */ computeShrinkWidth),\n/* harmony export */ c6: () => (/* binding */ sanitizeShrinkWidth),\n/* harmony export */ c7: () => (/* binding */ isColPropsEqual),\n/* harmony export */ c8: () => (/* binding */ renderScrollShim),\n/* harmony export */ c9: () => (/* binding */ getStickyFooterScrollbar),\n/* harmony export */ ca: () => (/* binding */ getStickyHeaderDates),\n/* harmony export */ cb: () => (/* binding */ Scroller),\n/* harmony export */ cc: () => (/* binding */ getScrollbarWidths),\n/* harmony export */ cd: () => (/* binding */ RefMap),\n/* harmony export */ ce: () => (/* binding */ getIsRtlScrollbarOnLeft),\n/* harmony export */ cf: () => (/* binding */ ScrollResponder),\n/* harmony export */ cg: () => (/* binding */ StandardEvent),\n/* harmony export */ ch: () => (/* binding */ NowIndicatorContainer),\n/* harmony export */ ci: () => (/* binding */ DayCellContainer),\n/* harmony export */ cj: () => (/* binding */ hasCustomDayCellContent),\n/* harmony export */ ck: () => (/* binding */ EventContainer),\n/* harmony export */ cl: () => (/* binding */ renderFill),\n/* harmony export */ cm: () => (/* binding */ BgEvent),\n/* harmony export */ cn: () => (/* binding */ WeekNumberContainer),\n/* harmony export */ co: () => (/* binding */ MoreLinkContainer),\n/* harmony export */ cp: () => (/* binding */ computeEarliestSegStart),\n/* harmony export */ cq: () => (/* binding */ ViewContainer),\n/* harmony export */ cr: () => (/* binding */ triggerDateSelect),\n/* harmony export */ cs: () => (/* binding */ getDefaultEventEnd),\n/* harmony export */ ct: () => (/* binding */ injectStyles),\n/* harmony export */ cu: () => (/* binding */ buildElAttrs),\n/* harmony export */ cv: () => (/* binding */ CustomRenderingStore),\n/* harmony export */ d: () => (/* binding */ createDuration),\n/* harmony export */ e: () => (/* binding */ BASE_OPTION_DEFAULTS),\n/* harmony export */ f: () => (/* binding */ arrayToHash),\n/* harmony export */ g: () => (/* binding */ guid),\n/* harmony export */ h: () => (/* binding */ filterHash),\n/* harmony export */ i: () => (/* binding */ isArraysEqual),\n/* harmony export */ j: () => (/* binding */ buildEventSourceRefiners),\n/* harmony export */ k: () => (/* binding */ formatWithOrdinals),\n/* harmony export */ l: () => (/* binding */ buildRangeApiWithTimeZone),\n/* harmony export */ m: () => (/* binding */ mergeProps),\n/* harmony export */ n: () => (/* binding */ identity),\n/* harmony export */ o: () => (/* binding */ intersectRanges),\n/* harmony export */ p: () => (/* binding */ parseEventSource),\n/* harmony export */ q: () => (/* binding */ startOfDay),\n/* harmony export */ r: () => (/* binding */ requestJson),\n/* harmony export */ s: () => (/* binding */ subtractDurations),\n/* harmony export */ t: () => (/* binding */ addDays),\n/* harmony export */ u: () => (/* binding */ unpromisify),\n/* harmony export */ v: () => (/* binding */ hashValuesToArray),\n/* harmony export */ w: () => (/* binding */ buildEventApis),\n/* harmony export */ x: () => (/* binding */ createFormatter),\n/* harmony export */ y: () => (/* binding */ diffWholeDays),\n/* harmony export */ z: () => (/* binding */ memoize)\n/* harmony export */ });\n/* harmony import */ var preact__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! preact */ \"(ssr)/./node_modules/preact/dist/preact.mjs\");\n/* harmony import */ var preact_compat__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! preact/compat */ \"(ssr)/./node_modules/preact/compat/dist/compat.mjs\");\n\n\n\n\nconst styleTexts = [];\nconst styleEls = new Map();\nfunction injectStyles(styleText) {\n styleTexts.push(styleText);\n styleEls.forEach((styleEl) => {\n appendStylesTo(styleEl, styleText);\n });\n}\nfunction ensureElHasStyles(el) {\n if (el.isConnected && // sometimes true if SSR system simulates DOM\n el.getRootNode // sometimes undefined if SSR system simulates DOM\n ) {\n registerStylesRoot(el.getRootNode());\n }\n}\nfunction registerStylesRoot(rootNode) {\n let styleEl = styleEls.get(rootNode);\n if (!styleEl || !styleEl.isConnected) {\n styleEl = rootNode.querySelector('style[data-fullcalendar]');\n if (!styleEl) {\n styleEl = document.createElement('style');\n styleEl.setAttribute('data-fullcalendar', '');\n const nonce = getNonceValue();\n if (nonce) {\n styleEl.nonce = nonce;\n }\n const parentEl = rootNode === document ? document.head : rootNode;\n const insertBefore = rootNode === document\n ? parentEl.querySelector('script,link[rel=stylesheet],link[as=style],style')\n : parentEl.firstChild;\n parentEl.insertBefore(styleEl, insertBefore);\n }\n styleEls.set(rootNode, styleEl);\n hydrateStylesRoot(styleEl);\n }\n}\nfunction hydrateStylesRoot(styleEl) {\n for (const styleText of styleTexts) {\n appendStylesTo(styleEl, styleText);\n }\n}\nfunction appendStylesTo(styleEl, styleText) {\n const { sheet } = styleEl;\n const ruleCnt = sheet.cssRules.length;\n styleText.split('}').forEach((styleStr, i) => {\n styleStr = styleStr.trim();\n if (styleStr) {\n sheet.insertRule(styleStr + '}', ruleCnt + i);\n }\n });\n}\n// nonce\n// -------------------------------------------------------------------------------------------------\nlet queriedNonceValue;\nfunction getNonceValue() {\n if (queriedNonceValue === undefined) {\n queriedNonceValue = queryNonceValue();\n }\n return queriedNonceValue;\n}\n/*\nTODO: discourage meta tag and instead put nonce attribute on placeholder <style> tag\n*/\nfunction queryNonceValue() {\n const metaWithNonce = document.querySelector('meta[name=\"csp-nonce\"]');\n if (metaWithNonce && metaWithNonce.hasAttribute('content')) {\n return metaWithNonce.getAttribute('content');\n }\n const elWithNonce = document.querySelector('script[nonce]');\n if (elWithNonce) {\n return elWithNonce.nonce || '';\n }\n return '';\n}\n// main\n// -------------------------------------------------------------------------------------------------\nif (typeof document !== 'undefined') {\n registerStylesRoot(document);\n}\n\nvar css_248z = \":root{--fc-small-font-size:.85em;--fc-page-bg-color:#fff;--fc-neutral-bg-color:hsla(0,0%,82%,.3);--fc-neutral-text-color:grey;--fc-border-color:#ddd;--fc-button-text-color:#fff;--fc-button-bg-color:#2c3e50;--fc-button-border-color:#2c3e50;--fc-button-hover-bg-color:#1e2b37;--fc-button-hover-border-color:#1a252f;--fc-button-active-bg-color:#1a252f;--fc-button-active-border-color:#151e27;--fc-event-bg-color:#3788d8;--fc-event-border-color:#3788d8;--fc-event-text-color:#fff;--fc-event-selected-overlay-color:rgba(0,0,0,.25);--fc-more-link-bg-color:#d0d0d0;--fc-more-link-text-color:inherit;--fc-event-resizer-thickness:8px;--fc-event-resizer-dot-total-width:8px;--fc-event-resizer-dot-border-width:1px;--fc-non-business-color:hsla(0,0%,84%,.3);--fc-bg-event-color:#8fdf82;--fc-bg-event-opacity:0.3;--fc-highlight-color:rgba(188,232,241,.3);--fc-today-bg-color:rgba(255,220,40,.15);--fc-now-indicator-color:red}.fc-not-allowed,.fc-not-allowed .fc-event{cursor:not-allowed}.fc{display:flex;flex-direction:column;font-size:1em}.fc,.fc *,.fc :after,.fc :before{box-sizing:border-box}.fc table{border-collapse:collapse;border-spacing:0;font-size:1em}.fc th{text-align:center}.fc td,.fc th{padding:0;vertical-align:top}.fc a[data-navlink]{cursor:pointer}.fc a[data-navlink]:hover{text-decoration:underline}.fc-direction-ltr{direction:ltr;text-align:left}.fc-direction-rtl{direction:rtl;text-align:right}.fc-theme-standard td,.fc-theme-standard th{border:1px solid var(--fc-border-color)}.fc-liquid-hack td,.fc-liquid-hack th{position:relative}@font-face{font-family:fcicons;font-style:normal;font-weight:400;src:url(\\\"data:application/x-font-ttf;charset=utf-8;base64,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\\\") format(\\\"truetype\\\")}.fc-icon{speak:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:inline-block;font-family:fcicons!important;font-style:normal;font-variant:normal;font-weight:400;height:1em;line-height:1;text-align:center;text-transform:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:1em}.fc-icon-chevron-left:before{content:\\\"\\\\e900\\\"}.fc-icon-chevron-right:before{content:\\\"\\\\e901\\\"}.fc-icon-chevrons-left:before{content:\\\"\\\\e902\\\"}.fc-icon-chevrons-right:before{content:\\\"\\\\e903\\\"}.fc-icon-minus-square:before{content:\\\"\\\\e904\\\"}.fc-icon-plus-square:before{content:\\\"\\\\e905\\\"}.fc-icon-x:before{content:\\\"\\\\e906\\\"}.fc .fc-button{border-radius:0;font-family:inherit;font-size:inherit;line-height:inherit;margin:0;overflow:visible;text-transform:none}.fc .fc-button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}.fc .fc-button{-webkit-appearance:button}.fc .fc-button:not(:disabled){cursor:pointer}.fc .fc-button{background-color:transparent;border:1px solid transparent;border-radius:.25em;display:inline-block;font-size:1em;font-weight:400;line-height:1.5;padding:.4em .65em;text-align:center;-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:middle}.fc .fc-button:hover{text-decoration:none}.fc .fc-button:focus{box-shadow:0 0 0 .2rem rgba(44,62,80,.25);outline:0}.fc .fc-button:disabled{opacity:.65}.fc .fc-button-primary{background-color:var(--fc-button-bg-color);border-color:var(--fc-button-border-color);color:var(--fc-button-text-color)}.fc .fc-button-primary:hover{background-color:var(--fc-button-hover-bg-color);border-color:var(--fc-button-hover-border-color);color:var(--fc-button-text-color)}.fc .fc-button-primary:disabled{background-color:var(--fc-button-bg-color);border-color:var(--fc-button-border-color);color:var(--fc-button-text-color)}.fc .fc-button-primary:focus{box-shadow:0 0 0 .2rem rgba(76,91,106,.5)}.fc .fc-button-primary:not(:disabled).fc-button-active,.fc .fc-button-primary:not(:disabled):active{background-color:var(--fc-button-active-bg-color);border-color:var(--fc-button-active-border-color);color:var(--fc-button-text-color)}.fc .fc-button-primary:not(:disabled).fc-button-active:focus,.fc .fc-button-primary:not(:disabled):active:focus{box-shadow:0 0 0 .2rem rgba(76,91,106,.5)}.fc .fc-button .fc-icon{font-size:1.5em;vertical-align:middle}.fc .fc-button-group{display:inline-flex;position:relative;vertical-align:middle}.fc .fc-button-group>.fc-button{flex:1 1 auto;position:relative}.fc .fc-button-group>.fc-button.fc-button-active,.fc .fc-button-group>.fc-button:active,.fc .fc-button-group>.fc-button:focus,.fc .fc-button-group>.fc-button:hover{z-index:1}.fc-direction-ltr .fc-button-group>.fc-button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0;margin-left:-1px}.fc-direction-ltr .fc-button-group>.fc-button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.fc-direction-rtl .fc-button-group>.fc-button:not(:first-child){border-bottom-right-radius:0;border-top-right-radius:0;margin-right:-1px}.fc-direction-rtl .fc-button-group>.fc-button:not(:last-child){border-bottom-left-radius:0;border-top-left-radius:0}.fc .fc-toolbar{align-items:center;display:flex;justify-content:space-between}.fc .fc-toolbar.fc-header-toolbar{margin-bottom:1.5em}.fc .fc-toolbar.fc-footer-toolbar{margin-top:1.5em}.fc .fc-toolbar-title{font-size:1.75em;margin:0}.fc-direction-ltr .fc-toolbar>*>:not(:first-child){margin-left:.75em}.fc-direction-rtl .fc-toolbar>*>:not(:first-child){margin-right:.75em}.fc-direction-rtl .fc-toolbar-ltr{flex-direction:row-reverse}.fc .fc-scroller{-webkit-overflow-scrolling:touch;position:relative}.fc .fc-scroller-liquid{height:100%}.fc .fc-scroller-liquid-absolute{bottom:0;left:0;position:absolute;right:0;top:0}.fc .fc-scroller-harness{direction:ltr;overflow:hidden;position:relative}.fc .fc-scroller-harness-liquid{height:100%}.fc-direction-rtl .fc-scroller-harness>.fc-scroller{direction:rtl}.fc-theme-standard .fc-scrollgrid{border:1px solid var(--fc-border-color)}.fc .fc-scrollgrid,.fc .fc-scrollgrid table{table-layout:fixed;width:100%}.fc .fc-scrollgrid table{border-left-style:hidden;border-right-style:hidden;border-top-style:hidden}.fc .fc-scrollgrid{border-bottom-width:0;border-collapse:separate;border-right-width:0}.fc .fc-scrollgrid-liquid{height:100%}.fc .fc-scrollgrid-section,.fc .fc-scrollgrid-section table,.fc .fc-scrollgrid-section>td{height:1px}.fc .fc-scrollgrid-section-liquid>td{height:100%}.fc .fc-scrollgrid-section>*{border-left-width:0;border-top-width:0}.fc .fc-scrollgrid-section-footer>*,.fc .fc-scrollgrid-section-header>*{border-bottom-width:0}.fc .fc-scrollgrid-section-body table,.fc .fc-scrollgrid-section-footer table{border-bottom-style:hidden}.fc .fc-scrollgrid-section-sticky>*{background:var(--fc-page-bg-color);position:sticky;z-index:3}.fc .fc-scrollgrid-section-header.fc-scrollgrid-section-sticky>*{top:0}.fc .fc-scrollgrid-section-footer.fc-scrollgrid-section-sticky>*{bottom:0}.fc .fc-scrollgrid-sticky-shim{height:1px;margin-bottom:-1px}.fc-sticky{position:sticky}.fc .fc-view-harness{flex-grow:1;position:relative}.fc .fc-view-harness-active>.fc-view{bottom:0;left:0;position:absolute;right:0;top:0}.fc .fc-col-header-cell-cushion{display:inline-block;padding:2px 4px}.fc .fc-bg-event,.fc .fc-highlight,.fc .fc-non-business{bottom:0;left:0;position:absolute;right:0;top:0}.fc .fc-non-business{background:var(--fc-non-business-color)}.fc .fc-bg-event{background:var(--fc-bg-event-color);opacity:var(--fc-bg-event-opacity)}.fc .fc-bg-event .fc-event-title{font-size:var(--fc-small-font-size);font-style:italic;margin:.5em}.fc .fc-highlight{background:var(--fc-highlight-color)}.fc .fc-cell-shaded,.fc .fc-day-disabled{background:var(--fc-neutral-bg-color)}a.fc-event,a.fc-event:hover{text-decoration:none}.fc-event.fc-event-draggable,.fc-event[href]{cursor:pointer}.fc-event .fc-event-main{position:relative;z-index:2}.fc-event-dragging:not(.fc-event-selected){opacity:.75}.fc-event-dragging.fc-event-selected{box-shadow:0 2px 7px rgba(0,0,0,.3)}.fc-event .fc-event-resizer{display:none;position:absolute;z-index:4}.fc-event-selected .fc-event-resizer,.fc-event:hover .fc-event-resizer{display:block}.fc-event-selected .fc-event-resizer{background:var(--fc-page-bg-color);border-color:inherit;border-radius:calc(var(--fc-event-resizer-dot-total-width)/2);border-style:solid;border-width:var(--fc-event-resizer-dot-border-width);height:var(--fc-event-resizer-dot-total-width);width:var(--fc-event-resizer-dot-total-width)}.fc-event-selected .fc-event-resizer:before{bottom:-20px;content:\\\"\\\";left:-20px;position:absolute;right:-20px;top:-20px}.fc-event-selected,.fc-event:focus{box-shadow:0 2px 5px rgba(0,0,0,.2)}.fc-event-selected:before,.fc-event:focus:before{bottom:0;content:\\\"\\\";left:0;position:absolute;right:0;top:0;z-index:3}.fc-event-selected:after,.fc-event:focus:after{background:var(--fc-event-selected-overlay-color);bottom:-1px;content:\\\"\\\";left:-1px;position:absolute;right:-1px;top:-1px;z-index:1}.fc-h-event{background-color:var(--fc-event-bg-color);border:1px solid var(--fc-event-border-color);display:block}.fc-h-event .fc-event-main{color:var(--fc-event-text-color)}.fc-h-event .fc-event-main-frame{display:flex}.fc-h-event .fc-event-time{max-width:100%;overflow:hidden}.fc-h-event .fc-event-title-container{flex-grow:1;flex-shrink:1;min-width:0}.fc-h-event .fc-event-title{display:inline-block;left:0;max-width:100%;overflow:hidden;right:0;vertical-align:top}.fc-h-event.fc-event-selected:before{bottom:-10px;top:-10px}.fc-direction-ltr .fc-daygrid-block-event:not(.fc-event-start),.fc-direction-rtl .fc-daygrid-block-event:not(.fc-event-end){border-bottom-left-radius:0;border-left-width:0;border-top-left-radius:0}.fc-direction-ltr .fc-daygrid-block-event:not(.fc-event-end),.fc-direction-rtl .fc-daygrid-block-event:not(.fc-event-start){border-bottom-right-radius:0;border-right-width:0;border-top-right-radius:0}.fc-h-event:not(.fc-event-selected) .fc-event-resizer{bottom:0;top:0;width:var(--fc-event-resizer-thickness)}.fc-direction-ltr .fc-h-event:not(.fc-event-selected) .fc-event-resizer-start,.fc-direction-rtl .fc-h-event:not(.fc-event-selected) .fc-event-resizer-end{cursor:w-resize;left:calc(var(--fc-event-resizer-thickness)*-.5)}.fc-direction-ltr .fc-h-event:not(.fc-event-selected) .fc-event-resizer-end,.fc-direction-rtl .fc-h-event:not(.fc-event-selected) .fc-event-resizer-start{cursor:e-resize;right:calc(var(--fc-event-resizer-thickness)*-.5)}.fc-h-event.fc-event-selected .fc-event-resizer{margin-top:calc(var(--fc-event-resizer-dot-total-width)*-.5);top:50%}.fc-direction-ltr .fc-h-event.fc-event-selected .fc-event-resizer-start,.fc-direction-rtl .fc-h-event.fc-event-selected .fc-event-resizer-end{left:calc(var(--fc-event-resizer-dot-total-width)*-.5)}.fc-direction-ltr .fc-h-event.fc-event-selected .fc-event-resizer-end,.fc-direction-rtl .fc-h-event.fc-event-selected .fc-event-resizer-start{right:calc(var(--fc-event-resizer-dot-total-width)*-.5)}.fc .fc-popover{box-shadow:0 2px 6px rgba(0,0,0,.15);position:absolute;z-index:9999}.fc .fc-popover-header{align-items:center;display:flex;flex-direction:row;justify-content:space-between;padding:3px 4px}.fc .fc-popover-title{margin:0 2px}.fc .fc-popover-close{cursor:pointer;font-size:1.1em;opacity:.65}.fc-theme-standard .fc-popover{background:var(--fc-page-bg-color);border:1px solid var(--fc-border-color)}.fc-theme-standard .fc-popover-header{background:var(--fc-neutral-bg-color)}\";\ninjectStyles(css_248z);\n\nclass DelayedRunner {\n constructor(drainedOption) {\n this.drainedOption = drainedOption;\n this.isRunning = false;\n this.isDirty = false;\n this.pauseDepths = {};\n this.timeoutId = 0;\n }\n request(delay) {\n this.isDirty = true;\n if (!this.isPaused()) {\n this.clearTimeout();\n if (delay == null) {\n this.tryDrain();\n }\n else {\n this.timeoutId = setTimeout(// NOT OPTIMAL! TODO: look at debounce\n this.tryDrain.bind(this), delay);\n }\n }\n }\n pause(scope = '') {\n let { pauseDepths } = this;\n pauseDepths[scope] = (pauseDepths[scope] || 0) + 1;\n this.clearTimeout();\n }\n resume(scope = '', force) {\n let { pauseDepths } = this;\n if (scope in pauseDepths) {\n if (force) {\n delete pauseDepths[scope];\n }\n else {\n pauseDepths[scope] -= 1;\n let depth = pauseDepths[scope];\n if (depth <= 0) {\n delete pauseDepths[scope];\n }\n }\n this.tryDrain();\n }\n }\n isPaused() {\n return Object.keys(this.pauseDepths).length;\n }\n tryDrain() {\n if (!this.isRunning && !this.isPaused()) {\n this.isRunning = true;\n while (this.isDirty) {\n this.isDirty = false;\n this.drained(); // might set isDirty to true again\n }\n this.isRunning = false;\n }\n }\n clear() {\n this.clearTimeout();\n this.isDirty = false;\n this.pauseDepths = {};\n }\n clearTimeout() {\n if (this.timeoutId) {\n clearTimeout(this.timeoutId);\n this.timeoutId = 0;\n }\n }\n drained() {\n if (this.drainedOption) {\n this.drainedOption();\n }\n }\n}\n\nfunction removeElement(el) {\n if (el.parentNode) {\n el.parentNode.removeChild(el);\n }\n}\n// Querying\n// ----------------------------------------------------------------------------------------------------------------\nfunction elementClosest(el, selector) {\n if (el.closest) {\n return el.closest(selector);\n // really bad fallback for IE\n // from https://developer.mozilla.org/en-US/docs/Web/API/Element/closest\n }\n if (!document.documentElement.contains(el)) {\n return null;\n }\n do {\n if (elementMatches(el, selector)) {\n return el;\n }\n el = (el.parentElement || el.parentNode);\n } while (el !== null && el.nodeType === 1);\n return null;\n}\nfunction elementMatches(el, selector) {\n let method = el.matches || el.matchesSelector || el.msMatchesSelector;\n return method.call(el, selector);\n}\n// accepts multiple subject els\n// returns a real array. good for methods like forEach\n// TODO: accept the document\nfunction findElements(container, selector) {\n let containers = container instanceof HTMLElement ? [container] : container;\n let allMatches = [];\n for (let i = 0; i < containers.length; i += 1) {\n let matches = containers[i].querySelectorAll(selector);\n for (let j = 0; j < matches.length; j += 1) {\n allMatches.push(matches[j]);\n }\n }\n return allMatches;\n}\n// accepts multiple subject els\n// only queries direct child elements // TODO: rename to findDirectChildren!\nfunction findDirectChildren(parent, selector) {\n let parents = parent instanceof HTMLElement ? [parent] : parent;\n let allMatches = [];\n for (let i = 0; i < parents.length; i += 1) {\n let childNodes = parents[i].children; // only ever elements\n for (let j = 0; j < childNodes.length; j += 1) {\n let childNode = childNodes[j];\n if (!selector || elementMatches(childNode, selector)) {\n allMatches.push(childNode);\n }\n }\n }\n return allMatches;\n}\n// Style\n// ----------------------------------------------------------------------------------------------------------------\nconst PIXEL_PROP_RE = /(top|left|right|bottom|width|height)$/i;\nfunction applyStyle(el, props) {\n for (let propName in props) {\n applyStyleProp(el, propName, props[propName]);\n }\n}\nfunction applyStyleProp(el, name, val) {\n if (val == null) {\n el.style[name] = '';\n }\n else if (typeof val === 'number' && PIXEL_PROP_RE.test(name)) {\n el.style[name] = `${val}px`;\n }\n else {\n el.style[name] = val;\n }\n}\n// Event Handling\n// ----------------------------------------------------------------------------------------------------------------\n// if intercepting bubbled events at the document/window/body level,\n// and want to see originating element (the 'target'), use this util instead\n// of `ev.target` because it goes within web-component boundaries.\nfunction getEventTargetViaRoot(ev) {\n var _a, _b;\n return (_b = (_a = ev.composedPath) === null || _a === void 0 ? void 0 : _a.call(ev)[0]) !== null && _b !== void 0 ? _b : ev.target;\n}\n// Unique ID for DOM attribute\nlet guid$1 = 0;\nfunction getUniqueDomId() {\n guid$1 += 1;\n return 'fc-dom-' + guid$1;\n}\n\n// Stops a mouse/touch event from doing it's native browser action\nfunction preventDefault(ev) {\n ev.preventDefault();\n}\n// Event Delegation\n// ----------------------------------------------------------------------------------------------------------------\nfunction buildDelegationHandler(selector, handler) {\n return (ev) => {\n let matchedChild = elementClosest(ev.target, selector);\n if (matchedChild) {\n handler.call(matchedChild, ev, matchedChild);\n }\n };\n}\nfunction listenBySelector(container, eventType, selector, handler) {\n let attachedHandler = buildDelegationHandler(selector, handler);\n container.addEventListener(eventType, attachedHandler);\n return () => {\n container.removeEventListener(eventType, attachedHandler);\n };\n}\nfunction listenToHoverBySelector(container, selector, onMouseEnter, onMouseLeave) {\n let currentMatchedChild;\n return listenBySelector(container, 'mouseover', selector, (mouseOverEv, matchedChild) => {\n if (matchedChild !== currentMatchedChild) {\n currentMatchedChild = matchedChild;\n onMouseEnter(mouseOverEv, matchedChild);\n let realOnMouseLeave = (mouseLeaveEv) => {\n currentMatchedChild = null;\n onMouseLeave(mouseLeaveEv, matchedChild);\n matchedChild.removeEventListener('mouseleave', realOnMouseLeave);\n };\n // listen to the next mouseleave, and then unattach\n matchedChild.addEventListener('mouseleave', realOnMouseLeave);\n }\n });\n}\n// Animation\n// ----------------------------------------------------------------------------------------------------------------\nconst transitionEventNames = [\n 'webkitTransitionEnd',\n 'otransitionend',\n 'oTransitionEnd',\n 'msTransitionEnd',\n 'transitionend',\n];\n// triggered only when the next single subsequent transition finishes\nfunction whenTransitionDone(el, callback) {\n let realCallback = (ev) => {\n callback(ev);\n transitionEventNames.forEach((eventName) => {\n el.removeEventListener(eventName, realCallback);\n });\n };\n transitionEventNames.forEach((eventName) => {\n el.addEventListener(eventName, realCallback); // cross-browser way to determine when the transition finishes\n });\n}\n// ARIA workarounds\n// ----------------------------------------------------------------------------------------------------------------\nfunction createAriaClickAttrs(handler) {\n return Object.assign({ onClick: handler }, createAriaKeyboardAttrs(handler));\n}\nfunction createAriaKeyboardAttrs(handler) {\n return {\n tabIndex: 0,\n onKeyDown(ev) {\n if (ev.key === 'Enter' || ev.key === ' ') {\n handler(ev);\n ev.preventDefault(); // if space, don't scroll down page\n }\n },\n };\n}\n\nlet guidNumber = 0;\nfunction guid() {\n guidNumber += 1;\n return String(guidNumber);\n}\n/* FullCalendar-specific DOM Utilities\n----------------------------------------------------------------------------------------------------------------------*/\n// Make the mouse cursor express that an event is not allowed in the current area\nfunction disableCursor() {\n document.body.classList.add('fc-not-allowed');\n}\n// Returns the mouse cursor to its original look\nfunction enableCursor() {\n document.body.classList.remove('fc-not-allowed');\n}\n/* Selection\n----------------------------------------------------------------------------------------------------------------------*/\nfunction preventSelection(el) {\n el.style.userSelect = 'none';\n el.style.webkitUserSelect = 'none';\n el.addEventListener('selectstart', preventDefault);\n}\nfunction allowSelection(el) {\n el.style.userSelect = '';\n el.style.webkitUserSelect = '';\n el.removeEventListener('selectstart', preventDefault);\n}\n/* Context Menu\n----------------------------------------------------------------------------------------------------------------------*/\nfunction preventContextMenu(el) {\n el.addEventListener('contextmenu', preventDefault);\n}\nfunction allowContextMenu(el) {\n el.removeEventListener('contextmenu', preventDefault);\n}\nfunction parseFieldSpecs(input) {\n let specs = [];\n let tokens = [];\n let i;\n let token;\n if (typeof input === 'string') {\n tokens = input.split(/\\s*,\\s*/);\n }\n else if (typeof input === 'function') {\n tokens = [input];\n }\n else if (Array.isArray(input)) {\n tokens = input;\n }\n for (i = 0; i < tokens.length; i += 1) {\n token = tokens[i];\n if (typeof token === 'string') {\n specs.push(token.charAt(0) === '-' ?\n { field: token.substring(1), order: -1 } :\n { field: token, order: 1 });\n }\n else if (typeof token === 'function') {\n specs.push({ func: token });\n }\n }\n return specs;\n}\nfunction compareByFieldSpecs(obj0, obj1, fieldSpecs) {\n let i;\n let cmp;\n for (i = 0; i < fieldSpecs.length; i += 1) {\n cmp = compareByFieldSpec(obj0, obj1, fieldSpecs[i]);\n if (cmp) {\n return cmp;\n }\n }\n return 0;\n}\nfunction compareByFieldSpec(obj0, obj1, fieldSpec) {\n if (fieldSpec.func) {\n return fieldSpec.func(obj0, obj1);\n }\n return flexibleCompare(obj0[fieldSpec.field], obj1[fieldSpec.field])\n * (fieldSpec.order || 1);\n}\nfunction flexibleCompare(a, b) {\n if (!a && !b) {\n return 0;\n }\n if (b == null) {\n return -1;\n }\n if (a == null) {\n return 1;\n }\n if (typeof a === 'string' || typeof b === 'string') {\n return String(a).localeCompare(String(b));\n }\n return a - b;\n}\n/* String Utilities\n----------------------------------------------------------------------------------------------------------------------*/\nfunction padStart(val, len) {\n let s = String(val);\n return '000'.substr(0, len - s.length) + s;\n}\nfunction formatWithOrdinals(formatter, args, fallbackText) {\n if (typeof formatter === 'function') {\n return formatter(...args);\n }\n if (typeof formatter === 'string') { // non-blank string\n return args.reduce((str, arg, index) => (str.replace('$' + index, arg || '')), formatter);\n }\n return fallbackText;\n}\n/* Number Utilities\n----------------------------------------------------------------------------------------------------------------------*/\nfunction compareNumbers(a, b) {\n return a - b;\n}\nfunction isInt(n) {\n return n % 1 === 0;\n}\n/* FC-specific DOM dimension stuff\n----------------------------------------------------------------------------------------------------------------------*/\nfunction computeSmallestCellWidth(cellEl) {\n let allWidthEl = cellEl.querySelector('.fc-scrollgrid-shrink-frame');\n let contentWidthEl = cellEl.querySelector('.fc-scrollgrid-shrink-cushion');\n if (!allWidthEl) {\n throw new Error('needs fc-scrollgrid-shrink-frame className'); // TODO: use const\n }\n if (!contentWidthEl) {\n throw new Error('needs fc-scrollgrid-shrink-cushion className');\n }\n return cellEl.getBoundingClientRect().width - allWidthEl.getBoundingClientRect().width + // the cell padding+border\n contentWidthEl.getBoundingClientRect().width;\n}\n\nconst INTERNAL_UNITS = ['years', 'months', 'days', 'milliseconds'];\nconst PARSE_RE = /^(-?)(?:(\\d+)\\.)?(\\d+):(\\d\\d)(?::(\\d\\d)(?:\\.(\\d\\d\\d))?)?/;\n// Parsing and Creation\nfunction createDuration(input, unit) {\n if (typeof input === 'string') {\n return parseString(input);\n }\n if (typeof input === 'object' && input) { // non-null object\n return parseObject(input);\n }\n if (typeof input === 'number') {\n return parseObject({ [unit || 'milliseconds']: input });\n }\n return null;\n}\nfunction parseString(s) {\n let m = PARSE_RE.exec(s);\n if (m) {\n let sign = m[1] ? -1 : 1;\n return {\n years: 0,\n months: 0,\n days: sign * (m[2] ? parseInt(m[2], 10) : 0),\n milliseconds: sign * ((m[3] ? parseInt(m[3], 10) : 0) * 60 * 60 * 1000 + // hours\n (m[4] ? parseInt(m[4], 10) : 0) * 60 * 1000 + // minutes\n (m[5] ? parseInt(m[5], 10) : 0) * 1000 + // seconds\n (m[6] ? parseInt(m[6], 10) : 0) // ms\n ),\n };\n }\n return null;\n}\nfunction parseObject(obj) {\n let duration = {\n years: obj.years || obj.year || 0,\n months: obj.months || obj.month || 0,\n days: obj.days || obj.day || 0,\n milliseconds: (obj.hours || obj.hour || 0) * 60 * 60 * 1000 + // hours\n (obj.minutes || obj.minute || 0) * 60 * 1000 + // minutes\n (obj.seconds || obj.second || 0) * 1000 + // seconds\n (obj.milliseconds || obj.millisecond || obj.ms || 0), // ms\n };\n let weeks = obj.weeks || obj.week;\n if (weeks) {\n duration.days += weeks * 7;\n duration.specifiedWeeks = true;\n }\n return duration;\n}\n// Equality\nfunction durationsEqual(d0, d1) {\n return d0.years === d1.years &&\n d0.months === d1.months &&\n d0.days === d1.days &&\n d0.milliseconds === d1.milliseconds;\n}\nfunction asCleanDays(dur) {\n if (!dur.years && !dur.months && !dur.milliseconds) {\n return dur.days;\n }\n return 0;\n}\n// Simple Math\nfunction addDurations(d0, d1) {\n return {\n years: d0.years + d1.years,\n months: d0.months + d1.months,\n days: d0.days + d1.days,\n milliseconds: d0.milliseconds + d1.milliseconds,\n };\n}\nfunction subtractDurations(d1, d0) {\n return {\n years: d1.years - d0.years,\n months: d1.months - d0.months,\n days: d1.days - d0.days,\n milliseconds: d1.milliseconds - d0.milliseconds,\n };\n}\nfunction multiplyDuration(d, n) {\n return {\n years: d.years * n,\n months: d.months * n,\n days: d.days * n,\n milliseconds: d.milliseconds * n,\n };\n}\n// Conversions\n// \"Rough\" because they are based on average-case Gregorian months/years\nfunction asRoughYears(dur) {\n return asRoughDays(dur) / 365;\n}\nfunction asRoughMonths(dur) {\n return asRoughDays(dur) / 30;\n}\nfunction asRoughDays(dur) {\n return asRoughMs(dur) / 864e5;\n}\nfunction asRoughMinutes(dur) {\n return asRoughMs(dur) / (1000 * 60);\n}\nfunction asRoughSeconds(dur) {\n return asRoughMs(dur) / 1000;\n}\nfunction asRoughMs(dur) {\n return dur.years * (365 * 864e5) +\n dur.months * (30 * 864e5) +\n dur.days * 864e5 +\n dur.milliseconds;\n}\n// Advanced Math\nfunction wholeDivideDurations(numerator, denominator) {\n let res = null;\n for (let i = 0; i < INTERNAL_UNITS.length; i += 1) {\n let unit = INTERNAL_UNITS[i];\n if (denominator[unit]) {\n let localRes = numerator[unit] / denominator[unit];\n if (!isInt(localRes) || (res !== null && res !== localRes)) {\n return null;\n }\n res = localRes;\n }\n else if (numerator[unit]) {\n // needs to divide by something but can't!\n return null;\n }\n }\n return res;\n}\nfunction greatestDurationDenominator(dur) {\n let ms = dur.milliseconds;\n if (ms) {\n if (ms % 1000 !== 0) {\n return { unit: 'millisecond', value: ms };\n }\n if (ms % (1000 * 60) !== 0) {\n return { unit: 'second', value: ms / 1000 };\n }\n if (ms % (1000 * 60 * 60) !== 0) {\n return { unit: 'minute', value: ms / (1000 * 60) };\n }\n if (ms) {\n return { unit: 'hour', value: ms / (1000 * 60 * 60) };\n }\n }\n if (dur.days) {\n if (dur.specifiedWeeks && dur.days % 7 === 0) {\n return { unit: 'week', value: dur.days / 7 };\n }\n return { unit: 'day', value: dur.days };\n }\n if (dur.months) {\n return { unit: 'month', value: dur.months };\n }\n if (dur.years) {\n return { unit: 'year', value: dur.years };\n }\n return { unit: 'millisecond', value: 0 };\n}\n\n// TODO: new util arrayify?\nfunction removeExact(array, exactVal) {\n let removeCnt = 0;\n let i = 0;\n while (i < array.length) {\n if (array[i] === exactVal) {\n array.splice(i, 1);\n removeCnt += 1;\n }\n else {\n i += 1;\n }\n }\n return removeCnt;\n}\nfunction isArraysEqual(a0, a1, equalityFunc) {\n if (a0 === a1) {\n return true;\n }\n let len = a0.length;\n let i;\n if (len !== a1.length) { // not array? or not same length?\n return false;\n }\n for (i = 0; i < len; i += 1) {\n if (!(equalityFunc ? equalityFunc(a0[i], a1[i]) : a0[i] === a1[i])) {\n return false;\n }\n }\n return true;\n}\n\nconst DAY_IDS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];\n// Adding\nfunction addWeeks(m, n) {\n let a = dateToUtcArray(m);\n a[2] += n * 7;\n return arrayToUtcDate(a);\n}\nfunction addDays(m, n) {\n let a = dateToUtcArray(m);\n a[2] += n;\n return arrayToUtcDate(a);\n}\nfunction addMs(m, n) {\n let a = dateToUtcArray(m);\n a[6] += n;\n return arrayToUtcDate(a);\n}\n// Diffing (all return floats)\n// TODO: why not use ranges?\nfunction diffWeeks(m0, m1) {\n return diffDays(m0, m1) / 7;\n}\nfunction diffDays(m0, m1) {\n return (m1.valueOf() - m0.valueOf()) / (1000 * 60 * 60 * 24);\n}\nfunction diffHours(m0, m1) {\n return (m1.valueOf() - m0.valueOf()) / (1000 * 60 * 60);\n}\nfunction diffMinutes(m0, m1) {\n return (m1.valueOf() - m0.valueOf()) / (1000 * 60);\n}\nfunction diffSeconds(m0, m1) {\n return (m1.valueOf() - m0.valueOf()) / 1000;\n}\nfunction diffDayAndTime(m0, m1) {\n let m0day = startOfDay(m0);\n let m1day = startOfDay(m1);\n return {\n years: 0,\n months: 0,\n days: Math.round(diffDays(m0day, m1day)),\n milliseconds: (m1.valueOf() - m1day.valueOf()) - (m0.valueOf() - m0day.valueOf()),\n };\n}\n// Diffing Whole Units\nfunction diffWholeWeeks(m0, m1) {\n let d = diffWholeDays(m0, m1);\n if (d !== null && d % 7 === 0) {\n return d / 7;\n }\n return null;\n}\nfunction diffWholeDays(m0, m1) {\n if (timeAsMs(m0) === timeAsMs(m1)) {\n return Math.round(diffDays(m0, m1));\n }\n return null;\n}\n// Start-Of\nfunction startOfDay(m) {\n return arrayToUtcDate([\n m.getUTCFullYear(),\n m.getUTCMonth(),\n m.getUTCDate(),\n ]);\n}\nfunction startOfHour(m) {\n return arrayToUtcDate([\n m.getUTCFullYear(),\n m.getUTCMonth(),\n m.getUTCDate(),\n m.getUTCHours(),\n ]);\n}\nfunction startOfMinute(m) {\n return arrayToUtcDate([\n m.getUTCFullYear(),\n m.getUTCMonth(),\n m.getUTCDate(),\n m.getUTCHours(),\n m.getUTCMinutes(),\n ]);\n}\nfunction startOfSecond(m) {\n return arrayToUtcDate([\n m.getUTCFullYear(),\n m.getUTCMonth(),\n m.getUTCDate(),\n m.getUTCHours(),\n m.getUTCMinutes(),\n m.getUTCSeconds(),\n ]);\n}\n// Week Computation\nfunction weekOfYear(marker, dow, doy) {\n let y = marker.getUTCFullYear();\n let w = weekOfGivenYear(marker, y, dow, doy);\n if (w < 1) {\n return weekOfGivenYear(marker, y - 1, dow, doy);\n }\n let nextW = weekOfGivenYear(marker, y + 1, dow, doy);\n if (nextW >= 1) {\n return Math.min(w, nextW);\n }\n return w;\n}\nfunction weekOfGivenYear(marker, year, dow, doy) {\n let firstWeekStart = arrayToUtcDate([year, 0, 1 + firstWeekOffset(year, dow, doy)]);\n let dayStart = startOfDay(marker);\n let days = Math.round(diffDays(firstWeekStart, dayStart));\n return Math.floor(days / 7) + 1; // zero-indexed\n}\n// start-of-first-week - start-of-year\nfunction firstWeekOffset(year, dow, doy) {\n // first-week day -- which january is always in the first week (4 for iso, 1 for other)\n let fwd = 7 + dow - doy;\n // first-week day local weekday -- which local weekday is fwd\n let fwdlw = (7 + arrayToUtcDate([year, 0, fwd]).getUTCDay() - dow) % 7;\n return -fwdlw + fwd - 1;\n}\n// Array Conversion\nfunction dateToLocalArray(date) {\n return [\n date.getFullYear(),\n date.getMonth(),\n date.getDate(),\n date.getHours(),\n date.getMinutes(),\n date.getSeconds(),\n date.getMilliseconds(),\n ];\n}\nfunction arrayToLocalDate(a) {\n return new Date(a[0], a[1] || 0, a[2] == null ? 1 : a[2], // day of month\n a[3] || 0, a[4] || 0, a[5] || 0);\n}\nfunction dateToUtcArray(date) {\n return [\n date.getUTCFullYear(),\n date.getUTCMonth(),\n date.getUTCDate(),\n date.getUTCHours(),\n date.getUTCMinutes(),\n date.getUTCSeconds(),\n date.getUTCMilliseconds(),\n ];\n}\nfunction arrayToUtcDate(a) {\n // according to web standards (and Safari), a month index is required.\n // massage if only given a year.\n if (a.length === 1) {\n a = a.concat([0]);\n }\n return new Date(Date.UTC(...a));\n}\n// Other Utils\nfunction isValidDate(m) {\n return !isNaN(m.valueOf());\n}\nfunction timeAsMs(m) {\n return m.getUTCHours() * 1000 * 60 * 60 +\n m.getUTCMinutes() * 1000 * 60 +\n m.getUTCSeconds() * 1000 +\n m.getUTCMilliseconds();\n}\n\n// timeZoneOffset is in minutes\nfunction buildIsoString(marker, timeZoneOffset, stripZeroTime = false) {\n let s = marker.toISOString();\n s = s.replace('.000', '');\n if (stripZeroTime) {\n s = s.replace('T00:00:00Z', '');\n }\n if (s.length > 10) { // time part wasn't stripped, can add timezone info\n if (timeZoneOffset == null) {\n s = s.replace('Z', '');\n }\n else if (timeZoneOffset !== 0) {\n s = s.replace('Z', formatTimeZoneOffset(timeZoneOffset, true));\n }\n // otherwise, its UTC-0 and we want to keep the Z\n }\n return s;\n}\n// formats the date, but with no time part\n// TODO: somehow merge with buildIsoString and stripZeroTime\n// TODO: rename. omit \"string\"\nfunction formatDayString(marker) {\n return marker.toISOString().replace(/T.*$/, '');\n}\nfunction formatIsoMonthStr(marker) {\n return marker.toISOString().match(/^\\d{4}-\\d{2}/)[0];\n}\n// TODO: use Date::toISOString and use everything after the T?\nfunction formatIsoTimeString(marker) {\n return padStart(marker.getUTCHours(), 2) + ':' +\n padStart(marker.getUTCMinutes(), 2) + ':' +\n padStart(marker.getUTCSeconds(), 2);\n}\nfunction formatTimeZoneOffset(minutes, doIso = false) {\n let sign = minutes < 0 ? '-' : '+';\n let abs = Math.abs(minutes);\n let hours = Math.floor(abs / 60);\n let mins = Math.round(abs % 60);\n if (doIso) {\n return `${sign + padStart(hours, 2)}:${padStart(mins, 2)}`;\n }\n return `GMT${sign}${hours}${mins ? `:${padStart(mins, 2)}` : ''}`;\n}\n\nfunction memoize(workerFunc, resEquality, teardownFunc) {\n let currentArgs;\n let currentRes;\n return function (...newArgs) {\n if (!currentArgs) {\n currentRes = workerFunc.apply(this, newArgs);\n }\n else if (!isArraysEqual(currentArgs, newArgs)) {\n if (teardownFunc) {\n teardownFunc(currentRes);\n }\n let res = workerFunc.apply(this, newArgs);\n if (!resEquality || !resEquality(res, currentRes)) {\n currentRes = res;\n }\n }\n currentArgs = newArgs;\n return currentRes;\n };\n}\nfunction memoizeObjArg(workerFunc, resEquality, teardownFunc) {\n let currentArg;\n let currentRes;\n return (newArg) => {\n if (!currentArg) {\n currentRes = workerFunc.call(this, newArg);\n }\n else if (!isPropsEqual(currentArg, newArg)) {\n if (teardownFunc) {\n teardownFunc(currentRes);\n }\n let res = workerFunc.call(this, newArg);\n if (!resEquality || !resEquality(res, currentRes)) {\n currentRes = res;\n }\n }\n currentArg = newArg;\n return currentRes;\n };\n}\nfunction memoizeArraylike(// used at all?\nworkerFunc, resEquality, teardownFunc) {\n let currentArgSets = [];\n let currentResults = [];\n return (newArgSets) => {\n let currentLen = currentArgSets.length;\n let newLen = newArgSets.length;\n let i = 0;\n for (; i < currentLen; i += 1) {\n if (!newArgSets[i]) { // one of the old sets no longer exists\n if (teardownFunc) {\n teardownFunc(currentResults[i]);\n }\n }\n else if (!isArraysEqual(currentArgSets[i], newArgSets[i])) {\n if (teardownFunc) {\n teardownFunc(currentResults[i]);\n }\n let res = workerFunc.apply(this, newArgSets[i]);\n if (!resEquality || !resEquality(res, currentResults[i])) {\n currentResults[i] = res;\n }\n }\n }\n for (; i < newLen; i += 1) {\n currentResults[i] = workerFunc.apply(this, newArgSets[i]);\n }\n currentArgSets = newArgSets;\n currentResults.splice(newLen); // remove excess\n return currentResults;\n };\n}\nfunction memoizeHashlike(workerFunc, resEquality, teardownFunc) {\n let currentArgHash = {};\n let currentResHash = {};\n return (newArgHash) => {\n let newResHash = {};\n for (let key in newArgHash) {\n if (!currentResHash[key]) {\n newResHash[key] = workerFunc.apply(this, newArgHash[key]);\n }\n else if (!isArraysEqual(currentArgHash[key], newArgHash[key])) {\n if (teardownFunc) {\n teardownFunc(currentResHash[key]);\n }\n let res = workerFunc.apply(this, newArgHash[key]);\n newResHash[key] = (resEquality && resEquality(res, currentResHash[key]))\n ? currentResHash[key]\n : res;\n }\n else {\n newResHash[key] = currentResHash[key];\n }\n }\n currentArgHash = newArgHash;\n currentResHash = newResHash;\n return newResHash;\n };\n}\n\nconst EXTENDED_SETTINGS_AND_SEVERITIES = {\n week: 3,\n separator: 9,\n omitZeroMinute: 9,\n meridiem: 9,\n omitCommas: 9,\n};\nconst STANDARD_DATE_PROP_SEVERITIES = {\n timeZoneName: 7,\n era: 6,\n year: 5,\n month: 4,\n day: 2,\n weekday: 2,\n hour: 1,\n minute: 1,\n second: 1,\n};\nconst MERIDIEM_RE = /\\s*([ap])\\.?m\\.?/i; // eats up leading spaces too\nconst COMMA_RE = /,/g; // we need re for globalness\nconst MULTI_SPACE_RE = /\\s+/g;\nconst LTR_RE = /\\u200e/g; // control character\nconst UTC_RE = /UTC|GMT/;\nclass NativeFormatter {\n constructor(formatSettings) {\n let standardDateProps = {};\n let extendedSettings = {};\n let smallestUnitNum = 9; // the smallest unit in the formatter (9 is a sentinel, beyond max)\n for (let name in formatSettings) {\n if (name in EXTENDED_SETTINGS_AND_SEVERITIES) {\n extendedSettings[name] = formatSettings[name];\n const severity = EXTENDED_SETTINGS_AND_SEVERITIES[name];\n if (severity < 9) {\n smallestUnitNum = Math.min(EXTENDED_SETTINGS_AND_SEVERITIES[name], smallestUnitNum);\n }\n }\n else {\n standardDateProps[name] = formatSettings[name];\n if (name in STANDARD_DATE_PROP_SEVERITIES) { // TODO: what about hour12? no severity\n smallestUnitNum = Math.min(STANDARD_DATE_PROP_SEVERITIES[name], smallestUnitNum);\n }\n }\n }\n this.standardDateProps = standardDateProps;\n this.extendedSettings = extendedSettings;\n this.smallestUnitNum = smallestUnitNum;\n this.buildFormattingFunc = memoize(buildFormattingFunc);\n }\n format(date, context) {\n return this.buildFormattingFunc(this.standardDateProps, this.extendedSettings, context)(date);\n }\n formatRange(start, end, context, betterDefaultSeparator) {\n let { standardDateProps, extendedSettings } = this;\n let diffSeverity = computeMarkerDiffSeverity(start.marker, end.marker, context.calendarSystem);\n if (!diffSeverity) {\n return this.format(start, context);\n }\n let biggestUnitForPartial = diffSeverity;\n if (biggestUnitForPartial > 1 && // the two dates are different in a way that's larger scale than time\n (standardDateProps.year === 'numeric' || standardDateProps.year === '2-digit') &&\n (standardDateProps.month === 'numeric' || standardDateProps.month === '2-digit') &&\n (standardDateProps.day === 'numeric' || standardDateProps.day === '2-digit')) {\n biggestUnitForPartial = 1; // make it look like the dates are only different in terms of time\n }\n let full0 = this.format(start, context);\n let full1 = this.format(end, context);\n if (full0 === full1) {\n return full0;\n }\n let partialDateProps = computePartialFormattingOptions(standardDateProps, biggestUnitForPartial);\n let partialFormattingFunc = buildFormattingFunc(partialDateProps, extendedSettings, context);\n let partial0 = partialFormattingFunc(start);\n let partial1 = partialFormattingFunc(end);\n let insertion = findCommonInsertion(full0, partial0, full1, partial1);\n let separator = extendedSettings.separator || betterDefaultSeparator || context.defaultSeparator || '';\n if (insertion) {\n return insertion.before + partial0 + separator + partial1 + insertion.after;\n }\n return full0 + separator + full1;\n }\n getSmallestUnit() {\n switch (this.smallestUnitNum) {\n case 7:\n case 6:\n case 5:\n return 'year';\n case 4:\n return 'month';\n case 3:\n return 'week';\n case 2:\n return 'day';\n default:\n return 'time'; // really?\n }\n }\n}\nfunction buildFormattingFunc(standardDateProps, extendedSettings, context) {\n let standardDatePropCnt = Object.keys(standardDateProps).length;\n if (standardDatePropCnt === 1 && standardDateProps.timeZoneName === 'short') {\n return (date) => (formatTimeZoneOffset(date.timeZoneOffset));\n }\n if (standardDatePropCnt === 0 && extendedSettings.week) {\n return (date) => (formatWeekNumber(context.computeWeekNumber(date.marker), context.weekText, context.weekTextLong, context.locale, extendedSettings.week));\n }\n return buildNativeFormattingFunc(standardDateProps, extendedSettings, context);\n}\nfunction buildNativeFormattingFunc(standardDateProps, extendedSettings, context) {\n standardDateProps = Object.assign({}, standardDateProps); // copy\n extendedSettings = Object.assign({}, extendedSettings); // copy\n sanitizeSettings(standardDateProps, extendedSettings);\n standardDateProps.timeZone = 'UTC'; // we leverage the only guaranteed timeZone for our UTC markers\n let normalFormat = new Intl.DateTimeFormat(context.locale.codes, standardDateProps);\n let zeroFormat; // needed?\n if (extendedSettings.omitZeroMinute) {\n let zeroProps = Object.assign({}, standardDateProps);\n delete zeroProps.minute; // seconds and ms were already considered in sanitizeSettings\n zeroFormat = new Intl.DateTimeFormat(context.locale.codes, zeroProps);\n }\n return (date) => {\n let { marker } = date;\n let format;\n if (zeroFormat && !marker.getUTCMinutes()) {\n format = zeroFormat;\n }\n else {\n format = normalFormat;\n }\n let s = format.format(marker);\n return postProcess(s, date, standardDateProps, extendedSettings, context);\n };\n}\nfunction sanitizeSettings(standardDateProps, extendedSettings) {\n // deal with a browser inconsistency where formatting the timezone\n // requires that the hour/minute be present.\n if (standardDateProps.timeZoneName) {\n if (!standardDateProps.hour) {\n standardDateProps.hour = '2-digit';\n }\n if (!standardDateProps.minute) {\n standardDateProps.minute = '2-digit';\n }\n }\n // only support short timezone names\n if (standardDateProps.timeZoneName === 'long') {\n standardDateProps.timeZoneName = 'short';\n }\n // if requesting to display seconds, MUST display minutes\n if (extendedSettings.omitZeroMinute && (standardDateProps.second || standardDateProps.millisecond)) {\n delete extendedSettings.omitZeroMinute;\n }\n}\nfunction postProcess(s, date, standardDateProps, extendedSettings, context) {\n s = s.replace(LTR_RE, ''); // remove left-to-right control chars. do first. good for other regexes\n if (standardDateProps.timeZoneName === 'short') {\n s = injectTzoStr(s, (context.timeZone === 'UTC' || date.timeZoneOffset == null) ?\n 'UTC' : // important to normalize for IE, which does \"GMT\"\n formatTimeZoneOffset(date.timeZoneOffset));\n }\n if (extendedSettings.omitCommas) {\n s = s.replace(COMMA_RE, '').trim();\n }\n if (extendedSettings.omitZeroMinute) {\n s = s.replace(':00', ''); // zeroFormat doesn't always achieve this\n }\n // ^ do anything that might create adjacent spaces before this point,\n // because MERIDIEM_RE likes to eat up loading spaces\n if (extendedSettings.meridiem === false) {\n s = s.replace(MERIDIEM_RE, '').trim();\n }\n else if (extendedSettings.meridiem === 'narrow') { // a/p\n s = s.replace(MERIDIEM_RE, (m0, m1) => m1.toLocaleLowerCase());\n }\n else if (extendedSettings.meridiem === 'short') { // am/pm\n s = s.replace(MERIDIEM_RE, (m0, m1) => `${m1.toLocaleLowerCase()}m`);\n }\n else if (extendedSettings.meridiem === 'lowercase') { // other meridiem transformers already converted to lowercase\n s = s.replace(MERIDIEM_RE, (m0) => m0.toLocaleLowerCase());\n }\n s = s.replace(MULTI_SPACE_RE, ' ');\n s = s.trim();\n return s;\n}\nfunction injectTzoStr(s, tzoStr) {\n let replaced = false;\n s = s.replace(UTC_RE, () => {\n replaced = true;\n return tzoStr;\n });\n // IE11 doesn't include UTC/GMT in the original string, so append to end\n if (!replaced) {\n s += ` ${tzoStr}`;\n }\n return s;\n}\nfunction formatWeekNumber(num, weekText, weekTextLong, locale, display) {\n let parts = [];\n if (display === 'long') {\n parts.push(weekTextLong);\n }\n else if (display === 'short' || display === 'narrow') {\n parts.push(weekText);\n }\n if (display === 'long' || display === 'short') {\n parts.push(' ');\n }\n parts.push(locale.simpleNumberFormat.format(num));\n if (locale.options.direction === 'rtl') { // TODO: use control characters instead?\n parts.reverse();\n }\n return parts.join('');\n}\n// Range Formatting Utils\n// 0 = exactly the same\n// 1 = different by time\n// and bigger\nfunction computeMarkerDiffSeverity(d0, d1, ca) {\n if (ca.getMarkerYear(d0) !== ca.getMarkerYear(d1)) {\n return 5;\n }\n if (ca.getMarkerMonth(d0) !== ca.getMarkerMonth(d1)) {\n return 4;\n }\n if (ca.getMarkerDay(d0) !== ca.getMarkerDay(d1)) {\n return 2;\n }\n if (timeAsMs(d0) !== timeAsMs(d1)) {\n return 1;\n }\n return 0;\n}\nfunction computePartialFormattingOptions(options, biggestUnit) {\n let partialOptions = {};\n for (let name in options) {\n if (!(name in STANDARD_DATE_PROP_SEVERITIES) || // not a date part prop (like timeZone)\n STANDARD_DATE_PROP_SEVERITIES[name] <= biggestUnit) {\n partialOptions[name] = options[name];\n }\n }\n return partialOptions;\n}\nfunction findCommonInsertion(full0, partial0, full1, partial1) {\n let i0 = 0;\n while (i0 < full0.length) {\n let found0 = full0.indexOf(partial0, i0);\n if (found0 === -1) {\n break;\n }\n let before0 = full0.substr(0, found0);\n i0 = found0 + partial0.length;\n let after0 = full0.substr(i0);\n let i1 = 0;\n while (i1 < full1.length) {\n let found1 = full1.indexOf(partial1, i1);\n if (found1 === -1) {\n break;\n }\n let before1 = full1.substr(0, found1);\n i1 = found1 + partial1.length;\n let after1 = full1.substr(i1);\n if (before0 === before1 && after0 === after1) {\n return {\n before: before0,\n after: after0,\n };\n }\n }\n }\n return null;\n}\n\nfunction expandZonedMarker(dateInfo, calendarSystem) {\n let a = calendarSystem.markerToArray(dateInfo.marker);\n return {\n marker: dateInfo.marker,\n timeZoneOffset: dateInfo.timeZoneOffset,\n array: a,\n year: a[0],\n month: a[1],\n day: a[2],\n hour: a[3],\n minute: a[4],\n second: a[5],\n millisecond: a[6],\n };\n}\n\nfunction createVerboseFormattingArg(start, end, context, betterDefaultSeparator) {\n let startInfo = expandZonedMarker(start, context.calendarSystem);\n let endInfo = end ? expandZonedMarker(end, context.calendarSystem) : null;\n return {\n date: startInfo,\n start: startInfo,\n end: endInfo,\n timeZone: context.timeZone,\n localeCodes: context.locale.codes,\n defaultSeparator: betterDefaultSeparator || context.defaultSeparator,\n };\n}\n\n/*\nTODO: fix the terminology of \"formatter\" vs \"formatting func\"\n*/\n/*\nAt the time of instantiation, this object does not know which cmd-formatting system it will use.\nIt receives this at the time of formatting, as a setting.\n*/\nclass CmdFormatter {\n constructor(cmdStr) {\n this.cmdStr = cmdStr;\n }\n format(date, context, betterDefaultSeparator) {\n return context.cmdFormatter(this.cmdStr, createVerboseFormattingArg(date, null, context, betterDefaultSeparator));\n }\n formatRange(start, end, context, betterDefaultSeparator) {\n return context.cmdFormatter(this.cmdStr, createVerboseFormattingArg(start, end, context, betterDefaultSeparator));\n }\n}\n\nclass FuncFormatter {\n constructor(func) {\n this.func = func;\n }\n format(date, context, betterDefaultSeparator) {\n return this.func(createVerboseFormattingArg(date, null, context, betterDefaultSeparator));\n }\n formatRange(start, end, context, betterDefaultSeparator) {\n return this.func(createVerboseFormattingArg(start, end, context, betterDefaultSeparator));\n }\n}\n\nfunction createFormatter(input) {\n if (typeof input === 'object' && input) { // non-null object\n return new NativeFormatter(input);\n }\n if (typeof input === 'string') {\n return new CmdFormatter(input);\n }\n if (typeof input === 'function') {\n return new FuncFormatter(input);\n }\n return null;\n}\n\n// base options\n// ------------\nconst BASE_OPTION_REFINERS = {\n navLinkDayClick: identity,\n navLinkWeekClick: identity,\n duration: createDuration,\n bootstrapFontAwesome: identity,\n buttonIcons: identity,\n customButtons: identity,\n defaultAllDayEventDuration: createDuration,\n defaultTimedEventDuration: createDuration,\n nextDayThreshold: createDuration,\n scrollTime: createDuration,\n scrollTimeReset: Boolean,\n slotMinTime: createDuration,\n slotMaxTime: createDuration,\n dayPopoverFormat: createFormatter,\n slotDuration: createDuration,\n snapDuration: createDuration,\n headerToolbar: identity,\n footerToolbar: identity,\n defaultRangeSeparator: String,\n titleRangeSeparator: String,\n forceEventDuration: Boolean,\n dayHeaders: Boolean,\n dayHeaderFormat: createFormatter,\n dayHeaderClassNames: identity,\n dayHeaderContent: identity,\n dayHeaderDidMount: identity,\n dayHeaderWillUnmount: identity,\n dayCellClassNames: identity,\n dayCellContent: identity,\n dayCellDidMount: identity,\n dayCellWillUnmount: identity,\n initialView: String,\n aspectRatio: Number,\n weekends: Boolean,\n weekNumberCalculation: identity,\n weekNumbers: Boolean,\n weekNumberClassNames: identity,\n weekNumberContent: identity,\n weekNumberDidMount: identity,\n weekNumberWillUnmount: identity,\n editable: Boolean,\n viewClassNames: identity,\n viewDidMount: identity,\n viewWillUnmount: identity,\n nowIndicator: Boolean,\n nowIndicatorSnap: identity,\n nowIndicatorClassNames: identity,\n nowIndicatorContent: identity,\n nowIndicatorDidMount: identity,\n nowIndicatorWillUnmount: identity,\n showNonCurrentDates: Boolean,\n lazyFetching: Boolean,\n startParam: String,\n endParam: String,\n timeZoneParam: String,\n timeZone: String,\n locales: identity,\n locale: identity,\n themeSystem: String,\n dragRevertDuration: Number,\n dragScroll: Boolean,\n allDayMaintainDuration: Boolean,\n unselectAuto: Boolean,\n dropAccept: identity,\n eventOrder: parseFieldSpecs,\n eventOrderStrict: Boolean,\n handleWindowResize: Boolean,\n windowResizeDelay: Number,\n longPressDelay: Number,\n eventDragMinDistance: Number,\n expandRows: Boolean,\n height: identity,\n contentHeight: identity,\n direction: String,\n weekNumberFormat: createFormatter,\n eventResizableFromStart: Boolean,\n displayEventTime: Boolean,\n displayEventEnd: Boolean,\n weekText: String,\n weekTextLong: String,\n progressiveEventRendering: Boolean,\n businessHours: identity,\n initialDate: identity,\n now: identity,\n eventDataTransform: identity,\n stickyHeaderDates: identity,\n stickyFooterScrollbar: identity,\n viewHeight: identity,\n defaultAllDay: Boolean,\n eventSourceFailure: identity,\n eventSourceSuccess: identity,\n eventDisplay: String,\n eventStartEditable: Boolean,\n eventDurationEditable: Boolean,\n eventOverlap: identity,\n eventConstraint: identity,\n eventAllow: identity,\n eventBackgroundColor: String,\n eventBorderColor: String,\n eventTextColor: String,\n eventColor: String,\n eventClassNames: identity,\n eventContent: identity,\n eventDidMount: identity,\n eventWillUnmount: identity,\n selectConstraint: identity,\n selectOverlap: identity,\n selectAllow: identity,\n droppable: Boolean,\n unselectCancel: String,\n slotLabelFormat: identity,\n slotLaneClassNames: identity,\n slotLaneContent: identity,\n slotLaneDidMount: identity,\n slotLaneWillUnmount: identity,\n slotLabelClassNames: identity,\n slotLabelContent: identity,\n slotLabelDidMount: identity,\n slotLabelWillUnmount: identity,\n dayMaxEvents: identity,\n dayMaxEventRows: identity,\n dayMinWidth: Number,\n slotLabelInterval: createDuration,\n allDayText: String,\n allDayClassNames: identity,\n allDayContent: identity,\n allDayDidMount: identity,\n allDayWillUnmount: identity,\n slotMinWidth: Number,\n navLinks: Boolean,\n eventTimeFormat: createFormatter,\n rerenderDelay: Number,\n moreLinkText: identity,\n moreLinkHint: identity,\n selectMinDistance: Number,\n selectable: Boolean,\n selectLongPressDelay: Number,\n eventLongPressDelay: Number,\n selectMirror: Boolean,\n eventMaxStack: Number,\n eventMinHeight: Number,\n eventMinWidth: Number,\n eventShortHeight: Number,\n slotEventOverlap: Boolean,\n plugins: identity,\n firstDay: Number,\n dayCount: Number,\n dateAlignment: String,\n dateIncrement: createDuration,\n hiddenDays: identity,\n fixedWeekCount: Boolean,\n validRange: identity,\n visibleRange: identity,\n titleFormat: identity,\n eventInteractive: Boolean,\n // only used by list-view, but languages define the value, so we need it in base options\n noEventsText: String,\n viewHint: identity,\n navLinkHint: identity,\n closeHint: String,\n timeHint: String,\n eventHint: String,\n moreLinkClick: identity,\n moreLinkClassNames: identity,\n moreLinkContent: identity,\n moreLinkDidMount: identity,\n moreLinkWillUnmount: identity,\n monthStartFormat: createFormatter,\n // for connectors\n // (can't be part of plugin system b/c must be provided at runtime)\n handleCustomRendering: identity,\n customRenderingMetaMap: identity,\n customRenderingReplaces: Boolean,\n};\n// do NOT give a type here. need `typeof BASE_OPTION_DEFAULTS` to give real results.\n// raw values.\nconst BASE_OPTION_DEFAULTS = {\n eventDisplay: 'auto',\n defaultRangeSeparator: ' - ',\n titleRangeSeparator: ' \\u2013 ',\n defaultTimedEventDuration: '01:00:00',\n defaultAllDayEventDuration: { day: 1 },\n forceEventDuration: false,\n nextDayThreshold: '00:00:00',\n dayHeaders: true,\n initialView: '',\n aspectRatio: 1.35,\n headerToolbar: {\n start: 'title',\n center: '',\n end: 'today prev,next',\n },\n weekends: true,\n weekNumbers: false,\n weekNumberCalculation: 'local',\n editable: false,\n nowIndicator: false,\n scrollTime: '06:00:00',\n scrollTimeReset: true,\n slotMinTime: '00:00:00',\n slotMaxTime: '24:00:00',\n showNonCurrentDates: true,\n lazyFetching: true,\n startParam: 'start',\n endParam: 'end',\n timeZoneParam: 'timeZone',\n timeZone: 'local',\n locales: [],\n locale: '',\n themeSystem: 'standard',\n dragRevertDuration: 500,\n dragScroll: true,\n allDayMaintainDuration: false,\n unselectAuto: true,\n dropAccept: '*',\n eventOrder: 'start,-duration,allDay,title',\n dayPopoverFormat: { month: 'long', day: 'numeric', year: 'numeric' },\n handleWindowResize: true,\n windowResizeDelay: 100,\n longPressDelay: 1000,\n eventDragMinDistance: 5,\n expandRows: false,\n navLinks: false,\n selectable: false,\n eventMinHeight: 15,\n eventMinWidth: 30,\n eventShortHeight: 30,\n monthStartFormat: { month: 'long', day: 'numeric' },\n nowIndicatorSnap: 'auto',\n};\n// calendar listeners\n// ------------------\nconst CALENDAR_LISTENER_REFINERS = {\n datesSet: identity,\n eventsSet: identity,\n eventAdd: identity,\n eventChange: identity,\n eventRemove: identity,\n windowResize: identity,\n eventClick: identity,\n eventMouseEnter: identity,\n eventMouseLeave: identity,\n select: identity,\n unselect: identity,\n loading: identity,\n // internal\n _unmount: identity,\n _beforeprint: identity,\n _afterprint: identity,\n _noEventDrop: identity,\n _noEventResize: identity,\n _resize: identity,\n _scrollRequest: identity,\n};\n// calendar-specific options\n// -------------------------\nconst CALENDAR_OPTION_REFINERS = {\n buttonText: identity,\n buttonHints: identity,\n views: identity,\n plugins: identity,\n initialEvents: identity,\n events: identity,\n eventSources: identity,\n};\nconst COMPLEX_OPTION_COMPARATORS = {\n headerToolbar: isMaybeObjectsEqual,\n footerToolbar: isMaybeObjectsEqual,\n buttonText: isMaybeObjectsEqual,\n buttonHints: isMaybeObjectsEqual,\n buttonIcons: isMaybeObjectsEqual,\n dateIncrement: isMaybeObjectsEqual,\n plugins: isMaybeArraysEqual,\n events: isMaybeArraysEqual,\n eventSources: isMaybeArraysEqual,\n ['resources']: isMaybeArraysEqual,\n};\nfunction isMaybeObjectsEqual(a, b) {\n if (typeof a === 'object' && typeof b === 'object' && a && b) { // both non-null objects\n return isPropsEqual(a, b);\n }\n return a === b;\n}\nfunction isMaybeArraysEqual(a, b) {\n if (Array.isArray(a) && Array.isArray(b)) {\n return isArraysEqual(a, b);\n }\n return a === b;\n}\n// view-specific options\n// ---------------------\nconst VIEW_OPTION_REFINERS = {\n type: String,\n component: identity,\n buttonText: String,\n buttonTextKey: String,\n dateProfileGeneratorClass: identity,\n usesMinMaxTime: Boolean,\n classNames: identity,\n content: identity,\n didMount: identity,\n willUnmount: identity,\n};\n// util funcs\n// ----------------------------------------------------------------------------------------------------\nfunction mergeRawOptions(optionSets) {\n return mergeProps(optionSets, COMPLEX_OPTION_COMPARATORS);\n}\nfunction refineProps(input, refiners) {\n let refined = {};\n let extra = {};\n for (let propName in refiners) {\n if (propName in input) {\n refined[propName] = refiners[propName](input[propName]);\n }\n }\n for (let propName in input) {\n if (!(propName in refiners)) {\n extra[propName] = input[propName];\n }\n }\n return { refined, extra };\n}\nfunction identity(raw) {\n return raw;\n}\n\nconst { hasOwnProperty } = Object.prototype;\n// Merges an array of objects into a single object.\n// The second argument allows for an array of property names who's object values will be merged together.\nfunction mergeProps(propObjs, complexPropsMap) {\n let dest = {};\n if (complexPropsMap) {\n for (let name in complexPropsMap) {\n if (complexPropsMap[name] === isMaybeObjectsEqual) { // implies that it's object-mergeable\n let complexObjs = [];\n // collect the trailing object values, stopping when a non-object is discovered\n for (let i = propObjs.length - 1; i >= 0; i -= 1) {\n let val = propObjs[i][name];\n if (typeof val === 'object' && val) { // non-null object\n complexObjs.unshift(val);\n }\n else if (val !== undefined) {\n dest[name] = val; // if there were no objects, this value will be used\n break;\n }\n }\n // if the trailing values were objects, use the merged value\n if (complexObjs.length) {\n dest[name] = mergeProps(complexObjs);\n }\n }\n }\n }\n // copy values into the destination, going from last to first\n for (let i = propObjs.length - 1; i >= 0; i -= 1) {\n let props = propObjs[i];\n for (let name in props) {\n if (!(name in dest)) { // if already assigned by previous props or complex props, don't reassign\n dest[name] = props[name];\n }\n }\n }\n return dest;\n}\nfunction filterHash(hash, func) {\n let filtered = {};\n for (let key in hash) {\n if (func(hash[key], key)) {\n filtered[key] = hash[key];\n }\n }\n return filtered;\n}\nfunction mapHash(hash, func) {\n let newHash = {};\n for (let key in hash) {\n newHash[key] = func(hash[key], key);\n }\n return newHash;\n}\nfunction arrayToHash(a) {\n let hash = {};\n for (let item of a) {\n hash[item] = true;\n }\n return hash;\n}\n// TODO: reassess browser support\n// https://caniuse.com/?search=object.values\nfunction hashValuesToArray(obj) {\n let a = [];\n for (let key in obj) {\n a.push(obj[key]);\n }\n return a;\n}\nfunction isPropsEqual(obj0, obj1) {\n if (obj0 === obj1) {\n return true;\n }\n for (let key in obj0) {\n if (hasOwnProperty.call(obj0, key)) {\n if (!(key in obj1)) {\n return false;\n }\n }\n }\n for (let key in obj1) {\n if (hasOwnProperty.call(obj1, key)) {\n if (obj0[key] !== obj1[key]) {\n return false;\n }\n }\n }\n return true;\n}\nconst HANDLER_RE = /^on[A-Z]/;\nfunction isNonHandlerPropsEqual(obj0, obj1) {\n const keys = getUnequalProps(obj0, obj1);\n for (let key of keys) {\n if (!HANDLER_RE.test(key)) {\n return false;\n }\n }\n return true;\n}\nfunction getUnequalProps(obj0, obj1) {\n let keys = [];\n for (let key in obj0) {\n if (hasOwnProperty.call(obj0, key)) {\n if (!(key in obj1)) {\n keys.push(key);\n }\n }\n }\n for (let key in obj1) {\n if (hasOwnProperty.call(obj1, key)) {\n if (obj0[key] !== obj1[key]) {\n keys.push(key);\n }\n }\n }\n return keys;\n}\nfunction compareObjs(oldProps, newProps, equalityFuncs = {}) {\n if (oldProps === newProps) {\n return true;\n }\n // if (debug) {\n // for (let key in newProps) {\n // if (key in oldProps && isObjValsEqual(oldProps[key], newProps[key], equalityFuncs[key])) {\n // // equal\n // } else {\n // if (debug) {\n // console.log('prop difference', key, oldProps[key], newProps[key])\n // }\n // }\n // }\n // // check for props that were omitted in the new\n // for (let key in oldProps) {\n // if (!(key in newProps)) {\n // if (debug) {\n // console.log('prop absent', key)\n // }\n // }\n // }\n // }\n for (let key in newProps) {\n if (key in oldProps && isObjValsEqual(oldProps[key], newProps[key], equalityFuncs[key])) ;\n else {\n return false;\n }\n }\n // check for props that were omitted in the new\n for (let key in oldProps) {\n if (!(key in newProps)) {\n return false;\n }\n }\n return true;\n}\n/*\nassumed \"true\" equality for handler names like \"onReceiveSomething\"\n*/\nfunction isObjValsEqual(val0, val1, comparator) {\n if (val0 === val1 || comparator === true) {\n return true;\n }\n if (comparator) {\n return comparator(val0, val1);\n }\n return false;\n}\nfunction collectFromHash(hash, startIndex = 0, endIndex, step = 1) {\n let res = [];\n if (endIndex == null) {\n endIndex = Object.keys(hash).length;\n }\n for (let i = startIndex; i < endIndex; i += step) {\n let val = hash[i];\n if (val !== undefined) { // will disregard undefined for sparse arrays\n res.push(val);\n }\n }\n return res;\n}\n\nlet calendarSystemClassMap = {};\nfunction registerCalendarSystem(name, theClass) {\n calendarSystemClassMap[name] = theClass;\n}\nfunction createCalendarSystem(name) {\n return new calendarSystemClassMap[name]();\n}\nclass GregorianCalendarSystem {\n getMarkerYear(d) {\n return d.getUTCFullYear();\n }\n getMarkerMonth(d) {\n return d.getUTCMonth();\n }\n getMarkerDay(d) {\n return d.getUTCDate();\n }\n arrayToMarker(arr) {\n return arrayToUtcDate(arr);\n }\n markerToArray(marker) {\n return dateToUtcArray(marker);\n }\n}\nregisterCalendarSystem('gregory', GregorianCalendarSystem);\n\nconst ISO_RE = /^\\s*(\\d{4})(-?(\\d{2})(-?(\\d{2})([T ](\\d{2}):?(\\d{2})(:?(\\d{2})(\\.(\\d+))?)?(Z|(([-+])(\\d{2})(:?(\\d{2}))?))?)?)?)?$/;\nfunction parse(str) {\n let m = ISO_RE.exec(str);\n if (m) {\n let 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));\n if (isValidDate(marker)) {\n let timeZoneOffset = null;\n if (m[13]) {\n timeZoneOffset = (m[15] === '-' ? -1 : 1) * (Number(m[16] || 0) * 60 +\n Number(m[18] || 0));\n }\n return {\n marker,\n isTimeUnspecified: !m[6],\n timeZoneOffset,\n };\n }\n }\n return null;\n}\n\nclass DateEnv {\n constructor(settings) {\n let timeZone = this.timeZone = settings.timeZone;\n let isNamedTimeZone = timeZone !== 'local' && timeZone !== 'UTC';\n if (settings.namedTimeZoneImpl && isNamedTimeZone) {\n this.namedTimeZoneImpl = new settings.namedTimeZoneImpl(timeZone);\n }\n this.canComputeOffset = Boolean(!isNamedTimeZone || this.namedTimeZoneImpl);\n this.calendarSystem = createCalendarSystem(settings.calendarSystem);\n this.locale = settings.locale;\n this.weekDow = settings.locale.week.dow;\n this.weekDoy = settings.locale.week.doy;\n if (settings.weekNumberCalculation === 'ISO') {\n this.weekDow = 1;\n this.weekDoy = 4;\n }\n if (typeof settings.firstDay === 'number') {\n this.weekDow = settings.firstDay;\n }\n if (typeof settings.weekNumberCalculation === 'function') {\n this.weekNumberFunc = settings.weekNumberCalculation;\n }\n this.weekText = settings.weekText != null ? settings.weekText : settings.locale.options.weekText;\n this.weekTextLong = (settings.weekTextLong != null ? settings.weekTextLong : settings.locale.options.weekTextLong) || this.weekText;\n this.cmdFormatter = settings.cmdFormatter;\n this.defaultSeparator = settings.defaultSeparator;\n }\n // Creating / Parsing\n createMarker(input) {\n let meta = this.createMarkerMeta(input);\n if (meta === null) {\n return null;\n }\n return meta.marker;\n }\n createNowMarker() {\n if (this.canComputeOffset) {\n return this.timestampToMarker(new Date().valueOf());\n }\n // if we can't compute the current date val for a timezone,\n // better to give the current local date vals than UTC\n return arrayToUtcDate(dateToLocalArray(new Date()));\n }\n createMarkerMeta(input) {\n if (typeof input === 'string') {\n return this.parse(input);\n }\n let marker = null;\n if (typeof input === 'number') {\n marker = this.timestampToMarker(input);\n }\n else if (input instanceof Date) {\n input = input.valueOf();\n if (!isNaN(input)) {\n marker = this.timestampToMarker(input);\n }\n }\n else if (Array.isArray(input)) {\n marker = arrayToUtcDate(input);\n }\n if (marker === null || !isValidDate(marker)) {\n return null;\n }\n return { marker, isTimeUnspecified: false, forcedTzo: null };\n }\n parse(s) {\n let parts = parse(s);\n if (parts === null) {\n return null;\n }\n let { marker } = parts;\n let forcedTzo = null;\n if (parts.timeZoneOffset !== null) {\n if (this.canComputeOffset) {\n marker = this.timestampToMarker(marker.valueOf() - parts.timeZoneOffset * 60 * 1000);\n }\n else {\n forcedTzo = parts.timeZoneOffset;\n }\n }\n return { marker, isTimeUnspecified: parts.isTimeUnspecified, forcedTzo };\n }\n // Accessors\n getYear(marker) {\n return this.calendarSystem.getMarkerYear(marker);\n }\n getMonth(marker) {\n return this.calendarSystem.getMarkerMonth(marker);\n }\n getDay(marker) {\n return this.calendarSystem.getMarkerDay(marker);\n }\n // Adding / Subtracting\n add(marker, dur) {\n let a = this.calendarSystem.markerToArray(marker);\n a[0] += dur.years;\n a[1] += dur.months;\n a[2] += dur.days;\n a[6] += dur.milliseconds;\n return this.calendarSystem.arrayToMarker(a);\n }\n subtract(marker, dur) {\n let a = this.calendarSystem.markerToArray(marker);\n a[0] -= dur.years;\n a[1] -= dur.months;\n a[2] -= dur.days;\n a[6] -= dur.milliseconds;\n return this.calendarSystem.arrayToMarker(a);\n }\n addYears(marker, n) {\n let a = this.calendarSystem.markerToArray(marker);\n a[0] += n;\n return this.calendarSystem.arrayToMarker(a);\n }\n addMonths(marker, n) {\n let a = this.calendarSystem.markerToArray(marker);\n a[1] += n;\n return this.calendarSystem.arrayToMarker(a);\n }\n // Diffing Whole Units\n diffWholeYears(m0, m1) {\n let { calendarSystem } = this;\n if (timeAsMs(m0) === timeAsMs(m1) &&\n calendarSystem.getMarkerDay(m0) === calendarSystem.getMarkerDay(m1) &&\n calendarSystem.getMarkerMonth(m0) === calendarSystem.getMarkerMonth(m1)) {\n return calendarSystem.getMarkerYear(m1) - calendarSystem.getMarkerYear(m0);\n }\n return null;\n }\n diffWholeMonths(m0, m1) {\n let { calendarSystem } = this;\n if (timeAsMs(m0) === timeAsMs(m1) &&\n calendarSystem.getMarkerDay(m0) === calendarSystem.getMarkerDay(m1)) {\n return (calendarSystem.getMarkerMonth(m1) - calendarSystem.getMarkerMonth(m0)) +\n (calendarSystem.getMarkerYear(m1) - calendarSystem.getMarkerYear(m0)) * 12;\n }\n return null;\n }\n // Range / Duration\n greatestWholeUnit(m0, m1) {\n let n = this.diffWholeYears(m0, m1);\n if (n !== null) {\n return { unit: 'year', value: n };\n }\n n = this.diffWholeMonths(m0, m1);\n if (n !== null) {\n return { unit: 'month', value: n };\n }\n n = diffWholeWeeks(m0, m1);\n if (n !== null) {\n return { unit: 'week', value: n };\n }\n n = diffWholeDays(m0, m1);\n if (n !== null) {\n return { unit: 'day', value: n };\n }\n n = diffHours(m0, m1);\n if (isInt(n)) {\n return { unit: 'hour', value: n };\n }\n n = diffMinutes(m0, m1);\n if (isInt(n)) {\n return { unit: 'minute', value: n };\n }\n n = diffSeconds(m0, m1);\n if (isInt(n)) {\n return { unit: 'second', value: n };\n }\n return { unit: 'millisecond', value: m1.valueOf() - m0.valueOf() };\n }\n countDurationsBetween(m0, m1, d) {\n // TODO: can use greatestWholeUnit\n let diff;\n if (d.years) {\n diff = this.diffWholeYears(m0, m1);\n if (diff !== null) {\n return diff / asRoughYears(d);\n }\n }\n if (d.months) {\n diff = this.diffWholeMonths(m0, m1);\n if (diff !== null) {\n return diff / asRoughMonths(d);\n }\n }\n if (d.days) {\n diff = diffWholeDays(m0, m1);\n if (diff !== null) {\n return diff / asRoughDays(d);\n }\n }\n return (m1.valueOf() - m0.valueOf()) / asRoughMs(d);\n }\n // Start-Of\n // these DON'T return zoned-dates. only UTC start-of dates\n startOf(m, unit) {\n if (unit === 'year') {\n return this.startOfYear(m);\n }\n if (unit === 'month') {\n return this.startOfMonth(m);\n }\n if (unit === 'week') {\n return this.startOfWeek(m);\n }\n if (unit === 'day') {\n return startOfDay(m);\n }\n if (unit === 'hour') {\n return startOfHour(m);\n }\n if (unit === 'minute') {\n return startOfMinute(m);\n }\n if (unit === 'second') {\n return startOfSecond(m);\n }\n return null;\n }\n startOfYear(m) {\n return this.calendarSystem.arrayToMarker([\n this.calendarSystem.getMarkerYear(m),\n ]);\n }\n startOfMonth(m) {\n return this.calendarSystem.arrayToMarker([\n this.calendarSystem.getMarkerYear(m),\n this.calendarSystem.getMarkerMonth(m),\n ]);\n }\n startOfWeek(m) {\n return this.calendarSystem.arrayToMarker([\n this.calendarSystem.getMarkerYear(m),\n this.calendarSystem.getMarkerMonth(m),\n m.getUTCDate() - ((m.getUTCDay() - this.weekDow + 7) % 7),\n ]);\n }\n // Week Number\n computeWeekNumber(marker) {\n if (this.weekNumberFunc) {\n return this.weekNumberFunc(this.toDate(marker));\n }\n return weekOfYear(marker, this.weekDow, this.weekDoy);\n }\n // TODO: choke on timeZoneName: long\n format(marker, formatter, dateOptions = {}) {\n return formatter.format({\n marker,\n timeZoneOffset: dateOptions.forcedTzo != null ?\n dateOptions.forcedTzo :\n this.offsetForMarker(marker),\n }, this);\n }\n formatRange(start, end, formatter, dateOptions = {}) {\n if (dateOptions.isEndExclusive) {\n end = addMs(end, -1);\n }\n return formatter.formatRange({\n marker: start,\n timeZoneOffset: dateOptions.forcedStartTzo != null ?\n dateOptions.forcedStartTzo :\n this.offsetForMarker(start),\n }, {\n marker: end,\n timeZoneOffset: dateOptions.forcedEndTzo != null ?\n dateOptions.forcedEndTzo :\n this.offsetForMarker(end),\n }, this, dateOptions.defaultSeparator);\n }\n /*\n DUMB: the omitTime arg is dumb. if we omit the time, we want to omit the timezone offset. and if we do that,\n might as well use buildIsoString or some other util directly\n */\n formatIso(marker, extraOptions = {}) {\n let timeZoneOffset = null;\n if (!extraOptions.omitTimeZoneOffset) {\n if (extraOptions.forcedTzo != null) {\n timeZoneOffset = extraOptions.forcedTzo;\n }\n else {\n timeZoneOffset = this.offsetForMarker(marker);\n }\n }\n return buildIsoString(marker, timeZoneOffset, extraOptions.omitTime);\n }\n // TimeZone\n timestampToMarker(ms) {\n if (this.timeZone === 'local') {\n return arrayToUtcDate(dateToLocalArray(new Date(ms)));\n }\n if (this.timeZone === 'UTC' || !this.namedTimeZoneImpl) {\n return new Date(ms);\n }\n return arrayToUtcDate(this.namedTimeZoneImpl.timestampToArray(ms));\n }\n offsetForMarker(m) {\n if (this.timeZone === 'local') {\n return -arrayToLocalDate(dateToUtcArray(m)).getTimezoneOffset(); // convert \"inverse\" offset to \"normal\" offset\n }\n if (this.timeZone === 'UTC') {\n return 0;\n }\n if (this.namedTimeZoneImpl) {\n return this.namedTimeZoneImpl.offsetForArray(dateToUtcArray(m));\n }\n return null;\n }\n // Conversion\n toDate(m, forcedTzo) {\n if (this.timeZone === 'local') {\n return arrayToLocalDate(dateToUtcArray(m));\n }\n if (this.timeZone === 'UTC') {\n return new Date(m.valueOf()); // make sure it's a copy\n }\n if (!this.namedTimeZoneImpl) {\n return new Date(m.valueOf() - (forcedTzo || 0));\n }\n return new Date(m.valueOf() -\n this.namedTimeZoneImpl.offsetForArray(dateToUtcArray(m)) * 1000 * 60);\n }\n}\n\nclass Theme {\n constructor(calendarOptions) {\n if (this.iconOverrideOption) {\n this.setIconOverride(calendarOptions[this.iconOverrideOption]);\n }\n }\n setIconOverride(iconOverrideHash) {\n let iconClassesCopy;\n let buttonName;\n if (typeof iconOverrideHash === 'object' && iconOverrideHash) { // non-null object\n iconClassesCopy = Object.assign({}, this.iconClasses);\n for (buttonName in iconOverrideHash) {\n iconClassesCopy[buttonName] = this.applyIconOverridePrefix(iconOverrideHash[buttonName]);\n }\n this.iconClasses = iconClassesCopy;\n }\n else if (iconOverrideHash === false) {\n this.iconClasses = {};\n }\n }\n applyIconOverridePrefix(className) {\n let prefix = this.iconOverridePrefix;\n if (prefix && className.indexOf(prefix) !== 0) { // if not already present\n className = prefix + className;\n }\n return className;\n }\n getClass(key) {\n return this.classes[key] || '';\n }\n getIconClass(buttonName, isRtl) {\n let className;\n if (isRtl && this.rtlIconClasses) {\n className = this.rtlIconClasses[buttonName] || this.iconClasses[buttonName];\n }\n else {\n className = this.iconClasses[buttonName];\n }\n if (className) {\n return `${this.baseIconClass} ${className}`;\n }\n return '';\n }\n getCustomButtonIconClass(customButtonProps) {\n let className;\n if (this.iconOverrideCustomButtonOption) {\n className = customButtonProps[this.iconOverrideCustomButtonOption];\n if (className) {\n return `${this.baseIconClass} ${this.applyIconOverridePrefix(className)}`;\n }\n }\n return '';\n }\n}\nTheme.prototype.classes = {};\nTheme.prototype.iconClasses = {};\nTheme.prototype.baseIconClass = '';\nTheme.prototype.iconOverridePrefix = '';\n\n/*\nNOTE: this can be a public API, especially createElement for hooks.\nSee examples/typescript-scheduler/src/index.ts\n*/\nfunction flushSync(runBeforeFlush) {\n runBeforeFlush();\n let oldDebounceRendering = preact__WEBPACK_IMPORTED_MODULE_0__.options.debounceRendering; // orig\n let callbackQ = [];\n function execCallbackSync(callback) {\n callbackQ.push(callback);\n }\n preact__WEBPACK_IMPORTED_MODULE_0__.options.debounceRendering = execCallbackSync;\n preact__WEBPACK_IMPORTED_MODULE_0__.render(preact__WEBPACK_IMPORTED_MODULE_0__.createElement(FakeComponent, {}), document.createElement('div'));\n while (callbackQ.length) {\n callbackQ.shift()();\n }\n preact__WEBPACK_IMPORTED_MODULE_0__.options.debounceRendering = oldDebounceRendering;\n}\nclass FakeComponent extends preact__WEBPACK_IMPORTED_MODULE_0__.Component {\n render() { return preact__WEBPACK_IMPORTED_MODULE_0__.createElement('div', {}); }\n componentDidMount() { this.setState({}); }\n}\n// TODO: use preact/compat instead?\nfunction createContext(defaultValue) {\n let ContextType = preact__WEBPACK_IMPORTED_MODULE_0__.createContext(defaultValue);\n let origProvider = ContextType.Provider;\n ContextType.Provider = function () {\n let isNew = !this.getChildContext;\n let children = origProvider.apply(this, arguments); // eslint-disable-line prefer-rest-params\n if (isNew) {\n let subs = [];\n this.shouldComponentUpdate = (_props) => {\n if (this.props.value !== _props.value) {\n subs.forEach((c) => {\n c.context = _props.value;\n c.forceUpdate();\n });\n }\n };\n this.sub = (c) => {\n subs.push(c);\n let old = c.componentWillUnmount;\n c.componentWillUnmount = () => {\n subs.splice(subs.indexOf(c), 1);\n old && old.call(c);\n };\n };\n }\n return children;\n };\n return ContextType;\n}\n\nclass ScrollResponder {\n constructor(execFunc, emitter, scrollTime, scrollTimeReset) {\n this.execFunc = execFunc;\n this.emitter = emitter;\n this.scrollTime = scrollTime;\n this.scrollTimeReset = scrollTimeReset;\n this.handleScrollRequest = (request) => {\n this.queuedRequest = Object.assign({}, this.queuedRequest || {}, request);\n this.drain();\n };\n emitter.on('_scrollRequest', this.handleScrollRequest);\n this.fireInitialScroll();\n }\n detach() {\n this.emitter.off('_scrollRequest', this.handleScrollRequest);\n }\n update(isDatesNew) {\n if (isDatesNew && this.scrollTimeReset) {\n this.fireInitialScroll(); // will drain\n }\n else {\n this.drain();\n }\n }\n fireInitialScroll() {\n this.handleScrollRequest({\n time: this.scrollTime,\n });\n }\n drain() {\n if (this.queuedRequest && this.execFunc(this.queuedRequest)) {\n this.queuedRequest = null;\n }\n }\n}\n\nconst ViewContextType = createContext({}); // for Components\nfunction buildViewContext(viewSpec, viewApi, viewOptions, dateProfileGenerator, dateEnv, nowManager, theme, pluginHooks, dispatch, getCurrentData, emitter, calendarApi, registerInteractiveComponent, unregisterInteractiveComponent) {\n return {\n dateEnv,\n nowManager,\n options: viewOptions,\n pluginHooks,\n emitter,\n dispatch,\n getCurrentData,\n calendarApi,\n viewSpec,\n viewApi,\n dateProfileGenerator,\n theme,\n isRtl: viewOptions.direction === 'rtl',\n addResizeHandler(handler) {\n emitter.on('_resize', handler);\n },\n removeResizeHandler(handler) {\n emitter.off('_resize', handler);\n },\n createScrollResponder(execFunc) {\n return new ScrollResponder(execFunc, emitter, createDuration(viewOptions.scrollTime), viewOptions.scrollTimeReset);\n },\n registerInteractiveComponent,\n unregisterInteractiveComponent,\n };\n}\n\n/* eslint max-classes-per-file: off */\nclass PureComponent extends preact__WEBPACK_IMPORTED_MODULE_0__.Component {\n // debug: boolean\n shouldComponentUpdate(nextProps, nextState) {\n const shouldUpdate = !compareObjs(this.props, nextProps, this.propEquality /*, this.debug */) ||\n !compareObjs(this.state, nextState, this.stateEquality /*, this.debug */);\n // if (this.debug && shouldUpdate) {\n // console.log('shouldUpdate!')\n // }\n return shouldUpdate;\n }\n // HACK for freakin' React StrictMode\n safeSetState(newState) {\n if (!compareObjs(this.state, Object.assign(Object.assign({}, this.state), newState), this.stateEquality)) {\n this.setState(newState);\n }\n }\n}\nPureComponent.addPropsEquality = addPropsEquality;\nPureComponent.addStateEquality = addStateEquality;\nPureComponent.contextType = ViewContextType;\nPureComponent.prototype.propEquality = {};\nPureComponent.prototype.stateEquality = {};\nclass BaseComponent extends PureComponent {\n}\nBaseComponent.contextType = ViewContextType;\nfunction addPropsEquality(propEquality) {\n let hash = Object.create(this.prototype.propEquality);\n Object.assign(hash, propEquality);\n this.prototype.propEquality = hash;\n}\nfunction addStateEquality(stateEquality) {\n let hash = Object.create(this.prototype.stateEquality);\n Object.assign(hash, stateEquality);\n this.prototype.stateEquality = hash;\n}\n// use other one\nfunction setRef(ref, current) {\n if (typeof ref === 'function') {\n ref(current);\n }\n else if (ref) {\n // see https://github.com/facebook/react/issues/13029\n ref.current = current;\n }\n}\n\nclass ContentInjector extends BaseComponent {\n constructor() {\n super(...arguments);\n this.id = guid();\n this.queuedDomNodes = [];\n this.currentDomNodes = [];\n this.handleEl = (el) => {\n const { options } = this.context;\n const { generatorName } = this.props;\n if (!options.customRenderingReplaces || !hasCustomRenderingHandler(generatorName, options)) {\n this.updateElRef(el);\n }\n };\n this.updateElRef = (el) => {\n if (this.props.elRef) {\n setRef(this.props.elRef, el);\n }\n };\n }\n render() {\n const { props, context } = this;\n const { options } = context;\n const { customGenerator, defaultGenerator, renderProps } = props;\n const attrs = buildElAttrs(props, [], this.handleEl);\n let useDefault = false;\n let innerContent;\n let queuedDomNodes = [];\n let currentGeneratorMeta;\n if (customGenerator != null) {\n const customGeneratorRes = typeof customGenerator === 'function' ?\n customGenerator(renderProps, preact__WEBPACK_IMPORTED_MODULE_0__.createElement) :\n customGenerator;\n if (customGeneratorRes === true) {\n useDefault = true;\n }\n else {\n const isObject = customGeneratorRes && typeof customGeneratorRes === 'object'; // non-null\n if (isObject && ('html' in customGeneratorRes)) {\n attrs.dangerouslySetInnerHTML = { __html: customGeneratorRes.html };\n }\n else if (isObject && ('domNodes' in customGeneratorRes)) {\n queuedDomNodes = Array.prototype.slice.call(customGeneratorRes.domNodes);\n }\n else if (isObject\n ? (0,preact__WEBPACK_IMPORTED_MODULE_0__.isValidElement)(customGeneratorRes) // vdom node\n : typeof customGeneratorRes !== 'function' // primitive value (like string or number)\n ) {\n // use in vdom\n innerContent = customGeneratorRes;\n }\n else {\n // an exotic object for handleCustomRendering\n currentGeneratorMeta = customGeneratorRes;\n }\n }\n }\n else {\n useDefault = !hasCustomRenderingHandler(props.generatorName, options);\n }\n if (useDefault && defaultGenerator) {\n innerContent = defaultGenerator(renderProps);\n }\n this.queuedDomNodes = queuedDomNodes;\n this.currentGeneratorMeta = currentGeneratorMeta;\n return (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(props.elTag, attrs, innerContent);\n }\n componentDidMount() {\n this.applyQueueudDomNodes();\n this.triggerCustomRendering(true);\n }\n componentDidUpdate() {\n this.applyQueueudDomNodes();\n this.triggerCustomRendering(true);\n }\n componentWillUnmount() {\n this.triggerCustomRendering(false); // TODO: different API for removal?\n }\n triggerCustomRendering(isActive) {\n var _a;\n const { props, context } = this;\n const { handleCustomRendering, customRenderingMetaMap } = context.options;\n if (handleCustomRendering) {\n const generatorMeta = (_a = this.currentGeneratorMeta) !== null && _a !== void 0 ? _a : customRenderingMetaMap === null || customRenderingMetaMap === void 0 ? void 0 : customRenderingMetaMap[props.generatorName];\n if (generatorMeta) {\n handleCustomRendering(Object.assign(Object.assign({ id: this.id, isActive, containerEl: this.base, reportNewContainerEl: this.updateElRef, // front-end framework tells us about new container els\n generatorMeta }, props), { elClasses: (props.elClasses || []).filter(isTruthy) }));\n }\n }\n }\n applyQueueudDomNodes() {\n const { queuedDomNodes, currentDomNodes } = this;\n const el = this.base;\n if (!isArraysEqual(queuedDomNodes, currentDomNodes)) {\n currentDomNodes.forEach(removeElement);\n for (let newNode of queuedDomNodes) {\n el.appendChild(newNode);\n }\n this.currentDomNodes = queuedDomNodes;\n }\n }\n}\nContentInjector.addPropsEquality({\n elClasses: isArraysEqual,\n elStyle: isPropsEqual,\n elAttrs: isNonHandlerPropsEqual,\n renderProps: isPropsEqual,\n});\n// Util\n/*\nDoes UI-framework provide custom way of rendering that does not use Preact VDOM\nAND does the calendar's options define custom rendering?\nAKA. Should we NOT render the default content?\n*/\nfunction hasCustomRenderingHandler(generatorName, options) {\n var _a;\n return Boolean(options.handleCustomRendering &&\n generatorName &&\n ((_a = options.customRenderingMetaMap) === null || _a === void 0 ? void 0 : _a[generatorName]));\n}\nfunction buildElAttrs(props, extraClassNames, elRef) {\n const attrs = Object.assign(Object.assign({}, props.elAttrs), { ref: elRef });\n if (props.elClasses || extraClassNames) {\n attrs.className = (props.elClasses || [])\n .concat(extraClassNames || [])\n .concat(attrs.className || [])\n .filter(Boolean)\n .join(' ');\n }\n if (props.elStyle) {\n attrs.style = props.elStyle;\n }\n return attrs;\n}\nfunction isTruthy(val) {\n return Boolean(val);\n}\n\nconst RenderId = createContext(0);\n\nclass ContentContainer extends preact__WEBPACK_IMPORTED_MODULE_0__.Component {\n constructor() {\n super(...arguments);\n this.InnerContent = InnerContentInjector.bind(undefined, this);\n this.handleEl = (el) => {\n this.el = el;\n if (this.props.elRef) {\n setRef(this.props.elRef, el);\n if (el && this.didMountMisfire) {\n this.componentDidMount();\n }\n }\n };\n }\n render() {\n const { props } = this;\n const generatedClassNames = generateClassNames(props.classNameGenerator, props.renderProps);\n if (props.children) {\n const elAttrs = buildElAttrs(props, generatedClassNames, this.handleEl);\n const children = props.children(this.InnerContent, props.renderProps, elAttrs);\n if (props.elTag) {\n return (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(props.elTag, elAttrs, children);\n }\n else {\n return children;\n }\n }\n else {\n return (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)((ContentInjector), Object.assign(Object.assign({}, props), { elRef: this.handleEl, elTag: props.elTag || 'div', elClasses: (props.elClasses || []).concat(generatedClassNames), renderId: this.context }));\n }\n }\n componentDidMount() {\n var _a, _b;\n if (this.el) {\n (_b = (_a = this.props).didMount) === null || _b === void 0 ? void 0 : _b.call(_a, Object.assign(Object.assign({}, this.props.renderProps), { el: this.el }));\n }\n else {\n this.didMountMisfire = true;\n }\n }\n componentWillUnmount() {\n var _a, _b;\n (_b = (_a = this.props).willUnmount) === null || _b === void 0 ? void 0 : _b.call(_a, Object.assign(Object.assign({}, this.props.renderProps), { el: this.el }));\n }\n}\nContentContainer.contextType = RenderId;\nfunction InnerContentInjector(containerComponent, props) {\n const parentProps = containerComponent.props;\n return (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)((ContentInjector), Object.assign({ renderProps: parentProps.renderProps, generatorName: parentProps.generatorName, customGenerator: parentProps.customGenerator, defaultGenerator: parentProps.defaultGenerator, renderId: containerComponent.context }, props));\n}\n// Utils\nfunction generateClassNames(classNameGenerator, renderProps) {\n const classNames = typeof classNameGenerator === 'function' ?\n classNameGenerator(renderProps) :\n classNameGenerator || [];\n return typeof classNames === 'string' ? [classNames] : classNames;\n}\n\nclass ViewContainer extends BaseComponent {\n render() {\n let { props, context } = this;\n let { options } = context;\n let renderProps = { view: context.viewApi };\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(ContentContainer, { elRef: props.elRef, elTag: props.elTag || 'div', elAttrs: props.elAttrs, elClasses: [\n ...buildViewClassNames(props.viewSpec),\n ...(props.elClasses || []),\n ], elStyle: props.elStyle, renderProps: renderProps, classNameGenerator: options.viewClassNames, generatorName: undefined, didMount: options.viewDidMount, willUnmount: options.viewWillUnmount }, () => props.children));\n }\n}\nfunction buildViewClassNames(viewSpec) {\n return [\n `fc-${viewSpec.type}-view`,\n 'fc-view',\n ];\n}\n\nfunction parseRange(input, dateEnv) {\n let start = null;\n let end = null;\n if (input.start) {\n start = dateEnv.createMarker(input.start);\n }\n if (input.end) {\n end = dateEnv.createMarker(input.end);\n }\n if (!start && !end) {\n return null;\n }\n if (start && end && end < start) {\n return null;\n }\n return { start, end };\n}\n// SIDE-EFFECT: will mutate ranges.\n// Will return a new array result.\nfunction invertRanges(ranges, constraintRange) {\n let invertedRanges = [];\n let { start } = constraintRange; // the end of the previous range. the start of the new range\n let i;\n let dateRange;\n // ranges need to be in order. required for our date-walking algorithm\n ranges.sort(compareRanges);\n for (i = 0; i < ranges.length; i += 1) {\n dateRange = ranges[i];\n // add the span of time before the event (if there is any)\n if (dateRange.start > start) { // compare millisecond time (skip any ambig logic)\n invertedRanges.push({ start, end: dateRange.start });\n }\n if (dateRange.end > start) {\n start = dateRange.end;\n }\n }\n // add the span of time after the last event (if there is any)\n if (start < constraintRange.end) { // compare millisecond time (skip any ambig logic)\n invertedRanges.push({ start, end: constraintRange.end });\n }\n return invertedRanges;\n}\nfunction compareRanges(range0, range1) {\n return range0.start.valueOf() - range1.start.valueOf(); // earlier ranges go first\n}\nfunction intersectRanges(range0, range1) {\n let { start, end } = range0;\n let newRange = null;\n if (range1.start !== null) {\n if (start === null) {\n start = range1.start;\n }\n else {\n start = new Date(Math.max(start.valueOf(), range1.start.valueOf()));\n }\n }\n if (range1.end != null) {\n if (end === null) {\n end = range1.end;\n }\n else {\n end = new Date(Math.min(end.valueOf(), range1.end.valueOf()));\n }\n }\n if (start === null || end === null || start < end) {\n newRange = { start, end };\n }\n return newRange;\n}\nfunction rangesEqual(range0, range1) {\n return (range0.start === null ? null : range0.start.valueOf()) === (range1.start === null ? null : range1.start.valueOf()) &&\n (range0.end === null ? null : range0.end.valueOf()) === (range1.end === null ? null : range1.end.valueOf());\n}\nfunction rangesIntersect(range0, range1) {\n return (range0.end === null || range1.start === null || range0.end > range1.start) &&\n (range0.start === null || range1.end === null || range0.start < range1.end);\n}\nfunction rangeContainsRange(outerRange, innerRange) {\n return (outerRange.start === null || (innerRange.start !== null && innerRange.start >= outerRange.start)) &&\n (outerRange.end === null || (innerRange.end !== null && innerRange.end <= outerRange.end));\n}\nfunction rangeContainsMarker(range, date) {\n return (range.start === null || date >= range.start) &&\n (range.end === null || date < range.end);\n}\n// If the given date is not within the given range, move it inside.\n// (If it's past the end, make it one millisecond before the end).\nfunction constrainMarkerToRange(date, range) {\n if (range.start != null && date < range.start) {\n return range.start;\n }\n if (range.end != null && date >= range.end) {\n return new Date(range.end.valueOf() - 1);\n }\n return date;\n}\n\n/* Date stuff that doesn't belong in datelib core\n----------------------------------------------------------------------------------------------------------------------*/\n// given a timed range, computes an all-day range that has the same exact duration,\n// but whose start time is aligned with the start of the day.\nfunction computeAlignedDayRange(timedRange) {\n let dayCnt = Math.floor(diffDays(timedRange.start, timedRange.end)) || 1;\n let start = startOfDay(timedRange.start);\n let end = addDays(start, dayCnt);\n return { start, end };\n}\n// given a timed range, computes an all-day range based on how for the end date bleeds into the next day\n// TODO: give nextDayThreshold a default arg\nfunction computeVisibleDayRange(timedRange, nextDayThreshold = createDuration(0)) {\n let startDay = null;\n let endDay = null;\n if (timedRange.end) {\n endDay = startOfDay(timedRange.end);\n let endTimeMS = timedRange.end.valueOf() - endDay.valueOf(); // # of milliseconds into `endDay`\n // If the end time is actually inclusively part of the next day and is equal to or\n // beyond the next day threshold, adjust the end to be the exclusive end of `endDay`.\n // Otherwise, leaving it as inclusive will cause it to exclude `endDay`.\n if (endTimeMS && endTimeMS >= asRoughMs(nextDayThreshold)) {\n endDay = addDays(endDay, 1);\n }\n }\n if (timedRange.start) {\n startDay = startOfDay(timedRange.start); // the beginning of the day the range starts\n // If end is within `startDay` but not past nextDayThreshold, assign the default duration of one day.\n if (endDay && endDay <= startDay) {\n endDay = addDays(startDay, 1);\n }\n }\n return { start: startDay, end: endDay };\n}\n// spans from one day into another?\nfunction isMultiDayRange(range) {\n let visibleRange = computeVisibleDayRange(range);\n return diffDays(visibleRange.start, visibleRange.end) > 1;\n}\nfunction diffDates(date0, date1, dateEnv, largeUnit) {\n if (largeUnit === 'year') {\n return createDuration(dateEnv.diffWholeYears(date0, date1), 'year');\n }\n if (largeUnit === 'month') {\n return createDuration(dateEnv.diffWholeMonths(date0, date1), 'month');\n }\n return diffDayAndTime(date0, date1); // returns a duration\n}\n\nclass DateProfileGenerator {\n constructor(props) {\n this.props = props;\n this.initHiddenDays();\n }\n /* Date Range Computation\n ------------------------------------------------------------------------------------------------------------------*/\n // Builds a structure with info about what the dates/ranges will be for the \"prev\" view.\n buildPrev(currentDateProfile, currentDate, forceToValid) {\n let { dateEnv } = this.props;\n let prevDate = dateEnv.subtract(dateEnv.startOf(currentDate, currentDateProfile.currentRangeUnit), // important for start-of-month\n currentDateProfile.dateIncrement);\n return this.build(prevDate, -1, forceToValid);\n }\n // Builds a structure with info about what the dates/ranges will be for the \"next\" view.\n buildNext(currentDateProfile, currentDate, forceToValid) {\n let { dateEnv } = this.props;\n let nextDate = dateEnv.add(dateEnv.startOf(currentDate, currentDateProfile.currentRangeUnit), // important for start-of-month\n currentDateProfile.dateIncrement);\n return this.build(nextDate, 1, forceToValid);\n }\n // Builds a structure holding dates/ranges for rendering around the given date.\n // Optional direction param indicates whether the date is being incremented/decremented\n // from its previous value. decremented = -1, incremented = 1 (default).\n build(currentDate, direction, forceToValid = true) {\n let { props } = this;\n let validRange;\n let currentInfo;\n let isRangeAllDay;\n let renderRange;\n let activeRange;\n let isValid;\n validRange = this.buildValidRange();\n validRange = this.trimHiddenDays(validRange);\n if (forceToValid) {\n currentDate = constrainMarkerToRange(currentDate, validRange);\n }\n currentInfo = this.buildCurrentRangeInfo(currentDate, direction);\n isRangeAllDay = /^(year|month|week|day)$/.test(currentInfo.unit);\n renderRange = this.buildRenderRange(this.trimHiddenDays(currentInfo.range), currentInfo.unit, isRangeAllDay);\n renderRange = this.trimHiddenDays(renderRange);\n activeRange = renderRange;\n if (!props.showNonCurrentDates) {\n activeRange = intersectRanges(activeRange, currentInfo.range);\n }\n activeRange = this.adjustActiveRange(activeRange);\n activeRange = intersectRanges(activeRange, validRange); // might return null\n // it's invalid if the originally requested date is not contained,\n // or if the range is completely outside of the valid range.\n isValid = rangesIntersect(currentInfo.range, validRange);\n // HACK: constrain to render-range so `currentDate` is more useful to view rendering\n if (!rangeContainsMarker(renderRange, currentDate)) {\n currentDate = renderRange.start;\n }\n return {\n currentDate,\n // constraint for where prev/next operations can go and where events can be dragged/resized to.\n // an object with optional start and end properties.\n validRange,\n // range the view is formally responsible for.\n // for example, a month view might have 1st-31st, excluding padded dates\n currentRange: currentInfo.range,\n // name of largest unit being displayed, like \"month\" or \"week\"\n currentRangeUnit: currentInfo.unit,\n isRangeAllDay,\n // dates that display events and accept drag-n-drop\n // will be `null` if no dates accept events\n activeRange,\n // date range with a rendered skeleton\n // includes not-active days that need some sort of DOM\n renderRange,\n // Duration object that denotes the first visible time of any given day\n slotMinTime: props.slotMinTime,\n // Duration object that denotes the exclusive visible end time of any given day\n slotMaxTime: props.slotMaxTime,\n isValid,\n // how far the current date will move for a prev/next operation\n dateIncrement: this.buildDateIncrement(currentInfo.duration),\n // pass a fallback (might be null) ^\n };\n }\n // Builds an object with optional start/end properties.\n // Indicates the minimum/maximum dates to display.\n // not responsible for trimming hidden days.\n buildValidRange() {\n let input = this.props.validRangeInput;\n let simpleInput = typeof input === 'function'\n ? input.call(this.props.calendarApi, this.props.dateEnv.toDate(this.props.nowManager.getDateMarker()))\n : input;\n return this.refineRange(simpleInput) ||\n { start: null, end: null }; // completely open-ended\n }\n // Builds a structure with info about the \"current\" range, the range that is\n // highlighted as being the current month for example.\n // See build() for a description of `direction`.\n // Guaranteed to have `range` and `unit` properties. `duration` is optional.\n buildCurrentRangeInfo(date, direction) {\n let { props } = this;\n let duration = null;\n let unit = null;\n let range = null;\n let dayCount;\n if (props.duration) {\n duration = props.duration;\n unit = props.durationUnit;\n range = this.buildRangeFromDuration(date, direction, duration, unit);\n }\n else if ((dayCount = this.props.dayCount)) {\n unit = 'day';\n range = this.buildRangeFromDayCount(date, direction, dayCount);\n }\n else if ((range = this.buildCustomVisibleRange(date))) {\n unit = props.dateEnv.greatestWholeUnit(range.start, range.end).unit;\n }\n else {\n duration = this.getFallbackDuration();\n unit = greatestDurationDenominator(duration).unit;\n range = this.buildRangeFromDuration(date, direction, duration, unit);\n }\n return { duration, unit, range };\n }\n getFallbackDuration() {\n return createDuration({ day: 1 });\n }\n // Returns a new activeRange to have time values (un-ambiguate)\n // slotMinTime or slotMaxTime causes the range to expand.\n adjustActiveRange(range) {\n let { dateEnv, usesMinMaxTime, slotMinTime, slotMaxTime } = this.props;\n let { start, end } = range;\n if (usesMinMaxTime) {\n // expand active range if slotMinTime is negative (why not when positive?)\n if (asRoughDays(slotMinTime) < 0) {\n start = startOfDay(start); // necessary?\n start = dateEnv.add(start, slotMinTime);\n }\n // expand active range if slotMaxTime is beyond one day (why not when negative?)\n if (asRoughDays(slotMaxTime) > 1) {\n end = startOfDay(end); // necessary?\n end = addDays(end, -1);\n end = dateEnv.add(end, slotMaxTime);\n }\n }\n return { start, end };\n }\n // Builds the \"current\" range when it is specified as an explicit duration.\n // `unit` is the already-computed greatestDurationDenominator unit of duration.\n buildRangeFromDuration(date, direction, duration, unit) {\n let { dateEnv, dateAlignment } = this.props;\n let start;\n let end;\n let res;\n // compute what the alignment should be\n if (!dateAlignment) {\n let { dateIncrement } = this.props;\n if (dateIncrement) {\n // use the smaller of the two units\n if (asRoughMs(dateIncrement) < asRoughMs(duration)) {\n dateAlignment = greatestDurationDenominator(dateIncrement).unit;\n }\n else {\n dateAlignment = unit;\n }\n }\n else {\n dateAlignment = unit;\n }\n }\n // if the view displays a single day or smaller\n if (asRoughDays(duration) <= 1) {\n if (this.isHiddenDay(start)) {\n start = this.skipHiddenDays(start, direction);\n start = startOfDay(start);\n }\n }\n function computeRes() {\n start = dateEnv.startOf(date, dateAlignment);\n end = dateEnv.add(start, duration);\n res = { start, end };\n }\n computeRes();\n // if range is completely enveloped by hidden days, go past the hidden days\n if (!this.trimHiddenDays(res)) {\n date = this.skipHiddenDays(date, direction);\n computeRes();\n }\n return res;\n }\n // Builds the \"current\" range when a dayCount is specified.\n buildRangeFromDayCount(date, direction, dayCount) {\n let { dateEnv, dateAlignment } = this.props;\n let runningCount = 0;\n let start = date;\n let end;\n if (dateAlignment) {\n start = dateEnv.startOf(start, dateAlignment);\n }\n start = startOfDay(start);\n start = this.skipHiddenDays(start, direction);\n end = start;\n do {\n end = addDays(end, 1);\n if (!this.isHiddenDay(end)) {\n runningCount += 1;\n }\n } while (runningCount < dayCount);\n return { start, end };\n }\n // Builds a normalized range object for the \"visible\" range,\n // which is a way to define the currentRange and activeRange at the same time.\n buildCustomVisibleRange(date) {\n let { props } = this;\n let input = props.visibleRangeInput;\n let simpleInput = typeof input === 'function'\n ? input.call(props.calendarApi, props.dateEnv.toDate(date))\n : input;\n let range = this.refineRange(simpleInput);\n if (range && (range.start == null || range.end == null)) {\n return null;\n }\n return range;\n }\n // Computes the range that will represent the element/cells for *rendering*,\n // but which may have voided days/times.\n // not responsible for trimming hidden days.\n buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay) {\n return currentRange;\n }\n // Compute the duration value that should be added/substracted to the current date\n // when a prev/next operation happens.\n buildDateIncrement(fallback) {\n let { dateIncrement } = this.props;\n let customAlignment;\n if (dateIncrement) {\n return dateIncrement;\n }\n if ((customAlignment = this.props.dateAlignment)) {\n return createDuration(1, customAlignment);\n }\n if (fallback) {\n return fallback;\n }\n return createDuration({ days: 1 });\n }\n refineRange(rangeInput) {\n if (rangeInput) {\n let range = parseRange(rangeInput, this.props.dateEnv);\n if (range) {\n range = computeVisibleDayRange(range);\n }\n return range;\n }\n return null;\n }\n /* Hidden Days\n ------------------------------------------------------------------------------------------------------------------*/\n // Initializes internal variables related to calculating hidden days-of-week\n initHiddenDays() {\n let hiddenDays = this.props.hiddenDays || []; // array of day-of-week indices that are hidden\n let isHiddenDayHash = []; // is the day-of-week hidden? (hash with day-of-week-index -> bool)\n let dayCnt = 0;\n let i;\n if (this.props.weekends === false) {\n hiddenDays.push(0, 6); // 0=sunday, 6=saturday\n }\n for (i = 0; i < 7; i += 1) {\n if (!(isHiddenDayHash[i] = hiddenDays.indexOf(i) !== -1)) {\n dayCnt += 1;\n }\n }\n if (!dayCnt) {\n throw new Error('invalid hiddenDays'); // all days were hidden? bad.\n }\n this.isHiddenDayHash = isHiddenDayHash;\n }\n // Remove days from the beginning and end of the range that are computed as hidden.\n // If the whole range is trimmed off, returns null\n trimHiddenDays(range) {\n let { start, end } = range;\n if (start) {\n start = this.skipHiddenDays(start);\n }\n if (end) {\n end = this.skipHiddenDays(end, -1, true);\n }\n if (start == null || end == null || start < end) {\n return { start, end };\n }\n return null;\n }\n // Is the current day hidden?\n // `day` is a day-of-week index (0-6), or a Date (used for UTC)\n isHiddenDay(day) {\n if (day instanceof Date) {\n day = day.getUTCDay();\n }\n return this.isHiddenDayHash[day];\n }\n // Incrementing the current day until it is no longer a hidden day, returning a copy.\n // DOES NOT CONSIDER validRange!\n // If the initial value of `date` is not a hidden day, don't do anything.\n // Pass `isExclusive` as `true` if you are dealing with an end date.\n // `inc` defaults to `1` (increment one day forward each time)\n skipHiddenDays(date, inc = 1, isExclusive = false) {\n while (this.isHiddenDayHash[(date.getUTCDay() + (isExclusive ? inc : 0) + 7) % 7]) {\n date = addDays(date, inc);\n }\n return date;\n }\n}\n\nfunction createEventInstance(defId, range, forcedStartTzo, forcedEndTzo) {\n return {\n instanceId: guid(),\n defId,\n range,\n forcedStartTzo: forcedStartTzo == null ? null : forcedStartTzo,\n forcedEndTzo: forcedEndTzo == null ? null : forcedEndTzo,\n };\n}\n\nfunction parseRecurring(refined, defaultAllDay, dateEnv, recurringTypes) {\n for (let i = 0; i < recurringTypes.length; i += 1) {\n let parsed = recurringTypes[i].parse(refined, dateEnv);\n if (parsed) {\n let { allDay } = refined;\n if (allDay == null) {\n allDay = defaultAllDay;\n if (allDay == null) {\n allDay = parsed.allDayGuess;\n if (allDay == null) {\n allDay = false;\n }\n }\n }\n return {\n allDay,\n duration: parsed.duration,\n typeData: parsed.typeData,\n typeId: i,\n };\n }\n }\n return null;\n}\nfunction expandRecurring(eventStore, framingRange, context) {\n let { dateEnv, pluginHooks, options } = context;\n let { defs, instances } = eventStore;\n // remove existing recurring instances\n // TODO: bad. always expand events as a second step\n instances = filterHash(instances, (instance) => !defs[instance.defId].recurringDef);\n for (let defId in defs) {\n let def = defs[defId];\n if (def.recurringDef) {\n let { duration } = def.recurringDef;\n if (!duration) {\n duration = def.allDay ?\n options.defaultAllDayEventDuration :\n options.defaultTimedEventDuration;\n }\n let starts = expandRecurringRanges(def, duration, framingRange, dateEnv, pluginHooks.recurringTypes);\n for (let start of starts) {\n let instance = createEventInstance(defId, {\n start,\n end: dateEnv.add(start, duration),\n });\n instances[instance.instanceId] = instance;\n }\n }\n }\n return { defs, instances };\n}\n/*\nEvent MUST have a recurringDef\n*/\nfunction expandRecurringRanges(eventDef, duration, framingRange, dateEnv, recurringTypes) {\n let typeDef = recurringTypes[eventDef.recurringDef.typeId];\n let markers = typeDef.expand(eventDef.recurringDef.typeData, {\n start: dateEnv.subtract(framingRange.start, duration),\n end: framingRange.end,\n }, dateEnv);\n // the recurrence plugins don't guarantee that all-day events are start-of-day, so we have to\n if (eventDef.allDay) {\n markers = markers.map(startOfDay);\n }\n return markers;\n}\n\nconst EVENT_NON_DATE_REFINERS = {\n id: String,\n groupId: String,\n title: String,\n url: String,\n interactive: Boolean,\n};\nconst EVENT_DATE_REFINERS = {\n start: identity,\n end: identity,\n date: identity,\n allDay: Boolean,\n};\nconst EVENT_REFINERS = Object.assign(Object.assign(Object.assign({}, EVENT_NON_DATE_REFINERS), EVENT_DATE_REFINERS), { extendedProps: identity });\nfunction parseEvent(raw, eventSource, context, allowOpenRange, refiners = buildEventRefiners(context), defIdMap, instanceIdMap) {\n let { refined, extra } = refineEventDef(raw, context, refiners);\n let defaultAllDay = computeIsDefaultAllDay(eventSource, context);\n let recurringRes = parseRecurring(refined, defaultAllDay, context.dateEnv, context.pluginHooks.recurringTypes);\n if (recurringRes) {\n let def = parseEventDef(refined, extra, eventSource ? eventSource.sourceId : '', recurringRes.allDay, Boolean(recurringRes.duration), context, defIdMap);\n def.recurringDef = {\n typeId: recurringRes.typeId,\n typeData: recurringRes.typeData,\n duration: recurringRes.duration,\n };\n return { def, instance: null };\n }\n let singleRes = parseSingle(refined, defaultAllDay, context, allowOpenRange);\n if (singleRes) {\n let def = parseEventDef(refined, extra, eventSource ? eventSource.sourceId : '', singleRes.allDay, singleRes.hasEnd, context, defIdMap);\n let instance = createEventInstance(def.defId, singleRes.range, singleRes.forcedStartTzo, singleRes.forcedEndTzo);\n if (instanceIdMap && def.publicId && instanceIdMap[def.publicId]) {\n instance.instanceId = instanceIdMap[def.publicId];\n }\n return { def, instance };\n }\n return null;\n}\nfunction refineEventDef(raw, context, refiners = buildEventRefiners(context)) {\n return refineProps(raw, refiners);\n}\nfunction buildEventRefiners(context) {\n return Object.assign(Object.assign(Object.assign({}, EVENT_UI_REFINERS), EVENT_REFINERS), context.pluginHooks.eventRefiners);\n}\n/*\nWill NOT populate extendedProps with the leftover properties.\nWill NOT populate date-related props.\n*/\nfunction parseEventDef(refined, extra, sourceId, allDay, hasEnd, context, defIdMap) {\n let def = {\n title: refined.title || '',\n groupId: refined.groupId || '',\n publicId: refined.id || '',\n url: refined.url || '',\n recurringDef: null,\n defId: ((defIdMap && refined.id) ? defIdMap[refined.id] : '') || guid(),\n sourceId,\n allDay,\n hasEnd,\n interactive: refined.interactive,\n ui: createEventUi(refined, context),\n extendedProps: Object.assign(Object.assign({}, (refined.extendedProps || {})), extra),\n };\n for (let memberAdder of context.pluginHooks.eventDefMemberAdders) {\n Object.assign(def, memberAdder(refined));\n }\n // help out EventImpl from having user modify props\n Object.freeze(def.ui.classNames);\n Object.freeze(def.extendedProps);\n return def;\n}\nfunction parseSingle(refined, defaultAllDay, context, allowOpenRange) {\n let { allDay } = refined;\n let startMeta;\n let startMarker = null;\n let hasEnd = false;\n let endMeta;\n let endMarker = null;\n let startInput = refined.start != null ? refined.start : refined.date;\n startMeta = context.dateEnv.createMarkerMeta(startInput);\n if (startMeta) {\n startMarker = startMeta.marker;\n }\n else if (!allowOpenRange) {\n return null;\n }\n if (refined.end != null) {\n endMeta = context.dateEnv.createMarkerMeta(refined.end);\n }\n if (allDay == null) {\n if (defaultAllDay != null) {\n allDay = defaultAllDay;\n }\n else {\n // fall back to the date props LAST\n allDay = (!startMeta || startMeta.isTimeUnspecified) &&\n (!endMeta || endMeta.isTimeUnspecified);\n }\n }\n if (allDay && startMarker) {\n startMarker = startOfDay(startMarker);\n }\n if (endMeta) {\n endMarker = endMeta.marker;\n if (allDay) {\n endMarker = startOfDay(endMarker);\n }\n if (startMarker && endMarker <= startMarker) {\n endMarker = null;\n }\n }\n if (endMarker) {\n hasEnd = true;\n }\n else if (!allowOpenRange) {\n hasEnd = context.options.forceEventDuration || false;\n endMarker = context.dateEnv.add(startMarker, allDay ?\n context.options.defaultAllDayEventDuration :\n context.options.defaultTimedEventDuration);\n }\n return {\n allDay,\n hasEnd,\n range: { start: startMarker, end: endMarker },\n forcedStartTzo: startMeta ? startMeta.forcedTzo : null,\n forcedEndTzo: endMeta ? endMeta.forcedTzo : null,\n };\n}\nfunction computeIsDefaultAllDay(eventSource, context) {\n let res = null;\n if (eventSource) {\n res = eventSource.defaultAllDay;\n }\n if (res == null) {\n res = context.options.defaultAllDay;\n }\n return res;\n}\n\nfunction parseEvents(rawEvents, eventSource, context, allowOpenRange, defIdMap, instanceIdMap) {\n let eventStore = createEmptyEventStore();\n let eventRefiners = buildEventRefiners(context);\n for (let rawEvent of rawEvents) {\n let tuple = parseEvent(rawEvent, eventSource, context, allowOpenRange, eventRefiners, defIdMap, instanceIdMap);\n if (tuple) {\n eventTupleToStore(tuple, eventStore);\n }\n }\n return eventStore;\n}\nfunction eventTupleToStore(tuple, eventStore = createEmptyEventStore()) {\n eventStore.defs[tuple.def.defId] = tuple.def;\n if (tuple.instance) {\n eventStore.instances[tuple.instance.instanceId] = tuple.instance;\n }\n return eventStore;\n}\n// retrieves events that have the same groupId as the instance specified by `instanceId`\n// or they are the same as the instance.\n// why might instanceId not be in the store? an event from another calendar?\nfunction getRelevantEvents(eventStore, instanceId) {\n let instance = eventStore.instances[instanceId];\n if (instance) {\n let def = eventStore.defs[instance.defId];\n // get events/instances with same group\n let newStore = filterEventStoreDefs(eventStore, (lookDef) => isEventDefsGrouped(def, lookDef));\n // add the original\n // TODO: wish we could use eventTupleToStore or something like it\n newStore.defs[def.defId] = def;\n newStore.instances[instance.instanceId] = instance;\n return newStore;\n }\n return createEmptyEventStore();\n}\nfunction isEventDefsGrouped(def0, def1) {\n return Boolean(def0.groupId && def0.groupId === def1.groupId);\n}\nfunction createEmptyEventStore() {\n return { defs: {}, instances: {} };\n}\nfunction mergeEventStores(store0, store1) {\n return {\n defs: Object.assign(Object.assign({}, store0.defs), store1.defs),\n instances: Object.assign(Object.assign({}, store0.instances), store1.instances),\n };\n}\nfunction filterEventStoreDefs(eventStore, filterFunc) {\n let defs = filterHash(eventStore.defs, filterFunc);\n let instances = filterHash(eventStore.instances, (instance) => (defs[instance.defId] // still exists?\n ));\n return { defs, instances };\n}\nfunction excludeSubEventStore(master, sub) {\n let { defs, instances } = master;\n let filteredDefs = {};\n let filteredInstances = {};\n for (let defId in defs) {\n if (!sub.defs[defId]) { // not explicitly excluded\n filteredDefs[defId] = defs[defId];\n }\n }\n for (let instanceId in instances) {\n if (!sub.instances[instanceId] && // not explicitly excluded\n filteredDefs[instances[instanceId].defId] // def wasn't filtered away\n ) {\n filteredInstances[instanceId] = instances[instanceId];\n }\n }\n return {\n defs: filteredDefs,\n instances: filteredInstances,\n };\n}\n\nfunction normalizeConstraint(input, context) {\n if (Array.isArray(input)) {\n return parseEvents(input, null, context, true); // allowOpenRange=true\n }\n if (typeof input === 'object' && input) { // non-null object\n return parseEvents([input], null, context, true); // allowOpenRange=true\n }\n if (input != null) {\n return String(input);\n }\n return null;\n}\n\nfunction parseClassNames(raw) {\n if (Array.isArray(raw)) {\n return raw;\n }\n if (typeof raw === 'string') {\n return raw.split(/\\s+/);\n }\n return [];\n}\n\n// TODO: better called \"EventSettings\" or \"EventConfig\"\n// TODO: move this file into structs\n// TODO: separate constraint/overlap/allow, because selection uses only that, not other props\nconst EVENT_UI_REFINERS = {\n display: String,\n editable: Boolean,\n startEditable: Boolean,\n durationEditable: Boolean,\n constraint: identity,\n overlap: identity,\n allow: identity,\n className: parseClassNames,\n classNames: parseClassNames,\n color: String,\n backgroundColor: String,\n borderColor: String,\n textColor: String,\n};\nconst EMPTY_EVENT_UI = {\n display: null,\n startEditable: null,\n durationEditable: null,\n constraints: [],\n overlap: null,\n allows: [],\n backgroundColor: '',\n borderColor: '',\n textColor: '',\n classNames: [],\n};\nfunction createEventUi(refined, context) {\n let constraint = normalizeConstraint(refined.constraint, context);\n return {\n display: refined.display || null,\n startEditable: refined.startEditable != null ? refined.startEditable : refined.editable,\n durationEditable: refined.durationEditable != null ? refined.durationEditable : refined.editable,\n constraints: constraint != null ? [constraint] : [],\n overlap: refined.overlap != null ? refined.overlap : null,\n allows: refined.allow != null ? [refined.allow] : [],\n backgroundColor: refined.backgroundColor || refined.color || '',\n borderColor: refined.borderColor || refined.color || '',\n textColor: refined.textColor || '',\n classNames: (refined.className || []).concat(refined.classNames || []), // join singular and plural\n };\n}\n// TODO: prevent against problems with <2 args!\nfunction combineEventUis(uis) {\n return uis.reduce(combineTwoEventUis, EMPTY_EVENT_UI);\n}\nfunction combineTwoEventUis(item0, item1) {\n return {\n display: item1.display != null ? item1.display : item0.display,\n startEditable: item1.startEditable != null ? item1.startEditable : item0.startEditable,\n durationEditable: item1.durationEditable != null ? item1.durationEditable : item0.durationEditable,\n constraints: item0.constraints.concat(item1.constraints),\n overlap: typeof item1.overlap === 'boolean' ? item1.overlap : item0.overlap,\n allows: item0.allows.concat(item1.allows),\n backgroundColor: item1.backgroundColor || item0.backgroundColor,\n borderColor: item1.borderColor || item0.borderColor,\n textColor: item1.textColor || item0.textColor,\n classNames: item0.classNames.concat(item1.classNames),\n };\n}\n\nconst EVENT_SOURCE_REFINERS = {\n id: String,\n defaultAllDay: Boolean,\n url: String,\n format: String,\n events: identity,\n eventDataTransform: identity,\n // for any network-related sources\n success: identity,\n failure: identity,\n};\nfunction parseEventSource(raw, context, refiners = buildEventSourceRefiners(context)) {\n let rawObj;\n if (typeof raw === 'string') {\n rawObj = { url: raw };\n }\n else if (typeof raw === 'function' || Array.isArray(raw)) {\n rawObj = { events: raw };\n }\n else if (typeof raw === 'object' && raw) { // not null\n rawObj = raw;\n }\n if (rawObj) {\n let { refined, extra } = refineProps(rawObj, refiners);\n let metaRes = buildEventSourceMeta(refined, context);\n if (metaRes) {\n return {\n _raw: raw,\n isFetching: false,\n latestFetchId: '',\n fetchRange: null,\n defaultAllDay: refined.defaultAllDay,\n eventDataTransform: refined.eventDataTransform,\n success: refined.success,\n failure: refined.failure,\n publicId: refined.id || '',\n sourceId: guid(),\n sourceDefId: metaRes.sourceDefId,\n meta: metaRes.meta,\n ui: createEventUi(refined, context),\n extendedProps: extra,\n };\n }\n }\n return null;\n}\nfunction buildEventSourceRefiners(context) {\n return Object.assign(Object.assign(Object.assign({}, EVENT_UI_REFINERS), EVENT_SOURCE_REFINERS), context.pluginHooks.eventSourceRefiners);\n}\nfunction buildEventSourceMeta(raw, context) {\n let defs = context.pluginHooks.eventSourceDefs;\n for (let i = defs.length - 1; i >= 0; i -= 1) { // later-added plugins take precedence\n let def = defs[i];\n let meta = def.parseMeta(raw);\n if (meta) {\n return { sourceDefId: i, meta };\n }\n }\n return null;\n}\n\nfunction reduceEventStore(eventStore, action, eventSources, dateProfile, context) {\n switch (action.type) {\n case 'RECEIVE_EVENTS': // raw\n return receiveRawEvents(eventStore, eventSources[action.sourceId], action.fetchId, action.fetchRange, action.rawEvents, context);\n case 'RESET_RAW_EVENTS':\n return resetRawEvents(eventStore, eventSources[action.sourceId], action.rawEvents, dateProfile.activeRange, context);\n case 'ADD_EVENTS': // already parsed, but not expanded\n return addEvent(eventStore, action.eventStore, // new ones\n dateProfile ? dateProfile.activeRange : null, context);\n case 'RESET_EVENTS':\n return action.eventStore;\n case 'MERGE_EVENTS': // already parsed and expanded\n return mergeEventStores(eventStore, action.eventStore);\n case 'PREV': // TODO: how do we track all actions that affect dateProfile :(\n case 'NEXT':\n case 'CHANGE_DATE':\n case 'CHANGE_VIEW_TYPE':\n if (dateProfile) {\n return expandRecurring(eventStore, dateProfile.activeRange, context);\n }\n return eventStore;\n case 'REMOVE_EVENTS':\n return excludeSubEventStore(eventStore, action.eventStore);\n case 'REMOVE_EVENT_SOURCE':\n return excludeEventsBySourceId(eventStore, action.sourceId);\n case 'REMOVE_ALL_EVENT_SOURCES':\n return filterEventStoreDefs(eventStore, (eventDef) => (!eventDef.sourceId // only keep events with no source id\n ));\n case 'REMOVE_ALL_EVENTS':\n return createEmptyEventStore();\n default:\n return eventStore;\n }\n}\nfunction receiveRawEvents(eventStore, eventSource, fetchId, fetchRange, rawEvents, context) {\n if (eventSource && // not already removed\n fetchId === eventSource.latestFetchId // TODO: wish this logic was always in event-sources\n ) {\n let subset = parseEvents(transformRawEvents(rawEvents, eventSource, context), eventSource, context);\n if (fetchRange) {\n subset = expandRecurring(subset, fetchRange, context);\n }\n return mergeEventStores(excludeEventsBySourceId(eventStore, eventSource.sourceId), subset);\n }\n return eventStore;\n}\nfunction resetRawEvents(existingEventStore, eventSource, rawEvents, activeRange, context) {\n const { defIdMap, instanceIdMap } = buildPublicIdMaps(existingEventStore);\n let newEventStore = parseEvents(transformRawEvents(rawEvents, eventSource, context), eventSource, context, false, defIdMap, instanceIdMap);\n return expandRecurring(newEventStore, activeRange, context);\n}\nfunction transformRawEvents(rawEvents, eventSource, context) {\n let calEachTransform = context.options.eventDataTransform;\n let sourceEachTransform = eventSource ? eventSource.eventDataTransform : null;\n if (sourceEachTransform) {\n rawEvents = transformEachRawEvent(rawEvents, sourceEachTransform);\n }\n if (calEachTransform) {\n rawEvents = transformEachRawEvent(rawEvents, calEachTransform);\n }\n return rawEvents;\n}\nfunction transformEachRawEvent(rawEvents, func) {\n let refinedEvents;\n if (!func) {\n refinedEvents = rawEvents;\n }\n else {\n refinedEvents = [];\n for (let rawEvent of rawEvents) {\n let refinedEvent = func(rawEvent);\n if (refinedEvent) {\n refinedEvents.push(refinedEvent);\n }\n else if (refinedEvent == null) {\n refinedEvents.push(rawEvent);\n } // if a different falsy value, do nothing\n }\n }\n return refinedEvents;\n}\nfunction addEvent(eventStore, subset, expandRange, context) {\n if (expandRange) {\n subset = expandRecurring(subset, expandRange, context);\n }\n return mergeEventStores(eventStore, subset);\n}\nfunction rezoneEventStoreDates(eventStore, oldDateEnv, newDateEnv) {\n let { defs } = eventStore;\n let instances = mapHash(eventStore.instances, (instance) => {\n let def = defs[instance.defId];\n if (def.allDay) {\n return instance; // isn't dependent on timezone\n }\n return Object.assign(Object.assign({}, instance), { range: {\n start: newDateEnv.createMarker(oldDateEnv.toDate(instance.range.start, instance.forcedStartTzo)),\n end: newDateEnv.createMarker(oldDateEnv.toDate(instance.range.end, instance.forcedEndTzo)),\n }, forcedStartTzo: newDateEnv.canComputeOffset ? null : instance.forcedStartTzo, forcedEndTzo: newDateEnv.canComputeOffset ? null : instance.forcedEndTzo });\n });\n return { defs, instances };\n}\nfunction excludeEventsBySourceId(eventStore, sourceId) {\n return filterEventStoreDefs(eventStore, (eventDef) => eventDef.sourceId !== sourceId);\n}\n// QUESTION: why not just return instances? do a general object-property-exclusion util\nfunction excludeInstances(eventStore, removals) {\n return {\n defs: eventStore.defs,\n instances: filterHash(eventStore.instances, (instance) => !removals[instance.instanceId]),\n };\n}\nfunction buildPublicIdMaps(eventStore) {\n const { defs, instances } = eventStore;\n const defIdMap = {};\n const instanceIdMap = {};\n for (let defId in defs) {\n const def = defs[defId];\n const { publicId } = def;\n if (publicId) {\n defIdMap[publicId] = defId;\n }\n }\n for (let instanceId in instances) {\n const instance = instances[instanceId];\n const def = defs[instance.defId];\n const { publicId } = def;\n if (publicId) {\n instanceIdMap[publicId] = instanceId;\n }\n }\n return { defIdMap, instanceIdMap };\n}\n\nclass Emitter {\n constructor() {\n this.handlers = {};\n this.thisContext = null;\n }\n setThisContext(thisContext) {\n this.thisContext = thisContext;\n }\n setOptions(options) {\n this.options = options;\n }\n on(type, handler) {\n addToHash(this.handlers, type, handler);\n }\n off(type, handler) {\n removeFromHash(this.handlers, type, handler);\n }\n trigger(type, ...args) {\n let attachedHandlers = this.handlers[type] || [];\n let optionHandler = this.options && this.options[type];\n let handlers = [].concat(optionHandler || [], attachedHandlers);\n for (let handler of handlers) {\n handler.apply(this.thisContext, args);\n }\n }\n hasHandlers(type) {\n return Boolean((this.handlers[type] && this.handlers[type].length) ||\n (this.options && this.options[type]));\n }\n}\nfunction addToHash(hash, type, handler) {\n (hash[type] || (hash[type] = []))\n .push(handler);\n}\nfunction removeFromHash(hash, type, handler) {\n if (handler) {\n if (hash[type]) {\n hash[type] = hash[type].filter((func) => func !== handler);\n }\n }\n else {\n delete hash[type]; // remove all handler funcs for this type\n }\n}\n\nconst DEF_DEFAULTS = {\n startTime: '09:00',\n endTime: '17:00',\n daysOfWeek: [1, 2, 3, 4, 5],\n display: 'inverse-background',\n classNames: 'fc-non-business',\n groupId: '_businessHours', // so multiple defs get grouped\n};\n/*\nTODO: pass around as EventDefHash!!!\n*/\nfunction parseBusinessHours(input, context) {\n return parseEvents(refineInputs(input), null, context);\n}\nfunction refineInputs(input) {\n let rawDefs;\n if (input === true) {\n rawDefs = [{}]; // will get DEF_DEFAULTS verbatim\n }\n else if (Array.isArray(input)) {\n // if specifying an array, every sub-definition NEEDS a day-of-week\n rawDefs = input.filter((rawDef) => rawDef.daysOfWeek);\n }\n else if (typeof input === 'object' && input) { // non-null object\n rawDefs = [input];\n }\n else { // is probably false\n rawDefs = [];\n }\n rawDefs = rawDefs.map((rawDef) => (Object.assign(Object.assign({}, DEF_DEFAULTS), rawDef)));\n return rawDefs;\n}\n\nfunction triggerDateSelect(selection, pev, context) {\n context.emitter.trigger('select', Object.assign(Object.assign({}, buildDateSpanApiWithContext(selection, context)), { jsEvent: pev ? pev.origEvent : null, view: context.viewApi || context.calendarApi.view }));\n}\nfunction triggerDateUnselect(pev, context) {\n context.emitter.trigger('unselect', {\n jsEvent: pev ? pev.origEvent : null,\n view: context.viewApi || context.calendarApi.view,\n });\n}\nfunction buildDateSpanApiWithContext(dateSpan, context) {\n let props = {};\n for (let transform of context.pluginHooks.dateSpanTransforms) {\n Object.assign(props, transform(dateSpan, context));\n }\n Object.assign(props, buildDateSpanApi(dateSpan, context.dateEnv));\n return props;\n}\n// Given an event's allDay status and start date, return what its fallback end date should be.\n// TODO: rename to computeDefaultEventEnd\nfunction getDefaultEventEnd(allDay, marker, context) {\n let { dateEnv, options } = context;\n let end = marker;\n if (allDay) {\n end = startOfDay(end);\n end = dateEnv.add(end, options.defaultAllDayEventDuration);\n }\n else {\n end = dateEnv.add(end, options.defaultTimedEventDuration);\n }\n return end;\n}\n\n// applies the mutation to ALL defs/instances within the event store\nfunction applyMutationToEventStore(eventStore, eventConfigBase, mutation, context) {\n let eventConfigs = compileEventUis(eventStore.defs, eventConfigBase);\n let dest = createEmptyEventStore();\n for (let defId in eventStore.defs) {\n let def = eventStore.defs[defId];\n dest.defs[defId] = applyMutationToEventDef(def, eventConfigs[defId], mutation, context);\n }\n for (let instanceId in eventStore.instances) {\n let instance = eventStore.instances[instanceId];\n let def = dest.defs[instance.defId]; // important to grab the newly modified def\n dest.instances[instanceId] = applyMutationToEventInstance(instance, def, eventConfigs[instance.defId], mutation, context);\n }\n return dest;\n}\nfunction applyMutationToEventDef(eventDef, eventConfig, mutation, context) {\n let standardProps = mutation.standardProps || {};\n // if hasEnd has not been specified, guess a good value based on deltas.\n // if duration will change, there's no way the default duration will persist,\n // and thus, we need to mark the event as having a real end\n if (standardProps.hasEnd == null &&\n eventConfig.durationEditable &&\n (mutation.startDelta || mutation.endDelta)) {\n standardProps.hasEnd = true; // TODO: is this mutation okay?\n }\n let copy = Object.assign(Object.assign(Object.assign({}, eventDef), standardProps), { ui: Object.assign(Object.assign({}, eventDef.ui), standardProps.ui) });\n if (mutation.extendedProps) {\n copy.extendedProps = Object.assign(Object.assign({}, copy.extendedProps), mutation.extendedProps);\n }\n for (let applier of context.pluginHooks.eventDefMutationAppliers) {\n applier(copy, mutation, context);\n }\n if (!copy.hasEnd && context.options.forceEventDuration) {\n copy.hasEnd = true;\n }\n return copy;\n}\nfunction applyMutationToEventInstance(eventInstance, eventDef, // must first be modified by applyMutationToEventDef\neventConfig, mutation, context) {\n let { dateEnv } = context;\n let forceAllDay = mutation.standardProps && mutation.standardProps.allDay === true;\n let clearEnd = mutation.standardProps && mutation.standardProps.hasEnd === false;\n let copy = Object.assign({}, eventInstance);\n if (forceAllDay) {\n copy.range = computeAlignedDayRange(copy.range);\n }\n if (mutation.datesDelta && eventConfig.startEditable) {\n copy.range = {\n start: dateEnv.add(copy.range.start, mutation.datesDelta),\n end: dateEnv.add(copy.range.end, mutation.datesDelta),\n };\n }\n if (mutation.startDelta && eventConfig.durationEditable) {\n copy.range = {\n start: dateEnv.add(copy.range.start, mutation.startDelta),\n end: copy.range.end,\n };\n }\n if (mutation.endDelta && eventConfig.durationEditable) {\n copy.range = {\n start: copy.range.start,\n end: dateEnv.add(copy.range.end, mutation.endDelta),\n };\n }\n if (clearEnd) {\n copy.range = {\n start: copy.range.start,\n end: getDefaultEventEnd(eventDef.allDay, copy.range.start, context),\n };\n }\n // in case event was all-day but the supplied deltas were not\n // better util for this?\n if (eventDef.allDay) {\n copy.range = {\n start: startOfDay(copy.range.start),\n end: startOfDay(copy.range.end),\n };\n }\n // handle invalid durations\n if (copy.range.end < copy.range.start) {\n copy.range.end = getDefaultEventEnd(eventDef.allDay, copy.range.start, context);\n }\n return copy;\n}\n\nclass EventSourceImpl {\n constructor(context, internalEventSource) {\n this.context = context;\n this.internalEventSource = internalEventSource;\n }\n remove() {\n this.context.dispatch({\n type: 'REMOVE_EVENT_SOURCE',\n sourceId: this.internalEventSource.sourceId,\n });\n }\n refetch() {\n this.context.dispatch({\n type: 'FETCH_EVENT_SOURCES',\n sourceIds: [this.internalEventSource.sourceId],\n isRefetch: true,\n });\n }\n get id() {\n return this.internalEventSource.publicId;\n }\n get url() {\n return this.internalEventSource.meta.url;\n }\n get format() {\n return this.internalEventSource.meta.format; // TODO: bad. not guaranteed\n }\n}\n\nclass EventImpl {\n // instance will be null if expressing a recurring event that has no current instances,\n // OR if trying to validate an incoming external event that has no dates assigned\n constructor(context, def, instance) {\n this._context = context;\n this._def = def;\n this._instance = instance || null;\n }\n /*\n TODO: make event struct more responsible for this\n */\n setProp(name, val) {\n if (name in EVENT_DATE_REFINERS) {\n console.warn('Could not set date-related prop \\'name\\'. Use one of the date-related methods instead.');\n // TODO: make proper aliasing system?\n }\n else if (name === 'id') {\n val = EVENT_NON_DATE_REFINERS[name](val);\n this.mutate({\n standardProps: { publicId: val }, // hardcoded internal name\n });\n }\n else if (name in EVENT_NON_DATE_REFINERS) {\n val = EVENT_NON_DATE_REFINERS[name](val);\n this.mutate({\n standardProps: { [name]: val },\n });\n }\n else if (name in EVENT_UI_REFINERS) {\n let ui = EVENT_UI_REFINERS[name](val);\n if (name === 'color') {\n ui = { backgroundColor: val, borderColor: val };\n }\n else if (name === 'editable') {\n ui = { startEditable: val, durationEditable: val };\n }\n else {\n ui = { [name]: val };\n }\n this.mutate({\n standardProps: { ui },\n });\n }\n else {\n console.warn(`Could not set prop '${name}'. Use setExtendedProp instead.`);\n }\n }\n setExtendedProp(name, val) {\n this.mutate({\n extendedProps: { [name]: val },\n });\n }\n setStart(startInput, options = {}) {\n let { dateEnv } = this._context;\n let start = dateEnv.createMarker(startInput);\n if (start && this._instance) { // TODO: warning if parsed bad\n let instanceRange = this._instance.range;\n let startDelta = diffDates(instanceRange.start, start, dateEnv, options.granularity); // what if parsed bad!?\n if (options.maintainDuration) {\n this.mutate({ datesDelta: startDelta });\n }\n else {\n this.mutate({ startDelta });\n }\n }\n }\n setEnd(endInput, options = {}) {\n let { dateEnv } = this._context;\n let end;\n if (endInput != null) {\n end = dateEnv.createMarker(endInput);\n if (!end) {\n return; // TODO: warning if parsed bad\n }\n }\n if (this._instance) {\n if (end) {\n let endDelta = diffDates(this._instance.range.end, end, dateEnv, options.granularity);\n this.mutate({ endDelta });\n }\n else {\n this.mutate({ standardProps: { hasEnd: false } });\n }\n }\n }\n setDates(startInput, endInput, options = {}) {\n let { dateEnv } = this._context;\n let standardProps = { allDay: options.allDay };\n let start = dateEnv.createMarker(startInput);\n let end;\n if (!start) {\n return; // TODO: warning if parsed bad\n }\n if (endInput != null) {\n end = dateEnv.createMarker(endInput);\n if (!end) { // TODO: warning if parsed bad\n return;\n }\n }\n if (this._instance) {\n let instanceRange = this._instance.range;\n // when computing the diff for an event being converted to all-day,\n // compute diff off of the all-day values the way event-mutation does.\n if (options.allDay === true) {\n instanceRange = computeAlignedDayRange(instanceRange);\n }\n let startDelta = diffDates(instanceRange.start, start, dateEnv, options.granularity);\n if (end) {\n let endDelta = diffDates(instanceRange.end, end, dateEnv, options.granularity);\n if (durationsEqual(startDelta, endDelta)) {\n this.mutate({ datesDelta: startDelta, standardProps });\n }\n else {\n this.mutate({ startDelta, endDelta, standardProps });\n }\n }\n else { // means \"clear the end\"\n standardProps.hasEnd = false;\n this.mutate({ datesDelta: startDelta, standardProps });\n }\n }\n }\n moveStart(deltaInput) {\n let delta = createDuration(deltaInput);\n if (delta) { // TODO: warning if parsed bad\n this.mutate({ startDelta: delta });\n }\n }\n moveEnd(deltaInput) {\n let delta = createDuration(deltaInput);\n if (delta) { // TODO: warning if parsed bad\n this.mutate({ endDelta: delta });\n }\n }\n moveDates(deltaInput) {\n let delta = createDuration(deltaInput);\n if (delta) { // TODO: warning if parsed bad\n this.mutate({ datesDelta: delta });\n }\n }\n setAllDay(allDay, options = {}) {\n let standardProps = { allDay };\n let { maintainDuration } = options;\n if (maintainDuration == null) {\n maintainDuration = this._context.options.allDayMaintainDuration;\n }\n if (this._def.allDay !== allDay) {\n standardProps.hasEnd = maintainDuration;\n }\n this.mutate({ standardProps });\n }\n formatRange(formatInput) {\n let { dateEnv } = this._context;\n let instance = this._instance;\n let formatter = createFormatter(formatInput);\n if (this._def.hasEnd) {\n return dateEnv.formatRange(instance.range.start, instance.range.end, formatter, {\n forcedStartTzo: instance.forcedStartTzo,\n forcedEndTzo: instance.forcedEndTzo,\n });\n }\n return dateEnv.format(instance.range.start, formatter, {\n forcedTzo: instance.forcedStartTzo,\n });\n }\n mutate(mutation) {\n let instance = this._instance;\n if (instance) {\n let def = this._def;\n let context = this._context;\n let { eventStore } = context.getCurrentData();\n let relevantEvents = getRelevantEvents(eventStore, instance.instanceId);\n let eventConfigBase = {\n '': {\n display: '',\n startEditable: true,\n durationEditable: true,\n constraints: [],\n overlap: null,\n allows: [],\n backgroundColor: '',\n borderColor: '',\n textColor: '',\n classNames: [],\n },\n };\n relevantEvents = applyMutationToEventStore(relevantEvents, eventConfigBase, mutation, context);\n let oldEvent = new EventImpl(context, def, instance); // snapshot\n this._def = relevantEvents.defs[def.defId];\n this._instance = relevantEvents.instances[instance.instanceId];\n context.dispatch({\n type: 'MERGE_EVENTS',\n eventStore: relevantEvents,\n });\n context.emitter.trigger('eventChange', {\n oldEvent,\n event: this,\n relatedEvents: buildEventApis(relevantEvents, context, instance),\n revert() {\n context.dispatch({\n type: 'RESET_EVENTS',\n eventStore, // the ORIGINAL store\n });\n },\n });\n }\n }\n remove() {\n let context = this._context;\n let asStore = eventApiToStore(this);\n context.dispatch({\n type: 'REMOVE_EVENTS',\n eventStore: asStore,\n });\n context.emitter.trigger('eventRemove', {\n event: this,\n relatedEvents: [],\n revert() {\n context.dispatch({\n type: 'MERGE_EVENTS',\n eventStore: asStore,\n });\n },\n });\n }\n get source() {\n let { sourceId } = this._def;\n if (sourceId) {\n return new EventSourceImpl(this._context, this._context.getCurrentData().eventSources[sourceId]);\n }\n return null;\n }\n get start() {\n return this._instance ?\n this._context.dateEnv.toDate(this._instance.range.start) :\n null;\n }\n get end() {\n return (this._instance && this._def.hasEnd) ?\n this._context.dateEnv.toDate(this._instance.range.end) :\n null;\n }\n get startStr() {\n let instance = this._instance;\n if (instance) {\n return this._context.dateEnv.formatIso(instance.range.start, {\n omitTime: this._def.allDay,\n forcedTzo: instance.forcedStartTzo,\n });\n }\n return '';\n }\n get endStr() {\n let instance = this._instance;\n if (instance && this._def.hasEnd) {\n return this._context.dateEnv.formatIso(instance.range.end, {\n omitTime: this._def.allDay,\n forcedTzo: instance.forcedEndTzo,\n });\n }\n return '';\n }\n // computable props that all access the def\n // TODO: find a TypeScript-compatible way to do this at scale\n get id() { return this._def.publicId; }\n get groupId() { return this._def.groupId; }\n get allDay() { return this._def.allDay; }\n get title() { return this._def.title; }\n get url() { return this._def.url; }\n get display() { return this._def.ui.display || 'auto'; } // bad. just normalize the type earlier\n get startEditable() { return this._def.ui.startEditable; }\n get durationEditable() { return this._def.ui.durationEditable; }\n get constraint() { return this._def.ui.constraints[0] || null; }\n get overlap() { return this._def.ui.overlap; }\n get allow() { return this._def.ui.allows[0] || null; }\n get backgroundColor() { return this._def.ui.backgroundColor; }\n get borderColor() { return this._def.ui.borderColor; }\n get textColor() { return this._def.ui.textColor; }\n // NOTE: user can't modify these because Object.freeze was called in event-def parsing\n get classNames() { return this._def.ui.classNames; }\n get extendedProps() { return this._def.extendedProps; }\n toPlainObject(settings = {}) {\n let def = this._def;\n let { ui } = def;\n let { startStr, endStr } = this;\n let res = {\n allDay: def.allDay,\n };\n if (def.title) {\n res.title = def.title;\n }\n if (startStr) {\n res.start = startStr;\n }\n if (endStr) {\n res.end = endStr;\n }\n if (def.publicId) {\n res.id = def.publicId;\n }\n if (def.groupId) {\n res.groupId = def.groupId;\n }\n if (def.url) {\n res.url = def.url;\n }\n if (ui.display && ui.display !== 'auto') {\n res.display = ui.display;\n }\n // TODO: what about recurring-event properties???\n // TODO: include startEditable/durationEditable/constraint/overlap/allow\n if (settings.collapseColor && ui.backgroundColor && ui.backgroundColor === ui.borderColor) {\n res.color = ui.backgroundColor;\n }\n else {\n if (ui.backgroundColor) {\n res.backgroundColor = ui.backgroundColor;\n }\n if (ui.borderColor) {\n res.borderColor = ui.borderColor;\n }\n }\n if (ui.textColor) {\n res.textColor = ui.textColor;\n }\n if (ui.classNames.length) {\n res.classNames = ui.classNames;\n }\n if (Object.keys(def.extendedProps).length) {\n if (settings.collapseExtendedProps) {\n Object.assign(res, def.extendedProps);\n }\n else {\n res.extendedProps = def.extendedProps;\n }\n }\n return res;\n }\n toJSON() {\n return this.toPlainObject();\n }\n}\nfunction eventApiToStore(eventApi) {\n let def = eventApi._def;\n let instance = eventApi._instance;\n return {\n defs: { [def.defId]: def },\n instances: instance\n ? { [instance.instanceId]: instance }\n : {},\n };\n}\nfunction buildEventApis(eventStore, context, excludeInstance) {\n let { defs, instances } = eventStore;\n let eventApis = [];\n let excludeInstanceId = excludeInstance ? excludeInstance.instanceId : '';\n for (let id in instances) {\n let instance = instances[id];\n let def = defs[instance.defId];\n if (instance.instanceId !== excludeInstanceId) {\n eventApis.push(new EventImpl(context, def, instance));\n }\n }\n return eventApis;\n}\n\n/*\nSpecifying nextDayThreshold signals that all-day ranges should be sliced.\n*/\nfunction sliceEventStore(eventStore, eventUiBases, framingRange, nextDayThreshold) {\n let inverseBgByGroupId = {};\n let inverseBgByDefId = {};\n let defByGroupId = {};\n let bgRanges = [];\n let fgRanges = [];\n let eventUis = compileEventUis(eventStore.defs, eventUiBases);\n for (let defId in eventStore.defs) {\n let def = eventStore.defs[defId];\n let ui = eventUis[def.defId];\n if (ui.display === 'inverse-background') {\n if (def.groupId) {\n inverseBgByGroupId[def.groupId] = [];\n if (!defByGroupId[def.groupId]) {\n defByGroupId[def.groupId] = def;\n }\n }\n else {\n inverseBgByDefId[defId] = [];\n }\n }\n }\n for (let instanceId in eventStore.instances) {\n let instance = eventStore.instances[instanceId];\n let def = eventStore.defs[instance.defId];\n let ui = eventUis[def.defId];\n let origRange = instance.range;\n let normalRange = (!def.allDay && nextDayThreshold) ?\n computeVisibleDayRange(origRange, nextDayThreshold) :\n origRange;\n let slicedRange = intersectRanges(normalRange, framingRange);\n if (slicedRange) {\n if (ui.display === 'inverse-background') {\n if (def.groupId) {\n inverseBgByGroupId[def.groupId].push(slicedRange);\n }\n else {\n inverseBgByDefId[instance.defId].push(slicedRange);\n }\n }\n else if (ui.display !== 'none') {\n (ui.display === 'background' ? bgRanges : fgRanges).push({\n def,\n ui,\n instance,\n range: slicedRange,\n isStart: normalRange.start && normalRange.start.valueOf() === slicedRange.start.valueOf(),\n isEnd: normalRange.end && normalRange.end.valueOf() === slicedRange.end.valueOf(),\n });\n }\n }\n }\n for (let groupId in inverseBgByGroupId) { // BY GROUP\n let ranges = inverseBgByGroupId[groupId];\n let invertedRanges = invertRanges(ranges, framingRange);\n for (let invertedRange of invertedRanges) {\n let def = defByGroupId[groupId];\n let ui = eventUis[def.defId];\n bgRanges.push({\n def,\n ui,\n instance: null,\n range: invertedRange,\n isStart: false,\n isEnd: false,\n });\n }\n }\n for (let defId in inverseBgByDefId) {\n let ranges = inverseBgByDefId[defId];\n let invertedRanges = invertRanges(ranges, framingRange);\n for (let invertedRange of invertedRanges) {\n bgRanges.push({\n def: eventStore.defs[defId],\n ui: eventUis[defId],\n instance: null,\n range: invertedRange,\n isStart: false,\n isEnd: false,\n });\n }\n }\n return { bg: bgRanges, fg: fgRanges };\n}\nfunction hasBgRendering(def) {\n return def.ui.display === 'background' || def.ui.display === 'inverse-background';\n}\nfunction setElSeg(el, seg) {\n el.fcSeg = seg;\n}\nfunction getElSeg(el) {\n return el.fcSeg ||\n el.parentNode.fcSeg || // for the harness\n null;\n}\n// event ui computation\nfunction compileEventUis(eventDefs, eventUiBases) {\n return mapHash(eventDefs, (eventDef) => compileEventUi(eventDef, eventUiBases));\n}\nfunction compileEventUi(eventDef, eventUiBases) {\n let uis = [];\n if (eventUiBases['']) {\n uis.push(eventUiBases['']);\n }\n if (eventUiBases[eventDef.defId]) {\n uis.push(eventUiBases[eventDef.defId]);\n }\n uis.push(eventDef.ui);\n return combineEventUis(uis);\n}\nfunction sortEventSegs(segs, eventOrderSpecs) {\n let objs = segs.map(buildSegCompareObj);\n objs.sort((obj0, obj1) => compareByFieldSpecs(obj0, obj1, eventOrderSpecs));\n return objs.map((c) => c._seg);\n}\n// returns a object with all primitive props that can be compared\nfunction buildSegCompareObj(seg) {\n let { eventRange } = seg;\n let eventDef = eventRange.def;\n let range = eventRange.instance ? eventRange.instance.range : eventRange.range;\n let start = range.start ? range.start.valueOf() : 0; // TODO: better support for open-range events\n let end = range.end ? range.end.valueOf() : 0; // \"\n return Object.assign(Object.assign(Object.assign({}, eventDef.extendedProps), eventDef), { id: eventDef.publicId, start,\n end, duration: end - start, allDay: Number(eventDef.allDay), _seg: seg });\n}\nfunction computeSegDraggable(seg, context) {\n let { pluginHooks } = context;\n let transformers = pluginHooks.isDraggableTransformers;\n let { def, ui } = seg.eventRange;\n let val = ui.startEditable;\n for (let transformer of transformers) {\n val = transformer(val, def, ui, context);\n }\n return val;\n}\nfunction computeSegStartResizable(seg, context) {\n return seg.isStart && seg.eventRange.ui.durationEditable && context.options.eventResizableFromStart;\n}\nfunction computeSegEndResizable(seg, context) {\n return seg.isEnd && seg.eventRange.ui.durationEditable;\n}\nfunction buildSegTimeText(seg, timeFormat, context, defaultDisplayEventTime, // defaults to true\ndefaultDisplayEventEnd, // defaults to true\nstartOverride, endOverride) {\n let { dateEnv, options } = context;\n let { displayEventTime, displayEventEnd } = options;\n let eventDef = seg.eventRange.def;\n let eventInstance = seg.eventRange.instance;\n if (displayEventTime == null) {\n displayEventTime = defaultDisplayEventTime !== false;\n }\n if (displayEventEnd == null) {\n displayEventEnd = defaultDisplayEventEnd !== false;\n }\n let wholeEventStart = eventInstance.range.start;\n let wholeEventEnd = eventInstance.range.end;\n let segStart = startOverride || seg.start || seg.eventRange.range.start;\n let segEnd = endOverride || seg.end || seg.eventRange.range.end;\n let isStartDay = startOfDay(wholeEventStart).valueOf() === startOfDay(segStart).valueOf();\n let isEndDay = startOfDay(addMs(wholeEventEnd, -1)).valueOf() === startOfDay(addMs(segEnd, -1)).valueOf();\n if (displayEventTime && !eventDef.allDay && (isStartDay || isEndDay)) {\n segStart = isStartDay ? wholeEventStart : segStart;\n segEnd = isEndDay ? wholeEventEnd : segEnd;\n if (displayEventEnd && eventDef.hasEnd) {\n return dateEnv.formatRange(segStart, segEnd, timeFormat, {\n forcedStartTzo: startOverride ? null : eventInstance.forcedStartTzo,\n forcedEndTzo: endOverride ? null : eventInstance.forcedEndTzo,\n });\n }\n return dateEnv.format(segStart, timeFormat, {\n forcedTzo: startOverride ? null : eventInstance.forcedStartTzo, // nooooo, same\n });\n }\n return '';\n}\nfunction getSegMeta(seg, todayRange, nowDate) {\n let segRange = seg.eventRange.range;\n return {\n isPast: segRange.end <= (nowDate || todayRange.start),\n isFuture: segRange.start >= (nowDate || todayRange.end),\n isToday: todayRange && rangeContainsMarker(todayRange, segRange.start),\n };\n}\nfunction getEventClassNames(props) {\n let classNames = ['fc-event'];\n if (props.isMirror) {\n classNames.push('fc-event-mirror');\n }\n if (props.isDraggable) {\n classNames.push('fc-event-draggable');\n }\n if (props.isStartResizable || props.isEndResizable) {\n classNames.push('fc-event-resizable');\n }\n if (props.isDragging) {\n classNames.push('fc-event-dragging');\n }\n if (props.isResizing) {\n classNames.push('fc-event-resizing');\n }\n if (props.isSelected) {\n classNames.push('fc-event-selected');\n }\n if (props.isStart) {\n classNames.push('fc-event-start');\n }\n if (props.isEnd) {\n classNames.push('fc-event-end');\n }\n if (props.isPast) {\n classNames.push('fc-event-past');\n }\n if (props.isToday) {\n classNames.push('fc-event-today');\n }\n if (props.isFuture) {\n classNames.push('fc-event-future');\n }\n return classNames;\n}\nfunction buildEventRangeKey(eventRange) {\n return eventRange.instance\n ? eventRange.instance.instanceId\n : `${eventRange.def.defId}:${eventRange.range.start.toISOString()}`;\n // inverse-background events don't have specific instances. TODO: better solution\n}\nfunction getSegAnchorAttrs(seg, context) {\n let { def, instance } = seg.eventRange;\n let { url } = def;\n if (url) {\n return { href: url };\n }\n let { emitter, options } = context;\n let { eventInteractive } = options;\n if (eventInteractive == null) {\n eventInteractive = def.interactive;\n if (eventInteractive == null) {\n eventInteractive = Boolean(emitter.hasHandlers('eventClick'));\n }\n }\n // mock what happens in EventClicking\n if (eventInteractive) {\n // only attach keyboard-related handlers because click handler is already done in EventClicking\n return createAriaKeyboardAttrs((ev) => {\n emitter.trigger('eventClick', {\n el: ev.target,\n event: new EventImpl(context, def, instance),\n jsEvent: ev,\n view: context.viewApi,\n });\n });\n }\n return {};\n}\n\nconst STANDARD_PROPS = {\n start: identity,\n end: identity,\n allDay: Boolean,\n};\nfunction parseDateSpan(raw, dateEnv, defaultDuration) {\n let span = parseOpenDateSpan(raw, dateEnv);\n let { range } = span;\n if (!range.start) {\n return null;\n }\n if (!range.end) {\n if (defaultDuration == null) {\n return null;\n }\n range.end = dateEnv.add(range.start, defaultDuration);\n }\n return span;\n}\n/*\nTODO: somehow combine with parseRange?\nWill return null if the start/end props were present but parsed invalidly.\n*/\nfunction parseOpenDateSpan(raw, dateEnv) {\n let { refined: standardProps, extra } = refineProps(raw, STANDARD_PROPS);\n let startMeta = standardProps.start ? dateEnv.createMarkerMeta(standardProps.start) : null;\n let endMeta = standardProps.end ? dateEnv.createMarkerMeta(standardProps.end) : null;\n let { allDay } = standardProps;\n if (allDay == null) {\n allDay = (startMeta && startMeta.isTimeUnspecified) &&\n (!endMeta || endMeta.isTimeUnspecified);\n }\n return Object.assign({ range: {\n start: startMeta ? startMeta.marker : null,\n end: endMeta ? endMeta.marker : null,\n }, allDay }, extra);\n}\nfunction isDateSpansEqual(span0, span1) {\n return rangesEqual(span0.range, span1.range) &&\n span0.allDay === span1.allDay &&\n isSpanPropsEqual(span0, span1);\n}\n// the NON-DATE-RELATED props\nfunction isSpanPropsEqual(span0, span1) {\n for (let propName in span1) {\n if (propName !== 'range' && propName !== 'allDay') {\n if (span0[propName] !== span1[propName]) {\n return false;\n }\n }\n }\n // are there any props that span0 has that span1 DOESN'T have?\n // both have range/allDay, so no need to special-case.\n for (let propName in span0) {\n if (!(propName in span1)) {\n return false;\n }\n }\n return true;\n}\nfunction buildDateSpanApi(span, dateEnv) {\n return Object.assign(Object.assign({}, buildRangeApi(span.range, dateEnv, span.allDay)), { allDay: span.allDay });\n}\nfunction buildRangeApiWithTimeZone(range, dateEnv, omitTime) {\n return Object.assign(Object.assign({}, buildRangeApi(range, dateEnv, omitTime)), { timeZone: dateEnv.timeZone });\n}\nfunction buildRangeApi(range, dateEnv, omitTime) {\n return {\n start: dateEnv.toDate(range.start),\n end: dateEnv.toDate(range.end),\n startStr: dateEnv.formatIso(range.start, { omitTime }),\n endStr: dateEnv.formatIso(range.end, { omitTime }),\n };\n}\nfunction fabricateEventRange(dateSpan, eventUiBases, context) {\n let res = refineEventDef({ editable: false }, context);\n let def = parseEventDef(res.refined, res.extra, '', // sourceId\n dateSpan.allDay, true, // hasEnd\n context);\n return {\n def,\n ui: compileEventUi(def, eventUiBases),\n instance: createEventInstance(def.defId, dateSpan.range),\n range: dateSpan.range,\n isStart: true,\n isEnd: true,\n };\n}\n\n/*\ngiven a function that resolves a result asynchronously.\nthe function can either call passed-in success and failure callbacks,\nor it can return a promise.\nif you need to pass additional params to func, bind them first.\n*/\nfunction unpromisify(func, normalizedSuccessCallback, normalizedFailureCallback) {\n // guard against success/failure callbacks being called more than once\n // and guard against a promise AND callback being used together.\n let isResolved = false;\n let wrappedSuccess = function (res) {\n if (!isResolved) {\n isResolved = true;\n normalizedSuccessCallback(res);\n }\n };\n let wrappedFailure = function (error) {\n if (!isResolved) {\n isResolved = true;\n normalizedFailureCallback(error);\n }\n };\n let res = func(wrappedSuccess, wrappedFailure);\n if (res && typeof res.then === 'function') {\n res.then(wrappedSuccess, wrappedFailure);\n }\n}\n\nclass JsonRequestError extends Error {\n constructor(message, response) {\n super(message);\n this.response = response;\n }\n}\nfunction requestJson(method, url, params) {\n method = method.toUpperCase();\n const fetchOptions = {\n method,\n };\n if (method === 'GET') {\n url += (url.indexOf('?') === -1 ? '?' : '&') +\n new URLSearchParams(params);\n }\n else {\n fetchOptions.body = new URLSearchParams(params);\n fetchOptions.headers = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n }\n return fetch(url, fetchOptions).then((fetchRes) => {\n if (fetchRes.ok) {\n return fetchRes.json().then((parsedResponse) => {\n return [parsedResponse, fetchRes];\n }, () => {\n throw new JsonRequestError('Failure parsing JSON', fetchRes);\n });\n }\n else {\n throw new JsonRequestError('Request failed', fetchRes);\n }\n });\n}\n\nlet canVGrowWithinCell;\nfunction getCanVGrowWithinCell() {\n if (canVGrowWithinCell == null) {\n canVGrowWithinCell = computeCanVGrowWithinCell();\n }\n return canVGrowWithinCell;\n}\nfunction computeCanVGrowWithinCell() {\n // for SSR, because this function is call immediately at top-level\n // TODO: just make this logic execute top-level, immediately, instead of doing lazily\n if (typeof document === 'undefined') {\n return true;\n }\n let el = document.createElement('div');\n el.style.position = 'absolute';\n el.style.top = '0px';\n el.style.left = '0px';\n el.innerHTML = '<table><tr><td><div></div></td></tr></table>';\n el.querySelector('table').style.height = '100px';\n el.querySelector('div').style.height = '100%';\n document.body.appendChild(el);\n let div = el.querySelector('div');\n let possible = div.offsetHeight > 0;\n document.body.removeChild(el);\n return possible;\n}\n\nclass CalendarRoot extends BaseComponent {\n constructor() {\n super(...arguments);\n this.state = {\n forPrint: false,\n };\n this.handleBeforePrint = () => {\n flushSync(() => {\n this.setState({ forPrint: true });\n });\n };\n this.handleAfterPrint = () => {\n flushSync(() => {\n this.setState({ forPrint: false });\n });\n };\n }\n render() {\n let { props } = this;\n let { options } = props;\n let { forPrint } = this.state;\n let isHeightAuto = forPrint || options.height === 'auto' || options.contentHeight === 'auto';\n let height = (!isHeightAuto && options.height != null) ? options.height : '';\n let classNames = [\n 'fc',\n forPrint ? 'fc-media-print' : 'fc-media-screen',\n `fc-direction-${options.direction}`,\n props.theme.getClass('root'),\n ];\n if (!getCanVGrowWithinCell()) {\n classNames.push('fc-liquid-hack');\n }\n return props.children(classNames, height, isHeightAuto, forPrint);\n }\n componentDidMount() {\n let { emitter } = this.props;\n emitter.on('_beforeprint', this.handleBeforePrint);\n emitter.on('_afterprint', this.handleAfterPrint);\n }\n componentWillUnmount() {\n let { emitter } = this.props;\n emitter.off('_beforeprint', this.handleBeforePrint);\n emitter.off('_afterprint', this.handleAfterPrint);\n }\n}\n\nclass Interaction {\n constructor(settings) {\n this.component = settings.component;\n this.isHitComboAllowed = settings.isHitComboAllowed || null;\n }\n destroy() {\n }\n}\nfunction parseInteractionSettings(component, input) {\n return {\n component,\n el: input.el,\n useEventCenter: input.useEventCenter != null ? input.useEventCenter : true,\n isHitComboAllowed: input.isHitComboAllowed || null,\n };\n}\nfunction interactionSettingsToStore(settings) {\n return {\n [settings.component.uid]: settings,\n };\n}\n// global state\nconst interactionSettingsStore = {};\n\nclass NowTimer extends preact__WEBPACK_IMPORTED_MODULE_0__.Component {\n constructor(props, context) {\n super(props, context);\n this.handleRefresh = () => {\n let timing = this.computeTiming();\n if (timing.state.nowDate.valueOf() !== this.state.nowDate.valueOf()) {\n this.setState(timing.state);\n }\n this.clearTimeout();\n this.setTimeout(timing.waitMs);\n };\n this.handleVisibilityChange = () => {\n if (!document.hidden) {\n this.handleRefresh();\n }\n };\n this.state = this.computeTiming().state;\n }\n render() {\n let { props, state } = this;\n return props.children(state.nowDate, state.todayRange);\n }\n componentDidMount() {\n this.setTimeout();\n this.context.nowManager.addResetListener(this.handleRefresh);\n // fired tab becomes visible after being hidden\n document.addEventListener('visibilitychange', this.handleVisibilityChange);\n }\n componentDidUpdate(prevProps) {\n if (prevProps.unit !== this.props.unit) {\n this.clearTimeout();\n this.setTimeout();\n }\n }\n componentWillUnmount() {\n this.clearTimeout();\n this.context.nowManager.removeResetListener(this.handleRefresh);\n document.removeEventListener('visibilitychange', this.handleVisibilityChange);\n }\n computeTiming() {\n let { props, context } = this;\n let unroundedNow = context.nowManager.getDateMarker();\n let { nowIndicatorSnap } = context.options;\n if (nowIndicatorSnap === 'auto') {\n nowIndicatorSnap =\n // large unit?\n /year|month|week|day/.test(props.unit) ||\n // if slotDuration 30 mins for example, would NOT appear to snap (legacy behavior)\n (props.unitValue || 1) === 1;\n }\n let nowDate;\n let waitMs;\n if (nowIndicatorSnap) {\n nowDate = context.dateEnv.startOf(unroundedNow, props.unit); // aka currentUnitStart\n let nextUnitStart = context.dateEnv.add(nowDate, createDuration(1, props.unit));\n waitMs = nextUnitStart.valueOf() - unroundedNow.valueOf();\n }\n else {\n nowDate = unroundedNow;\n waitMs = 1000 * 60; // 1 minute\n }\n // there is a max setTimeout ms value (https://stackoverflow.com/a/3468650/96342)\n // ensure no longer than a day\n waitMs = Math.min(1000 * 60 * 60 * 24, waitMs);\n return {\n state: { nowDate, todayRange: buildDayRange(nowDate) },\n waitMs,\n };\n }\n setTimeout(waitMs = this.computeTiming().waitMs) {\n // NOTE: timeout could take longer than expected if tab sleeps,\n // which is why we listen to 'visibilitychange'\n this.timeoutId = setTimeout(() => {\n // NOTE: timeout could also return *earlier* than expected, and we need to wait 2 ms more\n // This is why use use same waitMs from computeTiming, so we don't skip an interval while\n // .setState() is executing\n const timing = this.computeTiming();\n this.setState(timing.state, () => {\n this.setTimeout(timing.waitMs);\n });\n }, waitMs);\n }\n clearTimeout() {\n if (this.timeoutId) {\n clearTimeout(this.timeoutId);\n }\n }\n}\nNowTimer.contextType = ViewContextType;\nfunction buildDayRange(date) {\n let start = startOfDay(date);\n let end = addDays(start, 1);\n return { start, end };\n}\n\nclass CalendarImpl {\n getCurrentData() {\n return this.currentDataManager.getCurrentData();\n }\n dispatch(action) {\n this.currentDataManager.dispatch(action);\n }\n get view() { return this.getCurrentData().viewApi; }\n batchRendering(callback) {\n callback();\n }\n updateSize() {\n this.trigger('_resize', true);\n }\n // Options\n // -----------------------------------------------------------------------------------------------------------------\n setOption(name, val) {\n this.dispatch({\n type: 'SET_OPTION',\n optionName: name,\n rawOptionValue: val,\n });\n }\n getOption(name) {\n return this.currentDataManager.currentCalendarOptionsInput[name];\n }\n getAvailableLocaleCodes() {\n return Object.keys(this.getCurrentData().availableRawLocales);\n }\n // Trigger\n // -----------------------------------------------------------------------------------------------------------------\n on(handlerName, handler) {\n let { currentDataManager } = this;\n if (currentDataManager.currentCalendarOptionsRefiners[handlerName]) {\n currentDataManager.emitter.on(handlerName, handler);\n }\n else {\n console.warn(`Unknown listener name '${handlerName}'`);\n }\n }\n off(handlerName, handler) {\n this.currentDataManager.emitter.off(handlerName, handler);\n }\n // not meant for public use\n trigger(handlerName, ...args) {\n this.currentDataManager.emitter.trigger(handlerName, ...args);\n }\n // View\n // -----------------------------------------------------------------------------------------------------------------\n changeView(viewType, dateOrRange) {\n this.batchRendering(() => {\n this.unselect();\n if (dateOrRange) {\n if (dateOrRange.start && dateOrRange.end) { // a range\n this.dispatch({\n type: 'CHANGE_VIEW_TYPE',\n viewType,\n });\n this.dispatch({\n type: 'SET_OPTION',\n optionName: 'visibleRange',\n rawOptionValue: dateOrRange,\n });\n }\n else {\n let { dateEnv } = this.getCurrentData();\n this.dispatch({\n type: 'CHANGE_VIEW_TYPE',\n viewType,\n dateMarker: dateEnv.createMarker(dateOrRange),\n });\n }\n }\n else {\n this.dispatch({\n type: 'CHANGE_VIEW_TYPE',\n viewType,\n });\n }\n });\n }\n // Forces navigation to a view for the given date.\n // `viewType` can be a specific view name or a generic one like \"week\" or \"day\".\n // needs to change\n zoomTo(dateMarker, viewType) {\n let state = this.getCurrentData();\n let spec;\n viewType = viewType || 'day'; // day is default zoom\n spec = state.viewSpecs[viewType] || this.getUnitViewSpec(viewType);\n this.unselect();\n if (spec) {\n this.dispatch({\n type: 'CHANGE_VIEW_TYPE',\n viewType: spec.type,\n dateMarker,\n });\n }\n else {\n this.dispatch({\n type: 'CHANGE_DATE',\n dateMarker,\n });\n }\n }\n // Given a duration singular unit, like \"week\" or \"day\", finds a matching view spec.\n // Preference is given to views that have corresponding buttons.\n getUnitViewSpec(unit) {\n let { viewSpecs, toolbarConfig } = this.getCurrentData();\n let viewTypes = [].concat(toolbarConfig.header ? toolbarConfig.header.viewsWithButtons : [], toolbarConfig.footer ? toolbarConfig.footer.viewsWithButtons : []);\n let i;\n let spec;\n for (let viewType in viewSpecs) {\n viewTypes.push(viewType);\n }\n for (i = 0; i < viewTypes.length; i += 1) {\n spec = viewSpecs[viewTypes[i]];\n if (spec) {\n if (spec.singleUnit === unit) {\n return spec;\n }\n }\n }\n return null;\n }\n // Current Date\n // -----------------------------------------------------------------------------------------------------------------\n prev() {\n this.unselect();\n this.dispatch({ type: 'PREV' });\n }\n next() {\n this.unselect();\n this.dispatch({ type: 'NEXT' });\n }\n prevYear() {\n let state = this.getCurrentData();\n this.unselect();\n this.dispatch({\n type: 'CHANGE_DATE',\n dateMarker: state.dateEnv.addYears(state.currentDate, -1),\n });\n }\n nextYear() {\n let state = this.getCurrentData();\n this.unselect();\n this.dispatch({\n type: 'CHANGE_DATE',\n dateMarker: state.dateEnv.addYears(state.currentDate, 1),\n });\n }\n today() {\n let state = this.getCurrentData();\n this.unselect();\n this.dispatch({\n type: 'CHANGE_DATE',\n dateMarker: state.nowManager.getDateMarker(),\n });\n }\n gotoDate(zonedDateInput) {\n let state = this.getCurrentData();\n this.unselect();\n this.dispatch({\n type: 'CHANGE_DATE',\n dateMarker: state.dateEnv.createMarker(zonedDateInput),\n });\n }\n incrementDate(deltaInput) {\n let state = this.getCurrentData();\n let delta = createDuration(deltaInput);\n if (delta) { // else, warn about invalid input?\n this.unselect();\n this.dispatch({\n type: 'CHANGE_DATE',\n dateMarker: state.dateEnv.add(state.currentDate, delta),\n });\n }\n }\n getDate() {\n let state = this.getCurrentData();\n return state.dateEnv.toDate(state.currentDate);\n }\n // Date Formatting Utils\n // -----------------------------------------------------------------------------------------------------------------\n formatDate(d, formatter) {\n let { dateEnv } = this.getCurrentData();\n return dateEnv.format(dateEnv.createMarker(d), createFormatter(formatter));\n }\n // `settings` is for formatter AND isEndExclusive\n formatRange(d0, d1, settings) {\n let { dateEnv } = this.getCurrentData();\n return dateEnv.formatRange(dateEnv.createMarker(d0), dateEnv.createMarker(d1), createFormatter(settings), settings);\n }\n formatIso(d, omitTime) {\n let { dateEnv } = this.getCurrentData();\n return dateEnv.formatIso(dateEnv.createMarker(d), { omitTime });\n }\n // Date Selection / Event Selection / DayClick\n // -----------------------------------------------------------------------------------------------------------------\n select(dateOrObj, endDate) {\n let selectionInput;\n if (endDate == null) {\n if (dateOrObj.start != null) {\n selectionInput = dateOrObj;\n }\n else {\n selectionInput = {\n start: dateOrObj,\n end: null,\n };\n }\n }\n else {\n selectionInput = {\n start: dateOrObj,\n end: endDate,\n };\n }\n let state = this.getCurrentData();\n let selection = parseDateSpan(selectionInput, state.dateEnv, createDuration({ days: 1 }));\n if (selection) { // throw parse error otherwise?\n this.dispatch({ type: 'SELECT_DATES', selection });\n triggerDateSelect(selection, null, state);\n }\n }\n unselect(pev) {\n let state = this.getCurrentData();\n if (state.dateSelection) {\n this.dispatch({ type: 'UNSELECT_DATES' });\n triggerDateUnselect(pev, state);\n }\n }\n // Public Events API\n // -----------------------------------------------------------------------------------------------------------------\n addEvent(eventInput, sourceInput) {\n if (eventInput instanceof EventImpl) {\n let def = eventInput._def;\n let instance = eventInput._instance;\n let currentData = this.getCurrentData();\n // not already present? don't want to add an old snapshot\n if (!currentData.eventStore.defs[def.defId]) {\n this.dispatch({\n type: 'ADD_EVENTS',\n eventStore: eventTupleToStore({ def, instance }), // TODO: better util for two args?\n });\n this.triggerEventAdd(eventInput);\n }\n return eventInput;\n }\n let state = this.getCurrentData();\n let eventSource;\n if (sourceInput instanceof EventSourceImpl) {\n eventSource = sourceInput.internalEventSource;\n }\n else if (typeof sourceInput === 'boolean') {\n if (sourceInput) { // true. part of the first event source\n [eventSource] = hashValuesToArray(state.eventSources);\n }\n }\n else if (sourceInput != null) { // an ID. accepts a number too\n let sourceApi = this.getEventSourceById(sourceInput); // TODO: use an internal function\n if (!sourceApi) {\n console.warn(`Could not find an event source with ID \"${sourceInput}\"`); // TODO: test\n return null;\n }\n eventSource = sourceApi.internalEventSource;\n }\n let tuple = parseEvent(eventInput, eventSource, state, false);\n if (tuple) {\n let newEventApi = new EventImpl(state, tuple.def, tuple.def.recurringDef ? null : tuple.instance);\n this.dispatch({\n type: 'ADD_EVENTS',\n eventStore: eventTupleToStore(tuple),\n });\n this.triggerEventAdd(newEventApi);\n return newEventApi;\n }\n return null;\n }\n triggerEventAdd(eventApi) {\n let { emitter } = this.getCurrentData();\n emitter.trigger('eventAdd', {\n event: eventApi,\n relatedEvents: [],\n revert: () => {\n this.dispatch({\n type: 'REMOVE_EVENTS',\n eventStore: eventApiToStore(eventApi),\n });\n },\n });\n }\n // TODO: optimize\n getEventById(id) {\n let state = this.getCurrentData();\n let { defs, instances } = state.eventStore;\n id = String(id);\n for (let defId in defs) {\n let def = defs[defId];\n if (def.publicId === id) {\n if (def.recurringDef) {\n return new EventImpl(state, def, null);\n }\n for (let instanceId in instances) {\n let instance = instances[instanceId];\n if (instance.defId === def.defId) {\n return new EventImpl(state, def, instance);\n }\n }\n }\n }\n return null;\n }\n getEvents() {\n let currentData = this.getCurrentData();\n return buildEventApis(currentData.eventStore, currentData);\n }\n removeAllEvents() {\n this.dispatch({ type: 'REMOVE_ALL_EVENTS' });\n }\n // Public Event Sources API\n // -----------------------------------------------------------------------------------------------------------------\n getEventSources() {\n let state = this.getCurrentData();\n let sourceHash = state.eventSources;\n let sourceApis = [];\n for (let internalId in sourceHash) {\n sourceApis.push(new EventSourceImpl(state, sourceHash[internalId]));\n }\n return sourceApis;\n }\n getEventSourceById(id) {\n let state = this.getCurrentData();\n let sourceHash = state.eventSources;\n id = String(id);\n for (let sourceId in sourceHash) {\n if (sourceHash[sourceId].publicId === id) {\n return new EventSourceImpl(state, sourceHash[sourceId]);\n }\n }\n return null;\n }\n addEventSource(sourceInput) {\n let state = this.getCurrentData();\n if (sourceInput instanceof EventSourceImpl) {\n // not already present? don't want to add an old snapshot\n if (!state.eventSources[sourceInput.internalEventSource.sourceId]) {\n this.dispatch({\n type: 'ADD_EVENT_SOURCES',\n sources: [sourceInput.internalEventSource],\n });\n }\n return sourceInput;\n }\n let eventSource = parseEventSource(sourceInput, state);\n if (eventSource) { // TODO: error otherwise?\n this.dispatch({ type: 'ADD_EVENT_SOURCES', sources: [eventSource] });\n return new EventSourceImpl(state, eventSource);\n }\n return null;\n }\n removeAllEventSources() {\n this.dispatch({ type: 'REMOVE_ALL_EVENT_SOURCES' });\n }\n refetchEvents() {\n this.dispatch({ type: 'FETCH_EVENT_SOURCES', isRefetch: true });\n }\n // Scroll\n // -----------------------------------------------------------------------------------------------------------------\n scrollToTime(timeInput) {\n let time = createDuration(timeInput);\n if (time) {\n this.trigger('_scrollRequest', { time });\n }\n }\n}\n\nfunction pointInsideRect(point, rect) {\n return point.left >= rect.left &&\n point.left < rect.right &&\n point.top >= rect.top &&\n point.top < rect.bottom;\n}\n// Returns a new rectangle that is the intersection of the two rectangles. If they don't intersect, returns false\nfunction intersectRects(rect1, rect2) {\n let res = {\n left: Math.max(rect1.left, rect2.left),\n right: Math.min(rect1.right, rect2.right),\n top: Math.max(rect1.top, rect2.top),\n bottom: Math.min(rect1.bottom, rect2.bottom),\n };\n if (res.left < res.right && res.top < res.bottom) {\n return res;\n }\n return false;\n}\nfunction translateRect(rect, deltaX, deltaY) {\n return {\n left: rect.left + deltaX,\n right: rect.right + deltaX,\n top: rect.top + deltaY,\n bottom: rect.bottom + deltaY,\n };\n}\n// Returns a new point that will have been moved to reside within the given rectangle\nfunction constrainPoint(point, rect) {\n return {\n left: Math.min(Math.max(point.left, rect.left), rect.right),\n top: Math.min(Math.max(point.top, rect.top), rect.bottom),\n };\n}\n// Returns a point that is the center of the given rectangle\nfunction getRectCenter(rect) {\n return {\n left: (rect.left + rect.right) / 2,\n top: (rect.top + rect.bottom) / 2,\n };\n}\n// Subtracts point2's coordinates from point1's coordinates, returning a delta\nfunction diffPoints(point1, point2) {\n return {\n left: point1.left - point2.left,\n top: point1.top - point2.top,\n };\n}\n\nconst EMPTY_EVENT_STORE = createEmptyEventStore(); // for purecomponents. TODO: keep elsewhere\nclass Splitter {\n constructor() {\n this.getKeysForEventDefs = memoize(this._getKeysForEventDefs);\n this.splitDateSelection = memoize(this._splitDateSpan);\n this.splitEventStore = memoize(this._splitEventStore);\n this.splitIndividualUi = memoize(this._splitIndividualUi);\n this.splitEventDrag = memoize(this._splitInteraction);\n this.splitEventResize = memoize(this._splitInteraction);\n this.eventUiBuilders = {}; // TODO: typescript protection\n }\n splitProps(props) {\n let keyInfos = this.getKeyInfo(props);\n let defKeys = this.getKeysForEventDefs(props.eventStore);\n let dateSelections = this.splitDateSelection(props.dateSelection);\n let individualUi = this.splitIndividualUi(props.eventUiBases, defKeys); // the individual *bases*\n let eventStores = this.splitEventStore(props.eventStore, defKeys);\n let eventDrags = this.splitEventDrag(props.eventDrag);\n let eventResizes = this.splitEventResize(props.eventResize);\n let splitProps = {};\n this.eventUiBuilders = mapHash(keyInfos, (info, key) => this.eventUiBuilders[key] || memoize(buildEventUiForKey));\n for (let key in keyInfos) {\n let keyInfo = keyInfos[key];\n let eventStore = eventStores[key] || EMPTY_EVENT_STORE;\n let buildEventUi = this.eventUiBuilders[key];\n splitProps[key] = {\n businessHours: keyInfo.businessHours || props.businessHours,\n dateSelection: dateSelections[key] || null,\n eventStore,\n eventUiBases: buildEventUi(props.eventUiBases[''], keyInfo.ui, individualUi[key]),\n eventSelection: eventStore.instances[props.eventSelection] ? props.eventSelection : '',\n eventDrag: eventDrags[key] || null,\n eventResize: eventResizes[key] || null,\n };\n }\n return splitProps;\n }\n _splitDateSpan(dateSpan) {\n let dateSpans = {};\n if (dateSpan) {\n let keys = this.getKeysForDateSpan(dateSpan);\n for (let key of keys) {\n dateSpans[key] = dateSpan;\n }\n }\n return dateSpans;\n }\n _getKeysForEventDefs(eventStore) {\n return mapHash(eventStore.defs, (eventDef) => this.getKeysForEventDef(eventDef));\n }\n _splitEventStore(eventStore, defKeys) {\n let { defs, instances } = eventStore;\n let splitStores = {};\n for (let defId in defs) {\n for (let key of defKeys[defId]) {\n if (!splitStores[key]) {\n splitStores[key] = createEmptyEventStore();\n }\n splitStores[key].defs[defId] = defs[defId];\n }\n }\n for (let instanceId in instances) {\n let instance = instances[instanceId];\n for (let key of defKeys[instance.defId]) {\n if (splitStores[key]) { // must have already been created\n splitStores[key].instances[instanceId] = instance;\n }\n }\n }\n return splitStores;\n }\n _splitIndividualUi(eventUiBases, defKeys) {\n let splitHashes = {};\n for (let defId in eventUiBases) {\n if (defId) { // not the '' key\n for (let key of defKeys[defId]) {\n if (!splitHashes[key]) {\n splitHashes[key] = {};\n }\n splitHashes[key][defId] = eventUiBases[defId];\n }\n }\n }\n return splitHashes;\n }\n _splitInteraction(interaction) {\n let splitStates = {};\n if (interaction) {\n let affectedStores = this._splitEventStore(interaction.affectedEvents, this._getKeysForEventDefs(interaction.affectedEvents));\n // can't rely on defKeys because event data is mutated\n let mutatedKeysByDefId = this._getKeysForEventDefs(interaction.mutatedEvents);\n let mutatedStores = this._splitEventStore(interaction.mutatedEvents, mutatedKeysByDefId);\n let populate = (key) => {\n if (!splitStates[key]) {\n splitStates[key] = {\n affectedEvents: affectedStores[key] || EMPTY_EVENT_STORE,\n mutatedEvents: mutatedStores[key] || EMPTY_EVENT_STORE,\n isEvent: interaction.isEvent,\n };\n }\n };\n for (let key in affectedStores) {\n populate(key);\n }\n for (let key in mutatedStores) {\n populate(key);\n }\n }\n return splitStates;\n }\n}\nfunction buildEventUiForKey(allUi, eventUiForKey, individualUi) {\n let baseParts = [];\n if (allUi) {\n baseParts.push(allUi);\n }\n if (eventUiForKey) {\n baseParts.push(eventUiForKey);\n }\n let stuff = {\n '': combineEventUis(baseParts),\n };\n if (individualUi) {\n Object.assign(stuff, individualUi);\n }\n return stuff;\n}\n\nfunction getDateMeta(date, todayRange, nowDate, dateProfile) {\n return {\n dow: date.getUTCDay(),\n isDisabled: Boolean(dateProfile && (!dateProfile.activeRange || !rangeContainsMarker(dateProfile.activeRange, date))),\n isOther: Boolean(dateProfile && !rangeContainsMarker(dateProfile.currentRange, date)),\n isToday: Boolean(todayRange && rangeContainsMarker(todayRange, date)),\n isPast: Boolean(nowDate ? (date < nowDate) : todayRange ? (date < todayRange.start) : false),\n isFuture: Boolean(nowDate ? (date > nowDate) : todayRange ? (date >= todayRange.end) : false),\n };\n}\nfunction getDayClassNames(meta, theme) {\n let classNames = [\n 'fc-day',\n `fc-day-${DAY_IDS[meta.dow]}`,\n ];\n if (meta.isDisabled) {\n classNames.push('fc-day-disabled');\n }\n else {\n if (meta.isToday) {\n classNames.push('fc-day-today');\n classNames.push(theme.getClass('today'));\n }\n if (meta.isPast) {\n classNames.push('fc-day-past');\n }\n if (meta.isFuture) {\n classNames.push('fc-day-future');\n }\n if (meta.isOther) {\n classNames.push('fc-day-other');\n }\n }\n return classNames;\n}\nfunction getSlotClassNames(meta, theme) {\n let classNames = [\n 'fc-slot',\n `fc-slot-${DAY_IDS[meta.dow]}`,\n ];\n if (meta.isDisabled) {\n classNames.push('fc-slot-disabled');\n }\n else {\n if (meta.isToday) {\n classNames.push('fc-slot-today');\n classNames.push(theme.getClass('today'));\n }\n if (meta.isPast) {\n classNames.push('fc-slot-past');\n }\n if (meta.isFuture) {\n classNames.push('fc-slot-future');\n }\n }\n return classNames;\n}\n\nconst DAY_FORMAT = createFormatter({ year: 'numeric', month: 'long', day: 'numeric' });\nconst WEEK_FORMAT = createFormatter({ week: 'long' });\nfunction buildNavLinkAttrs(context, dateMarker, viewType = 'day', isTabbable = true) {\n const { dateEnv, options, calendarApi } = context;\n let dateStr = dateEnv.format(dateMarker, viewType === 'week' ? WEEK_FORMAT : DAY_FORMAT);\n if (options.navLinks) {\n let zonedDate = dateEnv.toDate(dateMarker);\n const handleInteraction = (ev) => {\n let customAction = viewType === 'day' ? options.navLinkDayClick :\n viewType === 'week' ? options.navLinkWeekClick : null;\n if (typeof customAction === 'function') {\n customAction.call(calendarApi, dateEnv.toDate(dateMarker), ev);\n }\n else {\n if (typeof customAction === 'string') {\n viewType = customAction;\n }\n calendarApi.zoomTo(dateMarker, viewType);\n }\n };\n return Object.assign({ title: formatWithOrdinals(options.navLinkHint, [dateStr, zonedDate], dateStr), 'data-navlink': '' }, (isTabbable\n ? createAriaClickAttrs(handleInteraction)\n : { onClick: handleInteraction }));\n }\n return { 'aria-label': dateStr };\n}\n\nlet _isRtlScrollbarOnLeft = null;\nfunction getIsRtlScrollbarOnLeft() {\n if (_isRtlScrollbarOnLeft === null) {\n _isRtlScrollbarOnLeft = computeIsRtlScrollbarOnLeft();\n }\n return _isRtlScrollbarOnLeft;\n}\nfunction computeIsRtlScrollbarOnLeft() {\n let outerEl = document.createElement('div');\n applyStyle(outerEl, {\n position: 'absolute',\n top: -1000,\n left: 0,\n border: 0,\n padding: 0,\n overflow: 'scroll',\n direction: 'rtl',\n });\n outerEl.innerHTML = '<div></div>';\n document.body.appendChild(outerEl);\n let innerEl = outerEl.firstChild;\n let res = innerEl.getBoundingClientRect().left > outerEl.getBoundingClientRect().left;\n removeElement(outerEl);\n return res;\n}\n\nlet _scrollbarWidths;\nfunction getScrollbarWidths() {\n if (!_scrollbarWidths) {\n _scrollbarWidths = computeScrollbarWidths();\n }\n return _scrollbarWidths;\n}\nfunction computeScrollbarWidths() {\n let el = document.createElement('div');\n el.style.overflow = 'scroll';\n el.style.position = 'absolute';\n el.style.top = '-9999px';\n el.style.left = '-9999px';\n document.body.appendChild(el);\n let res = computeScrollbarWidthsForEl(el);\n document.body.removeChild(el);\n return res;\n}\n// WARNING: will include border\nfunction computeScrollbarWidthsForEl(el) {\n return {\n x: el.offsetHeight - el.clientHeight,\n y: el.offsetWidth - el.clientWidth,\n };\n}\n\nfunction computeEdges(el, getPadding = false) {\n let computedStyle = window.getComputedStyle(el);\n let borderLeft = parseInt(computedStyle.borderLeftWidth, 10) || 0;\n let borderRight = parseInt(computedStyle.borderRightWidth, 10) || 0;\n let borderTop = parseInt(computedStyle.borderTopWidth, 10) || 0;\n let borderBottom = parseInt(computedStyle.borderBottomWidth, 10) || 0;\n let badScrollbarWidths = computeScrollbarWidthsForEl(el); // includes border!\n let scrollbarLeftRight = badScrollbarWidths.y - borderLeft - borderRight;\n let scrollbarBottom = badScrollbarWidths.x - borderTop - borderBottom;\n let res = {\n borderLeft,\n borderRight,\n borderTop,\n borderBottom,\n scrollbarBottom,\n scrollbarLeft: 0,\n scrollbarRight: 0,\n };\n if (getIsRtlScrollbarOnLeft() && computedStyle.direction === 'rtl') { // is the scrollbar on the left side?\n res.scrollbarLeft = scrollbarLeftRight;\n }\n else {\n res.scrollbarRight = scrollbarLeftRight;\n }\n if (getPadding) {\n res.paddingLeft = parseInt(computedStyle.paddingLeft, 10) || 0;\n res.paddingRight = parseInt(computedStyle.paddingRight, 10) || 0;\n res.paddingTop = parseInt(computedStyle.paddingTop, 10) || 0;\n res.paddingBottom = parseInt(computedStyle.paddingBottom, 10) || 0;\n }\n return res;\n}\nfunction computeInnerRect(el, goWithinPadding = false, doFromWindowViewport) {\n let outerRect = doFromWindowViewport ? el.getBoundingClientRect() : computeRect(el);\n let edges = computeEdges(el, goWithinPadding);\n let res = {\n left: outerRect.left + edges.borderLeft + edges.scrollbarLeft,\n right: outerRect.right - edges.borderRight - edges.scrollbarRight,\n top: outerRect.top + edges.borderTop,\n bottom: outerRect.bottom - edges.borderBottom - edges.scrollbarBottom,\n };\n if (goWithinPadding) {\n res.left += edges.paddingLeft;\n res.right -= edges.paddingRight;\n res.top += edges.paddingTop;\n res.bottom -= edges.paddingBottom;\n }\n return res;\n}\nfunction computeRect(el) {\n let rect = el.getBoundingClientRect();\n return {\n left: rect.left + window.scrollX,\n top: rect.top + window.scrollY,\n right: rect.right + window.scrollX,\n bottom: rect.bottom + window.scrollY,\n };\n}\nfunction computeClippedClientRect(el) {\n let clippingParents = getClippingParents(el);\n let rect = el.getBoundingClientRect();\n for (let clippingParent of clippingParents) {\n let intersection = intersectRects(rect, clippingParent.getBoundingClientRect());\n if (intersection) {\n rect = intersection;\n }\n else {\n return null;\n }\n }\n return rect;\n}\n// does not return window\nfunction getClippingParents(el) {\n let parents = [];\n while (el instanceof HTMLElement) { // will stop when gets to document or null\n let computedStyle = window.getComputedStyle(el);\n if (computedStyle.position === 'fixed') {\n break;\n }\n if ((/(auto|scroll)/).test(computedStyle.overflow + computedStyle.overflowY + computedStyle.overflowX)) {\n parents.push(el);\n }\n el = el.parentNode;\n }\n return parents;\n}\n\n/*\nRecords offset information for a set of elements, relative to an origin element.\nCan record the left/right OR the top/bottom OR both.\nProvides methods for querying the cache by position.\n*/\nclass PositionCache {\n constructor(originEl, els, isHorizontal, isVertical) {\n this.els = els;\n let originClientRect = this.originClientRect = originEl.getBoundingClientRect(); // relative to viewport top-left\n if (isHorizontal) {\n this.buildElHorizontals(originClientRect.left);\n }\n if (isVertical) {\n this.buildElVerticals(originClientRect.top);\n }\n }\n // Populates the left/right internal coordinate arrays\n buildElHorizontals(originClientLeft) {\n let lefts = [];\n let rights = [];\n for (let el of this.els) {\n let rect = el.getBoundingClientRect();\n lefts.push(rect.left - originClientLeft);\n rights.push(rect.right - originClientLeft);\n }\n this.lefts = lefts;\n this.rights = rights;\n }\n // Populates the top/bottom internal coordinate arrays\n buildElVerticals(originClientTop) {\n let tops = [];\n let bottoms = [];\n for (let el of this.els) {\n let rect = el.getBoundingClientRect();\n tops.push(rect.top - originClientTop);\n bottoms.push(rect.bottom - originClientTop);\n }\n this.tops = tops;\n this.bottoms = bottoms;\n }\n // Given a left offset (from document left), returns the index of the el that it horizontally intersects.\n // If no intersection is made, returns undefined.\n leftToIndex(leftPosition) {\n let { lefts, rights } = this;\n let len = lefts.length;\n let i;\n for (i = 0; i < len; i += 1) {\n if (leftPosition >= lefts[i] && leftPosition < rights[i]) {\n return i;\n }\n }\n return undefined; // TODO: better\n }\n // Given a top offset (from document top), returns the index of the el that it vertically intersects.\n // If no intersection is made, returns undefined.\n topToIndex(topPosition) {\n let { tops, bottoms } = this;\n let len = tops.length;\n let i;\n for (i = 0; i < len; i += 1) {\n if (topPosition >= tops[i] && topPosition < bottoms[i]) {\n return i;\n }\n }\n return undefined; // TODO: better\n }\n // Gets the width of the element at the given index\n getWidth(leftIndex) {\n return this.rights[leftIndex] - this.lefts[leftIndex];\n }\n // Gets the height of the element at the given index\n getHeight(topIndex) {\n return this.bottoms[topIndex] - this.tops[topIndex];\n }\n similarTo(otherCache) {\n return similarNumArrays(this.tops || [], otherCache.tops || []) &&\n similarNumArrays(this.bottoms || [], otherCache.bottoms || []) &&\n similarNumArrays(this.lefts || [], otherCache.lefts || []) &&\n similarNumArrays(this.rights || [], otherCache.rights || []);\n }\n}\nfunction similarNumArrays(a, b) {\n const len = a.length;\n if (len !== b.length) {\n return false;\n }\n for (let i = 0; i < len; i++) {\n if (Math.round(a[i]) !== Math.round(b[i])) {\n return false;\n }\n }\n return true;\n}\n\n/* eslint max-classes-per-file: \"off\" */\n/*\nAn object for getting/setting scroll-related information for an element.\nInternally, this is done very differently for window versus DOM element,\nso this object serves as a common interface.\n*/\nclass ScrollController {\n getMaxScrollTop() {\n return this.getScrollHeight() - this.getClientHeight();\n }\n getMaxScrollLeft() {\n return this.getScrollWidth() - this.getClientWidth();\n }\n canScrollVertically() {\n return this.getMaxScrollTop() > 0;\n }\n canScrollHorizontally() {\n return this.getMaxScrollLeft() > 0;\n }\n canScrollUp() {\n return this.getScrollTop() > 0;\n }\n canScrollDown() {\n return this.getScrollTop() < this.getMaxScrollTop();\n }\n canScrollLeft() {\n return this.getScrollLeft() > 0;\n }\n canScrollRight() {\n return this.getScrollLeft() < this.getMaxScrollLeft();\n }\n}\nclass ElementScrollController extends ScrollController {\n constructor(el) {\n super();\n this.el = el;\n }\n getScrollTop() {\n return this.el.scrollTop;\n }\n getScrollLeft() {\n return this.el.scrollLeft;\n }\n setScrollTop(top) {\n this.el.scrollTop = top;\n }\n setScrollLeft(left) {\n this.el.scrollLeft = left;\n }\n getScrollWidth() {\n return this.el.scrollWidth;\n }\n getScrollHeight() {\n return this.el.scrollHeight;\n }\n getClientHeight() {\n return this.el.clientHeight;\n }\n getClientWidth() {\n return this.el.clientWidth;\n }\n}\nclass WindowScrollController extends ScrollController {\n getScrollTop() {\n return window.scrollY;\n }\n getScrollLeft() {\n return window.scrollX;\n }\n setScrollTop(n) {\n window.scroll(window.scrollX, n);\n }\n setScrollLeft(n) {\n window.scroll(n, window.scrollY);\n }\n getScrollWidth() {\n return document.documentElement.scrollWidth;\n }\n getScrollHeight() {\n return document.documentElement.scrollHeight;\n }\n getClientHeight() {\n return document.documentElement.clientHeight;\n }\n getClientWidth() {\n return document.documentElement.clientWidth;\n }\n}\n\n/*\nan INTERACTABLE date component\n\nPURPOSES:\n- hook up to fg, fill, and mirror renderers\n- interface for dragging and hits\n*/\nclass DateComponent extends BaseComponent {\n constructor() {\n super(...arguments);\n this.uid = guid();\n }\n // Hit System\n // -----------------------------------------------------------------------------------------------------------------\n prepareHits() {\n }\n queryHit(positionLeft, positionTop, elWidth, elHeight) {\n return null; // this should be abstract\n }\n // Pointer Interaction Utils\n // -----------------------------------------------------------------------------------------------------------------\n isValidSegDownEl(el) {\n return !this.props.eventDrag && // HACK\n !this.props.eventResize && // HACK\n !elementClosest(el, '.fc-event-mirror');\n }\n isValidDateDownEl(el) {\n return !elementClosest(el, '.fc-event:not(.fc-bg-event)') &&\n !elementClosest(el, '.fc-more-link') && // a \"more..\" link\n !elementClosest(el, 'a[data-navlink]') && // a clickable nav link\n !elementClosest(el, '.fc-popover'); // hack\n }\n}\n\nclass NamedTimeZoneImpl {\n constructor(timeZoneName) {\n this.timeZoneName = timeZoneName;\n }\n}\n\nclass SegHierarchy {\n constructor(getEntryThickness = (entry) => {\n // if no thickness known, assume 1 (if 0, so small it always fits)\n return entry.thickness || 1;\n }) {\n this.getEntryThickness = getEntryThickness;\n // settings\n this.strictOrder = false;\n this.allowReslicing = false;\n this.maxCoord = -1; // -1 means no max\n this.maxStackCnt = -1; // -1 means no max\n this.levelCoords = []; // ordered\n this.entriesByLevel = []; // parallel with levelCoords\n this.stackCnts = {}; // TODO: use better technique!?\n }\n addSegs(inputs) {\n let hiddenEntries = [];\n for (let input of inputs) {\n this.insertEntry(input, hiddenEntries);\n }\n return hiddenEntries;\n }\n insertEntry(entry, hiddenEntries) {\n let insertion = this.findInsertion(entry);\n if (this.isInsertionValid(insertion, entry)) {\n this.insertEntryAt(entry, insertion);\n }\n else {\n this.handleInvalidInsertion(insertion, entry, hiddenEntries);\n }\n }\n isInsertionValid(insertion, entry) {\n return (this.maxCoord === -1 || insertion.levelCoord + this.getEntryThickness(entry) <= this.maxCoord) &&\n (this.maxStackCnt === -1 || insertion.stackCnt < this.maxStackCnt);\n }\n handleInvalidInsertion(insertion, entry, hiddenEntries) {\n if (this.allowReslicing && insertion.touchingEntry) {\n const hiddenEntry = Object.assign(Object.assign({}, entry), { span: intersectSpans(entry.span, insertion.touchingEntry.span) });\n hiddenEntries.push(hiddenEntry);\n this.splitEntry(entry, insertion.touchingEntry, hiddenEntries);\n }\n else {\n hiddenEntries.push(entry);\n }\n }\n /*\n Does NOT add what hit the `barrier` into hiddenEntries. Should already be done.\n */\n splitEntry(entry, barrier, hiddenEntries) {\n let entrySpan = entry.span;\n let barrierSpan = barrier.span;\n if (entrySpan.start < barrierSpan.start) {\n this.insertEntry({\n index: entry.index,\n thickness: entry.thickness,\n span: { start: entrySpan.start, end: barrierSpan.start },\n }, hiddenEntries);\n }\n if (entrySpan.end > barrierSpan.end) {\n this.insertEntry({\n index: entry.index,\n thickness: entry.thickness,\n span: { start: barrierSpan.end, end: entrySpan.end },\n }, hiddenEntries);\n }\n }\n insertEntryAt(entry, insertion) {\n let { entriesByLevel, levelCoords } = this;\n if (insertion.lateral === -1) {\n // create a new level\n insertAt(levelCoords, insertion.level, insertion.levelCoord);\n insertAt(entriesByLevel, insertion.level, [entry]);\n }\n else {\n // insert into existing level\n insertAt(entriesByLevel[insertion.level], insertion.lateral, entry);\n }\n this.stackCnts[buildEntryKey(entry)] = insertion.stackCnt;\n }\n /*\n does not care about limits\n */\n findInsertion(newEntry) {\n let { levelCoords, entriesByLevel, strictOrder, stackCnts } = this;\n let levelCnt = levelCoords.length;\n let candidateCoord = 0;\n let touchingLevel = -1;\n let touchingLateral = -1;\n let touchingEntry = null;\n let stackCnt = 0;\n for (let trackingLevel = 0; trackingLevel < levelCnt; trackingLevel += 1) {\n const trackingCoord = levelCoords[trackingLevel];\n // if the current level is past the placed entry, we have found a good empty space and can stop.\n // if strictOrder, keep finding more lateral intersections.\n if (!strictOrder && trackingCoord >= candidateCoord + this.getEntryThickness(newEntry)) {\n break;\n }\n let trackingEntries = entriesByLevel[trackingLevel];\n let trackingEntry;\n let searchRes = binarySearch(trackingEntries, newEntry.span.start, getEntrySpanEnd); // find first entry after newEntry's end\n let lateralIndex = searchRes[0] + searchRes[1]; // if exact match (which doesn't collide), go to next one\n while ( // loop through entries that horizontally intersect\n (trackingEntry = trackingEntries[lateralIndex]) && // but not past the whole entry list\n trackingEntry.span.start < newEntry.span.end // and not entirely past newEntry\n ) {\n let trackingEntryBottom = trackingCoord + this.getEntryThickness(trackingEntry);\n // intersects into the top of the candidate?\n if (trackingEntryBottom > candidateCoord) {\n candidateCoord = trackingEntryBottom;\n touchingEntry = trackingEntry;\n touchingLevel = trackingLevel;\n touchingLateral = lateralIndex;\n }\n // butts up against top of candidate? (will happen if just intersected as well)\n if (trackingEntryBottom === candidateCoord) {\n // accumulate the highest possible stackCnt of the trackingEntries that butt up\n stackCnt = Math.max(stackCnt, stackCnts[buildEntryKey(trackingEntry)] + 1);\n }\n lateralIndex += 1;\n }\n }\n // the destination level will be after touchingEntry's level. find it\n let destLevel = 0;\n if (touchingEntry) {\n destLevel = touchingLevel + 1;\n while (destLevel < levelCnt && levelCoords[destLevel] < candidateCoord) {\n destLevel += 1;\n }\n }\n // if adding to an existing level, find where to insert\n let destLateral = -1;\n if (destLevel < levelCnt && levelCoords[destLevel] === candidateCoord) {\n destLateral = binarySearch(entriesByLevel[destLevel], newEntry.span.end, getEntrySpanEnd)[0];\n }\n return {\n touchingLevel,\n touchingLateral,\n touchingEntry,\n stackCnt,\n levelCoord: candidateCoord,\n level: destLevel,\n lateral: destLateral,\n };\n }\n // sorted by levelCoord (lowest to highest)\n toRects() {\n let { entriesByLevel, levelCoords } = this;\n let levelCnt = entriesByLevel.length;\n let rects = [];\n for (let level = 0; level < levelCnt; level += 1) {\n let entries = entriesByLevel[level];\n let levelCoord = levelCoords[level];\n for (let entry of entries) {\n rects.push(Object.assign(Object.assign({}, entry), { thickness: this.getEntryThickness(entry), levelCoord }));\n }\n }\n return rects;\n }\n}\nfunction getEntrySpanEnd(entry) {\n return entry.span.end;\n}\nfunction buildEntryKey(entry) {\n return entry.index + ':' + entry.span.start;\n}\n// returns groups with entries sorted by input order\nfunction groupIntersectingEntries(entries) {\n let merges = [];\n for (let entry of entries) {\n let filteredMerges = [];\n let hungryMerge = {\n span: entry.span,\n entries: [entry],\n };\n for (let merge of merges) {\n if (intersectSpans(merge.span, hungryMerge.span)) {\n hungryMerge = {\n entries: merge.entries.concat(hungryMerge.entries),\n span: joinSpans(merge.span, hungryMerge.span),\n };\n }\n else {\n filteredMerges.push(merge);\n }\n }\n filteredMerges.push(hungryMerge);\n merges = filteredMerges;\n }\n return merges;\n}\nfunction joinSpans(span0, span1) {\n return {\n start: Math.min(span0.start, span1.start),\n end: Math.max(span0.end, span1.end),\n };\n}\nfunction intersectSpans(span0, span1) {\n let start = Math.max(span0.start, span1.start);\n let end = Math.min(span0.end, span1.end);\n if (start < end) {\n return { start, end };\n }\n return null;\n}\n// general util\n// ---------------------------------------------------------------------------------------------------------------------\nfunction insertAt(arr, index, item) {\n arr.splice(index, 0, item);\n}\nfunction binarySearch(a, searchVal, getItemVal) {\n let startIndex = 0;\n let endIndex = a.length; // exclusive\n if (!endIndex || searchVal < getItemVal(a[startIndex])) { // no items OR before first item\n return [0, 0];\n }\n if (searchVal > getItemVal(a[endIndex - 1])) { // after last item\n return [endIndex, 0];\n }\n while (startIndex < endIndex) {\n let middleIndex = Math.floor(startIndex + (endIndex - startIndex) / 2);\n let middleVal = getItemVal(a[middleIndex]);\n if (searchVal < middleVal) {\n endIndex = middleIndex;\n }\n else if (searchVal > middleVal) {\n startIndex = middleIndex + 1;\n }\n else { // equal!\n return [middleIndex, 1];\n }\n }\n return [startIndex, 0];\n}\n\n/*\nAn abstraction for a dragging interaction originating on an event.\nDoes higher-level things than PointerDragger, such as possibly:\n- a \"mirror\" that moves with the pointer\n- a minimum number of pixels or other criteria for a true drag to begin\n\nsubclasses must emit:\n- pointerdown\n- dragstart\n- dragmove\n- pointerup\n- dragend\n*/\nclass ElementDragging {\n constructor(el, selector) {\n this.emitter = new Emitter();\n }\n destroy() {\n }\n setMirrorIsVisible(bool) {\n // optional if subclass doesn't want to support a mirror\n }\n setMirrorNeedsRevert(bool) {\n // optional if subclass doesn't want to support a mirror\n }\n setAutoScrollEnabled(bool) {\n // optional\n }\n}\n\n// TODO: get rid of this in favor of options system,\n// tho it's really easy to access this globally rather than pass thru options.\nconst config = {};\n\n/*\nInformation about what will happen when an external element is dragged-and-dropped\nonto a calendar. Contains information for creating an event.\n*/\nconst DRAG_META_REFINERS = {\n startTime: createDuration,\n duration: createDuration,\n create: Boolean,\n sourceId: String,\n};\nfunction parseDragMeta(raw) {\n let { refined, extra } = refineProps(raw, DRAG_META_REFINERS);\n return {\n startTime: refined.startTime || null,\n duration: refined.duration || null,\n create: refined.create != null ? refined.create : true,\n sourceId: refined.sourceId,\n leftoverProps: extra,\n };\n}\n\n// Computes a default column header formatting string if `colFormat` is not explicitly defined\nfunction computeFallbackHeaderFormat(datesRepDistinctDays, dayCnt) {\n // if more than one week row, or if there are a lot of columns with not much space,\n // put just the day numbers will be in each cell\n if (!datesRepDistinctDays || dayCnt > 10) {\n return createFormatter({ weekday: 'short' }); // \"Sat\"\n }\n if (dayCnt > 1) {\n return createFormatter({ weekday: 'short', month: 'numeric', day: 'numeric', omitCommas: true }); // \"Sat 11/12\"\n }\n return createFormatter({ weekday: 'long' }); // \"Saturday\"\n}\n\nconst CLASS_NAME = 'fc-col-header-cell'; // do the cushion too? no\nfunction renderInner$1(renderProps) {\n return renderProps.text;\n}\n\n// BAD name for this class now. used in the Header\nclass TableDateCell extends BaseComponent {\n render() {\n let { dateEnv, options, theme, viewApi } = this.context;\n let { props } = this;\n let { date, dateProfile } = props;\n let dayMeta = getDateMeta(date, props.todayRange, null, dateProfile);\n let classNames = [CLASS_NAME].concat(getDayClassNames(dayMeta, theme));\n let text = dateEnv.format(date, props.dayHeaderFormat);\n // if colCnt is 1, we are already in a day-view and don't need a navlink\n let navLinkAttrs = (!dayMeta.isDisabled && props.colCnt > 1)\n ? buildNavLinkAttrs(this.context, date)\n : {};\n let publicDate = dateEnv.toDate(date);\n // workaround for Luxon (and maybe moment) returning prior-days when start-of-day\n // in DST gap: https://github.com/fullcalendar/fullcalendar/issues/7633\n if (dateEnv.namedTimeZoneImpl) {\n publicDate = addMs(publicDate, 3600000); // add an hour\n }\n let renderProps = Object.assign(Object.assign(Object.assign({ date: publicDate, view: viewApi }, props.extraRenderProps), { text }), dayMeta);\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(ContentContainer, { elTag: \"th\", elClasses: classNames, elAttrs: Object.assign({ role: 'columnheader', colSpan: props.colSpan, 'data-date': !dayMeta.isDisabled ? formatDayString(date) : undefined }, props.extraDataAttrs), renderProps: renderProps, generatorName: \"dayHeaderContent\", customGenerator: options.dayHeaderContent, defaultGenerator: renderInner$1, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount }, (InnerContainer) => ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"div\", { className: \"fc-scrollgrid-sync-inner\" }, !dayMeta.isDisabled && ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(InnerContainer, { elTag: \"a\", elAttrs: navLinkAttrs, elClasses: [\n 'fc-col-header-cell-cushion',\n props.isSticky && 'fc-sticky',\n ] }))))));\n }\n}\n\nconst WEEKDAY_FORMAT = createFormatter({ weekday: 'long' });\nclass TableDowCell extends BaseComponent {\n render() {\n let { props } = this;\n let { dateEnv, theme, viewApi, options } = this.context;\n let date = addDays(new Date(259200000), props.dow); // start with Sun, 04 Jan 1970 00:00:00 GMT\n let dateMeta = {\n dow: props.dow,\n isDisabled: false,\n isFuture: false,\n isPast: false,\n isToday: false,\n isOther: false,\n };\n let text = dateEnv.format(date, props.dayHeaderFormat);\n let renderProps = Object.assign(Object.assign(Object.assign(Object.assign({ // TODO: make this public?\n date }, dateMeta), { view: viewApi }), props.extraRenderProps), { text });\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(ContentContainer, { elTag: \"th\", elClasses: [\n CLASS_NAME,\n ...getDayClassNames(dateMeta, theme),\n ...(props.extraClassNames || []),\n ], elAttrs: Object.assign({ role: 'columnheader', colSpan: props.colSpan }, props.extraDataAttrs), renderProps: renderProps, generatorName: \"dayHeaderContent\", customGenerator: options.dayHeaderContent, defaultGenerator: renderInner$1, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount }, (InnerContent) => ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"div\", { className: \"fc-scrollgrid-sync-inner\" },\n (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(InnerContent, { elTag: \"a\", elClasses: [\n 'fc-col-header-cell-cushion',\n props.isSticky && 'fc-sticky',\n ], elAttrs: {\n 'aria-label': dateEnv.format(date, WEEKDAY_FORMAT),\n } })))));\n }\n}\n\nclass DayHeader extends BaseComponent {\n constructor() {\n super(...arguments);\n this.createDayHeaderFormatter = memoize(createDayHeaderFormatter);\n }\n render() {\n let { context } = this;\n let { dates, dateProfile, datesRepDistinctDays, renderIntro } = this.props;\n let dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, datesRepDistinctDays, dates.length);\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(NowTimer, { unit: \"day\" }, (nowDate, todayRange) => ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"tr\", { role: \"row\" },\n renderIntro && renderIntro('day'),\n dates.map((date) => (datesRepDistinctDays ? ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(TableDateCell, { key: date.toISOString(), date: date, dateProfile: dateProfile, todayRange: todayRange, colCnt: dates.length, dayHeaderFormat: dayHeaderFormat })) : ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(TableDowCell, { key: date.getUTCDay(), dow: date.getUTCDay(), dayHeaderFormat: dayHeaderFormat }))))))));\n }\n}\nfunction createDayHeaderFormatter(explicitFormat, datesRepDistinctDays, dateCnt) {\n return explicitFormat || computeFallbackHeaderFormat(datesRepDistinctDays, dateCnt);\n}\n\nclass DaySeriesModel {\n constructor(range, dateProfileGenerator) {\n let date = range.start;\n let { end } = range;\n let indices = [];\n let dates = [];\n let dayIndex = -1;\n while (date < end) { // loop each day from start to end\n if (dateProfileGenerator.isHiddenDay(date)) {\n indices.push(dayIndex + 0.5); // mark that it's between indices\n }\n else {\n dayIndex += 1;\n indices.push(dayIndex);\n dates.push(date);\n }\n date = addDays(date, 1);\n }\n this.dates = dates;\n this.indices = indices;\n this.cnt = dates.length;\n }\n sliceRange(range) {\n let firstIndex = this.getDateDayIndex(range.start); // inclusive first index\n let lastIndex = this.getDateDayIndex(addDays(range.end, -1)); // inclusive last index\n let clippedFirstIndex = Math.max(0, firstIndex);\n let clippedLastIndex = Math.min(this.cnt - 1, lastIndex);\n // deal with in-between indices\n clippedFirstIndex = Math.ceil(clippedFirstIndex); // in-between starts round to next cell\n clippedLastIndex = Math.floor(clippedLastIndex); // in-between ends round to prev cell\n if (clippedFirstIndex <= clippedLastIndex) {\n return {\n firstIndex: clippedFirstIndex,\n lastIndex: clippedLastIndex,\n isStart: firstIndex === clippedFirstIndex,\n isEnd: lastIndex === clippedLastIndex,\n };\n }\n return null;\n }\n // Given a date, returns its chronolocial cell-index from the first cell of the grid.\n // If the date lies between cells (because of hiddenDays), returns a floating-point value between offsets.\n // If before the first offset, returns a negative number.\n // If after the last offset, returns an offset past the last cell offset.\n // Only works for *start* dates of cells. Will not work for exclusive end dates for cells.\n getDateDayIndex(date) {\n let { indices } = this;\n let dayOffset = Math.floor(diffDays(this.dates[0], date));\n if (dayOffset < 0) {\n return indices[0] - 1;\n }\n if (dayOffset >= indices.length) {\n return indices[indices.length - 1] + 1;\n }\n return indices[dayOffset];\n }\n}\n\nclass DayTableModel {\n constructor(daySeries, breakOnWeeks) {\n let { dates } = daySeries;\n let daysPerRow;\n let firstDay;\n let rowCnt;\n if (breakOnWeeks) {\n // count columns until the day-of-week repeats\n firstDay = dates[0].getUTCDay();\n for (daysPerRow = 1; daysPerRow < dates.length; daysPerRow += 1) {\n if (dates[daysPerRow].getUTCDay() === firstDay) {\n break;\n }\n }\n rowCnt = Math.ceil(dates.length / daysPerRow);\n }\n else {\n rowCnt = 1;\n daysPerRow = dates.length;\n }\n this.rowCnt = rowCnt;\n this.colCnt = daysPerRow;\n this.daySeries = daySeries;\n this.cells = this.buildCells();\n this.headerDates = this.buildHeaderDates();\n }\n buildCells() {\n let rows = [];\n for (let row = 0; row < this.rowCnt; row += 1) {\n let cells = [];\n for (let col = 0; col < this.colCnt; col += 1) {\n cells.push(this.buildCell(row, col));\n }\n rows.push(cells);\n }\n return rows;\n }\n buildCell(row, col) {\n let date = this.daySeries.dates[row * this.colCnt + col];\n return {\n key: date.toISOString(),\n date,\n };\n }\n buildHeaderDates() {\n let dates = [];\n for (let col = 0; col < this.colCnt; col += 1) {\n dates.push(this.cells[0][col].date);\n }\n return dates;\n }\n sliceRange(range) {\n let { colCnt } = this;\n let seriesSeg = this.daySeries.sliceRange(range);\n let segs = [];\n if (seriesSeg) {\n let { firstIndex, lastIndex } = seriesSeg;\n let index = firstIndex;\n while (index <= lastIndex) {\n let row = Math.floor(index / colCnt);\n let nextIndex = Math.min((row + 1) * colCnt, lastIndex + 1);\n segs.push({\n row,\n firstCol: index % colCnt,\n lastCol: (nextIndex - 1) % colCnt,\n isStart: seriesSeg.isStart && index === firstIndex,\n isEnd: seriesSeg.isEnd && (nextIndex - 1) === lastIndex,\n });\n index = nextIndex;\n }\n }\n return segs;\n }\n}\n\nclass Slicer {\n constructor() {\n this.sliceBusinessHours = memoize(this._sliceBusinessHours);\n this.sliceDateSelection = memoize(this._sliceDateSpan);\n this.sliceEventStore = memoize(this._sliceEventStore);\n this.sliceEventDrag = memoize(this._sliceInteraction);\n this.sliceEventResize = memoize(this._sliceInteraction);\n this.forceDayIfListItem = false; // hack\n }\n sliceProps(props, dateProfile, nextDayThreshold, context, ...extraArgs) {\n let { eventUiBases } = props;\n let eventSegs = this.sliceEventStore(props.eventStore, eventUiBases, dateProfile, nextDayThreshold, ...extraArgs);\n return {\n dateSelectionSegs: this.sliceDateSelection(props.dateSelection, dateProfile, nextDayThreshold, eventUiBases, context, ...extraArgs),\n businessHourSegs: this.sliceBusinessHours(props.businessHours, dateProfile, nextDayThreshold, context, ...extraArgs),\n fgEventSegs: eventSegs.fg,\n bgEventSegs: eventSegs.bg,\n eventDrag: this.sliceEventDrag(props.eventDrag, eventUiBases, dateProfile, nextDayThreshold, ...extraArgs),\n eventResize: this.sliceEventResize(props.eventResize, eventUiBases, dateProfile, nextDayThreshold, ...extraArgs),\n eventSelection: props.eventSelection,\n }; // TODO: give interactionSegs?\n }\n sliceNowDate(// does not memoize\n date, dateProfile, nextDayThreshold, context, ...extraArgs) {\n return this._sliceDateSpan({ range: { start: date, end: addMs(date, 1) }, allDay: false }, // add 1 ms, protect against null range\n dateProfile, nextDayThreshold, {}, context, ...extraArgs);\n }\n _sliceBusinessHours(businessHours, dateProfile, nextDayThreshold, context, ...extraArgs) {\n if (!businessHours) {\n return [];\n }\n return this._sliceEventStore(expandRecurring(businessHours, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), context), {}, dateProfile, nextDayThreshold, ...extraArgs).bg;\n }\n _sliceEventStore(eventStore, eventUiBases, dateProfile, nextDayThreshold, ...extraArgs) {\n if (eventStore) {\n let rangeRes = sliceEventStore(eventStore, eventUiBases, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), nextDayThreshold);\n return {\n bg: this.sliceEventRanges(rangeRes.bg, extraArgs),\n fg: this.sliceEventRanges(rangeRes.fg, extraArgs),\n };\n }\n return { bg: [], fg: [] };\n }\n _sliceInteraction(interaction, eventUiBases, dateProfile, nextDayThreshold, ...extraArgs) {\n if (!interaction) {\n return null;\n }\n let rangeRes = sliceEventStore(interaction.mutatedEvents, eventUiBases, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), nextDayThreshold);\n return {\n segs: this.sliceEventRanges(rangeRes.fg, extraArgs),\n affectedInstances: interaction.affectedEvents.instances,\n isEvent: interaction.isEvent,\n };\n }\n _sliceDateSpan(dateSpan, dateProfile, nextDayThreshold, eventUiBases, context, ...extraArgs) {\n if (!dateSpan) {\n return [];\n }\n let activeRange = computeActiveRange(dateProfile, Boolean(nextDayThreshold));\n let activeDateSpanRange = intersectRanges(dateSpan.range, activeRange);\n if (activeDateSpanRange) {\n dateSpan = Object.assign(Object.assign({}, dateSpan), { range: activeDateSpanRange });\n let eventRange = fabricateEventRange(dateSpan, eventUiBases, context);\n let segs = this.sliceRange(dateSpan.range, ...extraArgs);\n for (let seg of segs) {\n seg.eventRange = eventRange;\n }\n return segs;\n }\n return [];\n }\n /*\n \"complete\" seg means it has component and eventRange\n */\n sliceEventRanges(eventRanges, extraArgs) {\n let segs = [];\n for (let eventRange of eventRanges) {\n segs.push(...this.sliceEventRange(eventRange, extraArgs));\n }\n return segs;\n }\n /*\n \"complete\" seg means it has component and eventRange\n */\n sliceEventRange(eventRange, extraArgs) {\n let dateRange = eventRange.range;\n // hack to make multi-day events that are being force-displayed as list-items to take up only one day\n if (this.forceDayIfListItem && eventRange.ui.display === 'list-item') {\n dateRange = {\n start: dateRange.start,\n end: addDays(dateRange.start, 1),\n };\n }\n let segs = this.sliceRange(dateRange, ...extraArgs);\n for (let seg of segs) {\n seg.eventRange = eventRange;\n seg.isStart = eventRange.isStart && seg.isStart;\n seg.isEnd = eventRange.isEnd && seg.isEnd;\n }\n return segs;\n }\n}\n/*\nfor incorporating slotMinTime/slotMaxTime if appropriate\nTODO: should be part of DateProfile!\nTimelineDateProfile already does this btw\n*/\nfunction computeActiveRange(dateProfile, isComponentAllDay) {\n let range = dateProfile.activeRange;\n if (isComponentAllDay) {\n return range;\n }\n return {\n start: addMs(range.start, dateProfile.slotMinTime.milliseconds),\n end: addMs(range.end, dateProfile.slotMaxTime.milliseconds - 864e5), // 864e5 = ms in a day\n };\n}\n\n// high-level segmenting-aware tester functions\n// ------------------------------------------------------------------------------------------------------------------------\nfunction isInteractionValid(interaction, dateProfile, context) {\n let { instances } = interaction.mutatedEvents;\n for (let instanceId in instances) {\n if (!rangeContainsRange(dateProfile.validRange, instances[instanceId].range)) {\n return false;\n }\n }\n return isNewPropsValid({ eventDrag: interaction }, context); // HACK: the eventDrag props is used for ALL interactions\n}\nfunction isDateSelectionValid(dateSelection, dateProfile, context) {\n if (!rangeContainsRange(dateProfile.validRange, dateSelection.range)) {\n return false;\n }\n return isNewPropsValid({ dateSelection }, context);\n}\nfunction isNewPropsValid(newProps, context) {\n let calendarState = context.getCurrentData();\n let props = Object.assign({ businessHours: calendarState.businessHours, dateSelection: '', eventStore: calendarState.eventStore, eventUiBases: calendarState.eventUiBases, eventSelection: '', eventDrag: null, eventResize: null }, newProps);\n return (context.pluginHooks.isPropsValid || isPropsValid)(props, context);\n}\nfunction isPropsValid(state, context, dateSpanMeta = {}, filterConfig) {\n if (state.eventDrag && !isInteractionPropsValid(state, context, dateSpanMeta, filterConfig)) {\n return false;\n }\n if (state.dateSelection && !isDateSelectionPropsValid(state, context, dateSpanMeta, filterConfig)) {\n return false;\n }\n return true;\n}\n// Moving Event Validation\n// ------------------------------------------------------------------------------------------------------------------------\nfunction isInteractionPropsValid(state, context, dateSpanMeta, filterConfig) {\n let currentState = context.getCurrentData();\n let interaction = state.eventDrag; // HACK: the eventDrag props is used for ALL interactions\n let subjectEventStore = interaction.mutatedEvents;\n let subjectDefs = subjectEventStore.defs;\n let subjectInstances = subjectEventStore.instances;\n let subjectConfigs = compileEventUis(subjectDefs, interaction.isEvent ?\n state.eventUiBases :\n { '': currentState.selectionConfig });\n if (filterConfig) {\n subjectConfigs = mapHash(subjectConfigs, filterConfig);\n }\n // exclude the subject events. TODO: exclude defs too?\n let otherEventStore = excludeInstances(state.eventStore, interaction.affectedEvents.instances);\n let otherDefs = otherEventStore.defs;\n let otherInstances = otherEventStore.instances;\n let otherConfigs = compileEventUis(otherDefs, state.eventUiBases);\n for (let subjectInstanceId in subjectInstances) {\n let subjectInstance = subjectInstances[subjectInstanceId];\n let subjectRange = subjectInstance.range;\n let subjectConfig = subjectConfigs[subjectInstance.defId];\n let subjectDef = subjectDefs[subjectInstance.defId];\n // constraint\n if (!allConstraintsPass(subjectConfig.constraints, subjectRange, otherEventStore, state.businessHours, context)) {\n return false;\n }\n // overlap\n let { eventOverlap } = context.options;\n let eventOverlapFunc = typeof eventOverlap === 'function' ? eventOverlap : null;\n for (let otherInstanceId in otherInstances) {\n let otherInstance = otherInstances[otherInstanceId];\n // intersect! evaluate\n if (rangesIntersect(subjectRange, otherInstance.range)) {\n let otherOverlap = otherConfigs[otherInstance.defId].overlap;\n // consider the other event's overlap. only do this if the subject event is a \"real\" event\n if (otherOverlap === false && interaction.isEvent) {\n return false;\n }\n if (subjectConfig.overlap === false) {\n return false;\n }\n if (eventOverlapFunc && !eventOverlapFunc(new EventImpl(context, otherDefs[otherInstance.defId], otherInstance), // still event\n new EventImpl(context, subjectDef, subjectInstance))) {\n return false;\n }\n }\n }\n // allow (a function)\n let calendarEventStore = currentState.eventStore; // need global-to-calendar, not local to component (splittable)state\n for (let subjectAllow of subjectConfig.allows) {\n let subjectDateSpan = Object.assign(Object.assign({}, dateSpanMeta), { range: subjectInstance.range, allDay: subjectDef.allDay });\n let origDef = calendarEventStore.defs[subjectDef.defId];\n let origInstance = calendarEventStore.instances[subjectInstanceId];\n let eventApi;\n if (origDef) { // was previously in the calendar\n eventApi = new EventImpl(context, origDef, origInstance);\n }\n else { // was an external event\n eventApi = new EventImpl(context, subjectDef); // no instance, because had no dates\n }\n if (!subjectAllow(buildDateSpanApiWithContext(subjectDateSpan, context), eventApi)) {\n return false;\n }\n }\n }\n return true;\n}\n// Date Selection Validation\n// ------------------------------------------------------------------------------------------------------------------------\nfunction isDateSelectionPropsValid(state, context, dateSpanMeta, filterConfig) {\n let relevantEventStore = state.eventStore;\n let relevantDefs = relevantEventStore.defs;\n let relevantInstances = relevantEventStore.instances;\n let selection = state.dateSelection;\n let selectionRange = selection.range;\n let { selectionConfig } = context.getCurrentData();\n if (filterConfig) {\n selectionConfig = filterConfig(selectionConfig);\n }\n // constraint\n if (!allConstraintsPass(selectionConfig.constraints, selectionRange, relevantEventStore, state.businessHours, context)) {\n return false;\n }\n // overlap\n let { selectOverlap } = context.options;\n let selectOverlapFunc = typeof selectOverlap === 'function' ? selectOverlap : null;\n for (let relevantInstanceId in relevantInstances) {\n let relevantInstance = relevantInstances[relevantInstanceId];\n // intersect! evaluate\n if (rangesIntersect(selectionRange, relevantInstance.range)) {\n if (selectionConfig.overlap === false) {\n return false;\n }\n if (selectOverlapFunc && !selectOverlapFunc(new EventImpl(context, relevantDefs[relevantInstance.defId], relevantInstance), null)) {\n return false;\n }\n }\n }\n // allow (a function)\n for (let selectionAllow of selectionConfig.allows) {\n let fullDateSpan = Object.assign(Object.assign({}, dateSpanMeta), selection);\n if (!selectionAllow(buildDateSpanApiWithContext(fullDateSpan, context), null)) {\n return false;\n }\n }\n return true;\n}\n// Constraint Utils\n// ------------------------------------------------------------------------------------------------------------------------\nfunction allConstraintsPass(constraints, subjectRange, otherEventStore, businessHoursUnexpanded, context) {\n for (let constraint of constraints) {\n if (!anyRangesContainRange(constraintToRanges(constraint, subjectRange, otherEventStore, businessHoursUnexpanded, context), subjectRange)) {\n return false;\n }\n }\n return true;\n}\nfunction constraintToRanges(constraint, subjectRange, // for expanding a recurring constraint, or expanding business hours\notherEventStore, // for if constraint is an even group ID\nbusinessHoursUnexpanded, // for if constraint is 'businessHours'\ncontext) {\n if (constraint === 'businessHours') {\n return eventStoreToRanges(expandRecurring(businessHoursUnexpanded, subjectRange, context));\n }\n if (typeof constraint === 'string') { // an group ID\n return eventStoreToRanges(filterEventStoreDefs(otherEventStore, (eventDef) => eventDef.groupId === constraint));\n }\n if (typeof constraint === 'object' && constraint) { // non-null object\n return eventStoreToRanges(expandRecurring(constraint, subjectRange, context));\n }\n return []; // if it's false\n}\n// TODO: move to event-store file?\nfunction eventStoreToRanges(eventStore) {\n let { instances } = eventStore;\n let ranges = [];\n for (let instanceId in instances) {\n ranges.push(instances[instanceId].range);\n }\n return ranges;\n}\n// TODO: move to geom file?\nfunction anyRangesContainRange(outerRanges, innerRange) {\n for (let outerRange of outerRanges) {\n if (rangeContainsRange(outerRange, innerRange)) {\n return true;\n }\n }\n return false;\n}\n\nconst VISIBLE_HIDDEN_RE = /^(visible|hidden)$/;\nclass Scroller extends BaseComponent {\n constructor() {\n super(...arguments);\n this.handleEl = (el) => {\n this.el = el;\n setRef(this.props.elRef, el);\n };\n }\n render() {\n let { props } = this;\n let { liquid, liquidIsAbsolute } = props;\n let isAbsolute = liquid && liquidIsAbsolute;\n let className = ['fc-scroller'];\n if (liquid) {\n if (liquidIsAbsolute) {\n className.push('fc-scroller-liquid-absolute');\n }\n else {\n className.push('fc-scroller-liquid');\n }\n }\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"div\", { ref: this.handleEl, className: className.join(' '), style: {\n overflowX: props.overflowX,\n overflowY: props.overflowY,\n left: (isAbsolute && -(props.overcomeLeft || 0)) || '',\n right: (isAbsolute && -(props.overcomeRight || 0)) || '',\n bottom: (isAbsolute && -(props.overcomeBottom || 0)) || '',\n marginLeft: (!isAbsolute && -(props.overcomeLeft || 0)) || '',\n marginRight: (!isAbsolute && -(props.overcomeRight || 0)) || '',\n marginBottom: (!isAbsolute && -(props.overcomeBottom || 0)) || '',\n maxHeight: props.maxHeight || '',\n } }, props.children));\n }\n needsXScrolling() {\n if (VISIBLE_HIDDEN_RE.test(this.props.overflowX)) {\n return false;\n }\n // testing scrollWidth>clientWidth is unreliable cross-browser when pixel heights aren't integers.\n // much more reliable to see if children are taller than the scroller, even tho doesn't account for\n // inner-child margins and absolute positioning\n let { el } = this;\n let realClientWidth = this.el.getBoundingClientRect().width - this.getYScrollbarWidth();\n let { children } = el;\n for (let i = 0; i < children.length; i += 1) {\n let childEl = children[i];\n if (childEl.getBoundingClientRect().width > realClientWidth) {\n return true;\n }\n }\n return false;\n }\n needsYScrolling() {\n if (VISIBLE_HIDDEN_RE.test(this.props.overflowY)) {\n return false;\n }\n // testing scrollHeight>clientHeight is unreliable cross-browser when pixel heights aren't integers.\n // much more reliable to see if children are taller than the scroller, even tho doesn't account for\n // inner-child margins and absolute positioning\n let { el } = this;\n let realClientHeight = this.el.getBoundingClientRect().height - this.getXScrollbarWidth();\n let { children } = el;\n for (let i = 0; i < children.length; i += 1) {\n let childEl = children[i];\n if (childEl.getBoundingClientRect().height > realClientHeight) {\n return true;\n }\n }\n return false;\n }\n getXScrollbarWidth() {\n if (VISIBLE_HIDDEN_RE.test(this.props.overflowX)) {\n return 0;\n }\n return this.el.offsetHeight - this.el.clientHeight; // only works because we guarantee no borders. TODO: add to CSS with important?\n }\n getYScrollbarWidth() {\n if (VISIBLE_HIDDEN_RE.test(this.props.overflowY)) {\n return 0;\n }\n return this.el.offsetWidth - this.el.clientWidth; // only works because we guarantee no borders. TODO: add to CSS with important?\n }\n}\n\n/*\nTODO: somehow infer OtherArgs from masterCallback?\nTODO: infer RefType from masterCallback if provided\n*/\nclass RefMap {\n constructor(masterCallback) {\n this.masterCallback = masterCallback;\n this.currentMap = {};\n this.depths = {};\n this.callbackMap = {};\n this.handleValue = (val, key) => {\n let { depths, currentMap } = this;\n let removed = false;\n let added = false;\n if (val !== null) {\n // for bug... ACTUALLY: can probably do away with this now that callers don't share numeric indices anymore\n removed = (key in currentMap);\n currentMap[key] = val;\n depths[key] = (depths[key] || 0) + 1;\n added = true;\n }\n else {\n depths[key] -= 1;\n if (!depths[key]) {\n delete currentMap[key];\n delete this.callbackMap[key];\n removed = true;\n }\n }\n if (this.masterCallback) {\n if (removed) {\n this.masterCallback(null, String(key));\n }\n if (added) {\n this.masterCallback(val, String(key));\n }\n }\n };\n }\n createRef(key) {\n let refCallback = this.callbackMap[key];\n if (!refCallback) {\n refCallback = this.callbackMap[key] = (val) => {\n this.handleValue(val, String(key));\n };\n }\n return refCallback;\n }\n // TODO: check callers that don't care about order. should use getAll instead\n // NOTE: this method has become less valuable now that we are encouraged to map order by some other index\n // TODO: provide ONE array-export function, buildArray, which fails on non-numeric indexes. caller can manipulate and \"collect\"\n collect(startIndex, endIndex, step) {\n return collectFromHash(this.currentMap, startIndex, endIndex, step);\n }\n getAll() {\n return hashValuesToArray(this.currentMap);\n }\n}\n\nfunction computeShrinkWidth(chunkEls) {\n let shrinkCells = findElements(chunkEls, '.fc-scrollgrid-shrink');\n let largestWidth = 0;\n for (let shrinkCell of shrinkCells) {\n largestWidth = Math.max(largestWidth, computeSmallestCellWidth(shrinkCell));\n }\n return Math.ceil(largestWidth); // <table> elements work best with integers. round up to ensure contents fits\n}\nfunction getSectionHasLiquidHeight(props, sectionConfig) {\n return props.liquid && sectionConfig.liquid; // does the section do liquid-height? (need to have whole scrollgrid liquid-height as well)\n}\nfunction getAllowYScrolling(props, sectionConfig) {\n return sectionConfig.maxHeight != null || // if its possible for the height to max out, we might need scrollbars\n getSectionHasLiquidHeight(props, sectionConfig); // if the section is liquid height, it might condense enough to require scrollbars\n}\n// TODO: ONLY use `arg`. force out internal function to use same API\nfunction renderChunkContent(sectionConfig, chunkConfig, arg, isHeader) {\n let { expandRows } = arg;\n let content = typeof chunkConfig.content === 'function' ?\n chunkConfig.content(arg) :\n (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)('table', {\n role: 'presentation',\n className: [\n chunkConfig.tableClassName,\n sectionConfig.syncRowHeights ? 'fc-scrollgrid-sync-table' : '',\n ].join(' '),\n style: {\n minWidth: arg.tableMinWidth,\n width: arg.clientWidth,\n height: expandRows ? arg.clientHeight : '', // css `height` on a <table> serves as a min-height\n },\n }, arg.tableColGroupNode, (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(isHeader ? 'thead' : 'tbody', {\n role: 'presentation',\n }, typeof chunkConfig.rowContent === 'function'\n ? chunkConfig.rowContent(arg)\n : chunkConfig.rowContent));\n return content;\n}\nfunction isColPropsEqual(cols0, cols1) {\n return isArraysEqual(cols0, cols1, isPropsEqual);\n}\nfunction renderMicroColGroup(cols, shrinkWidth) {\n let colNodes = [];\n /*\n for ColProps with spans, it would have been great to make a single <col span=\"\">\n HOWEVER, Chrome was getting messing up distributing the width to <td>/<th> elements with colspans.\n SOLUTION: making individual <col> elements makes Chrome behave.\n */\n for (let colProps of cols) {\n let span = colProps.span || 1;\n for (let i = 0; i < span; i += 1) {\n colNodes.push((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"col\", { style: {\n width: colProps.width === 'shrink' ? sanitizeShrinkWidth(shrinkWidth) : (colProps.width || ''),\n minWidth: colProps.minWidth || '',\n } }));\n }\n }\n return (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)('colgroup', {}, ...colNodes);\n}\nfunction sanitizeShrinkWidth(shrinkWidth) {\n /* why 4? if we do 0, it will kill any border, which are needed for computeSmallestCellWidth\n 4 accounts for 2 2-pixel borders. TODO: better solution? */\n return shrinkWidth == null ? 4 : shrinkWidth;\n}\nfunction hasShrinkWidth(cols) {\n for (let col of cols) {\n if (col.width === 'shrink') {\n return true;\n }\n }\n return false;\n}\nfunction getScrollGridClassNames(liquid, context) {\n let classNames = [\n 'fc-scrollgrid',\n context.theme.getClass('table'),\n ];\n if (liquid) {\n classNames.push('fc-scrollgrid-liquid');\n }\n return classNames;\n}\nfunction getSectionClassNames(sectionConfig, wholeTableVGrow) {\n let classNames = [\n 'fc-scrollgrid-section',\n `fc-scrollgrid-section-${sectionConfig.type}`,\n sectionConfig.className, // used?\n ];\n if (wholeTableVGrow && sectionConfig.liquid && sectionConfig.maxHeight == null) {\n classNames.push('fc-scrollgrid-section-liquid');\n }\n if (sectionConfig.isSticky) {\n classNames.push('fc-scrollgrid-section-sticky');\n }\n return classNames;\n}\nfunction renderScrollShim(arg) {\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"div\", { className: \"fc-scrollgrid-sticky-shim\", style: {\n width: arg.clientWidth,\n minWidth: arg.tableMinWidth,\n } }));\n}\nfunction getStickyHeaderDates(options) {\n let { stickyHeaderDates } = options;\n if (stickyHeaderDates == null || stickyHeaderDates === 'auto') {\n stickyHeaderDates = options.height === 'auto' || options.viewHeight === 'auto';\n }\n return stickyHeaderDates;\n}\nfunction getStickyFooterScrollbar(options) {\n let { stickyFooterScrollbar } = options;\n if (stickyFooterScrollbar == null || stickyFooterScrollbar === 'auto') {\n stickyFooterScrollbar = options.height === 'auto' || options.viewHeight === 'auto';\n }\n return stickyFooterScrollbar;\n}\n\nclass SimpleScrollGrid extends BaseComponent {\n constructor() {\n super(...arguments);\n this.processCols = memoize((a) => a, isColPropsEqual); // so we get same `cols` props every time\n // yucky to memoize VNodes, but much more efficient for consumers\n this.renderMicroColGroup = memoize(renderMicroColGroup);\n this.scrollerRefs = new RefMap();\n this.scrollerElRefs = new RefMap(this._handleScrollerEl.bind(this));\n this.state = {\n shrinkWidth: null,\n forceYScrollbars: false,\n scrollerClientWidths: {},\n scrollerClientHeights: {},\n };\n // TODO: can do a really simple print-view. dont need to join rows\n this.handleSizing = () => {\n this.safeSetState(Object.assign({ shrinkWidth: this.computeShrinkWidth() }, this.computeScrollerDims()));\n };\n }\n render() {\n let { props, state, context } = this;\n let sectionConfigs = props.sections || [];\n let cols = this.processCols(props.cols);\n let microColGroupNode = this.renderMicroColGroup(cols, state.shrinkWidth);\n let classNames = getScrollGridClassNames(props.liquid, context);\n if (props.collapsibleWidth) {\n classNames.push('fc-scrollgrid-collapsible');\n }\n // TODO: make DRY\n let configCnt = sectionConfigs.length;\n let configI = 0;\n let currentConfig;\n let headSectionNodes = [];\n let bodySectionNodes = [];\n let footSectionNodes = [];\n while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'header') {\n headSectionNodes.push(this.renderSection(currentConfig, microColGroupNode, true));\n configI += 1;\n }\n while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'body') {\n bodySectionNodes.push(this.renderSection(currentConfig, microColGroupNode, false));\n configI += 1;\n }\n while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'footer') {\n footSectionNodes.push(this.renderSection(currentConfig, microColGroupNode, true));\n configI += 1;\n }\n // firefox bug: when setting height on table and there is a thead or tfoot,\n // the necessary height:100% on the liquid-height body section forces the *whole* table to be taller. (bug #5524)\n // use getCanVGrowWithinCell as a way to detect table-stupid firefox.\n // if so, use a simpler dom structure, jam everything into a lone tbody.\n let isBuggy = !getCanVGrowWithinCell();\n const roleAttrs = { role: 'rowgroup' };\n return (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)('table', {\n role: 'grid',\n className: classNames.join(' '),\n style: { height: props.height },\n }, Boolean(!isBuggy && headSectionNodes.length) && (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)('thead', roleAttrs, ...headSectionNodes), Boolean(!isBuggy && bodySectionNodes.length) && (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)('tbody', roleAttrs, ...bodySectionNodes), Boolean(!isBuggy && footSectionNodes.length) && (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)('tfoot', roleAttrs, ...footSectionNodes), isBuggy && (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)('tbody', roleAttrs, ...headSectionNodes, ...bodySectionNodes, ...footSectionNodes));\n }\n renderSection(sectionConfig, microColGroupNode, isHeader) {\n if ('outerContent' in sectionConfig) {\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(preact__WEBPACK_IMPORTED_MODULE_0__.Fragment, { key: sectionConfig.key }, sectionConfig.outerContent));\n }\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"tr\", { key: sectionConfig.key, role: \"presentation\", className: getSectionClassNames(sectionConfig, this.props.liquid).join(' ') }, this.renderChunkTd(sectionConfig, microColGroupNode, sectionConfig.chunk, isHeader)));\n }\n renderChunkTd(sectionConfig, microColGroupNode, chunkConfig, isHeader) {\n if ('outerContent' in chunkConfig) {\n return chunkConfig.outerContent;\n }\n let { props } = this;\n let { forceYScrollbars, scrollerClientWidths, scrollerClientHeights } = this.state;\n let needsYScrolling = getAllowYScrolling(props, sectionConfig); // TODO: do lazily. do in section config?\n let isLiquid = getSectionHasLiquidHeight(props, sectionConfig);\n // for `!props.liquid` - is WHOLE scrollgrid natural height?\n // TODO: do same thing in advanced scrollgrid? prolly not b/c always has horizontal scrollbars\n let overflowY = !props.liquid ? 'visible' :\n forceYScrollbars ? 'scroll' :\n !needsYScrolling ? 'hidden' :\n 'auto';\n let sectionKey = sectionConfig.key;\n let content = renderChunkContent(sectionConfig, chunkConfig, {\n tableColGroupNode: microColGroupNode,\n tableMinWidth: '',\n clientWidth: (!props.collapsibleWidth && scrollerClientWidths[sectionKey] !== undefined) ? scrollerClientWidths[sectionKey] : null,\n clientHeight: scrollerClientHeights[sectionKey] !== undefined ? scrollerClientHeights[sectionKey] : null,\n expandRows: sectionConfig.expandRows,\n syncRowHeights: false,\n rowSyncHeights: [],\n reportRowHeightChange: () => { },\n }, isHeader);\n return (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(isHeader ? 'th' : 'td', {\n ref: chunkConfig.elRef,\n role: 'presentation',\n }, (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"div\", { className: `fc-scroller-harness${isLiquid ? ' fc-scroller-harness-liquid' : ''}` },\n (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(Scroller, { ref: this.scrollerRefs.createRef(sectionKey), elRef: this.scrollerElRefs.createRef(sectionKey), overflowY: overflowY, overflowX: !props.liquid ? 'visible' : 'hidden' /* natural height? */, maxHeight: sectionConfig.maxHeight, liquid: isLiquid, liquidIsAbsolute // because its within a harness\n : true }, content)));\n }\n _handleScrollerEl(scrollerEl, key) {\n let section = getSectionByKey(this.props.sections, key);\n if (section) {\n setRef(section.chunk.scrollerElRef, scrollerEl);\n }\n }\n componentDidMount() {\n this.handleSizing();\n this.context.addResizeHandler(this.handleSizing);\n }\n componentDidUpdate() {\n // TODO: need better solution when state contains non-sizing things\n this.handleSizing();\n }\n componentWillUnmount() {\n this.context.removeResizeHandler(this.handleSizing);\n }\n computeShrinkWidth() {\n return hasShrinkWidth(this.props.cols)\n ? computeShrinkWidth(this.scrollerElRefs.getAll())\n : 0;\n }\n computeScrollerDims() {\n let scrollbarWidth = getScrollbarWidths();\n let { scrollerRefs, scrollerElRefs } = this;\n let forceYScrollbars = false;\n let scrollerClientWidths = {};\n let scrollerClientHeights = {};\n for (let sectionKey in scrollerRefs.currentMap) {\n let scroller = scrollerRefs.currentMap[sectionKey];\n if (scroller && scroller.needsYScrolling()) {\n forceYScrollbars = true;\n break;\n }\n }\n for (let section of this.props.sections) {\n let sectionKey = section.key;\n let scrollerEl = scrollerElRefs.currentMap[sectionKey];\n if (scrollerEl) {\n let harnessEl = scrollerEl.parentNode; // TODO: weird way to get this. need harness b/c doesn't include table borders\n scrollerClientWidths[sectionKey] = Math.floor(harnessEl.getBoundingClientRect().width - (forceYScrollbars\n ? scrollbarWidth.y // use global because scroller might not have scrollbars yet but will need them in future\n : 0));\n scrollerClientHeights[sectionKey] = Math.floor(harnessEl.getBoundingClientRect().height);\n }\n }\n return { forceYScrollbars, scrollerClientWidths, scrollerClientHeights };\n }\n}\nSimpleScrollGrid.addStateEquality({\n scrollerClientWidths: isPropsEqual,\n scrollerClientHeights: isPropsEqual,\n});\nfunction getSectionByKey(sections, key) {\n for (let section of sections) {\n if (section.key === key) {\n return section;\n }\n }\n return null;\n}\n\nclass EventContainer extends BaseComponent {\n constructor() {\n super(...arguments);\n // memo\n this.buildPublicEvent = memoize((context, eventDef, eventInstance) => new EventImpl(context, eventDef, eventInstance));\n this.handleEl = (el) => {\n this.el = el;\n setRef(this.props.elRef, el);\n if (el) {\n setElSeg(el, this.props.seg);\n }\n };\n }\n render() {\n const { props, context } = this;\n const { options } = context;\n const { seg } = props;\n const { eventRange } = seg;\n const { ui } = eventRange;\n const renderProps = {\n event: this.buildPublicEvent(context, eventRange.def, eventRange.instance),\n view: context.viewApi,\n timeText: props.timeText,\n textColor: ui.textColor,\n backgroundColor: ui.backgroundColor,\n borderColor: ui.borderColor,\n isDraggable: !props.disableDragging && computeSegDraggable(seg, context),\n isStartResizable: !props.disableResizing && computeSegStartResizable(seg, context),\n isEndResizable: !props.disableResizing && computeSegEndResizable(seg),\n isMirror: Boolean(props.isDragging || props.isResizing || props.isDateSelecting),\n isStart: Boolean(seg.isStart),\n isEnd: Boolean(seg.isEnd),\n isPast: Boolean(props.isPast),\n isFuture: Boolean(props.isFuture),\n isToday: Boolean(props.isToday),\n isSelected: Boolean(props.isSelected),\n isDragging: Boolean(props.isDragging),\n isResizing: Boolean(props.isResizing),\n };\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(ContentContainer, { elRef: this.handleEl, elTag: props.elTag, elAttrs: props.elAttrs, elClasses: [\n ...getEventClassNames(renderProps),\n ...seg.eventRange.ui.classNames,\n ...(props.elClasses || []),\n ], elStyle: props.elStyle, renderProps: renderProps, generatorName: \"eventContent\", customGenerator: options.eventContent, defaultGenerator: props.defaultGenerator, classNameGenerator: options.eventClassNames, didMount: options.eventDidMount, willUnmount: options.eventWillUnmount }, props.children));\n }\n componentDidUpdate(prevProps) {\n if (this.el && this.props.seg !== prevProps.seg) {\n setElSeg(this.el, this.props.seg);\n }\n }\n}\n\n// should not be a purecomponent\nclass StandardEvent extends BaseComponent {\n render() {\n let { props, context } = this;\n let { options } = context;\n let { seg } = props;\n let { ui } = seg.eventRange;\n let timeFormat = options.eventTimeFormat || props.defaultTimeFormat;\n let timeText = buildSegTimeText(seg, timeFormat, context, props.defaultDisplayEventTime, props.defaultDisplayEventEnd);\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(EventContainer, Object.assign({}, props /* includes elRef */, { elTag: \"a\", elStyle: {\n borderColor: ui.borderColor,\n backgroundColor: ui.backgroundColor,\n }, elAttrs: getSegAnchorAttrs(seg, context), defaultGenerator: renderInnerContent$1, timeText: timeText }), (InnerContent, eventContentArg) => ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(preact__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(InnerContent, { elTag: \"div\", elClasses: ['fc-event-main'], elStyle: { color: eventContentArg.textColor } }),\n Boolean(eventContentArg.isStartResizable) && ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"div\", { className: \"fc-event-resizer fc-event-resizer-start\" })),\n Boolean(eventContentArg.isEndResizable) && ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"div\", { className: \"fc-event-resizer fc-event-resizer-end\" }))))));\n }\n}\nStandardEvent.addPropsEquality({\n seg: isPropsEqual,\n});\nfunction renderInnerContent$1(innerProps) {\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"div\", { className: \"fc-event-main-frame\" },\n innerProps.timeText && ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"div\", { className: \"fc-event-time\" }, innerProps.timeText)),\n (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"div\", { className: \"fc-event-title-container\" },\n (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"div\", { className: \"fc-event-title fc-sticky\" }, innerProps.event.title || (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(preact__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, \"\\u00A0\")))));\n}\n\nconst NowIndicatorContainer = (props) => ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(ViewContextType.Consumer, null, (context) => {\n let { options } = context;\n let renderProps = {\n isAxis: props.isAxis,\n date: context.dateEnv.toDate(props.date),\n view: context.viewApi,\n };\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(ContentContainer, { elRef: props.elRef, elTag: props.elTag || 'div', elAttrs: props.elAttrs, elClasses: props.elClasses, elStyle: props.elStyle, renderProps: renderProps, generatorName: \"nowIndicatorContent\", customGenerator: options.nowIndicatorContent, classNameGenerator: options.nowIndicatorClassNames, didMount: options.nowIndicatorDidMount, willUnmount: options.nowIndicatorWillUnmount }, props.children));\n}));\n\nconst DAY_NUM_FORMAT = createFormatter({ day: 'numeric' });\nclass DayCellContainer extends BaseComponent {\n constructor() {\n super(...arguments);\n this.refineRenderProps = memoizeObjArg(refineRenderProps);\n }\n render() {\n let { props, context } = this;\n let { options } = context;\n let renderProps = this.refineRenderProps({\n date: props.date,\n dateProfile: props.dateProfile,\n todayRange: props.todayRange,\n isMonthStart: props.isMonthStart || false,\n showDayNumber: props.showDayNumber,\n extraRenderProps: props.extraRenderProps,\n viewApi: context.viewApi,\n dateEnv: context.dateEnv,\n monthStartFormat: options.monthStartFormat,\n });\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(ContentContainer, { elRef: props.elRef, elTag: props.elTag, elAttrs: Object.assign(Object.assign({}, props.elAttrs), (renderProps.isDisabled ? {} : { 'data-date': formatDayString(props.date) })), elClasses: [\n ...getDayClassNames(renderProps, context.theme),\n ...(props.elClasses || []),\n ], elStyle: props.elStyle, renderProps: renderProps, generatorName: \"dayCellContent\", customGenerator: options.dayCellContent, defaultGenerator: props.defaultGenerator, classNameGenerator: \n // don't use custom classNames if disabled\n renderProps.isDisabled ? undefined : options.dayCellClassNames, didMount: options.dayCellDidMount, willUnmount: options.dayCellWillUnmount }, props.children));\n }\n}\nfunction hasCustomDayCellContent(options) {\n return Boolean(options.dayCellContent || hasCustomRenderingHandler('dayCellContent', options));\n}\nfunction refineRenderProps(raw) {\n let { date, dateEnv, dateProfile, isMonthStart } = raw;\n let dayMeta = getDateMeta(date, raw.todayRange, null, dateProfile);\n let dayNumberText = raw.showDayNumber ? (dateEnv.format(date, isMonthStart ? raw.monthStartFormat : DAY_NUM_FORMAT)) : '';\n return Object.assign(Object.assign(Object.assign({ date: dateEnv.toDate(date), view: raw.viewApi }, dayMeta), { isMonthStart,\n dayNumberText }), raw.extraRenderProps);\n}\n\nclass BgEvent extends BaseComponent {\n render() {\n let { props } = this;\n let { seg } = props;\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(EventContainer, { elTag: \"div\", elClasses: ['fc-bg-event'], elStyle: { backgroundColor: seg.eventRange.ui.backgroundColor }, defaultGenerator: renderInnerContent, seg: seg, timeText: \"\", isDragging: false, isResizing: false, isDateSelecting: false, isSelected: false, isPast: props.isPast, isFuture: props.isFuture, isToday: props.isToday, disableDragging: true, disableResizing: true }));\n }\n}\nfunction renderInnerContent(props) {\n let { title } = props.event;\n return title && ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"div\", { className: \"fc-event-title\" }, props.event.title));\n}\nfunction renderFill(fillType) {\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"div\", { className: `fc-${fillType}` }));\n}\n\nconst WeekNumberContainer = (props) => ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(ViewContextType.Consumer, null, (context) => {\n let { dateEnv, options } = context;\n let { date } = props;\n let format = options.weekNumberFormat || props.defaultFormat;\n let num = dateEnv.computeWeekNumber(date); // TODO: somehow use for formatting as well?\n let text = dateEnv.format(date, format);\n let renderProps = { num, text, date };\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(ContentContainer // why isn't WeekNumberContentArg being auto-detected?\n , { elRef: props.elRef, elTag: props.elTag, elAttrs: props.elAttrs, elClasses: props.elClasses, elStyle: props.elStyle, renderProps: renderProps, generatorName: \"weekNumberContent\", customGenerator: options.weekNumberContent, defaultGenerator: renderInner, classNameGenerator: options.weekNumberClassNames, didMount: options.weekNumberDidMount, willUnmount: options.weekNumberWillUnmount }, props.children));\n}));\nfunction renderInner(innerProps) {\n return innerProps.text;\n}\n\nconst PADDING_FROM_VIEWPORT = 10;\nclass Popover extends BaseComponent {\n constructor() {\n super(...arguments);\n this.state = {\n titleId: getUniqueDomId(),\n };\n this.handleRootEl = (el) => {\n this.rootEl = el;\n if (this.props.elRef) {\n setRef(this.props.elRef, el);\n }\n };\n // Triggered when the user clicks *anywhere* in the document, for the autoHide feature\n this.handleDocumentMouseDown = (ev) => {\n // only hide the popover if the click happened outside the popover\n const target = getEventTargetViaRoot(ev);\n if (!this.rootEl.contains(target)) {\n this.handleCloseClick();\n }\n };\n this.handleDocumentKeyDown = (ev) => {\n if (ev.key === 'Escape') {\n this.handleCloseClick();\n }\n };\n this.handleCloseClick = () => {\n let { onClose } = this.props;\n if (onClose) {\n onClose();\n }\n };\n }\n render() {\n let { theme, options } = this.context;\n let { props, state } = this;\n let classNames = [\n 'fc-popover',\n theme.getClass('popover'),\n ].concat(props.extraClassNames || []);\n return (0,preact_compat__WEBPACK_IMPORTED_MODULE_1__.createPortal)((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"div\", Object.assign({}, props.extraAttrs, { id: props.id, className: classNames.join(' '), \"aria-labelledby\": state.titleId, ref: this.handleRootEl }),\n (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"div\", { className: 'fc-popover-header ' + theme.getClass('popoverHeader') },\n (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"span\", { className: \"fc-popover-title\", id: state.titleId }, props.title),\n (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"span\", { className: 'fc-popover-close ' + theme.getIconClass('close'), title: options.closeHint, onClick: this.handleCloseClick })),\n (0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(\"div\", { className: 'fc-popover-body ' + theme.getClass('popoverContent') }, props.children)), props.parentEl);\n }\n componentDidMount() {\n document.addEventListener('mousedown', this.handleDocumentMouseDown);\n document.addEventListener('keydown', this.handleDocumentKeyDown);\n this.updateSize();\n }\n componentWillUnmount() {\n document.removeEventListener('mousedown', this.handleDocumentMouseDown);\n document.removeEventListener('keydown', this.handleDocumentKeyDown);\n }\n updateSize() {\n let { isRtl } = this.context;\n let { alignmentEl, alignGridTop } = this.props;\n let { rootEl } = this;\n let alignmentRect = computeClippedClientRect(alignmentEl);\n if (alignmentRect) {\n let popoverDims = rootEl.getBoundingClientRect();\n // position relative to viewport\n let popoverTop = alignGridTop\n ? elementClosest(alignmentEl, '.fc-scrollgrid').getBoundingClientRect().top\n : alignmentRect.top;\n let popoverLeft = isRtl ? alignmentRect.right - popoverDims.width : alignmentRect.left;\n // constrain\n popoverTop = Math.max(popoverTop, PADDING_FROM_VIEWPORT);\n popoverLeft = Math.min(popoverLeft, document.documentElement.clientWidth - PADDING_FROM_VIEWPORT - popoverDims.width);\n popoverLeft = Math.max(popoverLeft, PADDING_FROM_VIEWPORT);\n let origin = rootEl.offsetParent.getBoundingClientRect();\n applyStyle(rootEl, {\n top: popoverTop - origin.top,\n left: popoverLeft - origin.left,\n });\n }\n }\n}\n\nclass MorePopover extends DateComponent {\n constructor() {\n super(...arguments);\n this.handleRootEl = (rootEl) => {\n this.rootEl = rootEl;\n if (rootEl) {\n this.context.registerInteractiveComponent(this, {\n el: rootEl,\n useEventCenter: false,\n });\n }\n else {\n this.context.unregisterInteractiveComponent(this);\n }\n };\n }\n render() {\n let { options, dateEnv } = this.context;\n let { props } = this;\n let { startDate, todayRange, dateProfile } = props;\n let title = dateEnv.format(startDate, options.dayPopoverFormat);\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(DayCellContainer, { elRef: this.handleRootEl, date: startDate, dateProfile: dateProfile, todayRange: todayRange }, (InnerContent, renderProps, elAttrs) => ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(Popover, { elRef: elAttrs.ref, id: props.id, title: title, extraClassNames: ['fc-more-popover'].concat(elAttrs.className || []), extraAttrs: elAttrs /* TODO: make these time-based when not whole-day? */, parentEl: props.parentEl, alignmentEl: props.alignmentEl, alignGridTop: props.alignGridTop, onClose: props.onClose },\n hasCustomDayCellContent(options) && ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(InnerContent, { elTag: \"div\", elClasses: ['fc-more-popover-misc'] })),\n props.children))));\n }\n queryHit(positionLeft, positionTop, elWidth, elHeight) {\n let { rootEl, props } = this;\n if (positionLeft >= 0 && positionLeft < elWidth &&\n positionTop >= 0 && positionTop < elHeight) {\n return {\n dateProfile: props.dateProfile,\n dateSpan: Object.assign({ allDay: !props.forceTimed, range: {\n start: props.startDate,\n end: props.endDate,\n } }, props.extraDateSpan),\n dayEl: rootEl,\n rect: {\n left: 0,\n top: 0,\n right: elWidth,\n bottom: elHeight,\n },\n layer: 1, // important when comparing with hits from other components\n };\n }\n return null;\n }\n}\n\nclass MoreLinkContainer extends BaseComponent {\n constructor() {\n super(...arguments);\n this.state = {\n isPopoverOpen: false,\n popoverId: getUniqueDomId(),\n };\n this.handleLinkEl = (linkEl) => {\n this.linkEl = linkEl;\n if (this.props.elRef) {\n setRef(this.props.elRef, linkEl);\n }\n };\n this.handleClick = (ev) => {\n let { props, context } = this;\n let { moreLinkClick } = context.options;\n let date = computeRange(props).start;\n function buildPublicSeg(seg) {\n let { def, instance, range } = seg.eventRange;\n return {\n event: new EventImpl(context, def, instance),\n start: context.dateEnv.toDate(range.start),\n end: context.dateEnv.toDate(range.end),\n isStart: seg.isStart,\n isEnd: seg.isEnd,\n };\n }\n if (typeof moreLinkClick === 'function') {\n moreLinkClick = moreLinkClick({\n date,\n allDay: Boolean(props.allDayDate),\n allSegs: props.allSegs.map(buildPublicSeg),\n hiddenSegs: props.hiddenSegs.map(buildPublicSeg),\n jsEvent: ev,\n view: context.viewApi,\n });\n }\n if (!moreLinkClick || moreLinkClick === 'popover') {\n this.setState({ isPopoverOpen: true });\n }\n else if (typeof moreLinkClick === 'string') { // a view name\n context.calendarApi.zoomTo(date, moreLinkClick);\n }\n };\n this.handlePopoverClose = () => {\n this.setState({ isPopoverOpen: false });\n };\n }\n render() {\n let { props, state } = this;\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(ViewContextType.Consumer, null, (context) => {\n let { viewApi, options, calendarApi } = context;\n let { moreLinkText } = options;\n let { moreCnt } = props;\n let range = computeRange(props);\n let text = typeof moreLinkText === 'function' // TODO: eventually use formatWithOrdinals\n ? moreLinkText.call(calendarApi, moreCnt)\n : `+${moreCnt} ${moreLinkText}`;\n let hint = formatWithOrdinals(options.moreLinkHint, [moreCnt], text);\n let renderProps = {\n num: moreCnt,\n shortText: `+${moreCnt}`,\n text,\n view: viewApi,\n };\n return ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(preact__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n Boolean(props.moreCnt) && ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(ContentContainer, { elTag: props.elTag || 'a', elRef: this.handleLinkEl, elClasses: [\n ...(props.elClasses || []),\n 'fc-more-link',\n ], elStyle: props.elStyle, elAttrs: Object.assign(Object.assign(Object.assign({}, props.elAttrs), createAriaClickAttrs(this.handleClick)), { title: hint, 'aria-expanded': state.isPopoverOpen, 'aria-controls': state.isPopoverOpen ? state.popoverId : '' }), renderProps: renderProps, generatorName: \"moreLinkContent\", customGenerator: options.moreLinkContent, defaultGenerator: props.defaultGenerator || renderMoreLinkInner, classNameGenerator: options.moreLinkClassNames, didMount: options.moreLinkDidMount, willUnmount: options.moreLinkWillUnmount }, props.children)),\n state.isPopoverOpen && ((0,preact__WEBPACK_IMPORTED_MODULE_0__.createElement)(MorePopover, { id: state.popoverId, startDate: range.start, endDate: range.end, dateProfile: props.dateProfile, todayRange: props.todayRange, extraDateSpan: props.extraDateSpan, parentEl: this.parentEl, alignmentEl: props.alignmentElRef ?\n props.alignmentElRef.current :\n this.linkEl, alignGridTop: props.alignGridTop, forceTimed: props.forceTimed, onClose: this.handlePopoverClose }, props.popoverContent()))));\n }));\n }\n componentDidMount() {\n this.updateParentEl();\n }\n componentDidUpdate() {\n this.updateParentEl();\n }\n updateParentEl() {\n if (this.linkEl) {\n this.parentEl = elementClosest(this.linkEl, '.fc-view-harness');\n }\n }\n}\nfunction renderMoreLinkInner(props) {\n return props.text;\n}\nfunction computeRange(props) {\n if (props.allDayDate) {\n return {\n start: props.allDayDate,\n end: addDays(props.allDayDate, 1),\n };\n }\n let { hiddenSegs } = props;\n return {\n start: computeEarliestSegStart(hiddenSegs),\n end: computeLatestSegEnd(hiddenSegs),\n };\n}\nfunction computeEarliestSegStart(segs) {\n return segs.reduce(pickEarliestStart).eventRange.range.start;\n}\nfunction pickEarliestStart(seg0, seg1) {\n return seg0.eventRange.range.start < seg1.eventRange.range.start ? seg0 : seg1;\n}\nfunction computeLatestSegEnd(segs) {\n return segs.reduce(pickLatestEnd).eventRange.range.end;\n}\nfunction pickLatestEnd(seg0, seg1) {\n return seg0.eventRange.range.end > seg1.eventRange.range.end ? seg0 : seg1;\n}\n\nclass Store {\n constructor() {\n this.handlers = [];\n }\n set(value) {\n this.currentValue = value;\n for (let handler of this.handlers) {\n handler(value);\n }\n }\n subscribe(handler) {\n this.handlers.push(handler);\n if (this.currentValue !== undefined) {\n handler(this.currentValue);\n }\n }\n}\n\n/*\nSubscribers will get a LIST of CustomRenderings\n*/\nclass CustomRenderingStore extends Store {\n constructor() {\n super(...arguments);\n this.map = new Map();\n }\n // for consistent order\n handle(customRendering) {\n const { map } = this;\n let updated = false;\n if (customRendering.isActive) {\n map.set(customRendering.id, customRendering);\n updated = true;\n }\n else if (map.has(customRendering.id)) {\n map.delete(customRendering.id);\n updated = true;\n }\n if (updated) {\n this.set(map);\n }\n }\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKHNzcikvLi9ub2RlX21vZHVsZXMvQGZ1bGxjYWxlbmRhci9jb3JlL2ludGVybmFsLWNvbW1vbi5qcyIsIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBaUM7QUFDMkM7QUFDL0I7O0FBRTdDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxRQUFRO0FBQ3BCO0FBQ0Esc0JBQXNCO0FBQ3RCO0FBQ0E7QUFDQSwwQ0FBMEM7QUFDMUM7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxzQkFBc0IsMkJBQTJCLHdCQUF3Qix3Q0FBd0MsNkJBQTZCLHVCQUF1Qiw0QkFBNEIsNkJBQTZCLGlDQUFpQyxtQ0FBbUMsdUNBQXVDLG9DQUFvQyx3Q0FBd0MsNEJBQTRCLGdDQUFnQywyQkFBMkIsa0RBQWtELGdDQUFnQyxrQ0FB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QUFDckI7QUFDQTtBQUNBLHFCQUFxQjtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQjtBQUNyQjtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7QUFDQSxhQUFhO0FBQ2I7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCO0FBQzdCO0FBQ0E7QUFDQSxnQkFBZ0IsU0FBUztBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFDQUFxQztBQUNyQztBQUNBO0FBQ0E7QUFD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QTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsOENBQThDO0FBQzlDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0NBQWtDLFFBQVE7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3QixnREFBZ0Q7QUFDeEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IsK0JBQStCO0FBQ3ZEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvRUFBb0U7QUFDcEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBOztBQUVBLFFBQVEsaUJBQWlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlFQUFpRTtBQUNqRTtBQUNBO0FBQ0Esa0RBQWtELFFBQVE7QUFDMUQ7QUFDQSwwREFBMEQ7QUFDMUQ7QUFDQTtBQUNBO0FBQ0EsMENBQTBDO0FBQzFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQ0FBc0MsUUFBUTtBQUM5QztBQUNBO0FBQ0EsbUNBQW1DO0FBQ25DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwyREFBMkQ7QUFDM0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCLGNBQWM7QUFDM0M7QUFDQSxpQ0FBaUM7QUFDakM7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSx3QkFBd0IsRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLDJCQUEyQixFQUFFLFFBQVEsRUFBRTtBQUNwSDtBQUNBO0FBQ0E7QUFDQSxtTEFBbUwsTUFBTTtBQUN6TDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLGlCQUFpQjtBQUMvQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxpQkFBaUI7QUFDL0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQjtBQUNyQjtBQUNBO0FBQ0E7QUFDQSxxQkFBcUI7QUFDckI7QUFDQTtBQUNBO0FBQ0EscUJBQXFCO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQjtBQUNyQjtBQUNBO0FBQ0E7QUFDQSxxQkFBcUI7QUFDckI7QUFDQTtBQUNBO0FBQ0EscUJBQXFCO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQjtBQUNyQjtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhDQUE4QztBQUM5QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0EsdURBQXVEO0FBQ3ZEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVDQUF1QztBQUN2QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkVBQTZFO0FBQzdFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBDQUEwQztBQUMxQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdFQUF3RTtBQUN4RSw4Q0FBOEM7QUFDOUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlEQUF5RDtBQUN6RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNCQUFzQixvQkFBb0IsRUFBRSxV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QTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQjtBQUNuQjtBQUNBO0FBQ0EsbUJBQW1CO0FBQ25CO0FBQ0EsK0NBQStDO0FBQy9DO0FBQ0E7QUFDQTtBQUNBLGNBQWMsaUJBQWlCO0FBQy9CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1REFBdUQ7QUFDdkQ7QUFDQTtBQUNBO0FBQ0Esa0NBQWtDLFFBQVEsVUFBVTtBQUNwRDtBQUNBO0FBQ0E7QUFDQSxxQkFBcUI7QUFDckI7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7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ekY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLGdCQUFnQjtBQUM5QjtBQUNBO0FBQ0Esb0JBQW9CLFNBQVM7QUFDN0I7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQkFBMEI7QUFDMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLGdCQUFnQjtBQUM5QjtBQUNBO0FBQ0Esb0JBQW9CLFNBQVM7QUFDN0I7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQkFBMEI7QUFDMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CLFNBQVM7QUFDN0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7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Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsYUFBYTtBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsTUFBTTtBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVtdkoiLCJzb3VyY2VzIjpbIi9ob21lL3NpbHZpby9EZXZlbG9wL0NJUlVYLUFQUC9ub2RlX21vZHVsZXMvQGZ1bGxjYWxlbmRhci9jb3JlL2ludGVybmFsLWNvbW1vbi5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBwcmVhY3QgZnJvbSAncHJlYWN0JztcbmltcG9ydCB7IENvbXBvbmVudCwgY3JlYXRlRWxlbWVudCwgaXNWYWxpZEVsZW1lbnQsIEZyYWdtZW50IH0gZnJvbSAncHJlYWN0JztcbmltcG9ydCB7IGNyZWF0ZVBvcnRhbCB9IGZyb20gJ3ByZWFjdC9jb21wYXQnO1xuXG5jb25zdCBzdHlsZVRleHRzID0gW107XG5jb25zdCBzdHlsZUVscyA9IG5ldyBNYXAoKTtcbmZ1bmN0aW9uIGluamVjdFN0eWxlcyhzdHlsZVRleHQpIHtcbiAgICBzdHlsZVRleHRzLnB1c2goc3R5bGVUZXh0KTtcbiAgICBzdHlsZUVscy5mb3JFYWNoKChzdHlsZUVsKSA9PiB7XG4gICAgICAgIGFwcGVuZFN0eWxlc1RvKHN0eWxlRWwsIHN0eWxlVGV4dCk7XG4gICAgfSk7XG59XG5mdW5jdGlvbiBlbnN1cmVFbEhhc1N0eWxlcyhlbCkge1xuICAgIGlmIChlbC5pc0Nvbm5lY3RlZCAmJiAvLyBzb21ldGltZXMgdHJ1ZSBpZiBTU1Igc3lzdGVtIHNpbXVsYXRlcyBET01cbiAgICAgICAgZWwuZ2V0Um9vdE5vZGUgLy8gc29tZXRpbWVzIHVuZGVmaW5lZCBpZiBTU1Igc3lzdGVtIHNpbXVsYXRlcyBET01cbiAgICApIHtcbiAgICAgICAgcmVnaXN0ZXJTdHlsZXNSb290KGVsLmdldFJvb3ROb2RlKCkpO1xuICAgIH1cbn1cbmZ1bmN0aW9uIHJlZ2lzdGVyU3R5bGVzUm9vdChyb290Tm9kZSkge1xuICAgIGxldCBzdHlsZUVsID0gc3R5bGVFbHMuZ2V0KHJvb3ROb2RlKTtcbiAgICBpZiAoIXN0eWxlRWwgfHwgIXN0eWxlRWwuaXNDb25uZWN0ZWQpIHtcbiAgICAgICAgc3R5bGVFbCA9IHJvb3ROb2RlLnF1ZXJ5U2VsZWN0b3IoJ3N0eWxlW2RhdGEtZnVsbGNhbGVuZGFyXScpO1xuICAgICAgICBpZiAoIXN0eWxlRWwpIHtcbiAgICAgICAgICAgIHN0eWxlRWwgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzdHlsZScpO1xuICAgICAgICAgICAgc3R5bGVFbC5zZXRBdHRyaWJ1dGUoJ2RhdGEtZnVsbGNhbGVuZGFyJywgJycpO1xuICAgICAgICAgICAgY29uc3Qgbm9uY2UgPSBnZXROb25jZVZhbHVlKCk7XG4gICAgICAgICAgICBpZiAobm9uY2UpIHtcbiAgICAgICAgICAgICAgICBzdHlsZUVsLm5vbmNlID0gbm9uY2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBwYXJlbnRFbCA9IHJvb3ROb2RlID09PSBkb2N1bWVudCA/IGRvY3VtZW50LmhlYWQgOiByb290Tm9kZTtcbiAgICAgICAgICAgIGNvbnN0IGluc2VydEJlZm9yZSA9IHJvb3ROb2RlID09PSBkb2N1bWVudFxuICAgICAgICAgICAgICAgID8gcGFyZW50RWwucXVlcnlTZWxlY3Rvcignc2NyaXB0LGxpbmtbcmVsPXN0eWxlc2hlZXRdLGxpbmtbYXM9c3R5bGVdLHN0eWxlJylcbiAgICAgICAgICAgICAgICA6IHBhcmVudEVsLmZpcnN0Q2hpbGQ7XG4gICAgICAgICAgICBwYXJlbnRFbC5pbnNlcnRCZWZvcmUoc3R5bGVFbCwgaW5zZXJ0QmVmb3JlKTtcbiAgICAgICAgfVxuICAgICAgICBzdHlsZUVscy5zZXQocm9vdE5vZGUsIHN0eWxlRWwpO1xuICAgICAgICBoeWRyYXRlU3R5bGVzUm9vdChzdHlsZUVsKTtcbiAgICB9XG59XG5mdW5jdGlvbiBoeWRyYXRlU3R5bGVzUm9vdChzdHlsZUVsKSB7XG4gICAgZm9yIChjb25zdCBzdHlsZVRleHQgb2Ygc3R5bGVUZXh0cykge1xuICAgICAgICBhcHBlbmRTdHlsZXNUbyhzdHlsZUVsLCBzdHlsZVRleHQpO1xuICAgIH1cbn1cbmZ1bmN0aW9uIGFwcGVuZFN0eWxlc1RvKHN0eWxlRWwsIHN0eWxlVGV4dCkge1xuICAgIGNvbnN0IHsgc2hlZXQgfSA9IHN0eWxlRWw7XG4gICAgY29uc3QgcnVsZUNudCA9IHNoZWV0LmNzc1J1bGVzLmxlbmd0aDtcbiAgICBzdHlsZVRleHQuc3BsaXQoJ30nKS5mb3JFYWNoKChzdHlsZVN0ciwgaSkgPT4ge1xuICAgICAgICBzdHlsZVN0ciA9IHN0eWxlU3RyLnRyaW0oKTtcbiAgICAgICAgaWYgKHN0eWxlU3RyKSB7XG4gICAgICAgICAgICBzaGVldC5pbnNlcnRSdWxlKHN0eWxlU3RyICsgJ30nLCBydWxlQ250ICsgaSk7XG4gICAgICAgIH1cbiAgICB9KTtcbn1cbi8vIG5vbmNlXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5sZXQgcXVlcmllZE5vbmNlVmFsdWU7XG5mdW5jdGlvbiBnZXROb25jZVZhbHVlKCkge1xuICAgIGlmIChxdWVyaWVkTm9uY2VWYWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHF1ZXJpZWROb25jZVZhbHVlID0gcXVlcnlOb25jZVZhbHVlKCk7XG4gICAgfVxuICAgIHJldHVybiBxdWVyaWVkTm9uY2VWYWx1ZTtcbn1cbi8qXG5UT0RPOiBkaXNjb3VyYWdlIG1ldGEgdGFnIGFuZCBpbnN0ZWFkIHB1dCBub25jZSBhdHRyaWJ1dGUgb24gcGxhY2Vob2xkZXIgPHN0eWxlPiB0YWdcbiovXG5mdW5jdGlvbiBxdWVyeU5vbmNlVmFsdWUoKSB7XG4gICAgY29uc3QgbWV0YVdpdGhOb25jZSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ21ldGFbbmFtZT1cImNzcC1ub25jZVwiXScpO1xuICAgIGlmIChtZXRhV2l0aE5vbmNlICYmIG1ldGFXaXRoTm9uY2UuaGFzQXR0cmlidXRlKCdjb250ZW50JykpIHtcbiAgICAgICAgcmV0dXJuIG1ldGFXaXRoTm9uY2UuZ2V0QXR0cmlidXRlKCdjb250ZW50Jyk7XG4gICAgfVxuICAgIGNvbnN0IGVsV2l0aE5vbmNlID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcignc2NyaXB0W25vbmNlXScpO1xuICAgIGlmIChlbFdpdGhOb25jZSkge1xuICAgICAgICByZXR1cm4gZWxXaXRoTm9uY2Uubm9uY2UgfHwgJyc7XG4gICAgfVxuICAgIHJldHVybiAnJztcbn1cbi8vIG1haW5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbmlmICh0eXBlb2YgZG9jdW1lbnQgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgcmVnaXN0ZXJTdHlsZXNSb290KGRvY3VtZW50KTtcbn1cblxudmFyIGNzc18yNDh6ID0gXCI6cm9vdHstLWZjLXNtYWxsLWZvbnQtc2l6ZTouODVlbTstLWZjLXBhZ2UtYmctY29sb3I6I2ZmZjstLWZjLW5ldXRyYWwtYmctY29sb3I6aHNsYSgwLDAlLDgyJSwuMyk7LS1mYy1uZXV0cmFsLXRleHQtY29sb3I6Z3JleTstLWZjLWJvcmRlci1jb2xvcjojZGRkOy0tZmMtYnV0dG9uLXRleHQtY29sb3I6I2ZmZjstLWZjLWJ1dHRvbi1iZy1jb2xvcjojMmMzZTUwOy0tZmMtYnV0dG9uLWJvcmRlci1jb2xvcjojMmMzZTUwOy0tZmMtYnV0dG9uLWhvdmVyLWJnLWNvbG9yOiMxZTJiMzc7LS1mYy1idXR0b24taG92ZXItYm9yZGVyLWNvbG9yOiMxYTI1MmY7LS1mYy1idXR0b24tYWN0aXZlLWJnLWNvbG9yOiMxYTI1MmY7LS1mYy1idXR0b24tYWN0aXZlLWJvcmRlci1jb2xvcjojMTUxZTI3Oy0tZmMtZXZlbnQtYmctY29sb3I6IzM3ODhkODstLWZjLWV2ZW50LWJvcmRlci1jb2xvcjojMzc4OGQ4Oy0tZmMtZXZlbnQtdGV4dC1jb2xvcjojZmZmOy0tZmMtZXZlbnQtc2VsZWN0ZWQtb3ZlcmxheS1jb2xvcjpyZ2JhKDAsMCwwLC4yNSk7LS1mYy1tb3JlLWxpbmstYmctY29sb3I6I2QwZDBkMDstLWZjLW1vcmUtbGluay10ZXh0LWNvbG9yOmluaGVyaXQ7LS1mYy1ldmVudC1yZXNpemVyLXRoaWNrbmVzczo4cHg7LS1mYy1ldmVudC1yZXNpemVyLWRvdC10b3RhbC13aWR0aDo4cHg7LS1mYy1ldmVudC1yZXNpemVyLWRvdC1ib3JkZXItd2lkdGg6MXB4Oy0tZmMtbm9uLWJ1c2luZXNzLWNvbG9yOmhzbGEoMCwwJSw4NCUsLjMpOy0tZmMtYmctZXZlbnQtY29sb3I6IzhmZGY4MjstLWZjLWJnLWV2ZW50LW9wYWNpdHk6MC4zOy0tZmMtaGlnaGxpZ2h0LWNvbG9yOnJnYmEoMTg4LDIzMiwyNDEsLjMpOy0tZmMtdG9kYXktYmctY29sb3I6cmdiYSgyNTUsMjIwLDQwLC4xNSk7LS1mYy1ub3ctaW5kaWNhdG9yLWNvbG9yOnJlZH0uZmMtbm90LWFsbG93ZWQsLmZjLW5vdC1hbGxvd2VkIC5mYy1ldmVudHtjdXJzb3I6bm90LWFsbG93ZWR9LmZje2Rpc3BsYXk6ZmxleDtmbGV4LWRpcmVjdGlvbjpjb2x1bW47Zm9udC1zaXplOjFlbX0uZmMsLmZjICosLmZjIDphZnRlciwuZmMgOmJlZm9yZXtib3gtc2l6aW5nOmJvcmRlci1ib3h9LmZjIHRhYmxle2JvcmRlci1jb2xsYXBzZTpjb2xsYXBzZTtib3JkZXItc3BhY2luZzowO2ZvbnQtc2l6ZToxZW19LmZjIHRoe3RleHQtYWxpZ246Y2VudGVyfS5mYyB0ZCwuZmMgdGh7cGFkZGluZzowO3ZlcnRpY2FsLWFsaWduOnRvcH0uZmMgYVtkYXRhLW5hdmxpbmtde2N1cnNvcjpwb2ludGVyfS5mYyBhW2RhdGEtbmF2bGlua106aG92ZXJ7dGV4dC1kZWNvcmF0aW9uOnVuZGVybGluZX0uZmMtZGlyZWN0aW9uLWx0cntkaXJlY3Rpb246bHRyO3RleHQtYWxpZ246bGVmdH0uZmMtZGlyZWN0aW9uLXJ0bHtkaXJlY3Rpb246cnRsO3RleHQtYWxpZ246cmlnaHR9LmZjLXRoZW1lLXN0YW5kYXJkIHRkLC5mYy10aGVtZS1zdGFuZGFyZCB0aHtib3JkZXI6MXB4IHNvbGlkIHZhcigtLWZjLWJvcmRlci1jb2xvcil9LmZjLWxpcXVpZC1oYWNrIHRkLC5mYy1saXF1aWQtaGFjayB0aHtwb3NpdGlvbjpyZWxhdGl2ZX1AZm9udC1mYWNle2ZvbnQtZmFtaWx5OmZjaWNvbnM7Zm9udC1zdHlsZTpub3JtYWw7Zm9udC13ZWlnaHQ6NDAwO3NyYzp1cmwoXFxcImRhdGE6YXBwbGljYXRpb24veC1mb250LXR0ZjtjaGFyc2V0PXV0Zi04O2Jhc2U2NCxBQUVBQUFBTEFJQUFBd0F3VDFNdk1nOFNCZkFBQUFDOEFBQUFZR050WVhBWFZ0S05BQUFCSEFBQUFGUm5ZWE53QUFBQUVBQUFBWEFBQUFBSVoyeDVaZ1l5ZHhJQUFBRjRBQUFGTkdobFlXUVVKN2NJQUFBR3JBQUFBRFpvYUdWaEIyMER6QUFBQnVRQUFBQWthRzEwZUNJQUJoUUFBQWNJQUFBQUxHeHZZMkVENEFVNkFBQUhOQUFBQUJodFlYaHdBQThBakFBQUIwd0FBQUFnYm1GdFpYc3I2OTBBQUFkc0FBQUJobkJ2YzNRQUF3QUFBQUFJOUFBQUFDQUFBd1BBQVpBQUJRQUFBcGtDekFBQUFJOENtUUxNQUFBQjZ3QXpBUWtBQUFBQUFBQUFBQUFBQUFBQUFBQUJFQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkFBQURwQmdQQS84QUFRQVBBQUVBQUFBQUJBQUFBQUFBQUFBQUFBQUFnQUFBQUFBQURBQUFBQXdBQUFCd0FBUUFEQUFBQUhBQURBQUVBQUFBY0FBUUFPQUFBQUFvQUNBQUNBQUlBQVFBZzZRYi8vZi8vQUFBQUFBQWc2UUQvL2YvL0FBSC80eGNFQUFNQUFRQUFBQUFBQUFBQUFBQUFBUUFCLy84QUR3QUJBQUFBQUFBQUFBQUFBZ0FBTnprQkFBQUFBQUVBQUFBQUFBQUFBQUFDQUFBM09RRUFBQUFBQVFBQUFBQUFBQUFBQUFJQUFEYzVBUUFBQUFBQkFXSUFqUUtlQXNrQUV3QUFKU2MzTmpRbkppSUhBUVlVRndFV01qYzJOQ2NDbnVMaURRME1KQXovQUEwTkFRQU1KQXdORGNuaTRnd2pEUXdNL3dBTkl3ei9BQTBORENNTkFBQUFBUUZpQUkwQ25nTEpBQk1BQUNVQk5qUW5BU1lpQndZVUh3RUhCaFFYRmpJM0FaNEJBQTBOL3dBTUpBd05EZUxpRFEwTUpBeU5BUUFNSXcwQkFBd01EU01NNHVJTkl3d05EUUFBQUFJQTRnQzNBeDRDbmdBVEFDY0FBQ1VuTnpZMEp5WWlEd0VHRkI4QkZqSTNOalFuSVNjM05qUW5KaUlQQVFZVUh3RVdNamMyTkNjQjg3ZTNEUTBNSXczVkRRM1ZEU01NRFEwQks3ZTNEUTBNSkF6VkRRM1ZEQ1FNRFEzenVMY01KQXdORGRVTkl3eldEQXdOSXd5NHR3d2tEQTBOMVEwakROWU1EQTBqREFBQUFnRGlBTGNESGdLZUFCTUFKd0FBSlRjMk5DOEJKaUlIQmhRZkFRY0dGQmNXTWpjaE56WTBMd0VtSWdjR0ZCOEJCd1lVRnhZeU53SkoxUTBOMVEwakRBME50N2NORFF3akRmN1YxUTBOMVF3a0RBME50N2NORFF3a0RMZldEQ01OMVEwTkRDUU10N2dNSXcwTUROWU1JdzNWRFEwTUpBeTN1QXdqRFF3TUFBQURBRlVBQUFPckExVUFNd0JvQUhjQUFCTWlCZ2NPQVFjT0FRY09BUlVSRkJZWEhnRVhIZ0VYSGdFeklUSTJOejRCTno0Qk56NEJOUkUwSmljdUFTY3VBU2N1QVNNRklUSVdGeDRCRng0QkZ4NEJGUkVVQmdjT0FRY09BUWNPQVNNaElpWW5MZ0VuTGdFbkxnRTFFVFEyTno0Qk56NEJOejRCTXhNaE1qWTFOQ1lqSVNJR0ZSUVdNOVVOR0F3TEZRa0pEZ1VGQlFVRkJRNEpDUlVMREJnTkFsWU5HQXdMRlFrSkRnVUZCUVVGQlE0SkNSVUxEQmdOL2FvQ1ZnUUlCQVFIQXdNRkFRSUJBUUlCQlFNREJ3UUVDQVQ5cWdRSUJBUUhBd01GQVFJQkFRSUJCUU1EQndRRUNBU0FBVllSR1JrUi9xb1JHUmtSQTFVRkJBVU9DUWtWREFzWkRmMnJEUmtMREJVSkNBNEZCUVVGQlFVT0NRZ1ZEQXNaRFFKVkRSa0xEQlVKQ1E0RkJBVlZBZ0VDQlFNQ0J3UUVDQVg5cXdRSkF3UUhBd01GQVFJQ0FnSUJCUU1EQndRRENRUUNWUVVJQkFRSEFnTUZBZ0VDL29BWkVoRVpHUkVTR1FBQUFBQURBRlVBQUFPckExVUFNd0JvQUlrQUFCTWlCZ2NPQVFjT0FRY09BUlVSRkJZWEhnRVhIZ0VYSGdFeklUSTJOejRCTno0Qk56NEJOUkUwSmljdUFTY3VBU2N1QVNNRklUSVdGeDRCRng0QkZ4NEJGUkVVQmdjT0FRY09BUWNPQVNNaElpWW5MZ0VuTGdFbkxnRTFFVFEyTno0Qk56NEJOejRCTXhNekZSUVdNekkyUFFFek1qWTFOQ1lyQVRVMEppTWlCaDBCSXlJR0ZSUVdNOVVOR0F3TEZRa0pEZ1VGQlFVRkJRNEpDUlVMREJnTkFsWU5HQXdMRlFrSkRnVUZCUVVGQlE0SkNSVUxEQmdOL2FvQ1ZnUUlCQVFIQXdNRkFRSUJBUUlCQlFNREJ3UUVDQVQ5cWdRSUJBUUhBd01GQVFJQkFRSUJCUU1EQndRRUNBU0FnQmtTRWhtQUVSa1pFWUFaRWhJWmdCRVpHUkVEVlFVRUJRNEpDUlVNQ3hrTi9hc05HUXNNRlFrSURnVUZCUVVGQlE0SkNCVU1DeGtOQWxVTkdRc01GUWtKRGdVRUJWVUNBUUlGQXdJSEJBUUlCZjJyQkFrREJBY0RBd1VCQWdJQ0FnRUZBd01IQkFNSkJBSlZCUWdFQkFjQ0F3VUNBUUwrZ0lBU0dSa1NnQmtTRVJtQUVoa1pFb0FaRVJJWkFBQUJBT0lBalFNZUFza0FJQUFBRXhjSEJoUVhGakkvQVJjV01qYzJOQzhCTnpZMEp5WWlEd0VuSmlJSEJoUVg0dUxpRFEwTUpBemk0Z3drREEwTjR1SU5EUXdrRE9MaURDUU1EUTBDamVMaURTTU1EUTNoNFEwTkRDTU40dUlNSXcwTURPTGlEQXdOSXd3QUFBQUJBQUFBQVFBQWE1bjB5MThQUFBVQUN3UUFBQUFBQU5pdk9Wc0FBQUFBMks4NVd3QUFBQUFEcXdOVkFBQUFDQUFDQUFBQUFBQUFBQUVBQUFQQS84QUFBQVFBQUFBQUFBT3JBQUVBQUFBQUFBQUFBQUFBQUFBQUFBQUxCQUFBQUFBQUFBQUFBQUFBQWdBQUFBUUFBV0lFQUFGaUJBQUE0Z1FBQU9JRUFBQlZCQUFBVlFRQUFPSUFBQUFBQUFvQUZBQWVBRVFBYWdDcUFPb0JuZ0prQXBvQUFRQUFBQXNBaWdBREFBQUFBQUFDQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE0QXJnQUJBQUFBQUFBQkFBY0FBQUFCQUFBQUFBQUNBQWNBWUFBQkFBQUFBQUFEQUFjQU5nQUJBQUFBQUFBRUFBY0FkUUFCQUFBQUFBQUZBQXNBRlFBQkFBQUFBQUFHQUFjQVN3QUJBQUFBQUFBS0FCb0FpZ0FEQUFFRUNRQUJBQTRBQndBREFBRUVDUUFDQUE0QVp3QURBQUVFQ1FBREFBNEFQUUFEQUFFRUNRQUVBQTRBZkFBREFBRUVDUUFGQUJZQUlBQURBQUVFQ1FBR0FBNEFVZ0FEQUFFRUNRQUtBRFFBcEdaamFXTnZibk1BWmdCakFHa0FZd0J2QUc0QWMxWmxjbk5wYjI0Z01TNHdBRllBWlFCeUFITUFhUUJ2QUc0QUlBQXhBQzRBTUdaamFXTnZibk1BWmdCakFHa0FZd0J2QUc0QWMyWmphV052Ym5NQVpnQmpBR2tBWXdCdkFHNEFjMUpsWjNWc1lYSUFVZ0JsQUdjQWRRQnNBR0VBY21aamFXTnZibk1BWmdCakFHa0FZd0J2QUc0QWMwWnZiblFnWjJWdVpYSmhkR1ZrSUdKNUlFbGpiMDF2YjI0dUFFWUFid0J1QUhRQUlBQm5BR1VBYmdCbEFISUFZUUIwQUdVQVpBQWdBR0lBZVFBZ0FFa0FZd0J2QUUwQWJ3QnZBRzRBTGdBQUFBTUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE9XFxcIikgZm9ybWF0KFxcXCJ0cnVldHlwZVxcXCIpfS5mYy1pY29ue3NwZWFrOm5vbmU7LXdlYmtpdC1mb250LXNtb290aGluZzphbnRpYWxpYXNlZDstbW96LW9zeC1mb250LXNtb290aGluZzpncmF5c2NhbGU7ZGlzcGxheTppbmxpbmUtYmxvY2s7Zm9udC1mYW1pbHk6ZmNpY29ucyFpbXBvcnRhbnQ7Zm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDo0MDA7aGVpZ2h0OjFlbTtsaW5lLWhlaWdodDoxO3RleHQtYWxpZ246Y2VudGVyO3RleHQtdHJhbnNmb3JtOm5vbmU7LXdlYmtpdC11c2VyLXNlbGVjdDpub25lOy1tb3otdXNlci1zZWxlY3Q6bm9uZTt1c2VyLXNlbGVjdDpub25lO3dpZHRoOjFlbX0uZmMtaWNvbi1jaGV2cm9uLWxlZnQ6YmVmb3Jle2NvbnRlbnQ6XFxcIlxcXFxlOTAwXFxcIn0uZmMtaWNvbi1jaGV2cm9uLXJpZ2h0OmJlZm9yZXtjb250ZW50OlxcXCJcXFxcZTkwMVxcXCJ9LmZjLWljb24tY2hldnJvbnMtbGVmdDpiZWZvcmV7Y29udGVudDpcXFwiXFxcXGU5MDJcXFwifS5mYy1pY29uLWNoZXZyb25zLXJpZ2h0OmJlZm9yZXtjb250ZW50OlxcXCJcXFxcZTkwM1xcXCJ9LmZjLWljb24tbWludXMtc3F1YXJlOmJlZm9yZXtjb250ZW50OlxcXCJcXFxcZTkwNFxcXCJ9LmZjLWljb24tcGx1cy1zcXVhcmU6YmVmb3Jle2NvbnRlbnQ6XFxcIlxcXFxlOTA1XFxcIn0uZmMtaWNvbi14OmJlZm9yZXtjb250ZW50OlxcXCJcXFxcZTkwNlxcXCJ9LmZjIC5mYy1idXR0b257Ym9yZGVyLXJhZGl1czowO2ZvbnQtZmFtaWx5OmluaGVyaXQ7Zm9udC1zaXplOmluaGVyaXQ7bGluZS1oZWlnaHQ6aW5oZXJpdDttYXJnaW46MDtvdmVyZmxvdzp2aXNpYmxlO3RleHQtdHJhbnNmb3JtOm5vbmV9LmZjIC5mYy1idXR0b246Zm9jdXN7b3V0bGluZToxcHggZG90dGVkO291dGxpbmU6NXB4IGF1dG8gLXdlYmtpdC1mb2N1cy1yaW5nLWNvbG9yfS5mYyAuZmMtYnV0dG9uey13ZWJraXQtYXBwZWFyYW5jZTpidXR0b259LmZjIC5mYy1idXR0b246bm90KDpkaXNhYmxlZCl7Y3Vyc29yOnBvaW50ZXJ9LmZjIC5mYy1idXR0b257YmFja2dyb3VuZC1jb2xvcjp0cmFuc3BhcmVudDtib3JkZXI6MXB4IHNvbGlkIHRyYW5zcGFyZW50O2JvcmRlci1yYWRpdXM6LjI1ZW07ZGlzcGxheTppbmxpbmUtYmxvY2s7Zm9udC1zaXplOjFlbTtmb250LXdlaWdodDo0MDA7bGluZS1oZWlnaHQ6MS41O3BhZGRpbmc6LjRlbSAuNjVlbTt0ZXh0LWFsaWduOmNlbnRlcjstd2Via2l0LXVzZXItc2VsZWN0Om5vbmU7LW1vei11c2VyLXNlbGVjdDpub25lO3VzZXItc2VsZWN0Om5vbmU7dmVydGljYWwtYWxpZ246bWlkZGxlfS5mYyAuZmMtYnV0dG9uOmhvdmVye3RleHQtZGVjb3JhdGlvbjpub25lfS5mYyAuZmMtYnV0dG9uOmZvY3Vze2JveC1zaGFkb3c6MCAwIDAgLjJyZW0gcmdiYSg0NCw2Miw4MCwuMjUpO291dGxpbmU6MH0uZmMgLmZjLWJ1dHRvbjpkaXNhYmxlZHtvcGFjaXR5Oi42NX0uZmMgLmZjLWJ1dHRvbi1wcmltYXJ5e2JhY2tncm91bmQtY29sb3I6dmFyKC0tZmMtYnV0dG9uLWJnLWNvbG9yKTtib3JkZXItY29sb3I6dmFyKC0tZmMtYnV0dG9uLWJvcmRlci1jb2xvcik7Y29sb3I6dmFyKC0tZmMtYnV0dG9uLXRleHQtY29sb3IpfS5mYyAuZmMtYnV0dG9uLXByaW1hcnk6aG92ZXJ7YmFja2dyb3VuZC1jb2xvcjp2YXIoLS1mYy1idXR0b24taG92ZXItYmctY29sb3IpO2JvcmRlci1jb2xvcjp2YXIoLS1mYy1idXR0b24taG92ZXItYm9yZGVyLWNvbG9yKTtjb2xvcjp2YXIoLS1mYy1idXR0b24tdGV4dC1jb2xvcil9LmZjIC5mYy1idXR0b24tcHJpbWFyeTpkaXNhYmxlZHtiYWNrZ3JvdW5kLWNvbG9yOnZhcigtLWZjLWJ1dHRvbi1iZy1jb2xvcik7Ym9yZGVyLWNvbG9yOnZhcigtLWZjLWJ1dHRvbi1ib3JkZXItY29sb3IpO2NvbG9yOnZhcigtLWZjLWJ1dHRvbi10ZXh0LWNvbG9yKX0uZmMgLmZjLWJ1dHRvbi1wcmltYXJ5OmZvY3Vze2JveC1zaGFkb3c6MCAwIDAgLjJyZW0gcmdiYSg3Niw5MSwxMDYsLjUpfS5mYyAuZmMtYnV0dG9uLXByaW1hcnk6bm90KDpkaXNhYmxlZCkuZmMtYnV0dG9uLWFjdGl2ZSwuZmMgLmZjLWJ1dHRvbi1wcmltYXJ5Om5vdCg6ZGlzYWJsZWQpOmFjdGl2ZXtiYWNrZ3JvdW5kLWNvbG9yOnZhcigtLWZjLWJ1dHRvbi1hY3RpdmUtYmctY29sb3IpO2JvcmRlci1jb2xvcjp2YXIoLS1mYy1idXR0b24tYWN0aXZlLWJvcmRlci1jb2xvcik7Y29sb3I6dmFyKC0tZmMtYnV0dG9uLXRleHQtY29sb3IpfS5mYyAuZmMtYnV0dG9uLXByaW1hcnk6bm90KDpkaXNhYmxlZCkuZmMtYnV0dG9uLWFjdGl2ZTpmb2N1cywuZmMgLmZjLWJ1dHRvbi1wcmltYXJ5Om5vdCg6ZGlzYWJsZWQpOmFjdGl2ZTpmb2N1c3tib3gtc2hhZG93OjAgMCAwIC4ycmVtIHJnYmEoNzYsOTEsMTA2LC41KX0uZmMgLmZjLWJ1dHRvbiAuZmMtaWNvbntmb250LXNpemU6MS41ZW07dmVydGljYWwtYWxpZ246bWlkZGxlfS5mYyAuZmMtYnV0dG9uLWdyb3Vwe2Rpc3BsYXk6aW5saW5lLWZsZXg7cG9zaXRpb246cmVsYXRpdmU7dmVydGljYWwtYWxpZ246bWlkZGxlfS5mYyAuZmMtYnV0dG9uLWdyb3VwPi5mYy1idXR0b257ZmxleDoxIDEgYXV0bztwb3NpdGlvbjpyZWxhdGl2ZX0uZmMgLmZjLWJ1dHRvbi1ncm91cD4uZmMtYnV0dG9uLmZjLWJ1dHRvbi1hY3RpdmUsLmZjIC5mYy1idXR0b24tZ3JvdXA+LmZjLWJ1dHRvbjphY3RpdmUsLmZjIC5mYy1idXR0b24tZ3JvdXA+LmZjLWJ1dHRvbjpmb2N1cywuZmMgLmZjLWJ1dHRvbi1ncm91cD4uZmMtYnV0dG9uOmhvdmVye3otaW5kZXg6MX0uZmMtZGlyZWN0aW9uLWx0ciAuZmMtYnV0dG9uLWdyb3VwPi5mYy1idXR0b246bm90KDpmaXJzdC1jaGlsZCl7Ym9yZGVyLWJvdHRvbS1sZWZ0LXJhZGl1czowO2JvcmRlci10b3AtbGVmdC1yYWRpdXM6MDttYXJnaW4tbGVmdDotMXB4fS5mYy1kaXJlY3Rpb24tbHRyIC5mYy1idXR0b24tZ3JvdXA+LmZjLWJ1dHRvbjpub3QoOmxhc3QtY2hpbGQpe2JvcmRlci1ib3R0b20tcmlnaHQtcmFkaXVzOjA7Ym9yZGVyLXRvcC1yaWdodC1yYWRpdXM6MH0uZmMtZGlyZWN0aW9uLXJ0bCAuZmMtYnV0dG9uLWdyb3VwPi5mYy1idXR0b246bm90KDpmaXJzdC1jaGlsZCl7Ym9yZGVyLWJvdHRvbS1yaWdodC1yYWRpdXM6MDtib3JkZXItdG9wLXJpZ2h0LXJhZGl1czowO21hcmdpbi1yaWdodDotMXB4fS5mYy1kaXJlY3Rpb24tcnRsIC5mYy1idXR0b24tZ3JvdXA+LmZjLWJ1dHRvbjpub3QoOmxhc3QtY2hpbGQpe2JvcmRlci1ib3R0b20tbGVmdC1yYWRpdXM6MDtib3JkZXItdG9wLWxlZnQtcmFkaXVzOjB9LmZjIC5mYy10b29sYmFye2FsaWduLWl0ZW1zOmNlbnRlcjtkaXNwbGF5OmZsZXg7anVzdGlmeS1jb250ZW50OnNwYWNlLWJldHdlZW59LmZjIC5mYy10b29sYmFyLmZjLWhlYWRlci10b29sYmFye21hcmdpbi1ib3R0b206MS41ZW19LmZjIC5mYy10b29sYmFyLmZjLWZvb3Rlci10b29sYmFye21hcmdpbi10b3A6MS41ZW19LmZjIC5mYy10b29sYmFyLXRpdGxle2ZvbnQtc2l6ZToxLjc1ZW07bWFyZ2luOjB9LmZjLWRpcmVjdGlvbi1sdHIgLmZjLXRvb2xiYXI+Kj46bm90KDpmaXJzdC1jaGlsZCl7bWFyZ2luLWxlZnQ6Ljc1ZW19LmZjLWRpcmVjdGlvbi1ydGwgLmZjLXRvb2xiYXI+Kj46bm90KDpmaXJzdC1jaGlsZCl7bWFyZ2luLXJpZ2h0Oi43NWVtfS5mYy1kaXJlY3Rpb24tcnRsIC5mYy10b29sYmFyLWx0cntmbGV4LWRpcmVjdGlvbjpyb3ctcmV2ZXJzZX0uZmMgLmZjLXNjcm9sbGVyey13ZWJraXQtb3ZlcmZsb3ctc2Nyb2xsaW5nOnRvdWNoO3Bvc2l0aW9uOnJlbGF0aXZlfS5mYyAuZmMtc2Nyb2xsZXItbGlxdWlke2hlaWdodDoxMDAlfS5mYyAuZmMtc2Nyb2xsZXItbGlxdWlkLWFic29sdXRle2JvdHRvbTowO2xlZnQ6MDtwb3NpdGlvbjphYnNvbHV0ZTtyaWdodDowO3RvcDowfS5mYyAuZmMtc2Nyb2xsZXItaGFybmVzc3tkaXJlY3Rpb246bHRyO292ZXJmbG93OmhpZGRlbjtwb3NpdGlvbjpyZWxhdGl2ZX0uZmMgLmZjLXNjcm9sbGVyLWhhcm5lc3MtbGlxdWlke2hlaWdodDoxMDAlfS5mYy1kaXJlY3Rpb24tcnRsIC5mYy1zY3JvbGxlci1oYXJuZXNzPi5mYy1zY3JvbGxlcntkaXJlY3Rpb246cnRsfS5mYy10aGVtZS1zdGFuZGFyZCAuZmMtc2Nyb2xsZ3JpZHtib3JkZXI6MXB4IHNvbGlkIHZhcigtLWZjLWJvcmRlci1jb2xvcil9LmZjIC5mYy1zY3JvbGxncmlkLC5mYyAuZmMtc2Nyb2xsZ3JpZCB0YWJsZXt0YWJsZS1sYXlvdXQ6Zml4ZWQ7d2lkdGg6MTAwJX0uZmMgLmZjLXNjcm9sbGdyaWQgdGFibGV7Ym9yZGVyLWxlZnQtc3R5bGU6aGlkZGVuO2JvcmRlci1yaWdodC1zdHlsZTpoaWRkZW47Ym9yZGVyLXRvcC1zdHlsZTpoaWRkZW59LmZjIC5mYy1zY3JvbGxncmlke2JvcmRlci1ib3R0b20td2lkdGg6MDtib3JkZXItY29sbGFwc2U6c2VwYXJhdGU7Ym9yZGVyLXJpZ2h0LXdpZHRoOjB9LmZjIC5mYy1zY3JvbGxncmlkLWxpcXVpZHtoZWlnaHQ6MTAwJX0uZmMgLmZjLXNjcm9sbGdyaWQtc2VjdGlvbiwuZmMgLmZjLXNjcm9sbGdyaWQtc2VjdGlvbiB0YWJsZSwuZmMgLmZjLXNjcm9sbGdyaWQtc2VjdGlvbj50ZHtoZWlnaHQ6MXB4fS5mYyAuZmMtc2Nyb2xsZ3JpZC1zZWN0aW9uLWxpcXVpZD50ZHtoZWlnaHQ6MTAwJX0uZmMgLmZjLXNjcm9sbGdyaWQtc2VjdGlvbj4qe2JvcmRlci1sZWZ0LXdpZHRoOjA7Ym9yZGVyLXRvcC13aWR0aDowfS5mYyAuZmMtc2Nyb2xsZ3JpZC1zZWN0aW9uLWZvb3Rlcj4qLC5mYyAuZmMtc2Nyb2xsZ3JpZC1zZWN0aW9uLWhlYWRlcj4qe2JvcmRlci1ib3R0b20td2lkdGg6MH0uZmMgLmZjLXNjcm9sbGdyaWQtc2VjdGlvbi1ib2R5IHRhYmxlLC5mYyAuZmMtc2Nyb2xsZ3JpZC1zZWN0aW9uLWZvb3RlciB0YWJsZXtib3JkZXItYm90dG9tLXN0eWxlOmhpZGRlbn0uZmMgLmZjLXNjcm9sbGdyaWQtc2VjdGlvbi1zdGlja3k+KntiYWNrZ3JvdW5kOnZhcigtLWZjLXBhZ2UtYmctY29sb3IpO3Bvc2l0aW9uOnN0aWNreTt6LWluZGV4OjN9LmZjIC5mYy1zY3JvbGxncmlkLXNlY3Rpb24taGVhZGVyLmZjLXNjcm9sbGdyaWQtc2VjdGlvbi1zdGlja3k+Knt0b3A6MH0uZmMgLmZjLXNjcm9sbGdyaWQtc2VjdGlvbi1mb290ZXIuZmMtc2Nyb2xsZ3JpZC1zZWN0aW9uLXN0aWNreT4qe2JvdHRvbTowfS5mYyAuZmMtc2Nyb2xsZ3JpZC1zdGlja3ktc2hpbXtoZWlnaHQ6MXB4O21hcmdpbi1ib3R0b206LTFweH0uZmMtc3RpY2t5e3Bvc2l0aW9uOnN0aWNreX0uZmMgLmZjLXZpZXctaGFybmVzc3tmbGV4LWdyb3c6MTtwb3NpdGlvbjpyZWxhdGl2ZX0uZmMgLmZjLXZpZXctaGFybmVzcy1hY3RpdmU+LmZjLXZpZXd7Ym90dG9tOjA7bGVmdDowO3Bvc2l0aW9uOmFic29sdXRlO3JpZ2h0OjA7dG9wOjB9LmZjIC5mYy1jb2wtaGVhZGVyLWNlbGwtY3VzaGlvbntkaXNwbGF5OmlubGluZS1ibG9jaztwYWRkaW5nOjJweCA0cHh9LmZjIC5mYy1iZy1ldmVudCwuZmMgLmZjLWhpZ2hsaWdodCwuZmMgLmZjLW5vbi1idXNpbmVzc3tib3R0b206MDtsZWZ0OjA7cG9zaXRpb246YWJzb2x1dGU7cmlnaHQ6MDt0b3A6MH0uZmMgLmZjLW5vbi1idXNpbmVzc3tiYWNrZ3JvdW5kOnZhcigtLWZjLW5vbi1idXNpbmVzcy1jb2xvcil9LmZjIC5mYy1iZy1ldmVudHtiYWNrZ3JvdW5kOnZhcigtLWZjLWJnLWV2ZW50LWNvbG9yKTtvcGFjaXR5OnZhcigtLWZjLWJnLWV2ZW50LW9wYWNpdHkpfS5mYyAuZmMtYmctZXZlbnQgLmZjLWV2ZW50LXRpdGxle2ZvbnQtc2l6ZTp2YXIoLS1mYy1zbWFsbC1mb250LXNpemUpO2ZvbnQtc3R5bGU6aXRhbGljO21hcmdpbjouNWVtfS5mYyAuZmMtaGlnaGxpZ2h0e2JhY2tncm91bmQ6dmFyKC0tZmMtaGlnaGxpZ2h0LWNvbG9yKX0uZmMgLmZjLWNlbGwtc2hhZGVkLC5mYyAuZmMtZGF5LWRpc2FibGVke2JhY2tncm91bmQ6dmFyKC0tZmMtbmV1dHJhbC1iZy1jb2xvcil9YS5mYy1ldmVudCxhLmZjLWV2ZW50OmhvdmVye3RleHQtZGVjb3JhdGlvbjpub25lfS5mYy1ldmVudC5mYy1ldmVudC1kcmFnZ2FibGUsLmZjLWV2ZW50W2hyZWZde2N1cnNvcjpwb2ludGVyfS5mYy1ldmVudCAuZmMtZXZlbnQtbWFpbntwb3NpdGlvbjpyZWxhdGl2ZTt6LWluZGV4OjJ9LmZjLWV2ZW50LWRyYWdnaW5nOm5vdCguZmMtZXZlbnQtc2VsZWN0ZWQpe29wYWNpdHk6Ljc1fS5mYy1ldmVudC1kcmFnZ2luZy5mYy1ldmVudC1zZWxlY3RlZHtib3gtc2hhZG93OjAgMnB4IDdweCByZ2JhKDAsMCwwLC4zKX0uZmMtZXZlbnQgLmZjLWV2ZW50LXJlc2l6ZXJ7ZGlzcGxheTpub25lO3Bvc2l0aW9uOmFic29sdXRlO3otaW5kZXg6NH0uZmMtZXZlbnQtc2VsZWN0ZWQgLmZjLWV2ZW50LXJlc2l6ZXIsLmZjLWV2ZW50OmhvdmVyIC5mYy1ldmVudC1yZXNpemVye2Rpc3BsYXk6YmxvY2t9LmZjLWV2ZW50LXNlbGVjdGVkIC5mYy1ldmVudC1yZXNpemVye2JhY2tncm91bmQ6dmFyKC0tZmMtcGFnZS1iZy1jb2xvcik7Ym9yZGVyLWNvbG9yOmluaGVyaXQ7Ym9yZGVyLXJhZGl1czpjYWxjKHZhcigtLWZjLWV2ZW50LXJlc2l6ZXItZG90LXRvdGFsLXdpZHRoKS8yKTtib3JkZXItc3R5bGU6c29saWQ7Ym9yZGVyLXdpZHRoOnZhcigtLWZjLWV2ZW50LXJlc2l6ZXItZG90LWJvcmRlci13aWR0aCk7aGVpZ2h0OnZhcigtLWZjLWV2ZW50LXJlc2l6ZXItZG90LXRvdGFsLXdpZHRoKTt3aWR0aDp2YXIoLS1mYy1ldmVudC1yZXNpemVyLWRvdC10b3RhbC13aWR0aCl9LmZjLWV2ZW50LXNlbGVjdGVkIC5mYy1ldmVudC1yZXNpemVyOmJlZm9yZXtib3R0b206LTIwcHg7Y29udGVudDpcXFwiXFxcIjtsZWZ0Oi0yMHB4O3Bvc2l0aW9uOmFic29sdXRlO3JpZ2h0Oi0yMHB4O3RvcDotMjBweH0uZmMtZXZlbnQtc2VsZWN0ZWQsLmZjLWV2ZW50OmZvY3Vze2JveC1zaGFkb3c6MCAycHggNXB4IHJnYmEoMCwwLDAsLjIpfS5mYy1ldmVudC1zZWxlY3RlZDpiZWZvcmUsLmZjLWV2ZW50OmZvY3VzOmJlZm9yZXtib3R0b206MDtjb250ZW50OlxcXCJcXFwiO2xlZnQ6MDtwb3NpdGlvbjphYnNvbHV0ZTtyaWdodDowO3RvcDowO3otaW5kZXg6M30uZmMtZXZlbnQtc2VsZWN0ZWQ6YWZ0ZXIsLmZjLWV2ZW50OmZvY3VzOmFmdGVye2JhY2tncm91bmQ6dmFyKC0tZmMtZXZlbnQtc2VsZWN0ZWQtb3ZlcmxheS1jb2xvcik7Ym90dG9tOi0xcHg7Y29udGVudDpcXFwiXFxcIjtsZWZ0Oi0xcHg7cG9zaXRpb246YWJzb2x1dGU7cmlnaHQ6LTFweDt0b3A6LTFweDt6LWluZGV4OjF9LmZjLWgtZXZlbnR7YmFja2dyb3VuZC1jb2xvcjp2YXIoLS1mYy1ldmVudC1iZy1jb2xvcik7Ym9yZGVyOjFweCBzb2xpZCB2YXIoLS1mYy1ldmVudC1ib3JkZXItY29sb3IpO2Rpc3BsYXk6YmxvY2t9LmZjLWgtZXZlbnQgLmZjLWV2ZW50LW1haW57Y29sb3I6dmFyKC0tZmMtZXZlbnQtdGV4dC1jb2xvcil9LmZjLWgtZXZlbnQgLmZjLWV2ZW50LW1haW4tZnJhbWV7ZGlzcGxheTpmbGV4fS5mYy1oLWV2ZW50IC5mYy1ldmVudC10aW1le21heC13aWR0aDoxMDAlO292ZXJmbG93OmhpZGRlbn0uZmMtaC1ldmVudCAuZmMtZXZlbnQtdGl0bGUtY29udGFpbmVye2ZsZXgtZ3JvdzoxO2ZsZXgtc2hyaW5rOjE7bWluLXdpZHRoOjB9LmZjLWgtZXZlbnQgLmZjLWV2ZW50LXRpdGxle2Rpc3BsYXk6aW5saW5lLWJsb2NrO2xlZnQ6MDttYXgtd2lkdGg6MTAwJTtvdmVyZmxvdzpoaWRkZW47cmlnaHQ6MDt2ZXJ0aWNhbC1hbGlnbjp0b3B9LmZjLWgtZXZlbnQuZmMtZXZlbnQtc2VsZWN0ZWQ6YmVmb3Jle2JvdHRvbTotMTBweDt0b3A6LTEwcHh9LmZjLWRpcmVjdGlvbi1sdHIgLmZjLWRheWdyaWQtYmxvY2stZXZlbnQ6bm90KC5mYy1ldmVudC1zdGFydCksLmZjLWRpcmVjdGlvbi1ydGwgLmZjLWRheWdyaWQtYmxvY2stZXZlbnQ6bm90KC5mYy1ldmVudC1lbmQpe2JvcmRlci1ib3R0b20tbGVmdC1yYWRpdXM6MDtib3JkZXItbGVmdC13aWR0aDowO2JvcmRlci10b3AtbGVmdC1yYWRpdXM6MH0uZmMtZGlyZWN0aW9uLWx0ciAuZmMtZGF5Z3JpZC1ibG9jay1ldmVudDpub3QoLmZjLWV2ZW50LWVuZCksLmZjLWRpcmVjdGlvbi1ydGwgLmZjLWRheWdyaWQtYmxvY2stZXZlbnQ6bm90KC5mYy1ldmVudC1zdGFydCl7Ym9yZGVyLWJvdHRvbS1yaWdodC1yYWRpdXM6MDtib3JkZXItcmlnaHQtd2lkdGg6MDtib3JkZXItdG9wLXJpZ2h0LXJhZGl1czowfS5mYy1oLWV2ZW50Om5vdCguZmMtZXZlbnQtc2VsZWN0ZWQpIC5mYy1ldmVudC1yZXNpemVye2JvdHRvbTowO3RvcDowO3dpZHRoOnZhcigtLWZjLWV2ZW50LXJlc2l6ZXItdGhpY2tuZXNzKX0uZmMtZGlyZWN0aW9uLWx0ciAuZmMtaC1ldmVudDpub3QoLmZjLWV2ZW50LXNlbGVjdGVkKSAuZmMtZXZlbnQtcmVzaXplci1zdGFydCwuZmMtZGlyZWN0aW9uLXJ0bCAuZmMtaC1ldmVudDpub3QoLmZjLWV2ZW50LXNlbGVjdGVkKSAuZmMtZXZlbnQtcmVzaXplci1lbmR7Y3Vyc29yOnctcmVzaXplO2xlZnQ6Y2FsYyh2YXIoLS1mYy1ldmVudC1yZXNpemVyLXRoaWNrbmVzcykqLS41KX0uZmMtZGlyZWN0aW9uLWx0ciAuZmMtaC1ldmVudDpub3QoLmZjLWV2ZW50LXNlbGVjdGVkKSAuZmMtZXZlbnQtcmVzaXplci1lbmQsLmZjLWRpcmVjdGlvbi1ydGwgLmZjLWgtZXZlbnQ6bm90KC5mYy1ldmVudC1zZWxlY3RlZCkgLmZjLWV2ZW50LXJlc2l6ZXItc3RhcnR7Y3Vyc29yOmUtcmVzaXplO3JpZ2h0OmNhbGModmFyKC0tZmMtZXZlbnQtcmVzaXplci10aGlja25lc3MpKi0uNSl9LmZjLWgtZXZlbnQuZmMtZXZlbnQtc2VsZWN0ZWQgLmZjLWV2ZW50LXJlc2l6ZXJ7bWFyZ2luLXRvcDpjYWxjKHZhcigtLWZjLWV2ZW50LXJlc2l6ZXItZG90LXRvdGFsLXdpZHRoKSotLjUpO3RvcDo1MCV9LmZjLWRpcmVjdGlvbi1sdHIgLmZjLWgtZXZlbnQuZmMtZXZlbnQtc2VsZWN0ZWQgLmZjLWV2ZW50LXJlc2l6ZXItc3RhcnQsLmZjLWRpcmVjdGlvbi1ydGwgLmZjLWgtZXZlbnQuZmMtZXZlbnQtc2VsZWN0ZWQgLmZjLWV2ZW50LXJlc2l6ZXItZW5ke2xlZnQ6Y2FsYyh2YXIoLS1mYy1ldmVudC1yZXNpemVyLWRvdC10b3RhbC13aWR0aCkqLS41KX0uZmMtZGlyZWN0aW9uLWx0ciAuZmMtaC1ldmVudC5mYy1ldmVudC1zZWxlY3RlZCAuZmMtZXZlbnQtcmVzaXplci1lbmQsLmZjLWRpcmVjdGlvbi1ydGwgLmZjLWgtZXZlbnQuZmMtZXZlbnQtc2VsZWN0ZWQgLmZjLWV2ZW50LXJlc2l6ZXItc3RhcnR7cmlnaHQ6Y2FsYyh2YXIoLS1mYy1ldmVudC1yZXNpemVyLWRvdC10b3RhbC13aWR0aCkqLS41KX0uZmMgLmZjLXBvcG92ZXJ7Ym94LXNoYWRvdzowIDJweCA2cHggcmdiYSgwLDAsMCwuMTUpO3Bvc2l0aW9uOmFic29sdXRlO3otaW5kZXg6OTk5OX0uZmMgLmZjLXBvcG92ZXItaGVhZGVye2FsaWduLWl0ZW1zOmNlbnRlcjtkaXNwbGF5OmZsZXg7ZmxleC1kaXJlY3Rpb246cm93O2p1c3RpZnktY29udGVudDpzcGFjZS1iZXR3ZWVuO3BhZGRpbmc6M3B4IDRweH0uZmMgLmZjLXBvcG92ZXItdGl0bGV7bWFyZ2luOjAgMnB4fS5mYyAuZmMtcG9wb3Zlci1jbG9zZXtjdXJzb3I6cG9pbnRlcjtmb250LXNpemU6MS4xZW07b3BhY2l0eTouNjV9LmZjLXRoZW1lLXN0YW5kYXJkIC5mYy1wb3BvdmVye2JhY2tncm91bmQ6dmFyKC0tZmMtcGFnZS1iZy1jb2xvcik7Ym9yZGVyOjFweCBzb2xpZCB2YXIoLS1mYy1ib3JkZXItY29sb3IpfS5mYy10aGVtZS1zdGFuZGFyZCAuZmMtcG9wb3Zlci1oZWFkZXJ7YmFja2dyb3VuZDp2YXIoLS1mYy1uZXV0cmFsLWJnLWNvbG9yKX1cIjtcbmluamVjdFN0eWxlcyhjc3NfMjQ4eik7XG5cbmNsYXNzIERlbGF5ZWRSdW5uZXIge1xuICAgIGNvbnN0cnVjdG9yKGRyYWluZWRPcHRpb24pIHtcbiAgICAgICAgdGhpcy5kcmFpbmVkT3B0aW9uID0gZHJhaW5lZE9wdGlvbjtcbiAgICAgICAgdGhpcy5pc1J1bm5pbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5pc0RpcnR5ID0gZmFsc2U7XG4gICAgICAgIHRoaXMucGF1c2VEZXB0aHMgPSB7fTtcbiAgICAgICAgdGhpcy50aW1lb3V0SWQgPSAwO1xuICAgIH1cbiAgICByZXF1ZXN0KGRlbGF5KSB7XG4gICAgICAgIHRoaXMuaXNEaXJ0eSA9IHRydWU7XG4gICAgICAgIGlmICghdGhpcy5pc1BhdXNlZCgpKSB7XG4gICAgICAgICAgICB0aGlzLmNsZWFyVGltZW91dCgpO1xuICAgICAgICAgICAgaWYgKGRlbGF5ID09IG51bGwpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnRyeURyYWluKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnRpbWVvdXRJZCA9IHNldFRpbWVvdXQoLy8gTk9UIE9QVElNQUwhIFRPRE86IGxvb2sgYXQgZGVib3VuY2VcbiAgICAgICAgICAgICAgICB0aGlzLnRyeURyYWluLmJpbmQodGhpcyksIGRlbGF5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICBwYXVzZShzY29wZSA9ICcnKSB7XG4gICAgICAgIGxldCB7IHBhdXNlRGVwdGhzIH0gPSB0aGlzO1xuICAgICAgICBwYXVzZURlcHRoc1tzY29wZV0gPSAocGF1c2VEZXB0aHNbc2NvcGVdIHx8IDApICsgMTtcbiAgICAgICAgdGhpcy5jbGVhclRpbWVvdXQoKTtcbiAgICB9XG4gICAgcmVzdW1lKHNjb3BlID0gJycsIGZvcmNlKSB7XG4gICAgICAgIGxldCB7IHBhdXNlRGVwdGhzIH0gPSB0aGlzO1xuICAgICAgICBpZiAoc2NvcGUgaW4gcGF1c2VEZXB0aHMpIHtcbiAgICAgICAgICAgIGlmIChmb3JjZSkge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBwYXVzZURlcHRoc1tzY29wZV07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXVzZURlcHRoc1tzY29wZV0gLT0gMTtcbiAgICAgICAgICAgICAgICBsZXQgZGVwdGggPSBwYXVzZURlcHRoc1tzY29wZV07XG4gICAgICAgICAgICAgICAgaWYgKGRlcHRoIDw9IDApIHtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHBhdXNlRGVwdGhzW3Njb3BlXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnRyeURyYWluKCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgaXNQYXVzZWQoKSB7XG4gICAgICAgIHJldHVybiBPYmplY3Qua2V5cyh0aGlzLnBhdXNlRGVwdGhzKS5sZW5ndGg7XG4gICAgfVxuICAgIHRyeURyYWluKCkge1xuICAgICAgICBpZiAoIXRoaXMuaXNSdW5uaW5nICYmICF0aGlzLmlzUGF1c2VkKCkpIHtcbiAgICAgICAgICAgIHRoaXMuaXNSdW5uaW5nID0gdHJ1ZTtcbiAgICAgICAgICAgIHdoaWxlICh0aGlzLmlzRGlydHkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmlzRGlydHkgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB0aGlzLmRyYWluZWQoKTsgLy8gbWlnaHQgc2V0IGlzRGlydHkgdG8gdHJ1ZSBhZ2FpblxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5pc1J1bm5pbmcgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBjbGVhcigpIHtcbiAgICAgICAgdGhpcy5jbGVhclRpbWVvdXQoKTtcbiAgICAgICAgdGhpcy5pc0RpcnR5ID0gZmFsc2U7XG4gICAgICAgIHRoaXMucGF1c2VEZXB0aHMgPSB7fTtcbiAgICB9XG4gICAgY2xlYXJUaW1lb3V0KCkge1xuICAgICAgICBpZiAodGhpcy50aW1lb3V0SWQpIHtcbiAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aGlzLnRpbWVvdXRJZCk7XG4gICAgICAgICAgICB0aGlzLnRpbWVvdXRJZCA9IDA7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZHJhaW5lZCgpIHtcbiAgICAgICAgaWYgKHRoaXMuZHJhaW5lZE9wdGlvbikge1xuICAgICAgICAgICAgdGhpcy5kcmFpbmVkT3B0aW9uKCk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmZ1bmN0aW9uIHJlbW92ZUVsZW1lbnQoZWwpIHtcbiAgICBpZiAoZWwucGFyZW50Tm9kZSkge1xuICAgICAgICBlbC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGVsKTtcbiAgICB9XG59XG4vLyBRdWVyeWluZ1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuZnVuY3Rpb24gZWxlbWVudENsb3Nlc3QoZWwsIHNlbGVjdG9yKSB7XG4gICAgaWYgKGVsLmNsb3Nlc3QpIHtcbiAgICAgICAgcmV0dXJuIGVsLmNsb3Nlc3Qoc2VsZWN0b3IpO1xuICAgICAgICAvLyByZWFsbHkgYmFkIGZhbGxiYWNrIGZvciBJRVxuICAgICAgICAvLyBmcm9tIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0FQSS9FbGVtZW50L2Nsb3Nlc3RcbiAgICB9XG4gICAgaWYgKCFkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY29udGFpbnMoZWwpKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBkbyB7XG4gICAgICAgIGlmIChlbGVtZW50TWF0Y2hlcyhlbCwgc2VsZWN0b3IpKSB7XG4gICAgICAgICAgICByZXR1cm4gZWw7XG4gICAgICAgIH1cbiAgICAgICAgZWwgPSAoZWwucGFyZW50RWxlbWVudCB8fCBlbC5wYXJlbnROb2RlKTtcbiAgICB9IHdoaWxlIChlbCAhPT0gbnVsbCAmJiBlbC5ub2RlVHlwZSA9PT0gMSk7XG4gICAgcmV0dXJuIG51bGw7XG59XG5mdW5jdGlvbiBlbGVtZW50TWF0Y2hlcyhlbCwgc2VsZWN0b3IpIHtcbiAgICBsZXQgbWV0aG9kID0gZWwubWF0Y2hlcyB8fCBlbC5tYXRjaGVzU2VsZWN0b3IgfHwgZWwubXNNYXRjaGVzU2VsZWN0b3I7XG4gICAgcmV0dXJuIG1ldGhvZC5jYWxsKGVsLCBzZWxlY3Rvcik7XG59XG4vLyBhY2NlcHRzIG11bHRpcGxlIHN1YmplY3QgZWxzXG4vLyByZXR1cm5zIGEgcmVhbCBhcnJheS4gZ29vZCBmb3IgbWV0aG9kcyBsaWtlIGZvckVhY2hcbi8vIFRPRE86IGFjY2VwdCB0aGUgZG9jdW1lbnRcbmZ1bmN0aW9uIGZpbmRFbGVtZW50cyhjb250YWluZXIsIHNlbGVjdG9yKSB7XG4gICAgbGV0IGNvbnRhaW5lcnMgPSBjb250YWluZXIgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCA/IFtjb250YWluZXJdIDogY29udGFpbmVyO1xuICAgIGxldCBhbGxNYXRjaGVzID0gW107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjb250YWluZXJzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICAgIGxldCBtYXRjaGVzID0gY29udGFpbmVyc1tpXS5xdWVyeVNlbGVjdG9yQWxsKHNlbGVjdG9yKTtcbiAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBtYXRjaGVzLmxlbmd0aDsgaiArPSAxKSB7XG4gICAgICAgICAgICBhbGxNYXRjaGVzLnB1c2gobWF0Y2hlc1tqXSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGFsbE1hdGNoZXM7XG59XG4vLyBhY2NlcHRzIG11bHRpcGxlIHN1YmplY3QgZWxzXG4vLyBvbmx5IHF1ZXJpZXMgZGlyZWN0IGNoaWxkIGVsZW1lbnRzIC8vIFRPRE86IHJlbmFtZSB0byBmaW5kRGlyZWN0Q2hpbGRyZW4hXG5mdW5jdGlvbiBmaW5kRGlyZWN0Q2hpbGRyZW4ocGFyZW50LCBzZWxlY3Rvcikge1xuICAgIGxldCBwYXJlbnRzID0gcGFyZW50IGluc3RhbmNlb2YgSFRNTEVsZW1lbnQgPyBbcGFyZW50XSA6IHBhcmVudDtcbiAgICBsZXQgYWxsTWF0Y2hlcyA9IFtdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcGFyZW50cy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICBsZXQgY2hpbGROb2RlcyA9IHBhcmVudHNbaV0uY2hpbGRyZW47IC8vIG9ubHkgZXZlciBlbGVtZW50c1xuICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IGNoaWxkTm9kZXMubGVuZ3RoOyBqICs9IDEpIHtcbiAgICAgICAgICAgIGxldCBjaGlsZE5vZGUgPSBjaGlsZE5vZGVzW2pdO1xuICAgICAgICAgICAgaWYgKCFzZWxlY3RvciB8fCBlbGVtZW50TWF0Y2hlcyhjaGlsZE5vZGUsIHNlbGVjdG9yKSkge1xuICAgICAgICAgICAgICAgIGFsbE1hdGNoZXMucHVzaChjaGlsZE5vZGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBhbGxNYXRjaGVzO1xufVxuLy8gU3R5bGVcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbmNvbnN0IFBJWEVMX1BST1BfUkUgPSAvKHRvcHxsZWZ0fHJpZ2h0fGJvdHRvbXx3aWR0aHxoZWlnaHQpJC9pO1xuZnVuY3Rpb24gYXBwbHlTdHlsZShlbCwgcHJvcHMpIHtcbiAgICBmb3IgKGxldCBwcm9wTmFtZSBpbiBwcm9wcykge1xuICAgICAgICBhcHBseVN0eWxlUHJvcChlbCwgcHJvcE5hbWUsIHByb3BzW3Byb3BOYW1lXSk7XG4gICAgfVxufVxuZnVuY3Rpb24gYXBwbHlTdHlsZVByb3AoZWwsIG5hbWUsIHZhbCkge1xuICAgIGlmICh2YWwgPT0gbnVsbCkge1xuICAgICAgICBlbC5zdHlsZVtuYW1lXSA9ICcnO1xuICAgIH1cbiAgICBlbHNlIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJyAmJiBQSVhFTF9QUk9QX1JFLnRlc3QobmFtZSkpIHtcbiAgICAgICAgZWwuc3R5bGVbbmFtZV0gPSBgJHt2YWx9cHhgO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgZWwuc3R5bGVbbmFtZV0gPSB2YWw7XG4gICAgfVxufVxuLy8gRXZlbnQgSGFuZGxpbmdcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIGlmIGludGVyY2VwdGluZyBidWJibGVkIGV2ZW50cyBhdCB0aGUgZG9jdW1lbnQvd2luZG93L2JvZHkgbGV2ZWwsXG4vLyBhbmQgd2FudCB0byBzZWUgb3JpZ2luYXRpbmcgZWxlbWVudCAodGhlICd0YXJnZXQnKSwgdXNlIHRoaXMgdXRpbCBpbnN0ZWFkXG4vLyBvZiBgZXYudGFyZ2V0YCBiZWNhdXNlIGl0IGdvZXMgd2l0aGluIHdlYi1jb21wb25lbnQgYm91bmRhcmllcy5cbmZ1bmN0aW9uIGdldEV2ZW50VGFyZ2V0VmlhUm9vdChldikge1xuICAgIHZhciBfYSwgX2I7XG4gICAgcmV0dXJuIChfYiA9IChfYSA9IGV2LmNvbXBvc2VkUGF0aCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmNhbGwoZXYpWzBdKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiBldi50YXJnZXQ7XG59XG4vLyBVbmlxdWUgSUQgZm9yIERPTSBhdHRyaWJ1dGVcbmxldCBndWlkJDEgPSAwO1xuZnVuY3Rpb24gZ2V0VW5pcXVlRG9tSWQoKSB7XG4gICAgZ3VpZCQxICs9IDE7XG4gICAgcmV0dXJuICdmYy1kb20tJyArIGd1aWQkMTtcbn1cblxuLy8gU3RvcHMgYSBtb3VzZS90b3VjaCBldmVudCBmcm9tIGRvaW5nIGl0J3MgbmF0aXZlIGJyb3dzZXIgYWN0aW9uXG5mdW5jdGlvbiBwcmV2ZW50RGVmYXVsdChldikge1xuICAgIGV2LnByZXZlbnREZWZhdWx0KCk7XG59XG4vLyBFdmVudCBEZWxlZ2F0aW9uXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5mdW5jdGlvbiBidWlsZERlbGVnYXRpb25IYW5kbGVyKHNlbGVjdG9yLCBoYW5kbGVyKSB7XG4gICAgcmV0dXJuIChldikgPT4ge1xuICAgICAgICBsZXQgbWF0Y2hlZENoaWxkID0gZWxlbWVudENsb3Nlc3QoZXYudGFyZ2V0LCBzZWxlY3Rvcik7XG4gICAgICAgIGlmIChtYXRjaGVkQ2hpbGQpIHtcbiAgICAgICAgICAgIGhhbmRsZXIuY2FsbChtYXRjaGVkQ2hpbGQsIGV2LCBtYXRjaGVkQ2hpbGQpO1xuICAgICAgICB9XG4gICAgfTtcbn1cbmZ1bmN0aW9uIGxpc3RlbkJ5U2VsZWN0b3IoY29udGFpbmVyLCBldmVudFR5cGUsIHNlbGVjdG9yLCBoYW5kbGVyKSB7XG4gICAgbGV0IGF0dGFjaGVkSGFuZGxlciA9IGJ1aWxkRGVsZWdhdGlvbkhhbmRsZXIoc2VsZWN0b3IsIGhhbmRsZXIpO1xuICAgIGNvbnRhaW5lci5hZGRFdmVudExpc3RlbmVyKGV2ZW50VHlwZSwgYXR0YWNoZWRIYW5kbGVyKTtcbiAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICBjb250YWluZXIucmVtb3ZlRXZlbnRMaXN0ZW5lcihldmVudFR5cGUsIGF0dGFjaGVkSGFuZGxlcik7XG4gICAgfTtcbn1cbmZ1bmN0aW9uIGxpc3RlblRvSG92ZXJCeVNlbGVjdG9yKGNvbnRhaW5lciwgc2VsZWN0b3IsIG9uTW91c2VFbnRlciwgb25Nb3VzZUxlYXZlKSB7XG4gICAgbGV0IGN1cnJlbnRNYXRjaGVkQ2hpbGQ7XG4gICAgcmV0dXJuIGxpc3RlbkJ5U2VsZWN0b3IoY29udGFpbmVyLCAnbW91c2VvdmVyJywgc2VsZWN0b3IsIChtb3VzZU92ZXJFdiwgbWF0Y2hlZENoaWxkKSA9PiB7XG4gICAgICAgIGlmIChtYXRjaGVkQ2hpbGQgIT09IGN1cnJlbnRNYXRjaGVkQ2hpbGQpIHtcbiAgICAgICAgICAgIGN1cnJlbnRNYXRjaGVkQ2hpbGQgPSBtYXRjaGVkQ2hpbGQ7XG4gICAgICAgICAgICBvbk1vdXNlRW50ZXIobW91c2VPdmVyRXYsIG1hdGNoZWRDaGlsZCk7XG4gICAgICAgICAgICBsZXQgcmVhbE9uTW91c2VMZWF2ZSA9IChtb3VzZUxlYXZlRXYpID0+IHtcbiAgICAgICAgICAgICAgICBjdXJyZW50TWF0Y2hlZENoaWxkID0gbnVsbDtcbiAgICAgICAgICAgICAgICBvbk1vdXNlTGVhdmUobW91c2VMZWF2ZUV2LCBtYXRjaGVkQ2hpbGQpO1xuICAgICAgICAgICAgICAgIG1hdGNoZWRDaGlsZC5yZW1vdmVFdmVudExpc3RlbmVyKCdtb3VzZWxlYXZlJywgcmVhbE9uTW91c2VMZWF2ZSk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgLy8gbGlzdGVuIHRvIHRoZSBuZXh0IG1vdXNlbGVhdmUsIGFuZCB0aGVuIHVuYXR0YWNoXG4gICAgICAgICAgICBtYXRjaGVkQ2hpbGQuYWRkRXZlbnRMaXN0ZW5lcignbW91c2VsZWF2ZScsIHJlYWxPbk1vdXNlTGVhdmUpO1xuICAgICAgICB9XG4gICAgfSk7XG59XG4vLyBBbmltYXRpb25cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbmNvbnN0IHRyYW5zaXRpb25FdmVudE5hbWVzID0gW1xuICAgICd3ZWJraXRUcmFuc2l0aW9uRW5kJyxcbiAgICAnb3RyYW5zaXRpb25lbmQnLFxuICAgICdvVHJhbnNpdGlvbkVuZCcsXG4gICAgJ21zVHJhbnNpdGlvbkVuZCcsXG4gICAgJ3RyYW5zaXRpb25lbmQnLFxuXTtcbi8vIHRyaWdnZXJlZCBvbmx5IHdoZW4gdGhlIG5leHQgc2luZ2xlIHN1YnNlcXVlbnQgdHJhbnNpdGlvbiBmaW5pc2hlc1xuZnVuY3Rpb24gd2hlblRyYW5zaXRpb25Eb25lKGVsLCBjYWxsYmFjaykge1xuICAgIGxldCByZWFsQ2FsbGJhY2sgPSAoZXYpID0+IHtcbiAgICAgICAgY2FsbGJhY2soZXYpO1xuICAgICAgICB0cmFuc2l0aW9uRXZlbnROYW1lcy5mb3JFYWNoKChldmVudE5hbWUpID0+IHtcbiAgICAgICAgICAgIGVsLnJlbW92ZUV2ZW50TGlzdGVuZXIoZXZlbnROYW1lLCByZWFsQ2FsbGJhY2spO1xuICAgICAgICB9KTtcbiAgICB9O1xuICAgIHRyYW5zaXRpb25FdmVudE5hbWVzLmZvckVhY2goKGV2ZW50TmFtZSkgPT4ge1xuICAgICAgICBlbC5hZGRFdmVudExpc3RlbmVyKGV2ZW50TmFtZSwgcmVhbENhbGxiYWNrKTsgLy8gY3Jvc3MtYnJvd3NlciB3YXkgdG8gZGV0ZXJtaW5lIHdoZW4gdGhlIHRyYW5zaXRpb24gZmluaXNoZXNcbiAgICB9KTtcbn1cbi8vIEFSSUEgd29ya2Fyb3VuZHNcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbmZ1bmN0aW9uIGNyZWF0ZUFyaWFDbGlja0F0dHJzKGhhbmRsZXIpIHtcbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbih7IG9uQ2xpY2s6IGhhbmRsZXIgfSwgY3JlYXRlQXJpYUtleWJvYXJkQXR0cnMoaGFuZGxlcikpO1xufVxuZnVuY3Rpb24gY3JlYXRlQXJpYUtleWJvYXJkQXR0cnMoaGFuZGxlcikge1xuICAgIHJldHVybiB7XG4gICAgICAgIHRhYkluZGV4OiAwLFxuICAgICAgICBvbktleURvd24oZXYpIHtcbiAgICAgICAgICAgIGlmIChldi5rZXkgPT09ICdFbnRlcicgfHwgZXYua2V5ID09PSAnICcpIHtcbiAgICAgICAgICAgICAgICBoYW5kbGVyKGV2KTtcbiAgICAgICAgICAgICAgICBldi5wcmV2ZW50RGVmYXVsdCgpOyAvLyBpZiBzcGFjZSwgZG9uJ3Qgc2Nyb2xsIGRvd24gcGFnZVxuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgIH07XG59XG5cbmxldCBndWlkTnVtYmVyID0gMDtcbmZ1bmN0aW9uIGd1aWQoKSB7XG4gICAgZ3VpZE51bWJlciArPSAxO1xuICAgIHJldHVybiBTdHJpbmcoZ3VpZE51bWJlcik7XG59XG4vKiBGdWxsQ2FsZW5kYXItc3BlY2lmaWMgRE9NIFV0aWxpdGllc1xuLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG4vLyBNYWtlIHRoZSBtb3VzZSBjdXJzb3IgZXhwcmVzcyB0aGF0IGFuIGV2ZW50IGlzIG5vdCBhbGxvd2VkIGluIHRoZSBjdXJyZW50IGFyZWFcbmZ1bmN0aW9uIGRpc2FibGVDdXJzb3IoKSB7XG4gICAgZG9jdW1lbnQuYm9keS5jbGFzc0xpc3QuYWRkKCdmYy1ub3QtYWxsb3dlZCcpO1xufVxuLy8gUmV0dXJucyB0aGUgbW91c2UgY3Vyc29yIHRvIGl0cyBvcmlnaW5hbCBsb29rXG5mdW5jdGlvbiBlbmFibGVDdXJzb3IoKSB7XG4gICAgZG9jdW1lbnQuYm9keS5jbGFzc0xpc3QucmVtb3ZlKCdmYy1ub3QtYWxsb3dlZCcpO1xufVxuLyogU2VsZWN0aW9uXG4tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbmZ1bmN0aW9uIHByZXZlbnRTZWxlY3Rpb24oZWwpIHtcbiAgICBlbC5zdHlsZS51c2VyU2VsZWN0ID0gJ25vbmUnO1xuICAgIGVsLnN0eWxlLndlYmtpdFVzZXJTZWxlY3QgPSAnbm9uZSc7XG4gICAgZWwuYWRkRXZlbnRMaXN0ZW5lcignc2VsZWN0c3RhcnQnLCBwcmV2ZW50RGVmYXVsdCk7XG59XG5mdW5jdGlvbiBhbGxvd1NlbGVjdGlvbihlbCkge1xuICAgIGVsLnN0eWxlLnVzZXJTZWxlY3QgPSAnJztcbiAgICBlbC5zdHlsZS53ZWJraXRVc2VyU2VsZWN0ID0gJyc7XG4gICAgZWwucmVtb3ZlRXZlbnRMaXN0ZW5lcignc2VsZWN0c3RhcnQnLCBwcmV2ZW50RGVmYXVsdCk7XG59XG4vKiBDb250ZXh0IE1lbnVcbi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuZnVuY3Rpb24gcHJldmVudENvbnRleHRNZW51KGVsKSB7XG4gICAgZWwuYWRkRXZlbnRMaXN0ZW5lcignY29udGV4dG1lbnUnLCBwcmV2ZW50RGVmYXVsdCk7XG59XG5mdW5jdGlvbiBhbGxvd0NvbnRleHRNZW51KGVsKSB7XG4gICAgZWwucmVtb3ZlRXZlbnRMaXN0ZW5lcignY29udGV4dG1lbnUnLCBwcmV2ZW50RGVmYXVsdCk7XG59XG5mdW5jdGlvbiBwYXJzZUZpZWxkU3BlY3MoaW5wdXQpIHtcbiAgICBsZXQgc3BlY3MgPSBbXTtcbiAgICBsZXQgdG9rZW5zID0gW107XG4gICAgbGV0IGk7XG4gICAgbGV0IHRva2VuO1xuICAgIGlmICh0eXBlb2YgaW5wdXQgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgIHRva2VucyA9IGlucHV0LnNwbGl0KC9cXHMqLFxccyovKTtcbiAgICB9XG4gICAgZWxzZSBpZiAodHlwZW9mIGlucHV0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHRva2VucyA9IFtpbnB1dF07XG4gICAgfVxuICAgIGVsc2UgaWYgKEFycmF5LmlzQXJyYXkoaW5wdXQpKSB7XG4gICAgICAgIHRva2VucyA9IGlucHV0O1xuICAgIH1cbiAgICBmb3IgKGkgPSAwOyBpIDwgdG9rZW5zLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICAgIHRva2VuID0gdG9rZW5zW2ldO1xuICAgICAgICBpZiAodHlwZW9mIHRva2VuID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgc3BlY3MucHVzaCh0b2tlbi5jaGFyQXQoMCkgPT09ICctJyA/XG4gICAgICAgICAgICAgICAgeyBmaWVsZDogdG9rZW4uc3Vic3RyaW5nKDEpLCBvcmRlcjogLTEgfSA6XG4gICAgICAgICAgICAgICAgeyBmaWVsZDogdG9rZW4sIG9yZGVyOiAxIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHR5cGVvZiB0b2tlbiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgc3BlY3MucHVzaCh7IGZ1bmM6IHRva2VuIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBzcGVjcztcbn1cbmZ1bmN0aW9uIGNvbXBhcmVCeUZpZWxkU3BlY3Mob2JqMCwgb2JqMSwgZmllbGRTcGVjcykge1xuICAgIGxldCBpO1xuICAgIGxldCBjbXA7XG4gICAgZm9yIChpID0gMDsgaSA8IGZpZWxkU3BlY3MubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgY21wID0gY29tcGFyZUJ5RmllbGRTcGVjKG9iajAsIG9iajEsIGZpZWxkU3BlY3NbaV0pO1xuICAgICAgICBpZiAoY21wKSB7XG4gICAgICAgICAgICByZXR1cm4gY21wO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiAwO1xufVxuZnVuY3Rpb24gY29tcGFyZUJ5RmllbGRTcGVjKG9iajAsIG9iajEsIGZpZWxkU3BlYykge1xuICAgIGlmIChmaWVsZFNwZWMuZnVuYykge1xuICAgICAgICByZXR1cm4gZmllbGRTcGVjLmZ1bmMob2JqMCwgb2JqMSk7XG4gICAgfVxuICAgIHJldHVybiBmbGV4aWJsZUNvbXBhcmUob2JqMFtmaWVsZFNwZWMuZmllbGRdLCBvYmoxW2ZpZWxkU3BlYy5maWVsZF0pXG4gICAgICAgICogKGZpZWxkU3BlYy5vcmRlciB8fCAxKTtcbn1cbmZ1bmN0aW9uIGZsZXhpYmxlQ29tcGFyZShhLCBiKSB7XG4gICAgaWYgKCFhICYmICFiKSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgIH1cbiAgICBpZiAoYiA9PSBudWxsKSB7XG4gICAgICAgIHJldHVybiAtMTtcbiAgICB9XG4gICAgaWYgKGEgPT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gMTtcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBhID09PSAnc3RyaW5nJyB8fCB0eXBlb2YgYiA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgcmV0dXJuIFN0cmluZyhhKS5sb2NhbGVDb21wYXJlKFN0cmluZyhiKSk7XG4gICAgfVxuICAgIHJldHVybiBhIC0gYjtcbn1cbi8qIFN0cmluZyBVdGlsaXRpZXNcbi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuZnVuY3Rpb24gcGFkU3RhcnQodmFsLCBsZW4pIHtcbiAgICBsZXQgcyA9IFN0cmluZyh2YWwpO1xuICAgIHJldHVybiAnMDAwJy5zdWJzdHIoMCwgbGVuIC0gcy5sZW5ndGgpICsgcztcbn1cbmZ1bmN0aW9uIGZvcm1hdFdpdGhPcmRpbmFscyhmb3JtYXR0ZXIsIGFyZ3MsIGZhbGxiYWNrVGV4dCkge1xuICAgIGlmICh0eXBlb2YgZm9ybWF0dGVyID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHJldHVybiBmb3JtYXR0ZXIoLi4uYXJncyk7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgZm9ybWF0dGVyID09PSAnc3RyaW5nJykgeyAvLyBub24tYmxhbmsgc3RyaW5nXG4gICAgICAgIHJldHVybiBhcmdzLnJlZHVjZSgoc3RyLCBhcmcsIGluZGV4KSA9PiAoc3RyLnJlcGxhY2UoJyQnICsgaW5kZXgsIGFyZyB8fCAnJykpLCBmb3JtYXR0ZXIpO1xuICAgIH1cbiAgICByZXR1cm4gZmFsbGJhY2tUZXh0O1xufVxuLyogTnVtYmVyIFV0aWxpdGllc1xuLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5mdW5jdGlvbiBjb21wYXJlTnVtYmVycyhhLCBiKSB7XG4gICAgcmV0dXJuIGEgLSBiO1xufVxuZnVuY3Rpb24gaXNJbnQobikge1xuICAgIHJldHVybiBuICUgMSA9PT0gMDtcbn1cbi8qIEZDLXNwZWNpZmljIERPTSBkaW1lbnNpb24gc3R1ZmZcbi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuZnVuY3Rpb24gY29tcHV0ZVNtYWxsZXN0Q2VsbFdpZHRoKGNlbGxFbCkge1xuICAgIGxldCBhbGxXaWR0aEVsID0gY2VsbEVsLnF1ZXJ5U2VsZWN0b3IoJy5mYy1zY3JvbGxncmlkLXNocmluay1mcmFtZScpO1xuICAgIGxldCBjb250ZW50V2lkdGhFbCA9IGNlbGxFbC5xdWVyeVNlbGVjdG9yKCcuZmMtc2Nyb2xsZ3JpZC1zaHJpbmstY3VzaGlvbicpO1xuICAgIGlmICghYWxsV2lkdGhFbCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ25lZWRzIGZjLXNjcm9sbGdyaWQtc2hyaW5rLWZyYW1lIGNsYXNzTmFtZScpOyAvLyBUT0RPOiB1c2UgY29uc3RcbiAgICB9XG4gICAgaWYgKCFjb250ZW50V2lkdGhFbCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ25lZWRzIGZjLXNjcm9sbGdyaWQtc2hyaW5rLWN1c2hpb24gY2xhc3NOYW1lJyk7XG4gICAgfVxuICAgIHJldHVybiBjZWxsRWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkud2lkdGggLSBhbGxXaWR0aEVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLndpZHRoICsgLy8gdGhlIGNlbGwgcGFkZGluZytib3JkZXJcbiAgICAgICAgY29udGVudFdpZHRoRWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkud2lkdGg7XG59XG5cbmNvbnN0IElOVEVSTkFMX1VOSVRTID0gWyd5ZWFycycsICdtb250aHMnLCAnZGF5cycsICdtaWxsaXNlY29uZHMnXTtcbmNvbnN0IFBBUlNFX1JFID0gL14oLT8pKD86KFxcZCspXFwuKT8oXFxkKyk6KFxcZFxcZCkoPzo6KFxcZFxcZCkoPzpcXC4oXFxkXFxkXFxkKSk/KT8vO1xuLy8gUGFyc2luZyBhbmQgQ3JlYXRpb25cbmZ1bmN0aW9uIGNyZWF0ZUR1cmF0aW9uKGlucHV0LCB1bml0KSB7XG4gICAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgcmV0dXJuIHBhcnNlU3RyaW5nKGlucHV0KTtcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ29iamVjdCcgJiYgaW5wdXQpIHsgLy8gbm9uLW51bGwgb2JqZWN0XG4gICAgICAgIHJldHVybiBwYXJzZU9iamVjdChpbnB1dCk7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgaW5wdXQgPT09ICdudW1iZXInKSB7XG4gICAgICAgIHJldHVybiBwYXJzZU9iamVjdCh7IFt1bml0IHx8ICdtaWxsaXNlY29uZHMnXTogaW5wdXQgfSk7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufVxuZnVuY3Rpb24gcGFyc2VTdHJpbmcocykge1xuICAgIGxldCBtID0gUEFSU0VfUkUuZXhlYyhzKTtcbiAgICBpZiAobSkge1xuICAgICAgICBsZXQgc2lnbiA9IG1bMV0gPyAtMSA6IDE7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB5ZWFyczogMCxcbiAgICAgICAgICAgIG1vbnRoczogMCxcbiAgICAgICAgICAgIGRheXM6IHNpZ24gKiAobVsyXSA/IHBhcnNlSW50KG1bMl0sIDEwKSA6IDApLFxuICAgICAgICAgICAgbWlsbGlzZWNvbmRzOiBzaWduICogKChtWzNdID8gcGFyc2VJbnQobVszXSwgMTApIDogMCkgKiA2MCAqIDYwICogMTAwMCArIC8vIGhvdXJzXG4gICAgICAgICAgICAgICAgKG1bNF0gPyBwYXJzZUludChtWzRdLCAxMCkgOiAwKSAqIDYwICogMTAwMCArIC8vIG1pbnV0ZXNcbiAgICAgICAgICAgICAgICAobVs1XSA/IHBhcnNlSW50KG1bNV0sIDEwKSA6IDApICogMTAwMCArIC8vIHNlY29uZHNcbiAgICAgICAgICAgICAgICAobVs2XSA/IHBhcnNlSW50KG1bNl0sIDEwKSA6IDApIC8vIG1zXG4gICAgICAgICAgICApLFxuICAgICAgICB9O1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cbmZ1bmN0aW9uIHBhcnNlT2JqZWN0KG9iaikge1xuICAgIGxldCBkdXJhdGlvbiA9IHtcbiAgICAgICAgeWVhcnM6IG9iai55ZWFycyB8fCBvYmoueWVhciB8fCAwLFxuICAgICAgICBtb250aHM6IG9iai5tb250aHMgfHwgb2JqLm1vbnRoIHx8IDAsXG4gICAgICAgIGRheXM6IG9iai5kYXlzIHx8IG9iai5kYXkgfHwgMCxcbiAgICAgICAgbWlsbGlzZWNvbmRzOiAob2JqLmhvdXJzIHx8IG9iai5ob3VyIHx8IDApICogNjAgKiA2MCAqIDEwMDAgKyAvLyBob3Vyc1xuICAgICAgICAgICAgKG9iai5taW51dGVzIHx8IG9iai5taW51dGUgfHwgMCkgKiA2MCAqIDEwMDAgKyAvLyBtaW51dGVzXG4gICAgICAgICAgICAob2JqLnNlY29uZHMgfHwgb2JqLnNlY29uZCB8fCAwKSAqIDEwMDAgKyAvLyBzZWNvbmRzXG4gICAgICAgICAgICAob2JqLm1pbGxpc2Vjb25kcyB8fCBvYmoubWlsbGlzZWNvbmQgfHwgb2JqLm1zIHx8IDApLCAvLyBtc1xuICAgIH07XG4gICAgbGV0IHdlZWtzID0gb2JqLndlZWtzIHx8IG9iai53ZWVrO1xuICAgIGlmICh3ZWVrcykge1xuICAgICAgICBkdXJhdGlvbi5kYXlzICs9IHdlZWtzICogNztcbiAgICAgICAgZHVyYXRpb24uc3BlY2lmaWVkV2Vla3MgPSB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZHVyYXRpb247XG59XG4vLyBFcXVhbGl0eVxuZnVuY3Rpb24gZHVyYXRpb25zRXF1YWwoZDAsIGQxKSB7XG4gICAgcmV0dXJuIGQwLnllYXJzID09PSBkMS55ZWFycyAmJlxuICAgICAgICBkMC5tb250aHMgPT09IGQxLm1vbnRocyAmJlxuICAgICAgICBkMC5kYXlzID09PSBkMS5kYXlzICYmXG4gICAgICAgIGQwLm1pbGxpc2Vjb25kcyA9PT0gZDEubWlsbGlzZWNvbmRzO1xufVxuZnVuY3Rpb24gYXNDbGVhbkRheXMoZHVyKSB7XG4gICAgaWYgKCFkdXIueWVhcnMgJiYgIWR1ci5tb250aHMgJiYgIWR1ci5taWxsaXNlY29uZHMpIHtcbiAgICAgICAgcmV0dXJuIGR1ci5kYXlzO1xuICAgIH1cbiAgICByZXR1cm4gMDtcbn1cbi8vIFNpbXBsZSBNYXRoXG5mdW5jdGlvbiBhZGREdXJhdGlvbnMoZDAsIGQxKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgeWVhcnM6IGQwLnllYXJzICsgZDEueWVhcnMsXG4gICAgICAgIG1vbnRoczogZDAubW9udGhzICsgZDEubW9udGhzLFxuICAgICAgICBkYXlzOiBkMC5kYXlzICsgZDEuZGF5cyxcbiAgICAgICAgbWlsbGlzZWNvbmRzOiBkMC5taWxsaXNlY29uZHMgKyBkMS5taWxsaXNlY29uZHMsXG4gICAgfTtcbn1cbmZ1bmN0aW9uIHN1YnRyYWN0RHVyYXRpb25zKGQxLCBkMCkge1xuICAgIHJldHVybiB7XG4gICAgICAgIHllYXJzOiBkMS55ZWFycyAtIGQwLnllYXJzLFxuICAgICAgICBtb250aHM6IGQxLm1vbnRocyAtIGQwLm1vbnRocyxcbiAgICAgICAgZGF5czogZDEuZGF5cyAtIGQwLmRheXMsXG4gICAgICAgIG1pbGxpc2Vjb25kczogZDEubWlsbGlzZWNvbmRzIC0gZDAubWlsbGlzZWNvbmRzLFxuICAgIH07XG59XG5mdW5jdGlvbiBtdWx0aXBseUR1cmF0aW9uKGQsIG4pIHtcbiAgICByZXR1cm4ge1xuICAgICAgICB5ZWFyczogZC55ZWFycyAqIG4sXG4gICAgICAgIG1vbnRoczogZC5tb250aHMgKiBuLFxuICAgICAgICBkYXlzOiBkLmRheXMgKiBuLFxuICAgICAgICBtaWxsaXNlY29uZHM6IGQubWlsbGlzZWNvbmRzICogbixcbiAgICB9O1xufVxuLy8gQ29udmVyc2lvbnNcbi8vIFwiUm91Z2hcIiBiZWNhdXNlIHRoZXkgYXJlIGJhc2VkIG9uIGF2ZXJhZ2UtY2FzZSBHcmVnb3JpYW4gbW9udGhzL3llYXJzXG5mdW5jdGlvbiBhc1JvdWdoWWVhcnMoZHVyKSB7XG4gICAgcmV0dXJuIGFzUm91Z2hEYXlzKGR1cikgLyAzNjU7XG59XG5mdW5jdGlvbiBhc1JvdWdoTW9udGhzKGR1cikge1xuICAgIHJldHVybiBhc1JvdWdoRGF5cyhkdXIpIC8gMzA7XG59XG5mdW5jdGlvbiBhc1JvdWdoRGF5cyhkdXIpIHtcbiAgICByZXR1cm4gYXNSb3VnaE1zKGR1cikgLyA4NjRlNTtcbn1cbmZ1bmN0aW9uIGFzUm91Z2hNaW51dGVzKGR1cikge1xuICAgIHJldHVybiBhc1JvdWdoTXMoZHVyKSAvICgxMDAwICogNjApO1xufVxuZnVuY3Rpb24gYXNSb3VnaFNlY29uZHMoZHVyKSB7XG4gICAgcmV0dXJuIGFzUm91Z2hNcyhkdXIpIC8gMTAwMDtcbn1cbmZ1bmN0aW9uIGFzUm91Z2hNcyhkdXIpIHtcbiAgICByZXR1cm4gZHVyLnllYXJzICogKDM2NSAqIDg2NGU1KSArXG4gICAgICAgIGR1ci5tb250aHMgKiAoMzAgKiA4NjRlNSkgK1xuICAgICAgICBkdXIuZGF5cyAqIDg2NGU1ICtcbiAgICAgICAgZHVyLm1pbGxpc2Vjb25kcztcbn1cbi8vIEFkdmFuY2VkIE1hdGhcbmZ1bmN0aW9uIHdob2xlRGl2aWRlRHVyYXRpb25zKG51bWVyYXRvciwgZGVub21pbmF0b3IpIHtcbiAgICBsZXQgcmVzID0gbnVsbDtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IElOVEVSTkFMX1VOSVRTLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICAgIGxldCB1bml0ID0gSU5URVJOQUxfVU5JVFNbaV07XG4gICAgICAgIGlmIChkZW5vbWluYXRvclt1bml0XSkge1xuICAgICAgICAgICAgbGV0IGxvY2FsUmVzID0gbnVtZXJhdG9yW3VuaXRdIC8gZGVub21pbmF0b3JbdW5pdF07XG4gICAgICAgICAgICBpZiAoIWlzSW50KGxvY2FsUmVzKSB8fCAocmVzICE9PSBudWxsICYmIHJlcyAhPT0gbG9jYWxSZXMpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXMgPSBsb2NhbFJlcztcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChudW1lcmF0b3JbdW5pdF0pIHtcbiAgICAgICAgICAgIC8vIG5lZWRzIHRvIGRpdmlkZSBieSBzb21ldGhpbmcgYnV0IGNhbid0IVxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlcztcbn1cbmZ1bmN0aW9uIGdyZWF0ZXN0RHVyYXRpb25EZW5vbWluYXRvcihkdXIpIHtcbiAgICBsZXQgbXMgPSBkdXIubWlsbGlzZWNvbmRzO1xuICAgIGlmIChtcykge1xuICAgICAgICBpZiAobXMgJSAxMDAwICE9PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4geyB1bml0OiAnbWlsbGlzZWNvbmQnLCB2YWx1ZTogbXMgfTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobXMgJSAoMTAwMCAqIDYwKSAhPT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHsgdW5pdDogJ3NlY29uZCcsIHZhbHVlOiBtcyAvIDEwMDAgfTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobXMgJSAoMTAwMCAqIDYwICogNjApICE9PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4geyB1bml0OiAnbWludXRlJywgdmFsdWU6IG1zIC8gKDEwMDAgKiA2MCkgfTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobXMpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHVuaXQ6ICdob3VyJywgdmFsdWU6IG1zIC8gKDEwMDAgKiA2MCAqIDYwKSB9O1xuICAgICAgICB9XG4gICAgfVxuICAgIGlmIChkdXIuZGF5cykge1xuICAgICAgICBpZiAoZHVyLnNwZWNpZmllZFdlZWtzICYmIGR1ci5kYXlzICUgNyA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHsgdW5pdDogJ3dlZWsnLCB2YWx1ZTogZHVyLmRheXMgLyA3IH07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHsgdW5pdDogJ2RheScsIHZhbHVlOiBkdXIuZGF5cyB9O1xuICAgIH1cbiAgICBpZiAoZHVyLm1vbnRocykge1xuICAgICAgICByZXR1cm4geyB1bml0OiAnbW9udGgnLCB2YWx1ZTogZHVyLm1vbnRocyB9O1xuICAgIH1cbiAgICBpZiAoZHVyLnllYXJzKSB7XG4gICAgICAgIHJldHVybiB7IHVuaXQ6ICd5ZWFyJywgdmFsdWU6IGR1ci55ZWFycyB9O1xuICAgIH1cbiAgICByZXR1cm4geyB1bml0OiAnbWlsbGlzZWNvbmQnLCB2YWx1ZTogMCB9O1xufVxuXG4vLyBUT0RPOiBuZXcgdXRpbCBhcnJheWlmeT9cbmZ1bmN0aW9uIHJlbW92ZUV4YWN0KGFycmF5LCBleGFjdFZhbCkge1xuICAgIGxldCByZW1vdmVDbnQgPSAwO1xuICAgIGxldCBpID0gMDtcbiAgICB3aGlsZSAoaSA8IGFycmF5Lmxlbmd0aCkge1xuICAgICAgICBpZiAoYXJyYXlbaV0gPT09IGV4YWN0VmFsKSB7XG4gICAgICAgICAgICBhcnJheS5zcGxpY2UoaSwgMSk7XG4gICAgICAgICAgICByZW1vdmVDbnQgKz0gMTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGkgKz0gMTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVtb3ZlQ250O1xufVxuZnVuY3Rpb24gaXNBcnJheXNFcXVhbChhMCwgYTEsIGVxdWFsaXR5RnVuYykge1xuICAgIGlmIChhMCA9PT0gYTEpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGxldCBsZW4gPSBhMC5sZW5ndGg7XG4gICAgbGV0IGk7XG4gICAgaWYgKGxlbiAhPT0gYTEubGVuZ3RoKSB7IC8vIG5vdCBhcnJheT8gb3Igbm90IHNhbWUgbGVuZ3RoP1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkgKz0gMSkge1xuICAgICAgICBpZiAoIShlcXVhbGl0eUZ1bmMgPyBlcXVhbGl0eUZ1bmMoYTBbaV0sIGExW2ldKSA6IGEwW2ldID09PSBhMVtpXSkpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn1cblxuY29uc3QgREFZX0lEUyA9IFsnc3VuJywgJ21vbicsICd0dWUnLCAnd2VkJywgJ3RodScsICdmcmknLCAnc2F0J107XG4vLyBBZGRpbmdcbmZ1bmN0aW9uIGFkZFdlZWtzKG0sIG4pIHtcbiAgICBsZXQgYSA9IGRhdGVUb1V0Y0FycmF5KG0pO1xuICAgIGFbMl0gKz0gbiAqIDc7XG4gICAgcmV0dXJuIGFycmF5VG9VdGNEYXRlKGEpO1xufVxuZnVuY3Rpb24gYWRkRGF5cyhtLCBuKSB7XG4gICAgbGV0IGEgPSBkYXRlVG9VdGNBcnJheShtKTtcbiAgICBhWzJdICs9IG47XG4gICAgcmV0dXJuIGFycmF5VG9VdGNEYXRlKGEpO1xufVxuZnVuY3Rpb24gYWRkTXMobSwgbikge1xuICAgIGxldCBhID0gZGF0ZVRvVXRjQXJyYXkobSk7XG4gICAgYVs2XSArPSBuO1xuICAgIHJldHVybiBhcnJheVRvVXRjRGF0ZShhKTtcbn1cbi8vIERpZmZpbmcgKGFsbCByZXR1cm4gZmxvYXRzKVxuLy8gVE9ETzogd2h5IG5vdCB1c2UgcmFuZ2VzP1xuZnVuY3Rpb24gZGlmZldlZWtzKG0wLCBtMSkge1xuICAgIHJldHVybiBkaWZmRGF5cyhtMCwgbTEpIC8gNztcbn1cbmZ1bmN0aW9uIGRpZmZEYXlzKG0wLCBtMSkge1xuICAgIHJldHVybiAobTEudmFsdWVPZigpIC0gbTAudmFsdWVPZigpKSAvICgxMDAwICogNjAgKiA2MCAqIDI0KTtcbn1cbmZ1bmN0aW9uIGRpZmZIb3VycyhtMCwgbTEpIHtcbiAgICByZXR1cm4gKG0xLnZhbHVlT2YoKSAtIG0wLnZhbHVlT2YoKSkgLyAoMTAwMCAqIDYwICogNjApO1xufVxuZnVuY3Rpb24gZGlmZk1pbnV0ZXMobTAsIG0xKSB7XG4gICAgcmV0dXJuIChtMS52YWx1ZU9mKCkgLSBtMC52YWx1ZU9mKCkpIC8gKDEwMDAgKiA2MCk7XG59XG5mdW5jdGlvbiBkaWZmU2Vjb25kcyhtMCwgbTEpIHtcbiAgICByZXR1cm4gKG0xLnZhbHVlT2YoKSAtIG0wLnZhbHVlT2YoKSkgLyAxMDAwO1xufVxuZnVuY3Rpb24gZGlmZkRheUFuZFRpbWUobTAsIG0xKSB7XG4gICAgbGV0IG0wZGF5ID0gc3RhcnRPZkRheShtMCk7XG4gICAgbGV0IG0xZGF5ID0gc3RhcnRPZkRheShtMSk7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgeWVhcnM6IDAsXG4gICAgICAgIG1vbnRoczogMCxcbiAgICAgICAgZGF5czogTWF0aC5yb3VuZChkaWZmRGF5cyhtMGRheSwgbTFkYXkpKSxcbiAgICAgICAgbWlsbGlzZWNvbmRzOiAobTEudmFsdWVPZigpIC0gbTFkYXkudmFsdWVPZigpKSAtIChtMC52YWx1ZU9mKCkgLSBtMGRheS52YWx1ZU9mKCkpLFxuICAgIH07XG59XG4vLyBEaWZmaW5nIFdob2xlIFVuaXRzXG5mdW5jdGlvbiBkaWZmV2hvbGVXZWVrcyhtMCwgbTEpIHtcbiAgICBsZXQgZCA9IGRpZmZXaG9sZURheXMobTAsIG0xKTtcbiAgICBpZiAoZCAhPT0gbnVsbCAmJiBkICUgNyA9PT0gMCkge1xuICAgICAgICByZXR1cm4gZCAvIDc7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufVxuZnVuY3Rpb24gZGlmZldob2xlRGF5cyhtMCwgbTEpIHtcbiAgICBpZiAodGltZUFzTXMobTApID09PSB0aW1lQXNNcyhtMSkpIHtcbiAgICAgICAgcmV0dXJuIE1hdGgucm91bmQoZGlmZkRheXMobTAsIG0xKSk7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufVxuLy8gU3RhcnQtT2ZcbmZ1bmN0aW9uIHN0YXJ0T2ZEYXkobSkge1xuICAgIHJldHVybiBhcnJheVRvVXRjRGF0ZShbXG4gICAgICAgIG0uZ2V0VVRDRnVsbFllYXIoKSxcbiAgICAgICAgbS5nZXRVVENNb250aCgpLFxuICAgICAgICBtLmdldFVUQ0RhdGUoKSxcbiAgICBdKTtcbn1cbmZ1bmN0aW9uIHN0YXJ0T2ZIb3VyKG0pIHtcbiAgICByZXR1cm4gYXJyYXlUb1V0Y0RhdGUoW1xuICAgICAgICBtLmdldFVUQ0Z1bGxZZWFyKCksXG4gICAgICAgIG0uZ2V0VVRDTW9udGgoKSxcbiAgICAgICAgbS5nZXRVVENEYXRlKCksXG4gICAgICAgIG0uZ2V0VVRDSG91cnMoKSxcbiAgICBdKTtcbn1cbmZ1bmN0aW9uIHN0YXJ0T2ZNaW51dGUobSkge1xuICAgIHJldHVybiBhcnJheVRvVXRjRGF0ZShbXG4gICAgICAgIG0uZ2V0VVRDRnVsbFllYXIoKSxcbiAgICAgICAgbS5nZXRVVENNb250aCgpLFxuICAgICAgICBtLmdldFVUQ0RhdGUoKSxcbiAgICAgICAgbS5nZXRVVENIb3VycygpLFxuICAgICAgICBtLmdldFVUQ01pbnV0ZXMoKSxcbiAgICBdKTtcbn1cbmZ1bmN0aW9uIHN0YXJ0T2ZTZWNvbmQobSkge1xuICAgIHJldHVybiBhcnJheVRvVXRjRGF0ZShbXG4gICAgICAgIG0uZ2V0VVRDRnVsbFllYXIoKSxcbiAgICAgICAgbS5nZXRVVENNb250aCgpLFxuICAgICAgICBtLmdldFVUQ0RhdGUoKSxcbiAgICAgICAgbS5nZXRVVENIb3VycygpLFxuICAgICAgICBtLmdldFVUQ01pbnV0ZXMoKSxcbiAgICAgICAgbS5nZXRVVENTZWNvbmRzKCksXG4gICAgXSk7XG59XG4vLyBXZWVrIENvbXB1dGF0aW9uXG5mdW5jdGlvbiB3ZWVrT2ZZZWFyKG1hcmtlciwgZG93LCBkb3kpIHtcbiAgICBsZXQgeSA9IG1hcmtlci5nZXRVVENGdWxsWWVhcigpO1xuICAgIGxldCB3ID0gd2Vla09mR2l2ZW5ZZWFyKG1hcmtlciwgeSwgZG93LCBkb3kpO1xuICAgIGlmICh3IDwgMSkge1xuICAgICAgICByZXR1cm4gd2Vla09mR2l2ZW5ZZWFyKG1hcmtlciwgeSAtIDEsIGRvdywgZG95KTtcbiAgICB9XG4gICAgbGV0IG5leHRXID0gd2Vla09mR2l2ZW5ZZWFyKG1hcmtlciwgeSArIDEsIGRvdywgZG95KTtcbiAgICBpZiAobmV4dFcgPj0gMSkge1xuICAgICAgICByZXR1cm4gTWF0aC5taW4odywgbmV4dFcpO1xuICAgIH1cbiAgICByZXR1cm4gdztcbn1cbmZ1bmN0aW9uIHdlZWtPZkdpdmVuWWVhcihtYXJrZXIsIHllYXIsIGRvdywgZG95KSB7XG4gICAgbGV0IGZpcnN0V2Vla1N0YXJ0ID0gYXJyYXlUb1V0Y0RhdGUoW3llYXIsIDAsIDEgKyBmaXJzdFdlZWtPZmZzZXQoeWVhciwgZG93LCBkb3kpXSk7XG4gICAgbGV0IGRheVN0YXJ0ID0gc3RhcnRPZkRheShtYXJrZXIpO1xuICAgIGxldCBkYXlzID0gTWF0aC5yb3VuZChkaWZmRGF5cyhmaXJzdFdlZWtTdGFydCwgZGF5U3RhcnQpKTtcbiAgICByZXR1cm4gTWF0aC5mbG9vcihkYXlzIC8gNykgKyAxOyAvLyB6ZXJvLWluZGV4ZWRcbn1cbi8vIHN0YXJ0LW9mLWZpcnN0LXdlZWsgLSBzdGFydC1vZi15ZWFyXG5mdW5jdGlvbiBmaXJzdFdlZWtPZmZzZXQoeWVhciwgZG93LCBkb3kpIHtcbiAgICAvLyBmaXJzdC13ZWVrIGRheSAtLSB3aGljaCBqYW51YXJ5IGlzIGFsd2F5cyBpbiB0aGUgZmlyc3Qgd2VlayAoNCBmb3IgaXNvLCAxIGZvciBvdGhlcilcbiAgICBsZXQgZndkID0gNyArIGRvdyAtIGRveTtcbiAgICAvLyBmaXJzdC13ZWVrIGRheSBsb2NhbCB3ZWVrZGF5IC0tIHdoaWNoIGxvY2FsIHdlZWtkYXkgaXMgZndkXG4gICAgbGV0IGZ3ZGx3ID0gKDcgKyBhcnJheVRvVXRjRGF0ZShbeWVhciwgMCwgZndkXSkuZ2V0VVRDRGF5KCkgLSBkb3cpICUgNztcbiAgICByZXR1cm4gLWZ3ZGx3ICsgZndkIC0gMTtcbn1cbi8vIEFycmF5IENvbnZlcnNpb25cbmZ1bmN0aW9uIGRhdGVUb0xvY2FsQXJyYXkoZGF0ZSkge1xuICAgIHJldHVybiBbXG4gICAgICAgIGRhdGUuZ2V0RnVsbFllYXIoKSxcbiAgICAgICAgZGF0ZS5nZXRNb250aCgpLFxuICAgICAgICBkYXRlLmdldERhdGUoKSxcbiAgICAgICAgZGF0ZS5nZXRIb3VycygpLFxuICAgICAgICBkYXRlLmdldE1pbnV0ZXMoKSxcbiAgICAgICAgZGF0ZS5nZXRTZWNvbmRzKCksXG4gICAgICAgIGRhdGUuZ2V0TWlsbGlzZWNvbmRzKCksXG4gICAgXTtcbn1cbmZ1bmN0aW9uIGFycmF5VG9Mb2NhbERhdGUoYSkge1xuICAgIHJldHVybiBuZXcgRGF0ZShhWzBdLCBhWzFdIHx8IDAsIGFbMl0gPT0gbnVsbCA/IDEgOiBhWzJdLCAvLyBkYXkgb2YgbW9udGhcbiAgICBhWzNdIHx8IDAsIGFbNF0gfHwgMCwgYVs1XSB8fCAwKTtcbn1cbmZ1bmN0aW9uIGRhdGVUb1V0Y0FycmF5KGRhdGUpIHtcbiAgICByZXR1cm4gW1xuICAgICAgICBkYXRlLmdldFVUQ0Z1bGxZZWFyKCksXG4gICAgICAgIGRhdGUuZ2V0VVRDTW9udGgoKSxcbiAgICAgICAgZGF0ZS5nZXRVVENEYXRlKCksXG4gICAgICAgIGRhdGUuZ2V0VVRDSG91cnMoKSxcbiAgICAgICAgZGF0ZS5nZXRVVENNaW51dGVzKCksXG4gICAgICAgIGRhdGUuZ2V0VVRDU2Vjb25kcygpLFxuICAgICAgICBkYXRlLmdldFVUQ01pbGxpc2Vjb25kcygpLFxuICAgIF07XG59XG5mdW5jdGlvbiBhcnJheVRvVXRjRGF0ZShhKSB7XG4gICAgLy8gYWNjb3JkaW5nIHRvIHdlYiBzdGFuZGFyZHMgKGFuZCBTYWZhcmkpLCBhIG1vbnRoIGluZGV4IGlzIHJlcXVpcmVkLlxuICAgIC8vIG1hc3NhZ2UgaWYgb25seSBnaXZlbiBhIHllYXIuXG4gICAgaWYgKGEubGVuZ3RoID09PSAxKSB7XG4gICAgICAgIGEgPSBhLmNvbmNhdChbMF0pO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IERhdGUoRGF0ZS5VVEMoLi4uYSkpO1xufVxuLy8gT3RoZXIgVXRpbHNcbmZ1bmN0aW9uIGlzVmFsaWREYXRlKG0pIHtcbiAgICByZXR1cm4gIWlzTmFOKG0udmFsdWVPZigpKTtcbn1cbmZ1bmN0aW9uIHRpbWVBc01zKG0pIHtcbiAgICByZXR1cm4gbS5nZXRVVENIb3VycygpICogMTAwMCAqIDYwICogNjAgK1xuICAgICAgICBtLmdldFVUQ01pbnV0ZXMoKSAqIDEwMDAgKiA2MCArXG4gICAgICAgIG0uZ2V0VVRDU2Vjb25kcygpICogMTAwMCArXG4gICAgICAgIG0uZ2V0VVRDTWlsbGlzZWNvbmRzKCk7XG59XG5cbi8vIHRpbWVab25lT2Zmc2V0IGlzIGluIG1pbnV0ZXNcbmZ1bmN0aW9uIGJ1aWxkSXNvU3RyaW5nKG1hcmtlciwgdGltZVpvbmVPZmZzZXQsIHN0cmlwWmVyb1RpbWUgPSBmYWxzZSkge1xuICAgIGxldCBzID0gbWFya2VyLnRvSVNPU3RyaW5nKCk7XG4gICAgcyA9IHMucmVwbGFjZSgnLjAwMCcsICcnKTtcbiAgICBpZiAoc3RyaXBaZXJvVGltZSkge1xuICAgICAgICBzID0gcy5yZXBsYWNlKCdUMDA6MDA6MDBaJywgJycpO1xuICAgIH1cbiAgICBpZiAocy5sZW5ndGggPiAxMCkgeyAvLyB0aW1lIHBhcnQgd2Fzbid0IHN0cmlwcGVkLCBjYW4gYWRkIHRpbWV6b25lIGluZm9cbiAgICAgICAgaWYgKHRpbWVab25lT2Zmc2V0ID09IG51bGwpIHtcbiAgICAgICAgICAgIHMgPSBzLnJlcGxhY2UoJ1onLCAnJyk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodGltZVpvbmVPZmZzZXQgIT09IDApIHtcbiAgICAgICAgICAgIHMgPSBzLnJlcGxhY2UoJ1onLCBmb3JtYXRUaW1lWm9uZU9mZnNldCh0aW1lWm9uZU9mZnNldCwgdHJ1ZSkpO1xuICAgICAgICB9XG4gICAgICAgIC8vIG90aGVyd2lzZSwgaXRzIFVUQy0wIGFuZCB3ZSB3YW50IHRvIGtlZXAgdGhlIFpcbiAgICB9XG4gICAgcmV0dXJuIHM7XG59XG4vLyBmb3JtYXRzIHRoZSBkYXRlLCBidXQgd2l0aCBubyB0aW1lIHBhcnRcbi8vIFRPRE86IHNvbWVob3cgbWVyZ2Ugd2l0aCBidWlsZElzb1N0cmluZyBhbmQgc3RyaXBaZXJvVGltZVxuLy8gVE9ETzogcmVuYW1lLiBvbWl0IFwic3RyaW5nXCJcbmZ1bmN0aW9uIGZvcm1hdERheVN0cmluZyhtYXJrZXIpIHtcbiAgICByZXR1cm4gbWFya2VyLnRvSVNPU3RyaW5nKCkucmVwbGFjZSgvVC4qJC8sICcnKTtcbn1cbmZ1bmN0aW9uIGZvcm1hdElzb01vbnRoU3RyKG1hcmtlcikge1xuICAgIHJldHVybiBtYXJrZXIudG9JU09TdHJpbmcoKS5tYXRjaCgvXlxcZHs0fS1cXGR7Mn0vKVswXTtcbn1cbi8vIFRPRE86IHVzZSBEYXRlOjp0b0lTT1N0cmluZyBhbmQgdXNlIGV2ZXJ5dGhpbmcgYWZ0ZXIgdGhlIFQ/XG5mdW5jdGlvbiBmb3JtYXRJc29UaW1lU3RyaW5nKG1hcmtlcikge1xuICAgIHJldHVybiBwYWRTdGFydChtYXJrZXIuZ2V0VVRDSG91cnMoKSwgMikgKyAnOicgK1xuICAgICAgICBwYWRTdGFydChtYXJrZXIuZ2V0VVRDTWludXRlcygpLCAyKSArICc6JyArXG4gICAgICAgIHBhZFN0YXJ0KG1hcmtlci5nZXRVVENTZWNvbmRzKCksIDIpO1xufVxuZnVuY3Rpb24gZm9ybWF0VGltZVpvbmVPZmZzZXQobWludXRlcywgZG9Jc28gPSBmYWxzZSkge1xuICAgIGxldCBzaWduID0gbWludXRlcyA8IDAgPyAnLScgOiAnKyc7XG4gICAgbGV0IGFicyA9IE1hdGguYWJzKG1pbnV0ZXMpO1xuICAgIGxldCBob3VycyA9IE1hdGguZmxvb3IoYWJzIC8gNjApO1xuICAgIGxldCBtaW5zID0gTWF0aC5yb3VuZChhYnMgJSA2MCk7XG4gICAgaWYgKGRvSXNvKSB7XG4gICAgICAgIHJldHVybiBgJHtzaWduICsgcGFkU3RhcnQoaG91cnMsIDIpfToke3BhZFN0YXJ0KG1pbnMsIDIpfWA7XG4gICAgfVxuICAgIHJldHVybiBgR01UJHtzaWdufSR7aG91cnN9JHttaW5zID8gYDoke3BhZFN0YXJ0KG1pbnMsIDIpfWAgOiAnJ31gO1xufVxuXG5mdW5jdGlvbiBtZW1vaXplKHdvcmtlckZ1bmMsIHJlc0VxdWFsaXR5LCB0ZWFyZG93bkZ1bmMpIHtcbiAgICBsZXQgY3VycmVudEFyZ3M7XG4gICAgbGV0IGN1cnJlbnRSZXM7XG4gICAgcmV0dXJuIGZ1bmN0aW9uICguLi5uZXdBcmdzKSB7XG4gICAgICAgIGlmICghY3VycmVudEFyZ3MpIHtcbiAgICAgICAgICAgIGN1cnJlbnRSZXMgPSB3b3JrZXJGdW5jLmFwcGx5KHRoaXMsIG5ld0FyZ3MpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKCFpc0FycmF5c0VxdWFsKGN1cnJlbnRBcmdzLCBuZXdBcmdzKSkge1xuICAgICAgICAgICAgaWYgKHRlYXJkb3duRnVuYykge1xuICAgICAgICAgICAgICAgIHRlYXJkb3duRnVuYyhjdXJyZW50UmVzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCByZXMgPSB3b3JrZXJGdW5jLmFwcGx5KHRoaXMsIG5ld0FyZ3MpO1xuICAgICAgICAgICAgaWYgKCFyZXNFcXVhbGl0eSB8fCAhcmVzRXF1YWxpdHkocmVzLCBjdXJyZW50UmVzKSkge1xuICAgICAgICAgICAgICAgIGN1cnJlbnRSZXMgPSByZXM7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgY3VycmVudEFyZ3MgPSBuZXdBcmdzO1xuICAgICAgICByZXR1cm4gY3VycmVudFJlcztcbiAgICB9O1xufVxuZnVuY3Rpb24gbWVtb2l6ZU9iakFyZyh3b3JrZXJGdW5jLCByZXNFcXVhbGl0eSwgdGVhcmRvd25GdW5jKSB7XG4gICAgbGV0IGN1cnJlbnRBcmc7XG4gICAgbGV0IGN1cnJlbnRSZXM7XG4gICAgcmV0dXJuIChuZXdBcmcpID0+IHtcbiAgICAgICAgaWYgKCFjdXJyZW50QXJnKSB7XG4gICAgICAgICAgICBjdXJyZW50UmVzID0gd29ya2VyRnVuYy5jYWxsKHRoaXMsIG5ld0FyZyk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoIWlzUHJvcHNFcXVhbChjdXJyZW50QXJnLCBuZXdBcmcpKSB7XG4gICAgICAgICAgICBpZiAodGVhcmRvd25GdW5jKSB7XG4gICAgICAgICAgICAgICAgdGVhcmRvd25GdW5jKGN1cnJlbnRSZXMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGV0IHJlcyA9IHdvcmtlckZ1bmMuY2FsbCh0aGlzLCBuZXdBcmcpO1xuICAgICAgICAgICAgaWYgKCFyZXNFcXVhbGl0eSB8fCAhcmVzRXF1YWxpdHkocmVzLCBjdXJyZW50UmVzKSkge1xuICAgICAgICAgICAgICAgIGN1cnJlbnRSZXMgPSByZXM7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgY3VycmVudEFyZyA9IG5ld0FyZztcbiAgICAgICAgcmV0dXJuIGN1cnJlbnRSZXM7XG4gICAgfTtcbn1cbmZ1bmN0aW9uIG1lbW9pemVBcnJheWxpa2UoLy8gdXNlZCBhdCBhbGw/XG53b3JrZXJGdW5jLCByZXNFcXVhbGl0eSwgdGVhcmRvd25GdW5jKSB7XG4gICAgbGV0IGN1cnJlbnRBcmdTZXRzID0gW107XG4gICAgbGV0IGN1cnJlbnRSZXN1bHRzID0gW107XG4gICAgcmV0dXJuIChuZXdBcmdTZXRzKSA9PiB7XG4gICAgICAgIGxldCBjdXJyZW50TGVuID0gY3VycmVudEFyZ1NldHMubGVuZ3RoO1xuICAgICAgICBsZXQgbmV3TGVuID0gbmV3QXJnU2V0cy5sZW5ndGg7XG4gICAgICAgIGxldCBpID0gMDtcbiAgICAgICAgZm9yICg7IGkgPCBjdXJyZW50TGVuOyBpICs9IDEpIHtcbiAgICAgICAgICAgIGlmICghbmV3QXJnU2V0c1tpXSkgeyAvLyBvbmUgb2YgdGhlIG9sZCBzZXRzIG5vIGxvbmdlciBleGlzdHNcbiAgICAgICAgICAgICAgICBpZiAodGVhcmRvd25GdW5jKSB7XG4gICAgICAgICAgICAgICAgICAgIHRlYXJkb3duRnVuYyhjdXJyZW50UmVzdWx0c1tpXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoIWlzQXJyYXlzRXF1YWwoY3VycmVudEFyZ1NldHNbaV0sIG5ld0FyZ1NldHNbaV0pKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRlYXJkb3duRnVuYykge1xuICAgICAgICAgICAgICAgICAgICB0ZWFyZG93bkZ1bmMoY3VycmVudFJlc3VsdHNbaV0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBsZXQgcmVzID0gd29ya2VyRnVuYy5hcHBseSh0aGlzLCBuZXdBcmdTZXRzW2ldKTtcbiAgICAgICAgICAgICAgICBpZiAoIXJlc0VxdWFsaXR5IHx8ICFyZXNFcXVhbGl0eShyZXMsIGN1cnJlbnRSZXN1bHRzW2ldKSkge1xuICAgICAgICAgICAgICAgICAgICBjdXJyZW50UmVzdWx0c1tpXSA9IHJlcztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZm9yICg7IGkgPCBuZXdMZW47IGkgKz0gMSkge1xuICAgICAgICAgICAgY3VycmVudFJlc3VsdHNbaV0gPSB3b3JrZXJGdW5jLmFwcGx5KHRoaXMsIG5ld0FyZ1NldHNbaV0pO1xuICAgICAgICB9XG4gICAgICAgIGN1cnJlbnRBcmdTZXRzID0gbmV3QXJnU2V0cztcbiAgICAgICAgY3VycmVudFJlc3VsdHMuc3BsaWNlKG5ld0xlbik7IC8vIHJlbW92ZSBleGNlc3NcbiAgICAgICAgcmV0dXJuIGN1cnJlbnRSZXN1bHRzO1xuICAgIH07XG59XG5mdW5jdGlvbiBtZW1vaXplSGFzaGxpa2Uod29ya2VyRnVuYywgcmVzRXF1YWxpdHksIHRlYXJkb3duRnVuYykge1xuICAgIGxldCBjdXJyZW50QXJnSGFzaCA9IHt9O1xuICAgIGxldCBjdXJyZW50UmVzSGFzaCA9IHt9O1xuICAgIHJldHVybiAobmV3QXJnSGFzaCkgPT4ge1xuICAgICAgICBsZXQgbmV3UmVzSGFzaCA9IHt9O1xuICAgICAgICBmb3IgKGxldCBrZXkgaW4gbmV3QXJnSGFzaCkge1xuICAgICAgICAgICAgaWYgKCFjdXJyZW50UmVzSGFzaFtrZXldKSB7XG4gICAgICAgICAgICAgICAgbmV3UmVzSGFzaFtrZXldID0gd29ya2VyRnVuYy5hcHBseSh0aGlzLCBuZXdBcmdIYXNoW2tleV0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoIWlzQXJyYXlzRXF1YWwoY3VycmVudEFyZ0hhc2hba2V5XSwgbmV3QXJnSGFzaFtrZXldKSkge1xuICAgICAgICAgICAgICAgIGlmICh0ZWFyZG93bkZ1bmMpIHtcbiAgICAgICAgICAgICAgICAgICAgdGVhcmRvd25GdW5jKGN1cnJlbnRSZXNIYXNoW2tleV0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBsZXQgcmVzID0gd29ya2VyRnVuYy5hcHBseSh0aGlzLCBuZXdBcmdIYXNoW2tleV0pO1xuICAgICAgICAgICAgICAgIG5ld1Jlc0hhc2hba2V5XSA9IChyZXNFcXVhbGl0eSAmJiByZXNFcXVhbGl0eShyZXMsIGN1cnJlbnRSZXNIYXNoW2tleV0pKVxuICAgICAgICAgICAgICAgICAgICA/IGN1cnJlbnRSZXNIYXNoW2tleV1cbiAgICAgICAgICAgICAgICAgICAgOiByZXM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBuZXdSZXNIYXNoW2tleV0gPSBjdXJyZW50UmVzSGFzaFtrZXldO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGN1cnJlbnRBcmdIYXNoID0gbmV3QXJnSGFzaDtcbiAgICAgICAgY3VycmVudFJlc0hhc2ggPSBuZXdSZXNIYXNoO1xuICAgICAgICByZXR1cm4gbmV3UmVzSGFzaDtcbiAgICB9O1xufVxuXG5jb25zdCBFWFRFTkRFRF9TRVRUSU5HU19BTkRfU0VWRVJJVElFUyA9IHtcbiAgICB3ZWVrOiAzLFxuICAgIHNlcGFyYXRvcjogOSxcbiAgICBvbWl0WmVyb01pbnV0ZTogOSxcbiAgICBtZXJpZGllbTogOSxcbiAgICBvbWl0Q29tbWFzOiA5LFxufTtcbmNvbnN0IFNUQU5EQVJEX0RBVEVfUFJPUF9TRVZFUklUSUVTID0ge1xuICAgIHRpbWVab25lTmFtZTogNyxcbiAgICBlcmE6IDYsXG4gICAgeWVhcjogNSxcbiAgICBtb250aDogNCxcbiAgICBkYXk6IDIsXG4gICAgd2Vla2RheTogMixcbiAgICBob3VyOiAxLFxuICAgIG1pbnV0ZTogMSxcbiAgICBzZWNvbmQ6IDEsXG59O1xuY29uc3QgTUVSSURJRU1fUkUgPSAvXFxzKihbYXBdKVxcLj9tXFwuPy9pOyAvLyBlYXRzIHVwIGxlYWRpbmcgc3BhY2VzIHRvb1xuY29uc3QgQ09NTUFfUkUgPSAvLC9nOyAvLyB3ZSBuZWVkIHJlIGZvciBnbG9iYWxuZXNzXG5jb25zdCBNVUxUSV9TUEFDRV9SRSA9IC9cXHMrL2c7XG5jb25zdCBMVFJfUkUgPSAvXFx1MjAwZS9nOyAvLyBjb250cm9sIGNoYXJhY3RlclxuY29uc3QgVVRDX1JFID0gL1VUQ3xHTVQvO1xuY2xhc3MgTmF0aXZlRm9ybWF0dGVyIHtcbiAgICBjb25zdHJ1Y3Rvcihmb3JtYXRTZXR0aW5ncykge1xuICAgICAgICBsZXQgc3RhbmRhcmREYXRlUHJvcHMgPSB7fTtcbiAgICAgICAgbGV0IGV4dGVuZGVkU2V0dGluZ3MgPSB7fTtcbiAgICAgICAgbGV0IHNtYWxsZXN0VW5pdE51bSA9IDk7IC8vIHRoZSBzbWFsbGVzdCB1bml0IGluIHRoZSBmb3JtYXR0ZXIgKDkgaXMgYSBzZW50aW5lbCwgYmV5b25kIG1heClcbiAgICAgICAgZm9yIChsZXQgbmFtZSBpbiBmb3JtYXRTZXR0aW5ncykge1xuICAgICAgICAgICAgaWYgKG5hbWUgaW4gRVhURU5ERURfU0VUVElOR1NfQU5EX1NFVkVSSVRJRVMpIHtcbiAgICAgICAgICAgICAgICBleHRlbmRlZFNldHRpbmdzW25hbWVdID0gZm9ybWF0U2V0dGluZ3NbbmFtZV07XG4gICAgICAgICAgICAgICAgY29uc3Qgc2V2ZXJpdHkgPSBFWFRFTkRFRF9TRVRUSU5HU19BTkRfU0VWRVJJVElFU1tuYW1lXTtcbiAgICAgICAgICAgICAgICBpZiAoc2V2ZXJpdHkgPCA5KSB7XG4gICAgICAgICAgICAgICAgICAgIHNtYWxsZXN0VW5pdE51bSA9IE1hdGgubWluKEVYVEVOREVEX1NFVFRJTkdTX0FORF9TRVZFUklUSUVTW25hbWVdLCBzbWFsbGVzdFVuaXROdW0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHN0YW5kYXJkRGF0ZVByb3BzW25hbWVdID0gZm9ybWF0U2V0dGluZ3NbbmFtZV07XG4gICAgICAgICAgICAgICAgaWYgKG5hbWUgaW4gU1RBTkRBUkRfREFURV9QUk9QX1NFVkVSSVRJRVMpIHsgLy8gVE9ETzogd2hhdCBhYm91dCBob3VyMTI/IG5vIHNldmVyaXR5XG4gICAgICAgICAgICAgICAgICAgIHNtYWxsZXN0VW5pdE51bSA9IE1hdGgubWluKFNUQU5EQVJEX0RBVEVfUFJPUF9TRVZFUklUSUVTW25hbWVdLCBzbWFsbGVzdFVuaXROdW0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLnN0YW5kYXJkRGF0ZVByb3BzID0gc3RhbmRhcmREYXRlUHJvcHM7XG4gICAgICAgIHRoaXMuZXh0ZW5kZWRTZXR0aW5ncyA9IGV4dGVuZGVkU2V0dGluZ3M7XG4gICAgICAgIHRoaXMuc21hbGxlc3RVbml0TnVtID0gc21hbGxlc3RVbml0TnVtO1xuICAgICAgICB0aGlzLmJ1aWxkRm9ybWF0dGluZ0Z1bmMgPSBtZW1vaXplKGJ1aWxkRm9ybWF0dGluZ0Z1bmMpO1xuICAgIH1cbiAgICBmb3JtYXQoZGF0ZSwgY29udGV4dCkge1xuICAgICAgICByZXR1cm4gdGhpcy5idWlsZEZvcm1hdHRpbmdGdW5jKHRoaXMuc3RhbmRhcmREYXRlUHJvcHMsIHRoaXMuZXh0ZW5kZWRTZXR0aW5ncywgY29udGV4dCkoZGF0ZSk7XG4gICAgfVxuICAgIGZvcm1hdFJhbmdlKHN0YXJ0LCBlbmQsIGNvbnRleHQsIGJldHRlckRlZmF1bHRTZXBhcmF0b3IpIHtcbiAgICAgICAgbGV0IHsgc3RhbmRhcmREYXRlUHJvcHMsIGV4dGVuZGVkU2V0dGluZ3MgfSA9IHRoaXM7XG4gICAgICAgIGxldCBkaWZmU2V2ZXJpdHkgPSBjb21wdXRlTWFya2VyRGlmZlNldmVyaXR5KHN0YXJ0Lm1hcmtlciwgZW5kLm1hcmtlciwgY29udGV4dC5jYWxlbmRhclN5c3RlbSk7XG4gICAgICAgIGlmICghZGlmZlNldmVyaXR5KSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5mb3JtYXQoc3RhcnQsIGNvbnRleHQpO1xuICAgICAgICB9XG4gICAgICAgIGxldCBiaWdnZXN0VW5pdEZvclBhcnRpYWwgPSBkaWZmU2V2ZXJpdHk7XG4gICAgICAgIGlmIChiaWdnZXN0VW5pdEZvclBhcnRpYWwgPiAxICYmIC8vIHRoZSB0d28gZGF0ZXMgYXJlIGRpZmZlcmVudCBpbiBhIHdheSB0aGF0J3MgbGFyZ2VyIHNjYWxlIHRoYW4gdGltZVxuICAgICAgICAgICAgKHN0YW5kYXJkRGF0ZVByb3BzLnllYXIgPT09ICdudW1lcmljJyB8fCBzdGFuZGFyZERhdGVQcm9wcy55ZWFyID09PSAnMi1kaWdpdCcpICYmXG4gICAgICAgICAgICAoc3RhbmRhcmREYXRlUHJvcHMubW9udGggPT09ICdudW1lcmljJyB8fCBzdGFuZGFyZERhdGVQcm9wcy5tb250aCA9PT0gJzItZGlnaXQnKSAmJlxuICAgICAgICAgICAgKHN0YW5kYXJkRGF0ZVByb3BzLmRheSA9PT0gJ251bWVyaWMnIHx8IHN0YW5kYXJkRGF0ZVByb3BzLmRheSA9PT0gJzItZGlnaXQnKSkge1xuICAgICAgICAgICAgYmlnZ2VzdFVuaXRGb3JQYXJ0aWFsID0gMTsgLy8gbWFrZSBpdCBsb29rIGxpa2UgdGhlIGRhdGVzIGFyZSBvbmx5IGRpZmZlcmVudCBpbiB0ZXJtcyBvZiB0aW1lXG4gICAgICAgIH1cbiAgICAgICAgbGV0IGZ1bGwwID0gdGhpcy5mb3JtYXQoc3RhcnQsIGNvbnRleHQpO1xuICAgICAgICBsZXQgZnVsbDEgPSB0aGlzLmZvcm1hdChlbmQsIGNvbnRleHQpO1xuICAgICAgICBpZiAoZnVsbDAgPT09IGZ1bGwxKSB7XG4gICAgICAgICAgICByZXR1cm4gZnVsbDA7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHBhcnRpYWxEYXRlUHJvcHMgPSBjb21wdXRlUGFydGlhbEZvcm1hdHRpbmdPcHRpb25zKHN0YW5kYXJkRGF0ZVByb3BzLCBiaWdnZXN0VW5pdEZvclBhcnRpYWwpO1xuICAgICAgICBsZXQgcGFydGlhbEZvcm1hdHRpbmdGdW5jID0gYnVpbGRGb3JtYXR0aW5nRnVuYyhwYXJ0aWFsRGF0ZVByb3BzLCBleHRlbmRlZFNldHRpbmdzLCBjb250ZXh0KTtcbiAgICAgICAgbGV0IHBhcnRpYWwwID0gcGFydGlhbEZvcm1hdHRpbmdGdW5jKHN0YXJ0KTtcbiAgICAgICAgbGV0IHBhcnRpYWwxID0gcGFydGlhbEZvcm1hdHRpbmdGdW5jKGVuZCk7XG4gICAgICAgIGxldCBpbnNlcnRpb24gPSBmaW5kQ29tbW9uSW5zZXJ0aW9uKGZ1bGwwLCBwYXJ0aWFsMCwgZnVsbDEsIHBhcnRpYWwxKTtcbiAgICAgICAgbGV0IHNlcGFyYXRvciA9IGV4dGVuZGVkU2V0dGluZ3Muc2VwYXJhdG9yIHx8IGJldHRlckRlZmF1bHRTZXBhcmF0b3IgfHwgY29udGV4dC5kZWZhdWx0U2VwYXJhdG9yIHx8ICcnO1xuICAgICAgICBpZiAoaW5zZXJ0aW9uKSB7XG4gICAgICAgICAgICByZXR1cm4gaW5zZXJ0aW9uLmJlZm9yZSArIHBhcnRpYWwwICsgc2VwYXJhdG9yICsgcGFydGlhbDEgKyBpbnNlcnRpb24uYWZ0ZXI7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZ1bGwwICsgc2VwYXJhdG9yICsgZnVsbDE7XG4gICAgfVxuICAgIGdldFNtYWxsZXN0VW5pdCgpIHtcbiAgICAgICAgc3dpdGNoICh0aGlzLnNtYWxsZXN0VW5pdE51bSkge1xuICAgICAgICAgICAgY2FzZSA3OlxuICAgICAgICAgICAgY2FzZSA2OlxuICAgICAgICAgICAgY2FzZSA1OlxuICAgICAgICAgICAgICAgIHJldHVybiAneWVhcic7XG4gICAgICAgICAgICBjYXNlIDQ6XG4gICAgICAgICAgICAgICAgcmV0dXJuICdtb250aCc7XG4gICAgICAgICAgICBjYXNlIDM6XG4gICAgICAgICAgICAgICAgcmV0dXJuICd3ZWVrJztcbiAgICAgICAgICAgIGNhc2UgMjpcbiAgICAgICAgICAgICAgICByZXR1cm4gJ2RheSc7XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIHJldHVybiAndGltZSc7IC8vIHJlYWxseT9cbiAgICAgICAgfVxuICAgIH1cbn1cbmZ1bmN0aW9uIGJ1aWxkRm9ybWF0dGluZ0Z1bmMoc3RhbmRhcmREYXRlUHJvcHMsIGV4dGVuZGVkU2V0dGluZ3MsIGNvbnRleHQpIHtcbiAgICBsZXQgc3RhbmRhcmREYXRlUHJvcENudCA9IE9iamVjdC5rZXlzKHN0YW5kYXJkRGF0ZVByb3BzKS5sZW5ndGg7XG4gICAgaWYgKHN0YW5kYXJkRGF0ZVByb3BDbnQgPT09IDEgJiYgc3RhbmRhcmREYXRlUHJvcHMudGltZVpvbmVOYW1lID09PSAnc2hvcnQnKSB7XG4gICAgICAgIHJldHVybiAoZGF0ZSkgPT4gKGZvcm1hdFRpbWVab25lT2Zmc2V0KGRhdGUudGltZVpvbmVPZmZzZXQpKTtcbiAgICB9XG4gICAgaWYgKHN0YW5kYXJkRGF0ZVByb3BDbnQgPT09IDAgJiYgZXh0ZW5kZWRTZXR0aW5ncy53ZWVrKSB7XG4gICAgICAgIHJldHVybiAoZGF0ZSkgPT4gKGZvcm1hdFdlZWtOdW1iZXIoY29udGV4dC5jb21wdXRlV2Vla051bWJlcihkYXRlLm1hcmtlciksIGNvbnRleHQud2Vla1RleHQsIGNvbnRleHQud2Vla1RleHRMb25nLCBjb250ZXh0LmxvY2FsZSwgZXh0ZW5kZWRTZXR0aW5ncy53ZWVrKSk7XG4gICAgfVxuICAgIHJldHVybiBidWlsZE5hdGl2ZUZvcm1hdHRpbmdGdW5jKHN0YW5kYXJkRGF0ZVByb3BzLCBleHRlbmRlZFNldHRpbmdzLCBjb250ZXh0KTtcbn1cbmZ1bmN0aW9uIGJ1aWxkTmF0aXZlRm9ybWF0dGluZ0Z1bmMoc3RhbmRhcmREYXRlUHJvcHMsIGV4dGVuZGVkU2V0dGluZ3MsIGNvbnRleHQpIHtcbiAgICBzdGFuZGFyZERhdGVQcm9wcyA9IE9iamVjdC5hc3NpZ24oe30sIHN0YW5kYXJkRGF0ZVByb3BzKTsgLy8gY29weVxuICAgIGV4dGVuZGVkU2V0dGluZ3MgPSBPYmplY3QuYXNzaWduKHt9LCBleHRlbmRlZFNldHRpbmdzKTsgLy8gY29weVxuICAgIHNhbml0aXplU2V0dGluZ3Moc3RhbmRhcmREYXRlUHJvcHMsIGV4dGVuZGVkU2V0dGluZ3MpO1xuICAgIHN0YW5kYXJkRGF0ZVByb3BzLnRpbWVab25lID0gJ1VUQyc7IC8vIHdlIGxldmVyYWdlIHRoZSBvbmx5IGd1YXJhbnRlZWQgdGltZVpvbmUgZm9yIG91ciBVVEMgbWFya2Vyc1xuICAgIGxldCBub3JtYWxGb3JtYXQgPSBuZXcgSW50bC5EYXRlVGltZUZvcm1hdChjb250ZXh0LmxvY2FsZS5jb2Rlcywgc3RhbmRhcmREYXRlUHJvcHMpO1xuICAgIGxldCB6ZXJvRm9ybWF0OyAvLyBuZWVkZWQ/XG4gICAgaWYgKGV4dGVuZGVkU2V0dGluZ3Mub21pdFplcm9NaW51dGUpIHtcbiAgICAgICAgbGV0IHplcm9Qcm9wcyA9IE9iamVjdC5hc3NpZ24oe30sIHN0YW5kYXJkRGF0ZVByb3BzKTtcbiAgICAgICAgZGVsZXRlIHplcm9Qcm9wcy5taW51dGU7IC8vIHNlY29uZHMgYW5kIG1zIHdlcmUgYWxyZWFkeSBjb25zaWRlcmVkIGluIHNhbml0aXplU2V0dGluZ3NcbiAgICAgICAgemVyb0Zvcm1hdCA9IG5ldyBJbnRsLkRhdGVUaW1lRm9ybWF0KGNvbnRleHQubG9jYWxlLmNvZGVzLCB6ZXJvUHJvcHMpO1xuICAgIH1cbiAgICByZXR1cm4gKGRhdGUpID0+IHtcbiAgICAgICAgbGV0IHsgbWFya2VyIH0gPSBkYXRlO1xuICAgICAgICBsZXQgZm9ybWF0O1xuICAgICAgICBpZiAoemVyb0Zvcm1hdCAmJiAhbWFya2VyLmdldFVUQ01pbnV0ZXMoKSkge1xuICAgICAgICAgICAgZm9ybWF0ID0gemVyb0Zvcm1hdDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGZvcm1hdCA9IG5vcm1hbEZvcm1hdDtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcyA9IGZvcm1hdC5mb3JtYXQobWFya2VyKTtcbiAgICAgICAgcmV0dXJuIHBvc3RQcm9jZXNzKHMsIGRhdGUsIHN0YW5kYXJkRGF0ZVByb3BzLCBleHRlbmRlZFNldHRpbmdzLCBjb250ZXh0KTtcbiAgICB9O1xufVxuZnVuY3Rpb24gc2FuaXRpemVTZXR0aW5ncyhzdGFuZGFyZERhdGVQcm9wcywgZXh0ZW5kZWRTZXR0aW5ncykge1xuICAgIC8vIGRlYWwgd2l0aCBhIGJyb3dzZXIgaW5jb25zaXN0ZW5jeSB3aGVyZSBmb3JtYXR0aW5nIHRoZSB0aW1lem9uZVxuICAgIC8vIHJlcXVpcmVzIHRoYXQgdGhlIGhvdXIvbWludXRlIGJlIHByZXNlbnQuXG4gICAgaWYgKHN0YW5kYXJkRGF0ZVByb3BzLnRpbWVab25lTmFtZSkge1xuICAgICAgICBpZiAoIXN0YW5kYXJkRGF0ZVByb3BzLmhvdXIpIHtcbiAgICAgICAgICAgIHN0YW5kYXJkRGF0ZVByb3BzLmhvdXIgPSAnMi1kaWdpdCc7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzdGFuZGFyZERhdGVQcm9wcy5taW51dGUpIHtcbiAgICAgICAgICAgIHN0YW5kYXJkRGF0ZVByb3BzLm1pbnV0ZSA9ICcyLWRpZ2l0JztcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBvbmx5IHN1cHBvcnQgc2hvcnQgdGltZXpvbmUgbmFtZXNcbiAgICBpZiAoc3RhbmRhcmREYXRlUHJvcHMudGltZVpvbmVOYW1lID09PSAnbG9uZycpIHtcbiAgICAgICAgc3RhbmRhcmREYXRlUHJvcHMudGltZVpvbmVOYW1lID0gJ3Nob3J0JztcbiAgICB9XG4gICAgLy8gaWYgcmVxdWVzdGluZyB0byBkaXNwbGF5IHNlY29uZHMsIE1VU1QgZGlzcGxheSBtaW51dGVzXG4gICAgaWYgKGV4dGVuZGVkU2V0dGluZ3Mub21pdFplcm9NaW51dGUgJiYgKHN0YW5kYXJkRGF0ZVByb3BzLnNlY29uZCB8fCBzdGFuZGFyZERhdGVQcm9wcy5taWxsaXNlY29uZCkpIHtcbiAgICAgICAgZGVsZXRlIGV4dGVuZGVkU2V0dGluZ3Mub21pdFplcm9NaW51dGU7XG4gICAgfVxufVxuZnVuY3Rpb24gcG9zdFByb2Nlc3MocywgZGF0ZSwgc3RhbmRhcmREYXRlUHJvcHMsIGV4dGVuZGVkU2V0dGluZ3MsIGNvbnRleHQpIHtcbiAgICBzID0gcy5yZXBsYWNlKExUUl9SRSwgJycpOyAvLyByZW1vdmUgbGVmdC10by1yaWdodCBjb250cm9sIGNoYXJzLiBkbyBmaXJzdC4gZ29vZCBmb3Igb3RoZXIgcmVnZXhlc1xuICAgIGlmIChzdGFuZGFyZERhdGVQcm9wcy50aW1lWm9uZU5hbWUgPT09ICdzaG9ydCcpIHtcbiAgICAgICAgcyA9IGluamVjdFR6b1N0cihzLCAoY29udGV4dC50aW1lWm9uZSA9PT0gJ1VUQycgfHwgZGF0ZS50aW1lWm9uZU9mZnNldCA9PSBudWxsKSA/XG4gICAgICAgICAgICAnVVRDJyA6IC8vIGltcG9ydGFudCB0byBub3JtYWxpemUgZm9yIElFLCB3aGljaCBkb2VzIFwiR01UXCJcbiAgICAgICAgICAgIGZvcm1hdFRpbWVab25lT2Zmc2V0KGRhdGUudGltZVpvbmVPZmZzZXQpKTtcbiAgICB9XG4gICAgaWYgKGV4dGVuZGVkU2V0dGluZ3Mub21pdENvbW1hcykge1xuICAgICAgICBzID0gcy5yZXBsYWNlKENPTU1BX1JFLCAnJykudHJpbSgpO1xuICAgIH1cbiAgICBpZiAoZXh0ZW5kZWRTZXR0aW5ncy5vbWl0WmVyb01pbnV0ZSkge1xuICAgICAgICBzID0gcy5yZXBsYWNlKCc6MDAnLCAnJyk7IC8vIHplcm9Gb3JtYXQgZG9lc24ndCBhbHdheXMgYWNoaWV2ZSB0aGlzXG4gICAgfVxuICAgIC8vIF4gZG8gYW55dGhpbmcgdGhhdCBtaWdodCBjcmVhdGUgYWRqYWNlbnQgc3BhY2VzIGJlZm9yZSB0aGlzIHBvaW50LFxuICAgIC8vIGJlY2F1c2UgTUVSSURJRU1fUkUgbGlrZXMgdG8gZWF0IHVwIGxvYWRpbmcgc3BhY2VzXG4gICAgaWYgKGV4dGVuZGVkU2V0dGluZ3MubWVyaWRpZW0gPT09IGZhbHNlKSB7XG4gICAgICAgIHMgPSBzLnJlcGxhY2UoTUVSSURJRU1fUkUsICcnKS50cmltKCk7XG4gICAgfVxuICAgIGVsc2UgaWYgKGV4dGVuZGVkU2V0dGluZ3MubWVyaWRpZW0gPT09ICduYXJyb3cnKSB7IC8vIGEvcFxuICAgICAgICBzID0gcy5yZXBsYWNlKE1FUklESUVNX1JFLCAobTAsIG0xKSA9PiBtMS50b0xvY2FsZUxvd2VyQ2FzZSgpKTtcbiAgICB9XG4gICAgZWxzZSBpZiAoZXh0ZW5kZWRTZXR0aW5ncy5tZXJpZGllbSA9PT0gJ3Nob3J0JykgeyAvLyBhbS9wbVxuICAgICAgICBzID0gcy5yZXBsYWNlKE1FUklESUVNX1JFLCAobTAsIG0xKSA9PiBgJHttMS50b0xvY2FsZUxvd2VyQ2FzZSgpfW1gKTtcbiAgICB9XG4gICAgZWxzZSBpZiAoZXh0ZW5kZWRTZXR0aW5ncy5tZXJpZGllbSA9PT0gJ2xvd2VyY2FzZScpIHsgLy8gb3RoZXIgbWVyaWRpZW0gdHJhbnNmb3JtZXJzIGFscmVhZHkgY29udmVydGVkIHRvIGxvd2VyY2FzZVxuICAgICAgICBzID0gcy5yZXBsYWNlKE1FUklESUVNX1JFLCAobTApID0+IG0wLnRvTG9jYWxlTG93ZXJDYXNlKCkpO1xuICAgIH1cbiAgICBzID0gcy5yZXBsYWNlKE1VTFRJX1NQQUNFX1JFLCAnICcpO1xuICAgIHMgPSBzLnRyaW0oKTtcbiAgICByZXR1cm4gcztcbn1cbmZ1bmN0aW9uIGluamVjdFR6b1N0cihzLCB0em9TdHIpIHtcbiAgICBsZXQgcmVwbGFjZWQgPSBmYWxzZTtcbiAgICBzID0gcy5yZXBsYWNlKFVUQ19SRSwgKCkgPT4ge1xuICAgICAgICByZXBsYWNlZCA9IHRydWU7XG4gICAgICAgIHJldHVybiB0em9TdHI7XG4gICAgfSk7XG4gICAgLy8gSUUxMSBkb2Vzbid0IGluY2x1ZGUgVVRDL0dNVCBpbiB0aGUgb3JpZ2luYWwgc3RyaW5nLCBzbyBhcHBlbmQgdG8gZW5kXG4gICAgaWYgKCFyZXBsYWNlZCkge1xuICAgICAgICBzICs9IGAgJHt0em9TdHJ9YDtcbiAgICB9XG4gICAgcmV0dXJuIHM7XG59XG5mdW5jdGlvbiBmb3JtYXRXZWVrTnVtYmVyKG51bSwgd2Vla1RleHQsIHdlZWtUZXh0TG9uZywgbG9jYWxlLCBkaXNwbGF5KSB7XG4gICAgbGV0IHBhcnRzID0gW107XG4gICAgaWYgKGRpc3BsYXkgPT09ICdsb25nJykge1xuICAgICAgICBwYXJ0cy5wdXNoKHdlZWtUZXh0TG9uZyk7XG4gICAgfVxuICAgIGVsc2UgaWYgKGRpc3BsYXkgPT09ICdzaG9ydCcgfHwgZGlzcGxheSA9PT0gJ25hcnJvdycpIHtcbiAgICAgICAgcGFydHMucHVzaCh3ZWVrVGV4dCk7XG4gICAgfVxuICAgIGlmIChkaXNwbGF5ID09PSAnbG9uZycgfHwgZGlzcGxheSA9PT0gJ3Nob3J0Jykge1xuICAgICAgICBwYXJ0cy5wdXNoKCcgJyk7XG4gICAgfVxuICAgIHBhcnRzLnB1c2gobG9jYWxlLnNpbXBsZU51bWJlckZvcm1hdC5mb3JtYXQobnVtKSk7XG4gICAgaWYgKGxvY2FsZS5vcHRpb25zLmRpcmVjdGlvbiA9PT0gJ3J0bCcpIHsgLy8gVE9ETzogdXNlIGNvbnRyb2wgY2hhcmFjdGVycyBpbnN0ZWFkP1xuICAgICAgICBwYXJ0cy5yZXZlcnNlKCk7XG4gICAgfVxuICAgIHJldHVybiBwYXJ0cy5qb2luKCcnKTtcbn1cbi8vIFJhbmdlIEZvcm1hdHRpbmcgVXRpbHNcbi8vIDAgPSBleGFjdGx5IHRoZSBzYW1lXG4vLyAxID0gZGlmZmVyZW50IGJ5IHRpbWVcbi8vIGFuZCBiaWdnZXJcbmZ1bmN0aW9uIGNvbXB1dGVNYXJrZXJEaWZmU2V2ZXJpdHkoZDAsIGQxLCBjYSkge1xuICAgIGlmIChjYS5nZXRNYXJrZXJZZWFyKGQwKSAhPT0gY2EuZ2V0TWFya2VyWWVhcihkMSkpIHtcbiAgICAgICAgcmV0dXJuIDU7XG4gICAgfVxuICAgIGlmIChjYS5nZXRNYXJrZXJNb250aChkMCkgIT09IGNhLmdldE1hcmtlck1vbnRoKGQxKSkge1xuICAgICAgICByZXR1cm4gNDtcbiAgICB9XG4gICAgaWYgKGNhLmdldE1hcmtlckRheShkMCkgIT09IGNhLmdldE1hcmtlckRheShkMSkpIHtcbiAgICAgICAgcmV0dXJuIDI7XG4gICAgfVxuICAgIGlmICh0aW1lQXNNcyhkMCkgIT09IHRpbWVBc01zKGQxKSkge1xuICAgICAgICByZXR1cm4gMTtcbiAgICB9XG4gICAgcmV0dXJuIDA7XG59XG5mdW5jdGlvbiBjb21wdXRlUGFydGlhbEZvcm1hdHRpbmdPcHRpb25zKG9wdGlvbnMsIGJpZ2dlc3RVbml0KSB7XG4gICAgbGV0IHBhcnRpYWxPcHRpb25zID0ge307XG4gICAgZm9yIChsZXQgbmFtZSBpbiBvcHRpb25zKSB7XG4gICAgICAgIGlmICghKG5hbWUgaW4gU1RBTkRBUkRfREFURV9QUk9QX1NFVkVSSVRJRVMpIHx8IC8vIG5vdCBhIGRhdGUgcGFydCBwcm9wIChsaWtlIHRpbWVab25lKVxuICAgICAgICAgICAgU1RBTkRBUkRfREFURV9QUk9QX1NFVkVSSVRJRVNbbmFtZV0gPD0gYmlnZ2VzdFVuaXQpIHtcbiAgICAgICAgICAgIHBhcnRpYWxPcHRpb25zW25hbWVdID0gb3B0aW9uc1tuYW1lXTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcGFydGlhbE9wdGlvbnM7XG59XG5mdW5jdGlvbiBmaW5kQ29tbW9uSW5zZXJ0aW9uKGZ1bGwwLCBwYXJ0aWFsMCwgZnVsbDEsIHBhcnRpYWwxKSB7XG4gICAgbGV0IGkwID0gMDtcbiAgICB3aGlsZSAoaTAgPCBmdWxsMC5sZW5ndGgpIHtcbiAgICAgICAgbGV0IGZvdW5kMCA9IGZ1bGwwLmluZGV4T2YocGFydGlhbDAsIGkwKTtcbiAgICAgICAgaWYgKGZvdW5kMCA9PT0gLTEpIHtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIGxldCBiZWZvcmUwID0gZnVsbDAuc3Vic3RyKDAsIGZvdW5kMCk7XG4gICAgICAgIGkwID0gZm91bmQwICsgcGFydGlhbDAubGVuZ3RoO1xuICAgICAgICBsZXQgYWZ0ZXIwID0gZnVsbDAuc3Vic3RyKGkwKTtcbiAgICAgICAgbGV0IGkxID0gMDtcbiAgICAgICAgd2hpbGUgKGkxIDwgZnVsbDEubGVuZ3RoKSB7XG4gICAgICAgICAgICBsZXQgZm91bmQxID0gZnVsbDEuaW5kZXhPZihwYXJ0aWFsMSwgaTEpO1xuICAgICAgICAgICAgaWYgKGZvdW5kMSA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCBiZWZvcmUxID0gZnVsbDEuc3Vic3RyKDAsIGZvdW5kMSk7XG4gICAgICAgICAgICBpMSA9IGZvdW5kMSArIHBhcnRpYWwxLmxlbmd0aDtcbiAgICAgICAgICAgIGxldCBhZnRlcjEgPSBmdWxsMS5zdWJzdHIoaTEpO1xuICAgICAgICAgICAgaWYgKGJlZm9yZTAgPT09IGJlZm9yZTEgJiYgYWZ0ZXIwID09PSBhZnRlcjEpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICBiZWZvcmU6IGJlZm9yZTAsXG4gICAgICAgICAgICAgICAgICAgIGFmdGVyOiBhZnRlcjAsXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cblxuZnVuY3Rpb24gZXhwYW5kWm9uZWRNYXJrZXIoZGF0ZUluZm8sIGNhbGVuZGFyU3lzdGVtKSB7XG4gICAgbGV0IGEgPSBjYWxlbmRhclN5c3RlbS5tYXJrZXJUb0FycmF5KGRhdGVJbmZvLm1hcmtlcik7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgbWFya2VyOiBkYXRlSW5mby5tYXJrZXIsXG4gICAgICAgIHRpbWVab25lT2Zmc2V0OiBkYXRlSW5mby50aW1lWm9uZU9mZnNldCxcbiAgICAgICAgYXJyYXk6IGEsXG4gICAgICAgIHllYXI6IGFbMF0sXG4gICAgICAgIG1vbnRoOiBhWzFdLFxuICAgICAgICBkYXk6IGFbMl0sXG4gICAgICAgIGhvdXI6IGFbM10sXG4gICAgICAgIG1pbnV0ZTogYVs0XSxcbiAgICAgICAgc2Vjb25kOiBhWzVdLFxuICAgICAgICBtaWxsaXNlY29uZDogYVs2XSxcbiAgICB9O1xufVxuXG5mdW5jdGlvbiBjcmVhdGVWZXJib3NlRm9ybWF0dGluZ0FyZyhzdGFydCwgZW5kLCBjb250ZXh0LCBiZXR0ZXJEZWZhdWx0U2VwYXJhdG9yKSB7XG4gICAgbGV0IHN0YXJ0SW5mbyA9IGV4cGFuZFpvbmVkTWFya2VyKHN0YXJ0LCBjb250ZXh0LmNhbGVuZGFyU3lzdGVtKTtcbiAgICBsZXQgZW5kSW5mbyA9IGVuZCA/IGV4cGFuZFpvbmVkTWFya2VyKGVuZCwgY29udGV4dC5jYWxlbmRhclN5c3RlbSkgOiBudWxsO1xuICAgIHJldHVybiB7XG4gICAgICAgIGRhdGU6IHN0YXJ0SW5mbyxcbiAgICAgICAgc3RhcnQ6IHN0YXJ0SW5mbyxcbiAgICAgICAgZW5kOiBlbmRJbmZvLFxuICAgICAgICB0aW1lWm9uZTogY29udGV4dC50aW1lWm9uZSxcbiAgICAgICAgbG9jYWxlQ29kZXM6IGNvbnRleHQubG9jYWxlLmNvZGVzLFxuICAgICAgICBkZWZhdWx0U2VwYXJhdG9yOiBiZXR0ZXJEZWZhdWx0U2VwYXJhdG9yIHx8IGNvbnRleHQuZGVmYXVsdFNlcGFyYXRvcixcbiAgICB9O1xufVxuXG4vKlxuVE9ETzogZml4IHRoZSB0ZXJtaW5vbG9neSBvZiBcImZvcm1hdHRlclwiIHZzIFwiZm9ybWF0dGluZyBmdW5jXCJcbiovXG4vKlxuQXQgdGhlIHRpbWUgb2YgaW5zdGFudGlhdGlvbiwgdGhpcyBvYmplY3QgZG9lcyBub3Qga25vdyB3aGljaCBjbWQtZm9ybWF0dGluZyBzeXN0ZW0gaXQgd2lsbCB1c2UuXG5JdCByZWNlaXZlcyB0aGlzIGF0IHRoZSB0aW1lIG9mIGZvcm1hdHRpbmcsIGFzIGEgc2V0dGluZy5cbiovXG5jbGFzcyBDbWRGb3JtYXR0ZXIge1xuICAgIGNvbnN0cnVjdG9yKGNtZFN0cikge1xuICAgICAgICB0aGlzLmNtZFN0ciA9IGNtZFN0cjtcbiAgICB9XG4gICAgZm9ybWF0KGRhdGUsIGNvbnRleHQsIGJldHRlckRlZmF1bHRTZXBhcmF0b3IpIHtcbiAgICAgICAgcmV0dXJuIGNvbnRleHQuY21kRm9ybWF0dGVyKHRoaXMuY21kU3RyLCBjcmVhdGVWZXJib3NlRm9ybWF0dGluZ0FyZyhkYXRlLCBudWxsLCBjb250ZXh0LCBiZXR0ZXJEZWZhdWx0U2VwYXJhdG9yKSk7XG4gICAgfVxuICAgIGZvcm1hdFJhbmdlKHN0YXJ0LCBlbmQsIGNvbnRleHQsIGJldHRlckRlZmF1bHRTZXBhcmF0b3IpIHtcbiAgICAgICAgcmV0dXJuIGNvbnRleHQuY21kRm9ybWF0dGVyKHRoaXMuY21kU3RyLCBjcmVhdGVWZXJib3NlRm9ybWF0dGluZ0FyZyhzdGFydCwgZW5kLCBjb250ZXh0LCBiZXR0ZXJEZWZhdWx0U2VwYXJhdG9yKSk7XG4gICAgfVxufVxuXG5jbGFzcyBGdW5jRm9ybWF0dGVyIHtcbiAgICBjb25zdHJ1Y3RvcihmdW5jKSB7XG4gICAgICAgIHRoaXMuZnVuYyA9IGZ1bmM7XG4gICAgfVxuICAgIGZvcm1hdChkYXRlLCBjb250ZXh0LCBiZXR0ZXJEZWZhdWx0U2VwYXJhdG9yKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZ1bmMoY3JlYXRlVmVyYm9zZUZvcm1hdHRpbmdBcmcoZGF0ZSwgbnVsbCwgY29udGV4dCwgYmV0dGVyRGVmYXVsdFNlcGFyYXRvcikpO1xuICAgIH1cbiAgICBmb3JtYXRSYW5nZShzdGFydCwgZW5kLCBjb250ZXh0LCBiZXR0ZXJEZWZhdWx0U2VwYXJhdG9yKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZ1bmMoY3JlYXRlVmVyYm9zZUZvcm1hdHRpbmdBcmcoc3RhcnQsIGVuZCwgY29udGV4dCwgYmV0dGVyRGVmYXVsdFNlcGFyYXRvcikpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gY3JlYXRlRm9ybWF0dGVyKGlucHV0KSB7XG4gICAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ29iamVjdCcgJiYgaW5wdXQpIHsgLy8gbm9uLW51bGwgb2JqZWN0XG4gICAgICAgIHJldHVybiBuZXcgTmF0aXZlRm9ybWF0dGVyKGlucHV0KTtcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBDbWRGb3JtYXR0ZXIoaW5wdXQpO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIGlucHV0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHJldHVybiBuZXcgRnVuY0Zvcm1hdHRlcihpbnB1dCk7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufVxuXG4vLyBiYXNlIG9wdGlvbnNcbi8vIC0tLS0tLS0tLS0tLVxuY29uc3QgQkFTRV9PUFRJT05fUkVGSU5FUlMgPSB7XG4gICAgbmF2TGlua0RheUNsaWNrOiBpZGVudGl0eSxcbiAgICBuYXZMaW5rV2Vla0NsaWNrOiBpZGVudGl0eSxcbiAgICBkdXJhdGlvbjogY3JlYXRlRHVyYXRpb24sXG4gICAgYm9vdHN0cmFwRm9udEF3ZXNvbWU6IGlkZW50aXR5LFxuICAgIGJ1dHRvbkljb25zOiBpZGVudGl0eSxcbiAgICBjdXN0b21CdXR0b25zOiBpZGVudGl0eSxcbiAgICBkZWZhdWx0QWxsRGF5RXZlbnREdXJhdGlvbjogY3JlYXRlRHVyYXRpb24sXG4gICAgZGVmYXVsdFRpbWVkRXZlbnREdXJhdGlvbjogY3JlYXRlRHVyYXRpb24sXG4gICAgbmV4dERheVRocmVzaG9sZDogY3JlYXRlRHVyYXRpb24sXG4gICAgc2Nyb2xsVGltZTogY3JlYXRlRHVyYXRpb24sXG4gICAgc2Nyb2xsVGltZVJlc2V0OiBCb29sZWFuLFxuICAgIHNsb3RNaW5UaW1lOiBjcmVhdGVEdXJhdGlvbixcbiAgICBzbG90TWF4VGltZTogY3JlYXRlRHVyYXRpb24sXG4gICAgZGF5UG9wb3ZlckZvcm1hdDogY3JlYXRlRm9ybWF0dGVyLFxuICAgIHNsb3REdXJhdGlvbjogY3JlYXRlRHVyYXRpb24sXG4gICAgc25hcER1cmF0aW9uOiBjcmVhdGVEdXJhdGlvbixcbiAgICBoZWFkZXJUb29sYmFyOiBpZGVudGl0eSxcbiAgICBmb290ZXJUb29sYmFyOiBpZGVudGl0eSxcbiAgICBkZWZhdWx0UmFuZ2VTZXBhcmF0b3I6IFN0cmluZyxcbiAgICB0aXRsZVJhbmdlU2VwYXJhdG9yOiBTdHJpbmcsXG4gICAgZm9yY2VFdmVudER1cmF0aW9uOiBCb29sZWFuLFxuICAgIGRheUhlYWRlcnM6IEJvb2xlYW4sXG4gICAgZGF5SGVhZGVyRm9ybWF0OiBjcmVhdGVGb3JtYXR0ZXIsXG4gICAgZGF5SGVhZGVyQ2xhc3NOYW1lczogaWRlbnRpdHksXG4gICAgZGF5SGVhZGVyQ29udGVudDogaWRlbnRpdHksXG4gICAgZGF5SGVhZGVyRGlkTW91bnQ6IGlkZW50aXR5LFxuICAgIGRheUhlYWRlcldpbGxVbm1vdW50OiBpZGVudGl0eSxcbiAgICBkYXlDZWxsQ2xhc3NOYW1lczogaWRlbnRpdHksXG4gICAgZGF5Q2VsbENvbnRlbnQ6IGlkZW50aXR5LFxuICAgIGRheUNlbGxEaWRNb3VudDogaWRlbnRpdHksXG4gICAgZGF5Q2VsbFdpbGxVbm1vdW50OiBpZGVudGl0eSxcbiAgICBpbml0aWFsVmlldzogU3RyaW5nLFxuICAgIGFzcGVjdFJhdGlvOiBOdW1iZXIsXG4gICAgd2Vla2VuZHM6IEJvb2xlYW4sXG4gICAgd2Vla051bWJlckNhbGN1bGF0aW9uOiBpZGVudGl0eSxcbiAgICB3ZWVrTnVtYmVyczogQm9vbGVhbixcbiAgICB3ZWVrTnVtYmVyQ2xhc3NOYW1lczogaWRlbnRpdHksXG4gICAgd2Vla051bWJlckNvbnRlbnQ6IGlkZW50aXR5LFxuICAgIHdlZWtOdW1iZXJEaWRNb3VudDogaWRlbnRpdHksXG4gICAgd2Vla051bWJlcldpbGxVbm1vdW50OiBpZGVudGl0eSxcbiAgICBlZGl0YWJsZTogQm9vbGVhbixcbiAgICB2aWV3Q2xhc3NOYW1lczogaWRlbnRpdHksXG4gICAgdmlld0RpZE1vdW50OiBpZGVudGl0eSxcbiAgICB2aWV3V2lsbFVubW91bnQ6IGlkZW50aXR5LFxuICAgIG5vd0luZGljYXRvcjogQm9vbGVhbixcbiAgICBub3dJbmRpY2F0b3JTbmFwOiBpZGVudGl0eSxcbiAgICBub3dJbmRpY2F0b3JDbGFzc05hbWVzOiBpZGVudGl0eSxcbiAgICBub3dJbmRpY2F0b3JDb250ZW50OiBpZGVudGl0eSxcbiAgICBub3dJbmRpY2F0b3JEaWRNb3VudDogaWRlbnRpdHksXG4gICAgbm93SW5kaWNhdG9yV2lsbFVubW91bnQ6IGlkZW50aXR5LFxuICAgIHNob3dOb25DdXJyZW50RGF0ZXM6IEJvb2xlYW4sXG4gICAgbGF6eUZldGNoaW5nOiBCb29sZWFuLFxuICAgIHN0YXJ0UGFyYW06IFN0cmluZyxcbiAgICBlbmRQYXJhbTogU3RyaW5nLFxuICAgIHRpbWVab25lUGFyYW06IFN0cmluZyxcbiAgICB0aW1lWm9uZTogU3RyaW5nLFxuICAgIGxvY2FsZXM6IGlkZW50aXR5LFxuICAgIGxvY2FsZTogaWRlbnRpdHksXG4gICAgdGhlbWVTeXN0ZW06IFN0cmluZyxcbiAgICBkcmFnUmV2ZXJ0RHVyYXRpb246IE51bWJlcixcbiAgICBkcmFnU2Nyb2xsOiBCb29sZWFuLFxuICAgIGFsbERheU1haW50YWluRHVyYXRpb246IEJvb2xlYW4sXG4gICAgdW5zZWxlY3RBdXRvOiBCb29sZWFuLFxuICAgIGRyb3BBY2NlcHQ6IGlkZW50aXR5LFxuICAgIGV2ZW50T3JkZXI6IHBhcnNlRmllbGRTcGVjcyxcbiAgICBldmVudE9yZGVyU3RyaWN0OiBCb29sZWFuLFxuICAgIGhhbmRsZVdpbmRvd1Jlc2l6ZTogQm9vbGVhbixcbiAgICB3aW5kb3dSZXNpemVEZWxheTogTnVtYmVyLFxuICAgIGxvbmdQcmVzc0RlbGF5OiBOdW1iZXIsXG4gICAgZXZlbnREcmFnTWluRGlzdGFuY2U6IE51bWJlcixcbiAgICBleHBhbmRSb3dzOiBCb29sZWFuLFxuICAgIGhlaWdodDogaWRlbnRpdHksXG4gICAgY29udGVudEhlaWdodDogaWRlbnRpdHksXG4gICAgZGlyZWN0aW9uOiBTdHJpbmcsXG4gICAgd2Vla051bWJlckZvcm1hdDogY3JlYXRlRm9ybWF0dGVyLFxuICAgIGV2ZW50UmVzaXphYmxlRnJvbVN0YXJ0OiBCb29sZWFuLFxuICAgIGRpc3BsYXlFdmVudFRpbWU6IEJvb2xlYW4sXG4gICAgZGlzcGxheUV2ZW50RW5kOiBCb29sZWFuLFxuICAgIHdlZWtUZXh0OiBTdHJpbmcsXG4gICAgd2Vla1RleHRMb25nOiBTdHJpbmcsXG4gICAgcHJvZ3Jlc3NpdmVFdmVudFJlbmRlcmluZzogQm9vbGVhbixcbiAgICBidXNpbmVzc0hvdXJzOiBpZGVudGl0eSxcbiAgICBpbml0aWFsRGF0ZTogaWRlbnRpdHksXG4gICAgbm93OiBpZGVudGl0eSxcbiAgICBldmVudERhdGFUcmFuc2Zvcm06IGlkZW50aXR5LFxuICAgIHN0aWNreUhlYWRlckRhdGVzOiBpZGVudGl0eSxcbiAgICBzdGlja3lGb290ZXJTY3JvbGxiYXI6IGlkZW50aXR5LFxuICAgIHZpZXdIZWlnaHQ6IGlkZW50aXR5LFxuICAgIGRlZmF1bHRBbGxEYXk6IEJvb2xlYW4sXG4gICAgZXZlbnRTb3VyY2VGYWlsdXJlOiBpZGVudGl0eSxcbiAgICBldmVudFNvdXJjZVN1Y2Nlc3M6IGlkZW50aXR5LFxuICAgIGV2ZW50RGlzcGxheTogU3RyaW5nLFxuICAgIGV2ZW50U3RhcnRFZGl0YWJsZTogQm9vbGVhbixcbiAgICBldmVudER1cmF0aW9uRWRpdGFibGU6IEJvb2xlYW4sXG4gICAgZXZlbnRPdmVybGFwOiBpZGVudGl0eSxcbiAgICBldmVudENvbnN0cmFpbnQ6IGlkZW50aXR5LFxuICAgIGV2ZW50QWxsb3c6IGlkZW50aXR5LFxuICAgIGV2ZW50QmFja2dyb3VuZENvbG9yOiBTdHJpbmcsXG4gICAgZXZlbnRCb3JkZXJDb2xvcjogU3RyaW5nLFxuICAgIGV2ZW50VGV4dENvbG9yOiBTdHJpbmcsXG4gICAgZXZlbnRDb2xvcjogU3RyaW5nLFxuICAgIGV2ZW50Q2xhc3NOYW1lczogaWRlbnRpdHksXG4gICAgZXZlbnRDb250ZW50OiBpZGVudGl0eSxcbiAgICBldmVudERpZE1vdW50OiBpZGVudGl0eSxcbiAgICBldmVudFdpbGxVbm1vdW50OiBpZGVudGl0eSxcbiAgICBzZWxlY3RDb25zdHJhaW50OiBpZGVudGl0eSxcbiAgICBzZWxlY3RPdmVybGFwOiBpZGVudGl0eSxcbiAgICBzZWxlY3RBbGxvdzogaWRlbnRpdHksXG4gICAgZHJvcHBhYmxlOiBCb29sZWFuLFxuICAgIHVuc2VsZWN0Q2FuY2VsOiBTdHJpbmcsXG4gICAgc2xvdExhYmVsRm9ybWF0OiBpZGVudGl0eSxcbiAgICBzbG90TGFuZUNsYXNzTmFtZXM6IGlkZW50aXR5LFxuICAgIHNsb3RMYW5lQ29udGVudDogaWRlbnRpdHksXG4gICAgc2xvdExhbmVEaWRNb3VudDogaWRlbnRpdHksXG4gICAgc2xvdExhbmVXaWxsVW5tb3VudDogaWRlbnRpdHksXG4gICAgc2xvdExhYmVsQ2xhc3NOYW1lczogaWRlbnRpdHksXG4gICAgc2xvdExhYmVsQ29udGVudDogaWRlbnRpdHksXG4gICAgc2xvdExhYmVsRGlkTW91bnQ6IGlkZW50aXR5LFxuICAgIHNsb3RMYWJlbFdpbGxVbm1vdW50OiBpZGVudGl0eSxcbiAgICBkYXlNYXhFdmVudHM6IGlkZW50aXR5LFxuICAgIGRheU1heEV2ZW50Um93czogaWRlbnRpdHksXG4gICAgZGF5TWluV2lkdGg6IE51bWJlcixcbiAgICBzbG90TGFiZWxJbnRlcnZhbDogY3JlYXRlRHVyYXRpb24sXG4gICAgYWxsRGF5VGV4dDogU3RyaW5nLFxuICAgIGFsbERheUNsYXNzTmFtZXM6IGlkZW50aXR5LFxuICAgIGFsbERheUNvbnRlbnQ6IGlkZW50aXR5LFxuICAgIGFsbERheURpZE1vdW50OiBpZGVudGl0eSxcbiAgICBhbGxEYXlXaWxsVW5tb3VudDogaWRlbnRpdHksXG4gICAgc2xvdE1pbldpZHRoOiBOdW1iZXIsXG4gICAgbmF2TGlua3M6IEJvb2xlYW4sXG4gICAgZXZlbnRUaW1lRm9ybWF0OiBjcmVhdGVGb3JtYXR0ZXIsXG4gICAgcmVyZW5kZXJEZWxheTogTnVtYmVyLFxuICAgIG1vcmVMaW5rVGV4dDogaWRlbnRpdHksXG4gICAgbW9yZUxpbmtIaW50OiBpZGVudGl0eSxcbiAgICBzZWxlY3RNaW5EaXN0YW5jZTogTnVtYmVyLFxuICAgIHNlbGVjdGFibGU6IEJvb2xlYW4sXG4gICAgc2VsZWN0TG9uZ1ByZXNzRGVsYXk6IE51bWJlcixcbiAgICBldmVudExvbmdQcmVzc0RlbGF5OiBOdW1iZXIsXG4gICAgc2VsZWN0TWlycm9yOiBCb29sZWFuLFxuICAgIGV2ZW50TWF4U3RhY2s6IE51bWJlcixcbiAgICBldmVudE1pbkhlaWdodDogTnVtYmVyLFxuICAgIGV2ZW50TWluV2lkdGg6IE51bWJlcixcbiAgICBldmVudFNob3J0SGVpZ2h0OiBOdW1iZXIsXG4gICAgc2xvdEV2ZW50T3ZlcmxhcDogQm9vbGVhbixcbiAgICBwbHVnaW5zOiBpZGVudGl0eSxcbiAgICBmaXJzdERheTogTnVtYmVyLFxuICAgIGRheUNvdW50OiBOdW1iZXIsXG4gICAgZGF0ZUFsaWdubWVudDogU3RyaW5nLFxuICAgIGRhdGVJbmNyZW1lbnQ6IGNyZWF0ZUR1cmF0aW9uLFxuICAgIGhpZGRlbkRheXM6IGlkZW50aXR5LFxuICAgIGZpeGVkV2Vla0NvdW50OiBCb29sZWFuLFxuICAgIHZhbGlkUmFuZ2U6IGlkZW50aXR5LFxuICAgIHZpc2libGVSYW5nZTogaWRlbnRpdHksXG4gICAgdGl0bGVGb3JtYXQ6IGlkZW50aXR5LFxuICAgIGV2ZW50SW50ZXJhY3RpdmU6IEJvb2xlYW4sXG4gICAgLy8gb25seSB1c2VkIGJ5IGxpc3QtdmlldywgYnV0IGxhbmd1YWdlcyBkZWZpbmUgdGhlIHZhbHVlLCBzbyB3ZSBuZWVkIGl0IGluIGJhc2Ugb3B0aW9uc1xuICAgIG5vRXZlbnRzVGV4dDogU3RyaW5nLFxuICAgIHZpZXdIaW50OiBpZGVudGl0eSxcbiAgICBuYXZMaW5rSGludDogaWRlbnRpdHksXG4gICAgY2xvc2VIaW50OiBTdHJpbmcsXG4gICAgdGltZUhpbnQ6IFN0cmluZyxcbiAgICBldmVudEhpbnQ6IFN0cmluZyxcbiAgICBtb3JlTGlua0NsaWNrOiBpZGVudGl0eSxcbiAgICBtb3JlTGlua0NsYXNzTmFtZXM6IGlkZW50aXR5LFxuICAgIG1vcmVMaW5rQ29udGVudDogaWRlbnRpdHksXG4gICAgbW9yZUxpbmtEaWRNb3VudDogaWRlbnRpdHksXG4gICAgbW9yZUxpbmtXaWxsVW5tb3VudDogaWRlbnRpdHksXG4gICAgbW9udGhTdGFydEZvcm1hdDogY3JlYXRlRm9ybWF0dGVyLFxuICAgIC8vIGZvciBjb25uZWN0b3JzXG4gICAgLy8gKGNhbid0IGJlIHBhcnQgb2YgcGx1Z2luIHN5c3RlbSBiL2MgbXVzdCBiZSBwcm92aWRlZCBhdCBydW50aW1lKVxuICAgIGhhbmRsZUN1c3RvbVJlbmRlcmluZzogaWRlbnRpdHksXG4gICAgY3VzdG9tUmVuZGVyaW5nTWV0YU1hcDogaWRlbnRpdHksXG4gICAgY3VzdG9tUmVuZGVyaW5nUmVwbGFjZXM6IEJvb2xlYW4sXG59O1xuLy8gZG8gTk9UIGdpdmUgYSB0eXBlIGhlcmUuIG5lZWQgYHR5cGVvZiBCQVNFX09QVElPTl9ERUZBVUxUU2AgdG8gZ2l2ZSByZWFsIHJlc3VsdHMuXG4vLyByYXcgdmFsdWVzLlxuY29uc3QgQkFTRV9PUFRJT05fREVGQVVMVFMgPSB7XG4gICAgZXZlbnREaXNwbGF5OiAnYXV0bycsXG4gICAgZGVmYXVsdFJhbmdlU2VwYXJhdG9yOiAnIC0gJyxcbiAgICB0aXRsZVJhbmdlU2VwYXJhdG9yOiAnIFxcdTIwMTMgJyxcbiAgICBkZWZhdWx0VGltZWRFdmVudER1cmF0aW9uOiAnMDE6MDA6MDAnLFxuICAgIGRlZmF1bHRBbGxEYXlFdmVudER1cmF0aW9uOiB7IGRheTogMSB9LFxuICAgIGZvcmNlRXZlbnREdXJhdGlvbjogZmFsc2UsXG4gICAgbmV4dERheVRocmVzaG9sZDogJzAwOjAwOjAwJyxcbiAgICBkYXlIZWFkZXJzOiB0cnVlLFxuICAgIGluaXRpYWxWaWV3OiAnJyxcbiAgICBhc3BlY3RSYXRpbzogMS4zNSxcbiAgICBoZWFkZXJUb29sYmFyOiB7XG4gICAgICAgIHN0YXJ0OiAndGl0bGUnLFxuICAgICAgICBjZW50ZXI6ICcnLFxuICAgICAgICBlbmQ6ICd0b2RheSBwcmV2LG5leHQnLFxuICAgIH0sXG4gICAgd2Vla2VuZHM6IHRydWUsXG4gICAgd2Vla051bWJlcnM6IGZhbHNlLFxuICAgIHdlZWtOdW1iZXJDYWxjdWxhdGlvbjogJ2xvY2FsJyxcbiAgICBlZGl0YWJsZTogZmFsc2UsXG4gICAgbm93SW5kaWNhdG9yOiBmYWxzZSxcbiAgICBzY3JvbGxUaW1lOiAnMDY6MDA6MDAnLFxuICAgIHNjcm9sbFRpbWVSZXNldDogdHJ1ZSxcbiAgICBzbG90TWluVGltZTogJzAwOjAwOjAwJyxcbiAgICBzbG90TWF4VGltZTogJzI0OjAwOjAwJyxcbiAgICBzaG93Tm9uQ3VycmVudERhdGVzOiB0cnVlLFxuICAgIGxhenlGZXRjaGluZzogdHJ1ZSxcbiAgICBzdGFydFBhcmFtOiAnc3RhcnQnLFxuICAgIGVuZFBhcmFtOiAnZW5kJyxcbiAgICB0aW1lWm9uZVBhcmFtOiAndGltZVpvbmUnLFxuICAgIHRpbWVab25lOiAnbG9jYWwnLFxuICAgIGxvY2FsZXM6IFtdLFxuICAgIGxvY2FsZTogJycsXG4gICAgdGhlbWVTeXN0ZW06ICdzdGFuZGFyZCcsXG4gICAgZHJhZ1JldmVydER1cmF0aW9uOiA1MDAsXG4gICAgZHJhZ1Njcm9sbDogdHJ1ZSxcbiAgICBhbGxEYXlNYWludGFpbkR1cmF0aW9uOiBmYWxzZSxcbiAgICB1bnNlbGVjdEF1dG86IHRydWUsXG4gICAgZHJvcEFjY2VwdDogJyonLFxuICAgIGV2ZW50T3JkZXI6ICdzdGFydCwtZHVyYXRpb24sYWxsRGF5LHRpdGxlJyxcbiAgICBkYXlQb3BvdmVyRm9ybWF0OiB7IG1vbnRoOiAnbG9uZycsIGRheTogJ251bWVyaWMnLCB5ZWFyOiAnbnVtZXJpYycgfSxcbiAgICBoYW5kbGVXaW5kb3dSZXNpemU6IHRydWUsXG4gICAgd2luZG93UmVzaXplRGVsYXk6IDEwMCxcbiAgICBsb25nUHJlc3NEZWxheTogMTAwMCxcbiAgICBldmVudERyYWdNaW5EaXN0YW5jZTogNSxcbiAgICBleHBhbmRSb3dzOiBmYWxzZSxcbiAgICBuYXZMaW5rczogZmFsc2UsXG4gICAgc2VsZWN0YWJsZTogZmFsc2UsXG4gICAgZXZlbnRNaW5IZWlnaHQ6IDE1LFxuICAgIGV2ZW50TWluV2lkdGg6IDMwLFxuICAgIGV2ZW50U2hvcnRIZWlnaHQ6IDMwLFxuICAgIG1vbnRoU3RhcnRGb3JtYXQ6IHsgbW9udGg6ICdsb25nJywgZGF5OiAnbnVtZXJpYycgfSxcbiAgICBub3dJbmRpY2F0b3JTbmFwOiAnYXV0bycsXG59O1xuLy8gY2FsZW5kYXIgbGlzdGVuZXJzXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS1cbmNvbnN0IENBTEVOREFSX0xJU1RFTkVSX1JFRklORVJTID0ge1xuICAgIGRhdGVzU2V0OiBpZGVudGl0eSxcbiAgICBldmVudHNTZXQ6IGlkZW50aXR5LFxuICAgIGV2ZW50QWRkOiBpZGVudGl0eSxcbiAgICBldmVudENoYW5nZTogaWRlbnRpdHksXG4gICAgZXZlbnRSZW1vdmU6IGlkZW50aXR5LFxuICAgIHdpbmRvd1Jlc2l6ZTogaWRlbnRpdHksXG4gICAgZXZlbnRDbGljazogaWRlbnRpdHksXG4gICAgZXZlbnRNb3VzZUVudGVyOiBpZGVudGl0eSxcbiAgICBldmVudE1vdXNlTGVhdmU6IGlkZW50aXR5LFxuICAgIHNlbGVjdDogaWRlbnRpdHksXG4gICAgdW5zZWxlY3Q6IGlkZW50aXR5LFxuICAgIGxvYWRpbmc6IGlkZW50aXR5LFxuICAgIC8vIGludGVybmFsXG4gICAgX3VubW91bnQ6IGlkZW50aXR5LFxuICAgIF9iZWZvcmVwcmludDogaWRlbnRpdHksXG4gICAgX2FmdGVycHJpbnQ6IGlkZW50aXR5LFxuICAgIF9ub0V2ZW50RHJvcDogaWRlbnRpdHksXG4gICAgX25vRXZlbnRSZXNpemU6IGlkZW50aXR5LFxuICAgIF9yZXNpemU6IGlkZW50aXR5LFxuICAgIF9zY3JvbGxSZXF1ZXN0OiBpZGVudGl0eSxcbn07XG4vLyBjYWxlbmRhci1zcGVjaWZpYyBvcHRpb25zXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5jb25zdCBDQUxFTkRBUl9PUFRJT05fUkVGSU5FUlMgPSB7XG4gICAgYnV0dG9uVGV4dDogaWRlbnRpdHksXG4gICAgYnV0dG9uSGludHM6IGlkZW50aXR5LFxuICAgIHZpZXdzOiBpZGVudGl0eSxcbiAgICBwbHVnaW5zOiBpZGVudGl0eSxcbiAgICBpbml0aWFsRXZlbnRzOiBpZGVudGl0eSxcbiAgICBldmVudHM6IGlkZW50aXR5LFxuICAgIGV2ZW50U291cmNlczogaWRlbnRpdHksXG59O1xuY29uc3QgQ09NUExFWF9PUFRJT05fQ09NUEFSQVRPUlMgPSB7XG4gICAgaGVhZGVyVG9vbGJhcjogaXNNYXliZU9iamVjdHNFcXVhbCxcbiAgICBmb290ZXJUb29sYmFyOiBpc01heWJlT2JqZWN0c0VxdWFsLFxuICAgIGJ1dHRvblRleHQ6IGlzTWF5YmVPYmplY3RzRXF1YWwsXG4gICAgYnV0dG9uSGludHM6IGlzTWF5YmVPYmplY3RzRXF1YWwsXG4gICAgYnV0dG9uSWNvbnM6IGlzTWF5YmVPYmplY3RzRXF1YWwsXG4gICAgZGF0ZUluY3JlbWVudDogaXNNYXliZU9iamVjdHNFcXVhbCxcbiAgICBwbHVnaW5zOiBpc01heWJlQXJyYXlzRXF1YWwsXG4gICAgZXZlbnRzOiBpc01heWJlQXJyYXlzRXF1YWwsXG4gICAgZXZlbnRTb3VyY2VzOiBpc01heWJlQXJyYXlzRXF1YWwsXG4gICAgWydyZXNvdXJjZXMnXTogaXNNYXliZUFycmF5c0VxdWFsLFxufTtcbmZ1bmN0aW9uIGlzTWF5YmVPYmplY3RzRXF1YWwoYSwgYikge1xuICAgIGlmICh0eXBlb2YgYSA9PT0gJ29iamVjdCcgJiYgdHlwZW9mIGIgPT09ICdvYmplY3QnICYmIGEgJiYgYikgeyAvLyBib3RoIG5vbi1udWxsIG9iamVjdHNcbiAgICAgICAgcmV0dXJuIGlzUHJvcHNFcXVhbChhLCBiKTtcbiAgICB9XG4gICAgcmV0dXJuIGEgPT09IGI7XG59XG5mdW5jdGlvbiBpc01heWJlQXJyYXlzRXF1YWwoYSwgYikge1xuICAgIGlmIChBcnJheS5pc0FycmF5KGEpICYmIEFycmF5LmlzQXJyYXkoYikpIHtcbiAgICAgICAgcmV0dXJuIGlzQXJyYXlzRXF1YWwoYSwgYik7XG4gICAgfVxuICAgIHJldHVybiBhID09PSBiO1xufVxuLy8gdmlldy1zcGVjaWZpYyBvcHRpb25zXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS1cbmNvbnN0IFZJRVdfT1BUSU9OX1JFRklORVJTID0ge1xuICAgIHR5cGU6IFN0cmluZyxcbiAgICBjb21wb25lbnQ6IGlkZW50aXR5LFxuICAgIGJ1dHRvblRleHQ6IFN0cmluZyxcbiAgICBidXR0b25UZXh0S2V5OiBTdHJpbmcsXG4gICAgZGF0ZVByb2ZpbGVHZW5lcmF0b3JDbGFzczogaWRlbnRpdHksXG4gICAgdXNlc01pbk1heFRpbWU6IEJvb2xlYW4sXG4gICAgY2xhc3NOYW1lczogaWRlbnRpdHksXG4gICAgY29udGVudDogaWRlbnRpdHksXG4gICAgZGlkTW91bnQ6IGlkZW50aXR5LFxuICAgIHdpbGxVbm1vdW50OiBpZGVudGl0eSxcbn07XG4vLyB1dGlsIGZ1bmNzXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5mdW5jdGlvbiBtZXJnZVJhd09wdGlvbnMob3B0aW9uU2V0cykge1xuICAgIHJldHVybiBtZXJnZVByb3BzKG9wdGlvblNldHMsIENPTVBMRVhfT1BUSU9OX0NPTVBBUkFUT1JTKTtcbn1cbmZ1bmN0aW9uIHJlZmluZVByb3BzKGlucHV0LCByZWZpbmVycykge1xuICAgIGxldCByZWZpbmVkID0ge307XG4gICAgbGV0IGV4dHJhID0ge307XG4gICAgZm9yIChsZXQgcHJvcE5hbWUgaW4gcmVmaW5lcnMpIHtcbiAgICAgICAgaWYgKHByb3BOYW1lIGluIGlucHV0KSB7XG4gICAgICAgICAgICByZWZpbmVkW3Byb3BOYW1lXSA9IHJlZmluZXJzW3Byb3BOYW1lXShpbnB1dFtwcm9wTmFtZV0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIGZvciAobGV0IHByb3BOYW1lIGluIGlucHV0KSB7XG4gICAgICAgIGlmICghKHByb3BOYW1lIGluIHJlZmluZXJzKSkge1xuICAgICAgICAgICAgZXh0cmFbcHJvcE5hbWVdID0gaW5wdXRbcHJvcE5hbWVdO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB7IHJlZmluZWQsIGV4dHJhIH07XG59XG5mdW5jdGlvbiBpZGVudGl0eShyYXcpIHtcbiAgICByZXR1cm4gcmF3O1xufVxuXG5jb25zdCB7IGhhc093blByb3BlcnR5IH0gPSBPYmplY3QucHJvdG90eXBlO1xuLy8gTWVyZ2VzIGFuIGFycmF5IG9mIG9iamVjdHMgaW50byBhIHNpbmdsZSBvYmplY3QuXG4vLyBUaGUgc2Vjb25kIGFyZ3VtZW50IGFsbG93cyBmb3IgYW4gYXJyYXkgb2YgcHJvcGVydHkgbmFtZXMgd2hvJ3Mgb2JqZWN0IHZhbHVlcyB3aWxsIGJlIG1lcmdlZCB0b2dldGhlci5cbmZ1bmN0aW9uIG1lcmdlUHJvcHMocHJvcE9ianMsIGNvbXBsZXhQcm9wc01hcCkge1xuICAgIGxldCBkZXN0ID0ge307XG4gICAgaWYgKGNvbXBsZXhQcm9wc01hcCkge1xuICAgICAgICBmb3IgKGxldCBuYW1lIGluIGNvbXBsZXhQcm9wc01hcCkge1xuICAgICAgICAgICAgaWYgKGNvbXBsZXhQcm9wc01hcFtuYW1lXSA9PT0gaXNNYXliZU9iamVjdHNFcXVhbCkgeyAvLyBpbXBsaWVzIHRoYXQgaXQncyBvYmplY3QtbWVyZ2VhYmxlXG4gICAgICAgICAgICAgICAgbGV0IGNvbXBsZXhPYmpzID0gW107XG4gICAgICAgICAgICAgICAgLy8gY29sbGVjdCB0aGUgdHJhaWxpbmcgb2JqZWN0IHZhbHVlcywgc3RvcHBpbmcgd2hlbiBhIG5vbi1vYmplY3QgaXMgZGlzY292ZXJlZFxuICAgICAgICAgICAgICAgIGZvciAobGV0IGkgPSBwcm9wT2Jqcy5sZW5ndGggLSAxOyBpID49IDA7IGkgLT0gMSkge1xuICAgICAgICAgICAgICAgICAgICBsZXQgdmFsID0gcHJvcE9ianNbaV1bbmFtZV07XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsID09PSAnb2JqZWN0JyAmJiB2YWwpIHsgLy8gbm9uLW51bGwgb2JqZWN0XG4gICAgICAgICAgICAgICAgICAgICAgICBjb21wbGV4T2Jqcy51bnNoaWZ0KHZhbCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAodmFsICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlc3RbbmFtZV0gPSB2YWw7IC8vIGlmIHRoZXJlIHdlcmUgbm8gb2JqZWN0cywgdGhpcyB2YWx1ZSB3aWxsIGJlIHVzZWRcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIGlmIHRoZSB0cmFpbGluZyB2YWx1ZXMgd2VyZSBvYmplY3RzLCB1c2UgdGhlIG1lcmdlZCB2YWx1ZVxuICAgICAgICAgICAgICAgIGlmIChjb21wbGV4T2Jqcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgZGVzdFtuYW1lXSA9IG1lcmdlUHJvcHMoY29tcGxleE9ianMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBjb3B5IHZhbHVlcyBpbnRvIHRoZSBkZXN0aW5hdGlvbiwgZ29pbmcgZnJvbSBsYXN0IHRvIGZpcnN0XG4gICAgZm9yIChsZXQgaSA9IHByb3BPYmpzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaSAtPSAxKSB7XG4gICAgICAgIGxldCBwcm9wcyA9IHByb3BPYmpzW2ldO1xuICAgICAgICBmb3IgKGxldCBuYW1lIGluIHByb3BzKSB7XG4gICAgICAgICAgICBpZiAoIShuYW1lIGluIGRlc3QpKSB7IC8vIGlmIGFscmVhZHkgYXNzaWduZWQgYnkgcHJldmlvdXMgcHJvcHMgb3IgY29tcGxleCBwcm9wcywgZG9uJ3QgcmVhc3NpZ25cbiAgICAgICAgICAgICAgICBkZXN0W25hbWVdID0gcHJvcHNbbmFtZV07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGRlc3Q7XG59XG5mdW5jdGlvbiBmaWx0ZXJIYXNoKGhhc2gsIGZ1bmMpIHtcbiAgICBsZXQgZmlsdGVyZWQgPSB7fTtcbiAgICBmb3IgKGxldCBrZXkgaW4gaGFzaCkge1xuICAgICAgICBpZiAoZnVuYyhoYXNoW2tleV0sIGtleSkpIHtcbiAgICAgICAgICAgIGZpbHRlcmVkW2tleV0gPSBoYXNoW2tleV07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZpbHRlcmVkO1xufVxuZnVuY3Rpb24gbWFwSGFzaChoYXNoLCBmdW5jKSB7XG4gICAgbGV0IG5ld0hhc2ggPSB7fTtcbiAgICBmb3IgKGxldCBrZXkgaW4gaGFzaCkge1xuICAgICAgICBuZXdIYXNoW2tleV0gPSBmdW5jKGhhc2hba2V5XSwga2V5KTtcbiAgICB9XG4gICAgcmV0dXJuIG5ld0hhc2g7XG59XG5mdW5jdGlvbiBhcnJheVRvSGFzaChhKSB7XG4gICAgbGV0IGhhc2ggPSB7fTtcbiAgICBmb3IgKGxldCBpdGVtIG9mIGEpIHtcbiAgICAgICAgaGFzaFtpdGVtXSA9IHRydWU7XG4gICAgfVxuICAgIHJldHVybiBoYXNoO1xufVxuLy8gVE9ETzogcmVhc3Nlc3MgYnJvd3NlciBzdXBwb3J0XG4vLyBodHRwczovL2Nhbml1c2UuY29tLz9zZWFyY2g9b2JqZWN0LnZhbHVlc1xuZnVuY3Rpb24gaGFzaFZhbHVlc1RvQXJyYXkob2JqKSB7XG4gICAgbGV0IGEgPSBbXTtcbiAgICBmb3IgKGxldCBrZXkgaW4gb2JqKSB7XG4gICAgICAgIGEucHVzaChvYmpba2V5XSk7XG4gICAgfVxuICAgIHJldHVybiBhO1xufVxuZnVuY3Rpb24gaXNQcm9wc0VxdWFsKG9iajAsIG9iajEpIHtcbiAgICBpZiAob2JqMCA9PT0gb2JqMSkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgZm9yIChsZXQga2V5IGluIG9iajApIHtcbiAgICAgICAgaWYgKGhhc093blByb3BlcnR5LmNhbGwob2JqMCwga2V5KSkge1xuICAgICAgICAgICAgaWYgKCEoa2V5IGluIG9iajEpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIGZvciAobGV0IGtleSBpbiBvYmoxKSB7XG4gICAgICAgIGlmIChoYXNPd25Qcm9wZXJ0eS5jYWxsKG9iajEsIGtleSkpIHtcbiAgICAgICAgICAgIGlmIChvYmowW2tleV0gIT09IG9iajFba2V5XSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn1cbmNvbnN0IEhBTkRMRVJfUkUgPSAvXm9uW0EtWl0vO1xuZnVuY3Rpb24gaXNOb25IYW5kbGVyUHJvcHNFcXVhbChvYmowLCBvYmoxKSB7XG4gICAgY29uc3Qga2V5cyA9IGdldFVuZXF1YWxQcm9wcyhvYmowLCBvYmoxKTtcbiAgICBmb3IgKGxldCBrZXkgb2Yga2V5cykge1xuICAgICAgICBpZiAoIUhBTkRMRVJfUkUudGVzdChrZXkpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG59XG5mdW5jdGlvbiBnZXRVbmVxdWFsUHJvcHMob2JqMCwgb2JqMSkge1xuICAgIGxldCBrZXlzID0gW107XG4gICAgZm9yIChsZXQga2V5IGluIG9iajApIHtcbiAgICAgICAgaWYgKGhhc093blByb3BlcnR5LmNhbGwob2JqMCwga2V5KSkge1xuICAgICAgICAgICAgaWYgKCEoa2V5IGluIG9iajEpKSB7XG4gICAgICAgICAgICAgICAga2V5cy5wdXNoKGtleSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgZm9yIChsZXQga2V5IGluIG9iajEpIHtcbiAgICAgICAgaWYgKGhhc093blByb3BlcnR5LmNhbGwob2JqMSwga2V5KSkge1xuICAgICAgICAgICAgaWYgKG9iajBba2V5XSAhPT0gb2JqMVtrZXldKSB7XG4gICAgICAgICAgICAgICAga2V5cy5wdXNoKGtleSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGtleXM7XG59XG5mdW5jdGlvbiBjb21wYXJlT2JqcyhvbGRQcm9wcywgbmV3UHJvcHMsIGVxdWFsaXR5RnVuY3MgPSB7fSkge1xuICAgIGlmIChvbGRQcm9wcyA9PT0gbmV3UHJvcHMpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIC8vIGlmIChkZWJ1Zykge1xuICAgIC8vICAgZm9yIChsZXQga2V5IGluIG5ld1Byb3BzKSB7XG4gICAgLy8gICAgIGlmIChrZXkgaW4gb2xkUHJvcHMgJiYgaXNPYmpWYWxzRXF1YWwob2xkUHJvcHNba2V5XSwgbmV3UHJvcHNba2V5XSwgZXF1YWxpdHlGdW5jc1trZXldKSkge1xuICAgIC8vICAgICAgIC8vIGVxdWFsXG4gICAgLy8gICAgIH0gZWxzZSB7XG4gICAgLy8gICAgICAgaWYgKGRlYnVnKSB7XG4gICAgLy8gICAgICAgICBjb25zb2xlLmxvZygncHJvcCBkaWZmZXJlbmNlJywga2V5LCBvbGRQcm9wc1trZXldLCBuZXdQcm9wc1trZXldKVxuICAgIC8vICAgICAgIH1cbiAgICAvLyAgICAgfVxuICAgIC8vICAgfVxuICAgIC8vICAgLy8gY2hlY2sgZm9yIHByb3BzIHRoYXQgd2VyZSBvbWl0dGVkIGluIHRoZSBuZXdcbiAgICAvLyAgIGZvciAobGV0IGtleSBpbiBvbGRQcm9wcykge1xuICAgIC8vICAgICBpZiAoIShrZXkgaW4gbmV3UHJvcHMpKSB7XG4gICAgLy8gICAgICAgaWYgKGRlYnVnKSB7XG4gICAgLy8gICAgICAgICBjb25zb2xlLmxvZygncHJvcCBhYnNlbnQnLCBrZXkpXG4gICAgLy8gICAgICAgfVxuICAgIC8vICAgICB9XG4gICAgLy8gICB9XG4gICAgLy8gfVxuICAgIGZvciAobGV0IGtleSBpbiBuZXdQcm9wcykge1xuICAgICAgICBpZiAoa2V5IGluIG9sZFByb3BzICYmIGlzT2JqVmFsc0VxdWFsKG9sZFByb3BzW2tleV0sIG5ld1Byb3BzW2tleV0sIGVxdWFsaXR5RnVuY3Nba2V5XSkpIDtcbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gY2hlY2sgZm9yIHByb3BzIHRoYXQgd2VyZSBvbWl0dGVkIGluIHRoZSBuZXdcbiAgICBmb3IgKGxldCBrZXkgaW4gb2xkUHJvcHMpIHtcbiAgICAgICAgaWYgKCEoa2V5IGluIG5ld1Byb3BzKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xufVxuLypcbmFzc3VtZWQgXCJ0cnVlXCIgZXF1YWxpdHkgZm9yIGhhbmRsZXIgbmFtZXMgbGlrZSBcIm9uUmVjZWl2ZVNvbWV0aGluZ1wiXG4qL1xuZnVuY3Rpb24gaXNPYmpWYWxzRXF1YWwodmFsMCwgdmFsMSwgY29tcGFyYXRvcikge1xuICAgIGlmICh2YWwwID09PSB2YWwxIHx8IGNvbXBhcmF0b3IgPT09IHRydWUpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGlmIChjb21wYXJhdG9yKSB7XG4gICAgICAgIHJldHVybiBjb21wYXJhdG9yKHZhbDAsIHZhbDEpO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG59XG5mdW5jdGlvbiBjb2xsZWN0RnJvbUhhc2goaGFzaCwgc3RhcnRJbmRleCA9IDAsIGVuZEluZGV4LCBzdGVwID0gMSkge1xuICAgIGxldCByZXMgPSBbXTtcbiAgICBpZiAoZW5kSW5kZXggPT0gbnVsbCkge1xuICAgICAgICBlbmRJbmRleCA9IE9iamVjdC5rZXlzKGhhc2gpLmxlbmd0aDtcbiAgICB9XG4gICAgZm9yIChsZXQgaSA9IHN0YXJ0SW5kZXg7IGkgPCBlbmRJbmRleDsgaSArPSBzdGVwKSB7XG4gICAgICAgIGxldCB2YWwgPSBoYXNoW2ldO1xuICAgICAgICBpZiAodmFsICE9PSB1bmRlZmluZWQpIHsgLy8gd2lsbCBkaXNyZWdhcmQgdW5kZWZpbmVkIGZvciBzcGFyc2UgYXJyYXlzXG4gICAgICAgICAgICByZXMucHVzaCh2YWwpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXM7XG59XG5cbmxldCBjYWxlbmRhclN5c3RlbUNsYXNzTWFwID0ge307XG5mdW5jdGlvbiByZWdpc3RlckNhbGVuZGFyU3lzdGVtKG5hbWUsIHRoZUNsYXNzKSB7XG4gICAgY2FsZW5kYXJTeXN0ZW1DbGFzc01hcFtuYW1lXSA9IHRoZUNsYXNzO1xufVxuZnVuY3Rpb24gY3JlYXRlQ2FsZW5kYXJTeXN0ZW0obmFtZSkge1xuICAgIHJldHVybiBuZXcgY2FsZW5kYXJTeXN0ZW1DbGFzc01hcFtuYW1lXSgpO1xufVxuY2xhc3MgR3JlZ29yaWFuQ2FsZW5kYXJTeXN0ZW0ge1xuICAgIGdldE1hcmtlclllYXIoZCkge1xuICAgICAgICByZXR1cm4gZC5nZXRVVENGdWxsWWVhcigpO1xuICAgIH1cbiAgICBnZXRNYXJrZXJNb250aChkKSB7XG4gICAgICAgIHJldHVybiBkLmdldFVUQ01vbnRoKCk7XG4gICAgfVxuICAgIGdldE1hcmtlckRheShkKSB7XG4gICAgICAgIHJldHVybiBkLmdldFVUQ0RhdGUoKTtcbiAgICB9XG4gICAgYXJyYXlUb01hcmtlcihhcnIpIHtcbiAgICAgICAgcmV0dXJuIGFycmF5VG9VdGNEYXRlKGFycik7XG4gICAgfVxuICAgIG1hcmtlclRvQXJyYXkobWFya2VyKSB7XG4gICAgICAgIHJldHVybiBkYXRlVG9VdGNBcnJheShtYXJrZXIpO1xuICAgIH1cbn1cbnJlZ2lzdGVyQ2FsZW5kYXJTeXN0ZW0oJ2dyZWdvcnknLCBHcmVnb3JpYW5DYWxlbmRhclN5c3RlbSk7XG5cbmNvbnN0IElTT19SRSA9IC9eXFxzKihcXGR7NH0pKC0/KFxcZHsyfSkoLT8oXFxkezJ9KShbVCBdKFxcZHsyfSk6PyhcXGR7Mn0pKDo/KFxcZHsyfSkoXFwuKFxcZCspKT8pPyhafCgoWy0rXSkoXFxkezJ9KSg6PyhcXGR7Mn0pKT8pKT8pPyk/KT8kLztcbmZ1bmN0aW9uIHBhcnNlKHN0cikge1xuICAgIGxldCBtID0gSVNPX1JFLmV4ZWMoc3RyKTtcbiAgICBpZiAobSkge1xuICAgICAgICBsZXQgbWFya2VyID0gbmV3IERhdGUoRGF0ZS5VVEMoTnVtYmVyKG1bMV0pLCBtWzNdID8gTnVtYmVyKG1bM10pIC0gMSA6IDAsIE51bWJlcihtWzVdIHx8IDEpLCBOdW1iZXIobVs3XSB8fCAwKSwgTnVtYmVyKG1bOF0gfHwgMCksIE51bWJlcihtWzEwXSB8fCAwKSwgbVsxMl0gPyBOdW1iZXIoYDAuJHttWzEyXX1gKSAqIDEwMDAgOiAwKSk7XG4gICAgICAgIGlmIChpc1ZhbGlkRGF0ZShtYXJrZXIpKSB7XG4gICAgICAgICAgICBsZXQgdGltZVpvbmVPZmZzZXQgPSBudWxsO1xuICAgICAgICAgICAgaWYgKG1bMTNdKSB7XG4gICAgICAgICAgICAgICAgdGltZVpvbmVPZmZzZXQgPSAobVsxNV0gPT09ICctJyA/IC0xIDogMSkgKiAoTnVtYmVyKG1bMTZdIHx8IDApICogNjAgK1xuICAgICAgICAgICAgICAgICAgICBOdW1iZXIobVsxOF0gfHwgMCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBtYXJrZXIsXG4gICAgICAgICAgICAgICAgaXNUaW1lVW5zcGVjaWZpZWQ6ICFtWzZdLFxuICAgICAgICAgICAgICAgIHRpbWVab25lT2Zmc2V0LFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cblxuY2xhc3MgRGF0ZUVudiB7XG4gICAgY29uc3RydWN0b3Ioc2V0dGluZ3MpIHtcbiAgICAgICAgbGV0IHRpbWVab25lID0gdGhpcy50aW1lWm9uZSA9IHNldHRpbmdzLnRpbWVab25lO1xuICAgICAgICBsZXQgaXNOYW1lZFRpbWVab25lID0gdGltZVpvbmUgIT09ICdsb2NhbCcgJiYgdGltZVpvbmUgIT09ICdVVEMnO1xuICAgICAgICBpZiAoc2V0dGluZ3MubmFtZWRUaW1lWm9uZUltcGwgJiYgaXNOYW1lZFRpbWVab25lKSB7XG4gICAgICAgICAgICB0aGlzLm5hbWVkVGltZVpvbmVJbXBsID0gbmV3IHNldHRpbmdzLm5hbWVkVGltZVpvbmVJbXBsKHRpbWVab25lKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmNhbkNvbXB1dGVPZmZzZXQgPSBCb29sZWFuKCFpc05hbWVkVGltZVpvbmUgfHwgdGhpcy5uYW1lZFRpbWVab25lSW1wbCk7XG4gICAgICAgIHRoaXMuY2FsZW5kYXJTeXN0ZW0gPSBjcmVhdGVDYWxlbmRhclN5c3RlbShzZXR0aW5ncy5jYWxlbmRhclN5c3RlbSk7XG4gICAgICAgIHRoaXMubG9jYWxlID0gc2V0dGluZ3MubG9jYWxlO1xuICAgICAgICB0aGlzLndlZWtEb3cgPSBzZXR0aW5ncy5sb2NhbGUud2Vlay5kb3c7XG4gICAgICAgIHRoaXMud2Vla0RveSA9IHNldHRpbmdzLmxvY2FsZS53ZWVrLmRveTtcbiAgICAgICAgaWYgKHNldHRpbmdzLndlZWtOdW1iZXJDYWxjdWxhdGlvbiA9PT0gJ0lTTycpIHtcbiAgICAgICAgICAgIHRoaXMud2Vla0RvdyA9IDE7XG4gICAgICAgICAgICB0aGlzLndlZWtEb3kgPSA0O1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlb2Ygc2V0dGluZ3MuZmlyc3REYXkgPT09ICdudW1iZXInKSB7XG4gICAgICAgICAgICB0aGlzLndlZWtEb3cgPSBzZXR0aW5ncy5maXJzdERheTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodHlwZW9mIHNldHRpbmdzLndlZWtOdW1iZXJDYWxjdWxhdGlvbiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgdGhpcy53ZWVrTnVtYmVyRnVuYyA9IHNldHRpbmdzLndlZWtOdW1iZXJDYWxjdWxhdGlvbjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLndlZWtUZXh0ID0gc2V0dGluZ3Mud2Vla1RleHQgIT0gbnVsbCA/IHNldHRpbmdzLndlZWtUZXh0IDogc2V0dGluZ3MubG9jYWxlLm9wdGlvbnMud2Vla1RleHQ7XG4gICAgICAgIHRoaXMud2Vla1RleHRMb25nID0gKHNldHRpbmdzLndlZWtUZXh0TG9uZyAhPSBudWxsID8gc2V0dGluZ3Mud2Vla1RleHRMb25nIDogc2V0dGluZ3MubG9jYWxlLm9wdGlvbnMud2Vla1RleHRMb25nKSB8fCB0aGlzLndlZWtUZXh0O1xuICAgICAgICB0aGlzLmNtZEZvcm1hdHRlciA9IHNldHRpbmdzLmNtZEZvcm1hdHRlcjtcbiAgICAgICAgdGhpcy5kZWZhdWx0U2VwYXJhdG9yID0gc2V0dGluZ3MuZGVmYXVsdFNlcGFyYXRvcjtcbiAgICB9XG4gICAgLy8gQ3JlYXRpbmcgLyBQYXJzaW5nXG4gICAgY3JlYXRlTWFya2VyKGlucHV0KSB7XG4gICAgICAgIGxldCBtZXRhID0gdGhpcy5jcmVhdGVNYXJrZXJNZXRhKGlucHV0KTtcbiAgICAgICAgaWYgKG1ldGEgPT09IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBtZXRhLm1hcmtlcjtcbiAgICB9XG4gICAgY3JlYXRlTm93TWFya2VyKCkge1xuICAgICAgICBpZiAodGhpcy5jYW5Db21wdXRlT2Zmc2V0KSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy50aW1lc3RhbXBUb01hcmtlcihuZXcgRGF0ZSgpLnZhbHVlT2YoKSk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gaWYgd2UgY2FuJ3QgY29tcHV0ZSB0aGUgY3VycmVudCBkYXRlIHZhbCBmb3IgYSB0aW1lem9uZSxcbiAgICAgICAgLy8gYmV0dGVyIHRvIGdpdmUgdGhlIGN1cnJlbnQgbG9jYWwgZGF0ZSB2YWxzIHRoYW4gVVRDXG4gICAgICAgIHJldHVybiBhcnJheVRvVXRjRGF0ZShkYXRlVG9Mb2NhbEFycmF5KG5ldyBEYXRlKCkpKTtcbiAgICB9XG4gICAgY3JlYXRlTWFya2VyTWV0YShpbnB1dCkge1xuICAgICAgICBpZiAodHlwZW9mIGlucHV0ID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMucGFyc2UoaW5wdXQpO1xuICAgICAgICB9XG4gICAgICAgIGxldCBtYXJrZXIgPSBudWxsO1xuICAgICAgICBpZiAodHlwZW9mIGlucHV0ID09PSAnbnVtYmVyJykge1xuICAgICAgICAgICAgbWFya2VyID0gdGhpcy50aW1lc3RhbXBUb01hcmtlcihpbnB1dCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoaW5wdXQgaW5zdGFuY2VvZiBEYXRlKSB7XG4gICAgICAgICAgICBpbnB1dCA9IGlucHV0LnZhbHVlT2YoKTtcbiAgICAgICAgICAgIGlmICghaXNOYU4oaW5wdXQpKSB7XG4gICAgICAgICAgICAgICAgbWFya2VyID0gdGhpcy50aW1lc3RhbXBUb01hcmtlcihpbnB1dCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoQXJyYXkuaXNBcnJheShpbnB1dCkpIHtcbiAgICAgICAgICAgIG1hcmtlciA9IGFycmF5VG9VdGNEYXRlKGlucHV0KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobWFya2VyID09PSBudWxsIHx8ICFpc1ZhbGlkRGF0ZShtYXJrZXIpKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4geyBtYXJrZXIsIGlzVGltZVVuc3BlY2lmaWVkOiBmYWxzZSwgZm9yY2VkVHpvOiBudWxsIH07XG4gICAgfVxuICAgIHBhcnNlKHMpIHtcbiAgICAgICAgbGV0IHBhcnRzID0gcGFyc2Uocyk7XG4gICAgICAgIGlmIChwYXJ0cyA9PT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHsgbWFya2VyIH0gPSBwYXJ0cztcbiAgICAgICAgbGV0IGZvcmNlZFR6byA9IG51bGw7XG4gICAgICAgIGlmIChwYXJ0cy50aW1lWm9uZU9mZnNldCAhPT0gbnVsbCkge1xuICAgICAgICAgICAgaWYgKHRoaXMuY2FuQ29tcHV0ZU9mZnNldCkge1xuICAgICAgICAgICAgICAgIG1hcmtlciA9IHRoaXMudGltZXN0YW1wVG9NYXJrZXIobWFya2VyLnZhbHVlT2YoKSAtIHBhcnRzLnRpbWVab25lT2Zmc2V0ICogNjAgKiAxMDAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGZvcmNlZFR6byA9IHBhcnRzLnRpbWVab25lT2Zmc2V0O1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IG1hcmtlciwgaXNUaW1lVW5zcGVjaWZpZWQ6IHBhcnRzLmlzVGltZVVuc3BlY2lmaWVkLCBmb3JjZWRUem8gfTtcbiAgICB9XG4gICAgLy8gQWNjZXNzb3JzXG4gICAgZ2V0WWVhcihtYXJrZXIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2FsZW5kYXJTeXN0ZW0uZ2V0TWFya2VyWWVhcihtYXJrZXIpO1xuICAgIH1cbiAgICBnZXRNb250aChtYXJrZXIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2FsZW5kYXJTeXN0ZW0uZ2V0TWFya2VyTW9udGgobWFya2VyKTtcbiAgICB9XG4gICAgZ2V0RGF5KG1hcmtlcikge1xuICAgICAgICByZXR1cm4gdGhpcy5jYWxlbmRhclN5c3RlbS5nZXRNYXJrZXJEYXkobWFya2VyKTtcbiAgICB9XG4gICAgLy8gQWRkaW5nIC8gU3VidHJhY3RpbmdcbiAgICBhZGQobWFya2VyLCBkdXIpIHtcbiAgICAgICAgbGV0IGEgPSB0aGlzLmNhbGVuZGFyU3lzdGVtLm1hcmtlclRvQXJyYXkobWFya2VyKTtcbiAgICAgICAgYVswXSArPSBkdXIueWVhcnM7XG4gICAgICAgIGFbMV0gKz0gZHVyLm1vbnRocztcbiAgICAgICAgYVsyXSArPSBkdXIuZGF5cztcbiAgICAgICAgYVs2XSArPSBkdXIubWlsbGlzZWNvbmRzO1xuICAgICAgICByZXR1cm4gdGhpcy5jYWxlbmRhclN5c3RlbS5hcnJheVRvTWFya2VyKGEpO1xuICAgIH1cbiAgICBzdWJ0cmFjdChtYXJrZXIsIGR1cikge1xuICAgICAgICBsZXQgYSA9IHRoaXMuY2FsZW5kYXJTeXN0ZW0ubWFya2VyVG9BcnJheShtYXJrZXIpO1xuICAgICAgICBhWzBdIC09IGR1ci55ZWFycztcbiAgICAgICAgYVsxXSAtPSBkdXIubW9udGhzO1xuICAgICAgICBhWzJdIC09IGR1ci5kYXlzO1xuICAgICAgICBhWzZdIC09IGR1ci5taWxsaXNlY29uZHM7XG4gICAgICAgIHJldHVybiB0aGlzLmNhbGVuZGFyU3lzdGVtLmFycmF5VG9NYXJrZXIoYSk7XG4gICAgfVxuICAgIGFkZFllYXJzKG1hcmtlciwgbikge1xuICAgICAgICBsZXQgYSA9IHRoaXMuY2FsZW5kYXJTeXN0ZW0ubWFya2VyVG9BcnJheShtYXJrZXIpO1xuICAgICAgICBhWzBdICs9IG47XG4gICAgICAgIHJldHVybiB0aGlzLmNhbGVuZGFyU3lzdGVtLmFycmF5VG9NYXJrZXIoYSk7XG4gICAgfVxuICAgIGFkZE1vbnRocyhtYXJrZXIsIG4pIHtcbiAgICAgICAgbGV0IGEgPSB0aGlzLmNhbGVuZGFyU3lzdGVtLm1hcmtlclRvQXJyYXkobWFya2VyKTtcbiAgICAgICAgYVsxXSArPSBuO1xuICAgICAgICByZXR1cm4gdGhpcy5jYWxlbmRhclN5c3RlbS5hcnJheVRvTWFya2VyKGEpO1xuICAgIH1cbiAgICAvLyBEaWZmaW5nIFdob2xlIFVuaXRzXG4gICAgZGlmZldob2xlWWVhcnMobTAsIG0xKSB7XG4gICAgICAgIGxldCB7IGNhbGVuZGFyU3lzdGVtIH0gPSB0aGlzO1xuICAgICAgICBpZiAodGltZUFzTXMobTApID09PSB0aW1lQXNNcyhtMSkgJiZcbiAgICAgICAgICAgIGNhbGVuZGFyU3lzdGVtLmdldE1hcmtlckRheShtMCkgPT09IGNhbGVuZGFyU3lzdGVtLmdldE1hcmtlckRheShtMSkgJiZcbiAgICAgICAgICAgIGNhbGVuZGFyU3lzdGVtLmdldE1hcmtlck1vbnRoKG0wKSA9PT0gY2FsZW5kYXJTeXN0ZW0uZ2V0TWFya2VyTW9udGgobTEpKSB7XG4gICAgICAgICAgICByZXR1cm4gY2FsZW5kYXJTeXN0ZW0uZ2V0TWFya2VyWWVhcihtMSkgLSBjYWxlbmRhclN5c3RlbS5nZXRNYXJrZXJZZWFyKG0wKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgZGlmZldob2xlTW9udGhzKG0wLCBtMSkge1xuICAgICAgICBsZXQgeyBjYWxlbmRhclN5c3RlbSB9ID0gdGhpcztcbiAgICAgICAgaWYgKHRpbWVBc01zKG0wKSA9PT0gdGltZUFzTXMobTEpICYmXG4gICAgICAgICAgICBjYWxlbmRhclN5c3RlbS5nZXRNYXJrZXJEYXkobTApID09PSBjYWxlbmRhclN5c3RlbS5nZXRNYXJrZXJEYXkobTEpKSB7XG4gICAgICAgICAgICByZXR1cm4gKGNhbGVuZGFyU3lzdGVtLmdldE1hcmtlck1vbnRoKG0xKSAtIGNhbGVuZGFyU3lzdGVtLmdldE1hcmtlck1vbnRoKG0wKSkgK1xuICAgICAgICAgICAgICAgIChjYWxlbmRhclN5c3RlbS5nZXRNYXJrZXJZZWFyKG0xKSAtIGNhbGVuZGFyU3lzdGVtLmdldE1hcmtlclllYXIobTApKSAqIDEyO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICAvLyBSYW5nZSAvIER1cmF0aW9uXG4gICAgZ3JlYXRlc3RXaG9sZVVuaXQobTAsIG0xKSB7XG4gICAgICAgIGxldCBuID0gdGhpcy5kaWZmV2hvbGVZZWFycyhtMCwgbTEpO1xuICAgICAgICBpZiAobiAhPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIHsgdW5pdDogJ3llYXInLCB2YWx1ZTogbiB9O1xuICAgICAgICB9XG4gICAgICAgIG4gPSB0aGlzLmRpZmZXaG9sZU1vbnRocyhtMCwgbTEpO1xuICAgICAgICBpZiAobiAhPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIHsgdW5pdDogJ21vbnRoJywgdmFsdWU6IG4gfTtcbiAgICAgICAgfVxuICAgICAgICBuID0gZGlmZldob2xlV2Vla3MobTAsIG0xKTtcbiAgICAgICAgaWYgKG4gIT09IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHVuaXQ6ICd3ZWVrJywgdmFsdWU6IG4gfTtcbiAgICAgICAgfVxuICAgICAgICBuID0gZGlmZldob2xlRGF5cyhtMCwgbTEpO1xuICAgICAgICBpZiAobiAhPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIHsgdW5pdDogJ2RheScsIHZhbHVlOiBuIH07XG4gICAgICAgIH1cbiAgICAgICAgbiA9IGRpZmZIb3VycyhtMCwgbTEpO1xuICAgICAgICBpZiAoaXNJbnQobikpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHVuaXQ6ICdob3VyJywgdmFsdWU6IG4gfTtcbiAgICAgICAgfVxuICAgICAgICBuID0gZGlmZk1pbnV0ZXMobTAsIG0xKTtcbiAgICAgICAgaWYgKGlzSW50KG4pKSB7XG4gICAgICAgICAgICByZXR1cm4geyB1bml0OiAnbWludXRlJywgdmFsdWU6IG4gfTtcbiAgICAgICAgfVxuICAgICAgICBuID0gZGlmZlNlY29uZHMobTAsIG0xKTtcbiAgICAgICAgaWYgKGlzSW50KG4pKSB7XG4gICAgICAgICAgICByZXR1cm4geyB1bml0OiAnc2Vjb25kJywgdmFsdWU6IG4gfTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4geyB1bml0OiAnbWlsbGlzZWNvbmQnLCB2YWx1ZTogbTEudmFsdWVPZigpIC0gbTAudmFsdWVPZigpIH07XG4gICAgfVxuICAgIGNvdW50RHVyYXRpb25zQmV0d2VlbihtMCwgbTEsIGQpIHtcbiAgICAgICAgLy8gVE9ETzogY2FuIHVzZSBncmVhdGVzdFdob2xlVW5pdFxuICAgICAgICBsZXQgZGlmZjtcbiAgICAgICAgaWYgKGQueWVhcnMpIHtcbiAgICAgICAgICAgIGRpZmYgPSB0aGlzLmRpZmZXaG9sZVllYXJzKG0wLCBtMSk7XG4gICAgICAgICAgICBpZiAoZGlmZiAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBkaWZmIC8gYXNSb3VnaFllYXJzKGQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChkLm1vbnRocykge1xuICAgICAgICAgICAgZGlmZiA9IHRoaXMuZGlmZldob2xlTW9udGhzKG0wLCBtMSk7XG4gICAgICAgICAgICBpZiAoZGlmZiAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBkaWZmIC8gYXNSb3VnaE1vbnRocyhkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoZC5kYXlzKSB7XG4gICAgICAgICAgICBkaWZmID0gZGlmZldob2xlRGF5cyhtMCwgbTEpO1xuICAgICAgICAgICAgaWYgKGRpZmYgIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZGlmZiAvIGFzUm91Z2hEYXlzKGQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiAobTEudmFsdWVPZigpIC0gbTAudmFsdWVPZigpKSAvIGFzUm91Z2hNcyhkKTtcbiAgICB9XG4gICAgLy8gU3RhcnQtT2ZcbiAgICAvLyB0aGVzZSBET04nVCByZXR1cm4gem9uZWQtZGF0ZXMuIG9ubHkgVVRDIHN0YXJ0LW9mIGRhdGVzXG4gICAgc3RhcnRPZihtLCB1bml0KSB7XG4gICAgICAgIGlmICh1bml0ID09PSAneWVhcicpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnN0YXJ0T2ZZZWFyKG0pO1xuICAgICAgICB9XG4gICAgICAgIGlmICh1bml0ID09PSAnbW9udGgnKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zdGFydE9mTW9udGgobSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHVuaXQgPT09ICd3ZWVrJykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3RhcnRPZldlZWsobSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHVuaXQgPT09ICdkYXknKSB7XG4gICAgICAgICAgICByZXR1cm4gc3RhcnRPZkRheShtKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodW5pdCA9PT0gJ2hvdXInKSB7XG4gICAgICAgICAgICByZXR1cm4gc3RhcnRPZkhvdXIobSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHVuaXQgPT09ICdtaW51dGUnKSB7XG4gICAgICAgICAgICByZXR1cm4gc3RhcnRPZk1pbnV0ZShtKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodW5pdCA9PT0gJ3NlY29uZCcpIHtcbiAgICAgICAgICAgIHJldHVybiBzdGFydE9mU2Vjb25kKG0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBzdGFydE9mWWVhcihtKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmNhbGVuZGFyU3lzdGVtLmFycmF5VG9NYXJrZXIoW1xuICAgICAgICAgICAgdGhpcy5jYWxlbmRhclN5c3RlbS5nZXRNYXJrZXJZZWFyKG0pLFxuICAgICAgICBdKTtcbiAgICB9XG4gICAgc3RhcnRPZk1vbnRoKG0pIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2FsZW5kYXJTeXN0ZW0uYXJyYXlUb01hcmtlcihbXG4gICAgICAgICAgICB0aGlzLmNhbGVuZGFyU3lzdGVtLmdldE1hcmtlclllYXIobSksXG4gICAgICAgICAgICB0aGlzLmNhbGVuZGFyU3lzdGVtLmdldE1hcmtlck1vbnRoKG0pLFxuICAgICAgICBdKTtcbiAgICB9XG4gICAgc3RhcnRPZldlZWsobSkge1xuICAgICAgICByZXR1cm4gdGhpcy5jYWxlbmRhclN5c3RlbS5hcnJheVRvTWFya2VyKFtcbiAgICAgICAgICAgIHRoaXMuY2FsZW5kYXJTeXN0ZW0uZ2V0TWFya2VyWWVhcihtKSxcbiAgICAgICAgICAgIHRoaXMuY2FsZW5kYXJTeXN0ZW0uZ2V0TWFya2VyTW9udGgobSksXG4gICAgICAgICAgICBtLmdldFVUQ0RhdGUoKSAtICgobS5nZXRVVENEYXkoKSAtIHRoaXMud2Vla0RvdyArIDcpICUgNyksXG4gICAgICAgIF0pO1xuICAgIH1cbiAgICAvLyBXZWVrIE51bWJlclxuICAgIGNvbXB1dGVXZWVrTnVtYmVyKG1hcmtlcikge1xuICAgICAgICBpZiAodGhpcy53ZWVrTnVtYmVyRnVuYykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMud2Vla051bWJlckZ1bmModGhpcy50b0RhdGUobWFya2VyKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHdlZWtPZlllYXIobWFya2VyLCB0aGlzLndlZWtEb3csIHRoaXMud2Vla0RveSk7XG4gICAgfVxuICAgIC8vIFRPRE86IGNob2tlIG9uIHRpbWVab25lTmFtZTogbG9uZ1xuICAgIGZvcm1hdChtYXJrZXIsIGZvcm1hdHRlciwgZGF0ZU9wdGlvbnMgPSB7fSkge1xuICAgICAgICByZXR1cm4gZm9ybWF0dGVyLmZvcm1hdCh7XG4gICAgICAgICAgICBtYXJrZXIsXG4gICAgICAgICAgICB0aW1lWm9uZU9mZnNldDogZGF0ZU9wdGlvbnMuZm9yY2VkVHpvICE9IG51bGwgP1xuICAgICAgICAgICAgICAgIGRhdGVPcHRpb25zLmZvcmNlZFR6byA6XG4gICAgICAgICAgICAgICAgdGhpcy5vZmZzZXRGb3JNYXJrZXIobWFya2VyKSxcbiAgICAgICAgfSwgdGhpcyk7XG4gICAgfVxuICAgIGZvcm1hdFJhbmdlKHN0YXJ0LCBlbmQsIGZvcm1hdHRlciwgZGF0ZU9wdGlvbnMgPSB7fSkge1xuICAgICAgICBpZiAoZGF0ZU9wdGlvbnMuaXNFbmRFeGNsdXNpdmUpIHtcbiAgICAgICAgICAgIGVuZCA9IGFkZE1zKGVuZCwgLTEpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmb3JtYXR0ZXIuZm9ybWF0UmFuZ2Uoe1xuICAgICAgICAgICAgbWFya2VyOiBzdGFydCxcbiAgICAgICAgICAgIHRpbWVab25lT2Zmc2V0OiBkYXRlT3B0aW9ucy5mb3JjZWRTdGFydFR6byAhPSBudWxsID9cbiAgICAgICAgICAgICAgICBkYXRlT3B0aW9ucy5mb3JjZWRTdGFydFR6byA6XG4gICAgICAgICAgICAgICAgdGhpcy5vZmZzZXRGb3JNYXJrZXIoc3RhcnQpLFxuICAgICAgICB9LCB7XG4gICAgICAgICAgICBtYXJrZXI6IGVuZCxcbiAgICAgICAgICAgIHRpbWVab25lT2Zmc2V0OiBkYXRlT3B0aW9ucy5mb3JjZWRFbmRUem8gIT0gbnVsbCA/XG4gICAgICAgICAgICAgICAgZGF0ZU9wdGlvbnMuZm9yY2VkRW5kVHpvIDpcbiAgICAgICAgICAgICAgICB0aGlzLm9mZnNldEZvck1hcmtlcihlbmQpLFxuICAgICAgICB9LCB0aGlzLCBkYXRlT3B0aW9ucy5kZWZhdWx0U2VwYXJhdG9yKTtcbiAgICB9XG4gICAgLypcbiAgICBEVU1COiB0aGUgb21pdFRpbWUgYXJnIGlzIGR1bWIuIGlmIHdlIG9taXQgdGhlIHRpbWUsIHdlIHdhbnQgdG8gb21pdCB0aGUgdGltZXpvbmUgb2Zmc2V0LiBhbmQgaWYgd2UgZG8gdGhhdCxcbiAgICBtaWdodCBhcyB3ZWxsIHVzZSBidWlsZElzb1N0cmluZyBvciBzb21lIG90aGVyIHV0aWwgZGlyZWN0bHlcbiAgICAqL1xuICAgIGZvcm1hdElzbyhtYXJrZXIsIGV4dHJhT3B0aW9ucyA9IHt9KSB7XG4gICAgICAgIGxldCB0aW1lWm9uZU9mZnNldCA9IG51bGw7XG4gICAgICAgIGlmICghZXh0cmFPcHRpb25zLm9taXRUaW1lWm9uZU9mZnNldCkge1xuICAgICAgICAgICAgaWYgKGV4dHJhT3B0aW9ucy5mb3JjZWRUem8gIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHRpbWVab25lT2Zmc2V0ID0gZXh0cmFPcHRpb25zLmZvcmNlZFR6bztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHRpbWVab25lT2Zmc2V0ID0gdGhpcy5vZmZzZXRGb3JNYXJrZXIobWFya2VyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYnVpbGRJc29TdHJpbmcobWFya2VyLCB0aW1lWm9uZU9mZnNldCwgZXh0cmFPcHRpb25zLm9taXRUaW1lKTtcbiAgICB9XG4gICAgLy8gVGltZVpvbmVcbiAgICB0aW1lc3RhbXBUb01hcmtlcihtcykge1xuICAgICAgICBpZiAodGhpcy50aW1lWm9uZSA9PT0gJ2xvY2FsJykge1xuICAgICAgICAgICAgcmV0dXJuIGFycmF5VG9VdGNEYXRlKGRhdGVUb0xvY2FsQXJyYXkobmV3IERhdGUobXMpKSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMudGltZVpvbmUgPT09ICdVVEMnIHx8ICF0aGlzLm5hbWVkVGltZVpvbmVJbXBsKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IERhdGUobXMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBhcnJheVRvVXRjRGF0ZSh0aGlzLm5hbWVkVGltZVpvbmVJbXBsLnRpbWVzdGFtcFRvQXJyYXkobXMpKTtcbiAgICB9XG4gICAgb2Zmc2V0Rm9yTWFya2VyKG0pIHtcbiAgICAgICAgaWYgKHRoaXMudGltZVpvbmUgPT09ICdsb2NhbCcpIHtcbiAgICAgICAgICAgIHJldHVybiAtYXJyYXlUb0xvY2FsRGF0ZShkYXRlVG9VdGNBcnJheShtKSkuZ2V0VGltZXpvbmVPZmZzZXQoKTsgLy8gY29udmVydCBcImludmVyc2VcIiBvZmZzZXQgdG8gXCJub3JtYWxcIiBvZmZzZXRcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy50aW1lWm9uZSA9PT0gJ1VUQycpIHtcbiAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLm5hbWVkVGltZVpvbmVJbXBsKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5uYW1lZFRpbWVab25lSW1wbC5vZmZzZXRGb3JBcnJheShkYXRlVG9VdGNBcnJheShtKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIC8vIENvbnZlcnNpb25cbiAgICB0b0RhdGUobSwgZm9yY2VkVHpvKSB7XG4gICAgICAgIGlmICh0aGlzLnRpbWVab25lID09PSAnbG9jYWwnKSB7XG4gICAgICAgICAgICByZXR1cm4gYXJyYXlUb0xvY2FsRGF0ZShkYXRlVG9VdGNBcnJheShtKSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMudGltZVpvbmUgPT09ICdVVEMnKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IERhdGUobS52YWx1ZU9mKCkpOyAvLyBtYWtlIHN1cmUgaXQncyBhIGNvcHlcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRoaXMubmFtZWRUaW1lWm9uZUltcGwpIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgRGF0ZShtLnZhbHVlT2YoKSAtIChmb3JjZWRUem8gfHwgMCkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgRGF0ZShtLnZhbHVlT2YoKSAtXG4gICAgICAgICAgICB0aGlzLm5hbWVkVGltZVpvbmVJbXBsLm9mZnNldEZvckFycmF5KGRhdGVUb1V0Y0FycmF5KG0pKSAqIDEwMDAgKiA2MCk7XG4gICAgfVxufVxuXG5jbGFzcyBUaGVtZSB7XG4gICAgY29uc3RydWN0b3IoY2FsZW5kYXJPcHRpb25zKSB7XG4gICAgICAgIGlmICh0aGlzLmljb25PdmVycmlkZU9wdGlvbikge1xuICAgICAgICAgICAgdGhpcy5zZXRJY29uT3ZlcnJpZGUoY2FsZW5kYXJPcHRpb25zW3RoaXMuaWNvbk92ZXJyaWRlT3B0aW9uXSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgc2V0SWNvbk92ZXJyaWRlKGljb25PdmVycmlkZUhhc2gpIHtcbiAgICAgICAgbGV0IGljb25DbGFzc2VzQ29weTtcbiAgICAgICAgbGV0IGJ1dHRvbk5hbWU7XG4gICAgICAgIGlmICh0eXBlb2YgaWNvbk92ZXJyaWRlSGFzaCA9PT0gJ29iamVjdCcgJiYgaWNvbk92ZXJyaWRlSGFzaCkgeyAvLyBub24tbnVsbCBvYmplY3RcbiAgICAgICAgICAgIGljb25DbGFzc2VzQ29weSA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMuaWNvbkNsYXNzZXMpO1xuICAgICAgICAgICAgZm9yIChidXR0b25OYW1lIGluIGljb25PdmVycmlkZUhhc2gpIHtcbiAgICAgICAgICAgICAgICBpY29uQ2xhc3Nlc0NvcHlbYnV0dG9uTmFtZV0gPSB0aGlzLmFwcGx5SWNvbk92ZXJyaWRlUHJlZml4KGljb25PdmVycmlkZUhhc2hbYnV0dG9uTmFtZV0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5pY29uQ2xhc3NlcyA9IGljb25DbGFzc2VzQ29weTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChpY29uT3ZlcnJpZGVIYXNoID09PSBmYWxzZSkge1xuICAgICAgICAgICAgdGhpcy5pY29uQ2xhc3NlcyA9IHt9O1xuICAgICAgICB9XG4gICAgfVxuICAgIGFwcGx5SWNvbk92ZXJyaWRlUHJlZml4KGNsYXNzTmFtZSkge1xuICAgICAgICBsZXQgcHJlZml4ID0gdGhpcy5pY29uT3ZlcnJpZGVQcmVmaXg7XG4gICAgICAgIGlmIChwcmVmaXggJiYgY2xhc3NOYW1lLmluZGV4T2YocHJlZml4KSAhPT0gMCkgeyAvLyBpZiBub3QgYWxyZWFkeSBwcmVzZW50XG4gICAgICAgICAgICBjbGFzc05hbWUgPSBwcmVmaXggKyBjbGFzc05hbWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGNsYXNzTmFtZTtcbiAgICB9XG4gICAgZ2V0Q2xhc3Moa2V5KSB7XG4gICAgICAgIHJldHVybiB0aGlzLmNsYXNzZXNba2V5XSB8fCAnJztcbiAgICB9XG4gICAgZ2V0SWNvbkNsYXNzKGJ1dHRvbk5hbWUsIGlzUnRsKSB7XG4gICAgICAgIGxldCBjbGFzc05hbWU7XG4gICAgICAgIGlmIChpc1J0bCAmJiB0aGlzLnJ0bEljb25DbGFzc2VzKSB7XG4gICAgICAgICAgICBjbGFzc05hbWUgPSB0aGlzLnJ0bEljb25DbGFzc2VzW2J1dHRvbk5hbWVdIHx8IHRoaXMuaWNvbkNsYXNzZXNbYnV0dG9uTmFtZV07XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBjbGFzc05hbWUgPSB0aGlzLmljb25DbGFzc2VzW2J1dHRvbk5hbWVdO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjbGFzc05hbWUpIHtcbiAgICAgICAgICAgIHJldHVybiBgJHt0aGlzLmJhc2VJY29uQ2xhc3N9ICR7Y2xhc3NOYW1lfWA7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH1cbiAgICBnZXRDdXN0b21CdXR0b25JY29uQ2xhc3MoY3VzdG9tQnV0dG9uUHJvcHMpIHtcbiAgICAgICAgbGV0IGNsYXNzTmFtZTtcbiAgICAgICAgaWYgKHRoaXMuaWNvbk92ZXJyaWRlQ3VzdG9tQnV0dG9uT3B0aW9uKSB7XG4gICAgICAgICAgICBjbGFzc05hbWUgPSBjdXN0b21CdXR0b25Qcm9wc1t0aGlzLmljb25PdmVycmlkZUN1c3RvbUJ1dHRvbk9wdGlvbl07XG4gICAgICAgICAgICBpZiAoY2xhc3NOYW1lKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGAke3RoaXMuYmFzZUljb25DbGFzc30gJHt0aGlzLmFwcGx5SWNvbk92ZXJyaWRlUHJlZml4KGNsYXNzTmFtZSl9YDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gJyc7XG4gICAgfVxufVxuVGhlbWUucHJvdG90eXBlLmNsYXNzZXMgPSB7fTtcblRoZW1lLnByb3RvdHlwZS5pY29uQ2xhc3NlcyA9IHt9O1xuVGhlbWUucHJvdG90eXBlLmJhc2VJY29uQ2xhc3MgPSAnJztcblRoZW1lLnByb3RvdHlwZS5pY29uT3ZlcnJpZGVQcmVmaXggPSAnJztcblxuLypcbk5PVEU6IHRoaXMgY2FuIGJlIGEgcHVibGljIEFQSSwgZXNwZWNpYWxseSBjcmVhdGVFbGVtZW50IGZvciBob29rcy5cblNlZSBleGFtcGxlcy90eXBlc2NyaXB0LXNjaGVkdWxlci9zcmMvaW5kZXgudHNcbiovXG5mdW5jdGlvbiBmbHVzaFN5bmMocnVuQmVmb3JlRmx1c2gpIHtcbiAgICBydW5CZWZvcmVGbHVzaCgpO1xuICAgIGxldCBvbGREZWJvdW5jZVJlbmRlcmluZyA9IHByZWFjdC5vcHRpb25zLmRlYm91bmNlUmVuZGVyaW5nOyAvLyBvcmlnXG4gICAgbGV0IGNhbGxiYWNrUSA9IFtdO1xuICAgIGZ1bmN0aW9uIGV4ZWNDYWxsYmFja1N5bmMoY2FsbGJhY2spIHtcbiAgICAgICAgY2FsbGJhY2tRLnB1c2goY2FsbGJhY2spO1xuICAgIH1cbiAgICBwcmVhY3Qub3B0aW9ucy5kZWJvdW5jZVJlbmRlcmluZyA9IGV4ZWNDYWxsYmFja1N5bmM7XG4gICAgcHJlYWN0LnJlbmRlcihwcmVhY3QuY3JlYXRlRWxlbWVudChGYWtlQ29tcG9uZW50LCB7fSksIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpKTtcbiAgICB3aGlsZSAoY2FsbGJhY2tRLmxlbmd0aCkge1xuICAgICAgICBjYWxsYmFja1Euc2hpZnQoKSgpO1xuICAgIH1cbiAgICBwcmVhY3Qub3B0aW9ucy5kZWJvdW5jZVJlbmRlcmluZyA9IG9sZERlYm91bmNlUmVuZGVyaW5nO1xufVxuY2xhc3MgRmFrZUNvbXBvbmVudCBleHRlbmRzIHByZWFjdC5Db21wb25lbnQge1xuICAgIHJlbmRlcigpIHsgcmV0dXJuIHByZWFjdC5jcmVhdGVFbGVtZW50KCdkaXYnLCB7fSk7IH1cbiAgICBjb21wb25lbnREaWRNb3VudCgpIHsgdGhpcy5zZXRTdGF0ZSh7fSk7IH1cbn1cbi8vIFRPRE86IHVzZSBwcmVhY3QvY29tcGF0IGluc3RlYWQ/XG5mdW5jdGlvbiBjcmVhdGVDb250ZXh0KGRlZmF1bHRWYWx1ZSkge1xuICAgIGxldCBDb250ZXh0VHlwZSA9IHByZWFjdC5jcmVhdGVDb250ZXh0KGRlZmF1bHRWYWx1ZSk7XG4gICAgbGV0IG9yaWdQcm92aWRlciA9IENvbnRleHRUeXBlLlByb3ZpZGVyO1xuICAgIENvbnRleHRUeXBlLlByb3ZpZGVyID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBsZXQgaXNOZXcgPSAhdGhpcy5nZXRDaGlsZENvbnRleHQ7XG4gICAgICAgIGxldCBjaGlsZHJlbiA9IG9yaWdQcm92aWRlci5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIHByZWZlci1yZXN0LXBhcmFtc1xuICAgICAgICBpZiAoaXNOZXcpIHtcbiAgICAgICAgICAgIGxldCBzdWJzID0gW107XG4gICAgICAgICAgICB0aGlzLnNob3VsZENvbXBvbmVudFVwZGF0ZSA9IChfcHJvcHMpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5wcm9wcy52YWx1ZSAhPT0gX3Byb3BzLnZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgIHN1YnMuZm9yRWFjaCgoYykgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgYy5jb250ZXh0ID0gX3Byb3BzLnZhbHVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgYy5mb3JjZVVwZGF0ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgdGhpcy5zdWIgPSAoYykgPT4ge1xuICAgICAgICAgICAgICAgIHN1YnMucHVzaChjKTtcbiAgICAgICAgICAgICAgICBsZXQgb2xkID0gYy5jb21wb25lbnRXaWxsVW5tb3VudDtcbiAgICAgICAgICAgICAgICBjLmNvbXBvbmVudFdpbGxVbm1vdW50ID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBzdWJzLnNwbGljZShzdWJzLmluZGV4T2YoYyksIDEpO1xuICAgICAgICAgICAgICAgICAgICBvbGQgJiYgb2xkLmNhbGwoYyk7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGNoaWxkcmVuO1xuICAgIH07XG4gICAgcmV0dXJuIENvbnRleHRUeXBlO1xufVxuXG5jbGFzcyBTY3JvbGxSZXNwb25kZXIge1xuICAgIGNvbnN0cnVjdG9yKGV4ZWNGdW5jLCBlbWl0dGVyLCBzY3JvbGxUaW1lLCBzY3JvbGxUaW1lUmVzZXQpIHtcbiAgICAgICAgdGhpcy5leGVjRnVuYyA9IGV4ZWNGdW5jO1xuICAgICAgICB0aGlzLmVtaXR0ZXIgPSBlbWl0dGVyO1xuICAgICAgICB0aGlzLnNjcm9sbFRpbWUgPSBzY3JvbGxUaW1lO1xuICAgICAgICB0aGlzLnNjcm9sbFRpbWVSZXNldCA9IHNjcm9sbFRpbWVSZXNldDtcbiAgICAgICAgdGhpcy5oYW5kbGVTY3JvbGxSZXF1ZXN0ID0gKHJlcXVlc3QpID0+IHtcbiAgICAgICAgICAgIHRoaXMucXVldWVkUmVxdWVzdCA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMucXVldWVkUmVxdWVzdCB8fCB7fSwgcmVxdWVzdCk7XG4gICAgICAgICAgICB0aGlzLmRyYWluKCk7XG4gICAgICAgIH07XG4gICAgICAgIGVtaXR0ZXIub24oJ19zY3JvbGxSZXF1ZXN0JywgdGhpcy5oYW5kbGVTY3JvbGxSZXF1ZXN0KTtcbiAgICAgICAgdGhpcy5maXJlSW5pdGlhbFNjcm9sbCgpO1xuICAgIH1cbiAgICBkZXRhY2goKSB7XG4gICAgICAgIHRoaXMuZW1pdHRlci5vZmYoJ19zY3JvbGxSZXF1ZXN0JywgdGhpcy5oYW5kbGVTY3JvbGxSZXF1ZXN0KTtcbiAgICB9XG4gICAgdXBkYXRlKGlzRGF0ZXNOZXcpIHtcbiAgICAgICAgaWYgKGlzRGF0ZXNOZXcgJiYgdGhpcy5zY3JvbGxUaW1lUmVzZXQpIHtcbiAgICAgICAgICAgIHRoaXMuZmlyZUluaXRpYWxTY3JvbGwoKTsgLy8gd2lsbCBkcmFpblxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5kcmFpbigpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGZpcmVJbml0aWFsU2Nyb2xsKCkge1xuICAgICAgICB0aGlzLmhhbmRsZVNjcm9sbFJlcXVlc3Qoe1xuICAgICAgICAgICAgdGltZTogdGhpcy5zY3JvbGxUaW1lLFxuICAgICAgICB9KTtcbiAgICB9XG4gICAgZHJhaW4oKSB7XG4gICAgICAgIGlmICh0aGlzLnF1ZXVlZFJlcXVlc3QgJiYgdGhpcy5leGVjRnVuYyh0aGlzLnF1ZXVlZFJlcXVlc3QpKSB7XG4gICAgICAgICAgICB0aGlzLnF1ZXVlZFJlcXVlc3QgPSBudWxsO1xuICAgICAgICB9XG4gICAgfVxufVxuXG5jb25zdCBWaWV3Q29udGV4dFR5cGUgPSBjcmVhdGVDb250ZXh0KHt9KTsgLy8gZm9yIENvbXBvbmVudHNcbmZ1bmN0aW9uIGJ1aWxkVmlld0NvbnRleHQodmlld1NwZWMsIHZpZXdBcGksIHZpZXdPcHRpb25zLCBkYXRlUHJvZmlsZUdlbmVyYXRvciwgZGF0ZUVudiwgbm93TWFuYWdlciwgdGhlbWUsIHBsdWdpbkhvb2tzLCBkaXNwYXRjaCwgZ2V0Q3VycmVudERhdGEsIGVtaXR0ZXIsIGNhbGVuZGFyQXBpLCByZWdpc3RlckludGVyYWN0aXZlQ29tcG9uZW50LCB1bnJlZ2lzdGVySW50ZXJhY3RpdmVDb21wb25lbnQpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBkYXRlRW52LFxuICAgICAgICBub3dNYW5hZ2VyLFxuICAgICAgICBvcHRpb25zOiB2aWV3T3B0aW9ucyxcbiAgICAgICAgcGx1Z2luSG9va3MsXG4gICAgICAgIGVtaXR0ZXIsXG4gICAgICAgIGRpc3BhdGNoLFxuICAgICAgICBnZXRDdXJyZW50RGF0YSxcbiAgICAgICAgY2FsZW5kYXJBcGksXG4gICAgICAgIHZpZXdTcGVjLFxuICAgICAgICB2aWV3QXBpLFxuICAgICAgICBkYXRlUHJvZmlsZUdlbmVyYXRvcixcbiAgICAgICAgdGhlbWUsXG4gICAgICAgIGlzUnRsOiB2aWV3T3B0aW9ucy5kaXJlY3Rpb24gPT09ICdydGwnLFxuICAgICAgICBhZGRSZXNpemVIYW5kbGVyKGhhbmRsZXIpIHtcbiAgICAgICAgICAgIGVtaXR0ZXIub24oJ19yZXNpemUnLCBoYW5kbGVyKTtcbiAgICAgICAgfSxcbiAgICAgICAgcmVtb3ZlUmVzaXplSGFuZGxlcihoYW5kbGVyKSB7XG4gICAgICAgICAgICBlbWl0dGVyLm9mZignX3Jlc2l6ZScsIGhhbmRsZXIpO1xuICAgICAgICB9LFxuICAgICAgICBjcmVhdGVTY3JvbGxSZXNwb25kZXIoZXhlY0Z1bmMpIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgU2Nyb2xsUmVzcG9uZGVyKGV4ZWNGdW5jLCBlbWl0dGVyLCBjcmVhdGVEdXJhdGlvbih2aWV3T3B0aW9ucy5zY3JvbGxUaW1lKSwgdmlld09wdGlvbnMuc2Nyb2xsVGltZVJlc2V0KTtcbiAgICAgICAgfSxcbiAgICAgICAgcmVnaXN0ZXJJbnRlcmFjdGl2ZUNvbXBvbmVudCxcbiAgICAgICAgdW5yZWdpc3RlckludGVyYWN0aXZlQ29tcG9uZW50LFxuICAgIH07XG59XG5cbi8qIGVzbGludCBtYXgtY2xhc3Nlcy1wZXItZmlsZTogb2ZmICovXG5jbGFzcyBQdXJlQ29tcG9uZW50IGV4dGVuZHMgQ29tcG9uZW50IHtcbiAgICAvLyBkZWJ1ZzogYm9vbGVhblxuICAgIHNob3VsZENvbXBvbmVudFVwZGF0ZShuZXh0UHJvcHMsIG5leHRTdGF0ZSkge1xuICAgICAgICBjb25zdCBzaG91bGRVcGRhdGUgPSAhY29tcGFyZU9ianModGhpcy5wcm9wcywgbmV4dFByb3BzLCB0aGlzLnByb3BFcXVhbGl0eSAvKiwgdGhpcy5kZWJ1ZyAqLykgfHxcbiAgICAgICAgICAgICFjb21wYXJlT2Jqcyh0aGlzLnN0YXRlLCBuZXh0U3RhdGUsIHRoaXMuc3RhdGVFcXVhbGl0eSAvKiwgdGhpcy5kZWJ1ZyAqLyk7XG4gICAgICAgIC8vIGlmICh0aGlzLmRlYnVnICYmIHNob3VsZFVwZGF0ZSkge1xuICAgICAgICAvLyAgIGNvbnNvbGUubG9nKCdzaG91bGRVcGRhdGUhJylcbiAgICAgICAgLy8gfVxuICAgICAgICByZXR1cm4gc2hvdWxkVXBkYXRlO1xuICAgIH1cbiAgICAvLyBIQUNLIGZvciBmcmVha2luJyBSZWFjdCBTdHJpY3RNb2RlXG4gICAgc2FmZVNldFN0YXRlKG5ld1N0YXRlKSB7XG4gICAgICAgIGlmICghY29tcGFyZU9ianModGhpcy5zdGF0ZSwgT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlKSwgbmV3U3RhdGUpLCB0aGlzLnN0YXRlRXF1YWxpdHkpKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKG5ld1N0YXRlKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblB1cmVDb21wb25lbnQuYWRkUHJvcHNFcXVhbGl0eSA9IGFkZFByb3BzRXF1YWxpdHk7XG5QdXJlQ29tcG9uZW50LmFkZFN0YXRlRXF1YWxpdHkgPSBhZGRTdGF0ZUVxdWFsaXR5O1xuUHVyZUNvbXBvbmVudC5jb250ZXh0VHlwZSA9IFZpZXdDb250ZXh0VHlwZTtcblB1cmVDb21wb25lbnQucHJvdG90eXBlLnByb3BFcXVhbGl0eSA9IHt9O1xuUHVyZUNvbXBvbmVudC5wcm90b3R5cGUuc3RhdGVFcXVhbGl0eSA9IHt9O1xuY2xhc3MgQmFzZUNvbXBvbmVudCBleHRlbmRzIFB1cmVDb21wb25lbnQge1xufVxuQmFzZUNvbXBvbmVudC5jb250ZXh0VHlwZSA9IFZpZXdDb250ZXh0VHlwZTtcbmZ1bmN0aW9uIGFkZFByb3BzRXF1YWxpdHkocHJvcEVxdWFsaXR5KSB7XG4gICAgbGV0IGhhc2ggPSBPYmplY3QuY3JlYXRlKHRoaXMucHJvdG90eXBlLnByb3BFcXVhbGl0eSk7XG4gICAgT2JqZWN0LmFzc2lnbihoYXNoLCBwcm9wRXF1YWxpdHkpO1xuICAgIHRoaXMucHJvdG90eXBlLnByb3BFcXVhbGl0eSA9IGhhc2g7XG59XG5mdW5jdGlvbiBhZGRTdGF0ZUVxdWFsaXR5KHN0YXRlRXF1YWxpdHkpIHtcbiAgICBsZXQgaGFzaCA9IE9iamVjdC5jcmVhdGUodGhpcy5wcm90b3R5cGUuc3RhdGVFcXVhbGl0eSk7XG4gICAgT2JqZWN0LmFzc2lnbihoYXNoLCBzdGF0ZUVxdWFsaXR5KTtcbiAgICB0aGlzLnByb3RvdHlwZS5zdGF0ZUVxdWFsaXR5ID0gaGFzaDtcbn1cbi8vIHVzZSBvdGhlciBvbmVcbmZ1bmN0aW9uIHNldFJlZihyZWYsIGN1cnJlbnQpIHtcbiAgICBpZiAodHlwZW9mIHJlZiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICByZWYoY3VycmVudCk7XG4gICAgfVxuICAgIGVsc2UgaWYgKHJlZikge1xuICAgICAgICAvLyBzZWUgaHR0cHM6Ly9naXRodWIuY29tL2ZhY2Vib29rL3JlYWN0L2lzc3Vlcy8xMzAyOVxuICAgICAgICByZWYuY3VycmVudCA9IGN1cnJlbnQ7XG4gICAgfVxufVxuXG5jbGFzcyBDb250ZW50SW5qZWN0b3IgZXh0ZW5kcyBCYXNlQ29tcG9uZW50IHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoLi4uYXJndW1lbnRzKTtcbiAgICAgICAgdGhpcy5pZCA9IGd1aWQoKTtcbiAgICAgICAgdGhpcy5xdWV1ZWREb21Ob2RlcyA9IFtdO1xuICAgICAgICB0aGlzLmN1cnJlbnREb21Ob2RlcyA9IFtdO1xuICAgICAgICB0aGlzLmhhbmRsZUVsID0gKGVsKSA9PiB7XG4gICAgICAgICAgICBjb25zdCB7IG9wdGlvbnMgfSA9IHRoaXMuY29udGV4dDtcbiAgICAgICAgICAgIGNvbnN0IHsgZ2VuZXJhdG9yTmFtZSB9ID0gdGhpcy5wcm9wcztcbiAgICAgICAgICAgIGlmICghb3B0aW9ucy5jdXN0b21SZW5kZXJpbmdSZXBsYWNlcyB8fCAhaGFzQ3VzdG9tUmVuZGVyaW5nSGFuZGxlcihnZW5lcmF0b3JOYW1lLCBvcHRpb25zKSkge1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlRWxSZWYoZWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICB0aGlzLnVwZGF0ZUVsUmVmID0gKGVsKSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy5wcm9wcy5lbFJlZikge1xuICAgICAgICAgICAgICAgIHNldFJlZih0aGlzLnByb3BzLmVsUmVmLCBlbCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfVxuICAgIHJlbmRlcigpIHtcbiAgICAgICAgY29uc3QgeyBwcm9wcywgY29udGV4dCB9ID0gdGhpcztcbiAgICAgICAgY29uc3QgeyBvcHRpb25zIH0gPSBjb250ZXh0O1xuICAgICAgICBjb25zdCB7IGN1c3RvbUdlbmVyYXRvciwgZGVmYXVsdEdlbmVyYXRvciwgcmVuZGVyUHJvcHMgfSA9IHByb3BzO1xuICAgICAgICBjb25zdCBhdHRycyA9IGJ1aWxkRWxBdHRycyhwcm9wcywgW10sIHRoaXMuaGFuZGxlRWwpO1xuICAgICAgICBsZXQgdXNlRGVmYXVsdCA9IGZhbHNlO1xuICAgICAgICBsZXQgaW5uZXJDb250ZW50O1xuICAgICAgICBsZXQgcXVldWVkRG9tTm9kZXMgPSBbXTtcbiAgICAgICAgbGV0IGN1cnJlbnRHZW5lcmF0b3JNZXRhO1xuICAgICAgICBpZiAoY3VzdG9tR2VuZXJhdG9yICE9IG51bGwpIHtcbiAgICAgICAgICAgIGNvbnN0IGN1c3RvbUdlbmVyYXRvclJlcyA9IHR5cGVvZiBjdXN0b21HZW5lcmF0b3IgPT09ICdmdW5jdGlvbicgP1xuICAgICAgICAgICAgICAgIGN1c3RvbUdlbmVyYXRvcihyZW5kZXJQcm9wcywgY3JlYXRlRWxlbWVudCkgOlxuICAgICAgICAgICAgICAgIGN1c3RvbUdlbmVyYXRvcjtcbiAgICAgICAgICAgIGlmIChjdXN0b21HZW5lcmF0b3JSZXMgPT09IHRydWUpIHtcbiAgICAgICAgICAgICAgICB1c2VEZWZhdWx0ID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGNvbnN0IGlzT2JqZWN0ID0gY3VzdG9tR2VuZXJhdG9yUmVzICYmIHR5cGVvZiBjdXN0b21HZW5lcmF0b3JSZXMgPT09ICdvYmplY3QnOyAvLyBub24tbnVsbFxuICAgICAgICAgICAgICAgIGlmIChpc09iamVjdCAmJiAoJ2h0bWwnIGluIGN1c3RvbUdlbmVyYXRvclJlcykpIHtcbiAgICAgICAgICAgICAgICAgICAgYXR0cnMuZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUwgPSB7IF9faHRtbDogY3VzdG9tR2VuZXJhdG9yUmVzLmh0bWwgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoaXNPYmplY3QgJiYgKCdkb21Ob2RlcycgaW4gY3VzdG9tR2VuZXJhdG9yUmVzKSkge1xuICAgICAgICAgICAgICAgICAgICBxdWV1ZWREb21Ob2RlcyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGN1c3RvbUdlbmVyYXRvclJlcy5kb21Ob2Rlcyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKGlzT2JqZWN0XG4gICAgICAgICAgICAgICAgICAgID8gaXNWYWxpZEVsZW1lbnQoY3VzdG9tR2VuZXJhdG9yUmVzKSAvLyB2ZG9tIG5vZGVcbiAgICAgICAgICAgICAgICAgICAgOiB0eXBlb2YgY3VzdG9tR2VuZXJhdG9yUmVzICE9PSAnZnVuY3Rpb24nIC8vIHByaW1pdGl2ZSB2YWx1ZSAobGlrZSBzdHJpbmcgb3IgbnVtYmVyKVxuICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICAvLyB1c2UgaW4gdmRvbVxuICAgICAgICAgICAgICAgICAgICBpbm5lckNvbnRlbnQgPSBjdXN0b21HZW5lcmF0b3JSZXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAvLyBhbiBleG90aWMgb2JqZWN0IGZvciBoYW5kbGVDdXN0b21SZW5kZXJpbmdcbiAgICAgICAgICAgICAgICAgICAgY3VycmVudEdlbmVyYXRvck1ldGEgPSBjdXN0b21HZW5lcmF0b3JSZXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdXNlRGVmYXVsdCA9ICFoYXNDdXN0b21SZW5kZXJpbmdIYW5kbGVyKHByb3BzLmdlbmVyYXRvck5hbWUsIG9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgICAgIGlmICh1c2VEZWZhdWx0ICYmIGRlZmF1bHRHZW5lcmF0b3IpIHtcbiAgICAgICAgICAgIGlubmVyQ29udGVudCA9IGRlZmF1bHRHZW5lcmF0b3IocmVuZGVyUHJvcHMpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucXVldWVkRG9tTm9kZXMgPSBxdWV1ZWREb21Ob2RlcztcbiAgICAgICAgdGhpcy5jdXJyZW50R2VuZXJhdG9yTWV0YSA9IGN1cnJlbnRHZW5lcmF0b3JNZXRhO1xuICAgICAgICByZXR1cm4gY3JlYXRlRWxlbWVudChwcm9wcy5lbFRhZywgYXR0cnMsIGlubmVyQ29udGVudCk7XG4gICAgfVxuICAgIGNvbXBvbmVudERpZE1vdW50KCkge1xuICAgICAgICB0aGlzLmFwcGx5UXVldWV1ZERvbU5vZGVzKCk7XG4gICAgICAgIHRoaXMudHJpZ2dlckN1c3RvbVJlbmRlcmluZyh0cnVlKTtcbiAgICB9XG4gICAgY29tcG9uZW50RGlkVXBkYXRlKCkge1xuICAgICAgICB0aGlzLmFwcGx5UXVldWV1ZERvbU5vZGVzKCk7XG4gICAgICAgIHRoaXMudHJpZ2dlckN1c3RvbVJlbmRlcmluZyh0cnVlKTtcbiAgICB9XG4gICAgY29tcG9uZW50V2lsbFVubW91bnQoKSB7XG4gICAgICAgIHRoaXMudHJpZ2dlckN1c3RvbVJlbmRlcmluZyhmYWxzZSk7IC8vIFRPRE86IGRpZmZlcmVudCBBUEkgZm9yIHJlbW92YWw/XG4gICAgfVxuICAgIHRyaWdnZXJDdXN0b21SZW5kZXJpbmcoaXNBY3RpdmUpIHtcbiAgICAgICAgdmFyIF9hO1xuICAgICAgICBjb25zdCB7IHByb3BzLCBjb250ZXh0IH0gPSB0aGlzO1xuICAgICAgICBjb25zdCB7IGhhbmRsZUN1c3RvbVJlbmRlcmluZywgY3VzdG9tUmVuZGVyaW5nTWV0YU1hcCB9ID0gY29udGV4dC5vcHRpb25zO1xuICAgICAgICBpZiAoaGFuZGxlQ3VzdG9tUmVuZGVyaW5nKSB7XG4gICAgICAgICAgICBjb25zdCBnZW5lcmF0b3JNZXRhID0gKF9hID0gdGhpcy5jdXJyZW50R2VuZXJhdG9yTWV0YSkgIT09IG51bGwgJiYgX2EgIT09IHZvaWQgMCA/IF9hIDogY3VzdG9tUmVuZGVyaW5nTWV0YU1hcCA9PT0gbnVsbCB8fCBjdXN0b21SZW5kZXJpbmdNZXRhTWFwID09PSB2b2lkIDAgPyB2b2lkIDAgOiBjdXN0b21SZW5kZXJpbmdNZXRhTWFwW3Byb3BzLmdlbmVyYXRvck5hbWVdO1xuICAgICAgICAgICAgaWYgKGdlbmVyYXRvck1ldGEpIHtcbiAgICAgICAgICAgICAgICBoYW5kbGVDdXN0b21SZW5kZXJpbmcoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHsgaWQ6IHRoaXMuaWQsIGlzQWN0aXZlLCBjb250YWluZXJFbDogdGhpcy5iYXNlLCByZXBvcnROZXdDb250YWluZXJFbDogdGhpcy51cGRhdGVFbFJlZiwgLy8gZnJvbnQtZW5kIGZyYW1ld29yayB0ZWxscyB1cyBhYm91dCBuZXcgY29udGFpbmVyIGVsc1xuICAgICAgICAgICAgICAgICAgICBnZW5lcmF0b3JNZXRhIH0sIHByb3BzKSwgeyBlbENsYXNzZXM6IChwcm9wcy5lbENsYXNzZXMgfHwgW10pLmZpbHRlcihpc1RydXRoeSkgfSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIGFwcGx5UXVldWV1ZERvbU5vZGVzKCkge1xuICAgICAgICBjb25zdCB7IHF1ZXVlZERvbU5vZGVzLCBjdXJyZW50RG9tTm9kZXMgfSA9IHRoaXM7XG4gICAgICAgIGNvbnN0IGVsID0gdGhpcy5iYXNlO1xuICAgICAgICBpZiAoIWlzQXJyYXlzRXF1YWwocXVldWVkRG9tTm9kZXMsIGN1cnJlbnREb21Ob2RlcykpIHtcbiAgICAgICAgICAgIGN1cnJlbnREb21Ob2Rlcy5mb3JFYWNoKHJlbW92ZUVsZW1lbnQpO1xuICAgICAgICAgICAgZm9yIChsZXQgbmV3Tm9kZSBvZiBxdWV1ZWREb21Ob2Rlcykge1xuICAgICAgICAgICAgICAgIGVsLmFwcGVuZENoaWxkKG5ld05vZGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5jdXJyZW50RG9tTm9kZXMgPSBxdWV1ZWREb21Ob2RlcztcbiAgICAgICAgfVxuICAgIH1cbn1cbkNvbnRlbnRJbmplY3Rvci5hZGRQcm9wc0VxdWFsaXR5KHtcbiAgICBlbENsYXNzZXM6IGlzQXJyYXlzRXF1YWwsXG4gICAgZWxTdHlsZTogaXNQcm9wc0VxdWFsLFxuICAgIGVsQXR0cnM6IGlzTm9uSGFuZGxlclByb3BzRXF1YWwsXG4gICAgcmVuZGVyUHJvcHM6IGlzUHJvcHNFcXVhbCxcbn0pO1xuLy8gVXRpbFxuLypcbkRvZXMgVUktZnJhbWV3b3JrIHByb3ZpZGUgY3VzdG9tIHdheSBvZiByZW5kZXJpbmcgdGhhdCBkb2VzIG5vdCB1c2UgUHJlYWN0IFZET01cbkFORCBkb2VzIHRoZSBjYWxlbmRhcidzIG9wdGlvbnMgZGVmaW5lIGN1c3RvbSByZW5kZXJpbmc/XG5BS0EuIFNob3VsZCB3ZSBOT1QgcmVuZGVyIHRoZSBkZWZhdWx0IGNvbnRlbnQ/XG4qL1xuZnVuY3Rpb24gaGFzQ3VzdG9tUmVuZGVyaW5nSGFuZGxlcihnZW5lcmF0b3JOYW1lLCBvcHRpb25zKSB7XG4gICAgdmFyIF9hO1xuICAgIHJldHVybiBCb29sZWFuKG9wdGlvbnMuaGFuZGxlQ3VzdG9tUmVuZGVyaW5nICYmXG4gICAgICAgIGdlbmVyYXRvck5hbWUgJiZcbiAgICAgICAgKChfYSA9IG9wdGlvbnMuY3VzdG9tUmVuZGVyaW5nTWV0YU1hcCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hW2dlbmVyYXRvck5hbWVdKSk7XG59XG5mdW5jdGlvbiBidWlsZEVsQXR0cnMocHJvcHMsIGV4dHJhQ2xhc3NOYW1lcywgZWxSZWYpIHtcbiAgICBjb25zdCBhdHRycyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJvcHMuZWxBdHRycyksIHsgcmVmOiBlbFJlZiB9KTtcbiAgICBpZiAocHJvcHMuZWxDbGFzc2VzIHx8IGV4dHJhQ2xhc3NOYW1lcykge1xuICAgICAgICBhdHRycy5jbGFzc05hbWUgPSAocHJvcHMuZWxDbGFzc2VzIHx8IFtdKVxuICAgICAgICAgICAgLmNvbmNhdChleHRyYUNsYXNzTmFtZXMgfHwgW10pXG4gICAgICAgICAgICAuY29uY2F0KGF0dHJzLmNsYXNzTmFtZSB8fCBbXSlcbiAgICAgICAgICAgIC5maWx0ZXIoQm9vbGVhbilcbiAgICAgICAgICAgIC5qb2luKCcgJyk7XG4gICAgfVxuICAgIGlmIChwcm9wcy5lbFN0eWxlKSB7XG4gICAgICAgIGF0dHJzLnN0eWxlID0gcHJvcHMuZWxTdHlsZTtcbiAgICB9XG4gICAgcmV0dXJuIGF0dHJzO1xufVxuZnVuY3Rpb24gaXNUcnV0aHkodmFsKSB7XG4gICAgcmV0dXJuIEJvb2xlYW4odmFsKTtcbn1cblxuY29uc3QgUmVuZGVySWQgPSBjcmVhdGVDb250ZXh0KDApO1xuXG5jbGFzcyBDb250ZW50Q29udGFpbmVyIGV4dGVuZHMgQ29tcG9uZW50IHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoLi4uYXJndW1lbnRzKTtcbiAgICAgICAgdGhpcy5Jbm5lckNvbnRlbnQgPSBJbm5lckNvbnRlbnRJbmplY3Rvci5iaW5kKHVuZGVmaW5lZCwgdGhpcyk7XG4gICAgICAgIHRoaXMuaGFuZGxlRWwgPSAoZWwpID0+IHtcbiAgICAgICAgICAgIHRoaXMuZWwgPSBlbDtcbiAgICAgICAgICAgIGlmICh0aGlzLnByb3BzLmVsUmVmKSB7XG4gICAgICAgICAgICAgICAgc2V0UmVmKHRoaXMucHJvcHMuZWxSZWYsIGVsKTtcbiAgICAgICAgICAgICAgICBpZiAoZWwgJiYgdGhpcy5kaWRNb3VudE1pc2ZpcmUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb21wb25lbnREaWRNb3VudCgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG4gICAgcmVuZGVyKCkge1xuICAgICAgICBjb25zdCB7IHByb3BzIH0gPSB0aGlzO1xuICAgICAgICBjb25zdCBnZW5lcmF0ZWRDbGFzc05hbWVzID0gZ2VuZXJhdGVDbGFzc05hbWVzKHByb3BzLmNsYXNzTmFtZUdlbmVyYXRvciwgcHJvcHMucmVuZGVyUHJvcHMpO1xuICAgICAgICBpZiAocHJvcHMuY2hpbGRyZW4pIHtcbiAgICAgICAgICAgIGNvbnN0IGVsQXR0cnMgPSBidWlsZEVsQXR0cnMocHJvcHMsIGdlbmVyYXRlZENsYXNzTmFtZXMsIHRoaXMuaGFuZGxlRWwpO1xuICAgICAgICAgICAgY29uc3QgY2hpbGRyZW4gPSBwcm9wcy5jaGlsZHJlbih0aGlzLklubmVyQ29udGVudCwgcHJvcHMucmVuZGVyUHJvcHMsIGVsQXR0cnMpO1xuICAgICAgICAgICAgaWYgKHByb3BzLmVsVGFnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGNyZWF0ZUVsZW1lbnQocHJvcHMuZWxUYWcsIGVsQXR0cnMsIGNoaWxkcmVuKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBjaGlsZHJlbjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVFbGVtZW50KChDb250ZW50SW5qZWN0b3IpLCBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByb3BzKSwgeyBlbFJlZjogdGhpcy5oYW5kbGVFbCwgZWxUYWc6IHByb3BzLmVsVGFnIHx8ICdkaXYnLCBlbENsYXNzZXM6IChwcm9wcy5lbENsYXNzZXMgfHwgW10pLmNvbmNhdChnZW5lcmF0ZWRDbGFzc05hbWVzKSwgcmVuZGVySWQ6IHRoaXMuY29udGV4dCB9KSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgY29tcG9uZW50RGlkTW91bnQoKSB7XG4gICAgICAgIHZhciBfYSwgX2I7XG4gICAgICAgIGlmICh0aGlzLmVsKSB7XG4gICAgICAgICAgICAoX2IgPSAoX2EgPSB0aGlzLnByb3BzKS5kaWRNb3VudCkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmNhbGwoX2EsIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5wcm9wcy5yZW5kZXJQcm9wcyksIHsgZWw6IHRoaXMuZWwgfSkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5kaWRNb3VudE1pc2ZpcmUgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbXBvbmVudFdpbGxVbm1vdW50KCkge1xuICAgICAgICB2YXIgX2EsIF9iO1xuICAgICAgICAoX2IgPSAoX2EgPSB0aGlzLnByb3BzKS53aWxsVW5tb3VudCkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmNhbGwoX2EsIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5wcm9wcy5yZW5kZXJQcm9wcyksIHsgZWw6IHRoaXMuZWwgfSkpO1xuICAgIH1cbn1cbkNvbnRlbnRDb250YWluZXIuY29udGV4dFR5cGUgPSBSZW5kZXJJZDtcbmZ1bmN0aW9uIElubmVyQ29udGVudEluamVjdG9yKGNvbnRhaW5lckNvbXBvbmVudCwgcHJvcHMpIHtcbiAgICBjb25zdCBwYXJlbnRQcm9wcyA9IGNvbnRhaW5lckNvbXBvbmVudC5wcm9wcztcbiAgICByZXR1cm4gY3JlYXRlRWxlbWVudCgoQ29udGVudEluamVjdG9yKSwgT2JqZWN0LmFzc2lnbih7IHJlbmRlclByb3BzOiBwYXJlbnRQcm9wcy5yZW5kZXJQcm9wcywgZ2VuZXJhdG9yTmFtZTogcGFyZW50UHJvcHMuZ2VuZXJhdG9yTmFtZSwgY3VzdG9tR2VuZXJhdG9yOiBwYXJlbnRQcm9wcy5jdXN0b21HZW5lcmF0b3IsIGRlZmF1bHRHZW5lcmF0b3I6IHBhcmVudFByb3BzLmRlZmF1bHRHZW5lcmF0b3IsIHJlbmRlcklkOiBjb250YWluZXJDb21wb25lbnQuY29udGV4dCB9LCBwcm9wcykpO1xufVxuLy8gVXRpbHNcbmZ1bmN0aW9uIGdlbmVyYXRlQ2xhc3NOYW1lcyhjbGFzc05hbWVHZW5lcmF0b3IsIHJlbmRlclByb3BzKSB7XG4gICAgY29uc3QgY2xhc3NOYW1lcyA9IHR5cGVvZiBjbGFzc05hbWVHZW5lcmF0b3IgPT09ICdmdW5jdGlvbicgP1xuICAgICAgICBjbGFzc05hbWVHZW5lcmF0b3IocmVuZGVyUHJvcHMpIDpcbiAgICAgICAgY2xhc3NOYW1lR2VuZXJhdG9yIHx8IFtdO1xuICAgIHJldHVybiB0eXBlb2YgY2xhc3NOYW1lcyA9PT0gJ3N0cmluZycgPyBbY2xhc3NOYW1lc10gOiBjbGFzc05hbWVzO1xufVxuXG5jbGFzcyBWaWV3Q29udGFpbmVyIGV4dGVuZHMgQmFzZUNvbXBvbmVudCB7XG4gICAgcmVuZGVyKCkge1xuICAgICAgICBsZXQgeyBwcm9wcywgY29udGV4dCB9ID0gdGhpcztcbiAgICAgICAgbGV0IHsgb3B0aW9ucyB9ID0gY29udGV4dDtcbiAgICAgICAgbGV0IHJlbmRlclByb3BzID0geyB2aWV3OiBjb250ZXh0LnZpZXdBcGkgfTtcbiAgICAgICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KENvbnRlbnRDb250YWluZXIsIHsgZWxSZWY6IHByb3BzLmVsUmVmLCBlbFRhZzogcHJvcHMuZWxUYWcgfHwgJ2RpdicsIGVsQXR0cnM6IHByb3BzLmVsQXR0cnMsIGVsQ2xhc3NlczogW1xuICAgICAgICAgICAgICAgIC4uLmJ1aWxkVmlld0NsYXNzTmFtZXMocHJvcHMudmlld1NwZWMpLFxuICAgICAgICAgICAgICAgIC4uLihwcm9wcy5lbENsYXNzZXMgfHwgW10pLFxuICAgICAgICAgICAgXSwgZWxTdHlsZTogcHJvcHMuZWxTdHlsZSwgcmVuZGVyUHJvcHM6IHJlbmRlclByb3BzLCBjbGFzc05hbWVHZW5lcmF0b3I6IG9wdGlvbnMudmlld0NsYXNzTmFtZXMsIGdlbmVyYXRvck5hbWU6IHVuZGVmaW5lZCwgZGlkTW91bnQ6IG9wdGlvbnMudmlld0RpZE1vdW50LCB3aWxsVW5tb3VudDogb3B0aW9ucy52aWV3V2lsbFVubW91bnQgfSwgKCkgPT4gcHJvcHMuY2hpbGRyZW4pKTtcbiAgICB9XG59XG5mdW5jdGlvbiBidWlsZFZpZXdDbGFzc05hbWVzKHZpZXdTcGVjKSB7XG4gICAgcmV0dXJuIFtcbiAgICAgICAgYGZjLSR7dmlld1NwZWMudHlwZX0tdmlld2AsXG4gICAgICAgICdmYy12aWV3JyxcbiAgICBdO1xufVxuXG5mdW5jdGlvbiBwYXJzZVJhbmdlKGlucHV0LCBkYXRlRW52KSB7XG4gICAgbGV0IHN0YXJ0ID0gbnVsbDtcbiAgICBsZXQgZW5kID0gbnVsbDtcbiAgICBpZiAoaW5wdXQuc3RhcnQpIHtcbiAgICAgICAgc3RhcnQgPSBkYXRlRW52LmNyZWF0ZU1hcmtlcihpbnB1dC5zdGFydCk7XG4gICAgfVxuICAgIGlmIChpbnB1dC5lbmQpIHtcbiAgICAgICAgZW5kID0gZGF0ZUVudi5jcmVhdGVNYXJrZXIoaW5wdXQuZW5kKTtcbiAgICB9XG4gICAgaWYgKCFzdGFydCAmJiAhZW5kKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBpZiAoc3RhcnQgJiYgZW5kICYmIGVuZCA8IHN0YXJ0KSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICByZXR1cm4geyBzdGFydCwgZW5kIH07XG59XG4vLyBTSURFLUVGRkVDVDogd2lsbCBtdXRhdGUgcmFuZ2VzLlxuLy8gV2lsbCByZXR1cm4gYSBuZXcgYXJyYXkgcmVzdWx0LlxuZnVuY3Rpb24gaW52ZXJ0UmFuZ2VzKHJhbmdlcywgY29uc3RyYWludFJhbmdlKSB7XG4gICAgbGV0IGludmVydGVkUmFuZ2VzID0gW107XG4gICAgbGV0IHsgc3RhcnQgfSA9IGNvbnN0cmFpbnRSYW5nZTsgLy8gdGhlIGVuZCBvZiB0aGUgcHJldmlvdXMgcmFuZ2UuIHRoZSBzdGFydCBvZiB0aGUgbmV3IHJhbmdlXG4gICAgbGV0IGk7XG4gICAgbGV0IGRhdGVSYW5nZTtcbiAgICAvLyByYW5nZXMgbmVlZCB0byBiZSBpbiBvcmRlci4gcmVxdWlyZWQgZm9yIG91ciBkYXRlLXdhbGtpbmcgYWxnb3JpdGhtXG4gICAgcmFuZ2VzLnNvcnQoY29tcGFyZVJhbmdlcyk7XG4gICAgZm9yIChpID0gMDsgaSA8IHJhbmdlcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICBkYXRlUmFuZ2UgPSByYW5nZXNbaV07XG4gICAgICAgIC8vIGFkZCB0aGUgc3BhbiBvZiB0aW1lIGJlZm9yZSB0aGUgZXZlbnQgKGlmIHRoZXJlIGlzIGFueSlcbiAgICAgICAgaWYgKGRhdGVSYW5nZS5zdGFydCA+IHN0YXJ0KSB7IC8vIGNvbXBhcmUgbWlsbGlzZWNvbmQgdGltZSAoc2tpcCBhbnkgYW1iaWcgbG9naWMpXG4gICAgICAgICAgICBpbnZlcnRlZFJhbmdlcy5wdXNoKHsgc3RhcnQsIGVuZDogZGF0ZVJhbmdlLnN0YXJ0IH0pO1xuICAgICAgICB9XG4gICAgICAgIGlmIChkYXRlUmFuZ2UuZW5kID4gc3RhcnQpIHtcbiAgICAgICAgICAgIHN0YXJ0ID0gZGF0ZVJhbmdlLmVuZDtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBhZGQgdGhlIHNwYW4gb2YgdGltZSBhZnRlciB0aGUgbGFzdCBldmVudCAoaWYgdGhlcmUgaXMgYW55KVxuICAgIGlmIChzdGFydCA8IGNvbnN0cmFpbnRSYW5nZS5lbmQpIHsgLy8gY29tcGFyZSBtaWxsaXNlY29uZCB0aW1lIChza2lwIGFueSBhbWJpZyBsb2dpYylcbiAgICAgICAgaW52ZXJ0ZWRSYW5nZXMucHVzaCh7IHN0YXJ0LCBlbmQ6IGNvbnN0cmFpbnRSYW5nZS5lbmQgfSk7XG4gICAgfVxuICAgIHJldHVybiBpbnZlcnRlZFJhbmdlcztcbn1cbmZ1bmN0aW9uIGNvbXBhcmVSYW5nZXMocmFuZ2UwLCByYW5nZTEpIHtcbiAgICByZXR1cm4gcmFuZ2UwLnN0YXJ0LnZhbHVlT2YoKSAtIHJhbmdlMS5zdGFydC52YWx1ZU9mKCk7IC8vIGVhcmxpZXIgcmFuZ2VzIGdvIGZpcnN0XG59XG5mdW5jdGlvbiBpbnRlcnNlY3RSYW5nZXMocmFuZ2UwLCByYW5nZTEpIHtcbiAgICBsZXQgeyBzdGFydCwgZW5kIH0gPSByYW5nZTA7XG4gICAgbGV0IG5ld1JhbmdlID0gbnVsbDtcbiAgICBpZiAocmFuZ2UxLnN0YXJ0ICE9PSBudWxsKSB7XG4gICAgICAgIGlmIChzdGFydCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgc3RhcnQgPSByYW5nZTEuc3RhcnQ7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBzdGFydCA9IG5ldyBEYXRlKE1hdGgubWF4KHN0YXJ0LnZhbHVlT2YoKSwgcmFuZ2UxLnN0YXJ0LnZhbHVlT2YoKSkpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGlmIChyYW5nZTEuZW5kICE9IG51bGwpIHtcbiAgICAgICAgaWYgKGVuZCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgZW5kID0gcmFuZ2UxLmVuZDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGVuZCA9IG5ldyBEYXRlKE1hdGgubWluKGVuZC52YWx1ZU9mKCksIHJhbmdlMS5lbmQudmFsdWVPZigpKSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgaWYgKHN0YXJ0ID09PSBudWxsIHx8IGVuZCA9PT0gbnVsbCB8fCBzdGFydCA8IGVuZCkge1xuICAgICAgICBuZXdSYW5nZSA9IHsgc3RhcnQsIGVuZCB9O1xuICAgIH1cbiAgICByZXR1cm4gbmV3UmFuZ2U7XG59XG5mdW5jdGlvbiByYW5nZXNFcXVhbChyYW5nZTAsIHJhbmdlMSkge1xuICAgIHJldHVybiAocmFuZ2UwLnN0YXJ0ID09PSBudWxsID8gbnVsbCA6IHJhbmdlMC5zdGFydC52YWx1ZU9mKCkpID09PSAocmFuZ2UxLnN0YXJ0ID09PSBudWxsID8gbnVsbCA6IHJhbmdlMS5zdGFydC52YWx1ZU9mKCkpICYmXG4gICAgICAgIChyYW5nZTAuZW5kID09PSBudWxsID8gbnVsbCA6IHJhbmdlMC5lbmQudmFsdWVPZigpKSA9PT0gKHJhbmdlMS5lbmQgPT09IG51bGwgPyBudWxsIDogcmFuZ2UxLmVuZC52YWx1ZU9mKCkpO1xufVxuZnVuY3Rpb24gcmFuZ2VzSW50ZXJzZWN0KHJhbmdlMCwgcmFuZ2UxKSB7XG4gICAgcmV0dXJuIChyYW5nZTAuZW5kID09PSBudWxsIHx8IHJhbmdlMS5zdGFydCA9PT0gbnVsbCB8fCByYW5nZTAuZW5kID4gcmFuZ2UxLnN0YXJ0KSAmJlxuICAgICAgICAocmFuZ2UwLnN0YXJ0ID09PSBudWxsIHx8IHJhbmdlMS5lbmQgPT09IG51bGwgfHwgcmFuZ2UwLnN0YXJ0IDwgcmFuZ2UxLmVuZCk7XG59XG5mdW5jdGlvbiByYW5nZUNvbnRhaW5zUmFuZ2Uob3V0ZXJSYW5nZSwgaW5uZXJSYW5nZSkge1xuICAgIHJldHVybiAob3V0ZXJSYW5nZS5zdGFydCA9PT0gbnVsbCB8fCAoaW5uZXJSYW5nZS5zdGFydCAhPT0gbnVsbCAmJiBpbm5lclJhbmdlLnN0YXJ0ID49IG91dGVyUmFuZ2Uuc3RhcnQpKSAmJlxuICAgICAgICAob3V0ZXJSYW5nZS5lbmQgPT09IG51bGwgfHwgKGlubmVyUmFuZ2UuZW5kICE9PSBudWxsICYmIGlubmVyUmFuZ2UuZW5kIDw9IG91dGVyUmFuZ2UuZW5kKSk7XG59XG5mdW5jdGlvbiByYW5nZUNvbnRhaW5zTWFya2VyKHJhbmdlLCBkYXRlKSB7XG4gICAgcmV0dXJuIChyYW5nZS5zdGFydCA9PT0gbnVsbCB8fCBkYXRlID49IHJhbmdlLnN0YXJ0KSAmJlxuICAgICAgICAocmFuZ2UuZW5kID09PSBudWxsIHx8IGRhdGUgPCByYW5nZS5lbmQpO1xufVxuLy8gSWYgdGhlIGdpdmVuIGRhdGUgaXMgbm90IHdpdGhpbiB0aGUgZ2l2ZW4gcmFuZ2UsIG1vdmUgaXQgaW5zaWRlLlxuLy8gKElmIGl0J3MgcGFzdCB0aGUgZW5kLCBtYWtlIGl0IG9uZSBtaWxsaXNlY29uZCBiZWZvcmUgdGhlIGVuZCkuXG5mdW5jdGlvbiBjb25zdHJhaW5NYXJrZXJUb1JhbmdlKGRhdGUsIHJhbmdlKSB7XG4gICAgaWYgKHJhbmdlLnN0YXJ0ICE9IG51bGwgJiYgZGF0ZSA8IHJhbmdlLnN0YXJ0KSB7XG4gICAgICAgIHJldHVybiByYW5nZS5zdGFydDtcbiAgICB9XG4gICAgaWYgKHJhbmdlLmVuZCAhPSBudWxsICYmIGRhdGUgPj0gcmFuZ2UuZW5kKSB7XG4gICAgICAgIHJldHVybiBuZXcgRGF0ZShyYW5nZS5lbmQudmFsdWVPZigpIC0gMSk7XG4gICAgfVxuICAgIHJldHVybiBkYXRlO1xufVxuXG4vKiBEYXRlIHN0dWZmIHRoYXQgZG9lc24ndCBiZWxvbmcgaW4gZGF0ZWxpYiBjb3JlXG4tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbi8vIGdpdmVuIGEgdGltZWQgcmFuZ2UsIGNvbXB1dGVzIGFuIGFsbC1kYXkgcmFuZ2UgdGhhdCBoYXMgdGhlIHNhbWUgZXhhY3QgZHVyYXRpb24sXG4vLyBidXQgd2hvc2Ugc3RhcnQgdGltZSBpcyBhbGlnbmVkIHdpdGggdGhlIHN0YXJ0IG9mIHRoZSBkYXkuXG5mdW5jdGlvbiBjb21wdXRlQWxpZ25lZERheVJhbmdlKHRpbWVkUmFuZ2UpIHtcbiAgICBsZXQgZGF5Q250ID0gTWF0aC5mbG9vcihkaWZmRGF5cyh0aW1lZFJhbmdlLnN0YXJ0LCB0aW1lZFJhbmdlLmVuZCkpIHx8IDE7XG4gICAgbGV0IHN0YXJ0ID0gc3RhcnRPZkRheSh0aW1lZFJhbmdlLnN0YXJ0KTtcbiAgICBsZXQgZW5kID0gYWRkRGF5cyhzdGFydCwgZGF5Q250KTtcbiAgICByZXR1cm4geyBzdGFydCwgZW5kIH07XG59XG4vLyBnaXZlbiBhIHRpbWVkIHJhbmdlLCBjb21wdXRlcyBhbiBhbGwtZGF5IHJhbmdlIGJhc2VkIG9uIGhvdyBmb3IgdGhlIGVuZCBkYXRlIGJsZWVkcyBpbnRvIHRoZSBuZXh0IGRheVxuLy8gVE9ETzogZ2l2ZSBuZXh0RGF5VGhyZXNob2xkIGEgZGVmYXVsdCBhcmdcbmZ1bmN0aW9uIGNvbXB1dGVWaXNpYmxlRGF5UmFuZ2UodGltZWRSYW5nZSwgbmV4dERheVRocmVzaG9sZCA9IGNyZWF0ZUR1cmF0aW9uKDApKSB7XG4gICAgbGV0IHN0YXJ0RGF5ID0gbnVsbDtcbiAgICBsZXQgZW5kRGF5ID0gbnVsbDtcbiAgICBpZiAodGltZWRSYW5nZS5lbmQpIHtcbiAgICAgICAgZW5kRGF5ID0gc3RhcnRPZkRheSh0aW1lZFJhbmdlLmVuZCk7XG4gICAgICAgIGxldCBlbmRUaW1lTVMgPSB0aW1lZFJhbmdlLmVuZC52YWx1ZU9mKCkgLSBlbmREYXkudmFsdWVPZigpOyAvLyAjIG9mIG1pbGxpc2Vjb25kcyBpbnRvIGBlbmREYXlgXG4gICAgICAgIC8vIElmIHRoZSBlbmQgdGltZSBpcyBhY3R1YWxseSBpbmNsdXNpdmVseSBwYXJ0IG9mIHRoZSBuZXh0IGRheSBhbmQgaXMgZXF1YWwgdG8gb3JcbiAgICAgICAgLy8gYmV5b25kIHRoZSBuZXh0IGRheSB0aHJlc2hvbGQsIGFkanVzdCB0aGUgZW5kIHRvIGJlIHRoZSBleGNsdXNpdmUgZW5kIG9mIGBlbmREYXlgLlxuICAgICAgICAvLyBPdGhlcndpc2UsIGxlYXZpbmcgaXQgYXMgaW5jbHVzaXZlIHdpbGwgY2F1c2UgaXQgdG8gZXhjbHVkZSBgZW5kRGF5YC5cbiAgICAgICAgaWYgKGVuZFRpbWVNUyAmJiBlbmRUaW1lTVMgPj0gYXNSb3VnaE1zKG5leHREYXlUaHJlc2hvbGQpKSB7XG4gICAgICAgICAgICBlbmREYXkgPSBhZGREYXlzKGVuZERheSwgMSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgaWYgKHRpbWVkUmFuZ2Uuc3RhcnQpIHtcbiAgICAgICAgc3RhcnREYXkgPSBzdGFydE9mRGF5KHRpbWVkUmFuZ2Uuc3RhcnQpOyAvLyB0aGUgYmVnaW5uaW5nIG9mIHRoZSBkYXkgdGhlIHJhbmdlIHN0YXJ0c1xuICAgICAgICAvLyBJZiBlbmQgaXMgd2l0aGluIGBzdGFydERheWAgYnV0IG5vdCBwYXN0IG5leHREYXlUaHJlc2hvbGQsIGFzc2lnbiB0aGUgZGVmYXVsdCBkdXJhdGlvbiBvZiBvbmUgZGF5LlxuICAgICAgICBpZiAoZW5kRGF5ICYmIGVuZERheSA8PSBzdGFydERheSkge1xuICAgICAgICAgICAgZW5kRGF5ID0gYWRkRGF5cyhzdGFydERheSwgMSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgc3RhcnQ6IHN0YXJ0RGF5LCBlbmQ6IGVuZERheSB9O1xufVxuLy8gc3BhbnMgZnJvbSBvbmUgZGF5IGludG8gYW5vdGhlcj9cbmZ1bmN0aW9uIGlzTXVsdGlEYXlSYW5nZShyYW5nZSkge1xuICAgIGxldCB2aXNpYmxlUmFuZ2UgPSBjb21wdXRlVmlzaWJsZURheVJhbmdlKHJhbmdlKTtcbiAgICByZXR1cm4gZGlmZkRheXModmlzaWJsZVJhbmdlLnN0YXJ0LCB2aXNpYmxlUmFuZ2UuZW5kKSA+IDE7XG59XG5mdW5jdGlvbiBkaWZmRGF0ZXMoZGF0ZTAsIGRhdGUxLCBkYXRlRW52LCBsYXJnZVVuaXQpIHtcbiAgICBpZiAobGFyZ2VVbml0ID09PSAneWVhcicpIHtcbiAgICAgICAgcmV0dXJuIGNyZWF0ZUR1cmF0aW9uKGRhdGVFbnYuZGlmZldob2xlWWVhcnMoZGF0ZTAsIGRhdGUxKSwgJ3llYXInKTtcbiAgICB9XG4gICAgaWYgKGxhcmdlVW5pdCA9PT0gJ21vbnRoJykge1xuICAgICAgICByZXR1cm4gY3JlYXRlRHVyYXRpb24oZGF0ZUVudi5kaWZmV2hvbGVNb250aHMoZGF0ZTAsIGRhdGUxKSwgJ21vbnRoJyk7XG4gICAgfVxuICAgIHJldHVybiBkaWZmRGF5QW5kVGltZShkYXRlMCwgZGF0ZTEpOyAvLyByZXR1cm5zIGEgZHVyYXRpb25cbn1cblxuY2xhc3MgRGF0ZVByb2ZpbGVHZW5lcmF0b3Ige1xuICAgIGNvbnN0cnVjdG9yKHByb3BzKSB7XG4gICAgICAgIHRoaXMucHJvcHMgPSBwcm9wcztcbiAgICAgICAgdGhpcy5pbml0SGlkZGVuRGF5cygpO1xuICAgIH1cbiAgICAvKiBEYXRlIFJhbmdlIENvbXB1dGF0aW9uXG4gICAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbiAgICAvLyBCdWlsZHMgYSBzdHJ1Y3R1cmUgd2l0aCBpbmZvIGFib3V0IHdoYXQgdGhlIGRhdGVzL3JhbmdlcyB3aWxsIGJlIGZvciB0aGUgXCJwcmV2XCIgdmlldy5cbiAgICBidWlsZFByZXYoY3VycmVudERhdGVQcm9maWxlLCBjdXJyZW50RGF0ZSwgZm9yY2VUb1ZhbGlkKSB7XG4gICAgICAgIGxldCB7IGRhdGVFbnYgfSA9IHRoaXMucHJvcHM7XG4gICAgICAgIGxldCBwcmV2RGF0ZSA9IGRhdGVFbnYuc3VidHJhY3QoZGF0ZUVudi5zdGFydE9mKGN1cnJlbnREYXRlLCBjdXJyZW50RGF0ZVByb2ZpbGUuY3VycmVudFJhbmdlVW5pdCksIC8vIGltcG9ydGFudCBmb3Igc3RhcnQtb2YtbW9udGhcbiAgICAgICAgY3VycmVudERhdGVQcm9maWxlLmRhdGVJbmNyZW1lbnQpO1xuICAgICAgICByZXR1cm4gdGhpcy5idWlsZChwcmV2RGF0ZSwgLTEsIGZvcmNlVG9WYWxpZCk7XG4gICAgfVxuICAgIC8vIEJ1aWxkcyBhIHN0cnVjdHVyZSB3aXRoIGluZm8gYWJvdXQgd2hhdCB0aGUgZGF0ZXMvcmFuZ2VzIHdpbGwgYmUgZm9yIHRoZSBcIm5leHRcIiB2aWV3LlxuICAgIGJ1aWxkTmV4dChjdXJyZW50RGF0ZVByb2ZpbGUsIGN1cnJlbnREYXRlLCBmb3JjZVRvVmFsaWQpIHtcbiAgICAgICAgbGV0IHsgZGF0ZUVudiB9ID0gdGhpcy5wcm9wcztcbiAgICAgICAgbGV0IG5leHREYXRlID0gZGF0ZUVudi5hZGQoZGF0ZUVudi5zdGFydE9mKGN1cnJlbnREYXRlLCBjdXJyZW50RGF0ZVByb2ZpbGUuY3VycmVudFJhbmdlVW5pdCksIC8vIGltcG9ydGFudCBmb3Igc3RhcnQtb2YtbW9udGhcbiAgICAgICAgY3VycmVudERhdGVQcm9maWxlLmRhdGVJbmNyZW1lbnQpO1xuICAgICAgICByZXR1cm4gdGhpcy5idWlsZChuZXh0RGF0ZSwgMSwgZm9yY2VUb1ZhbGlkKTtcbiAgICB9XG4gICAgLy8gQnVpbGRzIGEgc3RydWN0dXJlIGhvbGRpbmcgZGF0ZXMvcmFuZ2VzIGZvciByZW5kZXJpbmcgYXJvdW5kIHRoZSBnaXZlbiBkYXRlLlxuICAgIC8vIE9wdGlvbmFsIGRpcmVjdGlvbiBwYXJhbSBpbmRpY2F0ZXMgd2hldGhlciB0aGUgZGF0ZSBpcyBiZWluZyBpbmNyZW1lbnRlZC9kZWNyZW1lbnRlZFxuICAgIC8vIGZyb20gaXRzIHByZXZpb3VzIHZhbHVlLiBkZWNyZW1lbnRlZCA9IC0xLCBpbmNyZW1lbnRlZCA9IDEgKGRlZmF1bHQpLlxuICAgIGJ1aWxkKGN1cnJlbnREYXRlLCBkaXJlY3Rpb24sIGZvcmNlVG9WYWxpZCA9IHRydWUpIHtcbiAgICAgICAgbGV0IHsgcHJvcHMgfSA9IHRoaXM7XG4gICAgICAgIGxldCB2YWxpZFJhbmdlO1xuICAgICAgICBsZXQgY3VycmVudEluZm87XG4gICAgICAgIGxldCBpc1JhbmdlQWxsRGF5O1xuICAgICAgICBsZXQgcmVuZGVyUmFuZ2U7XG4gICAgICAgIGxldCBhY3RpdmVSYW5nZTtcbiAgICAgICAgbGV0IGlzVmFsaWQ7XG4gICAgICAgIHZhbGlkUmFuZ2UgPSB0aGlzLmJ1aWxkVmFsaWRSYW5nZSgpO1xuICAgICAgICB2YWxpZFJhbmdlID0gdGhpcy50cmltSGlkZGVuRGF5cyh2YWxpZFJhbmdlKTtcbiAgICAgICAgaWYgKGZvcmNlVG9WYWxpZCkge1xuICAgICAgICAgICAgY3VycmVudERhdGUgPSBjb25zdHJhaW5NYXJrZXJUb1JhbmdlKGN1cnJlbnREYXRlLCB2YWxpZFJhbmdlKTtcbiAgICAgICAgfVxuICAgICAgICBjdXJyZW50SW5mbyA9IHRoaXMuYnVpbGRDdXJyZW50UmFuZ2VJbmZvKGN1cnJlbnREYXRlLCBkaXJlY3Rpb24pO1xuICAgICAgICBpc1JhbmdlQWxsRGF5ID0gL14oeWVhcnxtb250aHx3ZWVrfGRheSkkLy50ZXN0KGN1cnJlbnRJbmZvLnVuaXQpO1xuICAgICAgICByZW5kZXJSYW5nZSA9IHRoaXMuYnVpbGRSZW5kZXJSYW5nZSh0aGlzLnRyaW1IaWRkZW5EYXlzKGN1cnJlbnRJbmZvLnJhbmdlKSwgY3VycmVudEluZm8udW5pdCwgaXNSYW5nZUFsbERheSk7XG4gICAgICAgIHJlbmRlclJhbmdlID0gdGhpcy50cmltSGlkZGVuRGF5cyhyZW5kZXJSYW5nZSk7XG4gICAgICAgIGFjdGl2ZVJhbmdlID0gcmVuZGVyUmFuZ2U7XG4gICAgICAgIGlmICghcHJvcHMuc2hvd05vbkN1cnJlbnREYXRlcykge1xuICAgICAgICAgICAgYWN0aXZlUmFuZ2UgPSBpbnRlcnNlY3RSYW5nZXMoYWN0aXZlUmFuZ2UsIGN1cnJlbnRJbmZvLnJhbmdlKTtcbiAgICAgICAgfVxuICAgICAgICBhY3RpdmVSYW5nZSA9IHRoaXMuYWRqdXN0QWN0aXZlUmFuZ2UoYWN0aXZlUmFuZ2UpO1xuICAgICAgICBhY3RpdmVSYW5nZSA9IGludGVyc2VjdFJhbmdlcyhhY3RpdmVSYW5nZSwgdmFsaWRSYW5nZSk7IC8vIG1pZ2h0IHJldHVybiBudWxsXG4gICAgICAgIC8vIGl0J3MgaW52YWxpZCBpZiB0aGUgb3JpZ2luYWxseSByZXF1ZXN0ZWQgZGF0ZSBpcyBub3QgY29udGFpbmVkLFxuICAgICAgICAvLyBvciBpZiB0aGUgcmFuZ2UgaXMgY29tcGxldGVseSBvdXRzaWRlIG9mIHRoZSB2YWxpZCByYW5nZS5cbiAgICAgICAgaXNWYWxpZCA9IHJhbmdlc0ludGVyc2VjdChjdXJyZW50SW5mby5yYW5nZSwgdmFsaWRSYW5nZSk7XG4gICAgICAgIC8vIEhBQ0s6IGNvbnN0cmFpbiB0byByZW5kZXItcmFuZ2Ugc28gYGN1cnJlbnREYXRlYCBpcyBtb3JlIHVzZWZ1bCB0byB2aWV3IHJlbmRlcmluZ1xuICAgICAgICBpZiAoIXJhbmdlQ29udGFpbnNNYXJrZXIocmVuZGVyUmFuZ2UsIGN1cnJlbnREYXRlKSkge1xuICAgICAgICAgICAgY3VycmVudERhdGUgPSByZW5kZXJSYW5nZS5zdGFydDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgY3VycmVudERhdGUsXG4gICAgICAgICAgICAvLyBjb25zdHJhaW50IGZvciB3aGVyZSBwcmV2L25leHQgb3BlcmF0aW9ucyBjYW4gZ28gYW5kIHdoZXJlIGV2ZW50cyBjYW4gYmUgZHJhZ2dlZC9yZXNpemVkIHRvLlxuICAgICAgICAgICAgLy8gYW4gb2JqZWN0IHdpdGggb3B0aW9uYWwgc3RhcnQgYW5kIGVuZCBwcm9wZXJ0aWVzLlxuICAgICAgICAgICAgdmFsaWRSYW5nZSxcbiAgICAgICAgICAgIC8vIHJhbmdlIHRoZSB2aWV3IGlzIGZvcm1hbGx5IHJlc3BvbnNpYmxlIGZvci5cbiAgICAgICAgICAgIC8vIGZvciBleGFtcGxlLCBhIG1vbnRoIHZpZXcgbWlnaHQgaGF2ZSAxc3QtMzFzdCwgZXhjbHVkaW5nIHBhZGRlZCBkYXRlc1xuICAgICAgICAgICAgY3VycmVudFJhbmdlOiBjdXJyZW50SW5mby5yYW5nZSxcbiAgICAgICAgICAgIC8vIG5hbWUgb2YgbGFyZ2VzdCB1bml0IGJlaW5nIGRpc3BsYXllZCwgbGlrZSBcIm1vbnRoXCIgb3IgXCJ3ZWVrXCJcbiAgICAgICAgICAgIGN1cnJlbnRSYW5nZVVuaXQ6IGN1cnJlbnRJbmZvLnVuaXQsXG4gICAgICAgICAgICBpc1JhbmdlQWxsRGF5LFxuICAgICAgICAgICAgLy8gZGF0ZXMgdGhhdCBkaXNwbGF5IGV2ZW50cyBhbmQgYWNjZXB0IGRyYWctbi1kcm9wXG4gICAgICAgICAgICAvLyB3aWxsIGJlIGBudWxsYCBpZiBubyBkYXRlcyBhY2NlcHQgZXZlbnRzXG4gICAgICAgICAgICBhY3RpdmVSYW5nZSxcbiAgICAgICAgICAgIC8vIGRhdGUgcmFuZ2Ugd2l0aCBhIHJlbmRlcmVkIHNrZWxldG9uXG4gICAgICAgICAgICAvLyBpbmNsdWRlcyBub3QtYWN0aXZlIGRheXMgdGhhdCBuZWVkIHNvbWUgc29ydCBvZiBET01cbiAgICAgICAgICAgIHJlbmRlclJhbmdlLFxuICAgICAgICAgICAgLy8gRHVyYXRpb24gb2JqZWN0IHRoYXQgZGVub3RlcyB0aGUgZmlyc3QgdmlzaWJsZSB0aW1lIG9mIGFueSBnaXZlbiBkYXlcbiAgICAgICAgICAgIHNsb3RNaW5UaW1lOiBwcm9wcy5zbG90TWluVGltZSxcbiAgICAgICAgICAgIC8vIER1cmF0aW9uIG9iamVjdCB0aGF0IGRlbm90ZXMgdGhlIGV4Y2x1c2l2ZSB2aXNpYmxlIGVuZCB0aW1lIG9mIGFueSBnaXZlbiBkYXlcbiAgICAgICAgICAgIHNsb3RNYXhUaW1lOiBwcm9wcy5zbG90TWF4VGltZSxcbiAgICAgICAgICAgIGlzVmFsaWQsXG4gICAgICAgICAgICAvLyBob3cgZmFyIHRoZSBjdXJyZW50IGRhdGUgd2lsbCBtb3ZlIGZvciBhIHByZXYvbmV4dCBvcGVyYXRpb25cbiAgICAgICAgICAgIGRhdGVJbmNyZW1lbnQ6IHRoaXMuYnVpbGREYXRlSW5jcmVtZW50KGN1cnJlbnRJbmZvLmR1cmF0aW9uKSxcbiAgICAgICAgICAgIC8vIHBhc3MgYSBmYWxsYmFjayAobWlnaHQgYmUgbnVsbCkgXlxuICAgICAgICB9O1xuICAgIH1cbiAgICAvLyBCdWlsZHMgYW4gb2JqZWN0IHdpdGggb3B0aW9uYWwgc3RhcnQvZW5kIHByb3BlcnRpZXMuXG4gICAgLy8gSW5kaWNhdGVzIHRoZSBtaW5pbXVtL21heGltdW0gZGF0ZXMgdG8gZGlzcGxheS5cbiAgICAvLyBub3QgcmVzcG9uc2libGUgZm9yIHRyaW1taW5nIGhpZGRlbiBkYXlzLlxuICAgIGJ1aWxkVmFsaWRSYW5nZSgpIHtcbiAgICAgICAgbGV0IGlucHV0ID0gdGhpcy5wcm9wcy52YWxpZFJhbmdlSW5wdXQ7XG4gICAgICAgIGxldCBzaW1wbGVJbnB1dCA9IHR5cGVvZiBpbnB1dCA9PT0gJ2Z1bmN0aW9uJ1xuICAgICAgICAgICAgPyBpbnB1dC5jYWxsKHRoaXMucHJvcHMuY2FsZW5kYXJBcGksIHRoaXMucHJvcHMuZGF0ZUVudi50b0RhdGUodGhpcy5wcm9wcy5ub3dNYW5hZ2VyLmdldERhdGVNYXJrZXIoKSkpXG4gICAgICAgICAgICA6IGlucHV0O1xuICAgICAgICByZXR1cm4gdGhpcy5yZWZpbmVSYW5nZShzaW1wbGVJbnB1dCkgfHxcbiAgICAgICAgICAgIHsgc3RhcnQ6IG51bGwsIGVuZDogbnVsbCB9OyAvLyBjb21wbGV0ZWx5IG9wZW4tZW5kZWRcbiAgICB9XG4gICAgLy8gQnVpbGRzIGEgc3RydWN0dXJlIHdpdGggaW5mbyBhYm91dCB0aGUgXCJjdXJyZW50XCIgcmFuZ2UsIHRoZSByYW5nZSB0aGF0IGlzXG4gICAgLy8gaGlnaGxpZ2h0ZWQgYXMgYmVpbmcgdGhlIGN1cnJlbnQgbW9udGggZm9yIGV4YW1wbGUuXG4gICAgLy8gU2VlIGJ1aWxkKCkgZm9yIGEgZGVzY3JpcHRpb24gb2YgYGRpcmVjdGlvbmAuXG4gICAgLy8gR3VhcmFudGVlZCB0byBoYXZlIGByYW5nZWAgYW5kIGB1bml0YCBwcm9wZXJ0aWVzLiBgZHVyYXRpb25gIGlzIG9wdGlvbmFsLlxuICAgIGJ1aWxkQ3VycmVudFJhbmdlSW5mbyhkYXRlLCBkaXJlY3Rpb24pIHtcbiAgICAgICAgbGV0IHsgcHJvcHMgfSA9IHRoaXM7XG4gICAgICAgIGxldCBkdXJhdGlvbiA9IG51bGw7XG4gICAgICAgIGxldCB1bml0ID0gbnVsbDtcbiAgICAgICAgbGV0IHJhbmdlID0gbnVsbDtcbiAgICAgICAgbGV0IGRheUNvdW50O1xuICAgICAgICBpZiAocHJvcHMuZHVyYXRpb24pIHtcbiAgICAgICAgICAgIGR1cmF0aW9uID0gcHJvcHMuZHVyYXRpb247XG4gICAgICAgICAgICB1bml0ID0gcHJvcHMuZHVyYXRpb25Vbml0O1xuICAgICAgICAgICAgcmFuZ2UgPSB0aGlzLmJ1aWxkUmFuZ2VGcm9tRHVyYXRpb24oZGF0ZSwgZGlyZWN0aW9uLCBkdXJhdGlvbiwgdW5pdCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoKGRheUNvdW50ID0gdGhpcy5wcm9wcy5kYXlDb3VudCkpIHtcbiAgICAgICAgICAgIHVuaXQgPSAnZGF5JztcbiAgICAgICAgICAgIHJhbmdlID0gdGhpcy5idWlsZFJhbmdlRnJvbURheUNvdW50KGRhdGUsIGRpcmVjdGlvbiwgZGF5Q291bnQpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKChyYW5nZSA9IHRoaXMuYnVpbGRDdXN0b21WaXNpYmxlUmFuZ2UoZGF0ZSkpKSB7XG4gICAgICAgICAgICB1bml0ID0gcHJvcHMuZGF0ZUVudi5ncmVhdGVzdFdob2xlVW5pdChyYW5nZS5zdGFydCwgcmFuZ2UuZW5kKS51bml0O1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZHVyYXRpb24gPSB0aGlzLmdldEZhbGxiYWNrRHVyYXRpb24oKTtcbiAgICAgICAgICAgIHVuaXQgPSBncmVhdGVzdER1cmF0aW9uRGVub21pbmF0b3IoZHVyYXRpb24pLnVuaXQ7XG4gICAgICAgICAgICByYW5nZSA9IHRoaXMuYnVpbGRSYW5nZUZyb21EdXJhdGlvbihkYXRlLCBkaXJlY3Rpb24sIGR1cmF0aW9uLCB1bml0KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4geyBkdXJhdGlvbiwgdW5pdCwgcmFuZ2UgfTtcbiAgICB9XG4gICAgZ2V0RmFsbGJhY2tEdXJhdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIGNyZWF0ZUR1cmF0aW9uKHsgZGF5OiAxIH0pO1xuICAgIH1cbiAgICAvLyBSZXR1cm5zIGEgbmV3IGFjdGl2ZVJhbmdlIHRvIGhhdmUgdGltZSB2YWx1ZXMgKHVuLWFtYmlndWF0ZSlcbiAgICAvLyBzbG90TWluVGltZSBvciBzbG90TWF4VGltZSBjYXVzZXMgdGhlIHJhbmdlIHRvIGV4cGFuZC5cbiAgICBhZGp1c3RBY3RpdmVSYW5nZShyYW5nZSkge1xuICAgICAgICBsZXQgeyBkYXRlRW52LCB1c2VzTWluTWF4VGltZSwgc2xvdE1pblRpbWUsIHNsb3RNYXhUaW1lIH0gPSB0aGlzLnByb3BzO1xuICAgICAgICBsZXQgeyBzdGFydCwgZW5kIH0gPSByYW5nZTtcbiAgICAgICAgaWYgKHVzZXNNaW5NYXhUaW1lKSB7XG4gICAgICAgICAgICAvLyBleHBhbmQgYWN0aXZlIHJhbmdlIGlmIHNsb3RNaW5UaW1lIGlzIG5lZ2F0aXZlICh3aHkgbm90IHdoZW4gcG9zaXRpdmU/KVxuICAgICAgICAgICAgaWYgKGFzUm91Z2hEYXlzKHNsb3RNaW5UaW1lKSA8IDApIHtcbiAgICAgICAgICAgICAgICBzdGFydCA9IHN0YXJ0T2ZEYXkoc3RhcnQpOyAvLyBuZWNlc3Nhcnk/XG4gICAgICAgICAgICAgICAgc3RhcnQgPSBkYXRlRW52LmFkZChzdGFydCwgc2xvdE1pblRpbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gZXhwYW5kIGFjdGl2ZSByYW5nZSBpZiBzbG90TWF4VGltZSBpcyBiZXlvbmQgb25lIGRheSAod2h5IG5vdCB3aGVuIG5lZ2F0aXZlPylcbiAgICAgICAgICAgIGlmIChhc1JvdWdoRGF5cyhzbG90TWF4VGltZSkgPiAxKSB7XG4gICAgICAgICAgICAgICAgZW5kID0gc3RhcnRPZkRheShlbmQpOyAvLyBuZWNlc3Nhcnk/XG4gICAgICAgICAgICAgICAgZW5kID0gYWRkRGF5cyhlbmQsIC0xKTtcbiAgICAgICAgICAgICAgICBlbmQgPSBkYXRlRW52LmFkZChlbmQsIHNsb3RNYXhUaW1lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4geyBzdGFydCwgZW5kIH07XG4gICAgfVxuICAgIC8vIEJ1aWxkcyB0aGUgXCJjdXJyZW50XCIgcmFuZ2Ugd2hlbiBpdCBpcyBzcGVjaWZpZWQgYXMgYW4gZXhwbGljaXQgZHVyYXRpb24uXG4gICAgLy8gYHVuaXRgIGlzIHRoZSBhbHJlYWR5LWNvbXB1dGVkIGdyZWF0ZXN0RHVyYXRpb25EZW5vbWluYXRvciB1bml0IG9mIGR1cmF0aW9uLlxuICAgIGJ1aWxkUmFuZ2VGcm9tRHVyYXRpb24oZGF0ZSwgZGlyZWN0aW9uLCBkdXJhdGlvbiwgdW5pdCkge1xuICAgICAgICBsZXQgeyBkYXRlRW52LCBkYXRlQWxpZ25tZW50IH0gPSB0aGlzLnByb3BzO1xuICAgICAgICBsZXQgc3RhcnQ7XG4gICAgICAgIGxldCBlbmQ7XG4gICAgICAgIGxldCByZXM7XG4gICAgICAgIC8vIGNvbXB1dGUgd2hhdCB0aGUgYWxpZ25tZW50IHNob3VsZCBiZVxuICAgICAgICBpZiAoIWRhdGVBbGlnbm1lbnQpIHtcbiAgICAgICAgICAgIGxldCB7IGRhdGVJbmNyZW1lbnQgfSA9IHRoaXMucHJvcHM7XG4gICAgICAgICAgICBpZiAoZGF0ZUluY3JlbWVudCkge1xuICAgICAgICAgICAgICAgIC8vIHVzZSB0aGUgc21hbGxlciBvZiB0aGUgdHdvIHVuaXRzXG4gICAgICAgICAgICAgICAgaWYgKGFzUm91Z2hNcyhkYXRlSW5jcmVtZW50KSA8IGFzUm91Z2hNcyhkdXJhdGlvbikpIHtcbiAgICAgICAgICAgICAgICAgICAgZGF0ZUFsaWdubWVudCA9IGdyZWF0ZXN0RHVyYXRpb25EZW5vbWluYXRvcihkYXRlSW5jcmVtZW50KS51bml0O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZGF0ZUFsaWdubWVudCA9IHVuaXQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgZGF0ZUFsaWdubWVudCA9IHVuaXQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gaWYgdGhlIHZpZXcgZGlzcGxheXMgYSBzaW5nbGUgZGF5IG9yIHNtYWxsZXJcbiAgICAgICAgaWYgKGFzUm91Z2hEYXlzKGR1cmF0aW9uKSA8PSAxKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5pc0hpZGRlbkRheShzdGFydCkpIHtcbiAgICAgICAgICAgICAgICBzdGFydCA9IHRoaXMuc2tpcEhpZGRlbkRheXMoc3RhcnQsIGRpcmVjdGlvbik7XG4gICAgICAgICAgICAgICAgc3RhcnQgPSBzdGFydE9mRGF5KHN0YXJ0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBmdW5jdGlvbiBjb21wdXRlUmVzKCkge1xuICAgICAgICAgICAgc3RhcnQgPSBkYXRlRW52LnN0YXJ0T2YoZGF0ZSwgZGF0ZUFsaWdubWVudCk7XG4gICAgICAgICAgICBlbmQgPSBkYXRlRW52LmFkZChzdGFydCwgZHVyYXRpb24pO1xuICAgICAgICAgICAgcmVzID0geyBzdGFydCwgZW5kIH07XG4gICAgICAgIH1cbiAgICAgICAgY29tcHV0ZVJlcygpO1xuICAgICAgICAvLyBpZiByYW5nZSBpcyBjb21wbGV0ZWx5IGVudmVsb3BlZCBieSBoaWRkZW4gZGF5cywgZ28gcGFzdCB0aGUgaGlkZGVuIGRheXNcbiAgICAgICAgaWYgKCF0aGlzLnRyaW1IaWRkZW5EYXlzKHJlcykpIHtcbiAgICAgICAgICAgIGRhdGUgPSB0aGlzLnNraXBIaWRkZW5EYXlzKGRhdGUsIGRpcmVjdGlvbik7XG4gICAgICAgICAgICBjb21wdXRlUmVzKCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG4gICAgLy8gQnVpbGRzIHRoZSBcImN1cnJlbnRcIiByYW5nZSB3aGVuIGEgZGF5Q291bnQgaXMgc3BlY2lmaWVkLlxuICAgIGJ1aWxkUmFuZ2VGcm9tRGF5Q291bnQoZGF0ZSwgZGlyZWN0aW9uLCBkYXlDb3VudCkge1xuICAgICAgICBsZXQgeyBkYXRlRW52LCBkYXRlQWxpZ25tZW50IH0gPSB0aGlzLnByb3BzO1xuICAgICAgICBsZXQgcnVubmluZ0NvdW50ID0gMDtcbiAgICAgICAgbGV0IHN0YXJ0ID0gZGF0ZTtcbiAgICAgICAgbGV0IGVuZDtcbiAgICAgICAgaWYgKGRhdGVBbGlnbm1lbnQpIHtcbiAgICAgICAgICAgIHN0YXJ0ID0gZGF0ZUVudi5zdGFydE9mKHN0YXJ0LCBkYXRlQWxpZ25tZW50KTtcbiAgICAgICAgfVxuICAgICAgICBzdGFydCA9IHN0YXJ0T2ZEYXkoc3RhcnQpO1xuICAgICAgICBzdGFydCA9IHRoaXMuc2tpcEhpZGRlbkRheXMoc3RhcnQsIGRpcmVjdGlvbik7XG4gICAgICAgIGVuZCA9IHN0YXJ0O1xuICAgICAgICBkbyB7XG4gICAgICAgICAgICBlbmQgPSBhZGREYXlzKGVuZCwgMSk7XG4gICAgICAgICAgICBpZiAoIXRoaXMuaXNIaWRkZW5EYXkoZW5kKSkge1xuICAgICAgICAgICAgICAgIHJ1bm5pbmdDb3VudCArPSAxO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IHdoaWxlIChydW5uaW5nQ291bnQgPCBkYXlDb3VudCk7XG4gICAgICAgIHJldHVybiB7IHN0YXJ0LCBlbmQgfTtcbiAgICB9XG4gICAgLy8gQnVpbGRzIGEgbm9ybWFsaXplZCByYW5nZSBvYmplY3QgZm9yIHRoZSBcInZpc2libGVcIiByYW5nZSxcbiAgICAvLyB3aGljaCBpcyBhIHdheSB0byBkZWZpbmUgdGhlIGN1cnJlbnRSYW5nZSBhbmQgYWN0aXZlUmFuZ2UgYXQgdGhlIHNhbWUgdGltZS5cbiAgICBidWlsZEN1c3RvbVZpc2libGVSYW5nZShkYXRlKSB7XG4gICAgICAgIGxldCB7IHByb3BzIH0gPSB0aGlzO1xuICAgICAgICBsZXQgaW5wdXQgPSBwcm9wcy52aXNpYmxlUmFuZ2VJbnB1dDtcbiAgICAgICAgbGV0IHNpbXBsZUlucHV0ID0gdHlwZW9mIGlucHV0ID09PSAnZnVuY3Rpb24nXG4gICAgICAgICAgICA/IGlucHV0LmNhbGwocHJvcHMuY2FsZW5kYXJBcGksIHByb3BzLmRhdGVFbnYudG9EYXRlKGRhdGUpKVxuICAgICAgICAgICAgOiBpbnB1dDtcbiAgICAgICAgbGV0IHJhbmdlID0gdGhpcy5yZWZpbmVSYW5nZShzaW1wbGVJbnB1dCk7XG4gICAgICAgIGlmIChyYW5nZSAmJiAocmFuZ2Uuc3RhcnQgPT0gbnVsbCB8fCByYW5nZS5lbmQgPT0gbnVsbCkpIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByYW5nZTtcbiAgICB9XG4gICAgLy8gQ29tcHV0ZXMgdGhlIHJhbmdlIHRoYXQgd2lsbCByZXByZXNlbnQgdGhlIGVsZW1lbnQvY2VsbHMgZm9yICpyZW5kZXJpbmcqLFxuICAgIC8vIGJ1dCB3aGljaCBtYXkgaGF2ZSB2b2lkZWQgZGF5cy90aW1lcy5cbiAgICAvLyBub3QgcmVzcG9uc2libGUgZm9yIHRyaW1taW5nIGhpZGRlbiBkYXlzLlxuICAgIGJ1aWxkUmVuZGVyUmFuZ2UoY3VycmVudFJhbmdlLCBjdXJyZW50UmFuZ2VVbml0LCBpc1JhbmdlQWxsRGF5KSB7XG4gICAgICAgIHJldHVybiBjdXJyZW50UmFuZ2U7XG4gICAgfVxuICAgIC8vIENvbXB1dGUgdGhlIGR1cmF0aW9uIHZhbHVlIHRoYXQgc2hvdWxkIGJlIGFkZGVkL3N1YnN0cmFjdGVkIHRvIHRoZSBjdXJyZW50IGRhdGVcbiAgICAvLyB3aGVuIGEgcHJldi9uZXh0IG9wZXJhdGlvbiBoYXBwZW5zLlxuICAgIGJ1aWxkRGF0ZUluY3JlbWVudChmYWxsYmFjaykge1xuICAgICAgICBsZXQgeyBkYXRlSW5jcmVtZW50IH0gPSB0aGlzLnByb3BzO1xuICAgICAgICBsZXQgY3VzdG9tQWxpZ25tZW50O1xuICAgICAgICBpZiAoZGF0ZUluY3JlbWVudCkge1xuICAgICAgICAgICAgcmV0dXJuIGRhdGVJbmNyZW1lbnQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKChjdXN0b21BbGlnbm1lbnQgPSB0aGlzLnByb3BzLmRhdGVBbGlnbm1lbnQpKSB7XG4gICAgICAgICAgICByZXR1cm4gY3JlYXRlRHVyYXRpb24oMSwgY3VzdG9tQWxpZ25tZW50KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZmFsbGJhY2spIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxsYmFjaztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY3JlYXRlRHVyYXRpb24oeyBkYXlzOiAxIH0pO1xuICAgIH1cbiAgICByZWZpbmVSYW5nZShyYW5nZUlucHV0KSB7XG4gICAgICAgIGlmIChyYW5nZUlucHV0KSB7XG4gICAgICAgICAgICBsZXQgcmFuZ2UgPSBwYXJzZVJhbmdlKHJhbmdlSW5wdXQsIHRoaXMucHJvcHMuZGF0ZUVudik7XG4gICAgICAgICAgICBpZiAocmFuZ2UpIHtcbiAgICAgICAgICAgICAgICByYW5nZSA9IGNvbXB1dGVWaXNpYmxlRGF5UmFuZ2UocmFuZ2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHJhbmdlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICAvKiBIaWRkZW4gRGF5c1xuICAgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG4gICAgLy8gSW5pdGlhbGl6ZXMgaW50ZXJuYWwgdmFyaWFibGVzIHJlbGF0ZWQgdG8gY2FsY3VsYXRpbmcgaGlkZGVuIGRheXMtb2Ytd2Vla1xuICAgIGluaXRIaWRkZW5EYXlzKCkge1xuICAgICAgICBsZXQgaGlkZGVuRGF5cyA9IHRoaXMucHJvcHMuaGlkZGVuRGF5cyB8fCBbXTsgLy8gYXJyYXkgb2YgZGF5LW9mLXdlZWsgaW5kaWNlcyB0aGF0IGFyZSBoaWRkZW5cbiAgICAgICAgbGV0IGlzSGlkZGVuRGF5SGFzaCA9IFtdOyAvLyBpcyB0aGUgZGF5LW9mLXdlZWsgaGlkZGVuPyAoaGFzaCB3aXRoIGRheS1vZi13ZWVrLWluZGV4IC0+IGJvb2wpXG4gICAgICAgIGxldCBkYXlDbnQgPSAwO1xuICAgICAgICBsZXQgaTtcbiAgICAgICAgaWYgKHRoaXMucHJvcHMud2Vla2VuZHMgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICBoaWRkZW5EYXlzLnB1c2goMCwgNik7IC8vIDA9c3VuZGF5LCA2PXNhdHVyZGF5XG4gICAgICAgIH1cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IDc7IGkgKz0gMSkge1xuICAgICAgICAgICAgaWYgKCEoaXNIaWRkZW5EYXlIYXNoW2ldID0gaGlkZGVuRGF5cy5pbmRleE9mKGkpICE9PSAtMSkpIHtcbiAgICAgICAgICAgICAgICBkYXlDbnQgKz0gMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoIWRheUNudCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIGhpZGRlbkRheXMnKTsgLy8gYWxsIGRheXMgd2VyZSBoaWRkZW4/IGJhZC5cbiAgICAgICAgfVxuICAgICAgICB0aGlzLmlzSGlkZGVuRGF5SGFzaCA9IGlzSGlkZGVuRGF5SGFzaDtcbiAgICB9XG4gICAgLy8gUmVtb3ZlIGRheXMgZnJvbSB0aGUgYmVnaW5uaW5nIGFuZCBlbmQgb2YgdGhlIHJhbmdlIHRoYXQgYXJlIGNvbXB1dGVkIGFzIGhpZGRlbi5cbiAgICAvLyBJZiB0aGUgd2hvbGUgcmFuZ2UgaXMgdHJpbW1lZCBvZmYsIHJldHVybnMgbnVsbFxuICAgIHRyaW1IaWRkZW5EYXlzKHJhbmdlKSB7XG4gICAgICAgIGxldCB7IHN0YXJ0LCBlbmQgfSA9IHJhbmdlO1xuICAgICAgICBpZiAoc3RhcnQpIHtcbiAgICAgICAgICAgIHN0YXJ0ID0gdGhpcy5za2lwSGlkZGVuRGF5cyhzdGFydCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGVuZCkge1xuICAgICAgICAgICAgZW5kID0gdGhpcy5za2lwSGlkZGVuRGF5cyhlbmQsIC0xLCB0cnVlKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoc3RhcnQgPT0gbnVsbCB8fCBlbmQgPT0gbnVsbCB8fCBzdGFydCA8IGVuZCkge1xuICAgICAgICAgICAgcmV0dXJuIHsgc3RhcnQsIGVuZCB9O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICAvLyBJcyB0aGUgY3VycmVudCBkYXkgaGlkZGVuP1xuICAgIC8vIGBkYXlgIGlzIGEgZGF5LW9mLXdlZWsgaW5kZXggKDAtNiksIG9yIGEgRGF0ZSAodXNlZCBmb3IgVVRDKVxuICAgIGlzSGlkZGVuRGF5KGRheSkge1xuICAgICAgICBpZiAoZGF5IGluc3RhbmNlb2YgRGF0ZSkge1xuICAgICAgICAgICAgZGF5ID0gZGF5LmdldFVUQ0RheSgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLmlzSGlkZGVuRGF5SGFzaFtkYXldO1xuICAgIH1cbiAgICAvLyBJbmNyZW1lbnRpbmcgdGhlIGN1cnJlbnQgZGF5IHVudGlsIGl0IGlzIG5vIGxvbmdlciBhIGhpZGRlbiBkYXksIHJldHVybmluZyBhIGNvcHkuXG4gICAgLy8gRE9FUyBOT1QgQ09OU0lERVIgdmFsaWRSYW5nZSFcbiAgICAvLyBJZiB0aGUgaW5pdGlhbCB2YWx1ZSBvZiBgZGF0ZWAgaXMgbm90IGEgaGlkZGVuIGRheSwgZG9uJ3QgZG8gYW55dGhpbmcuXG4gICAgLy8gUGFzcyBgaXNFeGNsdXNpdmVgIGFzIGB0cnVlYCBpZiB5b3UgYXJlIGRlYWxpbmcgd2l0aCBhbiBlbmQgZGF0ZS5cbiAgICAvLyBgaW5jYCBkZWZhdWx0cyB0byBgMWAgKGluY3JlbWVudCBvbmUgZGF5IGZvcndhcmQgZWFjaCB0aW1lKVxuICAgIHNraXBIaWRkZW5EYXlzKGRhdGUsIGluYyA9IDEsIGlzRXhjbHVzaXZlID0gZmFsc2UpIHtcbiAgICAgICAgd2hpbGUgKHRoaXMuaXNIaWRkZW5EYXlIYXNoWyhkYXRlLmdldFVUQ0RheSgpICsgKGlzRXhjbHVzaXZlID8gaW5jIDogMCkgKyA3KSAlIDddKSB7XG4gICAgICAgICAgICBkYXRlID0gYWRkRGF5cyhkYXRlLCBpbmMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBkYXRlO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gY3JlYXRlRXZlbnRJbnN0YW5jZShkZWZJZCwgcmFuZ2UsIGZvcmNlZFN0YXJ0VHpvLCBmb3JjZWRFbmRUem8pIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBpbnN0YW5jZUlkOiBndWlkKCksXG4gICAgICAgIGRlZklkLFxuICAgICAgICByYW5nZSxcbiAgICAgICAgZm9yY2VkU3RhcnRUem86IGZvcmNlZFN0YXJ0VHpvID09IG51bGwgPyBudWxsIDogZm9yY2VkU3RhcnRUem8sXG4gICAgICAgIGZvcmNlZEVuZFR6bzogZm9yY2VkRW5kVHpvID09IG51bGwgPyBudWxsIDogZm9yY2VkRW5kVHpvLFxuICAgIH07XG59XG5cbmZ1bmN0aW9uIHBhcnNlUmVjdXJyaW5nKHJlZmluZWQsIGRlZmF1bHRBbGxEYXksIGRhdGVFbnYsIHJlY3VycmluZ1R5cGVzKSB7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCByZWN1cnJpbmdUeXBlcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICBsZXQgcGFyc2VkID0gcmVjdXJyaW5nVHlwZXNbaV0ucGFyc2UocmVmaW5lZCwgZGF0ZUVudik7XG4gICAgICAgIGlmIChwYXJzZWQpIHtcbiAgICAgICAgICAgIGxldCB7IGFsbERheSB9ID0gcmVmaW5lZDtcbiAgICAgICAgICAgIGlmIChhbGxEYXkgPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIGFsbERheSA9IGRlZmF1bHRBbGxEYXk7XG4gICAgICAgICAgICAgICAgaWYgKGFsbERheSA9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgIGFsbERheSA9IHBhcnNlZC5hbGxEYXlHdWVzcztcbiAgICAgICAgICAgICAgICAgICAgaWYgKGFsbERheSA9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhbGxEYXkgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgYWxsRGF5LFxuICAgICAgICAgICAgICAgIGR1cmF0aW9uOiBwYXJzZWQuZHVyYXRpb24sXG4gICAgICAgICAgICAgICAgdHlwZURhdGE6IHBhcnNlZC50eXBlRGF0YSxcbiAgICAgICAgICAgICAgICB0eXBlSWQ6IGksXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufVxuZnVuY3Rpb24gZXhwYW5kUmVjdXJyaW5nKGV2ZW50U3RvcmUsIGZyYW1pbmdSYW5nZSwgY29udGV4dCkge1xuICAgIGxldCB7IGRhdGVFbnYsIHBsdWdpbkhvb2tzLCBvcHRpb25zIH0gPSBjb250ZXh0O1xuICAgIGxldCB7IGRlZnMsIGluc3RhbmNlcyB9ID0gZXZlbnRTdG9yZTtcbiAgICAvLyByZW1vdmUgZXhpc3RpbmcgcmVjdXJyaW5nIGluc3RhbmNlc1xuICAgIC8vIFRPRE86IGJhZC4gYWx3YXlzIGV4cGFuZCBldmVudHMgYXMgYSBzZWNvbmQgc3RlcFxuICAgIGluc3RhbmNlcyA9IGZpbHRlckhhc2goaW5zdGFuY2VzLCAoaW5zdGFuY2UpID0+ICFkZWZzW2luc3RhbmNlLmRlZklkXS5yZWN1cnJpbmdEZWYpO1xuICAgIGZvciAobGV0IGRlZklkIGluIGRlZnMpIHtcbiAgICAgICAgbGV0IGRlZiA9IGRlZnNbZGVmSWRdO1xuICAgICAgICBpZiAoZGVmLnJlY3VycmluZ0RlZikge1xuICAgICAgICAgICAgbGV0IHsgZHVyYXRpb24gfSA9IGRlZi5yZWN1cnJpbmdEZWY7XG4gICAgICAgICAgICBpZiAoIWR1cmF0aW9uKSB7XG4gICAgICAgICAgICAgICAgZHVyYXRpb24gPSBkZWYuYWxsRGF5ID9cbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5kZWZhdWx0QWxsRGF5RXZlbnREdXJhdGlvbiA6XG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuZGVmYXVsdFRpbWVkRXZlbnREdXJhdGlvbjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCBzdGFydHMgPSBleHBhbmRSZWN1cnJpbmdSYW5nZXMoZGVmLCBkdXJhdGlvbiwgZnJhbWluZ1JhbmdlLCBkYXRlRW52LCBwbHVnaW5Ib29rcy5yZWN1cnJpbmdUeXBlcyk7XG4gICAgICAgICAgICBmb3IgKGxldCBzdGFydCBvZiBzdGFydHMpIHtcbiAgICAgICAgICAgICAgICBsZXQgaW5zdGFuY2UgPSBjcmVhdGVFdmVudEluc3RhbmNlKGRlZklkLCB7XG4gICAgICAgICAgICAgICAgICAgIHN0YXJ0LFxuICAgICAgICAgICAgICAgICAgICBlbmQ6IGRhdGVFbnYuYWRkKHN0YXJ0LCBkdXJhdGlvbiksXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgaW5zdGFuY2VzW2luc3RhbmNlLmluc3RhbmNlSWRdID0gaW5zdGFuY2U7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgZGVmcywgaW5zdGFuY2VzIH07XG59XG4vKlxuRXZlbnQgTVVTVCBoYXZlIGEgcmVjdXJyaW5nRGVmXG4qL1xuZnVuY3Rpb24gZXhwYW5kUmVjdXJyaW5nUmFuZ2VzKGV2ZW50RGVmLCBkdXJhdGlvbiwgZnJhbWluZ1JhbmdlLCBkYXRlRW52LCByZWN1cnJpbmdUeXBlcykge1xuICAgIGxldCB0eXBlRGVmID0gcmVjdXJyaW5nVHlwZXNbZXZlbnREZWYucmVjdXJyaW5nRGVmLnR5cGVJZF07XG4gICAgbGV0IG1hcmtlcnMgPSB0eXBlRGVmLmV4cGFuZChldmVudERlZi5yZWN1cnJpbmdEZWYudHlwZURhdGEsIHtcbiAgICAgICAgc3RhcnQ6IGRhdGVFbnYuc3VidHJhY3QoZnJhbWluZ1JhbmdlLnN0YXJ0LCBkdXJhdGlvbiksXG4gICAgICAgIGVuZDogZnJhbWluZ1JhbmdlLmVuZCxcbiAgICB9LCBkYXRlRW52KTtcbiAgICAvLyB0aGUgcmVjdXJyZW5jZSBwbHVnaW5zIGRvbid0IGd1YXJhbnRlZSB0aGF0IGFsbC1kYXkgZXZlbnRzIGFyZSBzdGFydC1vZi1kYXksIHNvIHdlIGhhdmUgdG9cbiAgICBpZiAoZXZlbnREZWYuYWxsRGF5KSB7XG4gICAgICAgIG1hcmtlcnMgPSBtYXJrZXJzLm1hcChzdGFydE9mRGF5KTtcbiAgICB9XG4gICAgcmV0dXJuIG1hcmtlcnM7XG59XG5cbmNvbnN0IEVWRU5UX05PTl9EQVRFX1JFRklORVJTID0ge1xuICAgIGlkOiBTdHJpbmcsXG4gICAgZ3JvdXBJZDogU3RyaW5nLFxuICAgIHRpdGxlOiBTdHJpbmcsXG4gICAgdXJsOiBTdHJpbmcsXG4gICAgaW50ZXJhY3RpdmU6IEJvb2xlYW4sXG59O1xuY29uc3QgRVZFTlRfREFURV9SRUZJTkVSUyA9IHtcbiAgICBzdGFydDogaWRlbnRpdHksXG4gICAgZW5kOiBpZGVudGl0eSxcbiAgICBkYXRlOiBpZGVudGl0eSxcbiAgICBhbGxEYXk6IEJvb2xlYW4sXG59O1xuY29uc3QgRVZFTlRfUkVGSU5FUlMgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgRVZFTlRfTk9OX0RBVEVfUkVGSU5FUlMpLCBFVkVOVF9EQVRFX1JFRklORVJTKSwgeyBleHRlbmRlZFByb3BzOiBpZGVudGl0eSB9KTtcbmZ1bmN0aW9uIHBhcnNlRXZlbnQocmF3LCBldmVudFNvdXJjZSwgY29udGV4dCwgYWxsb3dPcGVuUmFuZ2UsIHJlZmluZXJzID0gYnVpbGRFdmVudFJlZmluZXJzKGNvbnRleHQpLCBkZWZJZE1hcCwgaW5zdGFuY2VJZE1hcCkge1xuICAgIGxldCB7IHJlZmluZWQsIGV4dHJhIH0gPSByZWZpbmVFdmVudERlZihyYXcsIGNvbnRleHQsIHJlZmluZXJzKTtcbiAgICBsZXQgZGVmYXVsdEFsbERheSA9IGNvbXB1dGVJc0RlZmF1bHRBbGxEYXkoZXZlbnRTb3VyY2UsIGNvbnRleHQpO1xuICAgIGxldCByZWN1cnJpbmdSZXMgPSBwYXJzZVJlY3VycmluZyhyZWZpbmVkLCBkZWZhdWx0QWxsRGF5LCBjb250ZXh0LmRhdGVFbnYsIGNvbnRleHQucGx1Z2luSG9va3MucmVjdXJyaW5nVHlwZXMpO1xuICAgIGlmIChyZWN1cnJpbmdSZXMpIHtcbiAgICAgICAgbGV0IGRlZiA9IHBhcnNlRXZlbnREZWYocmVmaW5lZCwgZXh0cmEsIGV2ZW50U291cmNlID8gZXZlbnRTb3VyY2Uuc291cmNlSWQgOiAnJywgcmVjdXJyaW5nUmVzLmFsbERheSwgQm9vbGVhbihyZWN1cnJpbmdSZXMuZHVyYXRpb24pLCBjb250ZXh0LCBkZWZJZE1hcCk7XG4gICAgICAgIGRlZi5yZWN1cnJpbmdEZWYgPSB7XG4gICAgICAgICAgICB0eXBlSWQ6IHJlY3VycmluZ1Jlcy50eXBlSWQsXG4gICAgICAgICAgICB0eXBlRGF0YTogcmVjdXJyaW5nUmVzLnR5cGVEYXRhLFxuICAgICAgICAgICAgZHVyYXRpb246IHJlY3VycmluZ1Jlcy5kdXJhdGlvbixcbiAgICAgICAgfTtcbiAgICAgICAgcmV0dXJuIHsgZGVmLCBpbnN0YW5jZTogbnVsbCB9O1xuICAgIH1cbiAgICBsZXQgc2luZ2xlUmVzID0gcGFyc2VTaW5nbGUocmVmaW5lZCwgZGVmYXVsdEFsbERheSwgY29udGV4dCwgYWxsb3dPcGVuUmFuZ2UpO1xuICAgIGlmIChzaW5nbGVSZXMpIHtcbiAgICAgICAgbGV0IGRlZiA9IHBhcnNlRXZlbnREZWYocmVmaW5lZCwgZXh0cmEsIGV2ZW50U291cmNlID8gZXZlbnRTb3VyY2Uuc291cmNlSWQgOiAnJywgc2luZ2xlUmVzLmFsbERheSwgc2luZ2xlUmVzLmhhc0VuZCwgY29udGV4dCwgZGVmSWRNYXApO1xuICAgICAgICBsZXQgaW5zdGFuY2UgPSBjcmVhdGVFdmVudEluc3RhbmNlKGRlZi5kZWZJZCwgc2luZ2xlUmVzLnJhbmdlLCBzaW5nbGVSZXMuZm9yY2VkU3RhcnRUem8sIHNpbmdsZVJlcy5mb3JjZWRFbmRUem8pO1xuICAgICAgICBpZiAoaW5zdGFuY2VJZE1hcCAmJiBkZWYucHVibGljSWQgJiYgaW5zdGFuY2VJZE1hcFtkZWYucHVibGljSWRdKSB7XG4gICAgICAgICAgICBpbnN0YW5jZS5pbnN0YW5jZUlkID0gaW5zdGFuY2VJZE1hcFtkZWYucHVibGljSWRdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IGRlZiwgaW5zdGFuY2UgfTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG59XG5mdW5jdGlvbiByZWZpbmVFdmVudERlZihyYXcsIGNvbnRleHQsIHJlZmluZXJzID0gYnVpbGRFdmVudFJlZmluZXJzKGNvbnRleHQpKSB7XG4gICAgcmV0dXJuIHJlZmluZVByb3BzKHJhdywgcmVmaW5lcnMpO1xufVxuZnVuY3Rpb24gYnVpbGRFdmVudFJlZmluZXJzKGNvbnRleHQpIHtcbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIEVWRU5UX1VJX1JFRklORVJTKSwgRVZFTlRfUkVGSU5FUlMpLCBjb250ZXh0LnBsdWdpbkhvb2tzLmV2ZW50UmVmaW5lcnMpO1xufVxuLypcbldpbGwgTk9UIHBvcHVsYXRlIGV4dGVuZGVkUHJvcHMgd2l0aCB0aGUgbGVmdG92ZXIgcHJvcGVydGllcy5cbldpbGwgTk9UIHBvcHVsYXRlIGRhdGUtcmVsYXRlZCBwcm9wcy5cbiovXG5mdW5jdGlvbiBwYXJzZUV2ZW50RGVmKHJlZmluZWQsIGV4dHJhLCBzb3VyY2VJZCwgYWxsRGF5LCBoYXNFbmQsIGNvbnRleHQsIGRlZklkTWFwKSB7XG4gICAgbGV0IGRlZiA9IHtcbiAgICAgICAgdGl0bGU6IHJlZmluZWQudGl0bGUgfHwgJycsXG4gICAgICAgIGdyb3VwSWQ6IHJlZmluZWQuZ3JvdXBJZCB8fCAnJyxcbiAgICAgICAgcHVibGljSWQ6IHJlZmluZWQuaWQgfHwgJycsXG4gICAgICAgIHVybDogcmVmaW5lZC51cmwgfHwgJycsXG4gICAgICAgIHJlY3VycmluZ0RlZjogbnVsbCxcbiAgICAgICAgZGVmSWQ6ICgoZGVmSWRNYXAgJiYgcmVmaW5lZC5pZCkgPyBkZWZJZE1hcFtyZWZpbmVkLmlkXSA6ICcnKSB8fCBndWlkKCksXG4gICAgICAgIHNvdXJjZUlkLFxuICAgICAgICBhbGxEYXksXG4gICAgICAgIGhhc0VuZCxcbiAgICAgICAgaW50ZXJhY3RpdmU6IHJlZmluZWQuaW50ZXJhY3RpdmUsXG4gICAgICAgIHVpOiBjcmVhdGVFdmVudFVpKHJlZmluZWQsIGNvbnRleHQpLFxuICAgICAgICBleHRlbmRlZFByb3BzOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIChyZWZpbmVkLmV4dGVuZGVkUHJvcHMgfHwge30pKSwgZXh0cmEpLFxuICAgIH07XG4gICAgZm9yIChsZXQgbWVtYmVyQWRkZXIgb2YgY29udGV4dC5wbHVnaW5Ib29rcy5ldmVudERlZk1lbWJlckFkZGVycykge1xuICAgICAgICBPYmplY3QuYXNzaWduKGRlZiwgbWVtYmVyQWRkZXIocmVmaW5lZCkpO1xuICAgIH1cbiAgICAvLyBoZWxwIG91dCBFdmVudEltcGwgZnJvbSBoYXZpbmcgdXNlciBtb2RpZnkgcHJvcHNcbiAgICBPYmplY3QuZnJlZXplKGRlZi51aS5jbGFzc05hbWVzKTtcbiAgICBPYmplY3QuZnJlZXplKGRlZi5leHRlbmRlZFByb3BzKTtcbiAgICByZXR1cm4gZGVmO1xufVxuZnVuY3Rpb24gcGFyc2VTaW5nbGUocmVmaW5lZCwgZGVmYXVsdEFsbERheSwgY29udGV4dCwgYWxsb3dPcGVuUmFuZ2UpIHtcbiAgICBsZXQgeyBhbGxEYXkgfSA9IHJlZmluZWQ7XG4gICAgbGV0IHN0YXJ0TWV0YTtcbiAgICBsZXQgc3RhcnRNYXJrZXIgPSBudWxsO1xuICAgIGxldCBoYXNFbmQgPSBmYWxzZTtcbiAgICBsZXQgZW5kTWV0YTtcbiAgICBsZXQgZW5kTWFya2VyID0gbnVsbDtcbiAgICBsZXQgc3RhcnRJbnB1dCA9IHJlZmluZWQuc3RhcnQgIT0gbnVsbCA/IHJlZmluZWQuc3RhcnQgOiByZWZpbmVkLmRhdGU7XG4gICAgc3RhcnRNZXRhID0gY29udGV4dC5kYXRlRW52LmNyZWF0ZU1hcmtlck1ldGEoc3RhcnRJbnB1dCk7XG4gICAgaWYgKHN0YXJ0TWV0YSkge1xuICAgICAgICBzdGFydE1hcmtlciA9IHN0YXJ0TWV0YS5tYXJrZXI7XG4gICAgfVxuICAgIGVsc2UgaWYgKCFhbGxvd09wZW5SYW5nZSkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgaWYgKHJlZmluZWQuZW5kICE9IG51bGwpIHtcbiAgICAgICAgZW5kTWV0YSA9IGNvbnRleHQuZGF0ZUVudi5jcmVhdGVNYXJrZXJNZXRhKHJlZmluZWQuZW5kKTtcbiAgICB9XG4gICAgaWYgKGFsbERheSA9PSBudWxsKSB7XG4gICAgICAgIGlmIChkZWZhdWx0QWxsRGF5ICE9IG51bGwpIHtcbiAgICAgICAgICAgIGFsbERheSA9IGRlZmF1bHRBbGxEYXk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyBmYWxsIGJhY2sgdG8gdGhlIGRhdGUgcHJvcHMgTEFTVFxuICAgICAgICAgICAgYWxsRGF5ID0gKCFzdGFydE1ldGEgfHwgc3RhcnRNZXRhLmlzVGltZVVuc3BlY2lmaWVkKSAmJlxuICAgICAgICAgICAgICAgICghZW5kTWV0YSB8fCBlbmRNZXRhLmlzVGltZVVuc3BlY2lmaWVkKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAoYWxsRGF5ICYmIHN0YXJ0TWFya2VyKSB7XG4gICAgICAgIHN0YXJ0TWFya2VyID0gc3RhcnRPZkRheShzdGFydE1hcmtlcik7XG4gICAgfVxuICAgIGlmIChlbmRNZXRhKSB7XG4gICAgICAgIGVuZE1hcmtlciA9IGVuZE1ldGEubWFya2VyO1xuICAgICAgICBpZiAoYWxsRGF5KSB7XG4gICAgICAgICAgICBlbmRNYXJrZXIgPSBzdGFydE9mRGF5KGVuZE1hcmtlcik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHN0YXJ0TWFya2VyICYmIGVuZE1hcmtlciA8PSBzdGFydE1hcmtlcikge1xuICAgICAgICAgICAgZW5kTWFya2VyID0gbnVsbDtcbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAoZW5kTWFya2VyKSB7XG4gICAgICAgIGhhc0VuZCA9IHRydWU7XG4gICAgfVxuICAgIGVsc2UgaWYgKCFhbGxvd09wZW5SYW5nZSkge1xuICAgICAgICBoYXNFbmQgPSBjb250ZXh0Lm9wdGlvbnMuZm9yY2VFdmVudER1cmF0aW9uIHx8IGZhbHNlO1xuICAgICAgICBlbmRNYXJrZXIgPSBjb250ZXh0LmRhdGVFbnYuYWRkKHN0YXJ0TWFya2VyLCBhbGxEYXkgP1xuICAgICAgICAgICAgY29udGV4dC5vcHRpb25zLmRlZmF1bHRBbGxEYXlFdmVudER1cmF0aW9uIDpcbiAgICAgICAgICAgIGNvbnRleHQub3B0aW9ucy5kZWZhdWx0VGltZWRFdmVudER1cmF0aW9uKTtcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgICAgYWxsRGF5LFxuICAgICAgICBoYXNFbmQsXG4gICAgICAgIHJhbmdlOiB7IHN0YXJ0OiBzdGFydE1hcmtlciwgZW5kOiBlbmRNYXJrZXIgfSxcbiAgICAgICAgZm9yY2VkU3RhcnRUem86IHN0YXJ0TWV0YSA/IHN0YXJ0TWV0YS5mb3JjZWRUem8gOiBudWxsLFxuICAgICAgICBmb3JjZWRFbmRUem86IGVuZE1ldGEgPyBlbmRNZXRhLmZvcmNlZFR6byA6IG51bGwsXG4gICAgfTtcbn1cbmZ1bmN0aW9uIGNvbXB1dGVJc0RlZmF1bHRBbGxEYXkoZXZlbnRTb3VyY2UsIGNvbnRleHQpIHtcbiAgICBsZXQgcmVzID0gbnVsbDtcbiAgICBpZiAoZXZlbnRTb3VyY2UpIHtcbiAgICAgICAgcmVzID0gZXZlbnRTb3VyY2UuZGVmYXVsdEFsbERheTtcbiAgICB9XG4gICAgaWYgKHJlcyA9PSBudWxsKSB7XG4gICAgICAgIHJlcyA9IGNvbnRleHQub3B0aW9ucy5kZWZhdWx0QWxsRGF5O1xuICAgIH1cbiAgICByZXR1cm4gcmVzO1xufVxuXG5mdW5jdGlvbiBwYXJzZUV2ZW50cyhyYXdFdmVudHMsIGV2ZW50U291cmNlLCBjb250ZXh0LCBhbGxvd09wZW5SYW5nZSwgZGVmSWRNYXAsIGluc3RhbmNlSWRNYXApIHtcbiAgICBsZXQgZXZlbnRTdG9yZSA9IGNyZWF0ZUVtcHR5RXZlbnRTdG9yZSgpO1xuICAgIGxldCBldmVudFJlZmluZXJzID0gYnVpbGRFdmVudFJlZmluZXJzKGNvbnRleHQpO1xuICAgIGZvciAobGV0IHJhd0V2ZW50IG9mIHJhd0V2ZW50cykge1xuICAgICAgICBsZXQgdHVwbGUgPSBwYXJzZUV2ZW50KHJhd0V2ZW50LCBldmVudFNvdXJjZSwgY29udGV4dCwgYWxsb3dPcGVuUmFuZ2UsIGV2ZW50UmVmaW5lcnMsIGRlZklkTWFwLCBpbnN0YW5jZUlkTWFwKTtcbiAgICAgICAgaWYgKHR1cGxlKSB7XG4gICAgICAgICAgICBldmVudFR1cGxlVG9TdG9yZSh0dXBsZSwgZXZlbnRTdG9yZSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGV2ZW50U3RvcmU7XG59XG5mdW5jdGlvbiBldmVudFR1cGxlVG9TdG9yZSh0dXBsZSwgZXZlbnRTdG9yZSA9IGNyZWF0ZUVtcHR5RXZlbnRTdG9yZSgpKSB7XG4gICAgZXZlbnRTdG9yZS5kZWZzW3R1cGxlLmRlZi5kZWZJZF0gPSB0dXBsZS5kZWY7XG4gICAgaWYgKHR1cGxlLmluc3RhbmNlKSB7XG4gICAgICAgIGV2ZW50U3RvcmUuaW5zdGFuY2VzW3R1cGxlLmluc3RhbmNlLmluc3RhbmNlSWRdID0gdHVwbGUuaW5zdGFuY2U7XG4gICAgfVxuICAgIHJldHVybiBldmVudFN0b3JlO1xufVxuLy8gcmV0cmlldmVzIGV2ZW50cyB0aGF0IGhhdmUgdGhlIHNhbWUgZ3JvdXBJZCBhcyB0aGUgaW5zdGFuY2Ugc3BlY2lmaWVkIGJ5IGBpbnN0YW5jZUlkYFxuLy8gb3IgdGhleSBhcmUgdGhlIHNhbWUgYXMgdGhlIGluc3RhbmNlLlxuLy8gd2h5IG1pZ2h0IGluc3RhbmNlSWQgbm90IGJlIGluIHRoZSBzdG9yZT8gYW4gZXZlbnQgZnJvbSBhbm90aGVyIGNhbGVuZGFyP1xuZnVuY3Rpb24gZ2V0UmVsZXZhbnRFdmVudHMoZXZlbnRTdG9yZSwgaW5zdGFuY2VJZCkge1xuICAgIGxldCBpbnN0YW5jZSA9IGV2ZW50U3RvcmUuaW5zdGFuY2VzW2luc3RhbmNlSWRdO1xuICAgIGlmIChpbnN0YW5jZSkge1xuICAgICAgICBsZXQgZGVmID0gZXZlbnRTdG9yZS5kZWZzW2luc3RhbmNlLmRlZklkXTtcbiAgICAgICAgLy8gZ2V0IGV2ZW50cy9pbnN0YW5jZXMgd2l0aCBzYW1lIGdyb3VwXG4gICAgICAgIGxldCBuZXdTdG9yZSA9IGZpbHRlckV2ZW50U3RvcmVEZWZzKGV2ZW50U3RvcmUsIChsb29rRGVmKSA9PiBpc0V2ZW50RGVmc0dyb3VwZWQoZGVmLCBsb29rRGVmKSk7XG4gICAgICAgIC8vIGFkZCB0aGUgb3JpZ2luYWxcbiAgICAgICAgLy8gVE9ETzogd2lzaCB3ZSBjb3VsZCB1c2UgZXZlbnRUdXBsZVRvU3RvcmUgb3Igc29tZXRoaW5nIGxpa2UgaXRcbiAgICAgICAgbmV3U3RvcmUuZGVmc1tkZWYuZGVmSWRdID0gZGVmO1xuICAgICAgICBuZXdTdG9yZS5pbnN0YW5jZXNbaW5zdGFuY2UuaW5zdGFuY2VJZF0gPSBpbnN0YW5jZTtcbiAgICAgICAgcmV0dXJuIG5ld1N0b3JlO1xuICAgIH1cbiAgICByZXR1cm4gY3JlYXRlRW1wdHlFdmVudFN0b3JlKCk7XG59XG5mdW5jdGlvbiBpc0V2ZW50RGVmc0dyb3VwZWQoZGVmMCwgZGVmMSkge1xuICAgIHJldHVybiBCb29sZWFuKGRlZjAuZ3JvdXBJZCAmJiBkZWYwLmdyb3VwSWQgPT09IGRlZjEuZ3JvdXBJZCk7XG59XG5mdW5jdGlvbiBjcmVhdGVFbXB0eUV2ZW50U3RvcmUoKSB7XG4gICAgcmV0dXJuIHsgZGVmczoge30sIGluc3RhbmNlczoge30gfTtcbn1cbmZ1bmN0aW9uIG1lcmdlRXZlbnRTdG9yZXMoc3RvcmUwLCBzdG9yZTEpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBkZWZzOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHN0b3JlMC5kZWZzKSwgc3RvcmUxLmRlZnMpLFxuICAgICAgICBpbnN0YW5jZXM6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc3RvcmUwLmluc3RhbmNlcyksIHN0b3JlMS5pbnN0YW5jZXMpLFxuICAgIH07XG59XG5mdW5jdGlvbiBmaWx0ZXJFdmVudFN0b3JlRGVmcyhldmVudFN0b3JlLCBmaWx0ZXJGdW5jKSB7XG4gICAgbGV0IGRlZnMgPSBmaWx0ZXJIYXNoKGV2ZW50U3RvcmUuZGVmcywgZmlsdGVyRnVuYyk7XG4gICAgbGV0IGluc3RhbmNlcyA9IGZpbHRlckhhc2goZXZlbnRTdG9yZS5pbnN0YW5jZXMsIChpbnN0YW5jZSkgPT4gKGRlZnNbaW5zdGFuY2UuZGVmSWRdIC8vIHN0aWxsIGV4aXN0cz9cbiAgICApKTtcbiAgICByZXR1cm4geyBkZWZzLCBpbnN0YW5jZXMgfTtcbn1cbmZ1bmN0aW9uIGV4Y2x1ZGVTdWJFdmVudFN0b3JlKG1hc3Rlciwgc3ViKSB7XG4gICAgbGV0IHsgZGVmcywgaW5zdGFuY2VzIH0gPSBtYXN0ZXI7XG4gICAgbGV0IGZpbHRlcmVkRGVmcyA9IHt9O1xuICAgIGxldCBmaWx0ZXJlZEluc3RhbmNlcyA9IHt9O1xuICAgIGZvciAobGV0IGRlZklkIGluIGRlZnMpIHtcbiAgICAgICAgaWYgKCFzdWIuZGVmc1tkZWZJZF0pIHsgLy8gbm90IGV4cGxpY2l0bHkgZXhjbHVkZWRcbiAgICAgICAgICAgIGZpbHRlcmVkRGVmc1tkZWZJZF0gPSBkZWZzW2RlZklkXTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBmb3IgKGxldCBpbnN0YW5jZUlkIGluIGluc3RhbmNlcykge1xuICAgICAgICBpZiAoIXN1Yi5pbnN0YW5jZXNbaW5zdGFuY2VJZF0gJiYgLy8gbm90IGV4cGxpY2l0bHkgZXhjbHVkZWRcbiAgICAgICAgICAgIGZpbHRlcmVkRGVmc1tpbnN0YW5jZXNbaW5zdGFuY2VJZF0uZGVmSWRdIC8vIGRlZiB3YXNuJ3QgZmlsdGVyZWQgYXdheVxuICAgICAgICApIHtcbiAgICAgICAgICAgIGZpbHRlcmVkSW5zdGFuY2VzW2luc3RhbmNlSWRdID0gaW5zdGFuY2VzW2luc3RhbmNlSWRdO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICAgIGRlZnM6IGZpbHRlcmVkRGVmcyxcbiAgICAgICAgaW5zdGFuY2VzOiBmaWx0ZXJlZEluc3RhbmNlcyxcbiAgICB9O1xufVxuXG5mdW5jdGlvbiBub3JtYWxpemVDb25zdHJhaW50KGlucHV0LCBjb250ZXh0KSB7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkoaW5wdXQpKSB7XG4gICAgICAgIHJldHVybiBwYXJzZUV2ZW50cyhpbnB1dCwgbnVsbCwgY29udGV4dCwgdHJ1ZSk7IC8vIGFsbG93T3BlblJhbmdlPXRydWVcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ29iamVjdCcgJiYgaW5wdXQpIHsgLy8gbm9uLW51bGwgb2JqZWN0XG4gICAgICAgIHJldHVybiBwYXJzZUV2ZW50cyhbaW5wdXRdLCBudWxsLCBjb250ZXh0LCB0cnVlKTsgLy8gYWxsb3dPcGVuUmFuZ2U9dHJ1ZVxuICAgIH1cbiAgICBpZiAoaW5wdXQgIT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gU3RyaW5nKGlucHV0KTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG59XG5cbmZ1bmN0aW9uIHBhcnNlQ2xhc3NOYW1lcyhyYXcpIHtcbiAgICBpZiAoQXJyYXkuaXNBcnJheShyYXcpKSB7XG4gICAgICAgIHJldHVybiByYXc7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgcmF3ID09PSAnc3RyaW5nJykge1xuICAgICAgICByZXR1cm4gcmF3LnNwbGl0KC9cXHMrLyk7XG4gICAgfVxuICAgIHJldHVybiBbXTtcbn1cblxuLy8gVE9ETzogYmV0dGVyIGNhbGxlZCBcIkV2ZW50U2V0dGluZ3NcIiBvciBcIkV2ZW50Q29uZmlnXCJcbi8vIFRPRE86IG1vdmUgdGhpcyBmaWxlIGludG8gc3RydWN0c1xuLy8gVE9ETzogc2VwYXJhdGUgY29uc3RyYWludC9vdmVybGFwL2FsbG93LCBiZWNhdXNlIHNlbGVjdGlvbiB1c2VzIG9ubHkgdGhhdCwgbm90IG90aGVyIHByb3BzXG5jb25zdCBFVkVOVF9VSV9SRUZJTkVSUyA9IHtcbiAgICBkaXNwbGF5OiBTdHJpbmcsXG4gICAgZWRpdGFibGU6IEJvb2xlYW4sXG4gICAgc3RhcnRFZGl0YWJsZTogQm9vbGVhbixcbiAgICBkdXJhdGlvbkVkaXRhYmxlOiBCb29sZWFuLFxuICAgIGNvbnN0cmFpbnQ6IGlkZW50aXR5LFxuICAgIG92ZXJsYXA6IGlkZW50aXR5LFxuICAgIGFsbG93OiBpZGVudGl0eSxcbiAgICBjbGFzc05hbWU6IHBhcnNlQ2xhc3NOYW1lcyxcbiAgICBjbGFzc05hbWVzOiBwYXJzZUNsYXNzTmFtZXMsXG4gICAgY29sb3I6IFN0cmluZyxcbiAgICBiYWNrZ3JvdW5kQ29sb3I6IFN0cmluZyxcbiAgICBib3JkZXJDb2xvcjogU3RyaW5nLFxuICAgIHRleHRDb2xvcjogU3RyaW5nLFxufTtcbmNvbnN0IEVNUFRZX0VWRU5UX1VJID0ge1xuICAgIGRpc3BsYXk6IG51bGwsXG4gICAgc3RhcnRFZGl0YWJsZTogbnVsbCxcbiAgICBkdXJhdGlvbkVkaXRhYmxlOiBudWxsLFxuICAgIGNvbnN0cmFpbnRzOiBbXSxcbiAgICBvdmVybGFwOiBudWxsLFxuICAgIGFsbG93czogW10sXG4gICAgYmFja2dyb3VuZENvbG9yOiAnJyxcbiAgICBib3JkZXJDb2xvcjogJycsXG4gICAgdGV4dENvbG9yOiAnJyxcbiAgICBjbGFzc05hbWVzOiBbXSxcbn07XG5mdW5jdGlvbiBjcmVhdGVFdmVudFVpKHJlZmluZWQsIGNvbnRleHQpIHtcbiAgICBsZXQgY29uc3RyYWludCA9IG5vcm1hbGl6ZUNvbnN0cmFpbnQocmVmaW5lZC5jb25zdHJhaW50LCBjb250ZXh0KTtcbiAgICByZXR1cm4ge1xuICAgICAgICBkaXNwbGF5OiByZWZpbmVkLmRpc3BsYXkgfHwgbnVsbCxcbiAgICAgICAgc3RhcnRFZGl0YWJsZTogcmVmaW5lZC5zdGFydEVkaXRhYmxlICE9IG51bGwgPyByZWZpbmVkLnN0YXJ0RWRpdGFibGUgOiByZWZpbmVkLmVkaXRhYmxlLFxuICAgICAgICBkdXJhdGlvbkVkaXRhYmxlOiByZWZpbmVkLmR1cmF0aW9uRWRpdGFibGUgIT0gbnVsbCA/IHJlZmluZWQuZHVyYXRpb25FZGl0YWJsZSA6IHJlZmluZWQuZWRpdGFibGUsXG4gICAgICAgIGNvbnN0cmFpbnRzOiBjb25zdHJhaW50ICE9IG51bGwgPyBbY29uc3RyYWludF0gOiBbXSxcbiAgICAgICAgb3ZlcmxhcDogcmVmaW5lZC5vdmVybGFwICE9IG51bGwgPyByZWZpbmVkLm92ZXJsYXAgOiBudWxsLFxuICAgICAgICBhbGxvd3M6IHJlZmluZWQuYWxsb3cgIT0gbnVsbCA/IFtyZWZpbmVkLmFsbG93XSA6IFtdLFxuICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IHJlZmluZWQuYmFja2dyb3VuZENvbG9yIHx8IHJlZmluZWQuY29sb3IgfHwgJycsXG4gICAgICAgIGJvcmRlckNvbG9yOiByZWZpbmVkLmJvcmRlckNvbG9yIHx8IHJlZmluZWQuY29sb3IgfHwgJycsXG4gICAgICAgIHRleHRDb2xvcjogcmVmaW5lZC50ZXh0Q29sb3IgfHwgJycsXG4gICAgICAgIGNsYXNzTmFtZXM6IChyZWZpbmVkLmNsYXNzTmFtZSB8fCBbXSkuY29uY2F0KHJlZmluZWQuY2xhc3NOYW1lcyB8fCBbXSksIC8vIGpvaW4gc2luZ3VsYXIgYW5kIHBsdXJhbFxuICAgIH07XG59XG4vLyBUT0RPOiBwcmV2ZW50IGFnYWluc3QgcHJvYmxlbXMgd2l0aCA8MiBhcmdzIVxuZnVuY3Rpb24gY29tYmluZUV2ZW50VWlzKHVpcykge1xuICAgIHJldHVybiB1aXMucmVkdWNlKGNvbWJpbmVUd29FdmVudFVpcywgRU1QVFlfRVZFTlRfVUkpO1xufVxuZnVuY3Rpb24gY29tYmluZVR3b0V2ZW50VWlzKGl0ZW0wLCBpdGVtMSkge1xuICAgIHJldHVybiB7XG4gICAgICAgIGRpc3BsYXk6IGl0ZW0xLmRpc3BsYXkgIT0gbnVsbCA/IGl0ZW0xLmRpc3BsYXkgOiBpdGVtMC5kaXNwbGF5LFxuICAgICAgICBzdGFydEVkaXRhYmxlOiBpdGVtMS5zdGFydEVkaXRhYmxlICE9IG51bGwgPyBpdGVtMS5zdGFydEVkaXRhYmxlIDogaXRlbTAuc3RhcnRFZGl0YWJsZSxcbiAgICAgICAgZHVyYXRpb25FZGl0YWJsZTogaXRlbTEuZHVyYXRpb25FZGl0YWJsZSAhPSBudWxsID8gaXRlbTEuZHVyYXRpb25FZGl0YWJsZSA6IGl0ZW0wLmR1cmF0aW9uRWRpdGFibGUsXG4gICAgICAgIGNvbnN0cmFpbnRzOiBpdGVtMC5jb25zdHJhaW50cy5jb25jYXQoaXRlbTEuY29uc3RyYWludHMpLFxuICAgICAgICBvdmVybGFwOiB0eXBlb2YgaXRlbTEub3ZlcmxhcCA9PT0gJ2Jvb2xlYW4nID8gaXRlbTEub3ZlcmxhcCA6IGl0ZW0wLm92ZXJsYXAsXG4gICAgICAgIGFsbG93czogaXRlbTAuYWxsb3dzLmNvbmNhdChpdGVtMS5hbGxvd3MpLFxuICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IGl0ZW0xLmJhY2tncm91bmRDb2xvciB8fCBpdGVtMC5iYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgIGJvcmRlckNvbG9yOiBpdGVtMS5ib3JkZXJDb2xvciB8fCBpdGVtMC5ib3JkZXJDb2xvcixcbiAgICAgICAgdGV4dENvbG9yOiBpdGVtMS50ZXh0Q29sb3IgfHwgaXRlbTAudGV4dENvbG9yLFxuICAgICAgICBjbGFzc05hbWVzOiBpdGVtMC5jbGFzc05hbWVzLmNvbmNhdChpdGVtMS5jbGFzc05hbWVzKSxcbiAgICB9O1xufVxuXG5jb25zdCBFVkVOVF9TT1VSQ0VfUkVGSU5FUlMgPSB7XG4gICAgaWQ6IFN0cmluZyxcbiAgICBkZWZhdWx0QWxsRGF5OiBCb29sZWFuLFxuICAgIHVybDogU3RyaW5nLFxuICAgIGZvcm1hdDogU3RyaW5nLFxuICAgIGV2ZW50czogaWRlbnRpdHksXG4gICAgZXZlbnREYXRhVHJhbnNmb3JtOiBpZGVudGl0eSxcbiAgICAvLyBmb3IgYW55IG5ldHdvcmstcmVsYXRlZCBzb3VyY2VzXG4gICAgc3VjY2VzczogaWRlbnRpdHksXG4gICAgZmFpbHVyZTogaWRlbnRpdHksXG59O1xuZnVuY3Rpb24gcGFyc2VFdmVudFNvdXJjZShyYXcsIGNvbnRleHQsIHJlZmluZXJzID0gYnVpbGRFdmVudFNvdXJjZVJlZmluZXJzKGNvbnRleHQpKSB7XG4gICAgbGV0IHJhd09iajtcbiAgICBpZiAodHlwZW9mIHJhdyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgcmF3T2JqID0geyB1cmw6IHJhdyB9O1xuICAgIH1cbiAgICBlbHNlIGlmICh0eXBlb2YgcmF3ID09PSAnZnVuY3Rpb24nIHx8IEFycmF5LmlzQXJyYXkocmF3KSkge1xuICAgICAgICByYXdPYmogPSB7IGV2ZW50czogcmF3IH07XG4gICAgfVxuICAgIGVsc2UgaWYgKHR5cGVvZiByYXcgPT09ICdvYmplY3QnICYmIHJhdykgeyAvLyBub3QgbnVsbFxuICAgICAgICByYXdPYmogPSByYXc7XG4gICAgfVxuICAgIGlmIChyYXdPYmopIHtcbiAgICAgICAgbGV0IHsgcmVmaW5lZCwgZXh0cmEgfSA9IHJlZmluZVByb3BzKHJhd09iaiwgcmVmaW5lcnMpO1xuICAgICAgICBsZXQgbWV0YVJlcyA9IGJ1aWxkRXZlbnRTb3VyY2VNZXRhKHJlZmluZWQsIGNvbnRleHQpO1xuICAgICAgICBpZiAobWV0YVJlcykge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBfcmF3OiByYXcsXG4gICAgICAgICAgICAgICAgaXNGZXRjaGluZzogZmFsc2UsXG4gICAgICAgICAgICAgICAgbGF0ZXN0RmV0Y2hJZDogJycsXG4gICAgICAgICAgICAgICAgZmV0Y2hSYW5nZTogbnVsbCxcbiAgICAgICAgICAgICAgICBkZWZhdWx0QWxsRGF5OiByZWZpbmVkLmRlZmF1bHRBbGxEYXksXG4gICAgICAgICAgICAgICAgZXZlbnREYXRhVHJhbnNmb3JtOiByZWZpbmVkLmV2ZW50RGF0YVRyYW5zZm9ybSxcbiAgICAgICAgICAgICAgICBzdWNjZXNzOiByZWZpbmVkLnN1Y2Nlc3MsXG4gICAgICAgICAgICAgICAgZmFpbHVyZTogcmVmaW5lZC5mYWlsdXJlLFxuICAgICAgICAgICAgICAgIHB1YmxpY0lkOiByZWZpbmVkLmlkIHx8ICcnLFxuICAgICAgICAgICAgICAgIHNvdXJjZUlkOiBndWlkKCksXG4gICAgICAgICAgICAgICAgc291cmNlRGVmSWQ6IG1ldGFSZXMuc291cmNlRGVmSWQsXG4gICAgICAgICAgICAgICAgbWV0YTogbWV0YVJlcy5tZXRhLFxuICAgICAgICAgICAgICAgIHVpOiBjcmVhdGVFdmVudFVpKHJlZmluZWQsIGNvbnRleHQpLFxuICAgICAgICAgICAgICAgIGV4dGVuZGVkUHJvcHM6IGV4dHJhLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cbmZ1bmN0aW9uIGJ1aWxkRXZlbnRTb3VyY2VSZWZpbmVycyhjb250ZXh0KSB7XG4gICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBFVkVOVF9VSV9SRUZJTkVSUyksIEVWRU5UX1NPVVJDRV9SRUZJTkVSUyksIGNvbnRleHQucGx1Z2luSG9va3MuZXZlbnRTb3VyY2VSZWZpbmVycyk7XG59XG5mdW5jdGlvbiBidWlsZEV2ZW50U291cmNlTWV0YShyYXcsIGNvbnRleHQpIHtcbiAgICBsZXQgZGVmcyA9IGNvbnRleHQucGx1Z2luSG9va3MuZXZlbnRTb3VyY2VEZWZzO1xuICAgIGZvciAobGV0IGkgPSBkZWZzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaSAtPSAxKSB7IC8vIGxhdGVyLWFkZGVkIHBsdWdpbnMgdGFrZSBwcmVjZWRlbmNlXG4gICAgICAgIGxldCBkZWYgPSBkZWZzW2ldO1xuICAgICAgICBsZXQgbWV0YSA9IGRlZi5wYXJzZU1ldGEocmF3KTtcbiAgICAgICAgaWYgKG1ldGEpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHNvdXJjZURlZklkOiBpLCBtZXRhIH07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG59XG5cbmZ1bmN0aW9uIHJlZHVjZUV2ZW50U3RvcmUoZXZlbnRTdG9yZSwgYWN0aW9uLCBldmVudFNvdXJjZXMsIGRhdGVQcm9maWxlLCBjb250ZXh0KSB7XG4gICAgc3dpdGNoIChhY3Rpb24udHlwZSkge1xuICAgICAgICBjYXNlICdSRUNFSVZFX0VWRU5UUyc6IC8vIHJhd1xuICAgICAgICAgICAgcmV0dXJuIHJlY2VpdmVSYXdFdmVudHMoZXZlbnRTdG9yZSwgZXZlbnRTb3VyY2VzW2FjdGlvbi5zb3VyY2VJZF0sIGFjdGlvbi5mZXRjaElkLCBhY3Rpb24uZmV0Y2hSYW5nZSwgYWN0aW9uLnJhd0V2ZW50cywgY29udGV4dCk7XG4gICAgICAgIGNhc2UgJ1JFU0VUX1JBV19FVkVOVFMnOlxuICAgICAgICAgICAgcmV0dXJuIHJlc2V0UmF3RXZlbnRzKGV2ZW50U3RvcmUsIGV2ZW50U291cmNlc1thY3Rpb24uc291cmNlSWRdLCBhY3Rpb24ucmF3RXZlbnRzLCBkYXRlUHJvZmlsZS5hY3RpdmVSYW5nZSwgY29udGV4dCk7XG4gICAgICAgIGNhc2UgJ0FERF9FVkVOVFMnOiAvLyBhbHJlYWR5IHBhcnNlZCwgYnV0IG5vdCBleHBhbmRlZFxuICAgICAgICAgICAgcmV0dXJuIGFkZEV2ZW50KGV2ZW50U3RvcmUsIGFjdGlvbi5ldmVudFN0b3JlLCAvLyBuZXcgb25lc1xuICAgICAgICAgICAgZGF0ZVByb2ZpbGUgPyBkYXRlUHJvZmlsZS5hY3RpdmVSYW5nZSA6IG51bGwsIGNvbnRleHQpO1xuICAgICAgICBjYXNlICdSRVNFVF9FVkVOVFMnOlxuICAgICAgICAgICAgcmV0dXJuIGFjdGlvbi5ldmVudFN0b3JlO1xuICAgICAgICBjYXNlICdNRVJHRV9FVkVOVFMnOiAvLyBhbHJlYWR5IHBhcnNlZCBhbmQgZXhwYW5kZWRcbiAgICAgICAgICAgIHJldHVybiBtZXJnZUV2ZW50U3RvcmVzKGV2ZW50U3RvcmUsIGFjdGlvbi5ldmVudFN0b3JlKTtcbiAgICAgICAgY2FzZSAnUFJFVic6IC8vIFRPRE86IGhvdyBkbyB3ZSB0cmFjayBhbGwgYWN0aW9ucyB0aGF0IGFmZmVjdCBkYXRlUHJvZmlsZSA6KFxuICAgICAgICBjYXNlICdORVhUJzpcbiAgICAgICAgY2FzZSAnQ0hBTkdFX0RBVEUnOlxuICAgICAgICBjYXNlICdDSEFOR0VfVklFV19UWVBFJzpcbiAgICAgICAgICAgIGlmIChkYXRlUHJvZmlsZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBleHBhbmRSZWN1cnJpbmcoZXZlbnRTdG9yZSwgZGF0ZVByb2ZpbGUuYWN0aXZlUmFuZ2UsIGNvbnRleHQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGV2ZW50U3RvcmU7XG4gICAgICAgIGNhc2UgJ1JFTU9WRV9FVkVOVFMnOlxuICAgICAgICAgICAgcmV0dXJuIGV4Y2x1ZGVTdWJFdmVudFN0b3JlKGV2ZW50U3RvcmUsIGFjdGlvbi5ldmVudFN0b3JlKTtcbiAgICAgICAgY2FzZSAnUkVNT1ZFX0VWRU5UX1NPVVJDRSc6XG4gICAgICAgICAgICByZXR1cm4gZXhjbHVkZUV2ZW50c0J5U291cmNlSWQoZXZlbnRTdG9yZSwgYWN0aW9uLnNvdXJjZUlkKTtcbiAgICAgICAgY2FzZSAnUkVNT1ZFX0FMTF9FVkVOVF9TT1VSQ0VTJzpcbiAgICAgICAgICAgIHJldHVybiBmaWx0ZXJFdmVudFN0b3JlRGVmcyhldmVudFN0b3JlLCAoZXZlbnREZWYpID0+ICghZXZlbnREZWYuc291cmNlSWQgLy8gb25seSBrZWVwIGV2ZW50cyB3aXRoIG5vIHNvdXJjZSBpZFxuICAgICAgICAgICAgKSk7XG4gICAgICAgIGNhc2UgJ1JFTU9WRV9BTExfRVZFTlRTJzpcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVFbXB0eUV2ZW50U3RvcmUoKTtcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIHJldHVybiBldmVudFN0b3JlO1xuICAgIH1cbn1cbmZ1bmN0aW9uIHJlY2VpdmVSYXdFdmVudHMoZXZlbnRTdG9yZSwgZXZlbnRTb3VyY2UsIGZldGNoSWQsIGZldGNoUmFuZ2UsIHJhd0V2ZW50cywgY29udGV4dCkge1xuICAgIGlmIChldmVudFNvdXJjZSAmJiAvLyBub3QgYWxyZWFkeSByZW1vdmVkXG4gICAgICAgIGZldGNoSWQgPT09IGV2ZW50U291cmNlLmxhdGVzdEZldGNoSWQgLy8gVE9ETzogd2lzaCB0aGlzIGxvZ2ljIHdhcyBhbHdheXMgaW4gZXZlbnQtc291cmNlc1xuICAgICkge1xuICAgICAgICBsZXQgc3Vic2V0ID0gcGFyc2VFdmVudHModHJhbnNmb3JtUmF3RXZlbnRzKHJhd0V2ZW50cywgZXZlbnRTb3VyY2UsIGNvbnRleHQpLCBldmVudFNvdXJjZSwgY29udGV4dCk7XG4gICAgICAgIGlmIChmZXRjaFJhbmdlKSB7XG4gICAgICAgICAgICBzdWJzZXQgPSBleHBhbmRSZWN1cnJpbmcoc3Vic2V0LCBmZXRjaFJhbmdlLCBjb250ZXh0KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbWVyZ2VFdmVudFN0b3JlcyhleGNsdWRlRXZlbnRzQnlTb3VyY2VJZChldmVudFN0b3JlLCBldmVudFNvdXJjZS5zb3VyY2VJZCksIHN1YnNldCk7XG4gICAgfVxuICAgIHJldHVybiBldmVudFN0b3JlO1xufVxuZnVuY3Rpb24gcmVzZXRSYXdFdmVudHMoZXhpc3RpbmdFdmVudFN0b3JlLCBldmVudFNvdXJjZSwgcmF3RXZlbnRzLCBhY3RpdmVSYW5nZSwgY29udGV4dCkge1xuICAgIGNvbnN0IHsgZGVmSWRNYXAsIGluc3RhbmNlSWRNYXAgfSA9IGJ1aWxkUHVibGljSWRNYXBzKGV4aXN0aW5nRXZlbnRTdG9yZSk7XG4gICAgbGV0IG5ld0V2ZW50U3RvcmUgPSBwYXJzZUV2ZW50cyh0cmFuc2Zvcm1SYXdFdmVudHMocmF3RXZlbnRzLCBldmVudFNvdXJjZSwgY29udGV4dCksIGV2ZW50U291cmNlLCBjb250ZXh0LCBmYWxzZSwgZGVmSWRNYXAsIGluc3RhbmNlSWRNYXApO1xuICAgIHJldHVybiBleHBhbmRSZWN1cnJpbmcobmV3RXZlbnRTdG9yZSwgYWN0aXZlUmFuZ2UsIGNvbnRleHQpO1xufVxuZnVuY3Rpb24gdHJhbnNmb3JtUmF3RXZlbnRzKHJhd0V2ZW50cywgZXZlbnRTb3VyY2UsIGNvbnRleHQpIHtcbiAgICBsZXQgY2FsRWFjaFRyYW5zZm9ybSA9IGNvbnRleHQub3B0aW9ucy5ldmVudERhdGFUcmFuc2Zvcm07XG4gICAgbGV0IHNvdXJjZUVhY2hUcmFuc2Zvcm0gPSBldmVudFNvdXJjZSA/IGV2ZW50U291cmNlLmV2ZW50RGF0YVRyYW5zZm9ybSA6IG51bGw7XG4gICAgaWYgKHNvdXJjZUVhY2hUcmFuc2Zvcm0pIHtcbiAgICAgICAgcmF3RXZlbnRzID0gdHJhbnNmb3JtRWFjaFJhd0V2ZW50KHJhd0V2ZW50cywgc291cmNlRWFjaFRyYW5zZm9ybSk7XG4gICAgfVxuICAgIGlmIChjYWxFYWNoVHJhbnNmb3JtKSB7XG4gICAgICAgIHJhd0V2ZW50cyA9IHRyYW5zZm9ybUVhY2hSYXdFdmVudChyYXdFdmVudHMsIGNhbEVhY2hUcmFuc2Zvcm0pO1xuICAgIH1cbiAgICByZXR1cm4gcmF3RXZlbnRzO1xufVxuZnVuY3Rpb24gdHJhbnNmb3JtRWFjaFJhd0V2ZW50KHJhd0V2ZW50cywgZnVuYykge1xuICAgIGxldCByZWZpbmVkRXZlbnRzO1xuICAgIGlmICghZnVuYykge1xuICAgICAgICByZWZpbmVkRXZlbnRzID0gcmF3RXZlbnRzO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmVmaW5lZEV2ZW50cyA9IFtdO1xuICAgICAgICBmb3IgKGxldCByYXdFdmVudCBvZiByYXdFdmVudHMpIHtcbiAgICAgICAgICAgIGxldCByZWZpbmVkRXZlbnQgPSBmdW5jKHJhd0V2ZW50KTtcbiAgICAgICAgICAgIGlmIChyZWZpbmVkRXZlbnQpIHtcbiAgICAgICAgICAgICAgICByZWZpbmVkRXZlbnRzLnB1c2gocmVmaW5lZEV2ZW50KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKHJlZmluZWRFdmVudCA9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgcmVmaW5lZEV2ZW50cy5wdXNoKHJhd0V2ZW50KTtcbiAgICAgICAgICAgIH0gLy8gaWYgYSBkaWZmZXJlbnQgZmFsc3kgdmFsdWUsIGRvIG5vdGhpbmdcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVmaW5lZEV2ZW50cztcbn1cbmZ1bmN0aW9uIGFkZEV2ZW50KGV2ZW50U3RvcmUsIHN1YnNldCwgZXhwYW5kUmFuZ2UsIGNvbnRleHQpIHtcbiAgICBpZiAoZXhwYW5kUmFuZ2UpIHtcbiAgICAgICAgc3Vic2V0ID0gZXhwYW5kUmVjdXJyaW5nKHN1YnNldCwgZXhwYW5kUmFuZ2UsIGNvbnRleHQpO1xuICAgIH1cbiAgICByZXR1cm4gbWVyZ2VFdmVudFN0b3JlcyhldmVudFN0b3JlLCBzdWJzZXQpO1xufVxuZnVuY3Rpb24gcmV6b25lRXZlbnRTdG9yZURhdGVzKGV2ZW50U3RvcmUsIG9sZERhdGVFbnYsIG5ld0RhdGVFbnYpIHtcbiAgICBsZXQgeyBkZWZzIH0gPSBldmVudFN0b3JlO1xuICAgIGxldCBpbnN0YW5jZXMgPSBtYXBIYXNoKGV2ZW50U3RvcmUuaW5zdGFuY2VzLCAoaW5zdGFuY2UpID0+IHtcbiAgICAgICAgbGV0IGRlZiA9IGRlZnNbaW5zdGFuY2UuZGVmSWRdO1xuICAgICAgICBpZiAoZGVmLmFsbERheSkge1xuICAgICAgICAgICAgcmV0dXJuIGluc3RhbmNlOyAvLyBpc24ndCBkZXBlbmRlbnQgb24gdGltZXpvbmVcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBpbnN0YW5jZSksIHsgcmFuZ2U6IHtcbiAgICAgICAgICAgICAgICBzdGFydDogbmV3RGF0ZUVudi5jcmVhdGVNYXJrZXIob2xkRGF0ZUVudi50b0RhdGUoaW5zdGFuY2UucmFuZ2Uuc3RhcnQsIGluc3RhbmNlLmZvcmNlZFN0YXJ0VHpvKSksXG4gICAgICAgICAgICAgICAgZW5kOiBuZXdEYXRlRW52LmNyZWF0ZU1hcmtlcihvbGREYXRlRW52LnRvRGF0ZShpbnN0YW5jZS5yYW5nZS5lbmQsIGluc3RhbmNlLmZvcmNlZEVuZFR6bykpLFxuICAgICAgICAgICAgfSwgZm9yY2VkU3RhcnRUem86IG5ld0RhdGVFbnYuY2FuQ29tcHV0ZU9mZnNldCA/IG51bGwgOiBpbnN0YW5jZS5mb3JjZWRTdGFydFR6bywgZm9yY2VkRW5kVHpvOiBuZXdEYXRlRW52LmNhbkNvbXB1dGVPZmZzZXQgPyBudWxsIDogaW5zdGFuY2UuZm9yY2VkRW5kVHpvIH0pO1xuICAgIH0pO1xuICAgIHJldHVybiB7IGRlZnMsIGluc3RhbmNlcyB9O1xufVxuZnVuY3Rpb24gZXhjbHVkZUV2ZW50c0J5U291cmNlSWQoZXZlbnRTdG9yZSwgc291cmNlSWQpIHtcbiAgICByZXR1cm4gZmlsdGVyRXZlbnRTdG9yZURlZnMoZXZlbnRTdG9yZSwgKGV2ZW50RGVmKSA9PiBldmVudERlZi5zb3VyY2VJZCAhPT0gc291cmNlSWQpO1xufVxuLy8gUVVFU1RJT046IHdoeSBub3QganVzdCByZXR1cm4gaW5zdGFuY2VzPyBkbyBhIGdlbmVyYWwgb2JqZWN0LXByb3BlcnR5LWV4Y2x1c2lvbiB1dGlsXG5mdW5jdGlvbiBleGNsdWRlSW5zdGFuY2VzKGV2ZW50U3RvcmUsIHJlbW92YWxzKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgZGVmczogZXZlbnRTdG9yZS5kZWZzLFxuICAgICAgICBpbnN0YW5jZXM6IGZpbHRlckhhc2goZXZlbnRTdG9yZS5pbnN0YW5jZXMsIChpbnN0YW5jZSkgPT4gIXJlbW92YWxzW2luc3RhbmNlLmluc3RhbmNlSWRdKSxcbiAgICB9O1xufVxuZnVuY3Rpb24gYnVpbGRQdWJsaWNJZE1hcHMoZXZlbnRTdG9yZSkge1xuICAgIGNvbnN0IHsgZGVmcywgaW5zdGFuY2VzIH0gPSBldmVudFN0b3JlO1xuICAgIGNvbnN0IGRlZklkTWFwID0ge307XG4gICAgY29uc3QgaW5zdGFuY2VJZE1hcCA9IHt9O1xuICAgIGZvciAobGV0IGRlZklkIGluIGRlZnMpIHtcbiAgICAgICAgY29uc3QgZGVmID0gZGVmc1tkZWZJZF07XG4gICAgICAgIGNvbnN0IHsgcHVibGljSWQgfSA9IGRlZjtcbiAgICAgICAgaWYgKHB1YmxpY0lkKSB7XG4gICAgICAgICAgICBkZWZJZE1hcFtwdWJsaWNJZF0gPSBkZWZJZDtcbiAgICAgICAgfVxuICAgIH1cbiAgICBmb3IgKGxldCBpbnN0YW5jZUlkIGluIGluc3RhbmNlcykge1xuICAgICAgICBjb25zdCBpbnN0YW5jZSA9IGluc3RhbmNlc1tpbnN0YW5jZUlkXTtcbiAgICAgICAgY29uc3QgZGVmID0gZGVmc1tpbnN0YW5jZS5kZWZJZF07XG4gICAgICAgIGNvbnN0IHsgcHVibGljSWQgfSA9IGRlZjtcbiAgICAgICAgaWYgKHB1YmxpY0lkKSB7XG4gICAgICAgICAgICBpbnN0YW5jZUlkTWFwW3B1YmxpY0lkXSA9IGluc3RhbmNlSWQ7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgZGVmSWRNYXAsIGluc3RhbmNlSWRNYXAgfTtcbn1cblxuY2xhc3MgRW1pdHRlciB7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlcnMgPSB7fTtcbiAgICAgICAgdGhpcy50aGlzQ29udGV4dCA9IG51bGw7XG4gICAgfVxuICAgIHNldFRoaXNDb250ZXh0KHRoaXNDb250ZXh0KSB7XG4gICAgICAgIHRoaXMudGhpc0NvbnRleHQgPSB0aGlzQ29udGV4dDtcbiAgICB9XG4gICAgc2V0T3B0aW9ucyhvcHRpb25zKSB7XG4gICAgICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgfVxuICAgIG9uKHR5cGUsIGhhbmRsZXIpIHtcbiAgICAgICAgYWRkVG9IYXNoKHRoaXMuaGFuZGxlcnMsIHR5cGUsIGhhbmRsZXIpO1xuICAgIH1cbiAgICBvZmYodHlwZSwgaGFuZGxlcikge1xuICAgICAgICByZW1vdmVGcm9tSGFzaCh0aGlzLmhhbmRsZXJzLCB0eXBlLCBoYW5kbGVyKTtcbiAgICB9XG4gICAgdHJpZ2dlcih0eXBlLCAuLi5hcmdzKSB7XG4gICAgICAgIGxldCBhdHRhY2hlZEhhbmRsZXJzID0gdGhpcy5oYW5kbGVyc1t0eXBlXSB8fCBbXTtcbiAgICAgICAgbGV0IG9wdGlvbkhhbmRsZXIgPSB0aGlzLm9wdGlvbnMgJiYgdGhpcy5vcHRpb25zW3R5cGVdO1xuICAgICAgICBsZXQgaGFuZGxlcnMgPSBbXS5jb25jYXQob3B0aW9uSGFuZGxlciB8fCBbXSwgYXR0YWNoZWRIYW5kbGVycyk7XG4gICAgICAgIGZvciAobGV0IGhhbmRsZXIgb2YgaGFuZGxlcnMpIHtcbiAgICAgICAgICAgIGhhbmRsZXIuYXBwbHkodGhpcy50aGlzQ29udGV4dCwgYXJncyk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgaGFzSGFuZGxlcnModHlwZSkge1xuICAgICAgICByZXR1cm4gQm9vbGVhbigodGhpcy5oYW5kbGVyc1t0eXBlXSAmJiB0aGlzLmhhbmRsZXJzW3R5cGVdLmxlbmd0aCkgfHxcbiAgICAgICAgICAgICh0aGlzLm9wdGlvbnMgJiYgdGhpcy5vcHRpb25zW3R5cGVdKSk7XG4gICAgfVxufVxuZnVuY3Rpb24gYWRkVG9IYXNoKGhhc2gsIHR5cGUsIGhhbmRsZXIpIHtcbiAgICAoaGFzaFt0eXBlXSB8fCAoaGFzaFt0eXBlXSA9IFtdKSlcbiAgICAgICAgLnB1c2goaGFuZGxlcik7XG59XG5mdW5jdGlvbiByZW1vdmVGcm9tSGFzaChoYXNoLCB0eXBlLCBoYW5kbGVyKSB7XG4gICAgaWYgKGhhbmRsZXIpIHtcbiAgICAgICAgaWYgKGhhc2hbdHlwZV0pIHtcbiAgICAgICAgICAgIGhhc2hbdHlwZV0gPSBoYXNoW3R5cGVdLmZpbHRlcigoZnVuYykgPT4gZnVuYyAhPT0gaGFuZGxlcik7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGRlbGV0ZSBoYXNoW3R5cGVdOyAvLyByZW1vdmUgYWxsIGhhbmRsZXIgZnVuY3MgZm9yIHRoaXMgdHlwZVxuICAgIH1cbn1cblxuY29uc3QgREVGX0RFRkFVTFRTID0ge1xuICAgIHN0YXJ0VGltZTogJzA5OjAwJyxcbiAgICBlbmRUaW1lOiAnMTc6MDAnLFxuICAgIGRheXNPZldlZWs6IFsxLCAyLCAzLCA0LCA1XSxcbiAgICBkaXNwbGF5OiAnaW52ZXJzZS1iYWNrZ3JvdW5kJyxcbiAgICBjbGFzc05hbWVzOiAnZmMtbm9uLWJ1c2luZXNzJyxcbiAgICBncm91cElkOiAnX2J1c2luZXNzSG91cnMnLCAvLyBzbyBtdWx0aXBsZSBkZWZzIGdldCBncm91cGVkXG59O1xuLypcblRPRE86IHBhc3MgYXJvdW5kIGFzIEV2ZW50RGVmSGFzaCEhIVxuKi9cbmZ1bmN0aW9uIHBhcnNlQnVzaW5lc3NIb3VycyhpbnB1dCwgY29udGV4dCkge1xuICAgIHJldHVybiBwYXJzZUV2ZW50cyhyZWZpbmVJbnB1dHMoaW5wdXQpLCBudWxsLCBjb250ZXh0KTtcbn1cbmZ1bmN0aW9uIHJlZmluZUlucHV0cyhpbnB1dCkge1xuICAgIGxldCByYXdEZWZzO1xuICAgIGlmIChpbnB1dCA9PT0gdHJ1ZSkge1xuICAgICAgICByYXdEZWZzID0gW3t9XTsgLy8gd2lsbCBnZXQgREVGX0RFRkFVTFRTIHZlcmJhdGltXG4gICAgfVxuICAgIGVsc2UgaWYgKEFycmF5LmlzQXJyYXkoaW5wdXQpKSB7XG4gICAgICAgIC8vIGlmIHNwZWNpZnlpbmcgYW4gYXJyYXksIGV2ZXJ5IHN1Yi1kZWZpbml0aW9uIE5FRURTIGEgZGF5LW9mLXdlZWtcbiAgICAgICAgcmF3RGVmcyA9IGlucHV0LmZpbHRlcigocmF3RGVmKSA9PiByYXdEZWYuZGF5c09mV2Vlayk7XG4gICAgfVxuICAgIGVsc2UgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ29iamVjdCcgJiYgaW5wdXQpIHsgLy8gbm9uLW51bGwgb2JqZWN0XG4gICAgICAgIHJhd0RlZnMgPSBbaW5wdXRdO1xuICAgIH1cbiAgICBlbHNlIHsgLy8gaXMgcHJvYmFibHkgZmFsc2VcbiAgICAgICAgcmF3RGVmcyA9IFtdO1xuICAgIH1cbiAgICByYXdEZWZzID0gcmF3RGVmcy5tYXAoKHJhd0RlZikgPT4gKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgREVGX0RFRkFVTFRTKSwgcmF3RGVmKSkpO1xuICAgIHJldHVybiByYXdEZWZzO1xufVxuXG5mdW5jdGlvbiB0cmlnZ2VyRGF0ZVNlbGVjdChzZWxlY3Rpb24sIHBldiwgY29udGV4dCkge1xuICAgIGNvbnRleHQuZW1pdHRlci50cmlnZ2VyKCdzZWxlY3QnLCBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGJ1aWxkRGF0ZVNwYW5BcGlXaXRoQ29udGV4dChzZWxlY3Rpb24sIGNvbnRleHQpKSwgeyBqc0V2ZW50OiBwZXYgPyBwZXYub3JpZ0V2ZW50IDogbnVsbCwgdmlldzogY29udGV4dC52aWV3QXBpIHx8IGNvbnRleHQuY2FsZW5kYXJBcGkudmlldyB9KSk7XG59XG5mdW5jdGlvbiB0cmlnZ2VyRGF0ZVVuc2VsZWN0KHBldiwgY29udGV4dCkge1xuICAgIGNvbnRleHQuZW1pdHRlci50cmlnZ2VyKCd1bnNlbGVjdCcsIHtcbiAgICAgICAganNFdmVudDogcGV2ID8gcGV2Lm9yaWdFdmVudCA6IG51bGwsXG4gICAgICAgIHZpZXc6IGNvbnRleHQudmlld0FwaSB8fCBjb250ZXh0LmNhbGVuZGFyQXBpLnZpZXcsXG4gICAgfSk7XG59XG5mdW5jdGlvbiBidWlsZERhdGVTcGFuQXBpV2l0aENvbnRleHQoZGF0ZVNwYW4sIGNvbnRleHQpIHtcbiAgICBsZXQgcHJvcHMgPSB7fTtcbiAgICBmb3IgKGxldCB0cmFuc2Zvcm0gb2YgY29udGV4dC5wbHVnaW5Ib29rcy5kYXRlU3BhblRyYW5zZm9ybXMpIHtcbiAgICAgICAgT2JqZWN0LmFzc2lnbihwcm9wcywgdHJhbnNmb3JtKGRhdGVTcGFuLCBjb250ZXh0KSk7XG4gICAgfVxuICAgIE9iamVjdC5hc3NpZ24ocHJvcHMsIGJ1aWxkRGF0ZVNwYW5BcGkoZGF0ZVNwYW4sIGNvbnRleHQuZGF0ZUVudikpO1xuICAgIHJldHVybiBwcm9wcztcbn1cbi8vIEdpdmVuIGFuIGV2ZW50J3MgYWxsRGF5IHN0YXR1cyBhbmQgc3RhcnQgZGF0ZSwgcmV0dXJuIHdoYXQgaXRzIGZhbGxiYWNrIGVuZCBkYXRlIHNob3VsZCBiZS5cbi8vIFRPRE86IHJlbmFtZSB0byBjb21wdXRlRGVmYXVsdEV2ZW50RW5kXG5mdW5jdGlvbiBnZXREZWZhdWx0RXZlbnRFbmQoYWxsRGF5LCBtYXJrZXIsIGNvbnRleHQpIHtcbiAgICBsZXQgeyBkYXRlRW52LCBvcHRpb25zIH0gPSBjb250ZXh0O1xuICAgIGxldCBlbmQgPSBtYXJrZXI7XG4gICAgaWYgKGFsbERheSkge1xuICAgICAgICBlbmQgPSBzdGFydE9mRGF5KGVuZCk7XG4gICAgICAgIGVuZCA9IGRhdGVFbnYuYWRkKGVuZCwgb3B0aW9ucy5kZWZhdWx0QWxsRGF5RXZlbnREdXJhdGlvbik7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBlbmQgPSBkYXRlRW52LmFkZChlbmQsIG9wdGlvbnMuZGVmYXVsdFRpbWVkRXZlbnREdXJhdGlvbik7XG4gICAgfVxuICAgIHJldHVybiBlbmQ7XG59XG5cbi8vIGFwcGxpZXMgdGhlIG11dGF0aW9uIHRvIEFMTCBkZWZzL2luc3RhbmNlcyB3aXRoaW4gdGhlIGV2ZW50IHN0b3JlXG5mdW5jdGlvbiBhcHBseU11dGF0aW9uVG9FdmVudFN0b3JlKGV2ZW50U3RvcmUsIGV2ZW50Q29uZmlnQmFzZSwgbXV0YXRpb24sIGNvbnRleHQpIHtcbiAgICBsZXQgZXZlbnRDb25maWdzID0gY29tcGlsZUV2ZW50VWlzKGV2ZW50U3RvcmUuZGVmcywgZXZlbnRDb25maWdCYXNlKTtcbiAgICBsZXQgZGVzdCA9IGNyZWF0ZUVtcHR5RXZlbnRTdG9yZSgpO1xuICAgIGZvciAobGV0IGRlZklkIGluIGV2ZW50U3RvcmUuZGVmcykge1xuICAgICAgICBsZXQgZGVmID0gZXZlbnRTdG9yZS5kZWZzW2RlZklkXTtcbiAgICAgICAgZGVzdC5kZWZzW2RlZklkXSA9IGFwcGx5TXV0YXRpb25Ub0V2ZW50RGVmKGRlZiwgZXZlbnRDb25maWdzW2RlZklkXSwgbXV0YXRpb24sIGNvbnRleHQpO1xuICAgIH1cbiAgICBmb3IgKGxldCBpbnN0YW5jZUlkIGluIGV2ZW50U3RvcmUuaW5zdGFuY2VzKSB7XG4gICAgICAgIGxldCBpbnN0YW5jZSA9IGV2ZW50U3RvcmUuaW5zdGFuY2VzW2luc3RhbmNlSWRdO1xuICAgICAgICBsZXQgZGVmID0gZGVzdC5kZWZzW2luc3RhbmNlLmRlZklkXTsgLy8gaW1wb3J0YW50IHRvIGdyYWIgdGhlIG5ld2x5IG1vZGlmaWVkIGRlZlxuICAgICAgICBkZXN0Lmluc3RhbmNlc1tpbnN0YW5jZUlkXSA9IGFwcGx5TXV0YXRpb25Ub0V2ZW50SW5zdGFuY2UoaW5zdGFuY2UsIGRlZiwgZXZlbnRDb25maWdzW2luc3RhbmNlLmRlZklkXSwgbXV0YXRpb24sIGNvbnRleHQpO1xuICAgIH1cbiAgICByZXR1cm4gZGVzdDtcbn1cbmZ1bmN0aW9uIGFwcGx5TXV0YXRpb25Ub0V2ZW50RGVmKGV2ZW50RGVmLCBldmVudENvbmZpZywgbXV0YXRpb24sIGNvbnRleHQpIHtcbiAgICBsZXQgc3RhbmRhcmRQcm9wcyA9IG11dGF0aW9uLnN0YW5kYXJkUHJvcHMgfHwge307XG4gICAgLy8gaWYgaGFzRW5kIGhhcyBub3QgYmVlbiBzcGVjaWZpZWQsIGd1ZXNzIGEgZ29vZCB2YWx1ZSBiYXNlZCBvbiBkZWx0YXMuXG4gICAgLy8gaWYgZHVyYXRpb24gd2lsbCBjaGFuZ2UsIHRoZXJlJ3Mgbm8gd2F5IHRoZSBkZWZhdWx0IGR1cmF0aW9uIHdpbGwgcGVyc2lzdCxcbiAgICAvLyBhbmQgdGh1cywgd2UgbmVlZCB0byBtYXJrIHRoZSBldmVudCBhcyBoYXZpbmcgYSByZWFsIGVuZFxuICAgIGlmIChzdGFuZGFyZFByb3BzLmhhc0VuZCA9PSBudWxsICYmXG4gICAgICAgIGV2ZW50Q29uZmlnLmR1cmF0aW9uRWRpdGFibGUgJiZcbiAgICAgICAgKG11dGF0aW9uLnN0YXJ0RGVsdGEgfHwgbXV0YXRpb24uZW5kRGVsdGEpKSB7XG4gICAgICAgIHN0YW5kYXJkUHJvcHMuaGFzRW5kID0gdHJ1ZTsgLy8gVE9ETzogaXMgdGhpcyBtdXRhdGlvbiBva2F5P1xuICAgIH1cbiAgICBsZXQgY29weSA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBldmVudERlZiksIHN0YW5kYXJkUHJvcHMpLCB7IHVpOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGV2ZW50RGVmLnVpKSwgc3RhbmRhcmRQcm9wcy51aSkgfSk7XG4gICAgaWYgKG11dGF0aW9uLmV4dGVuZGVkUHJvcHMpIHtcbiAgICAgICAgY29weS5leHRlbmRlZFByb3BzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBjb3B5LmV4dGVuZGVkUHJvcHMpLCBtdXRhdGlvbi5leHRlbmRlZFByb3BzKTtcbiAgICB9XG4gICAgZm9yIChsZXQgYXBwbGllciBvZiBjb250ZXh0LnBsdWdpbkhvb2tzLmV2ZW50RGVmTXV0YXRpb25BcHBsaWVycykge1xuICAgICAgICBhcHBsaWVyKGNvcHksIG11dGF0aW9uLCBjb250ZXh0KTtcbiAgICB9XG4gICAgaWYgKCFjb3B5Lmhhc0VuZCAmJiBjb250ZXh0Lm9wdGlvbnMuZm9yY2VFdmVudER1cmF0aW9uKSB7XG4gICAgICAgIGNvcHkuaGFzRW5kID0gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGNvcHk7XG59XG5mdW5jdGlvbiBhcHBseU11dGF0aW9uVG9FdmVudEluc3RhbmNlKGV2ZW50SW5zdGFuY2UsIGV2ZW50RGVmLCAvLyBtdXN0IGZpcnN0IGJlIG1vZGlmaWVkIGJ5IGFwcGx5TXV0YXRpb25Ub0V2ZW50RGVmXG5ldmVudENvbmZpZywgbXV0YXRpb24sIGNvbnRleHQpIHtcbiAgICBsZXQgeyBkYXRlRW52IH0gPSBjb250ZXh0O1xuICAgIGxldCBmb3JjZUFsbERheSA9IG11dGF0aW9uLnN0YW5kYXJkUHJvcHMgJiYgbXV0YXRpb24uc3RhbmRhcmRQcm9wcy5hbGxEYXkgPT09IHRydWU7XG4gICAgbGV0IGNsZWFyRW5kID0gbXV0YXRpb24uc3RhbmRhcmRQcm9wcyAmJiBtdXRhdGlvbi5zdGFuZGFyZFByb3BzLmhhc0VuZCA9PT0gZmFsc2U7XG4gICAgbGV0IGNvcHkgPSBPYmplY3QuYXNzaWduKHt9LCBldmVudEluc3RhbmNlKTtcbiAgICBpZiAoZm9yY2VBbGxEYXkpIHtcbiAgICAgICAgY29weS5yYW5nZSA9IGNvbXB1dGVBbGlnbmVkRGF5UmFuZ2UoY29weS5yYW5nZSk7XG4gICAgfVxuICAgIGlmIChtdXRhdGlvbi5kYXRlc0RlbHRhICYmIGV2ZW50Q29uZmlnLnN0YXJ0RWRpdGFibGUpIHtcbiAgICAgICAgY29weS5yYW5nZSA9IHtcbiAgICAgICAgICAgIHN0YXJ0OiBkYXRlRW52LmFkZChjb3B5LnJhbmdlLnN0YXJ0LCBtdXRhdGlvbi5kYXRlc0RlbHRhKSxcbiAgICAgICAgICAgIGVuZDogZGF0ZUVudi5hZGQoY29weS5yYW5nZS5lbmQsIG11dGF0aW9uLmRhdGVzRGVsdGEpLFxuICAgICAgICB9O1xuICAgIH1cbiAgICBpZiAobXV0YXRpb24uc3RhcnREZWx0YSAmJiBldmVudENvbmZpZy5kdXJhdGlvbkVkaXRhYmxlKSB7XG4gICAgICAgIGNvcHkucmFuZ2UgPSB7XG4gICAgICAgICAgICBzdGFydDogZGF0ZUVudi5hZGQoY29weS5yYW5nZS5zdGFydCwgbXV0YXRpb24uc3RhcnREZWx0YSksXG4gICAgICAgICAgICBlbmQ6IGNvcHkucmFuZ2UuZW5kLFxuICAgICAgICB9O1xuICAgIH1cbiAgICBpZiAobXV0YXRpb24uZW5kRGVsdGEgJiYgZXZlbnRDb25maWcuZHVyYXRpb25FZGl0YWJsZSkge1xuICAgICAgICBjb3B5LnJhbmdlID0ge1xuICAgICAgICAgICAgc3RhcnQ6IGNvcHkucmFuZ2Uuc3RhcnQsXG4gICAgICAgICAgICBlbmQ6IGRhdGVFbnYuYWRkKGNvcHkucmFuZ2UuZW5kLCBtdXRhdGlvbi5lbmREZWx0YSksXG4gICAgICAgIH07XG4gICAgfVxuICAgIGlmIChjbGVhckVuZCkge1xuICAgICAgICBjb3B5LnJhbmdlID0ge1xuICAgICAgICAgICAgc3RhcnQ6IGNvcHkucmFuZ2Uuc3RhcnQsXG4gICAgICAgICAgICBlbmQ6IGdldERlZmF1bHRFdmVudEVuZChldmVudERlZi5hbGxEYXksIGNvcHkucmFuZ2Uuc3RhcnQsIGNvbnRleHQpLFxuICAgICAgICB9O1xuICAgIH1cbiAgICAvLyBpbiBjYXNlIGV2ZW50IHdhcyBhbGwtZGF5IGJ1dCB0aGUgc3VwcGxpZWQgZGVsdGFzIHdlcmUgbm90XG4gICAgLy8gYmV0dGVyIHV0aWwgZm9yIHRoaXM/XG4gICAgaWYgKGV2ZW50RGVmLmFsbERheSkge1xuICAgICAgICBjb3B5LnJhbmdlID0ge1xuICAgICAgICAgICAgc3RhcnQ6IHN0YXJ0T2ZEYXkoY29weS5yYW5nZS5zdGFydCksXG4gICAgICAgICAgICBlbmQ6IHN0YXJ0T2ZEYXkoY29weS5yYW5nZS5lbmQpLFxuICAgICAgICB9O1xuICAgIH1cbiAgICAvLyBoYW5kbGUgaW52YWxpZCBkdXJhdGlvbnNcbiAgICBpZiAoY29weS5yYW5nZS5lbmQgPCBjb3B5LnJhbmdlLnN0YXJ0KSB7XG4gICAgICAgIGNvcHkucmFuZ2UuZW5kID0gZ2V0RGVmYXVsdEV2ZW50RW5kKGV2ZW50RGVmLmFsbERheSwgY29weS5yYW5nZS5zdGFydCwgY29udGV4dCk7XG4gICAgfVxuICAgIHJldHVybiBjb3B5O1xufVxuXG5jbGFzcyBFdmVudFNvdXJjZUltcGwge1xuICAgIGNvbnN0cnVjdG9yKGNvbnRleHQsIGludGVybmFsRXZlbnRTb3VyY2UpIHtcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gY29udGV4dDtcbiAgICAgICAgdGhpcy5pbnRlcm5hbEV2ZW50U291cmNlID0gaW50ZXJuYWxFdmVudFNvdXJjZTtcbiAgICB9XG4gICAgcmVtb3ZlKCkge1xuICAgICAgICB0aGlzLmNvbnRleHQuZGlzcGF0Y2goe1xuICAgICAgICAgICAgdHlwZTogJ1JFTU9WRV9FVkVOVF9TT1VSQ0UnLFxuICAgICAgICAgICAgc291cmNlSWQ6IHRoaXMuaW50ZXJuYWxFdmVudFNvdXJjZS5zb3VyY2VJZCxcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIHJlZmV0Y2goKSB7XG4gICAgICAgIHRoaXMuY29udGV4dC5kaXNwYXRjaCh7XG4gICAgICAgICAgICB0eXBlOiAnRkVUQ0hfRVZFTlRfU09VUkNFUycsXG4gICAgICAgICAgICBzb3VyY2VJZHM6IFt0aGlzLmludGVybmFsRXZlbnRTb3VyY2Uuc291cmNlSWRdLFxuICAgICAgICAgICAgaXNSZWZldGNoOiB0cnVlLFxuICAgICAgICB9KTtcbiAgICB9XG4gICAgZ2V0IGlkKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5pbnRlcm5hbEV2ZW50U291cmNlLnB1YmxpY0lkO1xuICAgIH1cbiAgICBnZXQgdXJsKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5pbnRlcm5hbEV2ZW50U291cmNlLm1ldGEudXJsO1xuICAgIH1cbiAgICBnZXQgZm9ybWF0KCkge1xuICAgICAgICByZXR1cm4gdGhpcy5pbnRlcm5hbEV2ZW50U291cmNlLm1ldGEuZm9ybWF0OyAvLyBUT0RPOiBiYWQuIG5vdCBndWFyYW50ZWVkXG4gICAgfVxufVxuXG5jbGFzcyBFdmVudEltcGwge1xuICAgIC8vIGluc3RhbmNlIHdpbGwgYmUgbnVsbCBpZiBleHByZXNzaW5nIGEgcmVjdXJyaW5nIGV2ZW50IHRoYXQgaGFzIG5vIGN1cnJlbnQgaW5zdGFuY2VzLFxuICAgIC8vIE9SIGlmIHRyeWluZyB0byB2YWxpZGF0ZSBhbiBpbmNvbWluZyBleHRlcm5hbCBldmVudCB0aGF0IGhhcyBubyBkYXRlcyBhc3NpZ25lZFxuICAgIGNvbnN0cnVjdG9yKGNvbnRleHQsIGRlZiwgaW5zdGFuY2UpIHtcbiAgICAgICAgdGhpcy5fY29udGV4dCA9IGNvbnRleHQ7XG4gICAgICAgIHRoaXMuX2RlZiA9IGRlZjtcbiAgICAgICAgdGhpcy5faW5zdGFuY2UgPSBpbnN0YW5jZSB8fCBudWxsO1xuICAgIH1cbiAgICAvKlxuICAgIFRPRE86IG1ha2UgZXZlbnQgc3RydWN0IG1vcmUgcmVzcG9uc2libGUgZm9yIHRoaXNcbiAgICAqL1xuICAgIHNldFByb3AobmFtZSwgdmFsKSB7XG4gICAgICAgIGlmIChuYW1lIGluIEVWRU5UX0RBVEVfUkVGSU5FUlMpIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybignQ291bGQgbm90IHNldCBkYXRlLXJlbGF0ZWQgcHJvcCBcXCduYW1lXFwnLiBVc2Ugb25lIG9mIHRoZSBkYXRlLXJlbGF0ZWQgbWV0aG9kcyBpbnN0ZWFkLicpO1xuICAgICAgICAgICAgLy8gVE9ETzogbWFrZSBwcm9wZXIgYWxpYXNpbmcgc3lzdGVtP1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKG5hbWUgPT09ICdpZCcpIHtcbiAgICAgICAgICAgIHZhbCA9IEVWRU5UX05PTl9EQVRFX1JFRklORVJTW25hbWVdKHZhbCk7XG4gICAgICAgICAgICB0aGlzLm11dGF0ZSh7XG4gICAgICAgICAgICAgICAgc3RhbmRhcmRQcm9wczogeyBwdWJsaWNJZDogdmFsIH0sIC8vIGhhcmRjb2RlZCBpbnRlcm5hbCBuYW1lXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChuYW1lIGluIEVWRU5UX05PTl9EQVRFX1JFRklORVJTKSB7XG4gICAgICAgICAgICB2YWwgPSBFVkVOVF9OT05fREFURV9SRUZJTkVSU1tuYW1lXSh2YWwpO1xuICAgICAgICAgICAgdGhpcy5tdXRhdGUoe1xuICAgICAgICAgICAgICAgIHN0YW5kYXJkUHJvcHM6IHsgW25hbWVdOiB2YWwgfSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKG5hbWUgaW4gRVZFTlRfVUlfUkVGSU5FUlMpIHtcbiAgICAgICAgICAgIGxldCB1aSA9IEVWRU5UX1VJX1JFRklORVJTW25hbWVdKHZhbCk7XG4gICAgICAgICAgICBpZiAobmFtZSA9PT0gJ2NvbG9yJykge1xuICAgICAgICAgICAgICAgIHVpID0geyBiYWNrZ3JvdW5kQ29sb3I6IHZhbCwgYm9yZGVyQ29sb3I6IHZhbCB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAobmFtZSA9PT0gJ2VkaXRhYmxlJykge1xuICAgICAgICAgICAgICAgIHVpID0geyBzdGFydEVkaXRhYmxlOiB2YWwsIGR1cmF0aW9uRWRpdGFibGU6IHZhbCB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgdWkgPSB7IFtuYW1lXTogdmFsIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLm11dGF0ZSh7XG4gICAgICAgICAgICAgICAgc3RhbmRhcmRQcm9wczogeyB1aSB9LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oYENvdWxkIG5vdCBzZXQgcHJvcCAnJHtuYW1lfScuIFVzZSBzZXRFeHRlbmRlZFByb3AgaW5zdGVhZC5gKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBzZXRFeHRlbmRlZFByb3AobmFtZSwgdmFsKSB7XG4gICAgICAgIHRoaXMubXV0YXRlKHtcbiAgICAgICAgICAgIGV4dGVuZGVkUHJvcHM6IHsgW25hbWVdOiB2YWwgfSxcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIHNldFN0YXJ0KHN0YXJ0SW5wdXQsIG9wdGlvbnMgPSB7fSkge1xuICAgICAgICBsZXQgeyBkYXRlRW52IH0gPSB0aGlzLl9jb250ZXh0O1xuICAgICAgICBsZXQgc3RhcnQgPSBkYXRlRW52LmNyZWF0ZU1hcmtlcihzdGFydElucHV0KTtcbiAgICAgICAgaWYgKHN0YXJ0ICYmIHRoaXMuX2luc3RhbmNlKSB7IC8vIFRPRE86IHdhcm5pbmcgaWYgcGFyc2VkIGJhZFxuICAgICAgICAgICAgbGV0IGluc3RhbmNlUmFuZ2UgPSB0aGlzLl9pbnN0YW5jZS5yYW5nZTtcbiAgICAgICAgICAgIGxldCBzdGFydERlbHRhID0gZGlmZkRhdGVzKGluc3RhbmNlUmFuZ2Uuc3RhcnQsIHN0YXJ0LCBkYXRlRW52LCBvcHRpb25zLmdyYW51bGFyaXR5KTsgLy8gd2hhdCBpZiBwYXJzZWQgYmFkIT9cbiAgICAgICAgICAgIGlmIChvcHRpb25zLm1haW50YWluRHVyYXRpb24pIHtcbiAgICAgICAgICAgICAgICB0aGlzLm11dGF0ZSh7IGRhdGVzRGVsdGE6IHN0YXJ0RGVsdGEgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLm11dGF0ZSh7IHN0YXJ0RGVsdGEgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgc2V0RW5kKGVuZElucHV0LCBvcHRpb25zID0ge30pIHtcbiAgICAgICAgbGV0IHsgZGF0ZUVudiB9ID0gdGhpcy5fY29udGV4dDtcbiAgICAgICAgbGV0IGVuZDtcbiAgICAgICAgaWYgKGVuZElucHV0ICE9IG51bGwpIHtcbiAgICAgICAgICAgIGVuZCA9IGRhdGVFbnYuY3JlYXRlTWFya2VyKGVuZElucHV0KTtcbiAgICAgICAgICAgIGlmICghZW5kKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuOyAvLyBUT0RPOiB3YXJuaW5nIGlmIHBhcnNlZCBiYWRcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5faW5zdGFuY2UpIHtcbiAgICAgICAgICAgIGlmIChlbmQpIHtcbiAgICAgICAgICAgICAgICBsZXQgZW5kRGVsdGEgPSBkaWZmRGF0ZXModGhpcy5faW5zdGFuY2UucmFuZ2UuZW5kLCBlbmQsIGRhdGVFbnYsIG9wdGlvbnMuZ3JhbnVsYXJpdHkpO1xuICAgICAgICAgICAgICAgIHRoaXMubXV0YXRlKHsgZW5kRGVsdGEgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLm11dGF0ZSh7IHN0YW5kYXJkUHJvcHM6IHsgaGFzRW5kOiBmYWxzZSB9IH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIHNldERhdGVzKHN0YXJ0SW5wdXQsIGVuZElucHV0LCBvcHRpb25zID0ge30pIHtcbiAgICAgICAgbGV0IHsgZGF0ZUVudiB9ID0gdGhpcy5fY29udGV4dDtcbiAgICAgICAgbGV0IHN0YW5kYXJkUHJvcHMgPSB7IGFsbERheTogb3B0aW9ucy5hbGxEYXkgfTtcbiAgICAgICAgbGV0IHN0YXJ0ID0gZGF0ZUVudi5jcmVhdGVNYXJrZXIoc3RhcnRJbnB1dCk7XG4gICAgICAgIGxldCBlbmQ7XG4gICAgICAgIGlmICghc3RhcnQpIHtcbiAgICAgICAgICAgIHJldHVybjsgLy8gVE9ETzogd2FybmluZyBpZiBwYXJzZWQgYmFkXG4gICAgICAgIH1cbiAgICAgICAgaWYgKGVuZElucHV0ICE9IG51bGwpIHtcbiAgICAgICAgICAgIGVuZCA9IGRhdGVFbnYuY3JlYXRlTWFya2VyKGVuZElucHV0KTtcbiAgICAgICAgICAgIGlmICghZW5kKSB7IC8vIFRPRE86IHdhcm5pbmcgaWYgcGFyc2VkIGJhZFxuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5faW5zdGFuY2UpIHtcbiAgICAgICAgICAgIGxldCBpbnN0YW5jZVJhbmdlID0gdGhpcy5faW5zdGFuY2UucmFuZ2U7XG4gICAgICAgICAgICAvLyB3aGVuIGNvbXB1dGluZyB0aGUgZGlmZiBmb3IgYW4gZXZlbnQgYmVpbmcgY29udmVydGVkIHRvIGFsbC1kYXksXG4gICAgICAgICAgICAvLyBjb21wdXRlIGRpZmYgb2ZmIG9mIHRoZSBhbGwtZGF5IHZhbHVlcyB0aGUgd2F5IGV2ZW50LW11dGF0aW9uIGRvZXMuXG4gICAgICAgICAgICBpZiAob3B0aW9ucy5hbGxEYXkgPT09IHRydWUpIHtcbiAgICAgICAgICAgICAgICBpbnN0YW5jZVJhbmdlID0gY29tcHV0ZUFsaWduZWREYXlSYW5nZShpbnN0YW5jZVJhbmdlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCBzdGFydERlbHRhID0gZGlmZkRhdGVzKGluc3RhbmNlUmFuZ2Uuc3RhcnQsIHN0YXJ0LCBkYXRlRW52LCBvcHRpb25zLmdyYW51bGFyaXR5KTtcbiAgICAgICAgICAgIGlmIChlbmQpIHtcbiAgICAgICAgICAgICAgICBsZXQgZW5kRGVsdGEgPSBkaWZmRGF0ZXMoaW5zdGFuY2VSYW5nZS5lbmQsIGVuZCwgZGF0ZUVudiwgb3B0aW9ucy5ncmFudWxhcml0eSk7XG4gICAgICAgICAgICAgICAgaWYgKGR1cmF0aW9uc0VxdWFsKHN0YXJ0RGVsdGEsIGVuZERlbHRhKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm11dGF0ZSh7IGRhdGVzRGVsdGE6IHN0YXJ0RGVsdGEsIHN0YW5kYXJkUHJvcHMgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm11dGF0ZSh7IHN0YXJ0RGVsdGEsIGVuZERlbHRhLCBzdGFuZGFyZFByb3BzIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgeyAvLyBtZWFucyBcImNsZWFyIHRoZSBlbmRcIlxuICAgICAgICAgICAgICAgIHN0YW5kYXJkUHJvcHMuaGFzRW5kID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgdGhpcy5tdXRhdGUoeyBkYXRlc0RlbHRhOiBzdGFydERlbHRhLCBzdGFuZGFyZFByb3BzIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIG1vdmVTdGFydChkZWx0YUlucHV0KSB7XG4gICAgICAgIGxldCBkZWx0YSA9IGNyZWF0ZUR1cmF0aW9uKGRlbHRhSW5wdXQpO1xuICAgICAgICBpZiAoZGVsdGEpIHsgLy8gVE9ETzogd2FybmluZyBpZiBwYXJzZWQgYmFkXG4gICAgICAgICAgICB0aGlzLm11dGF0ZSh7IHN0YXJ0RGVsdGE6IGRlbHRhIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIG1vdmVFbmQoZGVsdGFJbnB1dCkge1xuICAgICAgICBsZXQgZGVsdGEgPSBjcmVhdGVEdXJhdGlvbihkZWx0YUlucHV0KTtcbiAgICAgICAgaWYgKGRlbHRhKSB7IC8vIFRPRE86IHdhcm5pbmcgaWYgcGFyc2VkIGJhZFxuICAgICAgICAgICAgdGhpcy5tdXRhdGUoeyBlbmREZWx0YTogZGVsdGEgfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgbW92ZURhdGVzKGRlbHRhSW5wdXQpIHtcbiAgICAgICAgbGV0IGRlbHRhID0gY3JlYXRlRHVyYXRpb24oZGVsdGFJbnB1dCk7XG4gICAgICAgIGlmIChkZWx0YSkgeyAvLyBUT0RPOiB3YXJuaW5nIGlmIHBhcnNlZCBiYWRcbiAgICAgICAgICAgIHRoaXMubXV0YXRlKHsgZGF0ZXNEZWx0YTogZGVsdGEgfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgc2V0QWxsRGF5KGFsbERheSwgb3B0aW9ucyA9IHt9KSB7XG4gICAgICAgIGxldCBzdGFuZGFyZFByb3BzID0geyBhbGxEYXkgfTtcbiAgICAgICAgbGV0IHsgbWFpbnRhaW5EdXJhdGlvbiB9ID0gb3B0aW9ucztcbiAgICAgICAgaWYgKG1haW50YWluRHVyYXRpb24gPT0gbnVsbCkge1xuICAgICAgICAgICAgbWFpbnRhaW5EdXJhdGlvbiA9IHRoaXMuX2NvbnRleHQub3B0aW9ucy5hbGxEYXlNYWludGFpbkR1cmF0aW9uO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLl9kZWYuYWxsRGF5ICE9PSBhbGxEYXkpIHtcbiAgICAgICAgICAgIHN0YW5kYXJkUHJvcHMuaGFzRW5kID0gbWFpbnRhaW5EdXJhdGlvbjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLm11dGF0ZSh7IHN0YW5kYXJkUHJvcHMgfSk7XG4gICAgfVxuICAgIGZvcm1hdFJhbmdlKGZvcm1hdElucHV0KSB7XG4gICAgICAgIGxldCB7IGRhdGVFbnYgfSA9IHRoaXMuX2NvbnRleHQ7XG4gICAgICAgIGxldCBpbnN0YW5jZSA9IHRoaXMuX2luc3RhbmNlO1xuICAgICAgICBsZXQgZm9ybWF0dGVyID0gY3JlYXRlRm9ybWF0dGVyKGZvcm1hdElucHV0KTtcbiAgICAgICAgaWYgKHRoaXMuX2RlZi5oYXNFbmQpIHtcbiAgICAgICAgICAgIHJldHVybiBkYXRlRW52LmZvcm1hdFJhbmdlKGluc3RhbmNlLnJhbmdlLnN0YXJ0LCBpbnN0YW5jZS5yYW5nZS5lbmQsIGZvcm1hdHRlciwge1xuICAgICAgICAgICAgICAgIGZvcmNlZFN0YXJ0VHpvOiBpbnN0YW5jZS5mb3JjZWRTdGFydFR6byxcbiAgICAgICAgICAgICAgICBmb3JjZWRFbmRUem86IGluc3RhbmNlLmZvcmNlZEVuZFR6byxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBkYXRlRW52LmZvcm1hdChpbnN0YW5jZS5yYW5nZS5zdGFydCwgZm9ybWF0dGVyLCB7XG4gICAgICAgICAgICBmb3JjZWRUem86IGluc3RhbmNlLmZvcmNlZFN0YXJ0VHpvLFxuICAgICAgICB9KTtcbiAgICB9XG4gICAgbXV0YXRlKG11dGF0aW9uKSB7XG4gICAgICAgIGxldCBpbnN0YW5jZSA9IHRoaXMuX2luc3RhbmNlO1xuICAgICAgICBpZiAoaW5zdGFuY2UpIHtcbiAgICAgICAgICAgIGxldCBkZWYgPSB0aGlzLl9kZWY7XG4gICAgICAgICAgICBsZXQgY29udGV4dCA9IHRoaXMuX2NvbnRleHQ7XG4gICAgICAgICAgICBsZXQgeyBldmVudFN0b3JlIH0gPSBjb250ZXh0LmdldEN1cnJlbnREYXRhKCk7XG4gICAgICAgICAgICBsZXQgcmVsZXZhbnRFdmVudHMgPSBnZXRSZWxldmFudEV2ZW50cyhldmVudFN0b3JlLCBpbnN0YW5jZS5pbnN0YW5jZUlkKTtcbiAgICAgICAgICAgIGxldCBldmVudENvbmZpZ0Jhc2UgPSB7XG4gICAgICAgICAgICAgICAgJyc6IHtcbiAgICAgICAgICAgICAgICAgICAgZGlzcGxheTogJycsXG4gICAgICAgICAgICAgICAgICAgIHN0YXJ0RWRpdGFibGU6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uRWRpdGFibGU6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0cmFpbnRzOiBbXSxcbiAgICAgICAgICAgICAgICAgICAgb3ZlcmxhcDogbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgYWxsb3dzOiBbXSxcbiAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZENvbG9yOiAnJyxcbiAgICAgICAgICAgICAgICAgICAgYm9yZGVyQ29sb3I6ICcnLFxuICAgICAgICAgICAgICAgICAgICB0ZXh0Q29sb3I6ICcnLFxuICAgICAgICAgICAgICAgICAgICBjbGFzc05hbWVzOiBbXSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJlbGV2YW50RXZlbnRzID0gYXBwbHlNdXRhdGlvblRvRXZlbnRTdG9yZShyZWxldmFudEV2ZW50cywgZXZlbnRDb25maWdCYXNlLCBtdXRhdGlvbiwgY29udGV4dCk7XG4gICAgICAgICAgICBsZXQgb2xkRXZlbnQgPSBuZXcgRXZlbnRJbXBsKGNvbnRleHQsIGRlZiwgaW5zdGFuY2UpOyAvLyBzbmFwc2hvdFxuICAgICAgICAgICAgdGhpcy5fZGVmID0gcmVsZXZhbnRFdmVudHMuZGVmc1tkZWYuZGVmSWRdO1xuICAgICAgICAgICAgdGhpcy5faW5zdGFuY2UgPSByZWxldmFudEV2ZW50cy5pbnN0YW5jZXNbaW5zdGFuY2UuaW5zdGFuY2VJZF07XG4gICAgICAgICAgICBjb250ZXh0LmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICB0eXBlOiAnTUVSR0VfRVZFTlRTJyxcbiAgICAgICAgICAgICAgICBldmVudFN0b3JlOiByZWxldmFudEV2ZW50cyxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY29udGV4dC5lbWl0dGVyLnRyaWdnZXIoJ2V2ZW50Q2hhbmdlJywge1xuICAgICAgICAgICAgICAgIG9sZEV2ZW50LFxuICAgICAgICAgICAgICAgIGV2ZW50OiB0aGlzLFxuICAgICAgICAgICAgICAgIHJlbGF0ZWRFdmVudHM6IGJ1aWxkRXZlbnRBcGlzKHJlbGV2YW50RXZlbnRzLCBjb250ZXh0LCBpbnN0YW5jZSksXG4gICAgICAgICAgICAgICAgcmV2ZXJ0KCkge1xuICAgICAgICAgICAgICAgICAgICBjb250ZXh0LmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdSRVNFVF9FVkVOVFMnLFxuICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRTdG9yZSwgLy8gdGhlIE9SSUdJTkFMIHN0b3JlXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZW1vdmUoKSB7XG4gICAgICAgIGxldCBjb250ZXh0ID0gdGhpcy5fY29udGV4dDtcbiAgICAgICAgbGV0IGFzU3RvcmUgPSBldmVudEFwaVRvU3RvcmUodGhpcyk7XG4gICAgICAgIGNvbnRleHQuZGlzcGF0Y2goe1xuICAgICAgICAgICAgdHlwZTogJ1JFTU9WRV9FVkVOVFMnLFxuICAgICAgICAgICAgZXZlbnRTdG9yZTogYXNTdG9yZSxcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnRleHQuZW1pdHRlci50cmlnZ2VyKCdldmVudFJlbW92ZScsIHtcbiAgICAgICAgICAgIGV2ZW50OiB0aGlzLFxuICAgICAgICAgICAgcmVsYXRlZEV2ZW50czogW10sXG4gICAgICAgICAgICByZXZlcnQoKSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdNRVJHRV9FVkVOVFMnLFxuICAgICAgICAgICAgICAgICAgICBldmVudFN0b3JlOiBhc1N0b3JlLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGdldCBzb3VyY2UoKSB7XG4gICAgICAgIGxldCB7IHNvdXJjZUlkIH0gPSB0aGlzLl9kZWY7XG4gICAgICAgIGlmIChzb3VyY2VJZCkge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBFdmVudFNvdXJjZUltcGwodGhpcy5fY29udGV4dCwgdGhpcy5fY29udGV4dC5nZXRDdXJyZW50RGF0YSgpLmV2ZW50U291cmNlc1tzb3VyY2VJZF0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBnZXQgc3RhcnQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9pbnN0YW5jZSA/XG4gICAgICAgICAgICB0aGlzLl9jb250ZXh0LmRhdGVFbnYudG9EYXRlKHRoaXMuX2luc3RhbmNlLnJhbmdlLnN0YXJ0KSA6XG4gICAgICAgICAgICBudWxsO1xuICAgIH1cbiAgICBnZXQgZW5kKCkge1xuICAgICAgICByZXR1cm4gKHRoaXMuX2luc3RhbmNlICYmIHRoaXMuX2RlZi5oYXNFbmQpID9cbiAgICAgICAgICAgIHRoaXMuX2NvbnRleHQuZGF0ZUVudi50b0RhdGUodGhpcy5faW5zdGFuY2UucmFuZ2UuZW5kKSA6XG4gICAgICAgICAgICBudWxsO1xuICAgIH1cbiAgICBnZXQgc3RhcnRTdHIoKSB7XG4gICAgICAgIGxldCBpbnN0YW5jZSA9IHRoaXMuX2luc3RhbmNlO1xuICAgICAgICBpZiAoaW5zdGFuY2UpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9jb250ZXh0LmRhdGVFbnYuZm9ybWF0SXNvKGluc3RhbmNlLnJhbmdlLnN0YXJ0LCB7XG4gICAgICAgICAgICAgICAgb21pdFRpbWU6IHRoaXMuX2RlZi5hbGxEYXksXG4gICAgICAgICAgICAgICAgZm9yY2VkVHpvOiBpbnN0YW5jZS5mb3JjZWRTdGFydFR6byxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9XG4gICAgZ2V0IGVuZFN0cigpIHtcbiAgICAgICAgbGV0IGluc3RhbmNlID0gdGhpcy5faW5zdGFuY2U7XG4gICAgICAgIGlmIChpbnN0YW5jZSAmJiB0aGlzLl9kZWYuaGFzRW5kKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fY29udGV4dC5kYXRlRW52LmZvcm1hdElzbyhpbnN0YW5jZS5yYW5nZS5lbmQsIHtcbiAgICAgICAgICAgICAgICBvbWl0VGltZTogdGhpcy5fZGVmLmFsbERheSxcbiAgICAgICAgICAgICAgICBmb3JjZWRUem86IGluc3RhbmNlLmZvcmNlZEVuZFR6byxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9XG4gICAgLy8gY29tcHV0YWJsZSBwcm9wcyB0aGF0IGFsbCBhY2Nlc3MgdGhlIGRlZlxuICAgIC8vIFRPRE86IGZpbmQgYSBUeXBlU2NyaXB0LWNvbXBhdGlibGUgd2F5IHRvIGRvIHRoaXMgYXQgc2NhbGVcbiAgICBnZXQgaWQoKSB7IHJldHVybiB0aGlzLl9kZWYucHVibGljSWQ7IH1cbiAgICBnZXQgZ3JvdXBJZCgpIHsgcmV0dXJuIHRoaXMuX2RlZi5ncm91cElkOyB9XG4gICAgZ2V0IGFsbERheSgpIHsgcmV0dXJuIHRoaXMuX2RlZi5hbGxEYXk7IH1cbiAgICBnZXQgdGl0bGUoKSB7IHJldHVybiB0aGlzLl9kZWYudGl0bGU7IH1cbiAgICBnZXQgdXJsKCkgeyByZXR1cm4gdGhpcy5fZGVmLnVybDsgfVxuICAgIGdldCBkaXNwbGF5KCkgeyByZXR1cm4gdGhpcy5fZGVmLnVpLmRpc3BsYXkgfHwgJ2F1dG8nOyB9IC8vIGJhZC4ganVzdCBub3JtYWxpemUgdGhlIHR5cGUgZWFybGllclxuICAgIGdldCBzdGFydEVkaXRhYmxlKCkgeyByZXR1cm4gdGhpcy5fZGVmLnVpLnN0YXJ0RWRpdGFibGU7IH1cbiAgICBnZXQgZHVyYXRpb25FZGl0YWJsZSgpIHsgcmV0dXJuIHRoaXMuX2RlZi51aS5kdXJhdGlvbkVkaXRhYmxlOyB9XG4gICAgZ2V0IGNvbnN0cmFpbnQoKSB7IHJldHVybiB0aGlzLl9kZWYudWkuY29uc3RyYWludHNbMF0gfHwgbnVsbDsgfVxuICAgIGdldCBvdmVybGFwKCkgeyByZXR1cm4gdGhpcy5fZGVmLnVpLm92ZXJsYXA7IH1cbiAgICBnZXQgYWxsb3coKSB7IHJldHVybiB0aGlzLl9kZWYudWkuYWxsb3dzWzBdIHx8IG51bGw7IH1cbiAgICBnZXQgYmFja2dyb3VuZENvbG9yKCkgeyByZXR1cm4gdGhpcy5fZGVmLnVpLmJhY2tncm91bmRDb2xvcjsgfVxuICAgIGdldCBib3JkZXJDb2xvcigpIHsgcmV0dXJuIHRoaXMuX2RlZi51aS5ib3JkZXJDb2xvcjsgfVxuICAgIGdldCB0ZXh0Q29sb3IoKSB7IHJldHVybiB0aGlzLl9kZWYudWkudGV4dENvbG9yOyB9XG4gICAgLy8gTk9URTogdXNlciBjYW4ndCBtb2RpZnkgdGhlc2UgYmVjYXVzZSBPYmplY3QuZnJlZXplIHdhcyBjYWxsZWQgaW4gZXZlbnQtZGVmIHBhcnNpbmdcbiAgICBnZXQgY2xhc3NOYW1lcygpIHsgcmV0dXJuIHRoaXMuX2RlZi51aS5jbGFzc05hbWVzOyB9XG4gICAgZ2V0IGV4dGVuZGVkUHJvcHMoKSB7IHJldHVybiB0aGlzLl9kZWYuZXh0ZW5kZWRQcm9wczsgfVxuICAgIHRvUGxhaW5PYmplY3Qoc2V0dGluZ3MgPSB7fSkge1xuICAgICAgICBsZXQgZGVmID0gdGhpcy5fZGVmO1xuICAgICAgICBsZXQgeyB1aSB9ID0gZGVmO1xuICAgICAgICBsZXQgeyBzdGFydFN0ciwgZW5kU3RyIH0gPSB0aGlzO1xuICAgICAgICBsZXQgcmVzID0ge1xuICAgICAgICAgICAgYWxsRGF5OiBkZWYuYWxsRGF5LFxuICAgICAgICB9O1xuICAgICAgICBpZiAoZGVmLnRpdGxlKSB7XG4gICAgICAgICAgICByZXMudGl0bGUgPSBkZWYudGl0bGU7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHN0YXJ0U3RyKSB7XG4gICAgICAgICAgICByZXMuc3RhcnQgPSBzdGFydFN0cjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZW5kU3RyKSB7XG4gICAgICAgICAgICByZXMuZW5kID0gZW5kU3RyO1xuICAgICAgICB9XG4gICAgICAgIGlmIChkZWYucHVibGljSWQpIHtcbiAgICAgICAgICAgIHJlcy5pZCA9IGRlZi5wdWJsaWNJZDtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZGVmLmdyb3VwSWQpIHtcbiAgICAgICAgICAgIHJlcy5ncm91cElkID0gZGVmLmdyb3VwSWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGRlZi51cmwpIHtcbiAgICAgICAgICAgIHJlcy51cmwgPSBkZWYudXJsO1xuICAgICAgICB9XG4gICAgICAgIGlmICh1aS5kaXNwbGF5ICYmIHVpLmRpc3BsYXkgIT09ICdhdXRvJykge1xuICAgICAgICAgICAgcmVzLmRpc3BsYXkgPSB1aS5kaXNwbGF5O1xuICAgICAgICB9XG4gICAgICAgIC8vIFRPRE86IHdoYXQgYWJvdXQgcmVjdXJyaW5nLWV2ZW50IHByb3BlcnRpZXM/Pz9cbiAgICAgICAgLy8gVE9ETzogaW5jbHVkZSBzdGFydEVkaXRhYmxlL2R1cmF0aW9uRWRpdGFibGUvY29uc3RyYWludC9vdmVybGFwL2FsbG93XG4gICAgICAgIGlmIChzZXR0aW5ncy5jb2xsYXBzZUNvbG9yICYmIHVpLmJhY2tncm91bmRDb2xvciAmJiB1aS5iYWNrZ3JvdW5kQ29sb3IgPT09IHVpLmJvcmRlckNvbG9yKSB7XG4gICAgICAgICAgICByZXMuY29sb3IgPSB1aS5iYWNrZ3JvdW5kQ29sb3I7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBpZiAodWkuYmFja2dyb3VuZENvbG9yKSB7XG4gICAgICAgICAgICAgICAgcmVzLmJhY2tncm91bmRDb2xvciA9IHVpLmJhY2tncm91bmRDb2xvcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh1aS5ib3JkZXJDb2xvcikge1xuICAgICAgICAgICAgICAgIHJlcy5ib3JkZXJDb2xvciA9IHVpLmJvcmRlckNvbG9yO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICh1aS50ZXh0Q29sb3IpIHtcbiAgICAgICAgICAgIHJlcy50ZXh0Q29sb3IgPSB1aS50ZXh0Q29sb3I7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHVpLmNsYXNzTmFtZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXMuY2xhc3NOYW1lcyA9IHVpLmNsYXNzTmFtZXM7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKE9iamVjdC5rZXlzKGRlZi5leHRlbmRlZFByb3BzKS5sZW5ndGgpIHtcbiAgICAgICAgICAgIGlmIChzZXR0aW5ncy5jb2xsYXBzZUV4dGVuZGVkUHJvcHMpIHtcbiAgICAgICAgICAgICAgICBPYmplY3QuYXNzaWduKHJlcywgZGVmLmV4dGVuZGVkUHJvcHMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgcmVzLmV4dGVuZGVkUHJvcHMgPSBkZWYuZXh0ZW5kZWRQcm9wcztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH1cbiAgICB0b0pTT04oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnRvUGxhaW5PYmplY3QoKTtcbiAgICB9XG59XG5mdW5jdGlvbiBldmVudEFwaVRvU3RvcmUoZXZlbnRBcGkpIHtcbiAgICBsZXQgZGVmID0gZXZlbnRBcGkuX2RlZjtcbiAgICBsZXQgaW5zdGFuY2UgPSBldmVudEFwaS5faW5zdGFuY2U7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgZGVmczogeyBbZGVmLmRlZklkXTogZGVmIH0sXG4gICAgICAgIGluc3RhbmNlczogaW5zdGFuY2VcbiAgICAgICAgICAgID8geyBbaW5zdGFuY2UuaW5zdGFuY2VJZF06IGluc3RhbmNlIH1cbiAgICAgICAgICAgIDoge30sXG4gICAgfTtcbn1cbmZ1bmN0aW9uIGJ1aWxkRXZlbnRBcGlzKGV2ZW50U3RvcmUsIGNvbnRleHQsIGV4Y2x1ZGVJbnN0YW5jZSkge1xuICAgIGxldCB7IGRlZnMsIGluc3RhbmNlcyB9ID0gZXZlbnRTdG9yZTtcbiAgICBsZXQgZXZlbnRBcGlzID0gW107XG4gICAgbGV0IGV4Y2x1ZGVJbnN0YW5jZUlkID0gZXhjbHVkZUluc3RhbmNlID8gZXhjbHVkZUluc3RhbmNlLmluc3RhbmNlSWQgOiAnJztcbiAgICBmb3IgKGxldCBpZCBpbiBpbnN0YW5jZXMpIHtcbiAgICAgICAgbGV0IGluc3RhbmNlID0gaW5zdGFuY2VzW2lkXTtcbiAgICAgICAgbGV0IGRlZiA9IGRlZnNbaW5zdGFuY2UuZGVmSWRdO1xuICAgICAgICBpZiAoaW5zdGFuY2UuaW5zdGFuY2VJZCAhPT0gZXhjbHVkZUluc3RhbmNlSWQpIHtcbiAgICAgICAgICAgIGV2ZW50QXBpcy5wdXNoKG5ldyBFdmVudEltcGwoY29udGV4dCwgZGVmLCBpbnN0YW5jZSkpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBldmVudEFwaXM7XG59XG5cbi8qXG5TcGVjaWZ5aW5nIG5leHREYXlUaHJlc2hvbGQgc2lnbmFscyB0aGF0IGFsbC1kYXkgcmFuZ2VzIHNob3VsZCBiZSBzbGljZWQuXG4qL1xuZnVuY3Rpb24gc2xpY2VFdmVudFN0b3JlKGV2ZW50U3RvcmUsIGV2ZW50VWlCYXNlcywgZnJhbWluZ1JhbmdlLCBuZXh0RGF5VGhyZXNob2xkKSB7XG4gICAgbGV0IGludmVyc2VCZ0J5R3JvdXBJZCA9IHt9O1xuICAgIGxldCBpbnZlcnNlQmdCeURlZklkID0ge307XG4gICAgbGV0IGRlZkJ5R3JvdXBJZCA9IHt9O1xuICAgIGxldCBiZ1JhbmdlcyA9IFtdO1xuICAgIGxldCBmZ1JhbmdlcyA9IFtdO1xuICAgIGxldCBldmVudFVpcyA9IGNvbXBpbGVFdmVudFVpcyhldmVudFN0b3JlLmRlZnMsIGV2ZW50VWlCYXNlcyk7XG4gICAgZm9yIChsZXQgZGVmSWQgaW4gZXZlbnRTdG9yZS5kZWZzKSB7XG4gICAgICAgIGxldCBkZWYgPSBldmVudFN0b3JlLmRlZnNbZGVmSWRdO1xuICAgICAgICBsZXQgdWkgPSBldmVudFVpc1tkZWYuZGVmSWRdO1xuICAgICAgICBpZiAodWkuZGlzcGxheSA9PT0gJ2ludmVyc2UtYmFja2dyb3VuZCcpIHtcbiAgICAgICAgICAgIGlmIChkZWYuZ3JvdXBJZCkge1xuICAgICAgICAgICAgICAgIGludmVyc2VCZ0J5R3JvdXBJZFtkZWYuZ3JvdXBJZF0gPSBbXTtcbiAgICAgICAgICAgICAgICBpZiAoIWRlZkJ5R3JvdXBJZFtkZWYuZ3JvdXBJZF0pIHtcbiAgICAgICAgICAgICAgICAgICAgZGVmQnlHcm91cElkW2RlZi5ncm91cElkXSA9IGRlZjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBpbnZlcnNlQmdCeURlZklkW2RlZklkXSA9IFtdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIGZvciAobGV0IGluc3RhbmNlSWQgaW4gZXZlbnRTdG9yZS5pbnN0YW5jZXMpIHtcbiAgICAgICAgbGV0IGluc3RhbmNlID0gZXZlbnRTdG9yZS5pbnN0YW5jZXNbaW5zdGFuY2VJZF07XG4gICAgICAgIGxldCBkZWYgPSBldmVudFN0b3JlLmRlZnNbaW5zdGFuY2UuZGVmSWRdO1xuICAgICAgICBsZXQgdWkgPSBldmVudFVpc1tkZWYuZGVmSWRdO1xuICAgICAgICBsZXQgb3JpZ1JhbmdlID0gaW5zdGFuY2UucmFuZ2U7XG4gICAgICAgIGxldCBub3JtYWxSYW5nZSA9ICghZGVmLmFsbERheSAmJiBuZXh0RGF5VGhyZXNob2xkKSA/XG4gICAgICAgICAgICBjb21wdXRlVmlzaWJsZURheVJhbmdlKG9yaWdSYW5nZSwgbmV4dERheVRocmVzaG9sZCkgOlxuICAgICAgICAgICAgb3JpZ1JhbmdlO1xuICAgICAgICBsZXQgc2xpY2VkUmFuZ2UgPSBpbnRlcnNlY3RSYW5nZXMobm9ybWFsUmFuZ2UsIGZyYW1pbmdSYW5nZSk7XG4gICAgICAgIGlmIChzbGljZWRSYW5nZSkge1xuICAgICAgICAgICAgaWYgKHVpLmRpc3BsYXkgPT09ICdpbnZlcnNlLWJhY2tncm91bmQnKSB7XG4gICAgICAgICAgICAgICAgaWYgKGRlZi5ncm91cElkKSB7XG4gICAgICAgICAgICAgICAgICAgIGludmVyc2VCZ0J5R3JvdXBJZFtkZWYuZ3JvdXBJZF0ucHVzaChzbGljZWRSYW5nZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBpbnZlcnNlQmdCeURlZklkW2luc3RhbmNlLmRlZklkXS5wdXNoKHNsaWNlZFJhbmdlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICh1aS5kaXNwbGF5ICE9PSAnbm9uZScpIHtcbiAgICAgICAgICAgICAgICAodWkuZGlzcGxheSA9PT0gJ2JhY2tncm91bmQnID8gYmdSYW5nZXMgOiBmZ1JhbmdlcykucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIGRlZixcbiAgICAgICAgICAgICAgICAgICAgdWksXG4gICAgICAgICAgICAgICAgICAgIGluc3RhbmNlLFxuICAgICAgICAgICAgICAgICAgICByYW5nZTogc2xpY2VkUmFuZ2UsXG4gICAgICAgICAgICAgICAgICAgIGlzU3RhcnQ6IG5vcm1hbFJhbmdlLnN0YXJ0ICYmIG5vcm1hbFJhbmdlLnN0YXJ0LnZhbHVlT2YoKSA9PT0gc2xpY2VkUmFuZ2Uuc3RhcnQudmFsdWVPZigpLFxuICAgICAgICAgICAgICAgICAgICBpc0VuZDogbm9ybWFsUmFuZ2UuZW5kICYmIG5vcm1hbFJhbmdlLmVuZC52YWx1ZU9mKCkgPT09IHNsaWNlZFJhbmdlLmVuZC52YWx1ZU9mKCksXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgZm9yIChsZXQgZ3JvdXBJZCBpbiBpbnZlcnNlQmdCeUdyb3VwSWQpIHsgLy8gQlkgR1JPVVBcbiAgICAgICAgbGV0IHJhbmdlcyA9IGludmVyc2VCZ0J5R3JvdXBJZFtncm91cElkXTtcbiAgICAgICAgbGV0IGludmVydGVkUmFuZ2VzID0gaW52ZXJ0UmFuZ2VzKHJhbmdlcywgZnJhbWluZ1JhbmdlKTtcbiAgICAgICAgZm9yIChsZXQgaW52ZXJ0ZWRSYW5nZSBvZiBpbnZlcnRlZFJhbmdlcykge1xuICAgICAgICAgICAgbGV0IGRlZiA9IGRlZkJ5R3JvdXBJZFtncm91cElkXTtcbiAgICAgICAgICAgIGxldCB1aSA9IGV2ZW50VWlzW2RlZi5kZWZJZF07XG4gICAgICAgICAgICBiZ1Jhbmdlcy5wdXNoKHtcbiAgICAgICAgICAgICAgICBkZWYsXG4gICAgICAgICAgICAgICAgdWksXG4gICAgICAgICAgICAgICAgaW5zdGFuY2U6IG51bGwsXG4gICAgICAgICAgICAgICAgcmFuZ2U6IGludmVydGVkUmFuZ2UsXG4gICAgICAgICAgICAgICAgaXNTdGFydDogZmFsc2UsXG4gICAgICAgICAgICAgICAgaXNFbmQ6IGZhbHNlLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZm9yIChsZXQgZGVmSWQgaW4gaW52ZXJzZUJnQnlEZWZJZCkge1xuICAgICAgICBsZXQgcmFuZ2VzID0gaW52ZXJzZUJnQnlEZWZJZFtkZWZJZF07XG4gICAgICAgIGxldCBpbnZlcnRlZFJhbmdlcyA9IGludmVydFJhbmdlcyhyYW5nZXMsIGZyYW1pbmdSYW5nZSk7XG4gICAgICAgIGZvciAobGV0IGludmVydGVkUmFuZ2Ugb2YgaW52ZXJ0ZWRSYW5nZXMpIHtcbiAgICAgICAgICAgIGJnUmFuZ2VzLnB1c2goe1xuICAgICAgICAgICAgICAgIGRlZjogZXZlbnRTdG9yZS5kZWZzW2RlZklkXSxcbiAgICAgICAgICAgICAgICB1aTogZXZlbnRVaXNbZGVmSWRdLFxuICAgICAgICAgICAgICAgIGluc3RhbmNlOiBudWxsLFxuICAgICAgICAgICAgICAgIHJhbmdlOiBpbnZlcnRlZFJhbmdlLFxuICAgICAgICAgICAgICAgIGlzU3RhcnQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGlzRW5kOiBmYWxzZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB7IGJnOiBiZ1JhbmdlcywgZmc6IGZnUmFuZ2VzIH07XG59XG5mdW5jdGlvbiBoYXNCZ1JlbmRlcmluZyhkZWYpIHtcbiAgICByZXR1cm4gZGVmLnVpLmRpc3BsYXkgPT09ICdiYWNrZ3JvdW5kJyB8fCBkZWYudWkuZGlzcGxheSA9PT0gJ2ludmVyc2UtYmFja2dyb3VuZCc7XG59XG5mdW5jdGlvbiBzZXRFbFNlZyhlbCwgc2VnKSB7XG4gICAgZWwuZmNTZWcgPSBzZWc7XG59XG5mdW5jdGlvbiBnZXRFbFNlZyhlbCkge1xuICAgIHJldHVybiBlbC5mY1NlZyB8fFxuICAgICAgICBlbC5wYXJlbnROb2RlLmZjU2VnIHx8IC8vIGZvciB0aGUgaGFybmVzc1xuICAgICAgICBudWxsO1xufVxuLy8gZXZlbnQgdWkgY29tcHV0YXRpb25cbmZ1bmN0aW9uIGNvbXBpbGVFdmVudFVpcyhldmVudERlZnMsIGV2ZW50VWlCYXNlcykge1xuICAgIHJldHVybiBtYXBIYXNoKGV2ZW50RGVmcywgKGV2ZW50RGVmKSA9PiBjb21waWxlRXZlbnRVaShldmVudERlZiwgZXZlbnRVaUJhc2VzKSk7XG59XG5mdW5jdGlvbiBjb21waWxlRXZlbnRVaShldmVudERlZiwgZXZlbnRVaUJhc2VzKSB7XG4gICAgbGV0IHVpcyA9IFtdO1xuICAgIGlmIChldmVudFVpQmFzZXNbJyddKSB7XG4gICAgICAgIHVpcy5wdXNoKGV2ZW50VWlCYXNlc1snJ10pO1xuICAgIH1cbiAgICBpZiAoZXZlbnRVaUJhc2VzW2V2ZW50RGVmLmRlZklkXSkge1xuICAgICAgICB1aXMucHVzaChldmVudFVpQmFzZXNbZXZlbnREZWYuZGVmSWRdKTtcbiAgICB9XG4gICAgdWlzLnB1c2goZXZlbnREZWYudWkpO1xuICAgIHJldHVybiBjb21iaW5lRXZlbnRVaXModWlzKTtcbn1cbmZ1bmN0aW9uIHNvcnRFdmVudFNlZ3Moc2VncywgZXZlbnRPcmRlclNwZWNzKSB7XG4gICAgbGV0IG9ianMgPSBzZWdzLm1hcChidWlsZFNlZ0NvbXBhcmVPYmopO1xuICAgIG9ianMuc29ydCgob2JqMCwgb2JqMSkgPT4gY29tcGFyZUJ5RmllbGRTcGVjcyhvYmowLCBvYmoxLCBldmVudE9yZGVyU3BlY3MpKTtcbiAgICByZXR1cm4gb2Jqcy5tYXAoKGMpID0+IGMuX3NlZyk7XG59XG4vLyByZXR1cm5zIGEgb2JqZWN0IHdpdGggYWxsIHByaW1pdGl2ZSBwcm9wcyB0aGF0IGNhbiBiZSBjb21wYXJlZFxuZnVuY3Rpb24gYnVpbGRTZWdDb21wYXJlT2JqKHNlZykge1xuICAgIGxldCB7IGV2ZW50UmFuZ2UgfSA9IHNlZztcbiAgICBsZXQgZXZlbnREZWYgPSBldmVudFJhbmdlLmRlZjtcbiAgICBsZXQgcmFuZ2UgPSBldmVudFJhbmdlLmluc3RhbmNlID8gZXZlbnRSYW5nZS5pbnN0YW5jZS5yYW5nZSA6IGV2ZW50UmFuZ2UucmFuZ2U7XG4gICAgbGV0IHN0YXJ0ID0gcmFuZ2Uuc3RhcnQgPyByYW5nZS5zdGFydC52YWx1ZU9mKCkgOiAwOyAvLyBUT0RPOiBiZXR0ZXIgc3VwcG9ydCBmb3Igb3Blbi1yYW5nZSBldmVudHNcbiAgICBsZXQgZW5kID0gcmFuZ2UuZW5kID8gcmFuZ2UuZW5kLnZhbHVlT2YoKSA6IDA7IC8vIFwiXG4gICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBldmVudERlZi5leHRlbmRlZFByb3BzKSwgZXZlbnREZWYpLCB7IGlkOiBldmVudERlZi5wdWJsaWNJZCwgc3RhcnQsXG4gICAgICAgIGVuZCwgZHVyYXRpb246IGVuZCAtIHN0YXJ0LCBhbGxEYXk6IE51bWJlcihldmVudERlZi5hbGxEYXkpLCBfc2VnOiBzZWcgfSk7XG59XG5mdW5jdGlvbiBjb21wdXRlU2VnRHJhZ2dhYmxlKHNlZywgY29udGV4dCkge1xuICAgIGxldCB7IHBsdWdpbkhvb2tzIH0gPSBjb250ZXh0O1xuICAgIGxldCB0cmFuc2Zvcm1lcnMgPSBwbHVnaW5Ib29rcy5pc0RyYWdnYWJsZVRyYW5zZm9ybWVycztcbiAgICBsZXQgeyBkZWYsIHVpIH0gPSBzZWcuZXZlbnRSYW5nZTtcbiAgICBsZXQgdmFsID0gdWkuc3RhcnRFZGl0YWJsZTtcbiAgICBmb3IgKGxldCB0cmFuc2Zvcm1lciBvZiB0cmFuc2Zvcm1lcnMpIHtcbiAgICAgICAgdmFsID0gdHJhbnNmb3JtZXIodmFsLCBkZWYsIHVpLCBjb250ZXh0KTtcbiAgICB9XG4gICAgcmV0dXJuIHZhbDtcbn1cbmZ1bmN0aW9uIGNvbXB1dGVTZWdTdGFydFJlc2l6YWJsZShzZWcsIGNvbnRleHQpIHtcbiAgICByZXR1cm4gc2VnLmlzU3RhcnQgJiYgc2VnLmV2ZW50UmFuZ2UudWkuZHVyYXRpb25FZGl0YWJsZSAmJiBjb250ZXh0Lm9wdGlvbnMuZXZlbnRSZXNpemFibGVGcm9tU3RhcnQ7XG59XG5mdW5jdGlvbiBjb21wdXRlU2VnRW5kUmVzaXphYmxlKHNlZywgY29udGV4dCkge1xuICAgIHJldHVybiBzZWcuaXNFbmQgJiYgc2VnLmV2ZW50UmFuZ2UudWkuZHVyYXRpb25FZGl0YWJsZTtcbn1cbmZ1bmN0aW9uIGJ1aWxkU2VnVGltZVRleHQoc2VnLCB0aW1lRm9ybWF0LCBjb250ZXh0LCBkZWZhdWx0RGlzcGxheUV2ZW50VGltZSwgLy8gZGVmYXVsdHMgdG8gdHJ1ZVxuZGVmYXVsdERpc3BsYXlFdmVudEVuZCwgLy8gZGVmYXVsdHMgdG8gdHJ1ZVxuc3RhcnRPdmVycmlkZSwgZW5kT3ZlcnJpZGUpIHtcbiAgICBsZXQgeyBkYXRlRW52LCBvcHRpb25zIH0gPSBjb250ZXh0O1xuICAgIGxldCB7IGRpc3BsYXlFdmVudFRpbWUsIGRpc3BsYXlFdmVudEVuZCB9ID0gb3B0aW9ucztcbiAgICBsZXQgZXZlbnREZWYgPSBzZWcuZXZlbnRSYW5nZS5kZWY7XG4gICAgbGV0IGV2ZW50SW5zdGFuY2UgPSBzZWcuZXZlbnRSYW5nZS5pbnN0YW5jZTtcbiAgICBpZiAoZGlzcGxheUV2ZW50VGltZSA9PSBudWxsKSB7XG4gICAgICAgIGRpc3BsYXlFdmVudFRpbWUgPSBkZWZhdWx0RGlzcGxheUV2ZW50VGltZSAhPT0gZmFsc2U7XG4gICAgfVxuICAgIGlmIChkaXNwbGF5RXZlbnRFbmQgPT0gbnVsbCkge1xuICAgICAgICBkaXNwbGF5RXZlbnRFbmQgPSBkZWZhdWx0RGlzcGxheUV2ZW50RW5kICE9PSBmYWxzZTtcbiAgICB9XG4gICAgbGV0IHdob2xlRXZlbnRTdGFydCA9IGV2ZW50SW5zdGFuY2UucmFuZ2Uuc3RhcnQ7XG4gICAgbGV0IHdob2xlRXZlbnRFbmQgPSBldmVudEluc3RhbmNlLnJhbmdlLmVuZDtcbiAgICBsZXQgc2VnU3RhcnQgPSBzdGFydE92ZXJyaWRlIHx8IHNlZy5zdGFydCB8fCBzZWcuZXZlbnRSYW5nZS5yYW5nZS5zdGFydDtcbiAgICBsZXQgc2VnRW5kID0gZW5kT3ZlcnJpZGUgfHwgc2VnLmVuZCB8fCBzZWcuZXZlbnRSYW5nZS5yYW5nZS5lbmQ7XG4gICAgbGV0IGlzU3RhcnREYXkgPSBzdGFydE9mRGF5KHdob2xlRXZlbnRTdGFydCkudmFsdWVPZigpID09PSBzdGFydE9mRGF5KHNlZ1N0YXJ0KS52YWx1ZU9mKCk7XG4gICAgbGV0IGlzRW5kRGF5ID0gc3RhcnRPZkRheShhZGRNcyh3aG9sZUV2ZW50RW5kLCAtMSkpLnZhbHVlT2YoKSA9PT0gc3RhcnRPZkRheShhZGRNcyhzZWdFbmQsIC0xKSkudmFsdWVPZigpO1xuICAgIGlmIChkaXNwbGF5RXZlbnRUaW1lICYmICFldmVudERlZi5hbGxEYXkgJiYgKGlzU3RhcnREYXkgfHwgaXNFbmREYXkpKSB7XG4gICAgICAgIHNlZ1N0YXJ0ID0gaXNTdGFydERheSA/IHdob2xlRXZlbnRTdGFydCA6IHNlZ1N0YXJ0O1xuICAgICAgICBzZWdFbmQgPSBpc0VuZERheSA/IHdob2xlRXZlbnRFbmQgOiBzZWdFbmQ7XG4gICAgICAgIGlmIChkaXNwbGF5RXZlbnRFbmQgJiYgZXZlbnREZWYuaGFzRW5kKSB7XG4gICAgICAgICAgICByZXR1cm4gZGF0ZUVudi5mb3JtYXRSYW5nZShzZWdTdGFydCwgc2VnRW5kLCB0aW1lRm9ybWF0LCB7XG4gICAgICAgICAgICAgICAgZm9yY2VkU3RhcnRUem86IHN0YXJ0T3ZlcnJpZGUgPyBudWxsIDogZXZlbnRJbnN0YW5jZS5mb3JjZWRTdGFydFR6byxcbiAgICAgICAgICAgICAgICBmb3JjZWRFbmRUem86IGVuZE92ZXJyaWRlID8gbnVsbCA6IGV2ZW50SW5zdGFuY2UuZm9yY2VkRW5kVHpvLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGRhdGVFbnYuZm9ybWF0KHNlZ1N0YXJ0LCB0aW1lRm9ybWF0LCB7XG4gICAgICAgICAgICBmb3JjZWRUem86IHN0YXJ0T3ZlcnJpZGUgPyBudWxsIDogZXZlbnRJbnN0YW5jZS5mb3JjZWRTdGFydFR6bywgLy8gbm9vb29vLCBzYW1lXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4gJyc7XG59XG5mdW5jdGlvbiBnZXRTZWdNZXRhKHNlZywgdG9kYXlSYW5nZSwgbm93RGF0ZSkge1xuICAgIGxldCBzZWdSYW5nZSA9IHNlZy5ldmVudFJhbmdlLnJhbmdlO1xuICAgIHJldHVybiB7XG4gICAgICAgIGlzUGFzdDogc2VnUmFuZ2UuZW5kIDw9IChub3dEYXRlIHx8IHRvZGF5UmFuZ2Uuc3RhcnQpLFxuICAgICAgICBpc0Z1dHVyZTogc2VnUmFuZ2Uuc3RhcnQgPj0gKG5vd0RhdGUgfHwgdG9kYXlSYW5nZS5lbmQpLFxuICAgICAgICBpc1RvZGF5OiB0b2RheVJhbmdlICYmIHJhbmdlQ29udGFpbnNNYXJrZXIodG9kYXlSYW5nZSwgc2VnUmFuZ2Uuc3RhcnQpLFxuICAgIH07XG59XG5mdW5jdGlvbiBnZXRFdmVudENsYXNzTmFtZXMocHJvcHMpIHtcbiAgICBsZXQgY2xhc3NOYW1lcyA9IFsnZmMtZXZlbnQnXTtcbiAgICBpZiAocHJvcHMuaXNNaXJyb3IpIHtcbiAgICAgICAgY2xhc3NOYW1lcy5wdXNoKCdmYy1ldmVudC1taXJyb3InKTtcbiAgICB9XG4gICAgaWYgKHByb3BzLmlzRHJhZ2dhYmxlKSB7XG4gICAgICAgIGNsYXNzTmFtZXMucHVzaCgnZmMtZXZlbnQtZHJhZ2dhYmxlJyk7XG4gICAgfVxuICAgIGlmIChwcm9wcy5pc1N0YXJ0UmVzaXphYmxlIHx8IHByb3BzLmlzRW5kUmVzaXphYmxlKSB7XG4gICAgICAgIGNsYXNzTmFtZXMucHVzaCgnZmMtZXZlbnQtcmVzaXphYmxlJyk7XG4gICAgfVxuICAgIGlmIChwcm9wcy5pc0RyYWdnaW5nKSB7XG4gICAgICAgIGNsYXNzTmFtZXMucHVzaCgnZmMtZXZlbnQtZHJhZ2dpbmcnKTtcbiAgICB9XG4gICAgaWYgKHByb3BzLmlzUmVzaXppbmcpIHtcbiAgICAgICAgY2xhc3NOYW1lcy5wdXNoKCdmYy1ldmVudC1yZXNpemluZycpO1xuICAgIH1cbiAgICBpZiAocHJvcHMuaXNTZWxlY3RlZCkge1xuICAgICAgICBjbGFzc05hbWVzLnB1c2goJ2ZjLWV2ZW50LXNlbGVjdGVkJyk7XG4gICAgfVxuICAgIGlmIChwcm9wcy5pc1N0YXJ0KSB7XG4gICAgICAgIGNsYXNzTmFtZXMucHVzaCgnZmMtZXZlbnQtc3RhcnQnKTtcbiAgICB9XG4gICAgaWYgKHByb3BzLmlzRW5kKSB7XG4gICAgICAgIGNsYXNzTmFtZXMucHVzaCgnZmMtZXZlbnQtZW5kJyk7XG4gICAgfVxuICAgIGlmIChwcm9wcy5pc1Bhc3QpIHtcbiAgICAgICAgY2xhc3NOYW1lcy5wdXNoKCdmYy1ldmVudC1wYXN0Jyk7XG4gICAgfVxuICAgIGlmIChwcm9wcy5pc1RvZGF5KSB7XG4gICAgICAgIGNsYXNzTmFtZXMucHVzaCgnZmMtZXZlbnQtdG9kYXknKTtcbiAgICB9XG4gICAgaWYgKHByb3BzLmlzRnV0dXJlKSB7XG4gICAgICAgIGNsYXNzTmFtZXMucHVzaCgnZmMtZXZlbnQtZnV0dXJlJyk7XG4gICAgfVxuICAgIHJldHVybiBjbGFzc05hbWVzO1xufVxuZnVuY3Rpb24gYnVpbGRFdmVudFJhbmdlS2V5KGV2ZW50UmFuZ2UpIHtcbiAgICByZXR1cm4gZXZlbnRSYW5nZS5pbnN0YW5jZVxuICAgICAgICA/IGV2ZW50UmFuZ2UuaW5zdGFuY2UuaW5zdGFuY2VJZFxuICAgICAgICA6IGAke2V2ZW50UmFuZ2UuZGVmLmRlZklkfToke2V2ZW50UmFuZ2UucmFuZ2Uuc3RhcnQudG9JU09TdHJpbmcoKX1gO1xuICAgIC8vIGludmVyc2UtYmFja2dyb3VuZCBldmVudHMgZG9uJ3QgaGF2ZSBzcGVjaWZpYyBpbnN0YW5jZXMuIFRPRE86IGJldHRlciBzb2x1dGlvblxufVxuZnVuY3Rpb24gZ2V0U2VnQW5jaG9yQXR0cnMoc2VnLCBjb250ZXh0KSB7XG4gICAgbGV0IHsgZGVmLCBpbnN0YW5jZSB9ID0gc2VnLmV2ZW50UmFuZ2U7XG4gICAgbGV0IHsgdXJsIH0gPSBkZWY7XG4gICAgaWYgKHVybCkge1xuICAgICAgICByZXR1cm4geyBocmVmOiB1cmwgfTtcbiAgICB9XG4gICAgbGV0IHsgZW1pdHRlciwgb3B0aW9ucyB9ID0gY29udGV4dDtcbiAgICBsZXQgeyBldmVudEludGVyYWN0aXZlIH0gPSBvcHRpb25zO1xuICAgIGlmIChldmVudEludGVyYWN0aXZlID09IG51bGwpIHtcbiAgICAgICAgZXZlbnRJbnRlcmFjdGl2ZSA9IGRlZi5pbnRlcmFjdGl2ZTtcbiAgICAgICAgaWYgKGV2ZW50SW50ZXJhY3RpdmUgPT0gbnVsbCkge1xuICAgICAgICAgICAgZXZlbnRJbnRlcmFjdGl2ZSA9IEJvb2xlYW4oZW1pdHRlci5oYXNIYW5kbGVycygnZXZlbnRDbGljaycpKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBtb2NrIHdoYXQgaGFwcGVucyBpbiBFdmVudENsaWNraW5nXG4gICAgaWYgKGV2ZW50SW50ZXJhY3RpdmUpIHtcbiAgICAgICAgLy8gb25seSBhdHRhY2gga2V5Ym9hcmQtcmVsYXRlZCBoYW5kbGVycyBiZWNhdXNlIGNsaWNrIGhhbmRsZXIgaXMgYWxyZWFkeSBkb25lIGluIEV2ZW50Q2xpY2tpbmdcbiAgICAgICAgcmV0dXJuIGNyZWF0ZUFyaWFLZXlib2FyZEF0dHJzKChldikgPT4ge1xuICAgICAgICAgICAgZW1pdHRlci50cmlnZ2VyKCdldmVudENsaWNrJywge1xuICAgICAgICAgICAgICAgIGVsOiBldi50YXJnZXQsXG4gICAgICAgICAgICAgICAgZXZlbnQ6IG5ldyBFdmVudEltcGwoY29udGV4dCwgZGVmLCBpbnN0YW5jZSksXG4gICAgICAgICAgICAgICAganNFdmVudDogZXYsXG4gICAgICAgICAgICAgICAgdmlldzogY29udGV4dC52aWV3QXBpLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4ge307XG59XG5cbmNvbnN0IFNUQU5EQVJEX1BST1BTID0ge1xuICAgIHN0YXJ0OiBpZGVudGl0eSxcbiAgICBlbmQ6IGlkZW50aXR5LFxuICAgIGFsbERheTogQm9vbGVhbixcbn07XG5mdW5jdGlvbiBwYXJzZURhdGVTcGFuKHJhdywgZGF0ZUVudiwgZGVmYXVsdER1cmF0aW9uKSB7XG4gICAgbGV0IHNwYW4gPSBwYXJzZU9wZW5EYXRlU3BhbihyYXcsIGRhdGVFbnYpO1xuICAgIGxldCB7IHJhbmdlIH0gPSBzcGFuO1xuICAgIGlmICghcmFuZ2Uuc3RhcnQpIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIGlmICghcmFuZ2UuZW5kKSB7XG4gICAgICAgIGlmIChkZWZhdWx0RHVyYXRpb24gPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgcmFuZ2UuZW5kID0gZGF0ZUVudi5hZGQocmFuZ2Uuc3RhcnQsIGRlZmF1bHREdXJhdGlvbik7XG4gICAgfVxuICAgIHJldHVybiBzcGFuO1xufVxuLypcblRPRE86IHNvbWVob3cgY29tYmluZSB3aXRoIHBhcnNlUmFuZ2U/XG5XaWxsIHJldHVybiBudWxsIGlmIHRoZSBzdGFydC9lbmQgcHJvcHMgd2VyZSBwcmVzZW50IGJ1dCBwYXJzZWQgaW52YWxpZGx5LlxuKi9cbmZ1bmN0aW9uIHBhcnNlT3BlbkRhdGVTcGFuKHJhdywgZGF0ZUVudikge1xuICAgIGxldCB7IHJlZmluZWQ6IHN0YW5kYXJkUHJvcHMsIGV4dHJhIH0gPSByZWZpbmVQcm9wcyhyYXcsIFNUQU5EQVJEX1BST1BTKTtcbiAgICBsZXQgc3RhcnRNZXRhID0gc3RhbmRhcmRQcm9wcy5zdGFydCA/IGRhdGVFbnYuY3JlYXRlTWFya2VyTWV0YShzdGFuZGFyZFByb3BzLnN0YXJ0KSA6IG51bGw7XG4gICAgbGV0IGVuZE1ldGEgPSBzdGFuZGFyZFByb3BzLmVuZCA/IGRhdGVFbnYuY3JlYXRlTWFya2VyTWV0YShzdGFuZGFyZFByb3BzLmVuZCkgOiBudWxsO1xuICAgIGxldCB7IGFsbERheSB9ID0gc3RhbmRhcmRQcm9wcztcbiAgICBpZiAoYWxsRGF5ID09IG51bGwpIHtcbiAgICAgICAgYWxsRGF5ID0gKHN0YXJ0TWV0YSAmJiBzdGFydE1ldGEuaXNUaW1lVW5zcGVjaWZpZWQpICYmXG4gICAgICAgICAgICAoIWVuZE1ldGEgfHwgZW5kTWV0YS5pc1RpbWVVbnNwZWNpZmllZCk7XG4gICAgfVxuICAgIHJldHVybiBPYmplY3QuYXNzaWduKHsgcmFuZ2U6IHtcbiAgICAgICAgICAgIHN0YXJ0OiBzdGFydE1ldGEgPyBzdGFydE1ldGEubWFya2VyIDogbnVsbCxcbiAgICAgICAgICAgIGVuZDogZW5kTWV0YSA/IGVuZE1ldGEubWFya2VyIDogbnVsbCxcbiAgICAgICAgfSwgYWxsRGF5IH0sIGV4dHJhKTtcbn1cbmZ1bmN0aW9uIGlzRGF0ZVNwYW5zRXF1YWwoc3BhbjAsIHNwYW4xKSB7XG4gICAgcmV0dXJuIHJhbmdlc0VxdWFsKHNwYW4wLnJhbmdlLCBzcGFuMS5yYW5nZSkgJiZcbiAgICAgICAgc3BhbjAuYWxsRGF5ID09PSBzcGFuMS5hbGxEYXkgJiZcbiAgICAgICAgaXNTcGFuUHJvcHNFcXVhbChzcGFuMCwgc3BhbjEpO1xufVxuLy8gdGhlIE5PTi1EQVRFLVJFTEFURUQgcHJvcHNcbmZ1bmN0aW9uIGlzU3BhblByb3BzRXF1YWwoc3BhbjAsIHNwYW4xKSB7XG4gICAgZm9yIChsZXQgcHJvcE5hbWUgaW4gc3BhbjEpIHtcbiAgICAgICAgaWYgKHByb3BOYW1lICE9PSAncmFuZ2UnICYmIHByb3BOYW1lICE9PSAnYWxsRGF5Jykge1xuICAgICAgICAgICAgaWYgKHNwYW4wW3Byb3BOYW1lXSAhPT0gc3BhbjFbcHJvcE5hbWVdKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIC8vIGFyZSB0aGVyZSBhbnkgcHJvcHMgdGhhdCBzcGFuMCBoYXMgdGhhdCBzcGFuMSBET0VTTidUIGhhdmU/XG4gICAgLy8gYm90aCBoYXZlIHJhbmdlL2FsbERheSwgc28gbm8gbmVlZCB0byBzcGVjaWFsLWNhc2UuXG4gICAgZm9yIChsZXQgcHJvcE5hbWUgaW4gc3BhbjApIHtcbiAgICAgICAgaWYgKCEocHJvcE5hbWUgaW4gc3BhbjEpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG59XG5mdW5jdGlvbiBidWlsZERhdGVTcGFuQXBpKHNwYW4sIGRhdGVFbnYpIHtcbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBidWlsZFJhbmdlQXBpKHNwYW4ucmFuZ2UsIGRhdGVFbnYsIHNwYW4uYWxsRGF5KSksIHsgYWxsRGF5OiBzcGFuLmFsbERheSB9KTtcbn1cbmZ1bmN0aW9uIGJ1aWxkUmFuZ2VBcGlXaXRoVGltZVpvbmUocmFuZ2UsIGRhdGVFbnYsIG9taXRUaW1lKSB7XG4gICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgYnVpbGRSYW5nZUFwaShyYW5nZSwgZGF0ZUVudiwgb21pdFRpbWUpKSwgeyB0aW1lWm9uZTogZGF0ZUVudi50aW1lWm9uZSB9KTtcbn1cbmZ1bmN0aW9uIGJ1aWxkUmFuZ2VBcGkocmFuZ2UsIGRhdGVFbnYsIG9taXRUaW1lKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgc3RhcnQ6IGRhdGVFbnYudG9EYXRlKHJhbmdlLnN0YXJ0KSxcbiAgICAgICAgZW5kOiBkYXRlRW52LnRvRGF0ZShyYW5nZS5lbmQpLFxuICAgICAgICBzdGFydFN0cjogZGF0ZUVudi5mb3JtYXRJc28ocmFuZ2Uuc3RhcnQsIHsgb21pdFRpbWUgfSksXG4gICAgICAgIGVuZFN0cjogZGF0ZUVudi5mb3JtYXRJc28ocmFuZ2UuZW5kLCB7IG9taXRUaW1lIH0pLFxuICAgIH07XG59XG5mdW5jdGlvbiBmYWJyaWNhdGVFdmVudFJhbmdlKGRhdGVTcGFuLCBldmVudFVpQmFzZXMsIGNvbnRleHQpIHtcbiAgICBsZXQgcmVzID0gcmVmaW5lRXZlbnREZWYoeyBlZGl0YWJsZTogZmFsc2UgfSwgY29udGV4dCk7XG4gICAgbGV0IGRlZiA9IHBhcnNlRXZlbnREZWYocmVzLnJlZmluZWQsIHJlcy5leHRyYSwgJycsIC8vIHNvdXJjZUlkXG4gICAgZGF0ZVNwYW4uYWxsRGF5LCB0cnVlLCAvLyBoYXNFbmRcbiAgICBjb250ZXh0KTtcbiAgICByZXR1cm4ge1xuICAgICAgICBkZWYsXG4gICAgICAgIHVpOiBjb21waWxlRXZlbnRVaShkZWYsIGV2ZW50VWlCYXNlcyksXG4gICAgICAgIGluc3RhbmNlOiBjcmVhdGVFdmVudEluc3RhbmNlKGRlZi5kZWZJZCwgZGF0ZVNwYW4ucmFuZ2UpLFxuICAgICAgICByYW5nZTogZGF0ZVNwYW4ucmFuZ2UsXG4gICAgICAgIGlzU3RhcnQ6IHRydWUsXG4gICAgICAgIGlzRW5kOiB0cnVlLFxuICAgIH07XG59XG5cbi8qXG5naXZlbiBhIGZ1bmN0aW9uIHRoYXQgcmVzb2x2ZXMgYSByZXN1bHQgYXN5bmNocm9ub3VzbHkuXG50aGUgZnVuY3Rpb24gY2FuIGVpdGhlciBjYWxsIHBhc3NlZC1pbiBzdWNjZXNzIGFuZCBmYWlsdXJlIGNhbGxiYWNrcyxcbm9yIGl0IGNhbiByZXR1cm4gYSBwcm9taXNlLlxuaWYgeW91IG5lZWQgdG8gcGFzcyBhZGRpdGlvbmFsIHBhcmFtcyB0byBmdW5jLCBiaW5kIHRoZW0gZmlyc3QuXG4qL1xuZnVuY3Rpb24gdW5wcm9taXNpZnkoZnVuYywgbm9ybWFsaXplZFN1Y2Nlc3NDYWxsYmFjaywgbm9ybWFsaXplZEZhaWx1cmVDYWxsYmFjaykge1xuICAgIC8vIGd1YXJkIGFnYWluc3Qgc3VjY2Vzcy9mYWlsdXJlIGNhbGxiYWNrcyBiZWluZyBjYWxsZWQgbW9yZSB0aGFuIG9uY2VcbiAgICAvLyBhbmQgZ3VhcmQgYWdhaW5zdCBhIHByb21pc2UgQU5EIGNhbGxiYWNrIGJlaW5nIHVzZWQgdG9nZXRoZXIuXG4gICAgbGV0IGlzUmVzb2x2ZWQgPSBmYWxzZTtcbiAgICBsZXQgd3JhcHBlZFN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgIGlmICghaXNSZXNvbHZlZCkge1xuICAgICAgICAgICAgaXNSZXNvbHZlZCA9IHRydWU7XG4gICAgICAgICAgICBub3JtYWxpemVkU3VjY2Vzc0NhbGxiYWNrKHJlcyk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIGxldCB3cmFwcGVkRmFpbHVyZSA9IGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICBpZiAoIWlzUmVzb2x2ZWQpIHtcbiAgICAgICAgICAgIGlzUmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgICAgICAgbm9ybWFsaXplZEZhaWx1cmVDYWxsYmFjayhlcnJvcik7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIGxldCByZXMgPSBmdW5jKHdyYXBwZWRTdWNjZXNzLCB3cmFwcGVkRmFpbHVyZSk7XG4gICAgaWYgKHJlcyAmJiB0eXBlb2YgcmVzLnRoZW4gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgcmVzLnRoZW4od3JhcHBlZFN1Y2Nlc3MsIHdyYXBwZWRGYWlsdXJlKTtcbiAgICB9XG59XG5cbmNsYXNzIEpzb25SZXF1ZXN0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gICAgY29uc3RydWN0b3IobWVzc2FnZSwgcmVzcG9uc2UpIHtcbiAgICAgICAgc3VwZXIobWVzc2FnZSk7XG4gICAgICAgIHRoaXMucmVzcG9uc2UgPSByZXNwb25zZTtcbiAgICB9XG59XG5mdW5jdGlvbiByZXF1ZXN0SnNvbihtZXRob2QsIHVybCwgcGFyYW1zKSB7XG4gICAgbWV0aG9kID0gbWV0aG9kLnRvVXBwZXJDYXNlKCk7XG4gICAgY29uc3QgZmV0Y2hPcHRpb25zID0ge1xuICAgICAgICBtZXRob2QsXG4gICAgfTtcbiAgICBpZiAobWV0aG9kID09PSAnR0VUJykge1xuICAgICAgICB1cmwgKz0gKHVybC5pbmRleE9mKCc/JykgPT09IC0xID8gJz8nIDogJyYnKSArXG4gICAgICAgICAgICBuZXcgVVJMU2VhcmNoUGFyYW1zKHBhcmFtcyk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBmZXRjaE9wdGlvbnMuYm9keSA9IG5ldyBVUkxTZWFyY2hQYXJhbXMocGFyYW1zKTtcbiAgICAgICAgZmV0Y2hPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCcsXG4gICAgICAgIH07XG4gICAgfVxuICAgIHJldHVybiBmZXRjaCh1cmwsIGZldGNoT3B0aW9ucykudGhlbigoZmV0Y2hSZXMpID0+IHtcbiAgICAgICAgaWYgKGZldGNoUmVzLm9rKSB7XG4gICAgICAgICAgICByZXR1cm4gZmV0Y2hSZXMuanNvbigpLnRoZW4oKHBhcnNlZFJlc3BvbnNlKSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFtwYXJzZWRSZXNwb25zZSwgZmV0Y2hSZXNdO1xuICAgICAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBKc29uUmVxdWVzdEVycm9yKCdGYWlsdXJlIHBhcnNpbmcgSlNPTicsIGZldGNoUmVzKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEpzb25SZXF1ZXN0RXJyb3IoJ1JlcXVlc3QgZmFpbGVkJywgZmV0Y2hSZXMpO1xuICAgICAgICB9XG4gICAgfSk7XG59XG5cbmxldCBjYW5WR3Jvd1dpdGhpbkNlbGw7XG5mdW5jdGlvbiBnZXRDYW5WR3Jvd1dpdGhpbkNlbGwoKSB7XG4gICAgaWYgKGNhblZHcm93V2l0aGluQ2VsbCA9PSBudWxsKSB7XG4gICAgICAgIGNhblZHcm93V2l0aGluQ2VsbCA9IGNvbXB1dGVDYW5WR3Jvd1dpdGhpbkNlbGwoKTtcbiAgICB9XG4gICAgcmV0dXJuIGNhblZHcm93V2l0aGluQ2VsbDtcbn1cbmZ1bmN0aW9uIGNvbXB1dGVDYW5WR3Jvd1dpdGhpbkNlbGwoKSB7XG4gICAgLy8gZm9yIFNTUiwgYmVjYXVzZSB0aGlzIGZ1bmN0aW9uIGlzIGNhbGwgaW1tZWRpYXRlbHkgYXQgdG9wLWxldmVsXG4gICAgLy8gVE9ETzoganVzdCBtYWtlIHRoaXMgbG9naWMgZXhlY3V0ZSB0b3AtbGV2ZWwsIGltbWVkaWF0ZWx5LCBpbnN0ZWFkIG9mIGRvaW5nIGxhemlseVxuICAgIGlmICh0eXBlb2YgZG9jdW1lbnQgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBsZXQgZWwgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICBlbC5zdHlsZS5wb3NpdGlvbiA9ICdhYnNvbHV0ZSc7XG4gICAgZWwuc3R5bGUudG9wID0gJzBweCc7XG4gICAgZWwuc3R5bGUubGVmdCA9ICcwcHgnO1xuICAgIGVsLmlubmVySFRNTCA9ICc8dGFibGU+PHRyPjx0ZD48ZGl2PjwvZGl2PjwvdGQ+PC90cj48L3RhYmxlPic7XG4gICAgZWwucXVlcnlTZWxlY3RvcigndGFibGUnKS5zdHlsZS5oZWlnaHQgPSAnMTAwcHgnO1xuICAgIGVsLnF1ZXJ5U2VsZWN0b3IoJ2RpdicpLnN0eWxlLmhlaWdodCA9ICcxMDAlJztcbiAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGVsKTtcbiAgICBsZXQgZGl2ID0gZWwucXVlcnlTZWxlY3RvcignZGl2Jyk7XG4gICAgbGV0IHBvc3NpYmxlID0gZGl2Lm9mZnNldEhlaWdodCA+IDA7XG4gICAgZG9jdW1lbnQuYm9keS5yZW1vdmVDaGlsZChlbCk7XG4gICAgcmV0dXJuIHBvc3NpYmxlO1xufVxuXG5jbGFzcyBDYWxlbmRhclJvb3QgZXh0ZW5kcyBCYXNlQ29tcG9uZW50IHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoLi4uYXJndW1lbnRzKTtcbiAgICAgICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgICAgICAgIGZvclByaW50OiBmYWxzZSxcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVCZWZvcmVQcmludCA9ICgpID0+IHtcbiAgICAgICAgICAgIGZsdXNoU3luYygoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IGZvclByaW50OiB0cnVlIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlQWZ0ZXJQcmludCA9ICgpID0+IHtcbiAgICAgICAgICAgIGZsdXNoU3luYygoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IGZvclByaW50OiBmYWxzZSB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuICAgIH1cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGxldCB7IHByb3BzIH0gPSB0aGlzO1xuICAgICAgICBsZXQgeyBvcHRpb25zIH0gPSBwcm9wcztcbiAgICAgICAgbGV0IHsgZm9yUHJpbnQgfSA9IHRoaXMuc3RhdGU7XG4gICAgICAgIGxldCBpc0hlaWdodEF1dG8gPSBmb3JQcmludCB8fCBvcHRpb25zLmhlaWdodCA9PT0gJ2F1dG8nIHx8IG9wdGlvbnMuY29udGVudEhlaWdodCA9PT0gJ2F1dG8nO1xuICAgICAgICBsZXQgaGVpZ2h0ID0gKCFpc0hlaWdodEF1dG8gJiYgb3B0aW9ucy5oZWlnaHQgIT0gbnVsbCkgPyBvcHRpb25zLmhlaWdodCA6ICcnO1xuICAgICAgICBsZXQgY2xhc3NOYW1lcyA9IFtcbiAgICAgICAgICAgICdmYycsXG4gICAgICAgICAgICBmb3JQcmludCA/ICdmYy1tZWRpYS1wcmludCcgOiAnZmMtbWVkaWEtc2NyZWVuJyxcbiAgICAgICAgICAgIGBmYy1kaXJlY3Rpb24tJHtvcHRpb25zLmRpcmVjdGlvbn1gLFxuICAgICAgICAgICAgcHJvcHMudGhlbWUuZ2V0Q2xhc3MoJ3Jvb3QnKSxcbiAgICAgICAgXTtcbiAgICAgICAgaWYgKCFnZXRDYW5WR3Jvd1dpdGhpbkNlbGwoKSkge1xuICAgICAgICAgICAgY2xhc3NOYW1lcy5wdXNoKCdmYy1saXF1aWQtaGFjaycpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBwcm9wcy5jaGlsZHJlbihjbGFzc05hbWVzLCBoZWlnaHQsIGlzSGVpZ2h0QXV0bywgZm9yUHJpbnQpO1xuICAgIH1cbiAgICBjb21wb25lbnREaWRNb3VudCgpIHtcbiAgICAgICAgbGV0IHsgZW1pdHRlciB9ID0gdGhpcy5wcm9wcztcbiAgICAgICAgZW1pdHRlci5vbignX2JlZm9yZXByaW50JywgdGhpcy5oYW5kbGVCZWZvcmVQcmludCk7XG4gICAgICAgIGVtaXR0ZXIub24oJ19hZnRlcnByaW50JywgdGhpcy5oYW5kbGVBZnRlclByaW50KTtcbiAgICB9XG4gICAgY29tcG9uZW50V2lsbFVubW91bnQoKSB7XG4gICAgICAgIGxldCB7IGVtaXR0ZXIgfSA9IHRoaXMucHJvcHM7XG4gICAgICAgIGVtaXR0ZXIub2ZmKCdfYmVmb3JlcHJpbnQnLCB0aGlzLmhhbmRsZUJlZm9yZVByaW50KTtcbiAgICAgICAgZW1pdHRlci5vZmYoJ19hZnRlcnByaW50JywgdGhpcy5oYW5kbGVBZnRlclByaW50KTtcbiAgICB9XG59XG5cbmNsYXNzIEludGVyYWN0aW9uIHtcbiAgICBjb25zdHJ1Y3RvcihzZXR0aW5ncykge1xuICAgICAgICB0aGlzLmNvbXBvbmVudCA9IHNldHRpbmdzLmNvbXBvbmVudDtcbiAgICAgICAgdGhpcy5pc0hpdENvbWJvQWxsb3dlZCA9IHNldHRpbmdzLmlzSGl0Q29tYm9BbGxvd2VkIHx8IG51bGw7XG4gICAgfVxuICAgIGRlc3Ryb3koKSB7XG4gICAgfVxufVxuZnVuY3Rpb24gcGFyc2VJbnRlcmFjdGlvblNldHRpbmdzKGNvbXBvbmVudCwgaW5wdXQpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBjb21wb25lbnQsXG4gICAgICAgIGVsOiBpbnB1dC5lbCxcbiAgICAgICAgdXNlRXZlbnRDZW50ZXI6IGlucHV0LnVzZUV2ZW50Q2VudGVyICE9IG51bGwgPyBpbnB1dC51c2VFdmVudENlbnRlciA6IHRydWUsXG4gICAgICAgIGlzSGl0Q29tYm9BbGxvd2VkOiBpbnB1dC5pc0hpdENvbWJvQWxsb3dlZCB8fCBudWxsLFxuICAgIH07XG59XG5mdW5jdGlvbiBpbnRlcmFjdGlvblNldHRpbmdzVG9TdG9yZShzZXR0aW5ncykge1xuICAgIHJldHVybiB7XG4gICAgICAgIFtzZXR0aW5ncy5jb21wb25lbnQudWlkXTogc2V0dGluZ3MsXG4gICAgfTtcbn1cbi8vIGdsb2JhbCBzdGF0ZVxuY29uc3QgaW50ZXJhY3Rpb25TZXR0aW5nc1N0b3JlID0ge307XG5cbmNsYXNzIE5vd1RpbWVyIGV4dGVuZHMgQ29tcG9uZW50IHtcbiAgICBjb25zdHJ1Y3Rvcihwcm9wcywgY29udGV4dCkge1xuICAgICAgICBzdXBlcihwcm9wcywgY29udGV4dCk7XG4gICAgICAgIHRoaXMuaGFuZGxlUmVmcmVzaCA9ICgpID0+IHtcbiAgICAgICAgICAgIGxldCB0aW1pbmcgPSB0aGlzLmNvbXB1dGVUaW1pbmcoKTtcbiAgICAgICAgICAgIGlmICh0aW1pbmcuc3RhdGUubm93RGF0ZS52YWx1ZU9mKCkgIT09IHRoaXMuc3RhdGUubm93RGF0ZS52YWx1ZU9mKCkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHRpbWluZy5zdGF0ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmNsZWFyVGltZW91dCgpO1xuICAgICAgICAgICAgdGhpcy5zZXRUaW1lb3V0KHRpbWluZy53YWl0TXMpO1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZVZpc2liaWxpdHlDaGFuZ2UgPSAoKSA9PiB7XG4gICAgICAgICAgICBpZiAoIWRvY3VtZW50LmhpZGRlbikge1xuICAgICAgICAgICAgICAgIHRoaXMuaGFuZGxlUmVmcmVzaCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICB0aGlzLnN0YXRlID0gdGhpcy5jb21wdXRlVGltaW5nKCkuc3RhdGU7XG4gICAgfVxuICAgIHJlbmRlcigpIHtcbiAgICAgICAgbGV0IHsgcHJvcHMsIHN0YXRlIH0gPSB0aGlzO1xuICAgICAgICByZXR1cm4gcHJvcHMuY2hpbGRyZW4oc3RhdGUubm93RGF0ZSwgc3RhdGUudG9kYXlSYW5nZSk7XG4gICAgfVxuICAgIGNvbXBvbmVudERpZE1vdW50KCkge1xuICAgICAgICB0aGlzLnNldFRpbWVvdXQoKTtcbiAgICAgICAgdGhpcy5jb250ZXh0Lm5vd01hbmFnZXIuYWRkUmVzZXRMaXN0ZW5lcih0aGlzLmhhbmRsZVJlZnJlc2gpO1xuICAgICAgICAvLyBmaXJlZCB0YWIgYmVjb21lcyB2aXNpYmxlIGFmdGVyIGJlaW5nIGhpZGRlblxuICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCd2aXNpYmlsaXR5Y2hhbmdlJywgdGhpcy5oYW5kbGVWaXNpYmlsaXR5Q2hhbmdlKTtcbiAgICB9XG4gICAgY29tcG9uZW50RGlkVXBkYXRlKHByZXZQcm9wcykge1xuICAgICAgICBpZiAocHJldlByb3BzLnVuaXQgIT09IHRoaXMucHJvcHMudW5pdCkge1xuICAgICAgICAgICAgdGhpcy5jbGVhclRpbWVvdXQoKTtcbiAgICAgICAgICAgIHRoaXMuc2V0VGltZW91dCgpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbXBvbmVudFdpbGxVbm1vdW50KCkge1xuICAgICAgICB0aGlzLmNsZWFyVGltZW91dCgpO1xuICAgICAgICB0aGlzLmNvbnRleHQubm93TWFuYWdlci5yZW1vdmVSZXNldExpc3RlbmVyKHRoaXMuaGFuZGxlUmVmcmVzaCk7XG4gICAgICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3Zpc2liaWxpdHljaGFuZ2UnLCB0aGlzLmhhbmRsZVZpc2liaWxpdHlDaGFuZ2UpO1xuICAgIH1cbiAgICBjb21wdXRlVGltaW5nKCkge1xuICAgICAgICBsZXQgeyBwcm9wcywgY29udGV4dCB9ID0gdGhpcztcbiAgICAgICAgbGV0IHVucm91bmRlZE5vdyA9IGNvbnRleHQubm93TWFuYWdlci5nZXREYXRlTWFya2VyKCk7XG4gICAgICAgIGxldCB7IG5vd0luZGljYXRvclNuYXAgfSA9IGNvbnRleHQub3B0aW9ucztcbiAgICAgICAgaWYgKG5vd0luZGljYXRvclNuYXAgPT09ICdhdXRvJykge1xuICAgICAgICAgICAgbm93SW5kaWNhdG9yU25hcCA9XG4gICAgICAgICAgICAgICAgLy8gbGFyZ2UgdW5pdD9cbiAgICAgICAgICAgICAgICAveWVhcnxtb250aHx3ZWVrfGRheS8udGVzdChwcm9wcy51bml0KSB8fFxuICAgICAgICAgICAgICAgICAgICAvLyBpZiBzbG90RHVyYXRpb24gMzAgbWlucyBmb3IgZXhhbXBsZSwgd291bGQgTk9UIGFwcGVhciB0byBzbmFwIChsZWdhY3kgYmVoYXZpb3IpXG4gICAgICAgICAgICAgICAgICAgIChwcm9wcy51bml0VmFsdWUgfHwgMSkgPT09IDE7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IG5vd0RhdGU7XG4gICAgICAgIGxldCB3YWl0TXM7XG4gICAgICAgIGlmIChub3dJbmRpY2F0b3JTbmFwKSB7XG4gICAgICAgICAgICBub3dEYXRlID0gY29udGV4dC5kYXRlRW52LnN0YXJ0T2YodW5yb3VuZGVkTm93LCBwcm9wcy51bml0KTsgLy8gYWthIGN1cnJlbnRVbml0U3RhcnRcbiAgICAgICAgICAgIGxldCBuZXh0VW5pdFN0YXJ0ID0gY29udGV4dC5kYXRlRW52LmFkZChub3dEYXRlLCBjcmVhdGVEdXJhdGlvbigxLCBwcm9wcy51bml0KSk7XG4gICAgICAgICAgICB3YWl0TXMgPSBuZXh0VW5pdFN0YXJ0LnZhbHVlT2YoKSAtIHVucm91bmRlZE5vdy52YWx1ZU9mKCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBub3dEYXRlID0gdW5yb3VuZGVkTm93O1xuICAgICAgICAgICAgd2FpdE1zID0gMTAwMCAqIDYwOyAvLyAxIG1pbnV0ZVxuICAgICAgICB9XG4gICAgICAgIC8vIHRoZXJlIGlzIGEgbWF4IHNldFRpbWVvdXQgbXMgdmFsdWUgKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8zNDY4NjUwLzk2MzQyKVxuICAgICAgICAvLyBlbnN1cmUgbm8gbG9uZ2VyIHRoYW4gYSBkYXlcbiAgICAgICAgd2FpdE1zID0gTWF0aC5taW4oMTAwMCAqIDYwICogNjAgKiAyNCwgd2FpdE1zKTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN0YXRlOiB7IG5vd0RhdGUsIHRvZGF5UmFuZ2U6IGJ1aWxkRGF5UmFuZ2Uobm93RGF0ZSkgfSxcbiAgICAgICAgICAgIHdhaXRNcyxcbiAgICAgICAgfTtcbiAgICB9XG4gICAgc2V0VGltZW91dCh3YWl0TXMgPSB0aGlzLmNvbXB1dGVUaW1pbmcoKS53YWl0TXMpIHtcbiAgICAgICAgLy8gTk9URTogdGltZW91dCBjb3VsZCB0YWtlIGxvbmdlciB0aGFuIGV4cGVjdGVkIGlmIHRhYiBzbGVlcHMsXG4gICAgICAgIC8vIHdoaWNoIGlzIHdoeSB3ZSBsaXN0ZW4gdG8gJ3Zpc2liaWxpdHljaGFuZ2UnXG4gICAgICAgIHRoaXMudGltZW91dElkID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAvLyBOT1RFOiB0aW1lb3V0IGNvdWxkIGFsc28gcmV0dXJuICplYXJsaWVyKiB0aGFuIGV4cGVjdGVkLCBhbmQgd2UgbmVlZCB0byB3YWl0IDIgbXMgbW9yZVxuICAgICAgICAgICAgLy8gVGhpcyBpcyB3aHkgdXNlIHVzZSBzYW1lIHdhaXRNcyBmcm9tIGNvbXB1dGVUaW1pbmcsIHNvIHdlIGRvbid0IHNraXAgYW4gaW50ZXJ2YWwgd2hpbGVcbiAgICAgICAgICAgIC8vIC5zZXRTdGF0ZSgpIGlzIGV4ZWN1dGluZ1xuICAgICAgICAgICAgY29uc3QgdGltaW5nID0gdGhpcy5jb21wdXRlVGltaW5nKCk7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHRpbWluZy5zdGF0ZSwgKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0VGltZW91dCh0aW1pbmcud2FpdE1zKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LCB3YWl0TXMpO1xuICAgIH1cbiAgICBjbGVhclRpbWVvdXQoKSB7XG4gICAgICAgIGlmICh0aGlzLnRpbWVvdXRJZCkge1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRoaXMudGltZW91dElkKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbk5vd1RpbWVyLmNvbnRleHRUeXBlID0gVmlld0NvbnRleHRUeXBlO1xuZnVuY3Rpb24gYnVpbGREYXlSYW5nZShkYXRlKSB7XG4gICAgbGV0IHN0YXJ0ID0gc3RhcnRPZkRheShkYXRlKTtcbiAgICBsZXQgZW5kID0gYWRkRGF5cyhzdGFydCwgMSk7XG4gICAgcmV0dXJuIHsgc3RhcnQsIGVuZCB9O1xufVxuXG5jbGFzcyBDYWxlbmRhckltcGwge1xuICAgIGdldEN1cnJlbnREYXRhKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jdXJyZW50RGF0YU1hbmFnZXIuZ2V0Q3VycmVudERhdGEoKTtcbiAgICB9XG4gICAgZGlzcGF0Y2goYWN0aW9uKSB7XG4gICAgICAgIHRoaXMuY3VycmVudERhdGFNYW5hZ2VyLmRpc3BhdGNoKGFjdGlvbik7XG4gICAgfVxuICAgIGdldCB2aWV3KCkgeyByZXR1cm4gdGhpcy5nZXRDdXJyZW50RGF0YSgpLnZpZXdBcGk7IH1cbiAgICBiYXRjaFJlbmRlcmluZyhjYWxsYmFjaykge1xuICAgICAgICBjYWxsYmFjaygpO1xuICAgIH1cbiAgICB1cGRhdGVTaXplKCkge1xuICAgICAgICB0aGlzLnRyaWdnZXIoJ19yZXNpemUnLCB0cnVlKTtcbiAgICB9XG4gICAgLy8gT3B0aW9uc1xuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgc2V0T3B0aW9uKG5hbWUsIHZhbCkge1xuICAgICAgICB0aGlzLmRpc3BhdGNoKHtcbiAgICAgICAgICAgIHR5cGU6ICdTRVRfT1BUSU9OJyxcbiAgICAgICAgICAgIG9wdGlvbk5hbWU6IG5hbWUsXG4gICAgICAgICAgICByYXdPcHRpb25WYWx1ZTogdmFsLFxuICAgICAgICB9KTtcbiAgICB9XG4gICAgZ2V0T3B0aW9uKG5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY3VycmVudERhdGFNYW5hZ2VyLmN1cnJlbnRDYWxlbmRhck9wdGlvbnNJbnB1dFtuYW1lXTtcbiAgICB9XG4gICAgZ2V0QXZhaWxhYmxlTG9jYWxlQ29kZXMoKSB7XG4gICAgICAgIHJldHVybiBPYmplY3Qua2V5cyh0aGlzLmdldEN1cnJlbnREYXRhKCkuYXZhaWxhYmxlUmF3TG9jYWxlcyk7XG4gICAgfVxuICAgIC8vIFRyaWdnZXJcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIG9uKGhhbmRsZXJOYW1lLCBoYW5kbGVyKSB7XG4gICAgICAgIGxldCB7IGN1cnJlbnREYXRhTWFuYWdlciB9ID0gdGhpcztcbiAgICAgICAgaWYgKGN1cnJlbnREYXRhTWFuYWdlci5jdXJyZW50Q2FsZW5kYXJPcHRpb25zUmVmaW5lcnNbaGFuZGxlck5hbWVdKSB7XG4gICAgICAgICAgICBjdXJyZW50RGF0YU1hbmFnZXIuZW1pdHRlci5vbihoYW5kbGVyTmFtZSwgaGFuZGxlcik7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oYFVua25vd24gbGlzdGVuZXIgbmFtZSAnJHtoYW5kbGVyTmFtZX0nYCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgb2ZmKGhhbmRsZXJOYW1lLCBoYW5kbGVyKSB7XG4gICAgICAgIHRoaXMuY3VycmVudERhdGFNYW5hZ2VyLmVtaXR0ZXIub2ZmKGhhbmRsZXJOYW1lLCBoYW5kbGVyKTtcbiAgICB9XG4gICAgLy8gbm90IG1lYW50IGZvciBwdWJsaWMgdXNlXG4gICAgdHJpZ2dlcihoYW5kbGVyTmFtZSwgLi4uYXJncykge1xuICAgICAgICB0aGlzLmN1cnJlbnREYXRhTWFuYWdlci5lbWl0dGVyLnRyaWdnZXIoaGFuZGxlck5hbWUsIC4uLmFyZ3MpO1xuICAgIH1cbiAgICAvLyBWaWV3XG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBjaGFuZ2VWaWV3KHZpZXdUeXBlLCBkYXRlT3JSYW5nZSkge1xuICAgICAgICB0aGlzLmJhdGNoUmVuZGVyaW5nKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMudW5zZWxlY3QoKTtcbiAgICAgICAgICAgIGlmIChkYXRlT3JSYW5nZSkge1xuICAgICAgICAgICAgICAgIGlmIChkYXRlT3JSYW5nZS5zdGFydCAmJiBkYXRlT3JSYW5nZS5lbmQpIHsgLy8gYSByYW5nZVxuICAgICAgICAgICAgICAgICAgICB0aGlzLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdDSEFOR0VfVklFV19UWVBFJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZpZXdUeXBlLFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnU0VUX09QVElPTicsXG4gICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25OYW1lOiAndmlzaWJsZVJhbmdlJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJhd09wdGlvblZhbHVlOiBkYXRlT3JSYW5nZSxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBsZXQgeyBkYXRlRW52IH0gPSB0aGlzLmdldEN1cnJlbnREYXRhKCk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogJ0NIQU5HRV9WSUVXX1RZUEUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmlld1R5cGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRlTWFya2VyOiBkYXRlRW52LmNyZWF0ZU1hcmtlcihkYXRlT3JSYW5nZSksXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnQ0hBTkdFX1ZJRVdfVFlQRScsXG4gICAgICAgICAgICAgICAgICAgIHZpZXdUeXBlLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgLy8gRm9yY2VzIG5hdmlnYXRpb24gdG8gYSB2aWV3IGZvciB0aGUgZ2l2ZW4gZGF0ZS5cbiAgICAvLyBgdmlld1R5cGVgIGNhbiBiZSBhIHNwZWNpZmljIHZpZXcgbmFtZSBvciBhIGdlbmVyaWMgb25lIGxpa2UgXCJ3ZWVrXCIgb3IgXCJkYXlcIi5cbiAgICAvLyBuZWVkcyB0byBjaGFuZ2VcbiAgICB6b29tVG8oZGF0ZU1hcmtlciwgdmlld1R5cGUpIHtcbiAgICAgICAgbGV0IHN0YXRlID0gdGhpcy5nZXRDdXJyZW50RGF0YSgpO1xuICAgICAgICBsZXQgc3BlYztcbiAgICAgICAgdmlld1R5cGUgPSB2aWV3VHlwZSB8fCAnZGF5JzsgLy8gZGF5IGlzIGRlZmF1bHQgem9vbVxuICAgICAgICBzcGVjID0gc3RhdGUudmlld1NwZWNzW3ZpZXdUeXBlXSB8fCB0aGlzLmdldFVuaXRWaWV3U3BlYyh2aWV3VHlwZSk7XG4gICAgICAgIHRoaXMudW5zZWxlY3QoKTtcbiAgICAgICAgaWYgKHNwZWMpIHtcbiAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgIHR5cGU6ICdDSEFOR0VfVklFV19UWVBFJyxcbiAgICAgICAgICAgICAgICB2aWV3VHlwZTogc3BlYy50eXBlLFxuICAgICAgICAgICAgICAgIGRhdGVNYXJrZXIsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgIHR5cGU6ICdDSEFOR0VfREFURScsXG4gICAgICAgICAgICAgICAgZGF0ZU1hcmtlcixcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8vIEdpdmVuIGEgZHVyYXRpb24gc2luZ3VsYXIgdW5pdCwgbGlrZSBcIndlZWtcIiBvciBcImRheVwiLCBmaW5kcyBhIG1hdGNoaW5nIHZpZXcgc3BlYy5cbiAgICAvLyBQcmVmZXJlbmNlIGlzIGdpdmVuIHRvIHZpZXdzIHRoYXQgaGF2ZSBjb3JyZXNwb25kaW5nIGJ1dHRvbnMuXG4gICAgZ2V0VW5pdFZpZXdTcGVjKHVuaXQpIHtcbiAgICAgICAgbGV0IHsgdmlld1NwZWNzLCB0b29sYmFyQ29uZmlnIH0gPSB0aGlzLmdldEN1cnJlbnREYXRhKCk7XG4gICAgICAgIGxldCB2aWV3VHlwZXMgPSBbXS5jb25jYXQodG9vbGJhckNvbmZpZy5oZWFkZXIgPyB0b29sYmFyQ29uZmlnLmhlYWRlci52aWV3c1dpdGhCdXR0b25zIDogW10sIHRvb2xiYXJDb25maWcuZm9vdGVyID8gdG9vbGJhckNvbmZpZy5mb290ZXIudmlld3NXaXRoQnV0dG9ucyA6IFtdKTtcbiAgICAgICAgbGV0IGk7XG4gICAgICAgIGxldCBzcGVjO1xuICAgICAgICBmb3IgKGxldCB2aWV3VHlwZSBpbiB2aWV3U3BlY3MpIHtcbiAgICAgICAgICAgIHZpZXdUeXBlcy5wdXNoKHZpZXdUeXBlKTtcbiAgICAgICAgfVxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgdmlld1R5cGVzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICAgICAgICBzcGVjID0gdmlld1NwZWNzW3ZpZXdUeXBlc1tpXV07XG4gICAgICAgICAgICBpZiAoc3BlYykge1xuICAgICAgICAgICAgICAgIGlmIChzcGVjLnNpbmdsZVVuaXQgPT09IHVuaXQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHNwZWM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICAvLyBDdXJyZW50IERhdGVcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIHByZXYoKSB7XG4gICAgICAgIHRoaXMudW5zZWxlY3QoKTtcbiAgICAgICAgdGhpcy5kaXNwYXRjaCh7IHR5cGU6ICdQUkVWJyB9KTtcbiAgICB9XG4gICAgbmV4dCgpIHtcbiAgICAgICAgdGhpcy51bnNlbGVjdCgpO1xuICAgICAgICB0aGlzLmRpc3BhdGNoKHsgdHlwZTogJ05FWFQnIH0pO1xuICAgIH1cbiAgICBwcmV2WWVhcigpIHtcbiAgICAgICAgbGV0IHN0YXRlID0gdGhpcy5nZXRDdXJyZW50RGF0YSgpO1xuICAgICAgICB0aGlzLnVuc2VsZWN0KCk7XG4gICAgICAgIHRoaXMuZGlzcGF0Y2goe1xuICAgICAgICAgICAgdHlwZTogJ0NIQU5HRV9EQVRFJyxcbiAgICAgICAgICAgIGRhdGVNYXJrZXI6IHN0YXRlLmRhdGVFbnYuYWRkWWVhcnMoc3RhdGUuY3VycmVudERhdGUsIC0xKSxcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIG5leHRZZWFyKCkge1xuICAgICAgICBsZXQgc3RhdGUgPSB0aGlzLmdldEN1cnJlbnREYXRhKCk7XG4gICAgICAgIHRoaXMudW5zZWxlY3QoKTtcbiAgICAgICAgdGhpcy5kaXNwYXRjaCh7XG4gICAgICAgICAgICB0eXBlOiAnQ0hBTkdFX0RBVEUnLFxuICAgICAgICAgICAgZGF0ZU1hcmtlcjogc3RhdGUuZGF0ZUVudi5hZGRZZWFycyhzdGF0ZS5jdXJyZW50RGF0ZSwgMSksXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICB0b2RheSgpIHtcbiAgICAgICAgbGV0IHN0YXRlID0gdGhpcy5nZXRDdXJyZW50RGF0YSgpO1xuICAgICAgICB0aGlzLnVuc2VsZWN0KCk7XG4gICAgICAgIHRoaXMuZGlzcGF0Y2goe1xuICAgICAgICAgICAgdHlwZTogJ0NIQU5HRV9EQVRFJyxcbiAgICAgICAgICAgIGRhdGVNYXJrZXI6IHN0YXRlLm5vd01hbmFnZXIuZ2V0RGF0ZU1hcmtlcigpLFxuICAgICAgICB9KTtcbiAgICB9XG4gICAgZ290b0RhdGUoem9uZWREYXRlSW5wdXQpIHtcbiAgICAgICAgbGV0IHN0YXRlID0gdGhpcy5nZXRDdXJyZW50RGF0YSgpO1xuICAgICAgICB0aGlzLnVuc2VsZWN0KCk7XG4gICAgICAgIHRoaXMuZGlzcGF0Y2goe1xuICAgICAgICAgICAgdHlwZTogJ0NIQU5HRV9EQVRFJyxcbiAgICAgICAgICAgIGRhdGVNYXJrZXI6IHN0YXRlLmRhdGVFbnYuY3JlYXRlTWFya2VyKHpvbmVkRGF0ZUlucHV0KSxcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGluY3JlbWVudERhdGUoZGVsdGFJbnB1dCkge1xuICAgICAgICBsZXQgc3RhdGUgPSB0aGlzLmdldEN1cnJlbnREYXRhKCk7XG4gICAgICAgIGxldCBkZWx0YSA9IGNyZWF0ZUR1cmF0aW9uKGRlbHRhSW5wdXQpO1xuICAgICAgICBpZiAoZGVsdGEpIHsgLy8gZWxzZSwgd2FybiBhYm91dCBpbnZhbGlkIGlucHV0P1xuICAgICAgICAgICAgdGhpcy51bnNlbGVjdCgpO1xuICAgICAgICAgICAgdGhpcy5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgdHlwZTogJ0NIQU5HRV9EQVRFJyxcbiAgICAgICAgICAgICAgICBkYXRlTWFya2VyOiBzdGF0ZS5kYXRlRW52LmFkZChzdGF0ZS5jdXJyZW50RGF0ZSwgZGVsdGEpLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZ2V0RGF0ZSgpIHtcbiAgICAgICAgbGV0IHN0YXRlID0gdGhpcy5nZXRDdXJyZW50RGF0YSgpO1xuICAgICAgICByZXR1cm4gc3RhdGUuZGF0ZUVudi50b0RhdGUoc3RhdGUuY3VycmVudERhdGUpO1xuICAgIH1cbiAgICAvLyBEYXRlIEZvcm1hdHRpbmcgVXRpbHNcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIGZvcm1hdERhdGUoZCwgZm9ybWF0dGVyKSB7XG4gICAgICAgIGxldCB7IGRhdGVFbnYgfSA9IHRoaXMuZ2V0Q3VycmVudERhdGEoKTtcbiAgICAgICAgcmV0dXJuIGRhdGVFbnYuZm9ybWF0KGRhdGVFbnYuY3JlYXRlTWFya2VyKGQpLCBjcmVhdGVGb3JtYXR0ZXIoZm9ybWF0dGVyKSk7XG4gICAgfVxuICAgIC8vIGBzZXR0aW5nc2AgaXMgZm9yIGZvcm1hdHRlciBBTkQgaXNFbmRFeGNsdXNpdmVcbiAgICBmb3JtYXRSYW5nZShkMCwgZDEsIHNldHRpbmdzKSB7XG4gICAgICAgIGxldCB7IGRhdGVFbnYgfSA9IHRoaXMuZ2V0Q3VycmVudERhdGEoKTtcbiAgICAgICAgcmV0dXJuIGRhdGVFbnYuZm9ybWF0UmFuZ2UoZGF0ZUVudi5jcmVhdGVNYXJrZXIoZDApLCBkYXRlRW52LmNyZWF0ZU1hcmtlcihkMSksIGNyZWF0ZUZvcm1hdHRlcihzZXR0aW5ncyksIHNldHRpbmdzKTtcbiAgICB9XG4gICAgZm9ybWF0SXNvKGQsIG9taXRUaW1lKSB7XG4gICAgICAgIGxldCB7IGRhdGVFbnYgfSA9IHRoaXMuZ2V0Q3VycmVudERhdGEoKTtcbiAgICAgICAgcmV0dXJuIGRhdGVFbnYuZm9ybWF0SXNvKGRhdGVFbnYuY3JlYXRlTWFya2VyKGQpLCB7IG9taXRUaW1lIH0pO1xuICAgIH1cbiAgICAvLyBEYXRlIFNlbGVjdGlvbiAvIEV2ZW50IFNlbGVjdGlvbiAvIERheUNsaWNrXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBzZWxlY3QoZGF0ZU9yT2JqLCBlbmREYXRlKSB7XG4gICAgICAgIGxldCBzZWxlY3Rpb25JbnB1dDtcbiAgICAgICAgaWYgKGVuZERhdGUgPT0gbnVsbCkge1xuICAgICAgICAgICAgaWYgKGRhdGVPck9iai5zdGFydCAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgc2VsZWN0aW9uSW5wdXQgPSBkYXRlT3JPYmo7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBzZWxlY3Rpb25JbnB1dCA9IHtcbiAgICAgICAgICAgICAgICAgICAgc3RhcnQ6IGRhdGVPck9iaixcbiAgICAgICAgICAgICAgICAgICAgZW5kOiBudWxsLFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBzZWxlY3Rpb25JbnB1dCA9IHtcbiAgICAgICAgICAgICAgICBzdGFydDogZGF0ZU9yT2JqLFxuICAgICAgICAgICAgICAgIGVuZDogZW5kRGF0ZSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHN0YXRlID0gdGhpcy5nZXRDdXJyZW50RGF0YSgpO1xuICAgICAgICBsZXQgc2VsZWN0aW9uID0gcGFyc2VEYXRlU3BhbihzZWxlY3Rpb25JbnB1dCwgc3RhdGUuZGF0ZUVudiwgY3JlYXRlRHVyYXRpb24oeyBkYXlzOiAxIH0pKTtcbiAgICAgICAgaWYgKHNlbGVjdGlvbikgeyAvLyB0aHJvdyBwYXJzZSBlcnJvciBvdGhlcndpc2U/XG4gICAgICAgICAgICB0aGlzLmRpc3BhdGNoKHsgdHlwZTogJ1NFTEVDVF9EQVRFUycsIHNlbGVjdGlvbiB9KTtcbiAgICAgICAgICAgIHRyaWdnZXJEYXRlU2VsZWN0KHNlbGVjdGlvbiwgbnVsbCwgc3RhdGUpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHVuc2VsZWN0KHBldikge1xuICAgICAgICBsZXQgc3RhdGUgPSB0aGlzLmdldEN1cnJlbnREYXRhKCk7XG4gICAgICAgIGlmIChzdGF0ZS5kYXRlU2VsZWN0aW9uKSB7XG4gICAgICAgICAgICB0aGlzLmRpc3BhdGNoKHsgdHlwZTogJ1VOU0VMRUNUX0RBVEVTJyB9KTtcbiAgICAgICAgICAgIHRyaWdnZXJEYXRlVW5zZWxlY3QocGV2LCBzdGF0ZSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gUHVibGljIEV2ZW50cyBBUElcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIGFkZEV2ZW50KGV2ZW50SW5wdXQsIHNvdXJjZUlucHV0KSB7XG4gICAgICAgIGlmIChldmVudElucHV0IGluc3RhbmNlb2YgRXZlbnRJbXBsKSB7XG4gICAgICAgICAgICBsZXQgZGVmID0gZXZlbnRJbnB1dC5fZGVmO1xuICAgICAgICAgICAgbGV0IGluc3RhbmNlID0gZXZlbnRJbnB1dC5faW5zdGFuY2U7XG4gICAgICAgICAgICBsZXQgY3VycmVudERhdGEgPSB0aGlzLmdldEN1cnJlbnREYXRhKCk7XG4gICAgICAgICAgICAvLyBub3QgYWxyZWFkeSBwcmVzZW50PyBkb24ndCB3YW50IHRvIGFkZCBhbiBvbGQgc25hcHNob3RcbiAgICAgICAgICAgIGlmICghY3VycmVudERhdGEuZXZlbnRTdG9yZS5kZWZzW2RlZi5kZWZJZF0pIHtcbiAgICAgICAgICAgICAgICB0aGlzLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogJ0FERF9FVkVOVFMnLFxuICAgICAgICAgICAgICAgICAgICBldmVudFN0b3JlOiBldmVudFR1cGxlVG9TdG9yZSh7IGRlZiwgaW5zdGFuY2UgfSksIC8vIFRPRE86IGJldHRlciB1dGlsIGZvciB0d28gYXJncz9cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB0aGlzLnRyaWdnZXJFdmVudEFkZChldmVudElucHV0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBldmVudElucHV0O1xuICAgICAgICB9XG4gICAgICAgIGxldCBzdGF0ZSA9IHRoaXMuZ2V0Q3VycmVudERhdGEoKTtcbiAgICAgICAgbGV0IGV2ZW50U291cmNlO1xuICAgICAgICBpZiAoc291cmNlSW5wdXQgaW5zdGFuY2VvZiBFdmVudFNvdXJjZUltcGwpIHtcbiAgICAgICAgICAgIGV2ZW50U291cmNlID0gc291cmNlSW5wdXQuaW50ZXJuYWxFdmVudFNvdXJjZTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0eXBlb2Ygc291cmNlSW5wdXQgPT09ICdib29sZWFuJykge1xuICAgICAgICAgICAgaWYgKHNvdXJjZUlucHV0KSB7IC8vIHRydWUuIHBhcnQgb2YgdGhlIGZpcnN0IGV2ZW50IHNvdXJjZVxuICAgICAgICAgICAgICAgIFtldmVudFNvdXJjZV0gPSBoYXNoVmFsdWVzVG9BcnJheShzdGF0ZS5ldmVudFNvdXJjZXMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHNvdXJjZUlucHV0ICE9IG51bGwpIHsgLy8gYW4gSUQuIGFjY2VwdHMgYSBudW1iZXIgdG9vXG4gICAgICAgICAgICBsZXQgc291cmNlQXBpID0gdGhpcy5nZXRFdmVudFNvdXJjZUJ5SWQoc291cmNlSW5wdXQpOyAvLyBUT0RPOiB1c2UgYW4gaW50ZXJuYWwgZnVuY3Rpb25cbiAgICAgICAgICAgIGlmICghc291cmNlQXBpKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKGBDb3VsZCBub3QgZmluZCBhbiBldmVudCBzb3VyY2Ugd2l0aCBJRCBcIiR7c291cmNlSW5wdXR9XCJgKTsgLy8gVE9ETzogdGVzdFxuICAgICAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZXZlbnRTb3VyY2UgPSBzb3VyY2VBcGkuaW50ZXJuYWxFdmVudFNvdXJjZTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgdHVwbGUgPSBwYXJzZUV2ZW50KGV2ZW50SW5wdXQsIGV2ZW50U291cmNlLCBzdGF0ZSwgZmFsc2UpO1xuICAgICAgICBpZiAodHVwbGUpIHtcbiAgICAgICAgICAgIGxldCBuZXdFdmVudEFwaSA9IG5ldyBFdmVudEltcGwoc3RhdGUsIHR1cGxlLmRlZiwgdHVwbGUuZGVmLnJlY3VycmluZ0RlZiA/IG51bGwgOiB0dXBsZS5pbnN0YW5jZSk7XG4gICAgICAgICAgICB0aGlzLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICB0eXBlOiAnQUREX0VWRU5UUycsXG4gICAgICAgICAgICAgICAgZXZlbnRTdG9yZTogZXZlbnRUdXBsZVRvU3RvcmUodHVwbGUpLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB0aGlzLnRyaWdnZXJFdmVudEFkZChuZXdFdmVudEFwaSk7XG4gICAgICAgICAgICByZXR1cm4gbmV3RXZlbnRBcGk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIHRyaWdnZXJFdmVudEFkZChldmVudEFwaSkge1xuICAgICAgICBsZXQgeyBlbWl0dGVyIH0gPSB0aGlzLmdldEN1cnJlbnREYXRhKCk7XG4gICAgICAgIGVtaXR0ZXIudHJpZ2dlcignZXZlbnRBZGQnLCB7XG4gICAgICAgICAgICBldmVudDogZXZlbnRBcGksXG4gICAgICAgICAgICByZWxhdGVkRXZlbnRzOiBbXSxcbiAgICAgICAgICAgIHJldmVydDogKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnUkVNT1ZFX0VWRU5UUycsXG4gICAgICAgICAgICAgICAgICAgIGV2ZW50U3RvcmU6IGV2ZW50QXBpVG9TdG9yZShldmVudEFwaSksXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICB9XG4gICAgLy8gVE9ETzogb3B0aW1pemVcbiAgICBnZXRFdmVudEJ5SWQoaWQpIHtcbiAgICAgICAgbGV0IHN0YXRlID0gdGhpcy5nZXRDdXJyZW50RGF0YSgpO1xuICAgICAgICBsZXQgeyBkZWZzLCBpbnN0YW5jZXMgfSA9IHN0YXRlLmV2ZW50U3RvcmU7XG4gICAgICAgIGlkID0gU3RyaW5nKGlkKTtcbiAgICAgICAgZm9yIChsZXQgZGVmSWQgaW4gZGVmcykge1xuICAgICAgICAgICAgbGV0IGRlZiA9IGRlZnNbZGVmSWRdO1xuICAgICAgICAgICAgaWYgKGRlZi5wdWJsaWNJZCA9PT0gaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoZGVmLnJlY3VycmluZ0RlZikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbmV3IEV2ZW50SW1wbChzdGF0ZSwgZGVmLCBudWxsKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgaW5zdGFuY2VJZCBpbiBpbnN0YW5jZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGluc3RhbmNlID0gaW5zdGFuY2VzW2luc3RhbmNlSWRdO1xuICAgICAgICAgICAgICAgICAgICBpZiAoaW5zdGFuY2UuZGVmSWQgPT09IGRlZi5kZWZJZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBFdmVudEltcGwoc3RhdGUsIGRlZiwgaW5zdGFuY2UpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBnZXRFdmVudHMoKSB7XG4gICAgICAgIGxldCBjdXJyZW50RGF0YSA9IHRoaXMuZ2V0Q3VycmVudERhdGEoKTtcbiAgICAgICAgcmV0dXJuIGJ1aWxkRXZlbnRBcGlzKGN1cnJlbnREYXRhLmV2ZW50U3RvcmUsIGN1cnJlbnREYXRhKTtcbiAgICB9XG4gICAgcmVtb3ZlQWxsRXZlbnRzKCkge1xuICAgICAgICB0aGlzLmRpc3BhdGNoKHsgdHlwZTogJ1JFTU9WRV9BTExfRVZFTlRTJyB9KTtcbiAgICB9XG4gICAgLy8gUHVibGljIEV2ZW50IFNvdXJjZXMgQVBJXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBnZXRFdmVudFNvdXJjZXMoKSB7XG4gICAgICAgIGxldCBzdGF0ZSA9IHRoaXMuZ2V0Q3VycmVudERhdGEoKTtcbiAgICAgICAgbGV0IHNvdXJjZUhhc2ggPSBzdGF0ZS5ldmVudFNvdXJjZXM7XG4gICAgICAgIGxldCBzb3VyY2VBcGlzID0gW107XG4gICAgICAgIGZvciAobGV0IGludGVybmFsSWQgaW4gc291cmNlSGFzaCkge1xuICAgICAgICAgICAgc291cmNlQXBpcy5wdXNoKG5ldyBFdmVudFNvdXJjZUltcGwoc3RhdGUsIHNvdXJjZUhhc2hbaW50ZXJuYWxJZF0pKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc291cmNlQXBpcztcbiAgICB9XG4gICAgZ2V0RXZlbnRTb3VyY2VCeUlkKGlkKSB7XG4gICAgICAgIGxldCBzdGF0ZSA9IHRoaXMuZ2V0Q3VycmVudERhdGEoKTtcbiAgICAgICAgbGV0IHNvdXJjZUhhc2ggPSBzdGF0ZS5ldmVudFNvdXJjZXM7XG4gICAgICAgIGlkID0gU3RyaW5nKGlkKTtcbiAgICAgICAgZm9yIChsZXQgc291cmNlSWQgaW4gc291cmNlSGFzaCkge1xuICAgICAgICAgICAgaWYgKHNvdXJjZUhhc2hbc291cmNlSWRdLnB1YmxpY0lkID09PSBpZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgRXZlbnRTb3VyY2VJbXBsKHN0YXRlLCBzb3VyY2VIYXNoW3NvdXJjZUlkXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIGFkZEV2ZW50U291cmNlKHNvdXJjZUlucHV0KSB7XG4gICAgICAgIGxldCBzdGF0ZSA9IHRoaXMuZ2V0Q3VycmVudERhdGEoKTtcbiAgICAgICAgaWYgKHNvdXJjZUlucHV0IGluc3RhbmNlb2YgRXZlbnRTb3VyY2VJbXBsKSB7XG4gICAgICAgICAgICAvLyBub3QgYWxyZWFkeSBwcmVzZW50PyBkb24ndCB3YW50IHRvIGFkZCBhbiBvbGQgc25hcHNob3RcbiAgICAgICAgICAgIGlmICghc3RhdGUuZXZlbnRTb3VyY2VzW3NvdXJjZUlucHV0LmludGVybmFsRXZlbnRTb3VyY2Uuc291cmNlSWRdKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdBRERfRVZFTlRfU09VUkNFUycsXG4gICAgICAgICAgICAgICAgICAgIHNvdXJjZXM6IFtzb3VyY2VJbnB1dC5pbnRlcm5hbEV2ZW50U291cmNlXSxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBzb3VyY2VJbnB1dDtcbiAgICAgICAgfVxuICAgICAgICBsZXQgZXZlbnRTb3VyY2UgPSBwYXJzZUV2ZW50U291cmNlKHNvdXJjZUlucHV0LCBzdGF0ZSk7XG4gICAgICAgIGlmIChldmVudFNvdXJjZSkgeyAvLyBUT0RPOiBlcnJvciBvdGhlcndpc2U/XG4gICAgICAgICAgICB0aGlzLmRpc3BhdGNoKHsgdHlwZTogJ0FERF9FVkVOVF9TT1VSQ0VTJywgc291cmNlczogW2V2ZW50U291cmNlXSB9KTtcbiAgICAgICAgICAgIHJldHVybiBuZXcgRXZlbnRTb3VyY2VJbXBsKHN0YXRlLCBldmVudFNvdXJjZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIHJlbW92ZUFsbEV2ZW50U291cmNlcygpIHtcbiAgICAgICAgdGhpcy5kaXNwYXRjaCh7IHR5cGU6ICdSRU1PVkVfQUxMX0VWRU5UX1NPVVJDRVMnIH0pO1xuICAgIH1cbiAgICByZWZldGNoRXZlbnRzKCkge1xuICAgICAgICB0aGlzLmRpc3BhdGNoKHsgdHlwZTogJ0ZFVENIX0VWRU5UX1NPVVJDRVMnLCBpc1JlZmV0Y2g6IHRydWUgfSk7XG4gICAgfVxuICAgIC8vIFNjcm9sbFxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgc2Nyb2xsVG9UaW1lKHRpbWVJbnB1dCkge1xuICAgICAgICBsZXQgdGltZSA9IGNyZWF0ZUR1cmF0aW9uKHRpbWVJbnB1dCk7XG4gICAgICAgIGlmICh0aW1lKSB7XG4gICAgICAgICAgICB0aGlzLnRyaWdnZXIoJ19zY3JvbGxSZXF1ZXN0JywgeyB0aW1lIH0pO1xuICAgICAgICB9XG4gICAgfVxufVxuXG5mdW5jdGlvbiBwb2ludEluc2lkZVJlY3QocG9pbnQsIHJlY3QpIHtcbiAgICByZXR1cm4gcG9pbnQubGVmdCA+PSByZWN0LmxlZnQgJiZcbiAgICAgICAgcG9pbnQubGVmdCA8IHJlY3QucmlnaHQgJiZcbiAgICAgICAgcG9pbnQudG9wID49IHJlY3QudG9wICYmXG4gICAgICAgIHBvaW50LnRvcCA8IHJlY3QuYm90dG9tO1xufVxuLy8gUmV0dXJucyBhIG5ldyByZWN0YW5nbGUgdGhhdCBpcyB0aGUgaW50ZXJzZWN0aW9uIG9mIHRoZSB0d28gcmVjdGFuZ2xlcy4gSWYgdGhleSBkb24ndCBpbnRlcnNlY3QsIHJldHVybnMgZmFsc2VcbmZ1bmN0aW9uIGludGVyc2VjdFJlY3RzKHJlY3QxLCByZWN0Mikge1xuICAgIGxldCByZXMgPSB7XG4gICAgICAgIGxlZnQ6IE1hdGgubWF4KHJlY3QxLmxlZnQsIHJlY3QyLmxlZnQpLFxuICAgICAgICByaWdodDogTWF0aC5taW4ocmVjdDEucmlnaHQsIHJlY3QyLnJpZ2h0KSxcbiAgICAgICAgdG9wOiBNYXRoLm1heChyZWN0MS50b3AsIHJlY3QyLnRvcCksXG4gICAgICAgIGJvdHRvbTogTWF0aC5taW4ocmVjdDEuYm90dG9tLCByZWN0Mi5ib3R0b20pLFxuICAgIH07XG4gICAgaWYgKHJlcy5sZWZ0IDwgcmVzLnJpZ2h0ICYmIHJlcy50b3AgPCByZXMuYm90dG9tKSB7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbn1cbmZ1bmN0aW9uIHRyYW5zbGF0ZVJlY3QocmVjdCwgZGVsdGFYLCBkZWx0YVkpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBsZWZ0OiByZWN0LmxlZnQgKyBkZWx0YVgsXG4gICAgICAgIHJpZ2h0OiByZWN0LnJpZ2h0ICsgZGVsdGFYLFxuICAgICAgICB0b3A6IHJlY3QudG9wICsgZGVsdGFZLFxuICAgICAgICBib3R0b206IHJlY3QuYm90dG9tICsgZGVsdGFZLFxuICAgIH07XG59XG4vLyBSZXR1cm5zIGEgbmV3IHBvaW50IHRoYXQgd2lsbCBoYXZlIGJlZW4gbW92ZWQgdG8gcmVzaWRlIHdpdGhpbiB0aGUgZ2l2ZW4gcmVjdGFuZ2xlXG5mdW5jdGlvbiBjb25zdHJhaW5Qb2ludChwb2ludCwgcmVjdCkge1xuICAgIHJldHVybiB7XG4gICAgICAgIGxlZnQ6IE1hdGgubWluKE1hdGgubWF4KHBvaW50LmxlZnQsIHJlY3QubGVmdCksIHJlY3QucmlnaHQpLFxuICAgICAgICB0b3A6IE1hdGgubWluKE1hdGgubWF4KHBvaW50LnRvcCwgcmVjdC50b3ApLCByZWN0LmJvdHRvbSksXG4gICAgfTtcbn1cbi8vIFJldHVybnMgYSBwb2ludCB0aGF0IGlzIHRoZSBjZW50ZXIgb2YgdGhlIGdpdmVuIHJlY3RhbmdsZVxuZnVuY3Rpb24gZ2V0UmVjdENlbnRlcihyZWN0KSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgbGVmdDogKHJlY3QubGVmdCArIHJlY3QucmlnaHQpIC8gMixcbiAgICAgICAgdG9wOiAocmVjdC50b3AgKyByZWN0LmJvdHRvbSkgLyAyLFxuICAgIH07XG59XG4vLyBTdWJ0cmFjdHMgcG9pbnQyJ3MgY29vcmRpbmF0ZXMgZnJvbSBwb2ludDEncyBjb29yZGluYXRlcywgcmV0dXJuaW5nIGEgZGVsdGFcbmZ1bmN0aW9uIGRpZmZQb2ludHMocG9pbnQxLCBwb2ludDIpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBsZWZ0OiBwb2ludDEubGVmdCAtIHBvaW50Mi5sZWZ0LFxuICAgICAgICB0b3A6IHBvaW50MS50b3AgLSBwb2ludDIudG9wLFxuICAgIH07XG59XG5cbmNvbnN0IEVNUFRZX0VWRU5UX1NUT1JFID0gY3JlYXRlRW1wdHlFdmVudFN0b3JlKCk7IC8vIGZvciBwdXJlY29tcG9uZW50cy4gVE9ETzoga2VlcCBlbHNld2hlcmVcbmNsYXNzIFNwbGl0dGVyIHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgdGhpcy5nZXRLZXlzRm9yRXZlbnREZWZzID0gbWVtb2l6ZSh0aGlzLl9nZXRLZXlzRm9yRXZlbnREZWZzKTtcbiAgICAgICAgdGhpcy5zcGxpdERhdGVTZWxlY3Rpb24gPSBtZW1vaXplKHRoaXMuX3NwbGl0RGF0ZVNwYW4pO1xuICAgICAgICB0aGlzLnNwbGl0RXZlbnRTdG9yZSA9IG1lbW9pemUodGhpcy5fc3BsaXRFdmVudFN0b3JlKTtcbiAgICAgICAgdGhpcy5zcGxpdEluZGl2aWR1YWxVaSA9IG1lbW9pemUodGhpcy5fc3BsaXRJbmRpdmlkdWFsVWkpO1xuICAgICAgICB0aGlzLnNwbGl0RXZlbnREcmFnID0gbWVtb2l6ZSh0aGlzLl9zcGxpdEludGVyYWN0aW9uKTtcbiAgICAgICAgdGhpcy5zcGxpdEV2ZW50UmVzaXplID0gbWVtb2l6ZSh0aGlzLl9zcGxpdEludGVyYWN0aW9uKTtcbiAgICAgICAgdGhpcy5ldmVudFVpQnVpbGRlcnMgPSB7fTsgLy8gVE9ETzogdHlwZXNjcmlwdCBwcm90ZWN0aW9uXG4gICAgfVxuICAgIHNwbGl0UHJvcHMocHJvcHMpIHtcbiAgICAgICAgbGV0IGtleUluZm9zID0gdGhpcy5nZXRLZXlJbmZvKHByb3BzKTtcbiAgICAgICAgbGV0IGRlZktleXMgPSB0aGlzLmdldEtleXNGb3JFdmVudERlZnMocHJvcHMuZXZlbnRTdG9yZSk7XG4gICAgICAgIGxldCBkYXRlU2VsZWN0aW9ucyA9IHRoaXMuc3BsaXREYXRlU2VsZWN0aW9uKHByb3BzLmRhdGVTZWxlY3Rpb24pO1xuICAgICAgICBsZXQgaW5kaXZpZHVhbFVpID0gdGhpcy5zcGxpdEluZGl2aWR1YWxVaShwcm9wcy5ldmVudFVpQmFzZXMsIGRlZktleXMpOyAvLyB0aGUgaW5kaXZpZHVhbCAqYmFzZXMqXG4gICAgICAgIGxldCBldmVudFN0b3JlcyA9IHRoaXMuc3BsaXRFdmVudFN0b3JlKHByb3BzLmV2ZW50U3RvcmUsIGRlZktleXMpO1xuICAgICAgICBsZXQgZXZlbnREcmFncyA9IHRoaXMuc3BsaXRFdmVudERyYWcocHJvcHMuZXZlbnREcmFnKTtcbiAgICAgICAgbGV0IGV2ZW50UmVzaXplcyA9IHRoaXMuc3BsaXRFdmVudFJlc2l6ZShwcm9wcy5ldmVudFJlc2l6ZSk7XG4gICAgICAgIGxldCBzcGxpdFByb3BzID0ge307XG4gICAgICAgIHRoaXMuZXZlbnRVaUJ1aWxkZXJzID0gbWFwSGFzaChrZXlJbmZvcywgKGluZm8sIGtleSkgPT4gdGhpcy5ldmVudFVpQnVpbGRlcnNba2V5XSB8fCBtZW1vaXplKGJ1aWxkRXZlbnRVaUZvcktleSkpO1xuICAgICAgICBmb3IgKGxldCBrZXkgaW4ga2V5SW5mb3MpIHtcbiAgICAgICAgICAgIGxldCBrZXlJbmZvID0ga2V5SW5mb3Nba2V5XTtcbiAgICAgICAgICAgIGxldCBldmVudFN0b3JlID0gZXZlbnRTdG9yZXNba2V5XSB8fCBFTVBUWV9FVkVOVF9TVE9SRTtcbiAgICAgICAgICAgIGxldCBidWlsZEV2ZW50VWkgPSB0aGlzLmV2ZW50VWlCdWlsZGVyc1trZXldO1xuICAgICAgICAgICAgc3BsaXRQcm9wc1trZXldID0ge1xuICAgICAgICAgICAgICAgIGJ1c2luZXNzSG91cnM6IGtleUluZm8uYnVzaW5lc3NIb3VycyB8fCBwcm9wcy5idXNpbmVzc0hvdXJzLFxuICAgICAgICAgICAgICAgIGRhdGVTZWxlY3Rpb246IGRhdGVTZWxlY3Rpb25zW2tleV0gfHwgbnVsbCxcbiAgICAgICAgICAgICAgICBldmVudFN0b3JlLFxuICAgICAgICAgICAgICAgIGV2ZW50VWlCYXNlczogYnVpbGRFdmVudFVpKHByb3BzLmV2ZW50VWlCYXNlc1snJ10sIGtleUluZm8udWksIGluZGl2aWR1YWxVaVtrZXldKSxcbiAgICAgICAgICAgICAgICBldmVudFNlbGVjdGlvbjogZXZlbnRTdG9yZS5pbnN0YW5jZXNbcHJvcHMuZXZlbnRTZWxlY3Rpb25dID8gcHJvcHMuZXZlbnRTZWxlY3Rpb24gOiAnJyxcbiAgICAgICAgICAgICAgICBldmVudERyYWc6IGV2ZW50RHJhZ3Nba2V5XSB8fCBudWxsLFxuICAgICAgICAgICAgICAgIGV2ZW50UmVzaXplOiBldmVudFJlc2l6ZXNba2V5XSB8fCBudWxsLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc3BsaXRQcm9wcztcbiAgICB9XG4gICAgX3NwbGl0RGF0ZVNwYW4oZGF0ZVNwYW4pIHtcbiAgICAgICAgbGV0IGRhdGVTcGFucyA9IHt9O1xuICAgICAgICBpZiAoZGF0ZVNwYW4pIHtcbiAgICAgICAgICAgIGxldCBrZXlzID0gdGhpcy5nZXRLZXlzRm9yRGF0ZVNwYW4oZGF0ZVNwYW4pO1xuICAgICAgICAgICAgZm9yIChsZXQga2V5IG9mIGtleXMpIHtcbiAgICAgICAgICAgICAgICBkYXRlU3BhbnNba2V5XSA9IGRhdGVTcGFuO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBkYXRlU3BhbnM7XG4gICAgfVxuICAgIF9nZXRLZXlzRm9yRXZlbnREZWZzKGV2ZW50U3RvcmUpIHtcbiAgICAgICAgcmV0dXJuIG1hcEhhc2goZXZlbnRTdG9yZS5kZWZzLCAoZXZlbnREZWYpID0+IHRoaXMuZ2V0S2V5c0ZvckV2ZW50RGVmKGV2ZW50RGVmKSk7XG4gICAgfVxuICAgIF9zcGxpdEV2ZW50U3RvcmUoZXZlbnRTdG9yZSwgZGVmS2V5cykge1xuICAgICAgICBsZXQgeyBkZWZzLCBpbnN0YW5jZXMgfSA9IGV2ZW50U3RvcmU7XG4gICAgICAgIGxldCBzcGxpdFN0b3JlcyA9IHt9O1xuICAgICAgICBmb3IgKGxldCBkZWZJZCBpbiBkZWZzKSB7XG4gICAgICAgICAgICBmb3IgKGxldCBrZXkgb2YgZGVmS2V5c1tkZWZJZF0pIHtcbiAgICAgICAgICAgICAgICBpZiAoIXNwbGl0U3RvcmVzW2tleV0pIHtcbiAgICAgICAgICAgICAgICAgICAgc3BsaXRTdG9yZXNba2V5XSA9IGNyZWF0ZUVtcHR5RXZlbnRTdG9yZSgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBzcGxpdFN0b3Jlc1trZXldLmRlZnNbZGVmSWRdID0gZGVmc1tkZWZJZF07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZm9yIChsZXQgaW5zdGFuY2VJZCBpbiBpbnN0YW5jZXMpIHtcbiAgICAgICAgICAgIGxldCBpbnN0YW5jZSA9IGluc3RhbmNlc1tpbnN0YW5jZUlkXTtcbiAgICAgICAgICAgIGZvciAobGV0IGtleSBvZiBkZWZLZXlzW2luc3RhbmNlLmRlZklkXSkge1xuICAgICAgICAgICAgICAgIGlmIChzcGxpdFN0b3Jlc1trZXldKSB7IC8vIG11c3QgaGF2ZSBhbHJlYWR5IGJlZW4gY3JlYXRlZFxuICAgICAgICAgICAgICAgICAgICBzcGxpdFN0b3Jlc1trZXldLmluc3RhbmNlc1tpbnN0YW5jZUlkXSA9IGluc3RhbmNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc3BsaXRTdG9yZXM7XG4gICAgfVxuICAgIF9zcGxpdEluZGl2aWR1YWxVaShldmVudFVpQmFzZXMsIGRlZktleXMpIHtcbiAgICAgICAgbGV0IHNwbGl0SGFzaGVzID0ge307XG4gICAgICAgIGZvciAobGV0IGRlZklkIGluIGV2ZW50VWlCYXNlcykge1xuICAgICAgICAgICAgaWYgKGRlZklkKSB7IC8vIG5vdCB0aGUgJycga2V5XG4gICAgICAgICAgICAgICAgZm9yIChsZXQga2V5IG9mIGRlZktleXNbZGVmSWRdKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICghc3BsaXRIYXNoZXNba2V5XSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc3BsaXRIYXNoZXNba2V5XSA9IHt9O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHNwbGl0SGFzaGVzW2tleV1bZGVmSWRdID0gZXZlbnRVaUJhc2VzW2RlZklkXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNwbGl0SGFzaGVzO1xuICAgIH1cbiAgICBfc3BsaXRJbnRlcmFjdGlvbihpbnRlcmFjdGlvbikge1xuICAgICAgICBsZXQgc3BsaXRTdGF0ZXMgPSB7fTtcbiAgICAgICAgaWYgKGludGVyYWN0aW9uKSB7XG4gICAgICAgICAgICBsZXQgYWZmZWN0ZWRTdG9yZXMgPSB0aGlzLl9zcGxpdEV2ZW50U3RvcmUoaW50ZXJhY3Rpb24uYWZmZWN0ZWRFdmVudHMsIHRoaXMuX2dldEtleXNGb3JFdmVudERlZnMoaW50ZXJhY3Rpb24uYWZmZWN0ZWRFdmVudHMpKTtcbiAgICAgICAgICAgIC8vIGNhbid0IHJlbHkgb24gZGVmS2V5cyBiZWNhdXNlIGV2ZW50IGRhdGEgaXMgbXV0YXRlZFxuICAgICAgICAgICAgbGV0IG11dGF0ZWRLZXlzQnlEZWZJZCA9IHRoaXMuX2dldEtleXNGb3JFdmVudERlZnMoaW50ZXJhY3Rpb24ubXV0YXRlZEV2ZW50cyk7XG4gICAgICAgICAgICBsZXQgbXV0YXRlZFN0b3JlcyA9IHRoaXMuX3NwbGl0RXZlbnRTdG9yZShpbnRlcmFjdGlvbi5tdXRhdGVkRXZlbnRzLCBtdXRhdGVkS2V5c0J5RGVmSWQpO1xuICAgICAgICAgICAgbGV0IHBvcHVsYXRlID0gKGtleSkgPT4ge1xuICAgICAgICAgICAgICAgIGlmICghc3BsaXRTdGF0ZXNba2V5XSkge1xuICAgICAgICAgICAgICAgICAgICBzcGxpdFN0YXRlc1trZXldID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgYWZmZWN0ZWRFdmVudHM6IGFmZmVjdGVkU3RvcmVzW2tleV0gfHwgRU1QVFlfRVZFTlRfU1RPUkUsXG4gICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGVkRXZlbnRzOiBtdXRhdGVkU3RvcmVzW2tleV0gfHwgRU1QVFlfRVZFTlRfU1RPUkUsXG4gICAgICAgICAgICAgICAgICAgICAgICBpc0V2ZW50OiBpbnRlcmFjdGlvbi5pc0V2ZW50LFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBmb3IgKGxldCBrZXkgaW4gYWZmZWN0ZWRTdG9yZXMpIHtcbiAgICAgICAgICAgICAgICBwb3B1bGF0ZShrZXkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yIChsZXQga2V5IGluIG11dGF0ZWRTdG9yZXMpIHtcbiAgICAgICAgICAgICAgICBwb3B1bGF0ZShrZXkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzcGxpdFN0YXRlcztcbiAgICB9XG59XG5mdW5jdGlvbiBidWlsZEV2ZW50VWlGb3JLZXkoYWxsVWksIGV2ZW50VWlGb3JLZXksIGluZGl2aWR1YWxVaSkge1xuICAgIGxldCBiYXNlUGFydHMgPSBbXTtcbiAgICBpZiAoYWxsVWkpIHtcbiAgICAgICAgYmFzZVBhcnRzLnB1c2goYWxsVWkpO1xuICAgIH1cbiAgICBpZiAoZXZlbnRVaUZvcktleSkge1xuICAgICAgICBiYXNlUGFydHMucHVzaChldmVudFVpRm9yS2V5KTtcbiAgICB9XG4gICAgbGV0IHN0dWZmID0ge1xuICAgICAgICAnJzogY29tYmluZUV2ZW50VWlzKGJhc2VQYXJ0cyksXG4gICAgfTtcbiAgICBpZiAoaW5kaXZpZHVhbFVpKSB7XG4gICAgICAgIE9iamVjdC5hc3NpZ24oc3R1ZmYsIGluZGl2aWR1YWxVaSk7XG4gICAgfVxuICAgIHJldHVybiBzdHVmZjtcbn1cblxuZnVuY3Rpb24gZ2V0RGF0ZU1ldGEoZGF0ZSwgdG9kYXlSYW5nZSwgbm93RGF0ZSwgZGF0ZVByb2ZpbGUpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBkb3c6IGRhdGUuZ2V0VVRDRGF5KCksXG4gICAgICAgIGlzRGlzYWJsZWQ6IEJvb2xlYW4oZGF0ZVByb2ZpbGUgJiYgKCFkYXRlUHJvZmlsZS5hY3RpdmVSYW5nZSB8fCAhcmFuZ2VDb250YWluc01hcmtlcihkYXRlUHJvZmlsZS5hY3RpdmVSYW5nZSwgZGF0ZSkpKSxcbiAgICAgICAgaXNPdGhlcjogQm9vbGVhbihkYXRlUHJvZmlsZSAmJiAhcmFuZ2VDb250YWluc01hcmtlcihkYXRlUHJvZmlsZS5jdXJyZW50UmFuZ2UsIGRhdGUpKSxcbiAgICAgICAgaXNUb2RheTogQm9vbGVhbih0b2RheVJhbmdlICYmIHJhbmdlQ29udGFpbnNNYXJrZXIodG9kYXlSYW5nZSwgZGF0ZSkpLFxuICAgICAgICBpc1Bhc3Q6IEJvb2xlYW4obm93RGF0ZSA/IChkYXRlIDwgbm93RGF0ZSkgOiB0b2RheVJhbmdlID8gKGRhdGUgPCB0b2RheVJhbmdlLnN0YXJ0KSA6IGZhbHNlKSxcbiAgICAgICAgaXNGdXR1cmU6IEJvb2xlYW4obm93RGF0ZSA/IChkYXRlID4gbm93RGF0ZSkgOiB0b2RheVJhbmdlID8gKGRhdGUgPj0gdG9kYXlSYW5nZS5lbmQpIDogZmFsc2UpLFxuICAgIH07XG59XG5mdW5jdGlvbiBnZXREYXlDbGFzc05hbWVzKG1ldGEsIHRoZW1lKSB7XG4gICAgbGV0IGNsYXNzTmFtZXMgPSBbXG4gICAgICAgICdmYy1kYXknLFxuICAgICAgICBgZmMtZGF5LSR7REFZX0lEU1ttZXRhLmRvd119YCxcbiAgICBdO1xuICAgIGlmIChtZXRhLmlzRGlzYWJsZWQpIHtcbiAgICAgICAgY2xhc3NOYW1lcy5wdXNoKCdmYy1kYXktZGlzYWJsZWQnKTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGlmIChtZXRhLmlzVG9kYXkpIHtcbiAgICAgICAgICAgIGNsYXNzTmFtZXMucHVzaCgnZmMtZGF5LXRvZGF5Jyk7XG4gICAgICAgICAgICBjbGFzc05hbWVzLnB1c2godGhlbWUuZ2V0Q2xhc3MoJ3RvZGF5JykpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChtZXRhLmlzUGFzdCkge1xuICAgICAgICAgICAgY2xhc3NOYW1lcy5wdXNoKCdmYy1kYXktcGFzdCcpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChtZXRhLmlzRnV0dXJlKSB7XG4gICAgICAgICAgICBjbGFzc05hbWVzLnB1c2goJ2ZjLWRheS1mdXR1cmUnKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobWV0YS5pc090aGVyKSB7XG4gICAgICAgICAgICBjbGFzc05hbWVzLnB1c2goJ2ZjLWRheS1vdGhlcicpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBjbGFzc05hbWVzO1xufVxuZnVuY3Rpb24gZ2V0U2xvdENsYXNzTmFtZXMobWV0YSwgdGhlbWUpIHtcbiAgICBsZXQgY2xhc3NOYW1lcyA9IFtcbiAgICAgICAgJ2ZjLXNsb3QnLFxuICAgICAgICBgZmMtc2xvdC0ke0RBWV9JRFNbbWV0YS5kb3ddfWAsXG4gICAgXTtcbiAgICBpZiAobWV0YS5pc0Rpc2FibGVkKSB7XG4gICAgICAgIGNsYXNzTmFtZXMucHVzaCgnZmMtc2xvdC1kaXNhYmxlZCcpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgaWYgKG1ldGEuaXNUb2RheSkge1xuICAgICAgICAgICAgY2xhc3NOYW1lcy5wdXNoKCdmYy1zbG90LXRvZGF5Jyk7XG4gICAgICAgICAgICBjbGFzc05hbWVzLnB1c2godGhlbWUuZ2V0Q2xhc3MoJ3RvZGF5JykpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChtZXRhLmlzUGFzdCkge1xuICAgICAgICAgICAgY2xhc3NOYW1lcy5wdXNoKCdmYy1zbG90LXBhc3QnKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobWV0YS5pc0Z1dHVyZSkge1xuICAgICAgICAgICAgY2xhc3NOYW1lcy5wdXNoKCdmYy1zbG90LWZ1dHVyZScpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBjbGFzc05hbWVzO1xufVxuXG5jb25zdCBEQVlfRk9STUFUID0gY3JlYXRlRm9ybWF0dGVyKHsgeWVhcjogJ251bWVyaWMnLCBtb250aDogJ2xvbmcnLCBkYXk6ICdudW1lcmljJyB9KTtcbmNvbnN0IFdFRUtfRk9STUFUID0gY3JlYXRlRm9ybWF0dGVyKHsgd2VlazogJ2xvbmcnIH0pO1xuZnVuY3Rpb24gYnVpbGROYXZMaW5rQXR0cnMoY29udGV4dCwgZGF0ZU1hcmtlciwgdmlld1R5cGUgPSAnZGF5JywgaXNUYWJiYWJsZSA9IHRydWUpIHtcbiAgICBjb25zdCB7IGRhdGVFbnYsIG9wdGlvbnMsIGNhbGVuZGFyQXBpIH0gPSBjb250ZXh0O1xuICAgIGxldCBkYXRlU3RyID0gZGF0ZUVudi5mb3JtYXQoZGF0ZU1hcmtlciwgdmlld1R5cGUgPT09ICd3ZWVrJyA/IFdFRUtfRk9STUFUIDogREFZX0ZPUk1BVCk7XG4gICAgaWYgKG9wdGlvbnMubmF2TGlua3MpIHtcbiAgICAgICAgbGV0IHpvbmVkRGF0ZSA9IGRhdGVFbnYudG9EYXRlKGRhdGVNYXJrZXIpO1xuICAgICAgICBjb25zdCBoYW5kbGVJbnRlcmFjdGlvbiA9IChldikgPT4ge1xuICAgICAgICAgICAgbGV0IGN1c3RvbUFjdGlvbiA9IHZpZXdUeXBlID09PSAnZGF5JyA/IG9wdGlvbnMubmF2TGlua0RheUNsaWNrIDpcbiAgICAgICAgICAgICAgICB2aWV3VHlwZSA9PT0gJ3dlZWsnID8gb3B0aW9ucy5uYXZMaW5rV2Vla0NsaWNrIDogbnVsbDtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgY3VzdG9tQWN0aW9uID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgY3VzdG9tQWN0aW9uLmNhbGwoY2FsZW5kYXJBcGksIGRhdGVFbnYudG9EYXRlKGRhdGVNYXJrZXIpLCBldik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGN1c3RvbUFjdGlvbiA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICAgICAgdmlld1R5cGUgPSBjdXN0b21BY3Rpb247XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhbGVuZGFyQXBpLnpvb21UbyhkYXRlTWFya2VyLCB2aWV3VHlwZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKHsgdGl0bGU6IGZvcm1hdFdpdGhPcmRpbmFscyhvcHRpb25zLm5hdkxpbmtIaW50LCBbZGF0ZVN0ciwgem9uZWREYXRlXSwgZGF0ZVN0ciksICdkYXRhLW5hdmxpbmsnOiAnJyB9LCAoaXNUYWJiYWJsZVxuICAgICAgICAgICAgPyBjcmVhdGVBcmlhQ2xpY2tBdHRycyhoYW5kbGVJbnRlcmFjdGlvbilcbiAgICAgICAgICAgIDogeyBvbkNsaWNrOiBoYW5kbGVJbnRlcmFjdGlvbiB9KSk7XG4gICAgfVxuICAgIHJldHVybiB7ICdhcmlhLWxhYmVsJzogZGF0ZVN0ciB9O1xufVxuXG5sZXQgX2lzUnRsU2Nyb2xsYmFyT25MZWZ0ID0gbnVsbDtcbmZ1bmN0aW9uIGdldElzUnRsU2Nyb2xsYmFyT25MZWZ0KCkge1xuICAgIGlmIChfaXNSdGxTY3JvbGxiYXJPbkxlZnQgPT09IG51bGwpIHtcbiAgICAgICAgX2lzUnRsU2Nyb2xsYmFyT25MZWZ0ID0gY29tcHV0ZUlzUnRsU2Nyb2xsYmFyT25MZWZ0KCk7XG4gICAgfVxuICAgIHJldHVybiBfaXNSdGxTY3JvbGxiYXJPbkxlZnQ7XG59XG5mdW5jdGlvbiBjb21wdXRlSXNSdGxTY3JvbGxiYXJPbkxlZnQoKSB7XG4gICAgbGV0IG91dGVyRWwgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICBhcHBseVN0eWxlKG91dGVyRWwsIHtcbiAgICAgICAgcG9zaXRpb246ICdhYnNvbHV0ZScsXG4gICAgICAgIHRvcDogLTEwMDAsXG4gICAgICAgIGxlZnQ6IDAsXG4gICAgICAgIGJvcmRlcjogMCxcbiAgICAgICAgcGFkZGluZzogMCxcbiAgICAgICAgb3ZlcmZsb3c6ICdzY3JvbGwnLFxuICAgICAgICBkaXJlY3Rpb246ICdydGwnLFxuICAgIH0pO1xuICAgIG91dGVyRWwuaW5uZXJIVE1MID0gJzxkaXY+PC9kaXY+JztcbiAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKG91dGVyRWwpO1xuICAgIGxldCBpbm5lckVsID0gb3V0ZXJFbC5maXJzdENoaWxkO1xuICAgIGxldCByZXMgPSBpbm5lckVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQgPiBvdXRlckVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQ7XG4gICAgcmVtb3ZlRWxlbWVudChvdXRlckVsKTtcbiAgICByZXR1cm4gcmVzO1xufVxuXG5sZXQgX3Njcm9sbGJhcldpZHRocztcbmZ1bmN0aW9uIGdldFNjcm9sbGJhcldpZHRocygpIHtcbiAgICBpZiAoIV9zY3JvbGxiYXJXaWR0aHMpIHtcbiAgICAgICAgX3Njcm9sbGJhcldpZHRocyA9IGNvbXB1dGVTY3JvbGxiYXJXaWR0aHMoKTtcbiAgICB9XG4gICAgcmV0dXJuIF9zY3JvbGxiYXJXaWR0aHM7XG59XG5mdW5jdGlvbiBjb21wdXRlU2Nyb2xsYmFyV2lkdGhzKCkge1xuICAgIGxldCBlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgIGVsLnN0eWxlLm92ZXJmbG93ID0gJ3Njcm9sbCc7XG4gICAgZWwuc3R5bGUucG9zaXRpb24gPSAnYWJzb2x1dGUnO1xuICAgIGVsLnN0eWxlLnRvcCA9ICctOTk5OXB4JztcbiAgICBlbC5zdHlsZS5sZWZ0ID0gJy05OTk5cHgnO1xuICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoZWwpO1xuICAgIGxldCByZXMgPSBjb21wdXRlU2Nyb2xsYmFyV2lkdGhzRm9yRWwoZWwpO1xuICAgIGRvY3VtZW50LmJvZHkucmVtb3ZlQ2hpbGQoZWwpO1xuICAgIHJldHVybiByZXM7XG59XG4vLyBXQVJOSU5HOiB3aWxsIGluY2x1ZGUgYm9yZGVyXG5mdW5jdGlvbiBjb21wdXRlU2Nyb2xsYmFyV2lkdGhzRm9yRWwoZWwpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICB4OiBlbC5vZmZzZXRIZWlnaHQgLSBlbC5jbGllbnRIZWlnaHQsXG4gICAgICAgIHk6IGVsLm9mZnNldFdpZHRoIC0gZWwuY2xpZW50V2lkdGgsXG4gICAgfTtcbn1cblxuZnVuY3Rpb24gY29tcHV0ZUVkZ2VzKGVsLCBnZXRQYWRkaW5nID0gZmFsc2UpIHtcbiAgICBsZXQgY29tcHV0ZWRTdHlsZSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGVsKTtcbiAgICBsZXQgYm9yZGVyTGVmdCA9IHBhcnNlSW50KGNvbXB1dGVkU3R5bGUuYm9yZGVyTGVmdFdpZHRoLCAxMCkgfHwgMDtcbiAgICBsZXQgYm9yZGVyUmlnaHQgPSBwYXJzZUludChjb21wdXRlZFN0eWxlLmJvcmRlclJpZ2h0V2lkdGgsIDEwKSB8fCAwO1xuICAgIGxldCBib3JkZXJUb3AgPSBwYXJzZUludChjb21wdXRlZFN0eWxlLmJvcmRlclRvcFdpZHRoLCAxMCkgfHwgMDtcbiAgICBsZXQgYm9yZGVyQm90dG9tID0gcGFyc2VJbnQoY29tcHV0ZWRTdHlsZS5ib3JkZXJCb3R0b21XaWR0aCwgMTApIHx8IDA7XG4gICAgbGV0IGJhZFNjcm9sbGJhcldpZHRocyA9IGNvbXB1dGVTY3JvbGxiYXJXaWR0aHNGb3JFbChlbCk7IC8vIGluY2x1ZGVzIGJvcmRlciFcbiAgICBsZXQgc2Nyb2xsYmFyTGVmdFJpZ2h0ID0gYmFkU2Nyb2xsYmFyV2lkdGhzLnkgLSBib3JkZXJMZWZ0IC0gYm9yZGVyUmlnaHQ7XG4gICAgbGV0IHNjcm9sbGJhckJvdHRvbSA9IGJhZFNjcm9sbGJhcldpZHRocy54IC0gYm9yZGVyVG9wIC0gYm9yZGVyQm90dG9tO1xuICAgIGxldCByZXMgPSB7XG4gICAgICAgIGJvcmRlckxlZnQsXG4gICAgICAgIGJvcmRlclJpZ2h0LFxuICAgICAgICBib3JkZXJUb3AsXG4gICAgICAgIGJvcmRlckJvdHRvbSxcbiAgICAgICAgc2Nyb2xsYmFyQm90dG9tLFxuICAgICAgICBzY3JvbGxiYXJMZWZ0OiAwLFxuICAgICAgICBzY3JvbGxiYXJSaWdodDogMCxcbiAgICB9O1xuICAgIGlmIChnZXRJc1J0bFNjcm9sbGJhck9uTGVmdCgpICYmIGNvbXB1dGVkU3R5bGUuZGlyZWN0aW9uID09PSAncnRsJykgeyAvLyBpcyB0aGUgc2Nyb2xsYmFyIG9uIHRoZSBsZWZ0IHNpZGU/XG4gICAgICAgIHJlcy5zY3JvbGxiYXJMZWZ0ID0gc2Nyb2xsYmFyTGVmdFJpZ2h0O1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmVzLnNjcm9sbGJhclJpZ2h0ID0gc2Nyb2xsYmFyTGVmdFJpZ2h0O1xuICAgIH1cbiAgICBpZiAoZ2V0UGFkZGluZykge1xuICAgICAgICByZXMucGFkZGluZ0xlZnQgPSBwYXJzZUludChjb21wdXRlZFN0eWxlLnBhZGRpbmdMZWZ0LCAxMCkgfHwgMDtcbiAgICAgICAgcmVzLnBhZGRpbmdSaWdodCA9IHBhcnNlSW50KGNvbXB1dGVkU3R5bGUucGFkZGluZ1JpZ2h0LCAxMCkgfHwgMDtcbiAgICAgICAgcmVzLnBhZGRpbmdUb3AgPSBwYXJzZUludChjb21wdXRlZFN0eWxlLnBhZGRpbmdUb3AsIDEwKSB8fCAwO1xuICAgICAgICByZXMucGFkZGluZ0JvdHRvbSA9IHBhcnNlSW50KGNvbXB1dGVkU3R5bGUucGFkZGluZ0JvdHRvbSwgMTApIHx8IDA7XG4gICAgfVxuICAgIHJldHVybiByZXM7XG59XG5mdW5jdGlvbiBjb21wdXRlSW5uZXJSZWN0KGVsLCBnb1dpdGhpblBhZGRpbmcgPSBmYWxzZSwgZG9Gcm9tV2luZG93Vmlld3BvcnQpIHtcbiAgICBsZXQgb3V0ZXJSZWN0ID0gZG9Gcm9tV2luZG93Vmlld3BvcnQgPyBlbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKSA6IGNvbXB1dGVSZWN0KGVsKTtcbiAgICBsZXQgZWRnZXMgPSBjb21wdXRlRWRnZXMoZWwsIGdvV2l0aGluUGFkZGluZyk7XG4gICAgbGV0IHJlcyA9IHtcbiAgICAgICAgbGVmdDogb3V0ZXJSZWN0LmxlZnQgKyBlZGdlcy5ib3JkZXJMZWZ0ICsgZWRnZXMuc2Nyb2xsYmFyTGVmdCxcbiAgICAgICAgcmlnaHQ6IG91dGVyUmVjdC5yaWdodCAtIGVkZ2VzLmJvcmRlclJpZ2h0IC0gZWRnZXMuc2Nyb2xsYmFyUmlnaHQsXG4gICAgICAgIHRvcDogb3V0ZXJSZWN0LnRvcCArIGVkZ2VzLmJvcmRlclRvcCxcbiAgICAgICAgYm90dG9tOiBvdXRlclJlY3QuYm90dG9tIC0gZWRnZXMuYm9yZGVyQm90dG9tIC0gZWRnZXMuc2Nyb2xsYmFyQm90dG9tLFxuICAgIH07XG4gICAgaWYgKGdvV2l0aGluUGFkZGluZykge1xuICAgICAgICByZXMubGVmdCArPSBlZGdlcy5wYWRkaW5nTGVmdDtcbiAgICAgICAgcmVzLnJpZ2h0IC09IGVkZ2VzLnBhZGRpbmdSaWdodDtcbiAgICAgICAgcmVzLnRvcCArPSBlZGdlcy5wYWRkaW5nVG9wO1xuICAgICAgICByZXMuYm90dG9tIC09IGVkZ2VzLnBhZGRpbmdCb3R0b207XG4gICAgfVxuICAgIHJldHVybiByZXM7XG59XG5mdW5jdGlvbiBjb21wdXRlUmVjdChlbCkge1xuICAgIGxldCByZWN0ID0gZWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgbGVmdDogcmVjdC5sZWZ0ICsgd2luZG93LnNjcm9sbFgsXG4gICAgICAgIHRvcDogcmVjdC50b3AgKyB3aW5kb3cuc2Nyb2xsWSxcbiAgICAgICAgcmlnaHQ6IHJlY3QucmlnaHQgKyB3aW5kb3cuc2Nyb2xsWCxcbiAgICAgICAgYm90dG9tOiByZWN0LmJvdHRvbSArIHdpbmRvdy5zY3JvbGxZLFxuICAgIH07XG59XG5mdW5jdGlvbiBjb21wdXRlQ2xpcHBlZENsaWVudFJlY3QoZWwpIHtcbiAgICBsZXQgY2xpcHBpbmdQYXJlbnRzID0gZ2V0Q2xpcHBpbmdQYXJlbnRzKGVsKTtcbiAgICBsZXQgcmVjdCA9IGVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIGZvciAobGV0IGNsaXBwaW5nUGFyZW50IG9mIGNsaXBwaW5nUGFyZW50cykge1xuICAgICAgICBsZXQgaW50ZXJzZWN0aW9uID0gaW50ZXJzZWN0UmVjdHMocmVjdCwgY2xpcHBpbmdQYXJlbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkpO1xuICAgICAgICBpZiAoaW50ZXJzZWN0aW9uKSB7XG4gICAgICAgICAgICByZWN0ID0gaW50ZXJzZWN0aW9uO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlY3Q7XG59XG4vLyBkb2VzIG5vdCByZXR1cm4gd2luZG93XG5mdW5jdGlvbiBnZXRDbGlwcGluZ1BhcmVudHMoZWwpIHtcbiAgICBsZXQgcGFyZW50cyA9IFtdO1xuICAgIHdoaWxlIChlbCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KSB7IC8vIHdpbGwgc3RvcCB3aGVuIGdldHMgdG8gZG9jdW1lbnQgb3IgbnVsbFxuICAgICAgICBsZXQgY29tcHV0ZWRTdHlsZSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGVsKTtcbiAgICAgICAgaWYgKGNvbXB1dGVkU3R5bGUucG9zaXRpb24gPT09ICdmaXhlZCcpIHtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIGlmICgoLyhhdXRvfHNjcm9sbCkvKS50ZXN0KGNvbXB1dGVkU3R5bGUub3ZlcmZsb3cgKyBjb21wdXRlZFN0eWxlLm92ZXJmbG93WSArIGNvbXB1dGVkU3R5bGUub3ZlcmZsb3dYKSkge1xuICAgICAgICAgICAgcGFyZW50cy5wdXNoKGVsKTtcbiAgICAgICAgfVxuICAgICAgICBlbCA9IGVsLnBhcmVudE5vZGU7XG4gICAgfVxuICAgIHJldHVybiBwYXJlbnRzO1xufVxuXG4vKlxuUmVjb3JkcyBvZmZzZXQgaW5mb3JtYXRpb24gZm9yIGEgc2V0IG9mIGVsZW1lbnRzLCByZWxhdGl2ZSB0byBhbiBvcmlnaW4gZWxlbWVudC5cbkNhbiByZWNvcmQgdGhlIGxlZnQvcmlnaHQgT1IgdGhlIHRvcC9ib3R0b20gT1IgYm90aC5cblByb3ZpZGVzIG1ldGhvZHMgZm9yIHF1ZXJ5aW5nIHRoZSBjYWNoZSBieSBwb3NpdGlvbi5cbiovXG5jbGFzcyBQb3NpdGlvbkNhY2hlIHtcbiAgICBjb25zdHJ1Y3RvcihvcmlnaW5FbCwgZWxzLCBpc0hvcml6b250YWwsIGlzVmVydGljYWwpIHtcbiAgICAgICAgdGhpcy5lbHMgPSBlbHM7XG4gICAgICAgIGxldCBvcmlnaW5DbGllbnRSZWN0ID0gdGhpcy5vcmlnaW5DbGllbnRSZWN0ID0gb3JpZ2luRWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7IC8vIHJlbGF0aXZlIHRvIHZpZXdwb3J0IHRvcC1sZWZ0XG4gICAgICAgIGlmIChpc0hvcml6b250YWwpIHtcbiAgICAgICAgICAgIHRoaXMuYnVpbGRFbEhvcml6b250YWxzKG9yaWdpbkNsaWVudFJlY3QubGVmdCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGlzVmVydGljYWwpIHtcbiAgICAgICAgICAgIHRoaXMuYnVpbGRFbFZlcnRpY2FscyhvcmlnaW5DbGllbnRSZWN0LnRvcCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gUG9wdWxhdGVzIHRoZSBsZWZ0L3JpZ2h0IGludGVybmFsIGNvb3JkaW5hdGUgYXJyYXlzXG4gICAgYnVpbGRFbEhvcml6b250YWxzKG9yaWdpbkNsaWVudExlZnQpIHtcbiAgICAgICAgbGV0IGxlZnRzID0gW107XG4gICAgICAgIGxldCByaWdodHMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgZWwgb2YgdGhpcy5lbHMpIHtcbiAgICAgICAgICAgIGxldCByZWN0ID0gZWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgICBsZWZ0cy5wdXNoKHJlY3QubGVmdCAtIG9yaWdpbkNsaWVudExlZnQpO1xuICAgICAgICAgICAgcmlnaHRzLnB1c2gocmVjdC5yaWdodCAtIG9yaWdpbkNsaWVudExlZnQpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMubGVmdHMgPSBsZWZ0cztcbiAgICAgICAgdGhpcy5yaWdodHMgPSByaWdodHM7XG4gICAgfVxuICAgIC8vIFBvcHVsYXRlcyB0aGUgdG9wL2JvdHRvbSBpbnRlcm5hbCBjb29yZGluYXRlIGFycmF5c1xuICAgIGJ1aWxkRWxWZXJ0aWNhbHMob3JpZ2luQ2xpZW50VG9wKSB7XG4gICAgICAgIGxldCB0b3BzID0gW107XG4gICAgICAgIGxldCBib3R0b21zID0gW107XG4gICAgICAgIGZvciAobGV0IGVsIG9mIHRoaXMuZWxzKSB7XG4gICAgICAgICAgICBsZXQgcmVjdCA9IGVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICAgICAgdG9wcy5wdXNoKHJlY3QudG9wIC0gb3JpZ2luQ2xpZW50VG9wKTtcbiAgICAgICAgICAgIGJvdHRvbXMucHVzaChyZWN0LmJvdHRvbSAtIG9yaWdpbkNsaWVudFRvcCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy50b3BzID0gdG9wcztcbiAgICAgICAgdGhpcy5ib3R0b21zID0gYm90dG9tcztcbiAgICB9XG4gICAgLy8gR2l2ZW4gYSBsZWZ0IG9mZnNldCAoZnJvbSBkb2N1bWVudCBsZWZ0KSwgcmV0dXJucyB0aGUgaW5kZXggb2YgdGhlIGVsIHRoYXQgaXQgaG9yaXpvbnRhbGx5IGludGVyc2VjdHMuXG4gICAgLy8gSWYgbm8gaW50ZXJzZWN0aW9uIGlzIG1hZGUsIHJldHVybnMgdW5kZWZpbmVkLlxuICAgIGxlZnRUb0luZGV4KGxlZnRQb3NpdGlvbikge1xuICAgICAgICBsZXQgeyBsZWZ0cywgcmlnaHRzIH0gPSB0aGlzO1xuICAgICAgICBsZXQgbGVuID0gbGVmdHMubGVuZ3RoO1xuICAgICAgICBsZXQgaTtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGxlbjsgaSArPSAxKSB7XG4gICAgICAgICAgICBpZiAobGVmdFBvc2l0aW9uID49IGxlZnRzW2ldICYmIGxlZnRQb3NpdGlvbiA8IHJpZ2h0c1tpXSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7IC8vIFRPRE86IGJldHRlclxuICAgIH1cbiAgICAvLyBHaXZlbiBhIHRvcCBvZmZzZXQgKGZyb20gZG9jdW1lbnQgdG9wKSwgcmV0dXJucyB0aGUgaW5kZXggb2YgdGhlIGVsIHRoYXQgaXQgdmVydGljYWxseSBpbnRlcnNlY3RzLlxuICAgIC8vIElmIG5vIGludGVyc2VjdGlvbiBpcyBtYWRlLCByZXR1cm5zIHVuZGVmaW5lZC5cbiAgICB0b3BUb0luZGV4KHRvcFBvc2l0aW9uKSB7XG4gICAgICAgIGxldCB7IHRvcHMsIGJvdHRvbXMgfSA9IHRoaXM7XG4gICAgICAgIGxldCBsZW4gPSB0b3BzLmxlbmd0aDtcbiAgICAgICAgbGV0IGk7XG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkgKz0gMSkge1xuICAgICAgICAgICAgaWYgKHRvcFBvc2l0aW9uID49IHRvcHNbaV0gJiYgdG9wUG9zaXRpb24gPCBib3R0b21zW2ldKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDsgLy8gVE9ETzogYmV0dGVyXG4gICAgfVxuICAgIC8vIEdldHMgdGhlIHdpZHRoIG9mIHRoZSBlbGVtZW50IGF0IHRoZSBnaXZlbiBpbmRleFxuICAgIGdldFdpZHRoKGxlZnRJbmRleCkge1xuICAgICAgICByZXR1cm4gdGhpcy5yaWdodHNbbGVmdEluZGV4XSAtIHRoaXMubGVmdHNbbGVmdEluZGV4XTtcbiAgICB9XG4gICAgLy8gR2V0cyB0aGUgaGVpZ2h0IG9mIHRoZSBlbGVtZW50IGF0IHRoZSBnaXZlbiBpbmRleFxuICAgIGdldEhlaWdodCh0b3BJbmRleCkge1xuICAgICAgICByZXR1cm4gdGhpcy5ib3R0b21zW3RvcEluZGV4XSAtIHRoaXMudG9wc1t0b3BJbmRleF07XG4gICAgfVxuICAgIHNpbWlsYXJUbyhvdGhlckNhY2hlKSB7XG4gICAgICAgIHJldHVybiBzaW1pbGFyTnVtQXJyYXlzKHRoaXMudG9wcyB8fCBbXSwgb3RoZXJDYWNoZS50b3BzIHx8IFtdKSAmJlxuICAgICAgICAgICAgc2ltaWxhck51bUFycmF5cyh0aGlzLmJvdHRvbXMgfHwgW10sIG90aGVyQ2FjaGUuYm90dG9tcyB8fCBbXSkgJiZcbiAgICAgICAgICAgIHNpbWlsYXJOdW1BcnJheXModGhpcy5sZWZ0cyB8fCBbXSwgb3RoZXJDYWNoZS5sZWZ0cyB8fCBbXSkgJiZcbiAgICAgICAgICAgIHNpbWlsYXJOdW1BcnJheXModGhpcy5yaWdodHMgfHwgW10sIG90aGVyQ2FjaGUucmlnaHRzIHx8IFtdKTtcbiAgICB9XG59XG5mdW5jdGlvbiBzaW1pbGFyTnVtQXJyYXlzKGEsIGIpIHtcbiAgICBjb25zdCBsZW4gPSBhLmxlbmd0aDtcbiAgICBpZiAobGVuICE9PSBiLmxlbmd0aCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgICAgaWYgKE1hdGgucm91bmQoYVtpXSkgIT09IE1hdGgucm91bmQoYltpXSkpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn1cblxuLyogZXNsaW50IG1heC1jbGFzc2VzLXBlci1maWxlOiBcIm9mZlwiICovXG4vKlxuQW4gb2JqZWN0IGZvciBnZXR0aW5nL3NldHRpbmcgc2Nyb2xsLXJlbGF0ZWQgaW5mb3JtYXRpb24gZm9yIGFuIGVsZW1lbnQuXG5JbnRlcm5hbGx5LCB0aGlzIGlzIGRvbmUgdmVyeSBkaWZmZXJlbnRseSBmb3Igd2luZG93IHZlcnN1cyBET00gZWxlbWVudCxcbnNvIHRoaXMgb2JqZWN0IHNlcnZlcyBhcyBhIGNvbW1vbiBpbnRlcmZhY2UuXG4qL1xuY2xhc3MgU2Nyb2xsQ29udHJvbGxlciB7XG4gICAgZ2V0TWF4U2Nyb2xsVG9wKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRTY3JvbGxIZWlnaHQoKSAtIHRoaXMuZ2V0Q2xpZW50SGVpZ2h0KCk7XG4gICAgfVxuICAgIGdldE1heFNjcm9sbExlZnQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFNjcm9sbFdpZHRoKCkgLSB0aGlzLmdldENsaWVudFdpZHRoKCk7XG4gICAgfVxuICAgIGNhblNjcm9sbFZlcnRpY2FsbHkoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldE1heFNjcm9sbFRvcCgpID4gMDtcbiAgICB9XG4gICAgY2FuU2Nyb2xsSG9yaXpvbnRhbGx5KCkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRNYXhTY3JvbGxMZWZ0KCkgPiAwO1xuICAgIH1cbiAgICBjYW5TY3JvbGxVcCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0U2Nyb2xsVG9wKCkgPiAwO1xuICAgIH1cbiAgICBjYW5TY3JvbGxEb3duKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRTY3JvbGxUb3AoKSA8IHRoaXMuZ2V0TWF4U2Nyb2xsVG9wKCk7XG4gICAgfVxuICAgIGNhblNjcm9sbExlZnQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFNjcm9sbExlZnQoKSA+IDA7XG4gICAgfVxuICAgIGNhblNjcm9sbFJpZ2h0KCkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRTY3JvbGxMZWZ0KCkgPCB0aGlzLmdldE1heFNjcm9sbExlZnQoKTtcbiAgICB9XG59XG5jbGFzcyBFbGVtZW50U2Nyb2xsQ29udHJvbGxlciBleHRlbmRzIFNjcm9sbENvbnRyb2xsZXIge1xuICAgIGNvbnN0cnVjdG9yKGVsKSB7XG4gICAgICAgIHN1cGVyKCk7XG4gICAgICAgIHRoaXMuZWwgPSBlbDtcbiAgICB9XG4gICAgZ2V0U2Nyb2xsVG9wKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5lbC5zY3JvbGxUb3A7XG4gICAgfVxuICAgIGdldFNjcm9sbExlZnQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmVsLnNjcm9sbExlZnQ7XG4gICAgfVxuICAgIHNldFNjcm9sbFRvcCh0b3ApIHtcbiAgICAgICAgdGhpcy5lbC5zY3JvbGxUb3AgPSB0b3A7XG4gICAgfVxuICAgIHNldFNjcm9sbExlZnQobGVmdCkge1xuICAgICAgICB0aGlzLmVsLnNjcm9sbExlZnQgPSBsZWZ0O1xuICAgIH1cbiAgICBnZXRTY3JvbGxXaWR0aCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZWwuc2Nyb2xsV2lkdGg7XG4gICAgfVxuICAgIGdldFNjcm9sbEhlaWdodCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZWwuc2Nyb2xsSGVpZ2h0O1xuICAgIH1cbiAgICBnZXRDbGllbnRIZWlnaHQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmVsLmNsaWVudEhlaWdodDtcbiAgICB9XG4gICAgZ2V0Q2xpZW50V2lkdGgoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmVsLmNsaWVudFdpZHRoO1xuICAgIH1cbn1cbmNsYXNzIFdpbmRvd1Njcm9sbENvbnRyb2xsZXIgZXh0ZW5kcyBTY3JvbGxDb250cm9sbGVyIHtcbiAgICBnZXRTY3JvbGxUb3AoKSB7XG4gICAgICAgIHJldHVybiB3aW5kb3cuc2Nyb2xsWTtcbiAgICB9XG4gICAgZ2V0U2Nyb2xsTGVmdCgpIHtcbiAgICAgICAgcmV0dXJuIHdpbmRvdy5zY3JvbGxYO1xuICAgIH1cbiAgICBzZXRTY3JvbGxUb3Aobikge1xuICAgICAgICB3aW5kb3cuc2Nyb2xsKHdpbmRvdy5zY3JvbGxYLCBuKTtcbiAgICB9XG4gICAgc2V0U2Nyb2xsTGVmdChuKSB7XG4gICAgICAgIHdpbmRvdy5zY3JvbGwobiwgd2luZG93LnNjcm9sbFkpO1xuICAgIH1cbiAgICBnZXRTY3JvbGxXaWR0aCgpIHtcbiAgICAgICAgcmV0dXJuIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zY3JvbGxXaWR0aDtcbiAgICB9XG4gICAgZ2V0U2Nyb2xsSGVpZ2h0KCkge1xuICAgICAgICByZXR1cm4gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbEhlaWdodDtcbiAgICB9XG4gICAgZ2V0Q2xpZW50SGVpZ2h0KCkge1xuICAgICAgICByZXR1cm4gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudEhlaWdodDtcbiAgICB9XG4gICAgZ2V0Q2xpZW50V2lkdGgoKSB7XG4gICAgICAgIHJldHVybiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50V2lkdGg7XG4gICAgfVxufVxuXG4vKlxuYW4gSU5URVJBQ1RBQkxFIGRhdGUgY29tcG9uZW50XG5cblBVUlBPU0VTOlxuLSBob29rIHVwIHRvIGZnLCBmaWxsLCBhbmQgbWlycm9yIHJlbmRlcmVyc1xuLSBpbnRlcmZhY2UgZm9yIGRyYWdnaW5nIGFuZCBoaXRzXG4qL1xuY2xhc3MgRGF0ZUNvbXBvbmVudCBleHRlbmRzIEJhc2VDb21wb25lbnQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICB0aGlzLnVpZCA9IGd1aWQoKTtcbiAgICB9XG4gICAgLy8gSGl0IFN5c3RlbVxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgcHJlcGFyZUhpdHMoKSB7XG4gICAgfVxuICAgIHF1ZXJ5SGl0KHBvc2l0aW9uTGVmdCwgcG9zaXRpb25Ub3AsIGVsV2lkdGgsIGVsSGVpZ2h0KSB7XG4gICAgICAgIHJldHVybiBudWxsOyAvLyB0aGlzIHNob3VsZCBiZSBhYnN0cmFjdFxuICAgIH1cbiAgICAvLyBQb2ludGVyIEludGVyYWN0aW9uIFV0aWxzXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBpc1ZhbGlkU2VnRG93bkVsKGVsKSB7XG4gICAgICAgIHJldHVybiAhdGhpcy5wcm9wcy5ldmVudERyYWcgJiYgLy8gSEFDS1xuICAgICAgICAgICAgIXRoaXMucHJvcHMuZXZlbnRSZXNpemUgJiYgLy8gSEFDS1xuICAgICAgICAgICAgIWVsZW1lbnRDbG9zZXN0KGVsLCAnLmZjLWV2ZW50LW1pcnJvcicpO1xuICAgIH1cbiAgICBpc1ZhbGlkRGF0ZURvd25FbChlbCkge1xuICAgICAgICByZXR1cm4gIWVsZW1lbnRDbG9zZXN0KGVsLCAnLmZjLWV2ZW50Om5vdCguZmMtYmctZXZlbnQpJykgJiZcbiAgICAgICAgICAgICFlbGVtZW50Q2xvc2VzdChlbCwgJy5mYy1tb3JlLWxpbmsnKSAmJiAvLyBhIFwibW9yZS4uXCIgbGlua1xuICAgICAgICAgICAgIWVsZW1lbnRDbG9zZXN0KGVsLCAnYVtkYXRhLW5hdmxpbmtdJykgJiYgLy8gYSBjbGlja2FibGUgbmF2IGxpbmtcbiAgICAgICAgICAgICFlbGVtZW50Q2xvc2VzdChlbCwgJy5mYy1wb3BvdmVyJyk7IC8vIGhhY2tcbiAgICB9XG59XG5cbmNsYXNzIE5hbWVkVGltZVpvbmVJbXBsIHtcbiAgICBjb25zdHJ1Y3Rvcih0aW1lWm9uZU5hbWUpIHtcbiAgICAgICAgdGhpcy50aW1lWm9uZU5hbWUgPSB0aW1lWm9uZU5hbWU7XG4gICAgfVxufVxuXG5jbGFzcyBTZWdIaWVyYXJjaHkge1xuICAgIGNvbnN0cnVjdG9yKGdldEVudHJ5VGhpY2tuZXNzID0gKGVudHJ5KSA9PiB7XG4gICAgICAgIC8vIGlmIG5vIHRoaWNrbmVzcyBrbm93biwgYXNzdW1lIDEgKGlmIDAsIHNvIHNtYWxsIGl0IGFsd2F5cyBmaXRzKVxuICAgICAgICByZXR1cm4gZW50cnkudGhpY2tuZXNzIHx8IDE7XG4gICAgfSkge1xuICAgICAgICB0aGlzLmdldEVudHJ5VGhpY2tuZXNzID0gZ2V0RW50cnlUaGlja25lc3M7XG4gICAgICAgIC8vIHNldHRpbmdzXG4gICAgICAgIHRoaXMuc3RyaWN0T3JkZXIgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5hbGxvd1Jlc2xpY2luZyA9IGZhbHNlO1xuICAgICAgICB0aGlzLm1heENvb3JkID0gLTE7IC8vIC0xIG1lYW5zIG5vIG1heFxuICAgICAgICB0aGlzLm1heFN0YWNrQ250ID0gLTE7IC8vIC0xIG1lYW5zIG5vIG1heFxuICAgICAgICB0aGlzLmxldmVsQ29vcmRzID0gW107IC8vIG9yZGVyZWRcbiAgICAgICAgdGhpcy5lbnRyaWVzQnlMZXZlbCA9IFtdOyAvLyBwYXJhbGxlbCB3aXRoIGxldmVsQ29vcmRzXG4gICAgICAgIHRoaXMuc3RhY2tDbnRzID0ge307IC8vIFRPRE86IHVzZSBiZXR0ZXIgdGVjaG5pcXVlIT9cbiAgICB9XG4gICAgYWRkU2VncyhpbnB1dHMpIHtcbiAgICAgICAgbGV0IGhpZGRlbkVudHJpZXMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgaW5wdXQgb2YgaW5wdXRzKSB7XG4gICAgICAgICAgICB0aGlzLmluc2VydEVudHJ5KGlucHV0LCBoaWRkZW5FbnRyaWVzKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gaGlkZGVuRW50cmllcztcbiAgICB9XG4gICAgaW5zZXJ0RW50cnkoZW50cnksIGhpZGRlbkVudHJpZXMpIHtcbiAgICAgICAgbGV0IGluc2VydGlvbiA9IHRoaXMuZmluZEluc2VydGlvbihlbnRyeSk7XG4gICAgICAgIGlmICh0aGlzLmlzSW5zZXJ0aW9uVmFsaWQoaW5zZXJ0aW9uLCBlbnRyeSkpIHtcbiAgICAgICAgICAgIHRoaXMuaW5zZXJ0RW50cnlBdChlbnRyeSwgaW5zZXJ0aW9uKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuaGFuZGxlSW52YWxpZEluc2VydGlvbihpbnNlcnRpb24sIGVudHJ5LCBoaWRkZW5FbnRyaWVzKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBpc0luc2VydGlvblZhbGlkKGluc2VydGlvbiwgZW50cnkpIHtcbiAgICAgICAgcmV0dXJuICh0aGlzLm1heENvb3JkID09PSAtMSB8fCBpbnNlcnRpb24ubGV2ZWxDb29yZCArIHRoaXMuZ2V0RW50cnlUaGlja25lc3MoZW50cnkpIDw9IHRoaXMubWF4Q29vcmQpICYmXG4gICAgICAgICAgICAodGhpcy5tYXhTdGFja0NudCA9PT0gLTEgfHwgaW5zZXJ0aW9uLnN0YWNrQ250IDwgdGhpcy5tYXhTdGFja0NudCk7XG4gICAgfVxuICAgIGhhbmRsZUludmFsaWRJbnNlcnRpb24oaW5zZXJ0aW9uLCBlbnRyeSwgaGlkZGVuRW50cmllcykge1xuICAgICAgICBpZiAodGhpcy5hbGxvd1Jlc2xpY2luZyAmJiBpbnNlcnRpb24udG91Y2hpbmdFbnRyeSkge1xuICAgICAgICAgICAgY29uc3QgaGlkZGVuRW50cnkgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGVudHJ5KSwgeyBzcGFuOiBpbnRlcnNlY3RTcGFucyhlbnRyeS5zcGFuLCBpbnNlcnRpb24udG91Y2hpbmdFbnRyeS5zcGFuKSB9KTtcbiAgICAgICAgICAgIGhpZGRlbkVudHJpZXMucHVzaChoaWRkZW5FbnRyeSk7XG4gICAgICAgICAgICB0aGlzLnNwbGl0RW50cnkoZW50cnksIGluc2VydGlvbi50b3VjaGluZ0VudHJ5LCBoaWRkZW5FbnRyaWVzKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGhpZGRlbkVudHJpZXMucHVzaChlbnRyeSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLypcbiAgICBEb2VzIE5PVCBhZGQgd2hhdCBoaXQgdGhlIGBiYXJyaWVyYCBpbnRvIGhpZGRlbkVudHJpZXMuIFNob3VsZCBhbHJlYWR5IGJlIGRvbmUuXG4gICAgKi9cbiAgICBzcGxpdEVudHJ5KGVudHJ5LCBiYXJyaWVyLCBoaWRkZW5FbnRyaWVzKSB7XG4gICAgICAgIGxldCBlbnRyeVNwYW4gPSBlbnRyeS5zcGFuO1xuICAgICAgICBsZXQgYmFycmllclNwYW4gPSBiYXJyaWVyLnNwYW47XG4gICAgICAgIGlmIChlbnRyeVNwYW4uc3RhcnQgPCBiYXJyaWVyU3Bhbi5zdGFydCkge1xuICAgICAgICAgICAgdGhpcy5pbnNlcnRFbnRyeSh7XG4gICAgICAgICAgICAgICAgaW5kZXg6IGVudHJ5LmluZGV4LFxuICAgICAgICAgICAgICAgIHRoaWNrbmVzczogZW50cnkudGhpY2tuZXNzLFxuICAgICAgICAgICAgICAgIHNwYW46IHsgc3RhcnQ6IGVudHJ5U3Bhbi5zdGFydCwgZW5kOiBiYXJyaWVyU3Bhbi5zdGFydCB9LFxuICAgICAgICAgICAgfSwgaGlkZGVuRW50cmllcyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGVudHJ5U3Bhbi5lbmQgPiBiYXJyaWVyU3Bhbi5lbmQpIHtcbiAgICAgICAgICAgIHRoaXMuaW5zZXJ0RW50cnkoe1xuICAgICAgICAgICAgICAgIGluZGV4OiBlbnRyeS5pbmRleCxcbiAgICAgICAgICAgICAgICB0aGlja25lc3M6IGVudHJ5LnRoaWNrbmVzcyxcbiAgICAgICAgICAgICAgICBzcGFuOiB7IHN0YXJ0OiBiYXJyaWVyU3Bhbi5lbmQsIGVuZDogZW50cnlTcGFuLmVuZCB9LFxuICAgICAgICAgICAgfSwgaGlkZGVuRW50cmllcyk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgaW5zZXJ0RW50cnlBdChlbnRyeSwgaW5zZXJ0aW9uKSB7XG4gICAgICAgIGxldCB7IGVudHJpZXNCeUxldmVsLCBsZXZlbENvb3JkcyB9ID0gdGhpcztcbiAgICAgICAgaWYgKGluc2VydGlvbi5sYXRlcmFsID09PSAtMSkge1xuICAgICAgICAgICAgLy8gY3JlYXRlIGEgbmV3IGxldmVsXG4gICAgICAgICAgICBpbnNlcnRBdChsZXZlbENvb3JkcywgaW5zZXJ0aW9uLmxldmVsLCBpbnNlcnRpb24ubGV2ZWxDb29yZCk7XG4gICAgICAgICAgICBpbnNlcnRBdChlbnRyaWVzQnlMZXZlbCwgaW5zZXJ0aW9uLmxldmVsLCBbZW50cnldKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIC8vIGluc2VydCBpbnRvIGV4aXN0aW5nIGxldmVsXG4gICAgICAgICAgICBpbnNlcnRBdChlbnRyaWVzQnlMZXZlbFtpbnNlcnRpb24ubGV2ZWxdLCBpbnNlcnRpb24ubGF0ZXJhbCwgZW50cnkpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuc3RhY2tDbnRzW2J1aWxkRW50cnlLZXkoZW50cnkpXSA9IGluc2VydGlvbi5zdGFja0NudDtcbiAgICB9XG4gICAgLypcbiAgICBkb2VzIG5vdCBjYXJlIGFib3V0IGxpbWl0c1xuICAgICovXG4gICAgZmluZEluc2VydGlvbihuZXdFbnRyeSkge1xuICAgICAgICBsZXQgeyBsZXZlbENvb3JkcywgZW50cmllc0J5TGV2ZWwsIHN0cmljdE9yZGVyLCBzdGFja0NudHMgfSA9IHRoaXM7XG4gICAgICAgIGxldCBsZXZlbENudCA9IGxldmVsQ29vcmRzLmxlbmd0aDtcbiAgICAgICAgbGV0IGNhbmRpZGF0ZUNvb3JkID0gMDtcbiAgICAgICAgbGV0IHRvdWNoaW5nTGV2ZWwgPSAtMTtcbiAgICAgICAgbGV0IHRvdWNoaW5nTGF0ZXJhbCA9IC0xO1xuICAgICAgICBsZXQgdG91Y2hpbmdFbnRyeSA9IG51bGw7XG4gICAgICAgIGxldCBzdGFja0NudCA9IDA7XG4gICAgICAgIGZvciAobGV0IHRyYWNraW5nTGV2ZWwgPSAwOyB0cmFja2luZ0xldmVsIDwgbGV2ZWxDbnQ7IHRyYWNraW5nTGV2ZWwgKz0gMSkge1xuICAgICAgICAgICAgY29uc3QgdHJhY2tpbmdDb29yZCA9IGxldmVsQ29vcmRzW3RyYWNraW5nTGV2ZWxdO1xuICAgICAgICAgICAgLy8gaWYgdGhlIGN1cnJlbnQgbGV2ZWwgaXMgcGFzdCB0aGUgcGxhY2VkIGVudHJ5LCB3ZSBoYXZlIGZvdW5kIGEgZ29vZCBlbXB0eSBzcGFjZSBhbmQgY2FuIHN0b3AuXG4gICAgICAgICAgICAvLyBpZiBzdHJpY3RPcmRlciwga2VlcCBmaW5kaW5nIG1vcmUgbGF0ZXJhbCBpbnRlcnNlY3Rpb25zLlxuICAgICAgICAgICAgaWYgKCFzdHJpY3RPcmRlciAmJiB0cmFja2luZ0Nvb3JkID49IGNhbmRpZGF0ZUNvb3JkICsgdGhpcy5nZXRFbnRyeVRoaWNrbmVzcyhuZXdFbnRyeSkpIHtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCB0cmFja2luZ0VudHJpZXMgPSBlbnRyaWVzQnlMZXZlbFt0cmFja2luZ0xldmVsXTtcbiAgICAgICAgICAgIGxldCB0cmFja2luZ0VudHJ5O1xuICAgICAgICAgICAgbGV0IHNlYXJjaFJlcyA9IGJpbmFyeVNlYXJjaCh0cmFja2luZ0VudHJpZXMsIG5ld0VudHJ5LnNwYW4uc3RhcnQsIGdldEVudHJ5U3BhbkVuZCk7IC8vIGZpbmQgZmlyc3QgZW50cnkgYWZ0ZXIgbmV3RW50cnkncyBlbmRcbiAgICAgICAgICAgIGxldCBsYXRlcmFsSW5kZXggPSBzZWFyY2hSZXNbMF0gKyBzZWFyY2hSZXNbMV07IC8vIGlmIGV4YWN0IG1hdGNoICh3aGljaCBkb2Vzbid0IGNvbGxpZGUpLCBnbyB0byBuZXh0IG9uZVxuICAgICAgICAgICAgd2hpbGUgKCAvLyBsb29wIHRocm91Z2ggZW50cmllcyB0aGF0IGhvcml6b250YWxseSBpbnRlcnNlY3RcbiAgICAgICAgICAgICh0cmFja2luZ0VudHJ5ID0gdHJhY2tpbmdFbnRyaWVzW2xhdGVyYWxJbmRleF0pICYmIC8vIGJ1dCBub3QgcGFzdCB0aGUgd2hvbGUgZW50cnkgbGlzdFxuICAgICAgICAgICAgICAgIHRyYWNraW5nRW50cnkuc3Bhbi5zdGFydCA8IG5ld0VudHJ5LnNwYW4uZW5kIC8vIGFuZCBub3QgZW50aXJlbHkgcGFzdCBuZXdFbnRyeVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgbGV0IHRyYWNraW5nRW50cnlCb3R0b20gPSB0cmFja2luZ0Nvb3JkICsgdGhpcy5nZXRFbnRyeVRoaWNrbmVzcyh0cmFja2luZ0VudHJ5KTtcbiAgICAgICAgICAgICAgICAvLyBpbnRlcnNlY3RzIGludG8gdGhlIHRvcCBvZiB0aGUgY2FuZGlkYXRlP1xuICAgICAgICAgICAgICAgIGlmICh0cmFja2luZ0VudHJ5Qm90dG9tID4gY2FuZGlkYXRlQ29vcmQpIHtcbiAgICAgICAgICAgICAgICAgICAgY2FuZGlkYXRlQ29vcmQgPSB0cmFja2luZ0VudHJ5Qm90dG9tO1xuICAgICAgICAgICAgICAgICAgICB0b3VjaGluZ0VudHJ5ID0gdHJhY2tpbmdFbnRyeTtcbiAgICAgICAgICAgICAgICAgICAgdG91Y2hpbmdMZXZlbCA9IHRyYWNraW5nTGV2ZWw7XG4gICAgICAgICAgICAgICAgICAgIHRvdWNoaW5nTGF0ZXJhbCA9IGxhdGVyYWxJbmRleDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gYnV0dHMgdXAgYWdhaW5zdCB0b3Agb2YgY2FuZGlkYXRlPyAod2lsbCBoYXBwZW4gaWYganVzdCBpbnRlcnNlY3RlZCBhcyB3ZWxsKVxuICAgICAgICAgICAgICAgIGlmICh0cmFja2luZ0VudHJ5Qm90dG9tID09PSBjYW5kaWRhdGVDb29yZCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBhY2N1bXVsYXRlIHRoZSBoaWdoZXN0IHBvc3NpYmxlIHN0YWNrQ250IG9mIHRoZSB0cmFja2luZ0VudHJpZXMgdGhhdCBidXR0IHVwXG4gICAgICAgICAgICAgICAgICAgIHN0YWNrQ250ID0gTWF0aC5tYXgoc3RhY2tDbnQsIHN0YWNrQ250c1tidWlsZEVudHJ5S2V5KHRyYWNraW5nRW50cnkpXSArIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBsYXRlcmFsSW5kZXggKz0gMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvLyB0aGUgZGVzdGluYXRpb24gbGV2ZWwgd2lsbCBiZSBhZnRlciB0b3VjaGluZ0VudHJ5J3MgbGV2ZWwuIGZpbmQgaXRcbiAgICAgICAgbGV0IGRlc3RMZXZlbCA9IDA7XG4gICAgICAgIGlmICh0b3VjaGluZ0VudHJ5KSB7XG4gICAgICAgICAgICBkZXN0TGV2ZWwgPSB0b3VjaGluZ0xldmVsICsgMTtcbiAgICAgICAgICAgIHdoaWxlIChkZXN0TGV2ZWwgPCBsZXZlbENudCAmJiBsZXZlbENvb3Jkc1tkZXN0TGV2ZWxdIDwgY2FuZGlkYXRlQ29vcmQpIHtcbiAgICAgICAgICAgICAgICBkZXN0TGV2ZWwgKz0gMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvLyBpZiBhZGRpbmcgdG8gYW4gZXhpc3RpbmcgbGV2ZWwsIGZpbmQgd2hlcmUgdG8gaW5zZXJ0XG4gICAgICAgIGxldCBkZXN0TGF0ZXJhbCA9IC0xO1xuICAgICAgICBpZiAoZGVzdExldmVsIDwgbGV2ZWxDbnQgJiYgbGV2ZWxDb29yZHNbZGVzdExldmVsXSA9PT0gY2FuZGlkYXRlQ29vcmQpIHtcbiAgICAgICAgICAgIGRlc3RMYXRlcmFsID0gYmluYXJ5U2VhcmNoKGVudHJpZXNCeUxldmVsW2Rlc3RMZXZlbF0sIG5ld0VudHJ5LnNwYW4uZW5kLCBnZXRFbnRyeVNwYW5FbmQpWzBdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB0b3VjaGluZ0xldmVsLFxuICAgICAgICAgICAgdG91Y2hpbmdMYXRlcmFsLFxuICAgICAgICAgICAgdG91Y2hpbmdFbnRyeSxcbiAgICAgICAgICAgIHN0YWNrQ250LFxuICAgICAgICAgICAgbGV2ZWxDb29yZDogY2FuZGlkYXRlQ29vcmQsXG4gICAgICAgICAgICBsZXZlbDogZGVzdExldmVsLFxuICAgICAgICAgICAgbGF0ZXJhbDogZGVzdExhdGVyYWwsXG4gICAgICAgIH07XG4gICAgfVxuICAgIC8vIHNvcnRlZCBieSBsZXZlbENvb3JkIChsb3dlc3QgdG8gaGlnaGVzdClcbiAgICB0b1JlY3RzKCkge1xuICAgICAgICBsZXQgeyBlbnRyaWVzQnlMZXZlbCwgbGV2ZWxDb29yZHMgfSA9IHRoaXM7XG4gICAgICAgIGxldCBsZXZlbENudCA9IGVudHJpZXNCeUxldmVsLmxlbmd0aDtcbiAgICAgICAgbGV0IHJlY3RzID0gW107XG4gICAgICAgIGZvciAobGV0IGxldmVsID0gMDsgbGV2ZWwgPCBsZXZlbENudDsgbGV2ZWwgKz0gMSkge1xuICAgICAgICAgICAgbGV0IGVudHJpZXMgPSBlbnRyaWVzQnlMZXZlbFtsZXZlbF07XG4gICAgICAgICAgICBsZXQgbGV2ZWxDb29yZCA9IGxldmVsQ29vcmRzW2xldmVsXTtcbiAgICAgICAgICAgIGZvciAobGV0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgICAgICAgICByZWN0cy5wdXNoKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZW50cnkpLCB7IHRoaWNrbmVzczogdGhpcy5nZXRFbnRyeVRoaWNrbmVzcyhlbnRyeSksIGxldmVsQ29vcmQgfSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZWN0cztcbiAgICB9XG59XG5mdW5jdGlvbiBnZXRFbnRyeVNwYW5FbmQoZW50cnkpIHtcbiAgICByZXR1cm4gZW50cnkuc3Bhbi5lbmQ7XG59XG5mdW5jdGlvbiBidWlsZEVudHJ5S2V5KGVudHJ5KSB7XG4gICAgcmV0dXJuIGVudHJ5LmluZGV4ICsgJzonICsgZW50cnkuc3Bhbi5zdGFydDtcbn1cbi8vIHJldHVybnMgZ3JvdXBzIHdpdGggZW50cmllcyBzb3J0ZWQgYnkgaW5wdXQgb3JkZXJcbmZ1bmN0aW9uIGdyb3VwSW50ZXJzZWN0aW5nRW50cmllcyhlbnRyaWVzKSB7XG4gICAgbGV0IG1lcmdlcyA9IFtdO1xuICAgIGZvciAobGV0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgbGV0IGZpbHRlcmVkTWVyZ2VzID0gW107XG4gICAgICAgIGxldCBodW5ncnlNZXJnZSA9IHtcbiAgICAgICAgICAgIHNwYW46IGVudHJ5LnNwYW4sXG4gICAgICAgICAgICBlbnRyaWVzOiBbZW50cnldLFxuICAgICAgICB9O1xuICAgICAgICBmb3IgKGxldCBtZXJnZSBvZiBtZXJnZXMpIHtcbiAgICAgICAgICAgIGlmIChpbnRlcnNlY3RTcGFucyhtZXJnZS5zcGFuLCBodW5ncnlNZXJnZS5zcGFuKSkge1xuICAgICAgICAgICAgICAgIGh1bmdyeU1lcmdlID0ge1xuICAgICAgICAgICAgICAgICAgICBlbnRyaWVzOiBtZXJnZS5lbnRyaWVzLmNvbmNhdChodW5ncnlNZXJnZS5lbnRyaWVzKSxcbiAgICAgICAgICAgICAgICAgICAgc3Bhbjogam9pblNwYW5zKG1lcmdlLnNwYW4sIGh1bmdyeU1lcmdlLnNwYW4pLFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBmaWx0ZXJlZE1lcmdlcy5wdXNoKG1lcmdlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBmaWx0ZXJlZE1lcmdlcy5wdXNoKGh1bmdyeU1lcmdlKTtcbiAgICAgICAgbWVyZ2VzID0gZmlsdGVyZWRNZXJnZXM7XG4gICAgfVxuICAgIHJldHVybiBtZXJnZXM7XG59XG5mdW5jdGlvbiBqb2luU3BhbnMoc3BhbjAsIHNwYW4xKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgc3RhcnQ6IE1hdGgubWluKHNwYW4wLnN0YXJ0LCBzcGFuMS5zdGFydCksXG4gICAgICAgIGVuZDogTWF0aC5tYXgoc3BhbjAuZW5kLCBzcGFuMS5lbmQpLFxuICAgIH07XG59XG5mdW5jdGlvbiBpbnRlcnNlY3RTcGFucyhzcGFuMCwgc3BhbjEpIHtcbiAgICBsZXQgc3RhcnQgPSBNYXRoLm1heChzcGFuMC5zdGFydCwgc3BhbjEuc3RhcnQpO1xuICAgIGxldCBlbmQgPSBNYXRoLm1pbihzcGFuMC5lbmQsIHNwYW4xLmVuZCk7XG4gICAgaWYgKHN0YXJ0IDwgZW5kKSB7XG4gICAgICAgIHJldHVybiB7IHN0YXJ0LCBlbmQgfTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG59XG4vLyBnZW5lcmFsIHV0aWxcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuZnVuY3Rpb24gaW5zZXJ0QXQoYXJyLCBpbmRleCwgaXRlbSkge1xuICAgIGFyci5zcGxpY2UoaW5kZXgsIDAsIGl0ZW0pO1xufVxuZnVuY3Rpb24gYmluYXJ5U2VhcmNoKGEsIHNlYXJjaFZhbCwgZ2V0SXRlbVZhbCkge1xuICAgIGxldCBzdGFydEluZGV4ID0gMDtcbiAgICBsZXQgZW5kSW5kZXggPSBhLmxlbmd0aDsgLy8gZXhjbHVzaXZlXG4gICAgaWYgKCFlbmRJbmRleCB8fCBzZWFyY2hWYWwgPCBnZXRJdGVtVmFsKGFbc3RhcnRJbmRleF0pKSB7IC8vIG5vIGl0ZW1zIE9SIGJlZm9yZSBmaXJzdCBpdGVtXG4gICAgICAgIHJldHVybiBbMCwgMF07XG4gICAgfVxuICAgIGlmIChzZWFyY2hWYWwgPiBnZXRJdGVtVmFsKGFbZW5kSW5kZXggLSAxXSkpIHsgLy8gYWZ0ZXIgbGFzdCBpdGVtXG4gICAgICAgIHJldHVybiBbZW5kSW5kZXgsIDBdO1xuICAgIH1cbiAgICB3aGlsZSAoc3RhcnRJbmRleCA8IGVuZEluZGV4KSB7XG4gICAgICAgIGxldCBtaWRkbGVJbmRleCA9IE1hdGguZmxvb3Ioc3RhcnRJbmRleCArIChlbmRJbmRleCAtIHN0YXJ0SW5kZXgpIC8gMik7XG4gICAgICAgIGxldCBtaWRkbGVWYWwgPSBnZXRJdGVtVmFsKGFbbWlkZGxlSW5kZXhdKTtcbiAgICAgICAgaWYgKHNlYXJjaFZhbCA8IG1pZGRsZVZhbCkge1xuICAgICAgICAgICAgZW5kSW5kZXggPSBtaWRkbGVJbmRleDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChzZWFyY2hWYWwgPiBtaWRkbGVWYWwpIHtcbiAgICAgICAgICAgIHN0YXJ0SW5kZXggPSBtaWRkbGVJbmRleCArIDE7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7IC8vIGVxdWFsIVxuICAgICAgICAgICAgcmV0dXJuIFttaWRkbGVJbmRleCwgMV07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIFtzdGFydEluZGV4LCAwXTtcbn1cblxuLypcbkFuIGFic3RyYWN0aW9uIGZvciBhIGRyYWdnaW5nIGludGVyYWN0aW9uIG9yaWdpbmF0aW5nIG9uIGFuIGV2ZW50LlxuRG9lcyBoaWdoZXItbGV2ZWwgdGhpbmdzIHRoYW4gUG9pbnRlckRyYWdnZXIsIHN1Y2ggYXMgcG9zc2libHk6XG4tIGEgXCJtaXJyb3JcIiB0aGF0IG1vdmVzIHdpdGggdGhlIHBvaW50ZXJcbi0gYSBtaW5pbXVtIG51bWJlciBvZiBwaXhlbHMgb3Igb3RoZXIgY3JpdGVyaWEgZm9yIGEgdHJ1ZSBkcmFnIHRvIGJlZ2luXG5cbnN1YmNsYXNzZXMgbXVzdCBlbWl0OlxuLSBwb2ludGVyZG93blxuLSBkcmFnc3RhcnRcbi0gZHJhZ21vdmVcbi0gcG9pbnRlcnVwXG4tIGRyYWdlbmRcbiovXG5jbGFzcyBFbGVtZW50RHJhZ2dpbmcge1xuICAgIGNvbnN0cnVjdG9yKGVsLCBzZWxlY3Rvcikge1xuICAgICAgICB0aGlzLmVtaXR0ZXIgPSBuZXcgRW1pdHRlcigpO1xuICAgIH1cbiAgICBkZXN0cm95KCkge1xuICAgIH1cbiAgICBzZXRNaXJyb3JJc1Zpc2libGUoYm9vbCkge1xuICAgICAgICAvLyBvcHRpb25hbCBpZiBzdWJjbGFzcyBkb2Vzbid0IHdhbnQgdG8gc3VwcG9ydCBhIG1pcnJvclxuICAgIH1cbiAgICBzZXRNaXJyb3JOZWVkc1JldmVydChib29sKSB7XG4gICAgICAgIC8vIG9wdGlvbmFsIGlmIHN1YmNsYXNzIGRvZXNuJ3Qgd2FudCB0byBzdXBwb3J0IGEgbWlycm9yXG4gICAgfVxuICAgIHNldEF1dG9TY3JvbGxFbmFibGVkKGJvb2wpIHtcbiAgICAgICAgLy8gb3B0aW9uYWxcbiAgICB9XG59XG5cbi8vIFRPRE86IGdldCByaWQgb2YgdGhpcyBpbiBmYXZvciBvZiBvcHRpb25zIHN5c3RlbSxcbi8vIHRobyBpdCdzIHJlYWxseSBlYXN5IHRvIGFjY2VzcyB0aGlzIGdsb2JhbGx5IHJhdGhlciB0aGFuIHBhc3MgdGhydSBvcHRpb25zLlxuY29uc3QgY29uZmlnID0ge307XG5cbi8qXG5JbmZvcm1hdGlvbiBhYm91dCB3aGF0IHdpbGwgaGFwcGVuIHdoZW4gYW4gZXh0ZXJuYWwgZWxlbWVudCBpcyBkcmFnZ2VkLWFuZC1kcm9wcGVkXG5vbnRvIGEgY2FsZW5kYXIuIENvbnRhaW5zIGluZm9ybWF0aW9uIGZvciBjcmVhdGluZyBhbiBldmVudC5cbiovXG5jb25zdCBEUkFHX01FVEFfUkVGSU5FUlMgPSB7XG4gICAgc3RhcnRUaW1lOiBjcmVhdGVEdXJhdGlvbixcbiAgICBkdXJhdGlvbjogY3JlYXRlRHVyYXRpb24sXG4gICAgY3JlYXRlOiBCb29sZWFuLFxuICAgIHNvdXJjZUlkOiBTdHJpbmcsXG59O1xuZnVuY3Rpb24gcGFyc2VEcmFnTWV0YShyYXcpIHtcbiAgICBsZXQgeyByZWZpbmVkLCBleHRyYSB9ID0gcmVmaW5lUHJvcHMocmF3LCBEUkFHX01FVEFfUkVGSU5FUlMpO1xuICAgIHJldHVybiB7XG4gICAgICAgIHN0YXJ0VGltZTogcmVmaW5lZC5zdGFydFRpbWUgfHwgbnVsbCxcbiAgICAgICAgZHVyYXRpb246IHJlZmluZWQuZHVyYXRpb24gfHwgbnVsbCxcbiAgICAgICAgY3JlYXRlOiByZWZpbmVkLmNyZWF0ZSAhPSBudWxsID8gcmVmaW5lZC5jcmVhdGUgOiB0cnVlLFxuICAgICAgICBzb3VyY2VJZDogcmVmaW5lZC5zb3VyY2VJZCxcbiAgICAgICAgbGVmdG92ZXJQcm9wczogZXh0cmEsXG4gICAgfTtcbn1cblxuLy8gQ29tcHV0ZXMgYSBkZWZhdWx0IGNvbHVtbiBoZWFkZXIgZm9ybWF0dGluZyBzdHJpbmcgaWYgYGNvbEZvcm1hdGAgaXMgbm90IGV4cGxpY2l0bHkgZGVmaW5lZFxuZnVuY3Rpb24gY29tcHV0ZUZhbGxiYWNrSGVhZGVyRm9ybWF0KGRhdGVzUmVwRGlzdGluY3REYXlzLCBkYXlDbnQpIHtcbiAgICAvLyBpZiBtb3JlIHRoYW4gb25lIHdlZWsgcm93LCBvciBpZiB0aGVyZSBhcmUgYSBsb3Qgb2YgY29sdW1ucyB3aXRoIG5vdCBtdWNoIHNwYWNlLFxuICAgIC8vIHB1dCBqdXN0IHRoZSBkYXkgbnVtYmVycyB3aWxsIGJlIGluIGVhY2ggY2VsbFxuICAgIGlmICghZGF0ZXNSZXBEaXN0aW5jdERheXMgfHwgZGF5Q250ID4gMTApIHtcbiAgICAgICAgcmV0dXJuIGNyZWF0ZUZvcm1hdHRlcih7IHdlZWtkYXk6ICdzaG9ydCcgfSk7IC8vIFwiU2F0XCJcbiAgICB9XG4gICAgaWYgKGRheUNudCA+IDEpIHtcbiAgICAgICAgcmV0dXJuIGNyZWF0ZUZvcm1hdHRlcih7IHdlZWtkYXk6ICdzaG9ydCcsIG1vbnRoOiAnbnVtZXJpYycsIGRheTogJ251bWVyaWMnLCBvbWl0Q29tbWFzOiB0cnVlIH0pOyAvLyBcIlNhdCAxMS8xMlwiXG4gICAgfVxuICAgIHJldHVybiBjcmVhdGVGb3JtYXR0ZXIoeyB3ZWVrZGF5OiAnbG9uZycgfSk7IC8vIFwiU2F0dXJkYXlcIlxufVxuXG5jb25zdCBDTEFTU19OQU1FID0gJ2ZjLWNvbC1oZWFkZXItY2VsbCc7IC8vIGRvIHRoZSBjdXNoaW9uIHRvbz8gbm9cbmZ1bmN0aW9uIHJlbmRlcklubmVyJDEocmVuZGVyUHJvcHMpIHtcbiAgICByZXR1cm4gcmVuZGVyUHJvcHMudGV4dDtcbn1cblxuLy8gQkFEIG5hbWUgZm9yIHRoaXMgY2xhc3Mgbm93LiB1c2VkIGluIHRoZSBIZWFkZXJcbmNsYXNzIFRhYmxlRGF0ZUNlbGwgZXh0ZW5kcyBCYXNlQ29tcG9uZW50IHtcbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGxldCB7IGRhdGVFbnYsIG9wdGlvbnMsIHRoZW1lLCB2aWV3QXBpIH0gPSB0aGlzLmNvbnRleHQ7XG4gICAgICAgIGxldCB7IHByb3BzIH0gPSB0aGlzO1xuICAgICAgICBsZXQgeyBkYXRlLCBkYXRlUHJvZmlsZSB9ID0gcHJvcHM7XG4gICAgICAgIGxldCBkYXlNZXRhID0gZ2V0RGF0ZU1ldGEoZGF0ZSwgcHJvcHMudG9kYXlSYW5nZSwgbnVsbCwgZGF0ZVByb2ZpbGUpO1xuICAgICAgICBsZXQgY2xhc3NOYW1lcyA9IFtDTEFTU19OQU1FXS5jb25jYXQoZ2V0RGF5Q2xhc3NOYW1lcyhkYXlNZXRhLCB0aGVtZSkpO1xuICAgICAgICBsZXQgdGV4dCA9IGRhdGVFbnYuZm9ybWF0KGRhdGUsIHByb3BzLmRheUhlYWRlckZvcm1hdCk7XG4gICAgICAgIC8vIGlmIGNvbENudCBpcyAxLCB3ZSBhcmUgYWxyZWFkeSBpbiBhIGRheS12aWV3IGFuZCBkb24ndCBuZWVkIGEgbmF2bGlua1xuICAgICAgICBsZXQgbmF2TGlua0F0dHJzID0gKCFkYXlNZXRhLmlzRGlzYWJsZWQgJiYgcHJvcHMuY29sQ250ID4gMSlcbiAgICAgICAgICAgID8gYnVpbGROYXZMaW5rQXR0cnModGhpcy5jb250ZXh0LCBkYXRlKVxuICAgICAgICAgICAgOiB7fTtcbiAgICAgICAgbGV0IHB1YmxpY0RhdGUgPSBkYXRlRW52LnRvRGF0ZShkYXRlKTtcbiAgICAgICAgLy8gd29ya2Fyb3VuZCBmb3IgTHV4b24gKGFuZCBtYXliZSBtb21lbnQpIHJldHVybmluZyBwcmlvci1kYXlzIHdoZW4gc3RhcnQtb2YtZGF5XG4gICAgICAgIC8vIGluIERTVCBnYXA6IGh0dHBzOi8vZ2l0aHViLmNvbS9mdWxsY2FsZW5kYXIvZnVsbGNhbGVuZGFyL2lzc3Vlcy83NjMzXG4gICAgICAgIGlmIChkYXRlRW52Lm5hbWVkVGltZVpvbmVJbXBsKSB7XG4gICAgICAgICAgICBwdWJsaWNEYXRlID0gYWRkTXMocHVibGljRGF0ZSwgMzYwMDAwMCk7IC8vIGFkZCBhbiBob3VyXG4gICAgICAgIH1cbiAgICAgICAgbGV0IHJlbmRlclByb3BzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oeyBkYXRlOiBwdWJsaWNEYXRlLCB2aWV3OiB2aWV3QXBpIH0sIHByb3BzLmV4dHJhUmVuZGVyUHJvcHMpLCB7IHRleHQgfSksIGRheU1ldGEpO1xuICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoQ29udGVudENvbnRhaW5lciwgeyBlbFRhZzogXCJ0aFwiLCBlbENsYXNzZXM6IGNsYXNzTmFtZXMsIGVsQXR0cnM6IE9iamVjdC5hc3NpZ24oeyByb2xlOiAnY29sdW1uaGVhZGVyJywgY29sU3BhbjogcHJvcHMuY29sU3BhbiwgJ2RhdGEtZGF0ZSc6ICFkYXlNZXRhLmlzRGlzYWJsZWQgPyBmb3JtYXREYXlTdHJpbmcoZGF0ZSkgOiB1bmRlZmluZWQgfSwgcHJvcHMuZXh0cmFEYXRhQXR0cnMpLCByZW5kZXJQcm9wczogcmVuZGVyUHJvcHMsIGdlbmVyYXRvck5hbWU6IFwiZGF5SGVhZGVyQ29udGVudFwiLCBjdXN0b21HZW5lcmF0b3I6IG9wdGlvbnMuZGF5SGVhZGVyQ29udGVudCwgZGVmYXVsdEdlbmVyYXRvcjogcmVuZGVySW5uZXIkMSwgY2xhc3NOYW1lR2VuZXJhdG9yOiBvcHRpb25zLmRheUhlYWRlckNsYXNzTmFtZXMsIGRpZE1vdW50OiBvcHRpb25zLmRheUhlYWRlckRpZE1vdW50LCB3aWxsVW5tb3VudDogb3B0aW9ucy5kYXlIZWFkZXJXaWxsVW5tb3VudCB9LCAoSW5uZXJDb250YWluZXIpID0+IChjcmVhdGVFbGVtZW50KFwiZGl2XCIsIHsgY2xhc3NOYW1lOiBcImZjLXNjcm9sbGdyaWQtc3luYy1pbm5lclwiIH0sICFkYXlNZXRhLmlzRGlzYWJsZWQgJiYgKGNyZWF0ZUVsZW1lbnQoSW5uZXJDb250YWluZXIsIHsgZWxUYWc6IFwiYVwiLCBlbEF0dHJzOiBuYXZMaW5rQXR0cnMsIGVsQ2xhc3NlczogW1xuICAgICAgICAgICAgICAgICdmYy1jb2wtaGVhZGVyLWNlbGwtY3VzaGlvbicsXG4gICAgICAgICAgICAgICAgcHJvcHMuaXNTdGlja3kgJiYgJ2ZjLXN0aWNreScsXG4gICAgICAgICAgICBdIH0pKSkpKSk7XG4gICAgfVxufVxuXG5jb25zdCBXRUVLREFZX0ZPUk1BVCA9IGNyZWF0ZUZvcm1hdHRlcih7IHdlZWtkYXk6ICdsb25nJyB9KTtcbmNsYXNzIFRhYmxlRG93Q2VsbCBleHRlbmRzIEJhc2VDb21wb25lbnQge1xuICAgIHJlbmRlcigpIHtcbiAgICAgICAgbGV0IHsgcHJvcHMgfSA9IHRoaXM7XG4gICAgICAgIGxldCB7IGRhdGVFbnYsIHRoZW1lLCB2aWV3QXBpLCBvcHRpb25zIH0gPSB0aGlzLmNvbnRleHQ7XG4gICAgICAgIGxldCBkYXRlID0gYWRkRGF5cyhuZXcgRGF0ZSgyNTkyMDAwMDApLCBwcm9wcy5kb3cpOyAvLyBzdGFydCB3aXRoIFN1biwgMDQgSmFuIDE5NzAgMDA6MDA6MDAgR01UXG4gICAgICAgIGxldCBkYXRlTWV0YSA9IHtcbiAgICAgICAgICAgIGRvdzogcHJvcHMuZG93LFxuICAgICAgICAgICAgaXNEaXNhYmxlZDogZmFsc2UsXG4gICAgICAgICAgICBpc0Z1dHVyZTogZmFsc2UsXG4gICAgICAgICAgICBpc1Bhc3Q6IGZhbHNlLFxuICAgICAgICAgICAgaXNUb2RheTogZmFsc2UsXG4gICAgICAgICAgICBpc090aGVyOiBmYWxzZSxcbiAgICAgICAgfTtcbiAgICAgICAgbGV0IHRleHQgPSBkYXRlRW52LmZvcm1hdChkYXRlLCBwcm9wcy5kYXlIZWFkZXJGb3JtYXQpO1xuICAgICAgICBsZXQgcmVuZGVyUHJvcHMgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHsgLy8gVE9ETzogbWFrZSB0aGlzIHB1YmxpYz9cbiAgICAgICAgICAgIGRhdGUgfSwgZGF0ZU1ldGEpLCB7IHZpZXc6IHZpZXdBcGkgfSksIHByb3BzLmV4dHJhUmVuZGVyUHJvcHMpLCB7IHRleHQgfSk7XG4gICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChDb250ZW50Q29udGFpbmVyLCB7IGVsVGFnOiBcInRoXCIsIGVsQ2xhc3NlczogW1xuICAgICAgICAgICAgICAgIENMQVNTX05BTUUsXG4gICAgICAgICAgICAgICAgLi4uZ2V0RGF5Q2xhc3NOYW1lcyhkYXRlTWV0YSwgdGhlbWUpLFxuICAgICAgICAgICAgICAgIC4uLihwcm9wcy5leHRyYUNsYXNzTmFtZXMgfHwgW10pLFxuICAgICAgICAgICAgXSwgZWxBdHRyczogT2JqZWN0LmFzc2lnbih7IHJvbGU6ICdjb2x1bW5oZWFkZXInLCBjb2xTcGFuOiBwcm9wcy5jb2xTcGFuIH0sIHByb3BzLmV4dHJhRGF0YUF0dHJzKSwgcmVuZGVyUHJvcHM6IHJlbmRlclByb3BzLCBnZW5lcmF0b3JOYW1lOiBcImRheUhlYWRlckNvbnRlbnRcIiwgY3VzdG9tR2VuZXJhdG9yOiBvcHRpb25zLmRheUhlYWRlckNvbnRlbnQsIGRlZmF1bHRHZW5lcmF0b3I6IHJlbmRlcklubmVyJDEsIGNsYXNzTmFtZUdlbmVyYXRvcjogb3B0aW9ucy5kYXlIZWFkZXJDbGFzc05hbWVzLCBkaWRNb3VudDogb3B0aW9ucy5kYXlIZWFkZXJEaWRNb3VudCwgd2lsbFVubW91bnQ6IG9wdGlvbnMuZGF5SGVhZGVyV2lsbFVubW91bnQgfSwgKElubmVyQ29udGVudCkgPT4gKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IFwiZmMtc2Nyb2xsZ3JpZC1zeW5jLWlubmVyXCIgfSxcbiAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoSW5uZXJDb250ZW50LCB7IGVsVGFnOiBcImFcIiwgZWxDbGFzc2VzOiBbXG4gICAgICAgICAgICAgICAgICAgICdmYy1jb2wtaGVhZGVyLWNlbGwtY3VzaGlvbicsXG4gICAgICAgICAgICAgICAgICAgIHByb3BzLmlzU3RpY2t5ICYmICdmYy1zdGlja3knLFxuICAgICAgICAgICAgICAgIF0sIGVsQXR0cnM6IHtcbiAgICAgICAgICAgICAgICAgICAgJ2FyaWEtbGFiZWwnOiBkYXRlRW52LmZvcm1hdChkYXRlLCBXRUVLREFZX0ZPUk1BVCksXG4gICAgICAgICAgICAgICAgfSB9KSkpKSk7XG4gICAgfVxufVxuXG5jbGFzcyBEYXlIZWFkZXIgZXh0ZW5kcyBCYXNlQ29tcG9uZW50IHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoLi4uYXJndW1lbnRzKTtcbiAgICAgICAgdGhpcy5jcmVhdGVEYXlIZWFkZXJGb3JtYXR0ZXIgPSBtZW1vaXplKGNyZWF0ZURheUhlYWRlckZvcm1hdHRlcik7XG4gICAgfVxuICAgIHJlbmRlcigpIHtcbiAgICAgICAgbGV0IHsgY29udGV4dCB9ID0gdGhpcztcbiAgICAgICAgbGV0IHsgZGF0ZXMsIGRhdGVQcm9maWxlLCBkYXRlc1JlcERpc3RpbmN0RGF5cywgcmVuZGVySW50cm8gfSA9IHRoaXMucHJvcHM7XG4gICAgICAgIGxldCBkYXlIZWFkZXJGb3JtYXQgPSB0aGlzLmNyZWF0ZURheUhlYWRlckZvcm1hdHRlcihjb250ZXh0Lm9wdGlvbnMuZGF5SGVhZGVyRm9ybWF0LCBkYXRlc1JlcERpc3RpbmN0RGF5cywgZGF0ZXMubGVuZ3RoKTtcbiAgICAgICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KE5vd1RpbWVyLCB7IHVuaXQ6IFwiZGF5XCIgfSwgKG5vd0RhdGUsIHRvZGF5UmFuZ2UpID0+IChjcmVhdGVFbGVtZW50KFwidHJcIiwgeyByb2xlOiBcInJvd1wiIH0sXG4gICAgICAgICAgICByZW5kZXJJbnRybyAmJiByZW5kZXJJbnRybygnZGF5JyksXG4gICAgICAgICAgICBkYXRlcy5tYXAoKGRhdGUpID0+IChkYXRlc1JlcERpc3RpbmN0RGF5cyA/IChjcmVhdGVFbGVtZW50KFRhYmxlRGF0ZUNlbGwsIHsga2V5OiBkYXRlLnRvSVNPU3RyaW5nKCksIGRhdGU6IGRhdGUsIGRhdGVQcm9maWxlOiBkYXRlUHJvZmlsZSwgdG9kYXlSYW5nZTogdG9kYXlSYW5nZSwgY29sQ250OiBkYXRlcy5sZW5ndGgsIGRheUhlYWRlckZvcm1hdDogZGF5SGVhZGVyRm9ybWF0IH0pKSA6IChjcmVhdGVFbGVtZW50KFRhYmxlRG93Q2VsbCwgeyBrZXk6IGRhdGUuZ2V0VVRDRGF5KCksIGRvdzogZGF0ZS5nZXRVVENEYXkoKSwgZGF5SGVhZGVyRm9ybWF0OiBkYXlIZWFkZXJGb3JtYXQgfSkpKSkpKSkpO1xuICAgIH1cbn1cbmZ1bmN0aW9uIGNyZWF0ZURheUhlYWRlckZvcm1hdHRlcihleHBsaWNpdEZvcm1hdCwgZGF0ZXNSZXBEaXN0aW5jdERheXMsIGRhdGVDbnQpIHtcbiAgICByZXR1cm4gZXhwbGljaXRGb3JtYXQgfHwgY29tcHV0ZUZhbGxiYWNrSGVhZGVyRm9ybWF0KGRhdGVzUmVwRGlzdGluY3REYXlzLCBkYXRlQ250KTtcbn1cblxuY2xhc3MgRGF5U2VyaWVzTW9kZWwge1xuICAgIGNvbnN0cnVjdG9yKHJhbmdlLCBkYXRlUHJvZmlsZUdlbmVyYXRvcikge1xuICAgICAgICBsZXQgZGF0ZSA9IHJhbmdlLnN0YXJ0O1xuICAgICAgICBsZXQgeyBlbmQgfSA9IHJhbmdlO1xuICAgICAgICBsZXQgaW5kaWNlcyA9IFtdO1xuICAgICAgICBsZXQgZGF0ZXMgPSBbXTtcbiAgICAgICAgbGV0IGRheUluZGV4ID0gLTE7XG4gICAgICAgIHdoaWxlIChkYXRlIDwgZW5kKSB7IC8vIGxvb3AgZWFjaCBkYXkgZnJvbSBzdGFydCB0byBlbmRcbiAgICAgICAgICAgIGlmIChkYXRlUHJvZmlsZUdlbmVyYXRvci5pc0hpZGRlbkRheShkYXRlKSkge1xuICAgICAgICAgICAgICAgIGluZGljZXMucHVzaChkYXlJbmRleCArIDAuNSk7IC8vIG1hcmsgdGhhdCBpdCdzIGJldHdlZW4gaW5kaWNlc1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgZGF5SW5kZXggKz0gMTtcbiAgICAgICAgICAgICAgICBpbmRpY2VzLnB1c2goZGF5SW5kZXgpO1xuICAgICAgICAgICAgICAgIGRhdGVzLnB1c2goZGF0ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkYXRlID0gYWRkRGF5cyhkYXRlLCAxKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmRhdGVzID0gZGF0ZXM7XG4gICAgICAgIHRoaXMuaW5kaWNlcyA9IGluZGljZXM7XG4gICAgICAgIHRoaXMuY250ID0gZGF0ZXMubGVuZ3RoO1xuICAgIH1cbiAgICBzbGljZVJhbmdlKHJhbmdlKSB7XG4gICAgICAgIGxldCBmaXJzdEluZGV4ID0gdGhpcy5nZXREYXRlRGF5SW5kZXgocmFuZ2Uuc3RhcnQpOyAvLyBpbmNsdXNpdmUgZmlyc3QgaW5kZXhcbiAgICAgICAgbGV0IGxhc3RJbmRleCA9IHRoaXMuZ2V0RGF0ZURheUluZGV4KGFkZERheXMocmFuZ2UuZW5kLCAtMSkpOyAvLyBpbmNsdXNpdmUgbGFzdCBpbmRleFxuICAgICAgICBsZXQgY2xpcHBlZEZpcnN0SW5kZXggPSBNYXRoLm1heCgwLCBmaXJzdEluZGV4KTtcbiAgICAgICAgbGV0IGNsaXBwZWRMYXN0SW5kZXggPSBNYXRoLm1pbih0aGlzLmNudCAtIDEsIGxhc3RJbmRleCk7XG4gICAgICAgIC8vIGRlYWwgd2l0aCBpbi1iZXR3ZWVuIGluZGljZXNcbiAgICAgICAgY2xpcHBlZEZpcnN0SW5kZXggPSBNYXRoLmNlaWwoY2xpcHBlZEZpcnN0SW5kZXgpOyAvLyBpbi1iZXR3ZWVuIHN0YXJ0cyByb3VuZCB0byBuZXh0IGNlbGxcbiAgICAgICAgY2xpcHBlZExhc3RJbmRleCA9IE1hdGguZmxvb3IoY2xpcHBlZExhc3RJbmRleCk7IC8vIGluLWJldHdlZW4gZW5kcyByb3VuZCB0byBwcmV2IGNlbGxcbiAgICAgICAgaWYgKGNsaXBwZWRGaXJzdEluZGV4IDw9IGNsaXBwZWRMYXN0SW5kZXgpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgZmlyc3RJbmRleDogY2xpcHBlZEZpcnN0SW5kZXgsXG4gICAgICAgICAgICAgICAgbGFzdEluZGV4OiBjbGlwcGVkTGFzdEluZGV4LFxuICAgICAgICAgICAgICAgIGlzU3RhcnQ6IGZpcnN0SW5kZXggPT09IGNsaXBwZWRGaXJzdEluZGV4LFxuICAgICAgICAgICAgICAgIGlzRW5kOiBsYXN0SW5kZXggPT09IGNsaXBwZWRMYXN0SW5kZXgsXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICAvLyBHaXZlbiBhIGRhdGUsIHJldHVybnMgaXRzIGNocm9ub2xvY2lhbCBjZWxsLWluZGV4IGZyb20gdGhlIGZpcnN0IGNlbGwgb2YgdGhlIGdyaWQuXG4gICAgLy8gSWYgdGhlIGRhdGUgbGllcyBiZXR3ZWVuIGNlbGxzIChiZWNhdXNlIG9mIGhpZGRlbkRheXMpLCByZXR1cm5zIGEgZmxvYXRpbmctcG9pbnQgdmFsdWUgYmV0d2VlbiBvZmZzZXRzLlxuICAgIC8vIElmIGJlZm9yZSB0aGUgZmlyc3Qgb2Zmc2V0LCByZXR1cm5zIGEgbmVnYXRpdmUgbnVtYmVyLlxuICAgIC8vIElmIGFmdGVyIHRoZSBsYXN0IG9mZnNldCwgcmV0dXJucyBhbiBvZmZzZXQgcGFzdCB0aGUgbGFzdCBjZWxsIG9mZnNldC5cbiAgICAvLyBPbmx5IHdvcmtzIGZvciAqc3RhcnQqIGRhdGVzIG9mIGNlbGxzLiBXaWxsIG5vdCB3b3JrIGZvciBleGNsdXNpdmUgZW5kIGRhdGVzIGZvciBjZWxscy5cbiAgICBnZXREYXRlRGF5SW5kZXgoZGF0ZSkge1xuICAgICAgICBsZXQgeyBpbmRpY2VzIH0gPSB0aGlzO1xuICAgICAgICBsZXQgZGF5T2Zmc2V0ID0gTWF0aC5mbG9vcihkaWZmRGF5cyh0aGlzLmRhdGVzWzBdLCBkYXRlKSk7XG4gICAgICAgIGlmIChkYXlPZmZzZXQgPCAwKSB7XG4gICAgICAgICAgICByZXR1cm4gaW5kaWNlc1swXSAtIDE7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGRheU9mZnNldCA+PSBpbmRpY2VzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuIGluZGljZXNbaW5kaWNlcy5sZW5ndGggLSAxXSArIDE7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGluZGljZXNbZGF5T2Zmc2V0XTtcbiAgICB9XG59XG5cbmNsYXNzIERheVRhYmxlTW9kZWwge1xuICAgIGNvbnN0cnVjdG9yKGRheVNlcmllcywgYnJlYWtPbldlZWtzKSB7XG4gICAgICAgIGxldCB7IGRhdGVzIH0gPSBkYXlTZXJpZXM7XG4gICAgICAgIGxldCBkYXlzUGVyUm93O1xuICAgICAgICBsZXQgZmlyc3REYXk7XG4gICAgICAgIGxldCByb3dDbnQ7XG4gICAgICAgIGlmIChicmVha09uV2Vla3MpIHtcbiAgICAgICAgICAgIC8vIGNvdW50IGNvbHVtbnMgdW50aWwgdGhlIGRheS1vZi13ZWVrIHJlcGVhdHNcbiAgICAgICAgICAgIGZpcnN0RGF5ID0gZGF0ZXNbMF0uZ2V0VVRDRGF5KCk7XG4gICAgICAgICAgICBmb3IgKGRheXNQZXJSb3cgPSAxOyBkYXlzUGVyUm93IDwgZGF0ZXMubGVuZ3RoOyBkYXlzUGVyUm93ICs9IDEpIHtcbiAgICAgICAgICAgICAgICBpZiAoZGF0ZXNbZGF5c1BlclJvd10uZ2V0VVRDRGF5KCkgPT09IGZpcnN0RGF5KSB7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJvd0NudCA9IE1hdGguY2VpbChkYXRlcy5sZW5ndGggLyBkYXlzUGVyUm93KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJvd0NudCA9IDE7XG4gICAgICAgICAgICBkYXlzUGVyUm93ID0gZGF0ZXMubGVuZ3RoO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucm93Q250ID0gcm93Q250O1xuICAgICAgICB0aGlzLmNvbENudCA9IGRheXNQZXJSb3c7XG4gICAgICAgIHRoaXMuZGF5U2VyaWVzID0gZGF5U2VyaWVzO1xuICAgICAgICB0aGlzLmNlbGxzID0gdGhpcy5idWlsZENlbGxzKCk7XG4gICAgICAgIHRoaXMuaGVhZGVyRGF0ZXMgPSB0aGlzLmJ1aWxkSGVhZGVyRGF0ZXMoKTtcbiAgICB9XG4gICAgYnVpbGRDZWxscygpIHtcbiAgICAgICAgbGV0IHJvd3MgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgcm93ID0gMDsgcm93IDwgdGhpcy5yb3dDbnQ7IHJvdyArPSAxKSB7XG4gICAgICAgICAgICBsZXQgY2VsbHMgPSBbXTtcbiAgICAgICAgICAgIGZvciAobGV0IGNvbCA9IDA7IGNvbCA8IHRoaXMuY29sQ250OyBjb2wgKz0gMSkge1xuICAgICAgICAgICAgICAgIGNlbGxzLnB1c2godGhpcy5idWlsZENlbGwocm93LCBjb2wpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJvd3MucHVzaChjZWxscyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJvd3M7XG4gICAgfVxuICAgIGJ1aWxkQ2VsbChyb3csIGNvbCkge1xuICAgICAgICBsZXQgZGF0ZSA9IHRoaXMuZGF5U2VyaWVzLmRhdGVzW3JvdyAqIHRoaXMuY29sQ250ICsgY29sXTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGtleTogZGF0ZS50b0lTT1N0cmluZygpLFxuICAgICAgICAgICAgZGF0ZSxcbiAgICAgICAgfTtcbiAgICB9XG4gICAgYnVpbGRIZWFkZXJEYXRlcygpIHtcbiAgICAgICAgbGV0IGRhdGVzID0gW107XG4gICAgICAgIGZvciAobGV0IGNvbCA9IDA7IGNvbCA8IHRoaXMuY29sQ250OyBjb2wgKz0gMSkge1xuICAgICAgICAgICAgZGF0ZXMucHVzaCh0aGlzLmNlbGxzWzBdW2NvbF0uZGF0ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGRhdGVzO1xuICAgIH1cbiAgICBzbGljZVJhbmdlKHJhbmdlKSB7XG4gICAgICAgIGxldCB7IGNvbENudCB9ID0gdGhpcztcbiAgICAgICAgbGV0IHNlcmllc1NlZyA9IHRoaXMuZGF5U2VyaWVzLnNsaWNlUmFuZ2UocmFuZ2UpO1xuICAgICAgICBsZXQgc2VncyA9IFtdO1xuICAgICAgICBpZiAoc2VyaWVzU2VnKSB7XG4gICAgICAgICAgICBsZXQgeyBmaXJzdEluZGV4LCBsYXN0SW5kZXggfSA9IHNlcmllc1NlZztcbiAgICAgICAgICAgIGxldCBpbmRleCA9IGZpcnN0SW5kZXg7XG4gICAgICAgICAgICB3aGlsZSAoaW5kZXggPD0gbGFzdEluZGV4KSB7XG4gICAgICAgICAgICAgICAgbGV0IHJvdyA9IE1hdGguZmxvb3IoaW5kZXggLyBjb2xDbnQpO1xuICAgICAgICAgICAgICAgIGxldCBuZXh0SW5kZXggPSBNYXRoLm1pbigocm93ICsgMSkgKiBjb2xDbnQsIGxhc3RJbmRleCArIDEpO1xuICAgICAgICAgICAgICAgIHNlZ3MucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIHJvdyxcbiAgICAgICAgICAgICAgICAgICAgZmlyc3RDb2w6IGluZGV4ICUgY29sQ250LFxuICAgICAgICAgICAgICAgICAgICBsYXN0Q29sOiAobmV4dEluZGV4IC0gMSkgJSBjb2xDbnQsXG4gICAgICAgICAgICAgICAgICAgIGlzU3RhcnQ6IHNlcmllc1NlZy5pc1N0YXJ0ICYmIGluZGV4ID09PSBmaXJzdEluZGV4LFxuICAgICAgICAgICAgICAgICAgICBpc0VuZDogc2VyaWVzU2VnLmlzRW5kICYmIChuZXh0SW5kZXggLSAxKSA9PT0gbGFzdEluZGV4LFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGluZGV4ID0gbmV4dEluZGV4O1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzZWdzO1xuICAgIH1cbn1cblxuY2xhc3MgU2xpY2VyIHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgdGhpcy5zbGljZUJ1c2luZXNzSG91cnMgPSBtZW1vaXplKHRoaXMuX3NsaWNlQnVzaW5lc3NIb3Vycyk7XG4gICAgICAgIHRoaXMuc2xpY2VEYXRlU2VsZWN0aW9uID0gbWVtb2l6ZSh0aGlzLl9zbGljZURhdGVTcGFuKTtcbiAgICAgICAgdGhpcy5zbGljZUV2ZW50U3RvcmUgPSBtZW1vaXplKHRoaXMuX3NsaWNlRXZlbnRTdG9yZSk7XG4gICAgICAgIHRoaXMuc2xpY2VFdmVudERyYWcgPSBtZW1vaXplKHRoaXMuX3NsaWNlSW50ZXJhY3Rpb24pO1xuICAgICAgICB0aGlzLnNsaWNlRXZlbnRSZXNpemUgPSBtZW1vaXplKHRoaXMuX3NsaWNlSW50ZXJhY3Rpb24pO1xuICAgICAgICB0aGlzLmZvcmNlRGF5SWZMaXN0SXRlbSA9IGZhbHNlOyAvLyBoYWNrXG4gICAgfVxuICAgIHNsaWNlUHJvcHMocHJvcHMsIGRhdGVQcm9maWxlLCBuZXh0RGF5VGhyZXNob2xkLCBjb250ZXh0LCAuLi5leHRyYUFyZ3MpIHtcbiAgICAgICAgbGV0IHsgZXZlbnRVaUJhc2VzIH0gPSBwcm9wcztcbiAgICAgICAgbGV0IGV2ZW50U2VncyA9IHRoaXMuc2xpY2VFdmVudFN0b3JlKHByb3BzLmV2ZW50U3RvcmUsIGV2ZW50VWlCYXNlcywgZGF0ZVByb2ZpbGUsIG5leHREYXlUaHJlc2hvbGQsIC4uLmV4dHJhQXJncyk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBkYXRlU2VsZWN0aW9uU2VnczogdGhpcy5zbGljZURhdGVTZWxlY3Rpb24ocHJvcHMuZGF0ZVNlbGVjdGlvbiwgZGF0ZVByb2ZpbGUsIG5leHREYXlUaHJlc2hvbGQsIGV2ZW50VWlCYXNlcywgY29udGV4dCwgLi4uZXh0cmFBcmdzKSxcbiAgICAgICAgICAgIGJ1c2luZXNzSG91clNlZ3M6IHRoaXMuc2xpY2VCdXNpbmVzc0hvdXJzKHByb3BzLmJ1c2luZXNzSG91cnMsIGRhdGVQcm9maWxlLCBuZXh0RGF5VGhyZXNob2xkLCBjb250ZXh0LCAuLi5leHRyYUFyZ3MpLFxuICAgICAgICAgICAgZmdFdmVudFNlZ3M6IGV2ZW50U2Vncy5mZyxcbiAgICAgICAgICAgIGJnRXZlbnRTZWdzOiBldmVudFNlZ3MuYmcsXG4gICAgICAgICAgICBldmVudERyYWc6IHRoaXMuc2xpY2VFdmVudERyYWcocHJvcHMuZXZlbnREcmFnLCBldmVudFVpQmFzZXMsIGRhdGVQcm9maWxlLCBuZXh0RGF5VGhyZXNob2xkLCAuLi5leHRyYUFyZ3MpLFxuICAgICAgICAgICAgZXZlbnRSZXNpemU6IHRoaXMuc2xpY2VFdmVudFJlc2l6ZShwcm9wcy5ldmVudFJlc2l6ZSwgZXZlbnRVaUJhc2VzLCBkYXRlUHJvZmlsZSwgbmV4dERheVRocmVzaG9sZCwgLi4uZXh0cmFBcmdzKSxcbiAgICAgICAgICAgIGV2ZW50U2VsZWN0aW9uOiBwcm9wcy5ldmVudFNlbGVjdGlvbixcbiAgICAgICAgfTsgLy8gVE9ETzogZ2l2ZSBpbnRlcmFjdGlvblNlZ3M/XG4gICAgfVxuICAgIHNsaWNlTm93RGF0ZSgvLyBkb2VzIG5vdCBtZW1vaXplXG4gICAgZGF0ZSwgZGF0ZVByb2ZpbGUsIG5leHREYXlUaHJlc2hvbGQsIGNvbnRleHQsIC4uLmV4dHJhQXJncykge1xuICAgICAgICByZXR1cm4gdGhpcy5fc2xpY2VEYXRlU3Bhbih7IHJhbmdlOiB7IHN0YXJ0OiBkYXRlLCBlbmQ6IGFkZE1zKGRhdGUsIDEpIH0sIGFsbERheTogZmFsc2UgfSwgLy8gYWRkIDEgbXMsIHByb3RlY3QgYWdhaW5zdCBudWxsIHJhbmdlXG4gICAgICAgIGRhdGVQcm9maWxlLCBuZXh0RGF5VGhyZXNob2xkLCB7fSwgY29udGV4dCwgLi4uZXh0cmFBcmdzKTtcbiAgICB9XG4gICAgX3NsaWNlQnVzaW5lc3NIb3VycyhidXNpbmVzc0hvdXJzLCBkYXRlUHJvZmlsZSwgbmV4dERheVRocmVzaG9sZCwgY29udGV4dCwgLi4uZXh0cmFBcmdzKSB7XG4gICAgICAgIGlmICghYnVzaW5lc3NIb3Vycykge1xuICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLl9zbGljZUV2ZW50U3RvcmUoZXhwYW5kUmVjdXJyaW5nKGJ1c2luZXNzSG91cnMsIGNvbXB1dGVBY3RpdmVSYW5nZShkYXRlUHJvZmlsZSwgQm9vbGVhbihuZXh0RGF5VGhyZXNob2xkKSksIGNvbnRleHQpLCB7fSwgZGF0ZVByb2ZpbGUsIG5leHREYXlUaHJlc2hvbGQsIC4uLmV4dHJhQXJncykuYmc7XG4gICAgfVxuICAgIF9zbGljZUV2ZW50U3RvcmUoZXZlbnRTdG9yZSwgZXZlbnRVaUJhc2VzLCBkYXRlUHJvZmlsZSwgbmV4dERheVRocmVzaG9sZCwgLi4uZXh0cmFBcmdzKSB7XG4gICAgICAgIGlmIChldmVudFN0b3JlKSB7XG4gICAgICAgICAgICBsZXQgcmFuZ2VSZXMgPSBzbGljZUV2ZW50U3RvcmUoZXZlbnRTdG9yZSwgZXZlbnRVaUJhc2VzLCBjb21wdXRlQWN0aXZlUmFuZ2UoZGF0ZVByb2ZpbGUsIEJvb2xlYW4obmV4dERheVRocmVzaG9sZCkpLCBuZXh0RGF5VGhyZXNob2xkKTtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgYmc6IHRoaXMuc2xpY2VFdmVudFJhbmdlcyhyYW5nZVJlcy5iZywgZXh0cmFBcmdzKSxcbiAgICAgICAgICAgICAgICBmZzogdGhpcy5zbGljZUV2ZW50UmFuZ2VzKHJhbmdlUmVzLmZnLCBleHRyYUFyZ3MpLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4geyBiZzogW10sIGZnOiBbXSB9O1xuICAgIH1cbiAgICBfc2xpY2VJbnRlcmFjdGlvbihpbnRlcmFjdGlvbiwgZXZlbnRVaUJhc2VzLCBkYXRlUHJvZmlsZSwgbmV4dERheVRocmVzaG9sZCwgLi4uZXh0cmFBcmdzKSB7XG4gICAgICAgIGlmICghaW50ZXJhY3Rpb24pIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICAgIGxldCByYW5nZVJlcyA9IHNsaWNlRXZlbnRTdG9yZShpbnRlcmFjdGlvbi5tdXRhdGVkRXZlbnRzLCBldmVudFVpQmFzZXMsIGNvbXB1dGVBY3RpdmVSYW5nZShkYXRlUHJvZmlsZSwgQm9vbGVhbihuZXh0RGF5VGhyZXNob2xkKSksIG5leHREYXlUaHJlc2hvbGQpO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc2VnczogdGhpcy5zbGljZUV2ZW50UmFuZ2VzKHJhbmdlUmVzLmZnLCBleHRyYUFyZ3MpLFxuICAgICAgICAgICAgYWZmZWN0ZWRJbnN0YW5jZXM6IGludGVyYWN0aW9uLmFmZmVjdGVkRXZlbnRzLmluc3RhbmNlcyxcbiAgICAgICAgICAgIGlzRXZlbnQ6IGludGVyYWN0aW9uLmlzRXZlbnQsXG4gICAgICAgIH07XG4gICAgfVxuICAgIF9zbGljZURhdGVTcGFuKGRhdGVTcGFuLCBkYXRlUHJvZmlsZSwgbmV4dERheVRocmVzaG9sZCwgZXZlbnRVaUJhc2VzLCBjb250ZXh0LCAuLi5leHRyYUFyZ3MpIHtcbiAgICAgICAgaWYgKCFkYXRlU3Bhbikge1xuICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICB9XG4gICAgICAgIGxldCBhY3RpdmVSYW5nZSA9IGNvbXB1dGVBY3RpdmVSYW5nZShkYXRlUHJvZmlsZSwgQm9vbGVhbihuZXh0RGF5VGhyZXNob2xkKSk7XG4gICAgICAgIGxldCBhY3RpdmVEYXRlU3BhblJhbmdlID0gaW50ZXJzZWN0UmFuZ2VzKGRhdGVTcGFuLnJhbmdlLCBhY3RpdmVSYW5nZSk7XG4gICAgICAgIGlmIChhY3RpdmVEYXRlU3BhblJhbmdlKSB7XG4gICAgICAgICAgICBkYXRlU3BhbiA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZGF0ZVNwYW4pLCB7IHJhbmdlOiBhY3RpdmVEYXRlU3BhblJhbmdlIH0pO1xuICAgICAgICAgICAgbGV0IGV2ZW50UmFuZ2UgPSBmYWJyaWNhdGVFdmVudFJhbmdlKGRhdGVTcGFuLCBldmVudFVpQmFzZXMsIGNvbnRleHQpO1xuICAgICAgICAgICAgbGV0IHNlZ3MgPSB0aGlzLnNsaWNlUmFuZ2UoZGF0ZVNwYW4ucmFuZ2UsIC4uLmV4dHJhQXJncyk7XG4gICAgICAgICAgICBmb3IgKGxldCBzZWcgb2Ygc2Vncykge1xuICAgICAgICAgICAgICAgIHNlZy5ldmVudFJhbmdlID0gZXZlbnRSYW5nZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBzZWdzO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gICAgLypcbiAgICBcImNvbXBsZXRlXCIgc2VnIG1lYW5zIGl0IGhhcyBjb21wb25lbnQgYW5kIGV2ZW50UmFuZ2VcbiAgICAqL1xuICAgIHNsaWNlRXZlbnRSYW5nZXMoZXZlbnRSYW5nZXMsIGV4dHJhQXJncykge1xuICAgICAgICBsZXQgc2VncyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBldmVudFJhbmdlIG9mIGV2ZW50UmFuZ2VzKSB7XG4gICAgICAgICAgICBzZWdzLnB1c2goLi4udGhpcy5zbGljZUV2ZW50UmFuZ2UoZXZlbnRSYW5nZSwgZXh0cmFBcmdzKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlZ3M7XG4gICAgfVxuICAgIC8qXG4gICAgXCJjb21wbGV0ZVwiIHNlZyBtZWFucyBpdCBoYXMgY29tcG9uZW50IGFuZCBldmVudFJhbmdlXG4gICAgKi9cbiAgICBzbGljZUV2ZW50UmFuZ2UoZXZlbnRSYW5nZSwgZXh0cmFBcmdzKSB7XG4gICAgICAgIGxldCBkYXRlUmFuZ2UgPSBldmVudFJhbmdlLnJhbmdlO1xuICAgICAgICAvLyBoYWNrIHRvIG1ha2UgbXVsdGktZGF5IGV2ZW50cyB0aGF0IGFyZSBiZWluZyBmb3JjZS1kaXNwbGF5ZWQgYXMgbGlzdC1pdGVtcyB0byB0YWtlIHVwIG9ubHkgb25lIGRheVxuICAgICAgICBpZiAodGhpcy5mb3JjZURheUlmTGlzdEl0ZW0gJiYgZXZlbnRSYW5nZS51aS5kaXNwbGF5ID09PSAnbGlzdC1pdGVtJykge1xuICAgICAgICAgICAgZGF0ZVJhbmdlID0ge1xuICAgICAgICAgICAgICAgIHN0YXJ0OiBkYXRlUmFuZ2Uuc3RhcnQsXG4gICAgICAgICAgICAgICAgZW5kOiBhZGREYXlzKGRhdGVSYW5nZS5zdGFydCwgMSksXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIGxldCBzZWdzID0gdGhpcy5zbGljZVJhbmdlKGRhdGVSYW5nZSwgLi4uZXh0cmFBcmdzKTtcbiAgICAgICAgZm9yIChsZXQgc2VnIG9mIHNlZ3MpIHtcbiAgICAgICAgICAgIHNlZy5ldmVudFJhbmdlID0gZXZlbnRSYW5nZTtcbiAgICAgICAgICAgIHNlZy5pc1N0YXJ0ID0gZXZlbnRSYW5nZS5pc1N0YXJ0ICYmIHNlZy5pc1N0YXJ0O1xuICAgICAgICAgICAgc2VnLmlzRW5kID0gZXZlbnRSYW5nZS5pc0VuZCAmJiBzZWcuaXNFbmQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlZ3M7XG4gICAgfVxufVxuLypcbmZvciBpbmNvcnBvcmF0aW5nIHNsb3RNaW5UaW1lL3Nsb3RNYXhUaW1lIGlmIGFwcHJvcHJpYXRlXG5UT0RPOiBzaG91bGQgYmUgcGFydCBvZiBEYXRlUHJvZmlsZSFcblRpbWVsaW5lRGF0ZVByb2ZpbGUgYWxyZWFkeSBkb2VzIHRoaXMgYnR3XG4qL1xuZnVuY3Rpb24gY29tcHV0ZUFjdGl2ZVJhbmdlKGRhdGVQcm9maWxlLCBpc0NvbXBvbmVudEFsbERheSkge1xuICAgIGxldCByYW5nZSA9IGRhdGVQcm9maWxlLmFjdGl2ZVJhbmdlO1xuICAgIGlmIChpc0NvbXBvbmVudEFsbERheSkge1xuICAgICAgICByZXR1cm4gcmFuZ2U7XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICAgIHN0YXJ0OiBhZGRNcyhyYW5nZS5zdGFydCwgZGF0ZVByb2ZpbGUuc2xvdE1pblRpbWUubWlsbGlzZWNvbmRzKSxcbiAgICAgICAgZW5kOiBhZGRNcyhyYW5nZS5lbmQsIGRhdGVQcm9maWxlLnNsb3RNYXhUaW1lLm1pbGxpc2Vjb25kcyAtIDg2NGU1KSwgLy8gODY0ZTUgPSBtcyBpbiBhIGRheVxuICAgIH07XG59XG5cbi8vIGhpZ2gtbGV2ZWwgc2VnbWVudGluZy1hd2FyZSB0ZXN0ZXIgZnVuY3Rpb25zXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbmZ1bmN0aW9uIGlzSW50ZXJhY3Rpb25WYWxpZChpbnRlcmFjdGlvbiwgZGF0ZVByb2ZpbGUsIGNvbnRleHQpIHtcbiAgICBsZXQgeyBpbnN0YW5jZXMgfSA9IGludGVyYWN0aW9uLm11dGF0ZWRFdmVudHM7XG4gICAgZm9yIChsZXQgaW5zdGFuY2VJZCBpbiBpbnN0YW5jZXMpIHtcbiAgICAgICAgaWYgKCFyYW5nZUNvbnRhaW5zUmFuZ2UoZGF0ZVByb2ZpbGUudmFsaWRSYW5nZSwgaW5zdGFuY2VzW2luc3RhbmNlSWRdLnJhbmdlKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBpc05ld1Byb3BzVmFsaWQoeyBldmVudERyYWc6IGludGVyYWN0aW9uIH0sIGNvbnRleHQpOyAvLyBIQUNLOiB0aGUgZXZlbnREcmFnIHByb3BzIGlzIHVzZWQgZm9yIEFMTCBpbnRlcmFjdGlvbnNcbn1cbmZ1bmN0aW9uIGlzRGF0ZVNlbGVjdGlvblZhbGlkKGRhdGVTZWxlY3Rpb24sIGRhdGVQcm9maWxlLCBjb250ZXh0KSB7XG4gICAgaWYgKCFyYW5nZUNvbnRhaW5zUmFuZ2UoZGF0ZVByb2ZpbGUudmFsaWRSYW5nZSwgZGF0ZVNlbGVjdGlvbi5yYW5nZSkpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gaXNOZXdQcm9wc1ZhbGlkKHsgZGF0ZVNlbGVjdGlvbiB9LCBjb250ZXh0KTtcbn1cbmZ1bmN0aW9uIGlzTmV3UHJvcHNWYWxpZChuZXdQcm9wcywgY29udGV4dCkge1xuICAgIGxldCBjYWxlbmRhclN0YXRlID0gY29udGV4dC5nZXRDdXJyZW50RGF0YSgpO1xuICAgIGxldCBwcm9wcyA9IE9iamVjdC5hc3NpZ24oeyBidXNpbmVzc0hvdXJzOiBjYWxlbmRhclN0YXRlLmJ1c2luZXNzSG91cnMsIGRhdGVTZWxlY3Rpb246ICcnLCBldmVudFN0b3JlOiBjYWxlbmRhclN0YXRlLmV2ZW50U3RvcmUsIGV2ZW50VWlCYXNlczogY2FsZW5kYXJTdGF0ZS5ldmVudFVpQmFzZXMsIGV2ZW50U2VsZWN0aW9uOiAnJywgZXZlbnREcmFnOiBudWxsLCBldmVudFJlc2l6ZTogbnVsbCB9LCBuZXdQcm9wcyk7XG4gICAgcmV0dXJuIChjb250ZXh0LnBsdWdpbkhvb2tzLmlzUHJvcHNWYWxpZCB8fCBpc1Byb3BzVmFsaWQpKHByb3BzLCBjb250ZXh0KTtcbn1cbmZ1bmN0aW9uIGlzUHJvcHNWYWxpZChzdGF0ZSwgY29udGV4dCwgZGF0ZVNwYW5NZXRhID0ge30sIGZpbHRlckNvbmZpZykge1xuICAgIGlmIChzdGF0ZS5ldmVudERyYWcgJiYgIWlzSW50ZXJhY3Rpb25Qcm9wc1ZhbGlkKHN0YXRlLCBjb250ZXh0LCBkYXRlU3Bhbk1ldGEsIGZpbHRlckNvbmZpZykpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAoc3RhdGUuZGF0ZVNlbGVjdGlvbiAmJiAhaXNEYXRlU2VsZWN0aW9uUHJvcHNWYWxpZChzdGF0ZSwgY29udGV4dCwgZGF0ZVNwYW5NZXRhLCBmaWx0ZXJDb25maWcpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG59XG4vLyBNb3ZpbmcgRXZlbnQgVmFsaWRhdGlvblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5mdW5jdGlvbiBpc0ludGVyYWN0aW9uUHJvcHNWYWxpZChzdGF0ZSwgY29udGV4dCwgZGF0ZVNwYW5NZXRhLCBmaWx0ZXJDb25maWcpIHtcbiAgICBsZXQgY3VycmVudFN0YXRlID0gY29udGV4dC5nZXRDdXJyZW50RGF0YSgpO1xuICAgIGxldCBpbnRlcmFjdGlvbiA9IHN0YXRlLmV2ZW50RHJhZzsgLy8gSEFDSzogdGhlIGV2ZW50RHJhZyBwcm9wcyBpcyB1c2VkIGZvciBBTEwgaW50ZXJhY3Rpb25zXG4gICAgbGV0IHN1YmplY3RFdmVudFN0b3JlID0gaW50ZXJhY3Rpb24ubXV0YXRlZEV2ZW50cztcbiAgICBsZXQgc3ViamVjdERlZnMgPSBzdWJqZWN0RXZlbnRTdG9yZS5kZWZzO1xuICAgIGxldCBzdWJqZWN0SW5zdGFuY2VzID0gc3ViamVjdEV2ZW50U3RvcmUuaW5zdGFuY2VzO1xuICAgIGxldCBzdWJqZWN0Q29uZmlncyA9IGNvbXBpbGVFdmVudFVpcyhzdWJqZWN0RGVmcywgaW50ZXJhY3Rpb24uaXNFdmVudCA/XG4gICAgICAgIHN0YXRlLmV2ZW50VWlCYXNlcyA6XG4gICAgICAgIHsgJyc6IGN1cnJlbnRTdGF0ZS5zZWxlY3Rpb25Db25maWcgfSk7XG4gICAgaWYgKGZpbHRlckNvbmZpZykge1xuICAgICAgICBzdWJqZWN0Q29uZmlncyA9IG1hcEhhc2goc3ViamVjdENvbmZpZ3MsIGZpbHRlckNvbmZpZyk7XG4gICAgfVxuICAgIC8vIGV4Y2x1ZGUgdGhlIHN1YmplY3QgZXZlbnRzLiBUT0RPOiBleGNsdWRlIGRlZnMgdG9vP1xuICAgIGxldCBvdGhlckV2ZW50U3RvcmUgPSBleGNsdWRlSW5zdGFuY2VzKHN0YXRlLmV2ZW50U3RvcmUsIGludGVyYWN0aW9uLmFmZmVjdGVkRXZlbnRzLmluc3RhbmNlcyk7XG4gICAgbGV0IG90aGVyRGVmcyA9IG90aGVyRXZlbnRTdG9yZS5kZWZzO1xuICAgIGxldCBvdGhlckluc3RhbmNlcyA9IG90aGVyRXZlbnRTdG9yZS5pbnN0YW5jZXM7XG4gICAgbGV0IG90aGVyQ29uZmlncyA9IGNvbXBpbGVFdmVudFVpcyhvdGhlckRlZnMsIHN0YXRlLmV2ZW50VWlCYXNlcyk7XG4gICAgZm9yIChsZXQgc3ViamVjdEluc3RhbmNlSWQgaW4gc3ViamVjdEluc3RhbmNlcykge1xuICAgICAgICBsZXQgc3ViamVjdEluc3RhbmNlID0gc3ViamVjdEluc3RhbmNlc1tzdWJqZWN0SW5zdGFuY2VJZF07XG4gICAgICAgIGxldCBzdWJqZWN0UmFuZ2UgPSBzdWJqZWN0SW5zdGFuY2UucmFuZ2U7XG4gICAgICAgIGxldCBzdWJqZWN0Q29uZmlnID0gc3ViamVjdENvbmZpZ3Nbc3ViamVjdEluc3RhbmNlLmRlZklkXTtcbiAgICAgICAgbGV0IHN1YmplY3REZWYgPSBzdWJqZWN0RGVmc1tzdWJqZWN0SW5zdGFuY2UuZGVmSWRdO1xuICAgICAgICAvLyBjb25zdHJhaW50XG4gICAgICAgIGlmICghYWxsQ29uc3RyYWludHNQYXNzKHN1YmplY3RDb25maWcuY29uc3RyYWludHMsIHN1YmplY3RSYW5nZSwgb3RoZXJFdmVudFN0b3JlLCBzdGF0ZS5idXNpbmVzc0hvdXJzLCBjb250ZXh0KSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIC8vIG92ZXJsYXBcbiAgICAgICAgbGV0IHsgZXZlbnRPdmVybGFwIH0gPSBjb250ZXh0Lm9wdGlvbnM7XG4gICAgICAgIGxldCBldmVudE92ZXJsYXBGdW5jID0gdHlwZW9mIGV2ZW50T3ZlcmxhcCA9PT0gJ2Z1bmN0aW9uJyA/IGV2ZW50T3ZlcmxhcCA6IG51bGw7XG4gICAgICAgIGZvciAobGV0IG90aGVySW5zdGFuY2VJZCBpbiBvdGhlckluc3RhbmNlcykge1xuICAgICAgICAgICAgbGV0IG90aGVySW5zdGFuY2UgPSBvdGhlckluc3RhbmNlc1tvdGhlckluc3RhbmNlSWRdO1xuICAgICAgICAgICAgLy8gaW50ZXJzZWN0ISBldmFsdWF0ZVxuICAgICAgICAgICAgaWYgKHJhbmdlc0ludGVyc2VjdChzdWJqZWN0UmFuZ2UsIG90aGVySW5zdGFuY2UucmFuZ2UpKSB7XG4gICAgICAgICAgICAgICAgbGV0IG90aGVyT3ZlcmxhcCA9IG90aGVyQ29uZmlnc1tvdGhlckluc3RhbmNlLmRlZklkXS5vdmVybGFwO1xuICAgICAgICAgICAgICAgIC8vIGNvbnNpZGVyIHRoZSBvdGhlciBldmVudCdzIG92ZXJsYXAuIG9ubHkgZG8gdGhpcyBpZiB0aGUgc3ViamVjdCBldmVudCBpcyBhIFwicmVhbFwiIGV2ZW50XG4gICAgICAgICAgICAgICAgaWYgKG90aGVyT3ZlcmxhcCA9PT0gZmFsc2UgJiYgaW50ZXJhY3Rpb24uaXNFdmVudCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChzdWJqZWN0Q29uZmlnLm92ZXJsYXAgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGV2ZW50T3ZlcmxhcEZ1bmMgJiYgIWV2ZW50T3ZlcmxhcEZ1bmMobmV3IEV2ZW50SW1wbChjb250ZXh0LCBvdGhlckRlZnNbb3RoZXJJbnN0YW5jZS5kZWZJZF0sIG90aGVySW5zdGFuY2UpLCAvLyBzdGlsbCBldmVudFxuICAgICAgICAgICAgICAgIG5ldyBFdmVudEltcGwoY29udGV4dCwgc3ViamVjdERlZiwgc3ViamVjdEluc3RhbmNlKSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvLyBhbGxvdyAoYSBmdW5jdGlvbilcbiAgICAgICAgbGV0IGNhbGVuZGFyRXZlbnRTdG9yZSA9IGN1cnJlbnRTdGF0ZS5ldmVudFN0b3JlOyAvLyBuZWVkIGdsb2JhbC10by1jYWxlbmRhciwgbm90IGxvY2FsIHRvIGNvbXBvbmVudCAoc3BsaXR0YWJsZSlzdGF0ZVxuICAgICAgICBmb3IgKGxldCBzdWJqZWN0QWxsb3cgb2Ygc3ViamVjdENvbmZpZy5hbGxvd3MpIHtcbiAgICAgICAgICAgIGxldCBzdWJqZWN0RGF0ZVNwYW4gPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGRhdGVTcGFuTWV0YSksIHsgcmFuZ2U6IHN1YmplY3RJbnN0YW5jZS5yYW5nZSwgYWxsRGF5OiBzdWJqZWN0RGVmLmFsbERheSB9KTtcbiAgICAgICAgICAgIGxldCBvcmlnRGVmID0gY2FsZW5kYXJFdmVudFN0b3JlLmRlZnNbc3ViamVjdERlZi5kZWZJZF07XG4gICAgICAgICAgICBsZXQgb3JpZ0luc3RhbmNlID0gY2FsZW5kYXJFdmVudFN0b3JlLmluc3RhbmNlc1tzdWJqZWN0SW5zdGFuY2VJZF07XG4gICAgICAgICAgICBsZXQgZXZlbnRBcGk7XG4gICAgICAgICAgICBpZiAob3JpZ0RlZikgeyAvLyB3YXMgcHJldmlvdXNseSBpbiB0aGUgY2FsZW5kYXJcbiAgICAgICAgICAgICAgICBldmVudEFwaSA9IG5ldyBFdmVudEltcGwoY29udGV4dCwgb3JpZ0RlZiwgb3JpZ0luc3RhbmNlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgeyAvLyB3YXMgYW4gZXh0ZXJuYWwgZXZlbnRcbiAgICAgICAgICAgICAgICBldmVudEFwaSA9IG5ldyBFdmVudEltcGwoY29udGV4dCwgc3ViamVjdERlZik7IC8vIG5vIGluc3RhbmNlLCBiZWNhdXNlIGhhZCBubyBkYXRlc1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFzdWJqZWN0QWxsb3coYnVpbGREYXRlU3BhbkFwaVdpdGhDb250ZXh0KHN1YmplY3REYXRlU3BhbiwgY29udGV4dCksIGV2ZW50QXBpKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn1cbi8vIERhdGUgU2VsZWN0aW9uIFZhbGlkYXRpb25cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuZnVuY3Rpb24gaXNEYXRlU2VsZWN0aW9uUHJvcHNWYWxpZChzdGF0ZSwgY29udGV4dCwgZGF0ZVNwYW5NZXRhLCBmaWx0ZXJDb25maWcpIHtcbiAgICBsZXQgcmVsZXZhbnRFdmVudFN0b3JlID0gc3RhdGUuZXZlbnRTdG9yZTtcbiAgICBsZXQgcmVsZXZhbnREZWZzID0gcmVsZXZhbnRFdmVudFN0b3JlLmRlZnM7XG4gICAgbGV0IHJlbGV2YW50SW5zdGFuY2VzID0gcmVsZXZhbnRFdmVudFN0b3JlLmluc3RhbmNlcztcbiAgICBsZXQgc2VsZWN0aW9uID0gc3RhdGUuZGF0ZVNlbGVjdGlvbjtcbiAgICBsZXQgc2VsZWN0aW9uUmFuZ2UgPSBzZWxlY3Rpb24ucmFuZ2U7XG4gICAgbGV0IHsgc2VsZWN0aW9uQ29uZmlnIH0gPSBjb250ZXh0LmdldEN1cnJlbnREYXRhKCk7XG4gICAgaWYgKGZpbHRlckNvbmZpZykge1xuICAgICAgICBzZWxlY3Rpb25Db25maWcgPSBmaWx0ZXJDb25maWcoc2VsZWN0aW9uQ29uZmlnKTtcbiAgICB9XG4gICAgLy8gY29uc3RyYWludFxuICAgIGlmICghYWxsQ29uc3RyYWludHNQYXNzKHNlbGVjdGlvbkNvbmZpZy5jb25zdHJhaW50cywgc2VsZWN0aW9uUmFuZ2UsIHJlbGV2YW50RXZlbnRTdG9yZSwgc3RhdGUuYnVzaW5lc3NIb3VycywgY29udGV4dCkpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICAvLyBvdmVybGFwXG4gICAgbGV0IHsgc2VsZWN0T3ZlcmxhcCB9ID0gY29udGV4dC5vcHRpb25zO1xuICAgIGxldCBzZWxlY3RPdmVybGFwRnVuYyA9IHR5cGVvZiBzZWxlY3RPdmVybGFwID09PSAnZnVuY3Rpb24nID8gc2VsZWN0T3ZlcmxhcCA6IG51bGw7XG4gICAgZm9yIChsZXQgcmVsZXZhbnRJbnN0YW5jZUlkIGluIHJlbGV2YW50SW5zdGFuY2VzKSB7XG4gICAgICAgIGxldCByZWxldmFudEluc3RhbmNlID0gcmVsZXZhbnRJbnN0YW5jZXNbcmVsZXZhbnRJbnN0YW5jZUlkXTtcbiAgICAgICAgLy8gaW50ZXJzZWN0ISBldmFsdWF0ZVxuICAgICAgICBpZiAocmFuZ2VzSW50ZXJzZWN0KHNlbGVjdGlvblJhbmdlLCByZWxldmFudEluc3RhbmNlLnJhbmdlKSkge1xuICAgICAgICAgICAgaWYgKHNlbGVjdGlvbkNvbmZpZy5vdmVybGFwID09PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChzZWxlY3RPdmVybGFwRnVuYyAmJiAhc2VsZWN0T3ZlcmxhcEZ1bmMobmV3IEV2ZW50SW1wbChjb250ZXh0LCByZWxldmFudERlZnNbcmVsZXZhbnRJbnN0YW5jZS5kZWZJZF0sIHJlbGV2YW50SW5zdGFuY2UpLCBudWxsKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBhbGxvdyAoYSBmdW5jdGlvbilcbiAgICBmb3IgKGxldCBzZWxlY3Rpb25BbGxvdyBvZiBzZWxlY3Rpb25Db25maWcuYWxsb3dzKSB7XG4gICAgICAgIGxldCBmdWxsRGF0ZVNwYW4gPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGRhdGVTcGFuTWV0YSksIHNlbGVjdGlvbik7XG4gICAgICAgIGlmICghc2VsZWN0aW9uQWxsb3coYnVpbGREYXRlU3BhbkFwaVdpdGhDb250ZXh0KGZ1bGxEYXRlU3BhbiwgY29udGV4dCksIG51bGwpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG59XG4vLyBDb25zdHJhaW50IFV0aWxzXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbmZ1bmN0aW9uIGFsbENvbnN0cmFpbnRzUGFzcyhjb25zdHJhaW50cywgc3ViamVjdFJhbmdlLCBvdGhlckV2ZW50U3RvcmUsIGJ1c2luZXNzSG91cnNVbmV4cGFuZGVkLCBjb250ZXh0KSB7XG4gICAgZm9yIChsZXQgY29uc3RyYWludCBvZiBjb25zdHJhaW50cykge1xuICAgICAgICBpZiAoIWFueVJhbmdlc0NvbnRhaW5SYW5nZShjb25zdHJhaW50VG9SYW5nZXMoY29uc3RyYWludCwgc3ViamVjdFJhbmdlLCBvdGhlckV2ZW50U3RvcmUsIGJ1c2luZXNzSG91cnNVbmV4cGFuZGVkLCBjb250ZXh0KSwgc3ViamVjdFJhbmdlKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xufVxuZnVuY3Rpb24gY29uc3RyYWludFRvUmFuZ2VzKGNvbnN0cmFpbnQsIHN1YmplY3RSYW5nZSwgLy8gZm9yIGV4cGFuZGluZyBhIHJlY3VycmluZyBjb25zdHJhaW50LCBvciBleHBhbmRpbmcgYnVzaW5lc3MgaG91cnNcbm90aGVyRXZlbnRTdG9yZSwgLy8gZm9yIGlmIGNvbnN0cmFpbnQgaXMgYW4gZXZlbiBncm91cCBJRFxuYnVzaW5lc3NIb3Vyc1VuZXhwYW5kZWQsIC8vIGZvciBpZiBjb25zdHJhaW50IGlzICdidXNpbmVzc0hvdXJzJ1xuY29udGV4dCkge1xuICAgIGlmIChjb25zdHJhaW50ID09PSAnYnVzaW5lc3NIb3VycycpIHtcbiAgICAgICAgcmV0dXJuIGV2ZW50U3RvcmVUb1JhbmdlcyhleHBhbmRSZWN1cnJpbmcoYnVzaW5lc3NIb3Vyc1VuZXhwYW5kZWQsIHN1YmplY3RSYW5nZSwgY29udGV4dCkpO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIGNvbnN0cmFpbnQgPT09ICdzdHJpbmcnKSB7IC8vIGFuIGdyb3VwIElEXG4gICAgICAgIHJldHVybiBldmVudFN0b3JlVG9SYW5nZXMoZmlsdGVyRXZlbnRTdG9yZURlZnMob3RoZXJFdmVudFN0b3JlLCAoZXZlbnREZWYpID0+IGV2ZW50RGVmLmdyb3VwSWQgPT09IGNvbnN0cmFpbnQpKTtcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBjb25zdHJhaW50ID09PSAnb2JqZWN0JyAmJiBjb25zdHJhaW50KSB7IC8vIG5vbi1udWxsIG9iamVjdFxuICAgICAgICByZXR1cm4gZXZlbnRTdG9yZVRvUmFuZ2VzKGV4cGFuZFJlY3VycmluZyhjb25zdHJhaW50LCBzdWJqZWN0UmFuZ2UsIGNvbnRleHQpKTtcbiAgICB9XG4gICAgcmV0dXJuIFtdOyAvLyBpZiBpdCdzIGZhbHNlXG59XG4vLyBUT0RPOiBtb3ZlIHRvIGV2ZW50LXN0b3JlIGZpbGU/XG5mdW5jdGlvbiBldmVudFN0b3JlVG9SYW5nZXMoZXZlbnRTdG9yZSkge1xuICAgIGxldCB7IGluc3RhbmNlcyB9ID0gZXZlbnRTdG9yZTtcbiAgICBsZXQgcmFuZ2VzID0gW107XG4gICAgZm9yIChsZXQgaW5zdGFuY2VJZCBpbiBpbnN0YW5jZXMpIHtcbiAgICAgICAgcmFuZ2VzLnB1c2goaW5zdGFuY2VzW2luc3RhbmNlSWRdLnJhbmdlKTtcbiAgICB9XG4gICAgcmV0dXJuIHJhbmdlcztcbn1cbi8vIFRPRE86IG1vdmUgdG8gZ2VvbSBmaWxlP1xuZnVuY3Rpb24gYW55UmFuZ2VzQ29udGFpblJhbmdlKG91dGVyUmFuZ2VzLCBpbm5lclJhbmdlKSB7XG4gICAgZm9yIChsZXQgb3V0ZXJSYW5nZSBvZiBvdXRlclJhbmdlcykge1xuICAgICAgICBpZiAocmFuZ2VDb250YWluc1JhbmdlKG91dGVyUmFuZ2UsIGlubmVyUmFuZ2UpKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG59XG5cbmNvbnN0IFZJU0lCTEVfSElEREVOX1JFID0gL14odmlzaWJsZXxoaWRkZW4pJC87XG5jbGFzcyBTY3JvbGxlciBleHRlbmRzIEJhc2VDb21wb25lbnQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICB0aGlzLmhhbmRsZUVsID0gKGVsKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmVsID0gZWw7XG4gICAgICAgICAgICBzZXRSZWYodGhpcy5wcm9wcy5lbFJlZiwgZWwpO1xuICAgICAgICB9O1xuICAgIH1cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGxldCB7IHByb3BzIH0gPSB0aGlzO1xuICAgICAgICBsZXQgeyBsaXF1aWQsIGxpcXVpZElzQWJzb2x1dGUgfSA9IHByb3BzO1xuICAgICAgICBsZXQgaXNBYnNvbHV0ZSA9IGxpcXVpZCAmJiBsaXF1aWRJc0Fic29sdXRlO1xuICAgICAgICBsZXQgY2xhc3NOYW1lID0gWydmYy1zY3JvbGxlciddO1xuICAgICAgICBpZiAobGlxdWlkKSB7XG4gICAgICAgICAgICBpZiAobGlxdWlkSXNBYnNvbHV0ZSkge1xuICAgICAgICAgICAgICAgIGNsYXNzTmFtZS5wdXNoKCdmYy1zY3JvbGxlci1saXF1aWQtYWJzb2x1dGUnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGNsYXNzTmFtZS5wdXNoKCdmYy1zY3JvbGxlci1saXF1aWQnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyByZWY6IHRoaXMuaGFuZGxlRWwsIGNsYXNzTmFtZTogY2xhc3NOYW1lLmpvaW4oJyAnKSwgc3R5bGU6IHtcbiAgICAgICAgICAgICAgICBvdmVyZmxvd1g6IHByb3BzLm92ZXJmbG93WCxcbiAgICAgICAgICAgICAgICBvdmVyZmxvd1k6IHByb3BzLm92ZXJmbG93WSxcbiAgICAgICAgICAgICAgICBsZWZ0OiAoaXNBYnNvbHV0ZSAmJiAtKHByb3BzLm92ZXJjb21lTGVmdCB8fCAwKSkgfHwgJycsXG4gICAgICAgICAgICAgICAgcmlnaHQ6IChpc0Fic29sdXRlICYmIC0ocHJvcHMub3ZlcmNvbWVSaWdodCB8fCAwKSkgfHwgJycsXG4gICAgICAgICAgICAgICAgYm90dG9tOiAoaXNBYnNvbHV0ZSAmJiAtKHByb3BzLm92ZXJjb21lQm90dG9tIHx8IDApKSB8fCAnJyxcbiAgICAgICAgICAgICAgICBtYXJnaW5MZWZ0OiAoIWlzQWJzb2x1dGUgJiYgLShwcm9wcy5vdmVyY29tZUxlZnQgfHwgMCkpIHx8ICcnLFxuICAgICAgICAgICAgICAgIG1hcmdpblJpZ2h0OiAoIWlzQWJzb2x1dGUgJiYgLShwcm9wcy5vdmVyY29tZVJpZ2h0IHx8IDApKSB8fCAnJyxcbiAgICAgICAgICAgICAgICBtYXJnaW5Cb3R0b206ICghaXNBYnNvbHV0ZSAmJiAtKHByb3BzLm92ZXJjb21lQm90dG9tIHx8IDApKSB8fCAnJyxcbiAgICAgICAgICAgICAgICBtYXhIZWlnaHQ6IHByb3BzLm1heEhlaWdodCB8fCAnJyxcbiAgICAgICAgICAgIH0gfSwgcHJvcHMuY2hpbGRyZW4pKTtcbiAgICB9XG4gICAgbmVlZHNYU2Nyb2xsaW5nKCkge1xuICAgICAgICBpZiAoVklTSUJMRV9ISURERU5fUkUudGVzdCh0aGlzLnByb3BzLm92ZXJmbG93WCkpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICAvLyB0ZXN0aW5nIHNjcm9sbFdpZHRoPmNsaWVudFdpZHRoIGlzIHVucmVsaWFibGUgY3Jvc3MtYnJvd3NlciB3aGVuIHBpeGVsIGhlaWdodHMgYXJlbid0IGludGVnZXJzLlxuICAgICAgICAvLyBtdWNoIG1vcmUgcmVsaWFibGUgdG8gc2VlIGlmIGNoaWxkcmVuIGFyZSB0YWxsZXIgdGhhbiB0aGUgc2Nyb2xsZXIsIGV2ZW4gdGhvIGRvZXNuJ3QgYWNjb3VudCBmb3JcbiAgICAgICAgLy8gaW5uZXItY2hpbGQgbWFyZ2lucyBhbmQgYWJzb2x1dGUgcG9zaXRpb25pbmdcbiAgICAgICAgbGV0IHsgZWwgfSA9IHRoaXM7XG4gICAgICAgIGxldCByZWFsQ2xpZW50V2lkdGggPSB0aGlzLmVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLndpZHRoIC0gdGhpcy5nZXRZU2Nyb2xsYmFyV2lkdGgoKTtcbiAgICAgICAgbGV0IHsgY2hpbGRyZW4gfSA9IGVsO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNoaWxkcmVuLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICAgICAgICBsZXQgY2hpbGRFbCA9IGNoaWxkcmVuW2ldO1xuICAgICAgICAgICAgaWYgKGNoaWxkRWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkud2lkdGggPiByZWFsQ2xpZW50V2lkdGgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIG5lZWRzWVNjcm9sbGluZygpIHtcbiAgICAgICAgaWYgKFZJU0lCTEVfSElEREVOX1JFLnRlc3QodGhpcy5wcm9wcy5vdmVyZmxvd1kpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgLy8gdGVzdGluZyBzY3JvbGxIZWlnaHQ+Y2xpZW50SGVpZ2h0IGlzIHVucmVsaWFibGUgY3Jvc3MtYnJvd3NlciB3aGVuIHBpeGVsIGhlaWdodHMgYXJlbid0IGludGVnZXJzLlxuICAgICAgICAvLyBtdWNoIG1vcmUgcmVsaWFibGUgdG8gc2VlIGlmIGNoaWxkcmVuIGFyZSB0YWxsZXIgdGhhbiB0aGUgc2Nyb2xsZXIsIGV2ZW4gdGhvIGRvZXNuJ3QgYWNjb3VudCBmb3JcbiAgICAgICAgLy8gaW5uZXItY2hpbGQgbWFyZ2lucyBhbmQgYWJzb2x1dGUgcG9zaXRpb25pbmdcbiAgICAgICAgbGV0IHsgZWwgfSA9IHRoaXM7XG4gICAgICAgIGxldCByZWFsQ2xpZW50SGVpZ2h0ID0gdGhpcy5lbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5oZWlnaHQgLSB0aGlzLmdldFhTY3JvbGxiYXJXaWR0aCgpO1xuICAgICAgICBsZXQgeyBjaGlsZHJlbiB9ID0gZWw7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY2hpbGRyZW4ubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgICAgIGxldCBjaGlsZEVsID0gY2hpbGRyZW5baV07XG4gICAgICAgICAgICBpZiAoY2hpbGRFbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5oZWlnaHQgPiByZWFsQ2xpZW50SGVpZ2h0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBnZXRYU2Nyb2xsYmFyV2lkdGgoKSB7XG4gICAgICAgIGlmIChWSVNJQkxFX0hJRERFTl9SRS50ZXN0KHRoaXMucHJvcHMub3ZlcmZsb3dYKSkge1xuICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuZWwub2Zmc2V0SGVpZ2h0IC0gdGhpcy5lbC5jbGllbnRIZWlnaHQ7IC8vIG9ubHkgd29ya3MgYmVjYXVzZSB3ZSBndWFyYW50ZWUgbm8gYm9yZGVycy4gVE9ETzogYWRkIHRvIENTUyB3aXRoIGltcG9ydGFudD9cbiAgICB9XG4gICAgZ2V0WVNjcm9sbGJhcldpZHRoKCkge1xuICAgICAgICBpZiAoVklTSUJMRV9ISURERU5fUkUudGVzdCh0aGlzLnByb3BzLm92ZXJmbG93WSkpIHtcbiAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLmVsLm9mZnNldFdpZHRoIC0gdGhpcy5lbC5jbGllbnRXaWR0aDsgLy8gb25seSB3b3JrcyBiZWNhdXNlIHdlIGd1YXJhbnRlZSBubyBib3JkZXJzLiBUT0RPOiBhZGQgdG8gQ1NTIHdpdGggaW1wb3J0YW50P1xuICAgIH1cbn1cblxuLypcblRPRE86IHNvbWVob3cgaW5mZXIgT3RoZXJBcmdzIGZyb20gbWFzdGVyQ2FsbGJhY2s/XG5UT0RPOiBpbmZlciBSZWZUeXBlIGZyb20gbWFzdGVyQ2FsbGJhY2sgaWYgcHJvdmlkZWRcbiovXG5jbGFzcyBSZWZNYXAge1xuICAgIGNvbnN0cnVjdG9yKG1hc3RlckNhbGxiYWNrKSB7XG4gICAgICAgIHRoaXMubWFzdGVyQ2FsbGJhY2sgPSBtYXN0ZXJDYWxsYmFjaztcbiAgICAgICAgdGhpcy5jdXJyZW50TWFwID0ge307XG4gICAgICAgIHRoaXMuZGVwdGhzID0ge307XG4gICAgICAgIHRoaXMuY2FsbGJhY2tNYXAgPSB7fTtcbiAgICAgICAgdGhpcy5oYW5kbGVWYWx1ZSA9ICh2YWwsIGtleSkgPT4ge1xuICAgICAgICAgICAgbGV0IHsgZGVwdGhzLCBjdXJyZW50TWFwIH0gPSB0aGlzO1xuICAgICAgICAgICAgbGV0IHJlbW92ZWQgPSBmYWxzZTtcbiAgICAgICAgICAgIGxldCBhZGRlZCA9IGZhbHNlO1xuICAgICAgICAgICAgaWYgKHZhbCAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIC8vIGZvciBidWcuLi4gQUNUVUFMTFk6IGNhbiBwcm9iYWJseSBkbyBhd2F5IHdpdGggdGhpcyBub3cgdGhhdCBjYWxsZXJzIGRvbid0IHNoYXJlIG51bWVyaWMgaW5kaWNlcyBhbnltb3JlXG4gICAgICAgICAgICAgICAgcmVtb3ZlZCA9IChrZXkgaW4gY3VycmVudE1hcCk7XG4gICAgICAgICAgICAgICAgY3VycmVudE1hcFtrZXldID0gdmFsO1xuICAgICAgICAgICAgICAgIGRlcHRoc1trZXldID0gKGRlcHRoc1trZXldIHx8IDApICsgMTtcbiAgICAgICAgICAgICAgICBhZGRlZCA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBkZXB0aHNba2V5XSAtPSAxO1xuICAgICAgICAgICAgICAgIGlmICghZGVwdGhzW2tleV0pIHtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIGN1cnJlbnRNYXBba2V5XTtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMuY2FsbGJhY2tNYXBba2V5XTtcbiAgICAgICAgICAgICAgICAgICAgcmVtb3ZlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHRoaXMubWFzdGVyQ2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICBpZiAocmVtb3ZlZCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm1hc3RlckNhbGxiYWNrKG51bGwsIFN0cmluZyhrZXkpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGFkZGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubWFzdGVyQ2FsbGJhY2sodmFsLCBTdHJpbmcoa2V5KSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgIH1cbiAgICBjcmVhdGVSZWYoa2V5KSB7XG4gICAgICAgIGxldCByZWZDYWxsYmFjayA9IHRoaXMuY2FsbGJhY2tNYXBba2V5XTtcbiAgICAgICAgaWYgKCFyZWZDYWxsYmFjaykge1xuICAgICAgICAgICAgcmVmQ2FsbGJhY2sgPSB0aGlzLmNhbGxiYWNrTWFwW2tleV0gPSAodmFsKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5oYW5kbGVWYWx1ZSh2YWwsIFN0cmluZyhrZXkpKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlZkNhbGxiYWNrO1xuICAgIH1cbiAgICAvLyBUT0RPOiBjaGVjayBjYWxsZXJzIHRoYXQgZG9uJ3QgY2FyZSBhYm91dCBvcmRlci4gc2hvdWxkIHVzZSBnZXRBbGwgaW5zdGVhZFxuICAgIC8vIE5PVEU6IHRoaXMgbWV0aG9kIGhhcyBiZWNvbWUgbGVzcyB2YWx1YWJsZSBub3cgdGhhdCB3ZSBhcmUgZW5jb3VyYWdlZCB0byBtYXAgb3JkZXIgYnkgc29tZSBvdGhlciBpbmRleFxuICAgIC8vIFRPRE86IHByb3ZpZGUgT05FIGFycmF5LWV4cG9ydCBmdW5jdGlvbiwgYnVpbGRBcnJheSwgd2hpY2ggZmFpbHMgb24gbm9uLW51bWVyaWMgaW5kZXhlcy4gY2FsbGVyIGNhbiBtYW5pcHVsYXRlIGFuZCBcImNvbGxlY3RcIlxuICAgIGNvbGxlY3Qoc3RhcnRJbmRleCwgZW5kSW5kZXgsIHN0ZXApIHtcbiAgICAgICAgcmV0dXJuIGNvbGxlY3RGcm9tSGFzaCh0aGlzLmN1cnJlbnRNYXAsIHN0YXJ0SW5kZXgsIGVuZEluZGV4LCBzdGVwKTtcbiAgICB9XG4gICAgZ2V0QWxsKCkge1xuICAgICAgICByZXR1cm4gaGFzaFZhbHVlc1RvQXJyYXkodGhpcy5jdXJyZW50TWFwKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGNvbXB1dGVTaHJpbmtXaWR0aChjaHVua0Vscykge1xuICAgIGxldCBzaHJpbmtDZWxscyA9IGZpbmRFbGVtZW50cyhjaHVua0VscywgJy5mYy1zY3JvbGxncmlkLXNocmluaycpO1xuICAgIGxldCBsYXJnZXN0V2lkdGggPSAwO1xuICAgIGZvciAobGV0IHNocmlua0NlbGwgb2Ygc2hyaW5rQ2VsbHMpIHtcbiAgICAgICAgbGFyZ2VzdFdpZHRoID0gTWF0aC5tYXgobGFyZ2VzdFdpZHRoLCBjb21wdXRlU21hbGxlc3RDZWxsV2lkdGgoc2hyaW5rQ2VsbCkpO1xuICAgIH1cbiAgICByZXR1cm4gTWF0aC5jZWlsKGxhcmdlc3RXaWR0aCk7IC8vIDx0YWJsZT4gZWxlbWVudHMgd29yayBiZXN0IHdpdGggaW50ZWdlcnMuIHJvdW5kIHVwIHRvIGVuc3VyZSBjb250ZW50cyBmaXRzXG59XG5mdW5jdGlvbiBnZXRTZWN0aW9uSGFzTGlxdWlkSGVpZ2h0KHByb3BzLCBzZWN0aW9uQ29uZmlnKSB7XG4gICAgcmV0dXJuIHByb3BzLmxpcXVpZCAmJiBzZWN0aW9uQ29uZmlnLmxpcXVpZDsgLy8gZG9lcyB0aGUgc2VjdGlvbiBkbyBsaXF1aWQtaGVpZ2h0PyAobmVlZCB0byBoYXZlIHdob2xlIHNjcm9sbGdyaWQgbGlxdWlkLWhlaWdodCBhcyB3ZWxsKVxufVxuZnVuY3Rpb24gZ2V0QWxsb3dZU2Nyb2xsaW5nKHByb3BzLCBzZWN0aW9uQ29uZmlnKSB7XG4gICAgcmV0dXJuIHNlY3Rpb25Db25maWcubWF4SGVpZ2h0ICE9IG51bGwgfHwgLy8gaWYgaXRzIHBvc3NpYmxlIGZvciB0aGUgaGVpZ2h0IHRvIG1heCBvdXQsIHdlIG1pZ2h0IG5lZWQgc2Nyb2xsYmFyc1xuICAgICAgICBnZXRTZWN0aW9uSGFzTGlxdWlkSGVpZ2h0KHByb3BzLCBzZWN0aW9uQ29uZmlnKTsgLy8gaWYgdGhlIHNlY3Rpb24gaXMgbGlxdWlkIGhlaWdodCwgaXQgbWlnaHQgY29uZGVuc2UgZW5vdWdoIHRvIHJlcXVpcmUgc2Nyb2xsYmFyc1xufVxuLy8gVE9ETzogT05MWSB1c2UgYGFyZ2AuIGZvcmNlIG91dCBpbnRlcm5hbCBmdW5jdGlvbiB0byB1c2Ugc2FtZSBBUElcbmZ1bmN0aW9uIHJlbmRlckNodW5rQ29udGVudChzZWN0aW9uQ29uZmlnLCBjaHVua0NvbmZpZywgYXJnLCBpc0hlYWRlcikge1xuICAgIGxldCB7IGV4cGFuZFJvd3MgfSA9IGFyZztcbiAgICBsZXQgY29udGVudCA9IHR5cGVvZiBjaHVua0NvbmZpZy5jb250ZW50ID09PSAnZnVuY3Rpb24nID9cbiAgICAgICAgY2h1bmtDb25maWcuY29udGVudChhcmcpIDpcbiAgICAgICAgY3JlYXRlRWxlbWVudCgndGFibGUnLCB7XG4gICAgICAgICAgICByb2xlOiAncHJlc2VudGF0aW9uJyxcbiAgICAgICAgICAgIGNsYXNzTmFtZTogW1xuICAgICAgICAgICAgICAgIGNodW5rQ29uZmlnLnRhYmxlQ2xhc3NOYW1lLFxuICAgICAgICAgICAgICAgIHNlY3Rpb25Db25maWcuc3luY1Jvd0hlaWdodHMgPyAnZmMtc2Nyb2xsZ3JpZC1zeW5jLXRhYmxlJyA6ICcnLFxuICAgICAgICAgICAgXS5qb2luKCcgJyksXG4gICAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgICAgIG1pbldpZHRoOiBhcmcudGFibGVNaW5XaWR0aCxcbiAgICAgICAgICAgICAgICB3aWR0aDogYXJnLmNsaWVudFdpZHRoLFxuICAgICAgICAgICAgICAgIGhlaWdodDogZXhwYW5kUm93cyA/IGFyZy5jbGllbnRIZWlnaHQgOiAnJywgLy8gY3NzIGBoZWlnaHRgIG9uIGEgPHRhYmxlPiBzZXJ2ZXMgYXMgYSBtaW4taGVpZ2h0XG4gICAgICAgICAgICB9LFxuICAgICAgICB9LCBhcmcudGFibGVDb2xHcm91cE5vZGUsIGNyZWF0ZUVsZW1lbnQoaXNIZWFkZXIgPyAndGhlYWQnIDogJ3Rib2R5Jywge1xuICAgICAgICAgICAgcm9sZTogJ3ByZXNlbnRhdGlvbicsXG4gICAgICAgIH0sIHR5cGVvZiBjaHVua0NvbmZpZy5yb3dDb250ZW50ID09PSAnZnVuY3Rpb24nXG4gICAgICAgICAgICA/IGNodW5rQ29uZmlnLnJvd0NvbnRlbnQoYXJnKVxuICAgICAgICAgICAgOiBjaHVua0NvbmZpZy5yb3dDb250ZW50KSk7XG4gICAgcmV0dXJuIGNvbnRlbnQ7XG59XG5mdW5jdGlvbiBpc0NvbFByb3BzRXF1YWwoY29sczAsIGNvbHMxKSB7XG4gICAgcmV0dXJuIGlzQXJyYXlzRXF1YWwoY29sczAsIGNvbHMxLCBpc1Byb3BzRXF1YWwpO1xufVxuZnVuY3Rpb24gcmVuZGVyTWljcm9Db2xHcm91cChjb2xzLCBzaHJpbmtXaWR0aCkge1xuICAgIGxldCBjb2xOb2RlcyA9IFtdO1xuICAgIC8qXG4gICAgZm9yIENvbFByb3BzIHdpdGggc3BhbnMsIGl0IHdvdWxkIGhhdmUgYmVlbiBncmVhdCB0byBtYWtlIGEgc2luZ2xlIDxjb2wgc3Bhbj1cIlwiPlxuICAgIEhPV0VWRVIsIENocm9tZSB3YXMgZ2V0dGluZyBtZXNzaW5nIHVwIGRpc3RyaWJ1dGluZyB0aGUgd2lkdGggdG8gPHRkPi88dGg+IGVsZW1lbnRzIHdpdGggY29sc3BhbnMuXG4gICAgU09MVVRJT046IG1ha2luZyBpbmRpdmlkdWFsIDxjb2w+IGVsZW1lbnRzIG1ha2VzIENocm9tZSBiZWhhdmUuXG4gICAgKi9cbiAgICBmb3IgKGxldCBjb2xQcm9wcyBvZiBjb2xzKSB7XG4gICAgICAgIGxldCBzcGFuID0gY29sUHJvcHMuc3BhbiB8fCAxO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNwYW47IGkgKz0gMSkge1xuICAgICAgICAgICAgY29sTm9kZXMucHVzaChjcmVhdGVFbGVtZW50KFwiY29sXCIsIHsgc3R5bGU6IHtcbiAgICAgICAgICAgICAgICAgICAgd2lkdGg6IGNvbFByb3BzLndpZHRoID09PSAnc2hyaW5rJyA/IHNhbml0aXplU2hyaW5rV2lkdGgoc2hyaW5rV2lkdGgpIDogKGNvbFByb3BzLndpZHRoIHx8ICcnKSxcbiAgICAgICAgICAgICAgICAgICAgbWluV2lkdGg6IGNvbFByb3BzLm1pbldpZHRoIHx8ICcnLFxuICAgICAgICAgICAgICAgIH0gfSkpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBjcmVhdGVFbGVtZW50KCdjb2xncm91cCcsIHt9LCAuLi5jb2xOb2Rlcyk7XG59XG5mdW5jdGlvbiBzYW5pdGl6ZVNocmlua1dpZHRoKHNocmlua1dpZHRoKSB7XG4gICAgLyogd2h5IDQ/IGlmIHdlIGRvIDAsIGl0IHdpbGwga2lsbCBhbnkgYm9yZGVyLCB3aGljaCBhcmUgbmVlZGVkIGZvciBjb21wdXRlU21hbGxlc3RDZWxsV2lkdGhcbiAgICA0IGFjY291bnRzIGZvciAyIDItcGl4ZWwgYm9yZGVycy4gVE9ETzogYmV0dGVyIHNvbHV0aW9uPyAqL1xuICAgIHJldHVybiBzaHJpbmtXaWR0aCA9PSBudWxsID8gNCA6IHNocmlua1dpZHRoO1xufVxuZnVuY3Rpb24gaGFzU2hyaW5rV2lkdGgoY29scykge1xuICAgIGZvciAobGV0IGNvbCBvZiBjb2xzKSB7XG4gICAgICAgIGlmIChjb2wud2lkdGggPT09ICdzaHJpbmsnKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG59XG5mdW5jdGlvbiBnZXRTY3JvbGxHcmlkQ2xhc3NOYW1lcyhsaXF1aWQsIGNvbnRleHQpIHtcbiAgICBsZXQgY2xhc3NOYW1lcyA9IFtcbiAgICAgICAgJ2ZjLXNjcm9sbGdyaWQnLFxuICAgICAgICBjb250ZXh0LnRoZW1lLmdldENsYXNzKCd0YWJsZScpLFxuICAgIF07XG4gICAgaWYgKGxpcXVpZCkge1xuICAgICAgICBjbGFzc05hbWVzLnB1c2goJ2ZjLXNjcm9sbGdyaWQtbGlxdWlkJyk7XG4gICAgfVxuICAgIHJldHVybiBjbGFzc05hbWVzO1xufVxuZnVuY3Rpb24gZ2V0U2VjdGlvbkNsYXNzTmFtZXMoc2VjdGlvbkNvbmZpZywgd2hvbGVUYWJsZVZHcm93KSB7XG4gICAgbGV0IGNsYXNzTmFtZXMgPSBbXG4gICAgICAgICdmYy1zY3JvbGxncmlkLXNlY3Rpb24nLFxuICAgICAgICBgZmMtc2Nyb2xsZ3JpZC1zZWN0aW9uLSR7c2VjdGlvbkNvbmZpZy50eXBlfWAsXG4gICAgICAgIHNlY3Rpb25Db25maWcuY2xhc3NOYW1lLCAvLyB1c2VkP1xuICAgIF07XG4gICAgaWYgKHdob2xlVGFibGVWR3JvdyAmJiBzZWN0aW9uQ29uZmlnLmxpcXVpZCAmJiBzZWN0aW9uQ29uZmlnLm1heEhlaWdodCA9PSBudWxsKSB7XG4gICAgICAgIGNsYXNzTmFtZXMucHVzaCgnZmMtc2Nyb2xsZ3JpZC1zZWN0aW9uLWxpcXVpZCcpO1xuICAgIH1cbiAgICBpZiAoc2VjdGlvbkNvbmZpZy5pc1N0aWNreSkge1xuICAgICAgICBjbGFzc05hbWVzLnB1c2goJ2ZjLXNjcm9sbGdyaWQtc2VjdGlvbi1zdGlja3knKTtcbiAgICB9XG4gICAgcmV0dXJuIGNsYXNzTmFtZXM7XG59XG5mdW5jdGlvbiByZW5kZXJTY3JvbGxTaGltKGFyZykge1xuICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChcImRpdlwiLCB7IGNsYXNzTmFtZTogXCJmYy1zY3JvbGxncmlkLXN0aWNreS1zaGltXCIsIHN0eWxlOiB7XG4gICAgICAgICAgICB3aWR0aDogYXJnLmNsaWVudFdpZHRoLFxuICAgICAgICAgICAgbWluV2lkdGg6IGFyZy50YWJsZU1pbldpZHRoLFxuICAgICAgICB9IH0pKTtcbn1cbmZ1bmN0aW9uIGdldFN0aWNreUhlYWRlckRhdGVzKG9wdGlvbnMpIHtcbiAgICBsZXQgeyBzdGlja3lIZWFkZXJEYXRlcyB9ID0gb3B0aW9ucztcbiAgICBpZiAoc3RpY2t5SGVhZGVyRGF0ZXMgPT0gbnVsbCB8fCBzdGlja3lIZWFkZXJEYXRlcyA9PT0gJ2F1dG8nKSB7XG4gICAgICAgIHN0aWNreUhlYWRlckRhdGVzID0gb3B0aW9ucy5oZWlnaHQgPT09ICdhdXRvJyB8fCBvcHRpb25zLnZpZXdIZWlnaHQgPT09ICdhdXRvJztcbiAgICB9XG4gICAgcmV0dXJuIHN0aWNreUhlYWRlckRhdGVzO1xufVxuZnVuY3Rpb24gZ2V0U3RpY2t5Rm9vdGVyU2Nyb2xsYmFyKG9wdGlvbnMpIHtcbiAgICBsZXQgeyBzdGlja3lGb290ZXJTY3JvbGxiYXIgfSA9IG9wdGlvbnM7XG4gICAgaWYgKHN0aWNreUZvb3RlclNjcm9sbGJhciA9PSBudWxsIHx8IHN0aWNreUZvb3RlclNjcm9sbGJhciA9PT0gJ2F1dG8nKSB7XG4gICAgICAgIHN0aWNreUZvb3RlclNjcm9sbGJhciA9IG9wdGlvbnMuaGVpZ2h0ID09PSAnYXV0bycgfHwgb3B0aW9ucy52aWV3SGVpZ2h0ID09PSAnYXV0byc7XG4gICAgfVxuICAgIHJldHVybiBzdGlja3lGb290ZXJTY3JvbGxiYXI7XG59XG5cbmNsYXNzIFNpbXBsZVNjcm9sbEdyaWQgZXh0ZW5kcyBCYXNlQ29tcG9uZW50IHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoLi4uYXJndW1lbnRzKTtcbiAgICAgICAgdGhpcy5wcm9jZXNzQ29scyA9IG1lbW9pemUoKGEpID0+IGEsIGlzQ29sUHJvcHNFcXVhbCk7IC8vIHNvIHdlIGdldCBzYW1lIGBjb2xzYCBwcm9wcyBldmVyeSB0aW1lXG4gICAgICAgIC8vIHl1Y2t5IHRvIG1lbW9pemUgVk5vZGVzLCBidXQgbXVjaCBtb3JlIGVmZmljaWVudCBmb3IgY29uc3VtZXJzXG4gICAgICAgIHRoaXMucmVuZGVyTWljcm9Db2xHcm91cCA9IG1lbW9pemUocmVuZGVyTWljcm9Db2xHcm91cCk7XG4gICAgICAgIHRoaXMuc2Nyb2xsZXJSZWZzID0gbmV3IFJlZk1hcCgpO1xuICAgICAgICB0aGlzLnNjcm9sbGVyRWxSZWZzID0gbmV3IFJlZk1hcCh0aGlzLl9oYW5kbGVTY3JvbGxlckVsLmJpbmQodGhpcykpO1xuICAgICAgICB0aGlzLnN0YXRlID0ge1xuICAgICAgICAgICAgc2hyaW5rV2lkdGg6IG51bGwsXG4gICAgICAgICAgICBmb3JjZVlTY3JvbGxiYXJzOiBmYWxzZSxcbiAgICAgICAgICAgIHNjcm9sbGVyQ2xpZW50V2lkdGhzOiB7fSxcbiAgICAgICAgICAgIHNjcm9sbGVyQ2xpZW50SGVpZ2h0czoge30sXG4gICAgICAgIH07XG4gICAgICAgIC8vIFRPRE86IGNhbiBkbyBhIHJlYWxseSBzaW1wbGUgcHJpbnQtdmlldy4gZG9udCBuZWVkIHRvIGpvaW4gcm93c1xuICAgICAgICB0aGlzLmhhbmRsZVNpemluZyA9ICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2FmZVNldFN0YXRlKE9iamVjdC5hc3NpZ24oeyBzaHJpbmtXaWR0aDogdGhpcy5jb21wdXRlU2hyaW5rV2lkdGgoKSB9LCB0aGlzLmNvbXB1dGVTY3JvbGxlckRpbXMoKSkpO1xuICAgICAgICB9O1xuICAgIH1cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGxldCB7IHByb3BzLCBzdGF0ZSwgY29udGV4dCB9ID0gdGhpcztcbiAgICAgICAgbGV0IHNlY3Rpb25Db25maWdzID0gcHJvcHMuc2VjdGlvbnMgfHwgW107XG4gICAgICAgIGxldCBjb2xzID0gdGhpcy5wcm9jZXNzQ29scyhwcm9wcy5jb2xzKTtcbiAgICAgICAgbGV0IG1pY3JvQ29sR3JvdXBOb2RlID0gdGhpcy5yZW5kZXJNaWNyb0NvbEdyb3VwKGNvbHMsIHN0YXRlLnNocmlua1dpZHRoKTtcbiAgICAgICAgbGV0IGNsYXNzTmFtZXMgPSBnZXRTY3JvbGxHcmlkQ2xhc3NOYW1lcyhwcm9wcy5saXF1aWQsIGNvbnRleHQpO1xuICAgICAgICBpZiAocHJvcHMuY29sbGFwc2libGVXaWR0aCkge1xuICAgICAgICAgICAgY2xhc3NOYW1lcy5wdXNoKCdmYy1zY3JvbGxncmlkLWNvbGxhcHNpYmxlJyk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gVE9ETzogbWFrZSBEUllcbiAgICAgICAgbGV0IGNvbmZpZ0NudCA9IHNlY3Rpb25Db25maWdzLmxlbmd0aDtcbiAgICAgICAgbGV0IGNvbmZpZ0kgPSAwO1xuICAgICAgICBsZXQgY3VycmVudENvbmZpZztcbiAgICAgICAgbGV0IGhlYWRTZWN0aW9uTm9kZXMgPSBbXTtcbiAgICAgICAgbGV0IGJvZHlTZWN0aW9uTm9kZXMgPSBbXTtcbiAgICAgICAgbGV0IGZvb3RTZWN0aW9uTm9kZXMgPSBbXTtcbiAgICAgICAgd2hpbGUgKGNvbmZpZ0kgPCBjb25maWdDbnQgJiYgKGN1cnJlbnRDb25maWcgPSBzZWN0aW9uQ29uZmlnc1tjb25maWdJXSkudHlwZSA9PT0gJ2hlYWRlcicpIHtcbiAgICAgICAgICAgIGhlYWRTZWN0aW9uTm9kZXMucHVzaCh0aGlzLnJlbmRlclNlY3Rpb24oY3VycmVudENvbmZpZywgbWljcm9Db2xHcm91cE5vZGUsIHRydWUpKTtcbiAgICAgICAgICAgIGNvbmZpZ0kgKz0gMTtcbiAgICAgICAgfVxuICAgICAgICB3aGlsZSAoY29uZmlnSSA8IGNvbmZpZ0NudCAmJiAoY3VycmVudENvbmZpZyA9IHNlY3Rpb25Db25maWdzW2NvbmZpZ0ldKS50eXBlID09PSAnYm9keScpIHtcbiAgICAgICAgICAgIGJvZHlTZWN0aW9uTm9kZXMucHVzaCh0aGlzLnJlbmRlclNlY3Rpb24oY3VycmVudENvbmZpZywgbWljcm9Db2xHcm91cE5vZGUsIGZhbHNlKSk7XG4gICAgICAgICAgICBjb25maWdJICs9IDE7XG4gICAgICAgIH1cbiAgICAgICAgd2hpbGUgKGNvbmZpZ0kgPCBjb25maWdDbnQgJiYgKGN1cnJlbnRDb25maWcgPSBzZWN0aW9uQ29uZmlnc1tjb25maWdJXSkudHlwZSA9PT0gJ2Zvb3RlcicpIHtcbiAgICAgICAgICAgIGZvb3RTZWN0aW9uTm9kZXMucHVzaCh0aGlzLnJlbmRlclNlY3Rpb24oY3VycmVudENvbmZpZywgbWljcm9Db2xHcm91cE5vZGUsIHRydWUpKTtcbiAgICAgICAgICAgIGNvbmZpZ0kgKz0gMTtcbiAgICAgICAgfVxuICAgICAgICAvLyBmaXJlZm94IGJ1Zzogd2hlbiBzZXR0aW5nIGhlaWdodCBvbiB0YWJsZSBhbmQgdGhlcmUgaXMgYSB0aGVhZCBvciB0Zm9vdCxcbiAgICAgICAgLy8gdGhlIG5lY2Vzc2FyeSBoZWlnaHQ6MTAwJSBvbiB0aGUgbGlxdWlkLWhlaWdodCBib2R5IHNlY3Rpb24gZm9yY2VzIHRoZSAqd2hvbGUqIHRhYmxlIHRvIGJlIHRhbGxlci4gKGJ1ZyAjNTUyNClcbiAgICAgICAgLy8gdXNlIGdldENhblZHcm93V2l0aGluQ2VsbCBhcyBhIHdheSB0byBkZXRlY3QgdGFibGUtc3R1cGlkIGZpcmVmb3guXG4gICAgICAgIC8vIGlmIHNvLCB1c2UgYSBzaW1wbGVyIGRvbSBzdHJ1Y3R1cmUsIGphbSBldmVyeXRoaW5nIGludG8gYSBsb25lIHRib2R5LlxuICAgICAgICBsZXQgaXNCdWdneSA9ICFnZXRDYW5WR3Jvd1dpdGhpbkNlbGwoKTtcbiAgICAgICAgY29uc3Qgcm9sZUF0dHJzID0geyByb2xlOiAncm93Z3JvdXAnIH07XG4gICAgICAgIHJldHVybiBjcmVhdGVFbGVtZW50KCd0YWJsZScsIHtcbiAgICAgICAgICAgIHJvbGU6ICdncmlkJyxcbiAgICAgICAgICAgIGNsYXNzTmFtZTogY2xhc3NOYW1lcy5qb2luKCcgJyksXG4gICAgICAgICAgICBzdHlsZTogeyBoZWlnaHQ6IHByb3BzLmhlaWdodCB9LFxuICAgICAgICB9LCBCb29sZWFuKCFpc0J1Z2d5ICYmIGhlYWRTZWN0aW9uTm9kZXMubGVuZ3RoKSAmJiBjcmVhdGVFbGVtZW50KCd0aGVhZCcsIHJvbGVBdHRycywgLi4uaGVhZFNlY3Rpb25Ob2RlcyksIEJvb2xlYW4oIWlzQnVnZ3kgJiYgYm9keVNlY3Rpb25Ob2Rlcy5sZW5ndGgpICYmIGNyZWF0ZUVsZW1lbnQoJ3Rib2R5Jywgcm9sZUF0dHJzLCAuLi5ib2R5U2VjdGlvbk5vZGVzKSwgQm9vbGVhbighaXNCdWdneSAmJiBmb290U2VjdGlvbk5vZGVzLmxlbmd0aCkgJiYgY3JlYXRlRWxlbWVudCgndGZvb3QnLCByb2xlQXR0cnMsIC4uLmZvb3RTZWN0aW9uTm9kZXMpLCBpc0J1Z2d5ICYmIGNyZWF0ZUVsZW1lbnQoJ3Rib2R5Jywgcm9sZUF0dHJzLCAuLi5oZWFkU2VjdGlvbk5vZGVzLCAuLi5ib2R5U2VjdGlvbk5vZGVzLCAuLi5mb290U2VjdGlvbk5vZGVzKSk7XG4gICAgfVxuICAgIHJlbmRlclNlY3Rpb24oc2VjdGlvbkNvbmZpZywgbWljcm9Db2xHcm91cE5vZGUsIGlzSGVhZGVyKSB7XG4gICAgICAgIGlmICgnb3V0ZXJDb250ZW50JyBpbiBzZWN0aW9uQ29uZmlnKSB7XG4gICAgICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoRnJhZ21lbnQsIHsga2V5OiBzZWN0aW9uQ29uZmlnLmtleSB9LCBzZWN0aW9uQ29uZmlnLm91dGVyQ29udGVudCkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChcInRyXCIsIHsga2V5OiBzZWN0aW9uQ29uZmlnLmtleSwgcm9sZTogXCJwcmVzZW50YXRpb25cIiwgY2xhc3NOYW1lOiBnZXRTZWN0aW9uQ2xhc3NOYW1lcyhzZWN0aW9uQ29uZmlnLCB0aGlzLnByb3BzLmxpcXVpZCkuam9pbignICcpIH0sIHRoaXMucmVuZGVyQ2h1bmtUZChzZWN0aW9uQ29uZmlnLCBtaWNyb0NvbEdyb3VwTm9kZSwgc2VjdGlvbkNvbmZpZy5jaHVuaywgaXNIZWFkZXIpKSk7XG4gICAgfVxuICAgIHJlbmRlckNodW5rVGQoc2VjdGlvbkNvbmZpZywgbWljcm9Db2xHcm91cE5vZGUsIGNodW5rQ29uZmlnLCBpc0hlYWRlcikge1xuICAgICAgICBpZiAoJ291dGVyQ29udGVudCcgaW4gY2h1bmtDb25maWcpIHtcbiAgICAgICAgICAgIHJldHVybiBjaHVua0NvbmZpZy5vdXRlckNvbnRlbnQ7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHsgcHJvcHMgfSA9IHRoaXM7XG4gICAgICAgIGxldCB7IGZvcmNlWVNjcm9sbGJhcnMsIHNjcm9sbGVyQ2xpZW50V2lkdGhzLCBzY3JvbGxlckNsaWVudEhlaWdodHMgfSA9IHRoaXMuc3RhdGU7XG4gICAgICAgIGxldCBuZWVkc1lTY3JvbGxpbmcgPSBnZXRBbGxvd1lTY3JvbGxpbmcocHJvcHMsIHNlY3Rpb25Db25maWcpOyAvLyBUT0RPOiBkbyBsYXppbHkuIGRvIGluIHNlY3Rpb24gY29uZmlnP1xuICAgICAgICBsZXQgaXNMaXF1aWQgPSBnZXRTZWN0aW9uSGFzTGlxdWlkSGVpZ2h0KHByb3BzLCBzZWN0aW9uQ29uZmlnKTtcbiAgICAgICAgLy8gZm9yIGAhcHJvcHMubGlxdWlkYCAtIGlzIFdIT0xFIHNjcm9sbGdyaWQgbmF0dXJhbCBoZWlnaHQ/XG4gICAgICAgIC8vIFRPRE86IGRvIHNhbWUgdGhpbmcgaW4gYWR2YW5jZWQgc2Nyb2xsZ3JpZD8gcHJvbGx5IG5vdCBiL2MgYWx3YXlzIGhhcyBob3Jpem9udGFsIHNjcm9sbGJhcnNcbiAgICAgICAgbGV0IG92ZXJmbG93WSA9ICFwcm9wcy5saXF1aWQgPyAndmlzaWJsZScgOlxuICAgICAgICAgICAgZm9yY2VZU2Nyb2xsYmFycyA/ICdzY3JvbGwnIDpcbiAgICAgICAgICAgICAgICAhbmVlZHNZU2Nyb2xsaW5nID8gJ2hpZGRlbicgOlxuICAgICAgICAgICAgICAgICAgICAnYXV0byc7XG4gICAgICAgIGxldCBzZWN0aW9uS2V5ID0gc2VjdGlvbkNvbmZpZy5rZXk7XG4gICAgICAgIGxldCBjb250ZW50ID0gcmVuZGVyQ2h1bmtDb250ZW50KHNlY3Rpb25Db25maWcsIGNodW5rQ29uZmlnLCB7XG4gICAgICAgICAgICB0YWJsZUNvbEdyb3VwTm9kZTogbWljcm9Db2xHcm91cE5vZGUsXG4gICAgICAgICAgICB0YWJsZU1pbldpZHRoOiAnJyxcbiAgICAgICAgICAgIGNsaWVudFdpZHRoOiAoIXByb3BzLmNvbGxhcHNpYmxlV2lkdGggJiYgc2Nyb2xsZXJDbGllbnRXaWR0aHNbc2VjdGlvbktleV0gIT09IHVuZGVmaW5lZCkgPyBzY3JvbGxlckNsaWVudFdpZHRoc1tzZWN0aW9uS2V5XSA6IG51bGwsXG4gICAgICAgICAgICBjbGllbnRIZWlnaHQ6IHNjcm9sbGVyQ2xpZW50SGVpZ2h0c1tzZWN0aW9uS2V5XSAhPT0gdW5kZWZpbmVkID8gc2Nyb2xsZXJDbGllbnRIZWlnaHRzW3NlY3Rpb25LZXldIDogbnVsbCxcbiAgICAgICAgICAgIGV4cGFuZFJvd3M6IHNlY3Rpb25Db25maWcuZXhwYW5kUm93cyxcbiAgICAgICAgICAgIHN5bmNSb3dIZWlnaHRzOiBmYWxzZSxcbiAgICAgICAgICAgIHJvd1N5bmNIZWlnaHRzOiBbXSxcbiAgICAgICAgICAgIHJlcG9ydFJvd0hlaWdodENoYW5nZTogKCkgPT4geyB9LFxuICAgICAgICB9LCBpc0hlYWRlcik7XG4gICAgICAgIHJldHVybiBjcmVhdGVFbGVtZW50KGlzSGVhZGVyID8gJ3RoJyA6ICd0ZCcsIHtcbiAgICAgICAgICAgIHJlZjogY2h1bmtDb25maWcuZWxSZWYsXG4gICAgICAgICAgICByb2xlOiAncHJlc2VudGF0aW9uJyxcbiAgICAgICAgfSwgY3JlYXRlRWxlbWVudChcImRpdlwiLCB7IGNsYXNzTmFtZTogYGZjLXNjcm9sbGVyLWhhcm5lc3Mke2lzTGlxdWlkID8gJyBmYy1zY3JvbGxlci1oYXJuZXNzLWxpcXVpZCcgOiAnJ31gIH0sXG4gICAgICAgICAgICBjcmVhdGVFbGVtZW50KFNjcm9sbGVyLCB7IHJlZjogdGhpcy5zY3JvbGxlclJlZnMuY3JlYXRlUmVmKHNlY3Rpb25LZXkpLCBlbFJlZjogdGhpcy5zY3JvbGxlckVsUmVmcy5jcmVhdGVSZWYoc2VjdGlvbktleSksIG92ZXJmbG93WTogb3ZlcmZsb3dZLCBvdmVyZmxvd1g6ICFwcm9wcy5saXF1aWQgPyAndmlzaWJsZScgOiAnaGlkZGVuJyAvKiBuYXR1cmFsIGhlaWdodD8gKi8sIG1heEhlaWdodDogc2VjdGlvbkNvbmZpZy5tYXhIZWlnaHQsIGxpcXVpZDogaXNMaXF1aWQsIGxpcXVpZElzQWJzb2x1dGUgLy8gYmVjYXVzZSBpdHMgd2l0aGluIGEgaGFybmVzc1xuICAgICAgICAgICAgICAgIDogdHJ1ZSB9LCBjb250ZW50KSkpO1xuICAgIH1cbiAgICBfaGFuZGxlU2Nyb2xsZXJFbChzY3JvbGxlckVsLCBrZXkpIHtcbiAgICAgICAgbGV0IHNlY3Rpb24gPSBnZXRTZWN0aW9uQnlLZXkodGhpcy5wcm9wcy5zZWN0aW9ucywga2V5KTtcbiAgICAgICAgaWYgKHNlY3Rpb24pIHtcbiAgICAgICAgICAgIHNldFJlZihzZWN0aW9uLmNodW5rLnNjcm9sbGVyRWxSZWYsIHNjcm9sbGVyRWwpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbXBvbmVudERpZE1vdW50KCkge1xuICAgICAgICB0aGlzLmhhbmRsZVNpemluZygpO1xuICAgICAgICB0aGlzLmNvbnRleHQuYWRkUmVzaXplSGFuZGxlcih0aGlzLmhhbmRsZVNpemluZyk7XG4gICAgfVxuICAgIGNvbXBvbmVudERpZFVwZGF0ZSgpIHtcbiAgICAgICAgLy8gVE9ETzogbmVlZCBiZXR0ZXIgc29sdXRpb24gd2hlbiBzdGF0ZSBjb250YWlucyBub24tc2l6aW5nIHRoaW5nc1xuICAgICAgICB0aGlzLmhhbmRsZVNpemluZygpO1xuICAgIH1cbiAgICBjb21wb25lbnRXaWxsVW5tb3VudCgpIHtcbiAgICAgICAgdGhpcy5jb250ZXh0LnJlbW92ZVJlc2l6ZUhhbmRsZXIodGhpcy5oYW5kbGVTaXppbmcpO1xuICAgIH1cbiAgICBjb21wdXRlU2hyaW5rV2lkdGgoKSB7XG4gICAgICAgIHJldHVybiBoYXNTaHJpbmtXaWR0aCh0aGlzLnByb3BzLmNvbHMpXG4gICAgICAgICAgICA/IGNvbXB1dGVTaHJpbmtXaWR0aCh0aGlzLnNjcm9sbGVyRWxSZWZzLmdldEFsbCgpKVxuICAgICAgICAgICAgOiAwO1xuICAgIH1cbiAgICBjb21wdXRlU2Nyb2xsZXJEaW1zKCkge1xuICAgICAgICBsZXQgc2Nyb2xsYmFyV2lkdGggPSBnZXRTY3JvbGxiYXJXaWR0aHMoKTtcbiAgICAgICAgbGV0IHsgc2Nyb2xsZXJSZWZzLCBzY3JvbGxlckVsUmVmcyB9ID0gdGhpcztcbiAgICAgICAgbGV0IGZvcmNlWVNjcm9sbGJhcnMgPSBmYWxzZTtcbiAgICAgICAgbGV0IHNjcm9sbGVyQ2xpZW50V2lkdGhzID0ge307XG4gICAgICAgIGxldCBzY3JvbGxlckNsaWVudEhlaWdodHMgPSB7fTtcbiAgICAgICAgZm9yIChsZXQgc2VjdGlvbktleSBpbiBzY3JvbGxlclJlZnMuY3VycmVudE1hcCkge1xuICAgICAgICAgICAgbGV0IHNjcm9sbGVyID0gc2Nyb2xsZXJSZWZzLmN1cnJlbnRNYXBbc2VjdGlvbktleV07XG4gICAgICAgICAgICBpZiAoc2Nyb2xsZXIgJiYgc2Nyb2xsZXIubmVlZHNZU2Nyb2xsaW5nKCkpIHtcbiAgICAgICAgICAgICAgICBmb3JjZVlTY3JvbGxiYXJzID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBmb3IgKGxldCBzZWN0aW9uIG9mIHRoaXMucHJvcHMuc2VjdGlvbnMpIHtcbiAgICAgICAgICAgIGxldCBzZWN0aW9uS2V5ID0gc2VjdGlvbi5rZXk7XG4gICAgICAgICAgICBsZXQgc2Nyb2xsZXJFbCA9IHNjcm9sbGVyRWxSZWZzLmN1cnJlbnRNYXBbc2VjdGlvbktleV07XG4gICAgICAgICAgICBpZiAoc2Nyb2xsZXJFbCkge1xuICAgICAgICAgICAgICAgIGxldCBoYXJuZXNzRWwgPSBzY3JvbGxlckVsLnBhcmVudE5vZGU7IC8vIFRPRE86IHdlaXJkIHdheSB0byBnZXQgdGhpcy4gbmVlZCBoYXJuZXNzIGIvYyBkb2Vzbid0IGluY2x1ZGUgdGFibGUgYm9yZGVyc1xuICAgICAgICAgICAgICAgIHNjcm9sbGVyQ2xpZW50V2lkdGhzW3NlY3Rpb25LZXldID0gTWF0aC5mbG9vcihoYXJuZXNzRWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkud2lkdGggLSAoZm9yY2VZU2Nyb2xsYmFyc1xuICAgICAgICAgICAgICAgICAgICA/IHNjcm9sbGJhcldpZHRoLnkgLy8gdXNlIGdsb2JhbCBiZWNhdXNlIHNjcm9sbGVyIG1pZ2h0IG5vdCBoYXZlIHNjcm9sbGJhcnMgeWV0IGJ1dCB3aWxsIG5lZWQgdGhlbSBpbiBmdXR1cmVcbiAgICAgICAgICAgICAgICAgICAgOiAwKSk7XG4gICAgICAgICAgICAgICAgc2Nyb2xsZXJDbGllbnRIZWlnaHRzW3NlY3Rpb25LZXldID0gTWF0aC5mbG9vcihoYXJuZXNzRWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuaGVpZ2h0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4geyBmb3JjZVlTY3JvbGxiYXJzLCBzY3JvbGxlckNsaWVudFdpZHRocywgc2Nyb2xsZXJDbGllbnRIZWlnaHRzIH07XG4gICAgfVxufVxuU2ltcGxlU2Nyb2xsR3JpZC5hZGRTdGF0ZUVxdWFsaXR5KHtcbiAgICBzY3JvbGxlckNsaWVudFdpZHRoczogaXNQcm9wc0VxdWFsLFxuICAgIHNjcm9sbGVyQ2xpZW50SGVpZ2h0czogaXNQcm9wc0VxdWFsLFxufSk7XG5mdW5jdGlvbiBnZXRTZWN0aW9uQnlLZXkoc2VjdGlvbnMsIGtleSkge1xuICAgIGZvciAobGV0IHNlY3Rpb24gb2Ygc2VjdGlvbnMpIHtcbiAgICAgICAgaWYgKHNlY3Rpb24ua2V5ID09PSBrZXkpIHtcbiAgICAgICAgICAgIHJldHVybiBzZWN0aW9uO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufVxuXG5jbGFzcyBFdmVudENvbnRhaW5lciBleHRlbmRzIEJhc2VDb21wb25lbnQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICAvLyBtZW1vXG4gICAgICAgIHRoaXMuYnVpbGRQdWJsaWNFdmVudCA9IG1lbW9pemUoKGNvbnRleHQsIGV2ZW50RGVmLCBldmVudEluc3RhbmNlKSA9PiBuZXcgRXZlbnRJbXBsKGNvbnRleHQsIGV2ZW50RGVmLCBldmVudEluc3RhbmNlKSk7XG4gICAgICAgIHRoaXMuaGFuZGxlRWwgPSAoZWwpID0+IHtcbiAgICAgICAgICAgIHRoaXMuZWwgPSBlbDtcbiAgICAgICAgICAgIHNldFJlZih0aGlzLnByb3BzLmVsUmVmLCBlbCk7XG4gICAgICAgICAgICBpZiAoZWwpIHtcbiAgICAgICAgICAgICAgICBzZXRFbFNlZyhlbCwgdGhpcy5wcm9wcy5zZWcpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgIH1cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGNvbnN0IHsgcHJvcHMsIGNvbnRleHQgfSA9IHRoaXM7XG4gICAgICAgIGNvbnN0IHsgb3B0aW9ucyB9ID0gY29udGV4dDtcbiAgICAgICAgY29uc3QgeyBzZWcgfSA9IHByb3BzO1xuICAgICAgICBjb25zdCB7IGV2ZW50UmFuZ2UgfSA9IHNlZztcbiAgICAgICAgY29uc3QgeyB1aSB9ID0gZXZlbnRSYW5nZTtcbiAgICAgICAgY29uc3QgcmVuZGVyUHJvcHMgPSB7XG4gICAgICAgICAgICBldmVudDogdGhpcy5idWlsZFB1YmxpY0V2ZW50KGNvbnRleHQsIGV2ZW50UmFuZ2UuZGVmLCBldmVudFJhbmdlLmluc3RhbmNlKSxcbiAgICAgICAgICAgIHZpZXc6IGNvbnRleHQudmlld0FwaSxcbiAgICAgICAgICAgIHRpbWVUZXh0OiBwcm9wcy50aW1lVGV4dCxcbiAgICAgICAgICAgIHRleHRDb2xvcjogdWkudGV4dENvbG9yLFxuICAgICAgICAgICAgYmFja2dyb3VuZENvbG9yOiB1aS5iYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgICAgICBib3JkZXJDb2xvcjogdWkuYm9yZGVyQ29sb3IsXG4gICAgICAgICAgICBpc0RyYWdnYWJsZTogIXByb3BzLmRpc2FibGVEcmFnZ2luZyAmJiBjb21wdXRlU2VnRHJhZ2dhYmxlKHNlZywgY29udGV4dCksXG4gICAgICAgICAgICBpc1N0YXJ0UmVzaXphYmxlOiAhcHJvcHMuZGlzYWJsZVJlc2l6aW5nICYmIGNvbXB1dGVTZWdTdGFydFJlc2l6YWJsZShzZWcsIGNvbnRleHQpLFxuICAgICAgICAgICAgaXNFbmRSZXNpemFibGU6ICFwcm9wcy5kaXNhYmxlUmVzaXppbmcgJiYgY29tcHV0ZVNlZ0VuZFJlc2l6YWJsZShzZWcpLFxuICAgICAgICAgICAgaXNNaXJyb3I6IEJvb2xlYW4ocHJvcHMuaXNEcmFnZ2luZyB8fCBwcm9wcy5pc1Jlc2l6aW5nIHx8IHByb3BzLmlzRGF0ZVNlbGVjdGluZyksXG4gICAgICAgICAgICBpc1N0YXJ0OiBCb29sZWFuKHNlZy5pc1N0YXJ0KSxcbiAgICAgICAgICAgIGlzRW5kOiBCb29sZWFuKHNlZy5pc0VuZCksXG4gICAgICAgICAgICBpc1Bhc3Q6IEJvb2xlYW4ocHJvcHMuaXNQYXN0KSxcbiAgICAgICAgICAgIGlzRnV0dXJlOiBCb29sZWFuKHByb3BzLmlzRnV0dXJlKSxcbiAgICAgICAgICAgIGlzVG9kYXk6IEJvb2xlYW4ocHJvcHMuaXNUb2RheSksXG4gICAgICAgICAgICBpc1NlbGVjdGVkOiBCb29sZWFuKHByb3BzLmlzU2VsZWN0ZWQpLFxuICAgICAgICAgICAgaXNEcmFnZ2luZzogQm9vbGVhbihwcm9wcy5pc0RyYWdnaW5nKSxcbiAgICAgICAgICAgIGlzUmVzaXppbmc6IEJvb2xlYW4ocHJvcHMuaXNSZXNpemluZyksXG4gICAgICAgIH07XG4gICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChDb250ZW50Q29udGFpbmVyLCB7IGVsUmVmOiB0aGlzLmhhbmRsZUVsLCBlbFRhZzogcHJvcHMuZWxUYWcsIGVsQXR0cnM6IHByb3BzLmVsQXR0cnMsIGVsQ2xhc3NlczogW1xuICAgICAgICAgICAgICAgIC4uLmdldEV2ZW50Q2xhc3NOYW1lcyhyZW5kZXJQcm9wcyksXG4gICAgICAgICAgICAgICAgLi4uc2VnLmV2ZW50UmFuZ2UudWkuY2xhc3NOYW1lcyxcbiAgICAgICAgICAgICAgICAuLi4ocHJvcHMuZWxDbGFzc2VzIHx8IFtdKSxcbiAgICAgICAgICAgIF0sIGVsU3R5bGU6IHByb3BzLmVsU3R5bGUsIHJlbmRlclByb3BzOiByZW5kZXJQcm9wcywgZ2VuZXJhdG9yTmFtZTogXCJldmVudENvbnRlbnRcIiwgY3VzdG9tR2VuZXJhdG9yOiBvcHRpb25zLmV2ZW50Q29udGVudCwgZGVmYXVsdEdlbmVyYXRvcjogcHJvcHMuZGVmYXVsdEdlbmVyYXRvciwgY2xhc3NOYW1lR2VuZXJhdG9yOiBvcHRpb25zLmV2ZW50Q2xhc3NOYW1lcywgZGlkTW91bnQ6IG9wdGlvbnMuZXZlbnREaWRNb3VudCwgd2lsbFVubW91bnQ6IG9wdGlvbnMuZXZlbnRXaWxsVW5tb3VudCB9LCBwcm9wcy5jaGlsZHJlbikpO1xuICAgIH1cbiAgICBjb21wb25lbnREaWRVcGRhdGUocHJldlByb3BzKSB7XG4gICAgICAgIGlmICh0aGlzLmVsICYmIHRoaXMucHJvcHMuc2VnICE9PSBwcmV2UHJvcHMuc2VnKSB7XG4gICAgICAgICAgICBzZXRFbFNlZyh0aGlzLmVsLCB0aGlzLnByb3BzLnNlZyk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8vIHNob3VsZCBub3QgYmUgYSBwdXJlY29tcG9uZW50XG5jbGFzcyBTdGFuZGFyZEV2ZW50IGV4dGVuZHMgQmFzZUNvbXBvbmVudCB7XG4gICAgcmVuZGVyKCkge1xuICAgICAgICBsZXQgeyBwcm9wcywgY29udGV4dCB9ID0gdGhpcztcbiAgICAgICAgbGV0IHsgb3B0aW9ucyB9ID0gY29udGV4dDtcbiAgICAgICAgbGV0IHsgc2VnIH0gPSBwcm9wcztcbiAgICAgICAgbGV0IHsgdWkgfSA9IHNlZy5ldmVudFJhbmdlO1xuICAgICAgICBsZXQgdGltZUZvcm1hdCA9IG9wdGlvbnMuZXZlbnRUaW1lRm9ybWF0IHx8IHByb3BzLmRlZmF1bHRUaW1lRm9ybWF0O1xuICAgICAgICBsZXQgdGltZVRleHQgPSBidWlsZFNlZ1RpbWVUZXh0KHNlZywgdGltZUZvcm1hdCwgY29udGV4dCwgcHJvcHMuZGVmYXVsdERpc3BsYXlFdmVudFRpbWUsIHByb3BzLmRlZmF1bHREaXNwbGF5RXZlbnRFbmQpO1xuICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoRXZlbnRDb250YWluZXIsIE9iamVjdC5hc3NpZ24oe30sIHByb3BzIC8qIGluY2x1ZGVzIGVsUmVmICovLCB7IGVsVGFnOiBcImFcIiwgZWxTdHlsZToge1xuICAgICAgICAgICAgICAgIGJvcmRlckNvbG9yOiB1aS5ib3JkZXJDb2xvcixcbiAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IHVpLmJhY2tncm91bmRDb2xvcixcbiAgICAgICAgICAgIH0sIGVsQXR0cnM6IGdldFNlZ0FuY2hvckF0dHJzKHNlZywgY29udGV4dCksIGRlZmF1bHRHZW5lcmF0b3I6IHJlbmRlcklubmVyQ29udGVudCQxLCB0aW1lVGV4dDogdGltZVRleHQgfSksIChJbm5lckNvbnRlbnQsIGV2ZW50Q29udGVudEFyZykgPT4gKGNyZWF0ZUVsZW1lbnQoRnJhZ21lbnQsIG51bGwsXG4gICAgICAgICAgICBjcmVhdGVFbGVtZW50KElubmVyQ29udGVudCwgeyBlbFRhZzogXCJkaXZcIiwgZWxDbGFzc2VzOiBbJ2ZjLWV2ZW50LW1haW4nXSwgZWxTdHlsZTogeyBjb2xvcjogZXZlbnRDb250ZW50QXJnLnRleHRDb2xvciB9IH0pLFxuICAgICAgICAgICAgQm9vbGVhbihldmVudENvbnRlbnRBcmcuaXNTdGFydFJlc2l6YWJsZSkgJiYgKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IFwiZmMtZXZlbnQtcmVzaXplciBmYy1ldmVudC1yZXNpemVyLXN0YXJ0XCIgfSkpLFxuICAgICAgICAgICAgQm9vbGVhbihldmVudENvbnRlbnRBcmcuaXNFbmRSZXNpemFibGUpICYmIChjcmVhdGVFbGVtZW50KFwiZGl2XCIsIHsgY2xhc3NOYW1lOiBcImZjLWV2ZW50LXJlc2l6ZXIgZmMtZXZlbnQtcmVzaXplci1lbmRcIiB9KSkpKSkpO1xuICAgIH1cbn1cblN0YW5kYXJkRXZlbnQuYWRkUHJvcHNFcXVhbGl0eSh7XG4gICAgc2VnOiBpc1Byb3BzRXF1YWwsXG59KTtcbmZ1bmN0aW9uIHJlbmRlcklubmVyQ29udGVudCQxKGlubmVyUHJvcHMpIHtcbiAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IFwiZmMtZXZlbnQtbWFpbi1mcmFtZVwiIH0sXG4gICAgICAgIGlubmVyUHJvcHMudGltZVRleHQgJiYgKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IFwiZmMtZXZlbnQtdGltZVwiIH0sIGlubmVyUHJvcHMudGltZVRleHQpKSxcbiAgICAgICAgY3JlYXRlRWxlbWVudChcImRpdlwiLCB7IGNsYXNzTmFtZTogXCJmYy1ldmVudC10aXRsZS1jb250YWluZXJcIiB9LFxuICAgICAgICAgICAgY3JlYXRlRWxlbWVudChcImRpdlwiLCB7IGNsYXNzTmFtZTogXCJmYy1ldmVudC10aXRsZSBmYy1zdGlja3lcIiB9LCBpbm5lclByb3BzLmV2ZW50LnRpdGxlIHx8IGNyZWF0ZUVsZW1lbnQoRnJhZ21lbnQsIG51bGwsIFwiXFx1MDBBMFwiKSkpKSk7XG59XG5cbmNvbnN0IE5vd0luZGljYXRvckNvbnRhaW5lciA9IChwcm9wcykgPT4gKGNyZWF0ZUVsZW1lbnQoVmlld0NvbnRleHRUeXBlLkNvbnN1bWVyLCBudWxsLCAoY29udGV4dCkgPT4ge1xuICAgIGxldCB7IG9wdGlvbnMgfSA9IGNvbnRleHQ7XG4gICAgbGV0IHJlbmRlclByb3BzID0ge1xuICAgICAgICBpc0F4aXM6IHByb3BzLmlzQXhpcyxcbiAgICAgICAgZGF0ZTogY29udGV4dC5kYXRlRW52LnRvRGF0ZShwcm9wcy5kYXRlKSxcbiAgICAgICAgdmlldzogY29udGV4dC52aWV3QXBpLFxuICAgIH07XG4gICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KENvbnRlbnRDb250YWluZXIsIHsgZWxSZWY6IHByb3BzLmVsUmVmLCBlbFRhZzogcHJvcHMuZWxUYWcgfHwgJ2RpdicsIGVsQXR0cnM6IHByb3BzLmVsQXR0cnMsIGVsQ2xhc3NlczogcHJvcHMuZWxDbGFzc2VzLCBlbFN0eWxlOiBwcm9wcy5lbFN0eWxlLCByZW5kZXJQcm9wczogcmVuZGVyUHJvcHMsIGdlbmVyYXRvck5hbWU6IFwibm93SW5kaWNhdG9yQ29udGVudFwiLCBjdXN0b21HZW5lcmF0b3I6IG9wdGlvbnMubm93SW5kaWNhdG9yQ29udGVudCwgY2xhc3NOYW1lR2VuZXJhdG9yOiBvcHRpb25zLm5vd0luZGljYXRvckNsYXNzTmFtZXMsIGRpZE1vdW50OiBvcHRpb25zLm5vd0luZGljYXRvckRpZE1vdW50LCB3aWxsVW5tb3VudDogb3B0aW9ucy5ub3dJbmRpY2F0b3JXaWxsVW5tb3VudCB9LCBwcm9wcy5jaGlsZHJlbikpO1xufSkpO1xuXG5jb25zdCBEQVlfTlVNX0ZPUk1BVCA9IGNyZWF0ZUZvcm1hdHRlcih7IGRheTogJ251bWVyaWMnIH0pO1xuY2xhc3MgRGF5Q2VsbENvbnRhaW5lciBleHRlbmRzIEJhc2VDb21wb25lbnQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICB0aGlzLnJlZmluZVJlbmRlclByb3BzID0gbWVtb2l6ZU9iakFyZyhyZWZpbmVSZW5kZXJQcm9wcyk7XG4gICAgfVxuICAgIHJlbmRlcigpIHtcbiAgICAgICAgbGV0IHsgcHJvcHMsIGNvbnRleHQgfSA9IHRoaXM7XG4gICAgICAgIGxldCB7IG9wdGlvbnMgfSA9IGNvbnRleHQ7XG4gICAgICAgIGxldCByZW5kZXJQcm9wcyA9IHRoaXMucmVmaW5lUmVuZGVyUHJvcHMoe1xuICAgICAgICAgICAgZGF0ZTogcHJvcHMuZGF0ZSxcbiAgICAgICAgICAgIGRhdGVQcm9maWxlOiBwcm9wcy5kYXRlUHJvZmlsZSxcbiAgICAgICAgICAgIHRvZGF5UmFuZ2U6IHByb3BzLnRvZGF5UmFuZ2UsXG4gICAgICAgICAgICBpc01vbnRoU3RhcnQ6IHByb3BzLmlzTW9udGhTdGFydCB8fCBmYWxzZSxcbiAgICAgICAgICAgIHNob3dEYXlOdW1iZXI6IHByb3BzLnNob3dEYXlOdW1iZXIsXG4gICAgICAgICAgICBleHRyYVJlbmRlclByb3BzOiBwcm9wcy5leHRyYVJlbmRlclByb3BzLFxuICAgICAgICAgICAgdmlld0FwaTogY29udGV4dC52aWV3QXBpLFxuICAgICAgICAgICAgZGF0ZUVudjogY29udGV4dC5kYXRlRW52LFxuICAgICAgICAgICAgbW9udGhTdGFydEZvcm1hdDogb3B0aW9ucy5tb250aFN0YXJ0Rm9ybWF0LFxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KENvbnRlbnRDb250YWluZXIsIHsgZWxSZWY6IHByb3BzLmVsUmVmLCBlbFRhZzogcHJvcHMuZWxUYWcsIGVsQXR0cnM6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJvcHMuZWxBdHRycyksIChyZW5kZXJQcm9wcy5pc0Rpc2FibGVkID8ge30gOiB7ICdkYXRhLWRhdGUnOiBmb3JtYXREYXlTdHJpbmcocHJvcHMuZGF0ZSkgfSkpLCBlbENsYXNzZXM6IFtcbiAgICAgICAgICAgICAgICAuLi5nZXREYXlDbGFzc05hbWVzKHJlbmRlclByb3BzLCBjb250ZXh0LnRoZW1lKSxcbiAgICAgICAgICAgICAgICAuLi4ocHJvcHMuZWxDbGFzc2VzIHx8IFtdKSxcbiAgICAgICAgICAgIF0sIGVsU3R5bGU6IHByb3BzLmVsU3R5bGUsIHJlbmRlclByb3BzOiByZW5kZXJQcm9wcywgZ2VuZXJhdG9yTmFtZTogXCJkYXlDZWxsQ29udGVudFwiLCBjdXN0b21HZW5lcmF0b3I6IG9wdGlvbnMuZGF5Q2VsbENvbnRlbnQsIGRlZmF1bHRHZW5lcmF0b3I6IHByb3BzLmRlZmF1bHRHZW5lcmF0b3IsIGNsYXNzTmFtZUdlbmVyYXRvcjogXG4gICAgICAgICAgICAvLyBkb24ndCB1c2UgY3VzdG9tIGNsYXNzTmFtZXMgaWYgZGlzYWJsZWRcbiAgICAgICAgICAgIHJlbmRlclByb3BzLmlzRGlzYWJsZWQgPyB1bmRlZmluZWQgOiBvcHRpb25zLmRheUNlbGxDbGFzc05hbWVzLCBkaWRNb3VudDogb3B0aW9ucy5kYXlDZWxsRGlkTW91bnQsIHdpbGxVbm1vdW50OiBvcHRpb25zLmRheUNlbGxXaWxsVW5tb3VudCB9LCBwcm9wcy5jaGlsZHJlbikpO1xuICAgIH1cbn1cbmZ1bmN0aW9uIGhhc0N1c3RvbURheUNlbGxDb250ZW50KG9wdGlvbnMpIHtcbiAgICByZXR1cm4gQm9vbGVhbihvcHRpb25zLmRheUNlbGxDb250ZW50IHx8IGhhc0N1c3RvbVJlbmRlcmluZ0hhbmRsZXIoJ2RheUNlbGxDb250ZW50Jywgb3B0aW9ucykpO1xufVxuZnVuY3Rpb24gcmVmaW5lUmVuZGVyUHJvcHMocmF3KSB7XG4gICAgbGV0IHsgZGF0ZSwgZGF0ZUVudiwgZGF0ZVByb2ZpbGUsIGlzTW9udGhTdGFydCB9ID0gcmF3O1xuICAgIGxldCBkYXlNZXRhID0gZ2V0RGF0ZU1ldGEoZGF0ZSwgcmF3LnRvZGF5UmFuZ2UsIG51bGwsIGRhdGVQcm9maWxlKTtcbiAgICBsZXQgZGF5TnVtYmVyVGV4dCA9IHJhdy5zaG93RGF5TnVtYmVyID8gKGRhdGVFbnYuZm9ybWF0KGRhdGUsIGlzTW9udGhTdGFydCA/IHJhdy5tb250aFN0YXJ0Rm9ybWF0IDogREFZX05VTV9GT1JNQVQpKSA6ICcnO1xuICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7IGRhdGU6IGRhdGVFbnYudG9EYXRlKGRhdGUpLCB2aWV3OiByYXcudmlld0FwaSB9LCBkYXlNZXRhKSwgeyBpc01vbnRoU3RhcnQsXG4gICAgICAgIGRheU51bWJlclRleHQgfSksIHJhdy5leHRyYVJlbmRlclByb3BzKTtcbn1cblxuY2xhc3MgQmdFdmVudCBleHRlbmRzIEJhc2VDb21wb25lbnQge1xuICAgIHJlbmRlcigpIHtcbiAgICAgICAgbGV0IHsgcHJvcHMgfSA9IHRoaXM7XG4gICAgICAgIGxldCB7IHNlZyB9ID0gcHJvcHM7XG4gICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChFdmVudENvbnRhaW5lciwgeyBlbFRhZzogXCJkaXZcIiwgZWxDbGFzc2VzOiBbJ2ZjLWJnLWV2ZW50J10sIGVsU3R5bGU6IHsgYmFja2dyb3VuZENvbG9yOiBzZWcuZXZlbnRSYW5nZS51aS5iYWNrZ3JvdW5kQ29sb3IgfSwgZGVmYXVsdEdlbmVyYXRvcjogcmVuZGVySW5uZXJDb250ZW50LCBzZWc6IHNlZywgdGltZVRleHQ6IFwiXCIsIGlzRHJhZ2dpbmc6IGZhbHNlLCBpc1Jlc2l6aW5nOiBmYWxzZSwgaXNEYXRlU2VsZWN0aW5nOiBmYWxzZSwgaXNTZWxlY3RlZDogZmFsc2UsIGlzUGFzdDogcHJvcHMuaXNQYXN0LCBpc0Z1dHVyZTogcHJvcHMuaXNGdXR1cmUsIGlzVG9kYXk6IHByb3BzLmlzVG9kYXksIGRpc2FibGVEcmFnZ2luZzogdHJ1ZSwgZGlzYWJsZVJlc2l6aW5nOiB0cnVlIH0pKTtcbiAgICB9XG59XG5mdW5jdGlvbiByZW5kZXJJbm5lckNvbnRlbnQocHJvcHMpIHtcbiAgICBsZXQgeyB0aXRsZSB9ID0gcHJvcHMuZXZlbnQ7XG4gICAgcmV0dXJuIHRpdGxlICYmIChjcmVhdGVFbGVtZW50KFwiZGl2XCIsIHsgY2xhc3NOYW1lOiBcImZjLWV2ZW50LXRpdGxlXCIgfSwgcHJvcHMuZXZlbnQudGl0bGUpKTtcbn1cbmZ1bmN0aW9uIHJlbmRlckZpbGwoZmlsbFR5cGUpIHtcbiAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IGBmYy0ke2ZpbGxUeXBlfWAgfSkpO1xufVxuXG5jb25zdCBXZWVrTnVtYmVyQ29udGFpbmVyID0gKHByb3BzKSA9PiAoY3JlYXRlRWxlbWVudChWaWV3Q29udGV4dFR5cGUuQ29uc3VtZXIsIG51bGwsIChjb250ZXh0KSA9PiB7XG4gICAgbGV0IHsgZGF0ZUVudiwgb3B0aW9ucyB9ID0gY29udGV4dDtcbiAgICBsZXQgeyBkYXRlIH0gPSBwcm9wcztcbiAgICBsZXQgZm9ybWF0ID0gb3B0aW9ucy53ZWVrTnVtYmVyRm9ybWF0IHx8IHByb3BzLmRlZmF1bHRGb3JtYXQ7XG4gICAgbGV0IG51bSA9IGRhdGVFbnYuY29tcHV0ZVdlZWtOdW1iZXIoZGF0ZSk7IC8vIFRPRE86IHNvbWVob3cgdXNlIGZvciBmb3JtYXR0aW5nIGFzIHdlbGw/XG4gICAgbGV0IHRleHQgPSBkYXRlRW52LmZvcm1hdChkYXRlLCBmb3JtYXQpO1xuICAgIGxldCByZW5kZXJQcm9wcyA9IHsgbnVtLCB0ZXh0LCBkYXRlIH07XG4gICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KENvbnRlbnRDb250YWluZXIgLy8gd2h5IGlzbid0IFdlZWtOdW1iZXJDb250ZW50QXJnIGJlaW5nIGF1dG8tZGV0ZWN0ZWQ/XG4gICAgLCB7IGVsUmVmOiBwcm9wcy5lbFJlZiwgZWxUYWc6IHByb3BzLmVsVGFnLCBlbEF0dHJzOiBwcm9wcy5lbEF0dHJzLCBlbENsYXNzZXM6IHByb3BzLmVsQ2xhc3NlcywgZWxTdHlsZTogcHJvcHMuZWxTdHlsZSwgcmVuZGVyUHJvcHM6IHJlbmRlclByb3BzLCBnZW5lcmF0b3JOYW1lOiBcIndlZWtOdW1iZXJDb250ZW50XCIsIGN1c3RvbUdlbmVyYXRvcjogb3B0aW9ucy53ZWVrTnVtYmVyQ29udGVudCwgZGVmYXVsdEdlbmVyYXRvcjogcmVuZGVySW5uZXIsIGNsYXNzTmFtZUdlbmVyYXRvcjogb3B0aW9ucy53ZWVrTnVtYmVyQ2xhc3NOYW1lcywgZGlkTW91bnQ6IG9wdGlvbnMud2Vla051bWJlckRpZE1vdW50LCB3aWxsVW5tb3VudDogb3B0aW9ucy53ZWVrTnVtYmVyV2lsbFVubW91bnQgfSwgcHJvcHMuY2hpbGRyZW4pKTtcbn0pKTtcbmZ1bmN0aW9uIHJlbmRlcklubmVyKGlubmVyUHJvcHMpIHtcbiAgICByZXR1cm4gaW5uZXJQcm9wcy50ZXh0O1xufVxuXG5jb25zdCBQQURESU5HX0ZST01fVklFV1BPUlQgPSAxMDtcbmNsYXNzIFBvcG92ZXIgZXh0ZW5kcyBCYXNlQ29tcG9uZW50IHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoLi4uYXJndW1lbnRzKTtcbiAgICAgICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgICAgICAgIHRpdGxlSWQ6IGdldFVuaXF1ZURvbUlkKCksXG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlUm9vdEVsID0gKGVsKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnJvb3RFbCA9IGVsO1xuICAgICAgICAgICAgaWYgKHRoaXMucHJvcHMuZWxSZWYpIHtcbiAgICAgICAgICAgICAgICBzZXRSZWYodGhpcy5wcm9wcy5lbFJlZiwgZWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICAvLyBUcmlnZ2VyZWQgd2hlbiB0aGUgdXNlciBjbGlja3MgKmFueXdoZXJlKiBpbiB0aGUgZG9jdW1lbnQsIGZvciB0aGUgYXV0b0hpZGUgZmVhdHVyZVxuICAgICAgICB0aGlzLmhhbmRsZURvY3VtZW50TW91c2VEb3duID0gKGV2KSA9PiB7XG4gICAgICAgICAgICAvLyBvbmx5IGhpZGUgdGhlIHBvcG92ZXIgaWYgdGhlIGNsaWNrIGhhcHBlbmVkIG91dHNpZGUgdGhlIHBvcG92ZXJcbiAgICAgICAgICAgIGNvbnN0IHRhcmdldCA9IGdldEV2ZW50VGFyZ2V0VmlhUm9vdChldik7XG4gICAgICAgICAgICBpZiAoIXRoaXMucm9vdEVsLmNvbnRhaW5zKHRhcmdldCkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZUNsb3NlQ2xpY2soKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVEb2N1bWVudEtleURvd24gPSAoZXYpID0+IHtcbiAgICAgICAgICAgIGlmIChldi5rZXkgPT09ICdFc2NhcGUnKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5oYW5kbGVDbG9zZUNsaWNrKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlQ2xvc2VDbGljayA9ICgpID0+IHtcbiAgICAgICAgICAgIGxldCB7IG9uQ2xvc2UgfSA9IHRoaXMucHJvcHM7XG4gICAgICAgICAgICBpZiAob25DbG9zZSkge1xuICAgICAgICAgICAgICAgIG9uQ2xvc2UoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG4gICAgcmVuZGVyKCkge1xuICAgICAgICBsZXQgeyB0aGVtZSwgb3B0aW9ucyB9ID0gdGhpcy5jb250ZXh0O1xuICAgICAgICBsZXQgeyBwcm9wcywgc3RhdGUgfSA9IHRoaXM7XG4gICAgICAgIGxldCBjbGFzc05hbWVzID0gW1xuICAgICAgICAgICAgJ2ZjLXBvcG92ZXInLFxuICAgICAgICAgICAgdGhlbWUuZ2V0Q2xhc3MoJ3BvcG92ZXInKSxcbiAgICAgICAgXS5jb25jYXQocHJvcHMuZXh0cmFDbGFzc05hbWVzIHx8IFtdKTtcbiAgICAgICAgcmV0dXJuIGNyZWF0ZVBvcnRhbChjcmVhdGVFbGVtZW50KFwiZGl2XCIsIE9iamVjdC5hc3NpZ24oe30sIHByb3BzLmV4dHJhQXR0cnMsIHsgaWQ6IHByb3BzLmlkLCBjbGFzc05hbWU6IGNsYXNzTmFtZXMuam9pbignICcpLCBcImFyaWEtbGFiZWxsZWRieVwiOiBzdGF0ZS50aXRsZUlkLCByZWY6IHRoaXMuaGFuZGxlUm9vdEVsIH0pLFxuICAgICAgICAgICAgY3JlYXRlRWxlbWVudChcImRpdlwiLCB7IGNsYXNzTmFtZTogJ2ZjLXBvcG92ZXItaGVhZGVyICcgKyB0aGVtZS5nZXRDbGFzcygncG9wb3ZlckhlYWRlcicpIH0sXG4gICAgICAgICAgICAgICAgY3JlYXRlRWxlbWVudChcInNwYW5cIiwgeyBjbGFzc05hbWU6IFwiZmMtcG9wb3Zlci10aXRsZVwiLCBpZDogc3RhdGUudGl0bGVJZCB9LCBwcm9wcy50aXRsZSksXG4gICAgICAgICAgICAgICAgY3JlYXRlRWxlbWVudChcInNwYW5cIiwgeyBjbGFzc05hbWU6ICdmYy1wb3BvdmVyLWNsb3NlICcgKyB0aGVtZS5nZXRJY29uQ2xhc3MoJ2Nsb3NlJyksIHRpdGxlOiBvcHRpb25zLmNsb3NlSGludCwgb25DbGljazogdGhpcy5oYW5kbGVDbG9zZUNsaWNrIH0pKSxcbiAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6ICdmYy1wb3BvdmVyLWJvZHkgJyArIHRoZW1lLmdldENsYXNzKCdwb3BvdmVyQ29udGVudCcpIH0sIHByb3BzLmNoaWxkcmVuKSksIHByb3BzLnBhcmVudEVsKTtcbiAgICB9XG4gICAgY29tcG9uZW50RGlkTW91bnQoKSB7XG4gICAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlZG93bicsIHRoaXMuaGFuZGxlRG9jdW1lbnRNb3VzZURvd24pO1xuICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdrZXlkb3duJywgdGhpcy5oYW5kbGVEb2N1bWVudEtleURvd24pO1xuICAgICAgICB0aGlzLnVwZGF0ZVNpemUoKTtcbiAgICB9XG4gICAgY29tcG9uZW50V2lsbFVubW91bnQoKSB7XG4gICAgICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21vdXNlZG93bicsIHRoaXMuaGFuZGxlRG9jdW1lbnRNb3VzZURvd24pO1xuICAgICAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdrZXlkb3duJywgdGhpcy5oYW5kbGVEb2N1bWVudEtleURvd24pO1xuICAgIH1cbiAgICB1cGRhdGVTaXplKCkge1xuICAgICAgICBsZXQgeyBpc1J0bCB9ID0gdGhpcy5jb250ZXh0O1xuICAgICAgICBsZXQgeyBhbGlnbm1lbnRFbCwgYWxpZ25HcmlkVG9wIH0gPSB0aGlzLnByb3BzO1xuICAgICAgICBsZXQgeyByb290RWwgfSA9IHRoaXM7XG4gICAgICAgIGxldCBhbGlnbm1lbnRSZWN0ID0gY29tcHV0ZUNsaXBwZWRDbGllbnRSZWN0KGFsaWdubWVudEVsKTtcbiAgICAgICAgaWYgKGFsaWdubWVudFJlY3QpIHtcbiAgICAgICAgICAgIGxldCBwb3BvdmVyRGltcyA9IHJvb3RFbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgICAgICAgIC8vIHBvc2l0aW9uIHJlbGF0aXZlIHRvIHZpZXdwb3J0XG4gICAgICAgICAgICBsZXQgcG9wb3ZlclRvcCA9IGFsaWduR3JpZFRvcFxuICAgICAgICAgICAgICAgID8gZWxlbWVudENsb3Nlc3QoYWxpZ25tZW50RWwsICcuZmMtc2Nyb2xsZ3JpZCcpLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcFxuICAgICAgICAgICAgICAgIDogYWxpZ25tZW50UmVjdC50b3A7XG4gICAgICAgICAgICBsZXQgcG9wb3ZlckxlZnQgPSBpc1J0bCA/IGFsaWdubWVudFJlY3QucmlnaHQgLSBwb3BvdmVyRGltcy53aWR0aCA6IGFsaWdubWVudFJlY3QubGVmdDtcbiAgICAgICAgICAgIC8vIGNvbnN0cmFpblxuICAgICAgICAgICAgcG9wb3ZlclRvcCA9IE1hdGgubWF4KHBvcG92ZXJUb3AsIFBBRERJTkdfRlJPTV9WSUVXUE9SVCk7XG4gICAgICAgICAgICBwb3BvdmVyTGVmdCA9IE1hdGgubWluKHBvcG92ZXJMZWZ0LCBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50V2lkdGggLSBQQURESU5HX0ZST01fVklFV1BPUlQgLSBwb3BvdmVyRGltcy53aWR0aCk7XG4gICAgICAgICAgICBwb3BvdmVyTGVmdCA9IE1hdGgubWF4KHBvcG92ZXJMZWZ0LCBQQURESU5HX0ZST01fVklFV1BPUlQpO1xuICAgICAgICAgICAgbGV0IG9yaWdpbiA9IHJvb3RFbC5vZmZzZXRQYXJlbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgICBhcHBseVN0eWxlKHJvb3RFbCwge1xuICAgICAgICAgICAgICAgIHRvcDogcG9wb3ZlclRvcCAtIG9yaWdpbi50b3AsXG4gICAgICAgICAgICAgICAgbGVmdDogcG9wb3ZlckxlZnQgLSBvcmlnaW4ubGVmdCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxufVxuXG5jbGFzcyBNb3JlUG9wb3ZlciBleHRlbmRzIERhdGVDb21wb25lbnQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICB0aGlzLmhhbmRsZVJvb3RFbCA9IChyb290RWwpID0+IHtcbiAgICAgICAgICAgIHRoaXMucm9vdEVsID0gcm9vdEVsO1xuICAgICAgICAgICAgaWYgKHJvb3RFbCkge1xuICAgICAgICAgICAgICAgIHRoaXMuY29udGV4dC5yZWdpc3RlckludGVyYWN0aXZlQ29tcG9uZW50KHRoaXMsIHtcbiAgICAgICAgICAgICAgICAgICAgZWw6IHJvb3RFbCxcbiAgICAgICAgICAgICAgICAgICAgdXNlRXZlbnRDZW50ZXI6IGZhbHNlLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jb250ZXh0LnVucmVnaXN0ZXJJbnRlcmFjdGl2ZUNvbXBvbmVudCh0aGlzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG4gICAgcmVuZGVyKCkge1xuICAgICAgICBsZXQgeyBvcHRpb25zLCBkYXRlRW52IH0gPSB0aGlzLmNvbnRleHQ7XG4gICAgICAgIGxldCB7IHByb3BzIH0gPSB0aGlzO1xuICAgICAgICBsZXQgeyBzdGFydERhdGUsIHRvZGF5UmFuZ2UsIGRhdGVQcm9maWxlIH0gPSBwcm9wcztcbiAgICAgICAgbGV0IHRpdGxlID0gZGF0ZUVudi5mb3JtYXQoc3RhcnREYXRlLCBvcHRpb25zLmRheVBvcG92ZXJGb3JtYXQpO1xuICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoRGF5Q2VsbENvbnRhaW5lciwgeyBlbFJlZjogdGhpcy5oYW5kbGVSb290RWwsIGRhdGU6IHN0YXJ0RGF0ZSwgZGF0ZVByb2ZpbGU6IGRhdGVQcm9maWxlLCB0b2RheVJhbmdlOiB0b2RheVJhbmdlIH0sIChJbm5lckNvbnRlbnQsIHJlbmRlclByb3BzLCBlbEF0dHJzKSA9PiAoY3JlYXRlRWxlbWVudChQb3BvdmVyLCB7IGVsUmVmOiBlbEF0dHJzLnJlZiwgaWQ6IHByb3BzLmlkLCB0aXRsZTogdGl0bGUsIGV4dHJhQ2xhc3NOYW1lczogWydmYy1tb3JlLXBvcG92ZXInXS5jb25jYXQoZWxBdHRycy5jbGFzc05hbWUgfHwgW10pLCBleHRyYUF0dHJzOiBlbEF0dHJzIC8qIFRPRE86IG1ha2UgdGhlc2UgdGltZS1iYXNlZCB3aGVuIG5vdCB3aG9sZS1kYXk/ICovLCBwYXJlbnRFbDogcHJvcHMucGFyZW50RWwsIGFsaWdubWVudEVsOiBwcm9wcy5hbGlnbm1lbnRFbCwgYWxpZ25HcmlkVG9wOiBwcm9wcy5hbGlnbkdyaWRUb3AsIG9uQ2xvc2U6IHByb3BzLm9uQ2xvc2UgfSxcbiAgICAgICAgICAgIGhhc0N1c3RvbURheUNlbGxDb250ZW50KG9wdGlvbnMpICYmIChjcmVhdGVFbGVtZW50KElubmVyQ29udGVudCwgeyBlbFRhZzogXCJkaXZcIiwgZWxDbGFzc2VzOiBbJ2ZjLW1vcmUtcG9wb3Zlci1taXNjJ10gfSkpLFxuICAgICAgICAgICAgcHJvcHMuY2hpbGRyZW4pKSkpO1xuICAgIH1cbiAgICBxdWVyeUhpdChwb3NpdGlvbkxlZnQsIHBvc2l0aW9uVG9wLCBlbFdpZHRoLCBlbEhlaWdodCkge1xuICAgICAgICBsZXQgeyByb290RWwsIHByb3BzIH0gPSB0aGlzO1xuICAgICAgICBpZiAocG9zaXRpb25MZWZ0ID49IDAgJiYgcG9zaXRpb25MZWZ0IDwgZWxXaWR0aCAmJlxuICAgICAgICAgICAgcG9zaXRpb25Ub3AgPj0gMCAmJiBwb3NpdGlvblRvcCA8IGVsSGVpZ2h0KSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGRhdGVQcm9maWxlOiBwcm9wcy5kYXRlUHJvZmlsZSxcbiAgICAgICAgICAgICAgICBkYXRlU3BhbjogT2JqZWN0LmFzc2lnbih7IGFsbERheTogIXByb3BzLmZvcmNlVGltZWQsIHJhbmdlOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzdGFydDogcHJvcHMuc3RhcnREYXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgZW5kOiBwcm9wcy5lbmREYXRlLFxuICAgICAgICAgICAgICAgICAgICB9IH0sIHByb3BzLmV4dHJhRGF0ZVNwYW4pLFxuICAgICAgICAgICAgICAgIGRheUVsOiByb290RWwsXG4gICAgICAgICAgICAgICAgcmVjdDoge1xuICAgICAgICAgICAgICAgICAgICBsZWZ0OiAwLFxuICAgICAgICAgICAgICAgICAgICB0b3A6IDAsXG4gICAgICAgICAgICAgICAgICAgIHJpZ2h0OiBlbFdpZHRoLFxuICAgICAgICAgICAgICAgICAgICBib3R0b206IGVsSGVpZ2h0LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgbGF5ZXI6IDEsIC8vIGltcG9ydGFudCB3aGVuIGNvbXBhcmluZyB3aXRoIGhpdHMgZnJvbSBvdGhlciBjb21wb25lbnRzXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbn1cblxuY2xhc3MgTW9yZUxpbmtDb250YWluZXIgZXh0ZW5kcyBCYXNlQ29tcG9uZW50IHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoLi4uYXJndW1lbnRzKTtcbiAgICAgICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgICAgICAgIGlzUG9wb3Zlck9wZW46IGZhbHNlLFxuICAgICAgICAgICAgcG9wb3ZlcklkOiBnZXRVbmlxdWVEb21JZCgpLFxuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZUxpbmtFbCA9IChsaW5rRWwpID0+IHtcbiAgICAgICAgICAgIHRoaXMubGlua0VsID0gbGlua0VsO1xuICAgICAgICAgICAgaWYgKHRoaXMucHJvcHMuZWxSZWYpIHtcbiAgICAgICAgICAgICAgICBzZXRSZWYodGhpcy5wcm9wcy5lbFJlZiwgbGlua0VsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVDbGljayA9IChldikgPT4ge1xuICAgICAgICAgICAgbGV0IHsgcHJvcHMsIGNvbnRleHQgfSA9IHRoaXM7XG4gICAgICAgICAgICBsZXQgeyBtb3JlTGlua0NsaWNrIH0gPSBjb250ZXh0Lm9wdGlvbnM7XG4gICAgICAgICAgICBsZXQgZGF0ZSA9IGNvbXB1dGVSYW5nZShwcm9wcykuc3RhcnQ7XG4gICAgICAgICAgICBmdW5jdGlvbiBidWlsZFB1YmxpY1NlZyhzZWcpIHtcbiAgICAgICAgICAgICAgICBsZXQgeyBkZWYsIGluc3RhbmNlLCByYW5nZSB9ID0gc2VnLmV2ZW50UmFuZ2U7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnQ6IG5ldyBFdmVudEltcGwoY29udGV4dCwgZGVmLCBpbnN0YW5jZSksXG4gICAgICAgICAgICAgICAgICAgIHN0YXJ0OiBjb250ZXh0LmRhdGVFbnYudG9EYXRlKHJhbmdlLnN0YXJ0KSxcbiAgICAgICAgICAgICAgICAgICAgZW5kOiBjb250ZXh0LmRhdGVFbnYudG9EYXRlKHJhbmdlLmVuZCksXG4gICAgICAgICAgICAgICAgICAgIGlzU3RhcnQ6IHNlZy5pc1N0YXJ0LFxuICAgICAgICAgICAgICAgICAgICBpc0VuZDogc2VnLmlzRW5kLFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodHlwZW9mIG1vcmVMaW5rQ2xpY2sgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICBtb3JlTGlua0NsaWNrID0gbW9yZUxpbmtDbGljayh7XG4gICAgICAgICAgICAgICAgICAgIGRhdGUsXG4gICAgICAgICAgICAgICAgICAgIGFsbERheTogQm9vbGVhbihwcm9wcy5hbGxEYXlEYXRlKSxcbiAgICAgICAgICAgICAgICAgICAgYWxsU2VnczogcHJvcHMuYWxsU2Vncy5tYXAoYnVpbGRQdWJsaWNTZWcpLFxuICAgICAgICAgICAgICAgICAgICBoaWRkZW5TZWdzOiBwcm9wcy5oaWRkZW5TZWdzLm1hcChidWlsZFB1YmxpY1NlZyksXG4gICAgICAgICAgICAgICAgICAgIGpzRXZlbnQ6IGV2LFxuICAgICAgICAgICAgICAgICAgICB2aWV3OiBjb250ZXh0LnZpZXdBcGksXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIW1vcmVMaW5rQ2xpY2sgfHwgbW9yZUxpbmtDbGljayA9PT0gJ3BvcG92ZXInKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IGlzUG9wb3Zlck9wZW46IHRydWUgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICh0eXBlb2YgbW9yZUxpbmtDbGljayA9PT0gJ3N0cmluZycpIHsgLy8gYSB2aWV3IG5hbWVcbiAgICAgICAgICAgICAgICBjb250ZXh0LmNhbGVuZGFyQXBpLnpvb21UbyhkYXRlLCBtb3JlTGlua0NsaWNrKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVQb3BvdmVyQ2xvc2UgPSAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHsgaXNQb3BvdmVyT3BlbjogZmFsc2UgfSk7XG4gICAgICAgIH07XG4gICAgfVxuICAgIHJlbmRlcigpIHtcbiAgICAgICAgbGV0IHsgcHJvcHMsIHN0YXRlIH0gPSB0aGlzO1xuICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoVmlld0NvbnRleHRUeXBlLkNvbnN1bWVyLCBudWxsLCAoY29udGV4dCkgPT4ge1xuICAgICAgICAgICAgbGV0IHsgdmlld0FwaSwgb3B0aW9ucywgY2FsZW5kYXJBcGkgfSA9IGNvbnRleHQ7XG4gICAgICAgICAgICBsZXQgeyBtb3JlTGlua1RleHQgfSA9IG9wdGlvbnM7XG4gICAgICAgICAgICBsZXQgeyBtb3JlQ250IH0gPSBwcm9wcztcbiAgICAgICAgICAgIGxldCByYW5nZSA9IGNvbXB1dGVSYW5nZShwcm9wcyk7XG4gICAgICAgICAgICBsZXQgdGV4dCA9IHR5cGVvZiBtb3JlTGlua1RleHQgPT09ICdmdW5jdGlvbicgLy8gVE9ETzogZXZlbnR1YWxseSB1c2UgZm9ybWF0V2l0aE9yZGluYWxzXG4gICAgICAgICAgICAgICAgPyBtb3JlTGlua1RleHQuY2FsbChjYWxlbmRhckFwaSwgbW9yZUNudClcbiAgICAgICAgICAgICAgICA6IGArJHttb3JlQ250fSAke21vcmVMaW5rVGV4dH1gO1xuICAgICAgICAgICAgbGV0IGhpbnQgPSBmb3JtYXRXaXRoT3JkaW5hbHMob3B0aW9ucy5tb3JlTGlua0hpbnQsIFttb3JlQ250XSwgdGV4dCk7XG4gICAgICAgICAgICBsZXQgcmVuZGVyUHJvcHMgPSB7XG4gICAgICAgICAgICAgICAgbnVtOiBtb3JlQ250LFxuICAgICAgICAgICAgICAgIHNob3J0VGV4dDogYCske21vcmVDbnR9YCxcbiAgICAgICAgICAgICAgICB0ZXh0LFxuICAgICAgICAgICAgICAgIHZpZXc6IHZpZXdBcGksXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KEZyYWdtZW50LCBudWxsLFxuICAgICAgICAgICAgICAgIEJvb2xlYW4ocHJvcHMubW9yZUNudCkgJiYgKGNyZWF0ZUVsZW1lbnQoQ29udGVudENvbnRhaW5lciwgeyBlbFRhZzogcHJvcHMuZWxUYWcgfHwgJ2EnLCBlbFJlZjogdGhpcy5oYW5kbGVMaW5rRWwsIGVsQ2xhc3NlczogW1xuICAgICAgICAgICAgICAgICAgICAgICAgLi4uKHByb3BzLmVsQ2xhc3NlcyB8fCBbXSksXG4gICAgICAgICAgICAgICAgICAgICAgICAnZmMtbW9yZS1saW5rJyxcbiAgICAgICAgICAgICAgICAgICAgXSwgZWxTdHlsZTogcHJvcHMuZWxTdHlsZSwgZWxBdHRyczogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByb3BzLmVsQXR0cnMpLCBjcmVhdGVBcmlhQ2xpY2tBdHRycyh0aGlzLmhhbmRsZUNsaWNrKSksIHsgdGl0bGU6IGhpbnQsICdhcmlhLWV4cGFuZGVkJzogc3RhdGUuaXNQb3BvdmVyT3BlbiwgJ2FyaWEtY29udHJvbHMnOiBzdGF0ZS5pc1BvcG92ZXJPcGVuID8gc3RhdGUucG9wb3ZlcklkIDogJycgfSksIHJlbmRlclByb3BzOiByZW5kZXJQcm9wcywgZ2VuZXJhdG9yTmFtZTogXCJtb3JlTGlua0NvbnRlbnRcIiwgY3VzdG9tR2VuZXJhdG9yOiBvcHRpb25zLm1vcmVMaW5rQ29udGVudCwgZGVmYXVsdEdlbmVyYXRvcjogcHJvcHMuZGVmYXVsdEdlbmVyYXRvciB8fCByZW5kZXJNb3JlTGlua0lubmVyLCBjbGFzc05hbWVHZW5lcmF0b3I6IG9wdGlvbnMubW9yZUxpbmtDbGFzc05hbWVzLCBkaWRNb3VudDogb3B0aW9ucy5tb3JlTGlua0RpZE1vdW50LCB3aWxsVW5tb3VudDogb3B0aW9ucy5tb3JlTGlua1dpbGxVbm1vdW50IH0sIHByb3BzLmNoaWxkcmVuKSksXG4gICAgICAgICAgICAgICAgc3RhdGUuaXNQb3BvdmVyT3BlbiAmJiAoY3JlYXRlRWxlbWVudChNb3JlUG9wb3ZlciwgeyBpZDogc3RhdGUucG9wb3ZlcklkLCBzdGFydERhdGU6IHJhbmdlLnN0YXJ0LCBlbmREYXRlOiByYW5nZS5lbmQsIGRhdGVQcm9maWxlOiBwcm9wcy5kYXRlUHJvZmlsZSwgdG9kYXlSYW5nZTogcHJvcHMudG9kYXlSYW5nZSwgZXh0cmFEYXRlU3BhbjogcHJvcHMuZXh0cmFEYXRlU3BhbiwgcGFyZW50RWw6IHRoaXMucGFyZW50RWwsIGFsaWdubWVudEVsOiBwcm9wcy5hbGlnbm1lbnRFbFJlZiA/XG4gICAgICAgICAgICAgICAgICAgICAgICBwcm9wcy5hbGlnbm1lbnRFbFJlZi5jdXJyZW50IDpcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubGlua0VsLCBhbGlnbkdyaWRUb3A6IHByb3BzLmFsaWduR3JpZFRvcCwgZm9yY2VUaW1lZDogcHJvcHMuZm9yY2VUaW1lZCwgb25DbG9zZTogdGhpcy5oYW5kbGVQb3BvdmVyQ2xvc2UgfSwgcHJvcHMucG9wb3ZlckNvbnRlbnQoKSkpKSk7XG4gICAgICAgIH0pKTtcbiAgICB9XG4gICAgY29tcG9uZW50RGlkTW91bnQoKSB7XG4gICAgICAgIHRoaXMudXBkYXRlUGFyZW50RWwoKTtcbiAgICB9XG4gICAgY29tcG9uZW50RGlkVXBkYXRlKCkge1xuICAgICAgICB0aGlzLnVwZGF0ZVBhcmVudEVsKCk7XG4gICAgfVxuICAgIHVwZGF0ZVBhcmVudEVsKCkge1xuICAgICAgICBpZiAodGhpcy5saW5rRWwpIHtcbiAgICAgICAgICAgIHRoaXMucGFyZW50RWwgPSBlbGVtZW50Q2xvc2VzdCh0aGlzLmxpbmtFbCwgJy5mYy12aWV3LWhhcm5lc3MnKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbmZ1bmN0aW9uIHJlbmRlck1vcmVMaW5rSW5uZXIocHJvcHMpIHtcbiAgICByZXR1cm4gcHJvcHMudGV4dDtcbn1cbmZ1bmN0aW9uIGNvbXB1dGVSYW5nZShwcm9wcykge1xuICAgIGlmIChwcm9wcy5hbGxEYXlEYXRlKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdGFydDogcHJvcHMuYWxsRGF5RGF0ZSxcbiAgICAgICAgICAgIGVuZDogYWRkRGF5cyhwcm9wcy5hbGxEYXlEYXRlLCAxKSxcbiAgICAgICAgfTtcbiAgICB9XG4gICAgbGV0IHsgaGlkZGVuU2VncyB9ID0gcHJvcHM7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgc3RhcnQ6IGNvbXB1dGVFYXJsaWVzdFNlZ1N0YXJ0KGhpZGRlblNlZ3MpLFxuICAgICAgICBlbmQ6IGNvbXB1dGVMYXRlc3RTZWdFbmQoaGlkZGVuU2VncyksXG4gICAgfTtcbn1cbmZ1bmN0aW9uIGNvbXB1dGVFYXJsaWVzdFNlZ1N0YXJ0KHNlZ3MpIHtcbiAgICByZXR1cm4gc2Vncy5yZWR1Y2UocGlja0VhcmxpZXN0U3RhcnQpLmV2ZW50UmFuZ2UucmFuZ2Uuc3RhcnQ7XG59XG5mdW5jdGlvbiBwaWNrRWFybGllc3RTdGFydChzZWcwLCBzZWcxKSB7XG4gICAgcmV0dXJuIHNlZzAuZXZlbnRSYW5nZS5yYW5nZS5zdGFydCA8IHNlZzEuZXZlbnRSYW5nZS5yYW5nZS5zdGFydCA/IHNlZzAgOiBzZWcxO1xufVxuZnVuY3Rpb24gY29tcHV0ZUxhdGVzdFNlZ0VuZChzZWdzKSB7XG4gICAgcmV0dXJuIHNlZ3MucmVkdWNlKHBpY2tMYXRlc3RFbmQpLmV2ZW50UmFuZ2UucmFuZ2UuZW5kO1xufVxuZnVuY3Rpb24gcGlja0xhdGVzdEVuZChzZWcwLCBzZWcxKSB7XG4gICAgcmV0dXJuIHNlZzAuZXZlbnRSYW5nZS5yYW5nZS5lbmQgPiBzZWcxLmV2ZW50UmFuZ2UucmFuZ2UuZW5kID8gc2VnMCA6IHNlZzE7XG59XG5cbmNsYXNzIFN0b3JlIHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgdGhpcy5oYW5kbGVycyA9IFtdO1xuICAgIH1cbiAgICBzZXQodmFsdWUpIHtcbiAgICAgICAgdGhpcy5jdXJyZW50VmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgZm9yIChsZXQgaGFuZGxlciBvZiB0aGlzLmhhbmRsZXJzKSB7XG4gICAgICAgICAgICBoYW5kbGVyKHZhbHVlKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBzdWJzY3JpYmUoaGFuZGxlcikge1xuICAgICAgICB0aGlzLmhhbmRsZXJzLnB1c2goaGFuZGxlcik7XG4gICAgICAgIGlmICh0aGlzLmN1cnJlbnRWYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBoYW5kbGVyKHRoaXMuY3VycmVudFZhbHVlKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuLypcblN1YnNjcmliZXJzIHdpbGwgZ2V0IGEgTElTVCBvZiBDdXN0b21SZW5kZXJpbmdzXG4qL1xuY2xhc3MgQ3VzdG9tUmVuZGVyaW5nU3RvcmUgZXh0ZW5kcyBTdG9yZSB7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKC4uLmFyZ3VtZW50cyk7XG4gICAgICAgIHRoaXMubWFwID0gbmV3IE1hcCgpO1xuICAgIH1cbiAgICAvLyBmb3IgY29uc2lzdGVudCBvcmRlclxuICAgIGhhbmRsZShjdXN0b21SZW5kZXJpbmcpIHtcbiAgICAgICAgY29uc3QgeyBtYXAgfSA9IHRoaXM7XG4gICAgICAgIGxldCB1cGRhdGVkID0gZmFsc2U7XG4gICAgICAgIGlmIChjdXN0b21SZW5kZXJpbmcuaXNBY3RpdmUpIHtcbiAgICAgICAgICAgIG1hcC5zZXQoY3VzdG9tUmVuZGVyaW5nLmlkLCBjdXN0b21SZW5kZXJpbmcpO1xuICAgICAgICAgICAgdXBkYXRlZCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAobWFwLmhhcyhjdXN0b21SZW5kZXJpbmcuaWQpKSB7XG4gICAgICAgICAgICBtYXAuZGVsZXRlKGN1c3RvbVJlbmRlcmluZy5pZCk7XG4gICAgICAgICAgICB1cGRhdGVkID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodXBkYXRlZCkge1xuICAgICAgICAgICAgdGhpcy5zZXQobWFwKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuZXhwb3J0IHsgbGlzdGVuQnlTZWxlY3RvciBhcyAkLCBtZW1vaXplT2JqQXJnIGFzIEEsIEJhc2VDb21wb25lbnQgYXMgQiwgQ29udGVudENvbnRhaW5lciBhcyBDLCBEZWxheWVkUnVubmVyIGFzIEQsIGlzUHJvcHNFcXVhbCBhcyBFLCBFbWl0dGVyIGFzIEYsIHJhbmdlQ29udGFpbnNNYXJrZXIgYXMgRywgY3JlYXRlRW1wdHlFdmVudFN0b3JlIGFzIEgsIHJlZHVjZUV2ZW50U3RvcmUgYXMgSSwgcmV6b25lRXZlbnRTdG9yZURhdGVzIGFzIEosIG1lcmdlUmF3T3B0aW9ucyBhcyBLLCBCQVNFX09QVElPTl9SRUZJTkVSUyBhcyBMLCBDQUxFTkRBUl9MSVNURU5FUl9SRUZJTkVSUyBhcyBNLCBDQUxFTkRBUl9PUFRJT05fUkVGSU5FUlMgYXMgTiwgQ09NUExFWF9PUFRJT05fQ09NUEFSQVRPUlMgYXMgTywgVklFV19PUFRJT05fUkVGSU5FUlMgYXMgUCwgRGF0ZUVudiBhcyBRLCBEYXRlUHJvZmlsZUdlbmVyYXRvciBhcyBSLCBjcmVhdGVFdmVudFVpIGFzIFMsIFRoZW1lIGFzIFQsIHBhcnNlQnVzaW5lc3NIb3VycyBhcyBVLCBWaWV3Q29udGV4dFR5cGUgYXMgViwgc2V0UmVmIGFzIFcsIEludGVyYWN0aW9uIGFzIFgsIGdldEVsU2VnIGFzIFksIGVsZW1lbnRDbG9zZXN0IGFzIFosIEV2ZW50SW1wbCBhcyBfLCBtYXBIYXNoIGFzIGEsIHByZXZlbnREZWZhdWx0IGFzIGEkLCBsaXN0ZW5Ub0hvdmVyQnlTZWxlY3RvciBhcyBhMCwgUHVyZUNvbXBvbmVudCBhcyBhMSwgYnVpbGRWaWV3Q29udGV4dCBhcyBhMiwgZ2V0VW5pcXVlRG9tSWQgYXMgYTMsIHBhcnNlSW50ZXJhY3Rpb25TZXR0aW5ncyBhcyBhNCwgaW50ZXJhY3Rpb25TZXR0aW5nc1N0b3JlIGFzIGE1LCBOb3dUaW1lciBhcyBhNiwgQ2FsZW5kYXJJbXBsIGFzIGE3LCBmbHVzaFN5bmMgYXMgYTgsIENhbGVuZGFyUm9vdCBhcyBhOSwgbWVtb2l6ZUFycmF5bGlrZSBhcyBhQSwgbWVtb2l6ZUhhc2hsaWtlIGFzIGFCLCBpbnRlcnNlY3RSZWN0cyBhcyBhQywgcG9pbnRJbnNpZGVSZWN0IGFzIGFELCBjb25zdHJhaW5Qb2ludCBhcyBhRSwgZ2V0UmVjdENlbnRlciBhcyBhRiwgZGlmZlBvaW50cyBhcyBhRywgdHJhbnNsYXRlUmVjdCBhcyBhSCwgY29tcGFyZU9ianMgYXMgYUksIGNvbGxlY3RGcm9tSGFzaCBhcyBhSiwgZmluZEVsZW1lbnRzIGFzIGFLLCBmaW5kRGlyZWN0Q2hpbGRyZW4gYXMgYUwsIHJlbW92ZUVsZW1lbnQgYXMgYU0sIGFwcGx5U3R5bGUgYXMgYU4sIGVsZW1lbnRNYXRjaGVzIGFzIGFPLCBnZXRFdmVudFRhcmdldFZpYVJvb3QgYXMgYVAsIHBhcnNlQ2xhc3NOYW1lcyBhcyBhUSwgZ2V0Q2FuVkdyb3dXaXRoaW5DZWxsIGFzIGFSLCBtZXJnZUV2ZW50U3RvcmVzIGFzIGFTLCBnZXRSZWxldmFudEV2ZW50cyBhcyBhVCwgZXZlbnRUdXBsZVRvU3RvcmUgYXMgYVUsIGNvbWJpbmVFdmVudFVpcyBhcyBhViwgU3BsaXR0ZXIgYXMgYVcsIGdldERheUNsYXNzTmFtZXMgYXMgYVgsIGdldERhdGVNZXRhIGFzIGFZLCBnZXRTbG90Q2xhc3NOYW1lcyBhcyBhWiwgYnVpbGROYXZMaW5rQXR0cnMgYXMgYV8sIFJlbmRlcklkIGFzIGFhLCBlbnN1cmVFbEhhc1N0eWxlcyBhcyBhYiwgYXBwbHlTdHlsZVByb3AgYXMgYWMsIHNsaWNlRXZlbnRTdG9yZSBhcyBhZCwgSnNvblJlcXVlc3RFcnJvciBhcyBhZSwgY3JlYXRlQ29udGV4dCBhcyBhZiwgcmVmaW5lUHJvcHMgYXMgYWcsIGNyZWF0ZUV2ZW50SW5zdGFuY2UgYXMgYWgsIHBhcnNlRXZlbnREZWYgYXMgYWksIHJlZmluZUV2ZW50RGVmIGFzIGFqLCBwYWRTdGFydCBhcyBhaywgaXNJbnQgYXMgYWwsIHBhcnNlRmllbGRTcGVjcyBhcyBhbSwgY29tcGFyZUJ5RmllbGRTcGVjcyBhcyBhbiwgZmxleGlibGVDb21wYXJlIGFzIGFvLCBwcmV2ZW50U2VsZWN0aW9uIGFzIGFwLCBhbGxvd1NlbGVjdGlvbiBhcyBhcSwgcHJldmVudENvbnRleHRNZW51IGFzIGFyLCBhbGxvd0NvbnRleHRNZW51IGFzIGFzLCBjb21wYXJlTnVtYmVycyBhcyBhdCwgZW5hYmxlQ3Vyc29yIGFzIGF1LCBkaXNhYmxlQ3Vyc29yIGFzIGF2LCBjb21wdXRlVmlzaWJsZURheVJhbmdlIGFzIGF3LCBpc011bHRpRGF5UmFuZ2UgYXMgYXgsIGRpZmZEYXRlcyBhcyBheSwgcmVtb3ZlRXhhY3QgYXMgYXosIGJ1aWxkVmlld0NsYXNzTmFtZXMgYXMgYiwgcmVuZGVyTWljcm9Db2xHcm91cCBhcyBiJCwgd2hlblRyYW5zaXRpb25Eb25lIGFzIGIwLCBjb21wdXRlSW5uZXJSZWN0IGFzIGIxLCBjb21wdXRlRWRnZXMgYXMgYjIsIGdldENsaXBwaW5nUGFyZW50cyBhcyBiMywgY29tcHV0ZVJlY3QgYXMgYjQsIHJhbmdlc0VxdWFsIGFzIGI1LCByYW5nZXNJbnRlcnNlY3QgYXMgYjYsIHJhbmdlQ29udGFpbnNSYW5nZSBhcyBiNywgUG9zaXRpb25DYWNoZSBhcyBiOCwgU2Nyb2xsQ29udHJvbGxlciBhcyBiOSwgZ2V0RW50cnlTcGFuRW5kIGFzIGJBLCBiaW5hcnlTZWFyY2ggYXMgYkIsIGdyb3VwSW50ZXJzZWN0aW5nRW50cmllcyBhcyBiQywgaW50ZXJzZWN0U3BhbnMgYXMgYkQsIGludGVyYWN0aW9uU2V0dGluZ3NUb1N0b3JlIGFzIGJFLCBFbGVtZW50RHJhZ2dpbmcgYXMgYkYsIGNvbmZpZyBhcyBiRywgcGFyc2VEcmFnTWV0YSBhcyBiSCwgRGF5SGVhZGVyIGFzIGJJLCBjb21wdXRlRmFsbGJhY2tIZWFkZXJGb3JtYXQgYXMgYkosIFRhYmxlRGF0ZUNlbGwgYXMgYkssIFRhYmxlRG93Q2VsbCBhcyBiTCwgRGF5U2VyaWVzTW9kZWwgYXMgYk0sIGhhc0JnUmVuZGVyaW5nIGFzIGJOLCBidWlsZFNlZ1RpbWVUZXh0IGFzIGJPLCBzb3J0RXZlbnRTZWdzIGFzIGJQLCBnZXRTZWdNZXRhIGFzIGJRLCBidWlsZEV2ZW50UmFuZ2VLZXkgYXMgYlIsIGdldFNlZ0FuY2hvckF0dHJzIGFzIGJTLCBEYXlUYWJsZU1vZGVsIGFzIGJULCBTbGljZXIgYXMgYlUsIGFwcGx5TXV0YXRpb25Ub0V2ZW50U3RvcmUgYXMgYlYsIGlzUHJvcHNWYWxpZCBhcyBiVywgaXNJbnRlcmFjdGlvblZhbGlkIGFzIGJYLCBpc0RhdGVTZWxlY3Rpb25WYWxpZCBhcyBiWSwgU2ltcGxlU2Nyb2xsR3JpZCBhcyBiWiwgaGFzU2hyaW5rV2lkdGggYXMgYl8sIEVsZW1lbnRTY3JvbGxDb250cm9sbGVyIGFzIGJhLCBXaW5kb3dTY3JvbGxDb250cm9sbGVyIGFzIGJiLCBEYXRlQ29tcG9uZW50IGFzIGJjLCBpc0RhdGVTcGFuc0VxdWFsIGFzIGJkLCBhZGRNcyBhcyBiZSwgYWRkV2Vla3MgYXMgYmYsIGRpZmZXZWVrcyBhcyBiZywgZGlmZldob2xlV2Vla3MgYXMgYmgsIGRpZmZEYXlBbmRUaW1lIGFzIGJpLCBkaWZmRGF5cyBhcyBiaiwgaXNWYWxpZERhdGUgYXMgYmssIGFzQ2xlYW5EYXlzIGFzIGJsLCBtdWx0aXBseUR1cmF0aW9uIGFzIGJtLCBhZGREdXJhdGlvbnMgYXMgYm4sIGFzUm91Z2hNaW51dGVzIGFzIGJvLCBhc1JvdWdoU2Vjb25kcyBhcyBicCwgYXNSb3VnaE1zIGFzIGJxLCB3aG9sZURpdmlkZUR1cmF0aW9ucyBhcyBiciwgZm9ybWF0SXNvVGltZVN0cmluZyBhcyBicywgZm9ybWF0RGF5U3RyaW5nIGFzIGJ0LCBidWlsZElzb1N0cmluZyBhcyBidSwgZm9ybWF0SXNvTW9udGhTdHIgYXMgYnYsIE5hbWVkVGltZVpvbmVJbXBsIGFzIGJ3LCBwYXJzZSBhcyBieCwgU2VnSGllcmFyY2h5IGFzIGJ5LCBidWlsZEVudHJ5S2V5IGFzIGJ6LCBncmVhdGVzdER1cmF0aW9uRGVub21pbmF0b3IgYXMgYywgZ2V0U2Nyb2xsR3JpZENsYXNzTmFtZXMgYXMgYzAsIGdldFNlY3Rpb25DbGFzc05hbWVzIGFzIGMxLCBnZXRTZWN0aW9uSGFzTGlxdWlkSGVpZ2h0IGFzIGMyLCBnZXRBbGxvd1lTY3JvbGxpbmcgYXMgYzMsIHJlbmRlckNodW5rQ29udGVudCBhcyBjNCwgY29tcHV0ZVNocmlua1dpZHRoIGFzIGM1LCBzYW5pdGl6ZVNocmlua1dpZHRoIGFzIGM2LCBpc0NvbFByb3BzRXF1YWwgYXMgYzcsIHJlbmRlclNjcm9sbFNoaW0gYXMgYzgsIGdldFN0aWNreUZvb3RlclNjcm9sbGJhciBhcyBjOSwgZ2V0U3RpY2t5SGVhZGVyRGF0ZXMgYXMgY2EsIFNjcm9sbGVyIGFzIGNiLCBnZXRTY3JvbGxiYXJXaWR0aHMgYXMgY2MsIFJlZk1hcCBhcyBjZCwgZ2V0SXNSdGxTY3JvbGxiYXJPbkxlZnQgYXMgY2UsIFNjcm9sbFJlc3BvbmRlciBhcyBjZiwgU3RhbmRhcmRFdmVudCBhcyBjZywgTm93SW5kaWNhdG9yQ29udGFpbmVyIGFzIGNoLCBEYXlDZWxsQ29udGFpbmVyIGFzIGNpLCBoYXNDdXN0b21EYXlDZWxsQ29udGVudCBhcyBjaiwgRXZlbnRDb250YWluZXIgYXMgY2ssIHJlbmRlckZpbGwgYXMgY2wsIEJnRXZlbnQgYXMgY20sIFdlZWtOdW1iZXJDb250YWluZXIgYXMgY24sIE1vcmVMaW5rQ29udGFpbmVyIGFzIGNvLCBjb21wdXRlRWFybGllc3RTZWdTdGFydCBhcyBjcCwgVmlld0NvbnRhaW5lciBhcyBjcSwgdHJpZ2dlckRhdGVTZWxlY3QgYXMgY3IsIGdldERlZmF1bHRFdmVudEVuZCBhcyBjcywgaW5qZWN0U3R5bGVzIGFzIGN0LCBidWlsZEVsQXR0cnMgYXMgY3UsIEN1c3RvbVJlbmRlcmluZ1N0b3JlIGFzIGN2LCBjcmVhdGVEdXJhdGlvbiBhcyBkLCBCQVNFX09QVElPTl9ERUZBVUxUUyBhcyBlLCBhcnJheVRvSGFzaCBhcyBmLCBndWlkIGFzIGcsIGZpbHRlckhhc2ggYXMgaCwgaXNBcnJheXNFcXVhbCBhcyBpLCBidWlsZEV2ZW50U291cmNlUmVmaW5lcnMgYXMgaiwgZm9ybWF0V2l0aE9yZGluYWxzIGFzIGssIGJ1aWxkUmFuZ2VBcGlXaXRoVGltZVpvbmUgYXMgbCwgbWVyZ2VQcm9wcyBhcyBtLCBpZGVudGl0eSBhcyBuLCBpbnRlcnNlY3RSYW5nZXMgYXMgbywgcGFyc2VFdmVudFNvdXJjZSBhcyBwLCBzdGFydE9mRGF5IGFzIHEsIHJlcXVlc3RKc29uIGFzIHIsIHN1YnRyYWN0RHVyYXRpb25zIGFzIHMsIGFkZERheXMgYXMgdCwgdW5wcm9taXNpZnkgYXMgdSwgaGFzaFZhbHVlc1RvQXJyYXkgYXMgdiwgYnVpbGRFdmVudEFwaXMgYXMgdywgY3JlYXRlRm9ybWF0dGVyIGFzIHgsIGRpZmZXaG9sZURheXMgYXMgeSwgbWVtb2l6ZSBhcyB6IH07XG4iXSwibmFtZXMiOltdLCJpZ25vcmVMaXN0IjpbMF0sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///(ssr)/./node_modules/@fullcalendar/core/internal-common.js\n");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "(ssr)/./node_modules/@fullcalendar/core/locales/es-us.js":
|
|
/*!**********************************************************!*\
|
|
!*** ./node_modules/@fullcalendar/core/locales/es-us.js ***!
|
|
\**********************************************************/
|
|
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
|
|
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ l23)\n/* harmony export */ });\nvar l23 = {\n code: 'es',\n week: {\n dow: 0,\n doy: 6, // The week that contains Jan 1st is the first week of the year.\n },\n buttonText: {\n prev: 'Ant',\n next: 'Sig',\n today: 'Hoy',\n year: 'Año',\n month: 'Mes',\n week: 'Semana',\n day: 'Día',\n list: 'Agenda',\n },\n weekText: 'Sm',\n allDayText: 'Todo el día',\n moreLinkText: 'más',\n noEventsText: 'No hay eventos para mostrar',\n};\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKHNzcikvLi9ub2RlX21vZHVsZXMvQGZ1bGxjYWxlbmRhci9jb3JlL2xvY2FsZXMvZXMtdXMuanMiLCJtYXBwaW5ncyI6Ijs7OztBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRTBCIiwic291cmNlcyI6WyIvaG9tZS9zaWx2aW8vRGV2ZWxvcC9DSVJVWC1BUFAvbm9kZV9tb2R1bGVzL0BmdWxsY2FsZW5kYXIvY29yZS9sb2NhbGVzL2VzLXVzLmpzIl0sInNvdXJjZXNDb250ZW50IjpbInZhciBsMjMgPSB7XG4gICAgY29kZTogJ2VzJyxcbiAgICB3ZWVrOiB7XG4gICAgICAgIGRvdzogMCxcbiAgICAgICAgZG95OiA2LCAvLyBUaGUgd2VlayB0aGF0IGNvbnRhaW5zIEphbiAxc3QgaXMgdGhlIGZpcnN0IHdlZWsgb2YgdGhlIHllYXIuXG4gICAgfSxcbiAgICBidXR0b25UZXh0OiB7XG4gICAgICAgIHByZXY6ICdBbnQnLFxuICAgICAgICBuZXh0OiAnU2lnJyxcbiAgICAgICAgdG9kYXk6ICdIb3knLFxuICAgICAgICB5ZWFyOiAnQcOxbycsXG4gICAgICAgIG1vbnRoOiAnTWVzJyxcbiAgICAgICAgd2VlazogJ1NlbWFuYScsXG4gICAgICAgIGRheTogJ0TDrWEnLFxuICAgICAgICBsaXN0OiAnQWdlbmRhJyxcbiAgICB9LFxuICAgIHdlZWtUZXh0OiAnU20nLFxuICAgIGFsbERheVRleHQ6ICdUb2RvIGVsIGTDrWEnLFxuICAgIG1vcmVMaW5rVGV4dDogJ23DoXMnLFxuICAgIG5vRXZlbnRzVGV4dDogJ05vIGhheSBldmVudG9zIHBhcmEgbW9zdHJhcicsXG59O1xuXG5leHBvcnQgeyBsMjMgYXMgZGVmYXVsdCB9O1xuIl0sIm5hbWVzIjpbXSwiaWdub3JlTGlzdCI6WzBdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///(ssr)/./node_modules/@fullcalendar/core/locales/es-us.js\n");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "(ssr)/./node_modules/@fullcalendar/daygrid/index.js":
|
|
/*!*****************************************************!*\
|
|
!*** ./node_modules/@fullcalendar/daygrid/index.js ***!
|
|
\*****************************************************/
|
|
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
|
|
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ index)\n/* harmony export */ });\n/* harmony import */ var _fullcalendar_core_index_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @fullcalendar/core/index.js */ \"(ssr)/./node_modules/@fullcalendar/core/index.js\");\n/* harmony import */ var _internal_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./internal.js */ \"(ssr)/./node_modules/@fullcalendar/daygrid/internal.js\");\n\n\n\n\n\nvar index = (0,_fullcalendar_core_index_js__WEBPACK_IMPORTED_MODULE_0__.createPlugin)({\n name: '@fullcalendar/daygrid',\n initialView: 'dayGridMonth',\n views: {\n dayGrid: {\n component: _internal_js__WEBPACK_IMPORTED_MODULE_1__.DayGridView,\n dateProfileGeneratorClass: _internal_js__WEBPACK_IMPORTED_MODULE_1__.TableDateProfileGenerator,\n },\n dayGridDay: {\n type: 'dayGrid',\n duration: { days: 1 },\n },\n dayGridWeek: {\n type: 'dayGrid',\n duration: { weeks: 1 },\n },\n dayGridMonth: {\n type: 'dayGrid',\n duration: { months: 1 },\n fixedWeekCount: true,\n },\n dayGridYear: {\n type: 'dayGrid',\n duration: { years: 1 },\n },\n },\n});\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKHNzcikvLi9ub2RlX21vZHVsZXMvQGZ1bGxjYWxlbmRhci9kYXlncmlkL2luZGV4LmpzIiwibWFwcGluZ3MiOiI7Ozs7OztBQUEyRDtBQUM0QjtBQUMvQztBQUNGOztBQUV0QyxZQUFZLHlFQUFZO0FBQ3hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLHFEQUFZO0FBQ25DLHVDQUF1QyxtRUFBeUI7QUFDaEUsU0FBUztBQUNUO0FBQ0E7QUFDQSx3QkFBd0IsU0FBUztBQUNqQyxTQUFTO0FBQ1Q7QUFDQTtBQUNBLHdCQUF3QixVQUFVO0FBQ2xDLFNBQVM7QUFDVDtBQUNBO0FBQ0Esd0JBQXdCLFdBQVc7QUFDbkM7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLHdCQUF3QixVQUFVO0FBQ2xDLFNBQVM7QUFDVCxLQUFLO0FBQ0wsQ0FBQzs7QUFFMkIiLCJzb3VyY2VzIjpbIi9ob21lL3NpbHZpby9EZXZlbG9wL0NJUlVYLUFQUC9ub2RlX21vZHVsZXMvQGZ1bGxjYWxlbmRhci9kYXlncmlkL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNyZWF0ZVBsdWdpbiB9IGZyb20gJ0BmdWxsY2FsZW5kYXIvY29yZS9pbmRleC5qcyc7XG5pbXBvcnQgeyBEYXlHcmlkVmlldyBhcyBEYXlUYWJsZVZpZXcsIFRhYmxlRGF0ZVByb2ZpbGVHZW5lcmF0b3IgfSBmcm9tICcuL2ludGVybmFsLmpzJztcbmltcG9ydCAnQGZ1bGxjYWxlbmRhci9jb3JlL2ludGVybmFsLmpzJztcbmltcG9ydCAnQGZ1bGxjYWxlbmRhci9jb3JlL3ByZWFjdC5qcyc7XG5cbnZhciBpbmRleCA9IGNyZWF0ZVBsdWdpbih7XG4gICAgbmFtZTogJ0BmdWxsY2FsZW5kYXIvZGF5Z3JpZCcsXG4gICAgaW5pdGlhbFZpZXc6ICdkYXlHcmlkTW9udGgnLFxuICAgIHZpZXdzOiB7XG4gICAgICAgIGRheUdyaWQ6IHtcbiAgICAgICAgICAgIGNvbXBvbmVudDogRGF5VGFibGVWaWV3LFxuICAgICAgICAgICAgZGF0ZVByb2ZpbGVHZW5lcmF0b3JDbGFzczogVGFibGVEYXRlUHJvZmlsZUdlbmVyYXRvcixcbiAgICAgICAgfSxcbiAgICAgICAgZGF5R3JpZERheToge1xuICAgICAgICAgICAgdHlwZTogJ2RheUdyaWQnLFxuICAgICAgICAgICAgZHVyYXRpb246IHsgZGF5czogMSB9LFxuICAgICAgICB9LFxuICAgICAgICBkYXlHcmlkV2Vlazoge1xuICAgICAgICAgICAgdHlwZTogJ2RheUdyaWQnLFxuICAgICAgICAgICAgZHVyYXRpb246IHsgd2Vla3M6IDEgfSxcbiAgICAgICAgfSxcbiAgICAgICAgZGF5R3JpZE1vbnRoOiB7XG4gICAgICAgICAgICB0eXBlOiAnZGF5R3JpZCcsXG4gICAgICAgICAgICBkdXJhdGlvbjogeyBtb250aHM6IDEgfSxcbiAgICAgICAgICAgIGZpeGVkV2Vla0NvdW50OiB0cnVlLFxuICAgICAgICB9LFxuICAgICAgICBkYXlHcmlkWWVhcjoge1xuICAgICAgICAgICAgdHlwZTogJ2RheUdyaWQnLFxuICAgICAgICAgICAgZHVyYXRpb246IHsgeWVhcnM6IDEgfSxcbiAgICAgICAgfSxcbiAgICB9LFxufSk7XG5cbmV4cG9ydCB7IGluZGV4IGFzIGRlZmF1bHQgfTtcbiJdLCJuYW1lcyI6W10sImlnbm9yZUxpc3QiOlswXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///(ssr)/./node_modules/@fullcalendar/daygrid/index.js\n");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "(ssr)/./node_modules/@fullcalendar/daygrid/internal.js":
|
|
/*!********************************************************!*\
|
|
!*** ./node_modules/@fullcalendar/daygrid/internal.js ***!
|
|
\********************************************************/
|
|
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
|
|
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ DayGridView: () => (/* binding */ DayTableView),\n/* harmony export */ DayTable: () => (/* binding */ DayTable),\n/* harmony export */ DayTableSlicer: () => (/* binding */ DayTableSlicer),\n/* harmony export */ Table: () => (/* binding */ Table),\n/* harmony export */ TableDateProfileGenerator: () => (/* binding */ TableDateProfileGenerator),\n/* harmony export */ TableRows: () => (/* binding */ TableRows),\n/* harmony export */ TableView: () => (/* binding */ TableView),\n/* harmony export */ buildDayTableModel: () => (/* binding */ buildDayTableModel),\n/* harmony export */ buildDayTableRenderRange: () => (/* binding */ buildDayTableRenderRange)\n/* harmony export */ });\n/* harmony import */ var _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @fullcalendar/core/internal.js */ \"(ssr)/./node_modules/@fullcalendar/core/internal-common.js\");\n/* harmony import */ var _fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @fullcalendar/core/preact.js */ \"(ssr)/./node_modules/preact/dist/preact.mjs\");\n\n\n\n/* An abstract class for the daygrid views, as well as month view. Renders one or more rows of day cells.\n----------------------------------------------------------------------------------------------------------------------*/\n// It is a manager for a Table subcomponent, which does most of the heavy lifting.\n// It is responsible for managing width/height.\nclass TableView extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bc {\n constructor() {\n super(...arguments);\n this.headerElRef = (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createRef)();\n }\n renderSimpleLayout(headerRowContent, bodyContent) {\n let { props, context } = this;\n let sections = [];\n let stickyHeaderDates = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ca)(context.options);\n if (headerRowContent) {\n sections.push({\n type: 'header',\n key: 'header',\n isSticky: stickyHeaderDates,\n chunk: {\n elRef: this.headerElRef,\n tableClassName: 'fc-col-header',\n rowContent: headerRowContent,\n },\n });\n }\n sections.push({\n type: 'body',\n key: 'body',\n liquid: true,\n chunk: { content: bodyContent },\n });\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cq, { elClasses: ['fc-daygrid'], viewSpec: context.viewSpec },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bZ, { liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: props.forPrint, cols: [] /* TODO: make optional? */, sections: sections })));\n }\n renderHScrollLayout(headerRowContent, bodyContent, colCnt, dayMinWidth) {\n let ScrollGrid = this.context.pluginHooks.scrollGridImpl;\n if (!ScrollGrid) {\n throw new Error('No ScrollGrid implementation');\n }\n let { props, context } = this;\n let stickyHeaderDates = !props.forPrint && (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ca)(context.options);\n let stickyFooterScrollbar = !props.forPrint && (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.c9)(context.options);\n let sections = [];\n if (headerRowContent) {\n sections.push({\n type: 'header',\n key: 'header',\n isSticky: stickyHeaderDates,\n chunks: [{\n key: 'main',\n elRef: this.headerElRef,\n tableClassName: 'fc-col-header',\n rowContent: headerRowContent,\n }],\n });\n }\n sections.push({\n type: 'body',\n key: 'body',\n liquid: true,\n chunks: [{\n key: 'main',\n content: bodyContent,\n }],\n });\n if (stickyFooterScrollbar) {\n sections.push({\n type: 'footer',\n key: 'footer',\n isSticky: true,\n chunks: [{\n key: 'main',\n content: _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.c8,\n }],\n });\n }\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cq, { elClasses: ['fc-daygrid'], viewSpec: context.viewSpec },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(ScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, forPrint: props.forPrint, collapsibleWidth: props.forPrint, colGroups: [{ cols: [{ span: colCnt, minWidth: dayMinWidth }] }], sections: sections })));\n }\n}\n\nfunction splitSegsByRow(segs, rowCnt) {\n let byRow = [];\n for (let i = 0; i < rowCnt; i += 1) {\n byRow[i] = [];\n }\n for (let seg of segs) {\n byRow[seg.row].push(seg);\n }\n return byRow;\n}\nfunction splitSegsByFirstCol(segs, colCnt) {\n let byCol = [];\n for (let i = 0; i < colCnt; i += 1) {\n byCol[i] = [];\n }\n for (let seg of segs) {\n byCol[seg.firstCol].push(seg);\n }\n return byCol;\n}\nfunction splitInteractionByRow(ui, rowCnt) {\n let byRow = [];\n if (!ui) {\n for (let i = 0; i < rowCnt; i += 1) {\n byRow[i] = null;\n }\n }\n else {\n for (let i = 0; i < rowCnt; i += 1) {\n byRow[i] = {\n affectedInstances: ui.affectedInstances,\n isEvent: ui.isEvent,\n segs: [],\n };\n }\n for (let seg of ui.segs) {\n byRow[seg.row].segs.push(seg);\n }\n }\n return byRow;\n}\n\nconst DEFAULT_TABLE_EVENT_TIME_FORMAT = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.x)({\n hour: 'numeric',\n minute: '2-digit',\n omitZeroMinute: true,\n meridiem: 'narrow',\n});\nfunction hasListItemDisplay(seg) {\n let { display } = seg.eventRange.ui;\n return display === 'list-item' || (display === 'auto' &&\n !seg.eventRange.def.allDay &&\n seg.firstCol === seg.lastCol && // can't be multi-day\n seg.isStart && // \"\n seg.isEnd // \"\n );\n}\n\nclass TableBlockEvent extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.B {\n render() {\n let { props } = this;\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cg, Object.assign({}, props, { elClasses: ['fc-daygrid-event', 'fc-daygrid-block-event', 'fc-h-event'], defaultTimeFormat: DEFAULT_TABLE_EVENT_TIME_FORMAT, defaultDisplayEventEnd: props.defaultDisplayEventEnd, disableResizing: !props.seg.eventRange.def.allDay })));\n }\n}\n\nclass TableListItemEvent extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.B {\n render() {\n let { props, context } = this;\n let { options } = context;\n let { seg } = props;\n let timeFormat = options.eventTimeFormat || DEFAULT_TABLE_EVENT_TIME_FORMAT;\n let timeText = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bO)(seg, timeFormat, context, true, props.defaultDisplayEventEnd);\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ck, Object.assign({}, props, { elTag: \"a\", elClasses: ['fc-daygrid-event', 'fc-daygrid-dot-event'], elAttrs: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bS)(props.seg, context), defaultGenerator: renderInnerContent, timeText: timeText, isResizing: false, isDateSelecting: false })));\n }\n}\nfunction renderInnerContent(renderProps) {\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.Fragment, null,\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-daygrid-event-dot\", style: { borderColor: renderProps.borderColor || renderProps.backgroundColor } }),\n renderProps.timeText && ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-event-time\" }, renderProps.timeText)),\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-event-title\" }, renderProps.event.title || (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.Fragment, null, \"\\u00A0\"))));\n}\n\nclass TableCellMoreLink extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.B {\n constructor() {\n super(...arguments);\n this.compileSegs = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(compileSegs);\n }\n render() {\n let { props } = this;\n let { allSegs, invisibleSegs } = this.compileSegs(props.singlePlacements);\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.co, { elClasses: ['fc-daygrid-more-link'], dateProfile: props.dateProfile, todayRange: props.todayRange, allDayDate: props.allDayDate, moreCnt: props.moreCnt, allSegs: allSegs, hiddenSegs: invisibleSegs, alignmentElRef: props.alignmentElRef, alignGridTop: props.alignGridTop, extraDateSpan: props.extraDateSpan, popoverContent: () => {\n let isForcedInvisible = (props.eventDrag ? props.eventDrag.affectedInstances : null) ||\n (props.eventResize ? props.eventResize.affectedInstances : null) ||\n {};\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.Fragment, null, allSegs.map((seg) => {\n let instanceId = seg.eventRange.instance.instanceId;\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-daygrid-event-harness\", key: instanceId, style: {\n visibility: isForcedInvisible[instanceId] ? 'hidden' : '',\n } }, hasListItemDisplay(seg) ? ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TableListItemEvent, Object.assign({ seg: seg, isDragging: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bQ)(seg, props.todayRange)))) : ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TableBlockEvent, Object.assign({ seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bQ)(seg, props.todayRange))))));\n })));\n } }));\n }\n}\nfunction compileSegs(singlePlacements) {\n let allSegs = [];\n let invisibleSegs = [];\n for (let placement of singlePlacements) {\n allSegs.push(placement.seg);\n if (!placement.isVisible) {\n invisibleSegs.push(placement.seg);\n }\n }\n return { allSegs, invisibleSegs };\n}\n\nconst DEFAULT_WEEK_NUM_FORMAT = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.x)({ week: 'narrow' });\nclass TableCell extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bc {\n constructor() {\n super(...arguments);\n this.rootElRef = (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createRef)();\n this.state = {\n dayNumberId: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.a3)(),\n };\n this.handleRootEl = (el) => {\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.W)(this.rootElRef, el);\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.W)(this.props.elRef, el);\n };\n }\n render() {\n let { context, props, state, rootElRef } = this;\n let { options, dateEnv } = context;\n let { date, dateProfile } = props;\n // TODO: memoize this?\n const isMonthStart = props.showDayNumber &&\n shouldDisplayMonthStart(date, dateProfile.currentRange, dateEnv);\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ci, { elTag: \"td\", elRef: this.handleRootEl, elClasses: [\n 'fc-daygrid-day',\n ...(props.extraClassNames || []),\n ], elAttrs: Object.assign(Object.assign(Object.assign({}, props.extraDataAttrs), (props.showDayNumber ? { 'aria-labelledby': state.dayNumberId } : {})), { role: 'gridcell' }), defaultGenerator: renderTopInner, date: date, dateProfile: dateProfile, todayRange: props.todayRange, showDayNumber: props.showDayNumber, isMonthStart: isMonthStart, extraRenderProps: props.extraRenderProps }, (InnerContent, renderProps) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { ref: props.innerElRef, className: \"fc-daygrid-day-frame fc-scrollgrid-sync-inner\", style: { minHeight: props.minHeight } },\n props.showWeekNumber && ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cn, { elTag: \"a\", elClasses: ['fc-daygrid-week-number'], elAttrs: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.a_)(context, date, 'week'), date: date, defaultFormat: DEFAULT_WEEK_NUM_FORMAT })),\n !renderProps.isDisabled &&\n (props.showDayNumber || (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cj)(options) || props.forceDayTop) ? ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-daygrid-day-top\" },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(InnerContent, { elTag: \"a\", elClasses: [\n 'fc-daygrid-day-number',\n isMonthStart && 'fc-daygrid-month-start',\n ], elAttrs: Object.assign(Object.assign({}, (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.a_)(context, date)), { id: state.dayNumberId }) }))) : props.showDayNumber ? (\n // for creating correct amount of space (see issue #7162)\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-daygrid-day-top\", style: { visibility: 'hidden' } },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"a\", { className: \"fc-daygrid-day-number\" }, \"\\u00A0\"))) : undefined,\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-daygrid-day-events\", ref: props.fgContentElRef },\n props.fgContent,\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-daygrid-day-bottom\", style: { marginTop: props.moreMarginTop } },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TableCellMoreLink, { allDayDate: date, singlePlacements: props.singlePlacements, moreCnt: props.moreCnt, alignmentElRef: rootElRef, alignGridTop: !props.showDayNumber, extraDateSpan: props.extraDateSpan, dateProfile: props.dateProfile, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, todayRange: props.todayRange }))),\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-daygrid-day-bg\" }, props.bgContent)))));\n }\n}\nfunction renderTopInner(props) {\n return props.dayNumberText || (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.Fragment, null, \"\\u00A0\");\n}\nfunction shouldDisplayMonthStart(date, currentRange, dateEnv) {\n const { start: currentStart, end: currentEnd } = currentRange;\n const currentEndIncl = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.be)(currentEnd, -1);\n const currentFirstYear = dateEnv.getYear(currentStart);\n const currentFirstMonth = dateEnv.getMonth(currentStart);\n const currentLastYear = dateEnv.getYear(currentEndIncl);\n const currentLastMonth = dateEnv.getMonth(currentEndIncl);\n // spans more than one month?\n return !(currentFirstYear === currentLastYear && currentFirstMonth === currentLastMonth) &&\n Boolean(\n // first date in current view?\n date.valueOf() === currentStart.valueOf() ||\n // a month-start that's within the current range?\n (dateEnv.getDay(date) === 1 && date.valueOf() < currentEnd.valueOf()));\n}\n\nfunction generateSegKey(seg) {\n return seg.eventRange.instance.instanceId + ':' + seg.firstCol;\n}\nfunction generateSegUid(seg) {\n return generateSegKey(seg) + ':' + seg.lastCol;\n}\nfunction computeFgSegPlacement(segs, // assumed already sorted\ndayMaxEvents, dayMaxEventRows, strictOrder, segHeights, maxContentHeight, cells) {\n let hierarchy = new DayGridSegHierarchy((segEntry) => {\n // TODO: more DRY with generateSegUid\n let segUid = segs[segEntry.index].eventRange.instance.instanceId +\n ':' + segEntry.span.start +\n ':' + (segEntry.span.end - 1);\n // if no thickness known, assume 1 (if 0, so small it always fits)\n return segHeights[segUid] || 1;\n });\n hierarchy.allowReslicing = true;\n hierarchy.strictOrder = strictOrder;\n if (dayMaxEvents === true || dayMaxEventRows === true) {\n hierarchy.maxCoord = maxContentHeight;\n hierarchy.hiddenConsumes = true;\n }\n else if (typeof dayMaxEvents === 'number') {\n hierarchy.maxStackCnt = dayMaxEvents;\n }\n else if (typeof dayMaxEventRows === 'number') {\n hierarchy.maxStackCnt = dayMaxEventRows;\n hierarchy.hiddenConsumes = true;\n }\n // create segInputs only for segs with known heights\n let segInputs = [];\n let unknownHeightSegs = [];\n for (let i = 0; i < segs.length; i += 1) {\n let seg = segs[i];\n let segUid = generateSegUid(seg);\n let eventHeight = segHeights[segUid];\n if (eventHeight != null) {\n segInputs.push({\n index: i,\n span: {\n start: seg.firstCol,\n end: seg.lastCol + 1,\n },\n });\n }\n else {\n unknownHeightSegs.push(seg);\n }\n }\n let hiddenEntries = hierarchy.addSegs(segInputs);\n let segRects = hierarchy.toRects();\n let { singleColPlacements, multiColPlacements, leftoverMargins } = placeRects(segRects, segs, cells);\n let moreCnts = [];\n let moreMarginTops = [];\n // add segs with unknown heights\n for (let seg of unknownHeightSegs) {\n multiColPlacements[seg.firstCol].push({\n seg,\n isVisible: false,\n isAbsolute: true,\n absoluteTop: 0,\n marginTop: 0,\n });\n for (let col = seg.firstCol; col <= seg.lastCol; col += 1) {\n singleColPlacements[col].push({\n seg: resliceSeg(seg, col, col + 1, cells),\n isVisible: false,\n isAbsolute: false,\n absoluteTop: 0,\n marginTop: 0,\n });\n }\n }\n // add the hidden entries\n for (let col = 0; col < cells.length; col += 1) {\n moreCnts.push(0);\n }\n for (let hiddenEntry of hiddenEntries) {\n let seg = segs[hiddenEntry.index];\n let hiddenSpan = hiddenEntry.span;\n multiColPlacements[hiddenSpan.start].push({\n seg: resliceSeg(seg, hiddenSpan.start, hiddenSpan.end, cells),\n isVisible: false,\n isAbsolute: true,\n absoluteTop: 0,\n marginTop: 0,\n });\n for (let col = hiddenSpan.start; col < hiddenSpan.end; col += 1) {\n moreCnts[col] += 1;\n singleColPlacements[col].push({\n seg: resliceSeg(seg, col, col + 1, cells),\n isVisible: false,\n isAbsolute: false,\n absoluteTop: 0,\n marginTop: 0,\n });\n }\n }\n // deal with leftover margins\n for (let col = 0; col < cells.length; col += 1) {\n moreMarginTops.push(leftoverMargins[col]);\n }\n return { singleColPlacements, multiColPlacements, moreCnts, moreMarginTops };\n}\n// rects ordered by top coord, then left\nfunction placeRects(allRects, segs, cells) {\n let rectsByEachCol = groupRectsByEachCol(allRects, cells.length);\n let singleColPlacements = [];\n let multiColPlacements = [];\n let leftoverMargins = [];\n for (let col = 0; col < cells.length; col += 1) {\n let rects = rectsByEachCol[col];\n // compute all static segs in singlePlacements\n let singlePlacements = [];\n let currentHeight = 0;\n let currentMarginTop = 0;\n for (let rect of rects) {\n let seg = segs[rect.index];\n singlePlacements.push({\n seg: resliceSeg(seg, col, col + 1, cells),\n isVisible: true,\n isAbsolute: false,\n absoluteTop: rect.levelCoord,\n marginTop: rect.levelCoord - currentHeight,\n });\n currentHeight = rect.levelCoord + rect.thickness;\n }\n // compute mixed static/absolute segs in multiPlacements\n let multiPlacements = [];\n currentHeight = 0;\n currentMarginTop = 0;\n for (let rect of rects) {\n let seg = segs[rect.index];\n let isAbsolute = rect.span.end - rect.span.start > 1; // multi-column?\n let isFirstCol = rect.span.start === col;\n currentMarginTop += rect.levelCoord - currentHeight; // amount of space since bottom of previous seg\n currentHeight = rect.levelCoord + rect.thickness; // height will now be bottom of current seg\n if (isAbsolute) {\n currentMarginTop += rect.thickness;\n if (isFirstCol) {\n multiPlacements.push({\n seg: resliceSeg(seg, rect.span.start, rect.span.end, cells),\n isVisible: true,\n isAbsolute: true,\n absoluteTop: rect.levelCoord,\n marginTop: 0,\n });\n }\n }\n else if (isFirstCol) {\n multiPlacements.push({\n seg: resliceSeg(seg, rect.span.start, rect.span.end, cells),\n isVisible: true,\n isAbsolute: false,\n absoluteTop: rect.levelCoord,\n marginTop: currentMarginTop, // claim the margin\n });\n currentMarginTop = 0;\n }\n }\n singleColPlacements.push(singlePlacements);\n multiColPlacements.push(multiPlacements);\n leftoverMargins.push(currentMarginTop);\n }\n return { singleColPlacements, multiColPlacements, leftoverMargins };\n}\nfunction groupRectsByEachCol(rects, colCnt) {\n let rectsByEachCol = [];\n for (let col = 0; col < colCnt; col += 1) {\n rectsByEachCol.push([]);\n }\n for (let rect of rects) {\n for (let col = rect.span.start; col < rect.span.end; col += 1) {\n rectsByEachCol[col].push(rect);\n }\n }\n return rectsByEachCol;\n}\nfunction resliceSeg(seg, spanStart, spanEnd, cells) {\n if (seg.firstCol === spanStart && seg.lastCol === spanEnd - 1) {\n return seg;\n }\n let eventRange = seg.eventRange;\n let origRange = eventRange.range;\n let slicedRange = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.o)(origRange, {\n start: cells[spanStart].date,\n end: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.t)(cells[spanEnd - 1].date, 1),\n });\n return Object.assign(Object.assign({}, seg), { firstCol: spanStart, lastCol: spanEnd - 1, eventRange: {\n def: eventRange.def,\n ui: Object.assign(Object.assign({}, eventRange.ui), { durationEditable: false }),\n instance: eventRange.instance,\n range: slicedRange,\n }, isStart: seg.isStart && slicedRange.start.valueOf() === origRange.start.valueOf(), isEnd: seg.isEnd && slicedRange.end.valueOf() === origRange.end.valueOf() });\n}\nclass DayGridSegHierarchy extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.by {\n constructor() {\n super(...arguments);\n // config\n this.hiddenConsumes = false;\n // allows us to keep hidden entries in the hierarchy so they take up space\n this.forceHidden = {};\n }\n addSegs(segInputs) {\n const hiddenSegs = super.addSegs(segInputs);\n const { entriesByLevel } = this;\n const excludeHidden = (entry) => !this.forceHidden[(0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bz)(entry)];\n // remove the forced-hidden segs\n for (let level = 0; level < entriesByLevel.length; level += 1) {\n entriesByLevel[level] = entriesByLevel[level].filter(excludeHidden);\n }\n return hiddenSegs;\n }\n handleInvalidInsertion(insertion, entry, hiddenEntries) {\n const { entriesByLevel, forceHidden } = this;\n const { touchingEntry, touchingLevel, touchingLateral } = insertion;\n // the entry that the new insertion is touching must be hidden\n if (this.hiddenConsumes && touchingEntry) {\n const touchingEntryId = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bz)(touchingEntry);\n if (!forceHidden[touchingEntryId]) {\n if (this.allowReslicing) {\n // split up the touchingEntry, reinsert it\n const hiddenEntry = Object.assign(Object.assign({}, touchingEntry), { span: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bD)(touchingEntry.span, entry.span) });\n // reinsert the area that turned into a \"more\" link (so no other entries try to\n // occupy the space) but mark it forced-hidden\n const hiddenEntryId = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bz)(hiddenEntry);\n forceHidden[hiddenEntryId] = true;\n entriesByLevel[touchingLevel][touchingLateral] = hiddenEntry;\n hiddenEntries.push(hiddenEntry);\n this.splitEntry(touchingEntry, entry, hiddenEntries);\n }\n else {\n forceHidden[touchingEntryId] = true;\n hiddenEntries.push(touchingEntry);\n }\n }\n }\n // will try to reslice...\n super.handleInvalidInsertion(insertion, entry, hiddenEntries);\n }\n}\n\nclass TableRow extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bc {\n constructor() {\n super(...arguments);\n this.cellElRefs = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cd(); // the <td>\n this.frameElRefs = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cd(); // the fc-daygrid-day-frame\n this.fgElRefs = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cd(); // the fc-daygrid-day-events\n this.segHarnessRefs = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cd(); // indexed by \"instanceId:firstCol\"\n this.rootElRef = (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createRef)();\n this.state = {\n framePositions: null,\n maxContentHeight: null,\n segHeights: {},\n };\n this.handleResize = (isForced) => {\n if (isForced) {\n this.updateSizing(true); // isExternal=true\n }\n };\n }\n render() {\n let { props, state, context } = this;\n let { options } = context;\n let colCnt = props.cells.length;\n let businessHoursByCol = splitSegsByFirstCol(props.businessHourSegs, colCnt);\n let bgEventSegsByCol = splitSegsByFirstCol(props.bgEventSegs, colCnt);\n let highlightSegsByCol = splitSegsByFirstCol(this.getHighlightSegs(), colCnt);\n let mirrorSegsByCol = splitSegsByFirstCol(this.getMirrorSegs(), colCnt);\n let { singleColPlacements, multiColPlacements, moreCnts, moreMarginTops } = computeFgSegPlacement((0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bP)(props.fgEventSegs, options.eventOrder), props.dayMaxEvents, props.dayMaxEventRows, options.eventOrderStrict, state.segHeights, state.maxContentHeight, props.cells);\n let isForcedInvisible = // TODO: messy way to compute this\n (props.eventDrag && props.eventDrag.affectedInstances) ||\n (props.eventResize && props.eventResize.affectedInstances) ||\n {};\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"tr\", { ref: this.rootElRef, role: \"row\" },\n props.renderIntro && props.renderIntro(),\n props.cells.map((cell, col) => {\n let normalFgNodes = this.renderFgSegs(col, props.forPrint ? singleColPlacements[col] : multiColPlacements[col], props.todayRange, isForcedInvisible);\n let mirrorFgNodes = this.renderFgSegs(col, buildMirrorPlacements(mirrorSegsByCol[col], multiColPlacements), props.todayRange, {}, Boolean(props.eventDrag), Boolean(props.eventResize), false);\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TableCell, { key: cell.key, elRef: this.cellElRefs.createRef(cell.key), innerElRef: this.frameElRefs.createRef(cell.key) /* FF <td> problem, but okay to use for left/right. TODO: rename prop */, dateProfile: props.dateProfile, date: cell.date, showDayNumber: props.showDayNumbers, showWeekNumber: props.showWeekNumbers && col === 0, forceDayTop: props.showWeekNumbers /* even displaying weeknum for row, not necessarily day */, todayRange: props.todayRange, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, extraRenderProps: cell.extraRenderProps, extraDataAttrs: cell.extraDataAttrs, extraClassNames: cell.extraClassNames, extraDateSpan: cell.extraDateSpan, moreCnt: moreCnts[col], moreMarginTop: moreMarginTops[col], singlePlacements: singleColPlacements[col], fgContentElRef: this.fgElRefs.createRef(cell.key), fgContent: ( // Fragment scopes the keys\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.Fragment, null,\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.Fragment, null, normalFgNodes),\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.Fragment, null, mirrorFgNodes))), bgContent: ( // Fragment scopes the keys\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.Fragment, null,\n this.renderFillSegs(highlightSegsByCol[col], 'highlight'),\n this.renderFillSegs(businessHoursByCol[col], 'non-business'),\n this.renderFillSegs(bgEventSegsByCol[col], 'bg-event'))), minHeight: props.cellMinHeight }));\n })));\n }\n componentDidMount() {\n this.updateSizing(true);\n this.context.addResizeHandler(this.handleResize);\n }\n componentDidUpdate(prevProps, prevState) {\n let currentProps = this.props;\n this.updateSizing(!(0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.E)(prevProps, currentProps));\n }\n componentWillUnmount() {\n this.context.removeResizeHandler(this.handleResize);\n }\n getHighlightSegs() {\n let { props } = this;\n if (props.eventDrag && props.eventDrag.segs.length) { // messy check\n return props.eventDrag.segs;\n }\n if (props.eventResize && props.eventResize.segs.length) { // messy check\n return props.eventResize.segs;\n }\n return props.dateSelectionSegs;\n }\n getMirrorSegs() {\n let { props } = this;\n if (props.eventResize && props.eventResize.segs.length) { // messy check\n return props.eventResize.segs;\n }\n return [];\n }\n renderFgSegs(col, segPlacements, todayRange, isForcedInvisible, isDragging, isResizing, isDateSelecting) {\n let { context } = this;\n let { eventSelection } = this.props;\n let { framePositions } = this.state;\n let defaultDisplayEventEnd = this.props.cells.length === 1; // colCnt === 1\n let isMirror = isDragging || isResizing || isDateSelecting;\n let nodes = [];\n if (framePositions) {\n for (let placement of segPlacements) {\n let { seg } = placement;\n let { instanceId } = seg.eventRange.instance;\n let isVisible = placement.isVisible && !isForcedInvisible[instanceId];\n let isAbsolute = placement.isAbsolute;\n let left = '';\n let right = '';\n if (isAbsolute) {\n if (context.isRtl) {\n right = 0;\n left = framePositions.lefts[seg.lastCol] - framePositions.lefts[seg.firstCol];\n }\n else {\n left = 0;\n right = framePositions.rights[seg.firstCol] - framePositions.rights[seg.lastCol];\n }\n }\n /*\n known bug: events that are force to be list-item but span multiple days still take up space in later columns\n todo: in print view, for multi-day events, don't display title within non-start/end segs\n */\n nodes.push((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: 'fc-daygrid-event-harness' + (isAbsolute ? ' fc-daygrid-event-harness-abs' : ''), key: generateSegKey(seg), ref: isMirror ? null : this.segHarnessRefs.createRef(generateSegUid(seg)), style: {\n visibility: isVisible ? '' : 'hidden',\n marginTop: isAbsolute ? '' : placement.marginTop,\n top: isAbsolute ? placement.absoluteTop : '',\n left,\n right,\n } }, hasListItemDisplay(seg) ? ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TableListItemEvent, Object.assign({ seg: seg, isDragging: isDragging, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bQ)(seg, todayRange)))) : ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TableBlockEvent, Object.assign({ seg: seg, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bQ)(seg, todayRange))))));\n }\n }\n return nodes;\n }\n renderFillSegs(segs, fillType) {\n let { isRtl } = this.context;\n let { todayRange } = this.props;\n let { framePositions } = this.state;\n let nodes = [];\n if (framePositions) {\n for (let seg of segs) {\n let leftRightCss = isRtl ? {\n right: 0,\n left: framePositions.lefts[seg.lastCol] - framePositions.lefts[seg.firstCol],\n } : {\n left: 0,\n right: framePositions.rights[seg.firstCol] - framePositions.rights[seg.lastCol],\n };\n nodes.push((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { key: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bR)(seg.eventRange), className: \"fc-daygrid-bg-harness\", style: leftRightCss }, fillType === 'bg-event' ?\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cm, Object.assign({ seg: seg }, (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bQ)(seg, todayRange))) :\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cl)(fillType)));\n }\n }\n return (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.Fragment, {}, ...nodes);\n }\n updateSizing(isExternalSizingChange) {\n let { props, state, frameElRefs } = this;\n if (!props.forPrint &&\n props.clientWidth !== null // positioning ready?\n ) {\n if (isExternalSizingChange) {\n let frameEls = props.cells.map((cell) => frameElRefs.currentMap[cell.key]);\n if (frameEls.length) {\n let originEl = this.rootElRef.current;\n let newPositionCache = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.b8(originEl, frameEls, true, // isHorizontal\n false);\n if (!state.framePositions || !state.framePositions.similarTo(newPositionCache)) {\n this.setState({\n framePositions: new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.b8(originEl, frameEls, true, // isHorizontal\n false),\n });\n }\n }\n }\n const oldSegHeights = this.state.segHeights;\n const newSegHeights = this.querySegHeights();\n const limitByContentHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;\n this.safeSetState({\n // HACK to prevent oscillations of events being shown/hidden from max-event-rows\n // Essentially, once you compute an element's height, never null-out.\n // TODO: always display all events, as visibility:hidden?\n segHeights: Object.assign(Object.assign({}, oldSegHeights), newSegHeights),\n maxContentHeight: limitByContentHeight ? this.computeMaxContentHeight() : null,\n });\n }\n }\n querySegHeights() {\n let segElMap = this.segHarnessRefs.currentMap;\n let segHeights = {};\n // get the max height amongst instance segs\n for (let segUid in segElMap) {\n let height = Math.round(segElMap[segUid].getBoundingClientRect().height);\n segHeights[segUid] = Math.max(segHeights[segUid] || 0, height);\n }\n return segHeights;\n }\n computeMaxContentHeight() {\n let firstKey = this.props.cells[0].key;\n let cellEl = this.cellElRefs.currentMap[firstKey];\n let fcContainerEl = this.fgElRefs.currentMap[firstKey];\n return cellEl.getBoundingClientRect().bottom - fcContainerEl.getBoundingClientRect().top;\n }\n getCellEls() {\n let elMap = this.cellElRefs.currentMap;\n return this.props.cells.map((cell) => elMap[cell.key]);\n }\n}\nTableRow.addStateEquality({\n segHeights: _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.E,\n});\nfunction buildMirrorPlacements(mirrorSegs, colPlacements) {\n if (!mirrorSegs.length) {\n return [];\n }\n let topsByInstanceId = buildAbsoluteTopHash(colPlacements); // TODO: cache this at first render?\n return mirrorSegs.map((seg) => ({\n seg,\n isVisible: true,\n isAbsolute: true,\n absoluteTop: topsByInstanceId[seg.eventRange.instance.instanceId],\n marginTop: 0,\n }));\n}\nfunction buildAbsoluteTopHash(colPlacements) {\n let topsByInstanceId = {};\n for (let placements of colPlacements) {\n for (let placement of placements) {\n topsByInstanceId[placement.seg.eventRange.instance.instanceId] = placement.absoluteTop;\n }\n }\n return topsByInstanceId;\n}\n\nclass TableRows extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bc {\n constructor() {\n super(...arguments);\n this.splitBusinessHourSegs = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(splitSegsByRow);\n this.splitBgEventSegs = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(splitAllDaySegsByRow);\n this.splitFgEventSegs = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(splitSegsByRow);\n this.splitDateSelectionSegs = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(splitSegsByRow);\n this.splitEventDrag = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(splitInteractionByRow);\n this.splitEventResize = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(splitInteractionByRow);\n this.rowRefs = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cd();\n }\n render() {\n let { props, context } = this;\n let rowCnt = props.cells.length;\n let businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, rowCnt);\n let bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, rowCnt);\n let fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, rowCnt);\n let dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, rowCnt);\n let eventDragByRow = this.splitEventDrag(props.eventDrag, rowCnt);\n let eventResizeByRow = this.splitEventResize(props.eventResize, rowCnt);\n // for DayGrid view with many rows, force a min-height on cells so doesn't appear squished\n // choose 7 because a month view will have max 6 rows\n let cellMinHeight = (rowCnt >= 7 && props.clientWidth) ?\n props.clientWidth / context.options.aspectRatio / 6 :\n null;\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.a6, { unit: \"day\" }, (nowDate, todayRange) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.Fragment, null, props.cells.map((cells, row) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TableRow, { ref: this.rowRefs.createRef(row), key: cells.length\n ? cells[0].date.toISOString() /* best? or put key on cell? or use diff formatter? */\n : row // in case there are no cells (like when resource view is loading)\n , showDayNumbers: rowCnt > 1, showWeekNumbers: props.showWeekNumbers, todayRange: todayRange, dateProfile: props.dateProfile, cells: cells, renderIntro: props.renderRowIntro, businessHourSegs: businessHourSegsByRow[row], eventSelection: props.eventSelection, bgEventSegs: bgEventSegsByRow[row], fgEventSegs: fgEventSegsByRow[row], dateSelectionSegs: dateSelectionSegsByRow[row], eventDrag: eventDragByRow[row], eventResize: eventResizeByRow[row], dayMaxEvents: props.dayMaxEvents, dayMaxEventRows: props.dayMaxEventRows, clientWidth: props.clientWidth, clientHeight: props.clientHeight, cellMinHeight: cellMinHeight, forPrint: props.forPrint })))))));\n }\n componentDidMount() {\n this.registerInteractiveComponent();\n }\n componentDidUpdate() {\n // for if started with zero cells\n this.registerInteractiveComponent();\n }\n registerInteractiveComponent() {\n if (!this.rootEl) {\n // HACK: need a daygrid wrapper parent to do positioning\n // NOTE: a daygrid resource view w/o resources can have zero cells\n const firstCellEl = this.rowRefs.currentMap[0].getCellEls()[0];\n const rootEl = firstCellEl ? firstCellEl.closest('.fc-daygrid-body') : null;\n if (rootEl) {\n this.rootEl = rootEl;\n this.context.registerInteractiveComponent(this, {\n el: rootEl,\n isHitComboAllowed: this.props.isHitComboAllowed,\n });\n }\n }\n }\n componentWillUnmount() {\n if (this.rootEl) {\n this.context.unregisterInteractiveComponent(this);\n this.rootEl = null;\n }\n }\n // Hit System\n // ----------------------------------------------------------------------------------------------------\n prepareHits() {\n this.rowPositions = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.b8(this.rootEl, this.rowRefs.collect().map((rowObj) => rowObj.getCellEls()[0]), // first cell el in each row. TODO: not optimal\n false, true);\n this.colPositions = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.b8(this.rootEl, this.rowRefs.currentMap[0].getCellEls(), // cell els in first row\n true, // horizontal\n false);\n }\n queryHit(positionLeft, positionTop) {\n let { colPositions, rowPositions } = this;\n let col = colPositions.leftToIndex(positionLeft);\n let row = rowPositions.topToIndex(positionTop);\n if (row != null && col != null) {\n let cell = this.props.cells[row][col];\n return {\n dateProfile: this.props.dateProfile,\n dateSpan: Object.assign({ range: this.getCellRange(row, col), allDay: true }, cell.extraDateSpan),\n dayEl: this.getCellEl(row, col),\n rect: {\n left: colPositions.lefts[col],\n right: colPositions.rights[col],\n top: rowPositions.tops[row],\n bottom: rowPositions.bottoms[row],\n },\n layer: 0,\n };\n }\n return null;\n }\n getCellEl(row, col) {\n return this.rowRefs.currentMap[row].getCellEls()[col]; // TODO: not optimal\n }\n getCellRange(row, col) {\n let start = this.props.cells[row][col].date;\n let end = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.t)(start, 1);\n return { start, end };\n }\n}\nfunction splitAllDaySegsByRow(segs, rowCnt) {\n return splitSegsByRow(segs.filter(isSegAllDay), rowCnt);\n}\nfunction isSegAllDay(seg) {\n return seg.eventRange.def.allDay;\n}\n\nclass Table extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bc {\n constructor() {\n super(...arguments);\n this.elRef = (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createRef)();\n this.needsScrollReset = false;\n }\n render() {\n let { props } = this;\n let { dayMaxEventRows, dayMaxEvents, expandRows } = props;\n let limitViaBalanced = dayMaxEvents === true || dayMaxEventRows === true;\n // if rows can't expand to fill fixed height, can't do balanced-height event limit\n // TODO: best place to normalize these options?\n if (limitViaBalanced && !expandRows) {\n limitViaBalanced = false;\n dayMaxEventRows = null;\n dayMaxEvents = null;\n }\n let classNames = [\n 'fc-daygrid-body',\n limitViaBalanced ? 'fc-daygrid-body-balanced' : 'fc-daygrid-body-unbalanced',\n expandRows ? '' : 'fc-daygrid-body-natural', // will height of one row depend on the others?\n ];\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { ref: this.elRef, className: classNames.join(' '), style: {\n // these props are important to give this wrapper correct dimensions for interactions\n // TODO: if we set it here, can we avoid giving to inner tables?\n width: props.clientWidth,\n minWidth: props.tableMinWidth,\n } },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"table\", { role: \"presentation\", className: \"fc-scrollgrid-sync-table\", style: {\n width: props.clientWidth,\n minWidth: props.tableMinWidth,\n height: expandRows ? props.clientHeight : '',\n } },\n props.colGroupNode,\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"tbody\", { role: \"presentation\" },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TableRows, { dateProfile: props.dateProfile, cells: props.cells, renderRowIntro: props.renderRowIntro, showWeekNumbers: props.showWeekNumbers, clientWidth: props.clientWidth, clientHeight: props.clientHeight, businessHourSegs: props.businessHourSegs, bgEventSegs: props.bgEventSegs, fgEventSegs: props.fgEventSegs, dateSelectionSegs: props.dateSelectionSegs, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, dayMaxEvents: dayMaxEvents, dayMaxEventRows: dayMaxEventRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed })))));\n }\n componentDidMount() {\n this.requestScrollReset();\n }\n componentDidUpdate(prevProps) {\n if (prevProps.dateProfile !== this.props.dateProfile) {\n this.requestScrollReset();\n }\n else {\n this.flushScrollReset();\n }\n }\n requestScrollReset() {\n this.needsScrollReset = true;\n this.flushScrollReset();\n }\n flushScrollReset() {\n if (this.needsScrollReset &&\n this.props.clientWidth // sizes computed?\n ) {\n const subjectEl = getScrollSubjectEl(this.elRef.current, this.props.dateProfile);\n if (subjectEl) {\n const originEl = subjectEl.closest('.fc-daygrid-body');\n const scrollEl = originEl.closest('.fc-scroller');\n const scrollTop = subjectEl.getBoundingClientRect().top -\n originEl.getBoundingClientRect().top;\n scrollEl.scrollTop = scrollTop ? (scrollTop + 1) : 0; // overcome border\n }\n this.needsScrollReset = false;\n }\n }\n}\nfunction getScrollSubjectEl(containerEl, dateProfile) {\n let el;\n if (dateProfile.currentRangeUnit.match(/year|month/)) {\n el = containerEl.querySelector(`[data-date=\"${(0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bv)(dateProfile.currentDate)}-01\"]`);\n // even if view is month-based, first-of-month might be hidden...\n }\n if (!el) {\n el = containerEl.querySelector(`[data-date=\"${(0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bt)(dateProfile.currentDate)}\"]`);\n // could still be hidden if an interior-view hidden day\n }\n return el;\n}\n\nclass DayTableSlicer extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bU {\n constructor() {\n super(...arguments);\n this.forceDayIfListItem = true;\n }\n sliceRange(dateRange, dayTableModel) {\n return dayTableModel.sliceRange(dateRange);\n }\n}\n\nclass DayTable extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bc {\n constructor() {\n super(...arguments);\n this.slicer = new DayTableSlicer();\n this.tableRef = (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createRef)();\n }\n render() {\n let { props, context } = this;\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(Table, Object.assign({ ref: this.tableRef }, this.slicer.sliceProps(props, props.dateProfile, props.nextDayThreshold, context, props.dayTableModel), { dateProfile: props.dateProfile, cells: props.dayTableModel.cells, colGroupNode: props.colGroupNode, tableMinWidth: props.tableMinWidth, renderRowIntro: props.renderRowIntro, dayMaxEvents: props.dayMaxEvents, dayMaxEventRows: props.dayMaxEventRows, showWeekNumbers: props.showWeekNumbers, expandRows: props.expandRows, headerAlignElRef: props.headerAlignElRef, clientWidth: props.clientWidth, clientHeight: props.clientHeight, forPrint: props.forPrint })));\n }\n}\n\nclass DayTableView extends TableView {\n constructor() {\n super(...arguments);\n this.buildDayTableModel = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(buildDayTableModel);\n this.headerRef = (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createRef)();\n this.tableRef = (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createRef)();\n // can't override any lifecycle methods from parent\n }\n render() {\n let { options, dateProfileGenerator } = this.context;\n let { props } = this;\n let dayTableModel = this.buildDayTableModel(props.dateProfile, dateProfileGenerator);\n let headerContent = options.dayHeaders && ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bI, { ref: this.headerRef, dateProfile: props.dateProfile, dates: dayTableModel.headerDates, datesRepDistinctDays: dayTableModel.rowCnt === 1 }));\n let bodyContent = (contentArg) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(DayTable, { ref: this.tableRef, dateProfile: props.dateProfile, dayTableModel: dayTableModel, businessHours: props.businessHours, dateSelection: props.dateSelection, eventStore: props.eventStore, eventUiBases: props.eventUiBases, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, nextDayThreshold: options.nextDayThreshold, colGroupNode: contentArg.tableColGroupNode, tableMinWidth: contentArg.tableMinWidth, dayMaxEvents: options.dayMaxEvents, dayMaxEventRows: options.dayMaxEventRows, showWeekNumbers: options.weekNumbers, expandRows: !props.isHeightAuto, headerAlignElRef: this.headerElRef, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, forPrint: props.forPrint }));\n return options.dayMinWidth\n ? this.renderHScrollLayout(headerContent, bodyContent, dayTableModel.colCnt, options.dayMinWidth)\n : this.renderSimpleLayout(headerContent, bodyContent);\n }\n}\nfunction buildDayTableModel(dateProfile, dateProfileGenerator) {\n let daySeries = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bM(dateProfile.renderRange, dateProfileGenerator);\n return new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bT(daySeries, /year|month|week/.test(dateProfile.currentRangeUnit));\n}\n\nclass TableDateProfileGenerator extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.R {\n // Computes the date range that will be rendered\n buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay) {\n let renderRange = super.buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay);\n let { props } = this;\n return buildDayTableRenderRange({\n currentRange: renderRange,\n snapToWeek: /^(year|month)$/.test(currentRangeUnit),\n fixedWeekCount: props.fixedWeekCount,\n dateEnv: props.dateEnv,\n });\n }\n}\nfunction buildDayTableRenderRange(props) {\n let { dateEnv, currentRange } = props;\n let { start, end } = currentRange;\n let endOfWeek;\n // year and month views should be aligned with weeks. this is already done for week\n if (props.snapToWeek) {\n start = dateEnv.startOfWeek(start);\n // make end-of-week if not already\n endOfWeek = dateEnv.startOfWeek(end);\n if (endOfWeek.valueOf() !== end.valueOf()) {\n end = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bf)(endOfWeek, 1);\n }\n }\n // ensure 6 weeks\n if (props.fixedWeekCount) {\n // TODO: instead of these date-math gymnastics (for multimonth view),\n // compute dateprofiles of all months, then use start of first and end of last.\n let lastMonthRenderStart = dateEnv.startOfWeek(dateEnv.startOfMonth((0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.t)(currentRange.end, -1)));\n let rowCnt = Math.ceil(// could be partial weeks due to hiddenDays\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bg)(lastMonthRenderStart, end));\n end = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bf)(end, 6 - rowCnt);\n }\n return { start, end };\n}\n\nvar css_248z = \":root{--fc-daygrid-event-dot-width:8px}.fc-daygrid-day-events:after,.fc-daygrid-day-events:before,.fc-daygrid-day-frame:after,.fc-daygrid-day-frame:before,.fc-daygrid-event-harness:after,.fc-daygrid-event-harness:before{clear:both;content:\\\"\\\";display:table}.fc .fc-daygrid-body{position:relative;z-index:1}.fc .fc-daygrid-day.fc-day-today{background-color:var(--fc-today-bg-color)}.fc .fc-daygrid-day-frame{min-height:100%;position:relative}.fc .fc-daygrid-day-top{display:flex;flex-direction:row-reverse}.fc .fc-day-other .fc-daygrid-day-top{opacity:.3}.fc .fc-daygrid-day-number{padding:4px;position:relative;z-index:4}.fc .fc-daygrid-month-start{font-size:1.1em;font-weight:700}.fc .fc-daygrid-day-events{margin-top:1px}.fc .fc-daygrid-body-balanced .fc-daygrid-day-events{left:0;position:absolute;right:0}.fc .fc-daygrid-body-unbalanced .fc-daygrid-day-events{min-height:2em;position:relative}.fc .fc-daygrid-body-natural .fc-daygrid-day-events{margin-bottom:1em}.fc .fc-daygrid-event-harness{position:relative}.fc .fc-daygrid-event-harness-abs{left:0;position:absolute;right:0;top:0}.fc .fc-daygrid-bg-harness{bottom:0;position:absolute;top:0}.fc .fc-daygrid-day-bg .fc-non-business{z-index:1}.fc .fc-daygrid-day-bg .fc-bg-event{z-index:2}.fc .fc-daygrid-day-bg .fc-highlight{z-index:3}.fc .fc-daygrid-event{margin-top:1px;z-index:6}.fc .fc-daygrid-event.fc-event-mirror{z-index:7}.fc .fc-daygrid-day-bottom{font-size:.85em;margin:0 2px}.fc .fc-daygrid-day-bottom:after,.fc .fc-daygrid-day-bottom:before{clear:both;content:\\\"\\\";display:table}.fc .fc-daygrid-more-link{border-radius:3px;cursor:pointer;line-height:1;margin-top:1px;max-width:100%;overflow:hidden;padding:2px;position:relative;white-space:nowrap;z-index:4}.fc .fc-daygrid-more-link:hover{background-color:rgba(0,0,0,.1)}.fc .fc-daygrid-week-number{background-color:var(--fc-neutral-bg-color);color:var(--fc-neutral-text-color);min-width:1.5em;padding:2px;position:absolute;text-align:center;top:0;z-index:5}.fc .fc-more-popover .fc-popover-body{min-width:220px;padding:10px}.fc-direction-ltr .fc-daygrid-event.fc-event-start,.fc-direction-rtl .fc-daygrid-event.fc-event-end{margin-left:2px}.fc-direction-ltr .fc-daygrid-event.fc-event-end,.fc-direction-rtl .fc-daygrid-event.fc-event-start{margin-right:2px}.fc-direction-ltr .fc-daygrid-more-link{float:left}.fc-direction-ltr .fc-daygrid-week-number{border-radius:0 0 3px 0;left:0}.fc-direction-rtl .fc-daygrid-more-link{float:right}.fc-direction-rtl .fc-daygrid-week-number{border-radius:0 0 0 3px;right:0}.fc-liquid-hack .fc-daygrid-day-frame{position:static}.fc-daygrid-event{border-radius:3px;font-size:var(--fc-small-font-size);position:relative;white-space:nowrap}.fc-daygrid-block-event .fc-event-time{font-weight:700}.fc-daygrid-block-event .fc-event-time,.fc-daygrid-block-event .fc-event-title{padding:1px}.fc-daygrid-dot-event{align-items:center;display:flex;padding:2px 0}.fc-daygrid-dot-event .fc-event-title{flex-grow:1;flex-shrink:1;font-weight:700;min-width:0;overflow:hidden}.fc-daygrid-dot-event.fc-event-mirror,.fc-daygrid-dot-event:hover{background:rgba(0,0,0,.1)}.fc-daygrid-dot-event.fc-event-selected:before{bottom:-10px;top:-10px}.fc-daygrid-event-dot{border:calc(var(--fc-daygrid-event-dot-width)/2) solid var(--fc-event-border-color);border-radius:calc(var(--fc-daygrid-event-dot-width)/2);box-sizing:content-box;height:0;margin:0 4px;width:0}.fc-direction-ltr .fc-daygrid-event .fc-event-time{margin-right:3px}.fc-direction-rtl .fc-daygrid-event .fc-event-time{margin-left:3px}\";\n(0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ct)(css_248z);\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKHNzcikvLi9ub2RlX21vZHVsZXMvQGZ1bGxjYWxlbmRhci9kYXlncmlkL2ludGVybmFsLmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7O0FBQTZ0QjtBQUMzb0I7O0FBRWxGO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCLDhEQUFhO0FBQ3JDO0FBQ0E7QUFDQSwyQkFBMkIsdUVBQVM7QUFDcEM7QUFDQTtBQUNBLGNBQWMsaUJBQWlCO0FBQy9CO0FBQ0EsZ0NBQWdDLGtFQUFvQjtBQUNwRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakIsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUIsc0JBQXNCO0FBQzNDLFNBQVM7QUFDVCxnQkFBZ0IsMkVBQWEsQ0FBQyw4REFBYSxJQUFJLHVEQUF1RDtBQUN0RyxZQUFZLDJFQUFhLENBQUMsOERBQWdCLElBQUksMklBQTJJO0FBQ3pMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsaUJBQWlCO0FBQy9CLG1EQUFtRCxrRUFBb0I7QUFDdkUsdURBQXVELGtFQUF3QjtBQUMvRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCO0FBQ3JCLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlDQUFpQyw4REFBZ0I7QUFDakQscUJBQXFCO0FBQ3JCLGFBQWE7QUFDYjtBQUNBLGdCQUFnQiwyRUFBYSxDQUFDLDhEQUFhLElBQUksdURBQXVEO0FBQ3RHLFlBQVksMkVBQWEsZUFBZSwwSEFBMEgsU0FBUyxxQ0FBcUMsR0FBRyx1QkFBdUI7QUFDMU87QUFDQTs7QUFFQTtBQUNBO0FBQ0Esb0JBQW9CLFlBQVk7QUFDaEM7QUFD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QUFRLE1BQU0sMkJBQTJCLFNBQVMsa0JBQWtCLE1BQU0sd0NBQXdDLFVBQVUsb0NBQW9DLFVBQVUscUNBQXFDLFVBQVUsc0JBQXNCLGVBQWUsVUFBVSxzQ0FBc0MsVUFBVSwyQkFBMkIsZ0JBQWdCLGFBQWEsbUVBQW1FLFdBQVcsYUFBYSxjQUFjLDBCQUEwQixrQkFBa0IsZUFBZSxjQUFjLGVBQWUsZUFBZSxnQkFBZ0IsWUFBWSxrQkFBa0IsbUJBQW1CLFVBQVUsZ0NBQWdDLGdDQUFnQyw0QkFBNEIsNENBQTRDLG1DQUFtQyxnQkFBZ0IsWUFBWSxrQkFBa0Isa0JBQWtCLE1BQU0sVUFBVSxzQ0FBc0MsZ0JBQWdCLGFBQWEsb0dBQW9HLGdCQUFnQixvR0FBb0csaUJBQWlCLHdDQUF3QyxXQUFXLDBDQUEwQyx3QkFBd0IsT0FBTyx3Q0FBd0MsWUFBWSwwQ0FBMEMsd0JBQXdCLFFBQVEsc0NBQXNDLGdCQUFnQixrQkFBa0Isa0JBQWtCLG9DQUFvQyxrQkFBa0IsbUJBQW1CLHVDQUF1QyxnQkFBZ0IsK0VBQStFLFlBQVksc0JBQXNCLG1CQUFtQixhQUFhLGNBQWMsc0NBQXNDLFlBQVksY0FBYyxnQkFBZ0IsWUFBWSxnQkFBZ0Isa0VBQWtFLDBCQUEwQiwrQ0FBK0MsYUFBYSxVQUFVLHNCQUFzQixvRkFBb0Ysd0RBQXdELHVCQUF1QixTQUFTLGFBQWEsUUFBUSxtREFBbUQsaUJBQWlCLG1EQUFtRCxnQkFBZ0I7QUFDcDlHLGtFQUFZOztBQUUySiIsInNvdXJjZXMiOlsiL2hvbWUvc2lsdmlvL0RldmVsb3AvQ0lSVVgtQVBQL25vZGVfbW9kdWxlcy9AZnVsbGNhbGVuZGFyL2RheWdyaWQvaW50ZXJuYWwuanMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRGF0ZUNvbXBvbmVudCwgZ2V0U3RpY2t5SGVhZGVyRGF0ZXMsIFZpZXdDb250YWluZXIsIFNpbXBsZVNjcm9sbEdyaWQsIGdldFN0aWNreUZvb3RlclNjcm9sbGJhciwgcmVuZGVyU2Nyb2xsU2hpbSwgY3JlYXRlRm9ybWF0dGVyLCBCYXNlQ29tcG9uZW50LCBTdGFuZGFyZEV2ZW50LCBidWlsZFNlZ1RpbWVUZXh0LCBFdmVudENvbnRhaW5lciwgZ2V0U2VnQW5jaG9yQXR0cnMsIG1lbW9pemUsIE1vcmVMaW5rQ29udGFpbmVyLCBnZXRTZWdNZXRhLCBnZXRVbmlxdWVEb21JZCwgc2V0UmVmLCBEYXlDZWxsQ29udGFpbmVyLCBXZWVrTnVtYmVyQ29udGFpbmVyLCBidWlsZE5hdkxpbmtBdHRycywgaGFzQ3VzdG9tRGF5Q2VsbENvbnRlbnQsIGFkZE1zLCBpbnRlcnNlY3RSYW5nZXMsIGFkZERheXMsIFNlZ0hpZXJhcmNoeSwgYnVpbGRFbnRyeUtleSwgaW50ZXJzZWN0U3BhbnMsIFJlZk1hcCwgc29ydEV2ZW50U2VncywgaXNQcm9wc0VxdWFsLCBidWlsZEV2ZW50UmFuZ2VLZXksIEJnRXZlbnQsIHJlbmRlckZpbGwsIFBvc2l0aW9uQ2FjaGUsIE5vd1RpbWVyLCBmb3JtYXRJc29Nb250aFN0ciwgZm9ybWF0RGF5U3RyaW5nLCBTbGljZXIsIERheUhlYWRlciwgRGF5U2VyaWVzTW9kZWwsIERheVRhYmxlTW9kZWwsIERhdGVQcm9maWxlR2VuZXJhdG9yLCBhZGRXZWVrcywgZGlmZldlZWtzLCBpbmplY3RTdHlsZXMgfSBmcm9tICdAZnVsbGNhbGVuZGFyL2NvcmUvaW50ZXJuYWwuanMnO1xuaW1wb3J0IHsgY3JlYXRlUmVmLCBjcmVhdGVFbGVtZW50LCBGcmFnbWVudCB9IGZyb20gJ0BmdWxsY2FsZW5kYXIvY29yZS9wcmVhY3QuanMnO1xuXG4vKiBBbiBhYnN0cmFjdCBjbGFzcyBmb3IgdGhlIGRheWdyaWQgdmlld3MsIGFzIHdlbGwgYXMgbW9udGggdmlldy4gUmVuZGVycyBvbmUgb3IgbW9yZSByb3dzIG9mIGRheSBjZWxscy5cbi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuLy8gSXQgaXMgYSBtYW5hZ2VyIGZvciBhIFRhYmxlIHN1YmNvbXBvbmVudCwgd2hpY2ggZG9lcyBtb3N0IG9mIHRoZSBoZWF2eSBsaWZ0aW5nLlxuLy8gSXQgaXMgcmVzcG9uc2libGUgZm9yIG1hbmFnaW5nIHdpZHRoL2hlaWdodC5cbmNsYXNzIFRhYmxlVmlldyBleHRlbmRzIERhdGVDb21wb25lbnQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICB0aGlzLmhlYWRlckVsUmVmID0gY3JlYXRlUmVmKCk7XG4gICAgfVxuICAgIHJlbmRlclNpbXBsZUxheW91dChoZWFkZXJSb3dDb250ZW50LCBib2R5Q29udGVudCkge1xuICAgICAgICBsZXQgeyBwcm9wcywgY29udGV4dCB9ID0gdGhpcztcbiAgICAgICAgbGV0IHNlY3Rpb25zID0gW107XG4gICAgICAgIGxldCBzdGlja3lIZWFkZXJEYXRlcyA9IGdldFN0aWNreUhlYWRlckRhdGVzKGNvbnRleHQub3B0aW9ucyk7XG4gICAgICAgIGlmIChoZWFkZXJSb3dDb250ZW50KSB7XG4gICAgICAgICAgICBzZWN0aW9ucy5wdXNoKHtcbiAgICAgICAgICAgICAgICB0eXBlOiAnaGVhZGVyJyxcbiAgICAgICAgICAgICAgICBrZXk6ICdoZWFkZXInLFxuICAgICAgICAgICAgICAgIGlzU3RpY2t5OiBzdGlja3lIZWFkZXJEYXRlcyxcbiAgICAgICAgICAgICAgICBjaHVuazoge1xuICAgICAgICAgICAgICAgICAgICBlbFJlZjogdGhpcy5oZWFkZXJFbFJlZixcbiAgICAgICAgICAgICAgICAgICAgdGFibGVDbGFzc05hbWU6ICdmYy1jb2wtaGVhZGVyJyxcbiAgICAgICAgICAgICAgICAgICAgcm93Q29udGVudDogaGVhZGVyUm93Q29udGVudCxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgc2VjdGlvbnMucHVzaCh7XG4gICAgICAgICAgICB0eXBlOiAnYm9keScsXG4gICAgICAgICAgICBrZXk6ICdib2R5JyxcbiAgICAgICAgICAgIGxpcXVpZDogdHJ1ZSxcbiAgICAgICAgICAgIGNodW5rOiB7IGNvbnRlbnQ6IGJvZHlDb250ZW50IH0sXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoVmlld0NvbnRhaW5lciwgeyBlbENsYXNzZXM6IFsnZmMtZGF5Z3JpZCddLCB2aWV3U3BlYzogY29udGV4dC52aWV3U3BlYyB9LFxuICAgICAgICAgICAgY3JlYXRlRWxlbWVudChTaW1wbGVTY3JvbGxHcmlkLCB7IGxpcXVpZDogIXByb3BzLmlzSGVpZ2h0QXV0byAmJiAhcHJvcHMuZm9yUHJpbnQsIGNvbGxhcHNpYmxlV2lkdGg6IHByb3BzLmZvclByaW50LCBjb2xzOiBbXSAvKiBUT0RPOiBtYWtlIG9wdGlvbmFsPyAqLywgc2VjdGlvbnM6IHNlY3Rpb25zIH0pKSk7XG4gICAgfVxuICAgIHJlbmRlckhTY3JvbGxMYXlvdXQoaGVhZGVyUm93Q29udGVudCwgYm9keUNvbnRlbnQsIGNvbENudCwgZGF5TWluV2lkdGgpIHtcbiAgICAgICAgbGV0IFNjcm9sbEdyaWQgPSB0aGlzLmNvbnRleHQucGx1Z2luSG9va3Muc2Nyb2xsR3JpZEltcGw7XG4gICAgICAgIGlmICghU2Nyb2xsR3JpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBTY3JvbGxHcmlkIGltcGxlbWVudGF0aW9uJyk7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHsgcHJvcHMsIGNvbnRleHQgfSA9IHRoaXM7XG4gICAgICAgIGxldCBzdGlja3lIZWFkZXJEYXRlcyA9ICFwcm9wcy5mb3JQcmludCAmJiBnZXRTdGlja3lIZWFkZXJEYXRlcyhjb250ZXh0Lm9wdGlvbnMpO1xuICAgICAgICBsZXQgc3RpY2t5Rm9vdGVyU2Nyb2xsYmFyID0gIXByb3BzLmZvclByaW50ICYmIGdldFN0aWNreUZvb3RlclNjcm9sbGJhcihjb250ZXh0Lm9wdGlvbnMpO1xuICAgICAgICBsZXQgc2VjdGlvbnMgPSBbXTtcbiAgICAgICAgaWYgKGhlYWRlclJvd0NvbnRlbnQpIHtcbiAgICAgICAgICAgIHNlY3Rpb25zLnB1c2goe1xuICAgICAgICAgICAgICAgIHR5cGU6ICdoZWFkZXInLFxuICAgICAgICAgICAgICAgIGtleTogJ2hlYWRlcicsXG4gICAgICAgICAgICAgICAgaXNTdGlja3k6IHN0aWNreUhlYWRlckRhdGVzLFxuICAgICAgICAgICAgICAgIGNodW5rczogW3tcbiAgICAgICAgICAgICAgICAgICAgICAgIGtleTogJ21haW4nLFxuICAgICAgICAgICAgICAgICAgICAgICAgZWxSZWY6IHRoaXMuaGVhZGVyRWxSZWYsXG4gICAgICAgICAgICAgICAgICAgICAgICB0YWJsZUNsYXNzTmFtZTogJ2ZjLWNvbC1oZWFkZXInLFxuICAgICAgICAgICAgICAgICAgICAgICAgcm93Q29udGVudDogaGVhZGVyUm93Q29udGVudCxcbiAgICAgICAgICAgICAgICAgICAgfV0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBzZWN0aW9ucy5wdXNoKHtcbiAgICAgICAgICAgIHR5cGU6ICdib2R5JyxcbiAgICAgICAgICAgIGtleTogJ2JvZHknLFxuICAgICAgICAgICAgbGlxdWlkOiB0cnVlLFxuICAgICAgICAgICAgY2h1bmtzOiBbe1xuICAgICAgICAgICAgICAgICAgICBrZXk6ICdtYWluJyxcbiAgICAgICAgICAgICAgICAgICAgY29udGVudDogYm9keUNvbnRlbnQsXG4gICAgICAgICAgICAgICAgfV0sXG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoc3RpY2t5Rm9vdGVyU2Nyb2xsYmFyKSB7XG4gICAgICAgICAgICBzZWN0aW9ucy5wdXNoKHtcbiAgICAgICAgICAgICAgICB0eXBlOiAnZm9vdGVyJyxcbiAgICAgICAgICAgICAgICBrZXk6ICdmb290ZXInLFxuICAgICAgICAgICAgICAgIGlzU3RpY2t5OiB0cnVlLFxuICAgICAgICAgICAgICAgIGNodW5rczogW3tcbiAgICAgICAgICAgICAgICAgICAgICAgIGtleTogJ21haW4nLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29udGVudDogcmVuZGVyU2Nyb2xsU2hpbSxcbiAgICAgICAgICAgICAgICAgICAgfV0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoVmlld0NvbnRhaW5lciwgeyBlbENsYXNzZXM6IFsnZmMtZGF5Z3JpZCddLCB2aWV3U3BlYzogY29udGV4dC52aWV3U3BlYyB9LFxuICAgICAgICAgICAgY3JlYXRlRWxlbWVudChTY3JvbGxHcmlkLCB7IGxpcXVpZDogIXByb3BzLmlzSGVpZ2h0QXV0byAmJiAhcHJvcHMuZm9yUHJpbnQsIGZvclByaW50OiBwcm9wcy5mb3JQcmludCwgY29sbGFwc2libGVXaWR0aDogcHJvcHMuZm9yUHJpbnQsIGNvbEdyb3VwczogW3sgY29sczogW3sgc3BhbjogY29sQ250LCBtaW5XaWR0aDogZGF5TWluV2lkdGggfV0gfV0sIHNlY3Rpb25zOiBzZWN0aW9ucyB9KSkpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gc3BsaXRTZWdzQnlSb3coc2Vncywgcm93Q250KSB7XG4gICAgbGV0IGJ5Um93ID0gW107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCByb3dDbnQ7IGkgKz0gMSkge1xuICAgICAgICBieVJvd1tpXSA9IFtdO1xuICAgIH1cbiAgICBmb3IgKGxldCBzZWcgb2Ygc2Vncykge1xuICAgICAgICBieVJvd1tzZWcucm93XS5wdXNoKHNlZyk7XG4gICAgfVxuICAgIHJldHVybiBieVJvdztcbn1cbmZ1bmN0aW9uIHNwbGl0U2Vnc0J5Rmlyc3RDb2woc2VncywgY29sQ250KSB7XG4gICAgbGV0IGJ5Q29sID0gW107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjb2xDbnQ7IGkgKz0gMSkge1xuICAgICAgICBieUNvbFtpXSA9IFtdO1xuICAgIH1cbiAgICBmb3IgKGxldCBzZWcgb2Ygc2Vncykge1xuICAgICAgICBieUNvbFtzZWcuZmlyc3RDb2xdLnB1c2goc2VnKTtcbiAgICB9XG4gICAgcmV0dXJuIGJ5Q29sO1xufVxuZnVuY3Rpb24gc3BsaXRJbnRlcmFjdGlvbkJ5Um93KHVpLCByb3dDbnQpIHtcbiAgICBsZXQgYnlSb3cgPSBbXTtcbiAgICBpZiAoIXVpKSB7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcm93Q250OyBpICs9IDEpIHtcbiAgICAgICAgICAgIGJ5Um93W2ldID0gbnVsbDtcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCByb3dDbnQ7IGkgKz0gMSkge1xuICAgICAgICAgICAgYnlSb3dbaV0gPSB7XG4gICAgICAgICAgICAgICAgYWZmZWN0ZWRJbnN0YW5jZXM6IHVpLmFmZmVjdGVkSW5zdGFuY2VzLFxuICAgICAgICAgICAgICAgIGlzRXZlbnQ6IHVpLmlzRXZlbnQsXG4gICAgICAgICAgICAgICAgc2VnczogW10sXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIGZvciAobGV0IHNlZyBvZiB1aS5zZWdzKSB7XG4gICAgICAgICAgICBieVJvd1tzZWcucm93XS5zZWdzLnB1c2goc2VnKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gYnlSb3c7XG59XG5cbmNvbnN0IERFRkFVTFRfVEFCTEVfRVZFTlRfVElNRV9GT1JNQVQgPSBjcmVhdGVGb3JtYXR0ZXIoe1xuICAgIGhvdXI6ICdudW1lcmljJyxcbiAgICBtaW51dGU6ICcyLWRpZ2l0JyxcbiAgICBvbWl0WmVyb01pbnV0ZTogdHJ1ZSxcbiAgICBtZXJpZGllbTogJ25hcnJvdycsXG59KTtcbmZ1bmN0aW9uIGhhc0xpc3RJdGVtRGlzcGxheShzZWcpIHtcbiAgICBsZXQgeyBkaXNwbGF5IH0gPSBzZWcuZXZlbnRSYW5nZS51aTtcbiAgICByZXR1cm4gZGlzcGxheSA9PT0gJ2xpc3QtaXRlbScgfHwgKGRpc3BsYXkgPT09ICdhdXRvJyAmJlxuICAgICAgICAhc2VnLmV2ZW50UmFuZ2UuZGVmLmFsbERheSAmJlxuICAgICAgICBzZWcuZmlyc3RDb2wgPT09IHNlZy5sYXN0Q29sICYmIC8vIGNhbid0IGJlIG11bHRpLWRheVxuICAgICAgICBzZWcuaXNTdGFydCAmJiAvLyBcIlxuICAgICAgICBzZWcuaXNFbmQgLy8gXCJcbiAgICApO1xufVxuXG5jbGFzcyBUYWJsZUJsb2NrRXZlbnQgZXh0ZW5kcyBCYXNlQ29tcG9uZW50IHtcbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGxldCB7IHByb3BzIH0gPSB0aGlzO1xuICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoU3RhbmRhcmRFdmVudCwgT2JqZWN0LmFzc2lnbih7fSwgcHJvcHMsIHsgZWxDbGFzc2VzOiBbJ2ZjLWRheWdyaWQtZXZlbnQnLCAnZmMtZGF5Z3JpZC1ibG9jay1ldmVudCcsICdmYy1oLWV2ZW50J10sIGRlZmF1bHRUaW1lRm9ybWF0OiBERUZBVUxUX1RBQkxFX0VWRU5UX1RJTUVfRk9STUFULCBkZWZhdWx0RGlzcGxheUV2ZW50RW5kOiBwcm9wcy5kZWZhdWx0RGlzcGxheUV2ZW50RW5kLCBkaXNhYmxlUmVzaXppbmc6ICFwcm9wcy5zZWcuZXZlbnRSYW5nZS5kZWYuYWxsRGF5IH0pKSk7XG4gICAgfVxufVxuXG5jbGFzcyBUYWJsZUxpc3RJdGVtRXZlbnQgZXh0ZW5kcyBCYXNlQ29tcG9uZW50IHtcbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGxldCB7IHByb3BzLCBjb250ZXh0IH0gPSB0aGlzO1xuICAgICAgICBsZXQgeyBvcHRpb25zIH0gPSBjb250ZXh0O1xuICAgICAgICBsZXQgeyBzZWcgfSA9IHByb3BzO1xuICAgICAgICBsZXQgdGltZUZvcm1hdCA9IG9wdGlvbnMuZXZlbnRUaW1lRm9ybWF0IHx8IERFRkFVTFRfVEFCTEVfRVZFTlRfVElNRV9GT1JNQVQ7XG4gICAgICAgIGxldCB0aW1lVGV4dCA9IGJ1aWxkU2VnVGltZVRleHQoc2VnLCB0aW1lRm9ybWF0LCBjb250ZXh0LCB0cnVlLCBwcm9wcy5kZWZhdWx0RGlzcGxheUV2ZW50RW5kKTtcbiAgICAgICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KEV2ZW50Q29udGFpbmVyLCBPYmplY3QuYXNzaWduKHt9LCBwcm9wcywgeyBlbFRhZzogXCJhXCIsIGVsQ2xhc3NlczogWydmYy1kYXlncmlkLWV2ZW50JywgJ2ZjLWRheWdyaWQtZG90LWV2ZW50J10sIGVsQXR0cnM6IGdldFNlZ0FuY2hvckF0dHJzKHByb3BzLnNlZywgY29udGV4dCksIGRlZmF1bHRHZW5lcmF0b3I6IHJlbmRlcklubmVyQ29udGVudCwgdGltZVRleHQ6IHRpbWVUZXh0LCBpc1Jlc2l6aW5nOiBmYWxzZSwgaXNEYXRlU2VsZWN0aW5nOiBmYWxzZSB9KSkpO1xuICAgIH1cbn1cbmZ1bmN0aW9uIHJlbmRlcklubmVyQ29udGVudChyZW5kZXJQcm9wcykge1xuICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChGcmFnbWVudCwgbnVsbCxcbiAgICAgICAgY3JlYXRlRWxlbWVudChcImRpdlwiLCB7IGNsYXNzTmFtZTogXCJmYy1kYXlncmlkLWV2ZW50LWRvdFwiLCBzdHlsZTogeyBib3JkZXJDb2xvcjogcmVuZGVyUHJvcHMuYm9yZGVyQ29sb3IgfHwgcmVuZGVyUHJvcHMuYmFja2dyb3VuZENvbG9yIH0gfSksXG4gICAgICAgIHJlbmRlclByb3BzLnRpbWVUZXh0ICYmIChjcmVhdGVFbGVtZW50KFwiZGl2XCIsIHsgY2xhc3NOYW1lOiBcImZjLWV2ZW50LXRpbWVcIiB9LCByZW5kZXJQcm9wcy50aW1lVGV4dCkpLFxuICAgICAgICBjcmVhdGVFbGVtZW50KFwiZGl2XCIsIHsgY2xhc3NOYW1lOiBcImZjLWV2ZW50LXRpdGxlXCIgfSwgcmVuZGVyUHJvcHMuZXZlbnQudGl0bGUgfHwgY3JlYXRlRWxlbWVudChGcmFnbWVudCwgbnVsbCwgXCJcXHUwMEEwXCIpKSkpO1xufVxuXG5jbGFzcyBUYWJsZUNlbGxNb3JlTGluayBleHRlbmRzIEJhc2VDb21wb25lbnQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICB0aGlzLmNvbXBpbGVTZWdzID0gbWVtb2l6ZShjb21waWxlU2Vncyk7XG4gICAgfVxuICAgIHJlbmRlcigpIHtcbiAgICAgICAgbGV0IHsgcHJvcHMgfSA9IHRoaXM7XG4gICAgICAgIGxldCB7IGFsbFNlZ3MsIGludmlzaWJsZVNlZ3MgfSA9IHRoaXMuY29tcGlsZVNlZ3MocHJvcHMuc2luZ2xlUGxhY2VtZW50cyk7XG4gICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChNb3JlTGlua0NvbnRhaW5lciwgeyBlbENsYXNzZXM6IFsnZmMtZGF5Z3JpZC1tb3JlLWxpbmsnXSwgZGF0ZVByb2ZpbGU6IHByb3BzLmRhdGVQcm9maWxlLCB0b2RheVJhbmdlOiBwcm9wcy50b2RheVJhbmdlLCBhbGxEYXlEYXRlOiBwcm9wcy5hbGxEYXlEYXRlLCBtb3JlQ250OiBwcm9wcy5tb3JlQ250LCBhbGxTZWdzOiBhbGxTZWdzLCBoaWRkZW5TZWdzOiBpbnZpc2libGVTZWdzLCBhbGlnbm1lbnRFbFJlZjogcHJvcHMuYWxpZ25tZW50RWxSZWYsIGFsaWduR3JpZFRvcDogcHJvcHMuYWxpZ25HcmlkVG9wLCBleHRyYURhdGVTcGFuOiBwcm9wcy5leHRyYURhdGVTcGFuLCBwb3BvdmVyQ29udGVudDogKCkgPT4ge1xuICAgICAgICAgICAgICAgIGxldCBpc0ZvcmNlZEludmlzaWJsZSA9IChwcm9wcy5ldmVudERyYWcgPyBwcm9wcy5ldmVudERyYWcuYWZmZWN0ZWRJbnN0YW5jZXMgOiBudWxsKSB8fFxuICAgICAgICAgICAgICAgICAgICAocHJvcHMuZXZlbnRSZXNpemUgPyBwcm9wcy5ldmVudFJlc2l6ZS5hZmZlY3RlZEluc3RhbmNlcyA6IG51bGwpIHx8XG4gICAgICAgICAgICAgICAgICAgIHt9O1xuICAgICAgICAgICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChGcmFnbWVudCwgbnVsbCwgYWxsU2Vncy5tYXAoKHNlZykgPT4ge1xuICAgICAgICAgICAgICAgICAgICBsZXQgaW5zdGFuY2VJZCA9IHNlZy5ldmVudFJhbmdlLmluc3RhbmNlLmluc3RhbmNlSWQ7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChcImRpdlwiLCB7IGNsYXNzTmFtZTogXCJmYy1kYXlncmlkLWV2ZW50LWhhcm5lc3NcIiwga2V5OiBpbnN0YW5jZUlkLCBzdHlsZToge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpc2liaWxpdHk6IGlzRm9yY2VkSW52aXNpYmxlW2luc3RhbmNlSWRdID8gJ2hpZGRlbicgOiAnJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gfSwgaGFzTGlzdEl0ZW1EaXNwbGF5KHNlZykgPyAoY3JlYXRlRWxlbWVudChUYWJsZUxpc3RJdGVtRXZlbnQsIE9iamVjdC5hc3NpZ24oeyBzZWc6IHNlZywgaXNEcmFnZ2luZzogZmFsc2UsIGlzU2VsZWN0ZWQ6IGluc3RhbmNlSWQgPT09IHByb3BzLmV2ZW50U2VsZWN0aW9uLCBkZWZhdWx0RGlzcGxheUV2ZW50RW5kOiBmYWxzZSB9LCBnZXRTZWdNZXRhKHNlZywgcHJvcHMudG9kYXlSYW5nZSkpKSkgOiAoY3JlYXRlRWxlbWVudChUYWJsZUJsb2NrRXZlbnQsIE9iamVjdC5hc3NpZ24oeyBzZWc6IHNlZywgaXNEcmFnZ2luZzogZmFsc2UsIGlzUmVzaXppbmc6IGZhbHNlLCBpc0RhdGVTZWxlY3Rpbmc6IGZhbHNlLCBpc1NlbGVjdGVkOiBpbnN0YW5jZUlkID09PSBwcm9wcy5ldmVudFNlbGVjdGlvbiwgZGVmYXVsdERpc3BsYXlFdmVudEVuZDogZmFsc2UgfSwgZ2V0U2VnTWV0YShzZWcsIHByb3BzLnRvZGF5UmFuZ2UpKSkpKSk7XG4gICAgICAgICAgICAgICAgfSkpKTtcbiAgICAgICAgICAgIH0gfSkpO1xuICAgIH1cbn1cbmZ1bmN0aW9uIGNvbXBpbGVTZWdzKHNpbmdsZVBsYWNlbWVudHMpIHtcbiAgICBsZXQgYWxsU2VncyA9IFtdO1xuICAgIGxldCBpbnZpc2libGVTZWdzID0gW107XG4gICAgZm9yIChsZXQgcGxhY2VtZW50IG9mIHNpbmdsZVBsYWNlbWVudHMpIHtcbiAgICAgICAgYWxsU2Vncy5wdXNoKHBsYWNlbWVudC5zZWcpO1xuICAgICAgICBpZiAoIXBsYWNlbWVudC5pc1Zpc2libGUpIHtcbiAgICAgICAgICAgIGludmlzaWJsZVNlZ3MucHVzaChwbGFjZW1lbnQuc2VnKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4geyBhbGxTZWdzLCBpbnZpc2libGVTZWdzIH07XG59XG5cbmNvbnN0IERFRkFVTFRfV0VFS19OVU1fRk9STUFUID0gY3JlYXRlRm9ybWF0dGVyKHsgd2VlazogJ25hcnJvdycgfSk7XG5jbGFzcyBUYWJsZUNlbGwgZXh0ZW5kcyBEYXRlQ29tcG9uZW50IHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoLi4uYXJndW1lbnRzKTtcbiAgICAgICAgdGhpcy5yb290RWxSZWYgPSBjcmVhdGVSZWYoKTtcbiAgICAgICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgICAgICAgIGRheU51bWJlcklkOiBnZXRVbmlxdWVEb21JZCgpLFxuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZVJvb3RFbCA9IChlbCkgPT4ge1xuICAgICAgICAgICAgc2V0UmVmKHRoaXMucm9vdEVsUmVmLCBlbCk7XG4gICAgICAgICAgICBzZXRSZWYodGhpcy5wcm9wcy5lbFJlZiwgZWwpO1xuICAgICAgICB9O1xuICAgIH1cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGxldCB7IGNvbnRleHQsIHByb3BzLCBzdGF0ZSwgcm9vdEVsUmVmIH0gPSB0aGlzO1xuICAgICAgICBsZXQgeyBvcHRpb25zLCBkYXRlRW52IH0gPSBjb250ZXh0O1xuICAgICAgICBsZXQgeyBkYXRlLCBkYXRlUHJvZmlsZSB9ID0gcHJvcHM7XG4gICAgICAgIC8vIFRPRE86IG1lbW9pemUgdGhpcz9cbiAgICAgICAgY29uc3QgaXNNb250aFN0YXJ0ID0gcHJvcHMuc2hvd0RheU51bWJlciAmJlxuICAgICAgICAgICAgc2hvdWxkRGlzcGxheU1vbnRoU3RhcnQoZGF0ZSwgZGF0ZVByb2ZpbGUuY3VycmVudFJhbmdlLCBkYXRlRW52KTtcbiAgICAgICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KERheUNlbGxDb250YWluZXIsIHsgZWxUYWc6IFwidGRcIiwgZWxSZWY6IHRoaXMuaGFuZGxlUm9vdEVsLCBlbENsYXNzZXM6IFtcbiAgICAgICAgICAgICAgICAnZmMtZGF5Z3JpZC1kYXknLFxuICAgICAgICAgICAgICAgIC4uLihwcm9wcy5leHRyYUNsYXNzTmFtZXMgfHwgW10pLFxuICAgICAgICAgICAgXSwgZWxBdHRyczogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByb3BzLmV4dHJhRGF0YUF0dHJzKSwgKHByb3BzLnNob3dEYXlOdW1iZXIgPyB7ICdhcmlhLWxhYmVsbGVkYnknOiBzdGF0ZS5kYXlOdW1iZXJJZCB9IDoge30pKSwgeyByb2xlOiAnZ3JpZGNlbGwnIH0pLCBkZWZhdWx0R2VuZXJhdG9yOiByZW5kZXJUb3BJbm5lciwgZGF0ZTogZGF0ZSwgZGF0ZVByb2ZpbGU6IGRhdGVQcm9maWxlLCB0b2RheVJhbmdlOiBwcm9wcy50b2RheVJhbmdlLCBzaG93RGF5TnVtYmVyOiBwcm9wcy5zaG93RGF5TnVtYmVyLCBpc01vbnRoU3RhcnQ6IGlzTW9udGhTdGFydCwgZXh0cmFSZW5kZXJQcm9wczogcHJvcHMuZXh0cmFSZW5kZXJQcm9wcyB9LCAoSW5uZXJDb250ZW50LCByZW5kZXJQcm9wcykgPT4gKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyByZWY6IHByb3BzLmlubmVyRWxSZWYsIGNsYXNzTmFtZTogXCJmYy1kYXlncmlkLWRheS1mcmFtZSBmYy1zY3JvbGxncmlkLXN5bmMtaW5uZXJcIiwgc3R5bGU6IHsgbWluSGVpZ2h0OiBwcm9wcy5taW5IZWlnaHQgfSB9LFxuICAgICAgICAgICAgcHJvcHMuc2hvd1dlZWtOdW1iZXIgJiYgKGNyZWF0ZUVsZW1lbnQoV2Vla051bWJlckNvbnRhaW5lciwgeyBlbFRhZzogXCJhXCIsIGVsQ2xhc3NlczogWydmYy1kYXlncmlkLXdlZWstbnVtYmVyJ10sIGVsQXR0cnM6IGJ1aWxkTmF2TGlua0F0dHJzKGNvbnRleHQsIGRhdGUsICd3ZWVrJyksIGRhdGU6IGRhdGUsIGRlZmF1bHRGb3JtYXQ6IERFRkFVTFRfV0VFS19OVU1fRk9STUFUIH0pKSxcbiAgICAgICAgICAgICFyZW5kZXJQcm9wcy5pc0Rpc2FibGVkICYmXG4gICAgICAgICAgICAgICAgKHByb3BzLnNob3dEYXlOdW1iZXIgfHwgaGFzQ3VzdG9tRGF5Q2VsbENvbnRlbnQob3B0aW9ucykgfHwgcHJvcHMuZm9yY2VEYXlUb3ApID8gKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IFwiZmMtZGF5Z3JpZC1kYXktdG9wXCIgfSxcbiAgICAgICAgICAgICAgICBjcmVhdGVFbGVtZW50KElubmVyQ29udGVudCwgeyBlbFRhZzogXCJhXCIsIGVsQ2xhc3NlczogW1xuICAgICAgICAgICAgICAgICAgICAgICAgJ2ZjLWRheWdyaWQtZGF5LW51bWJlcicsXG4gICAgICAgICAgICAgICAgICAgICAgICBpc01vbnRoU3RhcnQgJiYgJ2ZjLWRheWdyaWQtbW9udGgtc3RhcnQnLFxuICAgICAgICAgICAgICAgICAgICBdLCBlbEF0dHJzOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGJ1aWxkTmF2TGlua0F0dHJzKGNvbnRleHQsIGRhdGUpKSwgeyBpZDogc3RhdGUuZGF5TnVtYmVySWQgfSkgfSkpKSA6IHByb3BzLnNob3dEYXlOdW1iZXIgPyAoXG4gICAgICAgICAgICAvLyBmb3IgY3JlYXRpbmcgY29ycmVjdCBhbW91bnQgb2Ygc3BhY2UgKHNlZSBpc3N1ZSAjNzE2MilcbiAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IFwiZmMtZGF5Z3JpZC1kYXktdG9wXCIsIHN0eWxlOiB7IHZpc2liaWxpdHk6ICdoaWRkZW4nIH0gfSxcbiAgICAgICAgICAgICAgICBjcmVhdGVFbGVtZW50KFwiYVwiLCB7IGNsYXNzTmFtZTogXCJmYy1kYXlncmlkLWRheS1udW1iZXJcIiB9LCBcIlxcdTAwQTBcIikpKSA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IFwiZmMtZGF5Z3JpZC1kYXktZXZlbnRzXCIsIHJlZjogcHJvcHMuZmdDb250ZW50RWxSZWYgfSxcbiAgICAgICAgICAgICAgICBwcm9wcy5mZ0NvbnRlbnQsXG4gICAgICAgICAgICAgICAgY3JlYXRlRWxlbWVudChcImRpdlwiLCB7IGNsYXNzTmFtZTogXCJmYy1kYXlncmlkLWRheS1ib3R0b21cIiwgc3R5bGU6IHsgbWFyZ2luVG9wOiBwcm9wcy5tb3JlTWFyZ2luVG9wIH0gfSxcbiAgICAgICAgICAgICAgICAgICAgY3JlYXRlRWxlbWVudChUYWJsZUNlbGxNb3JlTGluaywgeyBhbGxEYXlEYXRlOiBkYXRlLCBzaW5nbGVQbGFjZW1lbnRzOiBwcm9wcy5zaW5nbGVQbGFjZW1lbnRzLCBtb3JlQ250OiBwcm9wcy5tb3JlQ250LCBhbGlnbm1lbnRFbFJlZjogcm9vdEVsUmVmLCBhbGlnbkdyaWRUb3A6ICFwcm9wcy5zaG93RGF5TnVtYmVyLCBleHRyYURhdGVTcGFuOiBwcm9wcy5leHRyYURhdGVTcGFuLCBkYXRlUHJvZmlsZTogcHJvcHMuZGF0ZVByb2ZpbGUsIGV2ZW50U2VsZWN0aW9uOiBwcm9wcy5ldmVudFNlbGVjdGlvbiwgZXZlbnREcmFnOiBwcm9wcy5ldmVudERyYWcsIGV2ZW50UmVzaXplOiBwcm9wcy5ldmVudFJlc2l6ZSwgdG9kYXlSYW5nZTogcHJvcHMudG9kYXlSYW5nZSB9KSkpLFxuICAgICAgICAgICAgY3JlYXRlRWxlbWVudChcImRpdlwiLCB7IGNsYXNzTmFtZTogXCJmYy1kYXlncmlkLWRheS1iZ1wiIH0sIHByb3BzLmJnQ29udGVudCkpKSkpO1xuICAgIH1cbn1cbmZ1bmN0aW9uIHJlbmRlclRvcElubmVyKHByb3BzKSB7XG4gICAgcmV0dXJuIHByb3BzLmRheU51bWJlclRleHQgfHwgY3JlYXRlRWxlbWVudChGcmFnbWVudCwgbnVsbCwgXCJcXHUwMEEwXCIpO1xufVxuZnVuY3Rpb24gc2hvdWxkRGlzcGxheU1vbnRoU3RhcnQoZGF0ZSwgY3VycmVudFJhbmdlLCBkYXRlRW52KSB7XG4gICAgY29uc3QgeyBzdGFydDogY3VycmVudFN0YXJ0LCBlbmQ6IGN1cnJlbnRFbmQgfSA9IGN1cnJlbnRSYW5nZTtcbiAgICBjb25zdCBjdXJyZW50RW5kSW5jbCA9IGFkZE1zKGN1cnJlbnRFbmQsIC0xKTtcbiAgICBjb25zdCBjdXJyZW50Rmlyc3RZZWFyID0gZGF0ZUVudi5nZXRZZWFyKGN1cnJlbnRTdGFydCk7XG4gICAgY29uc3QgY3VycmVudEZpcnN0TW9udGggPSBkYXRlRW52LmdldE1vbnRoKGN1cnJlbnRTdGFydCk7XG4gICAgY29uc3QgY3VycmVudExhc3RZZWFyID0gZGF0ZUVudi5nZXRZZWFyKGN1cnJlbnRFbmRJbmNsKTtcbiAgICBjb25zdCBjdXJyZW50TGFzdE1vbnRoID0gZGF0ZUVudi5nZXRNb250aChjdXJyZW50RW5kSW5jbCk7XG4gICAgLy8gc3BhbnMgbW9yZSB0aGFuIG9uZSBtb250aD9cbiAgICByZXR1cm4gIShjdXJyZW50Rmlyc3RZZWFyID09PSBjdXJyZW50TGFzdFllYXIgJiYgY3VycmVudEZpcnN0TW9udGggPT09IGN1cnJlbnRMYXN0TW9udGgpICYmXG4gICAgICAgIEJvb2xlYW4oXG4gICAgICAgIC8vIGZpcnN0IGRhdGUgaW4gY3VycmVudCB2aWV3P1xuICAgICAgICBkYXRlLnZhbHVlT2YoKSA9PT0gY3VycmVudFN0YXJ0LnZhbHVlT2YoKSB8fFxuICAgICAgICAgICAgLy8gYSBtb250aC1zdGFydCB0aGF0J3Mgd2l0aGluIHRoZSBjdXJyZW50IHJhbmdlP1xuICAgICAgICAgICAgKGRhdGVFbnYuZ2V0RGF5KGRhdGUpID09PSAxICYmIGRhdGUudmFsdWVPZigpIDwgY3VycmVudEVuZC52YWx1ZU9mKCkpKTtcbn1cblxuZnVuY3Rpb24gZ2VuZXJhdGVTZWdLZXkoc2VnKSB7XG4gICAgcmV0dXJuIHNlZy5ldmVudFJhbmdlLmluc3RhbmNlLmluc3RhbmNlSWQgKyAnOicgKyBzZWcuZmlyc3RDb2w7XG59XG5mdW5jdGlvbiBnZW5lcmF0ZVNlZ1VpZChzZWcpIHtcbiAgICByZXR1cm4gZ2VuZXJhdGVTZWdLZXkoc2VnKSArICc6JyArIHNlZy5sYXN0Q29sO1xufVxuZnVuY3Rpb24gY29tcHV0ZUZnU2VnUGxhY2VtZW50KHNlZ3MsIC8vIGFzc3VtZWQgYWxyZWFkeSBzb3J0ZWRcbmRheU1heEV2ZW50cywgZGF5TWF4RXZlbnRSb3dzLCBzdHJpY3RPcmRlciwgc2VnSGVpZ2h0cywgbWF4Q29udGVudEhlaWdodCwgY2VsbHMpIHtcbiAgICBsZXQgaGllcmFyY2h5ID0gbmV3IERheUdyaWRTZWdIaWVyYXJjaHkoKHNlZ0VudHJ5KSA9PiB7XG4gICAgICAgIC8vIFRPRE86IG1vcmUgRFJZIHdpdGggZ2VuZXJhdGVTZWdVaWRcbiAgICAgICAgbGV0IHNlZ1VpZCA9IHNlZ3Nbc2VnRW50cnkuaW5kZXhdLmV2ZW50UmFuZ2UuaW5zdGFuY2UuaW5zdGFuY2VJZCArXG4gICAgICAgICAgICAnOicgKyBzZWdFbnRyeS5zcGFuLnN0YXJ0ICtcbiAgICAgICAgICAgICc6JyArIChzZWdFbnRyeS5zcGFuLmVuZCAtIDEpO1xuICAgICAgICAvLyBpZiBubyB0aGlja25lc3Mga25vd24sIGFzc3VtZSAxIChpZiAwLCBzbyBzbWFsbCBpdCBhbHdheXMgZml0cylcbiAgICAgICAgcmV0dXJuIHNlZ0hlaWdodHNbc2VnVWlkXSB8fCAxO1xuICAgIH0pO1xuICAgIGhpZXJhcmNoeS5hbGxvd1Jlc2xpY2luZyA9IHRydWU7XG4gICAgaGllcmFyY2h5LnN0cmljdE9yZGVyID0gc3RyaWN0T3JkZXI7XG4gICAgaWYgKGRheU1heEV2ZW50cyA9PT0gdHJ1ZSB8fCBkYXlNYXhFdmVudFJvd3MgPT09IHRydWUpIHtcbiAgICAgICAgaGllcmFyY2h5Lm1heENvb3JkID0gbWF4Q29udGVudEhlaWdodDtcbiAgICAgICAgaGllcmFyY2h5LmhpZGRlbkNvbnN1bWVzID0gdHJ1ZTtcbiAgICB9XG4gICAgZWxzZSBpZiAodHlwZW9mIGRheU1heEV2ZW50cyA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgaGllcmFyY2h5Lm1heFN0YWNrQ250ID0gZGF5TWF4RXZlbnRzO1xuICAgIH1cbiAgICBlbHNlIGlmICh0eXBlb2YgZGF5TWF4RXZlbnRSb3dzID09PSAnbnVtYmVyJykge1xuICAgICAgICBoaWVyYXJjaHkubWF4U3RhY2tDbnQgPSBkYXlNYXhFdmVudFJvd3M7XG4gICAgICAgIGhpZXJhcmNoeS5oaWRkZW5Db25zdW1lcyA9IHRydWU7XG4gICAgfVxuICAgIC8vIGNyZWF0ZSBzZWdJbnB1dHMgb25seSBmb3Igc2VncyB3aXRoIGtub3duIGhlaWdodHNcbiAgICBsZXQgc2VnSW5wdXRzID0gW107XG4gICAgbGV0IHVua25vd25IZWlnaHRTZWdzID0gW107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzZWdzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICAgIGxldCBzZWcgPSBzZWdzW2ldO1xuICAgICAgICBsZXQgc2VnVWlkID0gZ2VuZXJhdGVTZWdVaWQoc2VnKTtcbiAgICAgICAgbGV0IGV2ZW50SGVpZ2h0ID0gc2VnSGVpZ2h0c1tzZWdVaWRdO1xuICAgICAgICBpZiAoZXZlbnRIZWlnaHQgIT0gbnVsbCkge1xuICAgICAgICAgICAgc2VnSW5wdXRzLnB1c2goe1xuICAgICAgICAgICAgICAgIGluZGV4OiBpLFxuICAgICAgICAgICAgICAgIHNwYW46IHtcbiAgICAgICAgICAgICAgICAgICAgc3RhcnQ6IHNlZy5maXJzdENvbCxcbiAgICAgICAgICAgICAgICAgICAgZW5kOiBzZWcubGFzdENvbCArIDEsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdW5rbm93bkhlaWdodFNlZ3MucHVzaChzZWcpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGxldCBoaWRkZW5FbnRyaWVzID0gaGllcmFyY2h5LmFkZFNlZ3Moc2VnSW5wdXRzKTtcbiAgICBsZXQgc2VnUmVjdHMgPSBoaWVyYXJjaHkudG9SZWN0cygpO1xuICAgIGxldCB7IHNpbmdsZUNvbFBsYWNlbWVudHMsIG11bHRpQ29sUGxhY2VtZW50cywgbGVmdG92ZXJNYXJnaW5zIH0gPSBwbGFjZVJlY3RzKHNlZ1JlY3RzLCBzZWdzLCBjZWxscyk7XG4gICAgbGV0IG1vcmVDbnRzID0gW107XG4gICAgbGV0IG1vcmVNYXJnaW5Ub3BzID0gW107XG4gICAgLy8gYWRkIHNlZ3Mgd2l0aCB1bmtub3duIGhlaWdodHNcbiAgICBmb3IgKGxldCBzZWcgb2YgdW5rbm93bkhlaWdodFNlZ3MpIHtcbiAgICAgICAgbXVsdGlDb2xQbGFjZW1lbnRzW3NlZy5maXJzdENvbF0ucHVzaCh7XG4gICAgICAgICAgICBzZWcsXG4gICAgICAgICAgICBpc1Zpc2libGU6IGZhbHNlLFxuICAgICAgICAgICAgaXNBYnNvbHV0ZTogdHJ1ZSxcbiAgICAgICAgICAgIGFic29sdXRlVG9wOiAwLFxuICAgICAgICAgICAgbWFyZ2luVG9wOiAwLFxuICAgICAgICB9KTtcbiAgICAgICAgZm9yIChsZXQgY29sID0gc2VnLmZpcnN0Q29sOyBjb2wgPD0gc2VnLmxhc3RDb2w7IGNvbCArPSAxKSB7XG4gICAgICAgICAgICBzaW5nbGVDb2xQbGFjZW1lbnRzW2NvbF0ucHVzaCh7XG4gICAgICAgICAgICAgICAgc2VnOiByZXNsaWNlU2VnKHNlZywgY29sLCBjb2wgKyAxLCBjZWxscyksXG4gICAgICAgICAgICAgICAgaXNWaXNpYmxlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBpc0Fic29sdXRlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBhYnNvbHV0ZVRvcDogMCxcbiAgICAgICAgICAgICAgICBtYXJnaW5Ub3A6IDAsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBhZGQgdGhlIGhpZGRlbiBlbnRyaWVzXG4gICAgZm9yIChsZXQgY29sID0gMDsgY29sIDwgY2VsbHMubGVuZ3RoOyBjb2wgKz0gMSkge1xuICAgICAgICBtb3JlQ250cy5wdXNoKDApO1xuICAgIH1cbiAgICBmb3IgKGxldCBoaWRkZW5FbnRyeSBvZiBoaWRkZW5FbnRyaWVzKSB7XG4gICAgICAgIGxldCBzZWcgPSBzZWdzW2hpZGRlbkVudHJ5LmluZGV4XTtcbiAgICAgICAgbGV0IGhpZGRlblNwYW4gPSBoaWRkZW5FbnRyeS5zcGFuO1xuICAgICAgICBtdWx0aUNvbFBsYWNlbWVudHNbaGlkZGVuU3Bhbi5zdGFydF0ucHVzaCh7XG4gICAgICAgICAgICBzZWc6IHJlc2xpY2VTZWcoc2VnLCBoaWRkZW5TcGFuLnN0YXJ0LCBoaWRkZW5TcGFuLmVuZCwgY2VsbHMpLFxuICAgICAgICAgICAgaXNWaXNpYmxlOiBmYWxzZSxcbiAgICAgICAgICAgIGlzQWJzb2x1dGU6IHRydWUsXG4gICAgICAgICAgICBhYnNvbHV0ZVRvcDogMCxcbiAgICAgICAgICAgIG1hcmdpblRvcDogMCxcbiAgICAgICAgfSk7XG4gICAgICAgIGZvciAobGV0IGNvbCA9IGhpZGRlblNwYW4uc3RhcnQ7IGNvbCA8IGhpZGRlblNwYW4uZW5kOyBjb2wgKz0gMSkge1xuICAgICAgICAgICAgbW9yZUNudHNbY29sXSArPSAxO1xuICAgICAgICAgICAgc2luZ2xlQ29sUGxhY2VtZW50c1tjb2xdLnB1c2goe1xuICAgICAgICAgICAgICAgIHNlZzogcmVzbGljZVNlZyhzZWcsIGNvbCwgY29sICsgMSwgY2VsbHMpLFxuICAgICAgICAgICAgICAgIGlzVmlzaWJsZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgaXNBYnNvbHV0ZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgYWJzb2x1dGVUb3A6IDAsXG4gICAgICAgICAgICAgICAgbWFyZ2luVG9wOiAwLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gZGVhbCB3aXRoIGxlZnRvdmVyIG1hcmdpbnNcbiAgICBmb3IgKGxldCBjb2wgPSAwOyBjb2wgPCBjZWxscy5sZW5ndGg7IGNvbCArPSAxKSB7XG4gICAgICAgIG1vcmVNYXJnaW5Ub3BzLnB1c2gobGVmdG92ZXJNYXJnaW5zW2NvbF0pO1xuICAgIH1cbiAgICByZXR1cm4geyBzaW5nbGVDb2xQbGFjZW1lbnRzLCBtdWx0aUNvbFBsYWNlbWVudHMsIG1vcmVDbnRzLCBtb3JlTWFyZ2luVG9wcyB9O1xufVxuLy8gcmVjdHMgb3JkZXJlZCBieSB0b3AgY29vcmQsIHRoZW4gbGVmdFxuZnVuY3Rpb24gcGxhY2VSZWN0cyhhbGxSZWN0cywgc2VncywgY2VsbHMpIHtcbiAgICBsZXQgcmVjdHNCeUVhY2hDb2wgPSBncm91cFJlY3RzQnlFYWNoQ29sKGFsbFJlY3RzLCBjZWxscy5sZW5ndGgpO1xuICAgIGxldCBzaW5nbGVDb2xQbGFjZW1lbnRzID0gW107XG4gICAgbGV0IG11bHRpQ29sUGxhY2VtZW50cyA9IFtdO1xuICAgIGxldCBsZWZ0b3Zlck1hcmdpbnMgPSBbXTtcbiAgICBmb3IgKGxldCBjb2wgPSAwOyBjb2wgPCBjZWxscy5sZW5ndGg7IGNvbCArPSAxKSB7XG4gICAgICAgIGxldCByZWN0cyA9IHJlY3RzQnlFYWNoQ29sW2NvbF07XG4gICAgICAgIC8vIGNvbXB1dGUgYWxsIHN0YXRpYyBzZWdzIGluIHNpbmdsZVBsYWNlbWVudHNcbiAgICAgICAgbGV0IHNpbmdsZVBsYWNlbWVudHMgPSBbXTtcbiAgICAgICAgbGV0IGN1cnJlbnRIZWlnaHQgPSAwO1xuICAgICAgICBsZXQgY3VycmVudE1hcmdpblRvcCA9IDA7XG4gICAgICAgIGZvciAobGV0IHJlY3Qgb2YgcmVjdHMpIHtcbiAgICAgICAgICAgIGxldCBzZWcgPSBzZWdzW3JlY3QuaW5kZXhdO1xuICAgICAgICAgICAgc2luZ2xlUGxhY2VtZW50cy5wdXNoKHtcbiAgICAgICAgICAgICAgICBzZWc6IHJlc2xpY2VTZWcoc2VnLCBjb2wsIGNvbCArIDEsIGNlbGxzKSxcbiAgICAgICAgICAgICAgICBpc1Zpc2libGU6IHRydWUsXG4gICAgICAgICAgICAgICAgaXNBYnNvbHV0ZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgYWJzb2x1dGVUb3A6IHJlY3QubGV2ZWxDb29yZCxcbiAgICAgICAgICAgICAgICBtYXJnaW5Ub3A6IHJlY3QubGV2ZWxDb29yZCAtIGN1cnJlbnRIZWlnaHQsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGN1cnJlbnRIZWlnaHQgPSByZWN0LmxldmVsQ29vcmQgKyByZWN0LnRoaWNrbmVzcztcbiAgICAgICAgfVxuICAgICAgICAvLyBjb21wdXRlIG1peGVkIHN0YXRpYy9hYnNvbHV0ZSBzZWdzIGluIG11bHRpUGxhY2VtZW50c1xuICAgICAgICBsZXQgbXVsdGlQbGFjZW1lbnRzID0gW107XG4gICAgICAgIGN1cnJlbnRIZWlnaHQgPSAwO1xuICAgICAgICBjdXJyZW50TWFyZ2luVG9wID0gMDtcbiAgICAgICAgZm9yIChsZXQgcmVjdCBvZiByZWN0cykge1xuICAgICAgICAgICAgbGV0IHNlZyA9IHNlZ3NbcmVjdC5pbmRleF07XG4gICAgICAgICAgICBsZXQgaXNBYnNvbHV0ZSA9IHJlY3Quc3Bhbi5lbmQgLSByZWN0LnNwYW4uc3RhcnQgPiAxOyAvLyBtdWx0aS1jb2x1bW4/XG4gICAgICAgICAgICBsZXQgaXNGaXJzdENvbCA9IHJlY3Quc3Bhbi5zdGFydCA9PT0gY29sO1xuICAgICAgICAgICAgY3VycmVudE1hcmdpblRvcCArPSByZWN0LmxldmVsQ29vcmQgLSBjdXJyZW50SGVpZ2h0OyAvLyBhbW91bnQgb2Ygc3BhY2Ugc2luY2UgYm90dG9tIG9mIHByZXZpb3VzIHNlZ1xuICAgICAgICAgICAgY3VycmVudEhlaWdodCA9IHJlY3QubGV2ZWxDb29yZCArIHJlY3QudGhpY2tuZXNzOyAvLyBoZWlnaHQgd2lsbCBub3cgYmUgYm90dG9tIG9mIGN1cnJlbnQgc2VnXG4gICAgICAgICAgICBpZiAoaXNBYnNvbHV0ZSkge1xuICAgICAgICAgICAgICAgIGN1cnJlbnRNYXJnaW5Ub3AgKz0gcmVjdC50aGlja25lc3M7XG4gICAgICAgICAgICAgICAgaWYgKGlzRmlyc3RDb2wpIHtcbiAgICAgICAgICAgICAgICAgICAgbXVsdGlQbGFjZW1lbnRzLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VnOiByZXNsaWNlU2VnKHNlZywgcmVjdC5zcGFuLnN0YXJ0LCByZWN0LnNwYW4uZW5kLCBjZWxscyksXG4gICAgICAgICAgICAgICAgICAgICAgICBpc1Zpc2libGU6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgICBpc0Fic29sdXRlOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgYWJzb2x1dGVUb3A6IHJlY3QubGV2ZWxDb29yZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIG1hcmdpblRvcDogMCxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoaXNGaXJzdENvbCkge1xuICAgICAgICAgICAgICAgIG11bHRpUGxhY2VtZW50cy5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgc2VnOiByZXNsaWNlU2VnKHNlZywgcmVjdC5zcGFuLnN0YXJ0LCByZWN0LnNwYW4uZW5kLCBjZWxscyksXG4gICAgICAgICAgICAgICAgICAgIGlzVmlzaWJsZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgaXNBYnNvbHV0ZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIGFic29sdXRlVG9wOiByZWN0LmxldmVsQ29vcmQsXG4gICAgICAgICAgICAgICAgICAgIG1hcmdpblRvcDogY3VycmVudE1hcmdpblRvcCwgLy8gY2xhaW0gdGhlIG1hcmdpblxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGN1cnJlbnRNYXJnaW5Ub3AgPSAwO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHNpbmdsZUNvbFBsYWNlbWVudHMucHVzaChzaW5nbGVQbGFjZW1lbnRzKTtcbiAgICAgICAgbXVsdGlDb2xQbGFjZW1lbnRzLnB1c2gobXVsdGlQbGFjZW1lbnRzKTtcbiAgICAgICAgbGVmdG92ZXJNYXJnaW5zLnB1c2goY3VycmVudE1hcmdpblRvcCk7XG4gICAgfVxuICAgIHJldHVybiB7IHNpbmdsZUNvbFBsYWNlbWVudHMsIG11bHRpQ29sUGxhY2VtZW50cywgbGVmdG92ZXJNYXJnaW5zIH07XG59XG5mdW5jdGlvbiBncm91cFJlY3RzQnlFYWNoQ29sKHJlY3RzLCBjb2xDbnQpIHtcbiAgICBsZXQgcmVjdHNCeUVhY2hDb2wgPSBbXTtcbiAgICBmb3IgKGxldCBjb2wgPSAwOyBjb2wgPCBjb2xDbnQ7IGNvbCArPSAxKSB7XG4gICAgICAgIHJlY3RzQnlFYWNoQ29sLnB1c2goW10pO1xuICAgIH1cbiAgICBmb3IgKGxldCByZWN0IG9mIHJlY3RzKSB7XG4gICAgICAgIGZvciAobGV0IGNvbCA9IHJlY3Quc3Bhbi5zdGFydDsgY29sIDwgcmVjdC5zcGFuLmVuZDsgY29sICs9IDEpIHtcbiAgICAgICAgICAgIHJlY3RzQnlFYWNoQ29sW2NvbF0ucHVzaChyZWN0KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVjdHNCeUVhY2hDb2w7XG59XG5mdW5jdGlvbiByZXNsaWNlU2VnKHNlZywgc3BhblN0YXJ0LCBzcGFuRW5kLCBjZWxscykge1xuICAgIGlmIChzZWcuZmlyc3RDb2wgPT09IHNwYW5TdGFydCAmJiBzZWcubGFzdENvbCA9PT0gc3BhbkVuZCAtIDEpIHtcbiAgICAgICAgcmV0dXJuIHNlZztcbiAgICB9XG4gICAgbGV0IGV2ZW50UmFuZ2UgPSBzZWcuZXZlbnRSYW5nZTtcbiAgICBsZXQgb3JpZ1JhbmdlID0gZXZlbnRSYW5nZS5yYW5nZTtcbiAgICBsZXQgc2xpY2VkUmFuZ2UgPSBpbnRlcnNlY3RSYW5nZXMob3JpZ1JhbmdlLCB7XG4gICAgICAgIHN0YXJ0OiBjZWxsc1tzcGFuU3RhcnRdLmRhdGUsXG4gICAgICAgIGVuZDogYWRkRGF5cyhjZWxsc1tzcGFuRW5kIC0gMV0uZGF0ZSwgMSksXG4gICAgfSk7XG4gICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2VnKSwgeyBmaXJzdENvbDogc3BhblN0YXJ0LCBsYXN0Q29sOiBzcGFuRW5kIC0gMSwgZXZlbnRSYW5nZToge1xuICAgICAgICAgICAgZGVmOiBldmVudFJhbmdlLmRlZixcbiAgICAgICAgICAgIHVpOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGV2ZW50UmFuZ2UudWkpLCB7IGR1cmF0aW9uRWRpdGFibGU6IGZhbHNlIH0pLFxuICAgICAgICAgICAgaW5zdGFuY2U6IGV2ZW50UmFuZ2UuaW5zdGFuY2UsXG4gICAgICAgICAgICByYW5nZTogc2xpY2VkUmFuZ2UsXG4gICAgICAgIH0sIGlzU3RhcnQ6IHNlZy5pc1N0YXJ0ICYmIHNsaWNlZFJhbmdlLnN0YXJ0LnZhbHVlT2YoKSA9PT0gb3JpZ1JhbmdlLnN0YXJ0LnZhbHVlT2YoKSwgaXNFbmQ6IHNlZy5pc0VuZCAmJiBzbGljZWRSYW5nZS5lbmQudmFsdWVPZigpID09PSBvcmlnUmFuZ2UuZW5kLnZhbHVlT2YoKSB9KTtcbn1cbmNsYXNzIERheUdyaWRTZWdIaWVyYXJjaHkgZXh0ZW5kcyBTZWdIaWVyYXJjaHkge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICAvLyBjb25maWdcbiAgICAgICAgdGhpcy5oaWRkZW5Db25zdW1lcyA9IGZhbHNlO1xuICAgICAgICAvLyBhbGxvd3MgdXMgdG8ga2VlcCBoaWRkZW4gZW50cmllcyBpbiB0aGUgaGllcmFyY2h5IHNvIHRoZXkgdGFrZSB1cCBzcGFjZVxuICAgICAgICB0aGlzLmZvcmNlSGlkZGVuID0ge307XG4gICAgfVxuICAgIGFkZFNlZ3Moc2VnSW5wdXRzKSB7XG4gICAgICAgIGNvbnN0IGhpZGRlblNlZ3MgPSBzdXBlci5hZGRTZWdzKHNlZ0lucHV0cyk7XG4gICAgICAgIGNvbnN0IHsgZW50cmllc0J5TGV2ZWwgfSA9IHRoaXM7XG4gICAgICAgIGNvbnN0IGV4Y2x1ZGVIaWRkZW4gPSAoZW50cnkpID0+ICF0aGlzLmZvcmNlSGlkZGVuW2J1aWxkRW50cnlLZXkoZW50cnkpXTtcbiAgICAgICAgLy8gcmVtb3ZlIHRoZSBmb3JjZWQtaGlkZGVuIHNlZ3NcbiAgICAgICAgZm9yIChsZXQgbGV2ZWwgPSAwOyBsZXZlbCA8IGVudHJpZXNCeUxldmVsLmxlbmd0aDsgbGV2ZWwgKz0gMSkge1xuICAgICAgICAgICAgZW50cmllc0J5TGV2ZWxbbGV2ZWxdID0gZW50cmllc0J5TGV2ZWxbbGV2ZWxdLmZpbHRlcihleGNsdWRlSGlkZGVuKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gaGlkZGVuU2VncztcbiAgICB9XG4gICAgaGFuZGxlSW52YWxpZEluc2VydGlvbihpbnNlcnRpb24sIGVudHJ5LCBoaWRkZW5FbnRyaWVzKSB7XG4gICAgICAgIGNvbnN0IHsgZW50cmllc0J5TGV2ZWwsIGZvcmNlSGlkZGVuIH0gPSB0aGlzO1xuICAgICAgICBjb25zdCB7IHRvdWNoaW5nRW50cnksIHRvdWNoaW5nTGV2ZWwsIHRvdWNoaW5nTGF0ZXJhbCB9ID0gaW5zZXJ0aW9uO1xuICAgICAgICAvLyB0aGUgZW50cnkgdGhhdCB0aGUgbmV3IGluc2VydGlvbiBpcyB0b3VjaGluZyBtdXN0IGJlIGhpZGRlblxuICAgICAgICBpZiAodGhpcy5oaWRkZW5Db25zdW1lcyAmJiB0b3VjaGluZ0VudHJ5KSB7XG4gICAgICAgICAgICBjb25zdCB0b3VjaGluZ0VudHJ5SWQgPSBidWlsZEVudHJ5S2V5KHRvdWNoaW5nRW50cnkpO1xuICAgICAgICAgICAgaWYgKCFmb3JjZUhpZGRlblt0b3VjaGluZ0VudHJ5SWRdKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuYWxsb3dSZXNsaWNpbmcpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gc3BsaXQgdXAgdGhlIHRvdWNoaW5nRW50cnksIHJlaW5zZXJ0IGl0XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGhpZGRlbkVudHJ5ID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0b3VjaGluZ0VudHJ5KSwgeyBzcGFuOiBpbnRlcnNlY3RTcGFucyh0b3VjaGluZ0VudHJ5LnNwYW4sIGVudHJ5LnNwYW4pIH0pO1xuICAgICAgICAgICAgICAgICAgICAvLyByZWluc2VydCB0aGUgYXJlYSB0aGF0IHR1cm5lZCBpbnRvIGEgXCJtb3JlXCIgbGluayAoc28gbm8gb3RoZXIgZW50cmllcyB0cnkgdG9cbiAgICAgICAgICAgICAgICAgICAgLy8gb2NjdXB5IHRoZSBzcGFjZSkgYnV0IG1hcmsgaXQgZm9yY2VkLWhpZGRlblxuICAgICAgICAgICAgICAgICAgICBjb25zdCBoaWRkZW5FbnRyeUlkID0gYnVpbGRFbnRyeUtleShoaWRkZW5FbnRyeSk7XG4gICAgICAgICAgICAgICAgICAgIGZvcmNlSGlkZGVuW2hpZGRlbkVudHJ5SWRdID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgZW50cmllc0J5TGV2ZWxbdG91Y2hpbmdMZXZlbF1bdG91Y2hpbmdMYXRlcmFsXSA9IGhpZGRlbkVudHJ5O1xuICAgICAgICAgICAgICAgICAgICBoaWRkZW5FbnRyaWVzLnB1c2goaGlkZGVuRW50cnkpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnNwbGl0RW50cnkodG91Y2hpbmdFbnRyeSwgZW50cnksIGhpZGRlbkVudHJpZXMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZm9yY2VIaWRkZW5bdG91Y2hpbmdFbnRyeUlkXSA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIGhpZGRlbkVudHJpZXMucHVzaCh0b3VjaGluZ0VudHJ5KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gd2lsbCB0cnkgdG8gcmVzbGljZS4uLlxuICAgICAgICBzdXBlci5oYW5kbGVJbnZhbGlkSW5zZXJ0aW9uKGluc2VydGlvbiwgZW50cnksIGhpZGRlbkVudHJpZXMpO1xuICAgIH1cbn1cblxuY2xhc3MgVGFibGVSb3cgZXh0ZW5kcyBEYXRlQ29tcG9uZW50IHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoLi4uYXJndW1lbnRzKTtcbiAgICAgICAgdGhpcy5jZWxsRWxSZWZzID0gbmV3IFJlZk1hcCgpOyAvLyB0aGUgPHRkPlxuICAgICAgICB0aGlzLmZyYW1lRWxSZWZzID0gbmV3IFJlZk1hcCgpOyAvLyB0aGUgZmMtZGF5Z3JpZC1kYXktZnJhbWVcbiAgICAgICAgdGhpcy5mZ0VsUmVmcyA9IG5ldyBSZWZNYXAoKTsgLy8gdGhlIGZjLWRheWdyaWQtZGF5LWV2ZW50c1xuICAgICAgICB0aGlzLnNlZ0hhcm5lc3NSZWZzID0gbmV3IFJlZk1hcCgpOyAvLyBpbmRleGVkIGJ5IFwiaW5zdGFuY2VJZDpmaXJzdENvbFwiXG4gICAgICAgIHRoaXMucm9vdEVsUmVmID0gY3JlYXRlUmVmKCk7XG4gICAgICAgIHRoaXMuc3RhdGUgPSB7XG4gICAgICAgICAgICBmcmFtZVBvc2l0aW9uczogbnVsbCxcbiAgICAgICAgICAgIG1heENvbnRlbnRIZWlnaHQ6IG51bGwsXG4gICAgICAgICAgICBzZWdIZWlnaHRzOiB7fSxcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVSZXNpemUgPSAoaXNGb3JjZWQpID0+IHtcbiAgICAgICAgICAgIGlmIChpc0ZvcmNlZCkge1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlU2l6aW5nKHRydWUpOyAvLyBpc0V4dGVybmFsPXRydWVcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG4gICAgcmVuZGVyKCkge1xuICAgICAgICBsZXQgeyBwcm9wcywgc3RhdGUsIGNvbnRleHQgfSA9IHRoaXM7XG4gICAgICAgIGxldCB7IG9wdGlvbnMgfSA9IGNvbnRleHQ7XG4gICAgICAgIGxldCBjb2xDbnQgPSBwcm9wcy5jZWxscy5sZW5ndGg7XG4gICAgICAgIGxldCBidXNpbmVzc0hvdXJzQnlDb2wgPSBzcGxpdFNlZ3NCeUZpcnN0Q29sKHByb3BzLmJ1c2luZXNzSG91clNlZ3MsIGNvbENudCk7XG4gICAgICAgIGxldCBiZ0V2ZW50U2Vnc0J5Q29sID0gc3BsaXRTZWdzQnlGaXJzdENvbChwcm9wcy5iZ0V2ZW50U2VncywgY29sQ250KTtcbiAgICAgICAgbGV0IGhpZ2hsaWdodFNlZ3NCeUNvbCA9IHNwbGl0U2Vnc0J5Rmlyc3RDb2wodGhpcy5nZXRIaWdobGlnaHRTZWdzKCksIGNvbENudCk7XG4gICAgICAgIGxldCBtaXJyb3JTZWdzQnlDb2wgPSBzcGxpdFNlZ3NCeUZpcnN0Q29sKHRoaXMuZ2V0TWlycm9yU2VncygpLCBjb2xDbnQpO1xuICAgICAgICBsZXQgeyBzaW5nbGVDb2xQbGFjZW1lbnRzLCBtdWx0aUNvbFBsYWNlbWVudHMsIG1vcmVDbnRzLCBtb3JlTWFyZ2luVG9wcyB9ID0gY29tcHV0ZUZnU2VnUGxhY2VtZW50KHNvcnRFdmVudFNlZ3MocHJvcHMuZmdFdmVudFNlZ3MsIG9wdGlvbnMuZXZlbnRPcmRlciksIHByb3BzLmRheU1heEV2ZW50cywgcHJvcHMuZGF5TWF4RXZlbnRSb3dzLCBvcHRpb25zLmV2ZW50T3JkZXJTdHJpY3QsIHN0YXRlLnNlZ0hlaWdodHMsIHN0YXRlLm1heENvbnRlbnRIZWlnaHQsIHByb3BzLmNlbGxzKTtcbiAgICAgICAgbGV0IGlzRm9yY2VkSW52aXNpYmxlID0gLy8gVE9ETzogbWVzc3kgd2F5IHRvIGNvbXB1dGUgdGhpc1xuICAgICAgICAgKHByb3BzLmV2ZW50RHJhZyAmJiBwcm9wcy5ldmVudERyYWcuYWZmZWN0ZWRJbnN0YW5jZXMpIHx8XG4gICAgICAgICAgICAocHJvcHMuZXZlbnRSZXNpemUgJiYgcHJvcHMuZXZlbnRSZXNpemUuYWZmZWN0ZWRJbnN0YW5jZXMpIHx8XG4gICAgICAgICAgICB7fTtcbiAgICAgICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KFwidHJcIiwgeyByZWY6IHRoaXMucm9vdEVsUmVmLCByb2xlOiBcInJvd1wiIH0sXG4gICAgICAgICAgICBwcm9wcy5yZW5kZXJJbnRybyAmJiBwcm9wcy5yZW5kZXJJbnRybygpLFxuICAgICAgICAgICAgcHJvcHMuY2VsbHMubWFwKChjZWxsLCBjb2wpID0+IHtcbiAgICAgICAgICAgICAgICBsZXQgbm9ybWFsRmdOb2RlcyA9IHRoaXMucmVuZGVyRmdTZWdzKGNvbCwgcHJvcHMuZm9yUHJpbnQgPyBzaW5nbGVDb2xQbGFjZW1lbnRzW2NvbF0gOiBtdWx0aUNvbFBsYWNlbWVudHNbY29sXSwgcHJvcHMudG9kYXlSYW5nZSwgaXNGb3JjZWRJbnZpc2libGUpO1xuICAgICAgICAgICAgICAgIGxldCBtaXJyb3JGZ05vZGVzID0gdGhpcy5yZW5kZXJGZ1NlZ3MoY29sLCBidWlsZE1pcnJvclBsYWNlbWVudHMobWlycm9yU2Vnc0J5Q29sW2NvbF0sIG11bHRpQ29sUGxhY2VtZW50cyksIHByb3BzLnRvZGF5UmFuZ2UsIHt9LCBCb29sZWFuKHByb3BzLmV2ZW50RHJhZyksIEJvb2xlYW4ocHJvcHMuZXZlbnRSZXNpemUpLCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KFRhYmxlQ2VsbCwgeyBrZXk6IGNlbGwua2V5LCBlbFJlZjogdGhpcy5jZWxsRWxSZWZzLmNyZWF0ZVJlZihjZWxsLmtleSksIGlubmVyRWxSZWY6IHRoaXMuZnJhbWVFbFJlZnMuY3JlYXRlUmVmKGNlbGwua2V5KSAvKiBGRiA8dGQ+IHByb2JsZW0sIGJ1dCBva2F5IHRvIHVzZSBmb3IgbGVmdC9yaWdodC4gVE9ETzogcmVuYW1lIHByb3AgKi8sIGRhdGVQcm9maWxlOiBwcm9wcy5kYXRlUHJvZmlsZSwgZGF0ZTogY2VsbC5kYXRlLCBzaG93RGF5TnVtYmVyOiBwcm9wcy5zaG93RGF5TnVtYmVycywgc2hvd1dlZWtOdW1iZXI6IHByb3BzLnNob3dXZWVrTnVtYmVycyAmJiBjb2wgPT09IDAsIGZvcmNlRGF5VG9wOiBwcm9wcy5zaG93V2Vla051bWJlcnMgLyogZXZlbiBkaXNwbGF5aW5nIHdlZWtudW0gZm9yIHJvdywgbm90IG5lY2Vzc2FyaWx5IGRheSAqLywgdG9kYXlSYW5nZTogcHJvcHMudG9kYXlSYW5nZSwgZXZlbnRTZWxlY3Rpb246IHByb3BzLmV2ZW50U2VsZWN0aW9uLCBldmVudERyYWc6IHByb3BzLmV2ZW50RHJhZywgZXZlbnRSZXNpemU6IHByb3BzLmV2ZW50UmVzaXplLCBleHRyYVJlbmRlclByb3BzOiBjZWxsLmV4dHJhUmVuZGVyUHJvcHMsIGV4dHJhRGF0YUF0dHJzOiBjZWxsLmV4dHJhRGF0YUF0dHJzLCBleHRyYUNsYXNzTmFtZXM6IGNlbGwuZXh0cmFDbGFzc05hbWVzLCBleHRyYURhdGVTcGFuOiBjZWxsLmV4dHJhRGF0ZVNwYW4sIG1vcmVDbnQ6IG1vcmVDbnRzW2NvbF0sIG1vcmVNYXJnaW5Ub3A6IG1vcmVNYXJnaW5Ub3BzW2NvbF0sIHNpbmdsZVBsYWNlbWVudHM6IHNpbmdsZUNvbFBsYWNlbWVudHNbY29sXSwgZmdDb250ZW50RWxSZWY6IHRoaXMuZmdFbFJlZnMuY3JlYXRlUmVmKGNlbGwua2V5KSwgZmdDb250ZW50OiAoIC8vIEZyYWdtZW50IHNjb3BlcyB0aGUga2V5c1xuICAgICAgICAgICAgICAgICAgICBjcmVhdGVFbGVtZW50KEZyYWdtZW50LCBudWxsLFxuICAgICAgICAgICAgICAgICAgICAgICAgY3JlYXRlRWxlbWVudChGcmFnbWVudCwgbnVsbCwgbm9ybWFsRmdOb2RlcyksXG4gICAgICAgICAgICAgICAgICAgICAgICBjcmVhdGVFbGVtZW50KEZyYWdtZW50LCBudWxsLCBtaXJyb3JGZ05vZGVzKSkpLCBiZ0NvbnRlbnQ6ICggLy8gRnJhZ21lbnQgc2NvcGVzIHRoZSBrZXlzXG4gICAgICAgICAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoRnJhZ21lbnQsIG51bGwsXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJlbmRlckZpbGxTZWdzKGhpZ2hsaWdodFNlZ3NCeUNvbFtjb2xdLCAnaGlnaGxpZ2h0JyksXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJlbmRlckZpbGxTZWdzKGJ1c2luZXNzSG91cnNCeUNvbFtjb2xdLCAnbm9uLWJ1c2luZXNzJyksXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJlbmRlckZpbGxTZWdzKGJnRXZlbnRTZWdzQnlDb2xbY29sXSwgJ2JnLWV2ZW50JykpKSwgbWluSGVpZ2h0OiBwcm9wcy5jZWxsTWluSGVpZ2h0IH0pKTtcbiAgICAgICAgICAgIH0pKSk7XG4gICAgfVxuICAgIGNvbXBvbmVudERpZE1vdW50KCkge1xuICAgICAgICB0aGlzLnVwZGF0ZVNpemluZyh0cnVlKTtcbiAgICAgICAgdGhpcy5jb250ZXh0LmFkZFJlc2l6ZUhhbmRsZXIodGhpcy5oYW5kbGVSZXNpemUpO1xuICAgIH1cbiAgICBjb21wb25lbnREaWRVcGRhdGUocHJldlByb3BzLCBwcmV2U3RhdGUpIHtcbiAgICAgICAgbGV0IGN1cnJlbnRQcm9wcyA9IHRoaXMucHJvcHM7XG4gICAgICAgIHRoaXMudXBkYXRlU2l6aW5nKCFpc1Byb3BzRXF1YWwocHJldlByb3BzLCBjdXJyZW50UHJvcHMpKTtcbiAgICB9XG4gICAgY29tcG9uZW50V2lsbFVubW91bnQoKSB7XG4gICAgICAgIHRoaXMuY29udGV4dC5yZW1vdmVSZXNpemVIYW5kbGVyKHRoaXMuaGFuZGxlUmVzaXplKTtcbiAgICB9XG4gICAgZ2V0SGlnaGxpZ2h0U2VncygpIHtcbiAgICAgICAgbGV0IHsgcHJvcHMgfSA9IHRoaXM7XG4gICAgICAgIGlmIChwcm9wcy5ldmVudERyYWcgJiYgcHJvcHMuZXZlbnREcmFnLnNlZ3MubGVuZ3RoKSB7IC8vIG1lc3N5IGNoZWNrXG4gICAgICAgICAgICByZXR1cm4gcHJvcHMuZXZlbnREcmFnLnNlZ3M7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHByb3BzLmV2ZW50UmVzaXplICYmIHByb3BzLmV2ZW50UmVzaXplLnNlZ3MubGVuZ3RoKSB7IC8vIG1lc3N5IGNoZWNrXG4gICAgICAgICAgICByZXR1cm4gcHJvcHMuZXZlbnRSZXNpemUuc2VncztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcHJvcHMuZGF0ZVNlbGVjdGlvblNlZ3M7XG4gICAgfVxuICAgIGdldE1pcnJvclNlZ3MoKSB7XG4gICAgICAgIGxldCB7IHByb3BzIH0gPSB0aGlzO1xuICAgICAgICBpZiAocHJvcHMuZXZlbnRSZXNpemUgJiYgcHJvcHMuZXZlbnRSZXNpemUuc2Vncy5sZW5ndGgpIHsgLy8gbWVzc3kgY2hlY2tcbiAgICAgICAgICAgIHJldHVybiBwcm9wcy5ldmVudFJlc2l6ZS5zZWdzO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gICAgcmVuZGVyRmdTZWdzKGNvbCwgc2VnUGxhY2VtZW50cywgdG9kYXlSYW5nZSwgaXNGb3JjZWRJbnZpc2libGUsIGlzRHJhZ2dpbmcsIGlzUmVzaXppbmcsIGlzRGF0ZVNlbGVjdGluZykge1xuICAgICAgICBsZXQgeyBjb250ZXh0IH0gPSB0aGlzO1xuICAgICAgICBsZXQgeyBldmVudFNlbGVjdGlvbiB9ID0gdGhpcy5wcm9wcztcbiAgICAgICAgbGV0IHsgZnJhbWVQb3NpdGlvbnMgfSA9IHRoaXMuc3RhdGU7XG4gICAgICAgIGxldCBkZWZhdWx0RGlzcGxheUV2ZW50RW5kID0gdGhpcy5wcm9wcy5jZWxscy5sZW5ndGggPT09IDE7IC8vIGNvbENudCA9PT0gMVxuICAgICAgICBsZXQgaXNNaXJyb3IgPSBpc0RyYWdnaW5nIHx8IGlzUmVzaXppbmcgfHwgaXNEYXRlU2VsZWN0aW5nO1xuICAgICAgICBsZXQgbm9kZXMgPSBbXTtcbiAgICAgICAgaWYgKGZyYW1lUG9zaXRpb25zKSB7XG4gICAgICAgICAgICBmb3IgKGxldCBwbGFjZW1lbnQgb2Ygc2VnUGxhY2VtZW50cykge1xuICAgICAgICAgICAgICAgIGxldCB7IHNlZyB9ID0gcGxhY2VtZW50O1xuICAgICAgICAgICAgICAgIGxldCB7IGluc3RhbmNlSWQgfSA9IHNlZy5ldmVudFJhbmdlLmluc3RhbmNlO1xuICAgICAgICAgICAgICAgIGxldCBpc1Zpc2libGUgPSBwbGFjZW1lbnQuaXNWaXNpYmxlICYmICFpc0ZvcmNlZEludmlzaWJsZVtpbnN0YW5jZUlkXTtcbiAgICAgICAgICAgICAgICBsZXQgaXNBYnNvbHV0ZSA9IHBsYWNlbWVudC5pc0Fic29sdXRlO1xuICAgICAgICAgICAgICAgIGxldCBsZWZ0ID0gJyc7XG4gICAgICAgICAgICAgICAgbGV0IHJpZ2h0ID0gJyc7XG4gICAgICAgICAgICAgICAgaWYgKGlzQWJzb2x1dGUpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNvbnRleHQuaXNSdGwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJpZ2h0ID0gMDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxlZnQgPSBmcmFtZVBvc2l0aW9ucy5sZWZ0c1tzZWcubGFzdENvbF0gLSBmcmFtZVBvc2l0aW9ucy5sZWZ0c1tzZWcuZmlyc3RDb2xdO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGVmdCA9IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICByaWdodCA9IGZyYW1lUG9zaXRpb25zLnJpZ2h0c1tzZWcuZmlyc3RDb2xdIC0gZnJhbWVQb3NpdGlvbnMucmlnaHRzW3NlZy5sYXN0Q29sXTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvKlxuICAgICAgICAgICAgICAgIGtub3duIGJ1ZzogZXZlbnRzIHRoYXQgYXJlIGZvcmNlIHRvIGJlIGxpc3QtaXRlbSBidXQgc3BhbiBtdWx0aXBsZSBkYXlzIHN0aWxsIHRha2UgdXAgc3BhY2UgaW4gbGF0ZXIgY29sdW1uc1xuICAgICAgICAgICAgICAgIHRvZG86IGluIHByaW50IHZpZXcsIGZvciBtdWx0aS1kYXkgZXZlbnRzLCBkb24ndCBkaXNwbGF5IHRpdGxlIHdpdGhpbiBub24tc3RhcnQvZW5kIHNlZ3NcbiAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIG5vZGVzLnB1c2goY3JlYXRlRWxlbWVudChcImRpdlwiLCB7IGNsYXNzTmFtZTogJ2ZjLWRheWdyaWQtZXZlbnQtaGFybmVzcycgKyAoaXNBYnNvbHV0ZSA/ICcgZmMtZGF5Z3JpZC1ldmVudC1oYXJuZXNzLWFicycgOiAnJyksIGtleTogZ2VuZXJhdGVTZWdLZXkoc2VnKSwgcmVmOiBpc01pcnJvciA/IG51bGwgOiB0aGlzLnNlZ0hhcm5lc3NSZWZzLmNyZWF0ZVJlZihnZW5lcmF0ZVNlZ1VpZChzZWcpKSwgc3R5bGU6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZpc2liaWxpdHk6IGlzVmlzaWJsZSA/ICcnIDogJ2hpZGRlbicsXG4gICAgICAgICAgICAgICAgICAgICAgICBtYXJnaW5Ub3A6IGlzQWJzb2x1dGUgPyAnJyA6IHBsYWNlbWVudC5tYXJnaW5Ub3AsXG4gICAgICAgICAgICAgICAgICAgICAgICB0b3A6IGlzQWJzb2x1dGUgPyBwbGFjZW1lbnQuYWJzb2x1dGVUb3AgOiAnJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGxlZnQsXG4gICAgICAgICAgICAgICAgICAgICAgICByaWdodCxcbiAgICAgICAgICAgICAgICAgICAgfSB9LCBoYXNMaXN0SXRlbURpc3BsYXkoc2VnKSA/IChjcmVhdGVFbGVtZW50KFRhYmxlTGlzdEl0ZW1FdmVudCwgT2JqZWN0LmFzc2lnbih7IHNlZzogc2VnLCBpc0RyYWdnaW5nOiBpc0RyYWdnaW5nLCBpc1NlbGVjdGVkOiBpbnN0YW5jZUlkID09PSBldmVudFNlbGVjdGlvbiwgZGVmYXVsdERpc3BsYXlFdmVudEVuZDogZGVmYXVsdERpc3BsYXlFdmVudEVuZCB9LCBnZXRTZWdNZXRhKHNlZywgdG9kYXlSYW5nZSkpKSkgOiAoY3JlYXRlRWxlbWVudChUYWJsZUJsb2NrRXZlbnQsIE9iamVjdC5hc3NpZ24oeyBzZWc6IHNlZywgaXNEcmFnZ2luZzogaXNEcmFnZ2luZywgaXNSZXNpemluZzogaXNSZXNpemluZywgaXNEYXRlU2VsZWN0aW5nOiBpc0RhdGVTZWxlY3RpbmcsIGlzU2VsZWN0ZWQ6IGluc3RhbmNlSWQgPT09IGV2ZW50U2VsZWN0aW9uLCBkZWZhdWx0RGlzcGxheUV2ZW50RW5kOiBkZWZhdWx0RGlzcGxheUV2ZW50RW5kIH0sIGdldFNlZ01ldGEoc2VnLCB0b2RheVJhbmdlKSkpKSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBub2RlcztcbiAgICB9XG4gICAgcmVuZGVyRmlsbFNlZ3Moc2VncywgZmlsbFR5cGUpIHtcbiAgICAgICAgbGV0IHsgaXNSdGwgfSA9IHRoaXMuY29udGV4dDtcbiAgICAgICAgbGV0IHsgdG9kYXlSYW5nZSB9ID0gdGhpcy5wcm9wcztcbiAgICAgICAgbGV0IHsgZnJhbWVQb3NpdGlvbnMgfSA9IHRoaXMuc3RhdGU7XG4gICAgICAgIGxldCBub2RlcyA9IFtdO1xuICAgICAgICBpZiAoZnJhbWVQb3NpdGlvbnMpIHtcbiAgICAgICAgICAgIGZvciAobGV0IHNlZyBvZiBzZWdzKSB7XG4gICAgICAgICAgICAgICAgbGV0IGxlZnRSaWdodENzcyA9IGlzUnRsID8ge1xuICAgICAgICAgICAgICAgICAgICByaWdodDogMCxcbiAgICAgICAgICAgICAgICAgICAgbGVmdDogZnJhbWVQb3NpdGlvbnMubGVmdHNbc2VnLmxhc3RDb2xdIC0gZnJhbWVQb3NpdGlvbnMubGVmdHNbc2VnLmZpcnN0Q29sXSxcbiAgICAgICAgICAgICAgICB9IDoge1xuICAgICAgICAgICAgICAgICAgICBsZWZ0OiAwLFxuICAgICAgICAgICAgICAgICAgICByaWdodDogZnJhbWVQb3NpdGlvbnMucmlnaHRzW3NlZy5maXJzdENvbF0gLSBmcmFtZVBvc2l0aW9ucy5yaWdodHNbc2VnLmxhc3RDb2xdLFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgbm9kZXMucHVzaChjcmVhdGVFbGVtZW50KFwiZGl2XCIsIHsga2V5OiBidWlsZEV2ZW50UmFuZ2VLZXkoc2VnLmV2ZW50UmFuZ2UpLCBjbGFzc05hbWU6IFwiZmMtZGF5Z3JpZC1iZy1oYXJuZXNzXCIsIHN0eWxlOiBsZWZ0UmlnaHRDc3MgfSwgZmlsbFR5cGUgPT09ICdiZy1ldmVudCcgP1xuICAgICAgICAgICAgICAgICAgICBjcmVhdGVFbGVtZW50KEJnRXZlbnQsIE9iamVjdC5hc3NpZ24oeyBzZWc6IHNlZyB9LCBnZXRTZWdNZXRhKHNlZywgdG9kYXlSYW5nZSkpKSA6XG4gICAgICAgICAgICAgICAgICAgIHJlbmRlckZpbGwoZmlsbFR5cGUpKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGNyZWF0ZUVsZW1lbnQoRnJhZ21lbnQsIHt9LCAuLi5ub2Rlcyk7XG4gICAgfVxuICAgIHVwZGF0ZVNpemluZyhpc0V4dGVybmFsU2l6aW5nQ2hhbmdlKSB7XG4gICAgICAgIGxldCB7IHByb3BzLCBzdGF0ZSwgZnJhbWVFbFJlZnMgfSA9IHRoaXM7XG4gICAgICAgIGlmICghcHJvcHMuZm9yUHJpbnQgJiZcbiAgICAgICAgICAgIHByb3BzLmNsaWVudFdpZHRoICE9PSBudWxsIC8vIHBvc2l0aW9uaW5nIHJlYWR5P1xuICAgICAgICApIHtcbiAgICAgICAgICAgIGlmIChpc0V4dGVybmFsU2l6aW5nQ2hhbmdlKSB7XG4gICAgICAgICAgICAgICAgbGV0IGZyYW1lRWxzID0gcHJvcHMuY2VsbHMubWFwKChjZWxsKSA9PiBmcmFtZUVsUmVmcy5jdXJyZW50TWFwW2NlbGwua2V5XSk7XG4gICAgICAgICAgICAgICAgaWYgKGZyYW1lRWxzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICBsZXQgb3JpZ2luRWwgPSB0aGlzLnJvb3RFbFJlZi5jdXJyZW50O1xuICAgICAgICAgICAgICAgICAgICBsZXQgbmV3UG9zaXRpb25DYWNoZSA9IG5ldyBQb3NpdGlvbkNhY2hlKG9yaWdpbkVsLCBmcmFtZUVscywgdHJ1ZSwgLy8gaXNIb3Jpem9udGFsXG4gICAgICAgICAgICAgICAgICAgIGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFzdGF0ZS5mcmFtZVBvc2l0aW9ucyB8fCAhc3RhdGUuZnJhbWVQb3NpdGlvbnMuc2ltaWxhclRvKG5ld1Bvc2l0aW9uQ2FjaGUpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmcmFtZVBvc2l0aW9uczogbmV3IFBvc2l0aW9uQ2FjaGUob3JpZ2luRWwsIGZyYW1lRWxzLCB0cnVlLCAvLyBpc0hvcml6b250YWxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWxzZSksXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IG9sZFNlZ0hlaWdodHMgPSB0aGlzLnN0YXRlLnNlZ0hlaWdodHM7XG4gICAgICAgICAgICBjb25zdCBuZXdTZWdIZWlnaHRzID0gdGhpcy5xdWVyeVNlZ0hlaWdodHMoKTtcbiAgICAgICAgICAgIGNvbnN0IGxpbWl0QnlDb250ZW50SGVpZ2h0ID0gcHJvcHMuZGF5TWF4RXZlbnRzID09PSB0cnVlIHx8IHByb3BzLmRheU1heEV2ZW50Um93cyA9PT0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMuc2FmZVNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICAvLyBIQUNLIHRvIHByZXZlbnQgb3NjaWxsYXRpb25zIG9mIGV2ZW50cyBiZWluZyBzaG93bi9oaWRkZW4gZnJvbSBtYXgtZXZlbnQtcm93c1xuICAgICAgICAgICAgICAgIC8vIEVzc2VudGlhbGx5LCBvbmNlIHlvdSBjb21wdXRlIGFuIGVsZW1lbnQncyBoZWlnaHQsIG5ldmVyIG51bGwtb3V0LlxuICAgICAgICAgICAgICAgIC8vIFRPRE86IGFsd2F5cyBkaXNwbGF5IGFsbCBldmVudHMsIGFzIHZpc2liaWxpdHk6aGlkZGVuP1xuICAgICAgICAgICAgICAgIHNlZ0hlaWdodHM6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgb2xkU2VnSGVpZ2h0cyksIG5ld1NlZ0hlaWdodHMpLFxuICAgICAgICAgICAgICAgIG1heENvbnRlbnRIZWlnaHQ6IGxpbWl0QnlDb250ZW50SGVpZ2h0ID8gdGhpcy5jb21wdXRlTWF4Q29udGVudEhlaWdodCgpIDogbnVsbCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIHF1ZXJ5U2VnSGVpZ2h0cygpIHtcbiAgICAgICAgbGV0IHNlZ0VsTWFwID0gdGhpcy5zZWdIYXJuZXNzUmVmcy5jdXJyZW50TWFwO1xuICAgICAgICBsZXQgc2VnSGVpZ2h0cyA9IHt9O1xuICAgICAgICAvLyBnZXQgdGhlIG1heCBoZWlnaHQgYW1vbmdzdCBpbnN0YW5jZSBzZWdzXG4gICAgICAgIGZvciAobGV0IHNlZ1VpZCBpbiBzZWdFbE1hcCkge1xuICAgICAgICAgICAgbGV0IGhlaWdodCA9IE1hdGgucm91bmQoc2VnRWxNYXBbc2VnVWlkXS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5oZWlnaHQpO1xuICAgICAgICAgICAgc2VnSGVpZ2h0c1tzZWdVaWRdID0gTWF0aC5tYXgoc2VnSGVpZ2h0c1tzZWdVaWRdIHx8IDAsIGhlaWdodCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlZ0hlaWdodHM7XG4gICAgfVxuICAgIGNvbXB1dGVNYXhDb250ZW50SGVpZ2h0KCkge1xuICAgICAgICBsZXQgZmlyc3RLZXkgPSB0aGlzLnByb3BzLmNlbGxzWzBdLmtleTtcbiAgICAgICAgbGV0IGNlbGxFbCA9IHRoaXMuY2VsbEVsUmVmcy5jdXJyZW50TWFwW2ZpcnN0S2V5XTtcbiAgICAgICAgbGV0IGZjQ29udGFpbmVyRWwgPSB0aGlzLmZnRWxSZWZzLmN1cnJlbnRNYXBbZmlyc3RLZXldO1xuICAgICAgICByZXR1cm4gY2VsbEVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmJvdHRvbSAtIGZjQ29udGFpbmVyRWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkudG9wO1xuICAgIH1cbiAgICBnZXRDZWxsRWxzKCkge1xuICAgICAgICBsZXQgZWxNYXAgPSB0aGlzLmNlbGxFbFJlZnMuY3VycmVudE1hcDtcbiAgICAgICAgcmV0dXJuIHRoaXMucHJvcHMuY2VsbHMubWFwKChjZWxsKSA9PiBlbE1hcFtjZWxsLmtleV0pO1xuICAgIH1cbn1cblRhYmxlUm93LmFkZFN0YXRlRXF1YWxpdHkoe1xuICAgIHNlZ0hlaWdodHM6IGlzUHJvcHNFcXVhbCxcbn0pO1xuZnVuY3Rpb24gYnVpbGRNaXJyb3JQbGFjZW1lbnRzKG1pcnJvclNlZ3MsIGNvbFBsYWNlbWVudHMpIHtcbiAgICBpZiAoIW1pcnJvclNlZ3MubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gICAgbGV0IHRvcHNCeUluc3RhbmNlSWQgPSBidWlsZEFic29sdXRlVG9wSGFzaChjb2xQbGFjZW1lbnRzKTsgLy8gVE9ETzogY2FjaGUgdGhpcyBhdCBmaXJzdCByZW5kZXI/XG4gICAgcmV0dXJuIG1pcnJvclNlZ3MubWFwKChzZWcpID0+ICh7XG4gICAgICAgIHNlZyxcbiAgICAgICAgaXNWaXNpYmxlOiB0cnVlLFxuICAgICAgICBpc0Fic29sdXRlOiB0cnVlLFxuICAgICAgICBhYnNvbHV0ZVRvcDogdG9wc0J5SW5zdGFuY2VJZFtzZWcuZXZlbnRSYW5nZS5pbnN0YW5jZS5pbnN0YW5jZUlkXSxcbiAgICAgICAgbWFyZ2luVG9wOiAwLFxuICAgIH0pKTtcbn1cbmZ1bmN0aW9uIGJ1aWxkQWJzb2x1dGVUb3BIYXNoKGNvbFBsYWNlbWVudHMpIHtcbiAgICBsZXQgdG9wc0J5SW5zdGFuY2VJZCA9IHt9O1xuICAgIGZvciAobGV0IHBsYWNlbWVudHMgb2YgY29sUGxhY2VtZW50cykge1xuICAgICAgICBmb3IgKGxldCBwbGFjZW1lbnQgb2YgcGxhY2VtZW50cykge1xuICAgICAgICAgICAgdG9wc0J5SW5zdGFuY2VJZFtwbGFjZW1lbnQuc2VnLmV2ZW50UmFuZ2UuaW5zdGFuY2UuaW5zdGFuY2VJZF0gPSBwbGFjZW1lbnQuYWJzb2x1dGVUb3A7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRvcHNCeUluc3RhbmNlSWQ7XG59XG5cbmNsYXNzIFRhYmxlUm93cyBleHRlbmRzIERhdGVDb21wb25lbnQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICB0aGlzLnNwbGl0QnVzaW5lc3NIb3VyU2VncyA9IG1lbW9pemUoc3BsaXRTZWdzQnlSb3cpO1xuICAgICAgICB0aGlzLnNwbGl0QmdFdmVudFNlZ3MgPSBtZW1vaXplKHNwbGl0QWxsRGF5U2Vnc0J5Um93KTtcbiAgICAgICAgdGhpcy5zcGxpdEZnRXZlbnRTZWdzID0gbWVtb2l6ZShzcGxpdFNlZ3NCeVJvdyk7XG4gICAgICAgIHRoaXMuc3BsaXREYXRlU2VsZWN0aW9uU2VncyA9IG1lbW9pemUoc3BsaXRTZWdzQnlSb3cpO1xuICAgICAgICB0aGlzLnNwbGl0RXZlbnREcmFnID0gbWVtb2l6ZShzcGxpdEludGVyYWN0aW9uQnlSb3cpO1xuICAgICAgICB0aGlzLnNwbGl0RXZlbnRSZXNpemUgPSBtZW1vaXplKHNwbGl0SW50ZXJhY3Rpb25CeVJvdyk7XG4gICAgICAgIHRoaXMucm93UmVmcyA9IG5ldyBSZWZNYXAoKTtcbiAgICB9XG4gICAgcmVuZGVyKCkge1xuICAgICAgICBsZXQgeyBwcm9wcywgY29udGV4dCB9ID0gdGhpcztcbiAgICAgICAgbGV0IHJvd0NudCA9IHByb3BzLmNlbGxzLmxlbmd0aDtcbiAgICAgICAgbGV0IGJ1c2luZXNzSG91clNlZ3NCeVJvdyA9IHRoaXMuc3BsaXRCdXNpbmVzc0hvdXJTZWdzKHByb3BzLmJ1c2luZXNzSG91clNlZ3MsIHJvd0NudCk7XG4gICAgICAgIGxldCBiZ0V2ZW50U2Vnc0J5Um93ID0gdGhpcy5zcGxpdEJnRXZlbnRTZWdzKHByb3BzLmJnRXZlbnRTZWdzLCByb3dDbnQpO1xuICAgICAgICBsZXQgZmdFdmVudFNlZ3NCeVJvdyA9IHRoaXMuc3BsaXRGZ0V2ZW50U2Vncyhwcm9wcy5mZ0V2ZW50U2Vncywgcm93Q250KTtcbiAgICAgICAgbGV0IGRhdGVTZWxlY3Rpb25TZWdzQnlSb3cgPSB0aGlzLnNwbGl0RGF0ZVNlbGVjdGlvblNlZ3MocHJvcHMuZGF0ZVNlbGVjdGlvblNlZ3MsIHJvd0NudCk7XG4gICAgICAgIGxldCBldmVudERyYWdCeVJvdyA9IHRoaXMuc3BsaXRFdmVudERyYWcocHJvcHMuZXZlbnREcmFnLCByb3dDbnQpO1xuICAgICAgICBsZXQgZXZlbnRSZXNpemVCeVJvdyA9IHRoaXMuc3BsaXRFdmVudFJlc2l6ZShwcm9wcy5ldmVudFJlc2l6ZSwgcm93Q250KTtcbiAgICAgICAgLy8gZm9yIERheUdyaWQgdmlldyB3aXRoIG1hbnkgcm93cywgZm9yY2UgYSBtaW4taGVpZ2h0IG9uIGNlbGxzIHNvIGRvZXNuJ3QgYXBwZWFyIHNxdWlzaGVkXG4gICAgICAgIC8vIGNob29zZSA3IGJlY2F1c2UgYSBtb250aCB2aWV3IHdpbGwgaGF2ZSBtYXggNiByb3dzXG4gICAgICAgIGxldCBjZWxsTWluSGVpZ2h0ID0gKHJvd0NudCA+PSA3ICYmIHByb3BzLmNsaWVudFdpZHRoKSA/XG4gICAgICAgICAgICBwcm9wcy5jbGllbnRXaWR0aCAvIGNvbnRleHQub3B0aW9ucy5hc3BlY3RSYXRpbyAvIDYgOlxuICAgICAgICAgICAgbnVsbDtcbiAgICAgICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KE5vd1RpbWVyLCB7IHVuaXQ6IFwiZGF5XCIgfSwgKG5vd0RhdGUsIHRvZGF5UmFuZ2UpID0+IChjcmVhdGVFbGVtZW50KEZyYWdtZW50LCBudWxsLCBwcm9wcy5jZWxscy5tYXAoKGNlbGxzLCByb3cpID0+IChjcmVhdGVFbGVtZW50KFRhYmxlUm93LCB7IHJlZjogdGhpcy5yb3dSZWZzLmNyZWF0ZVJlZihyb3cpLCBrZXk6IGNlbGxzLmxlbmd0aFxuICAgICAgICAgICAgICAgID8gY2VsbHNbMF0uZGF0ZS50b0lTT1N0cmluZygpIC8qIGJlc3Q/IG9yIHB1dCBrZXkgb24gY2VsbD8gb3IgdXNlIGRpZmYgZm9ybWF0dGVyPyAqL1xuICAgICAgICAgICAgICAgIDogcm93IC8vIGluIGNhc2UgdGhlcmUgYXJlIG5vIGNlbGxzIChsaWtlIHdoZW4gcmVzb3VyY2UgdmlldyBpcyBsb2FkaW5nKVxuICAgICAgICAgICAgLCBzaG93RGF5TnVtYmVyczogcm93Q250ID4gMSwgc2hvd1dlZWtOdW1iZXJzOiBwcm9wcy5zaG93V2Vla051bWJlcnMsIHRvZGF5UmFuZ2U6IHRvZGF5UmFuZ2UsIGRhdGVQcm9maWxlOiBwcm9wcy5kYXRlUHJvZmlsZSwgY2VsbHM6IGNlbGxzLCByZW5kZXJJbnRybzogcHJvcHMucmVuZGVyUm93SW50cm8sIGJ1c2luZXNzSG91clNlZ3M6IGJ1c2luZXNzSG91clNlZ3NCeVJvd1tyb3ddLCBldmVudFNlbGVjdGlvbjogcHJvcHMuZXZlbnRTZWxlY3Rpb24sIGJnRXZlbnRTZWdzOiBiZ0V2ZW50U2Vnc0J5Um93W3Jvd10sIGZnRXZlbnRTZWdzOiBmZ0V2ZW50U2Vnc0J5Um93W3Jvd10sIGRhdGVTZWxlY3Rpb25TZWdzOiBkYXRlU2VsZWN0aW9uU2Vnc0J5Um93W3Jvd10sIGV2ZW50RHJhZzogZXZlbnREcmFnQnlSb3dbcm93XSwgZXZlbnRSZXNpemU6IGV2ZW50UmVzaXplQnlSb3dbcm93XSwgZGF5TWF4RXZlbnRzOiBwcm9wcy5kYXlNYXhFdmVudHMsIGRheU1heEV2ZW50Um93czogcHJvcHMuZGF5TWF4RXZlbnRSb3dzLCBjbGllbnRXaWR0aDogcHJvcHMuY2xpZW50V2lkdGgsIGNsaWVudEhlaWdodDogcHJvcHMuY2xpZW50SGVpZ2h0LCBjZWxsTWluSGVpZ2h0OiBjZWxsTWluSGVpZ2h0LCBmb3JQcmludDogcHJvcHMuZm9yUHJpbnQgfSkpKSkpKSk7XG4gICAgfVxuICAgIGNvbXBvbmVudERpZE1vdW50KCkge1xuICAgICAgICB0aGlzLnJlZ2lzdGVySW50ZXJhY3RpdmVDb21wb25lbnQoKTtcbiAgICB9XG4gICAgY29tcG9uZW50RGlkVXBkYXRlKCkge1xuICAgICAgICAvLyBmb3IgaWYgc3RhcnRlZCB3aXRoIHplcm8gY2VsbHNcbiAgICAgICAgdGhpcy5yZWdpc3RlckludGVyYWN0aXZlQ29tcG9uZW50KCk7XG4gICAgfVxuICAgIHJlZ2lzdGVySW50ZXJhY3RpdmVDb21wb25lbnQoKSB7XG4gICAgICAgIGlmICghdGhpcy5yb290RWwpIHtcbiAgICAgICAgICAgIC8vIEhBQ0s6IG5lZWQgYSBkYXlncmlkIHdyYXBwZXIgcGFyZW50IHRvIGRvIHBvc2l0aW9uaW5nXG4gICAgICAgICAgICAvLyBOT1RFOiBhIGRheWdyaWQgcmVzb3VyY2UgdmlldyB3L28gcmVzb3VyY2VzIGNhbiBoYXZlIHplcm8gY2VsbHNcbiAgICAgICAgICAgIGNvbnN0IGZpcnN0Q2VsbEVsID0gdGhpcy5yb3dSZWZzLmN1cnJlbnRNYXBbMF0uZ2V0Q2VsbEVscygpWzBdO1xuICAgICAgICAgICAgY29uc3Qgcm9vdEVsID0gZmlyc3RDZWxsRWwgPyBmaXJzdENlbGxFbC5jbG9zZXN0KCcuZmMtZGF5Z3JpZC1ib2R5JykgOiBudWxsO1xuICAgICAgICAgICAgaWYgKHJvb3RFbCkge1xuICAgICAgICAgICAgICAgIHRoaXMucm9vdEVsID0gcm9vdEVsO1xuICAgICAgICAgICAgICAgIHRoaXMuY29udGV4dC5yZWdpc3RlckludGVyYWN0aXZlQ29tcG9uZW50KHRoaXMsIHtcbiAgICAgICAgICAgICAgICAgICAgZWw6IHJvb3RFbCxcbiAgICAgICAgICAgICAgICAgICAgaXNIaXRDb21ib0FsbG93ZWQ6IHRoaXMucHJvcHMuaXNIaXRDb21ib0FsbG93ZWQsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgY29tcG9uZW50V2lsbFVubW91bnQoKSB7XG4gICAgICAgIGlmICh0aGlzLnJvb3RFbCkge1xuICAgICAgICAgICAgdGhpcy5jb250ZXh0LnVucmVnaXN0ZXJJbnRlcmFjdGl2ZUNvbXBvbmVudCh0aGlzKTtcbiAgICAgICAgICAgIHRoaXMucm9vdEVsID0gbnVsbDtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBIaXQgU3lzdGVtXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIHByZXBhcmVIaXRzKCkge1xuICAgICAgICB0aGlzLnJvd1Bvc2l0aW9ucyA9IG5ldyBQb3NpdGlvbkNhY2hlKHRoaXMucm9vdEVsLCB0aGlzLnJvd1JlZnMuY29sbGVjdCgpLm1hcCgocm93T2JqKSA9PiByb3dPYmouZ2V0Q2VsbEVscygpWzBdKSwgLy8gZmlyc3QgY2VsbCBlbCBpbiBlYWNoIHJvdy4gVE9ETzogbm90IG9wdGltYWxcbiAgICAgICAgZmFsc2UsIHRydWUpO1xuICAgICAgICB0aGlzLmNvbFBvc2l0aW9ucyA9IG5ldyBQb3NpdGlvbkNhY2hlKHRoaXMucm9vdEVsLCB0aGlzLnJvd1JlZnMuY3VycmVudE1hcFswXS5nZXRDZWxsRWxzKCksIC8vIGNlbGwgZWxzIGluIGZpcnN0IHJvd1xuICAgICAgICB0cnVlLCAvLyBob3Jpem9udGFsXG4gICAgICAgIGZhbHNlKTtcbiAgICB9XG4gICAgcXVlcnlIaXQocG9zaXRpb25MZWZ0LCBwb3NpdGlvblRvcCkge1xuICAgICAgICBsZXQgeyBjb2xQb3NpdGlvbnMsIHJvd1Bvc2l0aW9ucyB9ID0gdGhpcztcbiAgICAgICAgbGV0IGNvbCA9IGNvbFBvc2l0aW9ucy5sZWZ0VG9JbmRleChwb3NpdGlvbkxlZnQpO1xuICAgICAgICBsZXQgcm93ID0gcm93UG9zaXRpb25zLnRvcFRvSW5kZXgocG9zaXRpb25Ub3ApO1xuICAgICAgICBpZiAocm93ICE9IG51bGwgJiYgY29sICE9IG51bGwpIHtcbiAgICAgICAgICAgIGxldCBjZWxsID0gdGhpcy5wcm9wcy5jZWxsc1tyb3ddW2NvbF07XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGRhdGVQcm9maWxlOiB0aGlzLnByb3BzLmRhdGVQcm9maWxlLFxuICAgICAgICAgICAgICAgIGRhdGVTcGFuOiBPYmplY3QuYXNzaWduKHsgcmFuZ2U6IHRoaXMuZ2V0Q2VsbFJhbmdlKHJvdywgY29sKSwgYWxsRGF5OiB0cnVlIH0sIGNlbGwuZXh0cmFEYXRlU3BhbiksXG4gICAgICAgICAgICAgICAgZGF5RWw6IHRoaXMuZ2V0Q2VsbEVsKHJvdywgY29sKSxcbiAgICAgICAgICAgICAgICByZWN0OiB7XG4gICAgICAgICAgICAgICAgICAgIGxlZnQ6IGNvbFBvc2l0aW9ucy5sZWZ0c1tjb2xdLFxuICAgICAgICAgICAgICAgICAgICByaWdodDogY29sUG9zaXRpb25zLnJpZ2h0c1tjb2xdLFxuICAgICAgICAgICAgICAgICAgICB0b3A6IHJvd1Bvc2l0aW9ucy50b3BzW3Jvd10sXG4gICAgICAgICAgICAgICAgICAgIGJvdHRvbTogcm93UG9zaXRpb25zLmJvdHRvbXNbcm93XSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGxheWVyOiAwLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgZ2V0Q2VsbEVsKHJvdywgY29sKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJvd1JlZnMuY3VycmVudE1hcFtyb3ddLmdldENlbGxFbHMoKVtjb2xdOyAvLyBUT0RPOiBub3Qgb3B0aW1hbFxuICAgIH1cbiAgICBnZXRDZWxsUmFuZ2Uocm93LCBjb2wpIHtcbiAgICAgICAgbGV0IHN0YXJ0ID0gdGhpcy5wcm9wcy5jZWxsc1tyb3ddW2NvbF0uZGF0ZTtcbiAgICAgICAgbGV0IGVuZCA9IGFkZERheXMoc3RhcnQsIDEpO1xuICAgICAgICByZXR1cm4geyBzdGFydCwgZW5kIH07XG4gICAgfVxufVxuZnVuY3Rpb24gc3BsaXRBbGxEYXlTZWdzQnlSb3coc2Vncywgcm93Q250KSB7XG4gICAgcmV0dXJuIHNwbGl0U2Vnc0J5Um93KHNlZ3MuZmlsdGVyKGlzU2VnQWxsRGF5KSwgcm93Q250KTtcbn1cbmZ1bmN0aW9uIGlzU2VnQWxsRGF5KHNlZykge1xuICAgIHJldHVybiBzZWcuZXZlbnRSYW5nZS5kZWYuYWxsRGF5O1xufVxuXG5jbGFzcyBUYWJsZSBleHRlbmRzIERhdGVDb21wb25lbnQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICB0aGlzLmVsUmVmID0gY3JlYXRlUmVmKCk7XG4gICAgICAgIHRoaXMubmVlZHNTY3JvbGxSZXNldCA9IGZhbHNlO1xuICAgIH1cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGxldCB7IHByb3BzIH0gPSB0aGlzO1xuICAgICAgICBsZXQgeyBkYXlNYXhFdmVudFJvd3MsIGRheU1heEV2ZW50cywgZXhwYW5kUm93cyB9ID0gcHJvcHM7XG4gICAgICAgIGxldCBsaW1pdFZpYUJhbGFuY2VkID0gZGF5TWF4RXZlbnRzID09PSB0cnVlIHx8IGRheU1heEV2ZW50Um93cyA9PT0gdHJ1ZTtcbiAgICAgICAgLy8gaWYgcm93cyBjYW4ndCBleHBhbmQgdG8gZmlsbCBmaXhlZCBoZWlnaHQsIGNhbid0IGRvIGJhbGFuY2VkLWhlaWdodCBldmVudCBsaW1pdFxuICAgICAgICAvLyBUT0RPOiBiZXN0IHBsYWNlIHRvIG5vcm1hbGl6ZSB0aGVzZSBvcHRpb25zP1xuICAgICAgICBpZiAobGltaXRWaWFCYWxhbmNlZCAmJiAhZXhwYW5kUm93cykge1xuICAgICAgICAgICAgbGltaXRWaWFCYWxhbmNlZCA9IGZhbHNlO1xuICAgICAgICAgICAgZGF5TWF4RXZlbnRSb3dzID0gbnVsbDtcbiAgICAgICAgICAgIGRheU1heEV2ZW50cyA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGNsYXNzTmFtZXMgPSBbXG4gICAgICAgICAgICAnZmMtZGF5Z3JpZC1ib2R5JyxcbiAgICAgICAgICAgIGxpbWl0VmlhQmFsYW5jZWQgPyAnZmMtZGF5Z3JpZC1ib2R5LWJhbGFuY2VkJyA6ICdmYy1kYXlncmlkLWJvZHktdW5iYWxhbmNlZCcsXG4gICAgICAgICAgICBleHBhbmRSb3dzID8gJycgOiAnZmMtZGF5Z3JpZC1ib2R5LW5hdHVyYWwnLCAvLyB3aWxsIGhlaWdodCBvZiBvbmUgcm93IGRlcGVuZCBvbiB0aGUgb3RoZXJzP1xuICAgICAgICBdO1xuICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyByZWY6IHRoaXMuZWxSZWYsIGNsYXNzTmFtZTogY2xhc3NOYW1lcy5qb2luKCcgJyksIHN0eWxlOiB7XG4gICAgICAgICAgICAgICAgLy8gdGhlc2UgcHJvcHMgYXJlIGltcG9ydGFudCB0byBnaXZlIHRoaXMgd3JhcHBlciBjb3JyZWN0IGRpbWVuc2lvbnMgZm9yIGludGVyYWN0aW9uc1xuICAgICAgICAgICAgICAgIC8vIFRPRE86IGlmIHdlIHNldCBpdCBoZXJlLCBjYW4gd2UgYXZvaWQgZ2l2aW5nIHRvIGlubmVyIHRhYmxlcz9cbiAgICAgICAgICAgICAgICB3aWR0aDogcHJvcHMuY2xpZW50V2lkdGgsXG4gICAgICAgICAgICAgICAgbWluV2lkdGg6IHByb3BzLnRhYmxlTWluV2lkdGgsXG4gICAgICAgICAgICB9IH0sXG4gICAgICAgICAgICBjcmVhdGVFbGVtZW50KFwidGFibGVcIiwgeyByb2xlOiBcInByZXNlbnRhdGlvblwiLCBjbGFzc05hbWU6IFwiZmMtc2Nyb2xsZ3JpZC1zeW5jLXRhYmxlXCIsIHN0eWxlOiB7XG4gICAgICAgICAgICAgICAgICAgIHdpZHRoOiBwcm9wcy5jbGllbnRXaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgbWluV2lkdGg6IHByb3BzLnRhYmxlTWluV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgIGhlaWdodDogZXhwYW5kUm93cyA/IHByb3BzLmNsaWVudEhlaWdodCA6ICcnLFxuICAgICAgICAgICAgICAgIH0gfSxcbiAgICAgICAgICAgICAgICBwcm9wcy5jb2xHcm91cE5vZGUsXG4gICAgICAgICAgICAgICAgY3JlYXRlRWxlbWVudChcInRib2R5XCIsIHsgcm9sZTogXCJwcmVzZW50YXRpb25cIiB9LFxuICAgICAgICAgICAgICAgICAgICBjcmVhdGVFbGVtZW50KFRhYmxlUm93cywgeyBkYXRlUHJvZmlsZTogcHJvcHMuZGF0ZVByb2ZpbGUsIGNlbGxzOiBwcm9wcy5jZWxscywgcmVuZGVyUm93SW50cm86IHByb3BzLnJlbmRlclJvd0ludHJvLCBzaG93V2Vla051bWJlcnM6IHByb3BzLnNob3dXZWVrTnVtYmVycywgY2xpZW50V2lkdGg6IHByb3BzLmNsaWVudFdpZHRoLCBjbGllbnRIZWlnaHQ6IHByb3BzLmNsaWVudEhlaWdodCwgYnVzaW5lc3NIb3VyU2VnczogcHJvcHMuYnVzaW5lc3NIb3VyU2VncywgYmdFdmVudFNlZ3M6IHByb3BzLmJnRXZlbnRTZWdzLCBmZ0V2ZW50U2VnczogcHJvcHMuZmdFdmVudFNlZ3MsIGRhdGVTZWxlY3Rpb25TZWdzOiBwcm9wcy5kYXRlU2VsZWN0aW9uU2VncywgZXZlbnRTZWxlY3Rpb246IHByb3BzLmV2ZW50U2VsZWN0aW9uLCBldmVudERyYWc6IHByb3BzLmV2ZW50RHJhZywgZXZlbnRSZXNpemU6IHByb3BzLmV2ZW50UmVzaXplLCBkYXlNYXhFdmVudHM6IGRheU1heEV2ZW50cywgZGF5TWF4RXZlbnRSb3dzOiBkYXlNYXhFdmVudFJvd3MsIGZvclByaW50OiBwcm9wcy5mb3JQcmludCwgaXNIaXRDb21ib0FsbG93ZWQ6IHByb3BzLmlzSGl0Q29tYm9BbGxvd2VkIH0pKSkpKTtcbiAgICB9XG4gICAgY29tcG9uZW50RGlkTW91bnQoKSB7XG4gICAgICAgIHRoaXMucmVxdWVzdFNjcm9sbFJlc2V0KCk7XG4gICAgfVxuICAgIGNvbXBvbmVudERpZFVwZGF0ZShwcmV2UHJvcHMpIHtcbiAgICAgICAgaWYgKHByZXZQcm9wcy5kYXRlUHJvZmlsZSAhPT0gdGhpcy5wcm9wcy5kYXRlUHJvZmlsZSkge1xuICAgICAgICAgICAgdGhpcy5yZXF1ZXN0U2Nyb2xsUmVzZXQoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuZmx1c2hTY3JvbGxSZXNldCgpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJlcXVlc3RTY3JvbGxSZXNldCgpIHtcbiAgICAgICAgdGhpcy5uZWVkc1Njcm9sbFJlc2V0ID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5mbHVzaFNjcm9sbFJlc2V0KCk7XG4gICAgfVxuICAgIGZsdXNoU2Nyb2xsUmVzZXQoKSB7XG4gICAgICAgIGlmICh0aGlzLm5lZWRzU2Nyb2xsUmVzZXQgJiZcbiAgICAgICAgICAgIHRoaXMucHJvcHMuY2xpZW50V2lkdGggLy8gc2l6ZXMgY29tcHV0ZWQ/XG4gICAgICAgICkge1xuICAgICAgICAgICAgY29uc3Qgc3ViamVjdEVsID0gZ2V0U2Nyb2xsU3ViamVjdEVsKHRoaXMuZWxSZWYuY3VycmVudCwgdGhpcy5wcm9wcy5kYXRlUHJvZmlsZSk7XG4gICAgICAgICAgICBpZiAoc3ViamVjdEVsKSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgb3JpZ2luRWwgPSBzdWJqZWN0RWwuY2xvc2VzdCgnLmZjLWRheWdyaWQtYm9keScpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHNjcm9sbEVsID0gb3JpZ2luRWwuY2xvc2VzdCgnLmZjLXNjcm9sbGVyJyk7XG4gICAgICAgICAgICAgICAgY29uc3Qgc2Nyb2xsVG9wID0gc3ViamVjdEVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCAtXG4gICAgICAgICAgICAgICAgICAgIG9yaWdpbkVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcDtcbiAgICAgICAgICAgICAgICBzY3JvbGxFbC5zY3JvbGxUb3AgPSBzY3JvbGxUb3AgPyAoc2Nyb2xsVG9wICsgMSkgOiAwOyAvLyBvdmVyY29tZSBib3JkZXJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMubmVlZHNTY3JvbGxSZXNldCA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxufVxuZnVuY3Rpb24gZ2V0U2Nyb2xsU3ViamVjdEVsKGNvbnRhaW5lckVsLCBkYXRlUHJvZmlsZSkge1xuICAgIGxldCBlbDtcbiAgICBpZiAoZGF0ZVByb2ZpbGUuY3VycmVudFJhbmdlVW5pdC5tYXRjaCgveWVhcnxtb250aC8pKSB7XG4gICAgICAgIGVsID0gY29udGFpbmVyRWwucXVlcnlTZWxlY3RvcihgW2RhdGEtZGF0ZT1cIiR7Zm9ybWF0SXNvTW9udGhTdHIoZGF0ZVByb2ZpbGUuY3VycmVudERhdGUpfS0wMVwiXWApO1xuICAgICAgICAvLyBldmVuIGlmIHZpZXcgaXMgbW9udGgtYmFzZWQsIGZpcnN0LW9mLW1vbnRoIG1pZ2h0IGJlIGhpZGRlbi4uLlxuICAgIH1cbiAgICBpZiAoIWVsKSB7XG4gICAgICAgIGVsID0gY29udGFpbmVyRWwucXVlcnlTZWxlY3RvcihgW2RhdGEtZGF0ZT1cIiR7Zm9ybWF0RGF5U3RyaW5nKGRhdGVQcm9maWxlLmN1cnJlbnREYXRlKX1cIl1gKTtcbiAgICAgICAgLy8gY291bGQgc3RpbGwgYmUgaGlkZGVuIGlmIGFuIGludGVyaW9yLXZpZXcgaGlkZGVuIGRheVxuICAgIH1cbiAgICByZXR1cm4gZWw7XG59XG5cbmNsYXNzIERheVRhYmxlU2xpY2VyIGV4dGVuZHMgU2xpY2VyIHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoLi4uYXJndW1lbnRzKTtcbiAgICAgICAgdGhpcy5mb3JjZURheUlmTGlzdEl0ZW0gPSB0cnVlO1xuICAgIH1cbiAgICBzbGljZVJhbmdlKGRhdGVSYW5nZSwgZGF5VGFibGVNb2RlbCkge1xuICAgICAgICByZXR1cm4gZGF5VGFibGVNb2RlbC5zbGljZVJhbmdlKGRhdGVSYW5nZSk7XG4gICAgfVxufVxuXG5jbGFzcyBEYXlUYWJsZSBleHRlbmRzIERhdGVDb21wb25lbnQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICB0aGlzLnNsaWNlciA9IG5ldyBEYXlUYWJsZVNsaWNlcigpO1xuICAgICAgICB0aGlzLnRhYmxlUmVmID0gY3JlYXRlUmVmKCk7XG4gICAgfVxuICAgIHJlbmRlcigpIHtcbiAgICAgICAgbGV0IHsgcHJvcHMsIGNvbnRleHQgfSA9IHRoaXM7XG4gICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChUYWJsZSwgT2JqZWN0LmFzc2lnbih7IHJlZjogdGhpcy50YWJsZVJlZiB9LCB0aGlzLnNsaWNlci5zbGljZVByb3BzKHByb3BzLCBwcm9wcy5kYXRlUHJvZmlsZSwgcHJvcHMubmV4dERheVRocmVzaG9sZCwgY29udGV4dCwgcHJvcHMuZGF5VGFibGVNb2RlbCksIHsgZGF0ZVByb2ZpbGU6IHByb3BzLmRhdGVQcm9maWxlLCBjZWxsczogcHJvcHMuZGF5VGFibGVNb2RlbC5jZWxscywgY29sR3JvdXBOb2RlOiBwcm9wcy5jb2xHcm91cE5vZGUsIHRhYmxlTWluV2lkdGg6IHByb3BzLnRhYmxlTWluV2lkdGgsIHJlbmRlclJvd0ludHJvOiBwcm9wcy5yZW5kZXJSb3dJbnRybywgZGF5TWF4RXZlbnRzOiBwcm9wcy5kYXlNYXhFdmVudHMsIGRheU1heEV2ZW50Um93czogcHJvcHMuZGF5TWF4RXZlbnRSb3dzLCBzaG93V2Vla051bWJlcnM6IHByb3BzLnNob3dXZWVrTnVtYmVycywgZXhwYW5kUm93czogcHJvcHMuZXhwYW5kUm93cywgaGVhZGVyQWxpZ25FbFJlZjogcHJvcHMuaGVhZGVyQWxpZ25FbFJlZiwgY2xpZW50V2lkdGg6IHByb3BzLmNsaWVudFdpZHRoLCBjbGllbnRIZWlnaHQ6IHByb3BzLmNsaWVudEhlaWdodCwgZm9yUHJpbnQ6IHByb3BzLmZvclByaW50IH0pKSk7XG4gICAgfVxufVxuXG5jbGFzcyBEYXlUYWJsZVZpZXcgZXh0ZW5kcyBUYWJsZVZpZXcge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICB0aGlzLmJ1aWxkRGF5VGFibGVNb2RlbCA9IG1lbW9pemUoYnVpbGREYXlUYWJsZU1vZGVsKTtcbiAgICAgICAgdGhpcy5oZWFkZXJSZWYgPSBjcmVhdGVSZWYoKTtcbiAgICAgICAgdGhpcy50YWJsZVJlZiA9IGNyZWF0ZVJlZigpO1xuICAgICAgICAvLyBjYW4ndCBvdmVycmlkZSBhbnkgbGlmZWN5Y2xlIG1ldGhvZHMgZnJvbSBwYXJlbnRcbiAgICB9XG4gICAgcmVuZGVyKCkge1xuICAgICAgICBsZXQgeyBvcHRpb25zLCBkYXRlUHJvZmlsZUdlbmVyYXRvciB9ID0gdGhpcy5jb250ZXh0O1xuICAgICAgICBsZXQgeyBwcm9wcyB9ID0gdGhpcztcbiAgICAgICAgbGV0IGRheVRhYmxlTW9kZWwgPSB0aGlzLmJ1aWxkRGF5VGFibGVNb2RlbChwcm9wcy5kYXRlUHJvZmlsZSwgZGF0ZVByb2ZpbGVHZW5lcmF0b3IpO1xuICAgICAgICBsZXQgaGVhZGVyQ29udGVudCA9IG9wdGlvbnMuZGF5SGVhZGVycyAmJiAoY3JlYXRlRWxlbWVudChEYXlIZWFkZXIsIHsgcmVmOiB0aGlzLmhlYWRlclJlZiwgZGF0ZVByb2ZpbGU6IHByb3BzLmRhdGVQcm9maWxlLCBkYXRlczogZGF5VGFibGVNb2RlbC5oZWFkZXJEYXRlcywgZGF0ZXNSZXBEaXN0aW5jdERheXM6IGRheVRhYmxlTW9kZWwucm93Q250ID09PSAxIH0pKTtcbiAgICAgICAgbGV0IGJvZHlDb250ZW50ID0gKGNvbnRlbnRBcmcpID0+IChjcmVhdGVFbGVtZW50KERheVRhYmxlLCB7IHJlZjogdGhpcy50YWJsZVJlZiwgZGF0ZVByb2ZpbGU6IHByb3BzLmRhdGVQcm9maWxlLCBkYXlUYWJsZU1vZGVsOiBkYXlUYWJsZU1vZGVsLCBidXNpbmVzc0hvdXJzOiBwcm9wcy5idXNpbmVzc0hvdXJzLCBkYXRlU2VsZWN0aW9uOiBwcm9wcy5kYXRlU2VsZWN0aW9uLCBldmVudFN0b3JlOiBwcm9wcy5ldmVudFN0b3JlLCBldmVudFVpQmFzZXM6IHByb3BzLmV2ZW50VWlCYXNlcywgZXZlbnRTZWxlY3Rpb246IHByb3BzLmV2ZW50U2VsZWN0aW9uLCBldmVudERyYWc6IHByb3BzLmV2ZW50RHJhZywgZXZlbnRSZXNpemU6IHByb3BzLmV2ZW50UmVzaXplLCBuZXh0RGF5VGhyZXNob2xkOiBvcHRpb25zLm5leHREYXlUaHJlc2hvbGQsIGNvbEdyb3VwTm9kZTogY29udGVudEFyZy50YWJsZUNvbEdyb3VwTm9kZSwgdGFibGVNaW5XaWR0aDogY29udGVudEFyZy50YWJsZU1pbldpZHRoLCBkYXlNYXhFdmVudHM6IG9wdGlvbnMuZGF5TWF4RXZlbnRzLCBkYXlNYXhFdmVudFJvd3M6IG9wdGlvbnMuZGF5TWF4RXZlbnRSb3dzLCBzaG93V2Vla051bWJlcnM6IG9wdGlvbnMud2Vla051bWJlcnMsIGV4cGFuZFJvd3M6ICFwcm9wcy5pc0hlaWdodEF1dG8sIGhlYWRlckFsaWduRWxSZWY6IHRoaXMuaGVhZGVyRWxSZWYsIGNsaWVudFdpZHRoOiBjb250ZW50QXJnLmNsaWVudFdpZHRoLCBjbGllbnRIZWlnaHQ6IGNvbnRlbnRBcmcuY2xpZW50SGVpZ2h0LCBmb3JQcmludDogcHJvcHMuZm9yUHJpbnQgfSkpO1xuICAgICAgICByZXR1cm4gb3B0aW9ucy5kYXlNaW5XaWR0aFxuICAgICAgICAgICAgPyB0aGlzLnJlbmRlckhTY3JvbGxMYXlvdXQoaGVhZGVyQ29udGVudCwgYm9keUNvbnRlbnQsIGRheVRhYmxlTW9kZWwuY29sQ250LCBvcHRpb25zLmRheU1pbldpZHRoKVxuICAgICAgICAgICAgOiB0aGlzLnJlbmRlclNpbXBsZUxheW91dChoZWFkZXJDb250ZW50LCBib2R5Q29udGVudCk7XG4gICAgfVxufVxuZnVuY3Rpb24gYnVpbGREYXlUYWJsZU1vZGVsKGRhdGVQcm9maWxlLCBkYXRlUHJvZmlsZUdlbmVyYXRvcikge1xuICAgIGxldCBkYXlTZXJpZXMgPSBuZXcgRGF5U2VyaWVzTW9kZWwoZGF0ZVByb2ZpbGUucmVuZGVyUmFuZ2UsIGRhdGVQcm9maWxlR2VuZXJhdG9yKTtcbiAgICByZXR1cm4gbmV3IERheVRhYmxlTW9kZWwoZGF5U2VyaWVzLCAveWVhcnxtb250aHx3ZWVrLy50ZXN0KGRhdGVQcm9maWxlLmN1cnJlbnRSYW5nZVVuaXQpKTtcbn1cblxuY2xhc3MgVGFibGVEYXRlUHJvZmlsZUdlbmVyYXRvciBleHRlbmRzIERhdGVQcm9maWxlR2VuZXJhdG9yIHtcbiAgICAvLyBDb21wdXRlcyB0aGUgZGF0ZSByYW5nZSB0aGF0IHdpbGwgYmUgcmVuZGVyZWRcbiAgICBidWlsZFJlbmRlclJhbmdlKGN1cnJlbnRSYW5nZSwgY3VycmVudFJhbmdlVW5pdCwgaXNSYW5nZUFsbERheSkge1xuICAgICAgICBsZXQgcmVuZGVyUmFuZ2UgPSBzdXBlci5idWlsZFJlbmRlclJhbmdlKGN1cnJlbnRSYW5nZSwgY3VycmVudFJhbmdlVW5pdCwgaXNSYW5nZUFsbERheSk7XG4gICAgICAgIGxldCB7IHByb3BzIH0gPSB0aGlzO1xuICAgICAgICByZXR1cm4gYnVpbGREYXlUYWJsZVJlbmRlclJhbmdlKHtcbiAgICAgICAgICAgIGN1cnJlbnRSYW5nZTogcmVuZGVyUmFuZ2UsXG4gICAgICAgICAgICBzbmFwVG9XZWVrOiAvXih5ZWFyfG1vbnRoKSQvLnRlc3QoY3VycmVudFJhbmdlVW5pdCksXG4gICAgICAgICAgICBmaXhlZFdlZWtDb3VudDogcHJvcHMuZml4ZWRXZWVrQ291bnQsXG4gICAgICAgICAgICBkYXRlRW52OiBwcm9wcy5kYXRlRW52LFxuICAgICAgICB9KTtcbiAgICB9XG59XG5mdW5jdGlvbiBidWlsZERheVRhYmxlUmVuZGVyUmFuZ2UocHJvcHMpIHtcbiAgICBsZXQgeyBkYXRlRW52LCBjdXJyZW50UmFuZ2UgfSA9IHByb3BzO1xuICAgIGxldCB7IHN0YXJ0LCBlbmQgfSA9IGN1cnJlbnRSYW5nZTtcbiAgICBsZXQgZW5kT2ZXZWVrO1xuICAgIC8vIHllYXIgYW5kIG1vbnRoIHZpZXdzIHNob3VsZCBiZSBhbGlnbmVkIHdpdGggd2Vla3MuIHRoaXMgaXMgYWxyZWFkeSBkb25lIGZvciB3ZWVrXG4gICAgaWYgKHByb3BzLnNuYXBUb1dlZWspIHtcbiAgICAgICAgc3RhcnQgPSBkYXRlRW52LnN0YXJ0T2ZXZWVrKHN0YXJ0KTtcbiAgICAgICAgLy8gbWFrZSBlbmQtb2Ytd2VlayBpZiBub3QgYWxyZWFkeVxuICAgICAgICBlbmRPZldlZWsgPSBkYXRlRW52LnN0YXJ0T2ZXZWVrKGVuZCk7XG4gICAgICAgIGlmIChlbmRPZldlZWsudmFsdWVPZigpICE9PSBlbmQudmFsdWVPZigpKSB7XG4gICAgICAgICAgICBlbmQgPSBhZGRXZWVrcyhlbmRPZldlZWssIDEpO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8vIGVuc3VyZSA2IHdlZWtzXG4gICAgaWYgKHByb3BzLmZpeGVkV2Vla0NvdW50KSB7XG4gICAgICAgIC8vIFRPRE86IGluc3RlYWQgb2YgdGhlc2UgZGF0ZS1tYXRoIGd5bW5hc3RpY3MgKGZvciBtdWx0aW1vbnRoIHZpZXcpLFxuICAgICAgICAvLyBjb21wdXRlIGRhdGVwcm9maWxlcyBvZiBhbGwgbW9udGhzLCB0aGVuIHVzZSBzdGFydCBvZiBmaXJzdCBhbmQgZW5kIG9mIGxhc3QuXG4gICAgICAgIGxldCBsYXN0TW9udGhSZW5kZXJTdGFydCA9IGRhdGVFbnYuc3RhcnRPZldlZWsoZGF0ZUVudi5zdGFydE9mTW9udGgoYWRkRGF5cyhjdXJyZW50UmFuZ2UuZW5kLCAtMSkpKTtcbiAgICAgICAgbGV0IHJvd0NudCA9IE1hdGguY2VpbCgvLyBjb3VsZCBiZSBwYXJ0aWFsIHdlZWtzIGR1ZSB0byBoaWRkZW5EYXlzXG4gICAgICAgIGRpZmZXZWVrcyhsYXN0TW9udGhSZW5kZXJTdGFydCwgZW5kKSk7XG4gICAgICAgIGVuZCA9IGFkZFdlZWtzKGVuZCwgNiAtIHJvd0NudCk7XG4gICAgfVxuICAgIHJldHVybiB7IHN0YXJ0LCBlbmQgfTtcbn1cblxudmFyIGNzc18yNDh6ID0gXCI6cm9vdHstLWZjLWRheWdyaWQtZXZlbnQtZG90LXdpZHRoOjhweH0uZmMtZGF5Z3JpZC1kYXktZXZlbnRzOmFmdGVyLC5mYy1kYXlncmlkLWRheS1ldmVudHM6YmVmb3JlLC5mYy1kYXlncmlkLWRheS1mcmFtZTphZnRlciwuZmMtZGF5Z3JpZC1kYXktZnJhbWU6YmVmb3JlLC5mYy1kYXlncmlkLWV2ZW50LWhhcm5lc3M6YWZ0ZXIsLmZjLWRheWdyaWQtZXZlbnQtaGFybmVzczpiZWZvcmV7Y2xlYXI6Ym90aDtjb250ZW50OlxcXCJcXFwiO2Rpc3BsYXk6dGFibGV9LmZjIC5mYy1kYXlncmlkLWJvZHl7cG9zaXRpb246cmVsYXRpdmU7ei1pbmRleDoxfS5mYyAuZmMtZGF5Z3JpZC1kYXkuZmMtZGF5LXRvZGF5e2JhY2tncm91bmQtY29sb3I6dmFyKC0tZmMtdG9kYXktYmctY29sb3IpfS5mYyAuZmMtZGF5Z3JpZC1kYXktZnJhbWV7bWluLWhlaWdodDoxMDAlO3Bvc2l0aW9uOnJlbGF0aXZlfS5mYyAuZmMtZGF5Z3JpZC1kYXktdG9we2Rpc3BsYXk6ZmxleDtmbGV4LWRpcmVjdGlvbjpyb3ctcmV2ZXJzZX0uZmMgLmZjLWRheS1vdGhlciAuZmMtZGF5Z3JpZC1kYXktdG9we29wYWNpdHk6LjN9LmZjIC5mYy1kYXlncmlkLWRheS1udW1iZXJ7cGFkZGluZzo0cHg7cG9zaXRpb246cmVsYXRpdmU7ei1pbmRleDo0fS5mYyAuZmMtZGF5Z3JpZC1tb250aC1zdGFydHtmb250LXNpemU6MS4xZW07Zm9udC13ZWlnaHQ6NzAwfS5mYyAuZmMtZGF5Z3JpZC1kYXktZXZlbnRze21hcmdpbi10b3A6MXB4fS5mYyAuZmMtZGF5Z3JpZC1ib2R5LWJhbGFuY2VkIC5mYy1kYXlncmlkLWRheS1ldmVudHN7bGVmdDowO3Bvc2l0aW9uOmFic29sdXRlO3JpZ2h0OjB9LmZjIC5mYy1kYXlncmlkLWJvZHktdW5iYWxhbmNlZCAuZmMtZGF5Z3JpZC1kYXktZXZlbnRze21pbi1oZWlnaHQ6MmVtO3Bvc2l0aW9uOnJlbGF0aXZlfS5mYyAuZmMtZGF5Z3JpZC1ib2R5LW5hdHVyYWwgLmZjLWRheWdyaWQtZGF5LWV2ZW50c3ttYXJnaW4tYm90dG9tOjFlbX0uZmMgLmZjLWRheWdyaWQtZXZlbnQtaGFybmVzc3twb3NpdGlvbjpyZWxhdGl2ZX0uZmMgLmZjLWRheWdyaWQtZXZlbnQtaGFybmVzcy1hYnN7bGVmdDowO3Bvc2l0aW9uOmFic29sdXRlO3JpZ2h0OjA7dG9wOjB9LmZjIC5mYy1kYXlncmlkLWJnLWhhcm5lc3N7Ym90dG9tOjA7cG9zaXRpb246YWJzb2x1dGU7dG9wOjB9LmZjIC5mYy1kYXlncmlkLWRheS1iZyAuZmMtbm9uLWJ1c2luZXNze3otaW5kZXg6MX0uZmMgLmZjLWRheWdyaWQtZGF5LWJnIC5mYy1iZy1ldmVudHt6LWluZGV4OjJ9LmZjIC5mYy1kYXlncmlkLWRheS1iZyAuZmMtaGlnaGxpZ2h0e3otaW5kZXg6M30uZmMgLmZjLWRheWdyaWQtZXZlbnR7bWFyZ2luLXRvcDoxcHg7ei1pbmRleDo2fS5mYyAuZmMtZGF5Z3JpZC1ldmVudC5mYy1ldmVudC1taXJyb3J7ei1pbmRleDo3fS5mYyAuZmMtZGF5Z3JpZC1kYXktYm90dG9te2ZvbnQtc2l6ZTouODVlbTttYXJnaW46MCAycHh9LmZjIC5mYy1kYXlncmlkLWRheS1ib3R0b206YWZ0ZXIsLmZjIC5mYy1kYXlncmlkLWRheS1ib3R0b206YmVmb3Jle2NsZWFyOmJvdGg7Y29udGVudDpcXFwiXFxcIjtkaXNwbGF5OnRhYmxlfS5mYyAuZmMtZGF5Z3JpZC1tb3JlLWxpbmt7Ym9yZGVyLXJhZGl1czozcHg7Y3Vyc29yOnBvaW50ZXI7bGluZS1oZWlnaHQ6MTttYXJnaW4tdG9wOjFweDttYXgtd2lkdGg6MTAwJTtvdmVyZmxvdzpoaWRkZW47cGFkZGluZzoycHg7cG9zaXRpb246cmVsYXRpdmU7d2hpdGUtc3BhY2U6bm93cmFwO3otaW5kZXg6NH0uZmMgLmZjLWRheWdyaWQtbW9yZS1saW5rOmhvdmVye2JhY2tncm91bmQtY29sb3I6cmdiYSgwLDAsMCwuMSl9LmZjIC5mYy1kYXlncmlkLXdlZWstbnVtYmVye2JhY2tncm91bmQtY29sb3I6dmFyKC0tZmMtbmV1dHJhbC1iZy1jb2xvcik7Y29sb3I6dmFyKC0tZmMtbmV1dHJhbC10ZXh0LWNvbG9yKTttaW4td2lkdGg6MS41ZW07cGFkZGluZzoycHg7cG9zaXRpb246YWJzb2x1dGU7dGV4dC1hbGlnbjpjZW50ZXI7dG9wOjA7ei1pbmRleDo1fS5mYyAuZmMtbW9yZS1wb3BvdmVyIC5mYy1wb3BvdmVyLWJvZHl7bWluLXdpZHRoOjIyMHB4O3BhZGRpbmc6MTBweH0uZmMtZGlyZWN0aW9uLWx0ciAuZmMtZGF5Z3JpZC1ldmVudC5mYy1ldmVudC1zdGFydCwuZmMtZGlyZWN0aW9uLXJ0bCAuZmMtZGF5Z3JpZC1ldmVudC5mYy1ldmVudC1lbmR7bWFyZ2luLWxlZnQ6MnB4fS5mYy1kaXJlY3Rpb24tbHRyIC5mYy1kYXlncmlkLWV2ZW50LmZjLWV2ZW50LWVuZCwuZmMtZGlyZWN0aW9uLXJ0bCAuZmMtZGF5Z3JpZC1ldmVudC5mYy1ldmVudC1zdGFydHttYXJnaW4tcmlnaHQ6MnB4fS5mYy1kaXJlY3Rpb24tbHRyIC5mYy1kYXlncmlkLW1vcmUtbGlua3tmbG9hdDpsZWZ0fS5mYy1kaXJlY3Rpb24tbHRyIC5mYy1kYXlncmlkLXdlZWstbnVtYmVye2JvcmRlci1yYWRpdXM6MCAwIDNweCAwO2xlZnQ6MH0uZmMtZGlyZWN0aW9uLXJ0bCAuZmMtZGF5Z3JpZC1tb3JlLWxpbmt7ZmxvYXQ6cmlnaHR9LmZjLWRpcmVjdGlvbi1ydGwgLmZjLWRheWdyaWQtd2Vlay1udW1iZXJ7Ym9yZGVyLXJhZGl1czowIDAgMCAzcHg7cmlnaHQ6MH0uZmMtbGlxdWlkLWhhY2sgLmZjLWRheWdyaWQtZGF5LWZyYW1le3Bvc2l0aW9uOnN0YXRpY30uZmMtZGF5Z3JpZC1ldmVudHtib3JkZXItcmFkaXVzOjNweDtmb250LXNpemU6dmFyKC0tZmMtc21hbGwtZm9udC1zaXplKTtwb3NpdGlvbjpyZWxhdGl2ZTt3aGl0ZS1zcGFjZTpub3dyYXB9LmZjLWRheWdyaWQtYmxvY2stZXZlbnQgLmZjLWV2ZW50LXRpbWV7Zm9udC13ZWlnaHQ6NzAwfS5mYy1kYXlncmlkLWJsb2NrLWV2ZW50IC5mYy1ldmVudC10aW1lLC5mYy1kYXlncmlkLWJsb2NrLWV2ZW50IC5mYy1ldmVudC10aXRsZXtwYWRkaW5nOjFweH0uZmMtZGF5Z3JpZC1kb3QtZXZlbnR7YWxpZ24taXRlbXM6Y2VudGVyO2Rpc3BsYXk6ZmxleDtwYWRkaW5nOjJweCAwfS5mYy1kYXlncmlkLWRvdC1ldmVudCAuZmMtZXZlbnQtdGl0bGV7ZmxleC1ncm93OjE7ZmxleC1zaHJpbms6MTtmb250LXdlaWdodDo3MDA7bWluLXdpZHRoOjA7b3ZlcmZsb3c6aGlkZGVufS5mYy1kYXlncmlkLWRvdC1ldmVudC5mYy1ldmVudC1taXJyb3IsLmZjLWRheWdyaWQtZG90LWV2ZW50OmhvdmVye2JhY2tncm91bmQ6cmdiYSgwLDAsMCwuMSl9LmZjLWRheWdyaWQtZG90LWV2ZW50LmZjLWV2ZW50LXNlbGVjdGVkOmJlZm9yZXtib3R0b206LTEwcHg7dG9wOi0xMHB4fS5mYy1kYXlncmlkLWV2ZW50LWRvdHtib3JkZXI6Y2FsYyh2YXIoLS1mYy1kYXlncmlkLWV2ZW50LWRvdC13aWR0aCkvMikgc29saWQgdmFyKC0tZmMtZXZlbnQtYm9yZGVyLWNvbG9yKTtib3JkZXItcmFkaXVzOmNhbGModmFyKC0tZmMtZGF5Z3JpZC1ldmVudC1kb3Qtd2lkdGgpLzIpO2JveC1zaXppbmc6Y29udGVudC1ib3g7aGVpZ2h0OjA7bWFyZ2luOjAgNHB4O3dpZHRoOjB9LmZjLWRpcmVjdGlvbi1sdHIgLmZjLWRheWdyaWQtZXZlbnQgLmZjLWV2ZW50LXRpbWV7bWFyZ2luLXJpZ2h0OjNweH0uZmMtZGlyZWN0aW9uLXJ0bCAuZmMtZGF5Z3JpZC1ldmVudCAuZmMtZXZlbnQtdGltZXttYXJnaW4tbGVmdDozcHh9XCI7XG5pbmplY3RTdHlsZXMoY3NzXzI0OHopO1xuXG5leHBvcnQgeyBEYXlUYWJsZVZpZXcgYXMgRGF5R3JpZFZpZXcsIERheVRhYmxlLCBEYXlUYWJsZVNsaWNlciwgVGFibGUsIFRhYmxlRGF0ZVByb2ZpbGVHZW5lcmF0b3IsIFRhYmxlUm93cywgVGFibGVWaWV3LCBidWlsZERheVRhYmxlTW9kZWwsIGJ1aWxkRGF5VGFibGVSZW5kZXJSYW5nZSB9O1xuIl0sIm5hbWVzIjpbXSwiaWdub3JlTGlzdCI6WzBdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///(ssr)/./node_modules/@fullcalendar/daygrid/internal.js\n");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "(ssr)/./node_modules/@fullcalendar/interaction/index.js":
|
|
/*!*********************************************************!*\
|
|
!*** ./node_modules/@fullcalendar/interaction/index.js ***!
|
|
\*********************************************************/
|
|
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
|
|
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ Draggable: () => (/* binding */ ExternalDraggable),\n/* harmony export */ ThirdPartyDraggable: () => (/* binding */ ThirdPartyDraggable),\n/* harmony export */ \"default\": () => (/* binding */ index)\n/* harmony export */ });\n/* harmony import */ var _fullcalendar_core_index_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @fullcalendar/core/index.js */ \"(ssr)/./node_modules/@fullcalendar/core/index.js\");\n/* harmony import */ var _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @fullcalendar/core/internal.js */ \"(ssr)/./node_modules/@fullcalendar/core/internal-common.js\");\n\n\n\n_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bG.touchMouseIgnoreWait = 500;\nlet ignoreMouseDepth = 0;\nlet listenerCnt = 0;\nlet isWindowTouchMoveCancelled = false;\n/*\nUses a \"pointer\" abstraction, which monitors UI events for both mouse and touch.\nTracks when the pointer \"drags\" on a certain element, meaning down+move+up.\n\nAlso, tracks if there was touch-scrolling.\nAlso, can prevent touch-scrolling from happening.\nAlso, can fire pointermove events when scrolling happens underneath, even when no real pointer movement.\n\nemits:\n- pointerdown\n- pointermove\n- pointerup\n*/\nclass PointerDragging {\n constructor(containerEl) {\n this.subjectEl = null;\n // options that can be directly assigned by caller\n this.selector = ''; // will cause subjectEl in all emitted events to be this element\n this.handleSelector = '';\n this.shouldIgnoreMove = false;\n this.shouldWatchScroll = true; // for simulating pointermove on scroll\n // internal states\n this.isDragging = false;\n this.isTouchDragging = false;\n this.wasTouchScroll = false;\n // Mouse\n // ----------------------------------------------------------------------------------------------------\n this.handleMouseDown = (ev) => {\n if (!this.shouldIgnoreMouse() &&\n isPrimaryMouseButton(ev) &&\n this.tryStart(ev)) {\n let pev = this.createEventFromMouse(ev, true);\n this.emitter.trigger('pointerdown', pev);\n this.initScrollWatch(pev);\n if (!this.shouldIgnoreMove) {\n document.addEventListener('mousemove', this.handleMouseMove);\n }\n document.addEventListener('mouseup', this.handleMouseUp);\n }\n };\n this.handleMouseMove = (ev) => {\n let pev = this.createEventFromMouse(ev);\n this.recordCoords(pev);\n this.emitter.trigger('pointermove', pev);\n };\n this.handleMouseUp = (ev) => {\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n this.emitter.trigger('pointerup', this.createEventFromMouse(ev));\n this.cleanup(); // call last so that pointerup has access to props\n };\n // Touch\n // ----------------------------------------------------------------------------------------------------\n this.handleTouchStart = (ev) => {\n if (this.tryStart(ev)) {\n this.isTouchDragging = true;\n let pev = this.createEventFromTouch(ev, true);\n this.emitter.trigger('pointerdown', pev);\n this.initScrollWatch(pev);\n // unlike mouse, need to attach to target, not document\n // https://stackoverflow.com/a/45760014\n let targetEl = ev.target;\n if (!this.shouldIgnoreMove) {\n targetEl.addEventListener('touchmove', this.handleTouchMove);\n }\n targetEl.addEventListener('touchend', this.handleTouchEnd);\n targetEl.addEventListener('touchcancel', this.handleTouchEnd); // treat it as a touch end\n // attach a handler to get called when ANY scroll action happens on the page.\n // this was impossible to do with normal on/off because 'scroll' doesn't bubble.\n // http://stackoverflow.com/a/32954565/96342\n window.addEventListener('scroll', this.handleTouchScroll, true);\n }\n };\n this.handleTouchMove = (ev) => {\n let pev = this.createEventFromTouch(ev);\n this.recordCoords(pev);\n this.emitter.trigger('pointermove', pev);\n };\n this.handleTouchEnd = (ev) => {\n if (this.isDragging) { // done to guard against touchend followed by touchcancel\n let targetEl = ev.target;\n targetEl.removeEventListener('touchmove', this.handleTouchMove);\n targetEl.removeEventListener('touchend', this.handleTouchEnd);\n targetEl.removeEventListener('touchcancel', this.handleTouchEnd);\n window.removeEventListener('scroll', this.handleTouchScroll, true); // useCaptured=true\n this.emitter.trigger('pointerup', this.createEventFromTouch(ev));\n this.cleanup(); // call last so that pointerup has access to props\n this.isTouchDragging = false;\n startIgnoringMouse();\n }\n };\n this.handleTouchScroll = () => {\n this.wasTouchScroll = true;\n };\n this.handleScroll = (ev) => {\n if (!this.shouldIgnoreMove) {\n let pageX = (window.scrollX - this.prevScrollX) + this.prevPageX;\n let pageY = (window.scrollY - this.prevScrollY) + this.prevPageY;\n this.emitter.trigger('pointermove', {\n origEvent: ev,\n isTouch: this.isTouchDragging,\n subjectEl: this.subjectEl,\n pageX,\n pageY,\n deltaX: pageX - this.origPageX,\n deltaY: pageY - this.origPageY,\n });\n }\n };\n this.containerEl = containerEl;\n this.emitter = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.F();\n containerEl.addEventListener('mousedown', this.handleMouseDown);\n containerEl.addEventListener('touchstart', this.handleTouchStart, { passive: true });\n listenerCreated();\n }\n destroy() {\n this.containerEl.removeEventListener('mousedown', this.handleMouseDown);\n this.containerEl.removeEventListener('touchstart', this.handleTouchStart, { passive: true });\n listenerDestroyed();\n }\n tryStart(ev) {\n let subjectEl = this.querySubjectEl(ev);\n let downEl = ev.target;\n if (subjectEl &&\n (!this.handleSelector || (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.Z)(downEl, this.handleSelector))) {\n this.subjectEl = subjectEl;\n this.isDragging = true; // do this first so cancelTouchScroll will work\n this.wasTouchScroll = false;\n return true;\n }\n return false;\n }\n cleanup() {\n isWindowTouchMoveCancelled = false;\n this.isDragging = false;\n this.subjectEl = null;\n // keep wasTouchScroll around for later access\n this.destroyScrollWatch();\n }\n querySubjectEl(ev) {\n if (this.selector) {\n return (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ev.target, this.selector);\n }\n return this.containerEl;\n }\n shouldIgnoreMouse() {\n return ignoreMouseDepth || this.isTouchDragging;\n }\n // can be called by user of this class, to cancel touch-based scrolling for the current drag\n cancelTouchScroll() {\n if (this.isDragging) {\n isWindowTouchMoveCancelled = true;\n }\n }\n // Scrolling that simulates pointermoves\n // ----------------------------------------------------------------------------------------------------\n initScrollWatch(ev) {\n if (this.shouldWatchScroll) {\n this.recordCoords(ev);\n window.addEventListener('scroll', this.handleScroll, true); // useCapture=true\n }\n }\n recordCoords(ev) {\n if (this.shouldWatchScroll) {\n this.prevPageX = ev.pageX;\n this.prevPageY = ev.pageY;\n this.prevScrollX = window.scrollX;\n this.prevScrollY = window.scrollY;\n }\n }\n destroyScrollWatch() {\n if (this.shouldWatchScroll) {\n window.removeEventListener('scroll', this.handleScroll, true); // useCaptured=true\n }\n }\n // Event Normalization\n // ----------------------------------------------------------------------------------------------------\n createEventFromMouse(ev, isFirst) {\n let deltaX = 0;\n let deltaY = 0;\n // TODO: repeat code\n if (isFirst) {\n this.origPageX = ev.pageX;\n this.origPageY = ev.pageY;\n }\n else {\n deltaX = ev.pageX - this.origPageX;\n deltaY = ev.pageY - this.origPageY;\n }\n return {\n origEvent: ev,\n isTouch: false,\n subjectEl: this.subjectEl,\n pageX: ev.pageX,\n pageY: ev.pageY,\n deltaX,\n deltaY,\n };\n }\n createEventFromTouch(ev, isFirst) {\n let touches = ev.touches;\n let pageX;\n let pageY;\n let deltaX = 0;\n let deltaY = 0;\n // if touch coords available, prefer,\n // because FF would give bad ev.pageX ev.pageY\n if (touches && touches.length) {\n pageX = touches[0].pageX;\n pageY = touches[0].pageY;\n }\n else {\n pageX = ev.pageX;\n pageY = ev.pageY;\n }\n // TODO: repeat code\n if (isFirst) {\n this.origPageX = pageX;\n this.origPageY = pageY;\n }\n else {\n deltaX = pageX - this.origPageX;\n deltaY = pageY - this.origPageY;\n }\n return {\n origEvent: ev,\n isTouch: true,\n subjectEl: this.subjectEl,\n pageX,\n pageY,\n deltaX,\n deltaY,\n };\n }\n}\n// Returns a boolean whether this was a left mouse click and no ctrl key (which means right click on Mac)\nfunction isPrimaryMouseButton(ev) {\n return ev.button === 0 && !ev.ctrlKey;\n}\n// Ignoring fake mouse events generated by touch\n// ----------------------------------------------------------------------------------------------------\nfunction startIgnoringMouse() {\n ignoreMouseDepth += 1;\n setTimeout(() => {\n ignoreMouseDepth -= 1;\n }, _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bG.touchMouseIgnoreWait);\n}\n// We want to attach touchmove as early as possible for Safari\n// ----------------------------------------------------------------------------------------------------\nfunction listenerCreated() {\n listenerCnt += 1;\n if (listenerCnt === 1) {\n window.addEventListener('touchmove', onWindowTouchMove, { passive: false });\n }\n}\nfunction listenerDestroyed() {\n listenerCnt -= 1;\n if (!listenerCnt) {\n window.removeEventListener('touchmove', onWindowTouchMove, { passive: false });\n }\n}\nfunction onWindowTouchMove(ev) {\n if (isWindowTouchMoveCancelled) {\n ev.preventDefault();\n }\n}\n\n/*\nAn effect in which an element follows the movement of a pointer across the screen.\nThe moving element is a clone of some other element.\nMust call start + handleMove + stop.\n*/\nclass ElementMirror {\n constructor() {\n this.isVisible = false; // must be explicitly enabled\n this.sourceEl = null;\n this.mirrorEl = null;\n this.sourceElRect = null; // screen coords relative to viewport\n // options that can be set directly by caller\n this.parentNode = document.body; // HIGHLY SUGGESTED to set this to sidestep ShadowDOM issues\n this.zIndex = 9999;\n this.revertDuration = 0;\n }\n start(sourceEl, pageX, pageY) {\n this.sourceEl = sourceEl;\n this.sourceElRect = this.sourceEl.getBoundingClientRect();\n this.origScreenX = pageX - window.scrollX;\n this.origScreenY = pageY - window.scrollY;\n this.deltaX = 0;\n this.deltaY = 0;\n this.updateElPosition();\n }\n handleMove(pageX, pageY) {\n this.deltaX = (pageX - window.scrollX) - this.origScreenX;\n this.deltaY = (pageY - window.scrollY) - this.origScreenY;\n this.updateElPosition();\n }\n // can be called before start\n setIsVisible(bool) {\n if (bool) {\n if (!this.isVisible) {\n if (this.mirrorEl) {\n this.mirrorEl.style.display = '';\n }\n this.isVisible = bool; // needs to happen before updateElPosition\n this.updateElPosition(); // because was not updating the position while invisible\n }\n }\n else if (this.isVisible) {\n if (this.mirrorEl) {\n this.mirrorEl.style.display = 'none';\n }\n this.isVisible = bool;\n }\n }\n // always async\n stop(needsRevertAnimation, callback) {\n let done = () => {\n this.cleanup();\n callback();\n };\n if (needsRevertAnimation &&\n this.mirrorEl &&\n this.isVisible &&\n this.revertDuration && // if 0, transition won't work\n (this.deltaX || this.deltaY) // if same coords, transition won't work\n ) {\n this.doRevertAnimation(done, this.revertDuration);\n }\n else {\n setTimeout(done, 0);\n }\n }\n doRevertAnimation(callback, revertDuration) {\n let mirrorEl = this.mirrorEl;\n let finalSourceElRect = this.sourceEl.getBoundingClientRect(); // because autoscrolling might have happened\n mirrorEl.style.transition =\n 'top ' + revertDuration + 'ms,' +\n 'left ' + revertDuration + 'ms';\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aN)(mirrorEl, {\n left: finalSourceElRect.left,\n top: finalSourceElRect.top,\n });\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.b0)(mirrorEl, () => {\n mirrorEl.style.transition = '';\n callback();\n });\n }\n cleanup() {\n if (this.mirrorEl) {\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aM)(this.mirrorEl);\n this.mirrorEl = null;\n }\n this.sourceEl = null;\n }\n updateElPosition() {\n if (this.sourceEl && this.isVisible) {\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aN)(this.getMirrorEl(), {\n left: this.sourceElRect.left + this.deltaX,\n top: this.sourceElRect.top + this.deltaY,\n });\n }\n }\n getMirrorEl() {\n let sourceElRect = this.sourceElRect;\n let mirrorEl = this.mirrorEl;\n if (!mirrorEl) {\n mirrorEl = this.mirrorEl = this.sourceEl.cloneNode(true); // cloneChildren=true\n // we don't want long taps or any mouse interaction causing selection/menus.\n // would use preventSelection(), but that prevents selectstart, causing problems.\n mirrorEl.style.userSelect = 'none';\n mirrorEl.style.webkitUserSelect = 'none';\n mirrorEl.style.pointerEvents = 'none';\n mirrorEl.classList.add('fc-event-dragging');\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aN)(mirrorEl, {\n position: 'fixed',\n zIndex: this.zIndex,\n visibility: '',\n boxSizing: 'border-box',\n width: sourceElRect.right - sourceElRect.left,\n height: sourceElRect.bottom - sourceElRect.top,\n right: 'auto',\n bottom: 'auto',\n margin: 0,\n });\n this.parentNode.appendChild(mirrorEl);\n }\n return mirrorEl;\n }\n}\n\n/*\nIs a cache for a given element's scroll information (all the info that ScrollController stores)\nin addition the \"client rectangle\" of the element.. the area within the scrollbars.\n\nThe cache can be in one of two modes:\n- doesListening:false - ignores when the container is scrolled by someone else\n- doesListening:true - watch for scrolling and update the cache\n*/\nclass ScrollGeomCache extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.b9 {\n constructor(scrollController, doesListening) {\n super();\n this.handleScroll = () => {\n this.scrollTop = this.scrollController.getScrollTop();\n this.scrollLeft = this.scrollController.getScrollLeft();\n this.handleScrollChange();\n };\n this.scrollController = scrollController;\n this.doesListening = doesListening;\n this.scrollTop = this.origScrollTop = scrollController.getScrollTop();\n this.scrollLeft = this.origScrollLeft = scrollController.getScrollLeft();\n this.scrollWidth = scrollController.getScrollWidth();\n this.scrollHeight = scrollController.getScrollHeight();\n this.clientWidth = scrollController.getClientWidth();\n this.clientHeight = scrollController.getClientHeight();\n this.clientRect = this.computeClientRect(); // do last in case it needs cached values\n if (this.doesListening) {\n this.getEventTarget().addEventListener('scroll', this.handleScroll);\n }\n }\n destroy() {\n if (this.doesListening) {\n this.getEventTarget().removeEventListener('scroll', this.handleScroll);\n }\n }\n getScrollTop() {\n return this.scrollTop;\n }\n getScrollLeft() {\n return this.scrollLeft;\n }\n setScrollTop(top) {\n this.scrollController.setScrollTop(top);\n if (!this.doesListening) {\n // we are not relying on the element to normalize out-of-bounds scroll values\n // so we need to sanitize ourselves\n this.scrollTop = Math.max(Math.min(top, this.getMaxScrollTop()), 0);\n this.handleScrollChange();\n }\n }\n setScrollLeft(top) {\n this.scrollController.setScrollLeft(top);\n if (!this.doesListening) {\n // we are not relying on the element to normalize out-of-bounds scroll values\n // so we need to sanitize ourselves\n this.scrollLeft = Math.max(Math.min(top, this.getMaxScrollLeft()), 0);\n this.handleScrollChange();\n }\n }\n getClientWidth() {\n return this.clientWidth;\n }\n getClientHeight() {\n return this.clientHeight;\n }\n getScrollWidth() {\n return this.scrollWidth;\n }\n getScrollHeight() {\n return this.scrollHeight;\n }\n handleScrollChange() {\n }\n}\n\nclass ElementScrollGeomCache extends ScrollGeomCache {\n constructor(el, doesListening) {\n super(new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ba(el), doesListening);\n }\n getEventTarget() {\n return this.scrollController.el;\n }\n computeClientRect() {\n return (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.b1)(this.scrollController.el);\n }\n}\n\nclass WindowScrollGeomCache extends ScrollGeomCache {\n constructor(doesListening) {\n super(new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bb(), doesListening);\n }\n getEventTarget() {\n return window;\n }\n computeClientRect() {\n return {\n left: this.scrollLeft,\n right: this.scrollLeft + this.clientWidth,\n top: this.scrollTop,\n bottom: this.scrollTop + this.clientHeight,\n };\n }\n // the window is the only scroll object that changes it's rectangle relative\n // to the document's topleft as it scrolls\n handleScrollChange() {\n this.clientRect = this.computeClientRect();\n }\n}\n\n// If available we are using native \"performance\" API instead of \"Date\"\n// Read more about it on MDN:\n// https://developer.mozilla.org/en-US/docs/Web/API/Performance\nconst getTime = typeof performance === 'function' ? performance.now : Date.now;\n/*\nFor a pointer interaction, automatically scrolls certain scroll containers when the pointer\napproaches the edge.\n\nThe caller must call start + handleMove + stop.\n*/\nclass AutoScroller {\n constructor() {\n // options that can be set by caller\n this.isEnabled = true;\n this.scrollQuery = [window, '.fc-scroller'];\n this.edgeThreshold = 50; // pixels\n this.maxVelocity = 300; // pixels per second\n // internal state\n this.pointerScreenX = null;\n this.pointerScreenY = null;\n this.isAnimating = false;\n this.scrollCaches = null;\n // protect against the initial pointerdown being too close to an edge and starting the scroll\n this.everMovedUp = false;\n this.everMovedDown = false;\n this.everMovedLeft = false;\n this.everMovedRight = false;\n this.animate = () => {\n if (this.isAnimating) { // wasn't cancelled between animation calls\n let edge = this.computeBestEdge(this.pointerScreenX + window.scrollX, this.pointerScreenY + window.scrollY);\n if (edge) {\n let now = getTime();\n this.handleSide(edge, (now - this.msSinceRequest) / 1000);\n this.requestAnimation(now);\n }\n else {\n this.isAnimating = false; // will stop animation\n }\n }\n };\n }\n start(pageX, pageY, scrollStartEl) {\n if (this.isEnabled) {\n this.scrollCaches = this.buildCaches(scrollStartEl);\n this.pointerScreenX = null;\n this.pointerScreenY = null;\n this.everMovedUp = false;\n this.everMovedDown = false;\n this.everMovedLeft = false;\n this.everMovedRight = false;\n this.handleMove(pageX, pageY);\n }\n }\n handleMove(pageX, pageY) {\n if (this.isEnabled) {\n let pointerScreenX = pageX - window.scrollX;\n let pointerScreenY = pageY - window.scrollY;\n let yDelta = this.pointerScreenY === null ? 0 : pointerScreenY - this.pointerScreenY;\n let xDelta = this.pointerScreenX === null ? 0 : pointerScreenX - this.pointerScreenX;\n if (yDelta < 0) {\n this.everMovedUp = true;\n }\n else if (yDelta > 0) {\n this.everMovedDown = true;\n }\n if (xDelta < 0) {\n this.everMovedLeft = true;\n }\n else if (xDelta > 0) {\n this.everMovedRight = true;\n }\n this.pointerScreenX = pointerScreenX;\n this.pointerScreenY = pointerScreenY;\n if (!this.isAnimating) {\n this.isAnimating = true;\n this.requestAnimation(getTime());\n }\n }\n }\n stop() {\n if (this.isEnabled) {\n this.isAnimating = false; // will stop animation\n for (let scrollCache of this.scrollCaches) {\n scrollCache.destroy();\n }\n this.scrollCaches = null;\n }\n }\n requestAnimation(now) {\n this.msSinceRequest = now;\n requestAnimationFrame(this.animate);\n }\n handleSide(edge, seconds) {\n let { scrollCache } = edge;\n let { edgeThreshold } = this;\n let invDistance = edgeThreshold - edge.distance;\n let velocity = // the closer to the edge, the faster we scroll\n ((invDistance * invDistance) / (edgeThreshold * edgeThreshold)) * // quadratic\n this.maxVelocity * seconds;\n let sign = 1;\n switch (edge.name) {\n case 'left':\n sign = -1;\n // falls through\n case 'right':\n scrollCache.setScrollLeft(scrollCache.getScrollLeft() + velocity * sign);\n break;\n case 'top':\n sign = -1;\n // falls through\n case 'bottom':\n scrollCache.setScrollTop(scrollCache.getScrollTop() + velocity * sign);\n break;\n }\n }\n // left/top are relative to document topleft\n computeBestEdge(left, top) {\n let { edgeThreshold } = this;\n let bestSide = null;\n let scrollCaches = this.scrollCaches || [];\n for (let scrollCache of scrollCaches) {\n let rect = scrollCache.clientRect;\n let leftDist = left - rect.left;\n let rightDist = rect.right - left;\n let topDist = top - rect.top;\n let bottomDist = rect.bottom - top;\n // completely within the rect?\n if (leftDist >= 0 && rightDist >= 0 && topDist >= 0 && bottomDist >= 0) {\n if (topDist <= edgeThreshold && this.everMovedUp && scrollCache.canScrollUp() &&\n (!bestSide || bestSide.distance > topDist)) {\n bestSide = { scrollCache, name: 'top', distance: topDist };\n }\n if (bottomDist <= edgeThreshold && this.everMovedDown && scrollCache.canScrollDown() &&\n (!bestSide || bestSide.distance > bottomDist)) {\n bestSide = { scrollCache, name: 'bottom', distance: bottomDist };\n }\n /*\n TODO: fix broken RTL scrolling. canScrollLeft always returning false\n https://github.com/fullcalendar/fullcalendar/issues/4837\n */\n if (leftDist <= edgeThreshold && this.everMovedLeft && scrollCache.canScrollLeft() &&\n (!bestSide || bestSide.distance > leftDist)) {\n bestSide = { scrollCache, name: 'left', distance: leftDist };\n }\n if (rightDist <= edgeThreshold && this.everMovedRight && scrollCache.canScrollRight() &&\n (!bestSide || bestSide.distance > rightDist)) {\n bestSide = { scrollCache, name: 'right', distance: rightDist };\n }\n }\n }\n return bestSide;\n }\n buildCaches(scrollStartEl) {\n return this.queryScrollEls(scrollStartEl).map((el) => {\n if (el === window) {\n return new WindowScrollGeomCache(false); // false = don't listen to user-generated scrolls\n }\n return new ElementScrollGeomCache(el, false); // false = don't listen to user-generated scrolls\n });\n }\n queryScrollEls(scrollStartEl) {\n let els = [];\n for (let query of this.scrollQuery) {\n if (typeof query === 'object') {\n els.push(query);\n }\n else {\n /*\n TODO: in the future, always have auto-scroll happen on element where current Hit came from\n Ticket: https://github.com/fullcalendar/fullcalendar/issues/4593\n */\n els.push(...Array.prototype.slice.call(scrollStartEl.getRootNode().querySelectorAll(query)));\n }\n }\n return els;\n }\n}\n\n/*\nMonitors dragging on an element. Has a number of high-level features:\n- minimum distance required before dragging\n- minimum wait time (\"delay\") before dragging\n- a mirror element that follows the pointer\n*/\nclass FeaturefulElementDragging extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bF {\n constructor(containerEl, selector) {\n super(containerEl);\n this.containerEl = containerEl;\n // options that can be directly set by caller\n // the caller can also set the PointerDragging's options as well\n this.delay = null;\n this.minDistance = 0;\n this.touchScrollAllowed = true; // prevents drag from starting and blocks scrolling during drag\n this.mirrorNeedsRevert = false;\n this.isInteracting = false; // is the user validly moving the pointer? lasts until pointerup\n this.isDragging = false; // is it INTENTFULLY dragging? lasts until after revert animation\n this.isDelayEnded = false;\n this.isDistanceSurpassed = false;\n this.delayTimeoutId = null;\n this.onPointerDown = (ev) => {\n if (!this.isDragging) { // so new drag doesn't happen while revert animation is going\n this.isInteracting = true;\n this.isDelayEnded = false;\n this.isDistanceSurpassed = false;\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ap)(document.body);\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ar)(document.body);\n // prevent links from being visited if there's an eventual drag.\n // also prevents selection in older browsers (maybe?).\n // not necessary for touch, besides, browser would complain about passiveness.\n if (!ev.isTouch) {\n ev.origEvent.preventDefault();\n }\n this.emitter.trigger('pointerdown', ev);\n if (this.isInteracting && // not destroyed via pointerdown handler\n !this.pointer.shouldIgnoreMove) {\n // actions related to initiating dragstart+dragmove+dragend...\n this.mirror.setIsVisible(false); // reset. caller must set-visible\n this.mirror.start(ev.subjectEl, ev.pageX, ev.pageY); // must happen on first pointer down\n this.startDelay(ev);\n if (!this.minDistance) {\n this.handleDistanceSurpassed(ev);\n }\n }\n }\n };\n this.onPointerMove = (ev) => {\n if (this.isInteracting) {\n this.emitter.trigger('pointermove', ev);\n if (!this.isDistanceSurpassed) {\n let minDistance = this.minDistance;\n let distanceSq; // current distance from the origin, squared\n let { deltaX, deltaY } = ev;\n distanceSq = deltaX * deltaX + deltaY * deltaY;\n if (distanceSq >= minDistance * minDistance) { // use pythagorean theorem\n this.handleDistanceSurpassed(ev);\n }\n }\n if (this.isDragging) {\n // a real pointer move? (not one simulated by scrolling)\n if (ev.origEvent.type !== 'scroll') {\n this.mirror.handleMove(ev.pageX, ev.pageY);\n this.autoScroller.handleMove(ev.pageX, ev.pageY);\n }\n this.emitter.trigger('dragmove', ev);\n }\n }\n };\n this.onPointerUp = (ev) => {\n if (this.isInteracting) {\n this.isInteracting = false;\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aq)(document.body);\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.as)(document.body);\n this.emitter.trigger('pointerup', ev); // can potentially set mirrorNeedsRevert\n if (this.isDragging) {\n this.autoScroller.stop();\n this.tryStopDrag(ev); // which will stop the mirror\n }\n if (this.delayTimeoutId) {\n clearTimeout(this.delayTimeoutId);\n this.delayTimeoutId = null;\n }\n }\n };\n let pointer = this.pointer = new PointerDragging(containerEl);\n pointer.emitter.on('pointerdown', this.onPointerDown);\n pointer.emitter.on('pointermove', this.onPointerMove);\n pointer.emitter.on('pointerup', this.onPointerUp);\n if (selector) {\n pointer.selector = selector;\n }\n this.mirror = new ElementMirror();\n this.autoScroller = new AutoScroller();\n }\n destroy() {\n this.pointer.destroy();\n // HACK: simulate a pointer-up to end the current drag\n // TODO: fire 'dragend' directly and stop interaction. discourage use of pointerup event (b/c might not fire)\n this.onPointerUp({});\n }\n startDelay(ev) {\n if (typeof this.delay === 'number') {\n this.delayTimeoutId = setTimeout(() => {\n this.delayTimeoutId = null;\n this.handleDelayEnd(ev);\n }, this.delay); // not assignable to number!\n }\n else {\n this.handleDelayEnd(ev);\n }\n }\n handleDelayEnd(ev) {\n this.isDelayEnded = true;\n this.tryStartDrag(ev);\n }\n handleDistanceSurpassed(ev) {\n this.isDistanceSurpassed = true;\n this.tryStartDrag(ev);\n }\n tryStartDrag(ev) {\n if (this.isDelayEnded && this.isDistanceSurpassed) {\n if (!this.pointer.wasTouchScroll || this.touchScrollAllowed) {\n this.isDragging = true;\n this.mirrorNeedsRevert = false;\n this.autoScroller.start(ev.pageX, ev.pageY, this.containerEl);\n this.emitter.trigger('dragstart', ev);\n if (this.touchScrollAllowed === false) {\n this.pointer.cancelTouchScroll();\n }\n }\n }\n }\n tryStopDrag(ev) {\n // .stop() is ALWAYS asynchronous, which we NEED because we want all pointerup events\n // that come from the document to fire beforehand. much more convenient this way.\n this.mirror.stop(this.mirrorNeedsRevert, this.stopDrag.bind(this, ev));\n }\n stopDrag(ev) {\n this.isDragging = false;\n this.emitter.trigger('dragend', ev);\n }\n // fill in the implementations...\n setIgnoreMove(bool) {\n this.pointer.shouldIgnoreMove = bool;\n }\n setMirrorIsVisible(bool) {\n this.mirror.setIsVisible(bool);\n }\n setMirrorNeedsRevert(bool) {\n this.mirrorNeedsRevert = bool;\n }\n setAutoScrollEnabled(bool) {\n this.autoScroller.isEnabled = bool;\n }\n}\n\n/*\nWhen this class is instantiated, it records the offset of an element (relative to the document topleft),\nand continues to monitor scrolling, updating the cached coordinates if it needs to.\nDoes not access the DOM after instantiation, so highly performant.\n\nAlso keeps track of all scrolling/overflow:hidden containers that are parents of the given element\nand an determine if a given point is inside the combined clipping rectangle.\n*/\nclass OffsetTracker {\n constructor(el) {\n this.el = el;\n this.origRect = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.b4)(el);\n // will work fine for divs that have overflow:hidden\n this.scrollCaches = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.b3)(el).map((scrollEl) => new ElementScrollGeomCache(scrollEl, true));\n }\n destroy() {\n for (let scrollCache of this.scrollCaches) {\n scrollCache.destroy();\n }\n }\n computeLeft() {\n let left = this.origRect.left;\n for (let scrollCache of this.scrollCaches) {\n left += scrollCache.origScrollLeft - scrollCache.getScrollLeft();\n }\n return left;\n }\n computeTop() {\n let top = this.origRect.top;\n for (let scrollCache of this.scrollCaches) {\n top += scrollCache.origScrollTop - scrollCache.getScrollTop();\n }\n return top;\n }\n isWithinClipping(pageX, pageY) {\n let point = { left: pageX, top: pageY };\n for (let scrollCache of this.scrollCaches) {\n if (!isIgnoredClipping(scrollCache.getEventTarget()) &&\n !(0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aD)(point, scrollCache.clientRect)) {\n return false;\n }\n }\n return true;\n }\n}\n// certain clipping containers should never constrain interactions, like <html> and <body>\n// https://github.com/fullcalendar/fullcalendar/issues/3615\nfunction isIgnoredClipping(node) {\n let tagName = node.tagName;\n return tagName === 'HTML' || tagName === 'BODY';\n}\n\n/*\nTracks movement over multiple droppable areas (aka \"hits\")\nthat exist in one or more DateComponents.\nRelies on an existing draggable.\n\nemits:\n- pointerdown\n- dragstart\n- hitchange - fires initially, even if not over a hit\n- pointerup\n- (hitchange - again, to null, if ended over a hit)\n- dragend\n*/\nclass HitDragging {\n constructor(dragging, droppableStore) {\n // options that can be set by caller\n this.useSubjectCenter = false;\n this.requireInitial = true; // if doesn't start out on a hit, won't emit any events\n this.disablePointCheck = false;\n this.initialHit = null;\n this.movingHit = null;\n this.finalHit = null; // won't ever be populated if shouldIgnoreMove\n this.handlePointerDown = (ev) => {\n let { dragging } = this;\n this.initialHit = null;\n this.movingHit = null;\n this.finalHit = null;\n this.prepareHits();\n this.processFirstCoord(ev);\n if (this.initialHit || !this.requireInitial) {\n dragging.setIgnoreMove(false);\n // TODO: fire this before computing processFirstCoord, so listeners can cancel. this gets fired by almost every handler :(\n this.emitter.trigger('pointerdown', ev);\n }\n else {\n dragging.setIgnoreMove(true);\n }\n };\n this.handleDragStart = (ev) => {\n this.emitter.trigger('dragstart', ev);\n this.handleMove(ev, true); // force = fire even if initially null\n };\n this.handleDragMove = (ev) => {\n this.emitter.trigger('dragmove', ev);\n this.handleMove(ev);\n };\n this.handlePointerUp = (ev) => {\n this.releaseHits();\n this.emitter.trigger('pointerup', ev);\n };\n this.handleDragEnd = (ev) => {\n if (this.movingHit) {\n this.emitter.trigger('hitupdate', null, true, ev);\n }\n this.finalHit = this.movingHit;\n this.movingHit = null;\n this.emitter.trigger('dragend', ev);\n };\n this.droppableStore = droppableStore;\n dragging.emitter.on('pointerdown', this.handlePointerDown);\n dragging.emitter.on('dragstart', this.handleDragStart);\n dragging.emitter.on('dragmove', this.handleDragMove);\n dragging.emitter.on('pointerup', this.handlePointerUp);\n dragging.emitter.on('dragend', this.handleDragEnd);\n this.dragging = dragging;\n this.emitter = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.F();\n }\n // sets initialHit\n // sets coordAdjust\n processFirstCoord(ev) {\n let origPoint = { left: ev.pageX, top: ev.pageY };\n let adjustedPoint = origPoint;\n let subjectEl = ev.subjectEl;\n let subjectRect;\n if (subjectEl instanceof HTMLElement) { // i.e. not a Document/ShadowRoot\n subjectRect = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.b4)(subjectEl);\n adjustedPoint = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aE)(adjustedPoint, subjectRect);\n }\n let initialHit = this.initialHit = this.queryHitForOffset(adjustedPoint.left, adjustedPoint.top);\n if (initialHit) {\n if (this.useSubjectCenter && subjectRect) {\n let slicedSubjectRect = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aC)(subjectRect, initialHit.rect);\n if (slicedSubjectRect) {\n adjustedPoint = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aF)(slicedSubjectRect);\n }\n }\n this.coordAdjust = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aG)(adjustedPoint, origPoint);\n }\n else {\n this.coordAdjust = { left: 0, top: 0 };\n }\n }\n handleMove(ev, forceHandle) {\n let hit = this.queryHitForOffset(ev.pageX + this.coordAdjust.left, ev.pageY + this.coordAdjust.top);\n if (forceHandle || !isHitsEqual(this.movingHit, hit)) {\n this.movingHit = hit;\n this.emitter.trigger('hitupdate', hit, false, ev);\n }\n }\n prepareHits() {\n this.offsetTrackers = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.a)(this.droppableStore, (interactionSettings) => {\n interactionSettings.component.prepareHits();\n return new OffsetTracker(interactionSettings.el);\n });\n }\n releaseHits() {\n let { offsetTrackers } = this;\n for (let id in offsetTrackers) {\n offsetTrackers[id].destroy();\n }\n this.offsetTrackers = {};\n }\n queryHitForOffset(offsetLeft, offsetTop) {\n let { droppableStore, offsetTrackers } = this;\n let bestHit = null;\n for (let id in droppableStore) {\n let component = droppableStore[id].component;\n let offsetTracker = offsetTrackers[id];\n if (offsetTracker && // wasn't destroyed mid-drag\n offsetTracker.isWithinClipping(offsetLeft, offsetTop)) {\n let originLeft = offsetTracker.computeLeft();\n let originTop = offsetTracker.computeTop();\n let positionLeft = offsetLeft - originLeft;\n let positionTop = offsetTop - originTop;\n let { origRect } = offsetTracker;\n let width = origRect.right - origRect.left;\n let height = origRect.bottom - origRect.top;\n if (\n // must be within the element's bounds\n positionLeft >= 0 && positionLeft < width &&\n positionTop >= 0 && positionTop < height) {\n let hit = component.queryHit(positionLeft, positionTop, width, height);\n if (hit && (\n // make sure the hit is within activeRange, meaning it's not a dead cell\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.b7)(hit.dateProfile.activeRange, hit.dateSpan.range)) &&\n // Ensure the component we are querying for the hit is accessibly my the pointer\n // Prevents obscured calendars (ex: under a modal dialog) from accepting hit\n // https://github.com/fullcalendar/fullcalendar/issues/5026\n (this.disablePointCheck ||\n offsetTracker.el.contains(offsetTracker.el.getRootNode().elementFromPoint(\n // add-back origins to get coordinate relative to top-left of window viewport\n positionLeft + originLeft - window.scrollX, positionTop + originTop - window.scrollY))) &&\n (!bestHit || hit.layer > bestHit.layer)) {\n hit.componentId = id;\n hit.context = component.context;\n // TODO: better way to re-orient rectangle\n hit.rect.left += originLeft;\n hit.rect.right += originLeft;\n hit.rect.top += originTop;\n hit.rect.bottom += originTop;\n bestHit = hit;\n }\n }\n }\n }\n return bestHit;\n }\n}\nfunction isHitsEqual(hit0, hit1) {\n if (!hit0 && !hit1) {\n return true;\n }\n if (Boolean(hit0) !== Boolean(hit1)) {\n return false;\n }\n return (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bd)(hit0.dateSpan, hit1.dateSpan);\n}\n\nfunction buildDatePointApiWithContext(dateSpan, context) {\n let props = {};\n for (let transform of context.pluginHooks.datePointTransforms) {\n Object.assign(props, transform(dateSpan, context));\n }\n Object.assign(props, buildDatePointApi(dateSpan, context.dateEnv));\n return props;\n}\nfunction buildDatePointApi(span, dateEnv) {\n return {\n date: dateEnv.toDate(span.range.start),\n dateStr: dateEnv.formatIso(span.range.start, { omitTime: span.allDay }),\n allDay: span.allDay,\n };\n}\n\n/*\nMonitors when the user clicks on a specific date/time of a component.\nA pointerdown+pointerup on the same \"hit\" constitutes a click.\n*/\nclass DateClicking extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.X {\n constructor(settings) {\n super(settings);\n this.handlePointerDown = (pev) => {\n let { dragging } = this;\n let downEl = pev.origEvent.target;\n // do this in pointerdown (not dragend) because DOM might be mutated by the time dragend is fired\n dragging.setIgnoreMove(!this.component.isValidDateDownEl(downEl));\n };\n // won't even fire if moving was ignored\n this.handleDragEnd = (ev) => {\n let { component } = this;\n let { pointer } = this.dragging;\n if (!pointer.wasTouchScroll) {\n let { initialHit, finalHit } = this.hitDragging;\n if (initialHit && finalHit && isHitsEqual(initialHit, finalHit)) {\n let { context } = component;\n let arg = Object.assign(Object.assign({}, buildDatePointApiWithContext(initialHit.dateSpan, context)), { dayEl: initialHit.dayEl, jsEvent: ev.origEvent, view: context.viewApi || context.calendarApi.view });\n context.emitter.trigger('dateClick', arg);\n }\n }\n };\n // we DO want to watch pointer moves because otherwise finalHit won't get populated\n this.dragging = new FeaturefulElementDragging(settings.el);\n this.dragging.autoScroller.isEnabled = false;\n let hitDragging = this.hitDragging = new HitDragging(this.dragging, (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bE)(settings));\n hitDragging.emitter.on('pointerdown', this.handlePointerDown);\n hitDragging.emitter.on('dragend', this.handleDragEnd);\n }\n destroy() {\n this.dragging.destroy();\n }\n}\n\n/*\nTracks when the user selects a portion of time of a component,\nconstituted by a drag over date cells, with a possible delay at the beginning of the drag.\n*/\nclass DateSelecting extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.X {\n constructor(settings) {\n super(settings);\n this.dragSelection = null;\n this.handlePointerDown = (ev) => {\n let { component, dragging } = this;\n let { options } = component.context;\n let canSelect = options.selectable &&\n component.isValidDateDownEl(ev.origEvent.target);\n // don't bother to watch expensive moves if component won't do selection\n dragging.setIgnoreMove(!canSelect);\n // if touch, require user to hold down\n dragging.delay = ev.isTouch ? getComponentTouchDelay$1(component) : null;\n };\n this.handleDragStart = (ev) => {\n this.component.context.calendarApi.unselect(ev); // unselect previous selections\n };\n this.handleHitUpdate = (hit, isFinal) => {\n let { context } = this.component;\n let dragSelection = null;\n let isInvalid = false;\n if (hit) {\n let initialHit = this.hitDragging.initialHit;\n let disallowed = hit.componentId === initialHit.componentId\n && this.isHitComboAllowed\n && !this.isHitComboAllowed(initialHit, hit);\n if (!disallowed) {\n dragSelection = joinHitsIntoSelection(initialHit, hit, context.pluginHooks.dateSelectionTransformers);\n }\n if (!dragSelection || !(0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bY)(dragSelection, hit.dateProfile, context)) {\n isInvalid = true;\n dragSelection = null;\n }\n }\n if (dragSelection) {\n context.dispatch({ type: 'SELECT_DATES', selection: dragSelection });\n }\n else if (!isFinal) { // only unselect if moved away while dragging\n context.dispatch({ type: 'UNSELECT_DATES' });\n }\n if (!isInvalid) {\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.au)();\n }\n else {\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.av)();\n }\n if (!isFinal) {\n this.dragSelection = dragSelection; // only clear if moved away from all hits while dragging\n }\n };\n this.handlePointerUp = (pev) => {\n if (this.dragSelection) {\n // selection is already rendered, so just need to report selection\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cr)(this.dragSelection, pev, this.component.context);\n this.dragSelection = null;\n }\n };\n let { component } = settings;\n let { options } = component.context;\n let dragging = this.dragging = new FeaturefulElementDragging(settings.el);\n dragging.touchScrollAllowed = false;\n dragging.minDistance = options.selectMinDistance || 0;\n dragging.autoScroller.isEnabled = options.dragScroll;\n let hitDragging = this.hitDragging = new HitDragging(this.dragging, (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bE)(settings));\n hitDragging.emitter.on('pointerdown', this.handlePointerDown);\n hitDragging.emitter.on('dragstart', this.handleDragStart);\n hitDragging.emitter.on('hitupdate', this.handleHitUpdate);\n hitDragging.emitter.on('pointerup', this.handlePointerUp);\n }\n destroy() {\n this.dragging.destroy();\n }\n}\nfunction getComponentTouchDelay$1(component) {\n let { options } = component.context;\n let delay = options.selectLongPressDelay;\n if (delay == null) {\n delay = options.longPressDelay;\n }\n return delay;\n}\nfunction joinHitsIntoSelection(hit0, hit1, dateSelectionTransformers) {\n let dateSpan0 = hit0.dateSpan;\n let dateSpan1 = hit1.dateSpan;\n let ms = [\n dateSpan0.range.start,\n dateSpan0.range.end,\n dateSpan1.range.start,\n dateSpan1.range.end,\n ];\n ms.sort(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.at);\n let props = {};\n for (let transformer of dateSelectionTransformers) {\n let res = transformer(hit0, hit1);\n if (res === false) {\n return null;\n }\n if (res) {\n Object.assign(props, res);\n }\n }\n props.range = { start: ms[0], end: ms[3] };\n props.allDay = dateSpan0.allDay;\n return props;\n}\n\nclass EventDragging extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.X {\n constructor(settings) {\n super(settings);\n // internal state\n this.subjectEl = null;\n this.subjectSeg = null; // the seg being selected/dragged\n this.isDragging = false;\n this.eventRange = null;\n this.relevantEvents = null; // the events being dragged\n this.receivingContext = null;\n this.validMutation = null;\n this.mutatedRelevantEvents = null;\n this.handlePointerDown = (ev) => {\n let origTarget = ev.origEvent.target;\n let { component, dragging } = this;\n let { mirror } = dragging;\n let { options } = component.context;\n let initialContext = component.context;\n this.subjectEl = ev.subjectEl;\n let subjectSeg = this.subjectSeg = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ev.subjectEl);\n let eventRange = this.eventRange = subjectSeg.eventRange;\n let eventInstanceId = eventRange.instance.instanceId;\n this.relevantEvents = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aT)(initialContext.getCurrentData().eventStore, eventInstanceId);\n dragging.minDistance = ev.isTouch ? 0 : options.eventDragMinDistance;\n dragging.delay =\n // only do a touch delay if touch and this event hasn't been selected yet\n (ev.isTouch && eventInstanceId !== component.props.eventSelection) ?\n getComponentTouchDelay(component) :\n null;\n if (options.fixedMirrorParent) {\n mirror.parentNode = options.fixedMirrorParent;\n }\n else {\n mirror.parentNode = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.Z)(origTarget, '.fc');\n }\n mirror.revertDuration = options.dragRevertDuration;\n let isValid = component.isValidSegDownEl(origTarget) &&\n !(0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.Z)(origTarget, '.fc-event-resizer'); // NOT on a resizer\n dragging.setIgnoreMove(!isValid);\n // disable dragging for elements that are resizable (ie, selectable)\n // but are not draggable\n this.isDragging = isValid &&\n ev.subjectEl.classList.contains('fc-event-draggable');\n };\n this.handleDragStart = (ev) => {\n let initialContext = this.component.context;\n let eventRange = this.eventRange;\n let eventInstanceId = eventRange.instance.instanceId;\n if (ev.isTouch) {\n // need to select a different event?\n if (eventInstanceId !== this.component.props.eventSelection) {\n initialContext.dispatch({ type: 'SELECT_EVENT', eventInstanceId });\n }\n }\n else {\n // if now using mouse, but was previous touch interaction, clear selected event\n initialContext.dispatch({ type: 'UNSELECT_EVENT' });\n }\n if (this.isDragging) {\n initialContext.calendarApi.unselect(ev); // unselect *date* selection\n initialContext.emitter.trigger('eventDragStart', {\n el: this.subjectEl,\n event: new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__._(initialContext, eventRange.def, eventRange.instance),\n jsEvent: ev.origEvent,\n view: initialContext.viewApi,\n });\n }\n };\n this.handleHitUpdate = (hit, isFinal) => {\n if (!this.isDragging) {\n return;\n }\n let relevantEvents = this.relevantEvents;\n let initialHit = this.hitDragging.initialHit;\n let initialContext = this.component.context;\n // states based on new hit\n let receivingContext = null;\n let mutation = null;\n let mutatedRelevantEvents = null;\n let isInvalid = false;\n let interaction = {\n affectedEvents: relevantEvents,\n mutatedEvents: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.H)(),\n isEvent: true,\n };\n if (hit) {\n receivingContext = hit.context;\n let receivingOptions = receivingContext.options;\n if (initialContext === receivingContext ||\n (receivingOptions.editable && receivingOptions.droppable)) {\n mutation = computeEventMutation(initialHit, hit, this.eventRange.instance.range.start, receivingContext.getCurrentData().pluginHooks.eventDragMutationMassagers);\n if (mutation) {\n mutatedRelevantEvents = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bV)(relevantEvents, receivingContext.getCurrentData().eventUiBases, mutation, receivingContext);\n interaction.mutatedEvents = mutatedRelevantEvents;\n if (!(0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bX)(interaction, hit.dateProfile, receivingContext)) {\n isInvalid = true;\n mutation = null;\n mutatedRelevantEvents = null;\n interaction.mutatedEvents = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.H)();\n }\n }\n }\n else {\n receivingContext = null;\n }\n }\n this.displayDrag(receivingContext, interaction);\n if (!isInvalid) {\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.au)();\n }\n else {\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.av)();\n }\n if (!isFinal) {\n if (initialContext === receivingContext && // TODO: write test for this\n isHitsEqual(initialHit, hit)) {\n mutation = null;\n }\n this.dragging.setMirrorNeedsRevert(!mutation);\n // render the mirror if no already-rendered mirror\n // TODO: wish we could somehow wait for dispatch to guarantee render\n this.dragging.setMirrorIsVisible(!hit || !this.subjectEl.getRootNode().querySelector('.fc-event-mirror'));\n // assign states based on new hit\n this.receivingContext = receivingContext;\n this.validMutation = mutation;\n this.mutatedRelevantEvents = mutatedRelevantEvents;\n }\n };\n this.handlePointerUp = () => {\n if (!this.isDragging) {\n this.cleanup(); // because handleDragEnd won't fire\n }\n };\n this.handleDragEnd = (ev) => {\n if (this.isDragging) {\n let initialContext = this.component.context;\n let initialView = initialContext.viewApi;\n let { receivingContext, validMutation } = this;\n let eventDef = this.eventRange.def;\n let eventInstance = this.eventRange.instance;\n let eventApi = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__._(initialContext, eventDef, eventInstance);\n let relevantEvents = this.relevantEvents;\n let mutatedRelevantEvents = this.mutatedRelevantEvents;\n let { finalHit } = this.hitDragging;\n this.clearDrag(); // must happen after revert animation\n initialContext.emitter.trigger('eventDragStop', {\n el: this.subjectEl,\n event: eventApi,\n jsEvent: ev.origEvent,\n view: initialView,\n });\n if (validMutation) {\n // dropped within same calendar\n if (receivingContext === initialContext) {\n let updatedEventApi = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__._(initialContext, mutatedRelevantEvents.defs[eventDef.defId], eventInstance ? mutatedRelevantEvents.instances[eventInstance.instanceId] : null);\n initialContext.dispatch({\n type: 'MERGE_EVENTS',\n eventStore: mutatedRelevantEvents,\n });\n let eventChangeArg = {\n oldEvent: eventApi,\n event: updatedEventApi,\n relatedEvents: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.w)(mutatedRelevantEvents, initialContext, eventInstance),\n revert() {\n initialContext.dispatch({\n type: 'MERGE_EVENTS',\n eventStore: relevantEvents, // the pre-change data\n });\n },\n };\n let transformed = {};\n for (let transformer of initialContext.getCurrentData().pluginHooks.eventDropTransformers) {\n Object.assign(transformed, transformer(validMutation, initialContext));\n }\n initialContext.emitter.trigger('eventDrop', Object.assign(Object.assign(Object.assign({}, eventChangeArg), transformed), { el: ev.subjectEl, delta: validMutation.datesDelta, jsEvent: ev.origEvent, view: initialView }));\n initialContext.emitter.trigger('eventChange', eventChangeArg);\n // dropped in different calendar\n }\n else if (receivingContext) {\n let eventRemoveArg = {\n event: eventApi,\n relatedEvents: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.w)(relevantEvents, initialContext, eventInstance),\n revert() {\n initialContext.dispatch({\n type: 'MERGE_EVENTS',\n eventStore: relevantEvents,\n });\n },\n };\n initialContext.emitter.trigger('eventLeave', Object.assign(Object.assign({}, eventRemoveArg), { draggedEl: ev.subjectEl, view: initialView }));\n initialContext.dispatch({\n type: 'REMOVE_EVENTS',\n eventStore: relevantEvents,\n });\n initialContext.emitter.trigger('eventRemove', eventRemoveArg);\n let addedEventDef = mutatedRelevantEvents.defs[eventDef.defId];\n let addedEventInstance = mutatedRelevantEvents.instances[eventInstance.instanceId];\n let addedEventApi = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__._(receivingContext, addedEventDef, addedEventInstance);\n receivingContext.dispatch({\n type: 'MERGE_EVENTS',\n eventStore: mutatedRelevantEvents,\n });\n let eventAddArg = {\n event: addedEventApi,\n relatedEvents: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.w)(mutatedRelevantEvents, receivingContext, addedEventInstance),\n revert() {\n receivingContext.dispatch({\n type: 'REMOVE_EVENTS',\n eventStore: mutatedRelevantEvents,\n });\n },\n };\n receivingContext.emitter.trigger('eventAdd', eventAddArg);\n if (ev.isTouch) {\n receivingContext.dispatch({\n type: 'SELECT_EVENT',\n eventInstanceId: eventInstance.instanceId,\n });\n }\n receivingContext.emitter.trigger('drop', Object.assign(Object.assign({}, buildDatePointApiWithContext(finalHit.dateSpan, receivingContext)), { draggedEl: ev.subjectEl, jsEvent: ev.origEvent, view: finalHit.context.viewApi }));\n receivingContext.emitter.trigger('eventReceive', Object.assign(Object.assign({}, eventAddArg), { draggedEl: ev.subjectEl, view: finalHit.context.viewApi }));\n }\n }\n else {\n initialContext.emitter.trigger('_noEventDrop');\n }\n }\n this.cleanup();\n };\n let { component } = this;\n let { options } = component.context;\n let dragging = this.dragging = new FeaturefulElementDragging(settings.el);\n dragging.pointer.selector = EventDragging.SELECTOR;\n dragging.touchScrollAllowed = false;\n dragging.autoScroller.isEnabled = options.dragScroll;\n let hitDragging = this.hitDragging = new HitDragging(this.dragging, _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.a5);\n hitDragging.useSubjectCenter = settings.useEventCenter;\n hitDragging.emitter.on('pointerdown', this.handlePointerDown);\n hitDragging.emitter.on('dragstart', this.handleDragStart);\n hitDragging.emitter.on('hitupdate', this.handleHitUpdate);\n hitDragging.emitter.on('pointerup', this.handlePointerUp);\n hitDragging.emitter.on('dragend', this.handleDragEnd);\n }\n destroy() {\n this.dragging.destroy();\n }\n // render a drag state on the next receivingCalendar\n displayDrag(nextContext, state) {\n let initialContext = this.component.context;\n let prevContext = this.receivingContext;\n // does the previous calendar need to be cleared?\n if (prevContext && prevContext !== nextContext) {\n // does the initial calendar need to be cleared?\n // if so, don't clear all the way. we still need to to hide the affectedEvents\n if (prevContext === initialContext) {\n prevContext.dispatch({\n type: 'SET_EVENT_DRAG',\n state: {\n affectedEvents: state.affectedEvents,\n mutatedEvents: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.H)(),\n isEvent: true,\n },\n });\n // completely clear the old calendar if it wasn't the initial\n }\n else {\n prevContext.dispatch({ type: 'UNSET_EVENT_DRAG' });\n }\n }\n if (nextContext) {\n nextContext.dispatch({ type: 'SET_EVENT_DRAG', state });\n }\n }\n clearDrag() {\n let initialCalendar = this.component.context;\n let { receivingContext } = this;\n if (receivingContext) {\n receivingContext.dispatch({ type: 'UNSET_EVENT_DRAG' });\n }\n // the initial calendar might have an dummy drag state from displayDrag\n if (initialCalendar !== receivingContext) {\n initialCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' });\n }\n }\n cleanup() {\n this.subjectSeg = null;\n this.isDragging = false;\n this.eventRange = null;\n this.relevantEvents = null;\n this.receivingContext = null;\n this.validMutation = null;\n this.mutatedRelevantEvents = null;\n }\n}\n// TODO: test this in IE11\n// QUESTION: why do we need it on the resizable???\nEventDragging.SELECTOR = '.fc-event-draggable, .fc-event-resizable';\nfunction computeEventMutation(hit0, hit1, eventInstanceStart, massagers) {\n let dateSpan0 = hit0.dateSpan;\n let dateSpan1 = hit1.dateSpan;\n let date0 = dateSpan0.range.start;\n let date1 = dateSpan1.range.start;\n let standardProps = {};\n if (dateSpan0.allDay !== dateSpan1.allDay) {\n standardProps.allDay = dateSpan1.allDay;\n standardProps.hasEnd = hit1.context.options.allDayMaintainDuration;\n if (dateSpan1.allDay) {\n // means date1 is already start-of-day,\n // but date0 needs to be converted\n date0 = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.q)(eventInstanceStart);\n }\n else {\n // Moving from allDate->timed\n // Doesn't matter where on the event the drag began, mutate the event's start-date to date1\n date0 = eventInstanceStart;\n }\n }\n let delta = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ay)(date0, date1, hit0.context.dateEnv, hit0.componentId === hit1.componentId ?\n hit0.largeUnit :\n null);\n if (delta.milliseconds) { // has hours/minutes/seconds\n standardProps.allDay = false;\n }\n let mutation = {\n datesDelta: delta,\n standardProps,\n };\n for (let massager of massagers) {\n massager(mutation, hit0, hit1);\n }\n return mutation;\n}\nfunction getComponentTouchDelay(component) {\n let { options } = component.context;\n let delay = options.eventLongPressDelay;\n if (delay == null) {\n delay = options.longPressDelay;\n }\n return delay;\n}\n\nclass EventResizing extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.X {\n constructor(settings) {\n super(settings);\n // internal state\n this.draggingSegEl = null;\n this.draggingSeg = null; // TODO: rename to resizingSeg? subjectSeg?\n this.eventRange = null;\n this.relevantEvents = null;\n this.validMutation = null;\n this.mutatedRelevantEvents = null;\n this.handlePointerDown = (ev) => {\n let { component } = this;\n let segEl = this.querySegEl(ev);\n let seg = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.Y)(segEl);\n let eventRange = this.eventRange = seg.eventRange;\n this.dragging.minDistance = component.context.options.eventDragMinDistance;\n // if touch, need to be working with a selected event\n this.dragging.setIgnoreMove(!this.component.isValidSegDownEl(ev.origEvent.target) ||\n (ev.isTouch && this.component.props.eventSelection !== eventRange.instance.instanceId));\n };\n this.handleDragStart = (ev) => {\n let { context } = this.component;\n let eventRange = this.eventRange;\n this.relevantEvents = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aT)(context.getCurrentData().eventStore, this.eventRange.instance.instanceId);\n let segEl = this.querySegEl(ev);\n this.draggingSegEl = segEl;\n this.draggingSeg = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.Y)(segEl);\n context.calendarApi.unselect();\n context.emitter.trigger('eventResizeStart', {\n el: segEl,\n event: new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__._(context, eventRange.def, eventRange.instance),\n jsEvent: ev.origEvent,\n view: context.viewApi,\n });\n };\n this.handleHitUpdate = (hit, isFinal, ev) => {\n let { context } = this.component;\n let relevantEvents = this.relevantEvents;\n let initialHit = this.hitDragging.initialHit;\n let eventInstance = this.eventRange.instance;\n let mutation = null;\n let mutatedRelevantEvents = null;\n let isInvalid = false;\n let interaction = {\n affectedEvents: relevantEvents,\n mutatedEvents: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.H)(),\n isEvent: true,\n };\n if (hit) {\n let disallowed = hit.componentId === initialHit.componentId\n && this.isHitComboAllowed\n && !this.isHitComboAllowed(initialHit, hit);\n if (!disallowed) {\n mutation = computeMutation(initialHit, hit, ev.subjectEl.classList.contains('fc-event-resizer-start'), eventInstance.range);\n }\n }\n if (mutation) {\n mutatedRelevantEvents = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bV)(relevantEvents, context.getCurrentData().eventUiBases, mutation, context);\n interaction.mutatedEvents = mutatedRelevantEvents;\n if (!(0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bX)(interaction, hit.dateProfile, context)) {\n isInvalid = true;\n mutation = null;\n mutatedRelevantEvents = null;\n interaction.mutatedEvents = null;\n }\n }\n if (mutatedRelevantEvents) {\n context.dispatch({\n type: 'SET_EVENT_RESIZE',\n state: interaction,\n });\n }\n else {\n context.dispatch({ type: 'UNSET_EVENT_RESIZE' });\n }\n if (!isInvalid) {\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.au)();\n }\n else {\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.av)();\n }\n if (!isFinal) {\n if (mutation && isHitsEqual(initialHit, hit)) {\n mutation = null;\n }\n this.validMutation = mutation;\n this.mutatedRelevantEvents = mutatedRelevantEvents;\n }\n };\n this.handleDragEnd = (ev) => {\n let { context } = this.component;\n let eventDef = this.eventRange.def;\n let eventInstance = this.eventRange.instance;\n let eventApi = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__._(context, eventDef, eventInstance);\n let relevantEvents = this.relevantEvents;\n let mutatedRelevantEvents = this.mutatedRelevantEvents;\n context.emitter.trigger('eventResizeStop', {\n el: this.draggingSegEl,\n event: eventApi,\n jsEvent: ev.origEvent,\n view: context.viewApi,\n });\n if (this.validMutation) {\n let updatedEventApi = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__._(context, mutatedRelevantEvents.defs[eventDef.defId], eventInstance ? mutatedRelevantEvents.instances[eventInstance.instanceId] : null);\n context.dispatch({\n type: 'MERGE_EVENTS',\n eventStore: mutatedRelevantEvents,\n });\n let eventChangeArg = {\n oldEvent: eventApi,\n event: updatedEventApi,\n relatedEvents: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.w)(mutatedRelevantEvents, context, eventInstance),\n revert() {\n context.dispatch({\n type: 'MERGE_EVENTS',\n eventStore: relevantEvents, // the pre-change events\n });\n },\n };\n context.emitter.trigger('eventResize', Object.assign(Object.assign({}, eventChangeArg), { el: this.draggingSegEl, startDelta: this.validMutation.startDelta || (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.d)(0), endDelta: this.validMutation.endDelta || (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.d)(0), jsEvent: ev.origEvent, view: context.viewApi }));\n context.emitter.trigger('eventChange', eventChangeArg);\n }\n else {\n context.emitter.trigger('_noEventResize');\n }\n // reset all internal state\n this.draggingSeg = null;\n this.relevantEvents = null;\n this.validMutation = null;\n // okay to keep eventInstance around. useful to set it in handlePointerDown\n };\n let { component } = settings;\n let dragging = this.dragging = new FeaturefulElementDragging(settings.el);\n dragging.pointer.selector = '.fc-event-resizer';\n dragging.touchScrollAllowed = false;\n dragging.autoScroller.isEnabled = component.context.options.dragScroll;\n let hitDragging = this.hitDragging = new HitDragging(this.dragging, (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bE)(settings));\n hitDragging.emitter.on('pointerdown', this.handlePointerDown);\n hitDragging.emitter.on('dragstart', this.handleDragStart);\n hitDragging.emitter.on('hitupdate', this.handleHitUpdate);\n hitDragging.emitter.on('dragend', this.handleDragEnd);\n }\n destroy() {\n this.dragging.destroy();\n }\n querySegEl(ev) {\n return (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ev.subjectEl, '.fc-event');\n }\n}\nfunction computeMutation(hit0, hit1, isFromStart, instanceRange) {\n let dateEnv = hit0.context.dateEnv;\n let date0 = hit0.dateSpan.range.start;\n let date1 = hit1.dateSpan.range.start;\n let delta = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ay)(date0, date1, dateEnv, hit0.largeUnit);\n if (isFromStart) {\n if (dateEnv.add(instanceRange.start, delta) < instanceRange.end) {\n return { startDelta: delta };\n }\n }\n else if (dateEnv.add(instanceRange.end, delta) > instanceRange.start) {\n return { endDelta: delta };\n }\n return null;\n}\n\nclass UnselectAuto {\n constructor(context) {\n this.context = context;\n this.isRecentPointerDateSelect = false; // wish we could use a selector to detect date selection, but uses hit system\n this.matchesCancel = false;\n this.matchesEvent = false;\n this.onSelect = (selectInfo) => {\n if (selectInfo.jsEvent) {\n this.isRecentPointerDateSelect = true;\n }\n };\n this.onDocumentPointerDown = (pev) => {\n let unselectCancel = this.context.options.unselectCancel;\n let downEl = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aP)(pev.origEvent);\n this.matchesCancel = !!(0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.Z)(downEl, unselectCancel);\n this.matchesEvent = !!(0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.Z)(downEl, EventDragging.SELECTOR); // interaction started on an event?\n };\n this.onDocumentPointerUp = (pev) => {\n let { context } = this;\n let { documentPointer } = this;\n let calendarState = context.getCurrentData();\n // touch-scrolling should never unfocus any type of selection\n if (!documentPointer.wasTouchScroll) {\n if (calendarState.dateSelection && // an existing date selection?\n !this.isRecentPointerDateSelect // a new pointer-initiated date selection since last onDocumentPointerUp?\n ) {\n let unselectAuto = context.options.unselectAuto;\n if (unselectAuto && (!unselectAuto || !this.matchesCancel)) {\n context.calendarApi.unselect(pev);\n }\n }\n if (calendarState.eventSelection && // an existing event selected?\n !this.matchesEvent // interaction DIDN'T start on an event\n ) {\n context.dispatch({ type: 'UNSELECT_EVENT' });\n }\n }\n this.isRecentPointerDateSelect = false;\n };\n let documentPointer = this.documentPointer = new PointerDragging(document);\n documentPointer.shouldIgnoreMove = true;\n documentPointer.shouldWatchScroll = false;\n documentPointer.emitter.on('pointerdown', this.onDocumentPointerDown);\n documentPointer.emitter.on('pointerup', this.onDocumentPointerUp);\n /*\n TODO: better way to know about whether there was a selection with the pointer\n */\n context.emitter.on('select', this.onSelect);\n }\n destroy() {\n this.context.emitter.off('select', this.onSelect);\n this.documentPointer.destroy();\n }\n}\n\nconst OPTION_REFINERS = {\n fixedMirrorParent: _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.n,\n};\nconst LISTENER_REFINERS = {\n dateClick: _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.n,\n eventDragStart: _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.n,\n eventDragStop: _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.n,\n eventDrop: _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.n,\n eventResizeStart: _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.n,\n eventResizeStop: _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.n,\n eventResize: _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.n,\n drop: _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.n,\n eventReceive: _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.n,\n eventLeave: _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.n,\n};\n\n/*\nGiven an already instantiated draggable object for one-or-more elements,\nInterprets any dragging as an attempt to drag an events that lives outside\nof a calendar onto a calendar.\n*/\nclass ExternalElementDragging {\n constructor(dragging, suppliedDragMeta) {\n this.receivingContext = null;\n this.droppableEvent = null; // will exist for all drags, even if create:false\n this.suppliedDragMeta = null;\n this.dragMeta = null;\n this.handleDragStart = (ev) => {\n this.dragMeta = this.buildDragMeta(ev.subjectEl);\n };\n this.handleHitUpdate = (hit, isFinal, ev) => {\n let { dragging } = this.hitDragging;\n let receivingContext = null;\n let droppableEvent = null;\n let isInvalid = false;\n let interaction = {\n affectedEvents: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.H)(),\n mutatedEvents: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.H)(),\n isEvent: this.dragMeta.create,\n };\n if (hit) {\n receivingContext = hit.context;\n if (this.canDropElOnCalendar(ev.subjectEl, receivingContext)) {\n droppableEvent = computeEventForDateSpan(hit.dateSpan, this.dragMeta, receivingContext);\n interaction.mutatedEvents = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aU)(droppableEvent);\n isInvalid = !(0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bX)(interaction, hit.dateProfile, receivingContext);\n if (isInvalid) {\n interaction.mutatedEvents = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.H)();\n droppableEvent = null;\n }\n }\n }\n this.displayDrag(receivingContext, interaction);\n // show mirror if no already-rendered mirror element OR if we are shutting down the mirror (?)\n // TODO: wish we could somehow wait for dispatch to guarantee render\n dragging.setMirrorIsVisible(isFinal || !droppableEvent || !document.querySelector('.fc-event-mirror'));\n if (!isInvalid) {\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.au)();\n }\n else {\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.av)();\n }\n if (!isFinal) {\n dragging.setMirrorNeedsRevert(!droppableEvent);\n this.receivingContext = receivingContext;\n this.droppableEvent = droppableEvent;\n }\n };\n this.handleDragEnd = (pev) => {\n let { receivingContext, droppableEvent } = this;\n this.clearDrag();\n if (receivingContext && droppableEvent) {\n let finalHit = this.hitDragging.finalHit;\n let finalView = finalHit.context.viewApi;\n let dragMeta = this.dragMeta;\n receivingContext.emitter.trigger('drop', Object.assign(Object.assign({}, buildDatePointApiWithContext(finalHit.dateSpan, receivingContext)), { draggedEl: pev.subjectEl, jsEvent: pev.origEvent, view: finalView }));\n if (dragMeta.create) {\n let addingEvents = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aU)(droppableEvent);\n receivingContext.dispatch({\n type: 'MERGE_EVENTS',\n eventStore: addingEvents,\n });\n if (pev.isTouch) {\n receivingContext.dispatch({\n type: 'SELECT_EVENT',\n eventInstanceId: droppableEvent.instance.instanceId,\n });\n }\n // signal that an external event landed\n receivingContext.emitter.trigger('eventReceive', {\n event: new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__._(receivingContext, droppableEvent.def, droppableEvent.instance),\n relatedEvents: [],\n revert() {\n receivingContext.dispatch({\n type: 'REMOVE_EVENTS',\n eventStore: addingEvents,\n });\n },\n draggedEl: pev.subjectEl,\n view: finalView,\n });\n }\n }\n this.receivingContext = null;\n this.droppableEvent = null;\n };\n let hitDragging = this.hitDragging = new HitDragging(dragging, _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.a5);\n hitDragging.requireInitial = false; // will start outside of a component\n hitDragging.emitter.on('dragstart', this.handleDragStart);\n hitDragging.emitter.on('hitupdate', this.handleHitUpdate);\n hitDragging.emitter.on('dragend', this.handleDragEnd);\n this.suppliedDragMeta = suppliedDragMeta;\n }\n buildDragMeta(subjectEl) {\n if (typeof this.suppliedDragMeta === 'object') {\n return (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bH)(this.suppliedDragMeta);\n }\n if (typeof this.suppliedDragMeta === 'function') {\n return (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bH)(this.suppliedDragMeta(subjectEl));\n }\n return getDragMetaFromEl(subjectEl);\n }\n displayDrag(nextContext, state) {\n let prevContext = this.receivingContext;\n if (prevContext && prevContext !== nextContext) {\n prevContext.dispatch({ type: 'UNSET_EVENT_DRAG' });\n }\n if (nextContext) {\n nextContext.dispatch({ type: 'SET_EVENT_DRAG', state });\n }\n }\n clearDrag() {\n if (this.receivingContext) {\n this.receivingContext.dispatch({ type: 'UNSET_EVENT_DRAG' });\n }\n }\n canDropElOnCalendar(el, receivingContext) {\n let dropAccept = receivingContext.options.dropAccept;\n if (typeof dropAccept === 'function') {\n return dropAccept.call(receivingContext.calendarApi, el);\n }\n if (typeof dropAccept === 'string' && dropAccept) {\n return Boolean((0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aO)(el, dropAccept));\n }\n return true;\n }\n}\n// Utils for computing event store from the DragMeta\n// ----------------------------------------------------------------------------------------------------\nfunction computeEventForDateSpan(dateSpan, dragMeta, context) {\n let defProps = Object.assign({}, dragMeta.leftoverProps);\n for (let transform of context.pluginHooks.externalDefTransforms) {\n Object.assign(defProps, transform(dateSpan, dragMeta));\n }\n let { refined, extra } = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aj)(defProps, context);\n let def = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ai)(refined, extra, dragMeta.sourceId, dateSpan.allDay, context.options.forceEventDuration || Boolean(dragMeta.duration), // hasEnd\n context);\n let start = dateSpan.range.start;\n // only rely on time info if drop zone is all-day,\n // otherwise, we already know the time\n if (dateSpan.allDay && dragMeta.startTime) {\n start = context.dateEnv.add(start, dragMeta.startTime);\n }\n let end = dragMeta.duration ?\n context.dateEnv.add(start, dragMeta.duration) :\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cs)(dateSpan.allDay, start, context);\n let instance = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ah)(def.defId, { start, end });\n return { def, instance };\n}\n// Utils for extracting data from element\n// ----------------------------------------------------------------------------------------------------\nfunction getDragMetaFromEl(el) {\n let str = getEmbeddedElData(el, 'event');\n let obj = str ?\n JSON.parse(str) :\n { create: false }; // if no embedded data, assume no event creation\n return (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bH)(obj);\n}\n_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bG.dataAttrPrefix = '';\nfunction getEmbeddedElData(el, name) {\n let prefix = _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bG.dataAttrPrefix;\n let prefixedName = (prefix ? prefix + '-' : '') + name;\n return el.getAttribute('data-' + prefixedName) || '';\n}\n\n/*\nMakes an element (that is *external* to any calendar) draggable.\nCan pass in data that determines how an event will be created when dropped onto a calendar.\nLeverages FullCalendar's internal drag-n-drop functionality WITHOUT a third-party drag system.\n*/\nclass ExternalDraggable {\n constructor(el, settings = {}) {\n this.handlePointerDown = (ev) => {\n let { dragging } = this;\n let { minDistance, longPressDelay } = this.settings;\n dragging.minDistance =\n minDistance != null ?\n minDistance :\n (ev.isTouch ? 0 : _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.e.eventDragMinDistance);\n dragging.delay =\n ev.isTouch ? // TODO: eventually read eventLongPressDelay instead vvv\n (longPressDelay != null ? longPressDelay : _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.e.longPressDelay) :\n 0;\n };\n this.handleDragStart = (ev) => {\n if (ev.isTouch &&\n this.dragging.delay &&\n ev.subjectEl.classList.contains('fc-event')) {\n this.dragging.mirror.getMirrorEl().classList.add('fc-event-selected');\n }\n };\n this.settings = settings;\n let dragging = this.dragging = new FeaturefulElementDragging(el);\n dragging.touchScrollAllowed = false;\n if (settings.itemSelector != null) {\n dragging.pointer.selector = settings.itemSelector;\n }\n if (settings.appendTo != null) {\n dragging.mirror.parentNode = settings.appendTo; // TODO: write tests\n }\n dragging.emitter.on('pointerdown', this.handlePointerDown);\n dragging.emitter.on('dragstart', this.handleDragStart);\n new ExternalElementDragging(dragging, settings.eventData); // eslint-disable-line no-new\n }\n destroy() {\n this.dragging.destroy();\n }\n}\n\n/*\nDetects when a *THIRD-PARTY* drag-n-drop system interacts with elements.\nThe third-party system is responsible for drawing the visuals effects of the drag.\nThis class simply monitors for pointer movements and fires events.\nIt also has the ability to hide the moving element (the \"mirror\") during the drag.\n*/\nclass InferredElementDragging extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bF {\n constructor(containerEl) {\n super(containerEl);\n this.shouldIgnoreMove = false;\n this.mirrorSelector = '';\n this.currentMirrorEl = null;\n this.handlePointerDown = (ev) => {\n this.emitter.trigger('pointerdown', ev);\n if (!this.shouldIgnoreMove) {\n // fire dragstart right away. does not support delay or min-distance\n this.emitter.trigger('dragstart', ev);\n }\n };\n this.handlePointerMove = (ev) => {\n if (!this.shouldIgnoreMove) {\n this.emitter.trigger('dragmove', ev);\n }\n };\n this.handlePointerUp = (ev) => {\n this.emitter.trigger('pointerup', ev);\n if (!this.shouldIgnoreMove) {\n // fire dragend right away. does not support a revert animation\n this.emitter.trigger('dragend', ev);\n }\n };\n let pointer = this.pointer = new PointerDragging(containerEl);\n pointer.emitter.on('pointerdown', this.handlePointerDown);\n pointer.emitter.on('pointermove', this.handlePointerMove);\n pointer.emitter.on('pointerup', this.handlePointerUp);\n }\n destroy() {\n this.pointer.destroy();\n }\n setIgnoreMove(bool) {\n this.shouldIgnoreMove = bool;\n }\n setMirrorIsVisible(bool) {\n if (bool) {\n // restore a previously hidden element.\n // use the reference in case the selector class has already been removed.\n if (this.currentMirrorEl) {\n this.currentMirrorEl.style.visibility = '';\n this.currentMirrorEl = null;\n }\n }\n else {\n let mirrorEl = this.mirrorSelector\n // TODO: somehow query FullCalendars WITHIN shadow-roots\n ? document.querySelector(this.mirrorSelector)\n : null;\n if (mirrorEl) {\n this.currentMirrorEl = mirrorEl;\n mirrorEl.style.visibility = 'hidden';\n }\n }\n }\n}\n\n/*\nBridges third-party drag-n-drop systems with FullCalendar.\nMust be instantiated and destroyed by caller.\n*/\nclass ThirdPartyDraggable {\n constructor(containerOrSettings, settings) {\n let containerEl = document;\n if (\n // wish we could just test instanceof EventTarget, but doesn't work in IE11\n containerOrSettings === document ||\n containerOrSettings instanceof Element) {\n containerEl = containerOrSettings;\n settings = settings || {};\n }\n else {\n settings = (containerOrSettings || {});\n }\n let dragging = this.dragging = new InferredElementDragging(containerEl);\n if (typeof settings.itemSelector === 'string') {\n dragging.pointer.selector = settings.itemSelector;\n }\n else if (containerEl === document) {\n dragging.pointer.selector = '[data-event]';\n }\n if (typeof settings.mirrorSelector === 'string') {\n dragging.mirrorSelector = settings.mirrorSelector;\n }\n let externalDragging = new ExternalElementDragging(dragging, settings.eventData);\n // The hit-detection system requires that the dnd-mirror-element be pointer-events:none,\n // but this can't be guaranteed for third-party draggables, so disable\n externalDragging.hitDragging.disablePointCheck = true;\n }\n destroy() {\n this.dragging.destroy();\n }\n}\n\nvar index = (0,_fullcalendar_core_index_js__WEBPACK_IMPORTED_MODULE_1__.createPlugin)({\n name: '@fullcalendar/interaction',\n componentInteractions: [DateClicking, DateSelecting, EventDragging, EventResizing],\n calendarInteractions: [UnselectAuto],\n elementDraggingImpl: FeaturefulElementDragging,\n optionRefiners: OPTION_REFINERS,\n listenerRefiners: LISTENER_REFINERS,\n});\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKHNzcikvLi9ub2RlX21vZHVsZXMvQGZ1bGxjYWxlbmRhci9pbnRlcmFjdGlvbi9pbmRleC5qcyIsIm1hcHBpbmdzIjoiOzs7Ozs7OztBQUEyRDtBQUM4M0I7O0FBRXo3Qiw4REFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCO0FBQzVCO0FBQ0E7QUFDQSx1Q0FBdUM7QUFDdkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0QkFBNEI7QUFDNUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrRUFBK0U7QUFDL0U7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DO0FBQ25DO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0ZBQW9GO0FBQ3BGO0FBQ0EsZ0NBQWdDO0FBQ2hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQiw2REFBTztBQUNsQztBQUNBLDRFQUE0RSxlQUFlO0FBQzNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0ZBQW9GLGVBQWU7QUFDbkc7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLGlFQUFjO0FBQ25EO0FBQ0Esb0NBQW9DO0FBQ3BDO0FB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O0FBQ3JEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaURBQWlEO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsWUFBWSx5RUFBWTtBQUN4QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVnRiIsInNvdXJjZXMiOlsiL2hvbWUvc2lsdmlvL0RldmVsb3AvQ0lSVVgtQVBQL25vZGVfbW9kdWxlcy9AZnVsbGNhbGVuZGFyL2ludGVyYWN0aW9uL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNyZWF0ZVBsdWdpbiB9IGZyb20gJ0BmdWxsY2FsZW5kYXIvY29yZS9pbmRleC5qcyc7XG5pbXBvcnQgeyBjb25maWcsIEVtaXR0ZXIsIGVsZW1lbnRDbG9zZXN0LCBhcHBseVN0eWxlLCB3aGVuVHJhbnNpdGlvbkRvbmUsIHJlbW92ZUVsZW1lbnQsIFNjcm9sbENvbnRyb2xsZXIsIEVsZW1lbnRTY3JvbGxDb250cm9sbGVyLCBjb21wdXRlSW5uZXJSZWN0LCBXaW5kb3dTY3JvbGxDb250cm9sbGVyLCBFbGVtZW50RHJhZ2dpbmcsIHByZXZlbnRTZWxlY3Rpb24sIHByZXZlbnRDb250ZXh0TWVudSwgYWxsb3dTZWxlY3Rpb24sIGFsbG93Q29udGV4dE1lbnUsIGNvbXB1dGVSZWN0LCBnZXRDbGlwcGluZ1BhcmVudHMsIHBvaW50SW5zaWRlUmVjdCwgY29uc3RyYWluUG9pbnQsIGludGVyc2VjdFJlY3RzLCBnZXRSZWN0Q2VudGVyLCBkaWZmUG9pbnRzLCBtYXBIYXNoLCByYW5nZUNvbnRhaW5zUmFuZ2UsIGlzRGF0ZVNwYW5zRXF1YWwsIEludGVyYWN0aW9uLCBpbnRlcmFjdGlvblNldHRpbmdzVG9TdG9yZSwgaXNEYXRlU2VsZWN0aW9uVmFsaWQsIGVuYWJsZUN1cnNvciwgZGlzYWJsZUN1cnNvciwgdHJpZ2dlckRhdGVTZWxlY3QsIGNvbXBhcmVOdW1iZXJzLCBnZXRFbFNlZywgZ2V0UmVsZXZhbnRFdmVudHMsIEV2ZW50SW1wbCwgY3JlYXRlRW1wdHlFdmVudFN0b3JlLCBhcHBseU11dGF0aW9uVG9FdmVudFN0b3JlLCBpc0ludGVyYWN0aW9uVmFsaWQsIGJ1aWxkRXZlbnRBcGlzLCBpbnRlcmFjdGlvblNldHRpbmdzU3RvcmUsIHN0YXJ0T2ZEYXksIGRpZmZEYXRlcywgY3JlYXRlRHVyYXRpb24sIGdldEV2ZW50VGFyZ2V0VmlhUm9vdCwgaWRlbnRpdHksIGV2ZW50VHVwbGVUb1N0b3JlLCBwYXJzZURyYWdNZXRhLCBlbGVtZW50TWF0Y2hlcywgcmVmaW5lRXZlbnREZWYsIHBhcnNlRXZlbnREZWYsIGdldERlZmF1bHRFdmVudEVuZCwgY3JlYXRlRXZlbnRJbnN0YW5jZSwgQkFTRV9PUFRJT05fREVGQVVMVFMgfSBmcm9tICdAZnVsbGNhbGVuZGFyL2NvcmUvaW50ZXJuYWwuanMnO1xuXG5jb25maWcudG91Y2hNb3VzZUlnbm9yZVdhaXQgPSA1MDA7XG5sZXQgaWdub3JlTW91c2VEZXB0aCA9IDA7XG5sZXQgbGlzdGVuZXJDbnQgPSAwO1xubGV0IGlzV2luZG93VG91Y2hNb3ZlQ2FuY2VsbGVkID0gZmFsc2U7XG4vKlxuVXNlcyBhIFwicG9pbnRlclwiIGFic3RyYWN0aW9uLCB3aGljaCBtb25pdG9ycyBVSSBldmVudHMgZm9yIGJvdGggbW91c2UgYW5kIHRvdWNoLlxuVHJhY2tzIHdoZW4gdGhlIHBvaW50ZXIgXCJkcmFnc1wiIG9uIGEgY2VydGFpbiBlbGVtZW50LCBtZWFuaW5nIGRvd24rbW92ZSt1cC5cblxuQWxzbywgdHJhY2tzIGlmIHRoZXJlIHdhcyB0b3VjaC1zY3JvbGxpbmcuXG5BbHNvLCBjYW4gcHJldmVudCB0b3VjaC1zY3JvbGxpbmcgZnJvbSBoYXBwZW5pbmcuXG5BbHNvLCBjYW4gZmlyZSBwb2ludGVybW92ZSBldmVudHMgd2hlbiBzY3JvbGxpbmcgaGFwcGVucyB1bmRlcm5lYXRoLCBldmVuIHdoZW4gbm8gcmVhbCBwb2ludGVyIG1vdmVtZW50LlxuXG5lbWl0czpcbi0gcG9pbnRlcmRvd25cbi0gcG9pbnRlcm1vdmVcbi0gcG9pbnRlcnVwXG4qL1xuY2xhc3MgUG9pbnRlckRyYWdnaW5nIHtcbiAgICBjb25zdHJ1Y3Rvcihjb250YWluZXJFbCkge1xuICAgICAgICB0aGlzLnN1YmplY3RFbCA9IG51bGw7XG4gICAgICAgIC8vIG9wdGlvbnMgdGhhdCBjYW4gYmUgZGlyZWN0bHkgYXNzaWduZWQgYnkgY2FsbGVyXG4gICAgICAgIHRoaXMuc2VsZWN0b3IgPSAnJzsgLy8gd2lsbCBjYXVzZSBzdWJqZWN0RWwgaW4gYWxsIGVtaXR0ZWQgZXZlbnRzIHRvIGJlIHRoaXMgZWxlbWVudFxuICAgICAgICB0aGlzLmhhbmRsZVNlbGVjdG9yID0gJyc7XG4gICAgICAgIHRoaXMuc2hvdWxkSWdub3JlTW92ZSA9IGZhbHNlO1xuICAgICAgICB0aGlzLnNob3VsZFdhdGNoU2Nyb2xsID0gdHJ1ZTsgLy8gZm9yIHNpbXVsYXRpbmcgcG9pbnRlcm1vdmUgb24gc2Nyb2xsXG4gICAgICAgIC8vIGludGVybmFsIHN0YXRlc1xuICAgICAgICB0aGlzLmlzRHJhZ2dpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5pc1RvdWNoRHJhZ2dpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy53YXNUb3VjaFNjcm9sbCA9IGZhbHNlO1xuICAgICAgICAvLyBNb3VzZVxuICAgICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgICAgIHRoaXMuaGFuZGxlTW91c2VEb3duID0gKGV2KSA9PiB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuc2hvdWxkSWdub3JlTW91c2UoKSAmJlxuICAgICAgICAgICAgICAgIGlzUHJpbWFyeU1vdXNlQnV0dG9uKGV2KSAmJlxuICAgICAgICAgICAgICAgIHRoaXMudHJ5U3RhcnQoZXYpKSB7XG4gICAgICAgICAgICAgICAgbGV0IHBldiA9IHRoaXMuY3JlYXRlRXZlbnRGcm9tTW91c2UoZXYsIHRydWUpO1xuICAgICAgICAgICAgICAgIHRoaXMuZW1pdHRlci50cmlnZ2VyKCdwb2ludGVyZG93bicsIHBldik7XG4gICAgICAgICAgICAgICAgdGhpcy5pbml0U2Nyb2xsV2F0Y2gocGV2KTtcbiAgICAgICAgICAgICAgICBpZiAoIXRoaXMuc2hvdWxkSWdub3JlTW92ZSkge1xuICAgICAgICAgICAgICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZW1vdmUnLCB0aGlzLmhhbmRsZU1vdXNlTW92ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNldXAnLCB0aGlzLmhhbmRsZU1vdXNlVXApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZU1vdXNlTW92ZSA9IChldikgPT4ge1xuICAgICAgICAgICAgbGV0IHBldiA9IHRoaXMuY3JlYXRlRXZlbnRGcm9tTW91c2UoZXYpO1xuICAgICAgICAgICAgdGhpcy5yZWNvcmRDb29yZHMocGV2KTtcbiAgICAgICAgICAgIHRoaXMuZW1pdHRlci50cmlnZ2VyKCdwb2ludGVybW92ZScsIHBldik7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlTW91c2VVcCA9IChldikgPT4ge1xuICAgICAgICAgICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgdGhpcy5oYW5kbGVNb3VzZU1vdmUpO1xuICAgICAgICAgICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsIHRoaXMuaGFuZGxlTW91c2VVcCk7XG4gICAgICAgICAgICB0aGlzLmVtaXR0ZXIudHJpZ2dlcigncG9pbnRlcnVwJywgdGhpcy5jcmVhdGVFdmVudEZyb21Nb3VzZShldikpO1xuICAgICAgICAgICAgdGhpcy5jbGVhbnVwKCk7IC8vIGNhbGwgbGFzdCBzbyB0aGF0IHBvaW50ZXJ1cCBoYXMgYWNjZXNzIHRvIHByb3BzXG4gICAgICAgIH07XG4gICAgICAgIC8vIFRvdWNoXG4gICAgICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAgICAgdGhpcy5oYW5kbGVUb3VjaFN0YXJ0ID0gKGV2KSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy50cnlTdGFydChldikpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmlzVG91Y2hEcmFnZ2luZyA9IHRydWU7XG4gICAgICAgICAgICAgICAgbGV0IHBldiA9IHRoaXMuY3JlYXRlRXZlbnRGcm9tVG91Y2goZXYsIHRydWUpO1xuICAgICAgICAgICAgICAgIHRoaXMuZW1pdHRlci50cmlnZ2VyKCdwb2ludGVyZG93bicsIHBldik7XG4gICAgICAgICAgICAgICAgdGhpcy5pbml0U2Nyb2xsV2F0Y2gocGV2KTtcbiAgICAgICAgICAgICAgICAvLyB1bmxpa2UgbW91c2UsIG5lZWQgdG8gYXR0YWNoIHRvIHRhcmdldCwgbm90IGRvY3VtZW50XG4gICAgICAgICAgICAgICAgLy8gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9hLzQ1NzYwMDE0XG4gICAgICAgICAgICAgICAgbGV0IHRhcmdldEVsID0gZXYudGFyZ2V0O1xuICAgICAgICAgICAgICAgIGlmICghdGhpcy5zaG91bGRJZ25vcmVNb3ZlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRhcmdldEVsLmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNobW92ZScsIHRoaXMuaGFuZGxlVG91Y2hNb3ZlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGFyZ2V0RWwuYWRkRXZlbnRMaXN0ZW5lcigndG91Y2hlbmQnLCB0aGlzLmhhbmRsZVRvdWNoRW5kKTtcbiAgICAgICAgICAgICAgICB0YXJnZXRFbC5hZGRFdmVudExpc3RlbmVyKCd0b3VjaGNhbmNlbCcsIHRoaXMuaGFuZGxlVG91Y2hFbmQpOyAvLyB0cmVhdCBpdCBhcyBhIHRvdWNoIGVuZFxuICAgICAgICAgICAgICAgIC8vIGF0dGFjaCBhIGhhbmRsZXIgdG8gZ2V0IGNhbGxlZCB3aGVuIEFOWSBzY3JvbGwgYWN0aW9uIGhhcHBlbnMgb24gdGhlIHBhZ2UuXG4gICAgICAgICAgICAgICAgLy8gdGhpcyB3YXMgaW1wb3NzaWJsZSB0byBkbyB3aXRoIG5vcm1hbCBvbi9vZmYgYmVjYXVzZSAnc2Nyb2xsJyBkb2Vzbid0IGJ1YmJsZS5cbiAgICAgICAgICAgICAgICAvLyBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8zMjk1NDU2NS85NjM0MlxuICAgICAgICAgICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdzY3JvbGwnLCB0aGlzLmhhbmRsZVRvdWNoU2Nyb2xsLCB0cnVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVUb3VjaE1vdmUgPSAoZXYpID0+IHtcbiAgICAgICAgICAgIGxldCBwZXYgPSB0aGlzLmNyZWF0ZUV2ZW50RnJvbVRvdWNoKGV2KTtcbiAgICAgICAgICAgIHRoaXMucmVjb3JkQ29vcmRzKHBldik7XG4gICAgICAgICAgICB0aGlzLmVtaXR0ZXIudHJpZ2dlcigncG9pbnRlcm1vdmUnLCBwZXYpO1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZVRvdWNoRW5kID0gKGV2KSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy5pc0RyYWdnaW5nKSB7IC8vIGRvbmUgdG8gZ3VhcmQgYWdhaW5zdCB0b3VjaGVuZCBmb2xsb3dlZCBieSB0b3VjaGNhbmNlbFxuICAgICAgICAgICAgICAgIGxldCB0YXJnZXRFbCA9IGV2LnRhcmdldDtcbiAgICAgICAgICAgICAgICB0YXJnZXRFbC5yZW1vdmVFdmVudExpc3RlbmVyKCd0b3VjaG1vdmUnLCB0aGlzLmhhbmRsZVRvdWNoTW92ZSk7XG4gICAgICAgICAgICAgICAgdGFyZ2V0RWwucmVtb3ZlRXZlbnRMaXN0ZW5lcigndG91Y2hlbmQnLCB0aGlzLmhhbmRsZVRvdWNoRW5kKTtcbiAgICAgICAgICAgICAgICB0YXJnZXRFbC5yZW1vdmVFdmVudExpc3RlbmVyKCd0b3VjaGNhbmNlbCcsIHRoaXMuaGFuZGxlVG91Y2hFbmQpO1xuICAgICAgICAgICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdzY3JvbGwnLCB0aGlzLmhhbmRsZVRvdWNoU2Nyb2xsLCB0cnVlKTsgLy8gdXNlQ2FwdHVyZWQ9dHJ1ZVxuICAgICAgICAgICAgICAgIHRoaXMuZW1pdHRlci50cmlnZ2VyKCdwb2ludGVydXAnLCB0aGlzLmNyZWF0ZUV2ZW50RnJvbVRvdWNoKGV2KSk7XG4gICAgICAgICAgICAgICAgdGhpcy5jbGVhbnVwKCk7IC8vIGNhbGwgbGFzdCBzbyB0aGF0IHBvaW50ZXJ1cCBoYXMgYWNjZXNzIHRvIHByb3BzXG4gICAgICAgICAgICAgICAgdGhpcy5pc1RvdWNoRHJhZ2dpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBzdGFydElnbm9yaW5nTW91c2UoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVUb3VjaFNjcm9sbCA9ICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMud2FzVG91Y2hTY3JvbGwgPSB0cnVlO1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZVNjcm9sbCA9IChldikgPT4ge1xuICAgICAgICAgICAgaWYgKCF0aGlzLnNob3VsZElnbm9yZU1vdmUpIHtcbiAgICAgICAgICAgICAgICBsZXQgcGFnZVggPSAod2luZG93LnNjcm9sbFggLSB0aGlzLnByZXZTY3JvbGxYKSArIHRoaXMucHJldlBhZ2VYO1xuICAgICAgICAgICAgICAgIGxldCBwYWdlWSA9ICh3aW5kb3cuc2Nyb2xsWSAtIHRoaXMucHJldlNjcm9sbFkpICsgdGhpcy5wcmV2UGFnZVk7XG4gICAgICAgICAgICAgICAgdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ3BvaW50ZXJtb3ZlJywge1xuICAgICAgICAgICAgICAgICAgICBvcmlnRXZlbnQ6IGV2LFxuICAgICAgICAgICAgICAgICAgICBpc1RvdWNoOiB0aGlzLmlzVG91Y2hEcmFnZ2luZyxcbiAgICAgICAgICAgICAgICAgICAgc3ViamVjdEVsOiB0aGlzLnN1YmplY3RFbCxcbiAgICAgICAgICAgICAgICAgICAgcGFnZVgsXG4gICAgICAgICAgICAgICAgICAgIHBhZ2VZLFxuICAgICAgICAgICAgICAgICAgICBkZWx0YVg6IHBhZ2VYIC0gdGhpcy5vcmlnUGFnZVgsXG4gICAgICAgICAgICAgICAgICAgIGRlbHRhWTogcGFnZVkgLSB0aGlzLm9yaWdQYWdlWSxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5jb250YWluZXJFbCA9IGNvbnRhaW5lckVsO1xuICAgICAgICB0aGlzLmVtaXR0ZXIgPSBuZXcgRW1pdHRlcigpO1xuICAgICAgICBjb250YWluZXJFbC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZWRvd24nLCB0aGlzLmhhbmRsZU1vdXNlRG93bik7XG4gICAgICAgIGNvbnRhaW5lckVsLmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNoc3RhcnQnLCB0aGlzLmhhbmRsZVRvdWNoU3RhcnQsIHsgcGFzc2l2ZTogdHJ1ZSB9KTtcbiAgICAgICAgbGlzdGVuZXJDcmVhdGVkKCk7XG4gICAgfVxuICAgIGRlc3Ryb3koKSB7XG4gICAgICAgIHRoaXMuY29udGFpbmVyRWwucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgdGhpcy5oYW5kbGVNb3VzZURvd24pO1xuICAgICAgICB0aGlzLmNvbnRhaW5lckVsLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNoc3RhcnQnLCB0aGlzLmhhbmRsZVRvdWNoU3RhcnQsIHsgcGFzc2l2ZTogdHJ1ZSB9KTtcbiAgICAgICAgbGlzdGVuZXJEZXN0cm95ZWQoKTtcbiAgICB9XG4gICAgdHJ5U3RhcnQoZXYpIHtcbiAgICAgICAgbGV0IHN1YmplY3RFbCA9IHRoaXMucXVlcnlTdWJqZWN0RWwoZXYpO1xuICAgICAgICBsZXQgZG93bkVsID0gZXYudGFyZ2V0O1xuICAgICAgICBpZiAoc3ViamVjdEVsICYmXG4gICAgICAgICAgICAoIXRoaXMuaGFuZGxlU2VsZWN0b3IgfHwgZWxlbWVudENsb3Nlc3QoZG93bkVsLCB0aGlzLmhhbmRsZVNlbGVjdG9yKSkpIHtcbiAgICAgICAgICAgIHRoaXMuc3ViamVjdEVsID0gc3ViamVjdEVsO1xuICAgICAgICAgICAgdGhpcy5pc0RyYWdnaW5nID0gdHJ1ZTsgLy8gZG8gdGhpcyBmaXJzdCBzbyBjYW5jZWxUb3VjaFNjcm9sbCB3aWxsIHdvcmtcbiAgICAgICAgICAgIHRoaXMud2FzVG91Y2hTY3JvbGwgPSBmYWxzZTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgY2xlYW51cCgpIHtcbiAgICAgICAgaXNXaW5kb3dUb3VjaE1vdmVDYW5jZWxsZWQgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5pc0RyYWdnaW5nID0gZmFsc2U7XG4gICAgICAgIHRoaXMuc3ViamVjdEVsID0gbnVsbDtcbiAgICAgICAgLy8ga2VlcCB3YXNUb3VjaFNjcm9sbCBhcm91bmQgZm9yIGxhdGVyIGFjY2Vzc1xuICAgICAgICB0aGlzLmRlc3Ryb3lTY3JvbGxXYXRjaCgpO1xuICAgIH1cbiAgICBxdWVyeVN1YmplY3RFbChldikge1xuICAgICAgICBpZiAodGhpcy5zZWxlY3Rvcikge1xuICAgICAgICAgICAgcmV0dXJuIGVsZW1lbnRDbG9zZXN0KGV2LnRhcmdldCwgdGhpcy5zZWxlY3Rvcik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuY29udGFpbmVyRWw7XG4gICAgfVxuICAgIHNob3VsZElnbm9yZU1vdXNlKCkge1xuICAgICAgICByZXR1cm4gaWdub3JlTW91c2VEZXB0aCB8fCB0aGlzLmlzVG91Y2hEcmFnZ2luZztcbiAgICB9XG4gICAgLy8gY2FuIGJlIGNhbGxlZCBieSB1c2VyIG9mIHRoaXMgY2xhc3MsIHRvIGNhbmNlbCB0b3VjaC1iYXNlZCBzY3JvbGxpbmcgZm9yIHRoZSBjdXJyZW50IGRyYWdcbiAgICBjYW5jZWxUb3VjaFNjcm9sbCgpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNEcmFnZ2luZykge1xuICAgICAgICAgICAgaXNXaW5kb3dUb3VjaE1vdmVDYW5jZWxsZWQgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8vIFNjcm9sbGluZyB0aGF0IHNpbXVsYXRlcyBwb2ludGVybW92ZXNcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgaW5pdFNjcm9sbFdhdGNoKGV2KSB7XG4gICAgICAgIGlmICh0aGlzLnNob3VsZFdhdGNoU2Nyb2xsKSB7XG4gICAgICAgICAgICB0aGlzLnJlY29yZENvb3Jkcyhldik7XG4gICAgICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignc2Nyb2xsJywgdGhpcy5oYW5kbGVTY3JvbGwsIHRydWUpOyAvLyB1c2VDYXB0dXJlPXRydWVcbiAgICAgICAgfVxuICAgIH1cbiAgICByZWNvcmRDb29yZHMoZXYpIHtcbiAgICAgICAgaWYgKHRoaXMuc2hvdWxkV2F0Y2hTY3JvbGwpIHtcbiAgICAgICAgICAgIHRoaXMucHJldlBhZ2VYID0gZXYucGFnZVg7XG4gICAgICAgICAgICB0aGlzLnByZXZQYWdlWSA9IGV2LnBhZ2VZO1xuICAgICAgICAgICAgdGhpcy5wcmV2U2Nyb2xsWCA9IHdpbmRvdy5zY3JvbGxYO1xuICAgICAgICAgICAgdGhpcy5wcmV2U2Nyb2xsWSA9IHdpbmRvdy5zY3JvbGxZO1xuICAgICAgICB9XG4gICAgfVxuICAgIGRlc3Ryb3lTY3JvbGxXYXRjaCgpIHtcbiAgICAgICAgaWYgKHRoaXMuc2hvdWxkV2F0Y2hTY3JvbGwpIHtcbiAgICAgICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdzY3JvbGwnLCB0aGlzLmhhbmRsZVNjcm9sbCwgdHJ1ZSk7IC8vIHVzZUNhcHR1cmVkPXRydWVcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBFdmVudCBOb3JtYWxpemF0aW9uXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIGNyZWF0ZUV2ZW50RnJvbU1vdXNlKGV2LCBpc0ZpcnN0KSB7XG4gICAgICAgIGxldCBkZWx0YVggPSAwO1xuICAgICAgICBsZXQgZGVsdGFZID0gMDtcbiAgICAgICAgLy8gVE9ETzogcmVwZWF0IGNvZGVcbiAgICAgICAgaWYgKGlzRmlyc3QpIHtcbiAgICAgICAgICAgIHRoaXMub3JpZ1BhZ2VYID0gZXYucGFnZVg7XG4gICAgICAgICAgICB0aGlzLm9yaWdQYWdlWSA9IGV2LnBhZ2VZO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZGVsdGFYID0gZXYucGFnZVggLSB0aGlzLm9yaWdQYWdlWDtcbiAgICAgICAgICAgIGRlbHRhWSA9IGV2LnBhZ2VZIC0gdGhpcy5vcmlnUGFnZVk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIG9yaWdFdmVudDogZXYsXG4gICAgICAgICAgICBpc1RvdWNoOiBmYWxzZSxcbiAgICAgICAgICAgIHN1YmplY3RFbDogdGhpcy5zdWJqZWN0RWwsXG4gICAgICAgICAgICBwYWdlWDogZXYucGFnZVgsXG4gICAgICAgICAgICBwYWdlWTogZXYucGFnZVksXG4gICAgICAgICAgICBkZWx0YVgsXG4gICAgICAgICAgICBkZWx0YVksXG4gICAgICAgIH07XG4gICAgfVxuICAgIGNyZWF0ZUV2ZW50RnJvbVRvdWNoKGV2LCBpc0ZpcnN0KSB7XG4gICAgICAgIGxldCB0b3VjaGVzID0gZXYudG91Y2hlcztcbiAgICAgICAgbGV0IHBhZ2VYO1xuICAgICAgICBsZXQgcGFnZVk7XG4gICAgICAgIGxldCBkZWx0YVggPSAwO1xuICAgICAgICBsZXQgZGVsdGFZID0gMDtcbiAgICAgICAgLy8gaWYgdG91Y2ggY29vcmRzIGF2YWlsYWJsZSwgcHJlZmVyLFxuICAgICAgICAvLyBiZWNhdXNlIEZGIHdvdWxkIGdpdmUgYmFkIGV2LnBhZ2VYIGV2LnBhZ2VZXG4gICAgICAgIGlmICh0b3VjaGVzICYmIHRvdWNoZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICBwYWdlWCA9IHRvdWNoZXNbMF0ucGFnZVg7XG4gICAgICAgICAgICBwYWdlWSA9IHRvdWNoZXNbMF0ucGFnZVk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBwYWdlWCA9IGV2LnBhZ2VYO1xuICAgICAgICAgICAgcGFnZVkgPSBldi5wYWdlWTtcbiAgICAgICAgfVxuICAgICAgICAvLyBUT0RPOiByZXBlYXQgY29kZVxuICAgICAgICBpZiAoaXNGaXJzdCkge1xuICAgICAgICAgICAgdGhpcy5vcmlnUGFnZVggPSBwYWdlWDtcbiAgICAgICAgICAgIHRoaXMub3JpZ1BhZ2VZID0gcGFnZVk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBkZWx0YVggPSBwYWdlWCAtIHRoaXMub3JpZ1BhZ2VYO1xuICAgICAgICAgICAgZGVsdGFZID0gcGFnZVkgLSB0aGlzLm9yaWdQYWdlWTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgb3JpZ0V2ZW50OiBldixcbiAgICAgICAgICAgIGlzVG91Y2g6IHRydWUsXG4gICAgICAgICAgICBzdWJqZWN0RWw6IHRoaXMuc3ViamVjdEVsLFxuICAgICAgICAgICAgcGFnZVgsXG4gICAgICAgICAgICBwYWdlWSxcbiAgICAgICAgICAgIGRlbHRhWCxcbiAgICAgICAgICAgIGRlbHRhWSxcbiAgICAgICAgfTtcbiAgICB9XG59XG4vLyBSZXR1cm5zIGEgYm9vbGVhbiB3aGV0aGVyIHRoaXMgd2FzIGEgbGVmdCBtb3VzZSBjbGljayBhbmQgbm8gY3RybCBrZXkgKHdoaWNoIG1lYW5zIHJpZ2h0IGNsaWNrIG9uIE1hYylcbmZ1bmN0aW9uIGlzUHJpbWFyeU1vdXNlQnV0dG9uKGV2KSB7XG4gICAgcmV0dXJuIGV2LmJ1dHRvbiA9PT0gMCAmJiAhZXYuY3RybEtleTtcbn1cbi8vIElnbm9yaW5nIGZha2UgbW91c2UgZXZlbnRzIGdlbmVyYXRlZCBieSB0b3VjaFxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuZnVuY3Rpb24gc3RhcnRJZ25vcmluZ01vdXNlKCkge1xuICAgIGlnbm9yZU1vdXNlRGVwdGggKz0gMTtcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgaWdub3JlTW91c2VEZXB0aCAtPSAxO1xuICAgIH0sIGNvbmZpZy50b3VjaE1vdXNlSWdub3JlV2FpdCk7XG59XG4vLyBXZSB3YW50IHRvIGF0dGFjaCB0b3VjaG1vdmUgYXMgZWFybHkgYXMgcG9zc2libGUgZm9yIFNhZmFyaVxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuZnVuY3Rpb24gbGlzdGVuZXJDcmVhdGVkKCkge1xuICAgIGxpc3RlbmVyQ250ICs9IDE7XG4gICAgaWYgKGxpc3RlbmVyQ250ID09PSAxKSB7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCd0b3VjaG1vdmUnLCBvbldpbmRvd1RvdWNoTW92ZSwgeyBwYXNzaXZlOiBmYWxzZSB9KTtcbiAgICB9XG59XG5mdW5jdGlvbiBsaXN0ZW5lckRlc3Ryb3llZCgpIHtcbiAgICBsaXN0ZW5lckNudCAtPSAxO1xuICAgIGlmICghbGlzdGVuZXJDbnQpIHtcbiAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNobW92ZScsIG9uV2luZG93VG91Y2hNb3ZlLCB7IHBhc3NpdmU6IGZhbHNlIH0pO1xuICAgIH1cbn1cbmZ1bmN0aW9uIG9uV2luZG93VG91Y2hNb3ZlKGV2KSB7XG4gICAgaWYgKGlzV2luZG93VG91Y2hNb3ZlQ2FuY2VsbGVkKSB7XG4gICAgICAgIGV2LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxufVxuXG4vKlxuQW4gZWZmZWN0IGluIHdoaWNoIGFuIGVsZW1lbnQgZm9sbG93cyB0aGUgbW92ZW1lbnQgb2YgYSBwb2ludGVyIGFjcm9zcyB0aGUgc2NyZWVuLlxuVGhlIG1vdmluZyBlbGVtZW50IGlzIGEgY2xvbmUgb2Ygc29tZSBvdGhlciBlbGVtZW50LlxuTXVzdCBjYWxsIHN0YXJ0ICsgaGFuZGxlTW92ZSArIHN0b3AuXG4qL1xuY2xhc3MgRWxlbWVudE1pcnJvciB7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHRoaXMuaXNWaXNpYmxlID0gZmFsc2U7IC8vIG11c3QgYmUgZXhwbGljaXRseSBlbmFibGVkXG4gICAgICAgIHRoaXMuc291cmNlRWwgPSBudWxsO1xuICAgICAgICB0aGlzLm1pcnJvckVsID0gbnVsbDtcbiAgICAgICAgdGhpcy5zb3VyY2VFbFJlY3QgPSBudWxsOyAvLyBzY3JlZW4gY29vcmRzIHJlbGF0aXZlIHRvIHZpZXdwb3J0XG4gICAgICAgIC8vIG9wdGlvbnMgdGhhdCBjYW4gYmUgc2V0IGRpcmVjdGx5IGJ5IGNhbGxlclxuICAgICAgICB0aGlzLnBhcmVudE5vZGUgPSBkb2N1bWVudC5ib2R5OyAvLyBISUdITFkgU1VHR0VTVEVEIHRvIHNldCB0aGlzIHRvIHNpZGVzdGVwIFNoYWRvd0RPTSBpc3N1ZXNcbiAgICAgICAgdGhpcy56SW5kZXggPSA5OTk5O1xuICAgICAgICB0aGlzLnJldmVydER1cmF0aW9uID0gMDtcbiAgICB9XG4gICAgc3RhcnQoc291cmNlRWwsIHBhZ2VYLCBwYWdlWSkge1xuICAgICAgICB0aGlzLnNvdXJjZUVsID0gc291cmNlRWw7XG4gICAgICAgIHRoaXMuc291cmNlRWxSZWN0ID0gdGhpcy5zb3VyY2VFbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgICAgdGhpcy5vcmlnU2NyZWVuWCA9IHBhZ2VYIC0gd2luZG93LnNjcm9sbFg7XG4gICAgICAgIHRoaXMub3JpZ1NjcmVlblkgPSBwYWdlWSAtIHdpbmRvdy5zY3JvbGxZO1xuICAgICAgICB0aGlzLmRlbHRhWCA9IDA7XG4gICAgICAgIHRoaXMuZGVsdGFZID0gMDtcbiAgICAgICAgdGhpcy51cGRhdGVFbFBvc2l0aW9uKCk7XG4gICAgfVxuICAgIGhhbmRsZU1vdmUocGFnZVgsIHBhZ2VZKSB7XG4gICAgICAgIHRoaXMuZGVsdGFYID0gKHBhZ2VYIC0gd2luZG93LnNjcm9sbFgpIC0gdGhpcy5vcmlnU2NyZWVuWDtcbiAgICAgICAgdGhpcy5kZWx0YVkgPSAocGFnZVkgLSB3aW5kb3cuc2Nyb2xsWSkgLSB0aGlzLm9yaWdTY3JlZW5ZO1xuICAgICAgICB0aGlzLnVwZGF0ZUVsUG9zaXRpb24oKTtcbiAgICB9XG4gICAgLy8gY2FuIGJlIGNhbGxlZCBiZWZvcmUgc3RhcnRcbiAgICBzZXRJc1Zpc2libGUoYm9vbCkge1xuICAgICAgICBpZiAoYm9vbCkge1xuICAgICAgICAgICAgaWYgKCF0aGlzLmlzVmlzaWJsZSkge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLm1pcnJvckVsKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubWlycm9yRWwuc3R5bGUuZGlzcGxheSA9ICcnO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLmlzVmlzaWJsZSA9IGJvb2w7IC8vIG5lZWRzIHRvIGhhcHBlbiBiZWZvcmUgdXBkYXRlRWxQb3NpdGlvblxuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlRWxQb3NpdGlvbigpOyAvLyBiZWNhdXNlIHdhcyBub3QgdXBkYXRpbmcgdGhlIHBvc2l0aW9uIHdoaWxlIGludmlzaWJsZVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHRoaXMuaXNWaXNpYmxlKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5taXJyb3JFbCkge1xuICAgICAgICAgICAgICAgIHRoaXMubWlycm9yRWwuc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuaXNWaXNpYmxlID0gYm9vbDtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBhbHdheXMgYXN5bmNcbiAgICBzdG9wKG5lZWRzUmV2ZXJ0QW5pbWF0aW9uLCBjYWxsYmFjaykge1xuICAgICAgICBsZXQgZG9uZSA9ICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuY2xlYW51cCgpO1xuICAgICAgICAgICAgY2FsbGJhY2soKTtcbiAgICAgICAgfTtcbiAgICAgICAgaWYgKG5lZWRzUmV2ZXJ0QW5pbWF0aW9uICYmXG4gICAgICAgICAgICB0aGlzLm1pcnJvckVsICYmXG4gICAgICAgICAgICB0aGlzLmlzVmlzaWJsZSAmJlxuICAgICAgICAgICAgdGhpcy5yZXZlcnREdXJhdGlvbiAmJiAvLyBpZiAwLCB0cmFuc2l0aW9uIHdvbid0IHdvcmtcbiAgICAgICAgICAgICh0aGlzLmRlbHRhWCB8fCB0aGlzLmRlbHRhWSkgLy8gaWYgc2FtZSBjb29yZHMsIHRyYW5zaXRpb24gd29uJ3Qgd29ya1xuICAgICAgICApIHtcbiAgICAgICAgICAgIHRoaXMuZG9SZXZlcnRBbmltYXRpb24oZG9uZSwgdGhpcy5yZXZlcnREdXJhdGlvbik7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBzZXRUaW1lb3V0KGRvbmUsIDApO1xuICAgICAgICB9XG4gICAgfVxuICAgIGRvUmV2ZXJ0QW5pbWF0aW9uKGNhbGxiYWNrLCByZXZlcnREdXJhdGlvbikge1xuICAgICAgICBsZXQgbWlycm9yRWwgPSB0aGlzLm1pcnJvckVsO1xuICAgICAgICBsZXQgZmluYWxTb3VyY2VFbFJlY3QgPSB0aGlzLnNvdXJjZUVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOyAvLyBiZWNhdXNlIGF1dG9zY3JvbGxpbmcgbWlnaHQgaGF2ZSBoYXBwZW5lZFxuICAgICAgICBtaXJyb3JFbC5zdHlsZS50cmFuc2l0aW9uID1cbiAgICAgICAgICAgICd0b3AgJyArIHJldmVydER1cmF0aW9uICsgJ21zLCcgK1xuICAgICAgICAgICAgICAgICdsZWZ0ICcgKyByZXZlcnREdXJhdGlvbiArICdtcyc7XG4gICAgICAgIGFwcGx5U3R5bGUobWlycm9yRWwsIHtcbiAgICAgICAgICAgIGxlZnQ6IGZpbmFsU291cmNlRWxSZWN0LmxlZnQsXG4gICAgICAgICAgICB0b3A6IGZpbmFsU291cmNlRWxSZWN0LnRvcCxcbiAgICAgICAgfSk7XG4gICAgICAgIHdoZW5UcmFuc2l0aW9uRG9uZShtaXJyb3JFbCwgKCkgPT4ge1xuICAgICAgICAgICAgbWlycm9yRWwuc3R5bGUudHJhbnNpdGlvbiA9ICcnO1xuICAgICAgICAgICAgY2FsbGJhY2soKTtcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGNsZWFudXAoKSB7XG4gICAgICAgIGlmICh0aGlzLm1pcnJvckVsKSB7XG4gICAgICAgICAgICByZW1vdmVFbGVtZW50KHRoaXMubWlycm9yRWwpO1xuICAgICAgICAgICAgdGhpcy5taXJyb3JFbCA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zb3VyY2VFbCA9IG51bGw7XG4gICAgfVxuICAgIHVwZGF0ZUVsUG9zaXRpb24oKSB7XG4gICAgICAgIGlmICh0aGlzLnNvdXJjZUVsICYmIHRoaXMuaXNWaXNpYmxlKSB7XG4gICAgICAgICAgICBhcHBseVN0eWxlKHRoaXMuZ2V0TWlycm9yRWwoKSwge1xuICAgICAgICAgICAgICAgIGxlZnQ6IHRoaXMuc291cmNlRWxSZWN0LmxlZnQgKyB0aGlzLmRlbHRhWCxcbiAgICAgICAgICAgICAgICB0b3A6IHRoaXMuc291cmNlRWxSZWN0LnRvcCArIHRoaXMuZGVsdGFZLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZ2V0TWlycm9yRWwoKSB7XG4gICAgICAgIGxldCBzb3VyY2VFbFJlY3QgPSB0aGlzLnNvdXJjZUVsUmVjdDtcbiAgICAgICAgbGV0IG1pcnJvckVsID0gdGhpcy5taXJyb3JFbDtcbiAgICAgICAgaWYgKCFtaXJyb3JFbCkge1xuICAgICAgICAgICAgbWlycm9yRWwgPSB0aGlzLm1pcnJvckVsID0gdGhpcy5zb3VyY2VFbC5jbG9uZU5vZGUodHJ1ZSk7IC8vIGNsb25lQ2hpbGRyZW49dHJ1ZVxuICAgICAgICAgICAgLy8gd2UgZG9uJ3Qgd2FudCBsb25nIHRhcHMgb3IgYW55IG1vdXNlIGludGVyYWN0aW9uIGNhdXNpbmcgc2VsZWN0aW9uL21lbnVzLlxuICAgICAgICAgICAgLy8gd291bGQgdXNlIHByZXZlbnRTZWxlY3Rpb24oKSwgYnV0IHRoYXQgcHJldmVudHMgc2VsZWN0c3RhcnQsIGNhdXNpbmcgcHJvYmxlbXMuXG4gICAgICAgICAgICBtaXJyb3JFbC5zdHlsZS51c2VyU2VsZWN0ID0gJ25vbmUnO1xuICAgICAgICAgICAgbWlycm9yRWwuc3R5bGUud2Via2l0VXNlclNlbGVjdCA9ICdub25lJztcbiAgICAgICAgICAgIG1pcnJvckVsLnN0eWxlLnBvaW50ZXJFdmVudHMgPSAnbm9uZSc7XG4gICAgICAgICAgICBtaXJyb3JFbC5jbGFzc0xpc3QuYWRkKCdmYy1ldmVudC1kcmFnZ2luZycpO1xuICAgICAgICAgICAgYXBwbHlTdHlsZShtaXJyb3JFbCwge1xuICAgICAgICAgICAgICAgIHBvc2l0aW9uOiAnZml4ZWQnLFxuICAgICAgICAgICAgICAgIHpJbmRleDogdGhpcy56SW5kZXgsXG4gICAgICAgICAgICAgICAgdmlzaWJpbGl0eTogJycsXG4gICAgICAgICAgICAgICAgYm94U2l6aW5nOiAnYm9yZGVyLWJveCcsXG4gICAgICAgICAgICAgICAgd2lkdGg6IHNvdXJjZUVsUmVjdC5yaWdodCAtIHNvdXJjZUVsUmVjdC5sZWZ0LFxuICAgICAgICAgICAgICAgIGhlaWdodDogc291cmNlRWxSZWN0LmJvdHRvbSAtIHNvdXJjZUVsUmVjdC50b3AsXG4gICAgICAgICAgICAgICAgcmlnaHQ6ICdhdXRvJyxcbiAgICAgICAgICAgICAgICBib3R0b206ICdhdXRvJyxcbiAgICAgICAgICAgICAgICBtYXJnaW46IDAsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHRoaXMucGFyZW50Tm9kZS5hcHBlbmRDaGlsZChtaXJyb3JFbCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG1pcnJvckVsO1xuICAgIH1cbn1cblxuLypcbklzIGEgY2FjaGUgZm9yIGEgZ2l2ZW4gZWxlbWVudCdzIHNjcm9sbCBpbmZvcm1hdGlvbiAoYWxsIHRoZSBpbmZvIHRoYXQgU2Nyb2xsQ29udHJvbGxlciBzdG9yZXMpXG5pbiBhZGRpdGlvbiB0aGUgXCJjbGllbnQgcmVjdGFuZ2xlXCIgb2YgdGhlIGVsZW1lbnQuLiB0aGUgYXJlYSB3aXRoaW4gdGhlIHNjcm9sbGJhcnMuXG5cblRoZSBjYWNoZSBjYW4gYmUgaW4gb25lIG9mIHR3byBtb2Rlczpcbi0gZG9lc0xpc3RlbmluZzpmYWxzZSAtIGlnbm9yZXMgd2hlbiB0aGUgY29udGFpbmVyIGlzIHNjcm9sbGVkIGJ5IHNvbWVvbmUgZWxzZVxuLSBkb2VzTGlzdGVuaW5nOnRydWUgLSB3YXRjaCBmb3Igc2Nyb2xsaW5nIGFuZCB1cGRhdGUgdGhlIGNhY2hlXG4qL1xuY2xhc3MgU2Nyb2xsR2VvbUNhY2hlIGV4dGVuZHMgU2Nyb2xsQ29udHJvbGxlciB7XG4gICAgY29uc3RydWN0b3Ioc2Nyb2xsQ29udHJvbGxlciwgZG9lc0xpc3RlbmluZykge1xuICAgICAgICBzdXBlcigpO1xuICAgICAgICB0aGlzLmhhbmRsZVNjcm9sbCA9ICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2Nyb2xsVG9wID0gdGhpcy5zY3JvbGxDb250cm9sbGVyLmdldFNjcm9sbFRvcCgpO1xuICAgICAgICAgICAgdGhpcy5zY3JvbGxMZWZ0ID0gdGhpcy5zY3JvbGxDb250cm9sbGVyLmdldFNjcm9sbExlZnQoKTtcbiAgICAgICAgICAgIHRoaXMuaGFuZGxlU2Nyb2xsQ2hhbmdlKCk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuc2Nyb2xsQ29udHJvbGxlciA9IHNjcm9sbENvbnRyb2xsZXI7XG4gICAgICAgIHRoaXMuZG9lc0xpc3RlbmluZyA9IGRvZXNMaXN0ZW5pbmc7XG4gICAgICAgIHRoaXMuc2Nyb2xsVG9wID0gdGhpcy5vcmlnU2Nyb2xsVG9wID0gc2Nyb2xsQ29udHJvbGxlci5nZXRTY3JvbGxUb3AoKTtcbiAgICAgICAgdGhpcy5zY3JvbGxMZWZ0ID0gdGhpcy5vcmlnU2Nyb2xsTGVmdCA9IHNjcm9sbENvbnRyb2xsZXIuZ2V0U2Nyb2xsTGVmdCgpO1xuICAgICAgICB0aGlzLnNjcm9sbFdpZHRoID0gc2Nyb2xsQ29udHJvbGxlci5nZXRTY3JvbGxXaWR0aCgpO1xuICAgICAgICB0aGlzLnNjcm9sbEhlaWdodCA9IHNjcm9sbENvbnRyb2xsZXIuZ2V0U2Nyb2xsSGVpZ2h0KCk7XG4gICAgICAgIHRoaXMuY2xpZW50V2lkdGggPSBzY3JvbGxDb250cm9sbGVyLmdldENsaWVudFdpZHRoKCk7XG4gICAgICAgIHRoaXMuY2xpZW50SGVpZ2h0ID0gc2Nyb2xsQ29udHJvbGxlci5nZXRDbGllbnRIZWlnaHQoKTtcbiAgICAgICAgdGhpcy5jbGllbnRSZWN0ID0gdGhpcy5jb21wdXRlQ2xpZW50UmVjdCgpOyAvLyBkbyBsYXN0IGluIGNhc2UgaXQgbmVlZHMgY2FjaGVkIHZhbHVlc1xuICAgICAgICBpZiAodGhpcy5kb2VzTGlzdGVuaW5nKSB7XG4gICAgICAgICAgICB0aGlzLmdldEV2ZW50VGFyZ2V0KCkuYWRkRXZlbnRMaXN0ZW5lcignc2Nyb2xsJywgdGhpcy5oYW5kbGVTY3JvbGwpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGRlc3Ryb3koKSB7XG4gICAgICAgIGlmICh0aGlzLmRvZXNMaXN0ZW5pbmcpIHtcbiAgICAgICAgICAgIHRoaXMuZ2V0RXZlbnRUYXJnZXQoKS5yZW1vdmVFdmVudExpc3RlbmVyKCdzY3JvbGwnLCB0aGlzLmhhbmRsZVNjcm9sbCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZ2V0U2Nyb2xsVG9wKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zY3JvbGxUb3A7XG4gICAgfVxuICAgIGdldFNjcm9sbExlZnQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNjcm9sbExlZnQ7XG4gICAgfVxuICAgIHNldFNjcm9sbFRvcCh0b3ApIHtcbiAgICAgICAgdGhpcy5zY3JvbGxDb250cm9sbGVyLnNldFNjcm9sbFRvcCh0b3ApO1xuICAgICAgICBpZiAoIXRoaXMuZG9lc0xpc3RlbmluZykge1xuICAgICAgICAgICAgLy8gd2UgYXJlIG5vdCByZWx5aW5nIG9uIHRoZSBlbGVtZW50IHRvIG5vcm1hbGl6ZSBvdXQtb2YtYm91bmRzIHNjcm9sbCB2YWx1ZXNcbiAgICAgICAgICAgIC8vIHNvIHdlIG5lZWQgdG8gc2FuaXRpemUgb3Vyc2VsdmVzXG4gICAgICAgICAgICB0aGlzLnNjcm9sbFRvcCA9IE1hdGgubWF4KE1hdGgubWluKHRvcCwgdGhpcy5nZXRNYXhTY3JvbGxUb3AoKSksIDApO1xuICAgICAgICAgICAgdGhpcy5oYW5kbGVTY3JvbGxDaGFuZ2UoKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBzZXRTY3JvbGxMZWZ0KHRvcCkge1xuICAgICAgICB0aGlzLnNjcm9sbENvbnRyb2xsZXIuc2V0U2Nyb2xsTGVmdCh0b3ApO1xuICAgICAgICBpZiAoIXRoaXMuZG9lc0xpc3RlbmluZykge1xuICAgICAgICAgICAgLy8gd2UgYXJlIG5vdCByZWx5aW5nIG9uIHRoZSBlbGVtZW50IHRvIG5vcm1hbGl6ZSBvdXQtb2YtYm91bmRzIHNjcm9sbCB2YWx1ZXNcbiAgICAgICAgICAgIC8vIHNvIHdlIG5lZWQgdG8gc2FuaXRpemUgb3Vyc2VsdmVzXG4gICAgICAgICAgICB0aGlzLnNjcm9sbExlZnQgPSBNYXRoLm1heChNYXRoLm1pbih0b3AsIHRoaXMuZ2V0TWF4U2Nyb2xsTGVmdCgpKSwgMCk7XG4gICAgICAgICAgICB0aGlzLmhhbmRsZVNjcm9sbENoYW5nZSgpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGdldENsaWVudFdpZHRoKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jbGllbnRXaWR0aDtcbiAgICB9XG4gICAgZ2V0Q2xpZW50SGVpZ2h0KCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jbGllbnRIZWlnaHQ7XG4gICAgfVxuICAgIGdldFNjcm9sbFdpZHRoKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zY3JvbGxXaWR0aDtcbiAgICB9XG4gICAgZ2V0U2Nyb2xsSGVpZ2h0KCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zY3JvbGxIZWlnaHQ7XG4gICAgfVxuICAgIGhhbmRsZVNjcm9sbENoYW5nZSgpIHtcbiAgICB9XG59XG5cbmNsYXNzIEVsZW1lbnRTY3JvbGxHZW9tQ2FjaGUgZXh0ZW5kcyBTY3JvbGxHZW9tQ2FjaGUge1xuICAgIGNvbnN0cnVjdG9yKGVsLCBkb2VzTGlzdGVuaW5nKSB7XG4gICAgICAgIHN1cGVyKG5ldyBFbGVtZW50U2Nyb2xsQ29udHJvbGxlcihlbCksIGRvZXNMaXN0ZW5pbmcpO1xuICAgIH1cbiAgICBnZXRFdmVudFRhcmdldCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2Nyb2xsQ29udHJvbGxlci5lbDtcbiAgICB9XG4gICAgY29tcHV0ZUNsaWVudFJlY3QoKSB7XG4gICAgICAgIHJldHVybiBjb21wdXRlSW5uZXJSZWN0KHRoaXMuc2Nyb2xsQ29udHJvbGxlci5lbCk7XG4gICAgfVxufVxuXG5jbGFzcyBXaW5kb3dTY3JvbGxHZW9tQ2FjaGUgZXh0ZW5kcyBTY3JvbGxHZW9tQ2FjaGUge1xuICAgIGNvbnN0cnVjdG9yKGRvZXNMaXN0ZW5pbmcpIHtcbiAgICAgICAgc3VwZXIobmV3IFdpbmRvd1Njcm9sbENvbnRyb2xsZXIoKSwgZG9lc0xpc3RlbmluZyk7XG4gICAgfVxuICAgIGdldEV2ZW50VGFyZ2V0KCkge1xuICAgICAgICByZXR1cm4gd2luZG93O1xuICAgIH1cbiAgICBjb21wdXRlQ2xpZW50UmVjdCgpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGxlZnQ6IHRoaXMuc2Nyb2xsTGVmdCxcbiAgICAgICAgICAgIHJpZ2h0OiB0aGlzLnNjcm9sbExlZnQgKyB0aGlzLmNsaWVudFdpZHRoLFxuICAgICAgICAgICAgdG9wOiB0aGlzLnNjcm9sbFRvcCxcbiAgICAgICAgICAgIGJvdHRvbTogdGhpcy5zY3JvbGxUb3AgKyB0aGlzLmNsaWVudEhlaWdodCxcbiAgICAgICAgfTtcbiAgICB9XG4gICAgLy8gdGhlIHdpbmRvdyBpcyB0aGUgb25seSBzY3JvbGwgb2JqZWN0IHRoYXQgY2hhbmdlcyBpdCdzIHJlY3RhbmdsZSByZWxhdGl2ZVxuICAgIC8vIHRvIHRoZSBkb2N1bWVudCdzIHRvcGxlZnQgYXMgaXQgc2Nyb2xsc1xuICAgIGhhbmRsZVNjcm9sbENoYW5nZSgpIHtcbiAgICAgICAgdGhpcy5jbGllbnRSZWN0ID0gdGhpcy5jb21wdXRlQ2xpZW50UmVjdCgpO1xuICAgIH1cbn1cblxuLy8gSWYgYXZhaWxhYmxlIHdlIGFyZSB1c2luZyBuYXRpdmUgXCJwZXJmb3JtYW5jZVwiIEFQSSBpbnN0ZWFkIG9mIFwiRGF0ZVwiXG4vLyBSZWFkIG1vcmUgYWJvdXQgaXQgb24gTUROOlxuLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL1BlcmZvcm1hbmNlXG5jb25zdCBnZXRUaW1lID0gdHlwZW9mIHBlcmZvcm1hbmNlID09PSAnZnVuY3Rpb24nID8gcGVyZm9ybWFuY2Uubm93IDogRGF0ZS5ub3c7XG4vKlxuRm9yIGEgcG9pbnRlciBpbnRlcmFjdGlvbiwgYXV0b21hdGljYWxseSBzY3JvbGxzIGNlcnRhaW4gc2Nyb2xsIGNvbnRhaW5lcnMgd2hlbiB0aGUgcG9pbnRlclxuYXBwcm9hY2hlcyB0aGUgZWRnZS5cblxuVGhlIGNhbGxlciBtdXN0IGNhbGwgc3RhcnQgKyBoYW5kbGVNb3ZlICsgc3RvcC5cbiovXG5jbGFzcyBBdXRvU2Nyb2xsZXIge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICAvLyBvcHRpb25zIHRoYXQgY2FuIGJlIHNldCBieSBjYWxsZXJcbiAgICAgICAgdGhpcy5pc0VuYWJsZWQgPSB0cnVlO1xuICAgICAgICB0aGlzLnNjcm9sbFF1ZXJ5ID0gW3dpbmRvdywgJy5mYy1zY3JvbGxlciddO1xuICAgICAgICB0aGlzLmVkZ2VUaHJlc2hvbGQgPSA1MDsgLy8gcGl4ZWxzXG4gICAgICAgIHRoaXMubWF4VmVsb2NpdHkgPSAzMDA7IC8vIHBpeGVscyBwZXIgc2Vjb25kXG4gICAgICAgIC8vIGludGVybmFsIHN0YXRlXG4gICAgICAgIHRoaXMucG9pbnRlclNjcmVlblggPSBudWxsO1xuICAgICAgICB0aGlzLnBvaW50ZXJTY3JlZW5ZID0gbnVsbDtcbiAgICAgICAgdGhpcy5pc0FuaW1hdGluZyA9IGZhbHNlO1xuICAgICAgICB0aGlzLnNjcm9sbENhY2hlcyA9IG51bGw7XG4gICAgICAgIC8vIHByb3RlY3QgYWdhaW5zdCB0aGUgaW5pdGlhbCBwb2ludGVyZG93biBiZWluZyB0b28gY2xvc2UgdG8gYW4gZWRnZSBhbmQgc3RhcnRpbmcgdGhlIHNjcm9sbFxuICAgICAgICB0aGlzLmV2ZXJNb3ZlZFVwID0gZmFsc2U7XG4gICAgICAgIHRoaXMuZXZlck1vdmVkRG93biA9IGZhbHNlO1xuICAgICAgICB0aGlzLmV2ZXJNb3ZlZExlZnQgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5ldmVyTW92ZWRSaWdodCA9IGZhbHNlO1xuICAgICAgICB0aGlzLmFuaW1hdGUgPSAoKSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy5pc0FuaW1hdGluZykgeyAvLyB3YXNuJ3QgY2FuY2VsbGVkIGJldHdlZW4gYW5pbWF0aW9uIGNhbGxzXG4gICAgICAgICAgICAgICAgbGV0IGVkZ2UgPSB0aGlzLmNvbXB1dGVCZXN0RWRnZSh0aGlzLnBvaW50ZXJTY3JlZW5YICsgd2luZG93LnNjcm9sbFgsIHRoaXMucG9pbnRlclNjcmVlblkgKyB3aW5kb3cuc2Nyb2xsWSk7XG4gICAgICAgICAgICAgICAgaWYgKGVkZ2UpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IG5vdyA9IGdldFRpbWUoKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5oYW5kbGVTaWRlKGVkZ2UsIChub3cgLSB0aGlzLm1zU2luY2VSZXF1ZXN0KSAvIDEwMDApO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJlcXVlc3RBbmltYXRpb24obm93KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaXNBbmltYXRpbmcgPSBmYWxzZTsgLy8gd2lsbCBzdG9wIGFuaW1hdGlvblxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG4gICAgc3RhcnQocGFnZVgsIHBhZ2VZLCBzY3JvbGxTdGFydEVsKSB7XG4gICAgICAgIGlmICh0aGlzLmlzRW5hYmxlZCkge1xuICAgICAgICAgICAgdGhpcy5zY3JvbGxDYWNoZXMgPSB0aGlzLmJ1aWxkQ2FjaGVzKHNjcm9sbFN0YXJ0RWwpO1xuICAgICAgICAgICAgdGhpcy5wb2ludGVyU2NyZWVuWCA9IG51bGw7XG4gICAgICAgICAgICB0aGlzLnBvaW50ZXJTY3JlZW5ZID0gbnVsbDtcbiAgICAgICAgICAgIHRoaXMuZXZlck1vdmVkVXAgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMuZXZlck1vdmVkRG93biA9IGZhbHNlO1xuICAgICAgICAgICAgdGhpcy5ldmVyTW92ZWRMZWZ0ID0gZmFsc2U7XG4gICAgICAgICAgICB0aGlzLmV2ZXJNb3ZlZFJpZ2h0ID0gZmFsc2U7XG4gICAgICAgICAgICB0aGlzLmhhbmRsZU1vdmUocGFnZVgsIHBhZ2VZKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBoYW5kbGVNb3ZlKHBhZ2VYLCBwYWdlWSkge1xuICAgICAgICBpZiAodGhpcy5pc0VuYWJsZWQpIHtcbiAgICAgICAgICAgIGxldCBwb2ludGVyU2NyZWVuWCA9IHBhZ2VYIC0gd2luZG93LnNjcm9sbFg7XG4gICAgICAgICAgICBsZXQgcG9pbnRlclNjcmVlblkgPSBwYWdlWSAtIHdpbmRvdy5zY3JvbGxZO1xuICAgICAgICAgICAgbGV0IHlEZWx0YSA9IHRoaXMucG9pbnRlclNjcmVlblkgPT09IG51bGwgPyAwIDogcG9pbnRlclNjcmVlblkgLSB0aGlzLnBvaW50ZXJTY3JlZW5ZO1xuICAgICAgICAgICAgbGV0IHhEZWx0YSA9IHRoaXMucG9pbnRlclNjcmVlblggPT09IG51bGwgPyAwIDogcG9pbnRlclNjcmVlblggLSB0aGlzLnBvaW50ZXJTY3JlZW5YO1xuICAgICAgICAgICAgaWYgKHlEZWx0YSA8IDApIHtcbiAgICAgICAgICAgICAgICB0aGlzLmV2ZXJNb3ZlZFVwID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKHlEZWx0YSA+IDApIHtcbiAgICAgICAgICAgICAgICB0aGlzLmV2ZXJNb3ZlZERvd24gPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHhEZWx0YSA8IDApIHtcbiAgICAgICAgICAgICAgICB0aGlzLmV2ZXJNb3ZlZExlZnQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoeERlbHRhID4gMCkge1xuICAgICAgICAgICAgICAgIHRoaXMuZXZlck1vdmVkUmlnaHQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5wb2ludGVyU2NyZWVuWCA9IHBvaW50ZXJTY3JlZW5YO1xuICAgICAgICAgICAgdGhpcy5wb2ludGVyU2NyZWVuWSA9IHBvaW50ZXJTY3JlZW5ZO1xuICAgICAgICAgICAgaWYgKCF0aGlzLmlzQW5pbWF0aW5nKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5pc0FuaW1hdGluZyA9IHRydWU7XG4gICAgICAgICAgICAgICAgdGhpcy5yZXF1ZXN0QW5pbWF0aW9uKGdldFRpbWUoKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgc3RvcCgpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNFbmFibGVkKSB7XG4gICAgICAgICAgICB0aGlzLmlzQW5pbWF0aW5nID0gZmFsc2U7IC8vIHdpbGwgc3RvcCBhbmltYXRpb25cbiAgICAgICAgICAgIGZvciAobGV0IHNjcm9sbENhY2hlIG9mIHRoaXMuc2Nyb2xsQ2FjaGVzKSB7XG4gICAgICAgICAgICAgICAgc2Nyb2xsQ2FjaGUuZGVzdHJveSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5zY3JvbGxDYWNoZXMgPSBudWxsO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJlcXVlc3RBbmltYXRpb24obm93KSB7XG4gICAgICAgIHRoaXMubXNTaW5jZVJlcXVlc3QgPSBub3c7XG4gICAgICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZSh0aGlzLmFuaW1hdGUpO1xuICAgIH1cbiAgICBoYW5kbGVTaWRlKGVkZ2UsIHNlY29uZHMpIHtcbiAgICAgICAgbGV0IHsgc2Nyb2xsQ2FjaGUgfSA9IGVkZ2U7XG4gICAgICAgIGxldCB7IGVkZ2VUaHJlc2hvbGQgfSA9IHRoaXM7XG4gICAgICAgIGxldCBpbnZEaXN0YW5jZSA9IGVkZ2VUaHJlc2hvbGQgLSBlZGdlLmRpc3RhbmNlO1xuICAgICAgICBsZXQgdmVsb2NpdHkgPSAvLyB0aGUgY2xvc2VyIHRvIHRoZSBlZGdlLCB0aGUgZmFzdGVyIHdlIHNjcm9sbFxuICAgICAgICAgKChpbnZEaXN0YW5jZSAqIGludkRpc3RhbmNlKSAvIChlZGdlVGhyZXNob2xkICogZWRnZVRocmVzaG9sZCkpICogLy8gcXVhZHJhdGljXG4gICAgICAgICAgICB0aGlzLm1heFZlbG9jaXR5ICogc2Vjb25kcztcbiAgICAgICAgbGV0IHNpZ24gPSAxO1xuICAgICAgICBzd2l0Y2ggKGVkZ2UubmFtZSkge1xuICAgICAgICAgICAgY2FzZSAnbGVmdCc6XG4gICAgICAgICAgICAgICAgc2lnbiA9IC0xO1xuICAgICAgICAgICAgLy8gZmFsbHMgdGhyb3VnaFxuICAgICAgICAgICAgY2FzZSAncmlnaHQnOlxuICAgICAgICAgICAgICAgIHNjcm9sbENhY2hlLnNldFNjcm9sbExlZnQoc2Nyb2xsQ2FjaGUuZ2V0U2Nyb2xsTGVmdCgpICsgdmVsb2NpdHkgKiBzaWduKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ3RvcCc6XG4gICAgICAgICAgICAgICAgc2lnbiA9IC0xO1xuICAgICAgICAgICAgLy8gZmFsbHMgdGhyb3VnaFxuICAgICAgICAgICAgY2FzZSAnYm90dG9tJzpcbiAgICAgICAgICAgICAgICBzY3JvbGxDYWNoZS5zZXRTY3JvbGxUb3Aoc2Nyb2xsQ2FjaGUuZ2V0U2Nyb2xsVG9wKCkgKyB2ZWxvY2l0eSAqIHNpZ24pO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8vIGxlZnQvdG9wIGFyZSByZWxhdGl2ZSB0byBkb2N1bWVudCB0b3BsZWZ0XG4gICAgY29tcHV0ZUJlc3RFZGdlKGxlZnQsIHRvcCkge1xuICAgICAgICBsZXQgeyBlZGdlVGhyZXNob2xkIH0gPSB0aGlzO1xuICAgICAgICBsZXQgYmVzdFNpZGUgPSBudWxsO1xuICAgICAgICBsZXQgc2Nyb2xsQ2FjaGVzID0gdGhpcy5zY3JvbGxDYWNoZXMgfHwgW107XG4gICAgICAgIGZvciAobGV0IHNjcm9sbENhY2hlIG9mIHNjcm9sbENhY2hlcykge1xuICAgICAgICAgICAgbGV0IHJlY3QgPSBzY3JvbGxDYWNoZS5jbGllbnRSZWN0O1xuICAgICAgICAgICAgbGV0IGxlZnREaXN0ID0gbGVmdCAtIHJlY3QubGVmdDtcbiAgICAgICAgICAgIGxldCByaWdodERpc3QgPSByZWN0LnJpZ2h0IC0gbGVmdDtcbiAgICAgICAgICAgIGxldCB0b3BEaXN0ID0gdG9wIC0gcmVjdC50b3A7XG4gICAgICAgICAgICBsZXQgYm90dG9tRGlzdCA9IHJlY3QuYm90dG9tIC0gdG9wO1xuICAgICAgICAgICAgLy8gY29tcGxldGVseSB3aXRoaW4gdGhlIHJlY3Q/XG4gICAgICAgICAgICBpZiAobGVmdERpc3QgPj0gMCAmJiByaWdodERpc3QgPj0gMCAmJiB0b3BEaXN0ID49IDAgJiYgYm90dG9tRGlzdCA+PSAwKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRvcERpc3QgPD0gZWRnZVRocmVzaG9sZCAmJiB0aGlzLmV2ZXJNb3ZlZFVwICYmIHNjcm9sbENhY2hlLmNhblNjcm9sbFVwKCkgJiZcbiAgICAgICAgICAgICAgICAgICAgKCFiZXN0U2lkZSB8fCBiZXN0U2lkZS5kaXN0YW5jZSA+IHRvcERpc3QpKSB7XG4gICAgICAgICAgICAgICAgICAgIGJlc3RTaWRlID0geyBzY3JvbGxDYWNoZSwgbmFtZTogJ3RvcCcsIGRpc3RhbmNlOiB0b3BEaXN0IH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChib3R0b21EaXN0IDw9IGVkZ2VUaHJlc2hvbGQgJiYgdGhpcy5ldmVyTW92ZWREb3duICYmIHNjcm9sbENhY2hlLmNhblNjcm9sbERvd24oKSAmJlxuICAgICAgICAgICAgICAgICAgICAoIWJlc3RTaWRlIHx8IGJlc3RTaWRlLmRpc3RhbmNlID4gYm90dG9tRGlzdCkpIHtcbiAgICAgICAgICAgICAgICAgICAgYmVzdFNpZGUgPSB7IHNjcm9sbENhY2hlLCBuYW1lOiAnYm90dG9tJywgZGlzdGFuY2U6IGJvdHRvbURpc3QgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLypcbiAgICAgICAgICAgICAgICBUT0RPOiBmaXggYnJva2VuIFJUTCBzY3JvbGxpbmcuIGNhblNjcm9sbExlZnQgYWx3YXlzIHJldHVybmluZyBmYWxzZVxuICAgICAgICAgICAgICAgIGh0dHBzOi8vZ2l0aHViLmNvbS9mdWxsY2FsZW5kYXIvZnVsbGNhbGVuZGFyL2lzc3Vlcy80ODM3XG4gICAgICAgICAgICAgICAgKi9cbiAgICAgICAgICAgICAgICBpZiAobGVmdERpc3QgPD0gZWRnZVRocmVzaG9sZCAmJiB0aGlzLmV2ZXJNb3ZlZExlZnQgJiYgc2Nyb2xsQ2FjaGUuY2FuU2Nyb2xsTGVmdCgpICYmXG4gICAgICAgICAgICAgICAgICAgICghYmVzdFNpZGUgfHwgYmVzdFNpZGUuZGlzdGFuY2UgPiBsZWZ0RGlzdCkpIHtcbiAgICAgICAgICAgICAgICAgICAgYmVzdFNpZGUgPSB7IHNjcm9sbENhY2hlLCBuYW1lOiAnbGVmdCcsIGRpc3RhbmNlOiBsZWZ0RGlzdCB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAocmlnaHREaXN0IDw9IGVkZ2VUaHJlc2hvbGQgJiYgdGhpcy5ldmVyTW92ZWRSaWdodCAmJiBzY3JvbGxDYWNoZS5jYW5TY3JvbGxSaWdodCgpICYmXG4gICAgICAgICAgICAgICAgICAgICghYmVzdFNpZGUgfHwgYmVzdFNpZGUuZGlzdGFuY2UgPiByaWdodERpc3QpKSB7XG4gICAgICAgICAgICAgICAgICAgIGJlc3RTaWRlID0geyBzY3JvbGxDYWNoZSwgbmFtZTogJ3JpZ2h0JywgZGlzdGFuY2U6IHJpZ2h0RGlzdCB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYmVzdFNpZGU7XG4gICAgfVxuICAgIGJ1aWxkQ2FjaGVzKHNjcm9sbFN0YXJ0RWwpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucXVlcnlTY3JvbGxFbHMoc2Nyb2xsU3RhcnRFbCkubWFwKChlbCkgPT4ge1xuICAgICAgICAgICAgaWYgKGVsID09PSB3aW5kb3cpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IFdpbmRvd1Njcm9sbEdlb21DYWNoZShmYWxzZSk7IC8vIGZhbHNlID0gZG9uJ3QgbGlzdGVuIHRvIHVzZXItZ2VuZXJhdGVkIHNjcm9sbHNcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBuZXcgRWxlbWVudFNjcm9sbEdlb21DYWNoZShlbCwgZmFsc2UpOyAvLyBmYWxzZSA9IGRvbid0IGxpc3RlbiB0byB1c2VyLWdlbmVyYXRlZCBzY3JvbGxzXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBxdWVyeVNjcm9sbEVscyhzY3JvbGxTdGFydEVsKSB7XG4gICAgICAgIGxldCBlbHMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgcXVlcnkgb2YgdGhpcy5zY3JvbGxRdWVyeSkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBxdWVyeSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgICAgICBlbHMucHVzaChxdWVyeSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAvKlxuICAgICAgICAgICAgICAgIFRPRE86IGluIHRoZSBmdXR1cmUsIGFsd2F5cyBoYXZlIGF1dG8tc2Nyb2xsIGhhcHBlbiBvbiBlbGVtZW50IHdoZXJlIGN1cnJlbnQgSGl0IGNhbWUgZnJvbVxuICAgICAgICAgICAgICAgIFRpY2tldDogaHR0cHM6Ly9naXRodWIuY29tL2Z1bGxjYWxlbmRhci9mdWxsY2FsZW5kYXIvaXNzdWVzLzQ1OTNcbiAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIGVscy5wdXNoKC4uLkFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKHNjcm9sbFN0YXJ0RWwuZ2V0Um9vdE5vZGUoKS5xdWVyeVNlbGVjdG9yQWxsKHF1ZXJ5KSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBlbHM7XG4gICAgfVxufVxuXG4vKlxuTW9uaXRvcnMgZHJhZ2dpbmcgb24gYW4gZWxlbWVudC4gSGFzIGEgbnVtYmVyIG9mIGhpZ2gtbGV2ZWwgZmVhdHVyZXM6XG4tIG1pbmltdW0gZGlzdGFuY2UgcmVxdWlyZWQgYmVmb3JlIGRyYWdnaW5nXG4tIG1pbmltdW0gd2FpdCB0aW1lIChcImRlbGF5XCIpIGJlZm9yZSBkcmFnZ2luZ1xuLSBhIG1pcnJvciBlbGVtZW50IHRoYXQgZm9sbG93cyB0aGUgcG9pbnRlclxuKi9cbmNsYXNzIEZlYXR1cmVmdWxFbGVtZW50RHJhZ2dpbmcgZXh0ZW5kcyBFbGVtZW50RHJhZ2dpbmcge1xuICAgIGNvbnN0cnVjdG9yKGNvbnRhaW5lckVsLCBzZWxlY3Rvcikge1xuICAgICAgICBzdXBlcihjb250YWluZXJFbCk7XG4gICAgICAgIHRoaXMuY29udGFpbmVyRWwgPSBjb250YWluZXJFbDtcbiAgICAgICAgLy8gb3B0aW9ucyB0aGF0IGNhbiBiZSBkaXJlY3RseSBzZXQgYnkgY2FsbGVyXG4gICAgICAgIC8vIHRoZSBjYWxsZXIgY2FuIGFsc28gc2V0IHRoZSBQb2ludGVyRHJhZ2dpbmcncyBvcHRpb25zIGFzIHdlbGxcbiAgICAgICAgdGhpcy5kZWxheSA9IG51bGw7XG4gICAgICAgIHRoaXMubWluRGlzdGFuY2UgPSAwO1xuICAgICAgICB0aGlzLnRvdWNoU2Nyb2xsQWxsb3dlZCA9IHRydWU7IC8vIHByZXZlbnRzIGRyYWcgZnJvbSBzdGFydGluZyBhbmQgYmxvY2tzIHNjcm9sbGluZyBkdXJpbmcgZHJhZ1xuICAgICAgICB0aGlzLm1pcnJvck5lZWRzUmV2ZXJ0ID0gZmFsc2U7XG4gICAgICAgIHRoaXMuaXNJbnRlcmFjdGluZyA9IGZhbHNlOyAvLyBpcyB0aGUgdXNlciB2YWxpZGx5IG1vdmluZyB0aGUgcG9pbnRlcj8gbGFzdHMgdW50aWwgcG9pbnRlcnVwXG4gICAgICAgIHRoaXMuaXNEcmFnZ2luZyA9IGZhbHNlOyAvLyBpcyBpdCBJTlRFTlRGVUxMWSBkcmFnZ2luZz8gbGFzdHMgdW50aWwgYWZ0ZXIgcmV2ZXJ0IGFuaW1hdGlvblxuICAgICAgICB0aGlzLmlzRGVsYXlFbmRlZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLmlzRGlzdGFuY2VTdXJwYXNzZWQgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5kZWxheVRpbWVvdXRJZCA9IG51bGw7XG4gICAgICAgIHRoaXMub25Qb2ludGVyRG93biA9IChldikgPT4ge1xuICAgICAgICAgICAgaWYgKCF0aGlzLmlzRHJhZ2dpbmcpIHsgLy8gc28gbmV3IGRyYWcgZG9lc24ndCBoYXBwZW4gd2hpbGUgcmV2ZXJ0IGFuaW1hdGlvbiBpcyBnb2luZ1xuICAgICAgICAgICAgICAgIHRoaXMuaXNJbnRlcmFjdGluZyA9IHRydWU7XG4gICAgICAgICAgICAgICAgdGhpcy5pc0RlbGF5RW5kZWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB0aGlzLmlzRGlzdGFuY2VTdXJwYXNzZWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBwcmV2ZW50U2VsZWN0aW9uKGRvY3VtZW50LmJvZHkpO1xuICAgICAgICAgICAgICAgIHByZXZlbnRDb250ZXh0TWVudShkb2N1bWVudC5ib2R5KTtcbiAgICAgICAgICAgICAgICAvLyBwcmV2ZW50IGxpbmtzIGZyb20gYmVpbmcgdmlzaXRlZCBpZiB0aGVyZSdzIGFuIGV2ZW50dWFsIGRyYWcuXG4gICAgICAgICAgICAgICAgLy8gYWxzbyBwcmV2ZW50cyBzZWxlY3Rpb24gaW4gb2xkZXIgYnJvd3NlcnMgKG1heWJlPykuXG4gICAgICAgICAgICAgICAgLy8gbm90IG5lY2Vzc2FyeSBmb3IgdG91Y2gsIGJlc2lkZXMsIGJyb3dzZXIgd291bGQgY29tcGxhaW4gYWJvdXQgcGFzc2l2ZW5lc3MuXG4gICAgICAgICAgICAgICAgaWYgKCFldi5pc1RvdWNoKSB7XG4gICAgICAgICAgICAgICAgICAgIGV2Lm9yaWdFdmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLmVtaXR0ZXIudHJpZ2dlcigncG9pbnRlcmRvd24nLCBldik7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuaXNJbnRlcmFjdGluZyAmJiAvLyBub3QgZGVzdHJveWVkIHZpYSBwb2ludGVyZG93biBoYW5kbGVyXG4gICAgICAgICAgICAgICAgICAgICF0aGlzLnBvaW50ZXIuc2hvdWxkSWdub3JlTW92ZSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBhY3Rpb25zIHJlbGF0ZWQgdG8gaW5pdGlhdGluZyBkcmFnc3RhcnQrZHJhZ21vdmUrZHJhZ2VuZC4uLlxuICAgICAgICAgICAgICAgICAgICB0aGlzLm1pcnJvci5zZXRJc1Zpc2libGUoZmFsc2UpOyAvLyByZXNldC4gY2FsbGVyIG11c3Qgc2V0LXZpc2libGVcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5taXJyb3Iuc3RhcnQoZXYuc3ViamVjdEVsLCBldi5wYWdlWCwgZXYucGFnZVkpOyAvLyBtdXN0IGhhcHBlbiBvbiBmaXJzdCBwb2ludGVyIGRvd25cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zdGFydERlbGF5KGV2KTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLm1pbkRpc3RhbmNlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZURpc3RhbmNlU3VycGFzc2VkKGV2KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5vblBvaW50ZXJNb3ZlID0gKGV2KSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy5pc0ludGVyYWN0aW5nKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ3BvaW50ZXJtb3ZlJywgZXYpO1xuICAgICAgICAgICAgICAgIGlmICghdGhpcy5pc0Rpc3RhbmNlU3VycGFzc2VkKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBtaW5EaXN0YW5jZSA9IHRoaXMubWluRGlzdGFuY2U7XG4gICAgICAgICAgICAgICAgICAgIGxldCBkaXN0YW5jZVNxOyAvLyBjdXJyZW50IGRpc3RhbmNlIGZyb20gdGhlIG9yaWdpbiwgc3F1YXJlZFxuICAgICAgICAgICAgICAgICAgICBsZXQgeyBkZWx0YVgsIGRlbHRhWSB9ID0gZXY7XG4gICAgICAgICAgICAgICAgICAgIGRpc3RhbmNlU3EgPSBkZWx0YVggKiBkZWx0YVggKyBkZWx0YVkgKiBkZWx0YVk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChkaXN0YW5jZVNxID49IG1pbkRpc3RhbmNlICogbWluRGlzdGFuY2UpIHsgLy8gdXNlIHB5dGhhZ29yZWFuIHRoZW9yZW1cbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuaGFuZGxlRGlzdGFuY2VTdXJwYXNzZWQoZXYpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gYSByZWFsIHBvaW50ZXIgbW92ZT8gKG5vdCBvbmUgc2ltdWxhdGVkIGJ5IHNjcm9sbGluZylcbiAgICAgICAgICAgICAgICAgICAgaWYgKGV2Lm9yaWdFdmVudC50eXBlICE9PSAnc2Nyb2xsJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5taXJyb3IuaGFuZGxlTW92ZShldi5wYWdlWCwgZXYucGFnZVkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5hdXRvU2Nyb2xsZXIuaGFuZGxlTW92ZShldi5wYWdlWCwgZXYucGFnZVkpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZW1pdHRlci50cmlnZ2VyKCdkcmFnbW92ZScsIGV2KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMub25Qb2ludGVyVXAgPSAoZXYpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLmlzSW50ZXJhY3RpbmcpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmlzSW50ZXJhY3RpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBhbGxvd1NlbGVjdGlvbihkb2N1bWVudC5ib2R5KTtcbiAgICAgICAgICAgICAgICBhbGxvd0NvbnRleHRNZW51KGRvY3VtZW50LmJvZHkpO1xuICAgICAgICAgICAgICAgIHRoaXMuZW1pdHRlci50cmlnZ2VyKCdwb2ludGVydXAnLCBldik7IC8vIGNhbiBwb3RlbnRpYWxseSBzZXQgbWlycm9yTmVlZHNSZXZlcnRcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5pc0RyYWdnaW5nKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYXV0b1Njcm9sbGVyLnN0b3AoKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy50cnlTdG9wRHJhZyhldik7IC8vIHdoaWNoIHdpbGwgc3RvcCB0aGUgbWlycm9yXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmRlbGF5VGltZW91dElkKSB7XG4gICAgICAgICAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aGlzLmRlbGF5VGltZW91dElkKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kZWxheVRpbWVvdXRJZCA9IG51bGw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICBsZXQgcG9pbnRlciA9IHRoaXMucG9pbnRlciA9IG5ldyBQb2ludGVyRHJhZ2dpbmcoY29udGFpbmVyRWwpO1xuICAgICAgICBwb2ludGVyLmVtaXR0ZXIub24oJ3BvaW50ZXJkb3duJywgdGhpcy5vblBvaW50ZXJEb3duKTtcbiAgICAgICAgcG9pbnRlci5lbWl0dGVyLm9uKCdwb2ludGVybW92ZScsIHRoaXMub25Qb2ludGVyTW92ZSk7XG4gICAgICAgIHBvaW50ZXIuZW1pdHRlci5vbigncG9pbnRlcnVwJywgdGhpcy5vblBvaW50ZXJVcCk7XG4gICAgICAgIGlmIChzZWxlY3Rvcikge1xuICAgICAgICAgICAgcG9pbnRlci5zZWxlY3RvciA9IHNlbGVjdG9yO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMubWlycm9yID0gbmV3IEVsZW1lbnRNaXJyb3IoKTtcbiAgICAgICAgdGhpcy5hdXRvU2Nyb2xsZXIgPSBuZXcgQXV0b1Njcm9sbGVyKCk7XG4gICAgfVxuICAgIGRlc3Ryb3koKSB7XG4gICAgICAgIHRoaXMucG9pbnRlci5kZXN0cm95KCk7XG4gICAgICAgIC8vIEhBQ0s6IHNpbXVsYXRlIGEgcG9pbnRlci11cCB0byBlbmQgdGhlIGN1cnJlbnQgZHJhZ1xuICAgICAgICAvLyBUT0RPOiBmaXJlICdkcmFnZW5kJyBkaXJlY3RseSBhbmQgc3RvcCBpbnRlcmFjdGlvbi4gZGlzY291cmFnZSB1c2Ugb2YgcG9pbnRlcnVwIGV2ZW50IChiL2MgbWlnaHQgbm90IGZpcmUpXG4gICAgICAgIHRoaXMub25Qb2ludGVyVXAoe30pO1xuICAgIH1cbiAgICBzdGFydERlbGF5KGV2KSB7XG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5kZWxheSA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgICAgIHRoaXMuZGVsYXlUaW1lb3V0SWQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmRlbGF5VGltZW91dElkID0gbnVsbDtcbiAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZURlbGF5RW5kKGV2KTtcbiAgICAgICAgICAgIH0sIHRoaXMuZGVsYXkpOyAvLyBub3QgYXNzaWduYWJsZSB0byBudW1iZXIhXG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmhhbmRsZURlbGF5RW5kKGV2KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBoYW5kbGVEZWxheUVuZChldikge1xuICAgICAgICB0aGlzLmlzRGVsYXlFbmRlZCA9IHRydWU7XG4gICAgICAgIHRoaXMudHJ5U3RhcnREcmFnKGV2KTtcbiAgICB9XG4gICAgaGFuZGxlRGlzdGFuY2VTdXJwYXNzZWQoZXYpIHtcbiAgICAgICAgdGhpcy5pc0Rpc3RhbmNlU3VycGFzc2VkID0gdHJ1ZTtcbiAgICAgICAgdGhpcy50cnlTdGFydERyYWcoZXYpO1xuICAgIH1cbiAgICB0cnlTdGFydERyYWcoZXYpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNEZWxheUVuZGVkICYmIHRoaXMuaXNEaXN0YW5jZVN1cnBhc3NlZCkge1xuICAgICAgICAgICAgaWYgKCF0aGlzLnBvaW50ZXIud2FzVG91Y2hTY3JvbGwgfHwgdGhpcy50b3VjaFNjcm9sbEFsbG93ZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmlzRHJhZ2dpbmcgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHRoaXMubWlycm9yTmVlZHNSZXZlcnQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB0aGlzLmF1dG9TY3JvbGxlci5zdGFydChldi5wYWdlWCwgZXYucGFnZVksIHRoaXMuY29udGFpbmVyRWwpO1xuICAgICAgICAgICAgICAgIHRoaXMuZW1pdHRlci50cmlnZ2VyKCdkcmFnc3RhcnQnLCBldik7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMudG91Y2hTY3JvbGxBbGxvd2VkID09PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnBvaW50ZXIuY2FuY2VsVG91Y2hTY3JvbGwoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgdHJ5U3RvcERyYWcoZXYpIHtcbiAgICAgICAgLy8gLnN0b3AoKSBpcyBBTFdBWVMgYXN5bmNocm9ub3VzLCB3aGljaCB3ZSBORUVEIGJlY2F1c2Ugd2Ugd2FudCBhbGwgcG9pbnRlcnVwIGV2ZW50c1xuICAgICAgICAvLyB0aGF0IGNvbWUgZnJvbSB0aGUgZG9jdW1lbnQgdG8gZmlyZSBiZWZvcmVoYW5kLiBtdWNoIG1vcmUgY29udmVuaWVudCB0aGlzIHdheS5cbiAgICAgICAgdGhpcy5taXJyb3Iuc3RvcCh0aGlzLm1pcnJvck5lZWRzUmV2ZXJ0LCB0aGlzLnN0b3BEcmFnLmJpbmQodGhpcywgZXYpKTtcbiAgICB9XG4gICAgc3RvcERyYWcoZXYpIHtcbiAgICAgICAgdGhpcy5pc0RyYWdnaW5nID0gZmFsc2U7XG4gICAgICAgIHRoaXMuZW1pdHRlci50cmlnZ2VyKCdkcmFnZW5kJywgZXYpO1xuICAgIH1cbiAgICAvLyBmaWxsIGluIHRoZSBpbXBsZW1lbnRhdGlvbnMuLi5cbiAgICBzZXRJZ25vcmVNb3ZlKGJvb2wpIHtcbiAgICAgICAgdGhpcy5wb2ludGVyLnNob3VsZElnbm9yZU1vdmUgPSBib29sO1xuICAgIH1cbiAgICBzZXRNaXJyb3JJc1Zpc2libGUoYm9vbCkge1xuICAgICAgICB0aGlzLm1pcnJvci5zZXRJc1Zpc2libGUoYm9vbCk7XG4gICAgfVxuICAgIHNldE1pcnJvck5lZWRzUmV2ZXJ0KGJvb2wpIHtcbiAgICAgICAgdGhpcy5taXJyb3JOZWVkc1JldmVydCA9IGJvb2w7XG4gICAgfVxuICAgIHNldEF1dG9TY3JvbGxFbmFibGVkKGJvb2wpIHtcbiAgICAgICAgdGhpcy5hdXRvU2Nyb2xsZXIuaXNFbmFibGVkID0gYm9vbDtcbiAgICB9XG59XG5cbi8qXG5XaGVuIHRoaXMgY2xhc3MgaXMgaW5zdGFudGlhdGVkLCBpdCByZWNvcmRzIHRoZSBvZmZzZXQgb2YgYW4gZWxlbWVudCAocmVsYXRpdmUgdG8gdGhlIGRvY3VtZW50IHRvcGxlZnQpLFxuYW5kIGNvbnRpbnVlcyB0byBtb25pdG9yIHNjcm9sbGluZywgdXBkYXRpbmcgdGhlIGNhY2hlZCBjb29yZGluYXRlcyBpZiBpdCBuZWVkcyB0by5cbkRvZXMgbm90IGFjY2VzcyB0aGUgRE9NIGFmdGVyIGluc3RhbnRpYXRpb24sIHNvIGhpZ2hseSBwZXJmb3JtYW50LlxuXG5BbHNvIGtlZXBzIHRyYWNrIG9mIGFsbCBzY3JvbGxpbmcvb3ZlcmZsb3c6aGlkZGVuIGNvbnRhaW5lcnMgdGhhdCBhcmUgcGFyZW50cyBvZiB0aGUgZ2l2ZW4gZWxlbWVudFxuYW5kIGFuIGRldGVybWluZSBpZiBhIGdpdmVuIHBvaW50IGlzIGluc2lkZSB0aGUgY29tYmluZWQgY2xpcHBpbmcgcmVjdGFuZ2xlLlxuKi9cbmNsYXNzIE9mZnNldFRyYWNrZXIge1xuICAgIGNvbnN0cnVjdG9yKGVsKSB7XG4gICAgICAgIHRoaXMuZWwgPSBlbDtcbiAgICAgICAgdGhpcy5vcmlnUmVjdCA9IGNvbXB1dGVSZWN0KGVsKTtcbiAgICAgICAgLy8gd2lsbCB3b3JrIGZpbmUgZm9yIGRpdnMgdGhhdCBoYXZlIG92ZXJmbG93OmhpZGRlblxuICAgICAgICB0aGlzLnNjcm9sbENhY2hlcyA9IGdldENsaXBwaW5nUGFyZW50cyhlbCkubWFwKChzY3JvbGxFbCkgPT4gbmV3IEVsZW1lbnRTY3JvbGxHZW9tQ2FjaGUoc2Nyb2xsRWwsIHRydWUpKTtcbiAgICB9XG4gICAgZGVzdHJveSgpIHtcbiAgICAgICAgZm9yIChsZXQgc2Nyb2xsQ2FjaGUgb2YgdGhpcy5zY3JvbGxDYWNoZXMpIHtcbiAgICAgICAgICAgIHNjcm9sbENhY2hlLmRlc3Ryb3koKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBjb21wdXRlTGVmdCgpIHtcbiAgICAgICAgbGV0IGxlZnQgPSB0aGlzLm9yaWdSZWN0LmxlZnQ7XG4gICAgICAgIGZvciAobGV0IHNjcm9sbENhY2hlIG9mIHRoaXMuc2Nyb2xsQ2FjaGVzKSB7XG4gICAgICAgICAgICBsZWZ0ICs9IHNjcm9sbENhY2hlLm9yaWdTY3JvbGxMZWZ0IC0gc2Nyb2xsQ2FjaGUuZ2V0U2Nyb2xsTGVmdCgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBsZWZ0O1xuICAgIH1cbiAgICBjb21wdXRlVG9wKCkge1xuICAgICAgICBsZXQgdG9wID0gdGhpcy5vcmlnUmVjdC50b3A7XG4gICAgICAgIGZvciAobGV0IHNjcm9sbENhY2hlIG9mIHRoaXMuc2Nyb2xsQ2FjaGVzKSB7XG4gICAgICAgICAgICB0b3AgKz0gc2Nyb2xsQ2FjaGUub3JpZ1Njcm9sbFRvcCAtIHNjcm9sbENhY2hlLmdldFNjcm9sbFRvcCgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0b3A7XG4gICAgfVxuICAgIGlzV2l0aGluQ2xpcHBpbmcocGFnZVgsIHBhZ2VZKSB7XG4gICAgICAgIGxldCBwb2ludCA9IHsgbGVmdDogcGFnZVgsIHRvcDogcGFnZVkgfTtcbiAgICAgICAgZm9yIChsZXQgc2Nyb2xsQ2FjaGUgb2YgdGhpcy5zY3JvbGxDYWNoZXMpIHtcbiAgICAgICAgICAgIGlmICghaXNJZ25vcmVkQ2xpcHBpbmcoc2Nyb2xsQ2FjaGUuZ2V0RXZlbnRUYXJnZXQoKSkgJiZcbiAgICAgICAgICAgICAgICAhcG9pbnRJbnNpZGVSZWN0KHBvaW50LCBzY3JvbGxDYWNoZS5jbGllbnRSZWN0KSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59XG4vLyBjZXJ0YWluIGNsaXBwaW5nIGNvbnRhaW5lcnMgc2hvdWxkIG5ldmVyIGNvbnN0cmFpbiBpbnRlcmFjdGlvbnMsIGxpa2UgPGh0bWw+IGFuZCA8Ym9keT5cbi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9mdWxsY2FsZW5kYXIvZnVsbGNhbGVuZGFyL2lzc3Vlcy8zNjE1XG5mdW5jdGlvbiBpc0lnbm9yZWRDbGlwcGluZyhub2RlKSB7XG4gICAgbGV0IHRhZ05hbWUgPSBub2RlLnRhZ05hbWU7XG4gICAgcmV0dXJuIHRhZ05hbWUgPT09ICdIVE1MJyB8fCB0YWdOYW1lID09PSAnQk9EWSc7XG59XG5cbi8qXG5UcmFja3MgbW92ZW1lbnQgb3ZlciBtdWx0aXBsZSBkcm9wcGFibGUgYXJlYXMgKGFrYSBcImhpdHNcIilcbnRoYXQgZXhpc3QgaW4gb25lIG9yIG1vcmUgRGF0ZUNvbXBvbmVudHMuXG5SZWxpZXMgb24gYW4gZXhpc3RpbmcgZHJhZ2dhYmxlLlxuXG5lbWl0czpcbi0gcG9pbnRlcmRvd25cbi0gZHJhZ3N0YXJ0XG4tIGhpdGNoYW5nZSAtIGZpcmVzIGluaXRpYWxseSwgZXZlbiBpZiBub3Qgb3ZlciBhIGhpdFxuLSBwb2ludGVydXBcbi0gKGhpdGNoYW5nZSAtIGFnYWluLCB0byBudWxsLCBpZiBlbmRlZCBvdmVyIGEgaGl0KVxuLSBkcmFnZW5kXG4qL1xuY2xhc3MgSGl0RHJhZ2dpbmcge1xuICAgIGNvbnN0cnVjdG9yKGRyYWdnaW5nLCBkcm9wcGFibGVTdG9yZSkge1xuICAgICAgICAvLyBvcHRpb25zIHRoYXQgY2FuIGJlIHNldCBieSBjYWxsZXJcbiAgICAgICAgdGhpcy51c2VTdWJqZWN0Q2VudGVyID0gZmFsc2U7XG4gICAgICAgIHRoaXMucmVxdWlyZUluaXRpYWwgPSB0cnVlOyAvLyBpZiBkb2Vzbid0IHN0YXJ0IG91dCBvbiBhIGhpdCwgd29uJ3QgZW1pdCBhbnkgZXZlbnRzXG4gICAgICAgIHRoaXMuZGlzYWJsZVBvaW50Q2hlY2sgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5pbml0aWFsSGl0ID0gbnVsbDtcbiAgICAgICAgdGhpcy5tb3ZpbmdIaXQgPSBudWxsO1xuICAgICAgICB0aGlzLmZpbmFsSGl0ID0gbnVsbDsgLy8gd29uJ3QgZXZlciBiZSBwb3B1bGF0ZWQgaWYgc2hvdWxkSWdub3JlTW92ZVxuICAgICAgICB0aGlzLmhhbmRsZVBvaW50ZXJEb3duID0gKGV2KSA9PiB7XG4gICAgICAgICAgICBsZXQgeyBkcmFnZ2luZyB9ID0gdGhpcztcbiAgICAgICAgICAgIHRoaXMuaW5pdGlhbEhpdCA9IG51bGw7XG4gICAgICAgICAgICB0aGlzLm1vdmluZ0hpdCA9IG51bGw7XG4gICAgICAgICAgICB0aGlzLmZpbmFsSGl0ID0gbnVsbDtcbiAgICAgICAgICAgIHRoaXMucHJlcGFyZUhpdHMoKTtcbiAgICAgICAgICAgIHRoaXMucHJvY2Vzc0ZpcnN0Q29vcmQoZXYpO1xuICAgICAgICAgICAgaWYgKHRoaXMuaW5pdGlhbEhpdCB8fCAhdGhpcy5yZXF1aXJlSW5pdGlhbCkge1xuICAgICAgICAgICAgICAgIGRyYWdnaW5nLnNldElnbm9yZU1vdmUoZmFsc2UpO1xuICAgICAgICAgICAgICAgIC8vIFRPRE86IGZpcmUgdGhpcyBiZWZvcmUgY29tcHV0aW5nIHByb2Nlc3NGaXJzdENvb3JkLCBzbyBsaXN0ZW5lcnMgY2FuIGNhbmNlbC4gdGhpcyBnZXRzIGZpcmVkIGJ5IGFsbW9zdCBldmVyeSBoYW5kbGVyIDooXG4gICAgICAgICAgICAgICAgdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ3BvaW50ZXJkb3duJywgZXYpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgZHJhZ2dpbmcuc2V0SWdub3JlTW92ZSh0cnVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVEcmFnU3RhcnQgPSAoZXYpID0+IHtcbiAgICAgICAgICAgIHRoaXMuZW1pdHRlci50cmlnZ2VyKCdkcmFnc3RhcnQnLCBldik7XG4gICAgICAgICAgICB0aGlzLmhhbmRsZU1vdmUoZXYsIHRydWUpOyAvLyBmb3JjZSA9IGZpcmUgZXZlbiBpZiBpbml0aWFsbHkgbnVsbFxuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZURyYWdNb3ZlID0gKGV2KSA9PiB7XG4gICAgICAgICAgICB0aGlzLmVtaXR0ZXIudHJpZ2dlcignZHJhZ21vdmUnLCBldik7XG4gICAgICAgICAgICB0aGlzLmhhbmRsZU1vdmUoZXYpO1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZVBvaW50ZXJVcCA9IChldikgPT4ge1xuICAgICAgICAgICAgdGhpcy5yZWxlYXNlSGl0cygpO1xuICAgICAgICAgICAgdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ3BvaW50ZXJ1cCcsIGV2KTtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVEcmFnRW5kID0gKGV2KSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy5tb3ZpbmdIaXQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVtaXR0ZXIudHJpZ2dlcignaGl0dXBkYXRlJywgbnVsbCwgdHJ1ZSwgZXYpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5maW5hbEhpdCA9IHRoaXMubW92aW5nSGl0O1xuICAgICAgICAgICAgdGhpcy5tb3ZpbmdIaXQgPSBudWxsO1xuICAgICAgICAgICAgdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ2RyYWdlbmQnLCBldik7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuZHJvcHBhYmxlU3RvcmUgPSBkcm9wcGFibGVTdG9yZTtcbiAgICAgICAgZHJhZ2dpbmcuZW1pdHRlci5vbigncG9pbnRlcmRvd24nLCB0aGlzLmhhbmRsZVBvaW50ZXJEb3duKTtcbiAgICAgICAgZHJhZ2dpbmcuZW1pdHRlci5vbignZHJhZ3N0YXJ0JywgdGhpcy5oYW5kbGVEcmFnU3RhcnQpO1xuICAgICAgICBkcmFnZ2luZy5lbWl0dGVyLm9uKCdkcmFnbW92ZScsIHRoaXMuaGFuZGxlRHJhZ01vdmUpO1xuICAgICAgICBkcmFnZ2luZy5lbWl0dGVyLm9uKCdwb2ludGVydXAnLCB0aGlzLmhhbmRsZVBvaW50ZXJVcCk7XG4gICAgICAgIGRyYWdnaW5nLmVtaXR0ZXIub24oJ2RyYWdlbmQnLCB0aGlzLmhhbmRsZURyYWdFbmQpO1xuICAgICAgICB0aGlzLmRyYWdnaW5nID0gZHJhZ2dpbmc7XG4gICAgICAgIHRoaXMuZW1pdHRlciA9IG5ldyBFbWl0dGVyKCk7XG4gICAgfVxuICAgIC8vIHNldHMgaW5pdGlhbEhpdFxuICAgIC8vIHNldHMgY29vcmRBZGp1c3RcbiAgICBwcm9jZXNzRmlyc3RDb29yZChldikge1xuICAgICAgICBsZXQgb3JpZ1BvaW50ID0geyBsZWZ0OiBldi5wYWdlWCwgdG9wOiBldi5wYWdlWSB9O1xuICAgICAgICBsZXQgYWRqdXN0ZWRQb2ludCA9IG9yaWdQb2ludDtcbiAgICAgICAgbGV0IHN1YmplY3RFbCA9IGV2LnN1YmplY3RFbDtcbiAgICAgICAgbGV0IHN1YmplY3RSZWN0O1xuICAgICAgICBpZiAoc3ViamVjdEVsIGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpIHsgLy8gaS5lLiBub3QgYSBEb2N1bWVudC9TaGFkb3dSb290XG4gICAgICAgICAgICBzdWJqZWN0UmVjdCA9IGNvbXB1dGVSZWN0KHN1YmplY3RFbCk7XG4gICAgICAgICAgICBhZGp1c3RlZFBvaW50ID0gY29uc3RyYWluUG9pbnQoYWRqdXN0ZWRQb2ludCwgc3ViamVjdFJlY3QpO1xuICAgICAgICB9XG4gICAgICAgIGxldCBpbml0aWFsSGl0ID0gdGhpcy5pbml0aWFsSGl0ID0gdGhpcy5xdWVyeUhpdEZvck9mZnNldChhZGp1c3RlZFBvaW50LmxlZnQsIGFkanVzdGVkUG9pbnQudG9wKTtcbiAgICAgICAgaWYgKGluaXRpYWxIaXQpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnVzZVN1YmplY3RDZW50ZXIgJiYgc3ViamVjdFJlY3QpIHtcbiAgICAgICAgICAgICAgICBsZXQgc2xpY2VkU3ViamVjdFJlY3QgPSBpbnRlcnNlY3RSZWN0cyhzdWJqZWN0UmVjdCwgaW5pdGlhbEhpdC5yZWN0KTtcbiAgICAgICAgICAgICAgICBpZiAoc2xpY2VkU3ViamVjdFJlY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgYWRqdXN0ZWRQb2ludCA9IGdldFJlY3RDZW50ZXIoc2xpY2VkU3ViamVjdFJlY3QpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuY29vcmRBZGp1c3QgPSBkaWZmUG9pbnRzKGFkanVzdGVkUG9pbnQsIG9yaWdQb2ludCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmNvb3JkQWRqdXN0ID0geyBsZWZ0OiAwLCB0b3A6IDAgfTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBoYW5kbGVNb3ZlKGV2LCBmb3JjZUhhbmRsZSkge1xuICAgICAgICBsZXQgaGl0ID0gdGhpcy5xdWVyeUhpdEZvck9mZnNldChldi5wYWdlWCArIHRoaXMuY29vcmRBZGp1c3QubGVmdCwgZXYucGFnZVkgKyB0aGlzLmNvb3JkQWRqdXN0LnRvcCk7XG4gICAgICAgIGlmIChmb3JjZUhhbmRsZSB8fCAhaXNIaXRzRXF1YWwodGhpcy5tb3ZpbmdIaXQsIGhpdCkpIHtcbiAgICAgICAgICAgIHRoaXMubW92aW5nSGl0ID0gaGl0O1xuICAgICAgICAgICAgdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ2hpdHVwZGF0ZScsIGhpdCwgZmFsc2UsIGV2KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBwcmVwYXJlSGl0cygpIHtcbiAgICAgICAgdGhpcy5vZmZzZXRUcmFja2VycyA9IG1hcEhhc2godGhpcy5kcm9wcGFibGVTdG9yZSwgKGludGVyYWN0aW9uU2V0dGluZ3MpID0+IHtcbiAgICAgICAgICAgIGludGVyYWN0aW9uU2V0dGluZ3MuY29tcG9uZW50LnByZXBhcmVIaXRzKCk7XG4gICAgICAgICAgICByZXR1cm4gbmV3IE9mZnNldFRyYWNrZXIoaW50ZXJhY3Rpb25TZXR0aW5ncy5lbCk7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICByZWxlYXNlSGl0cygpIHtcbiAgICAgICAgbGV0IHsgb2Zmc2V0VHJhY2tlcnMgfSA9IHRoaXM7XG4gICAgICAgIGZvciAobGV0IGlkIGluIG9mZnNldFRyYWNrZXJzKSB7XG4gICAgICAgICAgICBvZmZzZXRUcmFja2Vyc1tpZF0uZGVzdHJveSgpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMub2Zmc2V0VHJhY2tlcnMgPSB7fTtcbiAgICB9XG4gICAgcXVlcnlIaXRGb3JPZmZzZXQob2Zmc2V0TGVmdCwgb2Zmc2V0VG9wKSB7XG4gICAgICAgIGxldCB7IGRyb3BwYWJsZVN0b3JlLCBvZmZzZXRUcmFja2VycyB9ID0gdGhpcztcbiAgICAgICAgbGV0IGJlc3RIaXQgPSBudWxsO1xuICAgICAgICBmb3IgKGxldCBpZCBpbiBkcm9wcGFibGVTdG9yZSkge1xuICAgICAgICAgICAgbGV0IGNvbXBvbmVudCA9IGRyb3BwYWJsZVN0b3JlW2lkXS5jb21wb25lbnQ7XG4gICAgICAgICAgICBsZXQgb2Zmc2V0VHJhY2tlciA9IG9mZnNldFRyYWNrZXJzW2lkXTtcbiAgICAgICAgICAgIGlmIChvZmZzZXRUcmFja2VyICYmIC8vIHdhc24ndCBkZXN0cm95ZWQgbWlkLWRyYWdcbiAgICAgICAgICAgICAgICBvZmZzZXRUcmFja2VyLmlzV2l0aGluQ2xpcHBpbmcob2Zmc2V0TGVmdCwgb2Zmc2V0VG9wKSkge1xuICAgICAgICAgICAgICAgIGxldCBvcmlnaW5MZWZ0ID0gb2Zmc2V0VHJhY2tlci5jb21wdXRlTGVmdCgpO1xuICAgICAgICAgICAgICAgIGxldCBvcmlnaW5Ub3AgPSBvZmZzZXRUcmFja2VyLmNvbXB1dGVUb3AoKTtcbiAgICAgICAgICAgICAgICBsZXQgcG9zaXRpb25MZWZ0ID0gb2Zmc2V0TGVmdCAtIG9yaWdpbkxlZnQ7XG4gICAgICAgICAgICAgICAgbGV0IHBvc2l0aW9uVG9wID0gb2Zmc2V0VG9wIC0gb3JpZ2luVG9wO1xuICAgICAgICAgICAgICAgIGxldCB7IG9yaWdSZWN0IH0gPSBvZmZzZXRUcmFja2VyO1xuICAgICAgICAgICAgICAgIGxldCB3aWR0aCA9IG9yaWdSZWN0LnJpZ2h0IC0gb3JpZ1JlY3QubGVmdDtcbiAgICAgICAgICAgICAgICBsZXQgaGVpZ2h0ID0gb3JpZ1JlY3QuYm90dG9tIC0gb3JpZ1JlY3QudG9wO1xuICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAvLyBtdXN0IGJlIHdpdGhpbiB0aGUgZWxlbWVudCdzIGJvdW5kc1xuICAgICAgICAgICAgICAgIHBvc2l0aW9uTGVmdCA+PSAwICYmIHBvc2l0aW9uTGVmdCA8IHdpZHRoICYmXG4gICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uVG9wID49IDAgJiYgcG9zaXRpb25Ub3AgPCBoZWlnaHQpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGhpdCA9IGNvbXBvbmVudC5xdWVyeUhpdChwb3NpdGlvbkxlZnQsIHBvc2l0aW9uVG9wLCB3aWR0aCwgaGVpZ2h0KTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGhpdCAmJiAoXG4gICAgICAgICAgICAgICAgICAgIC8vIG1ha2Ugc3VyZSB0aGUgaGl0IGlzIHdpdGhpbiBhY3RpdmVSYW5nZSwgbWVhbmluZyBpdCdzIG5vdCBhIGRlYWQgY2VsbFxuICAgICAgICAgICAgICAgICAgICByYW5nZUNvbnRhaW5zUmFuZ2UoaGl0LmRhdGVQcm9maWxlLmFjdGl2ZVJhbmdlLCBoaXQuZGF0ZVNwYW4ucmFuZ2UpKSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRW5zdXJlIHRoZSBjb21wb25lbnQgd2UgYXJlIHF1ZXJ5aW5nIGZvciB0aGUgaGl0IGlzIGFjY2Vzc2libHkgbXkgdGhlIHBvaW50ZXJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFByZXZlbnRzIG9ic2N1cmVkIGNhbGVuZGFycyAoZXg6IHVuZGVyIGEgbW9kYWwgZGlhbG9nKSBmcm9tIGFjY2VwdGluZyBoaXRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9mdWxsY2FsZW5kYXIvZnVsbGNhbGVuZGFyL2lzc3Vlcy81MDI2XG4gICAgICAgICAgICAgICAgICAgICAgICAodGhpcy5kaXNhYmxlUG9pbnRDaGVjayB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9mZnNldFRyYWNrZXIuZWwuY29udGFpbnMob2Zmc2V0VHJhY2tlci5lbC5nZXRSb290Tm9kZSgpLmVsZW1lbnRGcm9tUG9pbnQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWRkLWJhY2sgb3JpZ2lucyB0byBnZXQgY29vcmRpbmF0ZSByZWxhdGl2ZSB0byB0b3AtbGVmdCBvZiB3aW5kb3cgdmlld3BvcnRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbkxlZnQgKyBvcmlnaW5MZWZ0IC0gd2luZG93LnNjcm9sbFgsIHBvc2l0aW9uVG9wICsgb3JpZ2luVG9wIC0gd2luZG93LnNjcm9sbFkpKSkgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICghYmVzdEhpdCB8fCBoaXQubGF5ZXIgPiBiZXN0SGl0LmxheWVyKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaGl0LmNvbXBvbmVudElkID0gaWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICBoaXQuY29udGV4dCA9IGNvbXBvbmVudC5jb250ZXh0O1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVE9ETzogYmV0dGVyIHdheSB0byByZS1vcmllbnQgcmVjdGFuZ2xlXG4gICAgICAgICAgICAgICAgICAgICAgICBoaXQucmVjdC5sZWZ0ICs9IG9yaWdpbkxlZnQ7XG4gICAgICAgICAgICAgICAgICAgICAgICBoaXQucmVjdC5yaWdodCArPSBvcmlnaW5MZWZ0O1xuICAgICAgICAgICAgICAgICAgICAgICAgaGl0LnJlY3QudG9wICs9IG9yaWdpblRvcDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGhpdC5yZWN0LmJvdHRvbSArPSBvcmlnaW5Ub3A7XG4gICAgICAgICAgICAgICAgICAgICAgICBiZXN0SGl0ID0gaGl0O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBiZXN0SGl0O1xuICAgIH1cbn1cbmZ1bmN0aW9uIGlzSGl0c0VxdWFsKGhpdDAsIGhpdDEpIHtcbiAgICBpZiAoIWhpdDAgJiYgIWhpdDEpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGlmIChCb29sZWFuKGhpdDApICE9PSBCb29sZWFuKGhpdDEpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIGlzRGF0ZVNwYW5zRXF1YWwoaGl0MC5kYXRlU3BhbiwgaGl0MS5kYXRlU3Bhbik7XG59XG5cbmZ1bmN0aW9uIGJ1aWxkRGF0ZVBvaW50QXBpV2l0aENvbnRleHQoZGF0ZVNwYW4sIGNvbnRleHQpIHtcbiAgICBsZXQgcHJvcHMgPSB7fTtcbiAgICBmb3IgKGxldCB0cmFuc2Zvcm0gb2YgY29udGV4dC5wbHVnaW5Ib29rcy5kYXRlUG9pbnRUcmFuc2Zvcm1zKSB7XG4gICAgICAgIE9iamVjdC5hc3NpZ24ocHJvcHMsIHRyYW5zZm9ybShkYXRlU3BhbiwgY29udGV4dCkpO1xuICAgIH1cbiAgICBPYmplY3QuYXNzaWduKHByb3BzLCBidWlsZERhdGVQb2ludEFwaShkYXRlU3BhbiwgY29udGV4dC5kYXRlRW52KSk7XG4gICAgcmV0dXJuIHByb3BzO1xufVxuZnVuY3Rpb24gYnVpbGREYXRlUG9pbnRBcGkoc3BhbiwgZGF0ZUVudikge1xuICAgIHJldHVybiB7XG4gICAgICAgIGRhdGU6IGRhdGVFbnYudG9EYXRlKHNwYW4ucmFuZ2Uuc3RhcnQpLFxuICAgICAgICBkYXRlU3RyOiBkYXRlRW52LmZvcm1hdElzbyhzcGFuLnJhbmdlLnN0YXJ0LCB7IG9taXRUaW1lOiBzcGFuLmFsbERheSB9KSxcbiAgICAgICAgYWxsRGF5OiBzcGFuLmFsbERheSxcbiAgICB9O1xufVxuXG4vKlxuTW9uaXRvcnMgd2hlbiB0aGUgdXNlciBjbGlja3Mgb24gYSBzcGVjaWZpYyBkYXRlL3RpbWUgb2YgYSBjb21wb25lbnQuXG5BIHBvaW50ZXJkb3duK3BvaW50ZXJ1cCBvbiB0aGUgc2FtZSBcImhpdFwiIGNvbnN0aXR1dGVzIGEgY2xpY2suXG4qL1xuY2xhc3MgRGF0ZUNsaWNraW5nIGV4dGVuZHMgSW50ZXJhY3Rpb24ge1xuICAgIGNvbnN0cnVjdG9yKHNldHRpbmdzKSB7XG4gICAgICAgIHN1cGVyKHNldHRpbmdzKTtcbiAgICAgICAgdGhpcy5oYW5kbGVQb2ludGVyRG93biA9IChwZXYpID0+IHtcbiAgICAgICAgICAgIGxldCB7IGRyYWdnaW5nIH0gPSB0aGlzO1xuICAgICAgICAgICAgbGV0IGRvd25FbCA9IHBldi5vcmlnRXZlbnQudGFyZ2V0O1xuICAgICAgICAgICAgLy8gZG8gdGhpcyBpbiBwb2ludGVyZG93biAobm90IGRyYWdlbmQpIGJlY2F1c2UgRE9NIG1pZ2h0IGJlIG11dGF0ZWQgYnkgdGhlIHRpbWUgZHJhZ2VuZCBpcyBmaXJlZFxuICAgICAgICAgICAgZHJhZ2dpbmcuc2V0SWdub3JlTW92ZSghdGhpcy5jb21wb25lbnQuaXNWYWxpZERhdGVEb3duRWwoZG93bkVsKSk7XG4gICAgICAgIH07XG4gICAgICAgIC8vIHdvbid0IGV2ZW4gZmlyZSBpZiBtb3Zpbmcgd2FzIGlnbm9yZWRcbiAgICAgICAgdGhpcy5oYW5kbGVEcmFnRW5kID0gKGV2KSA9PiB7XG4gICAgICAgICAgICBsZXQgeyBjb21wb25lbnQgfSA9IHRoaXM7XG4gICAgICAgICAgICBsZXQgeyBwb2ludGVyIH0gPSB0aGlzLmRyYWdnaW5nO1xuICAgICAgICAgICAgaWYgKCFwb2ludGVyLndhc1RvdWNoU2Nyb2xsKSB7XG4gICAgICAgICAgICAgICAgbGV0IHsgaW5pdGlhbEhpdCwgZmluYWxIaXQgfSA9IHRoaXMuaGl0RHJhZ2dpbmc7XG4gICAgICAgICAgICAgICAgaWYgKGluaXRpYWxIaXQgJiYgZmluYWxIaXQgJiYgaXNIaXRzRXF1YWwoaW5pdGlhbEhpdCwgZmluYWxIaXQpKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCB7IGNvbnRleHQgfSA9IGNvbXBvbmVudDtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGFyZyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgYnVpbGREYXRlUG9pbnRBcGlXaXRoQ29udGV4dChpbml0aWFsSGl0LmRhdGVTcGFuLCBjb250ZXh0KSksIHsgZGF5RWw6IGluaXRpYWxIaXQuZGF5RWwsIGpzRXZlbnQ6IGV2Lm9yaWdFdmVudCwgdmlldzogY29udGV4dC52aWV3QXBpIHx8IGNvbnRleHQuY2FsZW5kYXJBcGkudmlldyB9KTtcbiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5lbWl0dGVyLnRyaWdnZXIoJ2RhdGVDbGljaycsIGFyZyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICAvLyB3ZSBETyB3YW50IHRvIHdhdGNoIHBvaW50ZXIgbW92ZXMgYmVjYXVzZSBvdGhlcndpc2UgZmluYWxIaXQgd29uJ3QgZ2V0IHBvcHVsYXRlZFxuICAgICAgICB0aGlzLmRyYWdnaW5nID0gbmV3IEZlYXR1cmVmdWxFbGVtZW50RHJhZ2dpbmcoc2V0dGluZ3MuZWwpO1xuICAgICAgICB0aGlzLmRyYWdnaW5nLmF1dG9TY3JvbGxlci5pc0VuYWJsZWQgPSBmYWxzZTtcbiAgICAgICAgbGV0IGhpdERyYWdnaW5nID0gdGhpcy5oaXREcmFnZ2luZyA9IG5ldyBIaXREcmFnZ2luZyh0aGlzLmRyYWdnaW5nLCBpbnRlcmFjdGlvblNldHRpbmdzVG9TdG9yZShzZXR0aW5ncykpO1xuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdwb2ludGVyZG93bicsIHRoaXMuaGFuZGxlUG9pbnRlckRvd24pO1xuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdkcmFnZW5kJywgdGhpcy5oYW5kbGVEcmFnRW5kKTtcbiAgICB9XG4gICAgZGVzdHJveSgpIHtcbiAgICAgICAgdGhpcy5kcmFnZ2luZy5kZXN0cm95KCk7XG4gICAgfVxufVxuXG4vKlxuVHJhY2tzIHdoZW4gdGhlIHVzZXIgc2VsZWN0cyBhIHBvcnRpb24gb2YgdGltZSBvZiBhIGNvbXBvbmVudCxcbmNvbnN0aXR1dGVkIGJ5IGEgZHJhZyBvdmVyIGRhdGUgY2VsbHMsIHdpdGggYSBwb3NzaWJsZSBkZWxheSBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBkcmFnLlxuKi9cbmNsYXNzIERhdGVTZWxlY3RpbmcgZXh0ZW5kcyBJbnRlcmFjdGlvbiB7XG4gICAgY29uc3RydWN0b3Ioc2V0dGluZ3MpIHtcbiAgICAgICAgc3VwZXIoc2V0dGluZ3MpO1xuICAgICAgICB0aGlzLmRyYWdTZWxlY3Rpb24gPSBudWxsO1xuICAgICAgICB0aGlzLmhhbmRsZVBvaW50ZXJEb3duID0gKGV2KSA9PiB7XG4gICAgICAgICAgICBsZXQgeyBjb21wb25lbnQsIGRyYWdnaW5nIH0gPSB0aGlzO1xuICAgICAgICAgICAgbGV0IHsgb3B0aW9ucyB9ID0gY29tcG9uZW50LmNvbnRleHQ7XG4gICAgICAgICAgICBsZXQgY2FuU2VsZWN0ID0gb3B0aW9ucy5zZWxlY3RhYmxlICYmXG4gICAgICAgICAgICAgICAgY29tcG9uZW50LmlzVmFsaWREYXRlRG93bkVsKGV2Lm9yaWdFdmVudC50YXJnZXQpO1xuICAgICAgICAgICAgLy8gZG9uJ3QgYm90aGVyIHRvIHdhdGNoIGV4cGVuc2l2ZSBtb3ZlcyBpZiBjb21wb25lbnQgd29uJ3QgZG8gc2VsZWN0aW9uXG4gICAgICAgICAgICBkcmFnZ2luZy5zZXRJZ25vcmVNb3ZlKCFjYW5TZWxlY3QpO1xuICAgICAgICAgICAgLy8gaWYgdG91Y2gsIHJlcXVpcmUgdXNlciB0byBob2xkIGRvd25cbiAgICAgICAgICAgIGRyYWdnaW5nLmRlbGF5ID0gZXYuaXNUb3VjaCA/IGdldENvbXBvbmVudFRvdWNoRGVsYXkkMShjb21wb25lbnQpIDogbnVsbDtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVEcmFnU3RhcnQgPSAoZXYpID0+IHtcbiAgICAgICAgICAgIHRoaXMuY29tcG9uZW50LmNvbnRleHQuY2FsZW5kYXJBcGkudW5zZWxlY3QoZXYpOyAvLyB1bnNlbGVjdCBwcmV2aW91cyBzZWxlY3Rpb25zXG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlSGl0VXBkYXRlID0gKGhpdCwgaXNGaW5hbCkgPT4ge1xuICAgICAgICAgICAgbGV0IHsgY29udGV4dCB9ID0gdGhpcy5jb21wb25lbnQ7XG4gICAgICAgICAgICBsZXQgZHJhZ1NlbGVjdGlvbiA9IG51bGw7XG4gICAgICAgICAgICBsZXQgaXNJbnZhbGlkID0gZmFsc2U7XG4gICAgICAgICAgICBpZiAoaGl0KSB7XG4gICAgICAgICAgICAgICAgbGV0IGluaXRpYWxIaXQgPSB0aGlzLmhpdERyYWdnaW5nLmluaXRpYWxIaXQ7XG4gICAgICAgICAgICAgICAgbGV0IGRpc2FsbG93ZWQgPSBoaXQuY29tcG9uZW50SWQgPT09IGluaXRpYWxIaXQuY29tcG9uZW50SWRcbiAgICAgICAgICAgICAgICAgICAgJiYgdGhpcy5pc0hpdENvbWJvQWxsb3dlZFxuICAgICAgICAgICAgICAgICAgICAmJiAhdGhpcy5pc0hpdENvbWJvQWxsb3dlZChpbml0aWFsSGl0LCBoaXQpO1xuICAgICAgICAgICAgICAgIGlmICghZGlzYWxsb3dlZCkge1xuICAgICAgICAgICAgICAgICAgICBkcmFnU2VsZWN0aW9uID0gam9pbkhpdHNJbnRvU2VsZWN0aW9uKGluaXRpYWxIaXQsIGhpdCwgY29udGV4dC5wbHVnaW5Ib29rcy5kYXRlU2VsZWN0aW9uVHJhbnNmb3JtZXJzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKCFkcmFnU2VsZWN0aW9uIHx8ICFpc0RhdGVTZWxlY3Rpb25WYWxpZChkcmFnU2VsZWN0aW9uLCBoaXQuZGF0ZVByb2ZpbGUsIGNvbnRleHQpKSB7XG4gICAgICAgICAgICAgICAgICAgIGlzSW52YWxpZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIGRyYWdTZWxlY3Rpb24gPSBudWxsO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChkcmFnU2VsZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5kaXNwYXRjaCh7IHR5cGU6ICdTRUxFQ1RfREFURVMnLCBzZWxlY3Rpb246IGRyYWdTZWxlY3Rpb24gfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICghaXNGaW5hbCkgeyAvLyBvbmx5IHVuc2VsZWN0IGlmIG1vdmVkIGF3YXkgd2hpbGUgZHJhZ2dpbmdcbiAgICAgICAgICAgICAgICBjb250ZXh0LmRpc3BhdGNoKHsgdHlwZTogJ1VOU0VMRUNUX0RBVEVTJyB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghaXNJbnZhbGlkKSB7XG4gICAgICAgICAgICAgICAgZW5hYmxlQ3Vyc29yKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBkaXNhYmxlQ3Vyc29yKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWlzRmluYWwpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmRyYWdTZWxlY3Rpb24gPSBkcmFnU2VsZWN0aW9uOyAvLyBvbmx5IGNsZWFyIGlmIG1vdmVkIGF3YXkgZnJvbSBhbGwgaGl0cyB3aGlsZSBkcmFnZ2luZ1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZVBvaW50ZXJVcCA9IChwZXYpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLmRyYWdTZWxlY3Rpb24pIHtcbiAgICAgICAgICAgICAgICAvLyBzZWxlY3Rpb24gaXMgYWxyZWFkeSByZW5kZXJlZCwgc28ganVzdCBuZWVkIHRvIHJlcG9ydCBzZWxlY3Rpb25cbiAgICAgICAgICAgICAgICB0cmlnZ2VyRGF0ZVNlbGVjdCh0aGlzLmRyYWdTZWxlY3Rpb24sIHBldiwgdGhpcy5jb21wb25lbnQuY29udGV4dCk7XG4gICAgICAgICAgICAgICAgdGhpcy5kcmFnU2VsZWN0aW9uID0gbnVsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgbGV0IHsgY29tcG9uZW50IH0gPSBzZXR0aW5ncztcbiAgICAgICAgbGV0IHsgb3B0aW9ucyB9ID0gY29tcG9uZW50LmNvbnRleHQ7XG4gICAgICAgIGxldCBkcmFnZ2luZyA9IHRoaXMuZHJhZ2dpbmcgPSBuZXcgRmVhdHVyZWZ1bEVsZW1lbnREcmFnZ2luZyhzZXR0aW5ncy5lbCk7XG4gICAgICAgIGRyYWdnaW5nLnRvdWNoU2Nyb2xsQWxsb3dlZCA9IGZhbHNlO1xuICAgICAgICBkcmFnZ2luZy5taW5EaXN0YW5jZSA9IG9wdGlvbnMuc2VsZWN0TWluRGlzdGFuY2UgfHwgMDtcbiAgICAgICAgZHJhZ2dpbmcuYXV0b1Njcm9sbGVyLmlzRW5hYmxlZCA9IG9wdGlvbnMuZHJhZ1Njcm9sbDtcbiAgICAgICAgbGV0IGhpdERyYWdnaW5nID0gdGhpcy5oaXREcmFnZ2luZyA9IG5ldyBIaXREcmFnZ2luZyh0aGlzLmRyYWdnaW5nLCBpbnRlcmFjdGlvblNldHRpbmdzVG9TdG9yZShzZXR0aW5ncykpO1xuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdwb2ludGVyZG93bicsIHRoaXMuaGFuZGxlUG9pbnRlckRvd24pO1xuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdkcmFnc3RhcnQnLCB0aGlzLmhhbmRsZURyYWdTdGFydCk7XG4gICAgICAgIGhpdERyYWdnaW5nLmVtaXR0ZXIub24oJ2hpdHVwZGF0ZScsIHRoaXMuaGFuZGxlSGl0VXBkYXRlKTtcbiAgICAgICAgaGl0RHJhZ2dpbmcuZW1pdHRlci5vbigncG9pbnRlcnVwJywgdGhpcy5oYW5kbGVQb2ludGVyVXApO1xuICAgIH1cbiAgICBkZXN0cm95KCkge1xuICAgICAgICB0aGlzLmRyYWdnaW5nLmRlc3Ryb3koKTtcbiAgICB9XG59XG5mdW5jdGlvbiBnZXRDb21wb25lbnRUb3VjaERlbGF5JDEoY29tcG9uZW50KSB7XG4gICAgbGV0IHsgb3B0aW9ucyB9ID0gY29tcG9uZW50LmNvbnRleHQ7XG4gICAgbGV0IGRlbGF5ID0gb3B0aW9ucy5zZWxlY3RMb25nUHJlc3NEZWxheTtcbiAgICBpZiAoZGVsYXkgPT0gbnVsbCkge1xuICAgICAgICBkZWxheSA9IG9wdGlvbnMubG9uZ1ByZXNzRGVsYXk7XG4gICAgfVxuICAgIHJldHVybiBkZWxheTtcbn1cbmZ1bmN0aW9uIGpvaW5IaXRzSW50b1NlbGVjdGlvbihoaXQwLCBoaXQxLCBkYXRlU2VsZWN0aW9uVHJhbnNmb3JtZXJzKSB7XG4gICAgbGV0IGRhdGVTcGFuMCA9IGhpdDAuZGF0ZVNwYW47XG4gICAgbGV0IGRhdGVTcGFuMSA9IGhpdDEuZGF0ZVNwYW47XG4gICAgbGV0IG1zID0gW1xuICAgICAgICBkYXRlU3BhbjAucmFuZ2Uuc3RhcnQsXG4gICAgICAgIGRhdGVTcGFuMC5yYW5nZS5lbmQsXG4gICAgICAgIGRhdGVTcGFuMS5yYW5nZS5zdGFydCxcbiAgICAgICAgZGF0ZVNwYW4xLnJhbmdlLmVuZCxcbiAgICBdO1xuICAgIG1zLnNvcnQoY29tcGFyZU51bWJlcnMpO1xuICAgIGxldCBwcm9wcyA9IHt9O1xuICAgIGZvciAobGV0IHRyYW5zZm9ybWVyIG9mIGRhdGVTZWxlY3Rpb25UcmFuc2Zvcm1lcnMpIHtcbiAgICAgICAgbGV0IHJlcyA9IHRyYW5zZm9ybWVyKGhpdDAsIGhpdDEpO1xuICAgICAgICBpZiAocmVzID09PSBmYWxzZSkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHJlcykge1xuICAgICAgICAgICAgT2JqZWN0LmFzc2lnbihwcm9wcywgcmVzKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBwcm9wcy5yYW5nZSA9IHsgc3RhcnQ6IG1zWzBdLCBlbmQ6IG1zWzNdIH07XG4gICAgcHJvcHMuYWxsRGF5ID0gZGF0ZVNwYW4wLmFsbERheTtcbiAgICByZXR1cm4gcHJvcHM7XG59XG5cbmNsYXNzIEV2ZW50RHJhZ2dpbmcgZXh0ZW5kcyBJbnRlcmFjdGlvbiB7XG4gICAgY29uc3RydWN0b3Ioc2V0dGluZ3MpIHtcbiAgICAgICAgc3VwZXIoc2V0dGluZ3MpO1xuICAgICAgICAvLyBpbnRlcm5hbCBzdGF0ZVxuICAgICAgICB0aGlzLnN1YmplY3RFbCA9IG51bGw7XG4gICAgICAgIHRoaXMuc3ViamVjdFNlZyA9IG51bGw7IC8vIHRoZSBzZWcgYmVpbmcgc2VsZWN0ZWQvZHJhZ2dlZFxuICAgICAgICB0aGlzLmlzRHJhZ2dpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5ldmVudFJhbmdlID0gbnVsbDtcbiAgICAgICAgdGhpcy5yZWxldmFudEV2ZW50cyA9IG51bGw7IC8vIHRoZSBldmVudHMgYmVpbmcgZHJhZ2dlZFxuICAgICAgICB0aGlzLnJlY2VpdmluZ0NvbnRleHQgPSBudWxsO1xuICAgICAgICB0aGlzLnZhbGlkTXV0YXRpb24gPSBudWxsO1xuICAgICAgICB0aGlzLm11dGF0ZWRSZWxldmFudEV2ZW50cyA9IG51bGw7XG4gICAgICAgIHRoaXMuaGFuZGxlUG9pbnRlckRvd24gPSAoZXYpID0+IHtcbiAgICAgICAgICAgIGxldCBvcmlnVGFyZ2V0ID0gZXYub3JpZ0V2ZW50LnRhcmdldDtcbiAgICAgICAgICAgIGxldCB7IGNvbXBvbmVudCwgZHJhZ2dpbmcgfSA9IHRoaXM7XG4gICAgICAgICAgICBsZXQgeyBtaXJyb3IgfSA9IGRyYWdnaW5nO1xuICAgICAgICAgICAgbGV0IHsgb3B0aW9ucyB9ID0gY29tcG9uZW50LmNvbnRleHQ7XG4gICAgICAgICAgICBsZXQgaW5pdGlhbENvbnRleHQgPSBjb21wb25lbnQuY29udGV4dDtcbiAgICAgICAgICAgIHRoaXMuc3ViamVjdEVsID0gZXYuc3ViamVjdEVsO1xuICAgICAgICAgICAgbGV0IHN1YmplY3RTZWcgPSB0aGlzLnN1YmplY3RTZWcgPSBnZXRFbFNlZyhldi5zdWJqZWN0RWwpO1xuICAgICAgICAgICAgbGV0IGV2ZW50UmFuZ2UgPSB0aGlzLmV2ZW50UmFuZ2UgPSBzdWJqZWN0U2VnLmV2ZW50UmFuZ2U7XG4gICAgICAgICAgICBsZXQgZXZlbnRJbnN0YW5jZUlkID0gZXZlbnRSYW5nZS5pbnN0YW5jZS5pbnN0YW5jZUlkO1xuICAgICAgICAgICAgdGhpcy5yZWxldmFudEV2ZW50cyA9IGdldFJlbGV2YW50RXZlbnRzKGluaXRpYWxDb250ZXh0LmdldEN1cnJlbnREYXRhKCkuZXZlbnRTdG9yZSwgZXZlbnRJbnN0YW5jZUlkKTtcbiAgICAgICAgICAgIGRyYWdnaW5nLm1pbkRpc3RhbmNlID0gZXYuaXNUb3VjaCA/IDAgOiBvcHRpb25zLmV2ZW50RHJhZ01pbkRpc3RhbmNlO1xuICAgICAgICAgICAgZHJhZ2dpbmcuZGVsYXkgPVxuICAgICAgICAgICAgICAgIC8vIG9ubHkgZG8gYSB0b3VjaCBkZWxheSBpZiB0b3VjaCBhbmQgdGhpcyBldmVudCBoYXNuJ3QgYmVlbiBzZWxlY3RlZCB5ZXRcbiAgICAgICAgICAgICAgICAoZXYuaXNUb3VjaCAmJiBldmVudEluc3RhbmNlSWQgIT09IGNvbXBvbmVudC5wcm9wcy5ldmVudFNlbGVjdGlvbikgP1xuICAgICAgICAgICAgICAgICAgICBnZXRDb21wb25lbnRUb3VjaERlbGF5KGNvbXBvbmVudCkgOlxuICAgICAgICAgICAgICAgICAgICBudWxsO1xuICAgICAgICAgICAgaWYgKG9wdGlvbnMuZml4ZWRNaXJyb3JQYXJlbnQpIHtcbiAgICAgICAgICAgICAgICBtaXJyb3IucGFyZW50Tm9kZSA9IG9wdGlvbnMuZml4ZWRNaXJyb3JQYXJlbnQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBtaXJyb3IucGFyZW50Tm9kZSA9IGVsZW1lbnRDbG9zZXN0KG9yaWdUYXJnZXQsICcuZmMnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIG1pcnJvci5yZXZlcnREdXJhdGlvbiA9IG9wdGlvbnMuZHJhZ1JldmVydER1cmF0aW9uO1xuICAgICAgICAgICAgbGV0IGlzVmFsaWQgPSBjb21wb25lbnQuaXNWYWxpZFNlZ0Rvd25FbChvcmlnVGFyZ2V0KSAmJlxuICAgICAgICAgICAgICAgICFlbGVtZW50Q2xvc2VzdChvcmlnVGFyZ2V0LCAnLmZjLWV2ZW50LXJlc2l6ZXInKTsgLy8gTk9UIG9uIGEgcmVzaXplclxuICAgICAgICAgICAgZHJhZ2dpbmcuc2V0SWdub3JlTW92ZSghaXNWYWxpZCk7XG4gICAgICAgICAgICAvLyBkaXNhYmxlIGRyYWdnaW5nIGZvciBlbGVtZW50cyB0aGF0IGFyZSByZXNpemFibGUgKGllLCBzZWxlY3RhYmxlKVxuICAgICAgICAgICAgLy8gYnV0IGFyZSBub3QgZHJhZ2dhYmxlXG4gICAgICAgICAgICB0aGlzLmlzRHJhZ2dpbmcgPSBpc1ZhbGlkICYmXG4gICAgICAgICAgICAgICAgZXYuc3ViamVjdEVsLmNsYXNzTGlzdC5jb250YWlucygnZmMtZXZlbnQtZHJhZ2dhYmxlJyk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlRHJhZ1N0YXJ0ID0gKGV2KSA9PiB7XG4gICAgICAgICAgICBsZXQgaW5pdGlhbENvbnRleHQgPSB0aGlzLmNvbXBvbmVudC5jb250ZXh0O1xuICAgICAgICAgICAgbGV0IGV2ZW50UmFuZ2UgPSB0aGlzLmV2ZW50UmFuZ2U7XG4gICAgICAgICAgICBsZXQgZXZlbnRJbnN0YW5jZUlkID0gZXZlbnRSYW5nZS5pbnN0YW5jZS5pbnN0YW5jZUlkO1xuICAgICAgICAgICAgaWYgKGV2LmlzVG91Y2gpIHtcbiAgICAgICAgICAgICAgICAvLyBuZWVkIHRvIHNlbGVjdCBhIGRpZmZlcmVudCBldmVudD9cbiAgICAgICAgICAgICAgICBpZiAoZXZlbnRJbnN0YW5jZUlkICE9PSB0aGlzLmNvbXBvbmVudC5wcm9wcy5ldmVudFNlbGVjdGlvbikge1xuICAgICAgICAgICAgICAgICAgICBpbml0aWFsQ29udGV4dC5kaXNwYXRjaCh7IHR5cGU6ICdTRUxFQ1RfRVZFTlQnLCBldmVudEluc3RhbmNlSWQgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gaWYgbm93IHVzaW5nIG1vdXNlLCBidXQgd2FzIHByZXZpb3VzIHRvdWNoIGludGVyYWN0aW9uLCBjbGVhciBzZWxlY3RlZCBldmVudFxuICAgICAgICAgICAgICAgIGluaXRpYWxDb250ZXh0LmRpc3BhdGNoKHsgdHlwZTogJ1VOU0VMRUNUX0VWRU5UJyB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0aGlzLmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgICAgICAgICBpbml0aWFsQ29udGV4dC5jYWxlbmRhckFwaS51bnNlbGVjdChldik7IC8vIHVuc2VsZWN0ICpkYXRlKiBzZWxlY3Rpb25cbiAgICAgICAgICAgICAgICBpbml0aWFsQ29udGV4dC5lbWl0dGVyLnRyaWdnZXIoJ2V2ZW50RHJhZ1N0YXJ0Jywge1xuICAgICAgICAgICAgICAgICAgICBlbDogdGhpcy5zdWJqZWN0RWwsXG4gICAgICAgICAgICAgICAgICAgIGV2ZW50OiBuZXcgRXZlbnRJbXBsKGluaXRpYWxDb250ZXh0LCBldmVudFJhbmdlLmRlZiwgZXZlbnRSYW5nZS5pbnN0YW5jZSksXG4gICAgICAgICAgICAgICAgICAgIGpzRXZlbnQ6IGV2Lm9yaWdFdmVudCxcbiAgICAgICAgICAgICAgICAgICAgdmlldzogaW5pdGlhbENvbnRleHQudmlld0FwaSxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVIaXRVcGRhdGUgPSAoaGl0LCBpc0ZpbmFsKSA9PiB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuaXNEcmFnZ2luZykge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCByZWxldmFudEV2ZW50cyA9IHRoaXMucmVsZXZhbnRFdmVudHM7XG4gICAgICAgICAgICBsZXQgaW5pdGlhbEhpdCA9IHRoaXMuaGl0RHJhZ2dpbmcuaW5pdGlhbEhpdDtcbiAgICAgICAgICAgIGxldCBpbml0aWFsQ29udGV4dCA9IHRoaXMuY29tcG9uZW50LmNvbnRleHQ7XG4gICAgICAgICAgICAvLyBzdGF0ZXMgYmFzZWQgb24gbmV3IGhpdFxuICAgICAgICAgICAgbGV0IHJlY2VpdmluZ0NvbnRleHQgPSBudWxsO1xuICAgICAgICAgICAgbGV0IG11dGF0aW9uID0gbnVsbDtcbiAgICAgICAgICAgIGxldCBtdXRhdGVkUmVsZXZhbnRFdmVudHMgPSBudWxsO1xuICAgICAgICAgICAgbGV0IGlzSW52YWxpZCA9IGZhbHNlO1xuICAgICAgICAgICAgbGV0IGludGVyYWN0aW9uID0ge1xuICAgICAgICAgICAgICAgIGFmZmVjdGVkRXZlbnRzOiByZWxldmFudEV2ZW50cyxcbiAgICAgICAgICAgICAgICBtdXRhdGVkRXZlbnRzOiBjcmVhdGVFbXB0eUV2ZW50U3RvcmUoKSxcbiAgICAgICAgICAgICAgICBpc0V2ZW50OiB0cnVlLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGlmIChoaXQpIHtcbiAgICAgICAgICAgICAgICByZWNlaXZpbmdDb250ZXh0ID0gaGl0LmNvbnRleHQ7XG4gICAgICAgICAgICAgICAgbGV0IHJlY2VpdmluZ09wdGlvbnMgPSByZWNlaXZpbmdDb250ZXh0Lm9wdGlvbnM7XG4gICAgICAgICAgICAgICAgaWYgKGluaXRpYWxDb250ZXh0ID09PSByZWNlaXZpbmdDb250ZXh0IHx8XG4gICAgICAgICAgICAgICAgICAgIChyZWNlaXZpbmdPcHRpb25zLmVkaXRhYmxlICYmIHJlY2VpdmluZ09wdGlvbnMuZHJvcHBhYmxlKSkge1xuICAgICAgICAgICAgICAgICAgICBtdXRhdGlvbiA9IGNvbXB1dGVFdmVudE11dGF0aW9uKGluaXRpYWxIaXQsIGhpdCwgdGhpcy5ldmVudFJhbmdlLmluc3RhbmNlLnJhbmdlLnN0YXJ0LCByZWNlaXZpbmdDb250ZXh0LmdldEN1cnJlbnREYXRhKCkucGx1Z2luSG9va3MuZXZlbnREcmFnTXV0YXRpb25NYXNzYWdlcnMpO1xuICAgICAgICAgICAgICAgICAgICBpZiAobXV0YXRpb24pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZWRSZWxldmFudEV2ZW50cyA9IGFwcGx5TXV0YXRpb25Ub0V2ZW50U3RvcmUocmVsZXZhbnRFdmVudHMsIHJlY2VpdmluZ0NvbnRleHQuZ2V0Q3VycmVudERhdGEoKS5ldmVudFVpQmFzZXMsIG11dGF0aW9uLCByZWNlaXZpbmdDb250ZXh0KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGludGVyYWN0aW9uLm11dGF0ZWRFdmVudHMgPSBtdXRhdGVkUmVsZXZhbnRFdmVudHM7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWlzSW50ZXJhY3Rpb25WYWxpZChpbnRlcmFjdGlvbiwgaGl0LmRhdGVQcm9maWxlLCByZWNlaXZpbmdDb250ZXh0KSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzSW52YWxpZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRpb24gPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZWRSZWxldmFudEV2ZW50cyA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3Rpb24ubXV0YXRlZEV2ZW50cyA9IGNyZWF0ZUVtcHR5RXZlbnRTdG9yZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZWNlaXZpbmdDb250ZXh0ID0gbnVsbDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmRpc3BsYXlEcmFnKHJlY2VpdmluZ0NvbnRleHQsIGludGVyYWN0aW9uKTtcbiAgICAgICAgICAgIGlmICghaXNJbnZhbGlkKSB7XG4gICAgICAgICAgICAgICAgZW5hYmxlQ3Vyc29yKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBkaXNhYmxlQ3Vyc29yKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWlzRmluYWwpIHtcbiAgICAgICAgICAgICAgICBpZiAoaW5pdGlhbENvbnRleHQgPT09IHJlY2VpdmluZ0NvbnRleHQgJiYgLy8gVE9ETzogd3JpdGUgdGVzdCBmb3IgdGhpc1xuICAgICAgICAgICAgICAgICAgICBpc0hpdHNFcXVhbChpbml0aWFsSGl0LCBoaXQpKSB7XG4gICAgICAgICAgICAgICAgICAgIG11dGF0aW9uID0gbnVsbDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy5kcmFnZ2luZy5zZXRNaXJyb3JOZWVkc1JldmVydCghbXV0YXRpb24pO1xuICAgICAgICAgICAgICAgIC8vIHJlbmRlciB0aGUgbWlycm9yIGlmIG5vIGFscmVhZHktcmVuZGVyZWQgbWlycm9yXG4gICAgICAgICAgICAgICAgLy8gVE9ETzogd2lzaCB3ZSBjb3VsZCBzb21laG93IHdhaXQgZm9yIGRpc3BhdGNoIHRvIGd1YXJhbnRlZSByZW5kZXJcbiAgICAgICAgICAgICAgICB0aGlzLmRyYWdnaW5nLnNldE1pcnJvcklzVmlzaWJsZSghaGl0IHx8ICF0aGlzLnN1YmplY3RFbC5nZXRSb290Tm9kZSgpLnF1ZXJ5U2VsZWN0b3IoJy5mYy1ldmVudC1taXJyb3InKSk7XG4gICAgICAgICAgICAgICAgLy8gYXNzaWduIHN0YXRlcyBiYXNlZCBvbiBuZXcgaGl0XG4gICAgICAgICAgICAgICAgdGhpcy5yZWNlaXZpbmdDb250ZXh0ID0gcmVjZWl2aW5nQ29udGV4dDtcbiAgICAgICAgICAgICAgICB0aGlzLnZhbGlkTXV0YXRpb24gPSBtdXRhdGlvbjtcbiAgICAgICAgICAgICAgICB0aGlzLm11dGF0ZWRSZWxldmFudEV2ZW50cyA9IG11dGF0ZWRSZWxldmFudEV2ZW50cztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVQb2ludGVyVXAgPSAoKSA9PiB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuaXNEcmFnZ2luZykge1xuICAgICAgICAgICAgICAgIHRoaXMuY2xlYW51cCgpOyAvLyBiZWNhdXNlIGhhbmRsZURyYWdFbmQgd29uJ3QgZmlyZVxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZURyYWdFbmQgPSAoZXYpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgICAgICAgICBsZXQgaW5pdGlhbENvbnRleHQgPSB0aGlzLmNvbXBvbmVudC5jb250ZXh0O1xuICAgICAgICAgICAgICAgIGxldCBpbml0aWFsVmlldyA9IGluaXRpYWxDb250ZXh0LnZpZXdBcGk7XG4gICAgICAgICAgICAgICAgbGV0IHsgcmVjZWl2aW5nQ29udGV4dCwgdmFsaWRNdXRhdGlvbiB9ID0gdGhpcztcbiAgICAgICAgICAgICAgICBsZXQgZXZlbnREZWYgPSB0aGlzLmV2ZW50UmFuZ2UuZGVmO1xuICAgICAgICAgICAgICAgIGxldCBldmVudEluc3RhbmNlID0gdGhpcy5ldmVudFJhbmdlLmluc3RhbmNlO1xuICAgICAgICAgICAgICAgIGxldCBldmVudEFwaSA9IG5ldyBFdmVudEltcGwoaW5pdGlhbENvbnRleHQsIGV2ZW50RGVmLCBldmVudEluc3RhbmNlKTtcbiAgICAgICAgICAgICAgICBsZXQgcmVsZXZhbnRFdmVudHMgPSB0aGlzLnJlbGV2YW50RXZlbnRzO1xuICAgICAgICAgICAgICAgIGxldCBtdXRhdGVkUmVsZXZhbnRFdmVudHMgPSB0aGlzLm11dGF0ZWRSZWxldmFudEV2ZW50cztcbiAgICAgICAgICAgICAgICBsZXQgeyBmaW5hbEhpdCB9ID0gdGhpcy5oaXREcmFnZ2luZztcbiAgICAgICAgICAgICAgICB0aGlzLmNsZWFyRHJhZygpOyAvLyBtdXN0IGhhcHBlbiBhZnRlciByZXZlcnQgYW5pbWF0aW9uXG4gICAgICAgICAgICAgICAgaW5pdGlhbENvbnRleHQuZW1pdHRlci50cmlnZ2VyKCdldmVudERyYWdTdG9wJywge1xuICAgICAgICAgICAgICAgICAgICBlbDogdGhpcy5zdWJqZWN0RWwsXG4gICAgICAgICAgICAgICAgICAgIGV2ZW50OiBldmVudEFwaSxcbiAgICAgICAgICAgICAgICAgICAganNFdmVudDogZXYub3JpZ0V2ZW50LFxuICAgICAgICAgICAgICAgICAgICB2aWV3OiBpbml0aWFsVmlldyxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBpZiAodmFsaWRNdXRhdGlvbikge1xuICAgICAgICAgICAgICAgICAgICAvLyBkcm9wcGVkIHdpdGhpbiBzYW1lIGNhbGVuZGFyXG4gICAgICAgICAgICAgICAgICAgIGlmIChyZWNlaXZpbmdDb250ZXh0ID09PSBpbml0aWFsQ29udGV4dCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHVwZGF0ZWRFdmVudEFwaSA9IG5ldyBFdmVudEltcGwoaW5pdGlhbENvbnRleHQsIG11dGF0ZWRSZWxldmFudEV2ZW50cy5kZWZzW2V2ZW50RGVmLmRlZklkXSwgZXZlbnRJbnN0YW5jZSA/IG11dGF0ZWRSZWxldmFudEV2ZW50cy5pbnN0YW5jZXNbZXZlbnRJbnN0YW5jZS5pbnN0YW5jZUlkXSA6IG51bGwpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaW5pdGlhbENvbnRleHQuZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdNRVJHRV9FVkVOVFMnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50U3RvcmU6IG11dGF0ZWRSZWxldmFudEV2ZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGV2ZW50Q2hhbmdlQXJnID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZEV2ZW50OiBldmVudEFwaSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudDogdXBkYXRlZEV2ZW50QXBpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbGF0ZWRFdmVudHM6IGJ1aWxkRXZlbnRBcGlzKG11dGF0ZWRSZWxldmFudEV2ZW50cywgaW5pdGlhbENvbnRleHQsIGV2ZW50SW5zdGFuY2UpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldmVydCgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdGlhbENvbnRleHQuZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogJ01FUkdFX0VWRU5UUycsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudFN0b3JlOiByZWxldmFudEV2ZW50cywgLy8gdGhlIHByZS1jaGFuZ2UgZGF0YVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxldCB0cmFuc2Zvcm1lZCA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgdHJhbnNmb3JtZXIgb2YgaW5pdGlhbENvbnRleHQuZ2V0Q3VycmVudERhdGEoKS5wbHVnaW5Ib29rcy5ldmVudERyb3BUcmFuc2Zvcm1lcnMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBPYmplY3QuYXNzaWduKHRyYW5zZm9ybWVkLCB0cmFuc2Zvcm1lcih2YWxpZE11dGF0aW9uLCBpbml0aWFsQ29udGV4dCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgaW5pdGlhbENvbnRleHQuZW1pdHRlci50cmlnZ2VyKCdldmVudERyb3AnLCBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZXZlbnRDaGFuZ2VBcmcpLCB0cmFuc2Zvcm1lZCksIHsgZWw6IGV2LnN1YmplY3RFbCwgZGVsdGE6IHZhbGlkTXV0YXRpb24uZGF0ZXNEZWx0YSwganNFdmVudDogZXYub3JpZ0V2ZW50LCB2aWV3OiBpbml0aWFsVmlldyB9KSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpbml0aWFsQ29udGV4dC5lbWl0dGVyLnRyaWdnZXIoJ2V2ZW50Q2hhbmdlJywgZXZlbnRDaGFuZ2VBcmcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZHJvcHBlZCBpbiBkaWZmZXJlbnQgY2FsZW5kYXJcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChyZWNlaXZpbmdDb250ZXh0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgZXZlbnRSZW1vdmVBcmcgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnQ6IGV2ZW50QXBpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbGF0ZWRFdmVudHM6IGJ1aWxkRXZlbnRBcGlzKHJlbGV2YW50RXZlbnRzLCBpbml0aWFsQ29udGV4dCwgZXZlbnRJbnN0YW5jZSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV2ZXJ0KCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0aWFsQ29udGV4dC5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnTUVSR0VfRVZFTlRTJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50U3RvcmU6IHJlbGV2YW50RXZlbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGluaXRpYWxDb250ZXh0LmVtaXR0ZXIudHJpZ2dlcignZXZlbnRMZWF2ZScsIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZXZlbnRSZW1vdmVBcmcpLCB7IGRyYWdnZWRFbDogZXYuc3ViamVjdEVsLCB2aWV3OiBpbml0aWFsVmlldyB9KSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpbml0aWFsQ29udGV4dC5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogJ1JFTU9WRV9FVkVOVFMnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50U3RvcmU6IHJlbGV2YW50RXZlbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpbml0aWFsQ29udGV4dC5lbWl0dGVyLnRyaWdnZXIoJ2V2ZW50UmVtb3ZlJywgZXZlbnRSZW1vdmVBcmcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGFkZGVkRXZlbnREZWYgPSBtdXRhdGVkUmVsZXZhbnRFdmVudHMuZGVmc1tldmVudERlZi5kZWZJZF07XG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgYWRkZWRFdmVudEluc3RhbmNlID0gbXV0YXRlZFJlbGV2YW50RXZlbnRzLmluc3RhbmNlc1tldmVudEluc3RhbmNlLmluc3RhbmNlSWRdO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGFkZGVkRXZlbnRBcGkgPSBuZXcgRXZlbnRJbXBsKHJlY2VpdmluZ0NvbnRleHQsIGFkZGVkRXZlbnREZWYsIGFkZGVkRXZlbnRJbnN0YW5jZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZWNlaXZpbmdDb250ZXh0LmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnTUVSR0VfRVZFTlRTJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudFN0b3JlOiBtdXRhdGVkUmVsZXZhbnRFdmVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxldCBldmVudEFkZEFyZyA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudDogYWRkZWRFdmVudEFwaSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWxhdGVkRXZlbnRzOiBidWlsZEV2ZW50QXBpcyhtdXRhdGVkUmVsZXZhbnRFdmVudHMsIHJlY2VpdmluZ0NvbnRleHQsIGFkZGVkRXZlbnRJbnN0YW5jZSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV2ZXJ0KCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNlaXZpbmdDb250ZXh0LmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdSRU1PVkVfRVZFTlRTJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50U3RvcmU6IG11dGF0ZWRSZWxldmFudEV2ZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgICAgICByZWNlaXZpbmdDb250ZXh0LmVtaXR0ZXIudHJpZ2dlcignZXZlbnRBZGQnLCBldmVudEFkZEFyZyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZXYuaXNUb3VjaCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlY2VpdmluZ0NvbnRleHQuZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnU0VMRUNUX0VWRU5UJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRJbnN0YW5jZUlkOiBldmVudEluc3RhbmNlLmluc3RhbmNlSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICByZWNlaXZpbmdDb250ZXh0LmVtaXR0ZXIudHJpZ2dlcignZHJvcCcsIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgYnVpbGREYXRlUG9pbnRBcGlXaXRoQ29udGV4dChmaW5hbEhpdC5kYXRlU3BhbiwgcmVjZWl2aW5nQ29udGV4dCkpLCB7IGRyYWdnZWRFbDogZXYuc3ViamVjdEVsLCBqc0V2ZW50OiBldi5vcmlnRXZlbnQsIHZpZXc6IGZpbmFsSGl0LmNvbnRleHQudmlld0FwaSB9KSk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZWNlaXZpbmdDb250ZXh0LmVtaXR0ZXIudHJpZ2dlcignZXZlbnRSZWNlaXZlJywgT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBldmVudEFkZEFyZyksIHsgZHJhZ2dlZEVsOiBldi5zdWJqZWN0RWwsIHZpZXc6IGZpbmFsSGl0LmNvbnRleHQudmlld0FwaSB9KSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGluaXRpYWxDb250ZXh0LmVtaXR0ZXIudHJpZ2dlcignX25vRXZlbnREcm9wJyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5jbGVhbnVwKCk7XG4gICAgICAgIH07XG4gICAgICAgIGxldCB7IGNvbXBvbmVudCB9ID0gdGhpcztcbiAgICAgICAgbGV0IHsgb3B0aW9ucyB9ID0gY29tcG9uZW50LmNvbnRleHQ7XG4gICAgICAgIGxldCBkcmFnZ2luZyA9IHRoaXMuZHJhZ2dpbmcgPSBuZXcgRmVhdHVyZWZ1bEVsZW1lbnREcmFnZ2luZyhzZXR0aW5ncy5lbCk7XG4gICAgICAgIGRyYWdnaW5nLnBvaW50ZXIuc2VsZWN0b3IgPSBFdmVudERyYWdnaW5nLlNFTEVDVE9SO1xuICAgICAgICBkcmFnZ2luZy50b3VjaFNjcm9sbEFsbG93ZWQgPSBmYWxzZTtcbiAgICAgICAgZHJhZ2dpbmcuYXV0b1Njcm9sbGVyLmlzRW5hYmxlZCA9IG9wdGlvbnMuZHJhZ1Njcm9sbDtcbiAgICAgICAgbGV0IGhpdERyYWdnaW5nID0gdGhpcy5oaXREcmFnZ2luZyA9IG5ldyBIaXREcmFnZ2luZyh0aGlzLmRyYWdnaW5nLCBpbnRlcmFjdGlvblNldHRpbmdzU3RvcmUpO1xuICAgICAgICBoaXREcmFnZ2luZy51c2VTdWJqZWN0Q2VudGVyID0gc2V0dGluZ3MudXNlRXZlbnRDZW50ZXI7XG4gICAgICAgIGhpdERyYWdnaW5nLmVtaXR0ZXIub24oJ3BvaW50ZXJkb3duJywgdGhpcy5oYW5kbGVQb2ludGVyRG93bik7XG4gICAgICAgIGhpdERyYWdnaW5nLmVtaXR0ZXIub24oJ2RyYWdzdGFydCcsIHRoaXMuaGFuZGxlRHJhZ1N0YXJ0KTtcbiAgICAgICAgaGl0RHJhZ2dpbmcuZW1pdHRlci5vbignaGl0dXBkYXRlJywgdGhpcy5oYW5kbGVIaXRVcGRhdGUpO1xuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdwb2ludGVydXAnLCB0aGlzLmhhbmRsZVBvaW50ZXJVcCk7XG4gICAgICAgIGhpdERyYWdnaW5nLmVtaXR0ZXIub24oJ2RyYWdlbmQnLCB0aGlzLmhhbmRsZURyYWdFbmQpO1xuICAgIH1cbiAgICBkZXN0cm95KCkge1xuICAgICAgICB0aGlzLmRyYWdnaW5nLmRlc3Ryb3koKTtcbiAgICB9XG4gICAgLy8gcmVuZGVyIGEgZHJhZyBzdGF0ZSBvbiB0aGUgbmV4dCByZWNlaXZpbmdDYWxlbmRhclxuICAgIGRpc3BsYXlEcmFnKG5leHRDb250ZXh0LCBzdGF0ZSkge1xuICAgICAgICBsZXQgaW5pdGlhbENvbnRleHQgPSB0aGlzLmNvbXBvbmVudC5jb250ZXh0O1xuICAgICAgICBsZXQgcHJldkNvbnRleHQgPSB0aGlzLnJlY2VpdmluZ0NvbnRleHQ7XG4gICAgICAgIC8vIGRvZXMgdGhlIHByZXZpb3VzIGNhbGVuZGFyIG5lZWQgdG8gYmUgY2xlYXJlZD9cbiAgICAgICAgaWYgKHByZXZDb250ZXh0ICYmIHByZXZDb250ZXh0ICE9PSBuZXh0Q29udGV4dCkge1xuICAgICAgICAgICAgLy8gZG9lcyB0aGUgaW5pdGlhbCBjYWxlbmRhciBuZWVkIHRvIGJlIGNsZWFyZWQ/XG4gICAgICAgICAgICAvLyBpZiBzbywgZG9uJ3QgY2xlYXIgYWxsIHRoZSB3YXkuIHdlIHN0aWxsIG5lZWQgdG8gdG8gaGlkZSB0aGUgYWZmZWN0ZWRFdmVudHNcbiAgICAgICAgICAgIGlmIChwcmV2Q29udGV4dCA9PT0gaW5pdGlhbENvbnRleHQpIHtcbiAgICAgICAgICAgICAgICBwcmV2Q29udGV4dC5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdTRVRfRVZFTlRfRFJBRycsXG4gICAgICAgICAgICAgICAgICAgIHN0YXRlOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhZmZlY3RlZEV2ZW50czogc3RhdGUuYWZmZWN0ZWRFdmVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGVkRXZlbnRzOiBjcmVhdGVFbXB0eUV2ZW50U3RvcmUoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzRXZlbnQ6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgLy8gY29tcGxldGVseSBjbGVhciB0aGUgb2xkIGNhbGVuZGFyIGlmIGl0IHdhc24ndCB0aGUgaW5pdGlhbFxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgcHJldkNvbnRleHQuZGlzcGF0Y2goeyB0eXBlOiAnVU5TRVRfRVZFTlRfRFJBRycgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG5leHRDb250ZXh0KSB7XG4gICAgICAgICAgICBuZXh0Q29udGV4dC5kaXNwYXRjaCh7IHR5cGU6ICdTRVRfRVZFTlRfRFJBRycsIHN0YXRlIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNsZWFyRHJhZygpIHtcbiAgICAgICAgbGV0IGluaXRpYWxDYWxlbmRhciA9IHRoaXMuY29tcG9uZW50LmNvbnRleHQ7XG4gICAgICAgIGxldCB7IHJlY2VpdmluZ0NvbnRleHQgfSA9IHRoaXM7XG4gICAgICAgIGlmIChyZWNlaXZpbmdDb250ZXh0KSB7XG4gICAgICAgICAgICByZWNlaXZpbmdDb250ZXh0LmRpc3BhdGNoKHsgdHlwZTogJ1VOU0VUX0VWRU5UX0RSQUcnIH0pO1xuICAgICAgICB9XG4gICAgICAgIC8vIHRoZSBpbml0aWFsIGNhbGVuZGFyIG1pZ2h0IGhhdmUgYW4gZHVtbXkgZHJhZyBzdGF0ZSBmcm9tIGRpc3BsYXlEcmFnXG4gICAgICAgIGlmIChpbml0aWFsQ2FsZW5kYXIgIT09IHJlY2VpdmluZ0NvbnRleHQpIHtcbiAgICAgICAgICAgIGluaXRpYWxDYWxlbmRhci5kaXNwYXRjaCh7IHR5cGU6ICdVTlNFVF9FVkVOVF9EUkFHJyB9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBjbGVhbnVwKCkge1xuICAgICAgICB0aGlzLnN1YmplY3RTZWcgPSBudWxsO1xuICAgICAgICB0aGlzLmlzRHJhZ2dpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5ldmVudFJhbmdlID0gbnVsbDtcbiAgICAgICAgdGhpcy5yZWxldmFudEV2ZW50cyA9IG51bGw7XG4gICAgICAgIHRoaXMucmVjZWl2aW5nQ29udGV4dCA9IG51bGw7XG4gICAgICAgIHRoaXMudmFsaWRNdXRhdGlvbiA9IG51bGw7XG4gICAgICAgIHRoaXMubXV0YXRlZFJlbGV2YW50RXZlbnRzID0gbnVsbDtcbiAgICB9XG59XG4vLyBUT0RPOiB0ZXN0IHRoaXMgaW4gSUUxMVxuLy8gUVVFU1RJT046IHdoeSBkbyB3ZSBuZWVkIGl0IG9uIHRoZSByZXNpemFibGU/Pz9cbkV2ZW50RHJhZ2dpbmcuU0VMRUNUT1IgPSAnLmZjLWV2ZW50LWRyYWdnYWJsZSwgLmZjLWV2ZW50LXJlc2l6YWJsZSc7XG5mdW5jdGlvbiBjb21wdXRlRXZlbnRNdXRhdGlvbihoaXQwLCBoaXQxLCBldmVudEluc3RhbmNlU3RhcnQsIG1hc3NhZ2Vycykge1xuICAgIGxldCBkYXRlU3BhbjAgPSBoaXQwLmRhdGVTcGFuO1xuICAgIGxldCBkYXRlU3BhbjEgPSBoaXQxLmRhdGVTcGFuO1xuICAgIGxldCBkYXRlMCA9IGRhdGVTcGFuMC5yYW5nZS5zdGFydDtcbiAgICBsZXQgZGF0ZTEgPSBkYXRlU3BhbjEucmFuZ2Uuc3RhcnQ7XG4gICAgbGV0IHN0YW5kYXJkUHJvcHMgPSB7fTtcbiAgICBpZiAoZGF0ZVNwYW4wLmFsbERheSAhPT0gZGF0ZVNwYW4xLmFsbERheSkge1xuICAgICAgICBzdGFuZGFyZFByb3BzLmFsbERheSA9IGRhdGVTcGFuMS5hbGxEYXk7XG4gICAgICAgIHN0YW5kYXJkUHJvcHMuaGFzRW5kID0gaGl0MS5jb250ZXh0Lm9wdGlvbnMuYWxsRGF5TWFpbnRhaW5EdXJhdGlvbjtcbiAgICAgICAgaWYgKGRhdGVTcGFuMS5hbGxEYXkpIHtcbiAgICAgICAgICAgIC8vIG1lYW5zIGRhdGUxIGlzIGFscmVhZHkgc3RhcnQtb2YtZGF5LFxuICAgICAgICAgICAgLy8gYnV0IGRhdGUwIG5lZWRzIHRvIGJlIGNvbnZlcnRlZFxuICAgICAgICAgICAgZGF0ZTAgPSBzdGFydE9mRGF5KGV2ZW50SW5zdGFuY2VTdGFydCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyBNb3ZpbmcgZnJvbSBhbGxEYXRlLT50aW1lZFxuICAgICAgICAgICAgLy8gRG9lc24ndCBtYXR0ZXIgd2hlcmUgb24gdGhlIGV2ZW50IHRoZSBkcmFnIGJlZ2FuLCBtdXRhdGUgdGhlIGV2ZW50J3Mgc3RhcnQtZGF0ZSB0byBkYXRlMVxuICAgICAgICAgICAgZGF0ZTAgPSBldmVudEluc3RhbmNlU3RhcnQ7XG4gICAgICAgIH1cbiAgICB9XG4gICAgbGV0IGRlbHRhID0gZGlmZkRhdGVzKGRhdGUwLCBkYXRlMSwgaGl0MC5jb250ZXh0LmRhdGVFbnYsIGhpdDAuY29tcG9uZW50SWQgPT09IGhpdDEuY29tcG9uZW50SWQgP1xuICAgICAgICBoaXQwLmxhcmdlVW5pdCA6XG4gICAgICAgIG51bGwpO1xuICAgIGlmIChkZWx0YS5taWxsaXNlY29uZHMpIHsgLy8gaGFzIGhvdXJzL21pbnV0ZXMvc2Vjb25kc1xuICAgICAgICBzdGFuZGFyZFByb3BzLmFsbERheSA9IGZhbHNlO1xuICAgIH1cbiAgICBsZXQgbXV0YXRpb24gPSB7XG4gICAgICAgIGRhdGVzRGVsdGE6IGRlbHRhLFxuICAgICAgICBzdGFuZGFyZFByb3BzLFxuICAgIH07XG4gICAgZm9yIChsZXQgbWFzc2FnZXIgb2YgbWFzc2FnZXJzKSB7XG4gICAgICAgIG1hc3NhZ2VyKG11dGF0aW9uLCBoaXQwLCBoaXQxKTtcbiAgICB9XG4gICAgcmV0dXJuIG11dGF0aW9uO1xufVxuZnVuY3Rpb24gZ2V0Q29tcG9uZW50VG91Y2hEZWxheShjb21wb25lbnQpIHtcbiAgICBsZXQgeyBvcHRpb25zIH0gPSBjb21wb25lbnQuY29udGV4dDtcbiAgICBsZXQgZGVsYXkgPSBvcHRpb25zLmV2ZW50TG9uZ1ByZXNzRGVsYXk7XG4gICAgaWYgKGRlbGF5ID09IG51bGwpIHtcbiAgICAgICAgZGVsYXkgPSBvcHRpb25zLmxvbmdQcmVzc0RlbGF5O1xuICAgIH1cbiAgICByZXR1cm4gZGVsYXk7XG59XG5cbmNsYXNzIEV2ZW50UmVzaXppbmcgZXh0ZW5kcyBJbnRlcmFjdGlvbiB7XG4gICAgY29uc3RydWN0b3Ioc2V0dGluZ3MpIHtcbiAgICAgICAgc3VwZXIoc2V0dGluZ3MpO1xuICAgICAgICAvLyBpbnRlcm5hbCBzdGF0ZVxuICAgICAgICB0aGlzLmRyYWdnaW5nU2VnRWwgPSBudWxsO1xuICAgICAgICB0aGlzLmRyYWdnaW5nU2VnID0gbnVsbDsgLy8gVE9ETzogcmVuYW1lIHRvIHJlc2l6aW5nU2VnPyBzdWJqZWN0U2VnP1xuICAgICAgICB0aGlzLmV2ZW50UmFuZ2UgPSBudWxsO1xuICAgICAgICB0aGlzLnJlbGV2YW50RXZlbnRzID0gbnVsbDtcbiAgICAgICAgdGhpcy52YWxpZE11dGF0aW9uID0gbnVsbDtcbiAgICAgICAgdGhpcy5tdXRhdGVkUmVsZXZhbnRFdmVudHMgPSBudWxsO1xuICAgICAgICB0aGlzLmhhbmRsZVBvaW50ZXJEb3duID0gKGV2KSA9PiB7XG4gICAgICAgICAgICBsZXQgeyBjb21wb25lbnQgfSA9IHRoaXM7XG4gICAgICAgICAgICBsZXQgc2VnRWwgPSB0aGlzLnF1ZXJ5U2VnRWwoZXYpO1xuICAgICAgICAgICAgbGV0IHNlZyA9IGdldEVsU2VnKHNlZ0VsKTtcbiAgICAgICAgICAgIGxldCBldmVudFJhbmdlID0gdGhpcy5ldmVudFJhbmdlID0gc2VnLmV2ZW50UmFuZ2U7XG4gICAgICAgICAgICB0aGlzLmRyYWdnaW5nLm1pbkRpc3RhbmNlID0gY29tcG9uZW50LmNvbnRleHQub3B0aW9ucy5ldmVudERyYWdNaW5EaXN0YW5jZTtcbiAgICAgICAgICAgIC8vIGlmIHRvdWNoLCBuZWVkIHRvIGJlIHdvcmtpbmcgd2l0aCBhIHNlbGVjdGVkIGV2ZW50XG4gICAgICAgICAgICB0aGlzLmRyYWdnaW5nLnNldElnbm9yZU1vdmUoIXRoaXMuY29tcG9uZW50LmlzVmFsaWRTZWdEb3duRWwoZXYub3JpZ0V2ZW50LnRhcmdldCkgfHxcbiAgICAgICAgICAgICAgICAoZXYuaXNUb3VjaCAmJiB0aGlzLmNvbXBvbmVudC5wcm9wcy5ldmVudFNlbGVjdGlvbiAhPT0gZXZlbnRSYW5nZS5pbnN0YW5jZS5pbnN0YW5jZUlkKSk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlRHJhZ1N0YXJ0ID0gKGV2KSA9PiB7XG4gICAgICAgICAgICBsZXQgeyBjb250ZXh0IH0gPSB0aGlzLmNvbXBvbmVudDtcbiAgICAgICAgICAgIGxldCBldmVudFJhbmdlID0gdGhpcy5ldmVudFJhbmdlO1xuICAgICAgICAgICAgdGhpcy5yZWxldmFudEV2ZW50cyA9IGdldFJlbGV2YW50RXZlbnRzKGNvbnRleHQuZ2V0Q3VycmVudERhdGEoKS5ldmVudFN0b3JlLCB0aGlzLmV2ZW50UmFuZ2UuaW5zdGFuY2UuaW5zdGFuY2VJZCk7XG4gICAgICAgICAgICBsZXQgc2VnRWwgPSB0aGlzLnF1ZXJ5U2VnRWwoZXYpO1xuICAgICAgICAgICAgdGhpcy5kcmFnZ2luZ1NlZ0VsID0gc2VnRWw7XG4gICAgICAgICAgICB0aGlzLmRyYWdnaW5nU2VnID0gZ2V0RWxTZWcoc2VnRWwpO1xuICAgICAgICAgICAgY29udGV4dC5jYWxlbmRhckFwaS51bnNlbGVjdCgpO1xuICAgICAgICAgICAgY29udGV4dC5lbWl0dGVyLnRyaWdnZXIoJ2V2ZW50UmVzaXplU3RhcnQnLCB7XG4gICAgICAgICAgICAgICAgZWw6IHNlZ0VsLFxuICAgICAgICAgICAgICAgIGV2ZW50OiBuZXcgRXZlbnRJbXBsKGNvbnRleHQsIGV2ZW50UmFuZ2UuZGVmLCBldmVudFJhbmdlLmluc3RhbmNlKSxcbiAgICAgICAgICAgICAgICBqc0V2ZW50OiBldi5vcmlnRXZlbnQsXG4gICAgICAgICAgICAgICAgdmlldzogY29udGV4dC52aWV3QXBpLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlSGl0VXBkYXRlID0gKGhpdCwgaXNGaW5hbCwgZXYpID0+IHtcbiAgICAgICAgICAgIGxldCB7IGNvbnRleHQgfSA9IHRoaXMuY29tcG9uZW50O1xuICAgICAgICAgICAgbGV0IHJlbGV2YW50RXZlbnRzID0gdGhpcy5yZWxldmFudEV2ZW50cztcbiAgICAgICAgICAgIGxldCBpbml0aWFsSGl0ID0gdGhpcy5oaXREcmFnZ2luZy5pbml0aWFsSGl0O1xuICAgICAgICAgICAgbGV0IGV2ZW50SW5zdGFuY2UgPSB0aGlzLmV2ZW50UmFuZ2UuaW5zdGFuY2U7XG4gICAgICAgICAgICBsZXQgbXV0YXRpb24gPSBudWxsO1xuICAgICAgICAgICAgbGV0IG11dGF0ZWRSZWxldmFudEV2ZW50cyA9IG51bGw7XG4gICAgICAgICAgICBsZXQgaXNJbnZhbGlkID0gZmFsc2U7XG4gICAgICAgICAgICBsZXQgaW50ZXJhY3Rpb24gPSB7XG4gICAgICAgICAgICAgICAgYWZmZWN0ZWRFdmVudHM6IHJlbGV2YW50RXZlbnRzLFxuICAgICAgICAgICAgICAgIG11dGF0ZWRFdmVudHM6IGNyZWF0ZUVtcHR5RXZlbnRTdG9yZSgpLFxuICAgICAgICAgICAgICAgIGlzRXZlbnQ6IHRydWUsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKGhpdCkge1xuICAgICAgICAgICAgICAgIGxldCBkaXNhbGxvd2VkID0gaGl0LmNvbXBvbmVudElkID09PSBpbml0aWFsSGl0LmNvbXBvbmVudElkXG4gICAgICAgICAgICAgICAgICAgICYmIHRoaXMuaXNIaXRDb21ib0FsbG93ZWRcbiAgICAgICAgICAgICAgICAgICAgJiYgIXRoaXMuaXNIaXRDb21ib0FsbG93ZWQoaW5pdGlhbEhpdCwgaGl0KTtcbiAgICAgICAgICAgICAgICBpZiAoIWRpc2FsbG93ZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgbXV0YXRpb24gPSBjb21wdXRlTXV0YXRpb24oaW5pdGlhbEhpdCwgaGl0LCBldi5zdWJqZWN0RWwuY2xhc3NMaXN0LmNvbnRhaW5zKCdmYy1ldmVudC1yZXNpemVyLXN0YXJ0JyksIGV2ZW50SW5zdGFuY2UucmFuZ2UpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChtdXRhdGlvbikge1xuICAgICAgICAgICAgICAgIG11dGF0ZWRSZWxldmFudEV2ZW50cyA9IGFwcGx5TXV0YXRpb25Ub0V2ZW50U3RvcmUocmVsZXZhbnRFdmVudHMsIGNvbnRleHQuZ2V0Q3VycmVudERhdGEoKS5ldmVudFVpQmFzZXMsIG11dGF0aW9uLCBjb250ZXh0KTtcbiAgICAgICAgICAgICAgICBpbnRlcmFjdGlvbi5tdXRhdGVkRXZlbnRzID0gbXV0YXRlZFJlbGV2YW50RXZlbnRzO1xuICAgICAgICAgICAgICAgIGlmICghaXNJbnRlcmFjdGlvblZhbGlkKGludGVyYWN0aW9uLCBoaXQuZGF0ZVByb2ZpbGUsIGNvbnRleHQpKSB7XG4gICAgICAgICAgICAgICAgICAgIGlzSW52YWxpZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIG11dGF0aW9uID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgbXV0YXRlZFJlbGV2YW50RXZlbnRzID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3Rpb24ubXV0YXRlZEV2ZW50cyA9IG51bGw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG11dGF0ZWRSZWxldmFudEV2ZW50cykge1xuICAgICAgICAgICAgICAgIGNvbnRleHQuZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnU0VUX0VWRU5UX1JFU0laRScsXG4gICAgICAgICAgICAgICAgICAgIHN0YXRlOiBpbnRlcmFjdGlvbixcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGNvbnRleHQuZGlzcGF0Y2goeyB0eXBlOiAnVU5TRVRfRVZFTlRfUkVTSVpFJyB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghaXNJbnZhbGlkKSB7XG4gICAgICAgICAgICAgICAgZW5hYmxlQ3Vyc29yKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBkaXNhYmxlQ3Vyc29yKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWlzRmluYWwpIHtcbiAgICAgICAgICAgICAgICBpZiAobXV0YXRpb24gJiYgaXNIaXRzRXF1YWwoaW5pdGlhbEhpdCwgaGl0KSkge1xuICAgICAgICAgICAgICAgICAgICBtdXRhdGlvbiA9IG51bGw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMudmFsaWRNdXRhdGlvbiA9IG11dGF0aW9uO1xuICAgICAgICAgICAgICAgIHRoaXMubXV0YXRlZFJlbGV2YW50RXZlbnRzID0gbXV0YXRlZFJlbGV2YW50RXZlbnRzO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZURyYWdFbmQgPSAoZXYpID0+IHtcbiAgICAgICAgICAgIGxldCB7IGNvbnRleHQgfSA9IHRoaXMuY29tcG9uZW50O1xuICAgICAgICAgICAgbGV0IGV2ZW50RGVmID0gdGhpcy5ldmVudFJhbmdlLmRlZjtcbiAgICAgICAgICAgIGxldCBldmVudEluc3RhbmNlID0gdGhpcy5ldmVudFJhbmdlLmluc3RhbmNlO1xuICAgICAgICAgICAgbGV0IGV2ZW50QXBpID0gbmV3IEV2ZW50SW1wbChjb250ZXh0LCBldmVudERlZiwgZXZlbnRJbnN0YW5jZSk7XG4gICAgICAgICAgICBsZXQgcmVsZXZhbnRFdmVudHMgPSB0aGlzLnJlbGV2YW50RXZlbnRzO1xuICAgICAgICAgICAgbGV0IG11dGF0ZWRSZWxldmFudEV2ZW50cyA9IHRoaXMubXV0YXRlZFJlbGV2YW50RXZlbnRzO1xuICAgICAgICAgICAgY29udGV4dC5lbWl0dGVyLnRyaWdnZXIoJ2V2ZW50UmVzaXplU3RvcCcsIHtcbiAgICAgICAgICAgICAgICBlbDogdGhpcy5kcmFnZ2luZ1NlZ0VsLFxuICAgICAgICAgICAgICAgIGV2ZW50OiBldmVudEFwaSxcbiAgICAgICAgICAgICAgICBqc0V2ZW50OiBldi5vcmlnRXZlbnQsXG4gICAgICAgICAgICAgICAgdmlldzogY29udGV4dC52aWV3QXBpLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBpZiAodGhpcy52YWxpZE11dGF0aW9uKSB7XG4gICAgICAgICAgICAgICAgbGV0IHVwZGF0ZWRFdmVudEFwaSA9IG5ldyBFdmVudEltcGwoY29udGV4dCwgbXV0YXRlZFJlbGV2YW50RXZlbnRzLmRlZnNbZXZlbnREZWYuZGVmSWRdLCBldmVudEluc3RhbmNlID8gbXV0YXRlZFJlbGV2YW50RXZlbnRzLmluc3RhbmNlc1tldmVudEluc3RhbmNlLmluc3RhbmNlSWRdIDogbnVsbCk7XG4gICAgICAgICAgICAgICAgY29udGV4dC5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdNRVJHRV9FVkVOVFMnLFxuICAgICAgICAgICAgICAgICAgICBldmVudFN0b3JlOiBtdXRhdGVkUmVsZXZhbnRFdmVudHMsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgbGV0IGV2ZW50Q2hhbmdlQXJnID0ge1xuICAgICAgICAgICAgICAgICAgICBvbGRFdmVudDogZXZlbnRBcGksXG4gICAgICAgICAgICAgICAgICAgIGV2ZW50OiB1cGRhdGVkRXZlbnRBcGksXG4gICAgICAgICAgICAgICAgICAgIHJlbGF0ZWRFdmVudHM6IGJ1aWxkRXZlbnRBcGlzKG11dGF0ZWRSZWxldmFudEV2ZW50cywgY29udGV4dCwgZXZlbnRJbnN0YW5jZSksXG4gICAgICAgICAgICAgICAgICAgIHJldmVydCgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRleHQuZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdNRVJHRV9FVkVOVFMnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50U3RvcmU6IHJlbGV2YW50RXZlbnRzLCAvLyB0aGUgcHJlLWNoYW5nZSBldmVudHNcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgY29udGV4dC5lbWl0dGVyLnRyaWdnZXIoJ2V2ZW50UmVzaXplJywgT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBldmVudENoYW5nZUFyZyksIHsgZWw6IHRoaXMuZHJhZ2dpbmdTZWdFbCwgc3RhcnREZWx0YTogdGhpcy52YWxpZE11dGF0aW9uLnN0YXJ0RGVsdGEgfHwgY3JlYXRlRHVyYXRpb24oMCksIGVuZERlbHRhOiB0aGlzLnZhbGlkTXV0YXRpb24uZW5kRGVsdGEgfHwgY3JlYXRlRHVyYXRpb24oMCksIGpzRXZlbnQ6IGV2Lm9yaWdFdmVudCwgdmlldzogY29udGV4dC52aWV3QXBpIH0pKTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LmVtaXR0ZXIudHJpZ2dlcignZXZlbnRDaGFuZ2UnLCBldmVudENoYW5nZUFyZyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBjb250ZXh0LmVtaXR0ZXIudHJpZ2dlcignX25vRXZlbnRSZXNpemUnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIHJlc2V0IGFsbCBpbnRlcm5hbCBzdGF0ZVxuICAgICAgICAgICAgdGhpcy5kcmFnZ2luZ1NlZyA9IG51bGw7XG4gICAgICAgICAgICB0aGlzLnJlbGV2YW50RXZlbnRzID0gbnVsbDtcbiAgICAgICAgICAgIHRoaXMudmFsaWRNdXRhdGlvbiA9IG51bGw7XG4gICAgICAgICAgICAvLyBva2F5IHRvIGtlZXAgZXZlbnRJbnN0YW5jZSBhcm91bmQuIHVzZWZ1bCB0byBzZXQgaXQgaW4gaGFuZGxlUG9pbnRlckRvd25cbiAgICAgICAgfTtcbiAgICAgICAgbGV0IHsgY29tcG9uZW50IH0gPSBzZXR0aW5ncztcbiAgICAgICAgbGV0IGRyYWdnaW5nID0gdGhpcy5kcmFnZ2luZyA9IG5ldyBGZWF0dXJlZnVsRWxlbWVudERyYWdnaW5nKHNldHRpbmdzLmVsKTtcbiAgICAgICAgZHJhZ2dpbmcucG9pbnRlci5zZWxlY3RvciA9ICcuZmMtZXZlbnQtcmVzaXplcic7XG4gICAgICAgIGRyYWdnaW5nLnRvdWNoU2Nyb2xsQWxsb3dlZCA9IGZhbHNlO1xuICAgICAgICBkcmFnZ2luZy5hdXRvU2Nyb2xsZXIuaXNFbmFibGVkID0gY29tcG9uZW50LmNvbnRleHQub3B0aW9ucy5kcmFnU2Nyb2xsO1xuICAgICAgICBsZXQgaGl0RHJhZ2dpbmcgPSB0aGlzLmhpdERyYWdnaW5nID0gbmV3IEhpdERyYWdnaW5nKHRoaXMuZHJhZ2dpbmcsIGludGVyYWN0aW9uU2V0dGluZ3NUb1N0b3JlKHNldHRpbmdzKSk7XG4gICAgICAgIGhpdERyYWdnaW5nLmVtaXR0ZXIub24oJ3BvaW50ZXJkb3duJywgdGhpcy5oYW5kbGVQb2ludGVyRG93bik7XG4gICAgICAgIGhpdERyYWdnaW5nLmVtaXR0ZXIub24oJ2RyYWdzdGFydCcsIHRoaXMuaGFuZGxlRHJhZ1N0YXJ0KTtcbiAgICAgICAgaGl0RHJhZ2dpbmcuZW1pdHRlci5vbignaGl0dXBkYXRlJywgdGhpcy5oYW5kbGVIaXRVcGRhdGUpO1xuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdkcmFnZW5kJywgdGhpcy5oYW5kbGVEcmFnRW5kKTtcbiAgICB9XG4gICAgZGVzdHJveSgpIHtcbiAgICAgICAgdGhpcy5kcmFnZ2luZy5kZXN0cm95KCk7XG4gICAgfVxuICAgIHF1ZXJ5U2VnRWwoZXYpIHtcbiAgICAgICAgcmV0dXJuIGVsZW1lbnRDbG9zZXN0KGV2LnN1YmplY3RFbCwgJy5mYy1ldmVudCcpO1xuICAgIH1cbn1cbmZ1bmN0aW9uIGNvbXB1dGVNdXRhdGlvbihoaXQwLCBoaXQxLCBpc0Zyb21TdGFydCwgaW5zdGFuY2VSYW5nZSkge1xuICAgIGxldCBkYXRlRW52ID0gaGl0MC5jb250ZXh0LmRhdGVFbnY7XG4gICAgbGV0IGRhdGUwID0gaGl0MC5kYXRlU3Bhbi5yYW5nZS5zdGFydDtcbiAgICBsZXQgZGF0ZTEgPSBoaXQxLmRhdGVTcGFuLnJhbmdlLnN0YXJ0O1xuICAgIGxldCBkZWx0YSA9IGRpZmZEYXRlcyhkYXRlMCwgZGF0ZTEsIGRhdGVFbnYsIGhpdDAubGFyZ2VVbml0KTtcbiAgICBpZiAoaXNGcm9tU3RhcnQpIHtcbiAgICAgICAgaWYgKGRhdGVFbnYuYWRkKGluc3RhbmNlUmFuZ2Uuc3RhcnQsIGRlbHRhKSA8IGluc3RhbmNlUmFuZ2UuZW5kKSB7XG4gICAgICAgICAgICByZXR1cm4geyBzdGFydERlbHRhOiBkZWx0YSB9O1xuICAgICAgICB9XG4gICAgfVxuICAgIGVsc2UgaWYgKGRhdGVFbnYuYWRkKGluc3RhbmNlUmFuZ2UuZW5kLCBkZWx0YSkgPiBpbnN0YW5jZVJhbmdlLnN0YXJ0KSB7XG4gICAgICAgIHJldHVybiB7IGVuZERlbHRhOiBkZWx0YSB9O1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cblxuY2xhc3MgVW5zZWxlY3RBdXRvIHtcbiAgICBjb25zdHJ1Y3Rvcihjb250ZXh0KSB7XG4gICAgICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XG4gICAgICAgIHRoaXMuaXNSZWNlbnRQb2ludGVyRGF0ZVNlbGVjdCA9IGZhbHNlOyAvLyB3aXNoIHdlIGNvdWxkIHVzZSBhIHNlbGVjdG9yIHRvIGRldGVjdCBkYXRlIHNlbGVjdGlvbiwgYnV0IHVzZXMgaGl0IHN5c3RlbVxuICAgICAgICB0aGlzLm1hdGNoZXNDYW5jZWwgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5tYXRjaGVzRXZlbnQgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5vblNlbGVjdCA9IChzZWxlY3RJbmZvKSA9PiB7XG4gICAgICAgICAgICBpZiAoc2VsZWN0SW5mby5qc0V2ZW50KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5pc1JlY2VudFBvaW50ZXJEYXRlU2VsZWN0ID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5vbkRvY3VtZW50UG9pbnRlckRvd24gPSAocGV2KSA9PiB7XG4gICAgICAgICAgICBsZXQgdW5zZWxlY3RDYW5jZWwgPSB0aGlzLmNvbnRleHQub3B0aW9ucy51bnNlbGVjdENhbmNlbDtcbiAgICAgICAgICAgIGxldCBkb3duRWwgPSBnZXRFdmVudFRhcmdldFZpYVJvb3QocGV2Lm9yaWdFdmVudCk7XG4gICAgICAgICAgICB0aGlzLm1hdGNoZXNDYW5jZWwgPSAhIWVsZW1lbnRDbG9zZXN0KGRvd25FbCwgdW5zZWxlY3RDYW5jZWwpO1xuICAgICAgICAgICAgdGhpcy5tYXRjaGVzRXZlbnQgPSAhIWVsZW1lbnRDbG9zZXN0KGRvd25FbCwgRXZlbnREcmFnZ2luZy5TRUxFQ1RPUik7IC8vIGludGVyYWN0aW9uIHN0YXJ0ZWQgb24gYW4gZXZlbnQ/XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMub25Eb2N1bWVudFBvaW50ZXJVcCA9IChwZXYpID0+IHtcbiAgICAgICAgICAgIGxldCB7IGNvbnRleHQgfSA9IHRoaXM7XG4gICAgICAgICAgICBsZXQgeyBkb2N1bWVudFBvaW50ZXIgfSA9IHRoaXM7XG4gICAgICAgICAgICBsZXQgY2FsZW5kYXJTdGF0ZSA9IGNvbnRleHQuZ2V0Q3VycmVudERhdGEoKTtcbiAgICAgICAgICAgIC8vIHRvdWNoLXNjcm9sbGluZyBzaG91bGQgbmV2ZXIgdW5mb2N1cyBhbnkgdHlwZSBvZiBzZWxlY3Rpb25cbiAgICAgICAgICAgIGlmICghZG9jdW1lbnRQb2ludGVyLndhc1RvdWNoU2Nyb2xsKSB7XG4gICAgICAgICAgICAgICAgaWYgKGNhbGVuZGFyU3RhdGUuZGF0ZVNlbGVjdGlvbiAmJiAvLyBhbiBleGlzdGluZyBkYXRlIHNlbGVjdGlvbj9cbiAgICAgICAgICAgICAgICAgICAgIXRoaXMuaXNSZWNlbnRQb2ludGVyRGF0ZVNlbGVjdCAvLyBhIG5ldyBwb2ludGVyLWluaXRpYXRlZCBkYXRlIHNlbGVjdGlvbiBzaW5jZSBsYXN0IG9uRG9jdW1lbnRQb2ludGVyVXA/XG4gICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCB1bnNlbGVjdEF1dG8gPSBjb250ZXh0Lm9wdGlvbnMudW5zZWxlY3RBdXRvO1xuICAgICAgICAgICAgICAgICAgICBpZiAodW5zZWxlY3RBdXRvICYmICghdW5zZWxlY3RBdXRvIHx8ICF0aGlzLm1hdGNoZXNDYW5jZWwpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0LmNhbGVuZGFyQXBpLnVuc2VsZWN0KHBldik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGNhbGVuZGFyU3RhdGUuZXZlbnRTZWxlY3Rpb24gJiYgLy8gYW4gZXhpc3RpbmcgZXZlbnQgc2VsZWN0ZWQ/XG4gICAgICAgICAgICAgICAgICAgICF0aGlzLm1hdGNoZXNFdmVudCAvLyBpbnRlcmFjdGlvbiBESUROJ1Qgc3RhcnQgb24gYW4gZXZlbnRcbiAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5kaXNwYXRjaCh7IHR5cGU6ICdVTlNFTEVDVF9FVkVOVCcgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5pc1JlY2VudFBvaW50ZXJEYXRlU2VsZWN0ID0gZmFsc2U7XG4gICAgICAgIH07XG4gICAgICAgIGxldCBkb2N1bWVudFBvaW50ZXIgPSB0aGlzLmRvY3VtZW50UG9pbnRlciA9IG5ldyBQb2ludGVyRHJhZ2dpbmcoZG9jdW1lbnQpO1xuICAgICAgICBkb2N1bWVudFBvaW50ZXIuc2hvdWxkSWdub3JlTW92ZSA9IHRydWU7XG4gICAgICAgIGRvY3VtZW50UG9pbnRlci5zaG91bGRXYXRjaFNjcm9sbCA9IGZhbHNlO1xuICAgICAgICBkb2N1bWVudFBvaW50ZXIuZW1pdHRlci5vbigncG9pbnRlcmRvd24nLCB0aGlzLm9uRG9jdW1lbnRQb2ludGVyRG93bik7XG4gICAgICAgIGRvY3VtZW50UG9pbnRlci5lbWl0dGVyLm9uKCdwb2ludGVydXAnLCB0aGlzLm9uRG9jdW1lbnRQb2ludGVyVXApO1xuICAgICAgICAvKlxuICAgICAgICBUT0RPOiBiZXR0ZXIgd2F5IHRvIGtub3cgYWJvdXQgd2hldGhlciB0aGVyZSB3YXMgYSBzZWxlY3Rpb24gd2l0aCB0aGUgcG9pbnRlclxuICAgICAgICAqL1xuICAgICAgICBjb250ZXh0LmVtaXR0ZXIub24oJ3NlbGVjdCcsIHRoaXMub25TZWxlY3QpO1xuICAgIH1cbiAgICBkZXN0cm95KCkge1xuICAgICAgICB0aGlzLmNvbnRleHQuZW1pdHRlci5vZmYoJ3NlbGVjdCcsIHRoaXMub25TZWxlY3QpO1xuICAgICAgICB0aGlzLmRvY3VtZW50UG9pbnRlci5kZXN0cm95KCk7XG4gICAgfVxufVxuXG5jb25zdCBPUFRJT05fUkVGSU5FUlMgPSB7XG4gICAgZml4ZWRNaXJyb3JQYXJlbnQ6IGlkZW50aXR5LFxufTtcbmNvbnN0IExJU1RFTkVSX1JFRklORVJTID0ge1xuICAgIGRhdGVDbGljazogaWRlbnRpdHksXG4gICAgZXZlbnREcmFnU3RhcnQ6IGlkZW50aXR5LFxuICAgIGV2ZW50RHJhZ1N0b3A6IGlkZW50aXR5LFxuICAgIGV2ZW50RHJvcDogaWRlbnRpdHksXG4gICAgZXZlbnRSZXNpemVTdGFydDogaWRlbnRpdHksXG4gICAgZXZlbnRSZXNpemVTdG9wOiBpZGVudGl0eSxcbiAgICBldmVudFJlc2l6ZTogaWRlbnRpdHksXG4gICAgZHJvcDogaWRlbnRpdHksXG4gICAgZXZlbnRSZWNlaXZlOiBpZGVudGl0eSxcbiAgICBldmVudExlYXZlOiBpZGVudGl0eSxcbn07XG5cbi8qXG5HaXZlbiBhbiBhbHJlYWR5IGluc3RhbnRpYXRlZCBkcmFnZ2FibGUgb2JqZWN0IGZvciBvbmUtb3ItbW9yZSBlbGVtZW50cyxcbkludGVycHJldHMgYW55IGRyYWdnaW5nIGFzIGFuIGF0dGVtcHQgdG8gZHJhZyBhbiBldmVudHMgdGhhdCBsaXZlcyBvdXRzaWRlXG5vZiBhIGNhbGVuZGFyIG9udG8gYSBjYWxlbmRhci5cbiovXG5jbGFzcyBFeHRlcm5hbEVsZW1lbnREcmFnZ2luZyB7XG4gICAgY29uc3RydWN0b3IoZHJhZ2dpbmcsIHN1cHBsaWVkRHJhZ01ldGEpIHtcbiAgICAgICAgdGhpcy5yZWNlaXZpbmdDb250ZXh0ID0gbnVsbDtcbiAgICAgICAgdGhpcy5kcm9wcGFibGVFdmVudCA9IG51bGw7IC8vIHdpbGwgZXhpc3QgZm9yIGFsbCBkcmFncywgZXZlbiBpZiBjcmVhdGU6ZmFsc2VcbiAgICAgICAgdGhpcy5zdXBwbGllZERyYWdNZXRhID0gbnVsbDtcbiAgICAgICAgdGhpcy5kcmFnTWV0YSA9IG51bGw7XG4gICAgICAgIHRoaXMuaGFuZGxlRHJhZ1N0YXJ0ID0gKGV2KSA9PiB7XG4gICAgICAgICAgICB0aGlzLmRyYWdNZXRhID0gdGhpcy5idWlsZERyYWdNZXRhKGV2LnN1YmplY3RFbCk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlSGl0VXBkYXRlID0gKGhpdCwgaXNGaW5hbCwgZXYpID0+IHtcbiAgICAgICAgICAgIGxldCB7IGRyYWdnaW5nIH0gPSB0aGlzLmhpdERyYWdnaW5nO1xuICAgICAgICAgICAgbGV0IHJlY2VpdmluZ0NvbnRleHQgPSBudWxsO1xuICAgICAgICAgICAgbGV0IGRyb3BwYWJsZUV2ZW50ID0gbnVsbDtcbiAgICAgICAgICAgIGxldCBpc0ludmFsaWQgPSBmYWxzZTtcbiAgICAgICAgICAgIGxldCBpbnRlcmFjdGlvbiA9IHtcbiAgICAgICAgICAgICAgICBhZmZlY3RlZEV2ZW50czogY3JlYXRlRW1wdHlFdmVudFN0b3JlKCksXG4gICAgICAgICAgICAgICAgbXV0YXRlZEV2ZW50czogY3JlYXRlRW1wdHlFdmVudFN0b3JlKCksXG4gICAgICAgICAgICAgICAgaXNFdmVudDogdGhpcy5kcmFnTWV0YS5jcmVhdGUsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKGhpdCkge1xuICAgICAgICAgICAgICAgIHJlY2VpdmluZ0NvbnRleHQgPSBoaXQuY29udGV4dDtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5jYW5Ecm9wRWxPbkNhbGVuZGFyKGV2LnN1YmplY3RFbCwgcmVjZWl2aW5nQ29udGV4dCkpIHtcbiAgICAgICAgICAgICAgICAgICAgZHJvcHBhYmxlRXZlbnQgPSBjb21wdXRlRXZlbnRGb3JEYXRlU3BhbihoaXQuZGF0ZVNwYW4sIHRoaXMuZHJhZ01ldGEsIHJlY2VpdmluZ0NvbnRleHQpO1xuICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGlvbi5tdXRhdGVkRXZlbnRzID0gZXZlbnRUdXBsZVRvU3RvcmUoZHJvcHBhYmxlRXZlbnQpO1xuICAgICAgICAgICAgICAgICAgICBpc0ludmFsaWQgPSAhaXNJbnRlcmFjdGlvblZhbGlkKGludGVyYWN0aW9uLCBoaXQuZGF0ZVByb2ZpbGUsIHJlY2VpdmluZ0NvbnRleHQpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoaXNJbnZhbGlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGlvbi5tdXRhdGVkRXZlbnRzID0gY3JlYXRlRW1wdHlFdmVudFN0b3JlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBkcm9wcGFibGVFdmVudCA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmRpc3BsYXlEcmFnKHJlY2VpdmluZ0NvbnRleHQsIGludGVyYWN0aW9uKTtcbiAgICAgICAgICAgIC8vIHNob3cgbWlycm9yIGlmIG5vIGFscmVhZHktcmVuZGVyZWQgbWlycm9yIGVsZW1lbnQgT1IgaWYgd2UgYXJlIHNodXR0aW5nIGRvd24gdGhlIG1pcnJvciAoPylcbiAgICAgICAgICAgIC8vIFRPRE86IHdpc2ggd2UgY291bGQgc29tZWhvdyB3YWl0IGZvciBkaXNwYXRjaCB0byBndWFyYW50ZWUgcmVuZGVyXG4gICAgICAgICAgICBkcmFnZ2luZy5zZXRNaXJyb3JJc1Zpc2libGUoaXNGaW5hbCB8fCAhZHJvcHBhYmxlRXZlbnQgfHwgIWRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5mYy1ldmVudC1taXJyb3InKSk7XG4gICAgICAgICAgICBpZiAoIWlzSW52YWxpZCkge1xuICAgICAgICAgICAgICAgIGVuYWJsZUN1cnNvcigpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgZGlzYWJsZUN1cnNvcigpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFpc0ZpbmFsKSB7XG4gICAgICAgICAgICAgICAgZHJhZ2dpbmcuc2V0TWlycm9yTmVlZHNSZXZlcnQoIWRyb3BwYWJsZUV2ZW50KTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlY2VpdmluZ0NvbnRleHQgPSByZWNlaXZpbmdDb250ZXh0O1xuICAgICAgICAgICAgICAgIHRoaXMuZHJvcHBhYmxlRXZlbnQgPSBkcm9wcGFibGVFdmVudDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVEcmFnRW5kID0gKHBldikgPT4ge1xuICAgICAgICAgICAgbGV0IHsgcmVjZWl2aW5nQ29udGV4dCwgZHJvcHBhYmxlRXZlbnQgfSA9IHRoaXM7XG4gICAgICAgICAgICB0aGlzLmNsZWFyRHJhZygpO1xuICAgICAgICAgICAgaWYgKHJlY2VpdmluZ0NvbnRleHQgJiYgZHJvcHBhYmxlRXZlbnQpIHtcbiAgICAgICAgICAgICAgICBsZXQgZmluYWxIaXQgPSB0aGlzLmhpdERyYWdnaW5nLmZpbmFsSGl0O1xuICAgICAgICAgICAgICAgIGxldCBmaW5hbFZpZXcgPSBmaW5hbEhpdC5jb250ZXh0LnZpZXdBcGk7XG4gICAgICAgICAgICAgICAgbGV0IGRyYWdNZXRhID0gdGhpcy5kcmFnTWV0YTtcbiAgICAgICAgICAgICAgICByZWNlaXZpbmdDb250ZXh0LmVtaXR0ZXIudHJpZ2dlcignZHJvcCcsIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgYnVpbGREYXRlUG9pbnRBcGlXaXRoQ29udGV4dChmaW5hbEhpdC5kYXRlU3BhbiwgcmVjZWl2aW5nQ29udGV4dCkpLCB7IGRyYWdnZWRFbDogcGV2LnN1YmplY3RFbCwganNFdmVudDogcGV2Lm9yaWdFdmVudCwgdmlldzogZmluYWxWaWV3IH0pKTtcbiAgICAgICAgICAgICAgICBpZiAoZHJhZ01ldGEuY3JlYXRlKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBhZGRpbmdFdmVudHMgPSBldmVudFR1cGxlVG9TdG9yZShkcm9wcGFibGVFdmVudCk7XG4gICAgICAgICAgICAgICAgICAgIHJlY2VpdmluZ0NvbnRleHQuZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogJ01FUkdFX0VWRU5UUycsXG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudFN0b3JlOiBhZGRpbmdFdmVudHMsXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBpZiAocGV2LmlzVG91Y2gpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlY2VpdmluZ0NvbnRleHQuZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdTRUxFQ1RfRVZFTlQnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50SW5zdGFuY2VJZDogZHJvcHBhYmxlRXZlbnQuaW5zdGFuY2UuaW5zdGFuY2VJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIC8vIHNpZ25hbCB0aGF0IGFuIGV4dGVybmFsIGV2ZW50IGxhbmRlZFxuICAgICAgICAgICAgICAgICAgICByZWNlaXZpbmdDb250ZXh0LmVtaXR0ZXIudHJpZ2dlcignZXZlbnRSZWNlaXZlJywge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnQ6IG5ldyBFdmVudEltcGwocmVjZWl2aW5nQ29udGV4dCwgZHJvcHBhYmxlRXZlbnQuZGVmLCBkcm9wcGFibGVFdmVudC5pbnN0YW5jZSksXG4gICAgICAgICAgICAgICAgICAgICAgICByZWxhdGVkRXZlbnRzOiBbXSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldmVydCgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNlaXZpbmdDb250ZXh0LmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogJ1JFTU9WRV9FVkVOVFMnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudFN0b3JlOiBhZGRpbmdFdmVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgZHJhZ2dlZEVsOiBwZXYuc3ViamVjdEVsLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmlldzogZmluYWxWaWV3LFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnJlY2VpdmluZ0NvbnRleHQgPSBudWxsO1xuICAgICAgICAgICAgdGhpcy5kcm9wcGFibGVFdmVudCA9IG51bGw7XG4gICAgICAgIH07XG4gICAgICAgIGxldCBoaXREcmFnZ2luZyA9IHRoaXMuaGl0RHJhZ2dpbmcgPSBuZXcgSGl0RHJhZ2dpbmcoZHJhZ2dpbmcsIGludGVyYWN0aW9uU2V0dGluZ3NTdG9yZSk7XG4gICAgICAgIGhpdERyYWdnaW5nLnJlcXVpcmVJbml0aWFsID0gZmFsc2U7IC8vIHdpbGwgc3RhcnQgb3V0c2lkZSBvZiBhIGNvbXBvbmVudFxuICAgICAgICBoaXREcmFnZ2luZy5lbWl0dGVyLm9uKCdkcmFnc3RhcnQnLCB0aGlzLmhhbmRsZURyYWdTdGFydCk7XG4gICAgICAgIGhpdERyYWdnaW5nLmVtaXR0ZXIub24oJ2hpdHVwZGF0ZScsIHRoaXMuaGFuZGxlSGl0VXBkYXRlKTtcbiAgICAgICAgaGl0RHJhZ2dpbmcuZW1pdHRlci5vbignZHJhZ2VuZCcsIHRoaXMuaGFuZGxlRHJhZ0VuZCk7XG4gICAgICAgIHRoaXMuc3VwcGxpZWREcmFnTWV0YSA9IHN1cHBsaWVkRHJhZ01ldGE7XG4gICAgfVxuICAgIGJ1aWxkRHJhZ01ldGEoc3ViamVjdEVsKSB7XG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5zdXBwbGllZERyYWdNZXRhID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgcmV0dXJuIHBhcnNlRHJhZ01ldGEodGhpcy5zdXBwbGllZERyYWdNZXRhKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodHlwZW9mIHRoaXMuc3VwcGxpZWREcmFnTWV0YSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgcmV0dXJuIHBhcnNlRHJhZ01ldGEodGhpcy5zdXBwbGllZERyYWdNZXRhKHN1YmplY3RFbCkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBnZXREcmFnTWV0YUZyb21FbChzdWJqZWN0RWwpO1xuICAgIH1cbiAgICBkaXNwbGF5RHJhZyhuZXh0Q29udGV4dCwgc3RhdGUpIHtcbiAgICAgICAgbGV0IHByZXZDb250ZXh0ID0gdGhpcy5yZWNlaXZpbmdDb250ZXh0O1xuICAgICAgICBpZiAocHJldkNvbnRleHQgJiYgcHJldkNvbnRleHQgIT09IG5leHRDb250ZXh0KSB7XG4gICAgICAgICAgICBwcmV2Q29udGV4dC5kaXNwYXRjaCh7IHR5cGU6ICdVTlNFVF9FVkVOVF9EUkFHJyB9KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobmV4dENvbnRleHQpIHtcbiAgICAgICAgICAgIG5leHRDb250ZXh0LmRpc3BhdGNoKHsgdHlwZTogJ1NFVF9FVkVOVF9EUkFHJywgc3RhdGUgfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgY2xlYXJEcmFnKCkge1xuICAgICAgICBpZiAodGhpcy5yZWNlaXZpbmdDb250ZXh0KSB7XG4gICAgICAgICAgICB0aGlzLnJlY2VpdmluZ0NvbnRleHQuZGlzcGF0Y2goeyB0eXBlOiAnVU5TRVRfRVZFTlRfRFJBRycgfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgY2FuRHJvcEVsT25DYWxlbmRhcihlbCwgcmVjZWl2aW5nQ29udGV4dCkge1xuICAgICAgICBsZXQgZHJvcEFjY2VwdCA9IHJlY2VpdmluZ0NvbnRleHQub3B0aW9ucy5kcm9wQWNjZXB0O1xuICAgICAgICBpZiAodHlwZW9mIGRyb3BBY2NlcHQgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIHJldHVybiBkcm9wQWNjZXB0LmNhbGwocmVjZWl2aW5nQ29udGV4dC5jYWxlbmRhckFwaSwgZWwpO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlb2YgZHJvcEFjY2VwdCA9PT0gJ3N0cmluZycgJiYgZHJvcEFjY2VwdCkge1xuICAgICAgICAgICAgcmV0dXJuIEJvb2xlYW4oZWxlbWVudE1hdGNoZXMoZWwsIGRyb3BBY2NlcHQpKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59XG4vLyBVdGlscyBmb3IgY29tcHV0aW5nIGV2ZW50IHN0b3JlIGZyb20gdGhlIERyYWdNZXRhXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5mdW5jdGlvbiBjb21wdXRlRXZlbnRGb3JEYXRlU3BhbihkYXRlU3BhbiwgZHJhZ01ldGEsIGNvbnRleHQpIHtcbiAgICBsZXQgZGVmUHJvcHMgPSBPYmplY3QuYXNzaWduKHt9LCBkcmFnTWV0YS5sZWZ0b3ZlclByb3BzKTtcbiAgICBmb3IgKGxldCB0cmFuc2Zvcm0gb2YgY29udGV4dC5wbHVnaW5Ib29rcy5leHRlcm5hbERlZlRyYW5zZm9ybXMpIHtcbiAgICAgICAgT2JqZWN0LmFzc2lnbihkZWZQcm9wcywgdHJhbnNmb3JtKGRhdGVTcGFuLCBkcmFnTWV0YSkpO1xuICAgIH1cbiAgICBsZXQgeyByZWZpbmVkLCBleHRyYSB9ID0gcmVmaW5lRXZlbnREZWYoZGVmUHJvcHMsIGNvbnRleHQpO1xuICAgIGxldCBkZWYgPSBwYXJzZUV2ZW50RGVmKHJlZmluZWQsIGV4dHJhLCBkcmFnTWV0YS5zb3VyY2VJZCwgZGF0ZVNwYW4uYWxsRGF5LCBjb250ZXh0Lm9wdGlvbnMuZm9yY2VFdmVudER1cmF0aW9uIHx8IEJvb2xlYW4oZHJhZ01ldGEuZHVyYXRpb24pLCAvLyBoYXNFbmRcbiAgICBjb250ZXh0KTtcbiAgICBsZXQgc3RhcnQgPSBkYXRlU3Bhbi5yYW5nZS5zdGFydDtcbiAgICAvLyBvbmx5IHJlbHkgb24gdGltZSBpbmZvIGlmIGRyb3Agem9uZSBpcyBhbGwtZGF5LFxuICAgIC8vIG90aGVyd2lzZSwgd2UgYWxyZWFkeSBrbm93IHRoZSB0aW1lXG4gICAgaWYgKGRhdGVTcGFuLmFsbERheSAmJiBkcmFnTWV0YS5zdGFydFRpbWUpIHtcbiAgICAgICAgc3RhcnQgPSBjb250ZXh0LmRhdGVFbnYuYWRkKHN0YXJ0LCBkcmFnTWV0YS5zdGFydFRpbWUpO1xuICAgIH1cbiAgICBsZXQgZW5kID0gZHJhZ01ldGEuZHVyYXRpb24gP1xuICAgICAgICBjb250ZXh0LmRhdGVFbnYuYWRkKHN0YXJ0LCBkcmFnTWV0YS5kdXJhdGlvbikgOlxuICAgICAgICBnZXREZWZhdWx0RXZlbnRFbmQoZGF0ZVNwYW4uYWxsRGF5LCBzdGFydCwgY29udGV4dCk7XG4gICAgbGV0IGluc3RhbmNlID0gY3JlYXRlRXZlbnRJbnN0YW5jZShkZWYuZGVmSWQsIHsgc3RhcnQsIGVuZCB9KTtcbiAgICByZXR1cm4geyBkZWYsIGluc3RhbmNlIH07XG59XG4vLyBVdGlscyBmb3IgZXh0cmFjdGluZyBkYXRhIGZyb20gZWxlbWVudFxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuZnVuY3Rpb24gZ2V0RHJhZ01ldGFGcm9tRWwoZWwpIHtcbiAgICBsZXQgc3RyID0gZ2V0RW1iZWRkZWRFbERhdGEoZWwsICdldmVudCcpO1xuICAgIGxldCBvYmogPSBzdHIgP1xuICAgICAgICBKU09OLnBhcnNlKHN0cikgOlxuICAgICAgICB7IGNyZWF0ZTogZmFsc2UgfTsgLy8gaWYgbm8gZW1iZWRkZWQgZGF0YSwgYXNzdW1lIG5vIGV2ZW50IGNyZWF0aW9uXG4gICAgcmV0dXJuIHBhcnNlRHJhZ01ldGEob2JqKTtcbn1cbmNvbmZpZy5kYXRhQXR0clByZWZpeCA9ICcnO1xuZnVuY3Rpb24gZ2V0RW1iZWRkZWRFbERhdGEoZWwsIG5hbWUpIHtcbiAgICBsZXQgcHJlZml4ID0gY29uZmlnLmRhdGFBdHRyUHJlZml4O1xuICAgIGxldCBwcmVmaXhlZE5hbWUgPSAocHJlZml4ID8gcHJlZml4ICsgJy0nIDogJycpICsgbmFtZTtcbiAgICByZXR1cm4gZWwuZ2V0QXR0cmlidXRlKCdkYXRhLScgKyBwcmVmaXhlZE5hbWUpIHx8ICcnO1xufVxuXG4vKlxuTWFrZXMgYW4gZWxlbWVudCAodGhhdCBpcyAqZXh0ZXJuYWwqIHRvIGFueSBjYWxlbmRhcikgZHJhZ2dhYmxlLlxuQ2FuIHBhc3MgaW4gZGF0YSB0aGF0IGRldGVybWluZXMgaG93IGFuIGV2ZW50IHdpbGwgYmUgY3JlYXRlZCB3aGVuIGRyb3BwZWQgb250byBhIGNhbGVuZGFyLlxuTGV2ZXJhZ2VzIEZ1bGxDYWxlbmRhcidzIGludGVybmFsIGRyYWctbi1kcm9wIGZ1bmN0aW9uYWxpdHkgV0lUSE9VVCBhIHRoaXJkLXBhcnR5IGRyYWcgc3lzdGVtLlxuKi9cbmNsYXNzIEV4dGVybmFsRHJhZ2dhYmxlIHtcbiAgICBjb25zdHJ1Y3RvcihlbCwgc2V0dGluZ3MgPSB7fSkge1xuICAgICAgICB0aGlzLmhhbmRsZVBvaW50ZXJEb3duID0gKGV2KSA9PiB7XG4gICAgICAgICAgICBsZXQgeyBkcmFnZ2luZyB9ID0gdGhpcztcbiAgICAgICAgICAgIGxldCB7IG1pbkRpc3RhbmNlLCBsb25nUHJlc3NEZWxheSB9ID0gdGhpcy5zZXR0aW5ncztcbiAgICAgICAgICAgIGRyYWdnaW5nLm1pbkRpc3RhbmNlID1cbiAgICAgICAgICAgICAgICBtaW5EaXN0YW5jZSAhPSBudWxsID9cbiAgICAgICAgICAgICAgICAgICAgbWluRGlzdGFuY2UgOlxuICAgICAgICAgICAgICAgICAgICAoZXYuaXNUb3VjaCA/IDAgOiBCQVNFX09QVElPTl9ERUZBVUxUUy5ldmVudERyYWdNaW5EaXN0YW5jZSk7XG4gICAgICAgICAgICBkcmFnZ2luZy5kZWxheSA9XG4gICAgICAgICAgICAgICAgZXYuaXNUb3VjaCA/IC8vIFRPRE86IGV2ZW50dWFsbHkgcmVhZCBldmVudExvbmdQcmVzc0RlbGF5IGluc3RlYWQgdnZ2XG4gICAgICAgICAgICAgICAgICAgIChsb25nUHJlc3NEZWxheSAhPSBudWxsID8gbG9uZ1ByZXNzRGVsYXkgOiBCQVNFX09QVElPTl9ERUZBVUxUUy5sb25nUHJlc3NEZWxheSkgOlxuICAgICAgICAgICAgICAgICAgICAwO1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZURyYWdTdGFydCA9IChldikgPT4ge1xuICAgICAgICAgICAgaWYgKGV2LmlzVG91Y2ggJiZcbiAgICAgICAgICAgICAgICB0aGlzLmRyYWdnaW5nLmRlbGF5ICYmXG4gICAgICAgICAgICAgICAgZXYuc3ViamVjdEVsLmNsYXNzTGlzdC5jb250YWlucygnZmMtZXZlbnQnKSkge1xuICAgICAgICAgICAgICAgIHRoaXMuZHJhZ2dpbmcubWlycm9yLmdldE1pcnJvckVsKCkuY2xhc3NMaXN0LmFkZCgnZmMtZXZlbnQtc2VsZWN0ZWQnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5zZXR0aW5ncyA9IHNldHRpbmdzO1xuICAgICAgICBsZXQgZHJhZ2dpbmcgPSB0aGlzLmRyYWdnaW5nID0gbmV3IEZlYXR1cmVmdWxFbGVtZW50RHJhZ2dpbmcoZWwpO1xuICAgICAgICBkcmFnZ2luZy50b3VjaFNjcm9sbEFsbG93ZWQgPSBmYWxzZTtcbiAgICAgICAgaWYgKHNldHRpbmdzLml0ZW1TZWxlY3RvciAhPSBudWxsKSB7XG4gICAgICAgICAgICBkcmFnZ2luZy5wb2ludGVyLnNlbGVjdG9yID0gc2V0dGluZ3MuaXRlbVNlbGVjdG9yO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzZXR0aW5ncy5hcHBlbmRUbyAhPSBudWxsKSB7XG4gICAgICAgICAgICBkcmFnZ2luZy5taXJyb3IucGFyZW50Tm9kZSA9IHNldHRpbmdzLmFwcGVuZFRvOyAvLyBUT0RPOiB3cml0ZSB0ZXN0c1xuICAgICAgICB9XG4gICAgICAgIGRyYWdnaW5nLmVtaXR0ZXIub24oJ3BvaW50ZXJkb3duJywgdGhpcy5oYW5kbGVQb2ludGVyRG93bik7XG4gICAgICAgIGRyYWdnaW5nLmVtaXR0ZXIub24oJ2RyYWdzdGFydCcsIHRoaXMuaGFuZGxlRHJhZ1N0YXJ0KTtcbiAgICAgICAgbmV3IEV4dGVybmFsRWxlbWVudERyYWdnaW5nKGRyYWdnaW5nLCBzZXR0aW5ncy5ldmVudERhdGEpOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLW5ld1xuICAgIH1cbiAgICBkZXN0cm95KCkge1xuICAgICAgICB0aGlzLmRyYWdnaW5nLmRlc3Ryb3koKTtcbiAgICB9XG59XG5cbi8qXG5EZXRlY3RzIHdoZW4gYSAqVEhJUkQtUEFSVFkqIGRyYWctbi1kcm9wIHN5c3RlbSBpbnRlcmFjdHMgd2l0aCBlbGVtZW50cy5cblRoZSB0aGlyZC1wYXJ0eSBzeXN0ZW0gaXMgcmVzcG9uc2libGUgZm9yIGRyYXdpbmcgdGhlIHZpc3VhbHMgZWZmZWN0cyBvZiB0aGUgZHJhZy5cblRoaXMgY2xhc3Mgc2ltcGx5IG1vbml0b3JzIGZvciBwb2ludGVyIG1vdmVtZW50cyBhbmQgZmlyZXMgZXZlbnRzLlxuSXQgYWxzbyBoYXMgdGhlIGFiaWxpdHkgdG8gaGlkZSB0aGUgbW92aW5nIGVsZW1lbnQgKHRoZSBcIm1pcnJvclwiKSBkdXJpbmcgdGhlIGRyYWcuXG4qL1xuY2xhc3MgSW5mZXJyZWRFbGVtZW50RHJhZ2dpbmcgZXh0ZW5kcyBFbGVtZW50RHJhZ2dpbmcge1xuICAgIGNvbnN0cnVjdG9yKGNvbnRhaW5lckVsKSB7XG4gICAgICAgIHN1cGVyKGNvbnRhaW5lckVsKTtcbiAgICAgICAgdGhpcy5zaG91bGRJZ25vcmVNb3ZlID0gZmFsc2U7XG4gICAgICAgIHRoaXMubWlycm9yU2VsZWN0b3IgPSAnJztcbiAgICAgICAgdGhpcy5jdXJyZW50TWlycm9yRWwgPSBudWxsO1xuICAgICAgICB0aGlzLmhhbmRsZVBvaW50ZXJEb3duID0gKGV2KSA9PiB7XG4gICAgICAgICAgICB0aGlzLmVtaXR0ZXIudHJpZ2dlcigncG9pbnRlcmRvd24nLCBldik7XG4gICAgICAgICAgICBpZiAoIXRoaXMuc2hvdWxkSWdub3JlTW92ZSkge1xuICAgICAgICAgICAgICAgIC8vIGZpcmUgZHJhZ3N0YXJ0IHJpZ2h0IGF3YXkuIGRvZXMgbm90IHN1cHBvcnQgZGVsYXkgb3IgbWluLWRpc3RhbmNlXG4gICAgICAgICAgICAgICAgdGhpcy5lbWl0dGVyLnRyaWdnZXIoJ2RyYWdzdGFydCcsIGV2KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVQb2ludGVyTW92ZSA9IChldikgPT4ge1xuICAgICAgICAgICAgaWYgKCF0aGlzLnNob3VsZElnbm9yZU1vdmUpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVtaXR0ZXIudHJpZ2dlcignZHJhZ21vdmUnLCBldik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlUG9pbnRlclVwID0gKGV2KSA9PiB7XG4gICAgICAgICAgICB0aGlzLmVtaXR0ZXIudHJpZ2dlcigncG9pbnRlcnVwJywgZXYpO1xuICAgICAgICAgICAgaWYgKCF0aGlzLnNob3VsZElnbm9yZU1vdmUpIHtcbiAgICAgICAgICAgICAgICAvLyBmaXJlIGRyYWdlbmQgcmlnaHQgYXdheS4gZG9lcyBub3Qgc3VwcG9ydCBhIHJldmVydCBhbmltYXRpb25cbiAgICAgICAgICAgICAgICB0aGlzLmVtaXR0ZXIudHJpZ2dlcignZHJhZ2VuZCcsIGV2KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgbGV0IHBvaW50ZXIgPSB0aGlzLnBvaW50ZXIgPSBuZXcgUG9pbnRlckRyYWdnaW5nKGNvbnRhaW5lckVsKTtcbiAgICAgICAgcG9pbnRlci5lbWl0dGVyLm9uKCdwb2ludGVyZG93bicsIHRoaXMuaGFuZGxlUG9pbnRlckRvd24pO1xuICAgICAgICBwb2ludGVyLmVtaXR0ZXIub24oJ3BvaW50ZXJtb3ZlJywgdGhpcy5oYW5kbGVQb2ludGVyTW92ZSk7XG4gICAgICAgIHBvaW50ZXIuZW1pdHRlci5vbigncG9pbnRlcnVwJywgdGhpcy5oYW5kbGVQb2ludGVyVXApO1xuICAgIH1cbiAgICBkZXN0cm95KCkge1xuICAgICAgICB0aGlzLnBvaW50ZXIuZGVzdHJveSgpO1xuICAgIH1cbiAgICBzZXRJZ25vcmVNb3ZlKGJvb2wpIHtcbiAgICAgICAgdGhpcy5zaG91bGRJZ25vcmVNb3ZlID0gYm9vbDtcbiAgICB9XG4gICAgc2V0TWlycm9ySXNWaXNpYmxlKGJvb2wpIHtcbiAgICAgICAgaWYgKGJvb2wpIHtcbiAgICAgICAgICAgIC8vIHJlc3RvcmUgYSBwcmV2aW91c2x5IGhpZGRlbiBlbGVtZW50LlxuICAgICAgICAgICAgLy8gdXNlIHRoZSByZWZlcmVuY2UgaW4gY2FzZSB0aGUgc2VsZWN0b3IgY2xhc3MgaGFzIGFscmVhZHkgYmVlbiByZW1vdmVkLlxuICAgICAgICAgICAgaWYgKHRoaXMuY3VycmVudE1pcnJvckVsKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jdXJyZW50TWlycm9yRWwuc3R5bGUudmlzaWJpbGl0eSA9ICcnO1xuICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudE1pcnJvckVsID0gbnVsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGxldCBtaXJyb3JFbCA9IHRoaXMubWlycm9yU2VsZWN0b3JcbiAgICAgICAgICAgICAgICAvLyBUT0RPOiBzb21laG93IHF1ZXJ5IEZ1bGxDYWxlbmRhcnMgV0lUSElOIHNoYWRvdy1yb290c1xuICAgICAgICAgICAgICAgID8gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLm1pcnJvclNlbGVjdG9yKVxuICAgICAgICAgICAgICAgIDogbnVsbDtcbiAgICAgICAgICAgIGlmIChtaXJyb3JFbCkge1xuICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudE1pcnJvckVsID0gbWlycm9yRWw7XG4gICAgICAgICAgICAgICAgbWlycm9yRWwuc3R5bGUudmlzaWJpbGl0eSA9ICdoaWRkZW4nO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuXG4vKlxuQnJpZGdlcyB0aGlyZC1wYXJ0eSBkcmFnLW4tZHJvcCBzeXN0ZW1zIHdpdGggRnVsbENhbGVuZGFyLlxuTXVzdCBiZSBpbnN0YW50aWF0ZWQgYW5kIGRlc3Ryb3llZCBieSBjYWxsZXIuXG4qL1xuY2xhc3MgVGhpcmRQYXJ0eURyYWdnYWJsZSB7XG4gICAgY29uc3RydWN0b3IoY29udGFpbmVyT3JTZXR0aW5ncywgc2V0dGluZ3MpIHtcbiAgICAgICAgbGV0IGNvbnRhaW5lckVsID0gZG9jdW1lbnQ7XG4gICAgICAgIGlmIChcbiAgICAgICAgLy8gd2lzaCB3ZSBjb3VsZCBqdXN0IHRlc3QgaW5zdGFuY2VvZiBFdmVudFRhcmdldCwgYnV0IGRvZXNuJ3Qgd29yayBpbiBJRTExXG4gICAgICAgIGNvbnRhaW5lck9yU2V0dGluZ3MgPT09IGRvY3VtZW50IHx8XG4gICAgICAgICAgICBjb250YWluZXJPclNldHRpbmdzIGluc3RhbmNlb2YgRWxlbWVudCkge1xuICAgICAgICAgICAgY29udGFpbmVyRWwgPSBjb250YWluZXJPclNldHRpbmdzO1xuICAgICAgICAgICAgc2V0dGluZ3MgPSBzZXR0aW5ncyB8fCB7fTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHNldHRpbmdzID0gKGNvbnRhaW5lck9yU2V0dGluZ3MgfHwge30pO1xuICAgICAgICB9XG4gICAgICAgIGxldCBkcmFnZ2luZyA9IHRoaXMuZHJhZ2dpbmcgPSBuZXcgSW5mZXJyZWRFbGVtZW50RHJhZ2dpbmcoY29udGFpbmVyRWwpO1xuICAgICAgICBpZiAodHlwZW9mIHNldHRpbmdzLml0ZW1TZWxlY3RvciA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIGRyYWdnaW5nLnBvaW50ZXIuc2VsZWN0b3IgPSBzZXR0aW5ncy5pdGVtU2VsZWN0b3I7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoY29udGFpbmVyRWwgPT09IGRvY3VtZW50KSB7XG4gICAgICAgICAgICBkcmFnZ2luZy5wb2ludGVyLnNlbGVjdG9yID0gJ1tkYXRhLWV2ZW50XSc7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHR5cGVvZiBzZXR0aW5ncy5taXJyb3JTZWxlY3RvciA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIGRyYWdnaW5nLm1pcnJvclNlbGVjdG9yID0gc2V0dGluZ3MubWlycm9yU2VsZWN0b3I7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGV4dGVybmFsRHJhZ2dpbmcgPSBuZXcgRXh0ZXJuYWxFbGVtZW50RHJhZ2dpbmcoZHJhZ2dpbmcsIHNldHRpbmdzLmV2ZW50RGF0YSk7XG4gICAgICAgIC8vIFRoZSBoaXQtZGV0ZWN0aW9uIHN5c3RlbSByZXF1aXJlcyB0aGF0IHRoZSBkbmQtbWlycm9yLWVsZW1lbnQgYmUgcG9pbnRlci1ldmVudHM6bm9uZSxcbiAgICAgICAgLy8gYnV0IHRoaXMgY2FuJ3QgYmUgZ3VhcmFudGVlZCBmb3IgdGhpcmQtcGFydHkgZHJhZ2dhYmxlcywgc28gZGlzYWJsZVxuICAgICAgICBleHRlcm5hbERyYWdnaW5nLmhpdERyYWdnaW5nLmRpc2FibGVQb2ludENoZWNrID0gdHJ1ZTtcbiAgICB9XG4gICAgZGVzdHJveSgpIHtcbiAgICAgICAgdGhpcy5kcmFnZ2luZy5kZXN0cm95KCk7XG4gICAgfVxufVxuXG52YXIgaW5kZXggPSBjcmVhdGVQbHVnaW4oe1xuICAgIG5hbWU6ICdAZnVsbGNhbGVuZGFyL2ludGVyYWN0aW9uJyxcbiAgICBjb21wb25lbnRJbnRlcmFjdGlvbnM6IFtEYXRlQ2xpY2tpbmcsIERhdGVTZWxlY3RpbmcsIEV2ZW50RHJhZ2dpbmcsIEV2ZW50UmVzaXppbmddLFxuICAgIGNhbGVuZGFySW50ZXJhY3Rpb25zOiBbVW5zZWxlY3RBdXRvXSxcbiAgICBlbGVtZW50RHJhZ2dpbmdJbXBsOiBGZWF0dXJlZnVsRWxlbWVudERyYWdnaW5nLFxuICAgIG9wdGlvblJlZmluZXJzOiBPUFRJT05fUkVGSU5FUlMsXG4gICAgbGlzdGVuZXJSZWZpbmVyczogTElTVEVORVJfUkVGSU5FUlMsXG59KTtcblxuZXhwb3J0IHsgRXh0ZXJuYWxEcmFnZ2FibGUgYXMgRHJhZ2dhYmxlLCBUaGlyZFBhcnR5RHJhZ2dhYmxlLCBpbmRleCBhcyBkZWZhdWx0IH07XG4iXSwibmFtZXMiOltdLCJpZ25vcmVMaXN0IjpbMF0sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///(ssr)/./node_modules/@fullcalendar/interaction/index.js\n");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "(ssr)/./node_modules/@fullcalendar/timegrid/index.js":
|
|
/*!******************************************************!*\
|
|
!*** ./node_modules/@fullcalendar/timegrid/index.js ***!
|
|
\******************************************************/
|
|
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
|
|
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ index)\n/* harmony export */ });\n/* harmony import */ var _fullcalendar_core_index_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @fullcalendar/core/index.js */ \"(ssr)/./node_modules/@fullcalendar/core/index.js\");\n/* harmony import */ var _internal_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./internal.js */ \"(ssr)/./node_modules/@fullcalendar/timegrid/internal.js\");\n\n\n\n\n\n\nconst OPTION_REFINERS = {\n allDaySlot: Boolean,\n};\n\nvar index = (0,_fullcalendar_core_index_js__WEBPACK_IMPORTED_MODULE_0__.createPlugin)({\n name: '@fullcalendar/timegrid',\n initialView: 'timeGridWeek',\n optionRefiners: OPTION_REFINERS,\n views: {\n timeGrid: {\n component: _internal_js__WEBPACK_IMPORTED_MODULE_1__.DayTimeColsView,\n usesMinMaxTime: true,\n allDaySlot: true,\n slotDuration: '00:30:00',\n slotEventOverlap: true, // a bad name. confused with overlap/constraint system\n },\n timeGridDay: {\n type: 'timeGrid',\n duration: { days: 1 },\n },\n timeGridWeek: {\n type: 'timeGrid',\n duration: { weeks: 1 },\n },\n },\n});\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKHNzcikvLi9ub2RlX21vZHVsZXMvQGZ1bGxjYWxlbmRhci90aW1lZ3JpZC9pbmRleC5qcyIsIm1hcHBpbmdzIjoiOzs7Ozs7QUFBMkQ7QUFDWDtBQUNSO0FBQ0Y7QUFDSzs7QUFFM0M7QUFDQTtBQUNBOztBQUVBLFlBQVkseUVBQVk7QUFDeEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVCQUF1Qix5REFBZTtBQUN0QztBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0Esd0JBQXdCLFNBQVM7QUFDakMsU0FBUztBQUNUO0FBQ0E7QUFDQSx3QkFBd0IsVUFBVTtBQUNsQyxTQUFTO0FBQ1QsS0FBSztBQUNMLENBQUM7O0FBRTJCIiwic291cmNlcyI6WyIvaG9tZS9zaWx2aW8vRGV2ZWxvcC9DSVJVWC1BUFAvbm9kZV9tb2R1bGVzL0BmdWxsY2FsZW5kYXIvdGltZWdyaWQvaW5kZXguanMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgY3JlYXRlUGx1Z2luIH0gZnJvbSAnQGZ1bGxjYWxlbmRhci9jb3JlL2luZGV4LmpzJztcbmltcG9ydCB7IERheVRpbWVDb2xzVmlldyB9IGZyb20gJy4vaW50ZXJuYWwuanMnO1xuaW1wb3J0ICdAZnVsbGNhbGVuZGFyL2NvcmUvaW50ZXJuYWwuanMnO1xuaW1wb3J0ICdAZnVsbGNhbGVuZGFyL2NvcmUvcHJlYWN0LmpzJztcbmltcG9ydCAnQGZ1bGxjYWxlbmRhci9kYXlncmlkL2ludGVybmFsLmpzJztcblxuY29uc3QgT1BUSU9OX1JFRklORVJTID0ge1xuICAgIGFsbERheVNsb3Q6IEJvb2xlYW4sXG59O1xuXG52YXIgaW5kZXggPSBjcmVhdGVQbHVnaW4oe1xuICAgIG5hbWU6ICdAZnVsbGNhbGVuZGFyL3RpbWVncmlkJyxcbiAgICBpbml0aWFsVmlldzogJ3RpbWVHcmlkV2VlaycsXG4gICAgb3B0aW9uUmVmaW5lcnM6IE9QVElPTl9SRUZJTkVSUyxcbiAgICB2aWV3czoge1xuICAgICAgICB0aW1lR3JpZDoge1xuICAgICAgICAgICAgY29tcG9uZW50OiBEYXlUaW1lQ29sc1ZpZXcsXG4gICAgICAgICAgICB1c2VzTWluTWF4VGltZTogdHJ1ZSxcbiAgICAgICAgICAgIGFsbERheVNsb3Q6IHRydWUsXG4gICAgICAgICAgICBzbG90RHVyYXRpb246ICcwMDozMDowMCcsXG4gICAgICAgICAgICBzbG90RXZlbnRPdmVybGFwOiB0cnVlLCAvLyBhIGJhZCBuYW1lLiBjb25mdXNlZCB3aXRoIG92ZXJsYXAvY29uc3RyYWludCBzeXN0ZW1cbiAgICAgICAgfSxcbiAgICAgICAgdGltZUdyaWREYXk6IHtcbiAgICAgICAgICAgIHR5cGU6ICd0aW1lR3JpZCcsXG4gICAgICAgICAgICBkdXJhdGlvbjogeyBkYXlzOiAxIH0sXG4gICAgICAgIH0sXG4gICAgICAgIHRpbWVHcmlkV2Vlazoge1xuICAgICAgICAgICAgdHlwZTogJ3RpbWVHcmlkJyxcbiAgICAgICAgICAgIGR1cmF0aW9uOiB7IHdlZWtzOiAxIH0sXG4gICAgICAgIH0sXG4gICAgfSxcbn0pO1xuXG5leHBvcnQgeyBpbmRleCBhcyBkZWZhdWx0IH07XG4iXSwibmFtZXMiOltdLCJpZ25vcmVMaXN0IjpbMF0sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///(ssr)/./node_modules/@fullcalendar/timegrid/index.js\n");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "(ssr)/./node_modules/@fullcalendar/timegrid/internal.js":
|
|
/*!*********************************************************!*\
|
|
!*** ./node_modules/@fullcalendar/timegrid/internal.js ***!
|
|
\*********************************************************/
|
|
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
|
|
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ DayTimeCols: () => (/* binding */ DayTimeCols),\n/* harmony export */ DayTimeColsSlicer: () => (/* binding */ DayTimeColsSlicer),\n/* harmony export */ DayTimeColsView: () => (/* binding */ DayTimeColsView),\n/* harmony export */ TimeCols: () => (/* binding */ TimeCols),\n/* harmony export */ TimeColsSlatsCoords: () => (/* binding */ TimeColsSlatsCoords),\n/* harmony export */ TimeColsView: () => (/* binding */ TimeColsView),\n/* harmony export */ buildDayRanges: () => (/* binding */ buildDayRanges),\n/* harmony export */ buildSlatMetas: () => (/* binding */ buildSlatMetas),\n/* harmony export */ buildTimeColsModel: () => (/* binding */ buildTimeColsModel)\n/* harmony export */ });\n/* harmony import */ var _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @fullcalendar/core/internal.js */ \"(ssr)/./node_modules/@fullcalendar/core/internal-common.js\");\n/* harmony import */ var _fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @fullcalendar/core/preact.js */ \"(ssr)/./node_modules/preact/dist/preact.mjs\");\n/* harmony import */ var _fullcalendar_daygrid_internal_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @fullcalendar/daygrid/internal.js */ \"(ssr)/./node_modules/@fullcalendar/daygrid/internal.js\");\n\n\n\n\nclass AllDaySplitter extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.aW {\n getKeyInfo() {\n return {\n allDay: {},\n timed: {},\n };\n }\n getKeysForDateSpan(dateSpan) {\n if (dateSpan.allDay) {\n return ['allDay'];\n }\n return ['timed'];\n }\n getKeysForEventDef(eventDef) {\n if (!eventDef.allDay) {\n return ['timed'];\n }\n if ((0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bN)(eventDef)) {\n return ['timed', 'allDay'];\n }\n return ['allDay'];\n }\n}\n\nconst DEFAULT_SLAT_LABEL_FORMAT = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.x)({\n hour: 'numeric',\n minute: '2-digit',\n omitZeroMinute: true,\n meridiem: 'short',\n});\nfunction TimeColsAxisCell(props) {\n let classNames = [\n 'fc-timegrid-slot',\n 'fc-timegrid-slot-label',\n props.isLabeled ? 'fc-scrollgrid-shrink' : 'fc-timegrid-slot-minor',\n ];\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.V.Consumer, null, (context) => {\n if (!props.isLabeled) {\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"td\", { className: classNames.join(' '), \"data-time\": props.isoTimeStr }));\n }\n let { dateEnv, options, viewApi } = context;\n let labelFormat = // TODO: fully pre-parse\n options.slotLabelFormat == null ? DEFAULT_SLAT_LABEL_FORMAT :\n Array.isArray(options.slotLabelFormat) ? (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.x)(options.slotLabelFormat[0]) :\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.x)(options.slotLabelFormat);\n let renderProps = {\n level: 0,\n time: props.time,\n date: dateEnv.toDate(props.date),\n view: viewApi,\n text: dateEnv.format(props.date, labelFormat),\n };\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.C, { elTag: \"td\", elClasses: classNames, elAttrs: {\n 'data-time': props.isoTimeStr,\n }, renderProps: renderProps, generatorName: \"slotLabelContent\", customGenerator: options.slotLabelContent, defaultGenerator: renderInnerContent, classNameGenerator: options.slotLabelClassNames, didMount: options.slotLabelDidMount, willUnmount: options.slotLabelWillUnmount }, (InnerContent) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-timegrid-slot-label-frame fc-scrollgrid-shrink-frame\" },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(InnerContent, { elTag: \"div\", elClasses: [\n 'fc-timegrid-slot-label-cushion',\n 'fc-scrollgrid-shrink-cushion',\n ] })))));\n }));\n}\nfunction renderInnerContent(props) {\n return props.text;\n}\n\nclass TimeBodyAxis extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.B {\n render() {\n return this.props.slatMetas.map((slatMeta) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"tr\", { key: slatMeta.key },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TimeColsAxisCell, Object.assign({}, slatMeta)))));\n }\n}\n\nconst DEFAULT_WEEK_NUM_FORMAT = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.x)({ week: 'short' });\nconst AUTO_ALL_DAY_MAX_EVENT_ROWS = 5;\nclass TimeColsView extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bc {\n constructor() {\n super(...arguments);\n this.allDaySplitter = new AllDaySplitter(); // for use by subclasses\n this.headerElRef = (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createRef)();\n this.rootElRef = (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createRef)();\n this.scrollerElRef = (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createRef)();\n this.state = {\n slatCoords: null,\n };\n this.handleScrollTopRequest = (scrollTop) => {\n let scrollerEl = this.scrollerElRef.current;\n if (scrollerEl) { // TODO: not sure how this could ever be null. weirdness with the reducer\n scrollerEl.scrollTop = scrollTop;\n }\n };\n /* Header Render Methods\n ------------------------------------------------------------------------------------------------------------------*/\n this.renderHeadAxis = (rowKey, frameHeight = '') => {\n let { options } = this.context;\n let { dateProfile } = this.props;\n let range = dateProfile.renderRange;\n let dayCnt = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bj)(range.start, range.end);\n // only do in day views (to avoid doing in week views that dont need it)\n let navLinkAttrs = (dayCnt === 1)\n ? (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.a_)(this.context, range.start, 'week')\n : {};\n if (options.weekNumbers && rowKey === 'day') {\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cn, { elTag: \"th\", elClasses: [\n 'fc-timegrid-axis',\n 'fc-scrollgrid-shrink',\n ], elAttrs: {\n 'aria-hidden': true,\n }, date: range.start, defaultFormat: DEFAULT_WEEK_NUM_FORMAT }, (InnerContent) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: [\n 'fc-timegrid-axis-frame',\n 'fc-scrollgrid-shrink-frame',\n 'fc-timegrid-axis-frame-liquid',\n ].join(' '), style: { height: frameHeight } },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(InnerContent, { elTag: \"a\", elClasses: [\n 'fc-timegrid-axis-cushion',\n 'fc-scrollgrid-shrink-cushion',\n 'fc-scrollgrid-sync-inner',\n ], elAttrs: navLinkAttrs })))));\n }\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"th\", { \"aria-hidden\": true, className: \"fc-timegrid-axis\" },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-timegrid-axis-frame\", style: { height: frameHeight } })));\n };\n /* Table Component Render Methods\n ------------------------------------------------------------------------------------------------------------------*/\n // only a one-way height sync. we don't send the axis inner-content height to the DayGrid,\n // but DayGrid still needs to have classNames on inner elements in order to measure.\n this.renderTableRowAxis = (rowHeight) => {\n let { options, viewApi } = this.context;\n let renderProps = {\n text: options.allDayText,\n view: viewApi,\n };\n return (\n // TODO: make reusable hook. used in list view too\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.C, { elTag: \"td\", elClasses: [\n 'fc-timegrid-axis',\n 'fc-scrollgrid-shrink',\n ], elAttrs: {\n 'aria-hidden': true,\n }, renderProps: renderProps, generatorName: \"allDayContent\", customGenerator: options.allDayContent, defaultGenerator: renderAllDayInner, classNameGenerator: options.allDayClassNames, didMount: options.allDayDidMount, willUnmount: options.allDayWillUnmount }, (InnerContent) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: [\n 'fc-timegrid-axis-frame',\n 'fc-scrollgrid-shrink-frame',\n rowHeight == null ? ' fc-timegrid-axis-frame-liquid' : '',\n ].join(' '), style: { height: rowHeight } },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(InnerContent, { elTag: \"span\", elClasses: [\n 'fc-timegrid-axis-cushion',\n 'fc-scrollgrid-shrink-cushion',\n 'fc-scrollgrid-sync-inner',\n ] })))));\n };\n this.handleSlatCoords = (slatCoords) => {\n this.setState({ slatCoords });\n };\n }\n // rendering\n // ----------------------------------------------------------------------------------------------------\n renderSimpleLayout(headerRowContent, allDayContent, timeContent) {\n let { context, props } = this;\n let sections = [];\n let stickyHeaderDates = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ca)(context.options);\n if (headerRowContent) {\n sections.push({\n type: 'header',\n key: 'header',\n isSticky: stickyHeaderDates,\n chunk: {\n elRef: this.headerElRef,\n tableClassName: 'fc-col-header',\n rowContent: headerRowContent,\n },\n });\n }\n if (allDayContent) {\n sections.push({\n type: 'body',\n key: 'all-day',\n chunk: { content: allDayContent },\n });\n sections.push({\n type: 'body',\n key: 'all-day-divider',\n outerContent: ( // TODO: rename to cellContent so don't need to define <tr>?\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"tr\", { role: \"presentation\", className: \"fc-scrollgrid-section\" },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"td\", { className: 'fc-timegrid-divider ' + context.theme.getClass('tableCellShaded') }))),\n });\n }\n sections.push({\n type: 'body',\n key: 'body',\n liquid: true,\n expandRows: Boolean(context.options.expandRows),\n chunk: {\n scrollerElRef: this.scrollerElRef,\n content: timeContent,\n },\n });\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cq, { elRef: this.rootElRef, elClasses: ['fc-timegrid'], viewSpec: context.viewSpec },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bZ, { liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: props.forPrint, cols: [{ width: 'shrink' }], sections: sections })));\n }\n renderHScrollLayout(headerRowContent, allDayContent, timeContent, colCnt, dayMinWidth, slatMetas, slatCoords) {\n let ScrollGrid = this.context.pluginHooks.scrollGridImpl;\n if (!ScrollGrid) {\n throw new Error('No ScrollGrid implementation');\n }\n let { context, props } = this;\n let stickyHeaderDates = !props.forPrint && (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ca)(context.options);\n let stickyFooterScrollbar = !props.forPrint && (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.c9)(context.options);\n let sections = [];\n if (headerRowContent) {\n sections.push({\n type: 'header',\n key: 'header',\n isSticky: stickyHeaderDates,\n syncRowHeights: true,\n chunks: [\n {\n key: 'axis',\n rowContent: (arg) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"tr\", { role: \"presentation\" }, this.renderHeadAxis('day', arg.rowSyncHeights[0]))),\n },\n {\n key: 'cols',\n elRef: this.headerElRef,\n tableClassName: 'fc-col-header',\n rowContent: headerRowContent,\n },\n ],\n });\n }\n if (allDayContent) {\n sections.push({\n type: 'body',\n key: 'all-day',\n syncRowHeights: true,\n chunks: [\n {\n key: 'axis',\n rowContent: (contentArg) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"tr\", { role: \"presentation\" }, this.renderTableRowAxis(contentArg.rowSyncHeights[0]))),\n },\n {\n key: 'cols',\n content: allDayContent,\n },\n ],\n });\n sections.push({\n key: 'all-day-divider',\n type: 'body',\n outerContent: ( // TODO: rename to cellContent so don't need to define <tr>?\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"tr\", { role: \"presentation\", className: \"fc-scrollgrid-section\" },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"td\", { colSpan: 2, className: 'fc-timegrid-divider ' + context.theme.getClass('tableCellShaded') }))),\n });\n }\n let isNowIndicator = context.options.nowIndicator;\n sections.push({\n type: 'body',\n key: 'body',\n liquid: true,\n expandRows: Boolean(context.options.expandRows),\n chunks: [\n {\n key: 'axis',\n content: (arg) => (\n // TODO: make this now-indicator arrow more DRY with TimeColsContent\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-timegrid-axis-chunk\" },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"table\", { \"aria-hidden\": true, style: { height: arg.expandRows ? arg.clientHeight : '' } },\n arg.tableColGroupNode,\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"tbody\", null,\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TimeBodyAxis, { slatMetas: slatMetas }))),\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-timegrid-now-indicator-container\" },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.a6, { unit: isNowIndicator ? 'minute' : 'day' /* hacky */ }, (nowDate) => {\n let nowIndicatorTop = isNowIndicator &&\n slatCoords &&\n slatCoords.safeComputeTop(nowDate); // might return void\n if (typeof nowIndicatorTop === 'number') {\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ch, { elClasses: ['fc-timegrid-now-indicator-arrow'], elStyle: { top: nowIndicatorTop }, isAxis: true, date: nowDate }));\n }\n return null;\n })))),\n },\n {\n key: 'cols',\n scrollerElRef: this.scrollerElRef,\n content: timeContent,\n },\n ],\n });\n if (stickyFooterScrollbar) {\n sections.push({\n key: 'footer',\n type: 'footer',\n isSticky: true,\n chunks: [\n {\n key: 'axis',\n content: _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.c8,\n },\n {\n key: 'cols',\n content: _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.c8,\n },\n ],\n });\n }\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cq, { elRef: this.rootElRef, elClasses: ['fc-timegrid'], viewSpec: context.viewSpec },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(ScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, forPrint: props.forPrint, collapsibleWidth: false, colGroups: [\n { width: 'shrink', cols: [{ width: 'shrink' }] },\n { cols: [{ span: colCnt, minWidth: dayMinWidth }] },\n ], sections: sections })));\n }\n /* Dimensions\n ------------------------------------------------------------------------------------------------------------------*/\n getAllDayMaxEventProps() {\n let { dayMaxEvents, dayMaxEventRows } = this.context.options;\n if (dayMaxEvents === true || dayMaxEventRows === true) { // is auto?\n dayMaxEvents = undefined;\n dayMaxEventRows = AUTO_ALL_DAY_MAX_EVENT_ROWS; // make sure \"auto\" goes to a real number\n }\n return { dayMaxEvents, dayMaxEventRows };\n }\n}\nfunction renderAllDayInner(renderProps) {\n return renderProps.text;\n}\n\nclass TimeColsSlatsCoords {\n constructor(positions, dateProfile, slotDuration) {\n this.positions = positions;\n this.dateProfile = dateProfile;\n this.slotDuration = slotDuration;\n }\n safeComputeTop(date) {\n let { dateProfile } = this;\n if ((0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.G)(dateProfile.currentRange, date)) {\n let startOfDayDate = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.q)(date);\n let timeMs = date.valueOf() - startOfDayDate.valueOf();\n if (timeMs >= (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bq)(dateProfile.slotMinTime) &&\n timeMs < (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bq)(dateProfile.slotMaxTime)) {\n return this.computeTimeTop((0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.d)(timeMs));\n }\n }\n return null;\n }\n // Computes the top coordinate, relative to the bounds of the grid, of the given date.\n // A `startOfDayDate` must be given for avoiding ambiguity over how to treat midnight.\n computeDateTop(when, startOfDayDate) {\n if (!startOfDayDate) {\n startOfDayDate = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.q)(when);\n }\n return this.computeTimeTop((0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.d)(when.valueOf() - startOfDayDate.valueOf()));\n }\n // Computes the top coordinate, relative to the bounds of the grid, of the given time (a Duration).\n // This is a makeshify way to compute the time-top. Assumes all slatMetas dates are uniform.\n // Eventually allow computation with arbirary slat dates.\n computeTimeTop(duration) {\n let { positions, dateProfile } = this;\n let len = positions.els.length;\n // floating-point value of # of slots covered\n let slatCoverage = (duration.milliseconds - (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bq)(dateProfile.slotMinTime)) / (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bq)(this.slotDuration);\n let slatIndex;\n let slatRemainder;\n // compute a floating-point number for how many slats should be progressed through.\n // from 0 to number of slats (inclusive)\n // constrained because slotMinTime/slotMaxTime might be customized.\n slatCoverage = Math.max(0, slatCoverage);\n slatCoverage = Math.min(len, slatCoverage);\n // an integer index of the furthest whole slat\n // from 0 to number slats (*exclusive*, so len-1)\n slatIndex = Math.floor(slatCoverage);\n slatIndex = Math.min(slatIndex, len - 1);\n // how much further through the slatIndex slat (from 0.0-1.0) must be covered in addition.\n // could be 1.0 if slatCoverage is covering *all* the slots\n slatRemainder = slatCoverage - slatIndex;\n return positions.tops[slatIndex] +\n positions.getHeight(slatIndex) * slatRemainder;\n }\n}\n\nclass TimeColsSlatsBody extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.B {\n render() {\n let { props, context } = this;\n let { options } = context;\n let { slatElRefs } = props;\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"tbody\", null, props.slatMetas.map((slatMeta, i) => {\n let renderProps = {\n time: slatMeta.time,\n date: context.dateEnv.toDate(slatMeta.date),\n view: context.viewApi,\n };\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"tr\", { key: slatMeta.key, ref: slatElRefs.createRef(slatMeta.key) },\n props.axis && ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TimeColsAxisCell, Object.assign({}, slatMeta))),\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.C, { elTag: \"td\", elClasses: [\n 'fc-timegrid-slot',\n 'fc-timegrid-slot-lane',\n !slatMeta.isLabeled && 'fc-timegrid-slot-minor',\n ], elAttrs: {\n 'data-time': slatMeta.isoTimeStr,\n }, renderProps: renderProps, generatorName: \"slotLaneContent\", customGenerator: options.slotLaneContent, classNameGenerator: options.slotLaneClassNames, didMount: options.slotLaneDidMount, willUnmount: options.slotLaneWillUnmount })));\n })));\n }\n}\n\n/*\nfor the horizontal \"slats\" that run width-wise. Has a time axis on a side. Depends on RTL.\n*/\nclass TimeColsSlats extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.B {\n constructor() {\n super(...arguments);\n this.rootElRef = (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createRef)();\n this.slatElRefs = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cd();\n }\n render() {\n let { props, context } = this;\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { ref: this.rootElRef, className: \"fc-timegrid-slots\" },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"table\", { \"aria-hidden\": true, className: context.theme.getClass('table'), style: {\n minWidth: props.tableMinWidth,\n width: props.clientWidth,\n height: props.minHeight,\n } },\n props.tableColGroupNode /* relies on there only being a single <col> for the axis */,\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TimeColsSlatsBody, { slatElRefs: this.slatElRefs, axis: props.axis, slatMetas: props.slatMetas }))));\n }\n componentDidMount() {\n this.updateSizing();\n }\n componentDidUpdate() {\n this.updateSizing();\n }\n componentWillUnmount() {\n if (this.props.onCoords) {\n this.props.onCoords(null);\n }\n }\n updateSizing() {\n let { context, props } = this;\n if (props.onCoords &&\n props.clientWidth !== null // means sizing has stabilized\n ) {\n let rootEl = this.rootElRef.current;\n if (rootEl.offsetHeight) { // not hidden by css\n props.onCoords(new TimeColsSlatsCoords(new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.b8(this.rootElRef.current, collectSlatEls(this.slatElRefs.currentMap, props.slatMetas), false, true), this.props.dateProfile, context.options.slotDuration));\n }\n }\n }\n}\nfunction collectSlatEls(elMap, slatMetas) {\n return slatMetas.map((slatMeta) => elMap[slatMeta.key]);\n}\n\nfunction splitSegsByCol(segs, colCnt) {\n let segsByCol = [];\n let i;\n for (i = 0; i < colCnt; i += 1) {\n segsByCol.push([]);\n }\n if (segs) {\n for (i = 0; i < segs.length; i += 1) {\n segsByCol[segs[i].col].push(segs[i]);\n }\n }\n return segsByCol;\n}\nfunction splitInteractionByCol(ui, colCnt) {\n let byRow = [];\n if (!ui) {\n for (let i = 0; i < colCnt; i += 1) {\n byRow[i] = null;\n }\n }\n else {\n for (let i = 0; i < colCnt; i += 1) {\n byRow[i] = {\n affectedInstances: ui.affectedInstances,\n isEvent: ui.isEvent,\n segs: [],\n };\n }\n for (let seg of ui.segs) {\n byRow[seg.col].segs.push(seg);\n }\n }\n return byRow;\n}\n\nclass TimeColMoreLink extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.B {\n render() {\n let { props } = this;\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.co, { elClasses: ['fc-timegrid-more-link'], elStyle: {\n top: props.top,\n bottom: props.bottom,\n }, allDayDate: null, moreCnt: props.hiddenSegs.length, allSegs: props.hiddenSegs, hiddenSegs: props.hiddenSegs, extraDateSpan: props.extraDateSpan, dateProfile: props.dateProfile, todayRange: props.todayRange, popoverContent: () => renderPlainFgSegs(props.hiddenSegs, props), defaultGenerator: renderMoreLinkInner, forceTimed: true }, (InnerContent) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(InnerContent, { elTag: \"div\", elClasses: ['fc-timegrid-more-link-inner', 'fc-sticky'] }))));\n }\n}\nfunction renderMoreLinkInner(props) {\n return props.shortText;\n}\n\n// segInputs assumed sorted\nfunction buildPositioning(segInputs, strictOrder, maxStackCnt) {\n let hierarchy = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.by();\n if (strictOrder != null) {\n hierarchy.strictOrder = strictOrder;\n }\n if (maxStackCnt != null) {\n hierarchy.maxStackCnt = maxStackCnt;\n }\n let hiddenEntries = hierarchy.addSegs(segInputs);\n let hiddenGroups = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bC)(hiddenEntries);\n let web = buildWeb(hierarchy);\n web = stretchWeb(web, 1); // all levelCoords/thickness will have 0.0-1.0\n let segRects = webToRects(web);\n return { segRects, hiddenGroups };\n}\nfunction buildWeb(hierarchy) {\n const { entriesByLevel } = hierarchy;\n const buildNode = cacheable((level, lateral) => level + ':' + lateral, (level, lateral) => {\n let siblingRange = findNextLevelSegs(hierarchy, level, lateral);\n let nextLevelRes = buildNodes(siblingRange, buildNode);\n let entry = entriesByLevel[level][lateral];\n return [\n Object.assign(Object.assign({}, entry), { nextLevelNodes: nextLevelRes[0] }),\n entry.thickness + nextLevelRes[1], // the pressure builds\n ];\n });\n return buildNodes(entriesByLevel.length\n ? { level: 0, lateralStart: 0, lateralEnd: entriesByLevel[0].length }\n : null, buildNode)[0];\n}\nfunction buildNodes(siblingRange, buildNode) {\n if (!siblingRange) {\n return [[], 0];\n }\n let { level, lateralStart, lateralEnd } = siblingRange;\n let lateral = lateralStart;\n let pairs = [];\n while (lateral < lateralEnd) {\n pairs.push(buildNode(level, lateral));\n lateral += 1;\n }\n pairs.sort(cmpDescPressures);\n return [\n pairs.map(extractNode),\n pairs[0][1], // first item's pressure\n ];\n}\nfunction cmpDescPressures(a, b) {\n return b[1] - a[1];\n}\nfunction extractNode(a) {\n return a[0];\n}\nfunction findNextLevelSegs(hierarchy, subjectLevel, subjectLateral) {\n let { levelCoords, entriesByLevel } = hierarchy;\n let subjectEntry = entriesByLevel[subjectLevel][subjectLateral];\n let afterSubject = levelCoords[subjectLevel] + subjectEntry.thickness;\n let levelCnt = levelCoords.length;\n let level = subjectLevel;\n // skip past levels that are too high up\n for (; level < levelCnt && levelCoords[level] < afterSubject; level += 1)\n ; // do nothing\n for (; level < levelCnt; level += 1) {\n let entries = entriesByLevel[level];\n let entry;\n let searchIndex = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bB)(entries, subjectEntry.span.start, _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bA);\n let lateralStart = searchIndex[0] + searchIndex[1]; // if exact match (which doesn't collide), go to next one\n let lateralEnd = lateralStart;\n while ( // loop through entries that horizontally intersect\n (entry = entries[lateralEnd]) && // but not past the whole seg list\n entry.span.start < subjectEntry.span.end) {\n lateralEnd += 1;\n }\n if (lateralStart < lateralEnd) {\n return { level, lateralStart, lateralEnd };\n }\n }\n return null;\n}\nfunction stretchWeb(topLevelNodes, totalThickness) {\n const stretchNode = cacheable((node, startCoord, prevThickness) => (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bz)(node), (node, startCoord, prevThickness) => {\n let { nextLevelNodes, thickness } = node;\n let allThickness = thickness + prevThickness;\n let thicknessFraction = thickness / allThickness;\n let endCoord;\n let newChildren = [];\n if (!nextLevelNodes.length) {\n endCoord = totalThickness;\n }\n else {\n for (let childNode of nextLevelNodes) {\n if (endCoord === undefined) {\n let res = stretchNode(childNode, startCoord, allThickness);\n endCoord = res[0];\n newChildren.push(res[1]);\n }\n else {\n let res = stretchNode(childNode, endCoord, 0);\n newChildren.push(res[1]);\n }\n }\n }\n let newThickness = (endCoord - startCoord) * thicknessFraction;\n return [endCoord - newThickness, Object.assign(Object.assign({}, node), { thickness: newThickness, nextLevelNodes: newChildren })];\n });\n return topLevelNodes.map((node) => stretchNode(node, 0, 0)[1]);\n}\n// not sorted in any particular order\nfunction webToRects(topLevelNodes) {\n let rects = [];\n const processNode = cacheable((node, levelCoord, stackDepth) => (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bz)(node), (node, levelCoord, stackDepth) => {\n let rect = Object.assign(Object.assign({}, node), { levelCoord,\n stackDepth, stackForward: 0 });\n rects.push(rect);\n return (rect.stackForward = processNodes(node.nextLevelNodes, levelCoord + node.thickness, stackDepth + 1) + 1);\n });\n function processNodes(nodes, levelCoord, stackDepth) {\n let stackForward = 0;\n for (let node of nodes) {\n stackForward = Math.max(processNode(node, levelCoord, stackDepth), stackForward);\n }\n return stackForward;\n }\n processNodes(topLevelNodes, 0, 0);\n return rects; // TODO: sort rects by levelCoord to be consistent with toRects?\n}\n// TODO: move to general util\nfunction cacheable(keyFunc, workFunc) {\n const cache = {};\n return (...args) => {\n let key = keyFunc(...args);\n return (key in cache)\n ? cache[key]\n : (cache[key] = workFunc(...args));\n };\n}\n\nfunction computeSegVCoords(segs, colDate, slatCoords = null, eventMinHeight = 0) {\n let vcoords = [];\n if (slatCoords) {\n for (let i = 0; i < segs.length; i += 1) {\n let seg = segs[i];\n let spanStart = slatCoords.computeDateTop(seg.start, colDate);\n let spanEnd = Math.max(spanStart + (eventMinHeight || 0), // :(\n slatCoords.computeDateTop(seg.end, colDate));\n vcoords.push({\n start: Math.round(spanStart),\n end: Math.round(spanEnd), //\n });\n }\n }\n return vcoords;\n}\nfunction computeFgSegPlacements(segs, segVCoords, // might not have for every seg\neventOrderStrict, eventMaxStack) {\n let segInputs = [];\n let dumbSegs = []; // segs without coords\n for (let i = 0; i < segs.length; i += 1) {\n let vcoords = segVCoords[i];\n if (vcoords) {\n segInputs.push({\n index: i,\n thickness: 1,\n span: vcoords,\n });\n }\n else {\n dumbSegs.push(segs[i]);\n }\n }\n let { segRects, hiddenGroups } = buildPositioning(segInputs, eventOrderStrict, eventMaxStack);\n let segPlacements = [];\n for (let segRect of segRects) {\n segPlacements.push({\n seg: segs[segRect.index],\n rect: segRect,\n });\n }\n for (let dumbSeg of dumbSegs) {\n segPlacements.push({ seg: dumbSeg, rect: null });\n }\n return { segPlacements, hiddenGroups };\n}\n\nconst DEFAULT_TIME_FORMAT = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.x)({\n hour: 'numeric',\n minute: '2-digit',\n meridiem: false,\n});\nclass TimeColEvent extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.B {\n render() {\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cg, Object.assign({}, this.props, { elClasses: [\n 'fc-timegrid-event',\n 'fc-v-event',\n this.props.isShort && 'fc-timegrid-event-short',\n ], defaultTimeFormat: DEFAULT_TIME_FORMAT })));\n }\n}\n\nclass TimeCol extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.B {\n constructor() {\n super(...arguments);\n this.sortEventSegs = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bP);\n }\n // TODO: memoize event-placement?\n render() {\n let { props, context } = this;\n let { options } = context;\n let isSelectMirror = options.selectMirror;\n let mirrorSegs = // yuck\n (props.eventDrag && props.eventDrag.segs) ||\n (props.eventResize && props.eventResize.segs) ||\n (isSelectMirror && props.dateSelectionSegs) ||\n [];\n let interactionAffectedInstances = // TODO: messy way to compute this\n (props.eventDrag && props.eventDrag.affectedInstances) ||\n (props.eventResize && props.eventResize.affectedInstances) ||\n {};\n let sortedFgSegs = this.sortEventSegs(props.fgEventSegs, options.eventOrder);\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ci, { elTag: \"td\", elRef: props.elRef, elClasses: [\n 'fc-timegrid-col',\n ...(props.extraClassNames || []),\n ], elAttrs: Object.assign({ role: 'gridcell' }, props.extraDataAttrs), date: props.date, dateProfile: props.dateProfile, todayRange: props.todayRange, extraRenderProps: props.extraRenderProps }, (InnerContent) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-timegrid-col-frame\" },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-timegrid-col-bg\" },\n this.renderFillSegs(props.businessHourSegs, 'non-business'),\n this.renderFillSegs(props.bgEventSegs, 'bg-event'),\n this.renderFillSegs(props.dateSelectionSegs, 'highlight')),\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-timegrid-col-events\" }, this.renderFgSegs(sortedFgSegs, interactionAffectedInstances, false, false, false)),\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-timegrid-col-events\" }, this.renderFgSegs(mirrorSegs, {}, Boolean(props.eventDrag), Boolean(props.eventResize), Boolean(isSelectMirror), 'mirror')),\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-timegrid-now-indicator-container\" }, this.renderNowIndicator(props.nowIndicatorSegs)),\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cj)(options) && ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(InnerContent, { elTag: \"div\", elClasses: ['fc-timegrid-col-misc'] }))))));\n }\n renderFgSegs(sortedFgSegs, segIsInvisible, isDragging, isResizing, isDateSelecting, forcedKey) {\n let { props } = this;\n if (props.forPrint) {\n return renderPlainFgSegs(sortedFgSegs, props);\n }\n return this.renderPositionedFgSegs(sortedFgSegs, segIsInvisible, isDragging, isResizing, isDateSelecting, forcedKey);\n }\n renderPositionedFgSegs(segs, // if not mirror, needs to be sorted\n segIsInvisible, isDragging, isResizing, isDateSelecting, forcedKey) {\n let { eventMaxStack, eventShortHeight, eventOrderStrict, eventMinHeight } = this.context.options;\n let { date, slatCoords, eventSelection, todayRange, nowDate } = this.props;\n let isMirror = isDragging || isResizing || isDateSelecting;\n let segVCoords = computeSegVCoords(segs, date, slatCoords, eventMinHeight);\n let { segPlacements, hiddenGroups } = computeFgSegPlacements(segs, segVCoords, eventOrderStrict, eventMaxStack);\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.Fragment, null,\n this.renderHiddenGroups(hiddenGroups, segs),\n segPlacements.map((segPlacement) => {\n let { seg, rect } = segPlacement;\n let instanceId = seg.eventRange.instance.instanceId;\n let isVisible = isMirror || Boolean(!segIsInvisible[instanceId] && rect);\n let vStyle = computeSegVStyle(rect && rect.span);\n let hStyle = (!isMirror && rect) ? this.computeSegHStyle(rect) : { left: 0, right: 0 };\n let isInset = Boolean(rect) && rect.stackForward > 0;\n let isShort = Boolean(rect) && (rect.span.end - rect.span.start) < eventShortHeight; // look at other places for this problem\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: 'fc-timegrid-event-harness' +\n (isInset ? ' fc-timegrid-event-harness-inset' : ''), key: forcedKey || instanceId, style: Object.assign(Object.assign({ visibility: isVisible ? '' : 'hidden' }, vStyle), hStyle) },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TimeColEvent, Object.assign({ seg: seg, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === eventSelection, isShort: isShort }, (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bQ)(seg, todayRange, nowDate)))));\n })));\n }\n // will already have eventMinHeight applied because segInputs already had it\n renderHiddenGroups(hiddenGroups, segs) {\n let { extraDateSpan, dateProfile, todayRange, nowDate, eventSelection, eventDrag, eventResize } = this.props;\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.Fragment, null, hiddenGroups.map((hiddenGroup) => {\n let positionCss = computeSegVStyle(hiddenGroup.span);\n let hiddenSegs = compileSegsFromEntries(hiddenGroup.entries, segs);\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TimeColMoreLink, { key: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bu)((0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cp)(hiddenSegs)), hiddenSegs: hiddenSegs, top: positionCss.top, bottom: positionCss.bottom, extraDateSpan: extraDateSpan, dateProfile: dateProfile, todayRange: todayRange, nowDate: nowDate, eventSelection: eventSelection, eventDrag: eventDrag, eventResize: eventResize }));\n })));\n }\n renderFillSegs(segs, fillType) {\n let { props, context } = this;\n let segVCoords = computeSegVCoords(segs, props.date, props.slatCoords, context.options.eventMinHeight); // don't assume all populated\n let children = segVCoords.map((vcoords, i) => {\n let seg = segs[i];\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { key: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bR)(seg.eventRange), className: \"fc-timegrid-bg-harness\", style: computeSegVStyle(vcoords) }, fillType === 'bg-event' ?\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cm, Object.assign({ seg: seg }, (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bQ)(seg, props.todayRange, props.nowDate))) :\n (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cl)(fillType)));\n });\n return (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.Fragment, null, children);\n }\n renderNowIndicator(segs) {\n let { slatCoords, date } = this.props;\n if (!slatCoords) {\n return null;\n }\n return segs.map((seg, i) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ch\n // key doesn't matter. will only ever be one\n , { \n // key doesn't matter. will only ever be one\n key: i, elClasses: ['fc-timegrid-now-indicator-line'], elStyle: {\n top: slatCoords.computeDateTop(seg.start, date),\n }, isAxis: false, date: date })));\n }\n computeSegHStyle(segHCoords) {\n let { isRtl, options } = this.context;\n let shouldOverlap = options.slotEventOverlap;\n let nearCoord = segHCoords.levelCoord; // the left side if LTR. the right side if RTL. floating-point\n let farCoord = segHCoords.levelCoord + segHCoords.thickness; // the right side if LTR. the left side if RTL. floating-point\n let left; // amount of space from left edge, a fraction of the total width\n let right; // amount of space from right edge, a fraction of the total width\n if (shouldOverlap) {\n // double the width, but don't go beyond the maximum forward coordinate (1.0)\n farCoord = Math.min(1, nearCoord + (farCoord - nearCoord) * 2);\n }\n if (isRtl) {\n left = 1 - farCoord;\n right = nearCoord;\n }\n else {\n left = nearCoord;\n right = 1 - farCoord;\n }\n let props = {\n zIndex: segHCoords.stackDepth + 1,\n left: left * 100 + '%',\n right: right * 100 + '%',\n };\n if (shouldOverlap && !segHCoords.stackForward) {\n // add padding to the edge so that forward stacked events don't cover the resizer's icon\n props[isRtl ? 'marginLeft' : 'marginRight'] = 10 * 2; // 10 is a guesstimate of the icon's width\n }\n return props;\n }\n}\nfunction renderPlainFgSegs(sortedFgSegs, { todayRange, nowDate, eventSelection, eventDrag, eventResize }) {\n let hiddenInstances = (eventDrag ? eventDrag.affectedInstances : null) ||\n (eventResize ? eventResize.affectedInstances : null) ||\n {};\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.Fragment, null, sortedFgSegs.map((seg) => {\n let instanceId = seg.eventRange.instance.instanceId;\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { key: instanceId, style: { visibility: hiddenInstances[instanceId] ? 'hidden' : '' } },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TimeColEvent, Object.assign({ seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === eventSelection, isShort: false }, (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bQ)(seg, todayRange, nowDate)))));\n })));\n}\nfunction computeSegVStyle(segVCoords) {\n if (!segVCoords) {\n return { top: '', bottom: '' };\n }\n return {\n top: segVCoords.start,\n bottom: -segVCoords.end,\n };\n}\nfunction compileSegsFromEntries(segEntries, allSegs) {\n return segEntries.map((segEntry) => allSegs[segEntry.index]);\n}\n\nclass TimeColsContent extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.B {\n constructor() {\n super(...arguments);\n this.splitFgEventSegs = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(splitSegsByCol);\n this.splitBgEventSegs = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(splitSegsByCol);\n this.splitBusinessHourSegs = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(splitSegsByCol);\n this.splitNowIndicatorSegs = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(splitSegsByCol);\n this.splitDateSelectionSegs = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(splitSegsByCol);\n this.splitEventDrag = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(splitInteractionByCol);\n this.splitEventResize = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(splitInteractionByCol);\n this.rootElRef = (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createRef)();\n this.cellElRefs = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.cd();\n }\n render() {\n let { props, context } = this;\n let nowIndicatorTop = context.options.nowIndicator &&\n props.slatCoords &&\n props.slatCoords.safeComputeTop(props.nowDate); // might return void\n let colCnt = props.cells.length;\n let fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, colCnt);\n let bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, colCnt);\n let businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, colCnt);\n let nowIndicatorSegsByRow = this.splitNowIndicatorSegs(props.nowIndicatorSegs, colCnt);\n let dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, colCnt);\n let eventDragByRow = this.splitEventDrag(props.eventDrag, colCnt);\n let eventResizeByRow = this.splitEventResize(props.eventResize, colCnt);\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-timegrid-cols\", ref: this.rootElRef },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"table\", { role: \"presentation\", style: {\n minWidth: props.tableMinWidth,\n width: props.clientWidth,\n } },\n props.tableColGroupNode,\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"tbody\", { role: \"presentation\" },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"tr\", { role: \"row\" },\n props.axis && ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"td\", { \"aria-hidden\": true, className: \"fc-timegrid-col fc-timegrid-axis\" },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-timegrid-col-frame\" },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-timegrid-now-indicator-container\" }, typeof nowIndicatorTop === 'number' && ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ch, { elClasses: ['fc-timegrid-now-indicator-arrow'], elStyle: { top: nowIndicatorTop }, isAxis: true, date: props.nowDate })))))),\n props.cells.map((cell, i) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TimeCol, { key: cell.key, elRef: this.cellElRefs.createRef(cell.key), dateProfile: props.dateProfile, date: cell.date, nowDate: props.nowDate, todayRange: props.todayRange, extraRenderProps: cell.extraRenderProps, extraDataAttrs: cell.extraDataAttrs, extraClassNames: cell.extraClassNames, extraDateSpan: cell.extraDateSpan, fgEventSegs: fgEventSegsByRow[i], bgEventSegs: bgEventSegsByRow[i], businessHourSegs: businessHourSegsByRow[i], nowIndicatorSegs: nowIndicatorSegsByRow[i], dateSelectionSegs: dateSelectionSegsByRow[i], eventDrag: eventDragByRow[i], eventResize: eventResizeByRow[i], slatCoords: props.slatCoords, eventSelection: props.eventSelection, forPrint: props.forPrint }))))))));\n }\n componentDidMount() {\n this.updateCoords();\n }\n componentDidUpdate() {\n this.updateCoords();\n }\n updateCoords() {\n let { props } = this;\n if (props.onColCoords &&\n props.clientWidth !== null // means sizing has stabilized\n ) {\n props.onColCoords(new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.b8(this.rootElRef.current, collectCellEls(this.cellElRefs.currentMap, props.cells), true, // horizontal\n false));\n }\n }\n}\nfunction collectCellEls(elMap, cells) {\n return cells.map((cell) => elMap[cell.key]);\n}\n\n/* A component that renders one or more columns of vertical time slots\n----------------------------------------------------------------------------------------------------------------------*/\nclass TimeCols extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bc {\n constructor() {\n super(...arguments);\n this.processSlotOptions = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(processSlotOptions);\n this.state = {\n slatCoords: null,\n };\n this.handleRootEl = (el) => {\n if (el) {\n this.context.registerInteractiveComponent(this, {\n el,\n isHitComboAllowed: this.props.isHitComboAllowed,\n });\n }\n else {\n this.context.unregisterInteractiveComponent(this);\n }\n };\n this.handleScrollRequest = (request) => {\n let { onScrollTopRequest } = this.props;\n let { slatCoords } = this.state;\n if (onScrollTopRequest && slatCoords) {\n if (request.time) {\n let top = slatCoords.computeTimeTop(request.time);\n top = Math.ceil(top); // zoom can give weird floating-point values. rather scroll a little bit further\n if (top) {\n top += 1; // to overcome top border that slots beyond the first have. looks better\n }\n onScrollTopRequest(top);\n }\n return true;\n }\n return false;\n };\n this.handleColCoords = (colCoords) => {\n this.colCoords = colCoords;\n };\n this.handleSlatCoords = (slatCoords) => {\n this.setState({ slatCoords });\n if (this.props.onSlatCoords) {\n this.props.onSlatCoords(slatCoords);\n }\n };\n }\n render() {\n let { props, state } = this;\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(\"div\", { className: \"fc-timegrid-body\", ref: this.handleRootEl, style: {\n // these props are important to give this wrapper correct dimensions for interactions\n // TODO: if we set it here, can we avoid giving to inner tables?\n width: props.clientWidth,\n minWidth: props.tableMinWidth,\n } },\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TimeColsSlats, { axis: props.axis, dateProfile: props.dateProfile, slatMetas: props.slatMetas, clientWidth: props.clientWidth, minHeight: props.expandRows ? props.clientHeight : '', tableMinWidth: props.tableMinWidth, tableColGroupNode: props.axis ? props.tableColGroupNode : null /* axis depends on the colgroup's shrinking */, onCoords: this.handleSlatCoords }),\n (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TimeColsContent, { cells: props.cells, axis: props.axis, dateProfile: props.dateProfile, businessHourSegs: props.businessHourSegs, bgEventSegs: props.bgEventSegs, fgEventSegs: props.fgEventSegs, dateSelectionSegs: props.dateSelectionSegs, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, todayRange: props.todayRange, nowDate: props.nowDate, nowIndicatorSegs: props.nowIndicatorSegs, clientWidth: props.clientWidth, tableMinWidth: props.tableMinWidth, tableColGroupNode: props.tableColGroupNode, slatCoords: state.slatCoords, onColCoords: this.handleColCoords, forPrint: props.forPrint })));\n }\n componentDidMount() {\n this.scrollResponder = this.context.createScrollResponder(this.handleScrollRequest);\n }\n componentDidUpdate(prevProps) {\n this.scrollResponder.update(prevProps.dateProfile !== this.props.dateProfile);\n }\n componentWillUnmount() {\n this.scrollResponder.detach();\n }\n queryHit(positionLeft, positionTop) {\n let { dateEnv, options } = this.context;\n let { colCoords } = this;\n let { dateProfile } = this.props;\n let { slatCoords } = this.state;\n let { snapDuration, snapsPerSlot } = this.processSlotOptions(this.props.slotDuration, options.snapDuration);\n let colIndex = colCoords.leftToIndex(positionLeft);\n let slatIndex = slatCoords.positions.topToIndex(positionTop);\n if (colIndex != null && slatIndex != null) {\n let cell = this.props.cells[colIndex];\n let slatTop = slatCoords.positions.tops[slatIndex];\n let slatHeight = slatCoords.positions.getHeight(slatIndex);\n let partial = (positionTop - slatTop) / slatHeight; // floating point number between 0 and 1\n let localSnapIndex = Math.floor(partial * snapsPerSlot); // the snap # relative to start of slat\n let snapIndex = slatIndex * snapsPerSlot + localSnapIndex;\n let dayDate = this.props.cells[colIndex].date;\n let time = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bn)(dateProfile.slotMinTime, (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bm)(snapDuration, snapIndex));\n let start = dateEnv.add(dayDate, time);\n let end = dateEnv.add(start, snapDuration);\n return {\n dateProfile,\n dateSpan: Object.assign({ range: { start, end }, allDay: false }, cell.extraDateSpan),\n dayEl: colCoords.els[colIndex],\n rect: {\n left: colCoords.lefts[colIndex],\n right: colCoords.rights[colIndex],\n top: slatTop,\n bottom: slatTop + slatHeight,\n },\n layer: 0,\n };\n }\n return null;\n }\n}\nfunction processSlotOptions(slotDuration, snapDurationOverride) {\n let snapDuration = snapDurationOverride || slotDuration;\n let snapsPerSlot = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.br)(slotDuration, snapDuration);\n if (snapsPerSlot === null) {\n snapDuration = slotDuration;\n snapsPerSlot = 1;\n // TODO: say warning?\n }\n return { snapDuration, snapsPerSlot };\n}\n\nclass DayTimeColsSlicer extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bU {\n sliceRange(range, dayRanges) {\n let segs = [];\n for (let col = 0; col < dayRanges.length; col += 1) {\n let segRange = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.o)(range, dayRanges[col]);\n if (segRange) {\n segs.push({\n start: segRange.start,\n end: segRange.end,\n isStart: segRange.start.valueOf() === range.start.valueOf(),\n isEnd: segRange.end.valueOf() === range.end.valueOf(),\n col,\n });\n }\n }\n return segs;\n }\n}\n\nclass DayTimeCols extends _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bc {\n constructor() {\n super(...arguments);\n this.buildDayRanges = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(buildDayRanges);\n this.slicer = new DayTimeColsSlicer();\n this.timeColsRef = (0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createRef)();\n }\n render() {\n let { props, context } = this;\n let { dateProfile, dayTableModel } = props;\n let { nowIndicator, nextDayThreshold } = context.options;\n let dayRanges = this.buildDayRanges(dayTableModel, dateProfile, context.dateEnv);\n // give it the first row of cells\n // TODO: would move this further down hierarchy, but sliceNowDate needs it\n return ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.a6, { unit: nowIndicator ? 'minute' : 'day' }, (nowDate, todayRange) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(TimeCols, Object.assign({ ref: this.timeColsRef }, this.slicer.sliceProps(props, dateProfile, null, context, dayRanges), { forPrint: props.forPrint, axis: props.axis, dateProfile: dateProfile, slatMetas: props.slatMetas, slotDuration: props.slotDuration, cells: dayTableModel.cells[0], tableColGroupNode: props.tableColGroupNode, tableMinWidth: props.tableMinWidth, clientWidth: props.clientWidth, clientHeight: props.clientHeight, expandRows: props.expandRows, nowDate: nowDate, nowIndicatorSegs: nowIndicator && this.slicer.sliceNowDate(nowDate, dateProfile, nextDayThreshold, context, dayRanges), todayRange: todayRange, onScrollTopRequest: props.onScrollTopRequest, onSlatCoords: props.onSlatCoords })))));\n }\n}\nfunction buildDayRanges(dayTableModel, dateProfile, dateEnv) {\n let ranges = [];\n for (let date of dayTableModel.headerDates) {\n ranges.push({\n start: dateEnv.add(date, dateProfile.slotMinTime),\n end: dateEnv.add(date, dateProfile.slotMaxTime),\n });\n }\n return ranges;\n}\n\n// potential nice values for the slot-duration and interval-duration\n// from largest to smallest\nconst STOCK_SUB_DURATIONS = [\n { hours: 1 },\n { minutes: 30 },\n { minutes: 15 },\n { seconds: 30 },\n { seconds: 15 },\n];\nfunction buildSlatMetas(slotMinTime, slotMaxTime, explicitLabelInterval, slotDuration, dateEnv) {\n let dayStart = new Date(0);\n let slatTime = slotMinTime;\n let slatIterator = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.d)(0);\n let labelInterval = explicitLabelInterval || computeLabelInterval(slotDuration);\n let metas = [];\n while ((0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bq)(slatTime) < (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bq)(slotMaxTime)) {\n let date = dateEnv.add(dayStart, slatTime);\n let isLabeled = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.br)(slatIterator, labelInterval) !== null;\n metas.push({\n date,\n time: slatTime,\n key: date.toISOString(),\n isoTimeStr: (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bs)(date),\n isLabeled,\n });\n slatTime = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bn)(slatTime, slotDuration);\n slatIterator = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bn)(slatIterator, slotDuration);\n }\n return metas;\n}\n// Computes an automatic value for slotLabelInterval\nfunction computeLabelInterval(slotDuration) {\n let i;\n let labelInterval;\n let slotsPerLabel;\n // find the smallest stock label interval that results in more than one slots-per-label\n for (i = STOCK_SUB_DURATIONS.length - 1; i >= 0; i -= 1) {\n labelInterval = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.d)(STOCK_SUB_DURATIONS[i]);\n slotsPerLabel = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.br)(labelInterval, slotDuration);\n if (slotsPerLabel !== null && slotsPerLabel > 1) {\n return labelInterval;\n }\n }\n return slotDuration; // fall back\n}\n\nclass DayTimeColsView extends TimeColsView {\n constructor() {\n super(...arguments);\n this.buildTimeColsModel = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(buildTimeColsModel);\n this.buildSlatMetas = (0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.z)(buildSlatMetas);\n }\n render() {\n let { options, dateEnv, dateProfileGenerator } = this.context;\n let { props } = this;\n let { dateProfile } = props;\n let dayTableModel = this.buildTimeColsModel(dateProfile, dateProfileGenerator);\n let splitProps = this.allDaySplitter.splitProps(props);\n let slatMetas = this.buildSlatMetas(dateProfile.slotMinTime, dateProfile.slotMaxTime, options.slotLabelInterval, options.slotDuration, dateEnv);\n let { dayMinWidth } = options;\n let hasAttachedAxis = !dayMinWidth;\n let hasDetachedAxis = dayMinWidth;\n let headerContent = options.dayHeaders && ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bI, { dates: dayTableModel.headerDates, dateProfile: dateProfile, datesRepDistinctDays: true, renderIntro: hasAttachedAxis ? this.renderHeadAxis : null }));\n let allDayContent = (options.allDaySlot !== false) && ((contentArg) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(_fullcalendar_daygrid_internal_js__WEBPACK_IMPORTED_MODULE_2__.DayTable, Object.assign({}, splitProps.allDay, { dateProfile: dateProfile, dayTableModel: dayTableModel, nextDayThreshold: options.nextDayThreshold, tableMinWidth: contentArg.tableMinWidth, colGroupNode: contentArg.tableColGroupNode, renderRowIntro: hasAttachedAxis ? this.renderTableRowAxis : null, showWeekNumbers: false, expandRows: false, headerAlignElRef: this.headerElRef, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, forPrint: props.forPrint }, this.getAllDayMaxEventProps()))));\n let timeGridContent = (contentArg) => ((0,_fullcalendar_core_preact_js__WEBPACK_IMPORTED_MODULE_1__.createElement)(DayTimeCols, Object.assign({}, splitProps.timed, { dayTableModel: dayTableModel, dateProfile: dateProfile, axis: hasAttachedAxis, slotDuration: options.slotDuration, slatMetas: slatMetas, forPrint: props.forPrint, tableColGroupNode: contentArg.tableColGroupNode, tableMinWidth: contentArg.tableMinWidth, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, onSlatCoords: this.handleSlatCoords, expandRows: contentArg.expandRows, onScrollTopRequest: this.handleScrollTopRequest })));\n return hasDetachedAxis\n ? this.renderHScrollLayout(headerContent, allDayContent, timeGridContent, dayTableModel.colCnt, dayMinWidth, slatMetas, this.state.slatCoords)\n : this.renderSimpleLayout(headerContent, allDayContent, timeGridContent);\n }\n}\nfunction buildTimeColsModel(dateProfile, dateProfileGenerator) {\n let daySeries = new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bM(dateProfile.renderRange, dateProfileGenerator);\n return new _fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.bT(daySeries, false);\n}\n\nvar css_248z = \".fc-v-event{background-color:var(--fc-event-bg-color);border:1px solid var(--fc-event-border-color);display:block}.fc-v-event .fc-event-main{color:var(--fc-event-text-color);height:100%}.fc-v-event .fc-event-main-frame{display:flex;flex-direction:column;height:100%}.fc-v-event .fc-event-time{flex-grow:0;flex-shrink:0;max-height:100%;overflow:hidden}.fc-v-event .fc-event-title-container{flex-grow:1;flex-shrink:1;min-height:0}.fc-v-event .fc-event-title{bottom:0;max-height:100%;overflow:hidden;top:0}.fc-v-event:not(.fc-event-start){border-top-left-radius:0;border-top-right-radius:0;border-top-width:0}.fc-v-event:not(.fc-event-end){border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom-width:0}.fc-v-event.fc-event-selected:before{left:-10px;right:-10px}.fc-v-event .fc-event-resizer-start{cursor:n-resize}.fc-v-event .fc-event-resizer-end{cursor:s-resize}.fc-v-event:not(.fc-event-selected) .fc-event-resizer{height:var(--fc-event-resizer-thickness);left:0;right:0}.fc-v-event:not(.fc-event-selected) .fc-event-resizer-start{top:calc(var(--fc-event-resizer-thickness)/-2)}.fc-v-event:not(.fc-event-selected) .fc-event-resizer-end{bottom:calc(var(--fc-event-resizer-thickness)/-2)}.fc-v-event.fc-event-selected .fc-event-resizer{left:50%;margin-left:calc(var(--fc-event-resizer-dot-total-width)/-2)}.fc-v-event.fc-event-selected .fc-event-resizer-start{top:calc(var(--fc-event-resizer-dot-total-width)/-2)}.fc-v-event.fc-event-selected .fc-event-resizer-end{bottom:calc(var(--fc-event-resizer-dot-total-width)/-2)}.fc .fc-timegrid .fc-daygrid-body{z-index:2}.fc .fc-timegrid-divider{padding:0 0 2px}.fc .fc-timegrid-body{min-height:100%;position:relative;z-index:1}.fc .fc-timegrid-axis-chunk{position:relative}.fc .fc-timegrid-axis-chunk>table,.fc .fc-timegrid-slots{position:relative;z-index:1}.fc .fc-timegrid-slot{border-bottom:0;height:1.5em}.fc .fc-timegrid-slot:empty:before{content:\\\"\\\\00a0\\\"}.fc .fc-timegrid-slot-minor{border-top-style:dotted}.fc .fc-timegrid-slot-label-cushion{display:inline-block;white-space:nowrap}.fc .fc-timegrid-slot-label{vertical-align:middle}.fc .fc-timegrid-axis-cushion,.fc .fc-timegrid-slot-label-cushion{padding:0 4px}.fc .fc-timegrid-axis-frame-liquid{height:100%}.fc .fc-timegrid-axis-frame{align-items:center;display:flex;justify-content:flex-end;overflow:hidden}.fc .fc-timegrid-axis-cushion{flex-shrink:0;max-width:60px}.fc-direction-ltr .fc-timegrid-slot-label-frame{text-align:right}.fc-direction-rtl .fc-timegrid-slot-label-frame{text-align:left}.fc-liquid-hack .fc-timegrid-axis-frame-liquid{bottom:0;height:auto;left:0;position:absolute;right:0;top:0}.fc .fc-timegrid-col.fc-day-today{background-color:var(--fc-today-bg-color)}.fc .fc-timegrid-col-frame{min-height:100%;position:relative}.fc-media-screen.fc-liquid-hack .fc-timegrid-col-frame{bottom:0;height:auto;left:0;position:absolute;right:0;top:0}.fc-media-screen .fc-timegrid-cols{bottom:0;left:0;position:absolute;right:0;top:0}.fc-media-screen .fc-timegrid-cols>table{height:100%}.fc-media-screen .fc-timegrid-col-bg,.fc-media-screen .fc-timegrid-col-events,.fc-media-screen .fc-timegrid-now-indicator-container{left:0;position:absolute;right:0;top:0}.fc .fc-timegrid-col-bg{z-index:2}.fc .fc-timegrid-col-bg .fc-non-business{z-index:1}.fc .fc-timegrid-col-bg .fc-bg-event{z-index:2}.fc .fc-timegrid-col-bg .fc-highlight{z-index:3}.fc .fc-timegrid-bg-harness{left:0;position:absolute;right:0}.fc .fc-timegrid-col-events{z-index:3}.fc .fc-timegrid-now-indicator-container{bottom:0;overflow:hidden}.fc-direction-ltr .fc-timegrid-col-events{margin:0 2.5% 0 2px}.fc-direction-rtl .fc-timegrid-col-events{margin:0 2px 0 2.5%}.fc-timegrid-event-harness{position:absolute}.fc-timegrid-event-harness>.fc-timegrid-event{bottom:0;left:0;position:absolute;right:0;top:0}.fc-timegrid-event-harness-inset .fc-timegrid-event,.fc-timegrid-event.fc-event-mirror,.fc-timegrid-more-link{box-shadow:0 0 0 1px var(--fc-page-bg-color)}.fc-timegrid-event,.fc-timegrid-more-link{border-radius:3px;font-size:var(--fc-small-font-size)}.fc-timegrid-event{margin-bottom:1px}.fc-timegrid-event .fc-event-main{padding:1px 1px 0}.fc-timegrid-event .fc-event-time{font-size:var(--fc-small-font-size);margin-bottom:1px;white-space:nowrap}.fc-timegrid-event-short .fc-event-main-frame{flex-direction:row;overflow:hidden}.fc-timegrid-event-short .fc-event-time:after{content:\\\"\\\\00a0-\\\\00a0\\\"}.fc-timegrid-event-short .fc-event-title{font-size:var(--fc-small-font-size)}.fc-timegrid-more-link{background:var(--fc-more-link-bg-color);color:var(--fc-more-link-text-color);cursor:pointer;margin-bottom:1px;position:absolute;z-index:9999}.fc-timegrid-more-link-inner{padding:3px 2px;top:0}.fc-direction-ltr .fc-timegrid-more-link{right:0}.fc-direction-rtl .fc-timegrid-more-link{left:0}.fc .fc-timegrid-now-indicator-arrow,.fc .fc-timegrid-now-indicator-line{pointer-events:none}.fc .fc-timegrid-now-indicator-line{border-color:var(--fc-now-indicator-color);border-style:solid;border-width:1px 0 0;left:0;position:absolute;right:0;z-index:4}.fc .fc-timegrid-now-indicator-arrow{border-color:var(--fc-now-indicator-color);border-style:solid;margin-top:-5px;position:absolute;z-index:4}.fc-direction-ltr .fc-timegrid-now-indicator-arrow{border-bottom-color:transparent;border-top-color:transparent;border-width:5px 0 5px 6px;left:0}.fc-direction-rtl .fc-timegrid-now-indicator-arrow{border-bottom-color:transparent;border-top-color:transparent;border-width:5px 6px 5px 0;right:0}\";\n(0,_fullcalendar_core_internal_js__WEBPACK_IMPORTED_MODULE_0__.ct)(css_248z);\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKHNzcikvLi9ub2RlX21vZHVsZXMvQGZ1bGxjYWxlbmRhci90aW1lZ3JpZC9pbnRlcm5hbC5qcyIsIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7QUFBMDFCO0FBQ3h3QjtBQUNyQjs7QUFFN0QsNkJBQTZCLDhEQUFRO0FBQ3JDO0FBQ0E7QUFDQSxzQkFBc0I7QUFDdEIscUJBQXFCO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksa0VBQWM7QUFDMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxrQ0FBa0MsaUVBQWU7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSwyRUFBYSxDQUFDLDZEQUFlO0FBQ3pDO0FBQ0Esb0JBQW9CLDJFQUFhLFNBQVMsZ0VBQWdFO0FBQzFHO0FBQ0EsY0FBYyw0QkFBNEI7QUFDMUM7QUFDQTtBQUNBLHFEQUFxRCxpRUFBZTtBQUNwRSxnQkFBZ0IsaUVBQWU7QUFDL0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsMkVBQWEsQ0FBQyw2REFBZ0IsSUFBSTtBQUNsRDtBQUNBLGFBQWEsaVJBQWlSLHFCQUFxQiwyRUFBYSxVQUFVLHNFQUFzRTtBQUNoWixZQUFZLDJFQUFhLGlCQUFpQjtBQUMxQztBQUNBO0FBQ0EsbUJBQW1CO0FBQ25CLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQSwyQkFBMkIsNkRBQWE7QUFDeEM7QUFDQSx1REFBdUQsMkVBQWEsU0FBUyxtQkFBbUI7QUFDaEcsWUFBWSwyRUFBYSxtQ0FBbUM7QUFDNUQ7QUFDQTs7QUFFQSxnQ0FBZ0MsaUVBQWUsR0FBRyxlQUFlO0FBQ2pFO0FBQ0EsMkJBQTJCLDhEQUFhO0FBQ3hDO0FBQ0E7QUFDQSxvREFBb0Q7QUFDcEQsMkJBQTJCLHVFQUFTO0FBQ3BDLHlCQUF5Qix1RUFBUztB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NEIsVUFBVSx5Q0FBeUMsU0FBUyxnQkFBZ0IsMENBQTBDLG9CQUFvQiwwQ0FBMEMsb0JBQW9CLDJCQUEyQixrQkFBa0IsOENBQThDLFNBQVMsT0FBTyxrQkFBa0IsUUFBUSxNQUFNLDhHQUE4Ryw2Q0FBNkMsMENBQTBDLGtCQUFrQixvQ0FBb0MsbUJBQW1CLGtCQUFrQixrQ0FBa0Msa0JBQWtCLGtDQUFrQyxvQ0FBb0Msa0JBQWtCLG1CQUFtQiw4Q0FBOEMsbUJBQW1CLGdCQUFnQiw4Q0FBOEMsMEJBQTBCLHlDQUF5QyxvQ0FBb0MsdUJBQXVCLHdDQUF3QyxxQ0FBcUMsZUFBZSxrQkFBa0Isa0JBQWtCLGFBQWEsNkJBQTZCLGdCQUFnQixNQUFNLHlDQUF5QyxRQUFRLHlDQUF5QyxPQUFPLHlFQUF5RSxvQkFBb0Isb0NBQW9DLDJDQUEyQyxtQkFBbUIscUJBQXFCLE9BQU8sa0JBQWtCLFFBQVEsVUFBVSxxQ0FBcUMsMkNBQTJDLG1CQUFtQixnQkFBZ0Isa0JBQWtCLFVBQVUsbURBQW1ELGdDQUFnQyw2QkFBNkIsMkJBQTJCLE9BQU8sbURBQW1ELGdDQUFnQyw2QkFBNkIsMkJBQTJCLFFBQVE7QUFDLzJLLGtFQUFZOztBQUVnSiIsInNvdXJjZXMiOlsiL2hvbWUvc2lsdmlvL0RldmVsb3AvQ0lSVVgtQVBQL25vZGVfbW9kdWxlcy9AZnVsbGNhbGVuZGFyL3RpbWVncmlkL2ludGVybmFsLmpzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFNwbGl0dGVyLCBoYXNCZ1JlbmRlcmluZywgY3JlYXRlRm9ybWF0dGVyLCBWaWV3Q29udGV4dFR5cGUsIENvbnRlbnRDb250YWluZXIsIEJhc2VDb21wb25lbnQsIERhdGVDb21wb25lbnQsIGRpZmZEYXlzLCBidWlsZE5hdkxpbmtBdHRycywgV2Vla051bWJlckNvbnRhaW5lciwgZ2V0U3RpY2t5SGVhZGVyRGF0ZXMsIFZpZXdDb250YWluZXIsIFNpbXBsZVNjcm9sbEdyaWQsIGdldFN0aWNreUZvb3RlclNjcm9sbGJhciwgTm93VGltZXIsIE5vd0luZGljYXRvckNvbnRhaW5lciwgcmVuZGVyU2Nyb2xsU2hpbSwgcmFuZ2VDb250YWluc01hcmtlciwgc3RhcnRPZkRheSwgYXNSb3VnaE1zLCBjcmVhdGVEdXJhdGlvbiwgUmVmTWFwLCBQb3NpdGlvbkNhY2hlLCBNb3JlTGlua0NvbnRhaW5lciwgU2VnSGllcmFyY2h5LCBncm91cEludGVyc2VjdGluZ0VudHJpZXMsIGJpbmFyeVNlYXJjaCwgZ2V0RW50cnlTcGFuRW5kLCBidWlsZEVudHJ5S2V5LCBTdGFuZGFyZEV2ZW50LCBtZW1vaXplLCBzb3J0RXZlbnRTZWdzLCBEYXlDZWxsQ29udGFpbmVyLCBoYXNDdXN0b21EYXlDZWxsQ29udGVudCwgZ2V0U2VnTWV0YSwgYnVpbGRJc29TdHJpbmcsIGNvbXB1dGVFYXJsaWVzdFNlZ1N0YXJ0LCBidWlsZEV2ZW50UmFuZ2VLZXksIEJnRXZlbnQsIHJlbmRlckZpbGwsIGFkZER1cmF0aW9ucywgbXVsdGlwbHlEdXJhdGlvbiwgd2hvbGVEaXZpZGVEdXJhdGlvbnMsIFNsaWNlciwgaW50ZXJzZWN0UmFuZ2VzLCBmb3JtYXRJc29UaW1lU3RyaW5nLCBEYXlIZWFkZXIsIERheVNlcmllc01vZGVsLCBEYXlUYWJsZU1vZGVsLCBpbmplY3RTdHlsZXMgfSBmcm9tICdAZnVsbGNhbGVuZGFyL2NvcmUvaW50ZXJuYWwuanMnO1xuaW1wb3J0IHsgY3JlYXRlRWxlbWVudCwgY3JlYXRlUmVmLCBGcmFnbWVudCB9IGZyb20gJ0BmdWxsY2FsZW5kYXIvY29yZS9wcmVhY3QuanMnO1xuaW1wb3J0IHsgRGF5VGFibGUgfSBmcm9tICdAZnVsbGNhbGVuZGFyL2RheWdyaWQvaW50ZXJuYWwuanMnO1xuXG5jbGFzcyBBbGxEYXlTcGxpdHRlciBleHRlbmRzIFNwbGl0dGVyIHtcbiAgICBnZXRLZXlJbmZvKCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgYWxsRGF5OiB7fSxcbiAgICAgICAgICAgIHRpbWVkOiB7fSxcbiAgICAgICAgfTtcbiAgICB9XG4gICAgZ2V0S2V5c0ZvckRhdGVTcGFuKGRhdGVTcGFuKSB7XG4gICAgICAgIGlmIChkYXRlU3Bhbi5hbGxEYXkpIHtcbiAgICAgICAgICAgIHJldHVybiBbJ2FsbERheSddO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBbJ3RpbWVkJ107XG4gICAgfVxuICAgIGdldEtleXNGb3JFdmVudERlZihldmVudERlZikge1xuICAgICAgICBpZiAoIWV2ZW50RGVmLmFsbERheSkge1xuICAgICAgICAgICAgcmV0dXJuIFsndGltZWQnXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaGFzQmdSZW5kZXJpbmcoZXZlbnREZWYpKSB7XG4gICAgICAgICAgICByZXR1cm4gWyd0aW1lZCcsICdhbGxEYXknXTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gWydhbGxEYXknXTtcbiAgICB9XG59XG5cbmNvbnN0IERFRkFVTFRfU0xBVF9MQUJFTF9GT1JNQVQgPSBjcmVhdGVGb3JtYXR0ZXIoe1xuICAgIGhvdXI6ICdudW1lcmljJyxcbiAgICBtaW51dGU6ICcyLWRpZ2l0JyxcbiAgICBvbWl0WmVyb01pbnV0ZTogdHJ1ZSxcbiAgICBtZXJpZGllbTogJ3Nob3J0Jyxcbn0pO1xuZnVuY3Rpb24gVGltZUNvbHNBeGlzQ2VsbChwcm9wcykge1xuICAgIGxldCBjbGFzc05hbWVzID0gW1xuICAgICAgICAnZmMtdGltZWdyaWQtc2xvdCcsXG4gICAgICAgICdmYy10aW1lZ3JpZC1zbG90LWxhYmVsJyxcbiAgICAgICAgcHJvcHMuaXNMYWJlbGVkID8gJ2ZjLXNjcm9sbGdyaWQtc2hyaW5rJyA6ICdmYy10aW1lZ3JpZC1zbG90LW1pbm9yJyxcbiAgICBdO1xuICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChWaWV3Q29udGV4dFR5cGUuQ29uc3VtZXIsIG51bGwsIChjb250ZXh0KSA9PiB7XG4gICAgICAgIGlmICghcHJvcHMuaXNMYWJlbGVkKSB7XG4gICAgICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoXCJ0ZFwiLCB7IGNsYXNzTmFtZTogY2xhc3NOYW1lcy5qb2luKCcgJyksIFwiZGF0YS10aW1lXCI6IHByb3BzLmlzb1RpbWVTdHIgfSkpO1xuICAgICAgICB9XG4gICAgICAgIGxldCB7IGRhdGVFbnYsIG9wdGlvbnMsIHZpZXdBcGkgfSA9IGNvbnRleHQ7XG4gICAgICAgIGxldCBsYWJlbEZvcm1hdCA9IC8vIFRPRE86IGZ1bGx5IHByZS1wYXJzZVxuICAgICAgICAgb3B0aW9ucy5zbG90TGFiZWxGb3JtYXQgPT0gbnVsbCA/IERFRkFVTFRfU0xBVF9MQUJFTF9GT1JNQVQgOlxuICAgICAgICAgICAgQXJyYXkuaXNBcnJheShvcHRpb25zLnNsb3RMYWJlbEZvcm1hdCkgPyBjcmVhdGVGb3JtYXR0ZXIob3B0aW9ucy5zbG90TGFiZWxGb3JtYXRbMF0pIDpcbiAgICAgICAgICAgICAgICBjcmVhdGVGb3JtYXR0ZXIob3B0aW9ucy5zbG90TGFiZWxGb3JtYXQpO1xuICAgICAgICBsZXQgcmVuZGVyUHJvcHMgPSB7XG4gICAgICAgICAgICBsZXZlbDogMCxcbiAgICAgICAgICAgIHRpbWU6IHByb3BzLnRpbWUsXG4gICAgICAgICAgICBkYXRlOiBkYXRlRW52LnRvRGF0ZShwcm9wcy5kYXRlKSxcbiAgICAgICAgICAgIHZpZXc6IHZpZXdBcGksXG4gICAgICAgICAgICB0ZXh0OiBkYXRlRW52LmZvcm1hdChwcm9wcy5kYXRlLCBsYWJlbEZvcm1hdCksXG4gICAgICAgIH07XG4gICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChDb250ZW50Q29udGFpbmVyLCB7IGVsVGFnOiBcInRkXCIsIGVsQ2xhc3NlczogY2xhc3NOYW1lcywgZWxBdHRyczoge1xuICAgICAgICAgICAgICAgICdkYXRhLXRpbWUnOiBwcm9wcy5pc29UaW1lU3RyLFxuICAgICAgICAgICAgfSwgcmVuZGVyUHJvcHM6IHJlbmRlclByb3BzLCBnZW5lcmF0b3JOYW1lOiBcInNsb3RMYWJlbENvbnRlbnRcIiwgY3VzdG9tR2VuZXJhdG9yOiBvcHRpb25zLnNsb3RMYWJlbENvbnRlbnQsIGRlZmF1bHRHZW5lcmF0b3I6IHJlbmRlcklubmVyQ29udGVudCwgY2xhc3NOYW1lR2VuZXJhdG9yOiBvcHRpb25zLnNsb3RMYWJlbENsYXNzTmFtZXMsIGRpZE1vdW50OiBvcHRpb25zLnNsb3RMYWJlbERpZE1vdW50LCB3aWxsVW5tb3VudDogb3B0aW9ucy5zbG90TGFiZWxXaWxsVW5tb3VudCB9LCAoSW5uZXJDb250ZW50KSA9PiAoY3JlYXRlRWxlbWVudChcImRpdlwiLCB7IGNsYXNzTmFtZTogXCJmYy10aW1lZ3JpZC1zbG90LWxhYmVsLWZyYW1lIGZjLXNjcm9sbGdyaWQtc2hyaW5rLWZyYW1lXCIgfSxcbiAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoSW5uZXJDb250ZW50LCB7IGVsVGFnOiBcImRpdlwiLCBlbENsYXNzZXM6IFtcbiAgICAgICAgICAgICAgICAgICAgJ2ZjLXRpbWVncmlkLXNsb3QtbGFiZWwtY3VzaGlvbicsXG4gICAgICAgICAgICAgICAgICAgICdmYy1zY3JvbGxncmlkLXNocmluay1jdXNoaW9uJyxcbiAgICAgICAgICAgICAgICBdIH0pKSkpKTtcbiAgICB9KSk7XG59XG5mdW5jdGlvbiByZW5kZXJJbm5lckNvbnRlbnQocHJvcHMpIHtcbiAgICByZXR1cm4gcHJvcHMudGV4dDtcbn1cblxuY2xhc3MgVGltZUJvZHlBeGlzIGV4dGVuZHMgQmFzZUNvbXBvbmVudCB7XG4gICAgcmVuZGVyKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5wcm9wcy5zbGF0TWV0YXMubWFwKChzbGF0TWV0YSkgPT4gKGNyZWF0ZUVsZW1lbnQoXCJ0clwiLCB7IGtleTogc2xhdE1ldGEua2V5IH0sXG4gICAgICAgICAgICBjcmVhdGVFbGVtZW50KFRpbWVDb2xzQXhpc0NlbGwsIE9iamVjdC5hc3NpZ24oe30sIHNsYXRNZXRhKSkpKSk7XG4gICAgfVxufVxuXG5jb25zdCBERUZBVUxUX1dFRUtfTlVNX0ZPUk1BVCA9IGNyZWF0ZUZvcm1hdHRlcih7IHdlZWs6ICdzaG9ydCcgfSk7XG5jb25zdCBBVVRPX0FMTF9EQVlfTUFYX0VWRU5UX1JPV1MgPSA1O1xuY2xhc3MgVGltZUNvbHNWaWV3IGV4dGVuZHMgRGF0ZUNvbXBvbmVudCB7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKC4uLmFyZ3VtZW50cyk7XG4gICAgICAgIHRoaXMuYWxsRGF5U3BsaXR0ZXIgPSBuZXcgQWxsRGF5U3BsaXR0ZXIoKTsgLy8gZm9yIHVzZSBieSBzdWJjbGFzc2VzXG4gICAgICAgIHRoaXMuaGVhZGVyRWxSZWYgPSBjcmVhdGVSZWYoKTtcbiAgICAgICAgdGhpcy5yb290RWxSZWYgPSBjcmVhdGVSZWYoKTtcbiAgICAgICAgdGhpcy5zY3JvbGxlckVsUmVmID0gY3JlYXRlUmVmKCk7XG4gICAgICAgIHRoaXMuc3RhdGUgPSB7XG4gICAgICAgICAgICBzbGF0Q29vcmRzOiBudWxsLFxuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZVNjcm9sbFRvcFJlcXVlc3QgPSAoc2Nyb2xsVG9wKSA9PiB7XG4gICAgICAgICAgICBsZXQgc2Nyb2xsZXJFbCA9IHRoaXMuc2Nyb2xsZXJFbFJlZi5jdXJyZW50O1xuICAgICAgICAgICAgaWYgKHNjcm9sbGVyRWwpIHsgLy8gVE9ETzogbm90IHN1cmUgaG93IHRoaXMgY291bGQgZXZlciBiZSBudWxsLiB3ZWlyZG5lc3Mgd2l0aCB0aGUgcmVkdWNlclxuICAgICAgICAgICAgICAgIHNjcm9sbGVyRWwuc2Nyb2xsVG9wID0gc2Nyb2xsVG9wO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICAvKiBIZWFkZXIgUmVuZGVyIE1ldGhvZHNcbiAgICAgICAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbiAgICAgICAgdGhpcy5yZW5kZXJIZWFkQXhpcyA9IChyb3dLZXksIGZyYW1lSGVpZ2h0ID0gJycpID0+IHtcbiAgICAgICAgICAgIGxldCB7IG9wdGlvbnMgfSA9IHRoaXMuY29udGV4dDtcbiAgICAgICAgICAgIGxldCB7IGRhdGVQcm9maWxlIH0gPSB0aGlzLnByb3BzO1xuICAgICAgICAgICAgbGV0IHJhbmdlID0gZGF0ZVByb2ZpbGUucmVuZGVyUmFuZ2U7XG4gICAgICAgICAgICBsZXQgZGF5Q250ID0gZGlmZkRheXMocmFuZ2Uuc3RhcnQsIHJhbmdlLmVuZCk7XG4gICAgICAgICAgICAvLyBvbmx5IGRvIGluIGRheSB2aWV3cyAodG8gYXZvaWQgZG9pbmcgaW4gd2VlayB2aWV3cyB0aGF0IGRvbnQgbmVlZCBpdClcbiAgICAgICAgICAgIGxldCBuYXZMaW5rQXR0cnMgPSAoZGF5Q250ID09PSAxKVxuICAgICAgICAgICAgICAgID8gYnVpbGROYXZMaW5rQXR0cnModGhpcy5jb250ZXh0LCByYW5nZS5zdGFydCwgJ3dlZWsnKVxuICAgICAgICAgICAgICAgIDoge307XG4gICAgICAgICAgICBpZiAob3B0aW9ucy53ZWVrTnVtYmVycyAmJiByb3dLZXkgPT09ICdkYXknKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KFdlZWtOdW1iZXJDb250YWluZXIsIHsgZWxUYWc6IFwidGhcIiwgZWxDbGFzc2VzOiBbXG4gICAgICAgICAgICAgICAgICAgICAgICAnZmMtdGltZWdyaWQtYXhpcycsXG4gICAgICAgICAgICAgICAgICAgICAgICAnZmMtc2Nyb2xsZ3JpZC1zaHJpbmsnLFxuICAgICAgICAgICAgICAgICAgICBdLCBlbEF0dHJzOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAnYXJpYS1oaWRkZW4nOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICB9LCBkYXRlOiByYW5nZS5zdGFydCwgZGVmYXVsdEZvcm1hdDogREVGQVVMVF9XRUVLX05VTV9GT1JNQVQgfSwgKElubmVyQ29udGVudCkgPT4gKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IFtcbiAgICAgICAgICAgICAgICAgICAgICAgICdmYy10aW1lZ3JpZC1heGlzLWZyYW1lJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICdmYy1zY3JvbGxncmlkLXNocmluay1mcmFtZScsXG4gICAgICAgICAgICAgICAgICAgICAgICAnZmMtdGltZWdyaWQtYXhpcy1mcmFtZS1saXF1aWQnLFxuICAgICAgICAgICAgICAgICAgICBdLmpvaW4oJyAnKSwgc3R5bGU6IHsgaGVpZ2h0OiBmcmFtZUhlaWdodCB9IH0sXG4gICAgICAgICAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoSW5uZXJDb250ZW50LCB7IGVsVGFnOiBcImFcIiwgZWxDbGFzc2VzOiBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2ZjLXRpbWVncmlkLWF4aXMtY3VzaGlvbicsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2ZjLXNjcm9sbGdyaWQtc2hyaW5rLWN1c2hpb24nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICdmYy1zY3JvbGxncmlkLXN5bmMtaW5uZXInLFxuICAgICAgICAgICAgICAgICAgICAgICAgXSwgZWxBdHRyczogbmF2TGlua0F0dHJzIH0pKSkpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChcInRoXCIsIHsgXCJhcmlhLWhpZGRlblwiOiB0cnVlLCBjbGFzc05hbWU6IFwiZmMtdGltZWdyaWQtYXhpc1wiIH0sXG4gICAgICAgICAgICAgICAgY3JlYXRlRWxlbWVudChcImRpdlwiLCB7IGNsYXNzTmFtZTogXCJmYy10aW1lZ3JpZC1heGlzLWZyYW1lXCIsIHN0eWxlOiB7IGhlaWdodDogZnJhbWVIZWlnaHQgfSB9KSkpO1xuICAgICAgICB9O1xuICAgICAgICAvKiBUYWJsZSBDb21wb25lbnQgUmVuZGVyIE1ldGhvZHNcbiAgICAgICAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbiAgICAgICAgLy8gb25seSBhIG9uZS13YXkgaGVpZ2h0IHN5bmMuIHdlIGRvbid0IHNlbmQgdGhlIGF4aXMgaW5uZXItY29udGVudCBoZWlnaHQgdG8gdGhlIERheUdyaWQsXG4gICAgICAgIC8vIGJ1dCBEYXlHcmlkIHN0aWxsIG5lZWRzIHRvIGhhdmUgY2xhc3NOYW1lcyBvbiBpbm5lciBlbGVtZW50cyBpbiBvcmRlciB0byBtZWFzdXJlLlxuICAgICAgICB0aGlzLnJlbmRlclRhYmxlUm93QXhpcyA9IChyb3dIZWlnaHQpID0+IHtcbiAgICAgICAgICAgIGxldCB7IG9wdGlvbnMsIHZpZXdBcGkgfSA9IHRoaXMuY29udGV4dDtcbiAgICAgICAgICAgIGxldCByZW5kZXJQcm9wcyA9IHtcbiAgICAgICAgICAgICAgICB0ZXh0OiBvcHRpb25zLmFsbERheVRleHQsXG4gICAgICAgICAgICAgICAgdmlldzogdmlld0FwaSxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgLy8gVE9ETzogbWFrZSByZXVzYWJsZSBob29rLiB1c2VkIGluIGxpc3QgdmlldyB0b29cbiAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoQ29udGVudENvbnRhaW5lciwgeyBlbFRhZzogXCJ0ZFwiLCBlbENsYXNzZXM6IFtcbiAgICAgICAgICAgICAgICAgICAgJ2ZjLXRpbWVncmlkLWF4aXMnLFxuICAgICAgICAgICAgICAgICAgICAnZmMtc2Nyb2xsZ3JpZC1zaHJpbmsnLFxuICAgICAgICAgICAgICAgIF0sIGVsQXR0cnM6IHtcbiAgICAgICAgICAgICAgICAgICAgJ2FyaWEtaGlkZGVuJzogdHJ1ZSxcbiAgICAgICAgICAgICAgICB9LCByZW5kZXJQcm9wczogcmVuZGVyUHJvcHMsIGdlbmVyYXRvck5hbWU6IFwiYWxsRGF5Q29udGVudFwiLCBjdXN0b21HZW5lcmF0b3I6IG9wdGlvbnMuYWxsRGF5Q29udGVudCwgZGVmYXVsdEdlbmVyYXRvcjogcmVuZGVyQWxsRGF5SW5uZXIsIGNsYXNzTmFtZUdlbmVyYXRvcjogb3B0aW9ucy5hbGxEYXlDbGFzc05hbWVzLCBkaWRNb3VudDogb3B0aW9ucy5hbGxEYXlEaWRNb3VudCwgd2lsbFVubW91bnQ6IG9wdGlvbnMuYWxsRGF5V2lsbFVubW91bnQgfSwgKElubmVyQ29udGVudCkgPT4gKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IFtcbiAgICAgICAgICAgICAgICAgICAgJ2ZjLXRpbWVncmlkLWF4aXMtZnJhbWUnLFxuICAgICAgICAgICAgICAgICAgICAnZmMtc2Nyb2xsZ3JpZC1zaHJpbmstZnJhbWUnLFxuICAgICAgICAgICAgICAgICAgICByb3dIZWlnaHQgPT0gbnVsbCA/ICcgZmMtdGltZWdyaWQtYXhpcy1mcmFtZS1saXF1aWQnIDogJycsXG4gICAgICAgICAgICAgICAgXS5qb2luKCcgJyksIHN0eWxlOiB7IGhlaWdodDogcm93SGVpZ2h0IH0gfSxcbiAgICAgICAgICAgICAgICBjcmVhdGVFbGVtZW50KElubmVyQ29udGVudCwgeyBlbFRhZzogXCJzcGFuXCIsIGVsQ2xhc3NlczogW1xuICAgICAgICAgICAgICAgICAgICAgICAgJ2ZjLXRpbWVncmlkLWF4aXMtY3VzaGlvbicsXG4gICAgICAgICAgICAgICAgICAgICAgICAnZmMtc2Nyb2xsZ3JpZC1zaHJpbmstY3VzaGlvbicsXG4gICAgICAgICAgICAgICAgICAgICAgICAnZmMtc2Nyb2xsZ3JpZC1zeW5jLWlubmVyJyxcbiAgICAgICAgICAgICAgICAgICAgXSB9KSkpKSk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaGFuZGxlU2xhdENvb3JkcyA9IChzbGF0Q29vcmRzKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHsgc2xhdENvb3JkcyB9KTtcbiAgICAgICAgfTtcbiAgICB9XG4gICAgLy8gcmVuZGVyaW5nXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIHJlbmRlclNpbXBsZUxheW91dChoZWFkZXJSb3dDb250ZW50LCBhbGxEYXlDb250ZW50LCB0aW1lQ29udGVudCkge1xuICAgICAgICBsZXQgeyBjb250ZXh0LCBwcm9wcyB9ID0gdGhpcztcbiAgICAgICAgbGV0IHNlY3Rpb25zID0gW107XG4gICAgICAgIGxldCBzdGlja3lIZWFkZXJEYXRlcyA9IGdldFN0aWNreUhlYWRlckRhdGVzKGNvbnRleHQub3B0aW9ucyk7XG4gICAgICAgIGlmIChoZWFkZXJSb3dDb250ZW50KSB7XG4gICAgICAgICAgICBzZWN0aW9ucy5wdXNoKHtcbiAgICAgICAgICAgICAgICB0eXBlOiAnaGVhZGVyJyxcbiAgICAgICAgICAgICAgICBrZXk6ICdoZWFkZXInLFxuICAgICAgICAgICAgICAgIGlzU3RpY2t5OiBzdGlja3lIZWFkZXJEYXRlcyxcbiAgICAgICAgICAgICAgICBjaHVuazoge1xuICAgICAgICAgICAgICAgICAgICBlbFJlZjogdGhpcy5oZWFkZXJFbFJlZixcbiAgICAgICAgICAgICAgICAgICAgdGFibGVDbGFzc05hbWU6ICdmYy1jb2wtaGVhZGVyJyxcbiAgICAgICAgICAgICAgICAgICAgcm93Q29udGVudDogaGVhZGVyUm93Q29udGVudCxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGFsbERheUNvbnRlbnQpIHtcbiAgICAgICAgICAgIHNlY3Rpb25zLnB1c2goe1xuICAgICAgICAgICAgICAgIHR5cGU6ICdib2R5JyxcbiAgICAgICAgICAgICAgICBrZXk6ICdhbGwtZGF5JyxcbiAgICAgICAgICAgICAgICBjaHVuazogeyBjb250ZW50OiBhbGxEYXlDb250ZW50IH0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHNlY3Rpb25zLnB1c2goe1xuICAgICAgICAgICAgICAgIHR5cGU6ICdib2R5JyxcbiAgICAgICAgICAgICAgICBrZXk6ICdhbGwtZGF5LWRpdmlkZXInLFxuICAgICAgICAgICAgICAgIG91dGVyQ29udGVudDogKCAvLyBUT0RPOiByZW5hbWUgdG8gY2VsbENvbnRlbnQgc28gZG9uJ3QgbmVlZCB0byBkZWZpbmUgPHRyPj9cbiAgICAgICAgICAgICAgICBjcmVhdGVFbGVtZW50KFwidHJcIiwgeyByb2xlOiBcInByZXNlbnRhdGlvblwiLCBjbGFzc05hbWU6IFwiZmMtc2Nyb2xsZ3JpZC1zZWN0aW9uXCIgfSxcbiAgICAgICAgICAgICAgICAgICAgY3JlYXRlRWxlbWVudChcInRkXCIsIHsgY2xhc3NOYW1lOiAnZmMtdGltZWdyaWQtZGl2aWRlciAnICsgY29udGV4dC50aGVtZS5nZXRDbGFzcygndGFibGVDZWxsU2hhZGVkJykgfSkpKSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHNlY3Rpb25zLnB1c2goe1xuICAgICAgICAgICAgdHlwZTogJ2JvZHknLFxuICAgICAgICAgICAga2V5OiAnYm9keScsXG4gICAgICAgICAgICBsaXF1aWQ6IHRydWUsXG4gICAgICAgICAgICBleHBhbmRSb3dzOiBCb29sZWFuKGNvbnRleHQub3B0aW9ucy5leHBhbmRSb3dzKSxcbiAgICAgICAgICAgIGNodW5rOiB7XG4gICAgICAgICAgICAgICAgc2Nyb2xsZXJFbFJlZjogdGhpcy5zY3JvbGxlckVsUmVmLFxuICAgICAgICAgICAgICAgIGNvbnRlbnQ6IHRpbWVDb250ZW50LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChWaWV3Q29udGFpbmVyLCB7IGVsUmVmOiB0aGlzLnJvb3RFbFJlZiwgZWxDbGFzc2VzOiBbJ2ZjLXRpbWVncmlkJ10sIHZpZXdTcGVjOiBjb250ZXh0LnZpZXdTcGVjIH0sXG4gICAgICAgICAgICBjcmVhdGVFbGVtZW50KFNpbXBsZVNjcm9sbEdyaWQsIHsgbGlxdWlkOiAhcHJvcHMuaXNIZWlnaHRBdXRvICYmICFwcm9wcy5mb3JQcmludCwgY29sbGFwc2libGVXaWR0aDogcHJvcHMuZm9yUHJpbnQsIGNvbHM6IFt7IHdpZHRoOiAnc2hyaW5rJyB9XSwgc2VjdGlvbnM6IHNlY3Rpb25zIH0pKSk7XG4gICAgfVxuICAgIHJlbmRlckhTY3JvbGxMYXlvdXQoaGVhZGVyUm93Q29udGVudCwgYWxsRGF5Q29udGVudCwgdGltZUNvbnRlbnQsIGNvbENudCwgZGF5TWluV2lkdGgsIHNsYXRNZXRhcywgc2xhdENvb3Jkcykge1xuICAgICAgICBsZXQgU2Nyb2xsR3JpZCA9IHRoaXMuY29udGV4dC5wbHVnaW5Ib29rcy5zY3JvbGxHcmlkSW1wbDtcbiAgICAgICAgaWYgKCFTY3JvbGxHcmlkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIFNjcm9sbEdyaWQgaW1wbGVtZW50YXRpb24nKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgeyBjb250ZXh0LCBwcm9wcyB9ID0gdGhpcztcbiAgICAgICAgbGV0IHN0aWNreUhlYWRlckRhdGVzID0gIXByb3BzLmZvclByaW50ICYmIGdldFN0aWNreUhlYWRlckRhdGVzKGNvbnRleHQub3B0aW9ucyk7XG4gICAgICAgIGxldCBzdGlja3lGb290ZXJTY3JvbGxiYXIgPSAhcHJvcHMuZm9yUHJpbnQgJiYgZ2V0U3RpY2t5Rm9vdGVyU2Nyb2xsYmFyKGNvbnRleHQub3B0aW9ucyk7XG4gICAgICAgIGxldCBzZWN0aW9ucyA9IFtdO1xuICAgICAgICBpZiAoaGVhZGVyUm93Q29udGVudCkge1xuICAgICAgICAgICAgc2VjdGlvbnMucHVzaCh7XG4gICAgICAgICAgICAgICAgdHlwZTogJ2hlYWRlcicsXG4gICAgICAgICAgICAgICAga2V5OiAnaGVhZGVyJyxcbiAgICAgICAgICAgICAgICBpc1N0aWNreTogc3RpY2t5SGVhZGVyRGF0ZXMsXG4gICAgICAgICAgICAgICAgc3luY1Jvd0hlaWdodHM6IHRydWUsXG4gICAgICAgICAgICAgICAgY2h1bmtzOiBbXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGtleTogJ2F4aXMnLFxuICAgICAgICAgICAgICAgICAgICAgICAgcm93Q29udGVudDogKGFyZykgPT4gKGNyZWF0ZUVsZW1lbnQoXCJ0clwiLCB7IHJvbGU6IFwicHJlc2VudGF0aW9uXCIgfSwgdGhpcy5yZW5kZXJIZWFkQXhpcygnZGF5JywgYXJnLnJvd1N5bmNIZWlnaHRzWzBdKSkpLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBrZXk6ICdjb2xzJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsUmVmOiB0aGlzLmhlYWRlckVsUmVmLFxuICAgICAgICAgICAgICAgICAgICAgICAgdGFibGVDbGFzc05hbWU6ICdmYy1jb2wtaGVhZGVyJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJvd0NvbnRlbnQ6IGhlYWRlclJvd0NvbnRlbnQsXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGlmIChhbGxEYXlDb250ZW50KSB7XG4gICAgICAgICAgICBzZWN0aW9ucy5wdXNoKHtcbiAgICAgICAgICAgICAgICB0eXBlOiAnYm9keScsXG4gICAgICAgICAgICAgICAga2V5OiAnYWxsLWRheScsXG4gICAgICAgICAgICAgICAgc3luY1Jvd0hlaWdodHM6IHRydWUsXG4gICAgICAgICAgICAgICAgY2h1bmtzOiBbXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGtleTogJ2F4aXMnLFxuICAgICAgICAgICAgICAgICAgICAgICAgcm93Q29udGVudDogKGNvbnRlbnRBcmcpID0+IChjcmVhdGVFbGVtZW50KFwidHJcIiwgeyByb2xlOiBcInByZXNlbnRhdGlvblwiIH0sIHRoaXMucmVuZGVyVGFibGVSb3dBeGlzKGNvbnRlbnRBcmcucm93U3luY0hlaWdodHNbMF0pKSksXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGtleTogJ2NvbHMnLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29udGVudDogYWxsRGF5Q29udGVudCxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBzZWN0aW9ucy5wdXNoKHtcbiAgICAgICAgICAgICAgICBrZXk6ICdhbGwtZGF5LWRpdmlkZXInLFxuICAgICAgICAgICAgICAgIHR5cGU6ICdib2R5JyxcbiAgICAgICAgICAgICAgICBvdXRlckNvbnRlbnQ6ICggLy8gVE9ETzogcmVuYW1lIHRvIGNlbGxDb250ZW50IHNvIGRvbid0IG5lZWQgdG8gZGVmaW5lIDx0cj4/XG4gICAgICAgICAgICAgICAgY3JlYXRlRWxlbWVudChcInRyXCIsIHsgcm9sZTogXCJwcmVzZW50YXRpb25cIiwgY2xhc3NOYW1lOiBcImZjLXNjcm9sbGdyaWQtc2VjdGlvblwiIH0sXG4gICAgICAgICAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoXCJ0ZFwiLCB7IGNvbFNwYW46IDIsIGNsYXNzTmFtZTogJ2ZjLXRpbWVncmlkLWRpdmlkZXIgJyArIGNvbnRleHQudGhlbWUuZ2V0Q2xhc3MoJ3RhYmxlQ2VsbFNoYWRlZCcpIH0pKSksXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgaXNOb3dJbmRpY2F0b3IgPSBjb250ZXh0Lm9wdGlvbnMubm93SW5kaWNhdG9yO1xuICAgICAgICBzZWN0aW9ucy5wdXNoKHtcbiAgICAgICAgICAgIHR5cGU6ICdib2R5JyxcbiAgICAgICAgICAgIGtleTogJ2JvZHknLFxuICAgICAgICAgICAgbGlxdWlkOiB0cnVlLFxuICAgICAgICAgICAgZXhwYW5kUm93czogQm9vbGVhbihjb250ZXh0Lm9wdGlvbnMuZXhwYW5kUm93cyksXG4gICAgICAgICAgICBjaHVua3M6IFtcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGtleTogJ2F4aXMnLFxuICAgICAgICAgICAgICAgICAgICBjb250ZW50OiAoYXJnKSA9PiAoXG4gICAgICAgICAgICAgICAgICAgIC8vIFRPRE86IG1ha2UgdGhpcyBub3ctaW5kaWNhdG9yIGFycm93IG1vcmUgRFJZIHdpdGggVGltZUNvbHNDb250ZW50XG4gICAgICAgICAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IFwiZmMtdGltZWdyaWQtYXhpcy1jaHVua1wiIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICBjcmVhdGVFbGVtZW50KFwidGFibGVcIiwgeyBcImFyaWEtaGlkZGVuXCI6IHRydWUsIHN0eWxlOiB7IGhlaWdodDogYXJnLmV4cGFuZFJvd3MgPyBhcmcuY2xpZW50SGVpZ2h0IDogJycgfSB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyZy50YWJsZUNvbEdyb3VwTm9kZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcmVhdGVFbGVtZW50KFwidGJvZHlcIiwgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3JlYXRlRWxlbWVudChUaW1lQm9keUF4aXMsIHsgc2xhdE1ldGFzOiBzbGF0TWV0YXMgfSkpKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IFwiZmMtdGltZWdyaWQtbm93LWluZGljYXRvci1jb250YWluZXJcIiB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoTm93VGltZXIsIHsgdW5pdDogaXNOb3dJbmRpY2F0b3IgPyAnbWludXRlJyA6ICdkYXknIC8qIGhhY2t5ICovIH0sIChub3dEYXRlKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldCBub3dJbmRpY2F0b3JUb3AgPSBpc05vd0luZGljYXRvciAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xhdENvb3JkcyAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xhdENvb3Jkcy5zYWZlQ29tcHV0ZVRvcChub3dEYXRlKTsgLy8gbWlnaHQgcmV0dXJuIHZvaWRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBub3dJbmRpY2F0b3JUb3AgPT09ICdudW1iZXInKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoTm93SW5kaWNhdG9yQ29udGFpbmVyLCB7IGVsQ2xhc3NlczogWydmYy10aW1lZ3JpZC1ub3ctaW5kaWNhdG9yLWFycm93J10sIGVsU3R5bGU6IHsgdG9wOiBub3dJbmRpY2F0b3JUb3AgfSwgaXNBeGlzOiB0cnVlLCBkYXRlOiBub3dEYXRlIH0pKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSkpKSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAga2V5OiAnY29scycsXG4gICAgICAgICAgICAgICAgICAgIHNjcm9sbGVyRWxSZWY6IHRoaXMuc2Nyb2xsZXJFbFJlZixcbiAgICAgICAgICAgICAgICAgICAgY29udGVudDogdGltZUNvbnRlbnQsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoc3RpY2t5Rm9vdGVyU2Nyb2xsYmFyKSB7XG4gICAgICAgICAgICBzZWN0aW9ucy5wdXNoKHtcbiAgICAgICAgICAgICAgICBrZXk6ICdmb290ZXInLFxuICAgICAgICAgICAgICAgIHR5cGU6ICdmb290ZXInLFxuICAgICAgICAgICAgICAgIGlzU3RpY2t5OiB0cnVlLFxuICAgICAgICAgICAgICAgIGNodW5rczogW1xuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBrZXk6ICdheGlzJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRlbnQ6IHJlbmRlclNjcm9sbFNoaW0sXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGtleTogJ2NvbHMnLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29udGVudDogcmVuZGVyU2Nyb2xsU2hpbSxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KFZpZXdDb250YWluZXIsIHsgZWxSZWY6IHRoaXMucm9vdEVsUmVmLCBlbENsYXNzZXM6IFsnZmMtdGltZWdyaWQnXSwgdmlld1NwZWM6IGNvbnRleHQudmlld1NwZWMgfSxcbiAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoU2Nyb2xsR3JpZCwgeyBsaXF1aWQ6ICFwcm9wcy5pc0hlaWdodEF1dG8gJiYgIXByb3BzLmZvclByaW50LCBmb3JQcmludDogcHJvcHMuZm9yUHJpbnQsIGNvbGxhcHNpYmxlV2lkdGg6IGZhbHNlLCBjb2xHcm91cHM6IFtcbiAgICAgICAgICAgICAgICAgICAgeyB3aWR0aDogJ3NocmluaycsIGNvbHM6IFt7IHdpZHRoOiAnc2hyaW5rJyB9XSB9LFxuICAgICAgICAgICAgICAgICAgICB7IGNvbHM6IFt7IHNwYW46IGNvbENudCwgbWluV2lkdGg6IGRheU1pbldpZHRoIH1dIH0sXG4gICAgICAgICAgICAgICAgXSwgc2VjdGlvbnM6IHNlY3Rpb25zIH0pKSk7XG4gICAgfVxuICAgIC8qIERpbWVuc2lvbnNcbiAgICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuICAgIGdldEFsbERheU1heEV2ZW50UHJvcHMoKSB7XG4gICAgICAgIGxldCB7IGRheU1heEV2ZW50cywgZGF5TWF4RXZlbnRSb3dzIH0gPSB0aGlzLmNvbnRleHQub3B0aW9ucztcbiAgICAgICAgaWYgKGRheU1heEV2ZW50cyA9PT0gdHJ1ZSB8fCBkYXlNYXhFdmVudFJvd3MgPT09IHRydWUpIHsgLy8gaXMgYXV0bz9cbiAgICAgICAgICAgIGRheU1heEV2ZW50cyA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIGRheU1heEV2ZW50Um93cyA9IEFVVE9fQUxMX0RBWV9NQVhfRVZFTlRfUk9XUzsgLy8gbWFrZSBzdXJlIFwiYXV0b1wiIGdvZXMgdG8gYSByZWFsIG51bWJlclxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IGRheU1heEV2ZW50cywgZGF5TWF4RXZlbnRSb3dzIH07XG4gICAgfVxufVxuZnVuY3Rpb24gcmVuZGVyQWxsRGF5SW5uZXIocmVuZGVyUHJvcHMpIHtcbiAgICByZXR1cm4gcmVuZGVyUHJvcHMudGV4dDtcbn1cblxuY2xhc3MgVGltZUNvbHNTbGF0c0Nvb3JkcyB7XG4gICAgY29uc3RydWN0b3IocG9zaXRpb25zLCBkYXRlUHJvZmlsZSwgc2xvdER1cmF0aW9uKSB7XG4gICAgICAgIHRoaXMucG9zaXRpb25zID0gcG9zaXRpb25zO1xuICAgICAgICB0aGlzLmRhdGVQcm9maWxlID0gZGF0ZVByb2ZpbGU7XG4gICAgICAgIHRoaXMuc2xvdER1cmF0aW9uID0gc2xvdER1cmF0aW9uO1xuICAgIH1cbiAgICBzYWZlQ29tcHV0ZVRvcChkYXRlKSB7XG4gICAgICAgIGxldCB7IGRhdGVQcm9maWxlIH0gPSB0aGlzO1xuICAgICAgICBpZiAocmFuZ2VDb250YWluc01hcmtlcihkYXRlUHJvZmlsZS5jdXJyZW50UmFuZ2UsIGRhdGUpKSB7XG4gICAgICAgICAgICBsZXQgc3RhcnRPZkRheURhdGUgPSBzdGFydE9mRGF5KGRhdGUpO1xuICAgICAgICAgICAgbGV0IHRpbWVNcyA9IGRhdGUudmFsdWVPZigpIC0gc3RhcnRPZkRheURhdGUudmFsdWVPZigpO1xuICAgICAgICAgICAgaWYgKHRpbWVNcyA+PSBhc1JvdWdoTXMoZGF0ZVByb2ZpbGUuc2xvdE1pblRpbWUpICYmXG4gICAgICAgICAgICAgICAgdGltZU1zIDwgYXNSb3VnaE1zKGRhdGVQcm9maWxlLnNsb3RNYXhUaW1lKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbXB1dGVUaW1lVG9wKGNyZWF0ZUR1cmF0aW9uKHRpbWVNcykpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICAvLyBDb21wdXRlcyB0aGUgdG9wIGNvb3JkaW5hdGUsIHJlbGF0aXZlIHRvIHRoZSBib3VuZHMgb2YgdGhlIGdyaWQsIG9mIHRoZSBnaXZlbiBkYXRlLlxuICAgIC8vIEEgYHN0YXJ0T2ZEYXlEYXRlYCBtdXN0IGJlIGdpdmVuIGZvciBhdm9pZGluZyBhbWJpZ3VpdHkgb3ZlciBob3cgdG8gdHJlYXQgbWlkbmlnaHQuXG4gICAgY29tcHV0ZURhdGVUb3Aod2hlbiwgc3RhcnRPZkRheURhdGUpIHtcbiAgICAgICAgaWYgKCFzdGFydE9mRGF5RGF0ZSkge1xuICAgICAgICAgICAgc3RhcnRPZkRheURhdGUgPSBzdGFydE9mRGF5KHdoZW4pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLmNvbXB1dGVUaW1lVG9wKGNyZWF0ZUR1cmF0aW9uKHdoZW4udmFsdWVPZigpIC0gc3RhcnRPZkRheURhdGUudmFsdWVPZigpKSk7XG4gICAgfVxuICAgIC8vIENvbXB1dGVzIHRoZSB0b3AgY29vcmRpbmF0ZSwgcmVsYXRpdmUgdG8gdGhlIGJvdW5kcyBvZiB0aGUgZ3JpZCwgb2YgdGhlIGdpdmVuIHRpbWUgKGEgRHVyYXRpb24pLlxuICAgIC8vIFRoaXMgaXMgYSBtYWtlc2hpZnkgd2F5IHRvIGNvbXB1dGUgdGhlIHRpbWUtdG9wLiBBc3N1bWVzIGFsbCBzbGF0TWV0YXMgZGF0ZXMgYXJlIHVuaWZvcm0uXG4gICAgLy8gRXZlbnR1YWxseSBhbGxvdyBjb21wdXRhdGlvbiB3aXRoIGFyYmlyYXJ5IHNsYXQgZGF0ZXMuXG4gICAgY29tcHV0ZVRpbWVUb3AoZHVyYXRpb24pIHtcbiAgICAgICAgbGV0IHsgcG9zaXRpb25zLCBkYXRlUHJvZmlsZSB9ID0gdGhpcztcbiAgICAgICAgbGV0IGxlbiA9IHBvc2l0aW9ucy5lbHMubGVuZ3RoO1xuICAgICAgICAvLyBmbG9hdGluZy1wb2ludCB2YWx1ZSBvZiAjIG9mIHNsb3RzIGNvdmVyZWRcbiAgICAgICAgbGV0IHNsYXRDb3ZlcmFnZSA9IChkdXJhdGlvbi5taWxsaXNlY29uZHMgLSBhc1JvdWdoTXMoZGF0ZVByb2ZpbGUuc2xvdE1pblRpbWUpKSAvIGFzUm91Z2hNcyh0aGlzLnNsb3REdXJhdGlvbik7XG4gICAgICAgIGxldCBzbGF0SW5kZXg7XG4gICAgICAgIGxldCBzbGF0UmVtYWluZGVyO1xuICAgICAgICAvLyBjb21wdXRlIGEgZmxvYXRpbmctcG9pbnQgbnVtYmVyIGZvciBob3cgbWFueSBzbGF0cyBzaG91bGQgYmUgcHJvZ3Jlc3NlZCB0aHJvdWdoLlxuICAgICAgICAvLyBmcm9tIDAgdG8gbnVtYmVyIG9mIHNsYXRzIChpbmNsdXNpdmUpXG4gICAgICAgIC8vIGNvbnN0cmFpbmVkIGJlY2F1c2Ugc2xvdE1pblRpbWUvc2xvdE1heFRpbWUgbWlnaHQgYmUgY3VzdG9taXplZC5cbiAgICAgICAgc2xhdENvdmVyYWdlID0gTWF0aC5tYXgoMCwgc2xhdENvdmVyYWdlKTtcbiAgICAgICAgc2xhdENvdmVyYWdlID0gTWF0aC5taW4obGVuLCBzbGF0Q292ZXJhZ2UpO1xuICAgICAgICAvLyBhbiBpbnRlZ2VyIGluZGV4IG9mIHRoZSBmdXJ0aGVzdCB3aG9sZSBzbGF0XG4gICAgICAgIC8vIGZyb20gMCB0byBudW1iZXIgc2xhdHMgKCpleGNsdXNpdmUqLCBzbyBsZW4tMSlcbiAgICAgICAgc2xhdEluZGV4ID0gTWF0aC5mbG9vcihzbGF0Q292ZXJhZ2UpO1xuICAgICAgICBzbGF0SW5kZXggPSBNYXRoLm1pbihzbGF0SW5kZXgsIGxlbiAtIDEpO1xuICAgICAgICAvLyBob3cgbXVjaCBmdXJ0aGVyIHRocm91Z2ggdGhlIHNsYXRJbmRleCBzbGF0IChmcm9tIDAuMC0xLjApIG11c3QgYmUgY292ZXJlZCBpbiBhZGRpdGlvbi5cbiAgICAgICAgLy8gY291bGQgYmUgMS4wIGlmIHNsYXRDb3ZlcmFnZSBpcyBjb3ZlcmluZyAqYWxsKiB0aGUgc2xvdHNcbiAgICAgICAgc2xhdFJlbWFpbmRlciA9IHNsYXRDb3ZlcmFnZSAtIHNsYXRJbmRleDtcbiAgICAgICAgcmV0dXJuIHBvc2l0aW9ucy50b3BzW3NsYXRJbmRleF0gK1xuICAgICAgICAgICAgcG9zaXRpb25zLmdldEhlaWdodChzbGF0SW5kZXgpICogc2xhdFJlbWFpbmRlcjtcbiAgICB9XG59XG5cbmNsYXNzIFRpbWVDb2xzU2xhdHNCb2R5IGV4dGVuZHMgQmFzZUNvbXBvbmVudCB7XG4gICAgcmVuZGVyKCkge1xuICAgICAgICBsZXQgeyBwcm9wcywgY29udGV4dCB9ID0gdGhpcztcbiAgICAgICAgbGV0IHsgb3B0aW9ucyB9ID0gY29udGV4dDtcbiAgICAgICAgbGV0IHsgc2xhdEVsUmVmcyB9ID0gcHJvcHM7XG4gICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChcInRib2R5XCIsIG51bGwsIHByb3BzLnNsYXRNZXRhcy5tYXAoKHNsYXRNZXRhLCBpKSA9PiB7XG4gICAgICAgICAgICBsZXQgcmVuZGVyUHJvcHMgPSB7XG4gICAgICAgICAgICAgICAgdGltZTogc2xhdE1ldGEudGltZSxcbiAgICAgICAgICAgICAgICBkYXRlOiBjb250ZXh0LmRhdGVFbnYudG9EYXRlKHNsYXRNZXRhLmRhdGUpLFxuICAgICAgICAgICAgICAgIHZpZXc6IGNvbnRleHQudmlld0FwaSxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoXCJ0clwiLCB7IGtleTogc2xhdE1ldGEua2V5LCByZWY6IHNsYXRFbFJlZnMuY3JlYXRlUmVmKHNsYXRNZXRhLmtleSkgfSxcbiAgICAgICAgICAgICAgICBwcm9wcy5heGlzICYmIChjcmVhdGVFbGVtZW50KFRpbWVDb2xzQXhpc0NlbGwsIE9iamVjdC5hc3NpZ24oe30sIHNsYXRNZXRhKSkpLFxuICAgICAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoQ29udGVudENvbnRhaW5lciwgeyBlbFRhZzogXCJ0ZFwiLCBlbENsYXNzZXM6IFtcbiAgICAgICAgICAgICAgICAgICAgICAgICdmYy10aW1lZ3JpZC1zbG90JyxcbiAgICAgICAgICAgICAgICAgICAgICAgICdmYy10aW1lZ3JpZC1zbG90LWxhbmUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgIXNsYXRNZXRhLmlzTGFiZWxlZCAmJiAnZmMtdGltZWdyaWQtc2xvdC1taW5vcicsXG4gICAgICAgICAgICAgICAgICAgIF0sIGVsQXR0cnM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICdkYXRhLXRpbWUnOiBzbGF0TWV0YS5pc29UaW1lU3RyLFxuICAgICAgICAgICAgICAgICAgICB9LCByZW5kZXJQcm9wczogcmVuZGVyUHJvcHMsIGdlbmVyYXRvck5hbWU6IFwic2xvdExhbmVDb250ZW50XCIsIGN1c3RvbUdlbmVyYXRvcjogb3B0aW9ucy5zbG90TGFuZUNvbnRlbnQsIGNsYXNzTmFtZUdlbmVyYXRvcjogb3B0aW9ucy5zbG90TGFuZUNsYXNzTmFtZXMsIGRpZE1vdW50OiBvcHRpb25zLnNsb3RMYW5lRGlkTW91bnQsIHdpbGxVbm1vdW50OiBvcHRpb25zLnNsb3RMYW5lV2lsbFVubW91bnQgfSkpKTtcbiAgICAgICAgfSkpKTtcbiAgICB9XG59XG5cbi8qXG5mb3IgdGhlIGhvcml6b250YWwgXCJzbGF0c1wiIHRoYXQgcnVuIHdpZHRoLXdpc2UuIEhhcyBhIHRpbWUgYXhpcyBvbiBhIHNpZGUuIERlcGVuZHMgb24gUlRMLlxuKi9cbmNsYXNzIFRpbWVDb2xzU2xhdHMgZXh0ZW5kcyBCYXNlQ29tcG9uZW50IHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoLi4uYXJndW1lbnRzKTtcbiAgICAgICAgdGhpcy5yb290RWxSZWYgPSBjcmVhdGVSZWYoKTtcbiAgICAgICAgdGhpcy5zbGF0RWxSZWZzID0gbmV3IFJlZk1hcCgpO1xuICAgIH1cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGxldCB7IHByb3BzLCBjb250ZXh0IH0gPSB0aGlzO1xuICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyByZWY6IHRoaXMucm9vdEVsUmVmLCBjbGFzc05hbWU6IFwiZmMtdGltZWdyaWQtc2xvdHNcIiB9LFxuICAgICAgICAgICAgY3JlYXRlRWxlbWVudChcInRhYmxlXCIsIHsgXCJhcmlhLWhpZGRlblwiOiB0cnVlLCBjbGFzc05hbWU6IGNvbnRleHQudGhlbWUuZ2V0Q2xhc3MoJ3RhYmxlJyksIHN0eWxlOiB7XG4gICAgICAgICAgICAgICAgICAgIG1pbldpZHRoOiBwcm9wcy50YWJsZU1pbldpZHRoLFxuICAgICAgICAgICAgICAgICAgICB3aWR0aDogcHJvcHMuY2xpZW50V2lkdGgsXG4gICAgICAgICAgICAgICAgICAgIGhlaWdodDogcHJvcHMubWluSGVpZ2h0LFxuICAgICAgICAgICAgICAgIH0gfSxcbiAgICAgICAgICAgICAgICBwcm9wcy50YWJsZUNvbEdyb3VwTm9kZSAvKiByZWxpZXMgb24gdGhlcmUgb25seSBiZWluZyBhIHNpbmdsZSA8Y29sPiBmb3IgdGhlIGF4aXMgKi8sXG4gICAgICAgICAgICAgICAgY3JlYXRlRWxlbWVudChUaW1lQ29sc1NsYXRzQm9keSwgeyBzbGF0RWxSZWZzOiB0aGlzLnNsYXRFbFJlZnMsIGF4aXM6IHByb3BzLmF4aXMsIHNsYXRNZXRhczogcHJvcHMuc2xhdE1ldGFzIH0pKSkpO1xuICAgIH1cbiAgICBjb21wb25lbnREaWRNb3VudCgpIHtcbiAgICAgICAgdGhpcy51cGRhdGVTaXppbmcoKTtcbiAgICB9XG4gICAgY29tcG9uZW50RGlkVXBkYXRlKCkge1xuICAgICAgICB0aGlzLnVwZGF0ZVNpemluZygpO1xuICAgIH1cbiAgICBjb21wb25lbnRXaWxsVW5tb3VudCgpIHtcbiAgICAgICAgaWYgKHRoaXMucHJvcHMub25Db29yZHMpIHtcbiAgICAgICAgICAgIHRoaXMucHJvcHMub25Db29yZHMobnVsbCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgdXBkYXRlU2l6aW5nKCkge1xuICAgICAgICBsZXQgeyBjb250ZXh0LCBwcm9wcyB9ID0gdGhpcztcbiAgICAgICAgaWYgKHByb3BzLm9uQ29vcmRzICYmXG4gICAgICAgICAgICBwcm9wcy5jbGllbnRXaWR0aCAhPT0gbnVsbCAvLyBtZWFucyBzaXppbmcgaGFzIHN0YWJpbGl6ZWRcbiAgICAgICAgKSB7XG4gICAgICAgICAgICBsZXQgcm9vdEVsID0gdGhpcy5yb290RWxSZWYuY3VycmVudDtcbiAgICAgICAgICAgIGlmIChyb290RWwub2Zmc2V0SGVpZ2h0KSB7IC8vIG5vdCBoaWRkZW4gYnkgY3NzXG4gICAgICAgICAgICAgICAgcHJvcHMub25Db29yZHMobmV3IFRpbWVDb2xzU2xhdHNDb29yZHMobmV3IFBvc2l0aW9uQ2FjaGUodGhpcy5yb290RWxSZWYuY3VycmVudCwgY29sbGVjdFNsYXRFbHModGhpcy5zbGF0RWxSZWZzLmN1cnJlbnRNYXAsIHByb3BzLnNsYXRNZXRhcyksIGZhbHNlLCB0cnVlKSwgdGhpcy5wcm9wcy5kYXRlUHJvZmlsZSwgY29udGV4dC5vcHRpb25zLnNsb3REdXJhdGlvbikpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuZnVuY3Rpb24gY29sbGVjdFNsYXRFbHMoZWxNYXAsIHNsYXRNZXRhcykge1xuICAgIHJldHVybiBzbGF0TWV0YXMubWFwKChzbGF0TWV0YSkgPT4gZWxNYXBbc2xhdE1ldGEua2V5XSk7XG59XG5cbmZ1bmN0aW9uIHNwbGl0U2Vnc0J5Q29sKHNlZ3MsIGNvbENudCkge1xuICAgIGxldCBzZWdzQnlDb2wgPSBbXTtcbiAgICBsZXQgaTtcbiAgICBmb3IgKGkgPSAwOyBpIDwgY29sQ250OyBpICs9IDEpIHtcbiAgICAgICAgc2Vnc0J5Q29sLnB1c2goW10pO1xuICAgIH1cbiAgICBpZiAoc2Vncykge1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgc2Vncy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICAgICAgc2Vnc0J5Q29sW3NlZ3NbaV0uY29sXS5wdXNoKHNlZ3NbaV0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBzZWdzQnlDb2w7XG59XG5mdW5jdGlvbiBzcGxpdEludGVyYWN0aW9uQnlDb2wodWksIGNvbENudCkge1xuICAgIGxldCBieVJvdyA9IFtdO1xuICAgIGlmICghdWkpIHtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjb2xDbnQ7IGkgKz0gMSkge1xuICAgICAgICAgICAgYnlSb3dbaV0gPSBudWxsO1xuICAgICAgICB9XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNvbENudDsgaSArPSAxKSB7XG4gICAgICAgICAgICBieVJvd1tpXSA9IHtcbiAgICAgICAgICAgICAgICBhZmZlY3RlZEluc3RhbmNlczogdWkuYWZmZWN0ZWRJbnN0YW5jZXMsXG4gICAgICAgICAgICAgICAgaXNFdmVudDogdWkuaXNFdmVudCxcbiAgICAgICAgICAgICAgICBzZWdzOiBbXSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgZm9yIChsZXQgc2VnIG9mIHVpLnNlZ3MpIHtcbiAgICAgICAgICAgIGJ5Um93W3NlZy5jb2xdLnNlZ3MucHVzaChzZWcpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBieVJvdztcbn1cblxuY2xhc3MgVGltZUNvbE1vcmVMaW5rIGV4dGVuZHMgQmFzZUNvbXBvbmVudCB7XG4gICAgcmVuZGVyKCkge1xuICAgICAgICBsZXQgeyBwcm9wcyB9ID0gdGhpcztcbiAgICAgICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KE1vcmVMaW5rQ29udGFpbmVyLCB7IGVsQ2xhc3NlczogWydmYy10aW1lZ3JpZC1tb3JlLWxpbmsnXSwgZWxTdHlsZToge1xuICAgICAgICAgICAgICAgIHRvcDogcHJvcHMudG9wLFxuICAgICAgICAgICAgICAgIGJvdHRvbTogcHJvcHMuYm90dG9tLFxuICAgICAgICAgICAgfSwgYWxsRGF5RGF0ZTogbnVsbCwgbW9yZUNudDogcHJvcHMuaGlkZGVuU2Vncy5sZW5ndGgsIGFsbFNlZ3M6IHByb3BzLmhpZGRlblNlZ3MsIGhpZGRlblNlZ3M6IHByb3BzLmhpZGRlblNlZ3MsIGV4dHJhRGF0ZVNwYW46IHByb3BzLmV4dHJhRGF0ZVNwYW4sIGRhdGVQcm9maWxlOiBwcm9wcy5kYXRlUHJvZmlsZSwgdG9kYXlSYW5nZTogcHJvcHMudG9kYXlSYW5nZSwgcG9wb3ZlckNvbnRlbnQ6ICgpID0+IHJlbmRlclBsYWluRmdTZWdzKHByb3BzLmhpZGRlblNlZ3MsIHByb3BzKSwgZGVmYXVsdEdlbmVyYXRvcjogcmVuZGVyTW9yZUxpbmtJbm5lciwgZm9yY2VUaW1lZDogdHJ1ZSB9LCAoSW5uZXJDb250ZW50KSA9PiAoY3JlYXRlRWxlbWVudChJbm5lckNvbnRlbnQsIHsgZWxUYWc6IFwiZGl2XCIsIGVsQ2xhc3NlczogWydmYy10aW1lZ3JpZC1tb3JlLWxpbmstaW5uZXInLCAnZmMtc3RpY2t5J10gfSkpKSk7XG4gICAgfVxufVxuZnVuY3Rpb24gcmVuZGVyTW9yZUxpbmtJbm5lcihwcm9wcykge1xuICAgIHJldHVybiBwcm9wcy5zaG9ydFRleHQ7XG59XG5cbi8vIHNlZ0lucHV0cyBhc3N1bWVkIHNvcnRlZFxuZnVuY3Rpb24gYnVpbGRQb3NpdGlvbmluZyhzZWdJbnB1dHMsIHN0cmljdE9yZGVyLCBtYXhTdGFja0NudCkge1xuICAgIGxldCBoaWVyYXJjaHkgPSBuZXcgU2VnSGllcmFyY2h5KCk7XG4gICAgaWYgKHN0cmljdE9yZGVyICE9IG51bGwpIHtcbiAgICAgICAgaGllcmFyY2h5LnN0cmljdE9yZGVyID0gc3RyaWN0T3JkZXI7XG4gICAgfVxuICAgIGlmIChtYXhTdGFja0NudCAhPSBudWxsKSB7XG4gICAgICAgIGhpZXJhcmNoeS5tYXhTdGFja0NudCA9IG1heFN0YWNrQ250O1xuICAgIH1cbiAgICBsZXQgaGlkZGVuRW50cmllcyA9IGhpZXJhcmNoeS5hZGRTZWdzKHNlZ0lucHV0cyk7XG4gICAgbGV0IGhpZGRlbkdyb3VwcyA9IGdyb3VwSW50ZXJzZWN0aW5nRW50cmllcyhoaWRkZW5FbnRyaWVzKTtcbiAgICBsZXQgd2ViID0gYnVpbGRXZWIoaGllcmFyY2h5KTtcbiAgICB3ZWIgPSBzdHJldGNoV2ViKHdlYiwgMSk7IC8vIGFsbCBsZXZlbENvb3Jkcy90aGlja25lc3Mgd2lsbCBoYXZlIDAuMC0xLjBcbiAgICBsZXQgc2VnUmVjdHMgPSB3ZWJUb1JlY3RzKHdlYik7XG4gICAgcmV0dXJuIHsgc2VnUmVjdHMsIGhpZGRlbkdyb3VwcyB9O1xufVxuZnVuY3Rpb24gYnVpbGRXZWIoaGllcmFyY2h5KSB7XG4gICAgY29uc3QgeyBlbnRyaWVzQnlMZXZlbCB9ID0gaGllcmFyY2h5O1xuICAgIGNvbnN0IGJ1aWxkTm9kZSA9IGNhY2hlYWJsZSgobGV2ZWwsIGxhdGVyYWwpID0+IGxldmVsICsgJzonICsgbGF0ZXJhbCwgKGxldmVsLCBsYXRlcmFsKSA9PiB7XG4gICAgICAgIGxldCBzaWJsaW5nUmFuZ2UgPSBmaW5kTmV4dExldmVsU2VncyhoaWVyYXJjaHksIGxldmVsLCBsYXRlcmFsKTtcbiAgICAgICAgbGV0IG5leHRMZXZlbFJlcyA9IGJ1aWxkTm9kZXMoc2libGluZ1JhbmdlLCBidWlsZE5vZGUpO1xuICAgICAgICBsZXQgZW50cnkgPSBlbnRyaWVzQnlMZXZlbFtsZXZlbF1bbGF0ZXJhbF07XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGVudHJ5KSwgeyBuZXh0TGV2ZWxOb2RlczogbmV4dExldmVsUmVzWzBdIH0pLFxuICAgICAgICAgICAgZW50cnkudGhpY2tuZXNzICsgbmV4dExldmVsUmVzWzFdLCAvLyB0aGUgcHJlc3N1cmUgYnVpbGRzXG4gICAgICAgIF07XG4gICAgfSk7XG4gICAgcmV0dXJuIGJ1aWxkTm9kZXMoZW50cmllc0J5TGV2ZWwubGVuZ3RoXG4gICAgICAgID8geyBsZXZlbDogMCwgbGF0ZXJhbFN0YXJ0OiAwLCBsYXRlcmFsRW5kOiBlbnRyaWVzQnlMZXZlbFswXS5sZW5ndGggfVxuICAgICAgICA6IG51bGwsIGJ1aWxkTm9kZSlbMF07XG59XG5mdW5jdGlvbiBidWlsZE5vZGVzKHNpYmxpbmdSYW5nZSwgYnVpbGROb2RlKSB7XG4gICAgaWYgKCFzaWJsaW5nUmFuZ2UpIHtcbiAgICAgICAgcmV0dXJuIFtbXSwgMF07XG4gICAgfVxuICAgIGxldCB7IGxldmVsLCBsYXRlcmFsU3RhcnQsIGxhdGVyYWxFbmQgfSA9IHNpYmxpbmdSYW5nZTtcbiAgICBsZXQgbGF0ZXJhbCA9IGxhdGVyYWxTdGFydDtcbiAgICBsZXQgcGFpcnMgPSBbXTtcbiAgICB3aGlsZSAobGF0ZXJhbCA8IGxhdGVyYWxFbmQpIHtcbiAgICAgICAgcGFpcnMucHVzaChidWlsZE5vZGUobGV2ZWwsIGxhdGVyYWwpKTtcbiAgICAgICAgbGF0ZXJhbCArPSAxO1xuICAgIH1cbiAgICBwYWlycy5zb3J0KGNtcERlc2NQcmVzc3VyZXMpO1xuICAgIHJldHVybiBbXG4gICAgICAgIHBhaXJzLm1hcChleHRyYWN0Tm9kZSksXG4gICAgICAgIHBhaXJzWzBdWzFdLCAvLyBmaXJzdCBpdGVtJ3MgcHJlc3N1cmVcbiAgICBdO1xufVxuZnVuY3Rpb24gY21wRGVzY1ByZXNzdXJlcyhhLCBiKSB7XG4gICAgcmV0dXJuIGJbMV0gLSBhWzFdO1xufVxuZnVuY3Rpb24gZXh0cmFjdE5vZGUoYSkge1xuICAgIHJldHVybiBhWzBdO1xufVxuZnVuY3Rpb24gZmluZE5leHRMZXZlbFNlZ3MoaGllcmFyY2h5LCBzdWJqZWN0TGV2ZWwsIHN1YmplY3RMYXRlcmFsKSB7XG4gICAgbGV0IHsgbGV2ZWxDb29yZHMsIGVudHJpZXNCeUxldmVsIH0gPSBoaWVyYXJjaHk7XG4gICAgbGV0IHN1YmplY3RFbnRyeSA9IGVudHJpZXNCeUxldmVsW3N1YmplY3RMZXZlbF1bc3ViamVjdExhdGVyYWxdO1xuICAgIGxldCBhZnRlclN1YmplY3QgPSBsZXZlbENvb3Jkc1tzdWJqZWN0TGV2ZWxdICsgc3ViamVjdEVudHJ5LnRoaWNrbmVzcztcbiAgICBsZXQgbGV2ZWxDbnQgPSBsZXZlbENvb3Jkcy5sZW5ndGg7XG4gICAgbGV0IGxldmVsID0gc3ViamVjdExldmVsO1xuICAgIC8vIHNraXAgcGFzdCBsZXZlbHMgdGhhdCBhcmUgdG9vIGhpZ2ggdXBcbiAgICBmb3IgKDsgbGV2ZWwgPCBsZXZlbENudCAmJiBsZXZlbENvb3Jkc1tsZXZlbF0gPCBhZnRlclN1YmplY3Q7IGxldmVsICs9IDEpXG4gICAgICAgIDsgLy8gZG8gbm90aGluZ1xuICAgIGZvciAoOyBsZXZlbCA8IGxldmVsQ250OyBsZXZlbCArPSAxKSB7XG4gICAgICAgIGxldCBlbnRyaWVzID0gZW50cmllc0J5TGV2ZWxbbGV2ZWxdO1xuICAgICAgICBsZXQgZW50cnk7XG4gICAgICAgIGxldCBzZWFyY2hJbmRleCA9IGJpbmFyeVNlYXJjaChlbnRyaWVzLCBzdWJqZWN0RW50cnkuc3Bhbi5zdGFydCwgZ2V0RW50cnlTcGFuRW5kKTtcbiAgICAgICAgbGV0IGxhdGVyYWxTdGFydCA9IHNlYXJjaEluZGV4WzBdICsgc2VhcmNoSW5kZXhbMV07IC8vIGlmIGV4YWN0IG1hdGNoICh3aGljaCBkb2Vzbid0IGNvbGxpZGUpLCBnbyB0byBuZXh0IG9uZVxuICAgICAgICBsZXQgbGF0ZXJhbEVuZCA9IGxhdGVyYWxTdGFydDtcbiAgICAgICAgd2hpbGUgKCAvLyBsb29wIHRocm91Z2ggZW50cmllcyB0aGF0IGhvcml6b250YWxseSBpbnRlcnNlY3RcbiAgICAgICAgKGVudHJ5ID0gZW50cmllc1tsYXRlcmFsRW5kXSkgJiYgLy8gYnV0IG5vdCBwYXN0IHRoZSB3aG9sZSBzZWcgbGlzdFxuICAgICAgICAgICAgZW50cnkuc3Bhbi5zdGFydCA8IHN1YmplY3RFbnRyeS5zcGFuLmVuZCkge1xuICAgICAgICAgICAgbGF0ZXJhbEVuZCArPSAxO1xuICAgICAgICB9XG4gICAgICAgIGlmIChsYXRlcmFsU3RhcnQgPCBsYXRlcmFsRW5kKSB7XG4gICAgICAgICAgICByZXR1cm4geyBsZXZlbCwgbGF0ZXJhbFN0YXJ0LCBsYXRlcmFsRW5kIH07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG59XG5mdW5jdGlvbiBzdHJldGNoV2ViKHRvcExldmVsTm9kZXMsIHRvdGFsVGhpY2tuZXNzKSB7XG4gICAgY29uc3Qgc3RyZXRjaE5vZGUgPSBjYWNoZWFibGUoKG5vZGUsIHN0YXJ0Q29vcmQsIHByZXZUaGlja25lc3MpID0+IGJ1aWxkRW50cnlLZXkobm9kZSksIChub2RlLCBzdGFydENvb3JkLCBwcmV2VGhpY2tuZXNzKSA9PiB7XG4gICAgICAgIGxldCB7IG5leHRMZXZlbE5vZGVzLCB0aGlja25lc3MgfSA9IG5vZGU7XG4gICAgICAgIGxldCBhbGxUaGlja25lc3MgPSB0aGlja25lc3MgKyBwcmV2VGhpY2tuZXNzO1xuICAgICAgICBsZXQgdGhpY2tuZXNzRnJhY3Rpb24gPSB0aGlja25lc3MgLyBhbGxUaGlja25lc3M7XG4gICAgICAgIGxldCBlbmRDb29yZDtcbiAgICAgICAgbGV0IG5ld0NoaWxkcmVuID0gW107XG4gICAgICAgIGlmICghbmV4dExldmVsTm9kZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICBlbmRDb29yZCA9IHRvdGFsVGhpY2tuZXNzO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZm9yIChsZXQgY2hpbGROb2RlIG9mIG5leHRMZXZlbE5vZGVzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVuZENvb3JkID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHJlcyA9IHN0cmV0Y2hOb2RlKGNoaWxkTm9kZSwgc3RhcnRDb29yZCwgYWxsVGhpY2tuZXNzKTtcbiAgICAgICAgICAgICAgICAgICAgZW5kQ29vcmQgPSByZXNbMF07XG4gICAgICAgICAgICAgICAgICAgIG5ld0NoaWxkcmVuLnB1c2gocmVzWzFdKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCByZXMgPSBzdHJldGNoTm9kZShjaGlsZE5vZGUsIGVuZENvb3JkLCAwKTtcbiAgICAgICAgICAgICAgICAgICAgbmV3Q2hpbGRyZW4ucHVzaChyZXNbMV0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBsZXQgbmV3VGhpY2tuZXNzID0gKGVuZENvb3JkIC0gc3RhcnRDb29yZCkgKiB0aGlja25lc3NGcmFjdGlvbjtcbiAgICAgICAgcmV0dXJuIFtlbmRDb29yZCAtIG5ld1RoaWNrbmVzcywgT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBub2RlKSwgeyB0aGlja25lc3M6IG5ld1RoaWNrbmVzcywgbmV4dExldmVsTm9kZXM6IG5ld0NoaWxkcmVuIH0pXTtcbiAgICB9KTtcbiAgICByZXR1cm4gdG9wTGV2ZWxOb2Rlcy5tYXAoKG5vZGUpID0+IHN0cmV0Y2hOb2RlKG5vZGUsIDAsIDApWzFdKTtcbn1cbi8vIG5vdCBzb3J0ZWQgaW4gYW55IHBhcnRpY3VsYXIgb3JkZXJcbmZ1bmN0aW9uIHdlYlRvUmVjdHModG9wTGV2ZWxOb2Rlcykge1xuICAgIGxldCByZWN0cyA9IFtdO1xuICAgIGNvbnN0IHByb2Nlc3NOb2RlID0gY2FjaGVhYmxlKChub2RlLCBsZXZlbENvb3JkLCBzdGFja0RlcHRoKSA9PiBidWlsZEVudHJ5S2V5KG5vZGUpLCAobm9kZSwgbGV2ZWxDb29yZCwgc3RhY2tEZXB0aCkgPT4ge1xuICAgICAgICBsZXQgcmVjdCA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgbm9kZSksIHsgbGV2ZWxDb29yZCxcbiAgICAgICAgICAgIHN0YWNrRGVwdGgsIHN0YWNrRm9yd2FyZDogMCB9KTtcbiAgICAgICAgcmVjdHMucHVzaChyZWN0KTtcbiAgICAgICAgcmV0dXJuIChyZWN0LnN0YWNrRm9yd2FyZCA9IHByb2Nlc3NOb2Rlcyhub2RlLm5leHRMZXZlbE5vZGVzLCBsZXZlbENvb3JkICsgbm9kZS50aGlja25lc3MsIHN0YWNrRGVwdGggKyAxKSArIDEpO1xuICAgIH0pO1xuICAgIGZ1bmN0aW9uIHByb2Nlc3NOb2Rlcyhub2RlcywgbGV2ZWxDb29yZCwgc3RhY2tEZXB0aCkge1xuICAgICAgICBsZXQgc3RhY2tGb3J3YXJkID0gMDtcbiAgICAgICAgZm9yIChsZXQgbm9kZSBvZiBub2Rlcykge1xuICAgICAgICAgICAgc3RhY2tGb3J3YXJkID0gTWF0aC5tYXgocHJvY2Vzc05vZGUobm9kZSwgbGV2ZWxDb29yZCwgc3RhY2tEZXB0aCksIHN0YWNrRm9yd2FyZCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHN0YWNrRm9yd2FyZDtcbiAgICB9XG4gICAgcHJvY2Vzc05vZGVzKHRvcExldmVsTm9kZXMsIDAsIDApO1xuICAgIHJldHVybiByZWN0czsgLy8gVE9ETzogc29ydCByZWN0cyBieSBsZXZlbENvb3JkIHRvIGJlIGNvbnNpc3RlbnQgd2l0aCB0b1JlY3RzP1xufVxuLy8gVE9ETzogbW92ZSB0byBnZW5lcmFsIHV0aWxcbmZ1bmN0aW9uIGNhY2hlYWJsZShrZXlGdW5jLCB3b3JrRnVuYykge1xuICAgIGNvbnN0IGNhY2hlID0ge307XG4gICAgcmV0dXJuICguLi5hcmdzKSA9PiB7XG4gICAgICAgIGxldCBrZXkgPSBrZXlGdW5jKC4uLmFyZ3MpO1xuICAgICAgICByZXR1cm4gKGtleSBpbiBjYWNoZSlcbiAgICAgICAgICAgID8gY2FjaGVba2V5XVxuICAgICAgICAgICAgOiAoY2FjaGVba2V5XSA9IHdvcmtGdW5jKC4uLmFyZ3MpKTtcbiAgICB9O1xufVxuXG5mdW5jdGlvbiBjb21wdXRlU2VnVkNvb3JkcyhzZWdzLCBjb2xEYXRlLCBzbGF0Q29vcmRzID0gbnVsbCwgZXZlbnRNaW5IZWlnaHQgPSAwKSB7XG4gICAgbGV0IHZjb29yZHMgPSBbXTtcbiAgICBpZiAoc2xhdENvb3Jkcykge1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNlZ3MubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgICAgIGxldCBzZWcgPSBzZWdzW2ldO1xuICAgICAgICAgICAgbGV0IHNwYW5TdGFydCA9IHNsYXRDb29yZHMuY29tcHV0ZURhdGVUb3Aoc2VnLnN0YXJ0LCBjb2xEYXRlKTtcbiAgICAgICAgICAgIGxldCBzcGFuRW5kID0gTWF0aC5tYXgoc3BhblN0YXJ0ICsgKGV2ZW50TWluSGVpZ2h0IHx8IDApLCAvLyA6KFxuICAgICAgICAgICAgc2xhdENvb3Jkcy5jb21wdXRlRGF0ZVRvcChzZWcuZW5kLCBjb2xEYXRlKSk7XG4gICAgICAgICAgICB2Y29vcmRzLnB1c2goe1xuICAgICAgICAgICAgICAgIHN0YXJ0OiBNYXRoLnJvdW5kKHNwYW5TdGFydCksXG4gICAgICAgICAgICAgICAgZW5kOiBNYXRoLnJvdW5kKHNwYW5FbmQpLCAvL1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHZjb29yZHM7XG59XG5mdW5jdGlvbiBjb21wdXRlRmdTZWdQbGFjZW1lbnRzKHNlZ3MsIHNlZ1ZDb29yZHMsIC8vIG1pZ2h0IG5vdCBoYXZlIGZvciBldmVyeSBzZWdcbmV2ZW50T3JkZXJTdHJpY3QsIGV2ZW50TWF4U3RhY2spIHtcbiAgICBsZXQgc2VnSW5wdXRzID0gW107XG4gICAgbGV0IGR1bWJTZWdzID0gW107IC8vIHNlZ3Mgd2l0aG91dCBjb29yZHNcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNlZ3MubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgbGV0IHZjb29yZHMgPSBzZWdWQ29vcmRzW2ldO1xuICAgICAgICBpZiAodmNvb3Jkcykge1xuICAgICAgICAgICAgc2VnSW5wdXRzLnB1c2goe1xuICAgICAgICAgICAgICAgIGluZGV4OiBpLFxuICAgICAgICAgICAgICAgIHRoaWNrbmVzczogMSxcbiAgICAgICAgICAgICAgICBzcGFuOiB2Y29vcmRzLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBkdW1iU2Vncy5wdXNoKHNlZ3NbaV0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIGxldCB7IHNlZ1JlY3RzLCBoaWRkZW5Hcm91cHMgfSA9IGJ1aWxkUG9zaXRpb25pbmcoc2VnSW5wdXRzLCBldmVudE9yZGVyU3RyaWN0LCBldmVudE1heFN0YWNrKTtcbiAgICBsZXQgc2VnUGxhY2VtZW50cyA9IFtdO1xuICAgIGZvciAobGV0IHNlZ1JlY3Qgb2Ygc2VnUmVjdHMpIHtcbiAgICAgICAgc2VnUGxhY2VtZW50cy5wdXNoKHtcbiAgICAgICAgICAgIHNlZzogc2Vnc1tzZWdSZWN0LmluZGV4XSxcbiAgICAgICAgICAgIHJlY3Q6IHNlZ1JlY3QsXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBmb3IgKGxldCBkdW1iU2VnIG9mIGR1bWJTZWdzKSB7XG4gICAgICAgIHNlZ1BsYWNlbWVudHMucHVzaCh7IHNlZzogZHVtYlNlZywgcmVjdDogbnVsbCB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHsgc2VnUGxhY2VtZW50cywgaGlkZGVuR3JvdXBzIH07XG59XG5cbmNvbnN0IERFRkFVTFRfVElNRV9GT1JNQVQgPSBjcmVhdGVGb3JtYXR0ZXIoe1xuICAgIGhvdXI6ICdudW1lcmljJyxcbiAgICBtaW51dGU6ICcyLWRpZ2l0JyxcbiAgICBtZXJpZGllbTogZmFsc2UsXG59KTtcbmNsYXNzIFRpbWVDb2xFdmVudCBleHRlbmRzIEJhc2VDb21wb25lbnQge1xuICAgIHJlbmRlcigpIHtcbiAgICAgICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KFN0YW5kYXJkRXZlbnQsIE9iamVjdC5hc3NpZ24oe30sIHRoaXMucHJvcHMsIHsgZWxDbGFzc2VzOiBbXG4gICAgICAgICAgICAgICAgJ2ZjLXRpbWVncmlkLWV2ZW50JyxcbiAgICAgICAgICAgICAgICAnZmMtdi1ldmVudCcsXG4gICAgICAgICAgICAgICAgdGhpcy5wcm9wcy5pc1Nob3J0ICYmICdmYy10aW1lZ3JpZC1ldmVudC1zaG9ydCcsXG4gICAgICAgICAgICBdLCBkZWZhdWx0VGltZUZvcm1hdDogREVGQVVMVF9USU1FX0ZPUk1BVCB9KSkpO1xuICAgIH1cbn1cblxuY2xhc3MgVGltZUNvbCBleHRlbmRzIEJhc2VDb21wb25lbnQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICB0aGlzLnNvcnRFdmVudFNlZ3MgPSBtZW1vaXplKHNvcnRFdmVudFNlZ3MpO1xuICAgIH1cbiAgICAvLyBUT0RPOiBtZW1vaXplIGV2ZW50LXBsYWNlbWVudD9cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGxldCB7IHByb3BzLCBjb250ZXh0IH0gPSB0aGlzO1xuICAgICAgICBsZXQgeyBvcHRpb25zIH0gPSBjb250ZXh0O1xuICAgICAgICBsZXQgaXNTZWxlY3RNaXJyb3IgPSBvcHRpb25zLnNlbGVjdE1pcnJvcjtcbiAgICAgICAgbGV0IG1pcnJvclNlZ3MgPSAvLyB5dWNrXG4gICAgICAgICAocHJvcHMuZXZlbnREcmFnICYmIHByb3BzLmV2ZW50RHJhZy5zZWdzKSB8fFxuICAgICAgICAgICAgKHByb3BzLmV2ZW50UmVzaXplICYmIHByb3BzLmV2ZW50UmVzaXplLnNlZ3MpIHx8XG4gICAgICAgICAgICAoaXNTZWxlY3RNaXJyb3IgJiYgcHJvcHMuZGF0ZVNlbGVjdGlvblNlZ3MpIHx8XG4gICAgICAgICAgICBbXTtcbiAgICAgICAgbGV0IGludGVyYWN0aW9uQWZmZWN0ZWRJbnN0YW5jZXMgPSAvLyBUT0RPOiBtZXNzeSB3YXkgdG8gY29tcHV0ZSB0aGlzXG4gICAgICAgICAocHJvcHMuZXZlbnREcmFnICYmIHByb3BzLmV2ZW50RHJhZy5hZmZlY3RlZEluc3RhbmNlcykgfHxcbiAgICAgICAgICAgIChwcm9wcy5ldmVudFJlc2l6ZSAmJiBwcm9wcy5ldmVudFJlc2l6ZS5hZmZlY3RlZEluc3RhbmNlcykgfHxcbiAgICAgICAgICAgIHt9O1xuICAgICAgICBsZXQgc29ydGVkRmdTZWdzID0gdGhpcy5zb3J0RXZlbnRTZWdzKHByb3BzLmZnRXZlbnRTZWdzLCBvcHRpb25zLmV2ZW50T3JkZXIpO1xuICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoRGF5Q2VsbENvbnRhaW5lciwgeyBlbFRhZzogXCJ0ZFwiLCBlbFJlZjogcHJvcHMuZWxSZWYsIGVsQ2xhc3NlczogW1xuICAgICAgICAgICAgICAgICdmYy10aW1lZ3JpZC1jb2wnLFxuICAgICAgICAgICAgICAgIC4uLihwcm9wcy5leHRyYUNsYXNzTmFtZXMgfHwgW10pLFxuICAgICAgICAgICAgXSwgZWxBdHRyczogT2JqZWN0LmFzc2lnbih7IHJvbGU6ICdncmlkY2VsbCcgfSwgcHJvcHMuZXh0cmFEYXRhQXR0cnMpLCBkYXRlOiBwcm9wcy5kYXRlLCBkYXRlUHJvZmlsZTogcHJvcHMuZGF0ZVByb2ZpbGUsIHRvZGF5UmFuZ2U6IHByb3BzLnRvZGF5UmFuZ2UsIGV4dHJhUmVuZGVyUHJvcHM6IHByb3BzLmV4dHJhUmVuZGVyUHJvcHMgfSwgKElubmVyQ29udGVudCkgPT4gKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IFwiZmMtdGltZWdyaWQtY29sLWZyYW1lXCIgfSxcbiAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IFwiZmMtdGltZWdyaWQtY29sLWJnXCIgfSxcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlckZpbGxTZWdzKHByb3BzLmJ1c2luZXNzSG91clNlZ3MsICdub24tYnVzaW5lc3MnKSxcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlckZpbGxTZWdzKHByb3BzLmJnRXZlbnRTZWdzLCAnYmctZXZlbnQnKSxcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlckZpbGxTZWdzKHByb3BzLmRhdGVTZWxlY3Rpb25TZWdzLCAnaGlnaGxpZ2h0JykpLFxuICAgICAgICAgICAgY3JlYXRlRWxlbWVudChcImRpdlwiLCB7IGNsYXNzTmFtZTogXCJmYy10aW1lZ3JpZC1jb2wtZXZlbnRzXCIgfSwgdGhpcy5yZW5kZXJGZ1NlZ3Moc29ydGVkRmdTZWdzLCBpbnRlcmFjdGlvbkFmZmVjdGVkSW5zdGFuY2VzLCBmYWxzZSwgZmFsc2UsIGZhbHNlKSksXG4gICAgICAgICAgICBjcmVhdGVFbGVtZW50KFwiZGl2XCIsIHsgY2xhc3NOYW1lOiBcImZjLXRpbWVncmlkLWNvbC1ldmVudHNcIiB9LCB0aGlzLnJlbmRlckZnU2VncyhtaXJyb3JTZWdzLCB7fSwgQm9vbGVhbihwcm9wcy5ldmVudERyYWcpLCBCb29sZWFuKHByb3BzLmV2ZW50UmVzaXplKSwgQm9vbGVhbihpc1NlbGVjdE1pcnJvciksICdtaXJyb3InKSksXG4gICAgICAgICAgICBjcmVhdGVFbGVtZW50KFwiZGl2XCIsIHsgY2xhc3NOYW1lOiBcImZjLXRpbWVncmlkLW5vdy1pbmRpY2F0b3ItY29udGFpbmVyXCIgfSwgdGhpcy5yZW5kZXJOb3dJbmRpY2F0b3IocHJvcHMubm93SW5kaWNhdG9yU2VncykpLFxuICAgICAgICAgICAgaGFzQ3VzdG9tRGF5Q2VsbENvbnRlbnQob3B0aW9ucykgJiYgKGNyZWF0ZUVsZW1lbnQoSW5uZXJDb250ZW50LCB7IGVsVGFnOiBcImRpdlwiLCBlbENsYXNzZXM6IFsnZmMtdGltZWdyaWQtY29sLW1pc2MnXSB9KSkpKSkpO1xuICAgIH1cbiAgICByZW5kZXJGZ1NlZ3Moc29ydGVkRmdTZWdzLCBzZWdJc0ludmlzaWJsZSwgaXNEcmFnZ2luZywgaXNSZXNpemluZywgaXNEYXRlU2VsZWN0aW5nLCBmb3JjZWRLZXkpIHtcbiAgICAgICAgbGV0IHsgcHJvcHMgfSA9IHRoaXM7XG4gICAgICAgIGlmIChwcm9wcy5mb3JQcmludCkge1xuICAgICAgICAgICAgcmV0dXJuIHJlbmRlclBsYWluRmdTZWdzKHNvcnRlZEZnU2VncywgcHJvcHMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLnJlbmRlclBvc2l0aW9uZWRGZ1NlZ3Moc29ydGVkRmdTZWdzLCBzZWdJc0ludmlzaWJsZSwgaXNEcmFnZ2luZywgaXNSZXNpemluZywgaXNEYXRlU2VsZWN0aW5nLCBmb3JjZWRLZXkpO1xuICAgIH1cbiAgICByZW5kZXJQb3NpdGlvbmVkRmdTZWdzKHNlZ3MsIC8vIGlmIG5vdCBtaXJyb3IsIG5lZWRzIHRvIGJlIHNvcnRlZFxuICAgIHNlZ0lzSW52aXNpYmxlLCBpc0RyYWdnaW5nLCBpc1Jlc2l6aW5nLCBpc0RhdGVTZWxlY3RpbmcsIGZvcmNlZEtleSkge1xuICAgICAgICBsZXQgeyBldmVudE1heFN0YWNrLCBldmVudFNob3J0SGVpZ2h0LCBldmVudE9yZGVyU3RyaWN0LCBldmVudE1pbkhlaWdodCB9ID0gdGhpcy5jb250ZXh0Lm9wdGlvbnM7XG4gICAgICAgIGxldCB7IGRhdGUsIHNsYXRDb29yZHMsIGV2ZW50U2VsZWN0aW9uLCB0b2RheVJhbmdlLCBub3dEYXRlIH0gPSB0aGlzLnByb3BzO1xuICAgICAgICBsZXQgaXNNaXJyb3IgPSBpc0RyYWdnaW5nIHx8IGlzUmVzaXppbmcgfHwgaXNEYXRlU2VsZWN0aW5nO1xuICAgICAgICBsZXQgc2VnVkNvb3JkcyA9IGNvbXB1dGVTZWdWQ29vcmRzKHNlZ3MsIGRhdGUsIHNsYXRDb29yZHMsIGV2ZW50TWluSGVpZ2h0KTtcbiAgICAgICAgbGV0IHsgc2VnUGxhY2VtZW50cywgaGlkZGVuR3JvdXBzIH0gPSBjb21wdXRlRmdTZWdQbGFjZW1lbnRzKHNlZ3MsIHNlZ1ZDb29yZHMsIGV2ZW50T3JkZXJTdHJpY3QsIGV2ZW50TWF4U3RhY2spO1xuICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoRnJhZ21lbnQsIG51bGwsXG4gICAgICAgICAgICB0aGlzLnJlbmRlckhpZGRlbkdyb3VwcyhoaWRkZW5Hcm91cHMsIHNlZ3MpLFxuICAgICAgICAgICAgc2VnUGxhY2VtZW50cy5tYXAoKHNlZ1BsYWNlbWVudCkgPT4ge1xuICAgICAgICAgICAgICAgIGxldCB7IHNlZywgcmVjdCB9ID0gc2VnUGxhY2VtZW50O1xuICAgICAgICAgICAgICAgIGxldCBpbnN0YW5jZUlkID0gc2VnLmV2ZW50UmFuZ2UuaW5zdGFuY2UuaW5zdGFuY2VJZDtcbiAgICAgICAgICAgICAgICBsZXQgaXNWaXNpYmxlID0gaXNNaXJyb3IgfHwgQm9vbGVhbighc2VnSXNJbnZpc2libGVbaW5zdGFuY2VJZF0gJiYgcmVjdCk7XG4gICAgICAgICAgICAgICAgbGV0IHZTdHlsZSA9IGNvbXB1dGVTZWdWU3R5bGUocmVjdCAmJiByZWN0LnNwYW4pO1xuICAgICAgICAgICAgICAgIGxldCBoU3R5bGUgPSAoIWlzTWlycm9yICYmIHJlY3QpID8gdGhpcy5jb21wdXRlU2VnSFN0eWxlKHJlY3QpIDogeyBsZWZ0OiAwLCByaWdodDogMCB9O1xuICAgICAgICAgICAgICAgIGxldCBpc0luc2V0ID0gQm9vbGVhbihyZWN0KSAmJiByZWN0LnN0YWNrRm9yd2FyZCA+IDA7XG4gICAgICAgICAgICAgICAgbGV0IGlzU2hvcnQgPSBCb29sZWFuKHJlY3QpICYmIChyZWN0LnNwYW4uZW5kIC0gcmVjdC5zcGFuLnN0YXJ0KSA8IGV2ZW50U2hvcnRIZWlnaHQ7IC8vIGxvb2sgYXQgb3RoZXIgcGxhY2VzIGZvciB0aGlzIHByb2JsZW1cbiAgICAgICAgICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6ICdmYy10aW1lZ3JpZC1ldmVudC1oYXJuZXNzJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAoaXNJbnNldCA/ICcgZmMtdGltZWdyaWQtZXZlbnQtaGFybmVzcy1pbnNldCcgOiAnJyksIGtleTogZm9yY2VkS2V5IHx8IGluc3RhbmNlSWQsIHN0eWxlOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oeyB2aXNpYmlsaXR5OiBpc1Zpc2libGUgPyAnJyA6ICdoaWRkZW4nIH0sIHZTdHlsZSksIGhTdHlsZSkgfSxcbiAgICAgICAgICAgICAgICAgICAgY3JlYXRlRWxlbWVudChUaW1lQ29sRXZlbnQsIE9iamVjdC5hc3NpZ24oeyBzZWc6IHNlZywgaXNEcmFnZ2luZzogaXNEcmFnZ2luZywgaXNSZXNpemluZzogaXNSZXNpemluZywgaXNEYXRlU2VsZWN0aW5nOiBpc0RhdGVTZWxlY3RpbmcsIGlzU2VsZWN0ZWQ6IGluc3RhbmNlSWQgPT09IGV2ZW50U2VsZWN0aW9uLCBpc1Nob3J0OiBpc1Nob3J0IH0sIGdldFNlZ01ldGEoc2VnLCB0b2RheVJhbmdlLCBub3dEYXRlKSkpKSk7XG4gICAgICAgICAgICB9KSkpO1xuICAgIH1cbiAgICAvLyB3aWxsIGFscmVhZHkgaGF2ZSBldmVudE1pbkhlaWdodCBhcHBsaWVkIGJlY2F1c2Ugc2VnSW5wdXRzIGFscmVhZHkgaGFkIGl0XG4gICAgcmVuZGVySGlkZGVuR3JvdXBzKGhpZGRlbkdyb3Vwcywgc2Vncykge1xuICAgICAgICBsZXQgeyBleHRyYURhdGVTcGFuLCBkYXRlUHJvZmlsZSwgdG9kYXlSYW5nZSwgbm93RGF0ZSwgZXZlbnRTZWxlY3Rpb24sIGV2ZW50RHJhZywgZXZlbnRSZXNpemUgfSA9IHRoaXMucHJvcHM7XG4gICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChGcmFnbWVudCwgbnVsbCwgaGlkZGVuR3JvdXBzLm1hcCgoaGlkZGVuR3JvdXApID0+IHtcbiAgICAgICAgICAgIGxldCBwb3NpdGlvbkNzcyA9IGNvbXB1dGVTZWdWU3R5bGUoaGlkZGVuR3JvdXAuc3Bhbik7XG4gICAgICAgICAgICBsZXQgaGlkZGVuU2VncyA9IGNvbXBpbGVTZWdzRnJvbUVudHJpZXMoaGlkZGVuR3JvdXAuZW50cmllcywgc2Vncyk7XG4gICAgICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoVGltZUNvbE1vcmVMaW5rLCB7IGtleTogYnVpbGRJc29TdHJpbmcoY29tcHV0ZUVhcmxpZXN0U2VnU3RhcnQoaGlkZGVuU2VncykpLCBoaWRkZW5TZWdzOiBoaWRkZW5TZWdzLCB0b3A6IHBvc2l0aW9uQ3NzLnRvcCwgYm90dG9tOiBwb3NpdGlvbkNzcy5ib3R0b20sIGV4dHJhRGF0ZVNwYW46IGV4dHJhRGF0ZVNwYW4sIGRhdGVQcm9maWxlOiBkYXRlUHJvZmlsZSwgdG9kYXlSYW5nZTogdG9kYXlSYW5nZSwgbm93RGF0ZTogbm93RGF0ZSwgZXZlbnRTZWxlY3Rpb246IGV2ZW50U2VsZWN0aW9uLCBldmVudERyYWc6IGV2ZW50RHJhZywgZXZlbnRSZXNpemU6IGV2ZW50UmVzaXplIH0pKTtcbiAgICAgICAgfSkpKTtcbiAgICB9XG4gICAgcmVuZGVyRmlsbFNlZ3Moc2VncywgZmlsbFR5cGUpIHtcbiAgICAgICAgbGV0IHsgcHJvcHMsIGNvbnRleHQgfSA9IHRoaXM7XG4gICAgICAgIGxldCBzZWdWQ29vcmRzID0gY29tcHV0ZVNlZ1ZDb29yZHMoc2VncywgcHJvcHMuZGF0ZSwgcHJvcHMuc2xhdENvb3JkcywgY29udGV4dC5vcHRpb25zLmV2ZW50TWluSGVpZ2h0KTsgLy8gZG9uJ3QgYXNzdW1lIGFsbCBwb3B1bGF0ZWRcbiAgICAgICAgbGV0IGNoaWxkcmVuID0gc2VnVkNvb3Jkcy5tYXAoKHZjb29yZHMsIGkpID0+IHtcbiAgICAgICAgICAgIGxldCBzZWcgPSBzZWdzW2ldO1xuICAgICAgICAgICAgcmV0dXJuIChjcmVhdGVFbGVtZW50KFwiZGl2XCIsIHsga2V5OiBidWlsZEV2ZW50UmFuZ2VLZXkoc2VnLmV2ZW50UmFuZ2UpLCBjbGFzc05hbWU6IFwiZmMtdGltZWdyaWQtYmctaGFybmVzc1wiLCBzdHlsZTogY29tcHV0ZVNlZ1ZTdHlsZSh2Y29vcmRzKSB9LCBmaWxsVHlwZSA9PT0gJ2JnLWV2ZW50JyA/XG4gICAgICAgICAgICAgICAgY3JlYXRlRWxlbWVudChCZ0V2ZW50LCBPYmplY3QuYXNzaWduKHsgc2VnOiBzZWcgfSwgZ2V0U2VnTWV0YShzZWcsIHByb3BzLnRvZGF5UmFuZ2UsIHByb3BzLm5vd0RhdGUpKSkgOlxuICAgICAgICAgICAgICAgIHJlbmRlckZpbGwoZmlsbFR5cGUpKSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gY3JlYXRlRWxlbWVudChGcmFnbWVudCwgbnVsbCwgY2hpbGRyZW4pO1xuICAgIH1cbiAgICByZW5kZXJOb3dJbmRpY2F0b3Ioc2Vncykge1xuICAgICAgICBsZXQgeyBzbGF0Q29vcmRzLCBkYXRlIH0gPSB0aGlzLnByb3BzO1xuICAgICAgICBpZiAoIXNsYXRDb29yZHMpIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzZWdzLm1hcCgoc2VnLCBpKSA9PiAoY3JlYXRlRWxlbWVudChOb3dJbmRpY2F0b3JDb250YWluZXJcbiAgICAgICAgLy8ga2V5IGRvZXNuJ3QgbWF0dGVyLiB3aWxsIG9ubHkgZXZlciBiZSBvbmVcbiAgICAgICAgLCB7IFxuICAgICAgICAgICAgLy8ga2V5IGRvZXNuJ3QgbWF0dGVyLiB3aWxsIG9ubHkgZXZlciBiZSBvbmVcbiAgICAgICAgICAgIGtleTogaSwgZWxDbGFzc2VzOiBbJ2ZjLXRpbWVncmlkLW5vdy1pbmRpY2F0b3ItbGluZSddLCBlbFN0eWxlOiB7XG4gICAgICAgICAgICAgICAgdG9wOiBzbGF0Q29vcmRzLmNvbXB1dGVEYXRlVG9wKHNlZy5zdGFydCwgZGF0ZSksXG4gICAgICAgICAgICB9LCBpc0F4aXM6IGZhbHNlLCBkYXRlOiBkYXRlIH0pKSk7XG4gICAgfVxuICAgIGNvbXB1dGVTZWdIU3R5bGUoc2VnSENvb3Jkcykge1xuICAgICAgICBsZXQgeyBpc1J0bCwgb3B0aW9ucyB9ID0gdGhpcy5jb250ZXh0O1xuICAgICAgICBsZXQgc2hvdWxkT3ZlcmxhcCA9IG9wdGlvbnMuc2xvdEV2ZW50T3ZlcmxhcDtcbiAgICAgICAgbGV0IG5lYXJDb29yZCA9IHNlZ0hDb29yZHMubGV2ZWxDb29yZDsgLy8gdGhlIGxlZnQgc2lkZSBpZiBMVFIuIHRoZSByaWdodCBzaWRlIGlmIFJUTC4gZmxvYXRpbmctcG9pbnRcbiAgICAgICAgbGV0IGZhckNvb3JkID0gc2VnSENvb3Jkcy5sZXZlbENvb3JkICsgc2VnSENvb3Jkcy50aGlja25lc3M7IC8vIHRoZSByaWdodCBzaWRlIGlmIExUUi4gdGhlIGxlZnQgc2lkZSBpZiBSVEwuIGZsb2F0aW5nLXBvaW50XG4gICAgICAgIGxldCBsZWZ0OyAvLyBhbW91bnQgb2Ygc3BhY2UgZnJvbSBsZWZ0IGVkZ2UsIGEgZnJhY3Rpb24gb2YgdGhlIHRvdGFsIHdpZHRoXG4gICAgICAgIGxldCByaWdodDsgLy8gYW1vdW50IG9mIHNwYWNlIGZyb20gcmlnaHQgZWRnZSwgYSBmcmFjdGlvbiBvZiB0aGUgdG90YWwgd2lkdGhcbiAgICAgICAgaWYgKHNob3VsZE92ZXJsYXApIHtcbiAgICAgICAgICAgIC8vIGRvdWJsZSB0aGUgd2lkdGgsIGJ1dCBkb24ndCBnbyBiZXlvbmQgdGhlIG1heGltdW0gZm9yd2FyZCBjb29yZGluYXRlICgxLjApXG4gICAgICAgICAgICBmYXJDb29yZCA9IE1hdGgubWluKDEsIG5lYXJDb29yZCArIChmYXJDb29yZCAtIG5lYXJDb29yZCkgKiAyKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNSdGwpIHtcbiAgICAgICAgICAgIGxlZnQgPSAxIC0gZmFyQ29vcmQ7XG4gICAgICAgICAgICByaWdodCA9IG5lYXJDb29yZDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGxlZnQgPSBuZWFyQ29vcmQ7XG4gICAgICAgICAgICByaWdodCA9IDEgLSBmYXJDb29yZDtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcHJvcHMgPSB7XG4gICAgICAgICAgICB6SW5kZXg6IHNlZ0hDb29yZHMuc3RhY2tEZXB0aCArIDEsXG4gICAgICAgICAgICBsZWZ0OiBsZWZ0ICogMTAwICsgJyUnLFxuICAgICAgICAgICAgcmlnaHQ6IHJpZ2h0ICogMTAwICsgJyUnLFxuICAgICAgICB9O1xuICAgICAgICBpZiAoc2hvdWxkT3ZlcmxhcCAmJiAhc2VnSENvb3Jkcy5zdGFja0ZvcndhcmQpIHtcbiAgICAgICAgICAgIC8vIGFkZCBwYWRkaW5nIHRvIHRoZSBlZGdlIHNvIHRoYXQgZm9yd2FyZCBzdGFja2VkIGV2ZW50cyBkb24ndCBjb3ZlciB0aGUgcmVzaXplcidzIGljb25cbiAgICAgICAgICAgIHByb3BzW2lzUnRsID8gJ21hcmdpbkxlZnQnIDogJ21hcmdpblJpZ2h0J10gPSAxMCAqIDI7IC8vIDEwIGlzIGEgZ3Vlc3N0aW1hdGUgb2YgdGhlIGljb24ncyB3aWR0aFxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBwcm9wcztcbiAgICB9XG59XG5mdW5jdGlvbiByZW5kZXJQbGFpbkZnU2Vncyhzb3J0ZWRGZ1NlZ3MsIHsgdG9kYXlSYW5nZSwgbm93RGF0ZSwgZXZlbnRTZWxlY3Rpb24sIGV2ZW50RHJhZywgZXZlbnRSZXNpemUgfSkge1xuICAgIGxldCBoaWRkZW5JbnN0YW5jZXMgPSAoZXZlbnREcmFnID8gZXZlbnREcmFnLmFmZmVjdGVkSW5zdGFuY2VzIDogbnVsbCkgfHxcbiAgICAgICAgKGV2ZW50UmVzaXplID8gZXZlbnRSZXNpemUuYWZmZWN0ZWRJbnN0YW5jZXMgOiBudWxsKSB8fFxuICAgICAgICB7fTtcbiAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoRnJhZ21lbnQsIG51bGwsIHNvcnRlZEZnU2Vncy5tYXAoKHNlZykgPT4ge1xuICAgICAgICBsZXQgaW5zdGFuY2VJZCA9IHNlZy5ldmVudFJhbmdlLmluc3RhbmNlLmluc3RhbmNlSWQ7XG4gICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChcImRpdlwiLCB7IGtleTogaW5zdGFuY2VJZCwgc3R5bGU6IHsgdmlzaWJpbGl0eTogaGlkZGVuSW5zdGFuY2VzW2luc3RhbmNlSWRdID8gJ2hpZGRlbicgOiAnJyB9IH0sXG4gICAgICAgICAgICBjcmVhdGVFbGVtZW50KFRpbWVDb2xFdmVudCwgT2JqZWN0LmFzc2lnbih7IHNlZzogc2VnLCBpc0RyYWdnaW5nOiBmYWxzZSwgaXNSZXNpemluZzogZmFsc2UsIGlzRGF0ZVNlbGVjdGluZzogZmFsc2UsIGlzU2VsZWN0ZWQ6IGluc3RhbmNlSWQgPT09IGV2ZW50U2VsZWN0aW9uLCBpc1Nob3J0OiBmYWxzZSB9LCBnZXRTZWdNZXRhKHNlZywgdG9kYXlSYW5nZSwgbm93RGF0ZSkpKSkpO1xuICAgIH0pKSk7XG59XG5mdW5jdGlvbiBjb21wdXRlU2VnVlN0eWxlKHNlZ1ZDb29yZHMpIHtcbiAgICBpZiAoIXNlZ1ZDb29yZHMpIHtcbiAgICAgICAgcmV0dXJuIHsgdG9wOiAnJywgYm90dG9tOiAnJyB9O1xuICAgIH1cbiAgICByZXR1cm4ge1xuICAgICAgICB0b3A6IHNlZ1ZDb29yZHMuc3RhcnQsXG4gICAgICAgIGJvdHRvbTogLXNlZ1ZDb29yZHMuZW5kLFxuICAgIH07XG59XG5mdW5jdGlvbiBjb21waWxlU2Vnc0Zyb21FbnRyaWVzKHNlZ0VudHJpZXMsIGFsbFNlZ3MpIHtcbiAgICByZXR1cm4gc2VnRW50cmllcy5tYXAoKHNlZ0VudHJ5KSA9PiBhbGxTZWdzW3NlZ0VudHJ5LmluZGV4XSk7XG59XG5cbmNsYXNzIFRpbWVDb2xzQ29udGVudCBleHRlbmRzIEJhc2VDb21wb25lbnQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICB0aGlzLnNwbGl0RmdFdmVudFNlZ3MgPSBtZW1vaXplKHNwbGl0U2Vnc0J5Q29sKTtcbiAgICAgICAgdGhpcy5zcGxpdEJnRXZlbnRTZWdzID0gbWVtb2l6ZShzcGxpdFNlZ3NCeUNvbCk7XG4gICAgICAgIHRoaXMuc3BsaXRCdXNpbmVzc0hvdXJTZWdzID0gbWVtb2l6ZShzcGxpdFNlZ3NCeUNvbCk7XG4gICAgICAgIHRoaXMuc3BsaXROb3dJbmRpY2F0b3JTZWdzID0gbWVtb2l6ZShzcGxpdFNlZ3NCeUNvbCk7XG4gICAgICAgIHRoaXMuc3BsaXREYXRlU2VsZWN0aW9uU2VncyA9IG1lbW9pemUoc3BsaXRTZWdzQnlDb2wpO1xuICAgICAgICB0aGlzLnNwbGl0RXZlbnREcmFnID0gbWVtb2l6ZShzcGxpdEludGVyYWN0aW9uQnlDb2wpO1xuICAgICAgICB0aGlzLnNwbGl0RXZlbnRSZXNpemUgPSBtZW1vaXplKHNwbGl0SW50ZXJhY3Rpb25CeUNvbCk7XG4gICAgICAgIHRoaXMucm9vdEVsUmVmID0gY3JlYXRlUmVmKCk7XG4gICAgICAgIHRoaXMuY2VsbEVsUmVmcyA9IG5ldyBSZWZNYXAoKTtcbiAgICB9XG4gICAgcmVuZGVyKCkge1xuICAgICAgICBsZXQgeyBwcm9wcywgY29udGV4dCB9ID0gdGhpcztcbiAgICAgICAgbGV0IG5vd0luZGljYXRvclRvcCA9IGNvbnRleHQub3B0aW9ucy5ub3dJbmRpY2F0b3IgJiZcbiAgICAgICAgICAgIHByb3BzLnNsYXRDb29yZHMgJiZcbiAgICAgICAgICAgIHByb3BzLnNsYXRDb29yZHMuc2FmZUNvbXB1dGVUb3AocHJvcHMubm93RGF0ZSk7IC8vIG1pZ2h0IHJldHVybiB2b2lkXG4gICAgICAgIGxldCBjb2xDbnQgPSBwcm9wcy5jZWxscy5sZW5ndGg7XG4gICAgICAgIGxldCBmZ0V2ZW50U2Vnc0J5Um93ID0gdGhpcy5zcGxpdEZnRXZlbnRTZWdzKHByb3BzLmZnRXZlbnRTZWdzLCBjb2xDbnQpO1xuICAgICAgICBsZXQgYmdFdmVudFNlZ3NCeVJvdyA9IHRoaXMuc3BsaXRCZ0V2ZW50U2Vncyhwcm9wcy5iZ0V2ZW50U2VncywgY29sQ250KTtcbiAgICAgICAgbGV0IGJ1c2luZXNzSG91clNlZ3NCeVJvdyA9IHRoaXMuc3BsaXRCdXNpbmVzc0hvdXJTZWdzKHByb3BzLmJ1c2luZXNzSG91clNlZ3MsIGNvbENudCk7XG4gICAgICAgIGxldCBub3dJbmRpY2F0b3JTZWdzQnlSb3cgPSB0aGlzLnNwbGl0Tm93SW5kaWNhdG9yU2Vncyhwcm9wcy5ub3dJbmRpY2F0b3JTZWdzLCBjb2xDbnQpO1xuICAgICAgICBsZXQgZGF0ZVNlbGVjdGlvblNlZ3NCeVJvdyA9IHRoaXMuc3BsaXREYXRlU2VsZWN0aW9uU2Vncyhwcm9wcy5kYXRlU2VsZWN0aW9uU2VncywgY29sQ250KTtcbiAgICAgICAgbGV0IGV2ZW50RHJhZ0J5Um93ID0gdGhpcy5zcGxpdEV2ZW50RHJhZyhwcm9wcy5ldmVudERyYWcsIGNvbENudCk7XG4gICAgICAgIGxldCBldmVudFJlc2l6ZUJ5Um93ID0gdGhpcy5zcGxpdEV2ZW50UmVzaXplKHByb3BzLmV2ZW50UmVzaXplLCBjb2xDbnQpO1xuICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IFwiZmMtdGltZWdyaWQtY29sc1wiLCByZWY6IHRoaXMucm9vdEVsUmVmIH0sXG4gICAgICAgICAgICBjcmVhdGVFbGVtZW50KFwidGFibGVcIiwgeyByb2xlOiBcInByZXNlbnRhdGlvblwiLCBzdHlsZToge1xuICAgICAgICAgICAgICAgICAgICBtaW5XaWR0aDogcHJvcHMudGFibGVNaW5XaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgd2lkdGg6IHByb3BzLmNsaWVudFdpZHRoLFxuICAgICAgICAgICAgICAgIH0gfSxcbiAgICAgICAgICAgICAgICBwcm9wcy50YWJsZUNvbEdyb3VwTm9kZSxcbiAgICAgICAgICAgICAgICBjcmVhdGVFbGVtZW50KFwidGJvZHlcIiwgeyByb2xlOiBcInByZXNlbnRhdGlvblwiIH0sXG4gICAgICAgICAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoXCJ0clwiLCB7IHJvbGU6IFwicm93XCIgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHByb3BzLmF4aXMgJiYgKGNyZWF0ZUVsZW1lbnQoXCJ0ZFwiLCB7IFwiYXJpYS1oaWRkZW5cIjogdHJ1ZSwgY2xhc3NOYW1lOiBcImZjLXRpbWVncmlkLWNvbCBmYy10aW1lZ3JpZC1heGlzXCIgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcmVhdGVFbGVtZW50KFwiZGl2XCIsIHsgY2xhc3NOYW1lOiBcImZjLXRpbWVncmlkLWNvbC1mcmFtZVwiIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgeyBjbGFzc05hbWU6IFwiZmMtdGltZWdyaWQtbm93LWluZGljYXRvci1jb250YWluZXJcIiB9LCB0eXBlb2Ygbm93SW5kaWNhdG9yVG9wID09PSAnbnVtYmVyJyAmJiAoY3JlYXRlRWxlbWVudChOb3dJbmRpY2F0b3JDb250YWluZXIsIHsgZWxDbGFzc2VzOiBbJ2ZjLXRpbWVncmlkLW5vdy1pbmRpY2F0b3ItYXJyb3cnXSwgZWxTdHlsZTogeyB0b3A6IG5vd0luZGljYXRvclRvcCB9LCBpc0F4aXM6IHRydWUsIGRhdGU6IHByb3BzLm5vd0RhdGUgfSkpKSkpKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHByb3BzLmNlbGxzLm1hcCgoY2VsbCwgaSkgPT4gKGNyZWF0ZUVsZW1lbnQoVGltZUNvbCwgeyBrZXk6IGNlbGwua2V5LCBlbFJlZjogdGhpcy5jZWxsRWxSZWZzLmNyZWF0ZVJlZihjZWxsLmtleSksIGRhdGVQcm9maWxlOiBwcm9wcy5kYXRlUHJvZmlsZSwgZGF0ZTogY2VsbC5kYXRlLCBub3dEYXRlOiBwcm9wcy5ub3dEYXRlLCB0b2RheVJhbmdlOiBwcm9wcy50b2RheVJhbmdlLCBleHRyYVJlbmRlclByb3BzOiBjZWxsLmV4dHJhUmVuZGVyUHJvcHMsIGV4dHJhRGF0YUF0dHJzOiBjZWxsLmV4dHJhRGF0YUF0dHJzLCBleHRyYUNsYXNzTmFtZXM6IGNlbGwuZXh0cmFDbGFzc05hbWVzLCBleHRyYURhdGVTcGFuOiBjZWxsLmV4dHJhRGF0ZVNwYW4sIGZnRXZlbnRTZWdzOiBmZ0V2ZW50U2Vnc0J5Um93W2ldLCBiZ0V2ZW50U2VnczogYmdFdmVudFNlZ3NCeVJvd1tpXSwgYnVzaW5lc3NIb3VyU2VnczogYnVzaW5lc3NIb3VyU2Vnc0J5Um93W2ldLCBub3dJbmRpY2F0b3JTZWdzOiBub3dJbmRpY2F0b3JTZWdzQnlSb3dbaV0sIGRhdGVTZWxlY3Rpb25TZWdzOiBkYXRlU2VsZWN0aW9uU2Vnc0J5Um93W2ldLCBldmVudERyYWc6IGV2ZW50RHJhZ0J5Um93W2ldLCBldmVudFJlc2l6ZTogZXZlbnRSZXNpemVCeVJvd1tpXSwgc2xhdENvb3JkczogcHJvcHMuc2xhdENvb3JkcywgZXZlbnRTZWxlY3Rpb246IHByb3BzLmV2ZW50U2VsZWN0aW9uLCBmb3JQcmludDogcHJvcHMuZm9yUHJpbnQgfSkpKSkpKSkpO1xuICAgIH1cbiAgICBjb21wb25lbnREaWRNb3VudCgpIHtcbiAgICAgICAgdGhpcy51cGRhdGVDb29yZHMoKTtcbiAgICB9XG4gICAgY29tcG9uZW50RGlkVXBkYXRlKCkge1xuICAgICAgICB0aGlzLnVwZGF0ZUNvb3JkcygpO1xuICAgIH1cbiAgICB1cGRhdGVDb29yZHMoKSB7XG4gICAgICAgIGxldCB7IHByb3BzIH0gPSB0aGlzO1xuICAgICAgICBpZiAocHJvcHMub25Db2xDb29yZHMgJiZcbiAgICAgICAgICAgIHByb3BzLmNsaWVudFdpZHRoICE9PSBudWxsIC8vIG1lYW5zIHNpemluZyBoYXMgc3RhYmlsaXplZFxuICAgICAgICApIHtcbiAgICAgICAgICAgIHByb3BzLm9uQ29sQ29vcmRzKG5ldyBQb3NpdGlvbkNhY2hlKHRoaXMucm9vdEVsUmVmLmN1cnJlbnQsIGNvbGxlY3RDZWxsRWxzKHRoaXMuY2VsbEVsUmVmcy5jdXJyZW50TWFwLCBwcm9wcy5jZWxscyksIHRydWUsIC8vIGhvcml6b250YWxcbiAgICAgICAgICAgIGZhbHNlKSk7XG4gICAgICAgIH1cbiAgICB9XG59XG5mdW5jdGlvbiBjb2xsZWN0Q2VsbEVscyhlbE1hcCwgY2VsbHMpIHtcbiAgICByZXR1cm4gY2VsbHMubWFwKChjZWxsKSA9PiBlbE1hcFtjZWxsLmtleV0pO1xufVxuXG4vKiBBIGNvbXBvbmVudCB0aGF0IHJlbmRlcnMgb25lIG9yIG1vcmUgY29sdW1ucyBvZiB2ZXJ0aWNhbCB0aW1lIHNsb3RzXG4tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbmNsYXNzIFRpbWVDb2xzIGV4dGVuZHMgRGF0ZUNvbXBvbmVudCB7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKC4uLmFyZ3VtZW50cyk7XG4gICAgICAgIHRoaXMucHJvY2Vzc1Nsb3RPcHRpb25zID0gbWVtb2l6ZShwcm9jZXNzU2xvdE9wdGlvbnMpO1xuICAgICAgICB0aGlzLnN0YXRlID0ge1xuICAgICAgICAgICAgc2xhdENvb3JkczogbnVsbCxcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVSb290RWwgPSAoZWwpID0+IHtcbiAgICAgICAgICAgIGlmIChlbCkge1xuICAgICAgICAgICAgICAgIHRoaXMuY29udGV4dC5yZWdpc3RlckludGVyYWN0aXZlQ29tcG9uZW50KHRoaXMsIHtcbiAgICAgICAgICAgICAgICAgICAgZWwsXG4gICAgICAgICAgICAgICAgICAgIGlzSGl0Q29tYm9BbGxvd2VkOiB0aGlzLnByb3BzLmlzSGl0Q29tYm9BbGxvd2VkLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jb250ZXh0LnVucmVnaXN0ZXJJbnRlcmFjdGl2ZUNvbXBvbmVudCh0aGlzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5oYW5kbGVTY3JvbGxSZXF1ZXN0ID0gKHJlcXVlc3QpID0+IHtcbiAgICAgICAgICAgIGxldCB7IG9uU2Nyb2xsVG9wUmVxdWVzdCB9ID0gdGhpcy5wcm9wcztcbiAgICAgICAgICAgIGxldCB7IHNsYXRDb29yZHMgfSA9IHRoaXMuc3RhdGU7XG4gICAgICAgICAgICBpZiAob25TY3JvbGxUb3BSZXF1ZXN0ICYmIHNsYXRDb29yZHMpIHtcbiAgICAgICAgICAgICAgICBpZiAocmVxdWVzdC50aW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCB0b3AgPSBzbGF0Q29vcmRzLmNvbXB1dGVUaW1lVG9wKHJlcXVlc3QudGltZSk7XG4gICAgICAgICAgICAgICAgICAgIHRvcCA9IE1hdGguY2VpbCh0b3ApOyAvLyB6b29tIGNhbiBnaXZlIHdlaXJkIGZsb2F0aW5nLXBvaW50IHZhbHVlcy4gcmF0aGVyIHNjcm9sbCBhIGxpdHRsZSBiaXQgZnVydGhlclxuICAgICAgICAgICAgICAgICAgICBpZiAodG9wKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0b3AgKz0gMTsgLy8gdG8gb3ZlcmNvbWUgdG9wIGJvcmRlciB0aGF0IHNsb3RzIGJleW9uZCB0aGUgZmlyc3QgaGF2ZS4gbG9va3MgYmV0dGVyXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgb25TY3JvbGxUb3BSZXF1ZXN0KHRvcCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZUNvbENvb3JkcyA9IChjb2xDb29yZHMpID0+IHtcbiAgICAgICAgICAgIHRoaXMuY29sQ29vcmRzID0gY29sQ29vcmRzO1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLmhhbmRsZVNsYXRDb29yZHMgPSAoc2xhdENvb3JkcykgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IHNsYXRDb29yZHMgfSk7XG4gICAgICAgICAgICBpZiAodGhpcy5wcm9wcy5vblNsYXRDb29yZHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnByb3BzLm9uU2xhdENvb3JkcyhzbGF0Q29vcmRzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG4gICAgcmVuZGVyKCkge1xuICAgICAgICBsZXQgeyBwcm9wcywgc3RhdGUgfSA9IHRoaXM7XG4gICAgICAgIHJldHVybiAoY3JlYXRlRWxlbWVudChcImRpdlwiLCB7IGNsYXNzTmFtZTogXCJmYy10aW1lZ3JpZC1ib2R5XCIsIHJlZjogdGhpcy5oYW5kbGVSb290RWwsIHN0eWxlOiB7XG4gICAgICAgICAgICAgICAgLy8gdGhlc2UgcHJvcHMgYXJlIGltcG9ydGFudCB0byBnaXZlIHRoaXMgd3JhcHBlciBjb3JyZWN0IGRpbWVuc2lvbnMgZm9yIGludGVyYWN0aW9uc1xuICAgICAgICAgICAgICAgIC8vIFRPRE86IGlmIHdlIHNldCBpdCBoZXJlLCBjYW4gd2UgYXZvaWQgZ2l2aW5nIHRvIGlubmVyIHRhYmxlcz9cbiAgICAgICAgICAgICAgICB3aWR0aDogcHJvcHMuY2xpZW50V2lkdGgsXG4gICAgICAgICAgICAgICAgbWluV2lkdGg6IHByb3BzLnRhYmxlTWluV2lkdGgsXG4gICAgICAgICAgICB9IH0sXG4gICAgICAgICAgICBjcmVhdGVFbGVtZW50KFRpbWVDb2xzU2xhdHMsIHsgYXhpczogcHJvcHMuYXhpcywgZGF0ZVByb2ZpbGU6IHByb3BzLmRhdGVQcm9maWxlLCBzbGF0TWV0YXM6IHByb3BzLnNsYXRNZXRhcywgY2xpZW50V2lkdGg6IHByb3BzLmNsaWVudFdpZHRoLCBtaW5IZWlnaHQ6IHByb3BzLmV4cGFuZFJvd3MgPyBwcm9wcy5jbGllbnRIZWlnaHQgOiAnJywgdGFibGVNaW5XaWR0aDogcHJvcHMudGFibGVNaW5XaWR0aCwgdGFibGVDb2xHcm91cE5vZGU6IHByb3BzLmF4aXMgPyBwcm9wcy50YWJsZUNvbEdyb3VwTm9kZSA6IG51bGwgLyogYXhpcyBkZXBlbmRzIG9uIHRoZSBjb2xncm91cCdzIHNocmlua2luZyAqLywgb25Db29yZHM6IHRoaXMuaGFuZGxlU2xhdENvb3JkcyB9KSxcbiAgICAgICAgICAgIGNyZWF0ZUVsZW1lbnQoVGltZUNvbHNDb250ZW50LCB7IGNlbGxzOiBwcm9wcy5jZWxscywgYXhpczogcHJvcHMuYXhpcywgZGF0ZVByb2ZpbGU6IHByb3BzLmRhdGVQcm9maWxlLCBidXNpbmVzc0hvdXJTZWdzOiBwcm9wcy5idXNpbmVzc0hvdXJTZWdzLCBiZ0V2ZW50U2VnczogcHJvcHMuYmdFdmVudFNlZ3MsIGZnRXZlbnRTZWdzOiBwcm9wcy5mZ0V2ZW50U2VncywgZGF0ZVNlbGVjdGlvblNlZ3M6IHByb3BzLmRhdGVTZWxlY3Rpb25TZWdzLCBldmVudFNlbGVjdGlvbjogcHJvcHMuZXZlbnRTZWxlY3Rpb24sIGV2ZW50RHJhZzogcHJvcHMuZXZlbnREcmFnLCBldmVudFJlc2l6ZTogcHJvcHMuZXZlbnRSZXNpemUsIHRvZGF5UmFuZ2U6IHByb3BzLnRvZGF5UmFuZ2UsIG5vd0RhdGU6IHByb3BzLm5vd0RhdGUsIG5vd0luZGljYXRvclNlZ3M6IHByb3BzLm5vd0luZGljYXRvclNlZ3MsIGNsaWVudFdpZHRoOiBwcm9wcy5jbGllbnRXaWR0aCwgdGFibGVNaW5XaWR0aDogcHJvcHMudGFibGVNaW5XaWR0aCwgdGFibGVDb2xHcm91cE5vZGU6IHByb3BzLnRhYmxlQ29sR3JvdXBOb2RlLCBzbGF0Q29vcmRzOiBzdGF0ZS5zbGF0Q29vcmRzLCBvbkNvbENvb3JkczogdGhpcy5oYW5kbGVDb2xDb29yZHMsIGZvclByaW50OiBwcm9wcy5mb3JQcmludCB9KSkpO1xuICAgIH1cbiAgICBjb21wb25lbnREaWRNb3VudCgpIHtcbiAgICAgICAgdGhpcy5zY3JvbGxSZXNwb25kZXIgPSB0aGlzLmNvbnRleHQuY3JlYXRlU2Nyb2xsUmVzcG9uZGVyKHRoaXMuaGFuZGxlU2Nyb2xsUmVxdWVzdCk7XG4gICAgfVxuICAgIGNvbXBvbmVudERpZFVwZGF0ZShwcmV2UHJvcHMpIHtcbiAgICAgICAgdGhpcy5zY3JvbGxSZXNwb25kZXIudXBkYXRlKHByZXZQcm9wcy5kYXRlUHJvZmlsZSAhPT0gdGhpcy5wcm9wcy5kYXRlUHJvZmlsZSk7XG4gICAgfVxuICAgIGNvbXBvbmVudFdpbGxVbm1vdW50KCkge1xuICAgICAgICB0aGlzLnNjcm9sbFJlc3BvbmRlci5kZXRhY2goKTtcbiAgICB9XG4gICAgcXVlcnlIaXQocG9zaXRpb25MZWZ0LCBwb3NpdGlvblRvcCkge1xuICAgICAgICBsZXQgeyBkYXRlRW52LCBvcHRpb25zIH0gPSB0aGlzLmNvbnRleHQ7XG4gICAgICAgIGxldCB7IGNvbENvb3JkcyB9ID0gdGhpcztcbiAgICAgICAgbGV0IHsgZGF0ZVByb2ZpbGUgfSA9IHRoaXMucHJvcHM7XG4gICAgICAgIGxldCB7IHNsYXRDb29yZHMgfSA9IHRoaXMuc3RhdGU7XG4gICAgICAgIGxldCB7IHNuYXBEdXJhdGlvbiwgc25hcHNQZXJTbG90IH0gPSB0aGlzLnByb2Nlc3NTbG90T3B0aW9ucyh0aGlzLnByb3BzLnNsb3REdXJhdGlvbiwgb3B0aW9ucy5zbmFwRHVyYXRpb24pO1xuICAgICAgICBsZXQgY29sSW5kZXggPSBjb2xDb29yZHMubGVmdFRvSW5kZXgocG9zaXRpb25MZWZ0KTtcbiAgICAgICAgbGV0IHNsYXRJbmRleCA9IHNsYXRDb29yZHMucG9zaXRpb25zLnRvcFRvSW5kZXgocG9zaXRpb25Ub3ApO1xuICAgICAgICBpZiAoY29sSW5kZXggIT0gbnVsbCAmJiBzbGF0SW5kZXggIT0gbnVsbCkge1xuICAgICAgICAgICAgbGV0IGNlbGwgPSB0aGlzLnByb3BzLmNlbGxzW2NvbEluZGV4XTtcbiAgICAgICAgICAgIGxldCBzbGF0VG9wID0gc2xhdENvb3Jkcy5wb3NpdGlvbnMudG9wc1tzbGF0SW5kZXhdO1xuICAgICAgICAgICAgbGV0IHNsYXRIZWlnaHQgPSBzbGF0Q29vcmRzLnBvc2l0aW9ucy5nZXRIZWlnaHQoc2xhdEluZGV4KTtcbiAgICAgICAgICAgIGxldCBwYXJ0aWFsID0gKHBvc2l0aW9uVG9wIC0gc2xhdFRvcCkgLyBzbGF0SGVpZ2h0OyAvLyBmbG9hdGluZyBwb2ludCBudW1iZXIgYmV0d2VlbiAwIGFuZCAxXG4gICAgICAgICAgICBsZXQgbG9jYWxTbmFwSW5kZXggPSBNYXRoLmZsb29yKHBhcnRpYWwgKiBzbmFwc1BlclNsb3QpOyAvLyB0aGUgc25hcCAjIHJlbGF0aXZlIHRvIHN0YXJ0IG9mIHNsYXRcbiAgICAgICAgICAgIGxldCBzbmFwSW5kZXggPSBzbGF0SW5kZXggKiBzbmFwc1BlclNsb3QgKyBsb2NhbFNuYXBJbmRleDtcbiAgICAgICAgICAgIGxldCBkYXlEYXRlID0gdGhpcy5wcm9wcy5jZWxsc1tjb2xJbmRleF0uZGF0ZTtcbiAgICAgICAgICAgIGxldCB0aW1lID0gYWRkRHVyYXRpb25zKGRhdGVQcm9maWxlLnNsb3RNaW5UaW1lLCBtdWx0aXBseUR1cmF0aW9uKHNuYXBEdXJhdGlvbiwgc25hcEluZGV4KSk7XG4gICAgICAgICAgICBsZXQgc3RhcnQgPSBkYXRlRW52LmFkZChkYXlEYXRlLCB0aW1lKTtcbiAgICAgICAgICAgIGxldCBlbmQgPSBkYXRlRW52LmFkZChzdGFydCwgc25hcER1cmF0aW9uKTtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgZGF0ZVByb2ZpbGUsXG4gICAgICAgICAgICAgICAgZGF0ZVNwYW46IE9iamVjdC5hc3NpZ24oeyByYW5nZTogeyBzdGFydCwgZW5kIH0sIGFsbERheTogZmFsc2UgfSwgY2VsbC5leHRyYURhdGVTcGFuKSxcbiAgICAgICAgICAgICAgICBkYXlFbDogY29sQ29vcmRzLmVsc1tjb2xJbmRleF0sXG4gICAgICAgICAgICAgICAgcmVjdDoge1xuICAgICAgICAgICAgICAgICAgICBsZWZ0OiBjb2xDb29yZHMubGVmdHNbY29sSW5kZXhdLFxuICAgICAgICAgICAgICAgICAgICByaWdodDogY29sQ29vcmRzLnJpZ2h0c1tjb2xJbmRleF0sXG4gICAgICAgICAgICAgICAgICAgIHRvcDogc2xhdFRvcCxcbiAgICAgICAgICAgICAgICAgICAgYm90dG9tOiBzbGF0VG9wICsgc2xhdEhlaWdodCxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGxheWVyOiAwLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG59XG5mdW5jdGlvbiBwcm9jZXNzU2xvdE9wdGlvbnMoc2xvdER1cmF0aW9uLCBzbmFwRHVyYXRpb25PdmVycmlkZSkge1xuICAgIGxldCBzbmFwRHVyYXRpb24gPSBzbmFwRHVyYXRpb25PdmVycmlkZSB8fCBzbG90RHVyYXRpb247XG4gICAgbGV0IHNuYXBzUGVyU2xvdCA9IHdob2xlRGl2aWRlRHVyYXRpb25zKHNsb3REdXJhdGlvbiwgc25hcER1cmF0aW9uKTtcbiAgICBpZiAoc25hcHNQZXJTbG90ID09PSBudWxsKSB7XG4gICAgICAgIHNuYXBEdXJhdGlvbiA9IHNsb3REdXJhdGlvbjtcbiAgICAgICAgc25hcHNQZXJTbG90ID0gMTtcbiAgICAgICAgLy8gVE9ETzogc2F5IHdhcm5pbmc/XG4gICAgfVxuICAgIHJldHVybiB7IHNuYXBEdXJhdGlvbiwgc25hcHNQZXJTbG90IH07XG59XG5cbmNsYXNzIERheVRpbWVDb2xzU2xpY2VyIGV4dGVuZHMgU2xpY2VyIHtcbiAgICBzbGljZVJhbmdlKHJhbmdlLCBkYXlSYW5nZXMpIHtcbiAgICAgICAgbGV0IHNlZ3MgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgY29sID0gMDsgY29sIDwgZGF5UmFuZ2VzLmxlbmd0aDsgY29sICs9IDEpIHtcbiAgICAgICAgICAgIGxldCBzZWdSYW5nZSA9IGludGVyc2VjdFJhbmdlcyhyYW5nZSwgZGF5UmFuZ2VzW2NvbF0pO1xuICAgICAgICAgICAgaWYgKHNlZ1JhbmdlKSB7XG4gICAgICAgICAgICAgICAgc2Vncy5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgc3RhcnQ6IHNlZ1JhbmdlLnN0YXJ0LFxuICAgICAgICAgICAgICAgICAgICBlbmQ6IHNlZ1JhbmdlLmVuZCxcbiAgICAgICAgICAgICAgICAgICAgaXNTdGFydDogc2VnUmFuZ2Uuc3RhcnQudmFsdWVPZigpID09PSByYW5nZS5zdGFydC52YWx1ZU9mKCksXG4gICAgICAgICAgICAgICAgICAgIGlzRW5kOiBzZWdSYW5nZS5lbmQudmFsdWVPZigpID09PSByYW5nZS5lbmQudmFsdWVPZigpLFxuICAgICAgICAgICAgICAgICAgICBjb2wsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlZ3M7XG4gICAgfVxufVxuXG5jbGFzcyBEYXlUaW1lQ29scyBleHRlbmRzIERhdGVDb21wb25lbnQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlciguLi5hcmd1bWVudHMpO1xuICAgICAgICB0aGlzLmJ1aWxkRGF5UmFuZ2VzID0gbWVtb2l6ZShidWlsZERheVJhbmdlcyk7XG4gICAgICAgIHRoaXMuc2xpY2VyID0gbmV3IERheVRpbWVDb2xzU2xpY2VyKCk7XG4gICAgICAgIHRoaXMudGltZUNvbHNSZWYgPSBjcmVhdGVSZWYoKTtcbiAgICB9XG4gICAgcmVuZGVyKCkge1xuICAgICAgICBsZXQgeyBwcm9wcywgY29udGV4dCB9ID0gdGhpcztcbiAgICAgICAgbGV0IHsgZGF0ZVByb2ZpbGUsIGRheVRhYmxlTW9kZWwgfSA9IHByb3BzO1xuICAgICAgICBsZXQgeyBub3dJbmRpY2F0b3IsIG5leHREYXlUaHJlc2hvbGQgfSA9IGNvbnRleHQub3B0aW9ucztcbiAgICAgICAgbGV0IGRheVJhbmdlcyA9IHRoaXMuYnVpbGREYXlSYW5nZXMoZGF5VGFibGVNb2RlbCwgZGF0ZVByb2ZpbGUsIGNvbnRleHQuZGF0ZUVudik7XG4gICAgICAgIC8vIGdpdmUgaXQgdGhlIGZpcnN0IHJvdyBvZiBjZWxsc1xuICAgICAgICAvLyBUT0RPOiB3b3VsZCBtb3ZlIHRoaXMgZnVydGhlciBkb3duIGhpZXJhcmNoeSwgYnV0IHNsaWNlTm93RGF0ZSBuZWVkcyBpdFxuICAgICAgICByZXR1cm4gKGNyZWF0ZUVsZW1lbnQoTm93VGltZXIsIHsgdW5pdDogbm93SW5kaWNhdG9yID8gJ21pbnV0ZScgOiAnZGF5JyB9LCAobm93RGF0ZSwgdG9kYXlSYW5nZSkgPT4gKGNyZWF0ZUVsZW1lbnQoVGltZUNvbHMsIE9iamVjdC5hc3NpZ24oeyByZWY6IHRoaXMudGltZUNvbHNSZWYgfSwgdGhpcy5zbGljZXIuc2xpY2VQcm9wcyhwcm9wcywgZGF0ZVByb2ZpbGUsIG51bGwsIGNvbnRleHQsIGRheVJhbmdlcyksIHsgZm9yUHJpbnQ6IHByb3BzLmZvclByaW50LCBheGlzOiBwcm9wcy5heGlzLCBkYXRlUHJvZmlsZTogZGF0ZVByb2ZpbGUsIHNsYXRNZXRhczogcHJvcHMuc2xhdE1ldGFzLCBzbG90RHVyYXRpb246IHByb3BzLnNsb3REdXJhdGlvbiwgY2VsbHM6IGRheVRhYmxlTW9kZWwuY2VsbHNbMF0sIHRhYmxlQ29sR3JvdXBOb2RlOiBwcm9wcy50YWJsZUNvbEdyb3VwTm9kZSwgdGFibGVNaW5XaWR0aDogcHJvcHMudGFibGVNaW5XaWR0aCwgY2xpZW50V2lkdGg6IHByb3BzLmNsaWVudFdpZHRoLCBjbGllbnRIZWlnaHQ6IHByb3BzLmNsaWVudEhlaWdodCwgZXhwYW5kUm93czogcHJvcHMuZXhwYW5kUm93cywgbm93RGF0ZTogbm93RGF0ZSwgbm93SW5kaWNhdG9yU2Vnczogbm93SW5kaWNhdG9yICYmIHRoaXMuc2xpY2VyLnNsaWNlTm93RGF0ZShub3dEYXRlLCBkYXRlUHJvZmlsZSwgbmV4dERheVRocmVzaG9sZCwgY29udGV4dCwgZGF5UmFuZ2VzKSwgdG9kYXlSYW5nZTogdG9kYXlSYW5nZSwgb25TY3JvbGxUb3BSZXF1ZXN0OiBwcm9wcy5vblNjcm9sbFRvcFJlcXVlc3QsIG9uU2xhdENvb3JkczogcHJvcHMub25TbGF0Q29vcmRzIH0pKSkpKTtcbiAgICB9XG59XG5mdW5jdGlvbiBidWlsZERheVJhbmdlcyhkYXlUYWJsZU1vZGVsLCBkYXRlUHJvZmlsZSwgZGF0ZUVudikge1xuICAgIGxldCByYW5nZXMgPSBbXTtcbiAgICBmb3IgKGxldCBkYXRlIG9mIGRheVRhYmxlTW9kZWwuaGVhZGVyRGF0ZXMpIHtcbiAgICAgICAgcmFuZ2VzLnB1c2goe1xuICAgICAgICAgICAgc3RhcnQ6IGRhdGVFbnYuYWRkKGRhdGUsIGRhdGVQcm9maWxlLnNsb3RNaW5UaW1lKSxcbiAgICAgICAgICAgIGVuZDogZGF0ZUVudi5hZGQoZGF0ZSwgZGF0ZVByb2ZpbGUuc2xvdE1heFRpbWUpLFxuICAgICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHJhbmdlcztcbn1cblxuLy8gcG90ZW50aWFsIG5pY2UgdmFsdWVzIGZvciB0aGUgc2xvdC1kdXJhdGlvbiBhbmQgaW50ZXJ2YWwtZHVyYXRpb25cbi8vIGZyb20gbGFyZ2VzdCB0byBzbWFsbGVzdFxuY29uc3QgU1RPQ0tfU1VCX0RVUkFUSU9OUyA9IFtcbiAgICB7IGhvdXJzOiAxIH0sXG4gICAgeyBtaW51dGVzOiAzMCB9LFxuICAgIHsgbWludXRlczogMTUgfSxcbiAgICB7IHNlY29uZHM6IDMwIH0sXG4gICAgeyBzZWNvbmRzOiAxNSB9LFxuXTtcbmZ1bmN0aW9uIGJ1aWxkU2xhdE1ldGFzKHNsb3RNaW5UaW1lLCBzbG90TWF4VGltZSwgZXhwbGljaXRMYWJlbEludGVydmFsLCBzbG90RHVyYXRpb24sIGRhdGVFbnYpIHtcbiAgICBsZXQgZGF5U3RhcnQgPSBuZXcgRGF0ZSgwKTtcbiAgICBsZXQgc2xhdFRpbWUgPSBzbG90TWluVGltZTtcbiAgICBsZXQgc2xhdEl0ZXJhdG9yID0gY3JlYXRlRHVyYXRpb24oMCk7XG4gICAgbGV0IGxhYmVsSW50ZXJ2YWwgPSBleHBsaWNpdExhYmVsSW50ZXJ2YWwgfHwgY29tcHV0ZUxhYmVsSW50ZXJ2YWwoc2xvdER1cmF0aW9uKTtcbiAgICBsZXQgbWV0YXMgPSBbXTtcbiAgICB3aGlsZSAoYXNSb3VnaE1zKHNsYXRUaW1lKSA8IGFzUm91Z2hNcyhzbG90TWF4VGltZSkpIHtcbiAgICAgICAgbGV0IGRhdGUgPSBkYXRlRW52LmFkZChkYXlTdGFydCwgc2xhdFRpbWUpO1xuICAgICAgICBsZXQgaXNMYWJlbGVkID0gd2hvbGVEaXZpZGVEdXJhdGlvbnMoc2xhdEl0ZXJhdG9yLCBsYWJlbEludGVydmFsKSAhPT0gbnVsbDtcbiAgICAgICAgbWV0YXMucHVzaCh7XG4gICAgICAgICAgICBkYXRlLFxuICAgICAgICAgICAgdGltZTogc2xhdFRpbWUsXG4gICAgICAgICAgICBrZXk6IGRhdGUudG9JU09TdHJpbmcoKSxcbiAgICAgICAgICAgIGlzb1RpbWVTdHI6IGZvcm1hdElzb1RpbWVTdHJpbmcoZGF0ZSksXG4gICAgICAgICAgICBpc0xhYmVsZWQsXG4gICAgICAgIH0pO1xuICAgICAgICBzbGF0VGltZSA9IGFkZER1cmF0aW9ucyhzbGF0VGltZSwgc2xvdER1cmF0aW9uKTtcbiAgICAgICAgc2xhdEl0ZXJhdG9yID0gYWRkRHVyYXRpb25zKHNsYXRJdGVyYXRvciwgc2xvdER1cmF0aW9uKTtcbiAgICB9XG4gICAgcmV0dXJuIG1ldGFzO1xufVxuLy8gQ29tcHV0ZXMgYW4gYXV0b21hdGljIHZhbHVlIGZvciBzbG90TGFiZWxJbnRlcnZhbFxuZnVuY3Rpb24gY29tcHV0ZUxhYmVsSW50ZXJ2YWwoc2xvdER1cmF0aW9uKSB7XG4gICAgbGV0IGk7XG4gICAgbGV0IGxhYmVsSW50ZXJ2YWw7XG4gICAgbGV0IHNsb3RzUGVyTGFiZWw7XG4gICAgLy8gZmluZCB0aGUgc21hbGxlc3Qgc3RvY2sgbGFiZWwgaW50ZXJ2YWwgdGhhdCByZXN1bHRzIGluIG1vcmUgdGhhbiBvbmUgc2xvdHMtcGVyLWxhYmVsXG4gICAgZm9yIChpID0gU1RPQ0tfU1VCX0RVUkFUSU9OUy5sZW5ndGggLSAxOyBpID49IDA7IGkgLT0gMSkge1xuICAgICAgICBsYWJlbEludGVydmFsID0gY3JlYXRlRHVyYXRpb24oU1RPQ0tfU1VCX0RVUkFUSU9OU1tpXSk7XG4gICAgICAgIHNsb3RzUGVyTGFiZWwgPSB3aG9sZURpdmlkZUR1cmF0aW9ucyhsYWJlbEludGVydmFsLCBzbG90RHVyYXRpb24pO1xuICAgICAgICBpZiAoc2xvdHNQZXJMYWJlbCAhPT0gbnVsbCAmJiBzbG90c1BlckxhYmVsID4gMSkge1xuICAgICAgICAgICAgcmV0dXJuIGxhYmVsSW50ZXJ2YWw7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHNsb3REdXJhdGlvbjsgLy8gZmFsbCBiYWNrXG59XG5cbmNsYXNzIERheVRpbWVDb2xzVmlldyBleHRlbmRzIFRpbWVDb2xzVmlldyB7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKC4uLmFyZ3VtZW50cyk7XG4gICAgICAgIHRoaXMuYnVpbGRUaW1lQ29sc01vZGVsID0gbWVtb2l6ZShidWlsZFRpbWVDb2xzTW9kZWwpO1xuICAgICAgICB0aGlzLmJ1aWxkU2xhdE1ldGFzID0gbWVtb2l6ZShidWlsZFNsYXRNZXRhcyk7XG4gICAgfVxuICAgIHJlbmRlcigpIHtcbiAgICAgICAgbGV0IHsgb3B0aW9ucywgZGF0ZUVudiwgZGF0ZVByb2ZpbGVHZW5lcmF0b3IgfSA9IHRoaXMuY29udGV4dDtcbiAgICAgICAgbGV0IHsgcHJvcHMgfSA9IHRoaXM7XG4gICAgICAgIGxldCB7IGRhdGVQcm9maWxlIH0gPSBwcm9wcztcbiAgICAgICAgbGV0IGRheVRhYmxlTW9kZWwgPSB0aGlzLmJ1aWxkVGltZUNvbHNNb2RlbChkYXRlUHJvZmlsZSwgZGF0ZVByb2ZpbGVHZW5lcmF0b3IpO1xuICAgICAgICBsZXQgc3BsaXRQcm9wcyA9IHRoaXMuYWxsRGF5U3BsaXR0ZXIuc3BsaXRQcm9wcyhwcm9wcyk7XG4gICAgICAgIGxldCBzbGF0TWV0YXMgPSB0aGlzLmJ1aWxkU2xhdE1ldGFzKGRhdGVQcm9maWxlLnNsb3RNaW5UaW1lLCBkYXRlUHJvZmlsZS5zbG90TWF4VGltZSwgb3B0aW9ucy5zbG90TGFiZWxJbnRlcnZhbCwgb3B0aW9ucy5zbG90RHVyYXRpb24sIGRhdGVFbnYpO1xuICAgICAgICBsZXQgeyBkYXlNaW5XaWR0aCB9ID0gb3B0aW9ucztcbiAgICAgICAgbGV0IGhhc0F0dGFjaGVkQXhpcyA9ICFkYXlNaW5XaWR0aDtcbiAgICAgICAgbGV0IGhhc0RldGFjaGVkQXhpcyA9IGRheU1pbldpZHRoO1xuICAgICAgICBsZXQgaGVhZGVyQ29udGVudCA9IG9wdGlvbnMuZGF5SGVhZGVycyAmJiAoY3JlYXRlRWxlbWVudChEYXlIZWFkZXIsIHsgZGF0ZXM6IGRheVRhYmxlTW9kZWwuaGVhZGVyRGF0ZXMsIGRhdGVQcm9maWxlOiBkYXRlUHJvZmlsZSwgZGF0ZXNSZXBEaXN0aW5jdERheXM6IHRydWUsIHJlbmRlckludHJvOiBoYXNBdHRhY2hlZEF4aXMgPyB0aGlzLnJlbmRlckhlYWRBeGlzIDogbnVsbCB9KSk7XG4gICAgICAgIGxldCBhbGxEYXlDb250ZW50ID0gKG9wdGlvbnMuYWxsRGF5U2xvdCAhPT0gZmFsc2UpICYmICgoY29udGVudEFyZykgPT4gKGNyZWF0ZUVsZW1lbnQoRGF5VGFibGUsIE9iamVjdC5hc3NpZ24oe30sIHNwbGl0UHJvcHMuYWxsRGF5LCB7IGRhdGVQcm9maWxlOiBkYXRlUHJvZmlsZSwgZGF5VGFibGVNb2RlbDogZGF5VGFibGVNb2RlbCwgbmV4dERheVRocmVzaG9sZDogb3B0aW9ucy5uZXh0RGF5VGhyZXNob2xkLCB0YWJsZU1pbldpZHRoOiBjb250ZW50QXJnLnRhYmxlTWluV2lkdGgsIGNvbEdyb3VwTm9kZTogY29udGVudEFyZy50YWJsZUNvbEdyb3VwTm9kZSwgcmVuZGVyUm93SW50cm86IGhhc0F0dGFjaGVkQXhpcyA/IHRoaXMucmVuZGVyVGFibGVSb3dBeGlzIDogbnVsbCwgc2hvd1dlZWtOdW1iZXJzOiBmYWxzZSwgZXhwYW5kUm93czogZmFsc2UsIGhlYWRlckFsaWduRWxSZWY6IHRoaXMuaGVhZGVyRWxSZWYsIGNsaWVudFdpZHRoOiBjb250ZW50QXJnLmNsaWVudFdpZHRoLCBjbGllbnRIZWlnaHQ6IGNvbnRlbnRBcmcuY2xpZW50SGVpZ2h0LCBmb3JQcmludDogcHJvcHMuZm9yUHJpbnQgfSwgdGhpcy5nZXRBbGxEYXlNYXhFdmVudFByb3BzKCkpKSkpO1xuICAgICAgICBsZXQgdGltZUdyaWRDb250ZW50ID0gKGNvbnRlbnRBcmcpID0+IChjcmVhdGVFbGVtZW50KERheVRpbWVDb2xzLCBPYmplY3QuYXNzaWduKHt9LCBzcGxpdFByb3BzLnRpbWVkLCB7IGRheVRhYmxlTW9kZWw6IGRheVRhYmxlTW9kZWwsIGRhdGVQcm9maWxlOiBkYXRlUHJvZmlsZSwgYXhpczogaGFzQXR0YWNoZWRBeGlzLCBzbG90RHVyYXRpb246IG9wdGlvbnMuc2xvdER1cmF0aW9uLCBzbGF0TWV0YXM6IHNsYXRNZXRhcywgZm9yUHJpbnQ6IHByb3BzLmZvclByaW50LCB0YWJsZUNvbEdyb3VwTm9kZTogY29udGVudEFyZy50YWJsZUNvbEdyb3VwTm9kZSwgdGFibGVNaW5XaWR0aDogY29udGVudEFyZy50YWJsZU1pbldpZHRoLCBjbGllbnRXaWR0aDogY29udGVudEFyZy5jbGllbnRXaWR0aCwgY2xpZW50SGVpZ2h0OiBjb250ZW50QXJnLmNsaWVudEhlaWdodCwgb25TbGF0Q29vcmRzOiB0aGlzLmhhbmRsZVNsYXRDb29yZHMsIGV4cGFuZFJvd3M6IGNvbnRlbnRBcmcuZXhwYW5kUm93cywgb25TY3JvbGxUb3BSZXF1ZXN0OiB0aGlzLmhhbmRsZVNjcm9sbFRvcFJlcXVlc3QgfSkpKTtcbiAgICAgICAgcmV0dXJuIGhhc0RldGFjaGVkQXhpc1xuICAgICAgICAgICAgPyB0aGlzLnJlbmRlckhTY3JvbGxMYXlvdXQoaGVhZGVyQ29udGVudCwgYWxsRGF5Q29udGVudCwgdGltZUdyaWRDb250ZW50LCBkYXlUYWJsZU1vZGVsLmNvbENudCwgZGF5TWluV2lkdGgsIHNsYXRNZXRhcywgdGhpcy5zdGF0ZS5zbGF0Q29vcmRzKVxuICAgICAgICAgICAgOiB0aGlzLnJlbmRlclNpbXBsZUxheW91dChoZWFkZXJDb250ZW50LCBhbGxEYXlDb250ZW50LCB0aW1lR3JpZENvbnRlbnQpO1xuICAgIH1cbn1cbmZ1bmN0aW9uIGJ1aWxkVGltZUNvbHNNb2RlbChkYXRlUHJvZmlsZSwgZGF0ZVByb2ZpbGVHZW5lcmF0b3IpIHtcbiAgICBsZXQgZGF5U2VyaWVzID0gbmV3IERheVNlcmllc01vZGVsKGRhdGVQcm9maWxlLnJlbmRlclJhbmdlLCBkYXRlUHJvZmlsZUdlbmVyYXRvcik7XG4gICAgcmV0dXJuIG5ldyBEYXlUYWJsZU1vZGVsKGRheVNlcmllcywgZmFsc2UpO1xufVxuXG52YXIgY3NzXzI0OHogPSBcIi5mYy12LWV2ZW50e2JhY2tncm91bmQtY29sb3I6dmFyKC0tZmMtZXZlbnQtYmctY29sb3IpO2JvcmRlcjoxcHggc29saWQgdmFyKC0tZmMtZXZlbnQtYm9yZGVyLWNvbG9yKTtkaXNwbGF5OmJsb2NrfS5mYy12LWV2ZW50IC5mYy1ldmVudC1tYWlue2NvbG9yOnZhcigtLWZjLWV2ZW50LXRleHQtY29sb3IpO2hlaWdodDoxMDAlfS5mYy12LWV2ZW50IC5mYy1ldmVudC1tYWluLWZyYW1le2Rpc3BsYXk6ZmxleDtmbGV4LWRpcmVjdGlvbjpjb2x1bW47aGVpZ2h0OjEwMCV9LmZjLXYtZXZlbnQgLmZjLWV2ZW50LXRpbWV7ZmxleC1ncm93OjA7ZmxleC1zaHJpbms6MDttYXgtaGVpZ2h0OjEwMCU7b3ZlcmZsb3c6aGlkZGVufS5mYy12LWV2ZW50IC5mYy1ldmVudC10aXRsZS1jb250YWluZXJ7ZmxleC1ncm93OjE7ZmxleC1zaHJpbms6MTttaW4taGVpZ2h0OjB9LmZjLXYtZXZlbnQgLmZjLWV2ZW50LXRpdGxle2JvdHRvbTowO21heC1oZWlnaHQ6MTAwJTtvdmVyZmxvdzpoaWRkZW47dG9wOjB9LmZjLXYtZXZlbnQ6bm90KC5mYy1ldmVudC1zdGFydCl7Ym9yZGVyLXRvcC1sZWZ0LXJhZGl1czowO2JvcmRlci10b3AtcmlnaHQtcmFkaXVzOjA7Ym9yZGVyLXRvcC13aWR0aDowfS5mYy12LWV2ZW50Om5vdCguZmMtZXZlbnQtZW5kKXtib3JkZXItYm90dG9tLWxlZnQtcmFkaXVzOjA7Ym9yZGVyLWJvdHRvbS1yaWdodC1yYWRpdXM6MDtib3JkZXItYm90dG9tLXdpZHRoOjB9LmZjLXYtZXZlbnQuZmMtZXZlbnQtc2VsZWN0ZWQ6YmVmb3Jle2xlZnQ6LTEwcHg7cmlnaHQ6LTEwcHh9LmZjLXYtZXZlbnQgLmZjLWV2ZW50LXJlc2l6ZXItc3RhcnR7Y3Vyc29yOm4tcmVzaXplfS5mYy12LWV2ZW50IC5mYy1ldmVudC1yZXNpemVyLWVuZHtjdXJzb3I6cy1yZXNpemV9LmZjLXYtZXZlbnQ6bm90KC5mYy1ldmVudC1zZWxlY3RlZCkgLmZjLWV2ZW50LXJlc2l6ZXJ7aGVpZ2h0OnZhcigtLWZjLWV2ZW50LXJlc2l6ZXItdGhpY2tuZXNzKTtsZWZ0OjA7cmlnaHQ6MH0uZmMtdi1ldmVudDpub3QoLmZjLWV2ZW50LXNlbGVjdGVkKSAuZmMtZXZlbnQtcmVzaXplci1zdGFydHt0b3A6Y2FsYyh2YXIoLS1mYy1ldmVudC1yZXNpemVyLXRoaWNrbmVzcykvLTIpfS5mYy12LWV2ZW50Om5vdCguZmMtZXZlbnQtc2VsZWN0ZWQpIC5mYy1ldmVudC1yZXNpemVyLWVuZHtib3R0b206Y2FsYyh2YXIoLS1mYy1ldmVudC1yZXNpemVyLXRoaWNrbmVzcykvLTIpfS5mYy12LWV2ZW50LmZjLWV2ZW50LXNlbGVjdGVkIC5mYy1ldmVudC1yZXNpemVye2xlZnQ6NTAlO21hcmdpbi1sZWZ0OmNhbGModmFyKC0tZmMtZXZlbnQtcmVzaXplci1kb3QtdG90YWwtd2lkdGgpLy0yKX0uZmMtdi1ldmVudC5mYy1ldmVudC1zZWxlY3RlZCAuZmMtZXZlbnQtcmVzaXplci1zdGFydHt0b3A6Y2FsYyh2YXIoLS1mYy1ldmVudC1yZXNpemVyLWRvdC10b3RhbC13aWR0aCkvLTIpfS5mYy12LWV2ZW50LmZjLWV2ZW50LXNlbGVjdGVkIC5mYy1ldmVudC1yZXNpemVyLWVuZHtib3R0b206Y2FsYyh2YXIoLS1mYy1ldmVudC1yZXNpemVyLWRvdC10b3RhbC13aWR0aCkvLTIpfS5mYyAuZmMtdGltZWdyaWQgLmZjLWRheWdyaWQtYm9keXt6LWluZGV4OjJ9LmZjIC5mYy10aW1lZ3JpZC1kaXZpZGVye3BhZGRpbmc6MCAwIDJweH0uZmMgLmZjLXRpbWVncmlkLWJvZHl7bWluLWhlaWdodDoxMDAlO3Bvc2l0aW9uOnJlbGF0aXZlO3otaW5kZXg6MX0uZmMgLmZjLXRpbWVncmlkLWF4aXMtY2h1bmt7cG9zaXRpb246cmVsYXRpdmV9LmZjIC5mYy10aW1lZ3JpZC1heGlzLWNodW5rPnRhYmxlLC5mYyAuZmMtdGltZWdyaWQtc2xvdHN7cG9zaXRpb246cmVsYXRpdmU7ei1pbmRleDoxfS5mYyAuZmMtdGltZWdyaWQtc2xvdHtib3JkZXItYm90dG9tOjA7aGVpZ2h0OjEuNWVtfS5mYyAuZmMtdGltZWdyaWQtc2xvdDplbXB0eTpiZWZvcmV7Y29udGVudDpcXFwiXFxcXDAwYTBcXFwifS5mYyAuZmMtdGltZWdyaWQtc2xvdC1taW5vcntib3JkZXItdG9wLXN0eWxlOmRvdHRlZH0uZmMgLmZjLXRpbWVncmlkLXNsb3QtbGFiZWwtY3VzaGlvbntkaXNwbGF5OmlubGluZS1ibG9jazt3aGl0ZS1zcGFjZTpub3dyYXB9LmZjIC5mYy10aW1lZ3JpZC1zbG90LWxhYmVse3ZlcnRpY2FsLWFsaWduOm1pZGRsZX0uZmMgLmZjLXRpbWVncmlkLWF4aXMtY3VzaGlvbiwuZmMgLmZjLXRpbWVncmlkLXNsb3QtbGFiZWwtY3VzaGlvbntwYWRkaW5nOjAgNHB4fS5mYyAuZmMtdGltZWdyaWQtYXhpcy1mcmFtZS1saXF1aWR7aGVpZ2h0OjEwMCV9LmZjIC5mYy10aW1lZ3JpZC1heGlzLWZyYW1le2FsaWduLWl0ZW1zOmNlbnRlcjtkaXNwbGF5OmZsZXg7anVzdGlmeS1jb250ZW50OmZsZXgtZW5kO292ZXJmbG93OmhpZGRlbn0uZmMgLmZjLXRpbWVncmlkLWF4aXMtY3VzaGlvbntmbGV4LXNocmluazowO21heC13aWR0aDo2MHB4fS5mYy1kaXJlY3Rpb24tbHRyIC5mYy10aW1lZ3JpZC1zbG90LWxhYmVsLWZyYW1le3RleHQtYWxpZ246cmlnaHR9LmZjLWRpcmVjdGlvbi1ydGwgLmZjLXRpbWVncmlkLXNsb3QtbGFiZWwtZnJhbWV7dGV4dC1hbGlnbjpsZWZ0fS5mYy1saXF1aWQtaGFjayAuZmMtdGltZWdyaWQtYXhpcy1mcmFtZS1saXF1aWR7Ym90dG9tOjA7aGVpZ2h0OmF1dG87bGVmdDowO3Bvc2l0aW9uOmFic29sdXRlO3JpZ2h0OjA7dG9wOjB9LmZjIC5mYy10aW1lZ3JpZC1jb2wuZmMtZGF5LXRvZGF5e2JhY2tncm91bmQtY29sb3I6dmFyKC0tZmMtdG9kYXktYmctY29sb3IpfS5mYyAuZmMtdGltZWdyaWQtY29sLWZyYW1le21pbi1oZWlnaHQ6MTAwJTtwb3NpdGlvbjpyZWxhdGl2ZX0uZmMtbWVkaWEtc2NyZWVuLmZjLWxpcXVpZC1oYWNrIC5mYy10aW1lZ3JpZC1jb2wtZnJhbWV7Ym90dG9tOjA7aGVpZ2h0OmF1dG87bGVmdDowO3Bvc2l0aW9uOmFic29sdXRlO3JpZ2h0OjA7dG9wOjB9LmZjLW1lZGlhLXNjcmVlbiAuZmMtdGltZWdyaWQtY29sc3tib3R0b206MDtsZWZ0OjA7cG9zaXRpb246YWJzb2x1dGU7cmlnaHQ6MDt0b3A6MH0uZmMtbWVkaWEtc2NyZWVuIC5mYy10aW1lZ3JpZC1jb2xzPnRhYmxle2hlaWdodDoxMDAlfS5mYy1tZWRpYS1zY3JlZW4gLmZjLXRpbWVncmlkLWNvbC1iZywuZmMtbWVkaWEtc2NyZWVuIC5mYy10aW1lZ3JpZC1jb2wtZXZlbnRzLC5mYy1tZWRpYS1zY3JlZW4gLmZjLXRpbWVncmlkLW5vdy1pbmRpY2F0b3ItY29udGFpbmVye2xlZnQ6MDtwb3NpdGlvbjphYnNvbHV0ZTtyaWdodDowO3RvcDowfS5mYyAuZmMtdGltZWdyaWQtY29sLWJne3otaW5kZXg6Mn0uZmMgLmZjLXRpbWVncmlkLWNvbC1iZyAuZmMtbm9uLWJ1c2luZXNze3otaW5kZXg6MX0uZmMgLmZjLXRpbWVncmlkLWNvbC1iZyAuZmMtYmctZXZlbnR7ei1pbmRleDoyfS5mYyAuZmMtdGltZWdyaWQtY29sLWJnIC5mYy1oaWdobGlnaHR7ei1pbmRleDozfS5mYyAuZmMtdGltZWdyaWQtYmctaGFybmVzc3tsZWZ0OjA7cG9zaXRpb246YWJzb2x1dGU7cmlnaHQ6MH0uZmMgLmZjLXRpbWVncmlkLWNvbC1ldmVudHN7ei1pbmRleDozfS5mYyAuZmMtdGltZWdyaWQtbm93LWluZGljYXRvci1jb250YWluZXJ7Ym90dG9tOjA7b3ZlcmZsb3c6aGlkZGVufS5mYy1kaXJlY3Rpb24tbHRyIC5mYy10aW1lZ3JpZC1jb2wtZXZlbnRze21hcmdpbjowIDIuNSUgMCAycHh9LmZjLWRpcmVjdGlvbi1ydGwgLmZjLXRpbWVncmlkLWNvbC1ldmVudHN7bWFyZ2luOjAgMnB4IDAgMi41JX0uZmMtdGltZWdyaWQtZXZlbnQtaGFybmVzc3twb3NpdGlvbjphYnNvbHV0ZX0uZmMtdGltZWdyaWQtZXZlbnQtaGFybmVzcz4uZmMtdGltZWdyaWQtZXZlbnR7Ym90dG9tOjA7bGVmdDowO3Bvc2l0aW9uOmFic29sdXRlO3JpZ2h0OjA7dG9wOjB9LmZjLXRpbWVncmlkLWV2ZW50LWhhcm5lc3MtaW5zZXQgLmZjLXRpbWVncmlkLWV2ZW50LC5mYy10aW1lZ3JpZC1ldmVudC5mYy1ldmVudC1taXJyb3IsLmZjLXRpbWVncmlkLW1vcmUtbGlua3tib3gtc2hhZG93OjAgMCAwIDFweCB2YXIoLS1mYy1wYWdlLWJnLWNvbG9yKX0uZmMtdGltZWdyaWQtZXZlbnQsLmZjLXRpbWVncmlkLW1vcmUtbGlua3tib3JkZXItcmFkaXVzOjNweDtmb250LXNpemU6dmFyKC0tZmMtc21hbGwtZm9udC1zaXplKX0uZmMtdGltZWdyaWQtZXZlbnR7bWFyZ2luLWJvdHRvbToxcHh9LmZjLXRpbWVncmlkLWV2ZW50IC5mYy1ldmVudC1tYWlue3BhZGRpbmc6MXB4IDFweCAwfS5mYy10aW1lZ3JpZC1ldmVudCAuZmMtZXZlbnQtdGltZXtmb250LXNpemU6dmFyKC0tZmMtc21hbGwtZm9udC1zaXplKTttYXJnaW4tYm90dG9tOjFweDt3aGl0ZS1zcGFjZTpub3dyYXB9LmZjLXRpbWVncmlkLWV2ZW50LXNob3J0IC5mYy1ldmVudC1tYWluLWZyYW1le2ZsZXgtZGlyZWN0aW9uOnJvdztvdmVyZmxvdzpoaWRkZW59LmZjLXRpbWVncmlkLWV2ZW50LXNob3J0IC5mYy1ldmVudC10aW1lOmFmdGVye2NvbnRlbnQ6XFxcIlxcXFwwMGEwLVxcXFwwMGEwXFxcIn0uZmMtdGltZWdyaWQtZXZlbnQtc2hvcnQgLmZjLWV2ZW50LXRpdGxle2ZvbnQtc2l6ZTp2YXIoLS1mYy1zbWFsbC1mb250LXNpemUpfS5mYy10aW1lZ3JpZC1tb3JlLWxpbmt7YmFja2dyb3VuZDp2YXIoLS1mYy1tb3JlLWxpbmstYmctY29sb3IpO2NvbG9yOnZhcigtLWZjLW1vcmUtbGluay10ZXh0LWNvbG9yKTtjdXJzb3I6cG9pbnRlcjttYXJnaW4tYm90dG9tOjFweDtwb3NpdGlvbjphYnNvbHV0ZTt6LWluZGV4Ojk5OTl9LmZjLXRpbWVncmlkLW1vcmUtbGluay1pbm5lcntwYWRkaW5nOjNweCAycHg7dG9wOjB9LmZjLWRpcmVjdGlvbi1sdHIgLmZjLXRpbWVncmlkLW1vcmUtbGlua3tyaWdodDowfS5mYy1kaXJlY3Rpb24tcnRsIC5mYy10aW1lZ3JpZC1tb3JlLWxpbmt7bGVmdDowfS5mYyAuZmMtdGltZWdyaWQtbm93LWluZGljYXRvci1hcnJvdywuZmMgLmZjLXRpbWVncmlkLW5vdy1pbmRpY2F0b3ItbGluZXtwb2ludGVyLWV2ZW50czpub25lfS5mYyAuZmMtdGltZWdyaWQtbm93LWluZGljYXRvci1saW5le2JvcmRlci1jb2xvcjp2YXIoLS1mYy1ub3ctaW5kaWNhdG9yLWNvbG9yKTtib3JkZXItc3R5bGU6c29saWQ7Ym9yZGVyLXdpZHRoOjFweCAwIDA7bGVmdDowO3Bvc2l0aW9uOmFic29sdXRlO3JpZ2h0OjA7ei1pbmRleDo0fS5mYyAuZmMtdGltZWdyaWQtbm93LWluZGljYXRvci1hcnJvd3tib3JkZXItY29sb3I6dmFyKC0tZmMtbm93LWluZGljYXRvci1jb2xvcik7Ym9yZGVyLXN0eWxlOnNvbGlkO21hcmdpbi10b3A6LTVweDtwb3NpdGlvbjphYnNvbHV0ZTt6LWluZGV4OjR9LmZjLWRpcmVjdGlvbi1sdHIgLmZjLXRpbWVncmlkLW5vdy1pbmRpY2F0b3ItYXJyb3d7Ym9yZGVyLWJvdHRvbS1jb2xvcjp0cmFuc3BhcmVudDtib3JkZXItdG9wLWNvbG9yOnRyYW5zcGFyZW50O2JvcmRlci13aWR0aDo1cHggMCA1cHggNnB4O2xlZnQ6MH0uZmMtZGlyZWN0aW9uLXJ0bCAuZmMtdGltZWdyaWQtbm93LWluZGljYXRvci1hcnJvd3tib3JkZXItYm90dG9tLWNvbG9yOnRyYW5zcGFyZW50O2JvcmRlci10b3AtY29sb3I6dHJhbnNwYXJlbnQ7Ym9yZGVyLXdpZHRoOjVweCA2cHggNXB4IDA7cmlnaHQ6MH1cIjtcbmluamVjdFN0eWxlcyhjc3NfMjQ4eik7XG5cbmV4cG9ydCB7IERheVRpbWVDb2xzLCBEYXlUaW1lQ29sc1NsaWNlciwgRGF5VGltZUNvbHNWaWV3LCBUaW1lQ29scywgVGltZUNvbHNTbGF0c0Nvb3JkcywgVGltZUNvbHNWaWV3LCBidWlsZERheVJhbmdlcywgYnVpbGRTbGF0TWV0YXMsIGJ1aWxkVGltZUNvbHNNb2RlbCB9O1xuIl0sIm5hbWVzIjpbXSwiaWdub3JlTGlzdCI6WzBdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///(ssr)/./node_modules/@fullcalendar/timegrid/internal.js\n");
|
|
|
|
/***/ })
|
|
|
|
};
|
|
; |