diff --git a/build/main.js b/build/main.js new file mode 100644 index 0000000..41e11df --- /dev/null +++ b/build/main.js @@ -0,0 +1,371 @@ +/* +THIS IS A GENERATED/BUNDLED FILE BY ESBUILD +if you want to view the source, please visit the github repository of this plugin +*/ + +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getOwnPropSymbols = Object.getOwnPropertySymbols; +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 __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +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 +var main_exports = {}; +__export(main_exports, { + default: () => HeatmapCalendar +}); +module.exports = __toCommonJS(main_exports); + +// src/defaults.ts +var DEFAULT_COLORS = { default: ["#c6e48b", "#7bc96f", "#49af5d", "#2e8840", "#196127"] }; +var DEFAULT_SETTINGS = { + year: (/* @__PURE__ */ new Date()).getFullYear(), + colors: DEFAULT_COLORS, + entries: [], + showCurrentDayBorder: true, + intensity: { + default: 4, + startScale: 1, + endScale: 5 + } +}; + +// src/main.ts +var import_obsidian2 = require("obsidian"); + +// src/settings.ts +var import_obsidian = require("obsidian"); +var HeatmapCalendarSettingsTab = class extends import_obsidian.PluginSettingTab { + constructor(app, plugin, settings) { + super(app, plugin); + this.plugin = plugin; + this.settings = settings; + } + deleteColorMap(key) { + return __async(this, null, function* () { + delete this.settings.colors[key]; + yield this.plugin.saveSettings(this.settings); + this.display(); + }); + } + displayColorSettings() { + const { containerEl } = this; + containerEl.createEl("h3", { text: "Colors" }); + this.displayColorHelp(containerEl); + for (const [key, colors] of Object.entries(this.settings.colors)) { + const colorEntryContainer = containerEl.createDiv({ + cls: "heatmap-calendar-settings-colors__container" + }); + const colorDataContainer = colorEntryContainer.createDiv({ + cls: "heatmap-calendar-settings-colors__data-container" + }); + colorDataContainer.createEl("h4", { text: key }); + const colorRow = colorDataContainer.createDiv({ cls: "heatmap-calendar-settings-colors__row" }); + const colorsContainer = colorRow.createDiv({ + cls: "heatmap-calendar-settings-colors__color-container" + }); + for (const color of colors) { + colorsContainer.createEl("div", { + cls: "heatmap-calendar-settings-colors__color-box", + attr: { + style: `background-color: ${color}` + } + }); + colorsContainer.createEl("pre", { + cls: "heatmap-calendar-settings-colors__color-name", + text: color + }); + } + if (key !== "default") { + const deleteColorButton = colorEntryContainer.createEl("button", { + cls: "mod-warning heatmap-calendar-settings-colors__delete" + }); + (0, import_obsidian.setIcon)(deleteColorButton, "trash"); + deleteColorButton.addEventListener("click", () => this.deleteColorMap(key)); + } + } + this.displayColorInput(containerEl); + } + displayColorInput(parent) { + const inputContainer = parent.createDiv({ + cls: "heatmap-calendar-settings-colors__new-color-input-container" + }); + const colorNameInput = inputContainer.createEl("input", { + cls: "heatmap-calendar-settings-colors__new-color-input-name", + attr: { placeholder: "Color name", type: "text" } + }); + const colorValueInput = inputContainer.createEl("input", { + cls: "heatmap-calendar-settings-colors__new-color-input-value", + attr: { placeholder: "Colors array", type: "text" } + }); + const addColorButton = inputContainer.createEl("button", { + cls: "mod-cta heatmap-calendar-settings-colors__new-color-button" + }); + (0, import_obsidian.setIcon)(addColorButton, "plus"); + addColorButton.addEventListener("click", () => __async(this, null, function* () { + const name = this.validate( + colorNameInput, + (value) => value != null ? value : void 0, + "Please input a name for your color" + ); + const colors = this.validate( + colorValueInput, + (value) => { + var _a; + return (_a = this.parseColors(value)) != null ? _a : void 0; + }, + "Color is not a valid JSON array of colors" + ); + if (name !== void 0 && colors !== void 0) { + this.settings.colors[name] = colors; + yield this.plugin.saveSettings(this.settings); + this.display(); + } + })); + } + displayColorHelp(parent) { + parent.createEl("p", { + text: "Add lists of colors which will be globally available on your heatmaps." + }); + parent.createEl("p", { + text: "You can use those colors by referencing their name in your heatmap render settings." + }); + } + validate(input, validator, msg) { + const value = validator(input.value); + if (value !== void 0) { + input.classList.add("has-error"); + input.setCustomValidity(msg); + } else { + input.setCustomValidity(""); + } + input.reportValidity(); + return value; + } + parseColors(value) { + const colorRegex = /^(#[0-9a-f]{3,6}|rgba?\(\s*\d+%?\s*,\s*\d+%?\s*,\s*\d+%?\s*(,\s*\d+(\.\d+)?%?)?\s*\))$/i; + try { + const data = JSON.parse(value); + return Array.isArray(data) && data.every((color) => colorRegex.test(color)) ? data : void 0; + } catch (e) { + return void 0; + } + } + display() { + const { containerEl } = this; + containerEl.empty(); + containerEl.createEl("h2", { text: "Heatmap Calendar Settings" }); + this.displayColorSettings(); + console.log("settings", this.settings); + } +}; + +// src/main.ts +var HeatmapCalendar = class extends import_obsidian2.Plugin { + /** + * Returns a number representing how many days into the year the supplied date is. + * Example: first of january is 1, third of february is 34 (31+3) + * @param date + */ + getHowManyDaysIntoYear(date) { + return (Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()) - Date.UTC(date.getUTCFullYear(), 0, 0)) / 24 / 60 / 60 / 1e3; + } + getHowManyDaysIntoYearLocal(date) { + return (Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) - Date.UTC(date.getFullYear(), 0, 0)) / 24 / 60 / 60 / 1e3; + } + /** + * Removes HTMLElements passed as entry.content and outside of the displayed year from rendering above the calendar + */ + removeHtmlElementsNotInYear(entries, year) { + entries.filter((e) => new Date(e.date).getFullYear() !== year).forEach((e) => e.content instanceof HTMLElement && e.content.remove()); + } + clamp(input, min, max) { + return input < min ? min : input > max ? max : input; + } + map(current, inMin, inMax, outMin, outMax) { + const mapped = (current - inMin) * (outMax - outMin) / (inMax - inMin) + outMin; + return this.clamp(mapped, outMin, outMax); + } + onload() { + return __async(this, null, function* () { + const settings = yield this.loadSettings(); + this.addSettingTab(new HeatmapCalendarSettingsTab(this.app, this, settings)); + window.renderHeatmapCalendar = (el, calendarData) => { + var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p; + const year = (_a = calendarData.year) != null ? _a : settings.year; + const colors = typeof calendarData.colors === "string" ? settings.colors[calendarData.colors] ? { [calendarData.colors]: settings.colors[calendarData.colors] } : settings.colors : (_b = calendarData.colors) != null ? _b : settings.colors; + this.removeHtmlElementsNotInYear((_c = calendarData.entries) != null ? _c : [], year); + const calEntries = (_e = (_d = calendarData.entries) == null ? void 0 : _d.filter( + (entry) => (/* @__PURE__ */ new Date(entry.date + "T00:00")).getFullYear() === year + )) != null ? _e : settings.entries; + const showCurrentDayBorder = (_f = calendarData.showCurrentDayBorder) != null ? _f : settings.showCurrentDayBorder; + const defaultEntryIntensity = (_i = (_g = calendarData.intensity) == null ? void 0 : _g.default) != null ? _i : (_h = settings.intensity) == null ? void 0 : _h.default; + const intensities = calEntries.map((entry) => entry.intensity).filter((intensity) => intensity !== void 0); + const minimumIntensity = Math.min(settings.intensity.startScale, ...intensities); + const maximumIntensity = Math.max(settings.intensity.endScale, ...intensities); + const intensityScaleStart = (_k = (_j = calendarData.intensity) == null ? void 0 : _j.startScale) != null ? _k : minimumIntensity; + const intensityScaleEnd = (_m = (_l = calendarData.intensity) == null ? void 0 : _l.endScale) != null ? _m : maximumIntensity; + const mappedEntries = []; + calEntries.forEach((e) => { + var _a2; + const newEntry = __spreadValues({ + intensity: defaultEntryIntensity + }, e); + const colorIntensities = typeof colors === "string" ? settings.colors[colors] : (_a2 = colors[e.color]) != null ? _a2 : colors[Object.keys(colors)[0]]; + const numOfColorIntensities = Object.keys(colorIntensities).length; + if (minimumIntensity === maximumIntensity && intensityScaleStart === intensityScaleEnd) + newEntry.intensity = numOfColorIntensities; + else + newEntry.intensity = Math.round( + this.map( + newEntry.intensity, + intensityScaleStart, + intensityScaleEnd, + 1, + numOfColorIntensities + ) + ); + mappedEntries[this.getHowManyDaysIntoYear(new Date(e.date))] = newEntry; + }); + const firstDayOfYear = new Date(Date.UTC(year, 0, 1)); + let numberOfEmptyDaysBeforeYearBegins = (firstDayOfYear.getUTCDay() + 6) % 7; + const boxes = []; + while (numberOfEmptyDaysBeforeYearBegins) { + boxes.push({ backgroundColor: "transparent" }); + numberOfEmptyDaysBeforeYearBegins--; + } + const lastDayOfYear = new Date(Date.UTC(year, 11, 31)); + const numberOfDaysInYear = this.getHowManyDaysIntoYear(lastDayOfYear); + const todaysDayNumberLocal = this.getHowManyDaysIntoYearLocal(/* @__PURE__ */ new Date()); + for (let day = 1; day <= numberOfDaysInYear; day++) { + const box = { classNames: [] }; + if (day === todaysDayNumberLocal && showCurrentDayBorder) (_n = box.classNames) == null ? void 0 : _n.push("today"); + if (mappedEntries[day]) { + (_o = box.classNames) == null ? void 0 : _o.push("hasData"); + const entry = mappedEntries[day]; + box.date = entry.date; + if (entry.content) box.content = entry.content.toString(); + const currentDayColors = entry.color ? colors[entry.color] : colors[Object.keys(colors)[0]]; + box.backgroundColor = currentDayColors[entry.intensity - 1]; + } else (_p = box.classNames) == null ? void 0 : _p.push("isEmpty"); + boxes.push(box); + } + const heatmapCalendarGraphDiv = createDiv({ + cls: "heatmap-calendar-graph", + parent: el + }); + createDiv({ + cls: "heatmap-calendar-year", + text: String(year).slice(2), + parent: heatmapCalendarGraphDiv + }); + const heatmapCalendarMonthsUl = createEl("ul", { + cls: "heatmap-calendar-months", + parent: heatmapCalendarGraphDiv + }); + createEl("li", { text: "Jan", parent: heatmapCalendarMonthsUl }); + createEl("li", { text: "Feb", parent: heatmapCalendarMonthsUl }); + createEl("li", { text: "Mar", parent: heatmapCalendarMonthsUl }); + createEl("li", { text: "Apr", parent: heatmapCalendarMonthsUl }); + createEl("li", { text: "May", parent: heatmapCalendarMonthsUl }); + createEl("li", { text: "Jun", parent: heatmapCalendarMonthsUl }); + createEl("li", { text: "Jul", parent: heatmapCalendarMonthsUl }); + createEl("li", { text: "Aug", parent: heatmapCalendarMonthsUl }); + createEl("li", { text: "Sep", parent: heatmapCalendarMonthsUl }); + createEl("li", { text: "Oct", parent: heatmapCalendarMonthsUl }); + createEl("li", { text: "Nov", parent: heatmapCalendarMonthsUl }); + createEl("li", { text: "Dec", parent: heatmapCalendarMonthsUl }); + const heatmapCalendarDaysUl = createEl("ul", { + cls: "heatmap-calendar-days", + parent: heatmapCalendarGraphDiv + }); + createEl("li", { text: "Mon", parent: heatmapCalendarDaysUl }); + createEl("li", { text: "Tue", parent: heatmapCalendarDaysUl }); + createEl("li", { text: "Wed", parent: heatmapCalendarDaysUl }); + createEl("li", { text: "Thu", parent: heatmapCalendarDaysUl }); + createEl("li", { text: "Fri", parent: heatmapCalendarDaysUl }); + createEl("li", { text: "Sat", parent: heatmapCalendarDaysUl }); + createEl("li", { text: "Sun", parent: heatmapCalendarDaysUl }); + const heatmapCalendarBoxesUl = createEl("ul", { + cls: "heatmap-calendar-boxes", + parent: heatmapCalendarGraphDiv + }); + boxes.forEach((e) => { + const entry = createEl("li", { + attr: __spreadValues(__spreadValues({}, e.backgroundColor && { style: `background-color: ${e.backgroundColor};` }), e.date && { "data-date": e.date }), + cls: e.classNames, + parent: heatmapCalendarBoxesUl + }); + createSpan({ + cls: "heatmap-calendar-content", + parent: entry, + text: e.content + }); + }); + }; + }); + } + onunload() { + } + loadSettings() { + return __async(this, null, function* () { + const storedSettings = yield this.loadData(); + console.log("stored settings:", storedSettings); + const settings = Object.assign({}, DEFAULT_SETTINGS, storedSettings); + console.log("settings:", settings); + return settings; + }); + } + saveSettings(settings) { + return __async(this, null, function* () { + yield this.saveData(settings); + }); + } +}; +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL21haW4udHMiLCAiLi4vc3JjL2RlZmF1bHRzLnRzIiwgIi4uL3NyYy9zZXR0aW5ncy50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiaW1wb3J0IHsgREVGQVVMVF9TRVRUSU5HUyB9IGZyb20gXCJkZWZhdWx0c1wiO1xuaW1wb3J0IHsgQm94LCBDYWxlbmRhckRhdGEsIENhbGVuZGFyU2V0dGluZ3MsIEVudHJ5IH0gZnJvbSBcIm1vZGVsXCI7XG5pbXBvcnQgeyBQbHVnaW4gfSBmcm9tIFwib2JzaWRpYW5cIjtcbmltcG9ydCBIZWF0bWFwQ2FsZW5kYXJTZXR0aW5nc1RhYiBmcm9tIFwic2V0dGluZ3NcIjtcblxuZGVjbGFyZSBnbG9iYWwge1xuXHRpbnRlcmZhY2UgV2luZG93IHtcblx0XHRyZW5kZXJIZWF0bWFwQ2FsZW5kYXI6IGFueTtcblx0fVxufVxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBIZWF0bWFwQ2FsZW5kYXIgZXh0ZW5kcyBQbHVnaW4ge1xuXHQvKipcblx0ICogUmV0dXJucyBhIG51bWJlciByZXByZXNlbnRpbmcgaG93IG1hbnkgZGF5cyBpbnRvIHRoZSB5ZWFyIHRoZSBzdXBwbGllZCBkYXRlIGlzLlxuXHQgKiBFeGFtcGxlOiBmaXJzdCBvZiBqYW51YXJ5IGlzIDEsIHRoaXJkIG9mIGZlYnJ1YXJ5IGlzIDM0ICgzMSszKVxuXHQgKiBAcGFyYW0gZGF0ZVxuXHQgKi9cblxuXHRnZXRIb3dNYW55RGF5c0ludG9ZZWFyKGRhdGU6IERhdGUpOiBudW1iZXIge1xuXHRcdHJldHVybiAoXG5cdFx0XHQoRGF0ZS5VVEMoZGF0ZS5nZXRVVENGdWxsWWVhcigpLCBkYXRlLmdldFVUQ01vbnRoKCksIGRhdGUuZ2V0VVRDRGF0ZSgpKSAtXG5cdFx0XHRcdERhdGUuVVRDKGRhdGUuZ2V0VVRDRnVsbFllYXIoKSwgMCwgMCkpIC9cblx0XHRcdDI0IC9cblx0XHRcdDYwIC9cblx0XHRcdDYwIC9cblx0XHRcdDEwMDBcblx0XHQpO1xuXHR9XG5cdGdldEhvd01hbnlEYXlzSW50b1llYXJMb2NhbChkYXRlOiBEYXRlKTogbnVtYmVyIHtcblx0XHRyZXR1cm4gKFxuXHRcdFx0KERhdGUuVVRDKGRhdGUuZ2V0RnVsbFllYXIoKSwgZGF0ZS5nZXRNb250aCgpLCBkYXRlLmdldERhdGUoKSkgLVxuXHRcdFx0XHREYXRlLlVUQyhkYXRlLmdldEZ1bGxZZWFyKCksIDAsIDApKSAvXG5cdFx0XHQyNCAvXG5cdFx0XHQ2MCAvXG5cdFx0XHQ2MCAvXG5cdFx0XHQxMDAwXG5cdFx0KTtcblx0fVxuXHQvKipcblx0ICogUmVtb3ZlcyBIVE1MRWxlbWVudHMgcGFzc2VkIGFzIGVudHJ5LmNvbnRlbnQgYW5kIG91dHNpZGUgb2YgdGhlIGRpc3BsYXllZCB5ZWFyIGZyb20gcmVuZGVyaW5nIGFib3ZlIHRoZSBjYWxlbmRhclxuXHQgKi9cblx0cmVtb3ZlSHRtbEVsZW1lbnRzTm90SW5ZZWFyKGVudHJpZXM6IEVudHJ5W10sIHllYXI6IG51bWJlcik6IHZvaWQge1xuXHRcdGVudHJpZXNcblx0XHRcdC5maWx0ZXIoKGU6IEVudHJ5KSA9PiBuZXcgRGF0ZShlLmRhdGUpLmdldEZ1bGxZZWFyKCkgIT09IHllYXIpXG5cdFx0XHQuZm9yRWFjaCgoZTogRW50cnkpID0+IGUuY29udGVudCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50ICYmIGUuY29udGVudC5yZW1vdmUoKSk7XG5cdH1cblxuXHRjbGFtcChpbnB1dDogbnVtYmVyLCBtaW46IG51bWJlciwgbWF4OiBudW1iZXIpOiBudW1iZXIge1xuXHRcdHJldHVybiBpbnB1dCA8IG1pbiA/IG1pbiA6IGlucHV0ID4gbWF4ID8gbWF4IDogaW5wdXQ7XG5cdH1cblxuXHRtYXAoY3VycmVudDogbnVtYmVyLCBpbk1pbjogbnVtYmVyLCBpbk1heDogbnVtYmVyLCBvdXRNaW46IG51bWJlciwgb3V0TWF4OiBudW1iZXIpOiBudW1iZXIge1xuXHRcdGNvbnN0IG1hcHBlZDogbnVtYmVyID0gKChjdXJyZW50IC0gaW5NaW4pICogKG91dE1heCAtIG91dE1pbikpIC8gKGluTWF4IC0gaW5NaW4pICsgb3V0TWluO1xuXHRcdHJldHVybiB0aGlzLmNsYW1wKG1hcHBlZCwgb3V0TWluLCBvdXRNYXgpO1xuXHR9XG5cblx0YXN5bmMgb25sb2FkKCk6IFByb21pc2U8dm9pZD4ge1xuXHRcdGNvbnN0IHNldHRpbmdzID0gYXdhaXQgdGhpcy5sb2FkU2V0dGluZ3MoKTtcblxuXHRcdHRoaXMuYWRkU2V0dGluZ1RhYihuZXcgSGVhdG1hcENhbGVuZGFyU2V0dGluZ3NUYWIodGhpcy5hcHAsIHRoaXMsIHNldHRpbmdzKSk7XG5cblx0XHR3aW5kb3cucmVuZGVySGVhdG1hcENhbGVuZGFyID0gKGVsOiBIVE1MRWxlbWVudCwgY2FsZW5kYXJEYXRhOiBQYXJ0aWFsPENhbGVuZGFyRGF0YT4pOiB2b2lkID0+IHtcblx0XHRcdGNvbnN0IHllYXIgPSBjYWxlbmRhckRhdGEueWVhciA/PyBzZXR0aW5ncy55ZWFyO1xuXHRcdFx0Y29uc3QgY29sb3JzID1cblx0XHRcdFx0dHlwZW9mIGNhbGVuZGFyRGF0YS5jb2xvcnMgPT09IFwic3RyaW5nXCJcblx0XHRcdFx0XHQ/IHNldHRpbmdzLmNvbG9yc1tjYWxlbmRhckRhdGEuY29sb3JzXVxuXHRcdFx0XHRcdFx0PyB7IFtjYWxlbmRhckRhdGEuY29sb3JzXTogc2V0dGluZ3MuY29sb3JzW2NhbGVuZGFyRGF0YS5jb2xvcnNdIH1cblx0XHRcdFx0XHRcdDogc2V0dGluZ3MuY29sb3JzXG5cdFx0XHRcdFx0OiBjYWxlbmRhckRhdGEuY29sb3JzID8/IHNldHRpbmdzLmNvbG9ycztcblxuXHRcdFx0dGhpcy5yZW1vdmVIdG1sRWxlbWVudHNOb3RJblllYXIoY2FsZW5kYXJEYXRhLmVudHJpZXMgPz8gW10sIHllYXIpO1xuXG5cdFx0XHRjb25zdCBjYWxFbnRyaWVzID1cblx0XHRcdFx0Y2FsZW5kYXJEYXRhLmVudHJpZXM/LmZpbHRlcihcblx0XHRcdFx0XHQoZW50cnk6IEVudHJ5KSA9PiBuZXcgRGF0ZShlbnRyeS5kYXRlICsgXCJUMDA6MDBcIikuZ2V0RnVsbFllYXIoKSA9PT0geWVhcixcblx0XHRcdFx0KSA/PyBzZXR0aW5ncy5lbnRyaWVzO1xuXG5cdFx0XHRjb25zdCBzaG93Q3VycmVudERheUJvcmRlciA9IGNhbGVuZGFyRGF0YS5zaG93Q3VycmVudERheUJvcmRlciA/PyBzZXR0aW5ncy5zaG93Q3VycmVudERheUJvcmRlcjtcblx0XHRcdGNvbnN0IGRlZmF1bHRFbnRyeUludGVuc2l0eSA9IGNhbGVuZGFyRGF0YS5pbnRlbnNpdHk/LmRlZmF1bHQgPz8gc2V0dGluZ3MuaW50ZW5zaXR5Py5kZWZhdWx0O1xuXG5cdFx0XHRjb25zdCBpbnRlbnNpdGllczogbnVtYmVyW10gPSBjYWxFbnRyaWVzXG5cdFx0XHRcdC5tYXAoKGVudHJ5OiBFbnRyeSkgPT4gZW50cnkuaW50ZW5zaXR5KVxuXHRcdFx0XHQuZmlsdGVyKChpbnRlbnNpdHkpOiBpbnRlbnNpdHkgaXMgbnVtYmVyID0+IGludGVuc2l0eSAhPT0gdW5kZWZpbmVkKTtcblx0XHRcdGNvbnN0IG1pbmltdW1JbnRlbnNpdHkgPSBNYXRoLm1pbihzZXR0aW5ncy5pbnRlbnNpdHkuc3RhcnRTY2FsZSwgLi4uaW50ZW5zaXRpZXMpO1xuXHRcdFx0Y29uc3QgbWF4aW11bUludGVuc2l0eSA9IE1hdGgubWF4KHNldHRpbmdzLmludGVuc2l0eS5lbmRTY2FsZSwgLi4uaW50ZW5zaXRpZXMpO1xuXHRcdFx0Y29uc3QgaW50ZW5zaXR5U2NhbGVTdGFydCA9IGNhbGVuZGFyRGF0YS5pbnRlbnNpdHk/LnN0YXJ0U2NhbGUgPz8gbWluaW11bUludGVuc2l0eTtcblx0XHRcdGNvbnN0IGludGVuc2l0eVNjYWxlRW5kID0gY2FsZW5kYXJEYXRhLmludGVuc2l0eT8uZW5kU2NhbGUgPz8gbWF4aW11bUludGVuc2l0eTtcblxuXHRcdFx0Y29uc3QgbWFwcGVkRW50cmllczogRW50cnlbXSA9IFtdO1xuXHRcdFx0Y2FsRW50cmllcy5mb3JFYWNoKChlOiBFbnRyeSkgPT4ge1xuXHRcdFx0XHRjb25zdCBuZXdFbnRyeSA9IHtcblx0XHRcdFx0XHRpbnRlbnNpdHk6IGRlZmF1bHRFbnRyeUludGVuc2l0eSxcblx0XHRcdFx0XHQuLi5lLFxuXHRcdFx0XHR9O1xuXHRcdFx0XHRjb25zdCBjb2xvckludGVuc2l0aWVzID1cblx0XHRcdFx0XHR0eXBlb2YgY29sb3JzID09PSBcInN0cmluZ1wiXG5cdFx0XHRcdFx0XHQ/IHNldHRpbmdzLmNvbG9yc1tjb2xvcnNdXG5cdFx0XHRcdFx0XHQ6IGNvbG9yc1tlLmNvbG9yXSA/PyBjb2xvcnNbT2JqZWN0LmtleXMoY29sb3JzKVswXV07XG5cblx0XHRcdFx0Y29uc3QgbnVtT2ZDb2xvckludGVuc2l0aWVzID0gT2JqZWN0LmtleXMoY29sb3JJbnRlbnNpdGllcykubGVuZ3RoO1xuXG5cdFx0XHRcdGlmIChtaW5pbXVtSW50ZW5zaXR5ID09PSBtYXhpbXVtSW50ZW5zaXR5ICYmIGludGVuc2l0eVNjYWxlU3RhcnQgPT09IGludGVuc2l0eVNjYWxlRW5kKVxuXHRcdFx0XHRcdG5ld0VudHJ5LmludGVuc2l0eSA9IG51bU9mQ29sb3JJbnRlbnNpdGllcztcblx0XHRcdFx0ZWxzZVxuXHRcdFx0XHRcdG5ld0VudHJ5LmludGVuc2l0eSA9IE1hdGgucm91bmQoXG5cdFx0XHRcdFx0XHR0aGlzLm1hcChcblx0XHRcdFx0XHRcdFx0bmV3RW50cnkuaW50ZW5zaXR5LFxuXHRcdFx0XHRcdFx0XHRpbnRlbnNpdHlTY2FsZVN0YXJ0LFxuXHRcdFx0XHRcdFx0XHRpbnRlbnNpdHlTY2FsZUVuZCxcblx0XHRcdFx0XHRcdFx0MSxcblx0XHRcdFx0XHRcdFx0bnVtT2ZDb2xvckludGVuc2l0aWVzLFxuXHRcdFx0XHRcdFx0KSxcblx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdG1hcHBlZEVudHJpZXNbdGhpcy5nZXRIb3dNYW55RGF5c0ludG9ZZWFyKG5ldyBEYXRlKGUuZGF0ZSkpXSA9IG5ld0VudHJ5O1xuXHRcdFx0fSk7XG5cblx0XHRcdGNvbnN0IGZpcnN0RGF5T2ZZZWFyID0gbmV3IERhdGUoRGF0ZS5VVEMoeWVhciwgMCwgMSkpO1xuXHRcdFx0bGV0IG51bWJlck9mRW1wdHlEYXlzQmVmb3JlWWVhckJlZ2lucyA9IChmaXJzdERheU9mWWVhci5nZXRVVENEYXkoKSArIDYpICUgNztcblxuXHRcdFx0Y29uc3QgYm94ZXM6IEFycmF5PEJveD4gPSBbXTtcblxuXHRcdFx0d2hpbGUgKG51bWJlck9mRW1wdHlEYXlzQmVmb3JlWWVhckJlZ2lucykge1xuXHRcdFx0XHRib3hlcy5wdXNoKHsgYmFja2dyb3VuZENvbG9yOiBcInRyYW5zcGFyZW50XCIgfSk7XG5cdFx0XHRcdG51bWJlck9mRW1wdHlEYXlzQmVmb3JlWWVhckJlZ2lucy0tO1xuXHRcdFx0fVxuXHRcdFx0Y29uc3QgbGFzdERheU9mWWVhciA9IG5ldyBEYXRlKERhdGUuVVRDKHllYXIsIDExLCAzMSkpO1xuXHRcdFx0Y29uc3QgbnVtYmVyT2ZEYXlzSW5ZZWFyID0gdGhpcy5nZXRIb3dNYW55RGF5c0ludG9ZZWFyKGxhc3REYXlPZlllYXIpOyAvL2VnIDM2NSBvciAzNjZcblx0XHRcdGNvbnN0IHRvZGF5c0RheU51bWJlckxvY2FsID0gdGhpcy5nZXRIb3dNYW55RGF5c0ludG9ZZWFyTG9jYWwobmV3IERhdGUoKSk7XG5cblx0XHRcdGZvciAobGV0IGRheSA9IDE7IGRheSA8PSBudW1iZXJPZkRheXNJblllYXI7IGRheSsrKSB7XG5cdFx0XHRcdGNvbnN0IGJveDogQm94ID0geyBjbGFzc05hbWVzOiBbXSB9O1xuXG5cdFx0XHRcdGlmIChkYXkgPT09IHRvZGF5c0RheU51bWJlckxvY2FsICYmIHNob3dDdXJyZW50RGF5Qm9yZGVyKSBib3guY2xhc3NOYW1lcz8ucHVzaChcInRvZGF5XCIpO1xuXG5cdFx0XHRcdGlmIChtYXBwZWRFbnRyaWVzW2RheV0pIHtcblx0XHRcdFx0XHRib3guY2xhc3NOYW1lcz8ucHVzaChcImhhc0RhdGFcIik7XG5cdFx0XHRcdFx0Y29uc3QgZW50cnkgPSBtYXBwZWRFbnRyaWVzW2RheV07XG5cblx0XHRcdFx0XHRib3guZGF0ZSA9IGVudHJ5LmRhdGU7XG5cblx0XHRcdFx0XHRpZiAoZW50cnkuY29udGVudCkgYm94LmNvbnRlbnQgPSBlbnRyeS5jb250ZW50LnRvU3RyaW5nKCk7XG5cblx0XHRcdFx0XHRjb25zdCBjdXJyZW50RGF5Q29sb3JzID0gZW50cnkuY29sb3Jcblx0XHRcdFx0XHRcdD8gY29sb3JzW2VudHJ5LmNvbG9yXVxuXHRcdFx0XHRcdFx0OiBjb2xvcnNbT2JqZWN0LmtleXMoY29sb3JzKVswXV07XG5cdFx0XHRcdFx0Ym94LmJhY2tncm91bmRDb2xvciA9IGN1cnJlbnREYXlDb2xvcnNbKGVudHJ5LmludGVuc2l0eSBhcyBudW1iZXIpIC0gMV07XG5cdFx0XHRcdH0gZWxzZSBib3guY2xhc3NOYW1lcz8ucHVzaChcImlzRW1wdHlcIik7XG5cdFx0XHRcdGJveGVzLnB1c2goYm94KTtcblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgaGVhdG1hcENhbGVuZGFyR3JhcGhEaXYgPSBjcmVhdGVEaXYoe1xuXHRcdFx0XHRjbHM6IFwiaGVhdG1hcC1jYWxlbmRhci1ncmFwaFwiLFxuXHRcdFx0XHRwYXJlbnQ6IGVsLFxuXHRcdFx0fSk7XG5cblx0XHRcdGNyZWF0ZURpdih7XG5cdFx0XHRcdGNsczogXCJoZWF0bWFwLWNhbGVuZGFyLXllYXJcIixcblx0XHRcdFx0dGV4dDogU3RyaW5nKHllYXIpLnNsaWNlKDIpLFxuXHRcdFx0XHRwYXJlbnQ6IGhlYXRtYXBDYWxlbmRhckdyYXBoRGl2LFxuXHRcdFx0fSk7XG5cblx0XHRcdGNvbnN0IGhlYXRtYXBDYWxlbmRhck1vbnRoc1VsID0gY3JlYXRlRWwoXCJ1bFwiLCB7XG5cdFx0XHRcdGNsczogXCJoZWF0bWFwLWNhbGVuZGFyLW1vbnRoc1wiLFxuXHRcdFx0XHRwYXJlbnQ6IGhlYXRtYXBDYWxlbmRhckdyYXBoRGl2LFxuXHRcdFx0fSk7XG5cblx0XHRcdGNyZWF0ZUVsKFwibGlcIiwgeyB0ZXh0OiBcIkphblwiLCBwYXJlbnQ6IGhlYXRtYXBDYWxlbmRhck1vbnRoc1VsIH0pO1xuXHRcdFx0Y3JlYXRlRWwoXCJsaVwiLCB7IHRleHQ6IFwiRmViXCIsIHBhcmVudDogaGVhdG1hcENhbGVuZGFyTW9udGhzVWwgfSk7XG5cdFx0XHRjcmVhdGVFbChcImxpXCIsIHsgdGV4dDogXCJNYXJcIiwgcGFyZW50OiBoZWF0bWFwQ2FsZW5kYXJNb250aHNVbCB9KTtcblx0XHRcdGNyZWF0ZUVsKFwibGlcIiwgeyB0ZXh0OiBcIkFwclwiLCBwYXJlbnQ6IGhlYXRtYXBDYWxlbmRhck1vbnRoc1VsIH0pO1xuXHRcdFx0Y3JlYXRlRWwoXCJsaVwiLCB7IHRleHQ6IFwiTWF5XCIsIHBhcmVudDogaGVhdG1hcENhbGVuZGFyTW9udGhzVWwgfSk7XG5cdFx0XHRjcmVhdGVFbChcImxpXCIsIHsgdGV4dDogXCJKdW5cIiwgcGFyZW50OiBoZWF0bWFwQ2FsZW5kYXJNb250aHNVbCB9KTtcblx0XHRcdGNyZWF0ZUVsKFwibGlcIiwgeyB0ZXh0OiBcIkp1bFwiLCBwYXJlbnQ6IGhlYXRtYXBDYWxlbmRhck1vbnRoc1VsIH0pO1xuXHRcdFx0Y3JlYXRlRWwoXCJsaVwiLCB7IHRleHQ6IFwiQXVnXCIsIHBhcmVudDogaGVhdG1hcENhbGVuZGFyTW9udGhzVWwgfSk7XG5cdFx0XHRjcmVhdGVFbChcImxpXCIsIHsgdGV4dDogXCJTZXBcIiwgcGFyZW50OiBoZWF0bWFwQ2FsZW5kYXJNb250aHNVbCB9KTtcblx0XHRcdGNyZWF0ZUVsKFwibGlcIiwgeyB0ZXh0OiBcIk9jdFwiLCBwYXJlbnQ6IGhlYXRtYXBDYWxlbmRhck1vbnRoc1VsIH0pO1xuXHRcdFx0Y3JlYXRlRWwoXCJsaVwiLCB7IHRleHQ6IFwiTm92XCIsIHBhcmVudDogaGVhdG1hcENhbGVuZGFyTW9udGhzVWwgfSk7XG5cdFx0XHRjcmVhdGVFbChcImxpXCIsIHsgdGV4dDogXCJEZWNcIiwgcGFyZW50OiBoZWF0bWFwQ2FsZW5kYXJNb250aHNVbCB9KTtcblxuXHRcdFx0Y29uc3QgaGVhdG1hcENhbGVuZGFyRGF5c1VsID0gY3JlYXRlRWwoXCJ1bFwiLCB7XG5cdFx0XHRcdGNsczogXCJoZWF0bWFwLWNhbGVuZGFyLWRheXNcIixcblx0XHRcdFx0cGFyZW50OiBoZWF0bWFwQ2FsZW5kYXJHcmFwaERpdixcblx0XHRcdH0pO1xuXG5cdFx0XHRjcmVhdGVFbChcImxpXCIsIHsgdGV4dDogXCJNb25cIiwgcGFyZW50OiBoZWF0bWFwQ2FsZW5kYXJEYXlzVWwgfSk7XG5cdFx0XHRjcmVhdGVFbChcImxpXCIsIHsgdGV4dDogXCJUdWVcIiwgcGFyZW50OiBoZWF0bWFwQ2FsZW5kYXJEYXlzVWwgfSk7XG5cdFx0XHRjcmVhdGVFbChcImxpXCIsIHsgdGV4dDogXCJXZWRcIiwgcGFyZW50OiBoZWF0bWFwQ2FsZW5kYXJEYXlzVWwgfSk7XG5cdFx0XHRjcmVhdGVFbChcImxpXCIsIHsgdGV4dDogXCJUaHVcIiwgcGFyZW50OiBoZWF0bWFwQ2FsZW5kYXJEYXlzVWwgfSk7XG5cdFx0XHRjcmVhdGVFbChcImxpXCIsIHsgdGV4dDogXCJGcmlcIiwgcGFyZW50OiBoZWF0bWFwQ2FsZW5kYXJEYXlzVWwgfSk7XG5cdFx0XHRjcmVhdGVFbChcImxpXCIsIHsgdGV4dDogXCJTYXRcIiwgcGFyZW50OiBoZWF0bWFwQ2FsZW5kYXJEYXlzVWwgfSk7XG5cdFx0XHRjcmVhdGVFbChcImxpXCIsIHsgdGV4dDogXCJTdW5cIiwgcGFyZW50OiBoZWF0bWFwQ2FsZW5kYXJEYXlzVWwgfSk7XG5cblx0XHRcdGNvbnN0IGhlYXRtYXBDYWxlbmRhckJveGVzVWwgPSBjcmVhdGVFbChcInVsXCIsIHtcblx0XHRcdFx0Y2xzOiBcImhlYXRtYXAtY2FsZW5kYXItYm94ZXNcIixcblx0XHRcdFx0cGFyZW50OiBoZWF0bWFwQ2FsZW5kYXJHcmFwaERpdixcblx0XHRcdH0pO1xuXG5cdFx0XHRib3hlcy5mb3JFYWNoKChlKSA9PiB7XG5cdFx0XHRcdGNvbnN0IGVudHJ5ID0gY3JlYXRlRWwoXCJsaVwiLCB7XG5cdFx0XHRcdFx0YXR0cjoge1xuXHRcdFx0XHRcdFx0Li4uKGUuYmFja2dyb3VuZENvbG9yICYmIHsgc3R5bGU6IGBiYWNrZ3JvdW5kLWNvbG9yOiAke2UuYmFja2dyb3VuZENvbG9yfTtgIH0pLFxuXHRcdFx0XHRcdFx0Li4uKGUuZGF0ZSAmJiB7IFwiZGF0YS1kYXRlXCI6IGUuZGF0ZSB9KSxcblx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdGNsczogZS5jbGFzc05hbWVzLFxuXHRcdFx0XHRcdHBhcmVudDogaGVhdG1hcENhbGVuZGFyQm94ZXNVbCxcblx0XHRcdFx0fSk7XG5cblx0XHRcdFx0Y3JlYXRlU3Bhbih7XG5cdFx0XHRcdFx0Y2xzOiBcImhlYXRtYXAtY2FsZW5kYXItY29udGVudFwiLFxuXHRcdFx0XHRcdHBhcmVudDogZW50cnksXG5cdFx0XHRcdFx0dGV4dDogZS5jb250ZW50LFxuXHRcdFx0XHR9KTtcblx0XHRcdH0pO1xuXHRcdH07XG5cdH1cblxuXHRvbnVubG9hZCgpOiB2b2lkIHt9XG5cblx0YXN5bmMgbG9hZFNldHRpbmdzKCk6IFByb21pc2U8Q2FsZW5kYXJTZXR0aW5ncz4ge1xuXHRcdGNvbnN0IHN0b3JlZFNldHRpbmdzOiBDYWxlbmRhclNldHRpbmdzID0gYXdhaXQgdGhpcy5sb2FkRGF0YSgpO1xuXHRcdGNvbnNvbGUubG9nKFwic3RvcmVkIHNldHRpbmdzOlwiLCBzdG9yZWRTZXR0aW5ncyk7XG5cdFx0Y29uc3Qgc2V0dGluZ3MgPSBPYmplY3QuYXNzaWduKHt9LCBERUZBVUxUX1NFVFRJTkdTLCBzdG9yZWRTZXR0aW5ncyk7XG5cdFx0Y29uc29sZS5sb2coXCJzZXR0aW5nczpcIiwgc2V0dGluZ3MpO1xuXHRcdHJldHVybiBzZXR0aW5ncztcblx0fVxuXG5cdGFzeW5jIHNhdmVTZXR0aW5ncyhzZXR0aW5nczogQ2FsZW5kYXJTZXR0aW5ncyk6IFByb21pc2U8dm9pZD4ge1xuXHRcdGF3YWl0IHRoaXMuc2F2ZURhdGEoc2V0dGluZ3MpO1xuXHR9XG59XG4iLCAiaW1wb3J0IHsgQ2FsZW5kYXJEYXRhIH0gZnJvbSBcIm1vZGVsXCI7XG5cbmV4cG9ydCBjb25zdCBERUZBVUxUX0NPTE9SUyA9IHsgZGVmYXVsdDogW1wiI2M2ZTQ4YlwiLCBcIiM3YmM5NmZcIiwgXCIjNDlhZjVkXCIsIFwiIzJlODg0MFwiLCBcIiMxOTYxMjdcIl0gfTtcblxuZXhwb3J0IGNvbnN0IERFRkFVTFRfU0VUVElOR1M6IENhbGVuZGFyRGF0YSA9IHtcblx0eWVhcjogbmV3IERhdGUoKS5nZXRGdWxsWWVhcigpLFxuXHRjb2xvcnM6IERFRkFVTFRfQ09MT1JTLFxuXHRlbnRyaWVzOiBbXSxcblx0c2hvd0N1cnJlbnREYXlCb3JkZXI6IHRydWUsXG5cdGludGVuc2l0eToge1xuXHRcdGRlZmF1bHQ6IDQsXG5cdFx0c3RhcnRTY2FsZTogMSxcblx0XHRlbmRTY2FsZTogNSxcblx0fSxcbn07XG4iLCAiaW1wb3J0IEhlYXRtYXBDYWxlbmRhciBmcm9tIFwibWFpblwiO1xuaW1wb3J0IHsgQ2FsZW5kYXJTZXR0aW5ncyB9IGZyb20gXCJtb2RlbFwiO1xuaW1wb3J0IHsgQXBwLCBQbHVnaW5TZXR0aW5nVGFiLCBzZXRJY29uIH0gZnJvbSBcIm9ic2lkaWFuXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEhlYXRtYXBDYWxlbmRhclNldHRpbmdzVGFiIGV4dGVuZHMgUGx1Z2luU2V0dGluZ1RhYiB7XG5cdHBsdWdpbjogSGVhdG1hcENhbGVuZGFyO1xuXHRzZXR0aW5nczogQ2FsZW5kYXJTZXR0aW5ncztcblxuXHRjb25zdHJ1Y3RvcihhcHA6IEFwcCwgcGx1Z2luOiBIZWF0bWFwQ2FsZW5kYXIsIHNldHRpbmdzOiBDYWxlbmRhclNldHRpbmdzKSB7XG5cdFx0c3VwZXIoYXBwLCBwbHVnaW4pO1xuXHRcdHRoaXMucGx1Z2luID0gcGx1Z2luO1xuXHRcdHRoaXMuc2V0dGluZ3MgPSBzZXR0aW5ncztcblx0fVxuXG5cdHByaXZhdGUgYXN5bmMgZGVsZXRlQ29sb3JNYXAoa2V5OiBrZXlvZiB0eXBlb2YgdGhpcy5zZXR0aW5ncy5jb2xvcnMpIHtcblx0XHRkZWxldGUgdGhpcy5zZXR0aW5ncy5jb2xvcnNba2V5XTtcblx0XHRhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3ModGhpcy5zZXR0aW5ncyk7XG5cdFx0dGhpcy5kaXNwbGF5KCk7XG5cdH1cblxuXHRwcml2YXRlIGRpc3BsYXlDb2xvclNldHRpbmdzKCkge1xuXHRcdGNvbnN0IHsgY29udGFpbmVyRWwgfSA9IHRoaXM7XG5cblx0XHRjb250YWluZXJFbC5jcmVhdGVFbChcImgzXCIsIHsgdGV4dDogXCJDb2xvcnNcIiB9KTtcblx0XHR0aGlzLmRpc3BsYXlDb2xvckhlbHAoY29udGFpbmVyRWwpO1xuXG5cdFx0Zm9yIChjb25zdCBba2V5LCBjb2xvcnNdIG9mIE9iamVjdC5lbnRyaWVzKHRoaXMuc2V0dGluZ3MuY29sb3JzKSkge1xuXHRcdFx0Y29uc3QgY29sb3JFbnRyeUNvbnRhaW5lciA9IGNvbnRhaW5lckVsLmNyZWF0ZURpdih7XG5cdFx0XHRcdGNsczogXCJoZWF0bWFwLWNhbGVuZGFyLXNldHRpbmdzLWNvbG9yc19fY29udGFpbmVyXCIsXG5cdFx0XHR9KTtcblxuXHRcdFx0Y29uc3QgY29sb3JEYXRhQ29udGFpbmVyID0gY29sb3JFbnRyeUNvbnRhaW5lci5jcmVhdGVEaXYoe1xuXHRcdFx0XHRjbHM6IFwiaGVhdG1hcC1jYWxlbmRhci1zZXR0aW5ncy1jb2xvcnNfX2RhdGEtY29udGFpbmVyXCIsXG5cdFx0XHR9KTtcblxuXHRcdFx0Y29sb3JEYXRhQ29udGFpbmVyLmNyZWF0ZUVsKFwiaDRcIiwgeyB0ZXh0OiBrZXkgfSk7XG5cblx0XHRcdGNvbnN0IGNvbG9yUm93ID0gY29sb3JEYXRhQ29udGFpbmVyLmNyZWF0ZURpdih7IGNsczogXCJoZWF0bWFwLWNhbGVuZGFyLXNldHRpbmdzLWNvbG9yc19fcm93XCIgfSk7XG5cblx0XHRcdGNvbnN0IGNvbG9yc0NvbnRhaW5lciA9IGNvbG9yUm93LmNyZWF0ZURpdih7XG5cdFx0XHRcdGNsczogXCJoZWF0bWFwLWNhbGVuZGFyLXNldHRpbmdzLWNvbG9yc19fY29sb3ItY29udGFpbmVyXCIsXG5cdFx0XHR9KTtcblxuXHRcdFx0Zm9yIChjb25zdCBjb2xvciBvZiBjb2xvcnMpIHtcblx0XHRcdFx0Y29sb3JzQ29udGFpbmVyLmNyZWF0ZUVsKFwiZGl2XCIsIHtcblx0XHRcdFx0XHRjbHM6IFwiaGVhdG1hcC1jYWxlbmRhci1zZXR0aW5ncy1jb2xvcnNfX2NvbG9yLWJveFwiLFxuXHRcdFx0XHRcdGF0dHI6IHtcblx0XHRcdFx0XHRcdHN0eWxlOiBgYmFja2dyb3VuZC1jb2xvcjogJHtjb2xvcn1gLFxuXHRcdFx0XHRcdH0sXG5cdFx0XHRcdH0pO1xuXG5cdFx0XHRcdGNvbG9yc0NvbnRhaW5lci5jcmVhdGVFbChcInByZVwiLCB7XG5cdFx0XHRcdFx0Y2xzOiBcImhlYXRtYXAtY2FsZW5kYXItc2V0dGluZ3MtY29sb3JzX19jb2xvci1uYW1lXCIsXG5cdFx0XHRcdFx0dGV4dDogY29sb3IsXG5cdFx0XHRcdH0pO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoa2V5ICE9PSBcImRlZmF1bHRcIikge1xuXHRcdFx0XHRjb25zdCBkZWxldGVDb2xvckJ1dHRvbiA9IGNvbG9yRW50cnlDb250YWluZXIuY3JlYXRlRWwoXCJidXR0b25cIiwge1xuXHRcdFx0XHRcdGNsczogXCJtb2Qtd2FybmluZyBoZWF0bWFwLWNhbGVuZGFyLXNldHRpbmdzLWNvbG9yc19fZGVsZXRlXCIsXG5cdFx0XHRcdH0pO1xuXG5cdFx0XHRcdHNldEljb24oZGVsZXRlQ29sb3JCdXR0b24sIFwidHJhc2hcIik7XG5cblx0XHRcdFx0ZGVsZXRlQ29sb3JCdXR0b24uYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsICgpID0+IHRoaXMuZGVsZXRlQ29sb3JNYXAoa2V5KSk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhpcy5kaXNwbGF5Q29sb3JJbnB1dChjb250YWluZXJFbCk7XG5cdH1cblxuXHRwcml2YXRlIGRpc3BsYXlDb2xvcklucHV0KHBhcmVudDogSFRNTEVsZW1lbnQpIHtcblx0XHRjb25zdCBpbnB1dENvbnRhaW5lciA9IHBhcmVudC5jcmVhdGVEaXYoe1xuXHRcdFx0Y2xzOiBcImhlYXRtYXAtY2FsZW5kYXItc2V0dGluZ3MtY29sb3JzX19uZXctY29sb3ItaW5wdXQtY29udGFpbmVyXCIsXG5cdFx0fSk7XG5cblx0XHRjb25zdCBjb2xvck5hbWVJbnB1dCA9IGlucHV0Q29udGFpbmVyLmNyZWF0ZUVsKFwiaW5wdXRcIiwge1xuXHRcdFx0Y2xzOiBcImhlYXRtYXAtY2FsZW5kYXItc2V0dGluZ3MtY29sb3JzX19uZXctY29sb3ItaW5wdXQtbmFtZVwiLFxuXHRcdFx0YXR0cjogeyBwbGFjZWhvbGRlcjogXCJDb2xvciBuYW1lXCIsIHR5cGU6IFwidGV4dFwiIH0sXG5cdFx0fSk7XG5cblx0XHRjb25zdCBjb2xvclZhbHVlSW5wdXQgPSBpbnB1dENvbnRhaW5lci5jcmVhdGVFbChcImlucHV0XCIsIHtcblx0XHRcdGNsczogXCJoZWF0bWFwLWNhbGVuZGFyLXNldHRpbmdzLWNvbG9yc19fbmV3LWNvbG9yLWlucHV0LXZhbHVlXCIsXG5cdFx0XHRhdHRyOiB7IHBsYWNlaG9sZGVyOiBcIkNvbG9ycyBhcnJheVwiLCB0eXBlOiBcInRleHRcIiB9LFxuXHRcdH0pO1xuXG5cdFx0Y29uc3QgYWRkQ29sb3JCdXR0b24gPSBpbnB1dENvbnRhaW5lci5jcmVhdGVFbChcImJ1dHRvblwiLCB7XG5cdFx0XHRjbHM6IFwibW9kLWN0YSBoZWF0bWFwLWNhbGVuZGFyLXNldHRpbmdzLWNvbG9yc19fbmV3LWNvbG9yLWJ1dHRvblwiLFxuXHRcdH0pO1xuXG5cdFx0c2V0SWNvbihhZGRDb2xvckJ1dHRvbiwgXCJwbHVzXCIpO1xuXG5cdFx0YWRkQ29sb3JCdXR0b24uYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsIGFzeW5jICgpID0+IHtcblx0XHRcdGNvbnN0IG5hbWUgPSB0aGlzLnZhbGlkYXRlPHN0cmluZz4oXG5cdFx0XHRcdGNvbG9yTmFtZUlucHV0LFxuXHRcdFx0XHQodmFsdWUpID0+IHZhbHVlID8/IHVuZGVmaW5lZCxcblx0XHRcdFx0XCJQbGVhc2UgaW5wdXQgYSBuYW1lIGZvciB5b3VyIGNvbG9yXCIsXG5cdFx0XHQpO1xuXHRcdFx0Y29uc3QgY29sb3JzID0gdGhpcy52YWxpZGF0ZTxzdHJpbmdbXT4oXG5cdFx0XHRcdGNvbG9yVmFsdWVJbnB1dCxcblx0XHRcdFx0KHZhbHVlKSA9PiB0aGlzLnBhcnNlQ29sb3JzKHZhbHVlKSA/PyB1bmRlZmluZWQsXG5cdFx0XHRcdFwiQ29sb3IgaXMgbm90IGEgdmFsaWQgSlNPTiBhcnJheSBvZiBjb2xvcnNcIixcblx0XHRcdCk7XG5cblx0XHRcdGlmIChuYW1lICE9PSB1bmRlZmluZWQgJiYgY29sb3JzICE9PSB1bmRlZmluZWQpIHtcblx0XHRcdFx0dGhpcy5zZXR0aW5ncy5jb2xvcnNbbmFtZV0gPSBjb2xvcnM7XG5cdFx0XHRcdGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncyh0aGlzLnNldHRpbmdzKTtcblx0XHRcdFx0dGhpcy5kaXNwbGF5KCk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cblxuXHRwcml2YXRlIGRpc3BsYXlDb2xvckhlbHAocGFyZW50OiBIVE1MRWxlbWVudCkge1xuXHRcdHBhcmVudC5jcmVhdGVFbChcInBcIiwge1xuXHRcdFx0dGV4dDogXCJBZGQgbGlzdHMgb2YgY29sb3JzIHdoaWNoIHdpbGwgYmUgZ2xvYmFsbHkgYXZhaWxhYmxlIG9uIHlvdXIgaGVhdG1hcHMuXCIsXG5cdFx0fSk7XG5cdFx0cGFyZW50LmNyZWF0ZUVsKFwicFwiLCB7XG5cdFx0XHR0ZXh0OiBcIllvdSBjYW4gdXNlIHRob3NlIGNvbG9ycyBieSByZWZlcmVuY2luZyB0aGVpciBuYW1lIGluIHlvdXIgaGVhdG1hcCByZW5kZXIgc2V0dGluZ3MuXCIsXG5cdFx0fSk7XG5cdH1cblxuXHRwcml2YXRlIHZhbGlkYXRlPFQ+KGlucHV0OiBIVE1MSW5wdXRFbGVtZW50LCB2YWxpZGF0b3I6ICh4OiBzdHJpbmcpID0+IFQgfCB1bmRlZmluZWQsIG1zZzogc3RyaW5nKSB7XG5cdFx0Y29uc3QgdmFsdWUgPSB2YWxpZGF0b3IoaW5wdXQudmFsdWUpO1xuXHRcdGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG5cdFx0XHRpbnB1dC5jbGFzc0xpc3QuYWRkKFwiaGFzLWVycm9yXCIpO1xuXHRcdFx0aW5wdXQuc2V0Q3VzdG9tVmFsaWRpdHkobXNnKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0aW5wdXQuc2V0Q3VzdG9tVmFsaWRpdHkoXCJcIik7XG5cdFx0fVxuXHRcdGlucHV0LnJlcG9ydFZhbGlkaXR5KCk7XG5cdFx0cmV0dXJuIHZhbHVlO1xuXHR9XG5cblx0cHJpdmF0ZSBwYXJzZUNvbG9ycyh2YWx1ZTogc3RyaW5nKTogdW5kZWZpbmVkIHwgc3RyaW5nW10ge1xuXHRcdGNvbnN0IGNvbG9yUmVnZXggPVxuXHRcdFx0L14oI1swLTlhLWZdezMsNn18cmdiYT9cXChcXHMqXFxkKyU/XFxzKixcXHMqXFxkKyU/XFxzKixcXHMqXFxkKyU/XFxzKigsXFxzKlxcZCsoXFwuXFxkKyk/JT8pP1xccypcXCkpJC9pO1xuXHRcdHRyeSB7XG5cdFx0XHRjb25zdCBkYXRhOiBzdHJpbmdbXSA9IEpTT04ucGFyc2UodmFsdWUpO1xuXHRcdFx0cmV0dXJuIEFycmF5LmlzQXJyYXkoZGF0YSkgJiYgZGF0YS5ldmVyeSgoY29sb3IpID0+IGNvbG9yUmVnZXgudGVzdChjb2xvcikpID8gZGF0YSA6IHVuZGVmaW5lZDtcblx0XHR9IGNhdGNoIChlKSB7XG5cdFx0XHRyZXR1cm4gdW5kZWZpbmVkO1xuXHRcdH1cblx0fVxuXG5cdGRpc3BsYXkoKTogdm9pZCB7XG5cdFx0Y29uc3QgeyBjb250YWluZXJFbCB9ID0gdGhpcztcblx0XHRjb250YWluZXJFbC5lbXB0eSgpO1xuXHRcdGNvbnRhaW5lckVsLmNyZWF0ZUVsKFwiaDJcIiwgeyB0ZXh0OiBcIkhlYXRtYXAgQ2FsZW5kYXIgU2V0dGluZ3NcIiB9KTtcblx0XHR0aGlzLmRpc3BsYXlDb2xvclNldHRpbmdzKCk7XG5cdFx0Y29uc29sZS5sb2coXCJzZXR0aW5nc1wiLCB0aGlzLnNldHRpbmdzKTtcblx0fVxufVxuIl0sCiAgIm1hcHBpbmdzIjogIjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7OztBQ0VPLElBQU0saUJBQWlCLEVBQUUsU0FBUyxDQUFDLFdBQVcsV0FBVyxXQUFXLFdBQVcsU0FBUyxFQUFFO0FBRTFGLElBQU0sbUJBQWlDO0FBQUEsRUFDN0MsT0FBTSxvQkFBSSxLQUFLLEdBQUUsWUFBWTtBQUFBLEVBQzdCLFFBQVE7QUFBQSxFQUNSLFNBQVMsQ0FBQztBQUFBLEVBQ1Ysc0JBQXNCO0FBQUEsRUFDdEIsV0FBVztBQUFBLElBQ1YsU0FBUztBQUFBLElBQ1QsWUFBWTtBQUFBLElBQ1osVUFBVTtBQUFBLEVBQ1g7QUFDRDs7O0FEWkEsSUFBQUEsbUJBQXVCOzs7QUVBdkIsc0JBQStDO0FBRS9DLElBQXFCLDZCQUFyQixjQUF3RCxpQ0FBaUI7QUFBQSxFQUl4RSxZQUFZLEtBQVUsUUFBeUIsVUFBNEI7QUFDMUUsVUFBTSxLQUFLLE1BQU07QUFDakIsU0FBSyxTQUFTO0FBQ2QsU0FBSyxXQUFXO0FBQUEsRUFDakI7QUFBQSxFQUVjLGVBQWUsS0FBd0M7QUFBQTtBQUNwRSxhQUFPLEtBQUssU0FBUyxPQUFPLEdBQUc7QUFDL0IsWUFBTSxLQUFLLE9BQU8sYUFBYSxLQUFLLFFBQVE7QUFDNUMsV0FBSyxRQUFRO0FBQUEsSUFDZDtBQUFBO0FBQUEsRUFFUSx1QkFBdUI7QUFDOUIsVUFBTSxFQUFFLFlBQVksSUFBSTtBQUV4QixnQkFBWSxTQUFTLE1BQU0sRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUM3QyxTQUFLLGlCQUFpQixXQUFXO0FBRWpDLGVBQVcsQ0FBQyxLQUFLLE1BQU0sS0FBSyxPQUFPLFFBQVEsS0FBSyxTQUFTLE1B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 diff --git a/build/manifest.json b/build/manifest.json new file mode 100644 index 0000000..07a72ad --- /dev/null +++ b/build/manifest.json @@ -0,0 +1,10 @@ +{ + "id": "heatmap-calendar", + "name": "Heatmap Calendar", + "version": "0.6.0", + "minAppVersion": "0.12.0", + "description": "Activity Year Overview for DataviewJS, Github style – Track Goals, Progress, Habits, Tasks, Exercise, Finances, \"Dont Break the Chain\" etc.", + "author": "Richard Slettevoll", + "authorUrl": "https://richard.sl", + "isDesktopOnly": false +} diff --git a/build/styles.css b/build/styles.css new file mode 100644 index 0000000..9a364f5 --- /dev/null +++ b/build/styles.css @@ -0,0 +1,139 @@ +/* Obsidian/DataviewJS Github inspired calendar by Richard Slettevoll - https://richard.sl/ */ + +.heatmap-calendar-graph > * { + padding: 0px; + margin: 0px; + list-style: none; +} + +.heatmap-calendar-graph { + font-size: 0.65em; + display: grid; + grid-template-columns: auto 1fr; + grid-template-areas: + "year months" + "days boxes"; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, + "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + width: 100%; +} + +.heatmap-calendar-months { + display: grid; + grid-template-columns: repeat(12, minmax(0, 1fr)); + grid-area: months; + margin-top: 0.1em; + margin-bottom: 0.3em; + grid-gap: 0.3em; +} + +.heatmap-calendar-days { + grid-area: days; + margin-left: 0.1em; + margin-right: 0.3em; + white-space: nowrap; +} + +.heatmap-calendar-boxes { + grid-auto-flow: column; + grid-template-columns: repeat(53, minmax(0, 1fr)); + grid-area: boxes; +} + +.heatmap-calendar-days, +.heatmap-calendar-boxes { + display: grid; + grid-gap: 0.3em; + grid-template-rows: repeat(7, minmax(0, 1fr)); +} + +.heatmap-calendar-year { + grid-area: year; + font-weight: bold; + font-size: 1.2em; +} + +/* only label three days of the week */ +.heatmap-calendar-days li:nth-child(odd) { + visibility: hidden; +} + +.heatmap-calendar-boxes li { + position: relative; + font-size: 0.75em; + background-color: #ebedf0; +} + +.theme-dark .heatmap-calendar-boxes .isEmpty { + background: #333; +} + +.isEmpty { + width: 1em !important; +} + +.hasData { + width: 1em !important; +} + +.heatmap-calendar-boxes li:not(.task-list-item)::before { + content: unset; +} + +.heatmap-calendar-boxes .internal-link { + text-decoration: none; + position: absolute; + width: 100%; + height: 100%; + text-align: center; +} + +.heatmap-calendar-boxes .today { + border: solid 1px rgb(61, 61, 61); +} + +/* Settings */ + +.heatmap-calendar-settings-colors__color-box { + width: 10px; + height: 10px; + display: inline-block; + margin: 0 5px; +} + +.heatmap-calendar-settings-colors__color-box:first-child { + margin-left: 0; +} + +.heatmap-calendar-settings-colors__color-name { + display: inline-block; +} + +.heatmap-calendar-settings-colors__container { + align-items: center; + border-top: 1px solid var(--background-modifier-border); + display: flex; + justify-content: space-between; + padding: 0.5em 0; +} + +.heatmap-calendar-settings-colors__container h4 { + margin: 0.5em 0; +} + +.heatmap-calendar-settings-colors__new-color-input-container { + display: flex; + justify-content: space-between; +} + +.heatmap-calendar-settings-colors__new-color-input-container input { + margin-right: 1em; +} + +.heatmap-calendar-settings-colors__new-color-input-container input { + margin-right: 1em; +} + +.heatmap-calendar-settings-colors__new-color-input-value { + flex-grow: 1; +} diff --git a/styles.css b/styles.css index 8135fd3..57354ae 100644 --- a/styles.css +++ b/styles.css @@ -70,6 +70,7 @@ position: relative; font-size: 0.75em; background-color: #ebedf0; + margin-inline-start: 0 !important; } .theme-dark .heatmap-calendar-boxes .isEmpty { @@ -168,4 +169,4 @@ /* ---- /* ---- DEV Only /END ---- */ -/* ---- \ No newline at end of file +/* ----