mirror of
https://github.com/Ellpeck/ObsidianSimpleTimeTracker.git
synced 2024-12-19 03:39:23 +01:00
391 lines
48 KiB
Text
391 lines
48 KiB
Text
/*
|
|
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, 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) {
|
|
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);
|
|
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, file, 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, file, 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, file, 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, 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,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsic3JjL21haW4udHMiLCAic3JjL3NldHRpbmdzLnRzIiwgInNyYy9zZXR0aW5ncy10YWIudHMiLCAic3JjL3RyYWNrZXIudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImltcG9ydCB7IFBsdWdpbiB9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQgeyBkZWZhdWx0U2V0dGluZ3MsIFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3MgfSBmcm9tIFwiLi9zZXR0aW5nc1wiO1xyXG5pbXBvcnQgeyBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzVGFiIH0gZnJvbSBcIi4vc2V0dGluZ3MtdGFiXCI7XHJcbmltcG9ydCB7IGRpc3BsYXlUcmFja2VyLCBsb2FkVHJhY2tlciwgVHJhY2tlciB9IGZyb20gXCIuL3RyYWNrZXJcIjtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFNpbXBsZVRpbWVUcmFja2VyUGx1Z2luIGV4dGVuZHMgUGx1Z2luIHtcclxuXHJcbiAgICBzZXR0aW5nczogU2ltcGxlVGltZVRyYWNrZXJTZXR0aW5ncztcclxuXHJcbiAgICBhc3luYyBvbmxvYWQoKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICAgICAgYXdhaXQgdGhpcy5sb2FkU2V0dGluZ3MoKTtcclxuXHJcbiAgICAgICAgdGhpcy5hZGRTZXR0aW5nVGFiKG5ldyBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzVGFiKHRoaXMuYXBwLCB0aGlzKSk7XHJcblxyXG4gICAgICAgIHRoaXMucmVnaXN0ZXJNYXJrZG93bkNvZGVCbG9ja1Byb2Nlc3NvcihcInNpbXBsZS10aW1lLXRyYWNrZXJcIiwgKHMsIGUsIGkpID0+IHtcclxuICAgICAgICAgICAgbGV0IHRyYWNrZXI6IFRyYWNrZXIgPSBsb2FkVHJhY2tlcihzKTtcclxuICAgICAgICAgICAgZS5lbXB0eSgpO1xyXG4gICAgICAgICAgICBkaXNwbGF5VHJhY2tlcih0cmFja2VyLCBlLCBpLnNvdXJjZVBhdGgsICgpID0+IGkuZ2V0U2VjdGlvbkluZm8oZSksIHRoaXMuc2V0dGluZ3MpO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICB0aGlzLmFkZENvbW1hbmQoe1xyXG4gICAgICAgICAgICBpZDogYGluc2VydGAsXHJcbiAgICAgICAgICAgIG5hbWU6IGBJbnNlcnQgVGltZSBUcmFja2VyYCxcclxuICAgICAgICAgICAgZWRpdG9yQ2FsbGJhY2s6IChlLCBfKSA9PiB7XHJcbiAgICAgICAgICAgICAgICBlLnJlcGxhY2VTZWxlY3Rpb24oXCJgYGBzaW1wbGUtdGltZS10cmFja2VyXFxuYGBgXFxuXCIpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgYXN5bmMgbG9hZFNldHRpbmdzKCk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgICAgIHRoaXMuc2V0dGluZ3MgPSBPYmplY3QuYXNzaWduKHt9LCBkZWZhdWx0U2V0dGluZ3MsIGF3YWl0IHRoaXMubG9hZERhdGEoKSk7XHJcbiAgICB9XHJcblxyXG4gICAgYXN5bmMgc2F2ZVNldHRpbmdzKCk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgICAgIGF3YWl0IHRoaXMuc2F2ZURhdGEodGhpcy5zZXR0aW5ncyk7XHJcbiAgICB9XHJcbn1cclxuIiwgImV4cG9ydCBjb25zdCBkZWZhdWx0U2V0dGluZ3M6IFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3MgPSB7XHJcbiAgICB0aW1lc3RhbXBGb3JtYXQ6IFwiWVktTU0tREQgaGg6bW06c3NcIixcclxuICAgIGNzdkRlbGltaXRlcjogXCIsXCJcclxufTtcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgU2ltcGxlVGltZVRyYWNrZXJTZXR0aW5ncyB7XHJcblxyXG4gICAgdGltZXN0YW1wRm9ybWF0OiBzdHJpbmc7XHJcbiAgICBjc3ZEZWxpbWl0ZXI6IHN0cmluZztcclxuXHJcbn1cclxuIiwgImltcG9ydCB7IEFwcCwgUGx1Z2luU2V0dGluZ1RhYiwgU2V0dGluZyB9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQgU2ltcGxlVGltZVRyYWNrZXJQbHVnaW4gZnJvbSBcIi4vbWFpblwiO1xyXG5pbXBvcnQgeyBkZWZhdWx0U2V0dGluZ3MgfSBmcm9tIFwiLi9zZXR0aW5nc1wiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3NUYWIgZXh0ZW5kcyBQbHVnaW5TZXR0aW5nVGFiIHtcclxuXHJcbiAgICBwbHVnaW46IFNpbXBsZVRpbWVUcmFja2VyUGx1Z2luO1xyXG5cclxuICAgIGNvbnN0cnVjdG9yKGFwcDogQXBwLCBwbHVnaW46IFNpbXBsZVRpbWVUcmFja2VyUGx1Z2luKSB7XHJcbiAgICAgICAgc3VwZXIoYXBwLCBwbHVnaW4pO1xyXG4gICAgICAgIHRoaXMucGx1Z2luID0gcGx1Z2luO1xyXG4gICAgfVxyXG5cclxuICAgIGRpc3BsYXkoKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5jb250YWluZXJFbC5lbXB0eSgpO1xyXG4gICAgICAgIHRoaXMuY29udGFpbmVyRWwuY3JlYXRlRWwoXCJoMlwiLCB7dGV4dDogXCJTdXBlciBTaW1wbGUgVGltZSBUcmFja2VyIFNldHRpbmdzXCJ9KTtcclxuXHJcbiAgICAgICAgbmV3IFNldHRpbmcodGhpcy5jb250YWluZXJFbClcclxuICAgICAgICAgICAgLnNldE5hbWUoXCJUaW1lc3RhbXAgRGlzcGxheSBGb3JtYXRcIilcclxuICAgICAgICAgICAgLnNldERlc2MoY3JlYXRlRnJhZ21lbnQoZiA9PiB7XHJcbiAgICAgICAgICAgICAgICBmLmNyZWF0ZVNwYW4oe3RleHQ6IFwiVGhlIHdheSB0aGF0IHRpbWVzdGFtcHMgaW4gdGltZSB0cmFja2VyIHRhYmxlcyBzaG91bGQgYmUgZGlzcGxheWVkLiBVc2VzIFwifSk7XHJcbiAgICAgICAgICAgICAgICBmLmNyZWF0ZUVsKFwiYVwiLCB7dGV4dDogXCJtb21lbnQuanNcIiwgaHJlZjogXCJodHRwczovL21vbWVudGpzLmNvbS9kb2NzLyMvcGFyc2luZy9zdHJpbmctZm9ybWF0L1wifSk7XHJcbiAgICAgICAgICAgICAgICBmLmNyZWF0ZVNwYW4oe3RleHQ6IFwiIHN5bnRheC5cIn0pO1xyXG4gICAgICAgICAgICB9KSlcclxuICAgICAgICAgICAgLmFkZFRleHQodCA9PiB7XHJcbiAgICAgICAgICAgICAgICB0LnNldFZhbHVlKFN0cmluZyh0aGlzLnBsdWdpbi5zZXR0aW5ncy50aW1lc3RhbXBGb3JtYXQpKTtcclxuICAgICAgICAgICAgICAgIHQub25DaGFuZ2UoYXN5bmMgdiA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3MudGltZXN0YW1wRm9ybWF0ID0gdi5sZW5ndGggPyB2IDogZGVmYXVsdFNldHRpbmdzLnRpbWVzdGFtcEZvcm1hdDtcclxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgbmV3IFNldHRpbmcodGhpcy5jb250YWluZXJFbClcclxuICAgICAgICAgICAgLnNldE5hbWUoXCJDU1YgRGVsaW1pdGVyXCIpXHJcbiAgICAgICAgICAgIC5zZXREZXNjKFwiVGhlIGRlbGltaXRlciBjaGFyYWN0ZXIgdGhhdCBzaG91bGQgYmUgdXNlZCB3aGVuIGNvcHlpbmcgYSB0cmFja2VyIHRhYmxlIGFzIENTVi4gRm9yIGV4YW1wbGUsIHNvbWUgbGFuZ3VhZ2VzIHVzZSBhIHNlbWljb2xvbiBpbnN0ZWFkIG9mIGEgY29tbWEuXCIpXHJcbiAgICAgICAgICAgIC5hZGRUZXh0KHQgPT4ge1xyXG4gICAgICAgICAgICAgICAgdC5zZXRWYWx1ZShTdHJpbmcodGhpcy5wbHVnaW4uc2V0dGluZ3MuY3N2RGVsaW1pdGVyKSk7XHJcbiAgICAgICAgICAgICAgICB0Lm9uQ2hhbmdlKGFzeW5jIHYgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLnNldHRpbmdzLmNzdkRlbGltaXRlciA9IHYubGVuZ3RoID8gdiA6IGRlZmF1bHRTZXR0aW5ncy5jc3ZEZWxpbWl0ZXI7XHJcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XHJcbiAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIHRoaXMuY29udGFpbmVyRWwuY3JlYXRlRWwoXCJoclwiKTtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lckVsLmNyZWF0ZUVsKFwicFwiLCB7dGV4dDogXCJJZiB5b3UgbGlrZSB0aGlzIHBsdWdpbiBhbmQgd2FudCB0byBzdXBwb3J0IGl0cyBkZXZlbG9wbWVudCwgeW91IGNhbiBkbyBzbyB0aHJvdWdoIG15IHdlYnNpdGUgYnkgY2xpY2tpbmcgdGhpcyBmYW5jeSBpbWFnZSFcIn0pO1xyXG4gICAgICAgIHRoaXMuY29udGFpbmVyRWwuY3JlYXRlRWwoXCJhXCIsIHtocmVmOiBcImh0dHBzOi8vZWxscGVjay5kZS9zdXBwb3J0XCJ9KVxyXG4gICAgICAgICAgICAuY3JlYXRlRWwoXCJpbWdcIiwge1xyXG4gICAgICAgICAgICAgICAgYXR0cjoge3NyYzogXCJodHRwczovL2VsbHBlY2suZGUvcmVzL2dlbmVyYWxzdXBwb3J0LnBuZ1wifSxcclxuICAgICAgICAgICAgICAgIGNsczogXCJzaW1wbGUtdGltZS10cmFja2VyLXN1cHBvcnRcIlxyXG4gICAgICAgICAgICB9KTtcclxuICAgIH1cclxufVxyXG4iLCAiaW1wb3J0IHsgbW9tZW50LCBBcHAsIE1hcmtkb3duU2VjdGlvbkluZm9ybWF0aW9uLCBCdXR0b25Db21wb25lbnQsIFRleHRDb21wb25lbnQsIFRGaWxlIH0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCB7IFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3MgfSBmcm9tIFwiLi9zZXR0aW5nc1wiO1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBUcmFja2VyIHtcclxuICAgIGVudHJpZXM6IEVudHJ5W107XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgRW50cnkge1xyXG4gICAgbmFtZTogc3RyaW5nO1xyXG4gICAgc3RhcnRUaW1lOiBudW1iZXI7XHJcbiAgICBlbmRUaW1lOiBudW1iZXI7XHJcbiAgICBzdWJFbnRyaWVzOiBFbnRyeVtdO1xyXG59XHJcblxyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2F2ZVRyYWNrZXIodHJhY2tlcjogVHJhY2tlciwgYXBwOiBBcHAsIGZpbGVOYW1lOiBzdHJpbmcsIHNlY3Rpb246IE1hcmtkb3duU2VjdGlvbkluZm9ybWF0aW9uKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICBsZXQgZmlsZSA9IGFwcC52YXVsdC5nZXRBYnN0cmFjdEZpbGVCeVBhdGgoZmlsZU5hbWUpIGFzIFRGaWxlO1xyXG4gICAgaWYgKCFmaWxlKVxyXG4gICAgICAgIHJldHVybjtcclxuICAgIGxldCBjb250ZW50ID0gYXdhaXQgYXBwLnZhdWx0LnJlYWQoZmlsZSk7XHJcblxyXG4gICAgLy8gZmlndXJlIG91dCB3aGF0IHBhcnQgb2YgdGhlIGNvbnRlbnQgd2UgaGF2ZSB0byBlZGl0XHJcbiAgICBsZXQgbGluZXMgPSBjb250ZW50LnNwbGl0KFwiXFxuXCIpO1xyXG4gICAgbGV0IHByZXYgPSBsaW5lcy5maWx0ZXIoKF8sIGkpID0+IGkgPD0gc2VjdGlvbi5saW5lU3RhcnQpLmpvaW4oXCJcXG5cIik7XHJcbiAgICBsZXQgbmV4dCA9IGxpbmVzLmZpbHRlcigoXywgaSkgPT4gaSA+PSBzZWN0aW9uLmxpbmVFbmQpLmpvaW4oXCJcXG5cIik7XHJcbiAgICAvLyBlZGl0IG9ubHkgdGhlIGNvZGUgYmxvY2sgY29udGVudCwgbGVhdmUgdGhlIHJlc3QgdW50b3VjaGVkXHJcbiAgICBjb250ZW50ID0gYCR7cHJldn1cXG4ke0pTT04uc3RyaW5naWZ5KHRyYWNrZXIpfVxcbiR7bmV4dH1gO1xyXG5cclxuICAgIGF3YWl0IGFwcC52YXVsdC5tb2RpZnkoZmlsZSwgY29udGVudCk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBsb2FkVHJhY2tlcihqc29uOiBzdHJpbmcpOiBUcmFja2VyIHtcclxuICAgIGlmIChqc29uKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoanNvbik7XHJcbiAgICAgICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgRmFpbGVkIHRvIHBhcnNlIFRyYWNrZXIgZnJvbSAke2pzb259YCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIHtlbnRyaWVzOiBbXX07XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBkaXNwbGF5VHJhY2tlcih0cmFja2VyOiBUcmFja2VyLCBlbGVtZW50OiBIVE1MRWxlbWVudCwgZmlsZTogc3RyaW5nLCBnZXRTZWN0aW9uSW5mbzogKCkgPT4gTWFya2Rvd25TZWN0aW9uSW5mb3JtYXRpb24sIHNldHRpbmdzOiBTaW1wbGVUaW1lVHJhY2tlclNldHRpbmdzKTogdm9pZCB7XHJcbiAgICAvLyBhZGQgc3RhcnQvc3RvcCBjb250cm9sc1xyXG4gICAgbGV0IHJ1bm5pbmcgPSBpc1J1bm5pbmcodHJhY2tlcik7XHJcbiAgICBsZXQgYnRuID0gbmV3IEJ1dHRvbkNvbXBvbmVudChlbGVtZW50KVxyXG4gICAgICAgIC5zZXRDbGFzcyhcImNsaWNrYWJsZS1pY29uXCIpXHJcbiAgICAgICAgLnNldEljb24oYGx1Y2lkZS0ke3J1bm5pbmcgPyBcInN0b3BcIiA6IFwicGxheVwifS1jaXJjbGVgKVxyXG4gICAgICAgIC5zZXRUb29sdGlwKHJ1bm5pbmcgPyBcIkVuZFwiIDogXCJTdGFydFwiKVxyXG4gICAgICAgIC5vbkNsaWNrKGFzeW5jICgpID0+IHtcclxuICAgICAgICAgICAgaWYgKHJ1bm5pbmcpIHtcclxuICAgICAgICAgICAgICAgIGVuZFJ1bm5pbmdFbnRyeSh0cmFja2VyKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIHN0YXJ0TmV3RW50cnkodHJhY2tlciwgbmV3U2VnbWVudE5hbWVCb3guZ2V0VmFsdWUoKSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgYXdhaXQgc2F2ZVRyYWNrZXIodHJhY2tlciwgdGhpcy5hcHAsIGZpbGUsIGdldFNlY3Rpb25JbmZvKCkpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgYnRuLmJ1dHRvbkVsLmFkZENsYXNzKFwic2ltcGxlLXRpbWUtdHJhY2tlci1idG5cIik7XHJcbiAgICBsZXQgbmV3U2VnbWVudE5hbWVCb3ggPSBuZXcgVGV4dENvbXBvbmVudChlbGVtZW50KVxyXG4gICAgICAgIC5zZXRQbGFjZWhvbGRlcihcIlNlZ21lbnQgbmFtZVwiKVxyXG4gICAgICAgIC5zZXREaXNhYmxlZChydW5uaW5nKTtcclxuICAgIG5ld1NlZ21lbnROYW1lQm94LmlucHV0RWwuYWRkQ2xhc3MoXCJzaW1wbGUtdGltZS10cmFja2VyLXR4dFwiKTtcclxuXHJcbiAgICAvLyBhZGQgdGltZXJzXHJcbiAgICBsZXQgdGltZXIgPSBlbGVtZW50LmNyZWF0ZURpdih7Y2xzOiBcInNpbXBsZS10aW1lLXRyYWNrZXItdGltZXJzXCJ9KTtcclxuICAgIGxldCBjdXJyZW50RGl2ID0gdGltZXIuY3JlYXRlRWwoXCJkaXZcIiwge2NsczogXCJzaW1wbGUtdGltZS10cmFja2VyLXRpbWVyXCJ9KTtcclxuICAgIGxldCBjdXJyZW50ID0gY3VycmVudERpdi5jcmVhdGVFbChcInNwYW5cIiwge2NsczogXCJzaW1wbGUtdGltZS10cmFja2VyLXRpbWVyLXRpbWVcIn0pO1xyXG4gICAgY3VycmVudERpdi5jcmVhdGVFbChcInNwYW5cIiwge3RleHQ6IFwiQ3VycmVudFwifSk7XHJcbiAgICBsZXQgdG90YWxEaXYgPSB0aW1lci5jcmVhdGVFbChcImRpdlwiLCB7Y2xzOiBcInNpbXBsZS10aW1lLXRyYWNrZXItdGltZXJcIn0pO1xyXG4gICAgbGV0IHRvdGFsID0gdG90YWxEaXYuY3JlYXRlRWwoXCJzcGFuXCIsIHtjbHM6IFwic2ltcGxlLXRpbWUtdHJhY2tlci10aW1lci10aW1lXCIsIHRleHQ6IFwiMHNcIn0pO1xyXG4gICAgdG90YWxEaXYuY3JlYXRlRWwoXCJzcGFuXCIsIHt0ZXh0OiBcIlRvdGFsXCJ9KTtcclxuXHJcbiAgICBpZiAodHJhY2tlci5lbnRyaWVzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAvLyBhZGQgdGFibGVcclxuICAgICAgICBsZXQgdGFibGUgPSBlbGVtZW50LmNyZWF0ZUVsKFwidGFibGVcIiwge2NsczogXCJzaW1wbGUtdGltZS10cmFja2VyLXRhYmxlXCJ9KTtcclxuICAgICAgICB0YWJsZS5jcmVhdGVFbChcInRyXCIpLmFwcGVuZChcclxuICAgICAgICAgICAgY3JlYXRlRWwoXCJ0aFwiLCB7dGV4dDogXCJTZWdtZW50XCJ9KSxcclxuICAgICAgICAgICAgY3JlYXRlRWwoXCJ0aFwiLCB7dGV4dDogXCJTdGFydCB0aW1lXCJ9KSxcclxuICAgICAgICAgICAgY3JlYXRlRWwoXCJ0aFwiLCB7dGV4dDogXCJFbmQgdGltZVwifSksXHJcbiAgICAgICAgICAgIGNyZWF0ZUVsKFwidGhcIiwge3RleHQ6IFwiRHVyYXRpb25cIn0pLFxyXG4gICAgICAgICAgICBjcmVhdGVFbChcInRoXCIpKTtcclxuXHJcbiAgICAgICAgZm9yIChsZXQgZW50cnkgb2YgdHJhY2tlci5lbnRyaWVzKVxyXG4gICAgICAgICAgICBhZGRFZGl0YWJsZVRhYmxlUm93KHRyYWNrZXIsIGVudHJ5LCB0YWJsZSwgbmV3U2VnbWVudE5hbWVCb3gsIHJ1bm5pbmcsIGZpbGUsIGdldFNlY3Rpb25JbmZvLCBzZXR0aW5ncywgMCk7XHJcblxyXG4gICAgICAgIC8vIGFkZCBjb3B5IGJ1dHRvbnNcclxuICAgICAgICBsZXQgYnV0dG9ucyA9IGVsZW1lbnQuY3JlYXRlRWwoXCJkaXZcIiwge2NsczogXCJzaW1wbGUtdGltZS10cmFja2VyLWJvdHRvbVwifSk7XHJcbiAgICAgICAgbmV3IEJ1dHRvbkNvbXBvbmVudChidXR0b25zKVxyXG4gICAgICAgICAgICAuc2V0QnV0dG9uVGV4dChcIkNvcHkgYXMgdGFibGVcIilcclxuICAgICAgICAgICAgLm9uQ2xpY2soKCkgPT4gbmF2aWdhdG9yLmNsaXBib2FyZC53cml0ZVRleHQoY3JlYXRlTWFya2Rvd25UYWJsZSh0cmFja2VyLCBzZXR0aW5ncykpKTtcclxuICAgICAgICBuZXcgQnV0dG9uQ29tcG9uZW50KGJ1dHRvbnMpXHJcbiAgICAgICAgICAgIC5zZXRCdXR0b25UZXh0KFwiQ29weSBhcyBDU1ZcIilcclxuICAgICAgICAgICAgLm9uQ2xpY2soKCkgPT4gbmF2aWdhdG9yLmNsaXBib2FyZC53cml0ZVRleHQoY3JlYXRlQ3N2KHRyYWNrZXIsIHNldHRpbmdzKSkpO1xyXG4gICAgfVxyXG5cclxuXHJcbiAgICBzZXRDb3VudGRvd25WYWx1ZXModHJhY2tlciwgY3VycmVudCwgdG90YWwsIGN1cnJlbnREaXYpO1xyXG4gICAgbGV0IGludGVydmFsSWQgPSB3aW5kb3cuc2V0SW50ZXJ2YWwoKCkgPT4ge1xyXG4gICAgICAgIC8vIHdlIGRlbGV0ZSB0aGUgaW50ZXJ2YWwgdGltZXIgd2hlbiB0aGUgZWxlbWVudCBpcyByZW1vdmVkXHJcbiAgICAgICAgaWYgKCFlbGVtZW50LmlzQ29ubmVjdGVkKSB7XHJcbiAgICAgICAgICAgIHdpbmRvdy5jbGVhckludGVydmFsKGludGVydmFsSWQpO1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHNldENvdW50ZG93blZhbHVlcyh0cmFja2VyLCBjdXJyZW50LCB0b3RhbCwgY3VycmVudERpdik7XHJcbiAgICB9LCAxMDAwKTtcclxufVxyXG5cclxuZnVuY3Rpb24gc3RhcnRTdWJFbnRyeShlbnRyeTogRW50cnksIG5hbWU6IHN0cmluZykge1xyXG4gICAgLy8gaWYgdGhpcyBlbnRyeSBpcyBub3Qgc3BsaXQgeWV0LCB3ZSBhZGQgaXRzIHRpbWUgYXMgYSBzdWItZW50cnkgaW5zdGVhZFxyXG4gICAgaWYgKCFlbnRyeS5zdWJFbnRyaWVzKSB7XHJcbiAgICAgICAgZW50cnkuc3ViRW50cmllcyA9IFt7Li4uZW50cnksIG5hbWU6IGBQYXJ0IDFgfV07XHJcbiAgICAgICAgZW50cnkuc3RhcnRUaW1lID0gbnVsbDtcclxuICAgICAgICBlbnRyeS5lbmRUaW1lID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIW5hbWUpXHJcbiAgICAgICAgbmFtZSA9IGBQYXJ0ICR7ZW50cnkuc3ViRW50cmllcy5sZW5ndGggKyAxfWA7XHJcbiAgICBlbnRyeS5zdWJFbnRyaWVzLnB1c2goe25hbWU6IG5hbWUsIHN0YXJ0VGltZTogbW9tZW50KCkudW5peCgpLCBlbmRUaW1lOiBudWxsLCBzdWJFbnRyaWVzOiBudWxsfSk7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIHN0YXJ0TmV3RW50cnkodHJhY2tlcjogVHJhY2tlciwgbmFtZTogc3RyaW5nKTogdm9pZCB7XHJcbiAgICBpZiAoIW5hbWUpXHJcbiAgICAgICAgbmFtZSA9IGBTZWdtZW50ICR7dHJhY2tlci5lbnRyaWVzLmxlbmd0aCArIDF9YDtcclxuICAgIGxldCBlbnRyeTogRW50cnkgPSB7bmFtZTogbmFtZSwgc3RhcnRUaW1lOiBtb21lbnQoKS51bml4KCksIGVuZFRpbWU6IG51bGwsIHN1YkVudHJpZXM6IG51bGx9O1xyXG4gICAgdHJhY2tlci5lbnRyaWVzLnB1c2goZW50cnkpO1xyXG59XHJcblxyXG5mdW5jdGlvbiBlbmRSdW5uaW5nRW50cnkodHJhY2tlcjogVHJhY2tlcik6IHZvaWQge1xyXG4gICAgbGV0IGVudHJ5ID0gZ2V0UnVubmluZ0VudHJ5KHRyYWNrZXIuZW50cmllcyk7XHJcbiAgICBlbnRyeS5lbmRUaW1lID0gbW9tZW50KCkudW5peCgpO1xyXG59XHJcblxyXG5mdW5jdGlvbiByZW1vdmVFbnRyeShlbnRyaWVzOiBFbnRyeVtdLCB0b1JlbW92ZTogRW50cnkpOiBib29sZWFuIHtcclxuICAgIGlmIChlbnRyaWVzLmNvbnRhaW5zKHRvUmVtb3ZlKSkge1xyXG4gICAgICAgIGVudHJpZXMucmVtb3ZlKHRvUmVtb3ZlKTtcclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgICAgZm9yIChsZXQgZW50cnkgb2YgZW50cmllcykge1xyXG4gICAgICAgICAgICBpZiAoZW50cnkuc3ViRW50cmllcyAmJiByZW1vdmVFbnRyeShlbnRyeS5zdWJFbnRyaWVzLCB0b1JlbW92ZSkpIHtcclxuICAgICAgICAgICAgICAgIC8vIGlmIHdlIG9ubHkgaGF2ZSBvbmUgc3ViIGVudHJ5IHJlbWFpbmluZywgd2UgY2FuIG1lcmdlIGJhY2sgaW50byBvdXIgbWFpbiBlbnRyeVxyXG4gICAgICAgICAgICAgICAgaWYgKGVudHJ5LnN1YkVudHJpZXMubGVuZ3RoID09IDEpIHtcclxuICAgICAgICAgICAgICAgICAgICBsZXQgc2luZ2xlID0gZW50cnkuc3ViRW50cmllc1swXTtcclxuICAgICAgICAgICAgICAgICAgICBlbnRyeS5zdGFydFRpbWUgPSBzaW5nbGUuc3RhcnRUaW1lO1xyXG4gICAgICAgICAgICAgICAgICAgIGVudHJ5LmVuZFRpbWUgPSBzaW5nbGUuZW5kVGltZTtcclxuICAgICAgICAgICAgICAgICAgICBlbnRyeS5zdWJFbnRyaWVzID0gbnVsbDtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG59XHJcblxyXG5mdW5jdGlvbiBpc1J1bm5pbmcodHJhY2tlcjogVHJhY2tlcik6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuICEhZ2V0UnVubmluZ0VudHJ5KHRyYWNrZXIuZW50cmllcyk7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGdldFJ1bm5pbmdFbnRyeShlbnRyaWVzOiBFbnRyeVtdKTogRW50cnkge1xyXG4gICAgZm9yIChsZXQgZW50cnkgb2YgZW50cmllcykge1xyXG4gICAgICAgIC8vIGlmIHRoaXMgZW50cnkgaGFzIHN1YiBlbnRyaWVzLCBjaGVjayBpZiBvbmUgb2YgdGhlbSBpcyBydW5uaW5nXHJcbiAgICAgICAgaWYgKGVudHJ5LnN1YkVudHJpZXMpIHtcclxuICAgICAgICAgICAgbGV0IHJ1bm5pbmcgPSBnZXRSdW5uaW5nRW50cnkoZW50cnkuc3ViRW50cmllcyk7XHJcbiAgICAgICAgICAgIGlmIChydW5uaW5nKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bm5pbmc7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gaWYgdGhpcyBlbnRyeSBoYXMgbm8gc3ViIGVudHJpZXMgYW5kIG5vIGVuZCB0aW1lLCBpdCdzIHJ1bm5pbmdcclxuICAgICAgICAgICAgaWYgKCFlbnRyeS5lbmRUaW1lKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGVudHJ5O1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiBudWxsO1xyXG59XHJcblxyXG5mdW5jdGlvbiBnZXREdXJhdGlvbihlbnRyeTogRW50cnkpIHtcclxuICAgIGlmIChlbnRyeS5zdWJFbnRyaWVzKSB7XHJcbiAgICAgICAgcmV0dXJuIGdldFRvdGFsRHVyYXRpb24oZW50cnkuc3ViRW50cmllcyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxldCBlbmRUaW1lID0gZW50cnkuZW5kVGltZSA/IG1vbWVudC51bml4KGVudHJ5LmVuZFRpbWUpIDogbW9tZW50KCk7XHJcbiAgICAgICAgcmV0dXJuIGVuZFRpbWUuZGlmZihtb21lbnQudW5peChlbnRyeS5zdGFydFRpbWUpKTtcclxuICAgIH1cclxufVxyXG5cclxuZnVuY3Rpb24gZ2V0VG90YWxEdXJhdGlvbihlbnRyaWVzOiBFbnRyeVtdKTogbnVtYmVyIHtcclxuICAgIGxldCByZXQgPSAwO1xyXG4gICAgZm9yIChsZXQgZW50cnkgb2YgZW50cmllcylcclxuICAgICAgICByZXQgKz0gZ2V0RHVyYXRpb24oZW50cnkpO1xyXG4gICAgcmV0dXJuIHJldDtcclxufVxyXG5cclxuZnVuY3Rpb24gc2V0Q291bnRkb3duVmFsdWVzKHRyYWNrZXI6IFRyYWNrZXIsIGN1cnJlbnQ6IEhUTUxFbGVtZW50LCB0b3RhbDogSFRNTEVsZW1lbnQsIGN1cnJlbnREaXY6IEhUTUxEaXZFbGVtZW50KSB7XHJcbiAgICBsZXQgcnVubmluZyA9IGdldFJ1bm5pbmdFbnRyeSh0cmFja2VyLmVudHJpZXMpO1xyXG4gICAgaWYgKHJ1bm5pbmcgJiYgIXJ1bm5pbmcuZW5kVGltZSkge1xyXG4gICAgICAgIGN1cnJlbnQuc2V0VGV4dChmb3JtYXREdXJhdGlvbihnZXREdXJhdGlvbihydW5uaW5nKSkpO1xyXG4gICAgICAgIGN1cnJlbnREaXYuaGlkZGVuID0gZmFsc2U7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAgIGN1cnJlbnREaXYuaGlkZGVuID0gdHJ1ZTtcclxuICAgIH1cclxuICAgIHRvdGFsLnNldFRleHQoZm9ybWF0RHVyYXRpb24oZ2V0VG90YWxEdXJhdGlvbih0cmFja2VyLmVudHJpZXMpKSk7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGZvcm1hdFRpbWVzdGFtcCh0aW1lc3RhbXA6IG51bWJlciwgc2V0dGluZ3M6IFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3MpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIG1vbWVudC51bml4KHRpbWVzdGFtcCkuZm9ybWF0KHNldHRpbmdzLnRpbWVzdGFtcEZvcm1hdCk7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGZvcm1hdER1cmF0aW9uKHRvdGFsVGltZTogbnVtYmVyKTogc3RyaW5nIHtcclxuICAgIGxldCBkdXJhdGlvbiA9IG1vbWVudC5kdXJhdGlvbih0b3RhbFRpbWUpO1xyXG4gICAgbGV0IHJldCA9IFwiXCI7XHJcbiAgICBpZiAoZHVyYXRpb24ueWVhcnMoKSA+IDApXHJcbiAgICAgICAgcmV0ICs9IGR1cmF0aW9uLnllYXJzKCkgKyBcInkgXCI7XHJcbiAgICBpZiAoZHVyYXRpb24ubW9udGhzKCkgPiAwKVxyXG4gICAgICAgIHJldCArPSBkdXJhdGlvbi5tb250aHMoKSArIFwibSBcIjtcclxuICAgIGlmIChkdXJhdGlvbi5kYXlzKCkgPiAwKVxyXG4gICAgICAgIHJldCArPSBkdXJhdGlvbi5kYXlzKCkgKyBcImQgXCI7XHJcbiAgICBpZiAoZHVyYXRpb24uaG91cnMoKSA+IDApXHJcbiAgICAgICAgcmV0ICs9IGR1cmF0aW9uLmhvdXJzKCkgKyBcImggXCI7XHJcbiAgICBpZiAoZHVyYXRpb24ubWludXRlcygpID4gMClcclxuICAgICAgICByZXQgKz0gZHVyYXRpb24ubWludXRlcygpICsgXCJtIFwiO1xyXG4gICAgcmV0ICs9IGR1cmF0aW9uLnNlY29uZHMoKSArIFwic1wiO1xyXG4gICAgcmV0dXJuIHJldDtcclxufVxyXG5cclxuZnVuY3Rpb24gY3JlYXRlTWFya2Rvd25UYWJsZSh0cmFja2VyOiBUcmFja2VyLCBzZXR0aW5nczogU2ltcGxlVGltZVRyYWNrZXJTZXR0aW5ncyk6IHN0cmluZyB7XHJcbiAgICBsZXQgdGFibGUgPSBbW1wiU2VnbWVudFwiLCBcIlN0YXJ0IHRpbWVcIiwgXCJFbmQgdGltZVwiLCBcIkR1cmF0aW9uXCJdXTtcclxuICAgIGZvciAobGV0IGVudHJ5IG9mIHRyYWNrZXIuZW50cmllcylcclxuICAgICAgICB0YWJsZS5wdXNoKC4uLmNyZWF0ZVRhYmxlU2VjdGlvbihlbnRyeSwgc2V0dGluZ3MpKTtcclxuICAgIHRhYmxlLnB1c2goW1wiKipUb3RhbCoqXCIsIFwiXCIsIFwiXCIsIGAqKiR7Zm9ybWF0RHVyYXRpb24oZ2V0VG90YWxEdXJhdGlvbih0cmFja2VyLmVudHJpZXMpKX0qKmBdKTtcclxuXHJcbiAgICBsZXQgcmV0ID0gXCJcIjtcclxuICAgIC8vIGNhbGN1bGF0ZSB0aGUgd2lkdGggZXZlcnkgY29sdW1uIG5lZWRzIHRvIGxvb2sgbmVhdCB3aGVuIG1vbm9zcGFjZWRcclxuICAgIGxldCB3aWR0aHMgPSBBcnJheS5mcm9tKEFycmF5KDQpLmtleXMoKSkubWFwKGkgPT4gTWF0aC5tYXgoLi4udGFibGUubWFwKGEgPT4gYVtpXS5sZW5ndGgpKSk7XHJcbiAgICBmb3IgKGxldCByID0gMDsgciA8IHRhYmxlLmxlbmd0aDsgcisrKSB7XHJcbiAgICAgICAgLy8gYWRkIHNlcGFyYXRvcnMgYWZ0ZXIgZmlyc3Qgcm93XHJcbiAgICAgICAgaWYgKHIgPT0gMSlcclxuICAgICAgICAgICAgcmV0ICs9IEFycmF5LmZyb20oQXJyYXkoNCkua2V5cygpKS5tYXAoaSA9PiBcIi1cIi5yZXBlYXQod2lkdGhzW2ldKSkuam9pbihcIiB8IFwiKSArIFwiXFxuXCI7XHJcblxyXG4gICAgICAgIGxldCByb3c6IHN0cmluZ1tdID0gW107XHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCA0OyBpKyspXHJcbiAgICAgICAgICAgIHJvdy5wdXNoKHRhYmxlW3JdW2ldLnBhZEVuZCh3aWR0aHNbaV0sIFwiIFwiKSk7XHJcbiAgICAgICAgcmV0ICs9IHJvdy5qb2luKFwiIHwgXCIpICsgXCJcXG5cIjtcclxuICAgIH1cclxuICAgIHJldHVybiByZXQ7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNyZWF0ZUNzdih0cmFja2VyOiBUcmFja2VyLCBzZXR0aW5nczogU2ltcGxlVGltZVRyYWNrZXJTZXR0aW5ncyk6IHN0cmluZyB7XHJcbiAgICBsZXQgcmV0ID0gXCJcIjtcclxuICAgIGZvciAobGV0IGVudHJ5IG9mIHRyYWNrZXIuZW50cmllcykge1xyXG4gICAgICAgIGZvciAobGV0IHJvdyBvZiBjcmVhdGVUYWJsZVNlY3Rpb24oZW50cnksIHNldHRpbmdzKSlcclxuICAgICAgICAgICAgcmV0ICs9IHJvdy5qb2luKHNldHRpbmdzLmNzdkRlbGltaXRlcikgKyBcIlxcblwiO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHJldDtcclxufVxyXG5cclxuZnVuY3Rpb24gY3JlYXRlVGFibGVTZWN0aW9uKGVudHJ5OiBFbnRyeSwgc2V0dGluZ3M6IFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3MpOiBzdHJpbmdbXVtdIHtcclxuICAgIGxldCByZXQ6IHN0cmluZ1tdW10gPSBbW1xyXG4gICAgICAgIGVudHJ5Lm5hbWUsXHJcbiAgICAgICAgZW50cnkuc3RhcnRUaW1lID8gZm9ybWF0VGltZXN0YW1wKGVudHJ5LnN0YXJ0VGltZSwgc2V0dGluZ3MpIDogXCJcIixcclxuICAgICAgICBlbnRyeS5lbmRUaW1lID8gZm9ybWF0VGltZXN0YW1wKGVudHJ5LmVuZFRpbWUsIHNldHRpbmdzKSA6IFwiXCIsXHJcbiAgICAgICAgZW50cnkuZW5kVGltZSB8fCBlbnRyeS5zdWJFbnRyaWVzID8gZm9ybWF0RHVyYXRpb24oZ2V0RHVyYXRpb24oZW50cnkpKSA6IFwiXCJdXTtcclxuICAgIGlmIChlbnRyeS5zdWJFbnRyaWVzKSB7XHJcbiAgICAgICAgZm9yIChsZXQgc3ViIG9mIGVudHJ5LnN1YkVudHJpZXMpXHJcbiAgICAgICAgICAgIHJldC5wdXNoKC4uLmNyZWF0ZVRhYmxlU2VjdGlvbihzdWIsIHNldHRpbmdzKSk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gcmV0O1xyXG59XHJcblxyXG5mdW5jdGlvbiBhZGRFZGl0YWJsZVRhYmxlUm93KHRyYWNrZXI6IFRyYWNrZXIsIGVudHJ5OiBFbnRyeSwgdGFibGU6IEhUTUxUYWJsZUVsZW1lbnQsIG5ld1NlZ21lbnROYW1lQm94OiBUZXh0Q29tcG9uZW50LCBydW5uaW5nOiBib29sZWFuLCBmaWxlOiBzdHJpbmcsIGdldFNlY3Rpb25JbmZvOiAoKSA9PiBNYXJrZG93blNlY3Rpb25JbmZvcm1hdGlvbiwgc2V0dGluZ3M6IFNpbXBsZVRpbWVUcmFja2VyU2V0dGluZ3MsIGluZGVudDogbnVtYmVyKSB7XHJcbiAgICBsZXQgcm93ID0gdGFibGUuY3JlYXRlRWwoXCJ0clwiKTtcclxuXHJcbiAgICBsZXQgbmFtZSA9IHJvdy5jcmVhdGVFbChcInRkXCIpO1xyXG4gICAgbGV0IG5hbWVQYXIgPSBuYW1lLmNyZWF0ZUVsKFwic3BhblwiLCB7dGV4dDogZW50cnkubmFtZX0pO1xyXG4gICAgbmFtZVBhci5zdHlsZS5tYXJnaW5MZWZ0ID0gYCR7aW5kZW50fWVtYDtcclxuICAgIGxldCBuYW1lQm94ID0gbmV3IFRleHRDb21wb25lbnQobmFtZSkuc2V0VmFsdWUoZW50cnkubmFtZSk7XHJcbiAgICBuYW1lQm94LmlucHV0RWwuaGlkZGVuID0gdHJ1ZTtcclxuXHJcbiAgICByb3cuY3JlYXRlRWwoXCJ0ZFwiLCB7dGV4dDogZW50cnkuc3RhcnRUaW1lID8gZm9ybWF0VGltZXN0YW1wKGVudHJ5LnN0YXJ0VGltZSwgc2V0dGluZ3MpIDogXCJcIn0pO1xyXG4gICAgcm93LmNyZWF0ZUVsKFwidGRcIiwge3RleHQ6IGVudHJ5LmVuZFRpbWUgPyBmb3JtYXRUaW1lc3RhbXAoZW50cnkuZW5kVGltZSwgc2V0dGluZ3MpIDogXCJcIn0pO1xyXG4gICAgcm93LmNyZWF0ZUVsKFwidGRcIiwge3RleHQ6IGVudHJ5LmVuZFRpbWUgfHwgZW50cnkuc3ViRW50cmllcyA/IGZvcm1hdER1cmF0aW9uKGdldER1cmF0aW9uKGVudHJ5KSkgOiBcIlwifSk7XHJcblxyXG4gICAgbGV0IGVudHJ5QnV0dG9ucyA9IHJvdy5jcmVhdGVFbChcInRkXCIpO1xyXG4gICAgaWYgKCFydW5uaW5nKSB7XHJcbiAgICAgICAgbmV3IEJ1dHRvbkNvbXBvbmVudChlbnRyeUJ1dHRvbnMpXHJcbiAgICAgICAgICAgIC5zZXRDbGFzcyhcImNsaWNrYWJsZS1pY29uXCIpXHJcbiAgICAgICAgICAgIC5zZXRJY29uKGBsdWNpZGUtcGxheWApXHJcbiAgICAgICAgICAgIC5zZXRUb29sdGlwKFwiQ29udGludWVcIilcclxuICAgICAgICAgICAgLm9uQ2xpY2soYXN5bmMgKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgc3RhcnRTdWJFbnRyeShlbnRyeSwgbmV3U2VnbWVudE5hbWVCb3guZ2V0VmFsdWUoKSk7XHJcbiAgICAgICAgICAgICAgICBhd2FpdCBzYXZlVHJhY2tlcih0cmFja2VyLCB0aGlzLmFwcCwgZmlsZSwgZ2V0U2VjdGlvbkluZm8oKSk7XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgbGV0IGVkaXRCdXR0b24gPSBuZXcgQnV0dG9uQ29tcG9uZW50KGVudHJ5QnV0dG9ucylcclxuICAgICAgICAuc2V0Q2xhc3MoXCJjbGlja2FibGUtaWNvblwiKVxyXG4gICAgICAgIC5zZXRUb29sdGlwKFwiRWRpdFwiKVxyXG4gICAgICAgIC5zZXRJY29uKFwibHVjaWRlLXBlbmNpbFwiKVxyXG4gICAgICAgIC5vbkNsaWNrKGFzeW5jICgpID0+IHtcclxuICAgICAgICAgICAgaWYgKG5hbWVQYXIuaGlkZGVuKSB7XHJcbiAgICAgICAgICAgICAgICBuYW1lUGFyLmhpZGRlbiA9IGZhbHNlO1xyXG4gICAgICAgICAgICAgICAgbmFtZUJveC5pbnB1dEVsLmhpZGRlbiA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICBlZGl0QnV0dG9uLnNldEljb24oXCJsdWNpZGUtcGVuY2lsXCIpO1xyXG4gICAgICAgICAgICAgICAgaWYgKG5hbWVCb3guZ2V0VmFsdWUoKSkge1xyXG4gICAgICAgICAgICAgICAgICAgIGVudHJ5Lm5hbWUgPSBuYW1lQm94LmdldFZhbHVlKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgbmFtZVBhci5zZXRUZXh0KGVudHJ5Lm5hbWUpO1xyXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHNhdmVUcmFja2VyKHRyYWNrZXIsIHRoaXMuYXBwLCBmaWxlLCBnZXRTZWN0aW9uSW5mbygpKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIG5hbWVQYXIuaGlkZGVuID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgIG5hbWVCb3guaW5wdXRFbC5oaWRkZW4gPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgIG5hbWVCb3guc2V0VmFsdWUoZW50cnkubmFtZSk7XHJcbiAgICAgICAgICAgICAgICBlZGl0QnV0dG9uLnNldEljb24oXCJsdWNpZGUtY2hlY2tcIik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgIG5ldyBCdXR0b25Db21wb25lbnQoZW50cnlCdXR0b25zKVxyXG4gICAgICAgIC5zZXRDbGFzcyhcImNsaWNrYWJsZS1pY29uXCIpXHJcbiAgICAgICAgLnNldFRvb2x0aXAoXCJSZW1vdmVcIilcclxuICAgICAgICAuc2V0SWNvbihcImx1Y2lkZS10cmFzaFwiKVxyXG4gICAgICAgIC5vbkNsaWNrKGFzeW5jICgpID0+IHtcclxuICAgICAgICAgICAgcmVtb3ZlRW50cnkodHJhY2tlci5lbnRyaWVzLCBlbnRyeSk7XHJcbiAgICAgICAgICAgIGF3YWl0IHNhdmVUcmFja2VyKHRyYWNrZXIsIHRoaXMuYXBwLCBmaWxlLCBnZXRTZWN0aW9uSW5mbygpKTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICBpZiAoZW50cnkuc3ViRW50cmllcykge1xyXG4gICAgICAgIGZvciAobGV0IHN1YiBvZiBlbnRyeS5zdWJFbnRyaWVzKVxyXG4gICAgICAgICAgICBhZGRFZGl0YWJsZVRhYmxlUm93KHRyYWNrZXIsIHN1YiwgdGFibGUsIG5ld1NlZ21lbnROYW1lQm94LCBydW5uaW5nLCBmaWxlLCBnZXRTZWN0aW9uSW5mbywgc2V0dGluZ3MsIGluZGVudCArIDEpO1xyXG4gICAgfVxyXG59XHJcbiJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBO0FBQUE7QUFBQTtBQUFBLHVCQUF1Qjs7O0FDQWhCLElBQU0sa0JBQTZDO0FBQUEsRUFDdEQsaUJBQWlCO0FBQUEsRUFDakIsY0FBYztBQUFBOzs7QUNGbEIsc0JBQStDO0FBSXhDLGlEQUEyQyxpQ0FBaUI7QUFBQSxFQUkv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
|