ObsidianSimpleTimeTracker/test-vault/.obsidian/plugins/simple-time-tracker/main.js
2023-07-05 09:57:58 -04:00

457 lines
56 KiB
JavaScript

/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
var __create = Object.create;
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
var __export = (target, all) => {
__markAsModule(target);
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __reExport = (target, module2, desc) => {
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
for (let key of __getOwnPropNames(module2))
if (!__hasOwnProp.call(target, key) && key !== "default")
__defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
}
return target;
};
var __toModule = (module2) => {
return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
};
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
// src/main.ts
__export(exports, {
default: () => SimpleTimeTrackerPlugin
});
var import_obsidian3 = __toModule(require("obsidian"));
// src/settings.ts
var defaultSettings = {
timestampFormat: "YY-MM-DD HH:mm:ss",
editableTimestampFormat: "YYYY-MM-DD HH:mm:ss",
csvDelimiter: ",",
fineGrainedDurations: true
};
// src/settings-tab.ts
var import_obsidian = __toModule(require("obsidian"));
var SimpleTimeTrackerSettingsTab = class extends import_obsidian.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
this.plugin = plugin;
}
display() {
this.containerEl.empty();
this.containerEl.createEl("h2", { text: "Super Simple Time Tracker Settings" });
new import_obsidian.Setting(this.containerEl).setName("Timestamp Display Format").setDesc(createFragment((f) => {
f.createSpan({ text: "The way that timestamps in time tracker tables should be displayed. Uses " });
f.createEl("a", { text: "moment.js", href: "https://momentjs.com/docs/#/parsing/string-format/" });
f.createSpan({ text: " syntax." });
})).addText((t) => {
t.setValue(String(this.plugin.settings.timestampFormat));
t.onChange((v) => __async(this, null, function* () {
this.plugin.settings.timestampFormat = v.length ? v : defaultSettings.timestampFormat;
yield this.plugin.saveSettings();
}));
});
new import_obsidian.Setting(this.containerEl).setName("CSV Delimiter").setDesc("The delimiter character that should be used when copying a tracker table as CSV. For example, some languages use a semicolon instead of a comma.").addText((t) => {
t.setValue(String(this.plugin.settings.csvDelimiter));
t.onChange((v) => __async(this, null, function* () {
this.plugin.settings.csvDelimiter = v.length ? v : defaultSettings.csvDelimiter;
yield this.plugin.saveSettings();
}));
});
new import_obsidian.Setting(this.containerEl).setName("Fine-Grained Durations").setDesc("Whether durations should include days, months and years. If this is disabled, additional time units will be displayed as part of the hours.").addToggle((t) => {
t.setValue(this.plugin.settings.fineGrainedDurations);
t.onChange((v) => __async(this, null, function* () {
this.plugin.settings.fineGrainedDurations = v;
yield this.plugin.saveSettings();
}));
});
this.containerEl.createEl("hr");
this.containerEl.createEl("p", { text: "If you like this plugin and want to support its development, you can do so through my website by clicking this fancy image!" });
this.containerEl.createEl("a", { href: "https://ellpeck.de/support" }).createEl("img", {
attr: { src: "https://ellpeck.de/res/generalsupport.png" },
cls: "simple-time-tracker-support"
});
}
};
// src/tracker.ts
var import_obsidian2 = __toModule(require("obsidian"));
function saveTracker(tracker, app, fileName, section) {
return __async(this, null, function* () {
let file = app.vault.getAbstractFileByPath(fileName);
if (!file)
return;
let content = yield app.vault.read(file);
let lines = content.split("\n");
let prev = lines.filter((_, i) => i <= section.lineStart).join("\n");
let next = lines.filter((_, i) => i >= section.lineEnd).join("\n");
content = `${prev}
${JSON.stringify(tracker)}
${next}`;
yield app.vault.modify(file, content);
});
}
function loadTracker(json) {
if (json) {
try {
return JSON.parse(json);
} catch (e) {
console.log(`Failed to parse Tracker from ${json}`);
}
}
return { entries: [] };
}
function displayTracker(tracker, element, file, getSectionInfo, settings) {
element.classList.add("simple-time-tracker-container");
let running = isRunning(tracker);
let btn = new import_obsidian2.ButtonComponent(element).setClass("clickable-icon").setIcon(`lucide-${running ? "stop" : "play"}-circle`).setTooltip(running ? "End" : "Start").onClick(() => __async(this, null, function* () {
if (running) {
endRunningEntry(tracker);
} else {
startNewEntry(tracker, newSegmentNameBox.getValue());
}
yield saveTracker(tracker, this.app, file, getSectionInfo());
}));
btn.buttonEl.addClass("simple-time-tracker-btn");
let newSegmentNameBox = new import_obsidian2.TextComponent(element).setPlaceholder("Segment name").setDisabled(running);
newSegmentNameBox.inputEl.addClass("simple-time-tracker-txt");
let timer = element.createDiv({ cls: "simple-time-tracker-timers" });
let currentDiv = timer.createEl("div", { cls: "simple-time-tracker-timer" });
let current = currentDiv.createEl("span", { cls: "simple-time-tracker-timer-time" });
currentDiv.createEl("span", { text: "Current" });
let totalDiv = timer.createEl("div", { cls: "simple-time-tracker-timer" });
let total = totalDiv.createEl("span", { cls: "simple-time-tracker-timer-time", text: "0s" });
totalDiv.createEl("span", { text: "Total" });
if (tracker.entries.length > 0) {
let table = element.createEl("table", { cls: "simple-time-tracker-table" });
table.createEl("tr").append(createEl("th", { text: "Segment" }), createEl("th", { text: "Start time" }), createEl("th", { text: "End time" }), createEl("th", { text: "Duration" }), createEl("th"));
for (let entry of tracker.entries)
addEditableTableRow(tracker, entry, table, newSegmentNameBox, running, file, getSectionInfo, settings, 0);
let buttons = element.createEl("div", { cls: "simple-time-tracker-bottom" });
new import_obsidian2.ButtonComponent(buttons).setButtonText("Copy as table").onClick(() => navigator.clipboard.writeText(createMarkdownTable(tracker, settings)));
new import_obsidian2.ButtonComponent(buttons).setButtonText("Copy as CSV").onClick(() => navigator.clipboard.writeText(createCsv(tracker, settings)));
}
setCountdownValues(tracker, current, total, currentDiv, settings);
let intervalId = window.setInterval(() => {
if (!element.isConnected) {
window.clearInterval(intervalId);
return;
}
setCountdownValues(tracker, current, total, currentDiv, settings);
}, 1e3);
}
function startSubEntry(entry, name) {
if (!entry.subEntries) {
entry.subEntries = [__spreadProps(__spreadValues({}, entry), { name: `Part 1` })];
entry.startTime = null;
entry.endTime = null;
}
if (!name)
name = `Part ${entry.subEntries.length + 1}`;
entry.subEntries.push({ name, startTime: (0, import_obsidian2.moment)().unix(), endTime: null, subEntries: null });
}
function startNewEntry(tracker, name) {
if (!name)
name = `Segment ${tracker.entries.length + 1}`;
let entry = { name, startTime: (0, import_obsidian2.moment)().unix(), endTime: null, subEntries: null };
tracker.entries.push(entry);
}
function endRunningEntry(tracker) {
let entry = getRunningEntry(tracker.entries);
entry.endTime = (0, import_obsidian2.moment)().unix();
}
function removeEntry(entries, toRemove) {
if (entries.contains(toRemove)) {
entries.remove(toRemove);
return true;
} else {
for (let entry of entries) {
if (entry.subEntries && removeEntry(entry.subEntries, toRemove)) {
if (entry.subEntries.length == 1) {
let single = entry.subEntries[0];
entry.startTime = single.startTime;
entry.endTime = single.endTime;
entry.subEntries = null;
}
return true;
}
}
}
return false;
}
function isRunning(tracker) {
return !!getRunningEntry(tracker.entries);
}
function getRunningEntry(entries) {
for (let entry of entries) {
if (entry.subEntries) {
let running = getRunningEntry(entry.subEntries);
if (running)
return running;
} else {
if (!entry.endTime)
return entry;
}
}
return null;
}
function getDuration(entry) {
if (entry.subEntries) {
return getTotalDuration(entry.subEntries);
} else {
let endTime = entry.endTime ? import_obsidian2.moment.unix(entry.endTime) : (0, import_obsidian2.moment)();
return endTime.diff(import_obsidian2.moment.unix(entry.startTime));
}
}
function getTotalDuration(entries) {
let ret = 0;
for (let entry of entries)
ret += getDuration(entry);
return ret;
}
function setCountdownValues(tracker, current, total, currentDiv, settings) {
let running = getRunningEntry(tracker.entries);
if (running && !running.endTime) {
current.setText(formatDuration(getDuration(running), settings));
currentDiv.hidden = false;
} else {
currentDiv.hidden = true;
}
total.setText(formatDuration(getTotalDuration(tracker.entries), settings));
}
function formatTimestamp(timestamp, settings) {
return import_obsidian2.moment.unix(timestamp).format(settings.timestampFormat);
}
function formatEditableTimestamp(timestamp, settings) {
return import_obsidian2.moment.unix(timestamp).format(settings.editableTimestampFormat);
}
function unformatEditableTimestamp(formatted, settings) {
return (0, import_obsidian2.moment)(formatted, settings.editableTimestampFormat).unix();
}
function formatDuration(totalTime, settings) {
let ret = "";
let duration = import_obsidian2.moment.duration(totalTime);
let hours;
if (settings.fineGrainedDurations) {
if (duration.years() > 0)
ret += duration.years() + "y ";
if (duration.months() > 0)
ret += duration.months() + "M ";
if (duration.days() > 0)
ret += duration.days() + "d ";
hours = duration.hours();
} else {
hours = Math.floor(duration.asHours());
}
if (hours > 0)
ret += hours + "h ";
if (duration.minutes() > 0)
ret += duration.minutes() + "m ";
ret += duration.seconds() + "s";
return ret;
}
function createMarkdownTable(tracker, settings) {
let table = [["Segment", "Start time", "End time", "Duration"]];
for (let entry of tracker.entries)
table.push(...createTableSection(entry, settings));
table.push(["**Total**", "", "", `**${formatDuration(getTotalDuration(tracker.entries), settings)}**`]);
let ret = "";
let widths = Array.from(Array(4).keys()).map((i) => Math.max(...table.map((a) => a[i].length)));
for (let r = 0; r < table.length; r++) {
if (r == 1)
ret += "| " + Array.from(Array(4).keys()).map((i) => "-".repeat(widths[i])).join(" | ") + " |\n";
let row = [];
for (let i = 0; i < 4; i++)
row.push(table[r][i].padEnd(widths[i], " "));
ret += "| " + row.join(" | ") + " |\n";
}
return ret;
}
function createCsv(tracker, settings) {
let ret = "";
for (let entry of tracker.entries) {
for (let row of createTableSection(entry, settings))
ret += row.join(settings.csvDelimiter) + "\n";
}
return ret;
}
function createTableSection(entry, settings) {
let ret = [[
entry.name,
entry.startTime ? formatTimestamp(entry.startTime, settings) : "",
entry.endTime ? formatTimestamp(entry.endTime, settings) : "",
entry.endTime || entry.subEntries ? formatDuration(getDuration(entry), settings) : ""
]];
if (entry.subEntries) {
for (let sub of entry.subEntries)
ret.push(...createTableSection(sub, settings));
}
return ret;
}
var EditableField = class {
constructor(row, indent, value) {
this.cell = row.createEl("td");
this.label = this.cell.createEl("span", { text: value });
this.label.style.marginLeft = `${indent}em`;
this.box = new import_obsidian2.TextComponent(this.cell).setValue(value);
this.box.inputEl.classList.add("simple-time-tracker-input");
this.box.inputEl.hide();
}
editing() {
return this.label.hidden;
}
beginEdit(value) {
this.label.hidden = true;
this.box.setValue(value);
this.box.inputEl.show();
}
endEdit() {
const value = this.box.getValue();
this.label.setText(value);
this.box.inputEl.hide();
this.label.hidden = false;
return value;
}
};
var EditableTimestampField = class extends EditableField {
constructor(row, indent, value, settings) {
const timestamp = Number(value);
value = timestamp > 0 ? formatTimestamp(timestamp, settings) : "";
super(row, indent, value);
this.settings = settings;
}
beginEdit(value) {
value = formatEditableTimestamp(Number(value), this.settings);
super.beginEdit(value);
}
endEdit() {
const value = this.box.getValue();
const timestamp = unformatEditableTimestamp(value, this.settings);
const displayValue = formatTimestamp(timestamp, this.settings);
this.label.setText(displayValue);
this.box.inputEl.hide();
this.label.hidden = false;
return value;
}
getTimestamp() {
return unformatEditableTimestamp(this.box.getValue(), this.settings);
}
};
function addEditableTableRow(tracker, entry, table, newSegmentNameBox, running, file, getSectionInfo, settings, indent) {
let row = table.createEl("tr");
let nameField = new EditableField(row, indent, entry.name);
let startField = new EditableTimestampField(row, indent, String(entry.startTime), settings);
let endField = new EditableTimestampField(row, indent, String(entry.endTime), settings);
row.createEl("td", { text: entry.endTime || entry.subEntries ? formatDuration(getDuration(entry), settings) : "" });
let entryButtons = row.createEl("td");
if (!running) {
new import_obsidian2.ButtonComponent(entryButtons).setClass("clickable-icon").setIcon(`lucide-play`).setTooltip("Continue").onClick(() => __async(this, null, function* () {
startSubEntry(entry, newSegmentNameBox.getValue());
yield saveTracker(tracker, this.app, file, getSectionInfo());
}));
}
let editButton = new import_obsidian2.ButtonComponent(entryButtons).setClass("clickable-icon").setTooltip("Edit").setIcon("lucide-pencil").onClick(() => __async(this, null, function* () {
if (nameField.editing()) {
entry.name = nameField.endEdit();
startField.endEdit();
entry.startTime = startField.getTimestamp();
endField.endEdit();
entry.endTime = endField.getTimestamp();
yield saveTracker(tracker, this.app, file, getSectionInfo());
editButton.setIcon("lucide-pencil");
} else {
nameField.beginEdit(entry.name);
startField.beginEdit(String(entry.startTime));
endField.beginEdit(String(entry.endTime));
editButton.setIcon("lucide-check");
}
}));
new import_obsidian2.ButtonComponent(entryButtons).setClass("clickable-icon").setTooltip("Remove").setIcon("lucide-trash").onClick(() => __async(this, null, function* () {
removeEntry(tracker.entries, entry);
yield saveTracker(tracker, this.app, file, getSectionInfo());
}));
if (entry.subEntries) {
for (let sub of entry.subEntries)
addEditableTableRow(tracker, sub, table, newSegmentNameBox, running, file, getSectionInfo, settings, indent + 1);
}
}
// src/main.ts
var SimpleTimeTrackerPlugin = class extends import_obsidian3.Plugin {
onload() {
return __async(this, null, function* () {
yield this.loadSettings();
this.addSettingTab(new SimpleTimeTrackerSettingsTab(this.app, this));
this.registerMarkdownCodeBlockProcessor("simple-time-tracker", (s, e, i) => {
let tracker = loadTracker(s);
e.empty();
displayTracker(tracker, e, i.sourcePath, () => i.getSectionInfo(e), this.settings);
});
this.addCommand({
id: `insert`,
name: `Insert Time Tracker`,
editorCallback: (e, _) => {
e.replaceSelection("```simple-time-tracker\n```\n");
}
});
});
}
loadSettings() {
return __async(this, null, function* () {
this.settings = Object.assign({}, defaultSettings, yield this.loadData());
});
}
saveSettings() {
return __async(this, null, function* () {
yield this.saveData(this.settings);
});
}
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsic3JjL21haW4udHMiLCAic3JjL3NldHRpbmdzLnRzIiwgInNyYy9zZXR0aW5ncy10YWIudHMiLCAic3JjL3RyYWNrZXIudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImltcG9ydCB7IFBsdWdpbiB9IGZyb20gXCJvYnNpZGlhblwiO1xuaW1wb3J0IHsgZGVmYXVsdFNldHRpbmdzLCBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzIH0gZnJvbSBcIi4vc2V0dGluZ3NcIjtcbmltcG9ydCB7IFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3NUYWIgfSBmcm9tIFwiLi9zZXR0aW5ncy10YWJcIjtcbmltcG9ydCB7IGRpc3BsYXlUcmFja2VyLCBsb2FkVHJhY2tlciwgVHJhY2tlciB9IGZyb20gXCIuL3RyYWNrZXJcIjtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgU2ltcGxlVGltZVRyYWNrZXJQbHVnaW4gZXh0ZW5kcyBQbHVnaW4ge1xuXG4gICAgc2V0dGluZ3M6IFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3M7XG5cbiAgICBhc3luYyBvbmxvYWQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMubG9hZFNldHRpbmdzKCk7XG5cbiAgICAgICAgdGhpcy5hZGRTZXR0aW5nVGFiKG5ldyBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzVGFiKHRoaXMuYXBwLCB0aGlzKSk7XG5cbiAgICAgICAgdGhpcy5yZWdpc3Rlck1hcmtkb3duQ29kZUJsb2NrUHJvY2Vzc29yKFwic2ltcGxlLXRpbWUtdHJhY2tlclwiLCAocywgZSwgaSkgPT4ge1xuICAgICAgICAgICAgbGV0IHRyYWNrZXI6IFRyYWNrZXIgPSBsb2FkVHJhY2tlcihzKTtcbiAgICAgICAgICAgIGUuZW1wdHkoKTtcbiAgICAgICAgICAgIGRpc3BsYXlUcmFja2VyKHRyYWNrZXIsIGUsIGkuc291cmNlUGF0aCwgKCkgPT4gaS5nZXRTZWN0aW9uSW5mbyhlKSwgdGhpcy5zZXR0aW5ncyk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuYWRkQ29tbWFuZCh7XG4gICAgICAgICAgICBpZDogYGluc2VydGAsXG4gICAgICAgICAgICBuYW1lOiBgSW5zZXJ0IFRpbWUgVHJhY2tlcmAsXG4gICAgICAgICAgICBlZGl0b3JDYWxsYmFjazogKGUsIF8pID0+IHtcbiAgICAgICAgICAgICAgICBlLnJlcGxhY2VTZWxlY3Rpb24oXCJgYGBzaW1wbGUtdGltZS10cmFja2VyXFxuYGBgXFxuXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBhc3luYyBsb2FkU2V0dGluZ3MoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuc2V0dGluZ3MgPSBPYmplY3QuYXNzaWduKHt9LCBkZWZhdWx0U2V0dGluZ3MsIGF3YWl0IHRoaXMubG9hZERhdGEoKSk7XG4gICAgfVxuXG4gICAgYXN5bmMgc2F2ZVNldHRpbmdzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLnNhdmVEYXRhKHRoaXMuc2V0dGluZ3MpO1xuICAgIH1cbn1cbiIsICJleHBvcnQgY29uc3QgZGVmYXVsdFNldHRpbmdzOiBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzID0ge1xuICAgIHRpbWVzdGFtcEZvcm1hdDogXCJZWS1NTS1ERCBISDptbTpzc1wiLFxuICAgIGVkaXRhYmxlVGltZXN0YW1wRm9ybWF0OiBcIllZWVktTU0tREQgSEg6bW06c3NcIixcbiAgICBjc3ZEZWxpbWl0ZXI6IFwiLFwiLFxuICAgIGZpbmVHcmFpbmVkRHVyYXRpb25zOiB0cnVlXG59O1xuXG5leHBvcnQgaW50ZXJmYWNlIFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3Mge1xuXG4gICAgdGltZXN0YW1wRm9ybWF0OiBzdHJpbmc7XG4gICAgZWRpdGFibGVUaW1lc3RhbXBGb3JtYXQ6IHN0cmluZztcbiAgICBjc3ZEZWxpbWl0ZXI6IHN0cmluZztcbiAgICBmaW5lR3JhaW5lZER1cmF0aW9uczogYm9vbGVhbjtcblxufVxuIiwgImltcG9ydCB7IEFwcCwgUGx1Z2luU2V0dGluZ1RhYiwgU2V0dGluZyB9IGZyb20gXCJvYnNpZGlhblwiO1xuaW1wb3J0IFNpbXBsZVRpbWVUcmFja2VyUGx1Z2luIGZyb20gXCIuL21haW5cIjtcbmltcG9ydCB7IGRlZmF1bHRTZXR0aW5ncyB9IGZyb20gXCIuL3NldHRpbmdzXCI7XG5cbmV4cG9ydCBjbGFzcyBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzVGFiIGV4dGVuZHMgUGx1Z2luU2V0dGluZ1RhYiB7XG5cbiAgICBwbHVnaW46IFNpbXBsZVRpbWVUcmFja2VyUGx1Z2luO1xuXG4gICAgY29uc3RydWN0b3IoYXBwOiBBcHAsIHBsdWdpbjogU2ltcGxlVGltZVRyYWNrZXJQbHVnaW4pIHtcbiAgICAgICAgc3VwZXIoYXBwLCBwbHVnaW4pO1xuICAgICAgICB0aGlzLnBsdWdpbiA9IHBsdWdpbjtcbiAgICB9XG5cbiAgICBkaXNwbGF5KCk6IHZvaWQge1xuICAgICAgICB0aGlzLmNvbnRhaW5lckVsLmVtcHR5KCk7XG4gICAgICAgIHRoaXMuY29udGFpbmVyRWwuY3JlYXRlRWwoXCJoMlwiLCB7dGV4dDogXCJTdXBlciBTaW1wbGUgVGltZSBUcmFja2VyIFNldHRpbmdzXCJ9KTtcblxuICAgICAgICBuZXcgU2V0dGluZyh0aGlzLmNvbnRhaW5lckVsKVxuICAgICAgICAgICAgLnNldE5hbWUoXCJUaW1lc3RhbXAgRGlzcGxheSBGb3JtYXRcIilcbiAgICAgICAgICAgIC5zZXREZXNjKGNyZWF0ZUZyYWdtZW50KGYgPT4ge1xuICAgICAgICAgICAgICAgIGYuY3JlYXRlU3Bhbih7dGV4dDogXCJUaGUgd2F5IHRoYXQgdGltZXN0YW1wcyBpbiB0aW1lIHRyYWNrZXIgdGFibGVzIHNob3VsZCBiZSBkaXNwbGF5ZWQuIFVzZXMgXCJ9KTtcbiAgICAgICAgICAgICAgICBmLmNyZWF0ZUVsKFwiYVwiLCB7dGV4dDogXCJtb21lbnQuanNcIiwgaHJlZjogXCJodHRwczovL21vbWVudGpzLmNvbS9kb2NzLyMvcGFyc2luZy9zdHJpbmctZm9ybWF0L1wifSk7XG4gICAgICAgICAgICAgICAgZi5jcmVhdGVTcGFuKHt0ZXh0OiBcIiBzeW50YXguXCJ9KTtcbiAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgLmFkZFRleHQodCA9PiB7XG4gICAgICAgICAgICAgICAgdC5zZXRWYWx1ZShTdHJpbmcodGhpcy5wbHVnaW4uc2V0dGluZ3MudGltZXN0YW1wRm9ybWF0KSk7XG4gICAgICAgICAgICAgICAgdC5vbkNoYW5nZShhc3luYyB2ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3MudGltZXN0YW1wRm9ybWF0ID0gdi5sZW5ndGggPyB2IDogZGVmYXVsdFNldHRpbmdzLnRpbWVzdGFtcEZvcm1hdDtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICBuZXcgU2V0dGluZyh0aGlzLmNvbnRhaW5lckVsKVxuICAgICAgICAgICAgLnNldE5hbWUoXCJDU1YgRGVsaW1pdGVyXCIpXG4gICAgICAgICAgICAuc2V0RGVzYyhcIlRoZSBkZWxpbWl0ZXIgY2hhcmFjdGVyIHRoYXQgc2hvdWxkIGJlIHVzZWQgd2hlbiBjb3B5aW5nIGEgdHJhY2tlciB0YWJsZSBhcyBDU1YuIEZvciBleGFtcGxlLCBzb21lIGxhbmd1YWdlcyB1c2UgYSBzZW1pY29sb24gaW5zdGVhZCBvZiBhIGNvbW1hLlwiKVxuICAgICAgICAgICAgLmFkZFRleHQodCA9PiB7XG4gICAgICAgICAgICAgICAgdC5zZXRWYWx1ZShTdHJpbmcodGhpcy5wbHVnaW4uc2V0dGluZ3MuY3N2RGVsaW1pdGVyKSk7XG4gICAgICAgICAgICAgICAgdC5vbkNoYW5nZShhc3luYyB2ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3MuY3N2RGVsaW1pdGVyID0gdi5sZW5ndGggPyB2IDogZGVmYXVsdFNldHRpbmdzLmNzdkRlbGltaXRlcjtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICBuZXcgU2V0dGluZyh0aGlzLmNvbnRhaW5lckVsKVxuICAgICAgICAgICAgLnNldE5hbWUoXCJGaW5lLUdyYWluZWQgRHVyYXRpb25zXCIpXG4gICAgICAgICAgICAuc2V0RGVzYyhcIldoZXRoZXIgZHVyYXRpb25zIHNob3VsZCBpbmNsdWRlIGRheXMsIG1vbnRocyBhbmQgeWVhcnMuIElmIHRoaXMgaXMgZGlzYWJsZWQsIGFkZGl0aW9uYWwgdGltZSB1bml0cyB3aWxsIGJlIGRpc3BsYXllZCBhcyBwYXJ0IG9mIHRoZSBob3Vycy5cIilcbiAgICAgICAgICAgIC5hZGRUb2dnbGUodCA9PiB7XG4gICAgICAgICAgICAgICAgdC5zZXRWYWx1ZSh0aGlzLnBsdWdpbi5zZXR0aW5ncy5maW5lR3JhaW5lZER1cmF0aW9ucyk7XG4gICAgICAgICAgICAgICAgdC5vbkNoYW5nZShhc3luYyB2ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3MuZmluZUdyYWluZWREdXJhdGlvbnMgPSB2O1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuY29udGFpbmVyRWwuY3JlYXRlRWwoXCJoclwiKTtcbiAgICAgICAgdGhpcy5jb250YWluZXJFbC5jcmVhdGVFbChcInBcIiwge3RleHQ6IFwiSWYgeW91IGxpa2UgdGhpcyBwbHVnaW4gYW5kIHdhbnQgdG8gc3VwcG9ydCBpdHMgZGV2ZWxvcG1lbnQsIHlvdSBjYW4gZG8gc28gdGhyb3VnaCBteSB3ZWJzaXRlIGJ5IGNsaWNraW5nIHRoaXMgZmFuY3kgaW1hZ2UhXCJ9KTtcbiAgICAgICAgdGhpcy5jb250YWluZXJFbC5jcmVhdGVFbChcImFcIiwge2hyZWY6IFwiaHR0cHM6Ly9lbGxwZWNrLmRlL3N1cHBvcnRcIn0pXG4gICAgICAgICAgICAuY3JlYXRlRWwoXCJpbWdcIiwge1xuICAgICAgICAgICAgICAgIGF0dHI6IHtzcmM6IFwiaHR0cHM6Ly9lbGxwZWNrLmRlL3Jlcy9nZW5lcmFsc3VwcG9ydC5wbmdcIn0sXG4gICAgICAgICAgICAgICAgY2xzOiBcInNpbXBsZS10aW1lLXRyYWNrZXItc3VwcG9ydFwiXG4gICAgICAgICAgICB9KTtcbiAgICB9XG59XG4iLCAiaW1wb3J0IHsgbW9tZW50LCBBcHAsIE1hcmtkb3duU2VjdGlvbkluZm9ybWF0aW9uLCBCdXR0b25Db21wb25lbnQsIFRleHRDb21wb25lbnQsIFRGaWxlIH0gZnJvbSBcIm9ic2lkaWFuXCI7XG5pbXBvcnQgeyBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzIH0gZnJvbSBcIi4vc2V0dGluZ3NcIjtcblxuZXhwb3J0IGludGVyZmFjZSBUcmFja2VyIHtcbiAgICBlbnRyaWVzOiBFbnRyeVtdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEVudHJ5IHtcbiAgICBuYW1lOiBzdHJpbmc7XG4gICAgc3RhcnRUaW1lOiBudW1iZXI7XG4gICAgZW5kVGltZTogbnVtYmVyO1xuICAgIHN1YkVudHJpZXM6IEVudHJ5W107XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzYXZlVHJhY2tlcih0cmFja2VyOiBUcmFja2VyLCBhcHA6IEFwcCwgZmlsZU5hbWU6IHN0cmluZywgc2VjdGlvbjogTWFya2Rvd25TZWN0aW9uSW5mb3JtYXRpb24pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBsZXQgZmlsZSA9IGFwcC52YXVsdC5nZXRBYnN0cmFjdEZpbGVCeVBhdGgoZmlsZU5hbWUpIGFzIFRGaWxlO1xuICAgIGlmICghZmlsZSlcbiAgICAgICAgcmV0dXJuO1xuICAgIGxldCBjb250ZW50ID0gYXdhaXQgYXBwLnZhdWx0LnJlYWQoZmlsZSk7XG5cbiAgICAvLyBmaWd1cmUgb3V0IHdoYXQgcGFydCBvZiB0aGUgY29udGVudCB3ZSBoYXZlIHRvIGVkaXRcbiAgICBsZXQgbGluZXMgPSBjb250ZW50LnNwbGl0KFwiXFxuXCIpO1xuICAgIGxldCBwcmV2ID0gbGluZXMuZmlsdGVyKChfLCBpKSA9PiBpIDw9IHNlY3Rpb24ubGluZVN0YXJ0KS5qb2luKFwiXFxuXCIpO1xuICAgIGxldCBuZXh0ID0gbGluZXMuZmlsdGVyKChfLCBpKSA9PiBpID49IHNlY3Rpb24ubGluZUVuZCkuam9pbihcIlxcblwiKTtcbiAgICAvLyBlZGl0IG9ubHkgdGhlIGNvZGUgYmxvY2sgY29udGVudCwgbGVhdmUgdGhlIHJlc3QgdW50b3VjaGVkXG4gICAgY29udGVudCA9IGAke3ByZXZ9XFxuJHtKU09OLnN0cmluZ2lmeSh0cmFja2VyKX1cXG4ke25leHR9YDtcblxuICAgIGF3YWl0IGFwcC52YXVsdC5tb2RpZnkoZmlsZSwgY29udGVudCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBsb2FkVHJhY2tlcihqc29uOiBzdHJpbmcpOiBUcmFja2VyIHtcbiAgICBpZiAoanNvbikge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoanNvbik7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGBGYWlsZWQgdG8gcGFyc2UgVHJhY2tlciBmcm9tICR7anNvbn1gKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4ge2VudHJpZXM6IFtdfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRpc3BsYXlUcmFja2VyKHRyYWNrZXI6IFRyYWNrZXIsIGVsZW1lbnQ6IEhUTUxFbGVtZW50LCBmaWxlOiBzdHJpbmcsIGdldFNlY3Rpb25JbmZvOiAoKSA9PiBNYXJrZG93blNlY3Rpb25JbmZvcm1hdGlvbiwgc2V0dGluZ3M6IFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3MpOiB2b2lkIHtcbiAgICBlbGVtZW50LmNsYXNzTGlzdC5hZGQoJ3NpbXBsZS10aW1lLXRyYWNrZXItY29udGFpbmVyJyk7XG4gICAgLy8gYWRkIHN0YXJ0L3N0b3AgY29udHJvbHNcbiAgICBsZXQgcnVubmluZyA9IGlzUnVubmluZyh0cmFja2VyKTtcbiAgICBsZXQgYnRuID0gbmV3IEJ1dHRvbkNvbXBvbmVudChlbGVtZW50KVxuICAgICAgICAuc2V0Q2xhc3MoXCJjbGlja2FibGUtaWNvblwiKVxuICAgICAgICAuc2V0SWNvbihgbHVjaWRlLSR7cnVubmluZyA/IFwic3RvcFwiIDogXCJwbGF5XCJ9LWNpcmNsZWApXG4gICAgICAgIC5zZXRUb29sdGlwKHJ1bm5pbmcgPyBcIkVuZFwiIDogXCJTdGFydFwiKVxuICAgICAgICAub25DbGljayhhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBpZiAocnVubmluZykge1xuICAgICAgICAgICAgICAgIGVuZFJ1bm5pbmdFbnRyeSh0cmFja2VyKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc3RhcnROZXdFbnRyeSh0cmFja2VyLCBuZXdTZWdtZW50TmFtZUJveC5nZXRWYWx1ZSgpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGF3YWl0IHNhdmVUcmFja2VyKHRyYWNrZXIsIHRoaXMuYXBwLCBmaWxlLCBnZXRTZWN0aW9uSW5mbygpKTtcbiAgICAgICAgfSk7XG4gICAgYnRuLmJ1dHRvbkVsLmFkZENsYXNzKFwic2ltcGxlLXRpbWUtdHJhY2tlci1idG5cIik7XG4gICAgbGV0IG5ld1NlZ21lbnROYW1lQm94ID0gbmV3IFRleHRDb21wb25lbnQoZWxlbWVudClcbiAgICAgICAgLnNldFBsYWNlaG9sZGVyKFwiU2VnbWVudCBuYW1lXCIpXG4gICAgICAgIC5zZXREaXNhYmxlZChydW5uaW5nKTtcbiAgICBuZXdTZWdtZW50TmFtZUJveC5pbnB1dEVsLmFkZENsYXNzKFwic2ltcGxlLXRpbWUtdHJhY2tlci10eHRcIik7XG5cbiAgICAvLyBhZGQgdGltZXJzXG4gICAgbGV0IHRpbWVyID0gZWxlbWVudC5jcmVhdGVEaXYoe2NsczogXCJzaW1wbGUtdGltZS10cmFja2VyLXRpbWVyc1wifSk7XG4gICAgbGV0IGN1cnJlbnREaXYgPSB0aW1lci5jcmVhdGVFbChcImRpdlwiLCB7Y2xzOiBcInNpbXBsZS10aW1lLXRyYWNrZXItdGltZXJcIn0pO1xuICAgIGxldCBjdXJyZW50ID0gY3VycmVudERpdi5jcmVhdGVFbChcInNwYW5cIiwge2NsczogXCJzaW1wbGUtdGltZS10cmFja2VyLXRpbWVyLXRpbWVcIn0pO1xuICAgIGN1cnJlbnREaXYuY3JlYXRlRWwoXCJzcGFuXCIsIHt0ZXh0OiBcIkN1cnJlbnRcIn0pO1xuICAgIGxldCB0b3RhbERpdiA9IHRpbWVyLmNyZWF0ZUVsKFwiZGl2XCIsIHtjbHM6IFwic2ltcGxlLXRpbWUtdHJhY2tlci10aW1lclwifSk7XG4gICAgbGV0IHRvdGFsID0gdG90YWxEaXYuY3JlYXRlRWwoXCJzcGFuXCIsIHtjbHM6IFwic2ltcGxlLXRpbWUtdHJhY2tlci10aW1lci10aW1lXCIsIHRleHQ6IFwiMHNcIn0pO1xuICAgIHRvdGFsRGl2LmNyZWF0ZUVsKFwic3BhblwiLCB7dGV4dDogXCJUb3RhbFwifSk7XG5cbiAgICBpZiAodHJhY2tlci5lbnRyaWVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgLy8gYWRkIHRhYmxlXG4gICAgICAgIGxldCB0YWJsZSA9IGVsZW1lbnQuY3JlYXRlRWwoXCJ0YWJsZVwiLCB7Y2xzOiBcInNpbXBsZS10aW1lLXRyYWNrZXItdGFibGVcIn0pO1xuICAgICAgICB0YWJsZS5jcmVhdGVFbChcInRyXCIpLmFwcGVuZChcbiAgICAgICAgICAgIGNyZWF0ZUVsKFwidGhcIiwge3RleHQ6IFwiU2VnbWVudFwifSksXG4gICAgICAgICAgICBjcmVhdGVFbChcInRoXCIsIHt0ZXh0OiBcIlN0YXJ0IHRpbWVcIn0pLFxuICAgICAgICAgICAgY3JlYXRlRWwoXCJ0aFwiLCB7dGV4dDogXCJFbmQgdGltZVwifSksXG4gICAgICAgICAgICBjcmVhdGVFbChcInRoXCIsIHt0ZXh0OiBcIkR1cmF0aW9uXCJ9KSxcbiAgICAgICAgICAgIGNyZWF0ZUVsKFwidGhcIikpO1xuXG4gICAgICAgIGZvciAobGV0IGVudHJ5IG9mIHRyYWNrZXIuZW50cmllcylcbiAgICAgICAgICAgIGFkZEVkaXRhYmxlVGFibGVSb3codHJhY2tlciwgZW50cnksIHRhYmxlLCBuZXdTZWdtZW50TmFtZUJveCwgcnVubmluZywgZmlsZSwgZ2V0U2VjdGlvbkluZm8sIHNldHRpbmdzLCAwKTtcblxuICAgICAgICAvLyBhZGQgY29weSBidXR0b25zXG4gICAgICAgIGxldCBidXR0b25zID0gZWxlbWVudC5jcmVhdGVFbChcImRpdlwiLCB7Y2xzOiBcInNpbXBsZS10aW1lLXRyYWNrZXItYm90dG9tXCJ9KTtcbiAgICAgICAgbmV3IEJ1dHRvbkNvbXBvbmVudChidXR0b25zKVxuICAgICAgICAgICAgLnNldEJ1dHRvblRleHQoXCJDb3B5IGFzIHRhYmxlXCIpXG4gICAgICAgICAgICAub25DbGljaygoKSA9PiBuYXZpZ2F0b3IuY2xpcGJvYXJkLndyaXRlVGV4dChjcmVhdGVNYXJrZG93blRhYmxlKHRyYWNrZXIsIHNldHRpbmdzKSkpO1xuICAgICAgICBuZXcgQnV0dG9uQ29tcG9uZW50KGJ1dHRvbnMpXG4gICAgICAgICAgICAuc2V0QnV0dG9uVGV4dChcIkNvcHkgYXMgQ1NWXCIpXG4gICAgICAgICAgICAub25DbGljaygoKSA9PiBuYXZpZ2F0b3IuY2xpcGJvYXJkLndyaXRlVGV4dChjcmVhdGVDc3YodHJhY2tlciwgc2V0dGluZ3MpKSk7XG4gICAgfVxuXG5cbiAgICBzZXRDb3VudGRvd25WYWx1ZXModHJhY2tlciwgY3VycmVudCwgdG90YWwsIGN1cnJlbnREaXYsIHNldHRpbmdzKTtcbiAgICBsZXQgaW50ZXJ2YWxJZCA9IHdpbmRvdy5zZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICAgIC8vIHdlIGRlbGV0ZSB0aGUgaW50ZXJ2YWwgdGltZXIgd2hlbiB0aGUgZWxlbWVudCBpcyByZW1vdmVkXG4gICAgICAgIGlmICghZWxlbWVudC5pc0Nvbm5lY3RlZCkge1xuICAgICAgICAgICAgd2luZG93LmNsZWFySW50ZXJ2YWwoaW50ZXJ2YWxJZCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgc2V0Q291bnRkb3duVmFsdWVzKHRyYWNrZXIsIGN1cnJlbnQsIHRvdGFsLCBjdXJyZW50RGl2LCBzZXR0aW5ncyk7XG4gICAgfSwgMTAwMCk7XG59XG5cbmZ1bmN0aW9uIHN0YXJ0U3ViRW50cnkoZW50cnk6IEVudHJ5LCBuYW1lOiBzdHJpbmcpIHtcbiAgICAvLyBpZiB0aGlzIGVudHJ5IGlzIG5vdCBzcGxpdCB5ZXQsIHdlIGFkZCBpdHMgdGltZSBhcyBhIHN1Yi1lbnRyeSBpbnN0ZWFkXG4gICAgaWYgKCFlbnRyeS5zdWJFbnRyaWVzKSB7XG4gICAgICAgIGVudHJ5LnN1YkVudHJpZXMgPSBbey4uLmVudHJ5LCBuYW1lOiBgUGFydCAxYH1dO1xuICAgICAgICBlbnRyeS5zdGFydFRpbWUgPSBudWxsO1xuICAgICAgICBlbnRyeS5lbmRUaW1lID0gbnVsbDtcbiAgICB9XG5cbiAgICBpZiAoIW5hbWUpXG4gICAgICAgIG5hbWUgPSBgUGFydCAke2VudHJ5LnN1YkVudHJpZXMubGVuZ3RoICsgMX1gO1xuICAgIGVudHJ5LnN1YkVudHJpZXMucHVzaCh7bmFtZTogbmFtZSwgc3RhcnRUaW1lOiBtb21lbnQoKS51bml4KCksIGVuZFRpbWU6IG51bGwsIHN1YkVudHJpZXM6IG51bGx9KTtcbn1cblxuZnVuY3Rpb24gc3RhcnROZXdFbnRyeSh0cmFja2VyOiBUcmFja2VyLCBuYW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAoIW5hbWUpXG4gICAgICAgIG5hbWUgPSBgU2VnbWVudCAke3RyYWNrZXIuZW50cmllcy5sZW5ndGggKyAxfWA7XG4gICAgbGV0IGVudHJ5OiBFbnRyeSA9IHtuYW1lOiBuYW1lLCBzdGFydFRpbWU6IG1vbWVudCgpLnVuaXgoKSwgZW5kVGltZTogbnVsbCwgc3ViRW50cmllczogbnVsbH07XG4gICAgdHJhY2tlci5lbnRyaWVzLnB1c2goZW50cnkpO1xufVxuXG5mdW5jdGlvbiBlbmRSdW5uaW5nRW50cnkodHJhY2tlcjogVHJhY2tlcik6IHZvaWQge1xuICAgIGxldCBlbnRyeSA9IGdldFJ1bm5pbmdFbnRyeSh0cmFja2VyLmVudHJpZXMpO1xuICAgIGVudHJ5LmVuZFRpbWUgPSBtb21lbnQoKS51bml4KCk7XG59XG5cbmZ1bmN0aW9uIHJlbW92ZUVudHJ5KGVudHJpZXM6IEVudHJ5W10sIHRvUmVtb3ZlOiBFbnRyeSk6IGJvb2xlYW4ge1xuICAgIGlmIChlbnRyaWVzLmNvbnRhaW5zKHRvUmVtb3ZlKSkge1xuICAgICAgICBlbnRyaWVzLnJlbW92ZSh0b1JlbW92ZSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGZvciAobGV0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgICAgIGlmIChlbnRyeS5zdWJFbnRyaWVzICYmIHJlbW92ZUVudHJ5KGVudHJ5LnN1YkVudHJpZXMsIHRvUmVtb3ZlKSkge1xuICAgICAgICAgICAgICAgIC8vIGlmIHdlIG9ubHkgaGF2ZSBvbmUgc3ViIGVudHJ5IHJlbWFpbmluZywgd2UgY2FuIG1lcmdlIGJhY2sgaW50byBvdXIgbWFpbiBlbnRyeVxuICAgICAgICAgICAgICAgIGlmIChlbnRyeS5zdWJFbnRyaWVzLmxlbmd0aCA9PSAxKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBzaW5nbGUgPSBlbnRyeS5zdWJFbnRyaWVzWzBdO1xuICAgICAgICAgICAgICAgICAgICBlbnRyeS5zdGFydFRpbWUgPSBzaW5nbGUuc3RhcnRUaW1lO1xuICAgICAgICAgICAgICAgICAgICBlbnRyeS5lbmRUaW1lID0gc2luZ2xlLmVuZFRpbWU7XG4gICAgICAgICAgICAgICAgICAgIGVudHJ5LnN1YkVudHJpZXMgPSBudWxsO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG59XG5cbmZ1bmN0aW9uIGlzUnVubmluZyh0cmFja2VyOiBUcmFja2VyKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICEhZ2V0UnVubmluZ0VudHJ5KHRyYWNrZXIuZW50cmllcyk7XG59XG5cbmZ1bmN0aW9uIGdldFJ1bm5pbmdFbnRyeShlbnRyaWVzOiBFbnRyeVtdKTogRW50cnkge1xuICAgIGZvciAobGV0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgLy8gaWYgdGhpcyBlbnRyeSBoYXMgc3ViIGVudHJpZXMsIGNoZWNrIGlmIG9uZSBvZiB0aGVtIGlzIHJ1bm5pbmdcbiAgICAgICAgaWYgKGVudHJ5LnN1YkVudHJpZXMpIHtcbiAgICAgICAgICAgIGxldCBydW5uaW5nID0gZ2V0UnVubmluZ0VudHJ5KGVudHJ5LnN1YkVudHJpZXMpO1xuICAgICAgICAgICAgaWYgKHJ1bm5pbmcpXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bm5pbmc7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBpZiB0aGlzIGVudHJ5IGhhcyBubyBzdWIgZW50cmllcyBhbmQgbm8gZW5kIHRpbWUsIGl0J3MgcnVubmluZ1xuICAgICAgICAgICAgaWYgKCFlbnRyeS5lbmRUaW1lKVxuICAgICAgICAgICAgICAgIHJldHVybiBlbnRyeTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cblxuZnVuY3Rpb24gZ2V0RHVyYXRpb24oZW50cnk6IEVudHJ5KSB7XG4gICAgaWYgKGVudHJ5LnN1YkVudHJpZXMpIHtcbiAgICAgICAgcmV0dXJuIGdldFRvdGFsRHVyYXRpb24oZW50cnkuc3ViRW50cmllcyk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgbGV0IGVuZFRpbWUgPSBlbnRyeS5lbmRUaW1lID8gbW9tZW50LnVuaXgoZW50cnkuZW5kVGltZSkgOiBtb21lbnQoKTtcbiAgICAgICAgcmV0dXJuIGVuZFRpbWUuZGlmZihtb21lbnQudW5peChlbnRyeS5zdGFydFRpbWUpKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGdldFRvdGFsRHVyYXRpb24oZW50cmllczogRW50cnlbXSk6IG51bWJlciB7XG4gICAgbGV0IHJldCA9IDA7XG4gICAgZm9yIChsZXQgZW50cnkgb2YgZW50cmllcylcbiAgICAgICAgcmV0ICs9IGdldER1cmF0aW9uKGVudHJ5KTtcbiAgICByZXR1cm4gcmV0O1xufVxuXG5mdW5jdGlvbiBzZXRDb3VudGRvd25WYWx1ZXModHJhY2tlcjogVHJhY2tlciwgY3VycmVudDogSFRNTEVsZW1lbnQsIHRvdGFsOiBIVE1MRWxlbWVudCwgY3VycmVudERpdjogSFRNTERpdkVsZW1lbnQsIHNldHRpbmdzOiBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzKSB7XG4gICAgbGV0IHJ1bm5pbmcgPSBnZXRSdW5uaW5nRW50cnkodHJhY2tlci5lbnRyaWVzKTtcbiAgICBpZiAocnVubmluZyAmJiAhcnVubmluZy5lbmRUaW1lKSB7XG4gICAgICAgIGN1cnJlbnQuc2V0VGV4dChmb3JtYXREdXJhdGlvbihnZXREdXJhdGlvbihydW5uaW5nKSwgc2V0dGluZ3MpKTtcbiAgICAgICAgY3VycmVudERpdi5oaWRkZW4gPSBmYWxzZTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBjdXJyZW50RGl2LmhpZGRlbiA9IHRydWU7XG4gICAgfVxuICAgIHRvdGFsLnNldFRleHQoZm9ybWF0RHVyYXRpb24oZ2V0VG90YWxEdXJhdGlvbih0cmFja2VyLmVudHJpZXMpLCBzZXR0aW5ncykpO1xufVxuXG5mdW5jdGlvbiBmb3JtYXRUaW1lc3RhbXAodGltZXN0YW1wOiBudW1iZXIsIHNldHRpbmdzOiBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzKTogc3RyaW5nIHtcbiAgICByZXR1cm4gbW9tZW50LnVuaXgodGltZXN0YW1wKS5mb3JtYXQoc2V0dGluZ3MudGltZXN0YW1wRm9ybWF0KTtcbn1cblxuZnVuY3Rpb24gZm9ybWF0RWRpdGFibGVUaW1lc3RhbXAodGltZXN0YW1wOiBudW1iZXIsIHNldHRpbmdzOiBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzKSB7XG4gICAgcmV0dXJuIG1vbWVudC51bml4KHRpbWVzdGFtcCkuZm9ybWF0KHNldHRpbmdzLmVkaXRhYmxlVGltZXN0YW1wRm9ybWF0KTtcbn1cblxuZnVuY3Rpb24gdW5mb3JtYXRFZGl0YWJsZVRpbWVzdGFtcChmb3JtYXR0ZWQ6IHN0cmluZywgc2V0dGluZ3M6IFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3MpOiBudW1iZXIge1xuICAgIHJldHVybiBtb21lbnQoZm9ybWF0dGVkLCBzZXR0aW5ncy5lZGl0YWJsZVRpbWVzdGFtcEZvcm1hdCkudW5peCgpO1xufVxuXG5mdW5jdGlvbiBmb3JtYXREdXJhdGlvbih0b3RhbFRpbWU6IG51bWJlciwgc2V0dGluZ3M6IFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3MpOiBzdHJpbmcge1xuICAgIGxldCByZXQgPSBcIlwiO1xuICAgIGxldCBkdXJhdGlvbiA9IG1vbWVudC5kdXJhdGlvbih0b3RhbFRpbWUpO1xuICAgIGxldCBob3VyczogbnVtYmVyO1xuICAgIGlmIChzZXR0aW5ncy5maW5lR3JhaW5lZER1cmF0aW9ucykge1xuICAgICAgICBpZiAoZHVyYXRpb24ueWVhcnMoKSA+IDApXG4gICAgICAgICAgICByZXQgKz0gZHVyYXRpb24ueWVhcnMoKSArIFwieSBcIjtcbiAgICAgICAgaWYgKGR1cmF0aW9uLm1vbnRocygpID4gMClcbiAgICAgICAgICAgIHJldCArPSBkdXJhdGlvbi5tb250aHMoKSArIFwiTSBcIjtcbiAgICAgICAgaWYgKGR1cmF0aW9uLmRheXMoKSA+IDApXG4gICAgICAgICAgICByZXQgKz0gZHVyYXRpb24uZGF5cygpICsgXCJkIFwiO1xuICAgICAgICBob3VycyA9IGR1cmF0aW9uLmhvdXJzKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgaG91cnMgPSBNYXRoLmZsb29yKGR1cmF0aW9uLmFzSG91cnMoKSk7XG4gICAgfVxuICAgIGlmIChob3VycyA+IDApXG4gICAgICAgIHJldCArPSBob3VycyArIFwiaCBcIjtcbiAgICBpZiAoZHVyYXRpb24ubWludXRlcygpID4gMClcbiAgICAgICAgcmV0ICs9IGR1cmF0aW9uLm1pbnV0ZXMoKSArIFwibSBcIjtcbiAgICByZXQgKz0gZHVyYXRpb24uc2Vjb25kcygpICsgXCJzXCI7XG4gICAgcmV0dXJuIHJldDtcbn1cblxuZnVuY3Rpb24gY3JlYXRlTWFya2Rvd25UYWJsZSh0cmFja2VyOiBUcmFja2VyLCBzZXR0aW5nczogU2ltcGxlVGltZVRyYWNrZXJTZXR0aW5ncyk6IHN0cmluZyB7XG4gICAgbGV0IHRhYmxlID0gW1tcIlNlZ21lbnRcIiwgXCJTdGFydCB0aW1lXCIsIFwiRW5kIHRpbWVcIiwgXCJEdXJhdGlvblwiXV07XG4gICAgZm9yIChsZXQgZW50cnkgb2YgdHJhY2tlci5lbnRyaWVzKVxuICAgICAgICB0YWJsZS5wdXNoKC4uLmNyZWF0ZVRhYmxlU2VjdGlvbihlbnRyeSwgc2V0dGluZ3MpKTtcbiAgICB0YWJsZS5wdXNoKFtcIioqVG90YWwqKlwiLCBcIlwiLCBcIlwiLCBgKioke2Zvcm1hdER1cmF0aW9uKGdldFRvdGFsRHVyYXRpb24odHJhY2tlci5lbnRyaWVzKSwgc2V0dGluZ3MpfSoqYF0pO1xuXG4gICAgbGV0IHJldCA9IFwiXCI7XG4gICAgLy8gY2FsY3VsYXRlIHRoZSB3aWR0aCBldmVyeSBjb2x1bW4gbmVlZHMgdG8gbG9vayBuZWF0IHdoZW4gbW9ub3NwYWNlZFxuICAgIGxldCB3aWR0aHMgPSBBcnJheS5mcm9tKEFycmF5KDQpLmtleXMoKSkubWFwKGkgPT4gTWF0aC5tYXgoLi4udGFibGUubWFwKGEgPT4gYVtpXS5sZW5ndGgpKSk7XG4gICAgZm9yIChsZXQgciA9IDA7IHIgPCB0YWJsZS5sZW5ndGg7IHIrKykge1xuICAgICAgICAvLyBhZGQgc2VwYXJhdG9ycyBhZnRlciBmaXJzdCByb3dcbiAgICAgICAgaWYgKHIgPT0gMSlcbiAgICAgICAgICAgIHJldCArPSBcInwgXCIgKyBBcnJheS5mcm9tKEFycmF5KDQpLmtleXMoKSkubWFwKGkgPT4gXCItXCIucmVwZWF0KHdpZHRoc1tpXSkpLmpvaW4oXCIgfCBcIikgKyBcIiB8XFxuXCI7XG5cbiAgICAgICAgbGV0IHJvdzogc3RyaW5nW10gPSBbXTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCA0OyBpKyspXG4gICAgICAgICAgICByb3cucHVzaCh0YWJsZVtyXVtpXS5wYWRFbmQod2lkdGhzW2ldLCBcIiBcIikpO1xuICAgICAgICByZXQgKz0gXCJ8IFwiICsgcm93LmpvaW4oXCIgfCBcIikgKyBcIiB8XFxuXCI7XG4gICAgfVxuICAgIHJldHVybiByZXQ7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUNzdih0cmFja2VyOiBUcmFja2VyLCBzZXR0aW5nczogU2ltcGxlVGltZVRyYWNrZXJTZXR0aW5ncyk6IHN0cmluZyB7XG4gICAgbGV0IHJldCA9IFwiXCI7XG4gICAgZm9yIChsZXQgZW50cnkgb2YgdHJhY2tlci5lbnRyaWVzKSB7XG4gICAgICAgIGZvciAobGV0IHJvdyBvZiBjcmVhdGVUYWJsZVNlY3Rpb24oZW50cnksIHNldHRpbmdzKSlcbiAgICAgICAgICAgIHJldCArPSByb3cuam9pbihzZXR0aW5ncy5jc3ZEZWxpbWl0ZXIpICsgXCJcXG5cIjtcbiAgICB9XG4gICAgcmV0dXJuIHJldDtcbn1cblxuZnVuY3Rpb24gY3JlYXRlVGFibGVTZWN0aW9uKGVudHJ5OiBFbnRyeSwgc2V0dGluZ3M6IFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3MpOiBzdHJpbmdbXVtdIHtcbiAgICBsZXQgcmV0OiBzdHJpbmdbXVtdID0gW1tcbiAgICAgICAgZW50cnkubmFtZSxcbiAgICAgICAgZW50cnkuc3RhcnRUaW1lID8gZm9ybWF0VGltZXN0YW1wKGVudHJ5LnN0YXJ0VGltZSwgc2V0dGluZ3MpIDogXCJcIixcbiAgICAgICAgZW50cnkuZW5kVGltZSA/IGZvcm1hdFRpbWVzdGFtcChlbnRyeS5lbmRUaW1lLCBzZXR0aW5ncykgOiBcIlwiLFxuICAgICAgICBlbnRyeS5lbmRUaW1lIHx8IGVudHJ5LnN1YkVudHJpZXMgPyBmb3JtYXREdXJhdGlvbihnZXREdXJhdGlvbihlbnRyeSksIHNldHRpbmdzKSA6IFwiXCJdXTtcbiAgICBpZiAoZW50cnkuc3ViRW50cmllcykge1xuICAgICAgICBmb3IgKGxldCBzdWIgb2YgZW50cnkuc3ViRW50cmllcylcbiAgICAgICAgICAgIHJldC5wdXNoKC4uLmNyZWF0ZVRhYmxlU2VjdGlvbihzdWIsIHNldHRpbmdzKSk7XG4gICAgfVxuICAgIHJldHVybiByZXQ7XG59XG5cbmNsYXNzIEVkaXRhYmxlRmllbGQge1xuICAgIGNlbGw6IEhUTUxUYWJsZUNlbGxFbGVtZW50O1xuICAgIGxhYmVsOiBIVE1MU3BhbkVsZW1lbnQ7XG4gICAgYm94OiBUZXh0Q29tcG9uZW50O1xuICAgIGNvbnN0cnVjdG9yKHJvdzogSFRNTFRhYmxlUm93RWxlbWVudCwgaW5kZW50OiBudW1iZXIsIHZhbHVlOiBzdHJpbmcpIHtcbiAgICAgICAgdGhpcy5jZWxsID0gcm93LmNyZWF0ZUVsKFwidGRcIik7XG4gICAgICAgIHRoaXMubGFiZWwgPSB0aGlzLmNlbGwuY3JlYXRlRWwoXCJzcGFuXCIsIHsgdGV4dDogdmFsdWUgfSk7XG4gICAgICAgIHRoaXMubGFiZWwuc3R5bGUubWFyZ2luTGVmdCA9IGAke2luZGVudH1lbWA7XG4gICAgICAgIHRoaXMuYm94ID0gbmV3IFRleHRDb21wb25lbnQodGhpcy5jZWxsKS5zZXRWYWx1ZSh2YWx1ZSk7XG4gICAgICAgIHRoaXMuYm94LmlucHV0RWwuY2xhc3NMaXN0LmFkZCgnc2ltcGxlLXRpbWUtdHJhY2tlci1pbnB1dCcpO1xuICAgICAgICB0aGlzLmJveC5pbnB1dEVsLmhpZGUoKTtcbiAgICB9XG4gICAgZWRpdGluZygpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubGFiZWwuaGlkZGVuO1xuICAgIH1cbiAgICBiZWdpbkVkaXQodmFsdWU6IHN0cmluZykge1xuICAgICAgICB0aGlzLmxhYmVsLmhpZGRlbiA9IHRydWU7XG4gICAgICAgIHRoaXMuYm94LnNldFZhbHVlKHZhbHVlKTtcbiAgICAgICAgdGhpcy5ib3guaW5wdXRFbC5zaG93KCk7XG4gICAgfVxuICAgIGVuZEVkaXQoKTogc3RyaW5nIHtcbiAgICAgICAgY29uc3QgdmFsdWUgPSB0aGlzLmJveC5nZXRWYWx1ZSgpO1xuICAgICAgICB0aGlzLmxhYmVsLnNldFRleHQodmFsdWUpO1xuICAgICAgICB0aGlzLmJveC5pbnB1dEVsLmhpZGUoKTtcbiAgICAgICAgdGhpcy5sYWJlbC5oaWRkZW4gPSBmYWxzZTtcbiAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cbn1cblxuY2xhc3MgRWRpdGFibGVUaW1lc3RhbXBGaWVsZCBleHRlbmRzIEVkaXRhYmxlRmllbGQge1xuICAgIHNldHRpbmdzOiBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzO1xuICAgIGNvbnN0cnVjdG9yKHJvdzogSFRNTFRhYmxlUm93RWxlbWVudCwgaW5kZW50OiBudW1iZXIsIHZhbHVlOiBzdHJpbmcsIHNldHRpbmdzOiBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzKSB7XG4gICAgICAgIGNvbnN0IHRpbWVzdGFtcCA9IE51bWJlcih2YWx1ZSk7XG4gICAgICAgIHZhbHVlID0gdGltZXN0YW1wID4gMCA/IGZvcm1hdFRpbWVzdGFtcCh0aW1lc3RhbXAsIHNldHRpbmdzKSA6IFwiXCI7XG4gICAgICAgIHN1cGVyKHJvdywgaW5kZW50LCB2YWx1ZSk7XG4gICAgICAgIHRoaXMuc2V0dGluZ3MgPSBzZXR0aW5ncztcbiAgICB9XG4gICAgYmVnaW5FZGl0KHZhbHVlOiBzdHJpbmcpIHtcbiAgICAgICAgdmFsdWUgPSBmb3JtYXRFZGl0YWJsZVRpbWVzdGFtcChOdW1iZXIodmFsdWUpLCB0aGlzLnNldHRpbmdzKTtcbiAgICAgICAgc3VwZXIuYmVnaW5FZGl0KHZhbHVlKTtcbiAgICB9XG4gICAgZW5kRWRpdCgpOiBzdHJpbmcge1xuICAgICAgICBjb25zdCB2YWx1ZSA9IHRoaXMuYm94LmdldFZhbHVlKCk7XG4gICAgICAgIGNvbnN0IHRpbWVzdGFtcCA9IHVuZm9ybWF0RWRpdGFibGVUaW1lc3RhbXAodmFsdWUsIHRoaXMuc2V0dGluZ3MpO1xuICAgICAgICBjb25zdCBkaXNwbGF5VmFsdWUgPSBmb3JtYXRUaW1lc3RhbXAodGltZXN0YW1wLCB0aGlzLnNldHRpbmdzKTtcbiAgICAgICAgdGhpcy5sYWJlbC5zZXRUZXh0KGRpc3BsYXlWYWx1ZSk7XG4gICAgICAgIHRoaXMuYm94LmlucHV0RWwuaGlkZSgpO1xuICAgICAgICB0aGlzLmxhYmVsLmhpZGRlbiA9IGZhbHNlO1xuICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgfVxuICAgIGdldFRpbWVzdGFtcCgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdW5mb3JtYXRFZGl0YWJsZVRpbWVzdGFtcCh0aGlzLmJveC5nZXRWYWx1ZSgpLCB0aGlzLnNldHRpbmdzKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGFkZEVkaXRhYmxlVGFibGVSb3codHJhY2tlcjogVHJhY2tlciwgZW50cnk6IEVudHJ5LCB0YWJsZTogSFRNTFRhYmxlRWxlbWVudCwgbmV3U2VnbWVudE5hbWVCb3g6IFRleHRDb21wb25lbnQsIHJ1bm5pbmc6IGJvb2xlYW4sIGZpbGU6IHN0cmluZywgZ2V0U2VjdGlvbkluZm86ICgpID0+IE1hcmtkb3duU2VjdGlvbkluZm9ybWF0aW9uLCBzZXR0aW5nczogU2ltcGxlVGltZVRyYWNrZXJTZXR0aW5ncywgaW5kZW50OiBudW1iZXIpIHtcbiAgICBsZXQgcm93ID0gdGFibGUuY3JlYXRlRWwoXCJ0clwiKTtcblxuICAgIGxldCBuYW1lRmllbGQgPSBuZXcgRWRpdGFibGVGaWVsZChyb3csIGluZGVudCwgZW50cnkubmFtZSk7XG4gICAgbGV0IHN0YXJ0RmllbGQgPSBuZXcgRWRpdGFibGVUaW1lc3RhbXBGaWVsZChyb3csIGluZGVudCwgU3RyaW5nKGVudHJ5LnN0YXJ0VGltZSksIHNldHRpbmdzKTtcbiAgICBsZXQgZW5kRmllbGQgPSBuZXcgRWRpdGFibGVUaW1lc3RhbXBGaWVsZChyb3csIGluZGVudCwgU3RyaW5nKGVudHJ5LmVuZFRpbWUpLCBzZXR0aW5ncyk7XG5cbiAgICByb3cuY3JlYXRlRWwoXCJ0ZFwiLCB7IHRleHQ6IGVudHJ5LmVuZFRpbWUgfHwgZW50cnkuc3ViRW50cmllcyA/IGZvcm1hdER1cmF0aW9uKGdldER1cmF0aW9uKGVudHJ5KSwgc2V0dGluZ3MpIDogXCJcIiB9KTtcblxuICAgIGxldCBlbnRyeUJ1dHRvbnMgPSByb3cuY3JlYXRlRWwoXCJ0ZFwiKTtcbiAgICBpZiAoIXJ1bm5pbmcpIHtcbiAgICAgICAgbmV3IEJ1dHRvbkNvbXBvbmVudChlbnRyeUJ1dHRvbnMpXG4gICAgICAgICAgICAuc2V0Q2xhc3MoXCJjbGlja2FibGUtaWNvblwiKVxuICAgICAgICAgICAgLnNldEljb24oYGx1Y2lkZS1wbGF5YClcbiAgICAgICAgICAgIC5zZXRUb29sdGlwKFwiQ29udGludWVcIilcbiAgICAgICAgICAgIC5vbkNsaWNrKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgICAgICBzdGFydFN1YkVudHJ5KGVudHJ5LCBuZXdTZWdtZW50TmFtZUJveC5nZXRWYWx1ZSgpKTtcbiAgICAgICAgICAgICAgICBhd2FpdCBzYXZlVHJhY2tlcih0cmFja2VyLCB0aGlzLmFwcCwgZmlsZSwgZ2V0U2VjdGlvbkluZm8oKSk7XG4gICAgICAgICAgICB9KTtcbiAgICB9XG4gICAgbGV0IGVkaXRCdXR0b24gPSBuZXcgQnV0dG9uQ29tcG9uZW50KGVudHJ5QnV0dG9ucylcbiAgICAgICAgLnNldENsYXNzKFwiY2xpY2thYmxlLWljb25cIilcbiAgICAgICAgLnNldFRvb2x0aXAoXCJFZGl0XCIpXG4gICAgICAgIC5zZXRJY29uKFwibHVjaWRlLXBlbmNpbFwiKVxuICAgICAgICAub25DbGljayhhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBpZiAobmFtZUZpZWxkLmVkaXRpbmcoKSkge1xuICAgICAgICAgICAgICAgIGVudHJ5Lm5hbWUgPSBuYW1lRmllbGQuZW5kRWRpdCgpO1xuICAgICAgICAgICAgICAgIHN0YXJ0RmllbGQuZW5kRWRpdCgpO1xuICAgICAgICAgICAgICAgIGVudHJ5LnN0YXJ0VGltZSA9IHN0YXJ0RmllbGQuZ2V0VGltZXN0YW1wKCk7XG4gICAgICAgICAgICAgICAgZW5kRmllbGQuZW5kRWRpdCgpO1xuICAgICAgICAgICAgICAgIGVudHJ5LmVuZFRpbWUgPSBlbmRGaWVsZC5nZXRUaW1lc3RhbXAoKTtcbiAgICAgICAgICAgICAgICBhd2FpdCBzYXZlVHJhY2tlcih0cmFja2VyLCB0aGlzLmFwcCwgZmlsZSwgZ2V0U2VjdGlvbkluZm8oKSk7XG4gICAgICAgICAgICAgICAgZWRpdEJ1dHRvbi5zZXRJY29uKFwibHVjaWRlLXBlbmNpbFwiKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbmFtZUZpZWxkLmJlZ2luRWRpdChlbnRyeS5uYW1lKTtcbiAgICAgICAgICAgICAgICBzdGFydEZpZWxkLmJlZ2luRWRpdChTdHJpbmcoZW50cnkuc3RhcnRUaW1lKSk7XG4gICAgICAgICAgICAgICAgZW5kRmllbGQuYmVnaW5FZGl0KFN0cmluZyhlbnRyeS5lbmRUaW1lKSk7XG4gICAgICAgICAgICAgICAgZWRpdEJ1dHRvbi5zZXRJY29uKFwibHVjaWRlLWNoZWNrXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICBuZXcgQnV0dG9uQ29tcG9uZW50KGVudHJ5QnV0dG9ucylcbiAgICAgICAgLnNldENsYXNzKFwiY2xpY2thYmxlLWljb25cIilcbiAgICAgICAgLnNldFRvb2x0aXAoXCJSZW1vdmVcIilcbiAgICAgICAgLnNldEljb24oXCJsdWNpZGUtdHJhc2hcIilcbiAgICAgICAgLm9uQ2xpY2soYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgcmVtb3ZlRW50cnkodHJhY2tlci5lbnRyaWVzLCBlbnRyeSk7XG4gICAgICAgICAgICBhd2FpdCBzYXZlVHJhY2tlcih0cmFja2VyLCB0aGlzLmFwcCwgZmlsZSwgZ2V0U2VjdGlvbkluZm8oKSk7XG4gICAgICAgIH0pO1xuXG4gICAgaWYgKGVudHJ5LnN1YkVudHJpZXMpIHtcbiAgICAgICAgZm9yIChsZXQgc3ViIG9mIGVudHJ5LnN1YkVudHJpZXMpXG4gICAgICAgICAgICBhZGRFZGl0YWJsZVRhYmxlUm93KHRyYWNrZXIsIHN1YiwgdGFibGUsIG5ld1NlZ21lbnROYW1lQm94LCBydW5uaW5nLCBmaWxlLCBnZXRTZWN0aW9uSW5mbywgc2V0dGluZ3MsIGluZGVudCArIDEpO1xuICAgIH1cbn1cbiJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBO0FBQUE7QUFBQTtBQUFBLHVCQUF1Qjs7O0FDQWhCLElBQU0sa0JBQTZDO0FBQUEsRUFDdEQsaUJBQWlCO0FBQUEsRUFDakIseUJBQXlCO0FBQUEsRUFDekIsY0FBYztBQUFBLEVBQ2Qsc0JBQXNCO0FBQUE7OztBQ0oxQixzQkFBK0M7QUFJeEMsaURBQTJDLGlDQUFpQjtBQUFBLEVBSS9ELFlBQVksS0FBVSxRQUFpQztBQUNuRCxVQUFNLEtBQUs7QUFDWCxTQUFLLFNBQVM7QUFBQTtBQUFBLEVBR2xCLFVBQWdCO0FBQ1osU0FBSyxZQUFZO0FBQ2pCLFNBQUssWUFBWSxTQUFTLE1BQU0sRUFBQyxNQUFNO0FBRXZDLFFBQUksd0JBQVEsS0FBSyxhQUNaLFFBQVEsNEJBQ1IsUUFBUSxlQUFlLE9BQUs7QUFDekIsUUFBRSxXQUFXLEVBQUMsTUFBTTtBQUNwQixRQUFFLFNB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