mirror of
https://github.com/Ellpeck/ObsidianSimpleTimeTracker.git
synced 2024-11-16 15:33:12 +01:00
388 lines
47 KiB
JavaScript
388 lines
47 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",
|
|
csvDelimiter: ","
|
|
};
|
|
|
|
// 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();
|
|
}));
|
|
});
|
|
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, section) {
|
|
return __async(this, null, function* () {
|
|
let file = app.workspace.getActiveFile();
|
|
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, getSectionInfo, settings) {
|
|
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, 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, 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);
|
|
let intervalId = window.setInterval(() => {
|
|
if (!element.isConnected) {
|
|
window.clearInterval(intervalId);
|
|
return;
|
|
}
|
|
setCountdownValues(tracker, current, total, currentDiv);
|
|
}, 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) {
|
|
let running = getRunningEntry(tracker.entries);
|
|
if (running && !running.endTime) {
|
|
current.setText(formatDuration(getDuration(running)));
|
|
currentDiv.hidden = false;
|
|
} else {
|
|
currentDiv.hidden = true;
|
|
}
|
|
total.setText(formatDuration(getTotalDuration(tracker.entries)));
|
|
}
|
|
function formatTimestamp(timestamp, settings) {
|
|
return import_obsidian2.moment.unix(timestamp).format(settings.timestampFormat);
|
|
}
|
|
function formatDuration(totalTime) {
|
|
let duration = import_obsidian2.moment.duration(totalTime);
|
|
let ret = "";
|
|
if (duration.years() > 0)
|
|
ret += duration.years() + "y ";
|
|
if (duration.months() > 0)
|
|
ret += duration.months() + "m ";
|
|
if (duration.days() > 0)
|
|
ret += duration.days() + "d ";
|
|
if (duration.hours() > 0)
|
|
ret += duration.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))}**`]);
|
|
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)) : ""
|
|
]];
|
|
if (entry.subEntries) {
|
|
for (let sub of entry.subEntries)
|
|
ret.push(...createTableSection(sub, settings));
|
|
}
|
|
return ret;
|
|
}
|
|
function addEditableTableRow(tracker, entry, table, newSegmentNameBox, running, getSectionInfo, settings, indent) {
|
|
let row = table.createEl("tr");
|
|
let name = row.createEl("td");
|
|
let namePar = name.createEl("span", { text: entry.name });
|
|
namePar.style.marginLeft = `${indent}em`;
|
|
let nameBox = new import_obsidian2.TextComponent(name).setValue(entry.name);
|
|
nameBox.inputEl.hidden = true;
|
|
row.createEl("td", { text: entry.startTime ? formatTimestamp(entry.startTime, settings) : "" });
|
|
row.createEl("td", { text: entry.endTime ? formatTimestamp(entry.endTime, settings) : "" });
|
|
row.createEl("td", { text: entry.endTime || entry.subEntries ? formatDuration(getDuration(entry)) : "" });
|
|
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, getSectionInfo());
|
|
}));
|
|
}
|
|
let editButton = new import_obsidian2.ButtonComponent(entryButtons).setClass("clickable-icon").setTooltip("Edit").setIcon("lucide-pencil").onClick(() => __async(this, null, function* () {
|
|
if (namePar.hidden) {
|
|
namePar.hidden = false;
|
|
nameBox.inputEl.hidden = true;
|
|
editButton.setIcon("lucide-pencil");
|
|
if (nameBox.getValue()) {
|
|
entry.name = nameBox.getValue();
|
|
namePar.setText(entry.name);
|
|
yield saveTracker(tracker, this.app, getSectionInfo());
|
|
}
|
|
} else {
|
|
namePar.hidden = true;
|
|
nameBox.inputEl.hidden = false;
|
|
nameBox.setValue(entry.name);
|
|
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, getSectionInfo());
|
|
}));
|
|
if (entry.subEntries) {
|
|
for (let sub of entry.subEntries)
|
|
addEditableTableRow(tracker, sub, table, newSegmentNameBox, running, 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.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,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsic3JjL21haW4udHMiLCAic3JjL3NldHRpbmdzLnRzIiwgInNyYy9zZXR0aW5ncy10YWIudHMiLCAic3JjL3RyYWNrZXIudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImltcG9ydCB7IFBsdWdpbiB9IGZyb20gXCJvYnNpZGlhblwiO1xuaW1wb3J0IHsgZGVmYXVsdFNldHRpbmdzLCBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzIH0gZnJvbSBcIi4vc2V0dGluZ3NcIjtcbmltcG9ydCB7IFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3NUYWIgfSBmcm9tIFwiLi9zZXR0aW5ncy10YWJcIjtcbmltcG9ydCB7IGRpc3BsYXlUcmFja2VyLCBsb2FkVHJhY2tlciB9IGZyb20gXCIuL3RyYWNrZXJcIjtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgU2ltcGxlVGltZVRyYWNrZXJQbHVnaW4gZXh0ZW5kcyBQbHVnaW4ge1xuXG5cdHNldHRpbmdzOiBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzO1xuXG5cdGFzeW5jIG9ubG9hZCgpOiBQcm9taXNlPHZvaWQ+IHtcblx0XHRhd2FpdCB0aGlzLmxvYWRTZXR0aW5ncygpO1xuXG5cdFx0dGhpcy5hZGRTZXR0aW5nVGFiKG5ldyBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzVGFiKHRoaXMuYXBwLCB0aGlzKSk7XG5cblx0XHR0aGlzLnJlZ2lzdGVyTWFya2Rvd25Db2RlQmxvY2tQcm9jZXNzb3IoXCJzaW1wbGUtdGltZS10cmFja2VyXCIsIChzLCBlLCBpKSA9PiB7XG5cdFx0XHRsZXQgdHJhY2tlciA9IGxvYWRUcmFja2VyKHMpO1xuXHRcdFx0ZS5lbXB0eSgpO1xuXHRcdFx0ZGlzcGxheVRyYWNrZXIodHJhY2tlciwgZSwgKCkgPT4gaS5nZXRTZWN0aW9uSW5mbyhlKSwgdGhpcy5zZXR0aW5ncyk7XG5cdFx0fSk7XG5cblx0XHR0aGlzLmFkZENvbW1hbmQoe1xuXHRcdFx0aWQ6IGBpbnNlcnRgLFxuXHRcdFx0bmFtZTogYEluc2VydCBUaW1lIFRyYWNrZXJgLFxuXHRcdFx0ZWRpdG9yQ2FsbGJhY2s6IChlLCBfKSA9PiB7XG5cdFx0XHRcdGUucmVwbGFjZVNlbGVjdGlvbihcImBgYHNpbXBsZS10aW1lLXRyYWNrZXJcXG5gYGBcXG5cIik7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cblxuXHRhc3luYyBsb2FkU2V0dGluZ3MoKSB7XG5cdFx0dGhpcy5zZXR0aW5ncyA9IE9iamVjdC5hc3NpZ24oe30sIGRlZmF1bHRTZXR0aW5ncywgYXdhaXQgdGhpcy5sb2FkRGF0YSgpKTtcblx0fVxuXG5cdGFzeW5jIHNhdmVTZXR0aW5ncygpIHtcblx0XHRhd2FpdCB0aGlzLnNhdmVEYXRhKHRoaXMuc2V0dGluZ3MpO1xuXHR9XG59XG4iLCAiZXhwb3J0IGNvbnN0IGRlZmF1bHRTZXR0aW5nczogU2ltcGxlVGltZVRyYWNrZXJTZXR0aW5ncyA9IHtcbiAgICB0aW1lc3RhbXBGb3JtYXQ6IFwiWVktTU0tREQgaGg6bW06c3NcIixcbiAgICBjc3ZEZWxpbWl0ZXI6IFwiLFwiXG59O1xuXG5leHBvcnQgaW50ZXJmYWNlIFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3Mge1xuXG4gICAgdGltZXN0YW1wRm9ybWF0OiBzdHJpbmc7XG4gICAgY3N2RGVsaW1pdGVyOiBzdHJpbmc7XG5cbn1cbiIsICJpbXBvcnQgeyBBcHAsIFBsdWdpblNldHRpbmdUYWIsIFNldHRpbmcgfSBmcm9tIFwib2JzaWRpYW5cIjtcbmltcG9ydCBTaW1wbGVUaW1lVHJhY2tlclBsdWdpbiBmcm9tIFwiLi9tYWluXCI7XG5pbXBvcnQgeyBkZWZhdWx0U2V0dGluZ3MgfSBmcm9tIFwiLi9zZXR0aW5nc1wiO1xuXG5leHBvcnQgY2xhc3MgU2ltcGxlVGltZVRyYWNrZXJTZXR0aW5nc1RhYiBleHRlbmRzIFBsdWdpblNldHRpbmdUYWIge1xuXG4gICAgcGx1Z2luOiBTaW1wbGVUaW1lVHJhY2tlclBsdWdpbjtcblxuICAgIGNvbnN0cnVjdG9yKGFwcDogQXBwLCBwbHVnaW46IFNpbXBsZVRpbWVUcmFja2VyUGx1Z2luKSB7XG4gICAgICAgIHN1cGVyKGFwcCwgcGx1Z2luKTtcbiAgICAgICAgdGhpcy5wbHVnaW4gPSBwbHVnaW47XG4gICAgfVxuXG4gICAgZGlzcGxheSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5jb250YWluZXJFbC5lbXB0eSgpO1xuICAgICAgICB0aGlzLmNvbnRhaW5lckVsLmNyZWF0ZUVsKFwiaDJcIiwgeyB0ZXh0OiBcIlN1cGVyIFNpbXBsZSBUaW1lIFRyYWNrZXIgU2V0dGluZ3NcIiB9KTtcblxuICAgICAgICBuZXcgU2V0dGluZyh0aGlzLmNvbnRhaW5lckVsKVxuICAgICAgICAgICAgLnNldE5hbWUoXCJUaW1lc3RhbXAgRGlzcGxheSBGb3JtYXRcIilcbiAgICAgICAgICAgIC5zZXREZXNjKGNyZWF0ZUZyYWdtZW50KGYgPT4ge1xuICAgICAgICAgICAgICAgIGYuY3JlYXRlU3Bhbih7IHRleHQ6IFwiVGhlIHdheSB0aGF0IHRpbWVzdGFtcHMgaW4gdGltZSB0cmFja2VyIHRhYmxlcyBzaG91bGQgYmUgZGlzcGxheWVkLiBVc2VzIFwiIH0pO1xuICAgICAgICAgICAgICAgIGYuY3JlYXRlRWwoXCJhXCIsIHsgdGV4dDogXCJtb21lbnQuanNcIiwgaHJlZjogXCJodHRwczovL21vbWVudGpzLmNvbS9kb2NzLyMvcGFyc2luZy9zdHJpbmctZm9ybWF0L1wiIH0pO1xuICAgICAgICAgICAgICAgIGYuY3JlYXRlU3Bhbih7IHRleHQ6IFwiIHN5bnRheC5cIiB9KTtcbiAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgLmFkZFRleHQodCA9PiB7XG4gICAgICAgICAgICAgICAgdC5zZXRWYWx1ZShTdHJpbmcodGhpcy5wbHVnaW4uc2V0dGluZ3MudGltZXN0YW1wRm9ybWF0KSk7XG4gICAgICAgICAgICAgICAgdC5vbkNoYW5nZShhc3luYyB2ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3MudGltZXN0YW1wRm9ybWF0ID0gdi5sZW5ndGggPyB2IDogZGVmYXVsdFNldHRpbmdzLnRpbWVzdGFtcEZvcm1hdDtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICBuZXcgU2V0dGluZyh0aGlzLmNvbnRhaW5lckVsKVxuICAgICAgICAgICAgLnNldE5hbWUoXCJDU1YgRGVsaW1pdGVyXCIpXG4gICAgICAgICAgICAuc2V0RGVzYyhcIlRoZSBkZWxpbWl0ZXIgY2hhcmFjdGVyIHRoYXQgc2hvdWxkIGJlIHVzZWQgd2hlbiBjb3B5aW5nIGEgdHJhY2tlciB0YWJsZSBhcyBDU1YuIEZvciBleGFtcGxlLCBzb21lIGxhbmd1YWdlcyB1c2UgYSBzZW1pY29sb24gaW5zdGVhZCBvZiBhIGNvbW1hLlwiKVxuICAgICAgICAgICAgLmFkZFRleHQodCA9PiB7XG4gICAgICAgICAgICAgICAgdC5zZXRWYWx1ZShTdHJpbmcodGhpcy5wbHVnaW4uc2V0dGluZ3MuY3N2RGVsaW1pdGVyKSk7XG4gICAgICAgICAgICAgICAgdC5vbkNoYW5nZShhc3luYyB2ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3MuY3N2RGVsaW1pdGVyID0gdi5sZW5ndGggPyB2IDogZGVmYXVsdFNldHRpbmdzLmNzdkRlbGltaXRlcjtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLmNvbnRhaW5lckVsLmNyZWF0ZUVsKFwiaHJcIik7XG4gICAgICAgIHRoaXMuY29udGFpbmVyRWwuY3JlYXRlRWwoXCJwXCIsIHsgdGV4dDogXCJJZiB5b3UgbGlrZSB0aGlzIHBsdWdpbiBhbmQgd2FudCB0byBzdXBwb3J0IGl0cyBkZXZlbG9wbWVudCwgeW91IGNhbiBkbyBzbyB0aHJvdWdoIG15IHdlYnNpdGUgYnkgY2xpY2tpbmcgdGhpcyBmYW5jeSBpbWFnZSFcIiB9KTtcbiAgICAgICAgdGhpcy5jb250YWluZXJFbC5jcmVhdGVFbChcImFcIiwgeyBocmVmOiBcImh0dHBzOi8vZWxscGVjay5kZS9zdXBwb3J0XCIgfSlcbiAgICAgICAgICAgIC5jcmVhdGVFbChcImltZ1wiLCB7IGF0dHI6IHsgc3JjOiBcImh0dHBzOi8vZWxscGVjay5kZS9yZXMvZ2VuZXJhbHN1cHBvcnQucG5nXCIgfSwgY2xzOiBcInNpbXBsZS10aW1lLXRyYWNrZXItc3VwcG9ydFwiIH0pO1xuICAgIH1cbn1cbiIsICJpbXBvcnQgeyBtb21lbnQsIEFwcCwgTWFya2Rvd25TZWN0aW9uSW5mb3JtYXRpb24sIEJ1dHRvbkNvbXBvbmVudCwgVGV4dENvbXBvbmVudCB9IGZyb20gXCJvYnNpZGlhblwiO1xuaW1wb3J0IHsgU2ltcGxlVGltZVRyYWNrZXJTZXR0aW5ncyB9IGZyb20gXCIuL3NldHRpbmdzXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVHJhY2tlciB7XG4gICAgZW50cmllczogRW50cnlbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFbnRyeSB7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIHN0YXJ0VGltZTogbnVtYmVyO1xuICAgIGVuZFRpbWU6IG51bWJlcjtcbiAgICBzdWJFbnRyaWVzOiBFbnRyeVtdO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2F2ZVRyYWNrZXIodHJhY2tlcjogVHJhY2tlciwgYXBwOiBBcHAsIHNlY3Rpb246IE1hcmtkb3duU2VjdGlvbkluZm9ybWF0aW9uKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgbGV0IGZpbGUgPSBhcHAud29ya3NwYWNlLmdldEFjdGl2ZUZpbGUoKTtcbiAgICBpZiAoIWZpbGUpXG4gICAgICAgIHJldHVybjtcbiAgICBsZXQgY29udGVudCA9IGF3YWl0IGFwcC52YXVsdC5yZWFkKGZpbGUpO1xuXG4gICAgLy8gZmlndXJlIG91dCB3aGF0IHBhcnQgb2YgdGhlIGNvbnRlbnQgd2UgaGF2ZSB0byBlZGl0XG4gICAgbGV0IGxpbmVzID0gY29udGVudC5zcGxpdChcIlxcblwiKTtcbiAgICBsZXQgcHJldiA9IGxpbmVzLmZpbHRlcigoXywgaSkgPT4gaSA8PSBzZWN0aW9uLmxpbmVTdGFydCkuam9pbihcIlxcblwiKTtcbiAgICBsZXQgbmV4dCA9IGxpbmVzLmZpbHRlcigoXywgaSkgPT4gaSA+PSBzZWN0aW9uLmxpbmVFbmQpLmpvaW4oXCJcXG5cIik7XG4gICAgLy8gZWRpdCBvbmx5IHRoZSBjb2RlIGJsb2NrIGNvbnRlbnQsIGxlYXZlIHRoZSByZXN0IHVudG91Y2hlZFxuICAgIGNvbnRlbnQgPSBgJHtwcmV2fVxcbiR7SlNPTi5zdHJpbmdpZnkodHJhY2tlcil9XFxuJHtuZXh0fWA7XG5cbiAgICBhd2FpdCBhcHAudmF1bHQubW9kaWZ5KGZpbGUsIGNvbnRlbnQpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbG9hZFRyYWNrZXIoanNvbjogc3RyaW5nKTogVHJhY2tlciB7XG4gICAgaWYgKGpzb24pIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJldHVybiBKU09OLnBhcnNlKGpzb24pO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgRmFpbGVkIHRvIHBhcnNlIFRyYWNrZXIgZnJvbSAke2pzb259YCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgZW50cmllczogW10gfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRpc3BsYXlUcmFja2VyKHRyYWNrZXI6IFRyYWNrZXIsIGVsZW1lbnQ6IEhUTUxFbGVtZW50LCBnZXRTZWN0aW9uSW5mbzogKCkgPT4gTWFya2Rvd25TZWN0aW9uSW5mb3JtYXRpb24sIHNldHRpbmdzOiBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzKTogdm9pZCB7XG4gICAgLy8gYWRkIHN0YXJ0L3N0b3AgY29udHJvbHNcbiAgICBsZXQgcnVubmluZyA9IGlzUnVubmluZyh0cmFja2VyKTtcbiAgICBsZXQgYnRuID0gbmV3IEJ1dHRvbkNvbXBvbmVudChlbGVtZW50KVxuICAgICAgICAuc2V0Q2xhc3MoXCJjbGlja2FibGUtaWNvblwiKVxuICAgICAgICAuc2V0SWNvbihgbHVjaWRlLSR7cnVubmluZyA/IFwic3RvcFwiIDogXCJwbGF5XCJ9LWNpcmNsZWApXG4gICAgICAgIC5zZXRUb29sdGlwKHJ1bm5pbmcgPyBcIkVuZFwiIDogXCJTdGFydFwiKVxuICAgICAgICAub25DbGljayhhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBpZiAocnVubmluZykge1xuICAgICAgICAgICAgICAgIGVuZFJ1bm5pbmdFbnRyeSh0cmFja2VyKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc3RhcnROZXdFbnRyeSh0cmFja2VyLCBuZXdTZWdtZW50TmFtZUJveC5nZXRWYWx1ZSgpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGF3YWl0IHNhdmVUcmFja2VyKHRyYWNrZXIsIHRoaXMuYXBwLCBnZXRTZWN0aW9uSW5mbygpKTtcbiAgICAgICAgfSk7XG4gICAgYnRuLmJ1dHRvbkVsLmFkZENsYXNzKFwic2ltcGxlLXRpbWUtdHJhY2tlci1idG5cIik7XG4gICAgbGV0IG5ld1NlZ21lbnROYW1lQm94ID0gbmV3IFRleHRDb21wb25lbnQoZWxlbWVudClcbiAgICAgICAgLnNldFBsYWNlaG9sZGVyKFwiU2VnbWVudCBuYW1lXCIpXG4gICAgICAgIC5zZXREaXNhYmxlZChydW5uaW5nKTtcbiAgICBuZXdTZWdtZW50TmFtZUJveC5pbnB1dEVsLmFkZENsYXNzKFwic2ltcGxlLXRpbWUtdHJhY2tlci10eHRcIik7XG5cbiAgICAvLyBhZGQgdGltZXJzXG4gICAgbGV0IHRpbWVyID0gZWxlbWVudC5jcmVhdGVEaXYoeyBjbHM6IFwic2ltcGxlLXRpbWUtdHJhY2tlci10aW1lcnNcIiB9KTtcbiAgICBsZXQgY3VycmVudERpdiA9IHRpbWVyLmNyZWF0ZUVsKFwiZGl2XCIsIHsgY2xzOiBcInNpbXBsZS10aW1lLXRyYWNrZXItdGltZXJcIiB9KTtcbiAgICBsZXQgY3VycmVudCA9IGN1cnJlbnREaXYuY3JlYXRlRWwoXCJzcGFuXCIsIHsgY2xzOiBcInNpbXBsZS10aW1lLXRyYWNrZXItdGltZXItdGltZVwiIH0pO1xuICAgIGN1cnJlbnREaXYuY3JlYXRlRWwoXCJzcGFuXCIsIHsgdGV4dDogXCJDdXJyZW50XCIgfSk7XG4gICAgbGV0IHRvdGFsRGl2ID0gdGltZXIuY3JlYXRlRWwoXCJkaXZcIiwgeyBjbHM6IFwic2ltcGxlLXRpbWUtdHJhY2tlci10aW1lclwiIH0pO1xuICAgIGxldCB0b3RhbCA9IHRvdGFsRGl2LmNyZWF0ZUVsKFwic3BhblwiLCB7IGNsczogXCJzaW1wbGUtdGltZS10cmFja2VyLXRpbWVyLXRpbWVcIiwgdGV4dDogXCIwc1wiIH0pO1xuICAgIHRvdGFsRGl2LmNyZWF0ZUVsKFwic3BhblwiLCB7IHRleHQ6IFwiVG90YWxcIiB9KTtcblxuICAgIGlmICh0cmFja2VyLmVudHJpZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAvLyBhZGQgdGFibGVcbiAgICAgICAgbGV0IHRhYmxlID0gZWxlbWVudC5jcmVhdGVFbChcInRhYmxlXCIsIHsgY2xzOiBcInNpbXBsZS10aW1lLXRyYWNrZXItdGFibGVcIiB9KTtcbiAgICAgICAgdGFibGUuY3JlYXRlRWwoXCJ0clwiKS5hcHBlbmQoXG4gICAgICAgICAgICBjcmVhdGVFbChcInRoXCIsIHsgdGV4dDogXCJTZWdtZW50XCIgfSksXG4gICAgICAgICAgICBjcmVhdGVFbChcInRoXCIsIHsgdGV4dDogXCJTdGFydCB0aW1lXCIgfSksXG4gICAgICAgICAgICBjcmVhdGVFbChcInRoXCIsIHsgdGV4dDogXCJFbmQgdGltZVwiIH0pLFxuICAgICAgICAgICAgY3JlYXRlRWwoXCJ0aFwiLCB7IHRleHQ6IFwiRHVyYXRpb25cIiB9KSxcbiAgICAgICAgICAgIGNyZWF0ZUVsKFwidGhcIikpO1xuXG4gICAgICAgIGZvciAobGV0IGVudHJ5IG9mIHRyYWNrZXIuZW50cmllcylcbiAgICAgICAgICAgIGFkZEVkaXRhYmxlVGFibGVSb3codHJhY2tlciwgZW50cnksIHRhYmxlLCBuZXdTZWdtZW50TmFtZUJveCwgcnVubmluZywgZ2V0U2VjdGlvbkluZm8sIHNldHRpbmdzLCAwKTtcblxuICAgICAgICAvLyBhZGQgY29weSBidXR0b25zXG4gICAgICAgIGxldCBidXR0b25zID0gZWxlbWVudC5jcmVhdGVFbChcImRpdlwiLCB7IGNsczogXCJzaW1wbGUtdGltZS10cmFja2VyLWJvdHRvbVwiIH0pO1xuICAgICAgICBuZXcgQnV0dG9uQ29tcG9uZW50KGJ1dHRvbnMpXG4gICAgICAgICAgICAuc2V0QnV0dG9uVGV4dChcIkNvcHkgYXMgdGFibGVcIilcbiAgICAgICAgICAgIC5vbkNsaWNrKCgpID0+IG5hdmlnYXRvci5jbGlwYm9hcmQud3JpdGVUZXh0KGNyZWF0ZU1hcmtkb3duVGFibGUodHJhY2tlciwgc2V0dGluZ3MpKSk7XG4gICAgICAgIG5ldyBCdXR0b25Db21wb25lbnQoYnV0dG9ucylcbiAgICAgICAgICAgIC5zZXRCdXR0b25UZXh0KFwiQ29weSBhcyBDU1ZcIilcbiAgICAgICAgICAgIC5vbkNsaWNrKCgpID0+IG5hdmlnYXRvci5jbGlwYm9hcmQud3JpdGVUZXh0KGNyZWF0ZUNzdih0cmFja2VyLCBzZXR0aW5ncykpKTtcbiAgICB9XG5cblxuICAgIHNldENvdW50ZG93blZhbHVlcyh0cmFja2VyLCBjdXJyZW50LCB0b3RhbCwgY3VycmVudERpdik7XG4gICAgbGV0IGludGVydmFsSWQgPSB3aW5kb3cuc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgICAgICAvLyB3ZSBkZWxldGUgdGhlIGludGVydmFsIHRpbWVyIHdoZW4gdGhlIGVsZW1lbnQgaXMgcmVtb3ZlZFxuICAgICAgICBpZiAoIWVsZW1lbnQuaXNDb25uZWN0ZWQpIHtcbiAgICAgICAgICAgIHdpbmRvdy5jbGVhckludGVydmFsKGludGVydmFsSWQpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHNldENvdW50ZG93blZhbHVlcyh0cmFja2VyLCBjdXJyZW50LCB0b3RhbCwgY3VycmVudERpdik7XG4gICAgfSwgMTAwMCk7XG59XG5cbmZ1bmN0aW9uIHN0YXJ0U3ViRW50cnkoZW50cnk6IEVudHJ5LCBuYW1lOiBzdHJpbmcpIHtcbiAgICAvLyBpZiB0aGlzIGVudHJ5IGlzIG5vdCBzcGxpdCB5ZXQsIHdlIGFkZCBpdHMgdGltZSBhcyBhIHN1Yi1lbnRyeSBpbnN0ZWFkXG4gICAgaWYgKCFlbnRyeS5zdWJFbnRyaWVzKSB7XG4gICAgICAgIGVudHJ5LnN1YkVudHJpZXMgPSBbeyAuLi5lbnRyeSwgbmFtZTogYFBhcnQgMWAgfV07XG4gICAgICAgIGVudHJ5LnN0YXJ0VGltZSA9IG51bGw7XG4gICAgICAgIGVudHJ5LmVuZFRpbWUgPSBudWxsO1xuICAgIH1cblxuICAgIGlmICghbmFtZSlcbiAgICAgICAgbmFtZSA9IGBQYXJ0ICR7ZW50cnkuc3ViRW50cmllcy5sZW5ndGggKyAxfWA7XG4gICAgZW50cnkuc3ViRW50cmllcy5wdXNoKHsgbmFtZTogbmFtZSwgc3RhcnRUaW1lOiBtb21lbnQoKS51bml4KCksIGVuZFRpbWU6IG51bGwsIHN1YkVudHJpZXM6IG51bGwgfSk7XG59XG5cbmZ1bmN0aW9uIHN0YXJ0TmV3RW50cnkodHJhY2tlcjogVHJhY2tlciwgbmFtZTogc3RyaW5nKTogdm9pZCB7XG4gICAgaWYgKCFuYW1lKVxuICAgICAgICBuYW1lID0gYFNlZ21lbnQgJHt0cmFja2VyLmVudHJpZXMubGVuZ3RoICsgMX1gO1xuICAgIGxldCBlbnRyeTogRW50cnkgPSB7IG5hbWU6IG5hbWUsIHN0YXJ0VGltZTogbW9tZW50KCkudW5peCgpLCBlbmRUaW1lOiBudWxsLCBzdWJFbnRyaWVzOiBudWxsIH07XG4gICAgdHJhY2tlci5lbnRyaWVzLnB1c2goZW50cnkpO1xufTtcblxuZnVuY3Rpb24gZW5kUnVubmluZ0VudHJ5KHRyYWNrZXI6IFRyYWNrZXIpOiB2b2lkIHtcbiAgICBsZXQgZW50cnkgPSBnZXRSdW5uaW5nRW50cnkodHJhY2tlci5lbnRyaWVzKTtcbiAgICBlbnRyeS5lbmRUaW1lID0gbW9tZW50KCkudW5peCgpO1xufVxuXG5mdW5jdGlvbiByZW1vdmVFbnRyeShlbnRyaWVzOiBFbnRyeVtdLCB0b1JlbW92ZTogRW50cnkpOiBib29sZWFuIHtcbiAgICBpZiAoZW50cmllcy5jb250YWlucyh0b1JlbW92ZSkpIHtcbiAgICAgICAgZW50cmllcy5yZW1vdmUodG9SZW1vdmUpO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBmb3IgKGxldCBlbnRyeSBvZiBlbnRyaWVzKSB7XG4gICAgICAgICAgICBpZiAoZW50cnkuc3ViRW50cmllcyAmJiByZW1vdmVFbnRyeShlbnRyeS5zdWJFbnRyaWVzLCB0b1JlbW92ZSkpIHtcbiAgICAgICAgICAgICAgICAvLyBpZiB3ZSBvbmx5IGhhdmUgb25lIHN1YiBlbnRyeSByZW1haW5pbmcsIHdlIGNhbiBtZXJnZSBiYWNrIGludG8gb3VyIG1haW4gZW50cnlcbiAgICAgICAgICAgICAgICBpZiAoZW50cnkuc3ViRW50cmllcy5sZW5ndGggPT0gMSkge1xuICAgICAgICAgICAgICAgICAgICBsZXQgc2luZ2xlID0gZW50cnkuc3ViRW50cmllc1swXTtcbiAgICAgICAgICAgICAgICAgICAgZW50cnkuc3RhcnRUaW1lID0gc2luZ2xlLnN0YXJ0VGltZTtcbiAgICAgICAgICAgICAgICAgICAgZW50cnkuZW5kVGltZSA9IHNpbmdsZS5lbmRUaW1lO1xuICAgICAgICAgICAgICAgICAgICBlbnRyeS5zdWJFbnRyaWVzID0gbnVsbDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xufVxuXG5mdW5jdGlvbiBpc1J1bm5pbmcodHJhY2tlcjogVHJhY2tlcik6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhIWdldFJ1bm5pbmdFbnRyeSh0cmFja2VyLmVudHJpZXMpO1xufVxuXG5mdW5jdGlvbiBnZXRSdW5uaW5nRW50cnkoZW50cmllczogRW50cnlbXSk6IEVudHJ5IHtcbiAgICBmb3IgKGxldCBlbnRyeSBvZiBlbnRyaWVzKSB7XG4gICAgICAgIC8vIGlmIHRoaXMgZW50cnkgaGFzIHN1YiBlbnRyaWVzLCBjaGVjayBpZiBvbmUgb2YgdGhlbSBpcyBydW5uaW5nXG4gICAgICAgIGlmIChlbnRyeS5zdWJFbnRyaWVzKSB7XG4gICAgICAgICAgICBsZXQgcnVubmluZyA9IGdldFJ1bm5pbmdFbnRyeShlbnRyeS5zdWJFbnRyaWVzKTtcbiAgICAgICAgICAgIGlmIChydW5uaW5nKVxuICAgICAgICAgICAgICAgIHJldHVybiBydW5uaW5nO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gaWYgdGhpcyBlbnRyeSBoYXMgbm8gc3ViIGVudHJpZXMgYW5kIG5vIGVuZCB0aW1lLCBpdCdzIHJ1bm5pbmdcbiAgICAgICAgICAgIGlmICghZW50cnkuZW5kVGltZSlcbiAgICAgICAgICAgICAgICByZXR1cm4gZW50cnk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG59XG5cbmZ1bmN0aW9uIGdldER1cmF0aW9uKGVudHJ5OiBFbnRyeSkge1xuICAgIGlmIChlbnRyeS5zdWJFbnRyaWVzKSB7XG4gICAgICAgIHJldHVybiBnZXRUb3RhbER1cmF0aW9uKGVudHJ5LnN1YkVudHJpZXMpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGxldCBlbmRUaW1lID0gZW50cnkuZW5kVGltZSA/IG1vbWVudC51bml4KGVudHJ5LmVuZFRpbWUpIDogbW9tZW50KCk7XG4gICAgICAgIHJldHVybiBlbmRUaW1lLmRpZmYobW9tZW50LnVuaXgoZW50cnkuc3RhcnRUaW1lKSk7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBnZXRUb3RhbER1cmF0aW9uKGVudHJpZXM6IEVudHJ5W10pOiBudW1iZXIge1xuICAgIGxldCByZXQgPSAwO1xuICAgIGZvciAobGV0IGVudHJ5IG9mIGVudHJpZXMpXG4gICAgICAgIHJldCArPSBnZXREdXJhdGlvbihlbnRyeSk7XG4gICAgcmV0dXJuIHJldDtcbn1cblxuZnVuY3Rpb24gc2V0Q291bnRkb3duVmFsdWVzKHRyYWNrZXI6IFRyYWNrZXIsIGN1cnJlbnQ6IEhUTUxFbGVtZW50LCB0b3RhbDogSFRNTEVsZW1lbnQsIGN1cnJlbnREaXY6IEhUTUxEaXZFbGVtZW50KSB7XG4gICAgbGV0IHJ1bm5pbmcgPSBnZXRSdW5uaW5nRW50cnkodHJhY2tlci5lbnRyaWVzKTtcbiAgICBpZiAocnVubmluZyAmJiAhcnVubmluZy5lbmRUaW1lKSB7XG4gICAgICAgIGN1cnJlbnQuc2V0VGV4dChmb3JtYXREdXJhdGlvbihnZXREdXJhdGlvbihydW5uaW5nKSkpO1xuICAgICAgICBjdXJyZW50RGl2LmhpZGRlbiA9IGZhbHNlO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGN1cnJlbnREaXYuaGlkZGVuID0gdHJ1ZTtcbiAgICB9XG4gICAgdG90YWwuc2V0VGV4dChmb3JtYXREdXJhdGlvbihnZXRUb3RhbER1cmF0aW9uKHRyYWNrZXIuZW50cmllcykpKTtcbn1cblxuZnVuY3Rpb24gZm9ybWF0VGltZXN0YW1wKHRpbWVzdGFtcDogbnVtYmVyLCBzZXR0aW5nczogU2ltcGxlVGltZVRyYWNrZXJTZXR0aW5ncyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIG1vbWVudC51bml4KHRpbWVzdGFtcCkuZm9ybWF0KHNldHRpbmdzLnRpbWVzdGFtcEZvcm1hdCk7XG59XG5cbmZ1bmN0aW9uIGZvcm1hdER1cmF0aW9uKHRvdGFsVGltZTogbnVtYmVyKTogc3RyaW5nIHtcbiAgICBsZXQgZHVyYXRpb24gPSBtb21lbnQuZHVyYXRpb24odG90YWxUaW1lKTtcbiAgICBsZXQgcmV0ID0gXCJcIjtcblx0aWYgKGR1cmF0aW9uLnllYXJzKCkgPiAwKVxuXHRcdHJldCArPSBkdXJhdGlvbi55ZWFycygpICsgXCJ5IFwiO1xuXHRpZiAoZHVyYXRpb24ubW9udGhzKCkgPiAwKVxuXHRcdHJldCArPSBkdXJhdGlvbi5tb250aHMoKSArIFwibSBcIjtcblx0aWYgKGR1cmF0aW9uLmRheXMoKSA+IDApXG5cdFx0cmV0ICs9IGR1cmF0aW9uLmRheXMoKSArIFwiZCBcIjtcbiAgICBpZiAoZHVyYXRpb24uaG91cnMoKSA+IDApXG4gICAgICAgIHJldCArPSBkdXJhdGlvbi5ob3VycygpICsgXCJoIFwiO1xuICAgIGlmIChkdXJhdGlvbi5taW51dGVzKCkgPiAwKVxuICAgICAgICByZXQgKz0gZHVyYXRpb24ubWludXRlcygpICsgXCJtIFwiO1xuICAgIHJldCArPSBkdXJhdGlvbi5zZWNvbmRzKCkgKyBcInNcIjtcbiAgICByZXR1cm4gcmV0O1xufVxuXG5mdW5jdGlvbiBjcmVhdGVNYXJrZG93blRhYmxlKHRyYWNrZXI6IFRyYWNrZXIsIHNldHRpbmdzOiBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzKTogc3RyaW5nIHtcbiAgICBsZXQgdGFibGUgPSBbW1wiU2VnbWVudFwiLCBcIlN0YXJ0IHRpbWVcIiwgXCJFbmQgdGltZVwiLCBcIkR1cmF0aW9uXCJdXTtcbiAgICBmb3IgKGxldCBlbnRyeSBvZiB0cmFja2VyLmVudHJpZXMpXG4gICAgICAgIHRhYmxlLnB1c2goLi4uY3JlYXRlVGFibGVTZWN0aW9uKGVudHJ5LCBzZXR0aW5ncykpO1xuICAgIHRhYmxlLnB1c2goW1wiKipUb3RhbCoqXCIsIFwiXCIsIFwiXCIsIGAqKiR7Zm9ybWF0RHVyYXRpb24oZ2V0VG90YWxEdXJhdGlvbih0cmFja2VyLmVudHJpZXMpKX0qKmBdKTtcblxuICAgIGxldCByZXQgPSBcIlwiO1xuICAgIC8vIGNhbGN1bGF0ZSB0aGUgd2lkdGggZXZlcnkgY29sdW1uIG5lZWRzIHRvIGxvb2sgbmVhdCB3aGVuIG1vbm9zcGFjZWRcbiAgICBsZXQgd2lkdGhzID0gQXJyYXkuZnJvbShBcnJheSg0KS5rZXlzKCkpLm1hcChpID0+IE1hdGgubWF4KC4uLnRhYmxlLm1hcChhID0+IGFbaV0ubGVuZ3RoKSkpO1xuICAgIGZvciAobGV0IHIgPSAwOyByIDwgdGFibGUubGVuZ3RoOyByKyspIHtcbiAgICAgICAgLy8gYWRkIHNlcGFyYXRvcnMgYWZ0ZXIgZmlyc3Qgcm93XG4gICAgICAgIGlmIChyID09IDEpXG4gICAgICAgICAgICByZXQgKz0gQXJyYXkuZnJvbShBcnJheSg0KS5rZXlzKCkpLm1hcChpID0+IFwiLVwiLnJlcGVhdCh3aWR0aHNbaV0pKS5qb2luKFwiIHwgXCIpICsgXCJcXG5cIjtcblxuICAgICAgICBsZXQgcm93OiBzdHJpbmdbXSA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDQ7IGkrKylcbiAgICAgICAgICAgIHJvdy5wdXNoKHRhYmxlW3JdW2ldLnBhZEVuZCh3aWR0aHNbaV0sIFwiIFwiKSk7XG4gICAgICAgIHJldCArPSByb3cuam9pbihcIiB8IFwiKSArIFwiXFxuXCI7XG4gICAgfVxuICAgIHJldHVybiByZXQ7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUNzdih0cmFja2VyOiBUcmFja2VyLCBzZXR0aW5nczogU2ltcGxlVGltZVRyYWNrZXJTZXR0aW5ncyk6IHN0cmluZyB7XG4gICAgbGV0IHJldCA9IFwiXCI7XG4gICAgZm9yIChsZXQgZW50cnkgb2YgdHJhY2tlci5lbnRyaWVzKSB7XG4gICAgICAgIGZvciAobGV0IHJvdyBvZiBjcmVhdGVUYWJsZVNlY3Rpb24oZW50cnksIHNldHRpbmdzKSlcbiAgICAgICAgICAgIHJldCArPSByb3cuam9pbihzZXR0aW5ncy5jc3ZEZWxpbWl0ZXIpICsgXCJcXG5cIjtcbiAgICB9XG4gICAgcmV0dXJuIHJldDtcbn1cblxuZnVuY3Rpb24gY3JlYXRlVGFibGVTZWN0aW9uKGVudHJ5OiBFbnRyeSwgc2V0dGluZ3M6IFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3MpOiBzdHJpbmdbXVtdIHtcbiAgICBsZXQgcmV0OiBzdHJpbmdbXVtdID0gW1tcbiAgICAgICAgZW50cnkubmFtZSxcbiAgICAgICAgZW50cnkuc3RhcnRUaW1lID8gZm9ybWF0VGltZXN0YW1wKGVudHJ5LnN0YXJ0VGltZSwgc2V0dGluZ3MpIDogXCJcIixcbiAgICAgICAgZW50cnkuZW5kVGltZSA/IGZvcm1hdFRpbWVzdGFtcChlbnRyeS5lbmRUaW1lLCBzZXR0aW5ncykgOiBcIlwiLFxuICAgICAgICBlbnRyeS5lbmRUaW1lIHx8IGVudHJ5LnN1YkVudHJpZXMgPyBmb3JtYXREdXJhdGlvbihnZXREdXJhdGlvbihlbnRyeSkpIDogXCJcIl1dO1xuICAgIGlmIChlbnRyeS5zdWJFbnRyaWVzKSB7XG4gICAgICAgIGZvciAobGV0IHN1YiBvZiBlbnRyeS5zdWJFbnRyaWVzKVxuICAgICAgICAgICAgcmV0LnB1c2goLi4uY3JlYXRlVGFibGVTZWN0aW9uKHN1Yiwgc2V0dGluZ3MpKTtcbiAgICB9XG4gICAgcmV0dXJuIHJldDtcbn1cblxuZnVuY3Rpb24gYWRkRWRpdGFibGVUYWJsZVJvdyh0cmFja2VyOiBUcmFja2VyLCBlbnRyeTogRW50cnksIHRhYmxlOiBIVE1MVGFibGVFbGVtZW50LCBuZXdTZWdtZW50TmFtZUJveDogVGV4dENvbXBvbmVudCwgcnVubmluZzogYm9vbGVhbiwgZ2V0U2VjdGlvbkluZm86ICgpID0+IE1hcmtkb3duU2VjdGlvbkluZm9ybWF0aW9uLCBzZXR0aW5nczogU2ltcGxlVGltZVRyYWNrZXJTZXR0aW5ncywgaW5kZW50OiBudW1iZXIpIHtcbiAgICBsZXQgcm93ID0gdGFibGUuY3JlYXRlRWwoXCJ0clwiKTtcblxuICAgIGxldCBuYW1lID0gcm93LmNyZWF0ZUVsKFwidGRcIik7XG4gICAgbGV0IG5hbWVQYXIgPSBuYW1lLmNyZWF0ZUVsKFwic3BhblwiLCB7IHRleHQ6IGVudHJ5Lm5hbWUgfSk7XG4gICAgbmFtZVBhci5zdHlsZS5tYXJnaW5MZWZ0ID0gYCR7aW5kZW50fWVtYDtcbiAgICBsZXQgbmFtZUJveCA9IG5ldyBUZXh0Q29tcG9uZW50KG5hbWUpLnNldFZhbHVlKGVudHJ5Lm5hbWUpO1xuICAgIG5hbWVCb3guaW5wdXRFbC5oaWRkZW4gPSB0cnVlO1xuXG4gICAgcm93LmNyZWF0ZUVsKFwidGRcIiwgeyB0ZXh0OiBlbnRyeS5zdGFydFRpbWUgPyBmb3JtYXRUaW1lc3RhbXAoZW50cnkuc3RhcnRUaW1lLCBzZXR0aW5ncykgOiBcIlwiIH0pO1xuICAgIHJvdy5jcmVhdGVFbChcInRkXCIsIHsgdGV4dDogZW50cnkuZW5kVGltZSA/IGZvcm1hdFRpbWVzdGFtcChlbnRyeS5lbmRUaW1lLCBzZXR0aW5ncykgOiBcIlwiIH0pO1xuICAgIHJvdy5jcmVhdGVFbChcInRkXCIsIHsgdGV4dDogZW50cnkuZW5kVGltZSB8fCBlbnRyeS5zdWJFbnRyaWVzID8gZm9ybWF0RHVyYXRpb24oZ2V0RHVyYXRpb24oZW50cnkpKSA6IFwiXCIgfSk7XG5cbiAgICBsZXQgZW50cnlCdXR0b25zID0gcm93LmNyZWF0ZUVsKFwidGRcIik7XG4gICAgaWYgKCFydW5uaW5nKSB7XG4gICAgICAgIG5ldyBCdXR0b25Db21wb25lbnQoZW50cnlCdXR0b25zKVxuICAgICAgICAgICAgLnNldENsYXNzKFwiY2xpY2thYmxlLWljb25cIilcbiAgICAgICAgICAgIC5zZXRJY29uKGBsdWNpZGUtcGxheWApXG4gICAgICAgICAgICAuc2V0VG9vbHRpcChcIkNvbnRpbnVlXCIpXG4gICAgICAgICAgICAub25DbGljayhhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICAgICAgc3RhcnRTdWJFbnRyeShlbnRyeSwgbmV3U2VnbWVudE5hbWVCb3guZ2V0VmFsdWUoKSk7XG4gICAgICAgICAgICAgICAgYXdhaXQgc2F2ZVRyYWNrZXIodHJhY2tlciwgdGhpcy5hcHAsIGdldFNlY3Rpb25JbmZvKCkpO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxuICAgIGxldCBlZGl0QnV0dG9uID0gbmV3IEJ1dHRvbkNvbXBvbmVudChlbnRyeUJ1dHRvbnMpXG4gICAgICAgIC5zZXRDbGFzcyhcImNsaWNrYWJsZS1pY29uXCIpXG4gICAgICAgIC5zZXRUb29sdGlwKFwiRWRpdFwiKVxuICAgICAgICAuc2V0SWNvbihcImx1Y2lkZS1wZW5jaWxcIilcbiAgICAgICAgLm9uQ2xpY2soYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgaWYgKG5hbWVQYXIuaGlkZGVuKSB7XG4gICAgICAgICAgICAgICAgbmFtZVBhci5oaWRkZW4gPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBuYW1lQm94LmlucHV0RWwuaGlkZGVuID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBlZGl0QnV0dG9uLnNldEljb24oXCJsdWNpZGUtcGVuY2lsXCIpO1xuICAgICAgICAgICAgICAgIGlmIChuYW1lQm94LmdldFZhbHVlKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgZW50cnkubmFtZSA9IG5hbWVCb3guZ2V0VmFsdWUoKTtcbiAgICAgICAgICAgICAgICAgICAgbmFtZVBhci5zZXRUZXh0KGVudHJ5Lm5hbWUpO1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCBzYXZlVHJhY2tlcih0cmFja2VyLCB0aGlzLmFwcCwgZ2V0U2VjdGlvbkluZm8oKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBuYW1lUGFyLmhpZGRlbiA9IHRydWU7XG4gICAgICAgICAgICAgICAgbmFtZUJveC5pbnB1dEVsLmhpZGRlbiA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIG5hbWVCb3guc2V0VmFsdWUoZW50cnkubmFtZSk7XG4gICAgICAgICAgICAgICAgZWRpdEJ1dHRvbi5zZXRJY29uKFwibHVjaWRlLWNoZWNrXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICBuZXcgQnV0dG9uQ29tcG9uZW50KGVudHJ5QnV0dG9ucylcbiAgICAgICAgLnNldENsYXNzKFwiY2xpY2thYmxlLWljb25cIilcbiAgICAgICAgLnNldFRvb2x0aXAoXCJSZW1vdmVcIilcbiAgICAgICAgLnNldEljb24oXCJsdWNpZGUtdHJhc2hcIilcbiAgICAgICAgLm9uQ2xpY2soYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgcmVtb3ZlRW50cnkodHJhY2tlci5lbnRyaWVzLCBlbnRyeSk7XG4gICAgICAgICAgICBhd2FpdCBzYXZlVHJhY2tlcih0cmFja2VyLCB0aGlzLmFwcCwgZ2V0U2VjdGlvbkluZm8oKSk7XG4gICAgICAgIH0pO1xuXG4gICAgaWYgKGVudHJ5LnN1YkVudHJpZXMpIHtcbiAgICAgICAgZm9yIChsZXQgc3ViIG9mIGVudHJ5LnN1YkVudHJpZXMpXG4gICAgICAgICAgICBhZGRFZGl0YWJsZVRhYmxlUm93KHRyYWNrZXIsIHN1YiwgdGFibGUsIG5ld1NlZ21lbnROYW1lQm94LCBydW5uaW5nLCBnZXRTZWN0aW9uSW5mbywgc2V0dGluZ3MsIGluZGVudCArIDEpO1xuICAgIH1cbn1cbiJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBO0FBQUE7QUFBQTtBQUFBLHVCQUF1Qjs7O0FDQWhCLElBQU0sa0JBQTZDO0FBQUEsRUFDdEQsaUJBQWlCO0FBQUEsRUFDakIsY0FBYztBQUFBOzs7QUNGbEIsc0JBQStDO0FBSXhDLGlEQUEyQyxpQ0FBaUI7QUFBQSxFQUkvRCxZQUFZLEtBQVUsUUFBaUM7QUFDbkQsVUFBTSxLQUFLO0FBQ1gsU0FBSyxTQUFTO0FBQUE7QUFBQSxFQUdsQixVQUFnQjtBQUNaLFNBQUssWUFBWTtBQUNqQixTQUFLLFlBQVksU0FBUyxNQUFNLEVBQUUsTUFBTTtBQUV4QyxRQUFJLHdCQUFRLEtBQUssYUFDWixRQUFRLDRCQUNSLFFBQVEsZUFBZSxPQUFLO0FBQ3pCLFFBQUUsV0FBVyxFQUFFLE1BQU07QUFDckIsUUFBRSxTQUFTLEtBQUss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
|