diff --git a/.makemd/fileCache.mdc b/.makemd/fileCache.mdc new file mode 100644 index 0000000..afe2d99 Binary files /dev/null and b/.makemd/fileCache.mdc differ diff --git a/.makemd/superstate.mdc b/.makemd/superstate.mdc new file mode 100644 index 0000000..125c075 Binary files /dev/null and b/.makemd/superstate.mdc differ diff --git a/.obsidian/app.json b/.obsidian/app.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.obsidian/app.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/.obsidian/appearance.json b/.obsidian/appearance.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.obsidian/appearance.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/.obsidian/community-plugins.json b/.obsidian/community-plugins.json new file mode 100644 index 0000000..0ac0c2a --- /dev/null +++ b/.obsidian/community-plugins.json @@ -0,0 +1,15 @@ +[ + "table-editor-obsidian", + "better-search-views", + "better-word-count", + "bmo-chatbot", + "code-styler", + "editing-toolbar", + "obsidian-git", + "obsidian-hover-editor", + "make-md", + "obsidian-paste-image-rename", + "obsidian-spaced-repetition", + "templater-obsidian", + "obsidian-text-format" +] \ No newline at end of file diff --git a/.obsidian/core-plugins.json b/.obsidian/core-plugins.json new file mode 100644 index 0000000..3f2ab43 --- /dev/null +++ b/.obsidian/core-plugins.json @@ -0,0 +1,32 @@ +{ + "file-explorer": true, + "global-search": true, + "switcher": true, + "graph": true, + "backlink": true, + "canvas": true, + "outgoing-link": true, + "tag-pane": true, + "footnotes": false, + "properties": true, + "page-preview": true, + "daily-notes": true, + "templates": true, + "note-composer": true, + "command-palette": true, + "slash-command": false, + "editor-status": true, + "bookmarks": true, + "markdown-importer": false, + "zk-prefixer": false, + "random-note": false, + "outline": true, + "word-count": true, + "slides": false, + "audio-recorder": false, + "workspaces": false, + "file-recovery": true, + "publish": false, + "sync": true, + "bases": true +} \ No newline at end of file diff --git a/.obsidian/graph.json b/.obsidian/graph.json new file mode 100644 index 0000000..42a46ec --- /dev/null +++ b/.obsidian/graph.json @@ -0,0 +1,22 @@ +{ + "collapse-filter": true, + "search": "", + "showTags": false, + "showAttachments": false, + "hideUnresolved": false, + "showOrphans": true, + "collapse-color-groups": true, + "colorGroups": [], + "collapse-display": true, + "showArrow": false, + "textFadeMultiplier": 0, + "nodeSizeMultiplier": 1, + "lineSizeMultiplier": 1, + "collapse-forces": true, + "centerStrength": 0.518713248970312, + "repelStrength": 10, + "linkStrength": 1, + "linkDistance": 250, + "scale": 1, + "close": true +} \ No newline at end of file diff --git a/.obsidian/plugins/better-search-views/main.js b/.obsidian/plugins/better-search-views/main.js new file mode 100644 index 0000000..fffedf2 --- /dev/null +++ b/.obsidian/plugins/better-search-views/main.js @@ -0,0 +1,4733 @@ +/* +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 __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __esm = (fn, res) => function __init() { + return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; +}; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// node_modules/solid-js/dist/solid.cjs +var require_solid = __commonJS({ + "node_modules/solid-js/dist/solid.cjs"(exports) { + "use strict"; + var taskIdCounter = 1; + var isCallbackScheduled = false; + var isPerformingWork = false; + var taskQueue = []; + var currentTask = null; + var shouldYieldToHost = null; + var yieldInterval = 5; + var deadline = 0; + var maxYieldInterval = 300; + var scheduleCallback = null; + var scheduledCallback = null; + var maxSigned31BitInt = 1073741823; + function setupScheduler() { + const channel = new MessageChannel(), port = channel.port2; + scheduleCallback = () => port.postMessage(null); + channel.port1.onmessage = () => { + if (scheduledCallback !== null) { + const currentTime = performance.now(); + deadline = currentTime + yieldInterval; + const hasTimeRemaining = true; + try { + const hasMoreWork = scheduledCallback(hasTimeRemaining, currentTime); + if (!hasMoreWork) { + scheduledCallback = null; + } else + port.postMessage(null); + } catch (error) { + port.postMessage(null); + throw error; + } + } + }; + if (navigator && navigator.scheduling && navigator.scheduling.isInputPending) { + const scheduling = navigator.scheduling; + shouldYieldToHost = () => { + const currentTime = performance.now(); + if (currentTime >= deadline) { + if (scheduling.isInputPending()) { + return true; + } + return currentTime >= maxYieldInterval; + } else { + return false; + } + }; + } else { + shouldYieldToHost = () => performance.now() >= deadline; + } + } + function enqueue(taskQueue2, task) { + function findIndex() { + let m = 0; + let n = taskQueue2.length - 1; + while (m <= n) { + const k = n + m >> 1; + const cmp = task.expirationTime - taskQueue2[k].expirationTime; + if (cmp > 0) + m = k + 1; + else if (cmp < 0) + n = k - 1; + else + return k; + } + return m; + } + taskQueue2.splice(findIndex(), 0, task); + } + function requestCallback(fn, options) { + if (!scheduleCallback) + setupScheduler(); + let startTime = performance.now(), timeout = maxSigned31BitInt; + if (options && options.timeout) + timeout = options.timeout; + const newTask = { + id: taskIdCounter++, + fn, + startTime, + expirationTime: startTime + timeout + }; + enqueue(taskQueue, newTask); + if (!isCallbackScheduled && !isPerformingWork) { + isCallbackScheduled = true; + scheduledCallback = flushWork; + scheduleCallback(); + } + return newTask; + } + function cancelCallback(task) { + task.fn = null; + } + function flushWork(hasTimeRemaining, initialTime) { + isCallbackScheduled = false; + isPerformingWork = true; + try { + return workLoop(hasTimeRemaining, initialTime); + } finally { + currentTask = null; + isPerformingWork = false; + } + } + function workLoop(hasTimeRemaining, initialTime) { + let currentTime = initialTime; + currentTask = taskQueue[0] || null; + while (currentTask !== null) { + if (currentTask.expirationTime > currentTime && (!hasTimeRemaining || shouldYieldToHost())) { + break; + } + const callback = currentTask.fn; + if (callback !== null) { + currentTask.fn = null; + const didUserCallbackTimeout = currentTask.expirationTime <= currentTime; + callback(didUserCallbackTimeout); + currentTime = performance.now(); + if (currentTask === taskQueue[0]) { + taskQueue.shift(); + } + } else + taskQueue.shift(); + currentTask = taskQueue[0] || null; + } + return currentTask !== null; + } + var sharedConfig = { + context: void 0, + registry: void 0 + }; + function setHydrateContext(context) { + sharedConfig.context = context; + } + function nextHydrateContext() { + return { + ...sharedConfig.context, + id: `${sharedConfig.context.id}${sharedConfig.context.count++}-`, + count: 0 + }; + } + var equalFn = (a, b) => a === b; + var $PROXY = Symbol("solid-proxy"); + var $TRACK = Symbol("solid-track"); + var $DEVCOMP = Symbol("solid-dev-component"); + var signalOptions = { + equals: equalFn + }; + var ERROR = null; + var runEffects = runQueue; + var STALE = 1; + var PENDING = 2; + var UNOWNED = { + owned: null, + cleanups: null, + context: null, + owner: null + }; + var NO_INIT = {}; + var Owner = null; + var Transition = null; + var Scheduler = null; + var ExternalSourceFactory = null; + var Listener = null; + var Updates = null; + var Effects = null; + var ExecCount = 0; + var [transPending, setTransPending] = /* @__PURE__ */ createSignal(false); + function createRoot(fn, detachedOwner) { + const listener = Listener, owner = Owner, unowned = fn.length === 0, root = unowned ? UNOWNED : { + owned: null, + cleanups: null, + context: null, + owner: detachedOwner === void 0 ? owner : detachedOwner + }, updateFn = unowned ? fn : () => fn(() => untrack(() => cleanNode(root))); + Owner = root; + Listener = null; + try { + return runUpdates(updateFn, true); + } finally { + Listener = listener; + Owner = owner; + } + } + function createSignal(value, options) { + options = options ? Object.assign({}, signalOptions, options) : signalOptions; + const s = { + value, + observers: null, + observerSlots: null, + comparator: options.equals || void 0 + }; + const setter = (value2) => { + if (typeof value2 === "function") { + if (Transition && Transition.running && Transition.sources.has(s)) + value2 = value2(s.tValue); + else + value2 = value2(s.value); + } + return writeSignal(s, value2); + }; + return [readSignal.bind(s), setter]; + } + function createComputed(fn, value, options) { + const c = createComputation(fn, value, true, STALE); + if (Scheduler && Transition && Transition.running) + Updates.push(c); + else + updateComputation(c); + } + function createRenderEffect(fn, value, options) { + const c = createComputation(fn, value, false, STALE); + if (Scheduler && Transition && Transition.running) + Updates.push(c); + else + updateComputation(c); + } + function createEffect(fn, value, options) { + runEffects = runUserEffects; + const c = createComputation(fn, value, false, STALE), s = SuspenseContext && lookup(Owner, SuspenseContext.id); + if (s) + c.suspense = s; + if (!options || !options.render) + c.user = true; + Effects ? Effects.push(c) : updateComputation(c); + } + function createReaction(onInvalidate, options) { + let fn; + const c = createComputation(() => { + fn ? fn() : untrack(onInvalidate); + fn = void 0; + }, void 0, false, 0), s = SuspenseContext && lookup(Owner, SuspenseContext.id); + if (s) + c.suspense = s; + c.user = true; + return (tracking) => { + fn = tracking; + updateComputation(c); + }; + } + function createMemo(fn, value, options) { + options = options ? Object.assign({}, signalOptions, options) : signalOptions; + const c = createComputation(fn, value, true, 0); + c.observers = null; + c.observerSlots = null; + c.comparator = options.equals || void 0; + if (Scheduler && Transition && Transition.running) { + c.tState = STALE; + Updates.push(c); + } else + updateComputation(c); + return readSignal.bind(c); + } + function createResource(pSource, pFetcher, pOptions) { + let source; + let fetcher; + let options; + if (arguments.length === 2 && typeof pFetcher === "object" || arguments.length === 1) { + source = true; + fetcher = pSource; + options = pFetcher || {}; + } else { + source = pSource; + fetcher = pFetcher; + options = pOptions || {}; + } + let pr = null, initP = NO_INIT, id = null, loadedUnderTransition = false, scheduled = false, resolved = "initialValue" in options, dynamic = typeof source === "function" && createMemo(source); + const contexts = /* @__PURE__ */ new Set(), [value, setValue] = (options.storage || createSignal)(options.initialValue), [error, setError] = createSignal(void 0), [track, trigger] = createSignal(void 0, { + equals: false + }), [state, setState] = createSignal(resolved ? "ready" : "unresolved"); + if (sharedConfig.context) { + id = `${sharedConfig.context.id}${sharedConfig.context.count++}`; + let v; + if (options.ssrLoadFrom === "initial") + initP = options.initialValue; + else if (sharedConfig.load && (v = sharedConfig.load(id))) + initP = v[0]; + } + function loadEnd(p, v, error2, key) { + if (pr === p) { + pr = null; + key !== void 0 && (resolved = true); + if ((p === initP || v === initP) && options.onHydrated) + queueMicrotask(() => options.onHydrated(key, { + value: v + })); + initP = NO_INIT; + if (Transition && p && loadedUnderTransition) { + Transition.promises.delete(p); + loadedUnderTransition = false; + runUpdates(() => { + Transition.running = true; + completeLoad(v, error2); + }, false); + } else + completeLoad(v, error2); + } + return v; + } + function completeLoad(v, err) { + runUpdates(() => { + if (err === void 0) + setValue(() => v); + setState(err !== void 0 ? "errored" : resolved ? "ready" : "unresolved"); + setError(err); + for (const c of contexts.keys()) + c.decrement(); + contexts.clear(); + }, false); + } + function read() { + const c = SuspenseContext && lookup(Owner, SuspenseContext.id), v = value(), err = error(); + if (err !== void 0 && !pr) + throw err; + if (Listener && !Listener.user && c) { + createComputed(() => { + track(); + if (pr) { + if (c.resolved && Transition && loadedUnderTransition) + Transition.promises.add(pr); + else if (!contexts.has(c)) { + c.increment(); + contexts.add(c); + } + } + }); + } + return v; + } + function load(refetching = true) { + if (refetching !== false && scheduled) + return; + scheduled = false; + const lookup2 = dynamic ? dynamic() : source; + loadedUnderTransition = Transition && Transition.running; + if (lookup2 == null || lookup2 === false) { + loadEnd(pr, untrack(value)); + return; + } + if (Transition && pr) + Transition.promises.delete(pr); + const p = initP !== NO_INIT ? initP : untrack(() => fetcher(lookup2, { + value: value(), + refetching + })); + if (typeof p !== "object" || !(p && "then" in p)) { + loadEnd(pr, p, void 0, lookup2); + return p; + } + pr = p; + scheduled = true; + queueMicrotask(() => scheduled = false); + runUpdates(() => { + setState(resolved ? "refreshing" : "pending"); + trigger(); + }, false); + return p.then((v) => loadEnd(p, v, void 0, lookup2), (e) => loadEnd(p, void 0, castError(e), lookup2)); + } + Object.defineProperties(read, { + state: { + get: () => state() + }, + error: { + get: () => error() + }, + loading: { + get() { + const s = state(); + return s === "pending" || s === "refreshing"; + } + }, + latest: { + get() { + if (!resolved) + return read(); + const err = error(); + if (err && !pr) + throw err; + return value(); + } + } + }); + if (dynamic) + createComputed(() => load(false)); + else + load(false); + return [read, { + refetch: load, + mutate: setValue + }]; + } + function createDeferred(source, options) { + let t, timeout = options ? options.timeoutMs : void 0; + const node = createComputation(() => { + if (!t || !t.fn) + t = requestCallback(() => setDeferred(() => node.value), timeout !== void 0 ? { + timeout + } : void 0); + return source(); + }, void 0, true); + const [deferred, setDeferred] = createSignal(node.value, options); + updateComputation(node); + setDeferred(() => node.value); + return deferred; + } + function createSelector(source, fn = equalFn, options) { + const subs = /* @__PURE__ */ new Map(); + const node = createComputation((p) => { + const v = source(); + for (const [key, val] of subs.entries()) + if (fn(key, v) !== fn(key, p)) { + for (const c of val.values()) { + c.state = STALE; + if (c.pure) + Updates.push(c); + else + Effects.push(c); + } + } + return v; + }, void 0, true, STALE); + updateComputation(node); + return (key) => { + const listener = Listener; + if (listener) { + let l; + if (l = subs.get(key)) + l.add(listener); + else + subs.set(key, l = /* @__PURE__ */ new Set([listener])); + onCleanup(() => { + l.delete(listener); + !l.size && subs.delete(key); + }); + } + return fn(key, Transition && Transition.running && Transition.sources.has(node) ? node.tValue : node.value); + }; + } + function batch(fn) { + return runUpdates(fn, false); + } + function untrack(fn) { + if (Listener === null) + return fn(); + const listener = Listener; + Listener = null; + try { + return fn(); + } finally { + Listener = listener; + } + } + function on(deps, fn, options) { + const isArray = Array.isArray(deps); + let prevInput; + let defer = options && options.defer; + return (prevValue) => { + let input; + if (isArray) { + input = Array(deps.length); + for (let i = 0; i < deps.length; i++) + input[i] = deps[i](); + } else + input = deps(); + if (defer) { + defer = false; + return void 0; + } + const result = untrack(() => fn(input, prevInput, prevValue)); + prevInput = input; + return result; + }; + } + function onMount(fn) { + createEffect(() => untrack(fn)); + } + function onCleanup(fn) { + if (Owner === null) + ; + else if (Owner.cleanups === null) + Owner.cleanups = [fn]; + else + Owner.cleanups.push(fn); + return fn; + } + function catchError(fn, handler) { + ERROR || (ERROR = Symbol("error")); + Owner = createComputation(void 0, void 0, true); + Owner.context = { + [ERROR]: [handler] + }; + if (Transition && Transition.running) + Transition.sources.add(Owner); + try { + return fn(); + } catch (err) { + handleError(err); + } finally { + Owner = Owner.owner; + } + } + function onError(fn) { + ERROR || (ERROR = Symbol("error")); + if (Owner === null) + ; + else if (Owner.context === null) + Owner.context = { + [ERROR]: [fn] + }; + else if (!Owner.context[ERROR]) + Owner.context[ERROR] = [fn]; + else + Owner.context[ERROR].push(fn); + } + function getListener() { + return Listener; + } + function getOwner() { + return Owner; + } + function runWithOwner(o, fn) { + const prev = Owner; + const prevListener = Listener; + Owner = o; + Listener = null; + try { + return runUpdates(fn, true); + } catch (err) { + handleError(err); + } finally { + Owner = prev; + Listener = prevListener; + } + } + function enableScheduling(scheduler = requestCallback) { + Scheduler = scheduler; + } + function startTransition(fn) { + if (Transition && Transition.running) { + fn(); + return Transition.done; + } + const l = Listener; + const o = Owner; + return Promise.resolve().then(() => { + Listener = l; + Owner = o; + let t; + if (Scheduler || SuspenseContext) { + t = Transition || (Transition = { + sources: /* @__PURE__ */ new Set(), + effects: [], + promises: /* @__PURE__ */ new Set(), + disposed: /* @__PURE__ */ new Set(), + queue: /* @__PURE__ */ new Set(), + running: true + }); + t.done || (t.done = new Promise((res) => t.resolve = res)); + t.running = true; + } + runUpdates(fn, false); + Listener = Owner = null; + return t ? t.done : void 0; + }); + } + function useTransition() { + return [transPending, startTransition]; + } + function resumeEffects(e) { + Effects.push.apply(Effects, e); + e.length = 0; + } + function createContext(defaultValue, options) { + const id = Symbol("context"); + return { + id, + Provider: createProvider(id), + defaultValue + }; + } + function useContext(context) { + let ctx; + return (ctx = lookup(Owner, context.id)) !== void 0 ? ctx : context.defaultValue; + } + function children(fn) { + const children2 = createMemo(fn); + const memo = createMemo(() => resolveChildren(children2())); + memo.toArray = () => { + const c = memo(); + return Array.isArray(c) ? c : c != null ? [c] : []; + }; + return memo; + } + var SuspenseContext; + function getSuspenseContext() { + return SuspenseContext || (SuspenseContext = createContext({})); + } + function enableExternalSource(factory) { + if (ExternalSourceFactory) { + const oldFactory = ExternalSourceFactory; + ExternalSourceFactory = (fn, trigger) => { + const oldSource = oldFactory(fn, trigger); + const source = factory((x) => oldSource.track(x), trigger); + return { + track: (x) => source.track(x), + dispose() { + source.dispose(); + oldSource.dispose(); + } + }; + }; + } else { + ExternalSourceFactory = factory; + } + } + function readSignal() { + const runningTransition = Transition && Transition.running; + if (this.sources && (runningTransition ? this.tState : this.state)) { + if ((runningTransition ? this.tState : this.state) === STALE) + updateComputation(this); + else { + const updates = Updates; + Updates = null; + runUpdates(() => lookUpstream(this), false); + Updates = updates; + } + } + if (Listener) { + const sSlot = this.observers ? this.observers.length : 0; + if (!Listener.sources) { + Listener.sources = [this]; + Listener.sourceSlots = [sSlot]; + } else { + Listener.sources.push(this); + Listener.sourceSlots.push(sSlot); + } + if (!this.observers) { + this.observers = [Listener]; + this.observerSlots = [Listener.sources.length - 1]; + } else { + this.observers.push(Listener); + this.observerSlots.push(Listener.sources.length - 1); + } + } + if (runningTransition && Transition.sources.has(this)) + return this.tValue; + return this.value; + } + function writeSignal(node, value, isComp) { + let current = Transition && Transition.running && Transition.sources.has(node) ? node.tValue : node.value; + if (!node.comparator || !node.comparator(current, value)) { + if (Transition) { + const TransitionRunning = Transition.running; + if (TransitionRunning || !isComp && Transition.sources.has(node)) { + Transition.sources.add(node); + node.tValue = value; + } + if (!TransitionRunning) + node.value = value; + } else + node.value = value; + if (node.observers && node.observers.length) { + runUpdates(() => { + for (let i = 0; i < node.observers.length; i += 1) { + const o = node.observers[i]; + const TransitionRunning = Transition && Transition.running; + if (TransitionRunning && Transition.disposed.has(o)) + continue; + if (TransitionRunning ? !o.tState : !o.state) { + if (o.pure) + Updates.push(o); + else + Effects.push(o); + if (o.observers) + markDownstream(o); + } + if (!TransitionRunning) + o.state = STALE; + else + o.tState = STALE; + } + if (Updates.length > 1e6) { + Updates = []; + if (false) + ; + throw new Error(); + } + }, false); + } + } + return value; + } + function updateComputation(node) { + if (!node.fn) + return; + cleanNode(node); + const owner = Owner, listener = Listener, time = ExecCount; + Listener = Owner = node; + runComputation(node, Transition && Transition.running && Transition.sources.has(node) ? node.tValue : node.value, time); + if (Transition && !Transition.running && Transition.sources.has(node)) { + queueMicrotask(() => { + runUpdates(() => { + Transition && (Transition.running = true); + Listener = Owner = node; + runComputation(node, node.tValue, time); + Listener = Owner = null; + }, false); + }); + } + Listener = listener; + Owner = owner; + } + function runComputation(node, value, time) { + let nextValue; + try { + nextValue = node.fn(value); + } catch (err) { + if (node.pure) { + if (Transition && Transition.running) { + node.tState = STALE; + node.tOwned && node.tOwned.forEach(cleanNode); + node.tOwned = void 0; + } else { + node.state = STALE; + node.owned && node.owned.forEach(cleanNode); + node.owned = null; + } + } + node.updatedAt = time + 1; + return handleError(err); + } + if (!node.updatedAt || node.updatedAt <= time) { + if (node.updatedAt != null && "observers" in node) { + writeSignal(node, nextValue, true); + } else if (Transition && Transition.running && node.pure) { + Transition.sources.add(node); + node.tValue = nextValue; + } else + node.value = nextValue; + node.updatedAt = time; + } + } + function createComputation(fn, init, pure, state = STALE, options) { + const c = { + fn, + state, + updatedAt: null, + owned: null, + sources: null, + sourceSlots: null, + cleanups: null, + value: init, + owner: Owner, + context: null, + pure + }; + if (Transition && Transition.running) { + c.state = 0; + c.tState = state; + } + if (Owner === null) + ; + else if (Owner !== UNOWNED) { + if (Transition && Transition.running && Owner.pure) { + if (!Owner.tOwned) + Owner.tOwned = [c]; + else + Owner.tOwned.push(c); + } else { + if (!Owner.owned) + Owner.owned = [c]; + else + Owner.owned.push(c); + } + } + if (ExternalSourceFactory) { + const [track, trigger] = createSignal(void 0, { + equals: false + }); + const ordinary = ExternalSourceFactory(c.fn, trigger); + onCleanup(() => ordinary.dispose()); + const triggerInTransition = () => startTransition(trigger).then(() => inTransition.dispose()); + const inTransition = ExternalSourceFactory(c.fn, triggerInTransition); + c.fn = (x) => { + track(); + return Transition && Transition.running ? inTransition.track(x) : ordinary.track(x); + }; + } + return c; + } + function runTop(node) { + const runningTransition = Transition && Transition.running; + if ((runningTransition ? node.tState : node.state) === 0) + return; + if ((runningTransition ? node.tState : node.state) === PENDING) + return lookUpstream(node); + if (node.suspense && untrack(node.suspense.inFallback)) + return node.suspense.effects.push(node); + const ancestors = [node]; + while ((node = node.owner) && (!node.updatedAt || node.updatedAt < ExecCount)) { + if (runningTransition && Transition.disposed.has(node)) + return; + if (runningTransition ? node.tState : node.state) + ancestors.push(node); + } + for (let i = ancestors.length - 1; i >= 0; i--) { + node = ancestors[i]; + if (runningTransition) { + let top = node, prev = ancestors[i + 1]; + while ((top = top.owner) && top !== prev) { + if (Transition.disposed.has(top)) + return; + } + } + if ((runningTransition ? node.tState : node.state) === STALE) { + updateComputation(node); + } else if ((runningTransition ? node.tState : node.state) === PENDING) { + const updates = Updates; + Updates = null; + runUpdates(() => lookUpstream(node, ancestors[0]), false); + Updates = updates; + } + } + } + function runUpdates(fn, init) { + if (Updates) + return fn(); + let wait = false; + if (!init) + Updates = []; + if (Effects) + wait = true; + else + Effects = []; + ExecCount++; + try { + const res = fn(); + completeUpdates(wait); + return res; + } catch (err) { + if (!wait) + Effects = null; + Updates = null; + handleError(err); + } + } + function completeUpdates(wait) { + if (Updates) { + if (Scheduler && Transition && Transition.running) + scheduleQueue(Updates); + else + runQueue(Updates); + Updates = null; + } + if (wait) + return; + let res; + if (Transition) { + if (!Transition.promises.size && !Transition.queue.size) { + const sources = Transition.sources; + const disposed = Transition.disposed; + Effects.push.apply(Effects, Transition.effects); + res = Transition.resolve; + for (const e2 of Effects) { + "tState" in e2 && (e2.state = e2.tState); + delete e2.tState; + } + Transition = null; + runUpdates(() => { + for (const d of disposed) + cleanNode(d); + for (const v of sources) { + v.value = v.tValue; + if (v.owned) { + for (let i = 0, len = v.owned.length; i < len; i++) + cleanNode(v.owned[i]); + } + if (v.tOwned) + v.owned = v.tOwned; + delete v.tValue; + delete v.tOwned; + v.tState = 0; + } + setTransPending(false); + }, false); + } else if (Transition.running) { + Transition.running = false; + Transition.effects.push.apply(Transition.effects, Effects); + Effects = null; + setTransPending(true); + return; + } + } + const e = Effects; + Effects = null; + if (e.length) + runUpdates(() => runEffects(e), false); + if (res) + res(); + } + function runQueue(queue) { + for (let i = 0; i < queue.length; i++) + runTop(queue[i]); + } + function scheduleQueue(queue) { + for (let i = 0; i < queue.length; i++) { + const item = queue[i]; + const tasks = Transition.queue; + if (!tasks.has(item)) { + tasks.add(item); + Scheduler(() => { + tasks.delete(item); + runUpdates(() => { + Transition.running = true; + runTop(item); + }, false); + Transition && (Transition.running = false); + }); + } + } + } + function runUserEffects(queue) { + let i, userLength = 0; + for (i = 0; i < queue.length; i++) { + const e = queue[i]; + if (!e.user) + runTop(e); + else + queue[userLength++] = e; + } + if (sharedConfig.context) { + if (sharedConfig.count) { + sharedConfig.effects || (sharedConfig.effects = []); + sharedConfig.effects.push(...queue.slice(0, userLength)); + return; + } else if (sharedConfig.effects) { + queue = [...sharedConfig.effects, ...queue]; + userLength += sharedConfig.effects.length; + delete sharedConfig.effects; + } + setHydrateContext(); + } + for (i = 0; i < userLength; i++) + runTop(queue[i]); + } + function lookUpstream(node, ignore) { + const runningTransition = Transition && Transition.running; + if (runningTransition) + node.tState = 0; + else + node.state = 0; + for (let i = 0; i < node.sources.length; i += 1) { + const source = node.sources[i]; + if (source.sources) { + const state = runningTransition ? source.tState : source.state; + if (state === STALE) { + if (source !== ignore && (!source.updatedAt || source.updatedAt < ExecCount)) + runTop(source); + } else if (state === PENDING) + lookUpstream(source, ignore); + } + } + } + function markDownstream(node) { + const runningTransition = Transition && Transition.running; + for (let i = 0; i < node.observers.length; i += 1) { + const o = node.observers[i]; + if (runningTransition ? !o.tState : !o.state) { + if (runningTransition) + o.tState = PENDING; + else + o.state = PENDING; + if (o.pure) + Updates.push(o); + else + Effects.push(o); + o.observers && markDownstream(o); + } + } + } + function cleanNode(node) { + let i; + if (node.sources) { + while (node.sources.length) { + const source = node.sources.pop(), index = node.sourceSlots.pop(), obs = source.observers; + if (obs && obs.length) { + const n = obs.pop(), s = source.observerSlots.pop(); + if (index < obs.length) { + n.sourceSlots[s] = index; + obs[index] = n; + source.observerSlots[index] = s; + } + } + } + } + if (Transition && Transition.running && node.pure) { + if (node.tOwned) { + for (i = node.tOwned.length - 1; i >= 0; i--) + cleanNode(node.tOwned[i]); + delete node.tOwned; + } + reset(node, true); + } else if (node.owned) { + for (i = node.owned.length - 1; i >= 0; i--) + cleanNode(node.owned[i]); + node.owned = null; + } + if (node.cleanups) { + for (i = node.cleanups.length - 1; i >= 0; i--) + node.cleanups[i](); + node.cleanups = null; + } + if (Transition && Transition.running) + node.tState = 0; + else + node.state = 0; + node.context = null; + } + function reset(node, top) { + if (!top) { + node.tState = 0; + Transition.disposed.add(node); + } + if (node.owned) { + for (let i = 0; i < node.owned.length; i++) + reset(node.owned[i]); + } + } + function castError(err) { + if (err instanceof Error) + return err; + return new Error(typeof err === "string" ? err : "Unknown error", { + cause: err + }); + } + function runErrors(err, fns, owner) { + try { + for (const f of fns) + f(err); + } catch (e) { + handleError(e, owner && owner.owner || null); + } + } + function handleError(err, owner = Owner) { + const fns = ERROR && lookup(owner, ERROR); + const error = castError(err); + if (!fns) + throw error; + if (Effects) + Effects.push({ + fn() { + runErrors(error, fns, owner); + }, + state: STALE + }); + else + runErrors(error, fns, owner); + } + function lookup(owner, key) { + return owner ? owner.context && owner.context[key] !== void 0 ? owner.context[key] : lookup(owner.owner, key) : void 0; + } + function resolveChildren(children2) { + if (typeof children2 === "function" && !children2.length) + return resolveChildren(children2()); + if (Array.isArray(children2)) { + const results = []; + for (let i = 0; i < children2.length; i++) { + const result = resolveChildren(children2[i]); + Array.isArray(result) ? results.push.apply(results, result) : results.push(result); + } + return results; + } + return children2; + } + function createProvider(id, options) { + return function provider(props) { + let res; + createRenderEffect(() => res = untrack(() => { + Owner.context = { + [id]: props.value + }; + return children(() => props.children); + }), void 0); + return res; + }; + } + function observable(input) { + return { + subscribe(observer) { + if (!(observer instanceof Object) || observer == null) { + throw new TypeError("Expected the observer to be an object."); + } + const handler = typeof observer === "function" ? observer : observer.next && observer.next.bind(observer); + if (!handler) { + return { + unsubscribe() { + } + }; + } + const dispose2 = createRoot((disposer) => { + createEffect(() => { + const v = input(); + untrack(() => handler(v)); + }); + return disposer; + }); + if (getOwner()) + onCleanup(dispose2); + return { + unsubscribe() { + dispose2(); + } + }; + }, + [Symbol.observable || "@@observable"]() { + return this; + } + }; + } + function from(producer) { + const [s, set] = createSignal(void 0, { + equals: false + }); + if ("subscribe" in producer) { + const unsub = producer.subscribe((v) => set(() => v)); + onCleanup(() => "unsubscribe" in unsub ? unsub.unsubscribe() : unsub()); + } else { + const clean = producer(set); + onCleanup(clean); + } + return s; + } + var FALLBACK = Symbol("fallback"); + function dispose(d) { + for (let i = 0; i < d.length; i++) + d[i](); + } + function mapArray(list, mapFn, options = {}) { + let items = [], mapped = [], disposers = [], len = 0, indexes = mapFn.length > 1 ? [] : null; + onCleanup(() => dispose(disposers)); + return () => { + let newItems = list() || [], i, j; + newItems[$TRACK]; + return untrack(() => { + let newLen = newItems.length, newIndices, newIndicesNext, temp, tempdisposers, tempIndexes, start, end, newEnd, item; + if (newLen === 0) { + if (len !== 0) { + dispose(disposers); + disposers = []; + items = []; + mapped = []; + len = 0; + indexes && (indexes = []); + } + if (options.fallback) { + items = [FALLBACK]; + mapped[0] = createRoot((disposer) => { + disposers[0] = disposer; + return options.fallback(); + }); + len = 1; + } + } else if (len === 0) { + mapped = new Array(newLen); + for (j = 0; j < newLen; j++) { + items[j] = newItems[j]; + mapped[j] = createRoot(mapper); + } + len = newLen; + } else { + temp = new Array(newLen); + tempdisposers = new Array(newLen); + indexes && (tempIndexes = new Array(newLen)); + for (start = 0, end = Math.min(len, newLen); start < end && items[start] === newItems[start]; start++) + ; + for (end = len - 1, newEnd = newLen - 1; end >= start && newEnd >= start && items[end] === newItems[newEnd]; end--, newEnd--) { + temp[newEnd] = mapped[end]; + tempdisposers[newEnd] = disposers[end]; + indexes && (tempIndexes[newEnd] = indexes[end]); + } + newIndices = /* @__PURE__ */ new Map(); + newIndicesNext = new Array(newEnd + 1); + for (j = newEnd; j >= start; j--) { + item = newItems[j]; + i = newIndices.get(item); + newIndicesNext[j] = i === void 0 ? -1 : i; + newIndices.set(item, j); + } + for (i = start; i <= end; i++) { + item = items[i]; + j = newIndices.get(item); + if (j !== void 0 && j !== -1) { + temp[j] = mapped[i]; + tempdisposers[j] = disposers[i]; + indexes && (tempIndexes[j] = indexes[i]); + j = newIndicesNext[j]; + newIndices.set(item, j); + } else + disposers[i](); + } + for (j = start; j < newLen; j++) { + if (j in temp) { + mapped[j] = temp[j]; + disposers[j] = tempdisposers[j]; + if (indexes) { + indexes[j] = tempIndexes[j]; + indexes[j](j); + } + } else + mapped[j] = createRoot(mapper); + } + mapped = mapped.slice(0, len = newLen); + items = newItems.slice(0); + } + return mapped; + }); + function mapper(disposer) { + disposers[j] = disposer; + if (indexes) { + const [s, set] = createSignal(j); + indexes[j] = set; + return mapFn(newItems[j], s); + } + return mapFn(newItems[j]); + } + }; + } + function indexArray(list, mapFn, options = {}) { + let items = [], mapped = [], disposers = [], signals = [], len = 0, i; + onCleanup(() => dispose(disposers)); + return () => { + const newItems = list() || []; + newItems[$TRACK]; + return untrack(() => { + if (newItems.length === 0) { + if (len !== 0) { + dispose(disposers); + disposers = []; + items = []; + mapped = []; + len = 0; + signals = []; + } + if (options.fallback) { + items = [FALLBACK]; + mapped[0] = createRoot((disposer) => { + disposers[0] = disposer; + return options.fallback(); + }); + len = 1; + } + return mapped; + } + if (items[0] === FALLBACK) { + disposers[0](); + disposers = []; + items = []; + mapped = []; + len = 0; + } + for (i = 0; i < newItems.length; i++) { + if (i < items.length && items[i] !== newItems[i]) { + signals[i](() => newItems[i]); + } else if (i >= items.length) { + mapped[i] = createRoot(mapper); + } + } + for (; i < items.length; i++) { + disposers[i](); + } + len = signals.length = disposers.length = newItems.length; + items = newItems.slice(0); + return mapped = mapped.slice(0, len); + }); + function mapper(disposer) { + disposers[i] = disposer; + const [s, set] = createSignal(newItems[i]); + signals[i] = set; + return mapFn(s, i); + } + }; + } + var hydrationEnabled = false; + function enableHydration() { + hydrationEnabled = true; + } + function createComponent(Comp, props) { + if (hydrationEnabled) { + if (sharedConfig.context) { + const c = sharedConfig.context; + setHydrateContext(nextHydrateContext()); + const r = untrack(() => Comp(props || {})); + setHydrateContext(c); + return r; + } + } + return untrack(() => Comp(props || {})); + } + function trueFn() { + return true; + } + var propTraps = { + get(_, property, receiver) { + if (property === $PROXY) + return receiver; + return _.get(property); + }, + has(_, property) { + if (property === $PROXY) + return true; + return _.has(property); + }, + set: trueFn, + deleteProperty: trueFn, + getOwnPropertyDescriptor(_, property) { + return { + configurable: true, + enumerable: true, + get() { + return _.get(property); + }, + set: trueFn, + deleteProperty: trueFn + }; + }, + ownKeys(_) { + return _.keys(); + } + }; + function resolveSource(s) { + return !(s = typeof s === "function" ? s() : s) ? {} : s; + } + function resolveSources() { + for (let i = 0, length = this.length; i < length; ++i) { + const v = this[i](); + if (v !== void 0) + return v; + } + } + function mergeProps(...sources) { + let proxy = false; + for (let i = 0; i < sources.length; i++) { + const s = sources[i]; + proxy = proxy || !!s && $PROXY in s; + sources[i] = typeof s === "function" ? (proxy = true, createMemo(s)) : s; + } + if (proxy) { + return new Proxy({ + get(property) { + for (let i = sources.length - 1; i >= 0; i--) { + const v = resolveSource(sources[i])[property]; + if (v !== void 0) + return v; + } + }, + has(property) { + for (let i = sources.length - 1; i >= 0; i--) { + if (property in resolveSource(sources[i])) + return true; + } + return false; + }, + keys() { + const keys = []; + for (let i = 0; i < sources.length; i++) + keys.push(...Object.keys(resolveSource(sources[i]))); + return [...new Set(keys)]; + } + }, propTraps); + } + const target = {}; + const sourcesMap = {}; + const defined = /* @__PURE__ */ new Set(); + for (let i = sources.length - 1; i >= 0; i--) { + const source = sources[i]; + if (!source) + continue; + const sourceKeys = Object.getOwnPropertyNames(source); + for (let i2 = 0, length = sourceKeys.length; i2 < length; i2++) { + const key = sourceKeys[i2]; + if (key === "__proto__" || key === "constructor") + continue; + const desc = Object.getOwnPropertyDescriptor(source, key); + if (!defined.has(key)) { + if (desc.get) { + defined.add(key); + Object.defineProperty(target, key, { + enumerable: true, + configurable: true, + get: resolveSources.bind(sourcesMap[key] = [desc.get.bind(source)]) + }); + } else { + if (desc.value !== void 0) + defined.add(key); + target[key] = desc.value; + } + } else { + const sources2 = sourcesMap[key]; + if (sources2) { + if (desc.get) { + sources2.push(desc.get.bind(source)); + } else if (desc.value !== void 0) { + sources2.push(() => desc.value); + } + } else if (target[key] === void 0) + target[key] = desc.value; + } + } + } + return target; + } + function splitProps(props, ...keys) { + if ($PROXY in props) { + const blocked = new Set(keys.length > 1 ? keys.flat() : keys[0]); + const res = keys.map((k) => { + return new Proxy({ + get(property) { + return k.includes(property) ? props[property] : void 0; + }, + has(property) { + return k.includes(property) && property in props; + }, + keys() { + return k.filter((property) => property in props); + } + }, propTraps); + }); + res.push(new Proxy({ + get(property) { + return blocked.has(property) ? void 0 : props[property]; + }, + has(property) { + return blocked.has(property) ? false : property in props; + }, + keys() { + return Object.keys(props).filter((k) => !blocked.has(k)); + } + }, propTraps)); + return res; + } + const otherObject = {}; + const objects = keys.map(() => ({})); + for (const propName of Object.getOwnPropertyNames(props)) { + const desc = Object.getOwnPropertyDescriptor(props, propName); + const isDefaultDesc = !desc.get && !desc.set && desc.enumerable && desc.writable && desc.configurable; + let blocked = false; + let objectIndex = 0; + for (const k of keys) { + if (k.includes(propName)) { + blocked = true; + isDefaultDesc ? objects[objectIndex][propName] = desc.value : Object.defineProperty(objects[objectIndex], propName, desc); + } + ++objectIndex; + } + if (!blocked) { + isDefaultDesc ? otherObject[propName] = desc.value : Object.defineProperty(otherObject, propName, desc); + } + } + return [...objects, otherObject]; + } + function lazy(fn) { + let comp; + let p; + const wrap = (props) => { + const ctx = sharedConfig.context; + if (ctx) { + const [s, set] = createSignal(); + sharedConfig.count || (sharedConfig.count = 0); + sharedConfig.count++; + (p || (p = fn())).then((mod) => { + setHydrateContext(ctx); + sharedConfig.count--; + set(() => mod.default); + setHydrateContext(); + }); + comp = s; + } else if (!comp) { + const [s] = createResource(() => (p || (p = fn())).then((mod) => mod.default)); + comp = s; + } + let Comp; + return createMemo(() => (Comp = comp()) && untrack(() => { + if (false) + ; + if (!ctx) + return Comp(props); + const c = sharedConfig.context; + setHydrateContext(ctx); + const r = Comp(props); + setHydrateContext(c); + return r; + })); + }; + wrap.preload = () => p || ((p = fn()).then((mod) => comp = () => mod.default), p); + return wrap; + } + var counter = 0; + function createUniqueId() { + const ctx = sharedConfig.context; + return ctx ? `${ctx.id}${ctx.count++}` : `cl-${counter++}`; + } + var narrowedError = (name) => `Stale read from <${name}>.`; + function For(props) { + const fallback = "fallback" in props && { + fallback: () => props.fallback + }; + return createMemo(mapArray(() => props.each, props.children, fallback || void 0)); + } + function Index(props) { + const fallback = "fallback" in props && { + fallback: () => props.fallback + }; + return createMemo(indexArray(() => props.each, props.children, fallback || void 0)); + } + function Show(props) { + const keyed = props.keyed; + const condition = createMemo(() => props.when, void 0, { + equals: (a, b) => keyed ? a === b : !a === !b + }); + return createMemo(() => { + const c = condition(); + if (c) { + const child = props.children; + const fn = typeof child === "function" && child.length > 0; + return fn ? untrack(() => child(keyed ? c : () => { + if (!untrack(condition)) + throw narrowedError("Show"); + return props.when; + })) : child; + } + return props.fallback; + }, void 0, void 0); + } + function Switch(props) { + let keyed = false; + const equals = (a, b) => a[0] === b[0] && (keyed ? a[1] === b[1] : !a[1] === !b[1]) && a[2] === b[2]; + const conditions = children(() => props.children), evalConditions = createMemo(() => { + let conds = conditions(); + if (!Array.isArray(conds)) + conds = [conds]; + for (let i = 0; i < conds.length; i++) { + const c = conds[i].when; + if (c) { + keyed = !!conds[i].keyed; + return [i, c, conds[i]]; + } + } + return [-1]; + }, void 0, { + equals + }); + return createMemo(() => { + const [index, when, cond] = evalConditions(); + if (index < 0) + return props.fallback; + const c = cond.children; + const fn = typeof c === "function" && c.length > 0; + return fn ? untrack(() => c(keyed ? when : () => { + if (untrack(evalConditions)[0] !== index) + throw narrowedError("Match"); + return cond.when; + })) : c; + }, void 0, void 0); + } + function Match(props) { + return props; + } + var Errors; + function resetErrorBoundaries() { + Errors && [...Errors].forEach((fn) => fn()); + } + function ErrorBoundary(props) { + let err; + let v; + if (sharedConfig.context && sharedConfig.load && (v = sharedConfig.load(sharedConfig.context.id + sharedConfig.context.count))) + err = v[0]; + const [errored, setErrored] = createSignal(err, void 0); + Errors || (Errors = /* @__PURE__ */ new Set()); + Errors.add(setErrored); + onCleanup(() => Errors.delete(setErrored)); + return createMemo(() => { + let e; + if (e = errored()) { + const f = props.fallback; + return typeof f === "function" && f.length ? untrack(() => f(e, () => setErrored())) : f; + } + return catchError(() => props.children, setErrored); + }, void 0, void 0); + } + var suspenseListEquals = (a, b) => a.showContent === b.showContent && a.showFallback === b.showFallback; + var SuspenseListContext = createContext(); + function SuspenseList(props) { + let [wrapper, setWrapper] = createSignal(() => ({ + inFallback: false + })), show; + const listContext = useContext(SuspenseListContext); + const [registry, setRegistry] = createSignal([]); + if (listContext) { + show = listContext.register(createMemo(() => wrapper()().inFallback)); + } + const resolved = createMemo((prev) => { + const reveal = props.revealOrder, tail = props.tail, { + showContent = true, + showFallback = true + } = show ? show() : {}, reg = registry(), reverse = reveal === "backwards"; + if (reveal === "together") { + const all = reg.every((inFallback2) => !inFallback2()); + const res2 = reg.map(() => ({ + showContent: all && showContent, + showFallback + })); + res2.inFallback = !all; + return res2; + } + let stop = false; + let inFallback = prev.inFallback; + const res = []; + for (let i = 0, len = reg.length; i < len; i++) { + const n = reverse ? len - i - 1 : i, s = reg[n](); + if (!stop && !s) { + res[n] = { + showContent, + showFallback + }; + } else { + const next = !stop; + if (next) + inFallback = true; + res[n] = { + showContent: next, + showFallback: !tail || next && tail === "collapsed" ? showFallback : false + }; + stop = true; + } + } + if (!stop) + inFallback = false; + res.inFallback = inFallback; + return res; + }, { + inFallback: false + }); + setWrapper(() => resolved); + return createComponent(SuspenseListContext.Provider, { + value: { + register: (inFallback) => { + let index; + setRegistry((registry2) => { + index = registry2.length; + return [...registry2, inFallback]; + }); + return createMemo(() => resolved()[index], void 0, { + equals: suspenseListEquals + }); + } + }, + get children() { + return props.children; + } + }); + } + function Suspense(props) { + let counter2 = 0, show, ctx, p, flicker, error; + const [inFallback, setFallback] = createSignal(false), SuspenseContext2 = getSuspenseContext(), store = { + increment: () => { + if (++counter2 === 1) + setFallback(true); + }, + decrement: () => { + if (--counter2 === 0) + setFallback(false); + }, + inFallback, + effects: [], + resolved: false + }, owner = getOwner(); + if (sharedConfig.context && sharedConfig.load) { + const key = sharedConfig.context.id + sharedConfig.context.count; + let ref = sharedConfig.load(key); + if (ref && (p = ref[0]) && p !== "$$f") { + if (typeof p !== "object" || !("then" in p)) + p = Promise.resolve(p); + const [s, set] = createSignal(void 0, { + equals: false + }); + flicker = s; + p.then((err) => { + if (err || sharedConfig.done) { + err && (error = err); + return set(); + } + sharedConfig.gather(key); + setHydrateContext(ctx); + set(); + setHydrateContext(); + }); + } + } + const listContext = useContext(SuspenseListContext); + if (listContext) + show = listContext.register(store.inFallback); + let dispose2; + onCleanup(() => dispose2 && dispose2()); + return createComponent(SuspenseContext2.Provider, { + value: store, + get children() { + return createMemo(() => { + if (error) + throw error; + ctx = sharedConfig.context; + if (flicker) { + flicker(); + return flicker = void 0; + } + if (ctx && p === "$$f") + setHydrateContext(); + const rendered = createMemo(() => props.children); + return createMemo((prev) => { + const inFallback2 = store.inFallback(), { + showContent = true, + showFallback = true + } = show ? show() : {}; + if ((!inFallback2 || p && p !== "$$f") && showContent) { + store.resolved = true; + dispose2 && dispose2(); + dispose2 = ctx = p = void 0; + resumeEffects(store.effects); + return rendered(); + } + if (!showFallback) + return; + if (dispose2) + return prev; + return createRoot((disposer) => { + dispose2 = disposer; + if (ctx) { + setHydrateContext({ + id: ctx.id + "f", + count: 0 + }); + ctx = void 0; + } + return props.fallback; + }, owner); + }); + }); + } + }); + } + var DEV = void 0; + exports.$DEVCOMP = $DEVCOMP; + exports.$PROXY = $PROXY; + exports.$TRACK = $TRACK; + exports.DEV = DEV; + exports.ErrorBoundary = ErrorBoundary; + exports.For = For; + exports.Index = Index; + exports.Match = Match; + exports.Show = Show; + exports.Suspense = Suspense; + exports.SuspenseList = SuspenseList; + exports.Switch = Switch; + exports.batch = batch; + exports.cancelCallback = cancelCallback; + exports.catchError = catchError; + exports.children = children; + exports.createComponent = createComponent; + exports.createComputed = createComputed; + exports.createContext = createContext; + exports.createDeferred = createDeferred; + exports.createEffect = createEffect; + exports.createMemo = createMemo; + exports.createReaction = createReaction; + exports.createRenderEffect = createRenderEffect; + exports.createResource = createResource; + exports.createRoot = createRoot; + exports.createSelector = createSelector; + exports.createSignal = createSignal; + exports.createUniqueId = createUniqueId; + exports.enableExternalSource = enableExternalSource; + exports.enableHydration = enableHydration; + exports.enableScheduling = enableScheduling; + exports.equalFn = equalFn; + exports.from = from; + exports.getListener = getListener; + exports.getOwner = getOwner; + exports.indexArray = indexArray; + exports.lazy = lazy; + exports.mapArray = mapArray; + exports.mergeProps = mergeProps; + exports.observable = observable; + exports.on = on; + exports.onCleanup = onCleanup; + exports.onError = onError; + exports.onMount = onMount; + exports.requestCallback = requestCallback; + exports.resetErrorBoundaries = resetErrorBoundaries; + exports.runWithOwner = runWithOwner; + exports.sharedConfig = sharedConfig; + exports.splitProps = splitProps; + exports.startTransition = startTransition; + exports.untrack = untrack; + exports.useContext = useContext; + exports.useTransition = useTransition; + } +}); + +// node_modules/solid-js/web/dist/web.cjs +var require_web = __commonJS({ + "node_modules/solid-js/web/dist/web.cjs"(exports) { + "use strict"; + var solidJs = require_solid(); + var booleans = ["allowfullscreen", "async", "autofocus", "autoplay", "checked", "controls", "default", "disabled", "formnovalidate", "hidden", "indeterminate", "ismap", "loop", "multiple", "muted", "nomodule", "novalidate", "open", "playsinline", "readonly", "required", "reversed", "seamless", "selected"]; + var Properties = /* @__PURE__ */ new Set(["className", "value", "readOnly", "formNoValidate", "isMap", "noModule", "playsInline", ...booleans]); + var ChildProperties = /* @__PURE__ */ new Set(["innerHTML", "textContent", "innerText", "children"]); + var Aliases = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(null), { + className: "class", + htmlFor: "for" + }); + var PropAliases = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(null), { + class: "className", + formnovalidate: { + $: "formNoValidate", + BUTTON: 1, + INPUT: 1 + }, + ismap: { + $: "isMap", + IMG: 1 + }, + nomodule: { + $: "noModule", + SCRIPT: 1 + }, + playsinline: { + $: "playsInline", + VIDEO: 1 + }, + readonly: { + $: "readOnly", + INPUT: 1, + TEXTAREA: 1 + } + }); + function getPropAlias(prop, tagName) { + const a = PropAliases[prop]; + return typeof a === "object" ? a[tagName] ? a["$"] : void 0 : a; + } + var DelegatedEvents = /* @__PURE__ */ new Set(["beforeinput", "click", "dblclick", "contextmenu", "focusin", "focusout", "input", "keydown", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "pointerdown", "pointermove", "pointerout", "pointerover", "pointerup", "touchend", "touchmove", "touchstart"]); + var SVGElements = /* @__PURE__ */ new Set([ + "altGlyph", + "altGlyphDef", + "altGlyphItem", + "animate", + "animateColor", + "animateMotion", + "animateTransform", + "circle", + "clipPath", + "color-profile", + "cursor", + "defs", + "desc", + "ellipse", + "feBlend", + "feColorMatrix", + "feComponentTransfer", + "feComposite", + "feConvolveMatrix", + "feDiffuseLighting", + "feDisplacementMap", + "feDistantLight", + "feFlood", + "feFuncA", + "feFuncB", + "feFuncG", + "feFuncR", + "feGaussianBlur", + "feImage", + "feMerge", + "feMergeNode", + "feMorphology", + "feOffset", + "fePointLight", + "feSpecularLighting", + "feSpotLight", + "feTile", + "feTurbulence", + "filter", + "font", + "font-face", + "font-face-format", + "font-face-name", + "font-face-src", + "font-face-uri", + "foreignObject", + "g", + "glyph", + "glyphRef", + "hkern", + "image", + "line", + "linearGradient", + "marker", + "mask", + "metadata", + "missing-glyph", + "mpath", + "path", + "pattern", + "polygon", + "polyline", + "radialGradient", + "rect", + "set", + "stop", + "svg", + "switch", + "symbol", + "text", + "textPath", + "tref", + "tspan", + "use", + "view", + "vkern" + ]); + var SVGNamespace = { + xlink: "http://www.w3.org/1999/xlink", + xml: "http://www.w3.org/XML/1998/namespace" + }; + var DOMElements = /* @__PURE__ */ new Set(["html", "base", "head", "link", "meta", "style", "title", "body", "address", "article", "aside", "footer", "header", "main", "nav", "section", "body", "blockquote", "dd", "div", "dl", "dt", "figcaption", "figure", "hr", "li", "ol", "p", "pre", "ul", "a", "abbr", "b", "bdi", "bdo", "br", "cite", "code", "data", "dfn", "em", "i", "kbd", "mark", "q", "rp", "rt", "ruby", "s", "samp", "small", "span", "strong", "sub", "sup", "time", "u", "var", "wbr", "area", "audio", "img", "map", "track", "video", "embed", "iframe", "object", "param", "picture", "portal", "source", "svg", "math", "canvas", "noscript", "script", "del", "ins", "caption", "col", "colgroup", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "button", "datalist", "fieldset", "form", "input", "label", "legend", "meter", "optgroup", "option", "output", "progress", "select", "textarea", "details", "dialog", "menu", "summary", "details", "slot", "template", "acronym", "applet", "basefont", "bgsound", "big", "blink", "center", "content", "dir", "font", "frame", "frameset", "hgroup", "image", "keygen", "marquee", "menuitem", "nobr", "noembed", "noframes", "plaintext", "rb", "rtc", "shadow", "spacer", "strike", "tt", "xmp", "a", "abbr", "acronym", "address", "applet", "area", "article", "aside", "audio", "b", "base", "basefont", "bdi", "bdo", "bgsound", "big", "blink", "blockquote", "body", "br", "button", "canvas", "caption", "center", "cite", "code", "col", "colgroup", "content", "data", "datalist", "dd", "del", "details", "dfn", "dialog", "dir", "div", "dl", "dt", "em", "embed", "fieldset", "figcaption", "figure", "font", "footer", "form", "frame", "frameset", "head", "header", "hgroup", "hr", "html", "i", "iframe", "image", "img", "input", "ins", "kbd", "keygen", "label", "legend", "li", "link", "main", "map", "mark", "marquee", "menu", "menuitem", "meta", "meter", "nav", "nobr", "noembed", "noframes", "noscript", "object", "ol", "optgroup", "option", "output", "p", "param", "picture", "plaintext", "portal", "pre", "progress", "q", "rb", "rp", "rt", "rtc", "ruby", "s", "samp", "script", "section", "select", "shadow", "slot", "small", "source", "spacer", "span", "strike", "strong", "style", "sub", "summary", "sup", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "title", "tr", "track", "tt", "u", "ul", "var", "video", "wbr", "xmp", "input", "h1", "h2", "h3", "h4", "h5", "h6"]); + function reconcileArrays(parentNode, a, b) { + let bLength = b.length, aEnd = a.length, bEnd = bLength, aStart = 0, bStart = 0, after = a[aEnd - 1].nextSibling, map = null; + while (aStart < aEnd || bStart < bEnd) { + if (a[aStart] === b[bStart]) { + aStart++; + bStart++; + continue; + } + while (a[aEnd - 1] === b[bEnd - 1]) { + aEnd--; + bEnd--; + } + if (aEnd === aStart) { + const node = bEnd < bLength ? bStart ? b[bStart - 1].nextSibling : b[bEnd - bStart] : after; + while (bStart < bEnd) + parentNode.insertBefore(b[bStart++], node); + } else if (bEnd === bStart) { + while (aStart < aEnd) { + if (!map || !map.has(a[aStart])) + a[aStart].remove(); + aStart++; + } + } else if (a[aStart] === b[bEnd - 1] && b[bStart] === a[aEnd - 1]) { + const node = a[--aEnd].nextSibling; + parentNode.insertBefore(b[bStart++], a[aStart++].nextSibling); + parentNode.insertBefore(b[--bEnd], node); + a[aEnd] = b[bEnd]; + } else { + if (!map) { + map = /* @__PURE__ */ new Map(); + let i = bStart; + while (i < bEnd) + map.set(b[i], i++); + } + const index = map.get(a[aStart]); + if (index != null) { + if (bStart < index && index < bEnd) { + let i = aStart, sequence = 1, t; + while (++i < aEnd && i < bEnd) { + if ((t = map.get(a[i])) == null || t !== index + sequence) + break; + sequence++; + } + if (sequence > index - bStart) { + const node = a[aStart]; + while (bStart < index) + parentNode.insertBefore(b[bStart++], node); + } else + parentNode.replaceChild(b[bStart++], a[aStart++]); + } else + aStart++; + } else + a[aStart++].remove(); + } + } + } + var $$EVENTS = "_$DX_DELEGATE"; + function render(code, element, init, options = {}) { + let disposer; + solidJs.createRoot((dispose) => { + disposer = dispose; + element === document ? code() : insert(element, code(), element.firstChild ? null : void 0, init); + }, options.owner); + return () => { + disposer(); + element.textContent = ""; + }; + } + function template(html, isCE, isSVG) { + let node; + const create = () => { + const t = document.createElement("template"); + t.innerHTML = html; + return isSVG ? t.content.firstChild.firstChild : t.content.firstChild; + }; + const fn = isCE ? () => solidJs.untrack(() => document.importNode(node || (node = create()), true)) : () => (node || (node = create())).cloneNode(true); + fn.cloneNode = fn; + return fn; + } + function delegateEvents(eventNames, document2 = window.document) { + const e = document2[$$EVENTS] || (document2[$$EVENTS] = /* @__PURE__ */ new Set()); + for (let i = 0, l = eventNames.length; i < l; i++) { + const name = eventNames[i]; + if (!e.has(name)) { + e.add(name); + document2.addEventListener(name, eventHandler); + } + } + } + function clearDelegatedEvents(document2 = window.document) { + if (document2[$$EVENTS]) { + for (let name of document2[$$EVENTS].keys()) + document2.removeEventListener(name, eventHandler); + delete document2[$$EVENTS]; + } + } + function setAttribute(node, name, value) { + if (value == null) + node.removeAttribute(name); + else + node.setAttribute(name, value); + } + function setAttributeNS(node, namespace, name, value) { + if (value == null) + node.removeAttributeNS(namespace, name); + else + node.setAttributeNS(namespace, name, value); + } + function className(node, value) { + if (value == null) + node.removeAttribute("class"); + else + node.className = value; + } + function addEventListener(node, name, handler, delegate) { + if (delegate) { + if (Array.isArray(handler)) { + node[`$$${name}`] = handler[0]; + node[`$$${name}Data`] = handler[1]; + } else + node[`$$${name}`] = handler; + } else if (Array.isArray(handler)) { + const handlerFn = handler[0]; + node.addEventListener(name, handler[0] = (e) => handlerFn.call(node, handler[1], e)); + } else + node.addEventListener(name, handler); + } + function classList(node, value, prev = {}) { + const classKeys = Object.keys(value || {}), prevKeys = Object.keys(prev); + let i, len; + for (i = 0, len = prevKeys.length; i < len; i++) { + const key = prevKeys[i]; + if (!key || key === "undefined" || value[key]) + continue; + toggleClassKey(node, key, false); + delete prev[key]; + } + for (i = 0, len = classKeys.length; i < len; i++) { + const key = classKeys[i], classValue = !!value[key]; + if (!key || key === "undefined" || prev[key] === classValue || !classValue) + continue; + toggleClassKey(node, key, true); + prev[key] = classValue; + } + return prev; + } + function style(node, value, prev) { + if (!value) + return prev ? setAttribute(node, "style") : value; + const nodeStyle = node.style; + if (typeof value === "string") + return nodeStyle.cssText = value; + typeof prev === "string" && (nodeStyle.cssText = prev = void 0); + prev || (prev = {}); + value || (value = {}); + let v, s; + for (s in prev) { + value[s] == null && nodeStyle.removeProperty(s); + delete prev[s]; + } + for (s in value) { + v = value[s]; + if (v !== prev[s]) { + nodeStyle.setProperty(s, v); + prev[s] = v; + } + } + return prev; + } + function spread(node, props = {}, isSVG, skipChildren) { + const prevProps = {}; + if (!skipChildren) { + solidJs.createRenderEffect(() => prevProps.children = insertExpression(node, props.children, prevProps.children)); + } + solidJs.createRenderEffect(() => props.ref && props.ref(node)); + solidJs.createRenderEffect(() => assign(node, props, isSVG, true, prevProps, true)); + return prevProps; + } + function dynamicProperty(props, key) { + const src = props[key]; + Object.defineProperty(props, key, { + get() { + return src(); + }, + enumerable: true + }); + return props; + } + function innerHTML(parent, content) { + !solidJs.sharedConfig.context && (parent.innerHTML = content); + } + function use(fn, element, arg) { + return solidJs.untrack(() => fn(element, arg)); + } + function insert(parent, accessor, marker, initial) { + if (marker !== void 0 && !initial) + initial = []; + if (typeof accessor !== "function") + return insertExpression(parent, accessor, initial, marker); + solidJs.createRenderEffect((current) => insertExpression(parent, accessor(), current, marker), initial); + } + function assign(node, props, isSVG, skipChildren, prevProps = {}, skipRef = false) { + props || (props = {}); + for (const prop in prevProps) { + if (!(prop in props)) { + if (prop === "children") + continue; + prevProps[prop] = assignProp(node, prop, null, prevProps[prop], isSVG, skipRef); + } + } + for (const prop in props) { + if (prop === "children") { + if (!skipChildren) + insertExpression(node, props.children); + continue; + } + const value = props[prop]; + prevProps[prop] = assignProp(node, prop, value, prevProps[prop], isSVG, skipRef); + } + } + function hydrate$1(code, element, options = {}) { + solidJs.sharedConfig.completed = globalThis._$HY.completed; + solidJs.sharedConfig.events = globalThis._$HY.events; + solidJs.sharedConfig.load = globalThis._$HY.load; + solidJs.sharedConfig.gather = (root) => gatherHydratable(element, root); + solidJs.sharedConfig.registry = /* @__PURE__ */ new Map(); + solidJs.sharedConfig.context = { + id: options.renderId || "", + count: 0 + }; + gatherHydratable(element, options.renderId); + const dispose = render(code, element, [...element.childNodes], options); + solidJs.sharedConfig.context = null; + return dispose; + } + function getNextElement(template2) { + let node, key; + if (!solidJs.sharedConfig.context || !(node = solidJs.sharedConfig.registry.get(key = getHydrationKey()))) { + if (solidJs.sharedConfig.context) + console.warn("Unable to find DOM nodes for hydration key:", key); + if (!template2) + throw new Error("Unrecoverable Hydration Mismatch. No template for key: " + key); + return template2(); + } + if (solidJs.sharedConfig.completed) + solidJs.sharedConfig.completed.add(node); + solidJs.sharedConfig.registry.delete(key); + return node; + } + function getNextMatch(el, nodeName) { + while (el && el.localName !== nodeName) + el = el.nextSibling; + return el; + } + function getNextMarker(start) { + let end = start, count = 0, current = []; + if (solidJs.sharedConfig.context) { + while (end) { + if (end.nodeType === 8) { + const v = end.nodeValue; + if (v === "#") + count++; + else if (v === "/") { + if (count === 0) + return [end, current]; + count--; + } + } + current.push(end); + end = end.nextSibling; + } + } + return [end, current]; + } + function runHydrationEvents() { + if (solidJs.sharedConfig.events && !solidJs.sharedConfig.events.queued) { + queueMicrotask(() => { + const { + completed, + events + } = solidJs.sharedConfig; + events.queued = false; + while (events.length) { + const [el, e] = events[0]; + if (!completed.has(el)) + return; + eventHandler(e); + events.shift(); + } + }); + solidJs.sharedConfig.events.queued = true; + } + } + function toPropertyName(name) { + return name.toLowerCase().replace(/-([a-z])/g, (_, w) => w.toUpperCase()); + } + function toggleClassKey(node, key, value) { + const classNames = key.trim().split(/\s+/); + for (let i = 0, nameLen = classNames.length; i < nameLen; i++) + node.classList.toggle(classNames[i], value); + } + function assignProp(node, prop, value, prev, isSVG, skipRef) { + let isCE, isProp, isChildProp, propAlias, forceProp; + if (prop === "style") + return style(node, value, prev); + if (prop === "classList") + return classList(node, value, prev); + if (value === prev) + return prev; + if (prop === "ref") { + if (!skipRef) + value(node); + } else if (prop.slice(0, 3) === "on:") { + const e = prop.slice(3); + prev && node.removeEventListener(e, prev); + value && node.addEventListener(e, value); + } else if (prop.slice(0, 10) === "oncapture:") { + const e = prop.slice(10); + prev && node.removeEventListener(e, prev, true); + value && node.addEventListener(e, value, true); + } else if (prop.slice(0, 2) === "on") { + const name = prop.slice(2).toLowerCase(); + const delegate = DelegatedEvents.has(name); + if (!delegate && prev) { + const h = Array.isArray(prev) ? prev[0] : prev; + node.removeEventListener(name, h); + } + if (delegate || value) { + addEventListener(node, name, value, delegate); + delegate && delegateEvents([name]); + } + } else if (prop.slice(0, 5) === "attr:") { + setAttribute(node, prop.slice(5), value); + } else if ((forceProp = prop.slice(0, 5) === "prop:") || (isChildProp = ChildProperties.has(prop)) || !isSVG && ((propAlias = getPropAlias(prop, node.tagName)) || (isProp = Properties.has(prop))) || (isCE = node.nodeName.includes("-"))) { + if (forceProp) { + prop = prop.slice(5); + isProp = true; + } + if (prop === "class" || prop === "className") + className(node, value); + else if (isCE && !isProp && !isChildProp) + node[toPropertyName(prop)] = value; + else + node[propAlias || prop] = value; + } else { + const ns = isSVG && prop.indexOf(":") > -1 && SVGNamespace[prop.split(":")[0]]; + if (ns) + setAttributeNS(node, ns, prop, value); + else + setAttribute(node, Aliases[prop] || prop, value); + } + return value; + } + function eventHandler(e) { + const key = `$$${e.type}`; + let node = e.composedPath && e.composedPath()[0] || e.target; + if (e.target !== node) { + Object.defineProperty(e, "target", { + configurable: true, + value: node + }); + } + Object.defineProperty(e, "currentTarget", { + configurable: true, + get() { + return node || document; + } + }); + if (solidJs.sharedConfig.registry && !solidJs.sharedConfig.done) + solidJs.sharedConfig.done = _$HY.done = true; + while (node) { + const handler = node[key]; + if (handler && !node.disabled) { + const data = node[`${key}Data`]; + data !== void 0 ? handler.call(node, data, e) : handler.call(node, e); + if (e.cancelBubble) + return; + } + node = node._$host || node.parentNode || node.host; + } + } + function insertExpression(parent, value, current, marker, unwrapArray) { + if (solidJs.sharedConfig.context) { + !current && (current = [...parent.childNodes]); + let cleaned = []; + for (let i = 0; i < current.length; i++) { + const node = current[i]; + if (node.nodeType === 8 && node.data.slice(0, 2) === "!$") + node.remove(); + else + cleaned.push(node); + } + current = cleaned; + } + while (typeof current === "function") + current = current(); + if (value === current) + return current; + const t = typeof value, multi = marker !== void 0; + parent = multi && current[0] && current[0].parentNode || parent; + if (t === "string" || t === "number") { + if (solidJs.sharedConfig.context) + return current; + if (t === "number") + value = value.toString(); + if (multi) { + let node = current[0]; + if (node && node.nodeType === 3) { + node.data = value; + } else + node = document.createTextNode(value); + current = cleanChildren(parent, current, marker, node); + } else { + if (current !== "" && typeof current === "string") { + current = parent.firstChild.data = value; + } else + current = parent.textContent = value; + } + } else if (value == null || t === "boolean") { + if (solidJs.sharedConfig.context) + return current; + current = cleanChildren(parent, current, marker); + } else if (t === "function") { + solidJs.createRenderEffect(() => { + let v = value(); + while (typeof v === "function") + v = v(); + current = insertExpression(parent, v, current, marker); + }); + return () => current; + } else if (Array.isArray(value)) { + const array = []; + const currentArray = current && Array.isArray(current); + if (normalizeIncomingArray(array, value, current, unwrapArray)) { + solidJs.createRenderEffect(() => current = insertExpression(parent, array, current, marker, true)); + return () => current; + } + if (solidJs.sharedConfig.context) { + if (!array.length) + return current; + for (let i = 0; i < array.length; i++) { + if (array[i].parentNode) + return current = array; + } + } + if (array.length === 0) { + current = cleanChildren(parent, current, marker); + if (multi) + return current; + } else if (currentArray) { + if (current.length === 0) { + appendNodes(parent, array, marker); + } else + reconcileArrays(parent, current, array); + } else { + current && cleanChildren(parent); + appendNodes(parent, array); + } + current = array; + } else if (value.nodeType) { + if (solidJs.sharedConfig.context && value.parentNode) + return current = multi ? [value] : value; + if (Array.isArray(current)) { + if (multi) + return current = cleanChildren(parent, current, marker, value); + cleanChildren(parent, current, null, value); + } else if (current == null || current === "" || !parent.firstChild) { + parent.appendChild(value); + } else + parent.replaceChild(value, parent.firstChild); + current = value; + } else + console.warn(`Unrecognized value. Skipped inserting`, value); + return current; + } + function normalizeIncomingArray(normalized, array, current, unwrap) { + let dynamic = false; + for (let i = 0, len = array.length; i < len; i++) { + let item = array[i], prev = current && current[i], t; + if (item == null || item === true || item === false) + ; + else if ((t = typeof item) === "object" && item.nodeType) { + normalized.push(item); + } else if (Array.isArray(item)) { + dynamic = normalizeIncomingArray(normalized, item, prev) || dynamic; + } else if (t === "function") { + if (unwrap) { + while (typeof item === "function") + item = item(); + dynamic = normalizeIncomingArray(normalized, Array.isArray(item) ? item : [item], Array.isArray(prev) ? prev : [prev]) || dynamic; + } else { + normalized.push(item); + dynamic = true; + } + } else { + const value = String(item); + if (prev && prev.nodeType === 3 && prev.data === value) + normalized.push(prev); + else + normalized.push(document.createTextNode(value)); + } + } + return dynamic; + } + function appendNodes(parent, array, marker = null) { + for (let i = 0, len = array.length; i < len; i++) + parent.insertBefore(array[i], marker); + } + function cleanChildren(parent, current, marker, replacement) { + if (marker === void 0) + return parent.textContent = ""; + const node = replacement || document.createTextNode(""); + if (current.length) { + let inserted = false; + for (let i = current.length - 1; i >= 0; i--) { + const el = current[i]; + if (node !== el) { + const isParent = el.parentNode === parent; + if (!inserted && !i) + isParent ? parent.replaceChild(node, el) : parent.insertBefore(node, marker); + else + isParent && el.remove(); + } else + inserted = true; + } + } else + parent.insertBefore(node, marker); + return [node]; + } + function gatherHydratable(element, root) { + const templates = element.querySelectorAll(`*[data-hk]`); + for (let i = 0; i < templates.length; i++) { + const node = templates[i]; + const key = node.getAttribute("data-hk"); + if ((!root || key.startsWith(root)) && !solidJs.sharedConfig.registry.has(key)) + solidJs.sharedConfig.registry.set(key, node); + } + } + function getHydrationKey() { + const hydrate2 = solidJs.sharedConfig.context; + return `${hydrate2.id}${hydrate2.count++}`; + } + function NoHydration(props) { + return solidJs.sharedConfig.context ? void 0 : props.children; + } + function Hydration(props) { + return props.children; + } + function voidFn() { + } + function throwInBrowser(func) { + const err = new Error(`${func.name} is not supported in the browser, returning undefined`); + console.error(err); + } + function renderToString(fn, options) { + throwInBrowser(renderToString); + } + function renderToStringAsync(fn, options) { + throwInBrowser(renderToStringAsync); + } + function renderToStream(fn, options) { + throwInBrowser(renderToStream); + } + function ssr(template2, ...nodes) { + } + function ssrElement(name, props, children, needsId) { + } + function ssrClassList(value) { + } + function ssrStyle(value) { + } + function ssrAttribute(key, value) { + } + function ssrHydrationKey() { + } + function resolveSSRNode(node) { + } + function escape(html) { + } + function ssrSpread(props, isSVG, skipChildren) { + } + var isServer = false; + var isDev = false; + var SVG_NAMESPACE = "http://www.w3.org/2000/svg"; + function createElement(tagName, isSVG = false) { + return isSVG ? document.createElementNS(SVG_NAMESPACE, tagName) : document.createElement(tagName); + } + var hydrate = (...args) => { + solidJs.enableHydration(); + return hydrate$1(...args); + }; + function Portal(props) { + const { + useShadow + } = props, marker = document.createTextNode(""), mount = () => props.mount || document.body, owner = solidJs.getOwner(); + let content; + let hydrating = !!solidJs.sharedConfig.context; + solidJs.createEffect(() => { + if (hydrating) + solidJs.getOwner().user = hydrating = false; + content || (content = solidJs.runWithOwner(owner, () => solidJs.createMemo(() => props.children))); + const el = mount(); + if (el instanceof HTMLHeadElement) { + const [clean, setClean] = solidJs.createSignal(false); + const cleanup = () => setClean(true); + solidJs.createRoot((dispose) => insert(el, () => !clean() ? content() : dispose(), null)); + solidJs.onCleanup(cleanup); + } else { + const container = createElement(props.isSVG ? "g" : "div", props.isSVG), renderRoot = useShadow && container.attachShadow ? container.attachShadow({ + mode: "open" + }) : container; + Object.defineProperty(container, "_$host", { + get() { + return marker.parentNode; + }, + configurable: true + }); + insert(renderRoot, content); + el.appendChild(container); + props.ref && props.ref(container); + solidJs.onCleanup(() => el.removeChild(container)); + } + }, void 0, { + render: !hydrating + }); + return marker; + } + function Dynamic(props) { + const [p, others] = solidJs.splitProps(props, ["component"]); + const cached = solidJs.createMemo(() => p.component); + return solidJs.createMemo(() => { + const component = cached(); + switch (typeof component) { + case "function": + Object.assign(component, { + [solidJs.$DEVCOMP]: true + }); + return solidJs.untrack(() => component(others)); + case "string": + const isSvg = SVGElements.has(component); + const el = solidJs.sharedConfig.context ? getNextElement() : createElement(component, isSvg); + spread(el, others, isSvg); + return el; + } + }); + } + Object.defineProperty(exports, "ErrorBoundary", { + enumerable: true, + get: function() { + return solidJs.ErrorBoundary; + } + }); + Object.defineProperty(exports, "For", { + enumerable: true, + get: function() { + return solidJs.For; + } + }); + Object.defineProperty(exports, "Index", { + enumerable: true, + get: function() { + return solidJs.Index; + } + }); + Object.defineProperty(exports, "Match", { + enumerable: true, + get: function() { + return solidJs.Match; + } + }); + Object.defineProperty(exports, "Show", { + enumerable: true, + get: function() { + return solidJs.Show; + } + }); + Object.defineProperty(exports, "Suspense", { + enumerable: true, + get: function() { + return solidJs.Suspense; + } + }); + Object.defineProperty(exports, "SuspenseList", { + enumerable: true, + get: function() { + return solidJs.SuspenseList; + } + }); + Object.defineProperty(exports, "Switch", { + enumerable: true, + get: function() { + return solidJs.Switch; + } + }); + Object.defineProperty(exports, "createComponent", { + enumerable: true, + get: function() { + return solidJs.createComponent; + } + }); + Object.defineProperty(exports, "effect", { + enumerable: true, + get: function() { + return solidJs.createRenderEffect; + } + }); + Object.defineProperty(exports, "getOwner", { + enumerable: true, + get: function() { + return solidJs.getOwner; + } + }); + Object.defineProperty(exports, "memo", { + enumerable: true, + get: function() { + return solidJs.createMemo; + } + }); + Object.defineProperty(exports, "mergeProps", { + enumerable: true, + get: function() { + return solidJs.mergeProps; + } + }); + Object.defineProperty(exports, "untrack", { + enumerable: true, + get: function() { + return solidJs.untrack; + } + }); + exports.Aliases = Aliases; + exports.Assets = voidFn; + exports.ChildProperties = ChildProperties; + exports.DOMElements = DOMElements; + exports.DelegatedEvents = DelegatedEvents; + exports.Dynamic = Dynamic; + exports.Hydration = Hydration; + exports.HydrationScript = voidFn; + exports.NoHydration = NoHydration; + exports.Portal = Portal; + exports.Properties = Properties; + exports.SVGElements = SVGElements; + exports.SVGNamespace = SVGNamespace; + exports.addEventListener = addEventListener; + exports.assign = assign; + exports.classList = classList; + exports.className = className; + exports.clearDelegatedEvents = clearDelegatedEvents; + exports.delegateEvents = delegateEvents; + exports.dynamicProperty = dynamicProperty; + exports.escape = escape; + exports.generateHydrationScript = voidFn; + exports.getAssets = voidFn; + exports.getHydrationKey = getHydrationKey; + exports.getNextElement = getNextElement; + exports.getNextMarker = getNextMarker; + exports.getNextMatch = getNextMatch; + exports.getPropAlias = getPropAlias; + exports.hydrate = hydrate; + exports.innerHTML = innerHTML; + exports.insert = insert; + exports.isDev = isDev; + exports.isServer = isServer; + exports.render = render; + exports.renderToStream = renderToStream; + exports.renderToString = renderToString; + exports.renderToStringAsync = renderToStringAsync; + exports.resolveSSRNode = resolveSSRNode; + exports.runHydrationEvents = runHydrationEvents; + exports.setAttribute = setAttribute; + exports.setAttributeNS = setAttributeNS; + exports.spread = spread; + exports.ssr = ssr; + exports.ssrAttribute = ssrAttribute; + exports.ssrClassList = ssrClassList; + exports.ssrElement = ssrElement; + exports.ssrHydrationKey = ssrHydrationKey; + exports.ssrSpread = ssrSpread; + exports.ssrStyle = ssrStyle; + exports.style = style; + exports.template = template; + exports.use = use; + exports.useAssets = voidFn; + } +}); + +// src/ui/solid/plugin-context.tsx +var require_plugin_context = __commonJS({ + "src/ui/solid/plugin-context.tsx"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PluginContextProvider = PluginContextProvider; + exports.usePluginContext = usePluginContext; + var _web = require_web(); + var _solidJs = require_solid(); + var _obsidian = require("obsidian"); + var PluginContext = (0, _solidJs.createContext)(); + function PluginContextProvider(props) { + const handleClick = async (event, path, line) => { + if (event.target instanceof HTMLAnchorElement) { + return; + } + const file = props.plugin.app.metadataCache.getFirstLinkpathDest(path, path); + if (!file) { + new _obsidian.Notice(`File ${path} does not exist`); + return; + } + await props.plugin.app.workspace.getLeaf(false).openFile(file); + const activeMarkdownView = props.plugin.app.workspace.getActiveViewOfType(_obsidian.MarkdownView); + if (!activeMarkdownView) { + new _obsidian.Notice(`Failed to open file ${path}. Can't scroll to line ${line}`); + return; + } + try { + activeMarkdownView.setEphemeralState({ + line + }); + } catch (error) { + console.error(error); + } + }; + const handleMouseover = (event, path, line) => { + if (!props.plugin.app.internalPlugins.plugins["page-preview"].enabled) { + return; + } + if (_obsidian.Keymap.isModifier(event, "Mod")) { + const target = event.target; + const previewLocation = { + scroll: line + }; + if (path) { + props.plugin.app.workspace.trigger("link-hover", {}, target, path, "", previewLocation); + } + } + }; + const handleHeightChange = () => { + props.infinityScroll.invalidateAll(); + }; + return (0, _web.createComponent)(PluginContext.Provider, { + get value() { + return { + handleClick, + handleMouseover, + handleHeightChange, + plugin: props.plugin, + app: props.plugin.app + }; + }, + get children() { + return props.children; + } + }); + } + function usePluginContext() { + const pluginContext = (0, _solidJs.useContext)(PluginContext); + if (!pluginContext) { + throw new Error("pluginContext must be used inside a provider"); + } + return pluginContext; + } + } +}); + +// src/ui/solid/icons/list-icon.tsx +var require_list_icon = __commonJS({ + "src/ui/solid/icons/list-icon.tsx"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.ListIcon = ListIcon; + var _web = require_web(); + var _tmpl$ = /* @__PURE__ */ (0, _web.template)(``); + function ListIcon() { + return _tmpl$(); + } + } +}); + +// src/ui/solid/icons/heading-icon.tsx +var require_heading_icon = __commonJS({ + "src/ui/solid/icons/heading-icon.tsx"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.HeadingIcon = HeadingIcon; + var _web = require_web(); + var _tmpl$ = /* @__PURE__ */ (0, _web.template)(``); + function HeadingIcon() { + return _tmpl$(); + } + } +}); + +// src/patterns.ts +var patterns_exports = {}; +__export(patterns_exports, { + listItemToken: () => listItemToken, + wikiLinkBrackets: () => wikiLinkBrackets +}); +var wikiLinkBrackets, listItemToken; +var init_patterns = __esm({ + "src/patterns.ts"() { + wikiLinkBrackets = /\[\[|]]/g; + listItemToken = /^-\s+/; + } +}); + +// src/ui/solid/title.tsx +var require_title = __commonJS({ + "src/ui/solid/title.tsx"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.Title = Title; + var _web = require_web(); + var _solidJs = require_solid(); + var _pluginContext = require_plugin_context(); + var _listIcon = require_list_icon(); + var _headingIcon = require_heading_icon(); + var _patterns = (init_patterns(), __toCommonJS(patterns_exports)); + var _tmpl$ = /* @__PURE__ */ (0, _web.template)(`
`); + var _tmpl$2 = /* @__PURE__ */ (0, _web.template)(`
`); + function removeListToken(text) { + return text.trim().replace(_patterns.listItemToken, ""); + } + function Title(props) { + const { + handleClick, + handleMouseover + } = (0, _pluginContext.usePluginContext)(); + return (() => { + const _el$ = _tmpl$(); + (0, _web.insert)(_el$, (0, _web.createComponent)(_solidJs.For, { + get each() { + return props.breadcrumbs; + }, + children: (breadcrumb, i) => { + const handleTitleClick = async (event) => await handleClick(event, props.contextTree.filePath, breadcrumb.position.start.line); + const handleTitleMouseover = (event) => handleMouseover(event, props.contextTree.filePath, breadcrumb.position.start.line); + return (() => { + const _el$2 = _tmpl$2(), _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$4.nextSibling; + _el$3.$$mouseover = handleTitleMouseover; + _el$3.$$click = handleTitleClick; + (0, _web.insert)(_el$4, (0, _web.createComponent)(_solidJs.Switch, { + get fallback() { + return (0, _web.createComponent)(_listIcon.ListIcon, {}); + }, + get children() { + return (0, _web.createComponent)(_solidJs.Match, { + get when() { + return breadcrumb.type === "heading"; + }, + get children() { + return (0, _web.createComponent)(_headingIcon.HeadingIcon, {}); + } + }); + } + })); + (0, _web.insert)(_el$5, () => removeListToken(breadcrumb.text)); + return _el$2; + })(); + } + })); + return _el$; + })(); + } + (0, _web.delegateEvents)(["click", "mouseover"]); + } +}); + +// src/ui/solid/match-section.tsx +var require_match_section = __commonJS({ + "src/ui/solid/match-section.tsx"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.MatchSection = MatchSection; + var _web = require_web(); + var _solidJs = require_solid(); + var _obsidian = require("obsidian"); + var _pluginContext = require_plugin_context(); + var _tmpl$ = /* @__PURE__ */ (0, _web.template)(`
`); + var _tmpl$2 = /* @__PURE__ */ (0, _web.template)(`
`); + function MatchSection(props) { + const { + handleClick, + handleMouseover, + app + } = (0, _pluginContext.usePluginContext)(); + const matchLifecycleManager = new _obsidian.Component(); + (0, _solidJs.onCleanup)(() => { + matchLifecycleManager.unload(); + }); + return (0, _web.createComponent)(_solidJs.Show, { + get when() { + return props.sectionsWithMatches.length > 0; + }, + get children() { + const _el$ = _tmpl$(); + (0, _web.insert)(_el$, (0, _web.createComponent)(_solidJs.For, { + get each() { + return props.sectionsWithMatches; + }, + children: (section) => { + const line = section.cache.position.start.line; + return (() => { + const _el$2 = _tmpl$2(); + _el$2.$$mouseover = (event) => { + handleMouseover(event, section.filePath, line); + }; + _el$2.$$click = async (event) => { + await handleClick(event, section.filePath, line); + }; + (0, _web.use)(async (el) => { + await _obsidian.MarkdownRenderer.render(app, section.text, el, section.filePath, matchLifecycleManager); + matchLifecycleManager.load(); + }, _el$2); + return _el$2; + })(); + } + })); + return _el$; + } + }); + } + (0, _web.delegateEvents)(["click", "mouseover"]); + } +}); + +// src/ui/solid/icons/collapse-icon.tsx +var require_collapse_icon = __commonJS({ + "src/ui/solid/icons/collapse-icon.tsx"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.CollapseIcon = CollapseIcon; + var _web = require_web(); + var _tmpl$ = /* @__PURE__ */ (0, _web.template)(``); + function CollapseIcon() { + return _tmpl$(); + } + } +}); + +// src/ui/solid/branch.tsx +var require_branch = __commonJS({ + "src/ui/solid/branch.tsx"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.Branch = Branch; + var _web = require_web(); + var _solidJs = require_solid(); + var _title = require_title(); + var _matchSection = require_match_section(); + var _collapseIcon = require_collapse_icon(); + var _pluginContext = require_plugin_context(); + var _tmpl$ = /* @__PURE__ */ (0, _web.template)(`
`); + var _tmpl$2 = /* @__PURE__ */ (0, _web.template)(`
`); + function Branch(props) { + const { + handleHeightChange + } = (0, _pluginContext.usePluginContext)(); + const [isHidden, setIsHidden] = (0, _solidJs.createSignal)(false); + const breadcrumbs = () => { + const breadcrumbForBranch = { + text: props.contextTree.text, + type: props.contextTree.type, + position: props.contextTree.cacheItem.position + }; + return [breadcrumbForBranch, ...props.contextTree.breadcrumbs || []]; + }; + return (() => { + const _el$ = _tmpl$2(), _el$4 = _el$.firstChild, _el$5 = _el$4.firstChild; + (0, _web.insert)(_el$, (0, _web.createComponent)(_solidJs.Show, { + get when() { + return props.contextTree.type !== "file"; + }, + get children() { + const _el$2 = _tmpl$(), _el$3 = _el$2.firstChild; + _el$3.$$click = () => { + setIsHidden(!isHidden()); + handleHeightChange(); + }; + (0, _web.insert)(_el$3, (0, _web.createComponent)(_collapseIcon.CollapseIcon, {})); + (0, _web.insert)(_el$2, (0, _web.createComponent)(_title.Title, { + get breadcrumbs() { + return breadcrumbs(); + }, + get contextTree() { + return props.contextTree; + } + }), null); + (0, _web.effect)(() => (0, _web.className)(_el$3, `tree-item-icon collapse-icon ${isHidden() ? "is-collapsed" : ""}`)); + return _el$2; + } + }), _el$4); + (0, _web.insert)(_el$4, (0, _web.createComponent)(_matchSection.MatchSection, { + get sectionsWithMatches() { + return props.contextTree.sectionsWithMatches; + } + }), _el$5); + (0, _web.insert)(_el$5, (0, _web.createComponent)(_solidJs.For, { + get each() { + return props.contextTree.branches; + }, + children: (branch) => (0, _web.createComponent)(Branch, { + contextTree: branch + }) + })); + (0, _web.effect)(() => (0, _web.className)(_el$4, isHidden() ? "better-search-views-is-hidden" : "")); + return _el$; + })(); + } + (0, _web.delegateEvents)(["click"]); + } +}); + +// src/context-tree/collapse/collapse-empty-nodes.ts +var collapse_empty_nodes_exports = {}; +__export(collapse_empty_nodes_exports, { + collapseEmptyNodes: () => collapseEmptyNodes +}); +function collapseEmptyNodes(tree) { + var _a, _b; + if (!((_a = tree == null ? void 0 : tree.sectionsWithMatches) == null ? void 0 : _a.length) && tree.branches.length === 1) { + const firstBranch = tree.branches[0]; + const breadcrumb = { + text: firstBranch.text, + type: firstBranch.type, + position: (_b = firstBranch.cacheItem) == null ? void 0 : _b.position + }; + return collapseEmptyNodes({ + ...tree, + branches: firstBranch.branches, + breadcrumbs: [...tree.breadcrumbs || [], breadcrumb], + sectionsWithMatches: firstBranch.sectionsWithMatches + }); + } + return { ...tree, branches: tree.branches.map(collapseEmptyNodes) }; +} +var init_collapse_empty_nodes = __esm({ + "src/context-tree/collapse/collapse-empty-nodes.ts"() { + } +}); + +// node_modules/mark.js/dist/mark.js +var require_mark = __commonJS({ + "node_modules/mark.js/dist/mark.js"(exports, module2) { + (function(global, factory) { + typeof exports === "object" && typeof module2 !== "undefined" ? module2.exports = factory() : typeof define === "function" && define.amd ? define(factory) : global.Mark = factory(); + })(exports, function() { + "use strict"; + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function(obj) { + return typeof obj; + } : function(obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + var classCallCheck = function(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + }; + var createClass = function() { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) + descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + return function(Constructor, protoProps, staticProps) { + if (protoProps) + defineProperties(Constructor.prototype, protoProps); + if (staticProps) + defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + var _extends = Object.assign || function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + return target; + }; + var DOMIterator = function() { + function DOMIterator2(ctx) { + var iframes = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : true; + var exclude = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : []; + var iframesTimeout = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : 5e3; + classCallCheck(this, DOMIterator2); + this.ctx = ctx; + this.iframes = iframes; + this.exclude = exclude; + this.iframesTimeout = iframesTimeout; + } + createClass(DOMIterator2, [{ + key: "getContexts", + value: function getContexts() { + var ctx = void 0, filteredCtx = []; + if (typeof this.ctx === "undefined" || !this.ctx) { + ctx = []; + } else if (NodeList.prototype.isPrototypeOf(this.ctx)) { + ctx = Array.prototype.slice.call(this.ctx); + } else if (Array.isArray(this.ctx)) { + ctx = this.ctx; + } else if (typeof this.ctx === "string") { + ctx = Array.prototype.slice.call(document.querySelectorAll(this.ctx)); + } else { + ctx = [this.ctx]; + } + ctx.forEach(function(ctx2) { + var isDescendant = filteredCtx.filter(function(contexts) { + return contexts.contains(ctx2); + }).length > 0; + if (filteredCtx.indexOf(ctx2) === -1 && !isDescendant) { + filteredCtx.push(ctx2); + } + }); + return filteredCtx; + } + }, { + key: "getIframeContents", + value: function getIframeContents(ifr, successFn) { + var errorFn = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : function() { + }; + var doc = void 0; + try { + var ifrWin = ifr.contentWindow; + doc = ifrWin.document; + if (!ifrWin || !doc) { + throw new Error("iframe inaccessible"); + } + } catch (e) { + errorFn(); + } + if (doc) { + successFn(doc); + } + } + }, { + key: "isIframeBlank", + value: function isIframeBlank(ifr) { + var bl = "about:blank", src = ifr.getAttribute("src").trim(), href = ifr.contentWindow.location.href; + return href === bl && src !== bl && src; + } + }, { + key: "observeIframeLoad", + value: function observeIframeLoad(ifr, successFn, errorFn) { + var _this = this; + var called = false, tout = null; + var listener = function listener2() { + if (called) { + return; + } + called = true; + clearTimeout(tout); + try { + if (!_this.isIframeBlank(ifr)) { + ifr.removeEventListener("load", listener2); + _this.getIframeContents(ifr, successFn, errorFn); + } + } catch (e) { + errorFn(); + } + }; + ifr.addEventListener("load", listener); + tout = setTimeout(listener, this.iframesTimeout); + } + }, { + key: "onIframeReady", + value: function onIframeReady(ifr, successFn, errorFn) { + try { + if (ifr.contentWindow.document.readyState === "complete") { + if (this.isIframeBlank(ifr)) { + this.observeIframeLoad(ifr, successFn, errorFn); + } else { + this.getIframeContents(ifr, successFn, errorFn); + } + } else { + this.observeIframeLoad(ifr, successFn, errorFn); + } + } catch (e) { + errorFn(); + } + } + }, { + key: "waitForIframes", + value: function waitForIframes(ctx, done) { + var _this2 = this; + var eachCalled = 0; + this.forEachIframe(ctx, function() { + return true; + }, function(ifr) { + eachCalled++; + _this2.waitForIframes(ifr.querySelector("html"), function() { + if (!--eachCalled) { + done(); + } + }); + }, function(handled) { + if (!handled) { + done(); + } + }); + } + }, { + key: "forEachIframe", + value: function forEachIframe(ctx, filter, each) { + var _this3 = this; + var end = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : function() { + }; + var ifr = ctx.querySelectorAll("iframe"), open = ifr.length, handled = 0; + ifr = Array.prototype.slice.call(ifr); + var checkEnd = function checkEnd2() { + if (--open <= 0) { + end(handled); + } + }; + if (!open) { + checkEnd(); + } + ifr.forEach(function(ifr2) { + if (DOMIterator2.matches(ifr2, _this3.exclude)) { + checkEnd(); + } else { + _this3.onIframeReady(ifr2, function(con) { + if (filter(ifr2)) { + handled++; + each(con); + } + checkEnd(); + }, checkEnd); + } + }); + } + }, { + key: "createIterator", + value: function createIterator(ctx, whatToShow, filter) { + return document.createNodeIterator(ctx, whatToShow, filter, false); + } + }, { + key: "createInstanceOnIframe", + value: function createInstanceOnIframe(contents) { + return new DOMIterator2(contents.querySelector("html"), this.iframes); + } + }, { + key: "compareNodeIframe", + value: function compareNodeIframe(node, prevNode, ifr) { + var compCurr = node.compareDocumentPosition(ifr), prev = Node.DOCUMENT_POSITION_PRECEDING; + if (compCurr & prev) { + if (prevNode !== null) { + var compPrev = prevNode.compareDocumentPosition(ifr), after = Node.DOCUMENT_POSITION_FOLLOWING; + if (compPrev & after) { + return true; + } + } else { + return true; + } + } + return false; + } + }, { + key: "getIteratorNode", + value: function getIteratorNode(itr) { + var prevNode = itr.previousNode(); + var node = void 0; + if (prevNode === null) { + node = itr.nextNode(); + } else { + node = itr.nextNode() && itr.nextNode(); + } + return { + prevNode, + node + }; + } + }, { + key: "checkIframeFilter", + value: function checkIframeFilter(node, prevNode, currIfr, ifr) { + var key = false, handled = false; + ifr.forEach(function(ifrDict, i) { + if (ifrDict.val === currIfr) { + key = i; + handled = ifrDict.handled; + } + }); + if (this.compareNodeIframe(node, prevNode, currIfr)) { + if (key === false && !handled) { + ifr.push({ + val: currIfr, + handled: true + }); + } else if (key !== false && !handled) { + ifr[key].handled = true; + } + return true; + } + if (key === false) { + ifr.push({ + val: currIfr, + handled: false + }); + } + return false; + } + }, { + key: "handleOpenIframes", + value: function handleOpenIframes(ifr, whatToShow, eCb, fCb) { + var _this4 = this; + ifr.forEach(function(ifrDict) { + if (!ifrDict.handled) { + _this4.getIframeContents(ifrDict.val, function(con) { + _this4.createInstanceOnIframe(con).forEachNode(whatToShow, eCb, fCb); + }); + } + }); + } + }, { + key: "iterateThroughNodes", + value: function iterateThroughNodes(whatToShow, ctx, eachCb, filterCb, doneCb) { + var _this5 = this; + var itr = this.createIterator(ctx, whatToShow, filterCb); + var ifr = [], elements = [], node = void 0, prevNode = void 0, retrieveNodes = function retrieveNodes2() { + var _getIteratorNode = _this5.getIteratorNode(itr); + prevNode = _getIteratorNode.prevNode; + node = _getIteratorNode.node; + return node; + }; + while (retrieveNodes()) { + if (this.iframes) { + this.forEachIframe(ctx, function(currIfr) { + return _this5.checkIframeFilter(node, prevNode, currIfr, ifr); + }, function(con) { + _this5.createInstanceOnIframe(con).forEachNode(whatToShow, function(ifrNode) { + return elements.push(ifrNode); + }, filterCb); + }); + } + elements.push(node); + } + elements.forEach(function(node2) { + eachCb(node2); + }); + if (this.iframes) { + this.handleOpenIframes(ifr, whatToShow, eachCb, filterCb); + } + doneCb(); + } + }, { + key: "forEachNode", + value: function forEachNode(whatToShow, each, filter) { + var _this6 = this; + var done = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : function() { + }; + var contexts = this.getContexts(); + var open = contexts.length; + if (!open) { + done(); + } + contexts.forEach(function(ctx) { + var ready = function ready2() { + _this6.iterateThroughNodes(whatToShow, ctx, each, filter, function() { + if (--open <= 0) { + done(); + } + }); + }; + if (_this6.iframes) { + _this6.waitForIframes(ctx, ready); + } else { + ready(); + } + }); + } + }], [{ + key: "matches", + value: function matches(element, selector) { + var selectors = typeof selector === "string" ? [selector] : selector, fn = element.matches || element.matchesSelector || element.msMatchesSelector || element.mozMatchesSelector || element.oMatchesSelector || element.webkitMatchesSelector; + if (fn) { + var match = false; + selectors.every(function(sel) { + if (fn.call(element, sel)) { + match = true; + return false; + } + return true; + }); + return match; + } else { + return false; + } + } + }]); + return DOMIterator2; + }(); + var Mark$1 = function() { + function Mark2(ctx) { + classCallCheck(this, Mark2); + this.ctx = ctx; + this.ie = false; + var ua = window.navigator.userAgent; + if (ua.indexOf("MSIE") > -1 || ua.indexOf("Trident") > -1) { + this.ie = true; + } + } + createClass(Mark2, [{ + key: "log", + value: function log(msg) { + var level = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "debug"; + var log2 = this.opt.log; + if (!this.opt.debug) { + return; + } + if ((typeof log2 === "undefined" ? "undefined" : _typeof(log2)) === "object" && typeof log2[level] === "function") { + log2[level]("mark.js: " + msg); + } + } + }, { + key: "escapeStr", + value: function escapeStr(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + } + }, { + key: "createRegExp", + value: function createRegExp(str) { + if (this.opt.wildcards !== "disabled") { + str = this.setupWildcardsRegExp(str); + } + str = this.escapeStr(str); + if (Object.keys(this.opt.synonyms).length) { + str = this.createSynonymsRegExp(str); + } + if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) { + str = this.setupIgnoreJoinersRegExp(str); + } + if (this.opt.diacritics) { + str = this.createDiacriticsRegExp(str); + } + str = this.createMergedBlanksRegExp(str); + if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) { + str = this.createJoinersRegExp(str); + } + if (this.opt.wildcards !== "disabled") { + str = this.createWildcardsRegExp(str); + } + str = this.createAccuracyRegExp(str); + return str; + } + }, { + key: "createSynonymsRegExp", + value: function createSynonymsRegExp(str) { + var syn = this.opt.synonyms, sens = this.opt.caseSensitive ? "" : "i", joinerPlaceholder = this.opt.ignoreJoiners || this.opt.ignorePunctuation.length ? "\0" : ""; + for (var index in syn) { + if (syn.hasOwnProperty(index)) { + var value = syn[index], k1 = this.opt.wildcards !== "disabled" ? this.setupWildcardsRegExp(index) : this.escapeStr(index), k2 = this.opt.wildcards !== "disabled" ? this.setupWildcardsRegExp(value) : this.escapeStr(value); + if (k1 !== "" && k2 !== "") { + str = str.replace(new RegExp("(" + this.escapeStr(k1) + "|" + this.escapeStr(k2) + ")", "gm" + sens), joinerPlaceholder + ("(" + this.processSynomyms(k1) + "|") + (this.processSynomyms(k2) + ")") + joinerPlaceholder); + } + } + } + return str; + } + }, { + key: "processSynomyms", + value: function processSynomyms(str) { + if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) { + str = this.setupIgnoreJoinersRegExp(str); + } + return str; + } + }, { + key: "setupWildcardsRegExp", + value: function setupWildcardsRegExp(str) { + str = str.replace(/(?:\\)*\?/g, function(val) { + return val.charAt(0) === "\\" ? "?" : ""; + }); + return str.replace(/(?:\\)*\*/g, function(val) { + return val.charAt(0) === "\\" ? "*" : ""; + }); + } + }, { + key: "createWildcardsRegExp", + value: function createWildcardsRegExp(str) { + var spaces = this.opt.wildcards === "withSpaces"; + return str.replace(/\u0001/g, spaces ? "[\\S\\s]?" : "\\S?").replace(/\u0002/g, spaces ? "[\\S\\s]*?" : "\\S*"); + } + }, { + key: "setupIgnoreJoinersRegExp", + value: function setupIgnoreJoinersRegExp(str) { + return str.replace(/[^(|)\\]/g, function(val, indx, original) { + var nextChar = original.charAt(indx + 1); + if (/[(|)\\]/.test(nextChar) || nextChar === "") { + return val; + } else { + return val + "\0"; + } + }); + } + }, { + key: "createJoinersRegExp", + value: function createJoinersRegExp(str) { + var joiner = []; + var ignorePunctuation = this.opt.ignorePunctuation; + if (Array.isArray(ignorePunctuation) && ignorePunctuation.length) { + joiner.push(this.escapeStr(ignorePunctuation.join(""))); + } + if (this.opt.ignoreJoiners) { + joiner.push("\\u00ad\\u200b\\u200c\\u200d"); + } + return joiner.length ? str.split(/\u0000+/).join("[" + joiner.join("") + "]*") : str; + } + }, { + key: "createDiacriticsRegExp", + value: function createDiacriticsRegExp(str) { + var sens = this.opt.caseSensitive ? "" : "i", dct = this.opt.caseSensitive ? ["a\xE0\xE1\u1EA3\xE3\u1EA1\u0103\u1EB1\u1EAF\u1EB3\u1EB5\u1EB7\xE2\u1EA7\u1EA5\u1EA9\u1EAB\u1EAD\xE4\xE5\u0101\u0105", "A\xC0\xC1\u1EA2\xC3\u1EA0\u0102\u1EB0\u1EAE\u1EB2\u1EB4\u1EB6\xC2\u1EA6\u1EA4\u1EA8\u1EAA\u1EAC\xC4\xC5\u0100\u0104", "c\xE7\u0107\u010D", "C\xC7\u0106\u010C", "d\u0111\u010F", "D\u0110\u010E", "e\xE8\xE9\u1EBB\u1EBD\u1EB9\xEA\u1EC1\u1EBF\u1EC3\u1EC5\u1EC7\xEB\u011B\u0113\u0119", "E\xC8\xC9\u1EBA\u1EBC\u1EB8\xCA\u1EC0\u1EBE\u1EC2\u1EC4\u1EC6\xCB\u011A\u0112\u0118", "i\xEC\xED\u1EC9\u0129\u1ECB\xEE\xEF\u012B", "I\xCC\xCD\u1EC8\u0128\u1ECA\xCE\xCF\u012A", "l\u0142", "L\u0141", "n\xF1\u0148\u0144", "N\xD1\u0147\u0143", "o\xF2\xF3\u1ECF\xF5\u1ECD\xF4\u1ED3\u1ED1\u1ED5\u1ED7\u1ED9\u01A1\u1EDF\u1EE1\u1EDB\u1EDD\u1EE3\xF6\xF8\u014D", "O\xD2\xD3\u1ECE\xD5\u1ECC\xD4\u1ED2\u1ED0\u1ED4\u1ED6\u1ED8\u01A0\u1EDE\u1EE0\u1EDA\u1EDC\u1EE2\xD6\xD8\u014C", "r\u0159", "R\u0158", "s\u0161\u015B\u0219\u015F", "S\u0160\u015A\u0218\u015E", "t\u0165\u021B\u0163", "T\u0164\u021A\u0162", "u\xF9\xFA\u1EE7\u0169\u1EE5\u01B0\u1EEB\u1EE9\u1EED\u1EEF\u1EF1\xFB\xFC\u016F\u016B", "U\xD9\xDA\u1EE6\u0168\u1EE4\u01AF\u1EEA\u1EE8\u1EEC\u1EEE\u1EF0\xDB\xDC\u016E\u016A", "y\xFD\u1EF3\u1EF7\u1EF9\u1EF5\xFF", "Y\xDD\u1EF2\u1EF6\u1EF8\u1EF4\u0178", "z\u017E\u017C\u017A", "Z\u017D\u017B\u0179"] : ["a\xE0\xE1\u1EA3\xE3\u1EA1\u0103\u1EB1\u1EAF\u1EB3\u1EB5\u1EB7\xE2\u1EA7\u1EA5\u1EA9\u1EAB\u1EAD\xE4\xE5\u0101\u0105A\xC0\xC1\u1EA2\xC3\u1EA0\u0102\u1EB0\u1EAE\u1EB2\u1EB4\u1EB6\xC2\u1EA6\u1EA4\u1EA8\u1EAA\u1EAC\xC4\xC5\u0100\u0104", "c\xE7\u0107\u010DC\xC7\u0106\u010C", "d\u0111\u010FD\u0110\u010E", "e\xE8\xE9\u1EBB\u1EBD\u1EB9\xEA\u1EC1\u1EBF\u1EC3\u1EC5\u1EC7\xEB\u011B\u0113\u0119E\xC8\xC9\u1EBA\u1EBC\u1EB8\xCA\u1EC0\u1EBE\u1EC2\u1EC4\u1EC6\xCB\u011A\u0112\u0118", "i\xEC\xED\u1EC9\u0129\u1ECB\xEE\xEF\u012BI\xCC\xCD\u1EC8\u0128\u1ECA\xCE\xCF\u012A", "l\u0142L\u0141", "n\xF1\u0148\u0144N\xD1\u0147\u0143", "o\xF2\xF3\u1ECF\xF5\u1ECD\xF4\u1ED3\u1ED1\u1ED5\u1ED7\u1ED9\u01A1\u1EDF\u1EE1\u1EDB\u1EDD\u1EE3\xF6\xF8\u014DO\xD2\xD3\u1ECE\xD5\u1ECC\xD4\u1ED2\u1ED0\u1ED4\u1ED6\u1ED8\u01A0\u1EDE\u1EE0\u1EDA\u1EDC\u1EE2\xD6\xD8\u014C", "r\u0159R\u0158", "s\u0161\u015B\u0219\u015FS\u0160\u015A\u0218\u015E", "t\u0165\u021B\u0163T\u0164\u021A\u0162", "u\xF9\xFA\u1EE7\u0169\u1EE5\u01B0\u1EEB\u1EE9\u1EED\u1EEF\u1EF1\xFB\xFC\u016F\u016BU\xD9\xDA\u1EE6\u0168\u1EE4\u01AF\u1EEA\u1EE8\u1EEC\u1EEE\u1EF0\xDB\xDC\u016E\u016A", "y\xFD\u1EF3\u1EF7\u1EF9\u1EF5\xFFY\xDD\u1EF2\u1EF6\u1EF8\u1EF4\u0178", "z\u017E\u017C\u017AZ\u017D\u017B\u0179"]; + var handled = []; + str.split("").forEach(function(ch) { + dct.every(function(dct2) { + if (dct2.indexOf(ch) !== -1) { + if (handled.indexOf(dct2) > -1) { + return false; + } + str = str.replace(new RegExp("[" + dct2 + "]", "gm" + sens), "[" + dct2 + "]"); + handled.push(dct2); + } + return true; + }); + }); + return str; + } + }, { + key: "createMergedBlanksRegExp", + value: function createMergedBlanksRegExp(str) { + return str.replace(/[\s]+/gmi, "[\\s]+"); + } + }, { + key: "createAccuracyRegExp", + value: function createAccuracyRegExp(str) { + var _this = this; + var chars = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\xA1\xBF"; + var acc = this.opt.accuracy, val = typeof acc === "string" ? acc : acc.value, ls = typeof acc === "string" ? [] : acc.limiters, lsJoin = ""; + ls.forEach(function(limiter) { + lsJoin += "|" + _this.escapeStr(limiter); + }); + switch (val) { + case "partially": + default: + return "()(" + str + ")"; + case "complementary": + lsJoin = "\\s" + (lsJoin ? lsJoin : this.escapeStr(chars)); + return "()([^" + lsJoin + "]*" + str + "[^" + lsJoin + "]*)"; + case "exactly": + return "(^|\\s" + lsJoin + ")(" + str + ")(?=$|\\s" + lsJoin + ")"; + } + } + }, { + key: "getSeparatedKeywords", + value: function getSeparatedKeywords(sv) { + var _this2 = this; + var stack = []; + sv.forEach(function(kw) { + if (!_this2.opt.separateWordSearch) { + if (kw.trim() && stack.indexOf(kw) === -1) { + stack.push(kw); + } + } else { + kw.split(" ").forEach(function(kwSplitted) { + if (kwSplitted.trim() && stack.indexOf(kwSplitted) === -1) { + stack.push(kwSplitted); + } + }); + } + }); + return { + "keywords": stack.sort(function(a, b) { + return b.length - a.length; + }), + "length": stack.length + }; + } + }, { + key: "isNumeric", + value: function isNumeric(value) { + return Number(parseFloat(value)) == value; + } + }, { + key: "checkRanges", + value: function checkRanges(array) { + var _this3 = this; + if (!Array.isArray(array) || Object.prototype.toString.call(array[0]) !== "[object Object]") { + this.log("markRanges() will only accept an array of objects"); + this.opt.noMatch(array); + return []; + } + var stack = []; + var last = 0; + array.sort(function(a, b) { + return a.start - b.start; + }).forEach(function(item) { + var _callNoMatchOnInvalid = _this3.callNoMatchOnInvalidRanges(item, last), start = _callNoMatchOnInvalid.start, end = _callNoMatchOnInvalid.end, valid = _callNoMatchOnInvalid.valid; + if (valid) { + item.start = start; + item.length = end - start; + stack.push(item); + last = end; + } + }); + return stack; + } + }, { + key: "callNoMatchOnInvalidRanges", + value: function callNoMatchOnInvalidRanges(range, last) { + var start = void 0, end = void 0, valid = false; + if (range && typeof range.start !== "undefined") { + start = parseInt(range.start, 10); + end = start + parseInt(range.length, 10); + if (this.isNumeric(range.start) && this.isNumeric(range.length) && end - last > 0 && end - start > 0) { + valid = true; + } else { + this.log("Ignoring invalid or overlapping range: " + ("" + JSON.stringify(range))); + this.opt.noMatch(range); + } + } else { + this.log("Ignoring invalid range: " + JSON.stringify(range)); + this.opt.noMatch(range); + } + return { + start, + end, + valid + }; + } + }, { + key: "checkWhitespaceRanges", + value: function checkWhitespaceRanges(range, originalLength, string) { + var end = void 0, valid = true, max = string.length, offset = originalLength - max, start = parseInt(range.start, 10) - offset; + start = start > max ? max : start; + end = start + parseInt(range.length, 10); + if (end > max) { + end = max; + this.log("End range automatically set to the max value of " + max); + } + if (start < 0 || end - start < 0 || start > max || end > max) { + valid = false; + this.log("Invalid range: " + JSON.stringify(range)); + this.opt.noMatch(range); + } else if (string.substring(start, end).replace(/\s+/g, "") === "") { + valid = false; + this.log("Skipping whitespace only range: " + JSON.stringify(range)); + this.opt.noMatch(range); + } + return { + start, + end, + valid + }; + } + }, { + key: "getTextNodes", + value: function getTextNodes(cb) { + var _this4 = this; + var val = "", nodes = []; + this.iterator.forEachNode(NodeFilter.SHOW_TEXT, function(node) { + nodes.push({ + start: val.length, + end: (val += node.textContent).length, + node + }); + }, function(node) { + if (_this4.matchesExclude(node.parentNode)) { + return NodeFilter.FILTER_REJECT; + } else { + return NodeFilter.FILTER_ACCEPT; + } + }, function() { + cb({ + value: val, + nodes + }); + }); + } + }, { + key: "matchesExclude", + value: function matchesExclude(el) { + return DOMIterator.matches(el, this.opt.exclude.concat(["script", "style", "title", "head", "html"])); + } + }, { + key: "wrapRangeInTextNode", + value: function wrapRangeInTextNode(node, start, end) { + var hEl = !this.opt.element ? "mark" : this.opt.element, startNode = node.splitText(start), ret = startNode.splitText(end - start); + var repl = document.createElement(hEl); + repl.setAttribute("data-markjs", "true"); + if (this.opt.className) { + repl.setAttribute("class", this.opt.className); + } + repl.textContent = startNode.textContent; + startNode.parentNode.replaceChild(repl, startNode); + return ret; + } + }, { + key: "wrapRangeInMappedTextNode", + value: function wrapRangeInMappedTextNode(dict, start, end, filterCb, eachCb) { + var _this5 = this; + dict.nodes.every(function(n, i) { + var sibl = dict.nodes[i + 1]; + if (typeof sibl === "undefined" || sibl.start > start) { + if (!filterCb(n.node)) { + return false; + } + var s = start - n.start, e = (end > n.end ? n.end : end) - n.start, startStr = dict.value.substr(0, n.start), endStr = dict.value.substr(e + n.start); + n.node = _this5.wrapRangeInTextNode(n.node, s, e); + dict.value = startStr + endStr; + dict.nodes.forEach(function(k, j) { + if (j >= i) { + if (dict.nodes[j].start > 0 && j !== i) { + dict.nodes[j].start -= e; + } + dict.nodes[j].end -= e; + } + }); + end -= e; + eachCb(n.node.previousSibling, n.start); + if (end > n.end) { + start = n.end; + } else { + return false; + } + } + return true; + }); + } + }, { + key: "wrapMatches", + value: function wrapMatches(regex, ignoreGroups, filterCb, eachCb, endCb) { + var _this6 = this; + var matchIdx = ignoreGroups === 0 ? 0 : ignoreGroups + 1; + this.getTextNodes(function(dict) { + dict.nodes.forEach(function(node) { + node = node.node; + var match = void 0; + while ((match = regex.exec(node.textContent)) !== null && match[matchIdx] !== "") { + if (!filterCb(match[matchIdx], node)) { + continue; + } + var pos = match.index; + if (matchIdx !== 0) { + for (var i = 1; i < matchIdx; i++) { + pos += match[i].length; + } + } + node = _this6.wrapRangeInTextNode(node, pos, pos + match[matchIdx].length); + eachCb(node.previousSibling); + regex.lastIndex = 0; + } + }); + endCb(); + }); + } + }, { + key: "wrapMatchesAcrossElements", + value: function wrapMatchesAcrossElements(regex, ignoreGroups, filterCb, eachCb, endCb) { + var _this7 = this; + var matchIdx = ignoreGroups === 0 ? 0 : ignoreGroups + 1; + this.getTextNodes(function(dict) { + var match = void 0; + while ((match = regex.exec(dict.value)) !== null && match[matchIdx] !== "") { + var start = match.index; + if (matchIdx !== 0) { + for (var i = 1; i < matchIdx; i++) { + start += match[i].length; + } + } + var end = start + match[matchIdx].length; + _this7.wrapRangeInMappedTextNode(dict, start, end, function(node) { + return filterCb(match[matchIdx], node); + }, function(node, lastIndex) { + regex.lastIndex = lastIndex; + eachCb(node); + }); + } + endCb(); + }); + } + }, { + key: "wrapRangeFromIndex", + value: function wrapRangeFromIndex(ranges, filterCb, eachCb, endCb) { + var _this8 = this; + this.getTextNodes(function(dict) { + var originalLength = dict.value.length; + ranges.forEach(function(range, counter) { + var _checkWhitespaceRange = _this8.checkWhitespaceRanges(range, originalLength, dict.value), start = _checkWhitespaceRange.start, end = _checkWhitespaceRange.end, valid = _checkWhitespaceRange.valid; + if (valid) { + _this8.wrapRangeInMappedTextNode(dict, start, end, function(node) { + return filterCb(node, range, dict.value.substring(start, end), counter); + }, function(node) { + eachCb(node, range); + }); + } + }); + endCb(); + }); + } + }, { + key: "unwrapMatches", + value: function unwrapMatches(node) { + var parent = node.parentNode; + var docFrag = document.createDocumentFragment(); + while (node.firstChild) { + docFrag.appendChild(node.removeChild(node.firstChild)); + } + parent.replaceChild(docFrag, node); + if (!this.ie) { + parent.normalize(); + } else { + this.normalizeTextNode(parent); + } + } + }, { + key: "normalizeTextNode", + value: function normalizeTextNode(node) { + if (!node) { + return; + } + if (node.nodeType === 3) { + while (node.nextSibling && node.nextSibling.nodeType === 3) { + node.nodeValue += node.nextSibling.nodeValue; + node.parentNode.removeChild(node.nextSibling); + } + } else { + this.normalizeTextNode(node.firstChild); + } + this.normalizeTextNode(node.nextSibling); + } + }, { + key: "markRegExp", + value: function markRegExp(regexp, opt) { + var _this9 = this; + this.opt = opt; + this.log('Searching with expression "' + regexp + '"'); + var totalMatches = 0, fn = "wrapMatches"; + var eachCb = function eachCb2(element) { + totalMatches++; + _this9.opt.each(element); + }; + if (this.opt.acrossElements) { + fn = "wrapMatchesAcrossElements"; + } + this[fn](regexp, this.opt.ignoreGroups, function(match, node) { + return _this9.opt.filter(node, match, totalMatches); + }, eachCb, function() { + if (totalMatches === 0) { + _this9.opt.noMatch(regexp); + } + _this9.opt.done(totalMatches); + }); + } + }, { + key: "mark", + value: function mark(sv, opt) { + var _this10 = this; + this.opt = opt; + var totalMatches = 0, fn = "wrapMatches"; + var _getSeparatedKeywords = this.getSeparatedKeywords(typeof sv === "string" ? [sv] : sv), kwArr = _getSeparatedKeywords.keywords, kwArrLen = _getSeparatedKeywords.length, sens = this.opt.caseSensitive ? "" : "i", handler = function handler2(kw) { + var regex = new RegExp(_this10.createRegExp(kw), "gm" + sens), matches = 0; + _this10.log('Searching with expression "' + regex + '"'); + _this10[fn](regex, 1, function(term, node) { + return _this10.opt.filter(node, kw, totalMatches, matches); + }, function(element) { + matches++; + totalMatches++; + _this10.opt.each(element); + }, function() { + if (matches === 0) { + _this10.opt.noMatch(kw); + } + if (kwArr[kwArrLen - 1] === kw) { + _this10.opt.done(totalMatches); + } else { + handler2(kwArr[kwArr.indexOf(kw) + 1]); + } + }); + }; + if (this.opt.acrossElements) { + fn = "wrapMatchesAcrossElements"; + } + if (kwArrLen === 0) { + this.opt.done(totalMatches); + } else { + handler(kwArr[0]); + } + } + }, { + key: "markRanges", + value: function markRanges(rawRanges, opt) { + var _this11 = this; + this.opt = opt; + var totalMatches = 0, ranges = this.checkRanges(rawRanges); + if (ranges && ranges.length) { + this.log("Starting to mark with the following ranges: " + JSON.stringify(ranges)); + this.wrapRangeFromIndex(ranges, function(node, range, match, counter) { + return _this11.opt.filter(node, range, match, counter); + }, function(element, range) { + totalMatches++; + _this11.opt.each(element, range); + }, function() { + _this11.opt.done(totalMatches); + }); + } else { + this.opt.done(totalMatches); + } + } + }, { + key: "unmark", + value: function unmark(opt) { + var _this12 = this; + this.opt = opt; + var sel = this.opt.element ? this.opt.element : "*"; + sel += "[data-markjs]"; + if (this.opt.className) { + sel += "." + this.opt.className; + } + this.log('Removal selector "' + sel + '"'); + this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT, function(node) { + _this12.unwrapMatches(node); + }, function(node) { + var matchesSel = DOMIterator.matches(node, sel), matchesExclude = _this12.matchesExclude(node); + if (!matchesSel || matchesExclude) { + return NodeFilter.FILTER_REJECT; + } else { + return NodeFilter.FILTER_ACCEPT; + } + }, this.opt.done); + } + }, { + key: "opt", + set: function set$$1(val) { + this._opt = _extends({}, { + "element": "", + "className": "", + "exclude": [], + "iframes": false, + "iframesTimeout": 5e3, + "separateWordSearch": true, + "diacritics": true, + "synonyms": {}, + "accuracy": "partially", + "acrossElements": false, + "caseSensitive": false, + "ignoreJoiners": false, + "ignoreGroups": 0, + "ignorePunctuation": [], + "wildcards": "disabled", + "each": function each() { + }, + "noMatch": function noMatch() { + }, + "filter": function filter() { + return true; + }, + "done": function done() { + }, + "debug": false, + "log": window.console + }, val); + }, + get: function get$$1() { + return this._opt; + } + }, { + key: "iterator", + get: function get$$1() { + return new DOMIterator(this.ctx, this.opt.iframes, this.opt.exclude, this.opt.iframesTimeout); + } + }]); + return Mark2; + }(); + function Mark(ctx) { + var _this = this; + var instance = new Mark$1(ctx); + this.mark = function(sv, opt) { + instance.mark(sv, opt); + return _this; + }; + this.markRegExp = function(sv, opt) { + instance.markRegExp(sv, opt); + return _this; + }; + this.markRanges = function(sv, opt) { + instance.markRanges(sv, opt); + return _this; + }; + this.unmark = function(opt) { + instance.unmark(opt); + return _this; + }; + return this; + } + return Mark; + }); + } +}); + +// src/ui/solid/tree.tsx +var require_tree = __commonJS({ + "src/ui/solid/tree.tsx"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.Tree = Tree; + var _web = require_web(); + var _solidJs = require_solid(); + var _branch = require_branch(); + var _collapseEmptyNodes = (init_collapse_empty_nodes(), __toCommonJS(collapse_empty_nodes_exports)); + var _mark = _interopRequireDefault(require_mark()); + function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; + } + var _tmpl$ = /* @__PURE__ */ (0, _web.template)(`
`); + function Tree(props) { + const collapsedTree = () => ({ + ...props.fileContextTree, + branches: props.fileContextTree.branches.map(_collapseEmptyNodes.collapseEmptyNodes) + }); + let markContextRef; + (0, _solidJs.createEffect)(() => { + new _mark.default(markContextRef).mark(props.highlights, { + element: "span", + className: "search-result-file-matched-text", + separateWordSearch: false, + diacritics: false + }); + }); + return ( + // @ts-ignore + (() => { + const _el$ = _tmpl$(); + const _ref$ = markContextRef; + typeof _ref$ === "function" ? (0, _web.use)(_ref$, _el$) : markContextRef = _el$; + (0, _web.insert)(_el$, (0, _web.createComponent)(_branch.Branch, { + get contextTree() { + return collapsedTree(); + } + })); + return _el$; + })() + ); + } + } +}); + +// src/ui/solid/render-context-tree.tsx +var require_render_context_tree = __commonJS({ + "src/ui/solid/render-context-tree.tsx"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.renderContextTree = renderContextTree2; + var _web = require_web(); + var _pluginContext = require_plugin_context(); + var _tree = require_tree(); + function renderContextTree2({ + contextTree, + el, + plugin, + highlights, + infinityScroll + }) { + return (0, _web.render)(() => (0, _web.createComponent)(_pluginContext.PluginContextProvider, { + plugin, + infinityScroll, + get children() { + return (0, _web.createComponent)(_tree.Tree, { + fileContextTree: contextTree, + highlights + }); + } + }), el); + } + } +}); + +// src/plugin.ts +var plugin_exports = {}; +__export(plugin_exports, { + default: () => BetterBacklinksPlugin +}); +module.exports = __toCommonJS(plugin_exports); +var import_obsidian2 = require("obsidian"); + +// src/patcher.ts +var import_obsidian = require("obsidian"); + +// node_modules/monkey-around/mjs/index.js +function around(obj, factories) { + const removers = Object.keys(factories).map((key) => around1(obj, key, factories[key])); + return removers.length === 1 ? removers[0] : function() { + removers.forEach((r) => r()); + }; +} +function around1(obj, method, createWrapper) { + const original = obj[method], hadOwn = obj.hasOwnProperty(method); + let current = createWrapper(original); + if (original) + Object.setPrototypeOf(current, original); + Object.setPrototypeOf(wrapper, current); + obj[method] = wrapper; + return remove; + function wrapper(...args) { + if (current === original && obj[method] === wrapper) + remove(); + return current.apply(this, args); + } + function remove() { + if (obj[method] === wrapper) { + if (hadOwn) + obj[method] = original; + else + delete obj[method]; + } + if (current === original) + return; + current = original; + Object.setPrototypeOf(wrapper, original || Function); + } +} + +// src/metadata-cache-util/position.ts +var getTextAtPosition = (textInput, pos) => textInput.substring(pos.start.offset, pos.end.offset); +var getTextFromLineStartToPositionEnd = (textInput, pos) => textInput.substring(pos.start.offset - pos.start.col, pos.end.offset); +var doesPositionIncludeAnother = (container, child) => container.start.offset <= child.start.offset && container.end.offset >= child.end.offset; +function isSamePosition(a, b) { + return a && b && a.start.offset === b.start.offset && a.end.offset === b.end.offset; +} +function createPositionFromOffsets(content, startOffset, endOffset) { + const startLine = content.substring(0, startOffset).split("\n").length - 1; + const endLine = content.substring(0, endOffset).split("\n").length - 1; + const startLinePos = content.substring(0, startOffset).lastIndexOf("\n") + 1; + const startCol = content.substring(startLinePos, startOffset).length; + const endLinePos = content.substring(0, endOffset).lastIndexOf("\n") + 1; + const endCol = content.substring(endLinePos, endOffset).length; + return { + position: { + start: { line: startLine, col: startCol, offset: startOffset }, + end: { line: endLine, col: endCol, offset: endOffset } + } + }; +} + +// src/metadata-cache-util/heading.ts +function getHeadingIndexContaining(position, headings) { + return headings.findIndex( + (heading) => heading.position.start.line === position.start.line + ); +} +function getIndexOfHeadingAbove(position, headings) { + return headings.reduce( + (previousIndex, lookingAtHeading, index) => lookingAtHeading.position.start.line < position.start.line ? index : previousIndex, + -1 + ); +} +function getHeadingBreadcrumbs(position, headings) { + const headingBreadcrumbs = []; + if (headings.length === 0) { + return headingBreadcrumbs; + } + const collectAncestorHeadingsForHeadingAtIndex = (startIndex) => { + let currentLevel = headings[startIndex].level; + const previousHeadingIndex = startIndex - 1; + for (let i = previousHeadingIndex; i >= 0; i--) { + const lookingAtHeading = headings[i]; + if (lookingAtHeading.level < currentLevel) { + currentLevel = lookingAtHeading.level; + headingBreadcrumbs.unshift(lookingAtHeading); + } + } + }; + const headingIndexAtPosition = getHeadingIndexContaining(position, headings); + const positionIsInsideHeading = headingIndexAtPosition >= 0; + if (positionIsInsideHeading) { + headingBreadcrumbs.unshift(headings[headingIndexAtPosition]); + collectAncestorHeadingsForHeadingAtIndex(headingIndexAtPosition); + return headingBreadcrumbs; + } + const headingIndexAbovePosition = getIndexOfHeadingAbove(position, headings); + const positionIsBelowHeading = headingIndexAbovePosition >= 0; + if (positionIsBelowHeading) { + const headingAbovePosition = headings[headingIndexAbovePosition]; + headingBreadcrumbs.unshift(headingAbovePosition); + collectAncestorHeadingsForHeadingAtIndex(headingIndexAbovePosition); + return headingBreadcrumbs; + } + return headingBreadcrumbs; +} + +// src/metadata-cache-util/list.ts +function getListItemWithDescendants(listItemIndex, listItems) { + const rootListItem = listItems[listItemIndex]; + const listItemWithDescendants = [rootListItem]; + for (let i = listItemIndex + 1; i < listItems.length; i++) { + const nextItem = listItems[i]; + if (nextItem.parent < rootListItem.position.start.line) { + return listItemWithDescendants; + } + listItemWithDescendants.push(nextItem); + } + return listItemWithDescendants; +} +function getListBreadcrumbs(position, listItems) { + const listBreadcrumbs = []; + if (listItems.length === 0) { + return listBreadcrumbs; + } + const thisItemIndex = getListItemIndexContaining(position, listItems); + const isPositionOutsideListItem = thisItemIndex < 0; + if (isPositionOutsideListItem) { + return listBreadcrumbs; + } + const thisItem = listItems[thisItemIndex]; + let currentParent = thisItem.parent; + if (isTopLevelListItem(thisItem)) { + return listBreadcrumbs; + } + for (let i = thisItemIndex - 1; i >= 0; i--) { + const currentItem = listItems[i]; + const currentItemIsHigherUp = currentItem.parent < currentParent; + if (currentItemIsHigherUp) { + listBreadcrumbs.unshift(currentItem); + currentParent = currentItem.parent; + } + if (isTopLevelListItem(currentItem)) { + return listBreadcrumbs; + } + } + return listBreadcrumbs; +} +function isTopLevelListItem(listItem) { + return listItem.parent < 0; +} +function getListItemIndexContaining(searchedForPosition, listItems) { + return listItems.findIndex( + ({ position }) => doesPositionIncludeAnother(position, searchedForPosition) + ); +} +function isPositionInList(position, listItems) { + return getListItemIndexContaining(position, listItems) >= 0; +} + +// src/metadata-cache-util/section.ts +function getSectionContaining(searchedForPosition, sections) { + return sections.find( + ({ position }) => doesPositionIncludeAnother(position, searchedForPosition) + ); +} +function getFirstSectionUnder(position, sections) { + return sections.find( + (section) => section.position.start.line > position.start.line + ); +} + +// src/metadata-cache-util/format.ts +var formatListWithDescendants = (textInput, listItems) => { + const root = listItems[0]; + const leadingSpacesCount = root.position.start.col; + return listItems.map( + (itemCache) => getTextFromLineStartToPositionEnd(textInput, itemCache.position).slice( + leadingSpacesCount + ) + ).join("\n"); +}; + +// src/context-tree/create/create-context-tree.ts +function createContextTree({ + positions, + fileContents, + stat, + filePath, + listItems = [], + headings = [], + sections = [] +}) { + const positionsWithContext = positions.map((position) => { + return { + headingBreadcrumbs: getHeadingBreadcrumbs(position.position, headings), + listBreadcrumbs: getListBreadcrumbs(position.position, listItems), + sectionCache: getSectionContaining(position.position, sections), + position + }; + }); + const root = createContextTreeBranch("file", {}, stat, filePath, filePath); + for (const { + headingBreadcrumbs, + listBreadcrumbs, + sectionCache, + position + } of positionsWithContext) { + if (!sectionCache) { + continue; + } + let context = root; + for (const headingCache of headingBreadcrumbs) { + const headingFoundInChildren = context.branches.find( + (tree) => isSamePosition(tree.cacheItem.position, headingCache.position) + ); + if (headingFoundInChildren) { + context = headingFoundInChildren; + } else { + const newContext = createContextTreeBranch( + "heading", + headingCache, + stat, + filePath, + headingCache.heading + ); + context.branches.push(newContext); + context = newContext; + } + } + for (const listItemCache of listBreadcrumbs) { + const listItemFoundInChildren = context.branches.find( + (tree) => isSamePosition(tree.cacheItem.position, listItemCache.position) + ); + if (listItemFoundInChildren) { + context = listItemFoundInChildren; + } else { + const newListContext = createContextTreeBranch( + "list", + listItemCache, + stat, + filePath, + getTextAtPosition(fileContents, listItemCache.position) + ); + context.branches.push(newListContext); + context = newListContext; + } + } + const headingIndexAtPosition = getHeadingIndexContaining( + position.position, + headings + ); + const linkIsInsideHeading = headingIndexAtPosition >= 0; + if (isPositionInList(position.position, listItems)) { + const indexOfListItemContainingLink = getListItemIndexContaining( + position.position, + listItems + ); + const listItemCacheWithDescendants = getListItemWithDescendants( + indexOfListItemContainingLink, + listItems + ); + const text = formatListWithDescendants( + fileContents, + listItemCacheWithDescendants + ); + context.sectionsWithMatches.push({ + // TODO: add type to the cache + // @ts-ignore + cache: listItemCacheWithDescendants[0], + text, + filePath + }); + } else if (linkIsInsideHeading) { + const firstSectionUnderHeading = getFirstSectionUnder( + position.position, + sections + ); + if (firstSectionUnderHeading) { + context.sectionsWithMatches.push({ + cache: firstSectionUnderHeading, + text: getTextAtPosition( + fileContents, + firstSectionUnderHeading.position + ), + filePath + }); + } + } else { + const sectionText = getTextAtPosition( + fileContents, + sectionCache.position + ); + context.sectionsWithMatches.push({ + cache: sectionCache, + text: sectionText, + filePath + }); + } + } + return root; +} +function createContextTreeBranch(type, cacheItem, stat, filePath, text) { + return { + type, + cacheItem, + filePath, + text, + stat, + branches: [], + sectionsWithMatches: [] + }; +} + +// src/patcher.ts +var import_render_context_tree = __toESM(require_render_context_tree()); +init_patterns(); + +// src/disposer-registry.ts +var DisposerRegistry = class { + constructor() { + this.domToDisposers = /* @__PURE__ */ new WeakMap(); + } + /** + * We assume here that match results are going to be added synchronously to the same dom, on which onAddResult is + * called + * @param searchResultDom + */ + onAddResult(searchResultDom) { + this.contextDom = searchResultDom; + if (!this.domToDisposers.has(this)) { + this.domToDisposers.set(this, []); + } + } + addOnEmptyResultsCallback(fn) { + var _a; + if (!this.contextDom) { + throw new Error( + "You rendered a Solid root before you got a reference to the containing searchResultDom" + ); + } + (_a = this.domToDisposers.get(this.contextDom)) == null ? void 0 : _a.push(fn); + } + /** + * This may be called before any results are added + * @param searchResultDom + */ + onEmptyResults(searchResultDom) { + var _a; + (_a = this.domToDisposers.get(searchResultDom)) == null ? void 0 : _a.forEach((disposer) => disposer()); + this.domToDisposers.set(searchResultDom, []); + } +}; + +// src/context-tree/dedupe/dedupe-matches.ts +function dedupeMatches(tree) { + return { + ...tree, + sectionsWithMatches: dedupe(tree.sectionsWithMatches), + branches: tree.branches.map((branch) => dedupeMatches(branch)) + }; +} +function areMatchesInSameSection(a, b) { + return a.text === b.text && isSamePosition(a.cache.position, b.cache.position); +} +function dedupe(matches) { + return matches.filter( + (match, index, array) => index === array.findIndex((inner) => areMatchesInSameSection(inner, match)) + ); +} + +// src/patcher.ts +var errorTimeout = 1e4; +function getHighlightsFromVChild(vChild) { + const { content, matches } = vChild; + const firstMatch = matches[0]; + const [start, end] = firstMatch; + return content.substring(start, end).toLowerCase().replace(wikiLinkBrackets, ""); +} +var Patcher = class { + constructor(plugin) { + this.plugin = plugin; + this.wrappedMatches = /* @__PURE__ */ new WeakSet(); + this.wrappedSearchResultItems = /* @__PURE__ */ new WeakSet(); + this.triedPatchingSearchResultItem = false; + this.triedPatchingRenderContentMatches = false; + this.disposerRegistry = new DisposerRegistry(); + } + patchComponent() { + const patcher = this; + this.plugin.register( + around(import_obsidian.Component.prototype, { + addChild(old) { + return function(child, ...args) { + const thisIsSearchView = this.hasOwnProperty("searchQuery"); + const hasBacklinks = child == null ? void 0 : child.backlinkDom; + if ((thisIsSearchView || hasBacklinks) && !patcher.triedPatchingSearchResultItem) { + patcher.triedPatchingSearchResultItem = true; + try { + patcher.patchSearchResultDom(child.dom || child.backlinkDom); + } catch (error) { + patcher.reportError( + error, + "Error while patching Obsidian internals" + ); + } + } + return old.call(this, child, ...args); + }; + } + }) + ); + } + patchSearchResultDom(searchResultDom) { + const patcher = this; + this.plugin.register( + around(searchResultDom.constructor.prototype, { + addResult(old) { + return function(...args) { + patcher.disposerRegistry.onAddResult(this); + const result = old.call(this, ...args); + if (!patcher.triedPatchingRenderContentMatches) { + patcher.triedPatchingRenderContentMatches = true; + try { + patcher.patchSearchResultItem(result); + } catch (error) { + patcher.reportError( + error, + "Error while patching Obsidian internals" + ); + } + } + return result; + }; + }, + emptyResults(old) { + return function(...args) { + patcher.disposerRegistry.onEmptyResults(this); + return old.call(this, ...args); + }; + } + }) + ); + } + patchSearchResultItem(searchResultItem) { + const patcher = this; + this.plugin.register( + around(searchResultItem.constructor.prototype, { + renderContentMatches(old) { + return function(...args) { + const result = old.call(this, ...args); + if (patcher.wrappedSearchResultItems.has(this) || !this.vChildren._children || this.vChildren._children.length === 0) { + return result; + } + patcher.wrappedSearchResultItems.add(this); + try { + let someMatchIsInProperties = false; + const matchPositions = this.vChildren._children.map( + // todo: works only for one match per block + (child) => { + const { content, matches } = child; + const firstMatch2 = matches[0]; + if (Object.hasOwn(firstMatch2, "key")) { + someMatchIsInProperties = true; + return null; + } + const [start, end] = firstMatch2; + return createPositionFromOffsets(content, start, end); + } + ); + if (someMatchIsInProperties) { + return result; + } + const highlights = this.vChildren._children.map( + getHighlightsFromVChild + ); + const deduped = [...new Set(highlights)]; + const firstMatch = this.vChildren._children[0]; + patcher.mountContextTreeOnMatchEl( + this, + firstMatch, + matchPositions, + deduped, + this.parent.infinityScroll + ); + this.vChildren._children = this.vChildren._children.slice(0, 1); + } catch (e) { + patcher.reportError( + e, + `Failed to mount context tree for file path: ${this.file.path}` + ); + } + return result; + }; + } + }) + ); + } + reportError(error, message) { + var _a; + (_a = this.currentNotice) == null ? void 0 : _a.hide(); + this.currentNotice = new import_obsidian.Notice( + `Better Search Views: ${message}. Please report an issue with the details from the console attached.`, + errorTimeout + ); + console.error(`${message}. Reason:`, error); + } + mountContextTreeOnMatchEl(container, match, positions, highlights, infinityScroll) { + if (this.wrappedMatches.has(match)) { + return; + } + this.wrappedMatches.add(match); + const { cache, content } = match; + const { file } = container; + const matchIsOnlyInFileName = !cache.sections || content === ""; + if (file.extension === "canvas" || matchIsOnlyInFileName) { + return; + } + const contextTree = createContextTree({ + positions, + fileContents: content, + stat: file.stat, + filePath: file.path, + ...cache + }); + const mountPoint = createDiv(); + const dispose = (0, import_render_context_tree.renderContextTree)({ + highlights, + contextTree: dedupeMatches(contextTree), + el: mountPoint, + plugin: this.plugin, + infinityScroll + }); + this.disposerRegistry.addOnEmptyResultsCallback(dispose); + match.el = mountPoint; + } +}; + +// src/plugin.ts +var BetterBacklinksPlugin = class extends import_obsidian2.Plugin { + async onload() { + const patcher = new Patcher(this); + patcher.patchComponent(); + } +}; +/*! Bundled license information: + +mark.js/dist/mark.js: + (*!*************************************************** + * mark.js v8.11.1 + * https://markjs.io/ + * Copyright (c) 2014–2018, Julian Kühnel + * Released under the MIT license https://git.io/vwTVl + *****************************************************) +*/ + +/* nosourcemap */ \ No newline at end of file diff --git a/.obsidian/plugins/better-search-views/manifest.json b/.obsidian/plugins/better-search-views/manifest.json new file mode 100644 index 0000000..ee9493e --- /dev/null +++ b/.obsidian/plugins/better-search-views/manifest.json @@ -0,0 +1,11 @@ +{ + "id": "better-search-views", + "name": "Better Search Views", + "version": "0.3.0", + "minAppVersion": "0.16.0", + "description": "Outliner-like breadcrumb trees for search, backlinks and embedded queries ", + "author": "ivan-lednev", + "authorUrl": "https://github.com/ivan-lednev", + "fundingUrl": "https://www.buymeacoffee.com/machineelf", + "isDesktopOnly": false +} \ No newline at end of file diff --git a/.obsidian/plugins/better-search-views/styles.css b/.obsidian/plugins/better-search-views/styles.css new file mode 100644 index 0000000..a44a761 --- /dev/null +++ b/.obsidian/plugins/better-search-views/styles.css @@ -0,0 +1,190 @@ +/* TODO: blockquotes need a better fix */ +.better-search-views-file-match.markdown-rendered > *, +.better-search-views-file-match.markdown-rendered > blockquote > * { + margin-block-start: 0; + margin-block-end: 0; + white-space: normal; +} + +.better-search-views-file-match.markdown-rendered ul > li, +.better-search-views-file-match.markdown-rendered ol > li { + margin-inline-start: calc(var(--list-indent) * 0.8); +} + +.better-search-views-file-match > blockquote { + margin-inline-start: 0; + margin-inline-end: 0; +} + +.better-search-views-file-match ul { + position: relative; + padding-inline-start: 0; +} + +.better-search-views-file-match a { + cursor: default; + text-decoration: none; +} + +/* Copied from Obsidian */ +.better-search-views-file-match li > ul::before { + content: "\200B"; + + position: absolute; + top: 0; + bottom: 0; + left: -1em; + + display: block; + + border-right: var(--indentation-guide-width) solid + var(--indentation-guide-color); +} + +.better-search-views-breadcrumbs { + display: flex; + align-items: center; + border-bottom: 1px solid var(--background-modifier-border); +} + +.better-search-views-tree-item-children { + margin-left: 10px; + padding-left: 10px; + border-left: var(--nav-indentation-guide-width) solid + var(--indentation-guide-color); +} + +.better-search-views-tree-item-children:hover { + border-left-color: var(--indentation-guide-color-active); +} + +.better-search-views-breadcrumb-container { + display: flex; + gap: 0.5em; + align-items: flex-start; +} + +.better-search-views-tree .tree-item-inner { + display: flex; + flex-direction: column; + flex-grow: 1; + gap: 2px; + + padding-top: 4px; + padding-bottom: 4px; + + border-radius: var(--radius-s); +} + +.better-search-views-titles-container .tree-item-inner:not(:hover) { + color: var(--text-muted); +} + +.search-result-file-matches:has(.better-search-views-tree) { + overflow: hidden; + + font-size: var(--font-ui-smaller); + line-height: var(--line-height-tight); + color: var(--text-muted); + + background-color: revert; + border-radius: var(--radius-s); +} + +.search-result-file-matches:has(.better-search-views-tree), +.better-search-views-tree .search-result-file-matches { + margin: var(--size-4-1) 0 var(--size-4-1); +} + +.better-search-views-tree .search-result-file-matches { + margin-left: 21px; +} + +.tree-item.search-result + > .search-result-file-matches:has(.better-search-views-tree) { + /* This fixes box shadow in child match boxes */ + padding-right: 1px; + box-shadow: none; +} + +.search-result-file-matches:has(.better-search-views-tree) + .better-search-views-file-match:not(:hover) { + background-color: var(--search-result-background); + box-shadow: 0 0 0 1px var(--background-modifier-border); +} + +.better-search-views-icon { + width: var(--icon-xs); + height: var(--icon-xs); + color: var(--text-faint); +} + +.better-search-views-tree blockquote { + padding-left: 10px; + border-left: var(--blockquote-border-thickness) solid + var(--blockquote-border-color); +} + +.better-search-views-tree .tree-item-inner:hover { + background-color: var(--nav-item-background-hover); +} + +.better-search-views-tree .search-result-file-title { + padding-right: 0; + + /* TODO: this is still hardcoded */ + padding-left: calc(20px + var(--nav-indentation-guide-width)); +} + +body:not(.is-grabbing) + .better-search-views-tree + .tree-item-self.search-result-file-title:hover { + background-color: unset; +} + +.better-search-views-tree .better-search-views-breadcrumb-container { + flex-grow: 1; + padding-right: 2px; + padding-left: 2px; +} + +.better-search-views-tree + .better-search-views-breadcrumb-container:not(:last-child) { + padding-bottom: 2px; + border-bottom: var(--nav-indentation-guide-width) solid + var(--nav-indentation-guide-color); +} + +.better-search-views-breadcrumb-token { + color: var(--text-faint); + display: flex; + align-items: center; + height: calc(1em * var(--line-height-tight)); +} + +.better-search-views-tree .collapse-icon { + display: flex; + align-items: center; + align-self: flex-start; + + padding-top: 4px; + padding-bottom: 2px; + + border-radius: var(--radius-s); +} + +.better-search-views-titles-container { + display: flex; + flex-direction: column; + flex-grow: 1; +} + +.markdown-source-view.mod-cm6 + .better-search-views-tree + .task-list-item-checkbox { + margin-inline-start: calc(var(--checkbox-size) * -1.5); +} + +.better-search-views-is-hidden { + display: none; +} diff --git a/.obsidian/plugins/better-word-count/main.js b/.obsidian/plugins/better-word-count/main.js new file mode 100644 index 0000000..f31e9cc --- /dev/null +++ b/.obsidian/plugins/better-word-count/main.js @@ -0,0 +1,18801 @@ +'use strict'; + +var obsidian = require('obsidian'); +var state = require('@codemirror/state'); +var view = require('@codemirror/view'); +var language = require('@codemirror/language'); + +function noop$1() { } +// Adapted from https://github.com/then/is-promise/blob/master/index.js +// Distributed under MIT License https://github.com/then/is-promise/blob/master/LICENSE +function is_promise(value) { + return !!value && (typeof value === 'object' || typeof value === 'function') && typeof value.then === 'function'; +} +function run(fn) { + return fn(); +} +function blank_object() { + return Object.create(null); +} +function run_all(fns) { + fns.forEach(run); +} +function is_function(thing) { + return typeof thing === 'function'; +} +function safe_not_equal(a, b) { + return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function'); +} +function is_empty(obj) { + return Object.keys(obj).length === 0; +} +function append(target, node) { + target.appendChild(node); +} +function insert(target, node, anchor) { + target.insertBefore(node, anchor || null); +} +function detach(node) { + if (node.parentNode) { + node.parentNode.removeChild(node); + } +} +function destroy_each(iterations, detaching) { + for (let i = 0; i < iterations.length; i += 1) { + if (iterations[i]) + iterations[i].d(detaching); + } +} +function element(name) { + return document.createElement(name); +} +function text(data) { + return document.createTextNode(data); +} +function space() { + return text(' '); +} +function listen(node, event, handler, options) { + node.addEventListener(event, handler, options); + return () => node.removeEventListener(event, handler, options); +} +function attr(node, attribute, value) { + if (value == null) + node.removeAttribute(attribute); + else if (node.getAttribute(attribute) !== value) + node.setAttribute(attribute, value); +} +function children(element) { + return Array.from(element.childNodes); +} +function set_data(text, data) { + data = '' + data; + if (text.data === data) + return; + text.data = data; +} +function set_style(node, key, value, important) { + if (value == null) { + node.style.removeProperty(key); + } + else { + node.style.setProperty(key, value, important ? 'important' : ''); + } +} +function select_option(select, value, mounting) { + for (let i = 0; i < select.options.length; i += 1) { + const option = select.options[i]; + if (option.__value === value) { + option.selected = true; + return; + } + } + if (!mounting || value !== undefined) { + select.selectedIndex = -1; // no option should be selected + } +} + +let current_component; +function set_current_component(component) { + current_component = component; +} +function get_current_component() { + if (!current_component) + throw new Error('Function called outside component initialization'); + return current_component; +} + +const dirty_components = []; +const binding_callbacks = []; +let render_callbacks = []; +const flush_callbacks = []; +const resolved_promise = /* @__PURE__ */ Promise.resolve(); +let update_scheduled = false; +function schedule_update() { + if (!update_scheduled) { + update_scheduled = true; + resolved_promise.then(flush); + } +} +function add_render_callback(fn) { + render_callbacks.push(fn); +} +// flush() calls callbacks in this order: +// 1. All beforeUpdate callbacks, in order: parents before children +// 2. All bind:this callbacks, in reverse order: children before parents. +// 3. All afterUpdate callbacks, in order: parents before children. EXCEPT +// for afterUpdates called during the initial onMount, which are called in +// reverse order: children before parents. +// Since callbacks might update component values, which could trigger another +// call to flush(), the following steps guard against this: +// 1. During beforeUpdate, any updated components will be added to the +// dirty_components array and will cause a reentrant call to flush(). Because +// the flush index is kept outside the function, the reentrant call will pick +// up where the earlier call left off and go through all dirty components. The +// current_component value is saved and restored so that the reentrant call will +// not interfere with the "parent" flush() call. +// 2. bind:this callbacks cannot trigger new flush() calls. +// 3. During afterUpdate, any updated components will NOT have their afterUpdate +// callback called a second time; the seen_callbacks set, outside the flush() +// function, guarantees this behavior. +const seen_callbacks = new Set(); +let flushidx = 0; // Do *not* move this inside the flush() function +function flush() { + // Do not reenter flush while dirty components are updated, as this can + // result in an infinite loop. Instead, let the inner flush handle it. + // Reentrancy is ok afterwards for bindings etc. + if (flushidx !== 0) { + return; + } + const saved_component = current_component; + do { + // first, call beforeUpdate functions + // and update components + try { + while (flushidx < dirty_components.length) { + const component = dirty_components[flushidx]; + flushidx++; + set_current_component(component); + update(component.$$); + } + } + catch (e) { + // reset dirty state to not end up in a deadlocked state and then rethrow + dirty_components.length = 0; + flushidx = 0; + throw e; + } + set_current_component(null); + dirty_components.length = 0; + flushidx = 0; + while (binding_callbacks.length) + binding_callbacks.pop()(); + // then, once components are updated, call + // afterUpdate functions. This may cause + // subsequent updates... + for (let i = 0; i < render_callbacks.length; i += 1) { + const callback = render_callbacks[i]; + if (!seen_callbacks.has(callback)) { + // ...so guard against infinite loops + seen_callbacks.add(callback); + callback(); + } + } + render_callbacks.length = 0; + } while (dirty_components.length); + while (flush_callbacks.length) { + flush_callbacks.pop()(); + } + update_scheduled = false; + seen_callbacks.clear(); + set_current_component(saved_component); +} +function update($$) { + if ($$.fragment !== null) { + $$.update(); + run_all($$.before_update); + const dirty = $$.dirty; + $$.dirty = [-1]; + $$.fragment && $$.fragment.p($$.ctx, dirty); + $$.after_update.forEach(add_render_callback); + } +} +/** + * Useful for example to execute remaining `afterUpdate` callbacks before executing `destroy`. + */ +function flush_render_callbacks(fns) { + const filtered = []; + const targets = []; + render_callbacks.forEach((c) => fns.indexOf(c) === -1 ? filtered.push(c) : targets.push(c)); + targets.forEach((c) => c()); + render_callbacks = filtered; +} +const outroing = new Set(); +let outros; +function group_outros() { + outros = { + r: 0, + c: [], + p: outros // parent group + }; +} +function check_outros() { + if (!outros.r) { + run_all(outros.c); + } + outros = outros.p; +} +function transition_in(block, local) { + if (block && block.i) { + outroing.delete(block); + block.i(local); + } +} +function transition_out(block, local, detach, callback) { + if (block && block.o) { + if (outroing.has(block)) + return; + outroing.add(block); + outros.c.push(() => { + outroing.delete(block); + if (callback) { + if (detach) + block.d(1); + callback(); + } + }); + block.o(local); + } + else if (callback) { + callback(); + } +} + +function handle_promise(promise, info) { + const token = info.token = {}; + function update(type, index, key, value) { + if (info.token !== token) + return; + info.resolved = value; + let child_ctx = info.ctx; + if (key !== undefined) { + child_ctx = child_ctx.slice(); + child_ctx[key] = value; + } + const block = type && (info.current = type)(child_ctx); + let needs_flush = false; + if (info.block) { + if (info.blocks) { + info.blocks.forEach((block, i) => { + if (i !== index && block) { + group_outros(); + transition_out(block, 1, 1, () => { + if (info.blocks[i] === block) { + info.blocks[i] = null; + } + }); + check_outros(); + } + }); + } + else { + info.block.d(1); + } + block.c(); + transition_in(block, 1); + block.m(info.mount(), info.anchor); + needs_flush = true; + } + info.block = block; + if (info.blocks) + info.blocks[index] = block; + if (needs_flush) { + flush(); + } + } + if (is_promise(promise)) { + const current_component = get_current_component(); + promise.then(value => { + set_current_component(current_component); + update(info.then, 1, info.value, value); + set_current_component(null); + }, error => { + set_current_component(current_component); + update(info.catch, 2, info.error, error); + set_current_component(null); + if (!info.hasCatch) { + throw error; + } + }); + // if we previously had a then/catch block, destroy it + if (info.current !== info.pending) { + update(info.pending, 0); + return true; + } + } + else { + if (info.current !== info.then) { + update(info.then, 1, info.value, promise); + return true; + } + info.resolved = promise; + } +} +function update_await_block_branch(info, ctx, dirty) { + const child_ctx = ctx.slice(); + const { resolved } = info; + if (info.current === info.then) { + child_ctx[info.value] = resolved; + } + if (info.current === info.catch) { + child_ctx[info.error] = resolved; + } + info.block.p(child_ctx, dirty); +} +function mount_component(component, target, anchor, customElement) { + const { fragment, after_update } = component.$$; + fragment && fragment.m(target, anchor); + if (!customElement) { + // onMount happens before the initial afterUpdate + add_render_callback(() => { + const new_on_destroy = component.$$.on_mount.map(run).filter(is_function); + // if the component was destroyed immediately + // it will update the `$$.on_destroy` reference to `null`. + // the destructured on_destroy may still reference to the old array + if (component.$$.on_destroy) { + component.$$.on_destroy.push(...new_on_destroy); + } + else { + // Edge case - component was destroyed immediately, + // most likely as a result of a binding initialising + run_all(new_on_destroy); + } + component.$$.on_mount = []; + }); + } + after_update.forEach(add_render_callback); +} +function destroy_component(component, detaching) { + const $$ = component.$$; + if ($$.fragment !== null) { + flush_render_callbacks($$.after_update); + run_all($$.on_destroy); + $$.fragment && $$.fragment.d(detaching); + // TODO null out other refs, including component.$$ (but need to + // preserve final state?) + $$.on_destroy = $$.fragment = null; + $$.ctx = []; + } +} +function make_dirty(component, i) { + if (component.$$.dirty[0] === -1) { + dirty_components.push(component); + schedule_update(); + component.$$.dirty.fill(0); + } + component.$$.dirty[(i / 31) | 0] |= (1 << (i % 31)); +} +function init(component, options, instance, create_fragment, not_equal, props, append_styles, dirty = [-1]) { + const parent_component = current_component; + set_current_component(component); + const $$ = component.$$ = { + fragment: null, + ctx: [], + // state + props, + update: noop$1, + not_equal, + bound: blank_object(), + // lifecycle + on_mount: [], + on_destroy: [], + on_disconnect: [], + before_update: [], + after_update: [], + context: new Map(options.context || (parent_component ? parent_component.$$.context : [])), + // everything else + callbacks: blank_object(), + dirty, + skip_bound: false, + root: options.target || parent_component.$$.root + }; + append_styles && append_styles($$.root); + let ready = false; + $$.ctx = instance + ? instance(component, options.props || {}, (i, ret, ...rest) => { + const value = rest.length ? rest[0] : ret; + if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) { + if (!$$.skip_bound && $$.bound[i]) + $$.bound[i](value); + if (ready) + make_dirty(component, i); + } + return ret; + }) + : []; + $$.update(); + ready = true; + run_all($$.before_update); + // `false` as a special case of no DOM component + $$.fragment = create_fragment ? create_fragment($$.ctx) : false; + if (options.target) { + if (options.hydrate) { + const nodes = children(options.target); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + $$.fragment && $$.fragment.l(nodes); + nodes.forEach(detach); + } + else { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + $$.fragment && $$.fragment.c(); + } + if (options.intro) + transition_in(component.$$.fragment); + mount_component(component, options.target, options.anchor, options.customElement); + flush(); + } + set_current_component(parent_component); +} +/** + * Base class for Svelte components. Used when dev=false. + */ +class SvelteComponent { + $destroy() { + destroy_component(this, 1); + this.$destroy = noop$1; + } + $on(type, callback) { + if (!is_function(callback)) { + return noop$1; + } + const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = [])); + callbacks.push(callback); + return () => { + const index = callbacks.indexOf(callback); + if (index !== -1) + callbacks.splice(index, 1); + }; + } + $set($$props) { + if (this.$$set && !is_empty($$props)) { + this.$$.skip_bound = true; + this.$$set($$props); + this.$$.skip_bound = false; + } + } +} + +var MetricCounter; +(function (MetricCounter) { + MetricCounter[MetricCounter["words"] = 0] = "words"; + MetricCounter[MetricCounter["characters"] = 1] = "characters"; + MetricCounter[MetricCounter["sentences"] = 2] = "sentences"; + MetricCounter[MetricCounter["footnotes"] = 3] = "footnotes"; + MetricCounter[MetricCounter["citations"] = 4] = "citations"; + MetricCounter[MetricCounter["pages"] = 5] = "pages"; + MetricCounter[MetricCounter["files"] = 6] = "files"; +})(MetricCounter || (MetricCounter = {})); +var MetricType; +(function (MetricType) { + MetricType[MetricType["file"] = 0] = "file"; + MetricType[MetricType["daily"] = 1] = "daily"; + MetricType[MetricType["total"] = 2] = "total"; + MetricType[MetricType["folder"] = 3] = "folder"; +})(MetricType || (MetricType = {})); +const BLANK_SB_ITEM = { + prefix: "", + suffix: "", + metric: { + type: null, + counter: null, + }, +}; +const DEFAULT_SETTINGS = { + statusBar: [ + { + prefix: "", + suffix: " words", + metric: { + type: MetricType.file, + counter: MetricCounter.words, + }, + }, + { + prefix: " ", + suffix: " characters", + metric: { + type: MetricType.file, + counter: MetricCounter.characters, + }, + }, + ], + altBar: [ + { + prefix: "", + suffix: " files", + metric: { + type: MetricType.total, + counter: MetricCounter.files, + }, + }, + ], + countComments: false, + collectStats: false, + displaySectionCounts: false, + pageWords: 300, + statsPath: ".obsidian/vault-stats.json", +}; + +/* src/settings/StatusBarSettings.svelte generated by Svelte v3.59.2 */ + +function get_each_context(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[25] = list[i]; + child_ctx[26] = list; + child_ctx[27] = i; + return child_ctx; +} + +function get_each_context_1(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[25] = list[i]; + child_ctx[28] = list; + child_ctx[27] = i; + return child_ctx; +} + +// (140:10) {#if i !== 0} +function create_if_block_3(ctx) { + let button; + let mounted; + let dispose; + + function click_handler_2() { + return /*click_handler_2*/ ctx[8](/*i*/ ctx[27]); + } + + return { + c() { + button = element("button"); + button.textContent = "↑"; + attr(button, "aria-label", "Move Status Bar Item Up"); + }, + m(target, anchor) { + insert(target, button, anchor); + + if (!mounted) { + dispose = listen(button, "click", click_handler_2); + mounted = true; + } + }, + p(new_ctx, dirty) { + ctx = new_ctx; + }, + d(detaching) { + if (detaching) detach(button); + mounted = false; + dispose(); + } + }; +} + +// (151:10) {#if i !== statusItems.length - 1} +function create_if_block_2(ctx) { + let button; + let mounted; + let dispose; + + function click_handler_3() { + return /*click_handler_3*/ ctx[9](/*i*/ ctx[27]); + } + + return { + c() { + button = element("button"); + button.textContent = "↓"; + attr(button, "aria-label", "Move Status Bar Item Down"); + }, + m(target, anchor) { + insert(target, button, anchor); + + if (!mounted) { + dispose = listen(button, "click", click_handler_3); + mounted = true; + } + }, + p(new_ctx, dirty) { + ctx = new_ctx; + }, + d(detaching) { + if (detaching) detach(button); + mounted = false; + dispose(); + } + }; +} + +// (133:2) {#each statusItems as item, i} +function create_each_block_1(ctx) { + let details; + let summary; + let span0; + let t0_value = /*metricToString*/ ctx[3](/*item*/ ctx[25].metric) + ""; + let t0; + let t1; + let span1; + let t2; + let t3; + let button; + let t5; + let div4; + let div2; + let t9; + let div3; + let select0; + let option0; + let option1; + let t11; + let option2; + let t12; + let option3; + let t13; + let option4; + let t14; + let option5; + let t15; + let option6; + let t16; + let option7; + let t17; + let select0_value_value; + let t18; + let div9; + let div7; + let t22; + let div8; + let select1; + let option8; + let option9; + let t24; + let option10; + let t25; + let option11; + let t26; + let select1_value_value; + let t27; + let div14; + let div12; + let t31; + let div13; + let input0; + let input0_value_value; + let t32; + let div19; + let div17; + let t36; + let div18; + let input1; + let input1_value_value; + let mounted; + let dispose; + let if_block0 = /*i*/ ctx[27] !== 0 && create_if_block_3(ctx); + let if_block1 = /*i*/ ctx[27] !== /*statusItems*/ ctx[1].length - 1 && create_if_block_2(ctx); + + function click_handler_4() { + return /*click_handler_4*/ ctx[10](/*i*/ ctx[27]); + } + + function change_handler(...args) { + return /*change_handler*/ ctx[11](/*item*/ ctx[25], /*each_value_1*/ ctx[28], /*i*/ ctx[27], ...args); + } + + function change_handler_1(...args) { + return /*change_handler_1*/ ctx[12](/*item*/ ctx[25], /*each_value_1*/ ctx[28], /*i*/ ctx[27], ...args); + } + + function change_handler_2(...args) { + return /*change_handler_2*/ ctx[13](/*item*/ ctx[25], /*each_value_1*/ ctx[28], /*i*/ ctx[27], ...args); + } + + function change_handler_3(...args) { + return /*change_handler_3*/ ctx[14](/*item*/ ctx[25], /*each_value_1*/ ctx[28], /*i*/ ctx[27], ...args); + } + + return { + c() { + details = element("details"); + summary = element("summary"); + span0 = element("span"); + t0 = text(t0_value); + t1 = space(); + span1 = element("span"); + if (if_block0) if_block0.c(); + t2 = space(); + if (if_block1) if_block1.c(); + t3 = space(); + button = element("button"); + button.textContent = "X"; + t5 = space(); + div4 = element("div"); + div2 = element("div"); + + div2.innerHTML = `
Metric Counter
+
Select the counter to display, e.g. words, characters.
`; + + t9 = space(); + div3 = element("div"); + select0 = element("select"); + option0 = element("option"); + option0.textContent = "Select Option"; + option1 = element("option"); + t11 = text("Words"); + option2 = element("option"); + t12 = text("Characters"); + option3 = element("option"); + t13 = text("Sentences"); + option4 = element("option"); + t14 = text("Footnotes"); + option5 = element("option"); + t15 = text("Citations"); + option6 = element("option"); + t16 = text("Pages"); + option7 = element("option"); + t17 = text("Files"); + t18 = space(); + div9 = element("div"); + div7 = element("div"); + + div7.innerHTML = `
Metric Type
+
Select the type of metric that you want displayed.
`; + + t22 = space(); + div8 = element("div"); + select1 = element("select"); + option8 = element("option"); + option8.textContent = "Select Option"; + option9 = element("option"); + t24 = text("Current Note"); + option10 = element("option"); + t25 = text("Daily Metric"); + option11 = element("option"); + t26 = text("Total in Vault"); + t27 = space(); + div14 = element("div"); + div12 = element("div"); + + div12.innerHTML = `
Prefix Text
+
This is the text that is placed before the count.
`; + + t31 = space(); + div13 = element("div"); + input0 = element("input"); + t32 = space(); + div19 = element("div"); + div17 = element("div"); + + div17.innerHTML = `
Suffix Text
+
This is the text that is placed after the count.
`; + + t36 = space(); + div18 = element("div"); + input1 = element("input"); + attr(span0, "class", "bwc-sb-item-text"); + attr(button, "aria-label", "Remove Status Bar Item"); + attr(span1, "class", "bwc-sb-buttons"); + attr(div2, "class", "setting-item-info"); + option0.__value = ""; + option0.value = option0.__value; + option1.__value = MetricCounter.words; + option1.value = option1.__value; + option2.__value = MetricCounter.characters; + option2.value = option2.__value; + option3.__value = MetricCounter.sentences; + option3.value = option3.__value; + option4.__value = MetricCounter.footnotes; + option4.value = option4.__value; + option5.__value = MetricCounter.citations; + option5.value = option5.__value; + option6.__value = MetricCounter.pages; + option6.value = option6.__value; + option7.__value = MetricCounter.files; + option7.value = option7.__value; + attr(select0, "class", "dropdown"); + attr(div3, "class", "setting-item-control"); + attr(div4, "class", "setting-item"); + attr(div7, "class", "setting-item-info"); + option8.__value = ""; + option8.value = option8.__value; + option9.__value = MetricType.file; + option9.value = option9.__value; + option10.__value = MetricType.daily; + option10.value = option10.__value; + option11.__value = MetricType.total; + option11.value = option11.__value; + attr(select1, "class", "dropdown"); + attr(div8, "class", "setting-item-control"); + attr(div9, "class", "setting-item"); + attr(div12, "class", "setting-item-info"); + attr(input0, "type", "text"); + attr(input0, "name", "prefix"); + input0.value = input0_value_value = /*item*/ ctx[25].prefix; + attr(div13, "class", "setting-item-control"); + attr(div14, "class", "setting-item"); + attr(div17, "class", "setting-item-info"); + attr(input1, "type", "text"); + attr(input1, "name", "suffix"); + input1.value = input1_value_value = /*item*/ ctx[25].suffix; + attr(div18, "class", "setting-item-control"); + attr(div19, "class", "setting-item"); + attr(details, "class", "bwc-sb-item-setting"); + }, + m(target, anchor) { + insert(target, details, anchor); + append(details, summary); + append(summary, span0); + append(span0, t0); + append(summary, t1); + append(summary, span1); + if (if_block0) if_block0.m(span1, null); + append(span1, t2); + if (if_block1) if_block1.m(span1, null); + append(span1, t3); + append(span1, button); + append(details, t5); + append(details, div4); + append(div4, div2); + append(div4, t9); + append(div4, div3); + append(div3, select0); + append(select0, option0); + append(select0, option1); + append(option1, t11); + append(select0, option2); + append(option2, t12); + append(select0, option3); + append(option3, t13); + append(select0, option4); + append(option4, t14); + append(select0, option5); + append(option5, t15); + append(select0, option6); + append(option6, t16); + append(select0, option7); + append(option7, t17); + select_option(select0, /*item*/ ctx[25].metric.counter); + append(details, t18); + append(details, div9); + append(div9, div7); + append(div9, t22); + append(div9, div8); + append(div8, select1); + append(select1, option8); + append(select1, option9); + append(option9, t24); + append(select1, option10); + append(option10, t25); + append(select1, option11); + append(option11, t26); + select_option(select1, /*item*/ ctx[25].metric.type); + append(details, t27); + append(details, div14); + append(div14, div12); + append(div14, t31); + append(div14, div13); + append(div13, input0); + append(details, t32); + append(details, div19); + append(div19, div17); + append(div19, t36); + append(div19, div18); + append(div18, input1); + + if (!mounted) { + dispose = [ + listen(button, "click", click_handler_4), + listen(select0, "change", change_handler), + listen(select1, "change", change_handler_1), + listen(input0, "change", change_handler_2), + listen(input1, "change", change_handler_3) + ]; + + mounted = true; + } + }, + p(new_ctx, dirty) { + ctx = new_ctx; + if (dirty & /*statusItems*/ 2 && t0_value !== (t0_value = /*metricToString*/ ctx[3](/*item*/ ctx[25].metric) + "")) set_data(t0, t0_value); + if (/*i*/ ctx[27] !== 0) if_block0.p(ctx, dirty); + + if (/*i*/ ctx[27] !== /*statusItems*/ ctx[1].length - 1) { + if (if_block1) { + if_block1.p(ctx, dirty); + } else { + if_block1 = create_if_block_2(ctx); + if_block1.c(); + if_block1.m(span1, t3); + } + } else if (if_block1) { + if_block1.d(1); + if_block1 = null; + } + + if (dirty & /*statusItems, MetricCounter*/ 2 && select0_value_value !== (select0_value_value = /*item*/ ctx[25].metric.counter)) { + select_option(select0, /*item*/ ctx[25].metric.counter); + } + + if (dirty & /*statusItems, MetricCounter*/ 2 && select1_value_value !== (select1_value_value = /*item*/ ctx[25].metric.type)) { + select_option(select1, /*item*/ ctx[25].metric.type); + } + + if (dirty & /*statusItems, MetricCounter*/ 2 && input0_value_value !== (input0_value_value = /*item*/ ctx[25].prefix) && input0.value !== input0_value_value) { + input0.value = input0_value_value; + } + + if (dirty & /*statusItems, MetricCounter*/ 2 && input1_value_value !== (input1_value_value = /*item*/ ctx[25].suffix) && input1.value !== input1_value_value) { + input1.value = input1_value_value; + } + }, + d(detaching) { + if (detaching) detach(details); + if (if_block0) if_block0.d(); + if (if_block1) if_block1.d(); + mounted = false; + run_all(dispose); + } + }; +} + +// (310:10) {#if i !== 0} +function create_if_block_1(ctx) { + let button; + let mounted; + let dispose; + + function click_handler_7() { + return /*click_handler_7*/ ctx[17](/*i*/ ctx[27]); + } + + return { + c() { + button = element("button"); + button.textContent = "↑"; + attr(button, "aria-label", "Move Status Bar Item Up"); + }, + m(target, anchor) { + insert(target, button, anchor); + + if (!mounted) { + dispose = listen(button, "click", click_handler_7); + mounted = true; + } + }, + p(new_ctx, dirty) { + ctx = new_ctx; + }, + d(detaching) { + if (detaching) detach(button); + mounted = false; + dispose(); + } + }; +} + +// (321:10) {#if i !== altSItems.length - 1} +function create_if_block(ctx) { + let button; + let mounted; + let dispose; + + function click_handler_8() { + return /*click_handler_8*/ ctx[18](/*i*/ ctx[27]); + } + + return { + c() { + button = element("button"); + button.textContent = "↓"; + attr(button, "aria-label", "Move Status Bar Item Down"); + }, + m(target, anchor) { + insert(target, button, anchor); + + if (!mounted) { + dispose = listen(button, "click", click_handler_8); + mounted = true; + } + }, + p(new_ctx, dirty) { + ctx = new_ctx; + }, + d(detaching) { + if (detaching) detach(button); + mounted = false; + dispose(); + } + }; +} + +// (303:2) {#each altSItems as item, i} +function create_each_block(ctx) { + let details; + let summary; + let span0; + let t0_value = /*metricToString*/ ctx[3](/*item*/ ctx[25].metric) + ""; + let t0; + let t1; + let span1; + let t2; + let t3; + let button; + let t5; + let div4; + let div2; + let t9; + let div3; + let select0; + let option0; + let option1; + let t11; + let option2; + let t12; + let option3; + let t13; + let option4; + let t14; + let option5; + let t15; + let option6; + let t16; + let option7; + let t17; + let select0_value_value; + let t18; + let div9; + let div7; + let t22; + let div8; + let select1; + let option8; + let option9; + let t24; + let option10; + let t25; + let option11; + let t26; + let select1_value_value; + let t27; + let div14; + let div12; + let t31; + let div13; + let input0; + let input0_value_value; + let t32; + let div19; + let div17; + let t36; + let div18; + let input1; + let input1_value_value; + let t37; + let mounted; + let dispose; + let if_block0 = /*i*/ ctx[27] !== 0 && create_if_block_1(ctx); + let if_block1 = /*i*/ ctx[27] !== /*altSItems*/ ctx[2].length - 1 && create_if_block(ctx); + + function click_handler_9() { + return /*click_handler_9*/ ctx[19](/*i*/ ctx[27]); + } + + function change_handler_4(...args) { + return /*change_handler_4*/ ctx[20](/*item*/ ctx[25], /*each_value*/ ctx[26], /*i*/ ctx[27], ...args); + } + + function change_handler_5(...args) { + return /*change_handler_5*/ ctx[21](/*item*/ ctx[25], /*each_value*/ ctx[26], /*i*/ ctx[27], ...args); + } + + function change_handler_6(...args) { + return /*change_handler_6*/ ctx[22](/*item*/ ctx[25], /*each_value*/ ctx[26], /*i*/ ctx[27], ...args); + } + + function change_handler_7(...args) { + return /*change_handler_7*/ ctx[23](/*item*/ ctx[25], /*each_value*/ ctx[26], /*i*/ ctx[27], ...args); + } + + return { + c() { + details = element("details"); + summary = element("summary"); + span0 = element("span"); + t0 = text(t0_value); + t1 = space(); + span1 = element("span"); + if (if_block0) if_block0.c(); + t2 = space(); + if (if_block1) if_block1.c(); + t3 = space(); + button = element("button"); + button.textContent = "X"; + t5 = space(); + div4 = element("div"); + div2 = element("div"); + + div2.innerHTML = `
Metric Counter
+
Select the counter to display, e.g. words, characters.
`; + + t9 = space(); + div3 = element("div"); + select0 = element("select"); + option0 = element("option"); + option0.textContent = "Select Option"; + option1 = element("option"); + t11 = text("Words"); + option2 = element("option"); + t12 = text("Characters"); + option3 = element("option"); + t13 = text("Sentences"); + option4 = element("option"); + t14 = text("Footnotes"); + option5 = element("option"); + t15 = text("Citations"); + option6 = element("option"); + t16 = text("Pages"); + option7 = element("option"); + t17 = text("Files"); + t18 = space(); + div9 = element("div"); + div7 = element("div"); + + div7.innerHTML = `
Metric Type
+
Select the type of metric that you want displayed.
`; + + t22 = space(); + div8 = element("div"); + select1 = element("select"); + option8 = element("option"); + option8.textContent = "Select Option"; + option9 = element("option"); + t24 = text("Current Note"); + option10 = element("option"); + t25 = text("Daily Metric"); + option11 = element("option"); + t26 = text("Total in Vault"); + t27 = space(); + div14 = element("div"); + div12 = element("div"); + + div12.innerHTML = `
Prefix Text
+
This is the text that is placed before the count.
`; + + t31 = space(); + div13 = element("div"); + input0 = element("input"); + t32 = space(); + div19 = element("div"); + div17 = element("div"); + + div17.innerHTML = `
Suffix Text
+
This is the text that is placed after the count.
`; + + t36 = space(); + div18 = element("div"); + input1 = element("input"); + t37 = space(); + attr(span0, "class", "bwc-sb-item-text"); + attr(button, "aria-label", "Remove Status Bar Item"); + attr(span1, "class", "bwc-sb-buttons"); + attr(div2, "class", "setting-item-info"); + option0.__value = ""; + option0.value = option0.__value; + option1.__value = MetricCounter.words; + option1.value = option1.__value; + option2.__value = MetricCounter.characters; + option2.value = option2.__value; + option3.__value = MetricCounter.sentences; + option3.value = option3.__value; + option4.__value = MetricCounter.footnotes; + option4.value = option4.__value; + option5.__value = MetricCounter.citations; + option5.value = option5.__value; + option6.__value = MetricCounter.pages; + option6.value = option6.__value; + option7.__value = MetricCounter.files; + option7.value = option7.__value; + attr(select0, "class", "dropdown"); + attr(div3, "class", "setting-item-control"); + attr(div4, "class", "setting-item"); + attr(div7, "class", "setting-item-info"); + option8.__value = ""; + option8.value = option8.__value; + option9.__value = MetricType.file; + option9.value = option9.__value; + option10.__value = MetricType.daily; + option10.value = option10.__value; + option11.__value = MetricType.total; + option11.value = option11.__value; + attr(select1, "class", "dropdown"); + attr(div8, "class", "setting-item-control"); + attr(div9, "class", "setting-item"); + attr(div12, "class", "setting-item-info"); + attr(input0, "type", "text"); + attr(input0, "name", "prefix"); + input0.value = input0_value_value = /*item*/ ctx[25].prefix; + attr(div13, "class", "setting-item-control"); + attr(div14, "class", "setting-item"); + attr(div17, "class", "setting-item-info"); + attr(input1, "type", "text"); + attr(input1, "name", "suffix"); + input1.value = input1_value_value = /*item*/ ctx[25].suffix; + attr(div18, "class", "setting-item-control"); + attr(div19, "class", "setting-item"); + attr(details, "class", "bwc-sb-item-setting"); + }, + m(target, anchor) { + insert(target, details, anchor); + append(details, summary); + append(summary, span0); + append(span0, t0); + append(summary, t1); + append(summary, span1); + if (if_block0) if_block0.m(span1, null); + append(span1, t2); + if (if_block1) if_block1.m(span1, null); + append(span1, t3); + append(span1, button); + append(details, t5); + append(details, div4); + append(div4, div2); + append(div4, t9); + append(div4, div3); + append(div3, select0); + append(select0, option0); + append(select0, option1); + append(option1, t11); + append(select0, option2); + append(option2, t12); + append(select0, option3); + append(option3, t13); + append(select0, option4); + append(option4, t14); + append(select0, option5); + append(option5, t15); + append(select0, option6); + append(option6, t16); + append(select0, option7); + append(option7, t17); + select_option(select0, /*item*/ ctx[25].metric.counter); + append(details, t18); + append(details, div9); + append(div9, div7); + append(div9, t22); + append(div9, div8); + append(div8, select1); + append(select1, option8); + append(select1, option9); + append(option9, t24); + append(select1, option10); + append(option10, t25); + append(select1, option11); + append(option11, t26); + select_option(select1, /*item*/ ctx[25].metric.type); + append(details, t27); + append(details, div14); + append(div14, div12); + append(div14, t31); + append(div14, div13); + append(div13, input0); + append(details, t32); + append(details, div19); + append(div19, div17); + append(div19, t36); + append(div19, div18); + append(div18, input1); + append(details, t37); + + if (!mounted) { + dispose = [ + listen(button, "click", click_handler_9), + listen(select0, "change", change_handler_4), + listen(select1, "change", change_handler_5), + listen(input0, "change", change_handler_6), + listen(input1, "change", change_handler_7) + ]; + + mounted = true; + } + }, + p(new_ctx, dirty) { + ctx = new_ctx; + if (dirty & /*altSItems*/ 4 && t0_value !== (t0_value = /*metricToString*/ ctx[3](/*item*/ ctx[25].metric) + "")) set_data(t0, t0_value); + if (/*i*/ ctx[27] !== 0) if_block0.p(ctx, dirty); + + if (/*i*/ ctx[27] !== /*altSItems*/ ctx[2].length - 1) { + if (if_block1) { + if_block1.p(ctx, dirty); + } else { + if_block1 = create_if_block(ctx); + if_block1.c(); + if_block1.m(span1, t3); + } + } else if (if_block1) { + if_block1.d(1); + if_block1 = null; + } + + if (dirty & /*altSItems, MetricCounter*/ 4 && select0_value_value !== (select0_value_value = /*item*/ ctx[25].metric.counter)) { + select_option(select0, /*item*/ ctx[25].metric.counter); + } + + if (dirty & /*altSItems, MetricCounter*/ 4 && select1_value_value !== (select1_value_value = /*item*/ ctx[25].metric.type)) { + select_option(select1, /*item*/ ctx[25].metric.type); + } + + if (dirty & /*altSItems, MetricCounter*/ 4 && input0_value_value !== (input0_value_value = /*item*/ ctx[25].prefix) && input0.value !== input0_value_value) { + input0.value = input0_value_value; + } + + if (dirty & /*altSItems, MetricCounter*/ 4 && input1_value_value !== (input1_value_value = /*item*/ ctx[25].suffix) && input1.value !== input1_value_value) { + input1.value = input1_value_value; + } + }, + d(detaching) { + if (detaching) detach(details); + if (if_block0) if_block0.d(); + if (if_block1) if_block1.d(); + mounted = false; + run_all(dispose); + } + }; +} + +function create_fragment$1(ctx) { + let div6; + let h40; + let t1; + let p0; + let t3; + let div2; + let button0; + let t5; + let button1; + let t7; + let t8; + let h41; + let t10; + let p1; + let t12; + let div5; + let button2; + let t14; + let button3; + let t16; + let mounted; + let dispose; + let each_value_1 = /*statusItems*/ ctx[1]; + let each_blocks_1 = []; + + for (let i = 0; i < each_value_1.length; i += 1) { + each_blocks_1[i] = create_each_block_1(get_each_context_1(ctx, each_value_1, i)); + } + + let each_value = /*altSItems*/ ctx[2]; + let each_blocks = []; + + for (let i = 0; i < each_value.length; i += 1) { + each_blocks[i] = create_each_block(get_each_context(ctx, each_value, i)); + } + + return { + c() { + div6 = element("div"); + h40 = element("h4"); + h40.textContent = "Markdown Status Bar"; + t1 = space(); + p0 = element("p"); + p0.textContent = "Here you can customize what statistics are displayed on the status bar when editing a markdown note."; + t3 = space(); + div2 = element("div"); + button0 = element("button"); + button0.innerHTML = `
Add Item
`; + t5 = space(); + button1 = element("button"); + button1.innerHTML = `
Reset
`; + t7 = space(); + + for (let i = 0; i < each_blocks_1.length; i += 1) { + each_blocks_1[i].c(); + } + + t8 = space(); + h41 = element("h4"); + h41.textContent = "Alternative Status Bar"; + t10 = space(); + p1 = element("p"); + p1.textContent = "Here you can customize what statistics are displayed on the status bar when not editing a markdown file."; + t12 = space(); + div5 = element("div"); + button2 = element("button"); + button2.innerHTML = `
Add Item
`; + t14 = space(); + button3 = element("button"); + button3.innerHTML = `
Reset
`; + t16 = space(); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + attr(button0, "aria-label", "Add New Status Bar Item"); + attr(button1, "aria-label", "Reset Status Bar to Default"); + attr(div2, "class", "bwc-sb-buttons"); + attr(button2, "aria-label", "Add New Status Bar Item"); + attr(button3, "aria-label", "Reset Status Bar to Default"); + attr(div5, "class", "bwc-sb-buttons"); + }, + m(target, anchor) { + insert(target, div6, anchor); + append(div6, h40); + append(div6, t1); + append(div6, p0); + append(div6, t3); + append(div6, div2); + append(div2, button0); + append(div2, t5); + append(div2, button1); + append(div6, t7); + + for (let i = 0; i < each_blocks_1.length; i += 1) { + if (each_blocks_1[i]) { + each_blocks_1[i].m(div6, null); + } + } + + append(div6, t8); + append(div6, h41); + append(div6, t10); + append(div6, p1); + append(div6, t12); + append(div6, div5); + append(div5, button2); + append(div5, t14); + append(div5, button3); + append(div6, t16); + + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(div6, null); + } + } + + if (!mounted) { + dispose = [ + listen(button0, "click", /*click_handler*/ ctx[6]), + listen(button1, "click", /*click_handler_1*/ ctx[7]), + listen(button2, "click", /*click_handler_5*/ ctx[15]), + listen(button3, "click", /*click_handler_6*/ ctx[16]) + ]; + + mounted = true; + } + }, + p(ctx, [dirty]) { + if (dirty & /*statusItems, update, plugin, MetricType, MetricCounter, swapStatusBarItems, metricToString*/ 27) { + each_value_1 = /*statusItems*/ ctx[1]; + let i; + + for (i = 0; i < each_value_1.length; i += 1) { + const child_ctx = get_each_context_1(ctx, each_value_1, i); + + if (each_blocks_1[i]) { + each_blocks_1[i].p(child_ctx, dirty); + } else { + each_blocks_1[i] = create_each_block_1(child_ctx); + each_blocks_1[i].c(); + each_blocks_1[i].m(div6, t8); + } + } + + for (; i < each_blocks_1.length; i += 1) { + each_blocks_1[i].d(1); + } + + each_blocks_1.length = each_value_1.length; + } + + if (dirty & /*altSItems, updateAlt, plugin, MetricType, MetricCounter, swapStatusBarItems, metricToString*/ 45) { + each_value = /*altSItems*/ ctx[2]; + let i; + + for (i = 0; i < each_value.length; i += 1) { + const child_ctx = get_each_context(ctx, each_value, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(div6, null); + } + } + + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } + + each_blocks.length = each_value.length; + } + }, + i: noop$1, + o: noop$1, + d(detaching) { + if (detaching) detach(div6); + destroy_each(each_blocks_1, detaching); + destroy_each(each_blocks, detaching); + mounted = false; + run_all(dispose); + } + }; +} + +function swapStatusBarItems(i, j, arr) { + const max = arr.length - 1; + if (i < 0 || i > max || j < 0 || j > max) return arr; + const tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + return arr; +} + +function instance$1($$self, $$props, $$invalidate) { + let { plugin } = $$props; + let statusItems = [...plugin.settings.statusBar]; + let altSItems = [...plugin.settings.altBar]; + + function metricToString(metric) { + if (metric.type === MetricType.file) { + switch (metric.counter) { + case MetricCounter.words: + return "Words in Note"; + case MetricCounter.characters: + return "Chars in Note"; + case MetricCounter.sentences: + return "Sentences in Note"; + case MetricCounter.footnotes: + return "Footnotes in Note"; + case MetricCounter.citations: + return "Citations in Note"; + case MetricCounter.pages: + return "Pages in Note"; + case MetricCounter.files: + return "Total Notes"; + } + } else if (metric.type === MetricType.daily) { + switch (metric.counter) { + case MetricCounter.words: + return "Daily Words"; + case MetricCounter.characters: + return "Daily Chars"; + case MetricCounter.sentences: + return "Daily Sentences"; + case MetricCounter.footnotes: + return "Daily Footnotes"; + case MetricCounter.citations: + return "Daily Citations"; + case MetricCounter.pages: + return "Daily Pages"; + case MetricCounter.files: + return "Total Notes"; + } + } else if (metric.type === MetricType.total) { + switch (metric.counter) { + case MetricCounter.words: + return "Total Words"; + case MetricCounter.characters: + return "Total Chars"; + case MetricCounter.sentences: + return "Total Sentences"; + case MetricCounter.footnotes: + return "Total Footnotes"; + case MetricCounter.citations: + return "Total Citations"; + case MetricCounter.pages: + return "Total Pages"; + case MetricCounter.files: + return "Total Notes"; + } + } else { + return "Select Options"; + } + } + + async function update(statusItems) { + $$invalidate( + 0, + plugin.settings.statusBar = statusItems.filter(item => { + if (metricToString(item.metric) !== "Select Options") { + return item; + } + }), + plugin + ); + + await plugin.saveSettings(); + } + + async function updateAlt(altSItems) { + $$invalidate( + 0, + plugin.settings.altBar = altSItems.filter(item => { + if (metricToString(item.metric) !== "Select Options") { + return item; + } + }), + plugin + ); + + await plugin.saveSettings(); + } + + const click_handler = async () => $$invalidate(1, statusItems = [...statusItems, JSON.parse(JSON.stringify(BLANK_SB_ITEM))]); + + const click_handler_1 = async () => { + $$invalidate(1, statusItems = [ + { + prefix: "", + suffix: " words", + metric: { + type: MetricType.file, + counter: MetricCounter.words + } + }, + { + prefix: " ", + suffix: " characters", + metric: { + type: MetricType.file, + counter: MetricCounter.characters + } + } + ]); + + await update(statusItems); + }; + + const click_handler_2 = async i => { + $$invalidate(1, statusItems = swapStatusBarItems(i, i - 1, statusItems)); + await update(statusItems); + }; + + const click_handler_3 = async i => { + $$invalidate(1, statusItems = swapStatusBarItems(i, i + 1, statusItems)); + await update(statusItems); + }; + + const click_handler_4 = async i => { + $$invalidate(1, statusItems = statusItems.filter((item, j) => i !== j)); + await update(statusItems); + }; + + const change_handler = async (item, each_value_1, i, e) => { + const { value } = e.target; + $$invalidate(1, each_value_1[i].metric.counter = MetricCounter[MetricCounter[value]], statusItems); + await update(statusItems); + await plugin.saveSettings(); + }; + + const change_handler_1 = async (item, each_value_1, i, e) => { + const { value } = e.target; + $$invalidate(1, each_value_1[i].metric.type = MetricType[MetricType[value]], statusItems); + await update(statusItems); + await plugin.saveSettings(); + }; + + const change_handler_2 = async (item, each_value_1, i, e) => { + const { value } = e.target; + $$invalidate(1, each_value_1[i].prefix = value, statusItems); + await update(statusItems); + await plugin.saveSettings(); + }; + + const change_handler_3 = async (item, each_value_1, i, e) => { + const { value } = e.target; + $$invalidate(1, each_value_1[i].suffix = value, statusItems); + await update(statusItems); + await plugin.saveSettings(); + }; + + const click_handler_5 = async () => $$invalidate(2, altSItems = [...altSItems, JSON.parse(JSON.stringify(BLANK_SB_ITEM))]); + + const click_handler_6 = async () => { + $$invalidate(2, altSItems = [ + { + prefix: "", + suffix: " files", + metric: { + type: MetricType.total, + counter: MetricCounter.files + } + } + ]); + + await update(statusItems); + }; + + const click_handler_7 = async i => { + $$invalidate(2, altSItems = swapStatusBarItems(i, i - 1, altSItems)); + await updateAlt(altSItems); + }; + + const click_handler_8 = async i => { + $$invalidate(2, altSItems = swapStatusBarItems(i, i + 1, altSItems)); + await updateAlt(altSItems); + }; + + const click_handler_9 = async i => { + $$invalidate(2, altSItems = altSItems.filter((item, j) => i !== j)); + await updateAlt(altSItems); + }; + + const change_handler_4 = async (item, each_value, i, e) => { + const { value } = e.target; + $$invalidate(2, each_value[i].metric.counter = MetricCounter[MetricCounter[value]], altSItems); + await updateAlt(altSItems); + await plugin.saveSettings(); + }; + + const change_handler_5 = async (item, each_value, i, e) => { + const { value } = e.target; + $$invalidate(2, each_value[i].metric.type = MetricType[MetricType[value]], altSItems); + await updateAlt(altSItems); + await plugin.saveSettings(); + }; + + const change_handler_6 = async (item, each_value, i, e) => { + const { value } = e.target; + $$invalidate(2, each_value[i].prefix = value, altSItems); + await updateAlt(altSItems); + await plugin.saveSettings(); + }; + + const change_handler_7 = async (item, each_value, i, e) => { + const { value } = e.target; + $$invalidate(2, each_value[i].suffix = value, altSItems); + await updateAlt(altSItems); + await plugin.saveSettings(); + }; + + $$self.$$set = $$props => { + if ('plugin' in $$props) $$invalidate(0, plugin = $$props.plugin); + }; + + return [ + plugin, + statusItems, + altSItems, + metricToString, + update, + updateAlt, + click_handler, + click_handler_1, + click_handler_2, + click_handler_3, + click_handler_4, + change_handler, + change_handler_1, + change_handler_2, + change_handler_3, + click_handler_5, + click_handler_6, + click_handler_7, + click_handler_8, + click_handler_9, + change_handler_4, + change_handler_5, + change_handler_6, + change_handler_7 + ]; +} + +class StatusBarSettings extends SvelteComponent { + constructor(options) { + super(); + init(this, options, instance$1, create_fragment$1, safe_not_equal, { plugin: 0 }); + } +} + +function addStatusBarSettings(plugin, containerEl) { + const statusItemsEl = containerEl.createEl("div"); + new StatusBarSettings({ + target: statusItemsEl, + props: { plugin }, + }); +} + +class BetterWordCountSettingsTab extends obsidian.PluginSettingTab { + constructor(app, plugin) { + super(app, plugin); + this.plugin = plugin; + } + display() { + let { containerEl } = this; + containerEl.empty(); + containerEl.createEl("h3", { text: "Better Word Count Settings" }); + // General Settings + containerEl.createEl("h4", { text: "General Settings" }); + new obsidian.Setting(containerEl) + .setName("Collect Statistics") + .setDesc("Reload required for change to take effect. Turn on to start collecting daily statistics of your writing. Stored in the path specified below. This is required for counts of the day as well as total counts.") + .addToggle((cb) => { + cb.setValue(this.plugin.settings.collectStats); + cb.onChange(async (value) => { + this.plugin.settings.collectStats = value; + await this.plugin.saveSettings(); + }); + }); + new obsidian.Setting(containerEl) + .setName("Don't Count Comments") + .setDesc("Turn on if you don't want markdown comments to be counted.") + .addToggle((cb) => { + cb.setValue(this.plugin.settings.countComments); + cb.onChange(async (value) => { + this.plugin.settings.countComments = value; + await this.plugin.saveSettings(); + }); + }); + new obsidian.Setting(containerEl) + .setName("Display Section Word Count") + .setDesc("Turn on if you want to display section word counts next to headings.") + .addToggle((cb) => { + cb.setValue(this.plugin.settings.displaySectionCounts); + cb.onChange(async (value) => { + this.plugin.settings.displaySectionCounts = value; + this.plugin.onDisplaySectionCountsChange(); + await this.plugin.saveSettings(); + }); + }); + new obsidian.Setting(containerEl) + .setName("Page Word Count") + .setDesc("Set how many words count as one \"page\"") + .addText((text) => { + text.inputEl.type = "number"; + text.setPlaceholder("300"); + text.setValue(this.plugin.settings.pageWords.toString()); + text.onChange(async (value) => { + this.plugin.settings.pageWords = parseInt(value); + await this.plugin.saveSettings(); + }); + }); + // Advanced Settings + containerEl.createEl("h4", { text: "Advanced Settings" }); + new obsidian.Setting(containerEl) + .setName("Vault Stats File Path") + .setDesc("Reload required for change to take effect. The location of the vault statistics file, relative to the vault root.") + .addText((text) => { + text.setPlaceholder(".obsidian/vault-stats.json"); + text.setValue(this.plugin.settings.statsPath.toString()); + text.onChange(async (value) => { + this.plugin.settings.statsPath = value; + await this.plugin.saveSettings(); + }); + }); + // Status Bar Settings + addStatusBarSettings(this.plugin, containerEl); + } +} + +var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + +function createCommonjsModule(fn, basedir, module) { + return module = { + path: basedir, + exports: {}, + require: function (path, base) { + return commonjsRequire(path, (base === undefined || base === null) ? module.path : base); + } + }, fn(module, module.exports), module.exports; +} + +function commonjsRequire () { + throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs'); +} + +var moment = createCommonjsModule(function (module, exports) { +(function (global, factory) { + module.exports = factory() ; +}(commonjsGlobal, (function () { + var hookCallback; + + function hooks() { + return hookCallback.apply(null, arguments); + } + + // This is done to register the method called with moment() + // without creating circular dependencies. + function setHookCallback(callback) { + hookCallback = callback; + } + + function isArray(input) { + return ( + input instanceof Array || + Object.prototype.toString.call(input) === '[object Array]' + ); + } + + function isObject(input) { + // IE8 will treat undefined and null as object if it wasn't for + // input != null + return ( + input != null && + Object.prototype.toString.call(input) === '[object Object]' + ); + } + + function hasOwnProp(a, b) { + return Object.prototype.hasOwnProperty.call(a, b); + } + + function isObjectEmpty(obj) { + if (Object.getOwnPropertyNames) { + return Object.getOwnPropertyNames(obj).length === 0; + } else { + var k; + for (k in obj) { + if (hasOwnProp(obj, k)) { + return false; + } + } + return true; + } + } + + function isUndefined(input) { + return input === void 0; + } + + function isNumber(input) { + return ( + typeof input === 'number' || + Object.prototype.toString.call(input) === '[object Number]' + ); + } + + function isDate(input) { + return ( + input instanceof Date || + Object.prototype.toString.call(input) === '[object Date]' + ); + } + + function map(arr, fn) { + var res = [], + i, + arrLen = arr.length; + for (i = 0; i < arrLen; ++i) { + res.push(fn(arr[i], i)); + } + return res; + } + + function extend(a, b) { + for (var i in b) { + if (hasOwnProp(b, i)) { + a[i] = b[i]; + } + } + + if (hasOwnProp(b, 'toString')) { + a.toString = b.toString; + } + + if (hasOwnProp(b, 'valueOf')) { + a.valueOf = b.valueOf; + } + + return a; + } + + function createUTC(input, format, locale, strict) { + return createLocalOrUTC(input, format, locale, strict, true).utc(); + } + + function defaultParsingFlags() { + // We need to deep clone this object. + return { + empty: false, + unusedTokens: [], + unusedInput: [], + overflow: -2, + charsLeftOver: 0, + nullInput: false, + invalidEra: null, + invalidMonth: null, + invalidFormat: false, + userInvalidated: false, + iso: false, + parsedDateParts: [], + era: null, + meridiem: null, + rfc2822: false, + weekdayMismatch: false, + }; + } + + function getParsingFlags(m) { + if (m._pf == null) { + m._pf = defaultParsingFlags(); + } + return m._pf; + } + + var some; + if (Array.prototype.some) { + some = Array.prototype.some; + } else { + some = function (fun) { + var t = Object(this), + len = t.length >>> 0, + i; + + for (i = 0; i < len; i++) { + if (i in t && fun.call(this, t[i], i, t)) { + return true; + } + } + + return false; + }; + } + + function isValid(m) { + if (m._isValid == null) { + var flags = getParsingFlags(m), + parsedParts = some.call(flags.parsedDateParts, function (i) { + return i != null; + }), + isNowValid = + !isNaN(m._d.getTime()) && + flags.overflow < 0 && + !flags.empty && + !flags.invalidEra && + !flags.invalidMonth && + !flags.invalidWeekday && + !flags.weekdayMismatch && + !flags.nullInput && + !flags.invalidFormat && + !flags.userInvalidated && + (!flags.meridiem || (flags.meridiem && parsedParts)); + + if (m._strict) { + isNowValid = + isNowValid && + flags.charsLeftOver === 0 && + flags.unusedTokens.length === 0 && + flags.bigHour === undefined; + } + + if (Object.isFrozen == null || !Object.isFrozen(m)) { + m._isValid = isNowValid; + } else { + return isNowValid; + } + } + return m._isValid; + } + + function createInvalid(flags) { + var m = createUTC(NaN); + if (flags != null) { + extend(getParsingFlags(m), flags); + } else { + getParsingFlags(m).userInvalidated = true; + } + + return m; + } + + // Plugins that add properties should also add the key here (null value), + // so we can properly clone ourselves. + var momentProperties = (hooks.momentProperties = []), + updateInProgress = false; + + function copyConfig(to, from) { + var i, + prop, + val, + momentPropertiesLen = momentProperties.length; + + if (!isUndefined(from._isAMomentObject)) { + to._isAMomentObject = from._isAMomentObject; + } + if (!isUndefined(from._i)) { + to._i = from._i; + } + if (!isUndefined(from._f)) { + to._f = from._f; + } + if (!isUndefined(from._l)) { + to._l = from._l; + } + if (!isUndefined(from._strict)) { + to._strict = from._strict; + } + if (!isUndefined(from._tzm)) { + to._tzm = from._tzm; + } + if (!isUndefined(from._isUTC)) { + to._isUTC = from._isUTC; + } + if (!isUndefined(from._offset)) { + to._offset = from._offset; + } + if (!isUndefined(from._pf)) { + to._pf = getParsingFlags(from); + } + if (!isUndefined(from._locale)) { + to._locale = from._locale; + } + + if (momentPropertiesLen > 0) { + for (i = 0; i < momentPropertiesLen; i++) { + prop = momentProperties[i]; + val = from[prop]; + if (!isUndefined(val)) { + to[prop] = val; + } + } + } + + return to; + } + + // Moment prototype object + function Moment(config) { + copyConfig(this, config); + this._d = new Date(config._d != null ? config._d.getTime() : NaN); + if (!this.isValid()) { + this._d = new Date(NaN); + } + // Prevent infinite loop in case updateOffset creates new moment + // objects. + if (updateInProgress === false) { + updateInProgress = true; + hooks.updateOffset(this); + updateInProgress = false; + } + } + + function isMoment(obj) { + return ( + obj instanceof Moment || (obj != null && obj._isAMomentObject != null) + ); + } + + function warn(msg) { + if ( + hooks.suppressDeprecationWarnings === false && + typeof console !== 'undefined' && + console.warn + ) { + console.warn('Deprecation warning: ' + msg); + } + } + + function deprecate(msg, fn) { + var firstTime = true; + + return extend(function () { + if (hooks.deprecationHandler != null) { + hooks.deprecationHandler(null, msg); + } + if (firstTime) { + var args = [], + arg, + i, + key, + argLen = arguments.length; + for (i = 0; i < argLen; i++) { + arg = ''; + if (typeof arguments[i] === 'object') { + arg += '\n[' + i + '] '; + for (key in arguments[0]) { + if (hasOwnProp(arguments[0], key)) { + arg += key + ': ' + arguments[0][key] + ', '; + } + } + arg = arg.slice(0, -2); // Remove trailing comma and space + } else { + arg = arguments[i]; + } + args.push(arg); + } + warn( + msg + + '\nArguments: ' + + Array.prototype.slice.call(args).join('') + + '\n' + + new Error().stack + ); + firstTime = false; + } + return fn.apply(this, arguments); + }, fn); + } + + var deprecations = {}; + + function deprecateSimple(name, msg) { + if (hooks.deprecationHandler != null) { + hooks.deprecationHandler(name, msg); + } + if (!deprecations[name]) { + warn(msg); + deprecations[name] = true; + } + } + + hooks.suppressDeprecationWarnings = false; + hooks.deprecationHandler = null; + + function isFunction(input) { + return ( + (typeof Function !== 'undefined' && input instanceof Function) || + Object.prototype.toString.call(input) === '[object Function]' + ); + } + + function set(config) { + var prop, i; + for (i in config) { + if (hasOwnProp(config, i)) { + prop = config[i]; + if (isFunction(prop)) { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + } + this._config = config; + // Lenient ordinal parsing accepts just a number in addition to + // number + (possibly) stuff coming from _dayOfMonthOrdinalParse. + // TODO: Remove "ordinalParse" fallback in next major release. + this._dayOfMonthOrdinalParseLenient = new RegExp( + (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) + + '|' + + /\d{1,2}/.source + ); + } + + function mergeConfigs(parentConfig, childConfig) { + var res = extend({}, parentConfig), + prop; + for (prop in childConfig) { + if (hasOwnProp(childConfig, prop)) { + if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) { + res[prop] = {}; + extend(res[prop], parentConfig[prop]); + extend(res[prop], childConfig[prop]); + } else if (childConfig[prop] != null) { + res[prop] = childConfig[prop]; + } else { + delete res[prop]; + } + } + } + for (prop in parentConfig) { + if ( + hasOwnProp(parentConfig, prop) && + !hasOwnProp(childConfig, prop) && + isObject(parentConfig[prop]) + ) { + // make sure changes to properties don't modify parent config + res[prop] = extend({}, res[prop]); + } + } + return res; + } + + function Locale(config) { + if (config != null) { + this.set(config); + } + } + + var keys; + + if (Object.keys) { + keys = Object.keys; + } else { + keys = function (obj) { + var i, + res = []; + for (i in obj) { + if (hasOwnProp(obj, i)) { + res.push(i); + } + } + return res; + }; + } + + var defaultCalendar = { + sameDay: '[Today at] LT', + nextDay: '[Tomorrow at] LT', + nextWeek: 'dddd [at] LT', + lastDay: '[Yesterday at] LT', + lastWeek: '[Last] dddd [at] LT', + sameElse: 'L', + }; + + function calendar(key, mom, now) { + var output = this._calendar[key] || this._calendar['sameElse']; + return isFunction(output) ? output.call(mom, now) : output; + } + + function zeroFill(number, targetLength, forceSign) { + var absNumber = '' + Math.abs(number), + zerosToFill = targetLength - absNumber.length, + sign = number >= 0; + return ( + (sign ? (forceSign ? '+' : '') : '-') + + Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + + absNumber + ); + } + + var formattingTokens = + /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g, + localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, + formatFunctions = {}, + formatTokenFunctions = {}; + + // token: 'M' + // padded: ['MM', 2] + // ordinal: 'Mo' + // callback: function () { this.month() + 1 } + function addFormatToken(token, padded, ordinal, callback) { + var func = callback; + if (typeof callback === 'string') { + func = function () { + return this[callback](); + }; + } + if (token) { + formatTokenFunctions[token] = func; + } + if (padded) { + formatTokenFunctions[padded[0]] = function () { + return zeroFill(func.apply(this, arguments), padded[1], padded[2]); + }; + } + if (ordinal) { + formatTokenFunctions[ordinal] = function () { + return this.localeData().ordinal( + func.apply(this, arguments), + token + ); + }; + } + } + + function removeFormattingTokens(input) { + if (input.match(/\[[\s\S]/)) { + return input.replace(/^\[|\]$/g, ''); + } + return input.replace(/\\/g, ''); + } + + function makeFormatFunction(format) { + var array = format.match(formattingTokens), + i, + length; + + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } + + return function (mom) { + var output = '', + i; + for (i = 0; i < length; i++) { + output += isFunction(array[i]) + ? array[i].call(mom, format) + : array[i]; + } + return output; + }; + } + + // format date using native date object + function formatMoment(m, format) { + if (!m.isValid()) { + return m.localeData().invalidDate(); + } + + format = expandFormat(format, m.localeData()); + formatFunctions[format] = + formatFunctions[format] || makeFormatFunction(format); + + return formatFunctions[format](m); + } + + function expandFormat(format, locale) { + var i = 5; + + function replaceLongDateFormatTokens(input) { + return locale.longDateFormat(input) || input; + } + + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace( + localFormattingTokens, + replaceLongDateFormatTokens + ); + localFormattingTokens.lastIndex = 0; + i -= 1; + } + + return format; + } + + var defaultLongDateFormat = { + LTS: 'h:mm:ss A', + LT: 'h:mm A', + L: 'MM/DD/YYYY', + LL: 'MMMM D, YYYY', + LLL: 'MMMM D, YYYY h:mm A', + LLLL: 'dddd, MMMM D, YYYY h:mm A', + }; + + function longDateFormat(key) { + var format = this._longDateFormat[key], + formatUpper = this._longDateFormat[key.toUpperCase()]; + + if (format || !formatUpper) { + return format; + } + + this._longDateFormat[key] = formatUpper + .match(formattingTokens) + .map(function (tok) { + if ( + tok === 'MMMM' || + tok === 'MM' || + tok === 'DD' || + tok === 'dddd' + ) { + return tok.slice(1); + } + return tok; + }) + .join(''); + + return this._longDateFormat[key]; + } + + var defaultInvalidDate = 'Invalid date'; + + function invalidDate() { + return this._invalidDate; + } + + var defaultOrdinal = '%d', + defaultDayOfMonthOrdinalParse = /\d{1,2}/; + + function ordinal(number) { + return this._ordinal.replace('%d', number); + } + + var defaultRelativeTime = { + future: 'in %s', + past: '%s ago', + s: 'a few seconds', + ss: '%d seconds', + m: 'a minute', + mm: '%d minutes', + h: 'an hour', + hh: '%d hours', + d: 'a day', + dd: '%d days', + w: 'a week', + ww: '%d weeks', + M: 'a month', + MM: '%d months', + y: 'a year', + yy: '%d years', + }; + + function relativeTime(number, withoutSuffix, string, isFuture) { + var output = this._relativeTime[string]; + return isFunction(output) + ? output(number, withoutSuffix, string, isFuture) + : output.replace(/%d/i, number); + } + + function pastFuture(diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return isFunction(format) ? format(output) : format.replace(/%s/i, output); + } + + var aliases = {}; + + function addUnitAlias(unit, shorthand) { + var lowerCase = unit.toLowerCase(); + aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit; + } + + function normalizeUnits(units) { + return typeof units === 'string' + ? aliases[units] || aliases[units.toLowerCase()] + : undefined; + } + + function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; + + for (prop in inputObject) { + if (hasOwnProp(inputObject, prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } + + return normalizedInput; + } + + var priorities = {}; + + function addUnitPriority(unit, priority) { + priorities[unit] = priority; + } + + function getPrioritizedUnits(unitsObj) { + var units = [], + u; + for (u in unitsObj) { + if (hasOwnProp(unitsObj, u)) { + units.push({ unit: u, priority: priorities[u] }); + } + } + units.sort(function (a, b) { + return a.priority - b.priority; + }); + return units; + } + + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } + + function absFloor(number) { + if (number < 0) { + // -0 -> 0 + return Math.ceil(number) || 0; + } else { + return Math.floor(number); + } + } + + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; + + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + value = absFloor(coercedNumber); + } + + return value; + } + + function makeGetSet(unit, keepTime) { + return function (value) { + if (value != null) { + set$1(this, unit, value); + hooks.updateOffset(this, keepTime); + return this; + } else { + return get(this, unit); + } + }; + } + + function get(mom, unit) { + return mom.isValid() + ? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() + : NaN; + } + + function set$1(mom, unit, value) { + if (mom.isValid() && !isNaN(value)) { + if ( + unit === 'FullYear' && + isLeapYear(mom.year()) && + mom.month() === 1 && + mom.date() === 29 + ) { + value = toInt(value); + mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit]( + value, + mom.month(), + daysInMonth(value, mom.month()) + ); + } else { + mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); + } + } + } + + // MOMENTS + + function stringGet(units) { + units = normalizeUnits(units); + if (isFunction(this[units])) { + return this[units](); + } + return this; + } + + function stringSet(units, value) { + if (typeof units === 'object') { + units = normalizeObjectUnits(units); + var prioritized = getPrioritizedUnits(units), + i, + prioritizedLen = prioritized.length; + for (i = 0; i < prioritizedLen; i++) { + this[prioritized[i].unit](units[prioritized[i].unit]); + } + } else { + units = normalizeUnits(units); + if (isFunction(this[units])) { + return this[units](value); + } + } + return this; + } + + var match1 = /\d/, // 0 - 9 + match2 = /\d\d/, // 00 - 99 + match3 = /\d{3}/, // 000 - 999 + match4 = /\d{4}/, // 0000 - 9999 + match6 = /[+-]?\d{6}/, // -999999 - 999999 + match1to2 = /\d\d?/, // 0 - 99 + match3to4 = /\d\d\d\d?/, // 999 - 9999 + match5to6 = /\d\d\d\d\d\d?/, // 99999 - 999999 + match1to3 = /\d{1,3}/, // 0 - 999 + match1to4 = /\d{1,4}/, // 0 - 9999 + match1to6 = /[+-]?\d{1,6}/, // -999999 - 999999 + matchUnsigned = /\d+/, // 0 - inf + matchSigned = /[+-]?\d+/, // -inf - inf + matchOffset = /Z|[+-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z + matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi, // +00 -00 +00:00 -00:00 +0000 -0000 or Z + matchTimestamp = /[+-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 + // any word (or two) characters or numbers including two/three word month in arabic. + // includes scottish gaelic two word and hyphenated months + matchWord = + /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i, + regexes; + + regexes = {}; + + function addRegexToken(token, regex, strictRegex) { + regexes[token] = isFunction(regex) + ? regex + : function (isStrict, localeData) { + return isStrict && strictRegex ? strictRegex : regex; + }; + } + + function getParseRegexForToken(token, config) { + if (!hasOwnProp(regexes, token)) { + return new RegExp(unescapeFormat(token)); + } + + return regexes[token](config._strict, config._locale); + } + + // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + function unescapeFormat(s) { + return regexEscape( + s + .replace('\\', '') + .replace( + /\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, + function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + } + ) + ); + } + + function regexEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } + + var tokens = {}; + + function addParseToken(token, callback) { + var i, + func = callback, + tokenLen; + if (typeof token === 'string') { + token = [token]; + } + if (isNumber(callback)) { + func = function (input, array) { + array[callback] = toInt(input); + }; + } + tokenLen = token.length; + for (i = 0; i < tokenLen; i++) { + tokens[token[i]] = func; + } + } + + function addWeekParseToken(token, callback) { + addParseToken(token, function (input, array, config, token) { + config._w = config._w || {}; + callback(input, config._w, config, token); + }); + } + + function addTimeToArrayFromToken(token, input, config) { + if (input != null && hasOwnProp(tokens, token)) { + tokens[token](input, config._a, config, token); + } + } + + var YEAR = 0, + MONTH = 1, + DATE = 2, + HOUR = 3, + MINUTE = 4, + SECOND = 5, + MILLISECOND = 6, + WEEK = 7, + WEEKDAY = 8; + + function mod(n, x) { + return ((n % x) + x) % x; + } + + var indexOf; + + if (Array.prototype.indexOf) { + indexOf = Array.prototype.indexOf; + } else { + indexOf = function (o) { + // I know + var i; + for (i = 0; i < this.length; ++i) { + if (this[i] === o) { + return i; + } + } + return -1; + }; + } + + function daysInMonth(year, month) { + if (isNaN(year) || isNaN(month)) { + return NaN; + } + var modMonth = mod(month, 12); + year += (month - modMonth) / 12; + return modMonth === 1 + ? isLeapYear(year) + ? 29 + : 28 + : 31 - ((modMonth % 7) % 2); + } + + // FORMATTING + + addFormatToken('M', ['MM', 2], 'Mo', function () { + return this.month() + 1; + }); + + addFormatToken('MMM', 0, 0, function (format) { + return this.localeData().monthsShort(this, format); + }); + + addFormatToken('MMMM', 0, 0, function (format) { + return this.localeData().months(this, format); + }); + + // ALIASES + + addUnitAlias('month', 'M'); + + // PRIORITY + + addUnitPriority('month', 8); + + // PARSING + + addRegexToken('M', match1to2); + addRegexToken('MM', match1to2, match2); + addRegexToken('MMM', function (isStrict, locale) { + return locale.monthsShortRegex(isStrict); + }); + addRegexToken('MMMM', function (isStrict, locale) { + return locale.monthsRegex(isStrict); + }); + + addParseToken(['M', 'MM'], function (input, array) { + array[MONTH] = toInt(input) - 1; + }); + + addParseToken(['MMM', 'MMMM'], function (input, array, config, token) { + var month = config._locale.monthsParse(input, token, config._strict); + // if we didn't find a month name, mark the date as invalid. + if (month != null) { + array[MONTH] = month; + } else { + getParsingFlags(config).invalidMonth = input; + } + }); + + // LOCALES + + var defaultLocaleMonths = + 'January_February_March_April_May_June_July_August_September_October_November_December'.split( + '_' + ), + defaultLocaleMonthsShort = + 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/, + defaultMonthsShortRegex = matchWord, + defaultMonthsRegex = matchWord; + + function localeMonths(m, format) { + if (!m) { + return isArray(this._months) + ? this._months + : this._months['standalone']; + } + return isArray(this._months) + ? this._months[m.month()] + : this._months[ + (this._months.isFormat || MONTHS_IN_FORMAT).test(format) + ? 'format' + : 'standalone' + ][m.month()]; + } + + function localeMonthsShort(m, format) { + if (!m) { + return isArray(this._monthsShort) + ? this._monthsShort + : this._monthsShort['standalone']; + } + return isArray(this._monthsShort) + ? this._monthsShort[m.month()] + : this._monthsShort[ + MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone' + ][m.month()]; + } + + function handleStrictParse(monthName, format, strict) { + var i, + ii, + mom, + llc = monthName.toLocaleLowerCase(); + if (!this._monthsParse) { + // this is not used + this._monthsParse = []; + this._longMonthsParse = []; + this._shortMonthsParse = []; + for (i = 0; i < 12; ++i) { + mom = createUTC([2000, i]); + this._shortMonthsParse[i] = this.monthsShort( + mom, + '' + ).toLocaleLowerCase(); + this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase(); + } + } + + if (strict) { + if (format === 'MMM') { + ii = indexOf.call(this._shortMonthsParse, llc); + return ii !== -1 ? ii : null; + } else { + ii = indexOf.call(this._longMonthsParse, llc); + return ii !== -1 ? ii : null; + } + } else { + if (format === 'MMM') { + ii = indexOf.call(this._shortMonthsParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._longMonthsParse, llc); + return ii !== -1 ? ii : null; + } else { + ii = indexOf.call(this._longMonthsParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._shortMonthsParse, llc); + return ii !== -1 ? ii : null; + } + } + } + + function localeMonthsParse(monthName, format, strict) { + var i, mom, regex; + + if (this._monthsParseExact) { + return handleStrictParse.call(this, monthName, format, strict); + } + + if (!this._monthsParse) { + this._monthsParse = []; + this._longMonthsParse = []; + this._shortMonthsParse = []; + } + + // TODO: add sorting + // Sorting makes sure if one month (or abbr) is a prefix of another + // see sorting in computeMonthsParse + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = createUTC([2000, i]); + if (strict && !this._longMonthsParse[i]) { + this._longMonthsParse[i] = new RegExp( + '^' + this.months(mom, '').replace('.', '') + '$', + 'i' + ); + this._shortMonthsParse[i] = new RegExp( + '^' + this.monthsShort(mom, '').replace('.', '') + '$', + 'i' + ); + } + if (!strict && !this._monthsParse[i]) { + regex = + '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if ( + strict && + format === 'MMMM' && + this._longMonthsParse[i].test(monthName) + ) { + return i; + } else if ( + strict && + format === 'MMM' && + this._shortMonthsParse[i].test(monthName) + ) { + return i; + } else if (!strict && this._monthsParse[i].test(monthName)) { + return i; + } + } + } + + // MOMENTS + + function setMonth(mom, value) { + var dayOfMonth; + + if (!mom.isValid()) { + // No op + return mom; + } + + if (typeof value === 'string') { + if (/^\d+$/.test(value)) { + value = toInt(value); + } else { + value = mom.localeData().monthsParse(value); + // TODO: Another silent failure? + if (!isNumber(value)) { + return mom; + } + } + } + + dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value)); + mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); + return mom; + } + + function getSetMonth(value) { + if (value != null) { + setMonth(this, value); + hooks.updateOffset(this, true); + return this; + } else { + return get(this, 'Month'); + } + } + + function getDaysInMonth() { + return daysInMonth(this.year(), this.month()); + } + + function monthsShortRegex(isStrict) { + if (this._monthsParseExact) { + if (!hasOwnProp(this, '_monthsRegex')) { + computeMonthsParse.call(this); + } + if (isStrict) { + return this._monthsShortStrictRegex; + } else { + return this._monthsShortRegex; + } + } else { + if (!hasOwnProp(this, '_monthsShortRegex')) { + this._monthsShortRegex = defaultMonthsShortRegex; + } + return this._monthsShortStrictRegex && isStrict + ? this._monthsShortStrictRegex + : this._monthsShortRegex; + } + } + + function monthsRegex(isStrict) { + if (this._monthsParseExact) { + if (!hasOwnProp(this, '_monthsRegex')) { + computeMonthsParse.call(this); + } + if (isStrict) { + return this._monthsStrictRegex; + } else { + return this._monthsRegex; + } + } else { + if (!hasOwnProp(this, '_monthsRegex')) { + this._monthsRegex = defaultMonthsRegex; + } + return this._monthsStrictRegex && isStrict + ? this._monthsStrictRegex + : this._monthsRegex; + } + } + + function computeMonthsParse() { + function cmpLenRev(a, b) { + return b.length - a.length; + } + + var shortPieces = [], + longPieces = [], + mixedPieces = [], + i, + mom; + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = createUTC([2000, i]); + shortPieces.push(this.monthsShort(mom, '')); + longPieces.push(this.months(mom, '')); + mixedPieces.push(this.months(mom, '')); + mixedPieces.push(this.monthsShort(mom, '')); + } + // Sorting makes sure if one month (or abbr) is a prefix of another it + // will match the longer piece. + shortPieces.sort(cmpLenRev); + longPieces.sort(cmpLenRev); + mixedPieces.sort(cmpLenRev); + for (i = 0; i < 12; i++) { + shortPieces[i] = regexEscape(shortPieces[i]); + longPieces[i] = regexEscape(longPieces[i]); + } + for (i = 0; i < 24; i++) { + mixedPieces[i] = regexEscape(mixedPieces[i]); + } + + this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); + this._monthsShortRegex = this._monthsRegex; + this._monthsStrictRegex = new RegExp( + '^(' + longPieces.join('|') + ')', + 'i' + ); + this._monthsShortStrictRegex = new RegExp( + '^(' + shortPieces.join('|') + ')', + 'i' + ); + } + + // FORMATTING + + addFormatToken('Y', 0, 0, function () { + var y = this.year(); + return y <= 9999 ? zeroFill(y, 4) : '+' + y; + }); + + addFormatToken(0, ['YY', 2], 0, function () { + return this.year() % 100; + }); + + addFormatToken(0, ['YYYY', 4], 0, 'year'); + addFormatToken(0, ['YYYYY', 5], 0, 'year'); + addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); + + // ALIASES + + addUnitAlias('year', 'y'); + + // PRIORITIES + + addUnitPriority('year', 1); + + // PARSING + + addRegexToken('Y', matchSigned); + addRegexToken('YY', match1to2, match2); + addRegexToken('YYYY', match1to4, match4); + addRegexToken('YYYYY', match1to6, match6); + addRegexToken('YYYYYY', match1to6, match6); + + addParseToken(['YYYYY', 'YYYYYY'], YEAR); + addParseToken('YYYY', function (input, array) { + array[YEAR] = + input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input); + }); + addParseToken('YY', function (input, array) { + array[YEAR] = hooks.parseTwoDigitYear(input); + }); + addParseToken('Y', function (input, array) { + array[YEAR] = parseInt(input, 10); + }); + + // HELPERS + + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; + } + + // HOOKS + + hooks.parseTwoDigitYear = function (input) { + return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); + }; + + // MOMENTS + + var getSetYear = makeGetSet('FullYear', true); + + function getIsLeapYear() { + return isLeapYear(this.year()); + } + + function createDate(y, m, d, h, M, s, ms) { + // can't just apply() to create a date: + // https://stackoverflow.com/q/181348 + var date; + // the date constructor remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0) { + // preserve leap years using a full 400 year cycle, then reset + date = new Date(y + 400, m, d, h, M, s, ms); + if (isFinite(date.getFullYear())) { + date.setFullYear(y); + } + } else { + date = new Date(y, m, d, h, M, s, ms); + } + + return date; + } + + function createUTCDate(y) { + var date, args; + // the Date.UTC function remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0) { + args = Array.prototype.slice.call(arguments); + // preserve leap years using a full 400 year cycle, then reset + args[0] = y + 400; + date = new Date(Date.UTC.apply(null, args)); + if (isFinite(date.getUTCFullYear())) { + date.setUTCFullYear(y); + } + } else { + date = new Date(Date.UTC.apply(null, arguments)); + } + + return date; + } + + // start-of-first-week - start-of-year + function firstWeekOffset(year, dow, doy) { + var // first-week day -- which january is always in the first week (4 for iso, 1 for other) + fwd = 7 + dow - doy, + // first-week day local weekday -- which local weekday is fwd + fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7; + + return -fwdlw + fwd - 1; + } + + // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday + function dayOfYearFromWeeks(year, week, weekday, dow, doy) { + var localWeekday = (7 + weekday - dow) % 7, + weekOffset = firstWeekOffset(year, dow, doy), + dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset, + resYear, + resDayOfYear; + + if (dayOfYear <= 0) { + resYear = year - 1; + resDayOfYear = daysInYear(resYear) + dayOfYear; + } else if (dayOfYear > daysInYear(year)) { + resYear = year + 1; + resDayOfYear = dayOfYear - daysInYear(year); + } else { + resYear = year; + resDayOfYear = dayOfYear; + } + + return { + year: resYear, + dayOfYear: resDayOfYear, + }; + } + + function weekOfYear(mom, dow, doy) { + var weekOffset = firstWeekOffset(mom.year(), dow, doy), + week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1, + resWeek, + resYear; + + if (week < 1) { + resYear = mom.year() - 1; + resWeek = week + weeksInYear(resYear, dow, doy); + } else if (week > weeksInYear(mom.year(), dow, doy)) { + resWeek = week - weeksInYear(mom.year(), dow, doy); + resYear = mom.year() + 1; + } else { + resYear = mom.year(); + resWeek = week; + } + + return { + week: resWeek, + year: resYear, + }; + } + + function weeksInYear(year, dow, doy) { + var weekOffset = firstWeekOffset(year, dow, doy), + weekOffsetNext = firstWeekOffset(year + 1, dow, doy); + return (daysInYear(year) - weekOffset + weekOffsetNext) / 7; + } + + // FORMATTING + + addFormatToken('w', ['ww', 2], 'wo', 'week'); + addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); + + // ALIASES + + addUnitAlias('week', 'w'); + addUnitAlias('isoWeek', 'W'); + + // PRIORITIES + + addUnitPriority('week', 5); + addUnitPriority('isoWeek', 5); + + // PARSING + + addRegexToken('w', match1to2); + addRegexToken('ww', match1to2, match2); + addRegexToken('W', match1to2); + addRegexToken('WW', match1to2, match2); + + addWeekParseToken( + ['w', 'ww', 'W', 'WW'], + function (input, week, config, token) { + week[token.substr(0, 1)] = toInt(input); + } + ); + + // HELPERS + + // LOCALES + + function localeWeek(mom) { + return weekOfYear(mom, this._week.dow, this._week.doy).week; + } + + var defaultLocaleWeek = { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }; + + function localeFirstDayOfWeek() { + return this._week.dow; + } + + function localeFirstDayOfYear() { + return this._week.doy; + } + + // MOMENTS + + function getSetWeek(input) { + var week = this.localeData().week(this); + return input == null ? week : this.add((input - week) * 7, 'd'); + } + + function getSetISOWeek(input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add((input - week) * 7, 'd'); + } + + // FORMATTING + + addFormatToken('d', 0, 'do', 'day'); + + addFormatToken('dd', 0, 0, function (format) { + return this.localeData().weekdaysMin(this, format); + }); + + addFormatToken('ddd', 0, 0, function (format) { + return this.localeData().weekdaysShort(this, format); + }); + + addFormatToken('dddd', 0, 0, function (format) { + return this.localeData().weekdays(this, format); + }); + + addFormatToken('e', 0, 0, 'weekday'); + addFormatToken('E', 0, 0, 'isoWeekday'); + + // ALIASES + + addUnitAlias('day', 'd'); + addUnitAlias('weekday', 'e'); + addUnitAlias('isoWeekday', 'E'); + + // PRIORITY + addUnitPriority('day', 11); + addUnitPriority('weekday', 11); + addUnitPriority('isoWeekday', 11); + + // PARSING + + addRegexToken('d', match1to2); + addRegexToken('e', match1to2); + addRegexToken('E', match1to2); + addRegexToken('dd', function (isStrict, locale) { + return locale.weekdaysMinRegex(isStrict); + }); + addRegexToken('ddd', function (isStrict, locale) { + return locale.weekdaysShortRegex(isStrict); + }); + addRegexToken('dddd', function (isStrict, locale) { + return locale.weekdaysRegex(isStrict); + }); + + addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) { + var weekday = config._locale.weekdaysParse(input, token, config._strict); + // if we didn't get a weekday name, mark the date as invalid + if (weekday != null) { + week.d = weekday; + } else { + getParsingFlags(config).invalidWeekday = input; + } + }); + + addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) { + week[token] = toInt(input); + }); + + // HELPERS + + function parseWeekday(input, locale) { + if (typeof input !== 'string') { + return input; + } + + if (!isNaN(input)) { + return parseInt(input, 10); + } + + input = locale.weekdaysParse(input); + if (typeof input === 'number') { + return input; + } + + return null; + } + + function parseIsoWeekday(input, locale) { + if (typeof input === 'string') { + return locale.weekdaysParse(input) % 7 || 7; + } + return isNaN(input) ? null : input; + } + + // LOCALES + function shiftWeekdays(ws, n) { + return ws.slice(n, 7).concat(ws.slice(0, n)); + } + + var defaultLocaleWeekdays = + 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), + defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + defaultWeekdaysRegex = matchWord, + defaultWeekdaysShortRegex = matchWord, + defaultWeekdaysMinRegex = matchWord; + + function localeWeekdays(m, format) { + var weekdays = isArray(this._weekdays) + ? this._weekdays + : this._weekdays[ + m && m !== true && this._weekdays.isFormat.test(format) + ? 'format' + : 'standalone' + ]; + return m === true + ? shiftWeekdays(weekdays, this._week.dow) + : m + ? weekdays[m.day()] + : weekdays; + } + + function localeWeekdaysShort(m) { + return m === true + ? shiftWeekdays(this._weekdaysShort, this._week.dow) + : m + ? this._weekdaysShort[m.day()] + : this._weekdaysShort; + } + + function localeWeekdaysMin(m) { + return m === true + ? shiftWeekdays(this._weekdaysMin, this._week.dow) + : m + ? this._weekdaysMin[m.day()] + : this._weekdaysMin; + } + + function handleStrictParse$1(weekdayName, format, strict) { + var i, + ii, + mom, + llc = weekdayName.toLocaleLowerCase(); + if (!this._weekdaysParse) { + this._weekdaysParse = []; + this._shortWeekdaysParse = []; + this._minWeekdaysParse = []; + + for (i = 0; i < 7; ++i) { + mom = createUTC([2000, 1]).day(i); + this._minWeekdaysParse[i] = this.weekdaysMin( + mom, + '' + ).toLocaleLowerCase(); + this._shortWeekdaysParse[i] = this.weekdaysShort( + mom, + '' + ).toLocaleLowerCase(); + this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase(); + } + } + + if (strict) { + if (format === 'dddd') { + ii = indexOf.call(this._weekdaysParse, llc); + return ii !== -1 ? ii : null; + } else if (format === 'ddd') { + ii = indexOf.call(this._shortWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } else { + ii = indexOf.call(this._minWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } + } else { + if (format === 'dddd') { + ii = indexOf.call(this._weekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._shortWeekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._minWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } else if (format === 'ddd') { + ii = indexOf.call(this._shortWeekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._weekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._minWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } else { + ii = indexOf.call(this._minWeekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._weekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._shortWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } + } + } + + function localeWeekdaysParse(weekdayName, format, strict) { + var i, mom, regex; + + if (this._weekdaysParseExact) { + return handleStrictParse$1.call(this, weekdayName, format, strict); + } + + if (!this._weekdaysParse) { + this._weekdaysParse = []; + this._minWeekdaysParse = []; + this._shortWeekdaysParse = []; + this._fullWeekdaysParse = []; + } + + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + + mom = createUTC([2000, 1]).day(i); + if (strict && !this._fullWeekdaysParse[i]) { + this._fullWeekdaysParse[i] = new RegExp( + '^' + this.weekdays(mom, '').replace('.', '\\.?') + '$', + 'i' + ); + this._shortWeekdaysParse[i] = new RegExp( + '^' + this.weekdaysShort(mom, '').replace('.', '\\.?') + '$', + 'i' + ); + this._minWeekdaysParse[i] = new RegExp( + '^' + this.weekdaysMin(mom, '').replace('.', '\\.?') + '$', + 'i' + ); + } + if (!this._weekdaysParse[i]) { + regex = + '^' + + this.weekdays(mom, '') + + '|^' + + this.weekdaysShort(mom, '') + + '|^' + + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if ( + strict && + format === 'dddd' && + this._fullWeekdaysParse[i].test(weekdayName) + ) { + return i; + } else if ( + strict && + format === 'ddd' && + this._shortWeekdaysParse[i].test(weekdayName) + ) { + return i; + } else if ( + strict && + format === 'dd' && + this._minWeekdaysParse[i].test(weekdayName) + ) { + return i; + } else if (!strict && this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } + } + + // MOMENTS + + function getSetDayOfWeek(input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.localeData()); + return this.add(input - day, 'd'); + } else { + return day; + } + } + + function getSetLocaleDayOfWeek(input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; + return input == null ? weekday : this.add(input - weekday, 'd'); + } + + function getSetISODayOfWeek(input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + + if (input != null) { + var weekday = parseIsoWeekday(input, this.localeData()); + return this.day(this.day() % 7 ? weekday : weekday - 7); + } else { + return this.day() || 7; + } + } + + function weekdaysRegex(isStrict) { + if (this._weekdaysParseExact) { + if (!hasOwnProp(this, '_weekdaysRegex')) { + computeWeekdaysParse.call(this); + } + if (isStrict) { + return this._weekdaysStrictRegex; + } else { + return this._weekdaysRegex; + } + } else { + if (!hasOwnProp(this, '_weekdaysRegex')) { + this._weekdaysRegex = defaultWeekdaysRegex; + } + return this._weekdaysStrictRegex && isStrict + ? this._weekdaysStrictRegex + : this._weekdaysRegex; + } + } + + function weekdaysShortRegex(isStrict) { + if (this._weekdaysParseExact) { + if (!hasOwnProp(this, '_weekdaysRegex')) { + computeWeekdaysParse.call(this); + } + if (isStrict) { + return this._weekdaysShortStrictRegex; + } else { + return this._weekdaysShortRegex; + } + } else { + if (!hasOwnProp(this, '_weekdaysShortRegex')) { + this._weekdaysShortRegex = defaultWeekdaysShortRegex; + } + return this._weekdaysShortStrictRegex && isStrict + ? this._weekdaysShortStrictRegex + : this._weekdaysShortRegex; + } + } + + function weekdaysMinRegex(isStrict) { + if (this._weekdaysParseExact) { + if (!hasOwnProp(this, '_weekdaysRegex')) { + computeWeekdaysParse.call(this); + } + if (isStrict) { + return this._weekdaysMinStrictRegex; + } else { + return this._weekdaysMinRegex; + } + } else { + if (!hasOwnProp(this, '_weekdaysMinRegex')) { + this._weekdaysMinRegex = defaultWeekdaysMinRegex; + } + return this._weekdaysMinStrictRegex && isStrict + ? this._weekdaysMinStrictRegex + : this._weekdaysMinRegex; + } + } + + function computeWeekdaysParse() { + function cmpLenRev(a, b) { + return b.length - a.length; + } + + var minPieces = [], + shortPieces = [], + longPieces = [], + mixedPieces = [], + i, + mom, + minp, + shortp, + longp; + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + mom = createUTC([2000, 1]).day(i); + minp = regexEscape(this.weekdaysMin(mom, '')); + shortp = regexEscape(this.weekdaysShort(mom, '')); + longp = regexEscape(this.weekdays(mom, '')); + minPieces.push(minp); + shortPieces.push(shortp); + longPieces.push(longp); + mixedPieces.push(minp); + mixedPieces.push(shortp); + mixedPieces.push(longp); + } + // Sorting makes sure if one weekday (or abbr) is a prefix of another it + // will match the longer piece. + minPieces.sort(cmpLenRev); + shortPieces.sort(cmpLenRev); + longPieces.sort(cmpLenRev); + mixedPieces.sort(cmpLenRev); + + this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); + this._weekdaysShortRegex = this._weekdaysRegex; + this._weekdaysMinRegex = this._weekdaysRegex; + + this._weekdaysStrictRegex = new RegExp( + '^(' + longPieces.join('|') + ')', + 'i' + ); + this._weekdaysShortStrictRegex = new RegExp( + '^(' + shortPieces.join('|') + ')', + 'i' + ); + this._weekdaysMinStrictRegex = new RegExp( + '^(' + minPieces.join('|') + ')', + 'i' + ); + } + + // FORMATTING + + function hFormat() { + return this.hours() % 12 || 12; + } + + function kFormat() { + return this.hours() || 24; + } + + addFormatToken('H', ['HH', 2], 0, 'hour'); + addFormatToken('h', ['hh', 2], 0, hFormat); + addFormatToken('k', ['kk', 2], 0, kFormat); + + addFormatToken('hmm', 0, 0, function () { + return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2); + }); + + addFormatToken('hmmss', 0, 0, function () { + return ( + '' + + hFormat.apply(this) + + zeroFill(this.minutes(), 2) + + zeroFill(this.seconds(), 2) + ); + }); + + addFormatToken('Hmm', 0, 0, function () { + return '' + this.hours() + zeroFill(this.minutes(), 2); + }); + + addFormatToken('Hmmss', 0, 0, function () { + return ( + '' + + this.hours() + + zeroFill(this.minutes(), 2) + + zeroFill(this.seconds(), 2) + ); + }); + + function meridiem(token, lowercase) { + addFormatToken(token, 0, 0, function () { + return this.localeData().meridiem( + this.hours(), + this.minutes(), + lowercase + ); + }); + } + + meridiem('a', true); + meridiem('A', false); + + // ALIASES + + addUnitAlias('hour', 'h'); + + // PRIORITY + addUnitPriority('hour', 13); + + // PARSING + + function matchMeridiem(isStrict, locale) { + return locale._meridiemParse; + } + + addRegexToken('a', matchMeridiem); + addRegexToken('A', matchMeridiem); + addRegexToken('H', match1to2); + addRegexToken('h', match1to2); + addRegexToken('k', match1to2); + addRegexToken('HH', match1to2, match2); + addRegexToken('hh', match1to2, match2); + addRegexToken('kk', match1to2, match2); + + addRegexToken('hmm', match3to4); + addRegexToken('hmmss', match5to6); + addRegexToken('Hmm', match3to4); + addRegexToken('Hmmss', match5to6); + + addParseToken(['H', 'HH'], HOUR); + addParseToken(['k', 'kk'], function (input, array, config) { + var kInput = toInt(input); + array[HOUR] = kInput === 24 ? 0 : kInput; + }); + addParseToken(['a', 'A'], function (input, array, config) { + config._isPm = config._locale.isPM(input); + config._meridiem = input; + }); + addParseToken(['h', 'hh'], function (input, array, config) { + array[HOUR] = toInt(input); + getParsingFlags(config).bigHour = true; + }); + addParseToken('hmm', function (input, array, config) { + var pos = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos)); + array[MINUTE] = toInt(input.substr(pos)); + getParsingFlags(config).bigHour = true; + }); + addParseToken('hmmss', function (input, array, config) { + var pos1 = input.length - 4, + pos2 = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos1)); + array[MINUTE] = toInt(input.substr(pos1, 2)); + array[SECOND] = toInt(input.substr(pos2)); + getParsingFlags(config).bigHour = true; + }); + addParseToken('Hmm', function (input, array, config) { + var pos = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos)); + array[MINUTE] = toInt(input.substr(pos)); + }); + addParseToken('Hmmss', function (input, array, config) { + var pos1 = input.length - 4, + pos2 = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos1)); + array[MINUTE] = toInt(input.substr(pos1, 2)); + array[SECOND] = toInt(input.substr(pos2)); + }); + + // LOCALES + + function localeIsPM(input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return (input + '').toLowerCase().charAt(0) === 'p'; + } + + var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i, + // Setting the hour should keep the time, because the user explicitly + // specified which hour they want. So trying to maintain the same hour (in + // a new timezone) makes sense. Adding/subtracting hours does not follow + // this rule. + getSetHour = makeGetSet('Hours', true); + + function localeMeridiem(hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; + } + } + + var baseConfig = { + calendar: defaultCalendar, + longDateFormat: defaultLongDateFormat, + invalidDate: defaultInvalidDate, + ordinal: defaultOrdinal, + dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse, + relativeTime: defaultRelativeTime, + + months: defaultLocaleMonths, + monthsShort: defaultLocaleMonthsShort, + + week: defaultLocaleWeek, + + weekdays: defaultLocaleWeekdays, + weekdaysMin: defaultLocaleWeekdaysMin, + weekdaysShort: defaultLocaleWeekdaysShort, + + meridiemParse: defaultLocaleMeridiemParse, + }; + + // internal storage for locale config files + var locales = {}, + localeFamilies = {}, + globalLocale; + + function commonPrefix(arr1, arr2) { + var i, + minl = Math.min(arr1.length, arr2.length); + for (i = 0; i < minl; i += 1) { + if (arr1[i] !== arr2[i]) { + return i; + } + } + return minl; + } + + function normalizeLocale(key) { + return key ? key.toLowerCase().replace('_', '-') : key; + } + + // pick the locale from the array + // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each + // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root + function chooseLocale(names) { + var i = 0, + j, + next, + locale, + split; + + while (i < names.length) { + split = normalizeLocale(names[i]).split('-'); + j = split.length; + next = normalizeLocale(names[i + 1]); + next = next ? next.split('-') : null; + while (j > 0) { + locale = loadLocale(split.slice(0, j).join('-')); + if (locale) { + return locale; + } + if ( + next && + next.length >= j && + commonPrefix(split, next) >= j - 1 + ) { + //the next array item is better than a shallower substring of this one + break; + } + j--; + } + i++; + } + return globalLocale; + } + + function isLocaleNameSane(name) { + // Prevent names that look like filesystem paths, i.e contain '/' or '\' + return name.match('^[^/\\\\]*$') != null; + } + + function loadLocale(name) { + var oldLocale = null, + aliasedRequire; + // TODO: Find a better way to register and load all the locales in Node + if ( + locales[name] === undefined && + 'object' !== 'undefined' && + module && + module.exports && + isLocaleNameSane(name) + ) { + try { + oldLocale = globalLocale._abbr; + aliasedRequire = commonjsRequire; + aliasedRequire('./locale/' + name); + getSetGlobalLocale(oldLocale); + } catch (e) { + // mark as not found to avoid repeating expensive file require call causing high CPU + // when trying to find en-US, en_US, en-us for every format call + locales[name] = null; // null means not found + } + } + return locales[name]; + } + + // This function will load locale and then set the global locale. If + // no arguments are passed in, it will simply return the current global + // locale key. + function getSetGlobalLocale(key, values) { + var data; + if (key) { + if (isUndefined(values)) { + data = getLocale(key); + } else { + data = defineLocale(key, values); + } + + if (data) { + // moment.duration._locale = moment._locale = data; + globalLocale = data; + } else { + if (typeof console !== 'undefined' && console.warn) { + //warn user if arguments are passed but the locale could not be set + console.warn( + 'Locale ' + key + ' not found. Did you forget to load it?' + ); + } + } + } + + return globalLocale._abbr; + } + + function defineLocale(name, config) { + if (config !== null) { + var locale, + parentConfig = baseConfig; + config.abbr = name; + if (locales[name] != null) { + deprecateSimple( + 'defineLocaleOverride', + 'use moment.updateLocale(localeName, config) to change ' + + 'an existing locale. moment.defineLocale(localeName, ' + + 'config) should only be used for creating a new locale ' + + 'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.' + ); + parentConfig = locales[name]._config; + } else if (config.parentLocale != null) { + if (locales[config.parentLocale] != null) { + parentConfig = locales[config.parentLocale]._config; + } else { + locale = loadLocale(config.parentLocale); + if (locale != null) { + parentConfig = locale._config; + } else { + if (!localeFamilies[config.parentLocale]) { + localeFamilies[config.parentLocale] = []; + } + localeFamilies[config.parentLocale].push({ + name: name, + config: config, + }); + return null; + } + } + } + locales[name] = new Locale(mergeConfigs(parentConfig, config)); + + if (localeFamilies[name]) { + localeFamilies[name].forEach(function (x) { + defineLocale(x.name, x.config); + }); + } + + // backwards compat for now: also set the locale + // make sure we set the locale AFTER all child locales have been + // created, so we won't end up with the child locale set. + getSetGlobalLocale(name); + + return locales[name]; + } else { + // useful for testing + delete locales[name]; + return null; + } + } + + function updateLocale(name, config) { + if (config != null) { + var locale, + tmpLocale, + parentConfig = baseConfig; + + if (locales[name] != null && locales[name].parentLocale != null) { + // Update existing child locale in-place to avoid memory-leaks + locales[name].set(mergeConfigs(locales[name]._config, config)); + } else { + // MERGE + tmpLocale = loadLocale(name); + if (tmpLocale != null) { + parentConfig = tmpLocale._config; + } + config = mergeConfigs(parentConfig, config); + if (tmpLocale == null) { + // updateLocale is called for creating a new locale + // Set abbr so it will have a name (getters return + // undefined otherwise). + config.abbr = name; + } + locale = new Locale(config); + locale.parentLocale = locales[name]; + locales[name] = locale; + } + + // backwards compat for now: also set the locale + getSetGlobalLocale(name); + } else { + // pass null for config to unupdate, useful for tests + if (locales[name] != null) { + if (locales[name].parentLocale != null) { + locales[name] = locales[name].parentLocale; + if (name === getSetGlobalLocale()) { + getSetGlobalLocale(name); + } + } else if (locales[name] != null) { + delete locales[name]; + } + } + } + return locales[name]; + } + + // returns locale data + function getLocale(key) { + var locale; + + if (key && key._locale && key._locale._abbr) { + key = key._locale._abbr; + } + + if (!key) { + return globalLocale; + } + + if (!isArray(key)) { + //short-circuit everything else + locale = loadLocale(key); + if (locale) { + return locale; + } + key = [key]; + } + + return chooseLocale(key); + } + + function listLocales() { + return keys(locales); + } + + function checkOverflow(m) { + var overflow, + a = m._a; + + if (a && getParsingFlags(m).overflow === -2) { + overflow = + a[MONTH] < 0 || a[MONTH] > 11 + ? MONTH + : a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) + ? DATE + : a[HOUR] < 0 || + a[HOUR] > 24 || + (a[HOUR] === 24 && + (a[MINUTE] !== 0 || + a[SECOND] !== 0 || + a[MILLISECOND] !== 0)) + ? HOUR + : a[MINUTE] < 0 || a[MINUTE] > 59 + ? MINUTE + : a[SECOND] < 0 || a[SECOND] > 59 + ? SECOND + : a[MILLISECOND] < 0 || a[MILLISECOND] > 999 + ? MILLISECOND + : -1; + + if ( + getParsingFlags(m)._overflowDayOfYear && + (overflow < YEAR || overflow > DATE) + ) { + overflow = DATE; + } + if (getParsingFlags(m)._overflowWeeks && overflow === -1) { + overflow = WEEK; + } + if (getParsingFlags(m)._overflowWeekday && overflow === -1) { + overflow = WEEKDAY; + } + + getParsingFlags(m).overflow = overflow; + } + + return m; + } + + // iso 8601 regex + // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) + var extendedIsoRegex = + /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/, + basicIsoRegex = + /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/, + tzRegex = /Z|[+-]\d\d(?::?\d\d)?/, + isoDates = [ + ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/], + ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/], + ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/], + ['GGGG-[W]WW', /\d{4}-W\d\d/, false], + ['YYYY-DDD', /\d{4}-\d{3}/], + ['YYYY-MM', /\d{4}-\d\d/, false], + ['YYYYYYMMDD', /[+-]\d{10}/], + ['YYYYMMDD', /\d{8}/], + ['GGGG[W]WWE', /\d{4}W\d{3}/], + ['GGGG[W]WW', /\d{4}W\d{2}/, false], + ['YYYYDDD', /\d{7}/], + ['YYYYMM', /\d{6}/, false], + ['YYYY', /\d{4}/, false], + ], + // iso time formats and regexes + isoTimes = [ + ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/], + ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/], + ['HH:mm:ss', /\d\d:\d\d:\d\d/], + ['HH:mm', /\d\d:\d\d/], + ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/], + ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/], + ['HHmmss', /\d\d\d\d\d\d/], + ['HHmm', /\d\d\d\d/], + ['HH', /\d\d/], + ], + aspNetJsonRegex = /^\/?Date\((-?\d+)/i, + // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3 + rfc2822 = + /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/, + obsOffsets = { + UT: 0, + GMT: 0, + EDT: -4 * 60, + EST: -5 * 60, + CDT: -5 * 60, + CST: -6 * 60, + MDT: -6 * 60, + MST: -7 * 60, + PDT: -7 * 60, + PST: -8 * 60, + }; + + // date from iso format + function configFromISO(config) { + var i, + l, + string = config._i, + match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string), + allowTime, + dateFormat, + timeFormat, + tzFormat, + isoDatesLen = isoDates.length, + isoTimesLen = isoTimes.length; + + if (match) { + getParsingFlags(config).iso = true; + for (i = 0, l = isoDatesLen; i < l; i++) { + if (isoDates[i][1].exec(match[1])) { + dateFormat = isoDates[i][0]; + allowTime = isoDates[i][2] !== false; + break; + } + } + if (dateFormat == null) { + config._isValid = false; + return; + } + if (match[3]) { + for (i = 0, l = isoTimesLen; i < l; i++) { + if (isoTimes[i][1].exec(match[3])) { + // match[2] should be 'T' or space + timeFormat = (match[2] || ' ') + isoTimes[i][0]; + break; + } + } + if (timeFormat == null) { + config._isValid = false; + return; + } + } + if (!allowTime && timeFormat != null) { + config._isValid = false; + return; + } + if (match[4]) { + if (tzRegex.exec(match[4])) { + tzFormat = 'Z'; + } else { + config._isValid = false; + return; + } + } + config._f = dateFormat + (timeFormat || '') + (tzFormat || ''); + configFromStringAndFormat(config); + } else { + config._isValid = false; + } + } + + function extractFromRFC2822Strings( + yearStr, + monthStr, + dayStr, + hourStr, + minuteStr, + secondStr + ) { + var result = [ + untruncateYear(yearStr), + defaultLocaleMonthsShort.indexOf(monthStr), + parseInt(dayStr, 10), + parseInt(hourStr, 10), + parseInt(minuteStr, 10), + ]; + + if (secondStr) { + result.push(parseInt(secondStr, 10)); + } + + return result; + } + + function untruncateYear(yearStr) { + var year = parseInt(yearStr, 10); + if (year <= 49) { + return 2000 + year; + } else if (year <= 999) { + return 1900 + year; + } + return year; + } + + function preprocessRFC2822(s) { + // Remove comments and folding whitespace and replace multiple-spaces with a single space + return s + .replace(/\([^()]*\)|[\n\t]/g, ' ') + .replace(/(\s\s+)/g, ' ') + .replace(/^\s\s*/, '') + .replace(/\s\s*$/, ''); + } + + function checkWeekday(weekdayStr, parsedInput, config) { + if (weekdayStr) { + // TODO: Replace the vanilla JS Date object with an independent day-of-week check. + var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr), + weekdayActual = new Date( + parsedInput[0], + parsedInput[1], + parsedInput[2] + ).getDay(); + if (weekdayProvided !== weekdayActual) { + getParsingFlags(config).weekdayMismatch = true; + config._isValid = false; + return false; + } + } + return true; + } + + function calculateOffset(obsOffset, militaryOffset, numOffset) { + if (obsOffset) { + return obsOffsets[obsOffset]; + } else if (militaryOffset) { + // the only allowed military tz is Z + return 0; + } else { + var hm = parseInt(numOffset, 10), + m = hm % 100, + h = (hm - m) / 100; + return h * 60 + m; + } + } + + // date and time from ref 2822 format + function configFromRFC2822(config) { + var match = rfc2822.exec(preprocessRFC2822(config._i)), + parsedArray; + if (match) { + parsedArray = extractFromRFC2822Strings( + match[4], + match[3], + match[2], + match[5], + match[6], + match[7] + ); + if (!checkWeekday(match[1], parsedArray, config)) { + return; + } + + config._a = parsedArray; + config._tzm = calculateOffset(match[8], match[9], match[10]); + + config._d = createUTCDate.apply(null, config._a); + config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + + getParsingFlags(config).rfc2822 = true; + } else { + config._isValid = false; + } + } + + // date from 1) ASP.NET, 2) ISO, 3) RFC 2822 formats, or 4) optional fallback if parsing isn't strict + function configFromString(config) { + var matched = aspNetJsonRegex.exec(config._i); + if (matched !== null) { + config._d = new Date(+matched[1]); + return; + } + + configFromISO(config); + if (config._isValid === false) { + delete config._isValid; + } else { + return; + } + + configFromRFC2822(config); + if (config._isValid === false) { + delete config._isValid; + } else { + return; + } + + if (config._strict) { + config._isValid = false; + } else { + // Final attempt, use Input Fallback + hooks.createFromInputFallback(config); + } + } + + hooks.createFromInputFallback = deprecate( + 'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' + + 'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' + + 'discouraged. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.', + function (config) { + config._d = new Date(config._i + (config._useUTC ? ' UTC' : '')); + } + ); + + // Pick the first defined of two or three arguments. + function defaults(a, b, c) { + if (a != null) { + return a; + } + if (b != null) { + return b; + } + return c; + } + + function currentDateArray(config) { + // hooks is actually the exported moment object + var nowValue = new Date(hooks.now()); + if (config._useUTC) { + return [ + nowValue.getUTCFullYear(), + nowValue.getUTCMonth(), + nowValue.getUTCDate(), + ]; + } + return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()]; + } + + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function configFromArray(config) { + var i, + date, + input = [], + currentDate, + expectedWeekday, + yearToUse; + + if (config._d) { + return; + } + + currentDate = currentDateArray(config); + + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + dayOfYearFromWeekInfo(config); + } + + //if the day of the year is set, figure out what it is + if (config._dayOfYear != null) { + yearToUse = defaults(config._a[YEAR], currentDate[YEAR]); + + if ( + config._dayOfYear > daysInYear(yearToUse) || + config._dayOfYear === 0 + ) { + getParsingFlags(config)._overflowDayOfYear = true; + } + + date = createUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } + + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } + + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = + config._a[i] == null ? (i === 2 ? 1 : 0) : config._a[i]; + } + + // Check for 24:00:00.000 + if ( + config._a[HOUR] === 24 && + config._a[MINUTE] === 0 && + config._a[SECOND] === 0 && + config._a[MILLISECOND] === 0 + ) { + config._nextDay = true; + config._a[HOUR] = 0; + } + + config._d = (config._useUTC ? createUTCDate : createDate).apply( + null, + input + ); + expectedWeekday = config._useUTC + ? config._d.getUTCDay() + : config._d.getDay(); + + // Apply timezone offset from input. The actual utcOffset can be changed + // with parseZone. + if (config._tzm != null) { + config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + } + + if (config._nextDay) { + config._a[HOUR] = 24; + } + + // check for mismatching day of week + if ( + config._w && + typeof config._w.d !== 'undefined' && + config._w.d !== expectedWeekday + ) { + getParsingFlags(config).weekdayMismatch = true; + } + } + + function dayOfYearFromWeekInfo(config) { + var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow, curWeek; + + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + dow = 1; + doy = 4; + + // TODO: We need to take the current isoWeekYear, but that depends on + // how we interpret now (local, utc, fixed offset). So create + // a now version of current config (take local/utc/offset flags, and + // create now). + weekYear = defaults( + w.GG, + config._a[YEAR], + weekOfYear(createLocal(), 1, 4).year + ); + week = defaults(w.W, 1); + weekday = defaults(w.E, 1); + if (weekday < 1 || weekday > 7) { + weekdayOverflow = true; + } + } else { + dow = config._locale._week.dow; + doy = config._locale._week.doy; + + curWeek = weekOfYear(createLocal(), dow, doy); + + weekYear = defaults(w.gg, config._a[YEAR], curWeek.year); + + // Default to current week. + week = defaults(w.w, curWeek.week); + + if (w.d != null) { + // weekday -- low day numbers are considered next week + weekday = w.d; + if (weekday < 0 || weekday > 6) { + weekdayOverflow = true; + } + } else if (w.e != null) { + // local weekday -- counting starts from beginning of week + weekday = w.e + dow; + if (w.e < 0 || w.e > 6) { + weekdayOverflow = true; + } + } else { + // default to beginning of week + weekday = dow; + } + } + if (week < 1 || week > weeksInYear(weekYear, dow, doy)) { + getParsingFlags(config)._overflowWeeks = true; + } else if (weekdayOverflow != null) { + getParsingFlags(config)._overflowWeekday = true; + } else { + temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy); + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } + } + + // constant that refers to the ISO standard + hooks.ISO_8601 = function () {}; + + // constant that refers to the RFC 2822 form + hooks.RFC_2822 = function () {}; + + // date from string and format string + function configFromStringAndFormat(config) { + // TODO: Move this to another part of the creation flow to prevent circular deps + if (config._f === hooks.ISO_8601) { + configFromISO(config); + return; + } + if (config._f === hooks.RFC_2822) { + configFromRFC2822(config); + return; + } + config._a = []; + getParsingFlags(config).empty = true; + + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var string = '' + config._i, + i, + parsedInput, + tokens, + token, + skipped, + stringLength = string.length, + totalParsedInputLength = 0, + era, + tokenLen; + + tokens = + expandFormat(config._f, config._locale).match(formattingTokens) || []; + tokenLen = tokens.length; + for (i = 0; i < tokenLen; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || + [])[0]; + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + getParsingFlags(config).unusedInput.push(skipped); + } + string = string.slice( + string.indexOf(parsedInput) + parsedInput.length + ); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + getParsingFlags(config).empty = false; + } else { + getParsingFlags(config).unusedTokens.push(token); + } + addTimeToArrayFromToken(token, parsedInput, config); + } else if (config._strict && !parsedInput) { + getParsingFlags(config).unusedTokens.push(token); + } + } + + // add remaining unparsed input length to the string + getParsingFlags(config).charsLeftOver = + stringLength - totalParsedInputLength; + if (string.length > 0) { + getParsingFlags(config).unusedInput.push(string); + } + + // clear _12h flag if hour is <= 12 + if ( + config._a[HOUR] <= 12 && + getParsingFlags(config).bigHour === true && + config._a[HOUR] > 0 + ) { + getParsingFlags(config).bigHour = undefined; + } + + getParsingFlags(config).parsedDateParts = config._a.slice(0); + getParsingFlags(config).meridiem = config._meridiem; + // handle meridiem + config._a[HOUR] = meridiemFixWrap( + config._locale, + config._a[HOUR], + config._meridiem + ); + + // handle era + era = getParsingFlags(config).era; + if (era !== null) { + config._a[YEAR] = config._locale.erasConvertYear(era, config._a[YEAR]); + } + + configFromArray(config); + checkOverflow(config); + } + + function meridiemFixWrap(locale, hour, meridiem) { + var isPm; + + if (meridiem == null) { + // nothing to do + return hour; + } + if (locale.meridiemHour != null) { + return locale.meridiemHour(hour, meridiem); + } else if (locale.isPM != null) { + // Fallback + isPm = locale.isPM(meridiem); + if (isPm && hour < 12) { + hour += 12; + } + if (!isPm && hour === 12) { + hour = 0; + } + return hour; + } else { + // this is not supposed to happen + return hour; + } + } + + // date from string and array of format strings + function configFromStringAndArray(config) { + var tempConfig, + bestMoment, + scoreToBeat, + i, + currentScore, + validFormatFound, + bestFormatIsValid = false, + configfLen = config._f.length; + + if (configfLen === 0) { + getParsingFlags(config).invalidFormat = true; + config._d = new Date(NaN); + return; + } + + for (i = 0; i < configfLen; i++) { + currentScore = 0; + validFormatFound = false; + tempConfig = copyConfig({}, config); + if (config._useUTC != null) { + tempConfig._useUTC = config._useUTC; + } + tempConfig._f = config._f[i]; + configFromStringAndFormat(tempConfig); + + if (isValid(tempConfig)) { + validFormatFound = true; + } + + // if there is any input that was not parsed add a penalty for that format + currentScore += getParsingFlags(tempConfig).charsLeftOver; + + //or tokens + currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10; + + getParsingFlags(tempConfig).score = currentScore; + + if (!bestFormatIsValid) { + if ( + scoreToBeat == null || + currentScore < scoreToBeat || + validFormatFound + ) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + if (validFormatFound) { + bestFormatIsValid = true; + } + } + } else { + if (currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + } + } + } + + extend(config, bestMoment || tempConfig); + } + + function configFromObject(config) { + if (config._d) { + return; + } + + var i = normalizeObjectUnits(config._i), + dayOrDate = i.day === undefined ? i.date : i.day; + config._a = map( + [i.year, i.month, dayOrDate, i.hour, i.minute, i.second, i.millisecond], + function (obj) { + return obj && parseInt(obj, 10); + } + ); + + configFromArray(config); + } + + function createFromConfig(config) { + var res = new Moment(checkOverflow(prepareConfig(config))); + if (res._nextDay) { + // Adding is smart enough around DST + res.add(1, 'd'); + res._nextDay = undefined; + } + + return res; + } + + function prepareConfig(config) { + var input = config._i, + format = config._f; + + config._locale = config._locale || getLocale(config._l); + + if (input === null || (format === undefined && input === '')) { + return createInvalid({ nullInput: true }); + } + + if (typeof input === 'string') { + config._i = input = config._locale.preparse(input); + } + + if (isMoment(input)) { + return new Moment(checkOverflow(input)); + } else if (isDate(input)) { + config._d = input; + } else if (isArray(format)) { + configFromStringAndArray(config); + } else if (format) { + configFromStringAndFormat(config); + } else { + configFromInput(config); + } + + if (!isValid(config)) { + config._d = null; + } + + return config; + } + + function configFromInput(config) { + var input = config._i; + if (isUndefined(input)) { + config._d = new Date(hooks.now()); + } else if (isDate(input)) { + config._d = new Date(input.valueOf()); + } else if (typeof input === 'string') { + configFromString(config); + } else if (isArray(input)) { + config._a = map(input.slice(0), function (obj) { + return parseInt(obj, 10); + }); + configFromArray(config); + } else if (isObject(input)) { + configFromObject(config); + } else if (isNumber(input)) { + // from milliseconds + config._d = new Date(input); + } else { + hooks.createFromInputFallback(config); + } + } + + function createLocalOrUTC(input, format, locale, strict, isUTC) { + var c = {}; + + if (format === true || format === false) { + strict = format; + format = undefined; + } + + if (locale === true || locale === false) { + strict = locale; + locale = undefined; + } + + if ( + (isObject(input) && isObjectEmpty(input)) || + (isArray(input) && input.length === 0) + ) { + input = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c._isAMomentObject = true; + c._useUTC = c._isUTC = isUTC; + c._l = locale; + c._i = input; + c._f = format; + c._strict = strict; + + return createFromConfig(c); + } + + function createLocal(input, format, locale, strict) { + return createLocalOrUTC(input, format, locale, strict, false); + } + + var prototypeMin = deprecate( + 'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/', + function () { + var other = createLocal.apply(null, arguments); + if (this.isValid() && other.isValid()) { + return other < this ? this : other; + } else { + return createInvalid(); + } + } + ), + prototypeMax = deprecate( + 'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/', + function () { + var other = createLocal.apply(null, arguments); + if (this.isValid() && other.isValid()) { + return other > this ? this : other; + } else { + return createInvalid(); + } + } + ); + + // Pick a moment m from moments so that m[fn](other) is true for all + // other. This relies on the function fn to be transitive. + // + // moments should either be an array of moment objects or an array, whose + // first element is an array of moment objects. + function pickBy(fn, moments) { + var res, i; + if (moments.length === 1 && isArray(moments[0])) { + moments = moments[0]; + } + if (!moments.length) { + return createLocal(); + } + res = moments[0]; + for (i = 1; i < moments.length; ++i) { + if (!moments[i].isValid() || moments[i][fn](res)) { + res = moments[i]; + } + } + return res; + } + + // TODO: Use [].sort instead? + function min() { + var args = [].slice.call(arguments, 0); + + return pickBy('isBefore', args); + } + + function max() { + var args = [].slice.call(arguments, 0); + + return pickBy('isAfter', args); + } + + var now = function () { + return Date.now ? Date.now() : +new Date(); + }; + + var ordering = [ + 'year', + 'quarter', + 'month', + 'week', + 'day', + 'hour', + 'minute', + 'second', + 'millisecond', + ]; + + function isDurationValid(m) { + var key, + unitHasDecimal = false, + i, + orderLen = ordering.length; + for (key in m) { + if ( + hasOwnProp(m, key) && + !( + indexOf.call(ordering, key) !== -1 && + (m[key] == null || !isNaN(m[key])) + ) + ) { + return false; + } + } + + for (i = 0; i < orderLen; ++i) { + if (m[ordering[i]]) { + if (unitHasDecimal) { + return false; // only allow non-integers for smallest unit + } + if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) { + unitHasDecimal = true; + } + } + } + + return true; + } + + function isValid$1() { + return this._isValid; + } + + function createInvalid$1() { + return createDuration(NaN); + } + + function Duration(duration) { + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + quarters = normalizedInput.quarter || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || normalizedInput.isoWeek || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 0; + + this._isValid = isDurationValid(normalizedInput); + + // representation for dateAddRemove + this._milliseconds = + +milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = +days + weeks * 7; + // It is impossible to translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = +months + quarters * 3 + years * 12; + + this._data = {}; + + this._locale = getLocale(); + + this._bubble(); + } + + function isDuration(obj) { + return obj instanceof Duration; + } + + function absRound(number) { + if (number < 0) { + return Math.round(-1 * number) * -1; + } else { + return Math.round(number); + } + } + + // compare two arrays, return the number of differences + function compareArrays(array1, array2, dontConvert) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if ( + (dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i])) + ) { + diffs++; + } + } + return diffs + lengthDiff; + } + + // FORMATTING + + function offset(token, separator) { + addFormatToken(token, 0, 0, function () { + var offset = this.utcOffset(), + sign = '+'; + if (offset < 0) { + offset = -offset; + sign = '-'; + } + return ( + sign + + zeroFill(~~(offset / 60), 2) + + separator + + zeroFill(~~offset % 60, 2) + ); + }); + } + + offset('Z', ':'); + offset('ZZ', ''); + + // PARSING + + addRegexToken('Z', matchShortOffset); + addRegexToken('ZZ', matchShortOffset); + addParseToken(['Z', 'ZZ'], function (input, array, config) { + config._useUTC = true; + config._tzm = offsetFromString(matchShortOffset, input); + }); + + // HELPERS + + // timezone chunker + // '+10:00' > ['10', '00'] + // '-1530' > ['-15', '30'] + var chunkOffset = /([\+\-]|\d\d)/gi; + + function offsetFromString(matcher, string) { + var matches = (string || '').match(matcher), + chunk, + parts, + minutes; + + if (matches === null) { + return null; + } + + chunk = matches[matches.length - 1] || []; + parts = (chunk + '').match(chunkOffset) || ['-', 0, 0]; + minutes = +(parts[1] * 60) + toInt(parts[2]); + + return minutes === 0 ? 0 : parts[0] === '+' ? minutes : -minutes; + } + + // Return a moment from input, that is local/utc/zone equivalent to model. + function cloneWithOffset(input, model) { + var res, diff; + if (model._isUTC) { + res = model.clone(); + diff = + (isMoment(input) || isDate(input) + ? input.valueOf() + : createLocal(input).valueOf()) - res.valueOf(); + // Use low-level api, because this fn is low-level api. + res._d.setTime(res._d.valueOf() + diff); + hooks.updateOffset(res, false); + return res; + } else { + return createLocal(input).local(); + } + } + + function getDateOffset(m) { + // On Firefox.24 Date#getTimezoneOffset returns a floating point. + // https://github.com/moment/moment/pull/1871 + return -Math.round(m._d.getTimezoneOffset()); + } + + // HOOKS + + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + hooks.updateOffset = function () {}; + + // MOMENTS + + // keepLocalTime = true means only change the timezone, without + // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> + // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset + // +0200, so we adjust the time as needed, to be valid. + // + // Keeping the time actually adds/subtracts (one hour) + // from the actual represented time. That is why we call updateOffset + // a second time. In case it wants us to change the offset again + // _changeInProgress == true case, then we have to adjust, because + // there is no such time in the given timezone. + function getSetOffset(input, keepLocalTime, keepMinutes) { + var offset = this._offset || 0, + localAdjust; + if (!this.isValid()) { + return input != null ? this : NaN; + } + if (input != null) { + if (typeof input === 'string') { + input = offsetFromString(matchShortOffset, input); + if (input === null) { + return this; + } + } else if (Math.abs(input) < 16 && !keepMinutes) { + input = input * 60; + } + if (!this._isUTC && keepLocalTime) { + localAdjust = getDateOffset(this); + } + this._offset = input; + this._isUTC = true; + if (localAdjust != null) { + this.add(localAdjust, 'm'); + } + if (offset !== input) { + if (!keepLocalTime || this._changeInProgress) { + addSubtract( + this, + createDuration(input - offset, 'm'), + 1, + false + ); + } else if (!this._changeInProgress) { + this._changeInProgress = true; + hooks.updateOffset(this, true); + this._changeInProgress = null; + } + } + return this; + } else { + return this._isUTC ? offset : getDateOffset(this); + } + } + + function getSetZone(input, keepLocalTime) { + if (input != null) { + if (typeof input !== 'string') { + input = -input; + } + + this.utcOffset(input, keepLocalTime); + + return this; + } else { + return -this.utcOffset(); + } + } + + function setOffsetToUTC(keepLocalTime) { + return this.utcOffset(0, keepLocalTime); + } + + function setOffsetToLocal(keepLocalTime) { + if (this._isUTC) { + this.utcOffset(0, keepLocalTime); + this._isUTC = false; + + if (keepLocalTime) { + this.subtract(getDateOffset(this), 'm'); + } + } + return this; + } + + function setOffsetToParsedOffset() { + if (this._tzm != null) { + this.utcOffset(this._tzm, false, true); + } else if (typeof this._i === 'string') { + var tZone = offsetFromString(matchOffset, this._i); + if (tZone != null) { + this.utcOffset(tZone); + } else { + this.utcOffset(0, true); + } + } + return this; + } + + function hasAlignedHourOffset(input) { + if (!this.isValid()) { + return false; + } + input = input ? createLocal(input).utcOffset() : 0; + + return (this.utcOffset() - input) % 60 === 0; + } + + function isDaylightSavingTime() { + return ( + this.utcOffset() > this.clone().month(0).utcOffset() || + this.utcOffset() > this.clone().month(5).utcOffset() + ); + } + + function isDaylightSavingTimeShifted() { + if (!isUndefined(this._isDSTShifted)) { + return this._isDSTShifted; + } + + var c = {}, + other; + + copyConfig(c, this); + c = prepareConfig(c); + + if (c._a) { + other = c._isUTC ? createUTC(c._a) : createLocal(c._a); + this._isDSTShifted = + this.isValid() && compareArrays(c._a, other.toArray()) > 0; + } else { + this._isDSTShifted = false; + } + + return this._isDSTShifted; + } + + function isLocal() { + return this.isValid() ? !this._isUTC : false; + } + + function isUtcOffset() { + return this.isValid() ? this._isUTC : false; + } + + function isUtc() { + return this.isValid() ? this._isUTC && this._offset === 0 : false; + } + + // ASP.NET json date format regex + var aspNetRegex = /^(-|\+)?(?:(\d*)[. ])?(\d+):(\d+)(?::(\d+)(\.\d*)?)?$/, + // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html + // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere + // and further modified to allow for strings containing both week and day + isoRegex = + /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/; + + function createDuration(input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + diffRes; + + if (isDuration(input)) { + duration = { + ms: input._milliseconds, + d: input._days, + M: input._months, + }; + } else if (isNumber(input) || !isNaN(+input)) { + duration = {}; + if (key) { + duration[key] = +input; + } else { + duration.milliseconds = +input; + } + } else if ((match = aspNetRegex.exec(input))) { + sign = match[1] === '-' ? -1 : 1; + duration = { + y: 0, + d: toInt(match[DATE]) * sign, + h: toInt(match[HOUR]) * sign, + m: toInt(match[MINUTE]) * sign, + s: toInt(match[SECOND]) * sign, + ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign, // the millisecond decimal point is included in the match + }; + } else if ((match = isoRegex.exec(input))) { + sign = match[1] === '-' ? -1 : 1; + duration = { + y: parseIso(match[2], sign), + M: parseIso(match[3], sign), + w: parseIso(match[4], sign), + d: parseIso(match[5], sign), + h: parseIso(match[6], sign), + m: parseIso(match[7], sign), + s: parseIso(match[8], sign), + }; + } else if (duration == null) { + // checks for null or undefined + duration = {}; + } else if ( + typeof duration === 'object' && + ('from' in duration || 'to' in duration) + ) { + diffRes = momentsDifference( + createLocal(duration.from), + createLocal(duration.to) + ); + + duration = {}; + duration.ms = diffRes.milliseconds; + duration.M = diffRes.months; + } + + ret = new Duration(duration); + + if (isDuration(input) && hasOwnProp(input, '_locale')) { + ret._locale = input._locale; + } + + if (isDuration(input) && hasOwnProp(input, '_isValid')) { + ret._isValid = input._isValid; + } + + return ret; + } + + createDuration.fn = Duration.prototype; + createDuration.invalid = createInvalid$1; + + function parseIso(inp, sign) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; + } + + function positiveMomentsDifference(base, other) { + var res = {}; + + res.months = + other.month() - base.month() + (other.year() - base.year()) * 12; + if (base.clone().add(res.months, 'M').isAfter(other)) { + --res.months; + } + + res.milliseconds = +other - +base.clone().add(res.months, 'M'); + + return res; + } + + function momentsDifference(base, other) { + var res; + if (!(base.isValid() && other.isValid())) { + return { milliseconds: 0, months: 0 }; + } + + other = cloneWithOffset(other, base); + if (base.isBefore(other)) { + res = positiveMomentsDifference(base, other); + } else { + res = positiveMomentsDifference(other, base); + res.milliseconds = -res.milliseconds; + res.months = -res.months; + } + + return res; + } + + // TODO: remove 'name' arg after deprecation is removed + function createAdder(direction, name) { + return function (val, period) { + var dur, tmp; + //invert the arguments, but complain about it + if (period !== null && !isNaN(+period)) { + deprecateSimple( + name, + 'moment().' + + name + + '(period, number) is deprecated. Please use moment().' + + name + + '(number, period). ' + + 'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.' + ); + tmp = val; + val = period; + period = tmp; + } + + dur = createDuration(val, period); + addSubtract(this, dur, direction); + return this; + }; + } + + function addSubtract(mom, duration, isAdding, updateOffset) { + var milliseconds = duration._milliseconds, + days = absRound(duration._days), + months = absRound(duration._months); + + if (!mom.isValid()) { + // No op + return; + } + + updateOffset = updateOffset == null ? true : updateOffset; + + if (months) { + setMonth(mom, get(mom, 'Month') + months * isAdding); + } + if (days) { + set$1(mom, 'Date', get(mom, 'Date') + days * isAdding); + } + if (milliseconds) { + mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding); + } + if (updateOffset) { + hooks.updateOffset(mom, days || months); + } + } + + var add = createAdder(1, 'add'), + subtract = createAdder(-1, 'subtract'); + + function isString(input) { + return typeof input === 'string' || input instanceof String; + } + + // type MomentInput = Moment | Date | string | number | (number | string)[] | MomentInputObject | void; // null | undefined + function isMomentInput(input) { + return ( + isMoment(input) || + isDate(input) || + isString(input) || + isNumber(input) || + isNumberOrStringArray(input) || + isMomentInputObject(input) || + input === null || + input === undefined + ); + } + + function isMomentInputObject(input) { + var objectTest = isObject(input) && !isObjectEmpty(input), + propertyTest = false, + properties = [ + 'years', + 'year', + 'y', + 'months', + 'month', + 'M', + 'days', + 'day', + 'd', + 'dates', + 'date', + 'D', + 'hours', + 'hour', + 'h', + 'minutes', + 'minute', + 'm', + 'seconds', + 'second', + 's', + 'milliseconds', + 'millisecond', + 'ms', + ], + i, + property, + propertyLen = properties.length; + + for (i = 0; i < propertyLen; i += 1) { + property = properties[i]; + propertyTest = propertyTest || hasOwnProp(input, property); + } + + return objectTest && propertyTest; + } + + function isNumberOrStringArray(input) { + var arrayTest = isArray(input), + dataTypeTest = false; + if (arrayTest) { + dataTypeTest = + input.filter(function (item) { + return !isNumber(item) && isString(input); + }).length === 0; + } + return arrayTest && dataTypeTest; + } + + function isCalendarSpec(input) { + var objectTest = isObject(input) && !isObjectEmpty(input), + propertyTest = false, + properties = [ + 'sameDay', + 'nextDay', + 'lastDay', + 'nextWeek', + 'lastWeek', + 'sameElse', + ], + i, + property; + + for (i = 0; i < properties.length; i += 1) { + property = properties[i]; + propertyTest = propertyTest || hasOwnProp(input, property); + } + + return objectTest && propertyTest; + } + + function getCalendarFormat(myMoment, now) { + var diff = myMoment.diff(now, 'days', true); + return diff < -6 + ? 'sameElse' + : diff < -1 + ? 'lastWeek' + : diff < 0 + ? 'lastDay' + : diff < 1 + ? 'sameDay' + : diff < 2 + ? 'nextDay' + : diff < 7 + ? 'nextWeek' + : 'sameElse'; + } + + function calendar$1(time, formats) { + // Support for single parameter, formats only overload to the calendar function + if (arguments.length === 1) { + if (!arguments[0]) { + time = undefined; + formats = undefined; + } else if (isMomentInput(arguments[0])) { + time = arguments[0]; + formats = undefined; + } else if (isCalendarSpec(arguments[0])) { + formats = arguments[0]; + time = undefined; + } + } + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're local/utc/offset or not. + var now = time || createLocal(), + sod = cloneWithOffset(now, this).startOf('day'), + format = hooks.calendarFormat(this, sod) || 'sameElse', + output = + formats && + (isFunction(formats[format]) + ? formats[format].call(this, now) + : formats[format]); + + return this.format( + output || this.localeData().calendar(format, this, createLocal(now)) + ); + } + + function clone() { + return new Moment(this); + } + + function isAfter(input, units) { + var localInput = isMoment(input) ? input : createLocal(input); + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(units) || 'millisecond'; + if (units === 'millisecond') { + return this.valueOf() > localInput.valueOf(); + } else { + return localInput.valueOf() < this.clone().startOf(units).valueOf(); + } + } + + function isBefore(input, units) { + var localInput = isMoment(input) ? input : createLocal(input); + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(units) || 'millisecond'; + if (units === 'millisecond') { + return this.valueOf() < localInput.valueOf(); + } else { + return this.clone().endOf(units).valueOf() < localInput.valueOf(); + } + } + + function isBetween(from, to, units, inclusivity) { + var localFrom = isMoment(from) ? from : createLocal(from), + localTo = isMoment(to) ? to : createLocal(to); + if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) { + return false; + } + inclusivity = inclusivity || '()'; + return ( + (inclusivity[0] === '(' + ? this.isAfter(localFrom, units) + : !this.isBefore(localFrom, units)) && + (inclusivity[1] === ')' + ? this.isBefore(localTo, units) + : !this.isAfter(localTo, units)) + ); + } + + function isSame(input, units) { + var localInput = isMoment(input) ? input : createLocal(input), + inputMs; + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(units) || 'millisecond'; + if (units === 'millisecond') { + return this.valueOf() === localInput.valueOf(); + } else { + inputMs = localInput.valueOf(); + return ( + this.clone().startOf(units).valueOf() <= inputMs && + inputMs <= this.clone().endOf(units).valueOf() + ); + } + } + + function isSameOrAfter(input, units) { + return this.isSame(input, units) || this.isAfter(input, units); + } + + function isSameOrBefore(input, units) { + return this.isSame(input, units) || this.isBefore(input, units); + } + + function diff(input, units, asFloat) { + var that, zoneDelta, output; + + if (!this.isValid()) { + return NaN; + } + + that = cloneWithOffset(input, this); + + if (!that.isValid()) { + return NaN; + } + + zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4; + + units = normalizeUnits(units); + + switch (units) { + case 'year': + output = monthDiff(this, that) / 12; + break; + case 'month': + output = monthDiff(this, that); + break; + case 'quarter': + output = monthDiff(this, that) / 3; + break; + case 'second': + output = (this - that) / 1e3; + break; // 1000 + case 'minute': + output = (this - that) / 6e4; + break; // 1000 * 60 + case 'hour': + output = (this - that) / 36e5; + break; // 1000 * 60 * 60 + case 'day': + output = (this - that - zoneDelta) / 864e5; + break; // 1000 * 60 * 60 * 24, negate dst + case 'week': + output = (this - that - zoneDelta) / 6048e5; + break; // 1000 * 60 * 60 * 24 * 7, negate dst + default: + output = this - that; + } + + return asFloat ? output : absFloor(output); + } + + function monthDiff(a, b) { + if (a.date() < b.date()) { + // end-of-month calculations work correct when the start month has more + // days than the end month. + return -monthDiff(b, a); + } + // difference in months + var wholeMonthDiff = (b.year() - a.year()) * 12 + (b.month() - a.month()), + // b is in (anchor - 1 month, anchor + 1 month) + anchor = a.clone().add(wholeMonthDiff, 'months'), + anchor2, + adjust; + + if (b - anchor < 0) { + anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor - anchor2); + } else { + anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor2 - anchor); + } + + //check for negative zero, return zero if negative zero + return -(wholeMonthDiff + adjust) || 0; + } + + hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ'; + hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]'; + + function toString() { + return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); + } + + function toISOString(keepOffset) { + if (!this.isValid()) { + return null; + } + var utc = keepOffset !== true, + m = utc ? this.clone().utc() : this; + if (m.year() < 0 || m.year() > 9999) { + return formatMoment( + m, + utc + ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' + : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ' + ); + } + if (isFunction(Date.prototype.toISOString)) { + // native implementation is ~50x faster, use it when we can + if (utc) { + return this.toDate().toISOString(); + } else { + return new Date(this.valueOf() + this.utcOffset() * 60 * 1000) + .toISOString() + .replace('Z', formatMoment(m, 'Z')); + } + } + return formatMoment( + m, + utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ' + ); + } + + /** + * Return a human readable representation of a moment that can + * also be evaluated to get a new moment which is the same + * + * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects + */ + function inspect() { + if (!this.isValid()) { + return 'moment.invalid(/* ' + this._i + ' */)'; + } + var func = 'moment', + zone = '', + prefix, + year, + datetime, + suffix; + if (!this.isLocal()) { + func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone'; + zone = 'Z'; + } + prefix = '[' + func + '("]'; + year = 0 <= this.year() && this.year() <= 9999 ? 'YYYY' : 'YYYYYY'; + datetime = '-MM-DD[T]HH:mm:ss.SSS'; + suffix = zone + '[")]'; + + return this.format(prefix + year + datetime + suffix); + } + + function format(inputString) { + if (!inputString) { + inputString = this.isUtc() + ? hooks.defaultFormatUtc + : hooks.defaultFormat; + } + var output = formatMoment(this, inputString); + return this.localeData().postformat(output); + } + + function from(time, withoutSuffix) { + if ( + this.isValid() && + ((isMoment(time) && time.isValid()) || createLocal(time).isValid()) + ) { + return createDuration({ to: this, from: time }) + .locale(this.locale()) + .humanize(!withoutSuffix); + } else { + return this.localeData().invalidDate(); + } + } + + function fromNow(withoutSuffix) { + return this.from(createLocal(), withoutSuffix); + } + + function to(time, withoutSuffix) { + if ( + this.isValid() && + ((isMoment(time) && time.isValid()) || createLocal(time).isValid()) + ) { + return createDuration({ from: this, to: time }) + .locale(this.locale()) + .humanize(!withoutSuffix); + } else { + return this.localeData().invalidDate(); + } + } + + function toNow(withoutSuffix) { + return this.to(createLocal(), withoutSuffix); + } + + // If passed a locale key, it will set the locale for this + // instance. Otherwise, it will return the locale configuration + // variables for this instance. + function locale(key) { + var newLocaleData; + + if (key === undefined) { + return this._locale._abbr; + } else { + newLocaleData = getLocale(key); + if (newLocaleData != null) { + this._locale = newLocaleData; + } + return this; + } + } + + var lang = deprecate( + 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', + function (key) { + if (key === undefined) { + return this.localeData(); + } else { + return this.locale(key); + } + } + ); + + function localeData() { + return this._locale; + } + + var MS_PER_SECOND = 1000, + MS_PER_MINUTE = 60 * MS_PER_SECOND, + MS_PER_HOUR = 60 * MS_PER_MINUTE, + MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR; + + // actual modulo - handles negative numbers (for dates before 1970): + function mod$1(dividend, divisor) { + return ((dividend % divisor) + divisor) % divisor; + } + + function localStartOfDate(y, m, d) { + // the date constructor remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0) { + // preserve leap years using a full 400 year cycle, then reset + return new Date(y + 400, m, d) - MS_PER_400_YEARS; + } else { + return new Date(y, m, d).valueOf(); + } + } + + function utcStartOfDate(y, m, d) { + // Date.UTC remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0) { + // preserve leap years using a full 400 year cycle, then reset + return Date.UTC(y + 400, m, d) - MS_PER_400_YEARS; + } else { + return Date.UTC(y, m, d); + } + } + + function startOf(units) { + var time, startOfDate; + units = normalizeUnits(units); + if (units === undefined || units === 'millisecond' || !this.isValid()) { + return this; + } + + startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate; + + switch (units) { + case 'year': + time = startOfDate(this.year(), 0, 1); + break; + case 'quarter': + time = startOfDate( + this.year(), + this.month() - (this.month() % 3), + 1 + ); + break; + case 'month': + time = startOfDate(this.year(), this.month(), 1); + break; + case 'week': + time = startOfDate( + this.year(), + this.month(), + this.date() - this.weekday() + ); + break; + case 'isoWeek': + time = startOfDate( + this.year(), + this.month(), + this.date() - (this.isoWeekday() - 1) + ); + break; + case 'day': + case 'date': + time = startOfDate(this.year(), this.month(), this.date()); + break; + case 'hour': + time = this._d.valueOf(); + time -= mod$1( + time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), + MS_PER_HOUR + ); + break; + case 'minute': + time = this._d.valueOf(); + time -= mod$1(time, MS_PER_MINUTE); + break; + case 'second': + time = this._d.valueOf(); + time -= mod$1(time, MS_PER_SECOND); + break; + } + + this._d.setTime(time); + hooks.updateOffset(this, true); + return this; + } + + function endOf(units) { + var time, startOfDate; + units = normalizeUnits(units); + if (units === undefined || units === 'millisecond' || !this.isValid()) { + return this; + } + + startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate; + + switch (units) { + case 'year': + time = startOfDate(this.year() + 1, 0, 1) - 1; + break; + case 'quarter': + time = + startOfDate( + this.year(), + this.month() - (this.month() % 3) + 3, + 1 + ) - 1; + break; + case 'month': + time = startOfDate(this.year(), this.month() + 1, 1) - 1; + break; + case 'week': + time = + startOfDate( + this.year(), + this.month(), + this.date() - this.weekday() + 7 + ) - 1; + break; + case 'isoWeek': + time = + startOfDate( + this.year(), + this.month(), + this.date() - (this.isoWeekday() - 1) + 7 + ) - 1; + break; + case 'day': + case 'date': + time = startOfDate(this.year(), this.month(), this.date() + 1) - 1; + break; + case 'hour': + time = this._d.valueOf(); + time += + MS_PER_HOUR - + mod$1( + time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), + MS_PER_HOUR + ) - + 1; + break; + case 'minute': + time = this._d.valueOf(); + time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1; + break; + case 'second': + time = this._d.valueOf(); + time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1; + break; + } + + this._d.setTime(time); + hooks.updateOffset(this, true); + return this; + } + + function valueOf() { + return this._d.valueOf() - (this._offset || 0) * 60000; + } + + function unix() { + return Math.floor(this.valueOf() / 1000); + } + + function toDate() { + return new Date(this.valueOf()); + } + + function toArray() { + var m = this; + return [ + m.year(), + m.month(), + m.date(), + m.hour(), + m.minute(), + m.second(), + m.millisecond(), + ]; + } + + function toObject() { + var m = this; + return { + years: m.year(), + months: m.month(), + date: m.date(), + hours: m.hours(), + minutes: m.minutes(), + seconds: m.seconds(), + milliseconds: m.milliseconds(), + }; + } + + function toJSON() { + // new Date(NaN).toJSON() === null + return this.isValid() ? this.toISOString() : null; + } + + function isValid$2() { + return isValid(this); + } + + function parsingFlags() { + return extend({}, getParsingFlags(this)); + } + + function invalidAt() { + return getParsingFlags(this).overflow; + } + + function creationData() { + return { + input: this._i, + format: this._f, + locale: this._locale, + isUTC: this._isUTC, + strict: this._strict, + }; + } + + addFormatToken('N', 0, 0, 'eraAbbr'); + addFormatToken('NN', 0, 0, 'eraAbbr'); + addFormatToken('NNN', 0, 0, 'eraAbbr'); + addFormatToken('NNNN', 0, 0, 'eraName'); + addFormatToken('NNNNN', 0, 0, 'eraNarrow'); + + addFormatToken('y', ['y', 1], 'yo', 'eraYear'); + addFormatToken('y', ['yy', 2], 0, 'eraYear'); + addFormatToken('y', ['yyy', 3], 0, 'eraYear'); + addFormatToken('y', ['yyyy', 4], 0, 'eraYear'); + + addRegexToken('N', matchEraAbbr); + addRegexToken('NN', matchEraAbbr); + addRegexToken('NNN', matchEraAbbr); + addRegexToken('NNNN', matchEraName); + addRegexToken('NNNNN', matchEraNarrow); + + addParseToken( + ['N', 'NN', 'NNN', 'NNNN', 'NNNNN'], + function (input, array, config, token) { + var era = config._locale.erasParse(input, token, config._strict); + if (era) { + getParsingFlags(config).era = era; + } else { + getParsingFlags(config).invalidEra = input; + } + } + ); + + addRegexToken('y', matchUnsigned); + addRegexToken('yy', matchUnsigned); + addRegexToken('yyy', matchUnsigned); + addRegexToken('yyyy', matchUnsigned); + addRegexToken('yo', matchEraYearOrdinal); + + addParseToken(['y', 'yy', 'yyy', 'yyyy'], YEAR); + addParseToken(['yo'], function (input, array, config, token) { + var match; + if (config._locale._eraYearOrdinalRegex) { + match = input.match(config._locale._eraYearOrdinalRegex); + } + + if (config._locale.eraYearOrdinalParse) { + array[YEAR] = config._locale.eraYearOrdinalParse(input, match); + } else { + array[YEAR] = parseInt(input, 10); + } + }); + + function localeEras(m, format) { + var i, + l, + date, + eras = this._eras || getLocale('en')._eras; + for (i = 0, l = eras.length; i < l; ++i) { + switch (typeof eras[i].since) { + case 'string': + // truncate time + date = hooks(eras[i].since).startOf('day'); + eras[i].since = date.valueOf(); + break; + } + + switch (typeof eras[i].until) { + case 'undefined': + eras[i].until = +Infinity; + break; + case 'string': + // truncate time + date = hooks(eras[i].until).startOf('day').valueOf(); + eras[i].until = date.valueOf(); + break; + } + } + return eras; + } + + function localeErasParse(eraName, format, strict) { + var i, + l, + eras = this.eras(), + name, + abbr, + narrow; + eraName = eraName.toUpperCase(); + + for (i = 0, l = eras.length; i < l; ++i) { + name = eras[i].name.toUpperCase(); + abbr = eras[i].abbr.toUpperCase(); + narrow = eras[i].narrow.toUpperCase(); + + if (strict) { + switch (format) { + case 'N': + case 'NN': + case 'NNN': + if (abbr === eraName) { + return eras[i]; + } + break; + + case 'NNNN': + if (name === eraName) { + return eras[i]; + } + break; + + case 'NNNNN': + if (narrow === eraName) { + return eras[i]; + } + break; + } + } else if ([name, abbr, narrow].indexOf(eraName) >= 0) { + return eras[i]; + } + } + } + + function localeErasConvertYear(era, year) { + var dir = era.since <= era.until ? +1 : -1; + if (year === undefined) { + return hooks(era.since).year(); + } else { + return hooks(era.since).year() + (year - era.offset) * dir; + } + } + + function getEraName() { + var i, + l, + val, + eras = this.localeData().eras(); + for (i = 0, l = eras.length; i < l; ++i) { + // truncate time + val = this.clone().startOf('day').valueOf(); + + if (eras[i].since <= val && val <= eras[i].until) { + return eras[i].name; + } + if (eras[i].until <= val && val <= eras[i].since) { + return eras[i].name; + } + } + + return ''; + } + + function getEraNarrow() { + var i, + l, + val, + eras = this.localeData().eras(); + for (i = 0, l = eras.length; i < l; ++i) { + // truncate time + val = this.clone().startOf('day').valueOf(); + + if (eras[i].since <= val && val <= eras[i].until) { + return eras[i].narrow; + } + if (eras[i].until <= val && val <= eras[i].since) { + return eras[i].narrow; + } + } + + return ''; + } + + function getEraAbbr() { + var i, + l, + val, + eras = this.localeData().eras(); + for (i = 0, l = eras.length; i < l; ++i) { + // truncate time + val = this.clone().startOf('day').valueOf(); + + if (eras[i].since <= val && val <= eras[i].until) { + return eras[i].abbr; + } + if (eras[i].until <= val && val <= eras[i].since) { + return eras[i].abbr; + } + } + + return ''; + } + + function getEraYear() { + var i, + l, + dir, + val, + eras = this.localeData().eras(); + for (i = 0, l = eras.length; i < l; ++i) { + dir = eras[i].since <= eras[i].until ? +1 : -1; + + // truncate time + val = this.clone().startOf('day').valueOf(); + + if ( + (eras[i].since <= val && val <= eras[i].until) || + (eras[i].until <= val && val <= eras[i].since) + ) { + return ( + (this.year() - hooks(eras[i].since).year()) * dir + + eras[i].offset + ); + } + } + + return this.year(); + } + + function erasNameRegex(isStrict) { + if (!hasOwnProp(this, '_erasNameRegex')) { + computeErasParse.call(this); + } + return isStrict ? this._erasNameRegex : this._erasRegex; + } + + function erasAbbrRegex(isStrict) { + if (!hasOwnProp(this, '_erasAbbrRegex')) { + computeErasParse.call(this); + } + return isStrict ? this._erasAbbrRegex : this._erasRegex; + } + + function erasNarrowRegex(isStrict) { + if (!hasOwnProp(this, '_erasNarrowRegex')) { + computeErasParse.call(this); + } + return isStrict ? this._erasNarrowRegex : this._erasRegex; + } + + function matchEraAbbr(isStrict, locale) { + return locale.erasAbbrRegex(isStrict); + } + + function matchEraName(isStrict, locale) { + return locale.erasNameRegex(isStrict); + } + + function matchEraNarrow(isStrict, locale) { + return locale.erasNarrowRegex(isStrict); + } + + function matchEraYearOrdinal(isStrict, locale) { + return locale._eraYearOrdinalRegex || matchUnsigned; + } + + function computeErasParse() { + var abbrPieces = [], + namePieces = [], + narrowPieces = [], + mixedPieces = [], + i, + l, + eras = this.eras(); + + for (i = 0, l = eras.length; i < l; ++i) { + namePieces.push(regexEscape(eras[i].name)); + abbrPieces.push(regexEscape(eras[i].abbr)); + narrowPieces.push(regexEscape(eras[i].narrow)); + + mixedPieces.push(regexEscape(eras[i].name)); + mixedPieces.push(regexEscape(eras[i].abbr)); + mixedPieces.push(regexEscape(eras[i].narrow)); + } + + this._erasRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); + this._erasNameRegex = new RegExp('^(' + namePieces.join('|') + ')', 'i'); + this._erasAbbrRegex = new RegExp('^(' + abbrPieces.join('|') + ')', 'i'); + this._erasNarrowRegex = new RegExp( + '^(' + narrowPieces.join('|') + ')', + 'i' + ); + } + + // FORMATTING + + addFormatToken(0, ['gg', 2], 0, function () { + return this.weekYear() % 100; + }); + + addFormatToken(0, ['GG', 2], 0, function () { + return this.isoWeekYear() % 100; + }); + + function addWeekYearFormatToken(token, getter) { + addFormatToken(0, [token, token.length], 0, getter); + } + + addWeekYearFormatToken('gggg', 'weekYear'); + addWeekYearFormatToken('ggggg', 'weekYear'); + addWeekYearFormatToken('GGGG', 'isoWeekYear'); + addWeekYearFormatToken('GGGGG', 'isoWeekYear'); + + // ALIASES + + addUnitAlias('weekYear', 'gg'); + addUnitAlias('isoWeekYear', 'GG'); + + // PRIORITY + + addUnitPriority('weekYear', 1); + addUnitPriority('isoWeekYear', 1); + + // PARSING + + addRegexToken('G', matchSigned); + addRegexToken('g', matchSigned); + addRegexToken('GG', match1to2, match2); + addRegexToken('gg', match1to2, match2); + addRegexToken('GGGG', match1to4, match4); + addRegexToken('gggg', match1to4, match4); + addRegexToken('GGGGG', match1to6, match6); + addRegexToken('ggggg', match1to6, match6); + + addWeekParseToken( + ['gggg', 'ggggg', 'GGGG', 'GGGGG'], + function (input, week, config, token) { + week[token.substr(0, 2)] = toInt(input); + } + ); + + addWeekParseToken(['gg', 'GG'], function (input, week, config, token) { + week[token] = hooks.parseTwoDigitYear(input); + }); + + // MOMENTS + + function getSetWeekYear(input) { + return getSetWeekYearHelper.call( + this, + input, + this.week(), + this.weekday(), + this.localeData()._week.dow, + this.localeData()._week.doy + ); + } + + function getSetISOWeekYear(input) { + return getSetWeekYearHelper.call( + this, + input, + this.isoWeek(), + this.isoWeekday(), + 1, + 4 + ); + } + + function getISOWeeksInYear() { + return weeksInYear(this.year(), 1, 4); + } + + function getISOWeeksInISOWeekYear() { + return weeksInYear(this.isoWeekYear(), 1, 4); + } + + function getWeeksInYear() { + var weekInfo = this.localeData()._week; + return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); + } + + function getWeeksInWeekYear() { + var weekInfo = this.localeData()._week; + return weeksInYear(this.weekYear(), weekInfo.dow, weekInfo.doy); + } + + function getSetWeekYearHelper(input, week, weekday, dow, doy) { + var weeksTarget; + if (input == null) { + return weekOfYear(this, dow, doy).year; + } else { + weeksTarget = weeksInYear(input, dow, doy); + if (week > weeksTarget) { + week = weeksTarget; + } + return setWeekAll.call(this, input, week, weekday, dow, doy); + } + } + + function setWeekAll(weekYear, week, weekday, dow, doy) { + var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy), + date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear); + + this.year(date.getUTCFullYear()); + this.month(date.getUTCMonth()); + this.date(date.getUTCDate()); + return this; + } + + // FORMATTING + + addFormatToken('Q', 0, 'Qo', 'quarter'); + + // ALIASES + + addUnitAlias('quarter', 'Q'); + + // PRIORITY + + addUnitPriority('quarter', 7); + + // PARSING + + addRegexToken('Q', match1); + addParseToken('Q', function (input, array) { + array[MONTH] = (toInt(input) - 1) * 3; + }); + + // MOMENTS + + function getSetQuarter(input) { + return input == null + ? Math.ceil((this.month() + 1) / 3) + : this.month((input - 1) * 3 + (this.month() % 3)); + } + + // FORMATTING + + addFormatToken('D', ['DD', 2], 'Do', 'date'); + + // ALIASES + + addUnitAlias('date', 'D'); + + // PRIORITY + addUnitPriority('date', 9); + + // PARSING + + addRegexToken('D', match1to2); + addRegexToken('DD', match1to2, match2); + addRegexToken('Do', function (isStrict, locale) { + // TODO: Remove "ordinalParse" fallback in next major release. + return isStrict + ? locale._dayOfMonthOrdinalParse || locale._ordinalParse + : locale._dayOfMonthOrdinalParseLenient; + }); + + addParseToken(['D', 'DD'], DATE); + addParseToken('Do', function (input, array) { + array[DATE] = toInt(input.match(match1to2)[0]); + }); + + // MOMENTS + + var getSetDayOfMonth = makeGetSet('Date', true); + + // FORMATTING + + addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); + + // ALIASES + + addUnitAlias('dayOfYear', 'DDD'); + + // PRIORITY + addUnitPriority('dayOfYear', 4); + + // PARSING + + addRegexToken('DDD', match1to3); + addRegexToken('DDDD', match3); + addParseToken(['DDD', 'DDDD'], function (input, array, config) { + config._dayOfYear = toInt(input); + }); + + // HELPERS + + // MOMENTS + + function getSetDayOfYear(input) { + var dayOfYear = + Math.round( + (this.clone().startOf('day') - this.clone().startOf('year')) / 864e5 + ) + 1; + return input == null ? dayOfYear : this.add(input - dayOfYear, 'd'); + } + + // FORMATTING + + addFormatToken('m', ['mm', 2], 0, 'minute'); + + // ALIASES + + addUnitAlias('minute', 'm'); + + // PRIORITY + + addUnitPriority('minute', 14); + + // PARSING + + addRegexToken('m', match1to2); + addRegexToken('mm', match1to2, match2); + addParseToken(['m', 'mm'], MINUTE); + + // MOMENTS + + var getSetMinute = makeGetSet('Minutes', false); + + // FORMATTING + + addFormatToken('s', ['ss', 2], 0, 'second'); + + // ALIASES + + addUnitAlias('second', 's'); + + // PRIORITY + + addUnitPriority('second', 15); + + // PARSING + + addRegexToken('s', match1to2); + addRegexToken('ss', match1to2, match2); + addParseToken(['s', 'ss'], SECOND); + + // MOMENTS + + var getSetSecond = makeGetSet('Seconds', false); + + // FORMATTING + + addFormatToken('S', 0, 0, function () { + return ~~(this.millisecond() / 100); + }); + + addFormatToken(0, ['SS', 2], 0, function () { + return ~~(this.millisecond() / 10); + }); + + addFormatToken(0, ['SSS', 3], 0, 'millisecond'); + addFormatToken(0, ['SSSS', 4], 0, function () { + return this.millisecond() * 10; + }); + addFormatToken(0, ['SSSSS', 5], 0, function () { + return this.millisecond() * 100; + }); + addFormatToken(0, ['SSSSSS', 6], 0, function () { + return this.millisecond() * 1000; + }); + addFormatToken(0, ['SSSSSSS', 7], 0, function () { + return this.millisecond() * 10000; + }); + addFormatToken(0, ['SSSSSSSS', 8], 0, function () { + return this.millisecond() * 100000; + }); + addFormatToken(0, ['SSSSSSSSS', 9], 0, function () { + return this.millisecond() * 1000000; + }); + + // ALIASES + + addUnitAlias('millisecond', 'ms'); + + // PRIORITY + + addUnitPriority('millisecond', 16); + + // PARSING + + addRegexToken('S', match1to3, match1); + addRegexToken('SS', match1to3, match2); + addRegexToken('SSS', match1to3, match3); + + var token, getSetMillisecond; + for (token = 'SSSS'; token.length <= 9; token += 'S') { + addRegexToken(token, matchUnsigned); + } + + function parseMs(input, array) { + array[MILLISECOND] = toInt(('0.' + input) * 1000); + } + + for (token = 'S'; token.length <= 9; token += 'S') { + addParseToken(token, parseMs); + } + + getSetMillisecond = makeGetSet('Milliseconds', false); + + // FORMATTING + + addFormatToken('z', 0, 0, 'zoneAbbr'); + addFormatToken('zz', 0, 0, 'zoneName'); + + // MOMENTS + + function getZoneAbbr() { + return this._isUTC ? 'UTC' : ''; + } + + function getZoneName() { + return this._isUTC ? 'Coordinated Universal Time' : ''; + } + + var proto = Moment.prototype; + + proto.add = add; + proto.calendar = calendar$1; + proto.clone = clone; + proto.diff = diff; + proto.endOf = endOf; + proto.format = format; + proto.from = from; + proto.fromNow = fromNow; + proto.to = to; + proto.toNow = toNow; + proto.get = stringGet; + proto.invalidAt = invalidAt; + proto.isAfter = isAfter; + proto.isBefore = isBefore; + proto.isBetween = isBetween; + proto.isSame = isSame; + proto.isSameOrAfter = isSameOrAfter; + proto.isSameOrBefore = isSameOrBefore; + proto.isValid = isValid$2; + proto.lang = lang; + proto.locale = locale; + proto.localeData = localeData; + proto.max = prototypeMax; + proto.min = prototypeMin; + proto.parsingFlags = parsingFlags; + proto.set = stringSet; + proto.startOf = startOf; + proto.subtract = subtract; + proto.toArray = toArray; + proto.toObject = toObject; + proto.toDate = toDate; + proto.toISOString = toISOString; + proto.inspect = inspect; + if (typeof Symbol !== 'undefined' && Symbol.for != null) { + proto[Symbol.for('nodejs.util.inspect.custom')] = function () { + return 'Moment<' + this.format() + '>'; + }; + } + proto.toJSON = toJSON; + proto.toString = toString; + proto.unix = unix; + proto.valueOf = valueOf; + proto.creationData = creationData; + proto.eraName = getEraName; + proto.eraNarrow = getEraNarrow; + proto.eraAbbr = getEraAbbr; + proto.eraYear = getEraYear; + proto.year = getSetYear; + proto.isLeapYear = getIsLeapYear; + proto.weekYear = getSetWeekYear; + proto.isoWeekYear = getSetISOWeekYear; + proto.quarter = proto.quarters = getSetQuarter; + proto.month = getSetMonth; + proto.daysInMonth = getDaysInMonth; + proto.week = proto.weeks = getSetWeek; + proto.isoWeek = proto.isoWeeks = getSetISOWeek; + proto.weeksInYear = getWeeksInYear; + proto.weeksInWeekYear = getWeeksInWeekYear; + proto.isoWeeksInYear = getISOWeeksInYear; + proto.isoWeeksInISOWeekYear = getISOWeeksInISOWeekYear; + proto.date = getSetDayOfMonth; + proto.day = proto.days = getSetDayOfWeek; + proto.weekday = getSetLocaleDayOfWeek; + proto.isoWeekday = getSetISODayOfWeek; + proto.dayOfYear = getSetDayOfYear; + proto.hour = proto.hours = getSetHour; + proto.minute = proto.minutes = getSetMinute; + proto.second = proto.seconds = getSetSecond; + proto.millisecond = proto.milliseconds = getSetMillisecond; + proto.utcOffset = getSetOffset; + proto.utc = setOffsetToUTC; + proto.local = setOffsetToLocal; + proto.parseZone = setOffsetToParsedOffset; + proto.hasAlignedHourOffset = hasAlignedHourOffset; + proto.isDST = isDaylightSavingTime; + proto.isLocal = isLocal; + proto.isUtcOffset = isUtcOffset; + proto.isUtc = isUtc; + proto.isUTC = isUtc; + proto.zoneAbbr = getZoneAbbr; + proto.zoneName = getZoneName; + proto.dates = deprecate( + 'dates accessor is deprecated. Use date instead.', + getSetDayOfMonth + ); + proto.months = deprecate( + 'months accessor is deprecated. Use month instead', + getSetMonth + ); + proto.years = deprecate( + 'years accessor is deprecated. Use year instead', + getSetYear + ); + proto.zone = deprecate( + 'moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', + getSetZone + ); + proto.isDSTShifted = deprecate( + 'isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', + isDaylightSavingTimeShifted + ); + + function createUnix(input) { + return createLocal(input * 1000); + } + + function createInZone() { + return createLocal.apply(null, arguments).parseZone(); + } + + function preParsePostFormat(string) { + return string; + } + + var proto$1 = Locale.prototype; + + proto$1.calendar = calendar; + proto$1.longDateFormat = longDateFormat; + proto$1.invalidDate = invalidDate; + proto$1.ordinal = ordinal; + proto$1.preparse = preParsePostFormat; + proto$1.postformat = preParsePostFormat; + proto$1.relativeTime = relativeTime; + proto$1.pastFuture = pastFuture; + proto$1.set = set; + proto$1.eras = localeEras; + proto$1.erasParse = localeErasParse; + proto$1.erasConvertYear = localeErasConvertYear; + proto$1.erasAbbrRegex = erasAbbrRegex; + proto$1.erasNameRegex = erasNameRegex; + proto$1.erasNarrowRegex = erasNarrowRegex; + + proto$1.months = localeMonths; + proto$1.monthsShort = localeMonthsShort; + proto$1.monthsParse = localeMonthsParse; + proto$1.monthsRegex = monthsRegex; + proto$1.monthsShortRegex = monthsShortRegex; + proto$1.week = localeWeek; + proto$1.firstDayOfYear = localeFirstDayOfYear; + proto$1.firstDayOfWeek = localeFirstDayOfWeek; + + proto$1.weekdays = localeWeekdays; + proto$1.weekdaysMin = localeWeekdaysMin; + proto$1.weekdaysShort = localeWeekdaysShort; + proto$1.weekdaysParse = localeWeekdaysParse; + + proto$1.weekdaysRegex = weekdaysRegex; + proto$1.weekdaysShortRegex = weekdaysShortRegex; + proto$1.weekdaysMinRegex = weekdaysMinRegex; + + proto$1.isPM = localeIsPM; + proto$1.meridiem = localeMeridiem; + + function get$1(format, index, field, setter) { + var locale = getLocale(), + utc = createUTC().set(setter, index); + return locale[field](utc, format); + } + + function listMonthsImpl(format, index, field) { + if (isNumber(format)) { + index = format; + format = undefined; + } + + format = format || ''; + + if (index != null) { + return get$1(format, index, field, 'month'); + } + + var i, + out = []; + for (i = 0; i < 12; i++) { + out[i] = get$1(format, i, field, 'month'); + } + return out; + } + + // () + // (5) + // (fmt, 5) + // (fmt) + // (true) + // (true, 5) + // (true, fmt, 5) + // (true, fmt) + function listWeekdaysImpl(localeSorted, format, index, field) { + if (typeof localeSorted === 'boolean') { + if (isNumber(format)) { + index = format; + format = undefined; + } + + format = format || ''; + } else { + format = localeSorted; + index = format; + localeSorted = false; + + if (isNumber(format)) { + index = format; + format = undefined; + } + + format = format || ''; + } + + var locale = getLocale(), + shift = localeSorted ? locale._week.dow : 0, + i, + out = []; + + if (index != null) { + return get$1(format, (index + shift) % 7, field, 'day'); + } + + for (i = 0; i < 7; i++) { + out[i] = get$1(format, (i + shift) % 7, field, 'day'); + } + return out; + } + + function listMonths(format, index) { + return listMonthsImpl(format, index, 'months'); + } + + function listMonthsShort(format, index) { + return listMonthsImpl(format, index, 'monthsShort'); + } + + function listWeekdays(localeSorted, format, index) { + return listWeekdaysImpl(localeSorted, format, index, 'weekdays'); + } + + function listWeekdaysShort(localeSorted, format, index) { + return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort'); + } + + function listWeekdaysMin(localeSorted, format, index) { + return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin'); + } + + getSetGlobalLocale('en', { + eras: [ + { + since: '0001-01-01', + until: +Infinity, + offset: 1, + name: 'Anno Domini', + narrow: 'AD', + abbr: 'AD', + }, + { + since: '0000-12-31', + until: -Infinity, + offset: 1, + name: 'Before Christ', + narrow: 'BC', + abbr: 'BC', + }, + ], + dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/, + ordinal: function (number) { + var b = number % 10, + output = + toInt((number % 100) / 10) === 1 + ? 'th' + : b === 1 + ? 'st' + : b === 2 + ? 'nd' + : b === 3 + ? 'rd' + : 'th'; + return number + output; + }, + }); + + // Side effect imports + + hooks.lang = deprecate( + 'moment.lang is deprecated. Use moment.locale instead.', + getSetGlobalLocale + ); + hooks.langData = deprecate( + 'moment.langData is deprecated. Use moment.localeData instead.', + getLocale + ); + + var mathAbs = Math.abs; + + function abs() { + var data = this._data; + + this._milliseconds = mathAbs(this._milliseconds); + this._days = mathAbs(this._days); + this._months = mathAbs(this._months); + + data.milliseconds = mathAbs(data.milliseconds); + data.seconds = mathAbs(data.seconds); + data.minutes = mathAbs(data.minutes); + data.hours = mathAbs(data.hours); + data.months = mathAbs(data.months); + data.years = mathAbs(data.years); + + return this; + } + + function addSubtract$1(duration, input, value, direction) { + var other = createDuration(input, value); + + duration._milliseconds += direction * other._milliseconds; + duration._days += direction * other._days; + duration._months += direction * other._months; + + return duration._bubble(); + } + + // supports only 2.0-style add(1, 's') or add(duration) + function add$1(input, value) { + return addSubtract$1(this, input, value, 1); + } + + // supports only 2.0-style subtract(1, 's') or subtract(duration) + function subtract$1(input, value) { + return addSubtract$1(this, input, value, -1); + } + + function absCeil(number) { + if (number < 0) { + return Math.floor(number); + } else { + return Math.ceil(number); + } + } + + function bubble() { + var milliseconds = this._milliseconds, + days = this._days, + months = this._months, + data = this._data, + seconds, + minutes, + hours, + years, + monthsFromDays; + + // if we have a mix of positive and negative values, bubble down first + // check: https://github.com/moment/moment/issues/2166 + if ( + !( + (milliseconds >= 0 && days >= 0 && months >= 0) || + (milliseconds <= 0 && days <= 0 && months <= 0) + ) + ) { + milliseconds += absCeil(monthsToDays(months) + days) * 864e5; + days = 0; + months = 0; + } + + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; + + seconds = absFloor(milliseconds / 1000); + data.seconds = seconds % 60; + + minutes = absFloor(seconds / 60); + data.minutes = minutes % 60; + + hours = absFloor(minutes / 60); + data.hours = hours % 24; + + days += absFloor(hours / 24); + + // convert days to months + monthsFromDays = absFloor(daysToMonths(days)); + months += monthsFromDays; + days -= absCeil(monthsToDays(monthsFromDays)); + + // 12 months -> 1 year + years = absFloor(months / 12); + months %= 12; + + data.days = days; + data.months = months; + data.years = years; + + return this; + } + + function daysToMonths(days) { + // 400 years have 146097 days (taking into account leap year rules) + // 400 years have 12 months === 4800 + return (days * 4800) / 146097; + } + + function monthsToDays(months) { + // the reverse of daysToMonths + return (months * 146097) / 4800; + } + + function as(units) { + if (!this.isValid()) { + return NaN; + } + var days, + months, + milliseconds = this._milliseconds; + + units = normalizeUnits(units); + + if (units === 'month' || units === 'quarter' || units === 'year') { + days = this._days + milliseconds / 864e5; + months = this._months + daysToMonths(days); + switch (units) { + case 'month': + return months; + case 'quarter': + return months / 3; + case 'year': + return months / 12; + } + } else { + // handle milliseconds separately because of floating point math errors (issue #1867) + days = this._days + Math.round(monthsToDays(this._months)); + switch (units) { + case 'week': + return days / 7 + milliseconds / 6048e5; + case 'day': + return days + milliseconds / 864e5; + case 'hour': + return days * 24 + milliseconds / 36e5; + case 'minute': + return days * 1440 + milliseconds / 6e4; + case 'second': + return days * 86400 + milliseconds / 1000; + // Math.floor prevents floating point math errors here + case 'millisecond': + return Math.floor(days * 864e5) + milliseconds; + default: + throw new Error('Unknown unit ' + units); + } + } + } + + // TODO: Use this.as('ms')? + function valueOf$1() { + if (!this.isValid()) { + return NaN; + } + return ( + this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6 + ); + } + + function makeAs(alias) { + return function () { + return this.as(alias); + }; + } + + var asMilliseconds = makeAs('ms'), + asSeconds = makeAs('s'), + asMinutes = makeAs('m'), + asHours = makeAs('h'), + asDays = makeAs('d'), + asWeeks = makeAs('w'), + asMonths = makeAs('M'), + asQuarters = makeAs('Q'), + asYears = makeAs('y'); + + function clone$1() { + return createDuration(this); + } + + function get$2(units) { + units = normalizeUnits(units); + return this.isValid() ? this[units + 's']() : NaN; + } + + function makeGetter(name) { + return function () { + return this.isValid() ? this._data[name] : NaN; + }; + } + + var milliseconds = makeGetter('milliseconds'), + seconds = makeGetter('seconds'), + minutes = makeGetter('minutes'), + hours = makeGetter('hours'), + days = makeGetter('days'), + months = makeGetter('months'), + years = makeGetter('years'); + + function weeks() { + return absFloor(this.days() / 7); + } + + var round = Math.round, + thresholds = { + ss: 44, // a few seconds to seconds + s: 45, // seconds to minute + m: 45, // minutes to hour + h: 22, // hours to day + d: 26, // days to month/week + w: null, // weeks to month + M: 11, // months to year + }; + + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { + return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); + } + + function relativeTime$1(posNegDuration, withoutSuffix, thresholds, locale) { + var duration = createDuration(posNegDuration).abs(), + seconds = round(duration.as('s')), + minutes = round(duration.as('m')), + hours = round(duration.as('h')), + days = round(duration.as('d')), + months = round(duration.as('M')), + weeks = round(duration.as('w')), + years = round(duration.as('y')), + a = + (seconds <= thresholds.ss && ['s', seconds]) || + (seconds < thresholds.s && ['ss', seconds]) || + (minutes <= 1 && ['m']) || + (minutes < thresholds.m && ['mm', minutes]) || + (hours <= 1 && ['h']) || + (hours < thresholds.h && ['hh', hours]) || + (days <= 1 && ['d']) || + (days < thresholds.d && ['dd', days]); + + if (thresholds.w != null) { + a = + a || + (weeks <= 1 && ['w']) || + (weeks < thresholds.w && ['ww', weeks]); + } + a = a || + (months <= 1 && ['M']) || + (months < thresholds.M && ['MM', months]) || + (years <= 1 && ['y']) || ['yy', years]; + + a[2] = withoutSuffix; + a[3] = +posNegDuration > 0; + a[4] = locale; + return substituteTimeAgo.apply(null, a); + } + + // This function allows you to set the rounding function for relative time strings + function getSetRelativeTimeRounding(roundingFunction) { + if (roundingFunction === undefined) { + return round; + } + if (typeof roundingFunction === 'function') { + round = roundingFunction; + return true; + } + return false; + } + + // This function allows you to set a threshold for relative time strings + function getSetRelativeTimeThreshold(threshold, limit) { + if (thresholds[threshold] === undefined) { + return false; + } + if (limit === undefined) { + return thresholds[threshold]; + } + thresholds[threshold] = limit; + if (threshold === 's') { + thresholds.ss = limit - 1; + } + return true; + } + + function humanize(argWithSuffix, argThresholds) { + if (!this.isValid()) { + return this.localeData().invalidDate(); + } + + var withSuffix = false, + th = thresholds, + locale, + output; + + if (typeof argWithSuffix === 'object') { + argThresholds = argWithSuffix; + argWithSuffix = false; + } + if (typeof argWithSuffix === 'boolean') { + withSuffix = argWithSuffix; + } + if (typeof argThresholds === 'object') { + th = Object.assign({}, thresholds, argThresholds); + if (argThresholds.s != null && argThresholds.ss == null) { + th.ss = argThresholds.s - 1; + } + } + + locale = this.localeData(); + output = relativeTime$1(this, !withSuffix, th, locale); + + if (withSuffix) { + output = locale.pastFuture(+this, output); + } + + return locale.postformat(output); + } + + var abs$1 = Math.abs; + + function sign(x) { + return (x > 0) - (x < 0) || +x; + } + + function toISOString$1() { + // for ISO strings we do not use the normal bubbling rules: + // * milliseconds bubble up until they become hours + // * days do not bubble at all + // * months bubble up until they become years + // This is because there is no context-free conversion between hours and days + // (think of clock changes) + // and also not between days and months (28-31 days per month) + if (!this.isValid()) { + return this.localeData().invalidDate(); + } + + var seconds = abs$1(this._milliseconds) / 1000, + days = abs$1(this._days), + months = abs$1(this._months), + minutes, + hours, + years, + s, + total = this.asSeconds(), + totalSign, + ymSign, + daysSign, + hmsSign; + + if (!total) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; + } + + // 3600 seconds -> 60 minutes -> 1 hour + minutes = absFloor(seconds / 60); + hours = absFloor(minutes / 60); + seconds %= 60; + minutes %= 60; + + // 12 months -> 1 year + years = absFloor(months / 12); + months %= 12; + + // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js + s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : ''; + + totalSign = total < 0 ? '-' : ''; + ymSign = sign(this._months) !== sign(total) ? '-' : ''; + daysSign = sign(this._days) !== sign(total) ? '-' : ''; + hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : ''; + + return ( + totalSign + + 'P' + + (years ? ymSign + years + 'Y' : '') + + (months ? ymSign + months + 'M' : '') + + (days ? daysSign + days + 'D' : '') + + (hours || minutes || seconds ? 'T' : '') + + (hours ? hmsSign + hours + 'H' : '') + + (minutes ? hmsSign + minutes + 'M' : '') + + (seconds ? hmsSign + s + 'S' : '') + ); + } + + var proto$2 = Duration.prototype; + + proto$2.isValid = isValid$1; + proto$2.abs = abs; + proto$2.add = add$1; + proto$2.subtract = subtract$1; + proto$2.as = as; + proto$2.asMilliseconds = asMilliseconds; + proto$2.asSeconds = asSeconds; + proto$2.asMinutes = asMinutes; + proto$2.asHours = asHours; + proto$2.asDays = asDays; + proto$2.asWeeks = asWeeks; + proto$2.asMonths = asMonths; + proto$2.asQuarters = asQuarters; + proto$2.asYears = asYears; + proto$2.valueOf = valueOf$1; + proto$2._bubble = bubble; + proto$2.clone = clone$1; + proto$2.get = get$2; + proto$2.milliseconds = milliseconds; + proto$2.seconds = seconds; + proto$2.minutes = minutes; + proto$2.hours = hours; + proto$2.days = days; + proto$2.weeks = weeks; + proto$2.months = months; + proto$2.years = years; + proto$2.humanize = humanize; + proto$2.toISOString = toISOString$1; + proto$2.toString = toISOString$1; + proto$2.toJSON = toISOString$1; + proto$2.locale = locale; + proto$2.localeData = localeData; + + proto$2.toIsoString = deprecate( + 'toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', + toISOString$1 + ); + proto$2.lang = lang; + + // FORMATTING + + addFormatToken('X', 0, 0, 'unix'); + addFormatToken('x', 0, 0, 'valueOf'); + + // PARSING + + addRegexToken('x', matchSigned); + addRegexToken('X', matchTimestamp); + addParseToken('X', function (input, array, config) { + config._d = new Date(parseFloat(input) * 1000); + }); + addParseToken('x', function (input, array, config) { + config._d = new Date(toInt(input)); + }); + + //! moment.js + + hooks.version = '2.29.4'; + + setHookCallback(createLocal); + + hooks.fn = proto; + hooks.min = min; + hooks.max = max; + hooks.now = now; + hooks.utc = createUTC; + hooks.unix = createUnix; + hooks.months = listMonths; + hooks.isDate = isDate; + hooks.locale = getSetGlobalLocale; + hooks.invalid = createInvalid; + hooks.duration = createDuration; + hooks.isMoment = isMoment; + hooks.weekdays = listWeekdays; + hooks.parseZone = createInZone; + hooks.localeData = getLocale; + hooks.isDuration = isDuration; + hooks.monthsShort = listMonthsShort; + hooks.weekdaysMin = listWeekdaysMin; + hooks.defineLocale = defineLocale; + hooks.updateLocale = updateLocale; + hooks.locales = listLocales; + hooks.weekdaysShort = listWeekdaysShort; + hooks.normalizeUnits = normalizeUnits; + hooks.relativeTimeRounding = getSetRelativeTimeRounding; + hooks.relativeTimeThreshold = getSetRelativeTimeThreshold; + hooks.calendarFormat = getCalendarFormat; + hooks.prototype = proto; + + // currently HTML5 input type only supports 24-hour formats + hooks.HTML5_FMT = { + DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm', // + DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss', // + DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS', // + DATE: 'YYYY-MM-DD', // + TIME: 'HH:mm', // + TIME_SECONDS: 'HH:mm:ss', // + TIME_MS: 'HH:mm:ss.SSS', // + WEEK: 'GGGG-[W]WW', // + MONTH: 'YYYY-MM', // + }; + + return hooks; + +}))); +}); + +const MATCH_HTML_COMMENT = new RegExp(")?" + + "a--->2 Outer + * / \ + * 8 3 + * | | + * | | + * 7 4 + * \ / + * 6<---b<---5 Inner + */ function pathArc(ctx, element, offset, spacing, end, circular) { + const { x , y , startAngle: start , pixelMargin , innerRadius: innerR } = element; + const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0); + const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0; + let spacingOffset = 0; + const alpha = end - start; + if (spacing) { + // When spacing is present, it is the same for all items + // So we adjust the start and end angle of the arc such that + // the distance is the same as it would be without the spacing + const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0; + const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0; + const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2; + const adjustedAngle = avNogSpacingRadius !== 0 ? alpha * avNogSpacingRadius / (avNogSpacingRadius + spacing) : alpha; + spacingOffset = (alpha - adjustedAngle) / 2; + } + const beta = Math.max(0.001, alpha * outerRadius - offset / PI) / outerRadius; + const angleOffset = (alpha - beta) / 2; + const startAngle = start + angleOffset + spacingOffset; + const endAngle = end - angleOffset - spacingOffset; + const { outerStart , outerEnd , innerStart , innerEnd } = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle); + const outerStartAdjustedRadius = outerRadius - outerStart; + const outerEndAdjustedRadius = outerRadius - outerEnd; + const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius; + const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius; + const innerStartAdjustedRadius = innerRadius + innerStart; + const innerEndAdjustedRadius = innerRadius + innerEnd; + const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius; + const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius; + ctx.beginPath(); + if (circular) { + // The first arc segments from point 1 to point a to point 2 + const outerMidAdjustedAngle = (outerStartAdjustedAngle + outerEndAdjustedAngle) / 2; + ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerMidAdjustedAngle); + ctx.arc(x, y, outerRadius, outerMidAdjustedAngle, outerEndAdjustedAngle); + // The corner segment from point 2 to point 3 + if (outerEnd > 0) { + const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y); + ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + HALF_PI); + } + // The line from point 3 to point 4 + const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y); + ctx.lineTo(p4.x, p4.y); + // The corner segment from point 4 to point 5 + if (innerEnd > 0) { + const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y); + ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + HALF_PI, innerEndAdjustedAngle + Math.PI); + } + // The inner arc from point 5 to point b to point 6 + const innerMidAdjustedAngle = (endAngle - innerEnd / innerRadius + (startAngle + innerStart / innerRadius)) / 2; + ctx.arc(x, y, innerRadius, endAngle - innerEnd / innerRadius, innerMidAdjustedAngle, true); + ctx.arc(x, y, innerRadius, innerMidAdjustedAngle, startAngle + innerStart / innerRadius, true); + // The corner segment from point 6 to point 7 + if (innerStart > 0) { + const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y); + ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - HALF_PI); + } + // The line from point 7 to point 8 + const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y); + ctx.lineTo(p8.x, p8.y); + // The corner segment from point 8 to point 1 + if (outerStart > 0) { + const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y); + ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - HALF_PI, outerStartAdjustedAngle); + } + } else { + ctx.moveTo(x, y); + const outerStartX = Math.cos(outerStartAdjustedAngle) * outerRadius + x; + const outerStartY = Math.sin(outerStartAdjustedAngle) * outerRadius + y; + ctx.lineTo(outerStartX, outerStartY); + const outerEndX = Math.cos(outerEndAdjustedAngle) * outerRadius + x; + const outerEndY = Math.sin(outerEndAdjustedAngle) * outerRadius + y; + ctx.lineTo(outerEndX, outerEndY); + } + ctx.closePath(); +} +function drawArc(ctx, element, offset, spacing, circular) { + const { fullCircles , startAngle , circumference } = element; + let endAngle = element.endAngle; + if (fullCircles) { + pathArc(ctx, element, offset, spacing, endAngle, circular); + for(let i = 0; i < fullCircles; ++i){ + ctx.fill(); + } + if (!isNaN(circumference)) { + endAngle = startAngle + (circumference % TAU || TAU); + } + } + pathArc(ctx, element, offset, spacing, endAngle, circular); + ctx.fill(); + return endAngle; +} +function drawBorder(ctx, element, offset, spacing, circular) { + const { fullCircles , startAngle , circumference , options } = element; + const { borderWidth , borderJoinStyle , borderDash , borderDashOffset } = options; + const inner = options.borderAlign === 'inner'; + if (!borderWidth) { + return; + } + ctx.setLineDash(borderDash || []); + ctx.lineDashOffset = borderDashOffset; + if (inner) { + ctx.lineWidth = borderWidth * 2; + ctx.lineJoin = borderJoinStyle || 'round'; + } else { + ctx.lineWidth = borderWidth; + ctx.lineJoin = borderJoinStyle || 'bevel'; + } + let endAngle = element.endAngle; + if (fullCircles) { + pathArc(ctx, element, offset, spacing, endAngle, circular); + for(let i = 0; i < fullCircles; ++i){ + ctx.stroke(); + } + if (!isNaN(circumference)) { + endAngle = startAngle + (circumference % TAU || TAU); + } + } + if (inner) { + clipArc(ctx, element, endAngle); + } + if (!fullCircles) { + pathArc(ctx, element, offset, spacing, endAngle, circular); + ctx.stroke(); + } +} +class ArcElement extends Element { + static id = 'arc'; + static defaults = { + borderAlign: 'center', + borderColor: '#fff', + borderDash: [], + borderDashOffset: 0, + borderJoinStyle: undefined, + borderRadius: 0, + borderWidth: 2, + offset: 0, + spacing: 0, + angle: undefined, + circular: true + }; + static defaultRoutes = { + backgroundColor: 'backgroundColor' + }; + static descriptors = { + _scriptable: true, + _indexable: (name)=>name !== 'borderDash' + }; + circumference; + endAngle; + fullCircles; + innerRadius; + outerRadius; + pixelMargin; + startAngle; + constructor(cfg){ + super(); + this.options = undefined; + this.circumference = undefined; + this.startAngle = undefined; + this.endAngle = undefined; + this.innerRadius = undefined; + this.outerRadius = undefined; + this.pixelMargin = 0; + this.fullCircles = 0; + if (cfg) { + Object.assign(this, cfg); + } + } + inRange(chartX, chartY, useFinalPosition) { + const point = this.getProps([ + 'x', + 'y' + ], useFinalPosition); + const { angle , distance } = getAngleFromPoint(point, { + x: chartX, + y: chartY + }); + const { startAngle , endAngle , innerRadius , outerRadius , circumference } = this.getProps([ + 'startAngle', + 'endAngle', + 'innerRadius', + 'outerRadius', + 'circumference' + ], useFinalPosition); + const rAdjust = (this.options.spacing + this.options.borderWidth) / 2; + const _circumference = valueOrDefault(circumference, endAngle - startAngle); + const betweenAngles = _circumference >= TAU || _angleBetween(angle, startAngle, endAngle); + const withinRadius = _isBetween(distance, innerRadius + rAdjust, outerRadius + rAdjust); + return betweenAngles && withinRadius; + } + getCenterPoint(useFinalPosition) { + const { x , y , startAngle , endAngle , innerRadius , outerRadius } = this.getProps([ + 'x', + 'y', + 'startAngle', + 'endAngle', + 'innerRadius', + 'outerRadius' + ], useFinalPosition); + const { offset , spacing } = this.options; + const halfAngle = (startAngle + endAngle) / 2; + const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2; + return { + x: x + Math.cos(halfAngle) * halfRadius, + y: y + Math.sin(halfAngle) * halfRadius + }; + } + tooltipPosition(useFinalPosition) { + return this.getCenterPoint(useFinalPosition); + } + draw(ctx) { + const { options , circumference } = this; + const offset = (options.offset || 0) / 4; + const spacing = (options.spacing || 0) / 2; + const circular = options.circular; + this.pixelMargin = options.borderAlign === 'inner' ? 0.33 : 0; + this.fullCircles = circumference > TAU ? Math.floor(circumference / TAU) : 0; + if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) { + return; + } + ctx.save(); + const halfAngle = (this.startAngle + this.endAngle) / 2; + ctx.translate(Math.cos(halfAngle) * offset, Math.sin(halfAngle) * offset); + const fix = 1 - Math.sin(Math.min(PI, circumference || 0)); + const radiusOffset = offset * fix; + ctx.fillStyle = options.backgroundColor; + ctx.strokeStyle = options.borderColor; + drawArc(ctx, this, radiusOffset, spacing, circular); + drawBorder(ctx, this, radiusOffset, spacing, circular); + ctx.restore(); + } +} + +const positioners = { + average (items) { + if (!items.length) { + return false; + } + let i, len; + let x = 0; + let y = 0; + let count = 0; + for(i = 0, len = items.length; i < len; ++i){ + const el = items[i].element; + if (el && el.hasValue()) { + const pos = el.tooltipPosition(); + x += pos.x; + y += pos.y; + ++count; + } + } + return { + x: x / count, + y: y / count + }; + }, + nearest (items, eventPosition) { + if (!items.length) { + return false; + } + let x = eventPosition.x; + let y = eventPosition.y; + let minDistance = Number.POSITIVE_INFINITY; + let i, len, nearestElement; + for(i = 0, len = items.length; i < len; ++i){ + const el = items[i].element; + if (el && el.hasValue()) { + const center = el.getCenterPoint(); + const d = distanceBetweenPoints(eventPosition, center); + if (d < minDistance) { + minDistance = d; + nearestElement = el; + } + } + } + if (nearestElement) { + const tp = nearestElement.tooltipPosition(); + x = tp.x; + y = tp.y; + } + return { + x, + y + }; + } +}; +function pushOrConcat(base, toPush) { + if (toPush) { + if (isArray(toPush)) { + Array.prototype.push.apply(base, toPush); + } else { + base.push(toPush); + } + } + return base; +} + function splitNewlines(str) { + if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) { + return str.split('\n'); + } + return str; +} + function createTooltipItem(chart, item) { + const { element , datasetIndex , index } = item; + const controller = chart.getDatasetMeta(datasetIndex).controller; + const { label , value } = controller.getLabelAndValue(index); + return { + chart, + label, + parsed: controller.getParsed(index), + raw: chart.data.datasets[datasetIndex].data[index], + formattedValue: value, + dataset: controller.getDataset(), + dataIndex: index, + datasetIndex, + element + }; +} + function getTooltipSize(tooltip, options) { + const ctx = tooltip.chart.ctx; + const { body , footer , title } = tooltip; + const { boxWidth , boxHeight } = options; + const bodyFont = toFont(options.bodyFont); + const titleFont = toFont(options.titleFont); + const footerFont = toFont(options.footerFont); + const titleLineCount = title.length; + const footerLineCount = footer.length; + const bodyLineItemCount = body.length; + const padding = toPadding(options.padding); + let height = padding.height; + let width = 0; + let combinedBodyLength = body.reduce((count, bodyItem)=>count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0); + combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length; + if (titleLineCount) { + height += titleLineCount * titleFont.lineHeight + (titleLineCount - 1) * options.titleSpacing + options.titleMarginBottom; + } + if (combinedBodyLength) { + const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight; + height += bodyLineItemCount * bodyLineHeight + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight + (combinedBodyLength - 1) * options.bodySpacing; + } + if (footerLineCount) { + height += options.footerMarginTop + footerLineCount * footerFont.lineHeight + (footerLineCount - 1) * options.footerSpacing; + } + let widthPadding = 0; + const maxLineWidth = function(line) { + width = Math.max(width, ctx.measureText(line).width + widthPadding); + }; + ctx.save(); + ctx.font = titleFont.string; + each(tooltip.title, maxLineWidth); + ctx.font = bodyFont.string; + each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth); + widthPadding = options.displayColors ? boxWidth + 2 + options.boxPadding : 0; + each(body, (bodyItem)=>{ + each(bodyItem.before, maxLineWidth); + each(bodyItem.lines, maxLineWidth); + each(bodyItem.after, maxLineWidth); + }); + widthPadding = 0; + ctx.font = footerFont.string; + each(tooltip.footer, maxLineWidth); + ctx.restore(); + width += padding.width; + return { + width, + height + }; +} +function determineYAlign(chart, size) { + const { y , height } = size; + if (y < height / 2) { + return 'top'; + } else if (y > chart.height - height / 2) { + return 'bottom'; + } + return 'center'; +} +function doesNotFitWithAlign(xAlign, chart, options, size) { + const { x , width } = size; + const caret = options.caretSize + options.caretPadding; + if (xAlign === 'left' && x + width + caret > chart.width) { + return true; + } + if (xAlign === 'right' && x - width - caret < 0) { + return true; + } +} +function determineXAlign(chart, options, size, yAlign) { + const { x , width } = size; + const { width: chartWidth , chartArea: { left , right } } = chart; + let xAlign = 'center'; + if (yAlign === 'center') { + xAlign = x <= (left + right) / 2 ? 'left' : 'right'; + } else if (x <= width / 2) { + xAlign = 'left'; + } else if (x >= chartWidth - width / 2) { + xAlign = 'right'; + } + if (doesNotFitWithAlign(xAlign, chart, options, size)) { + xAlign = 'center'; + } + return xAlign; +} + function determineAlignment(chart, options, size) { + const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size); + return { + xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign), + yAlign + }; +} +function alignX(size, xAlign) { + let { x , width } = size; + if (xAlign === 'right') { + x -= width; + } else if (xAlign === 'center') { + x -= width / 2; + } + return x; +} +function alignY(size, yAlign, paddingAndSize) { + let { y , height } = size; + if (yAlign === 'top') { + y += paddingAndSize; + } else if (yAlign === 'bottom') { + y -= height + paddingAndSize; + } else { + y -= height / 2; + } + return y; +} + function getBackgroundPoint(options, size, alignment, chart) { + const { caretSize , caretPadding , cornerRadius } = options; + const { xAlign , yAlign } = alignment; + const paddingAndSize = caretSize + caretPadding; + const { topLeft , topRight , bottomLeft , bottomRight } = toTRBLCorners(cornerRadius); + let x = alignX(size, xAlign); + const y = alignY(size, yAlign, paddingAndSize); + if (yAlign === 'center') { + if (xAlign === 'left') { + x += paddingAndSize; + } else if (xAlign === 'right') { + x -= paddingAndSize; + } + } else if (xAlign === 'left') { + x -= Math.max(topLeft, bottomLeft) + caretSize; + } else if (xAlign === 'right') { + x += Math.max(topRight, bottomRight) + caretSize; + } + return { + x: _limitValue(x, 0, chart.width - size.width), + y: _limitValue(y, 0, chart.height - size.height) + }; +} +function getAlignedX(tooltip, align, options) { + const padding = toPadding(options.padding); + return align === 'center' ? tooltip.x + tooltip.width / 2 : align === 'right' ? tooltip.x + tooltip.width - padding.right : tooltip.x + padding.left; +} + function getBeforeAfterBodyLines(callback) { + return pushOrConcat([], splitNewlines(callback)); +} +function createTooltipContext(parent, tooltip, tooltipItems) { + return createContext(parent, { + tooltip, + tooltipItems, + type: 'tooltip' + }); +} +function overrideCallbacks(callbacks, context) { + const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks; + return override ? callbacks.override(override) : callbacks; +} +const defaultCallbacks = { + beforeTitle: noop, + title (tooltipItems) { + if (tooltipItems.length > 0) { + const item = tooltipItems[0]; + const labels = item.chart.data.labels; + const labelCount = labels ? labels.length : 0; + if (this && this.options && this.options.mode === 'dataset') { + return item.dataset.label || ''; + } else if (item.label) { + return item.label; + } else if (labelCount > 0 && item.dataIndex < labelCount) { + return labels[item.dataIndex]; + } + } + return ''; + }, + afterTitle: noop, + beforeBody: noop, + beforeLabel: noop, + label (tooltipItem) { + if (this && this.options && this.options.mode === 'dataset') { + return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue; + } + let label = tooltipItem.dataset.label || ''; + if (label) { + label += ': '; + } + const value = tooltipItem.formattedValue; + if (!isNullOrUndef(value)) { + label += value; + } + return label; + }, + labelColor (tooltipItem) { + const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); + const options = meta.controller.getStyle(tooltipItem.dataIndex); + return { + borderColor: options.borderColor, + backgroundColor: options.backgroundColor, + borderWidth: options.borderWidth, + borderDash: options.borderDash, + borderDashOffset: options.borderDashOffset, + borderRadius: 0 + }; + }, + labelTextColor () { + return this.options.bodyColor; + }, + labelPointStyle (tooltipItem) { + const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); + const options = meta.controller.getStyle(tooltipItem.dataIndex); + return { + pointStyle: options.pointStyle, + rotation: options.rotation + }; + }, + afterLabel: noop, + afterBody: noop, + beforeFooter: noop, + footer: noop, + afterFooter: noop +}; + function invokeCallbackWithFallback(callbacks, name, ctx, arg) { + const result = callbacks[name].call(ctx, arg); + if (typeof result === 'undefined') { + return defaultCallbacks[name].call(ctx, arg); + } + return result; +} +class Tooltip extends Element { + static positioners = positioners; + constructor(config){ + super(); + this.opacity = 0; + this._active = []; + this._eventPosition = undefined; + this._size = undefined; + this._cachedAnimations = undefined; + this._tooltipItems = []; + this.$animations = undefined; + this.$context = undefined; + this.chart = config.chart; + this.options = config.options; + this.dataPoints = undefined; + this.title = undefined; + this.beforeBody = undefined; + this.body = undefined; + this.afterBody = undefined; + this.footer = undefined; + this.xAlign = undefined; + this.yAlign = undefined; + this.x = undefined; + this.y = undefined; + this.height = undefined; + this.width = undefined; + this.caretX = undefined; + this.caretY = undefined; + this.labelColors = undefined; + this.labelPointStyles = undefined; + this.labelTextColors = undefined; + } + initialize(options) { + this.options = options; + this._cachedAnimations = undefined; + this.$context = undefined; + } + _resolveAnimations() { + const cached = this._cachedAnimations; + if (cached) { + return cached; + } + const chart = this.chart; + const options = this.options.setContext(this.getContext()); + const opts = options.enabled && chart.options.animation && options.animations; + const animations = new Animations(this.chart, opts); + if (opts._cacheable) { + this._cachedAnimations = Object.freeze(animations); + } + return animations; + } + getContext() { + return this.$context || (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems)); + } + getTitle(context, options) { + const { callbacks } = options; + const beforeTitle = invokeCallbackWithFallback(callbacks, 'beforeTitle', this, context); + const title = invokeCallbackWithFallback(callbacks, 'title', this, context); + const afterTitle = invokeCallbackWithFallback(callbacks, 'afterTitle', this, context); + let lines = []; + lines = pushOrConcat(lines, splitNewlines(beforeTitle)); + lines = pushOrConcat(lines, splitNewlines(title)); + lines = pushOrConcat(lines, splitNewlines(afterTitle)); + return lines; + } + getBeforeBody(tooltipItems, options) { + return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'beforeBody', this, tooltipItems)); + } + getBody(tooltipItems, options) { + const { callbacks } = options; + const bodyItems = []; + each(tooltipItems, (context)=>{ + const bodyItem = { + before: [], + lines: [], + after: [] + }; + const scoped = overrideCallbacks(callbacks, context); + pushOrConcat(bodyItem.before, splitNewlines(invokeCallbackWithFallback(scoped, 'beforeLabel', this, context))); + pushOrConcat(bodyItem.lines, invokeCallbackWithFallback(scoped, 'label', this, context)); + pushOrConcat(bodyItem.after, splitNewlines(invokeCallbackWithFallback(scoped, 'afterLabel', this, context))); + bodyItems.push(bodyItem); + }); + return bodyItems; + } + getAfterBody(tooltipItems, options) { + return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'afterBody', this, tooltipItems)); + } + getFooter(tooltipItems, options) { + const { callbacks } = options; + const beforeFooter = invokeCallbackWithFallback(callbacks, 'beforeFooter', this, tooltipItems); + const footer = invokeCallbackWithFallback(callbacks, 'footer', this, tooltipItems); + const afterFooter = invokeCallbackWithFallback(callbacks, 'afterFooter', this, tooltipItems); + let lines = []; + lines = pushOrConcat(lines, splitNewlines(beforeFooter)); + lines = pushOrConcat(lines, splitNewlines(footer)); + lines = pushOrConcat(lines, splitNewlines(afterFooter)); + return lines; + } + _createItems(options) { + const active = this._active; + const data = this.chart.data; + const labelColors = []; + const labelPointStyles = []; + const labelTextColors = []; + let tooltipItems = []; + let i, len; + for(i = 0, len = active.length; i < len; ++i){ + tooltipItems.push(createTooltipItem(this.chart, active[i])); + } + if (options.filter) { + tooltipItems = tooltipItems.filter((element, index, array)=>options.filter(element, index, array, data)); + } + if (options.itemSort) { + tooltipItems = tooltipItems.sort((a, b)=>options.itemSort(a, b, data)); + } + each(tooltipItems, (context)=>{ + const scoped = overrideCallbacks(options.callbacks, context); + labelColors.push(invokeCallbackWithFallback(scoped, 'labelColor', this, context)); + labelPointStyles.push(invokeCallbackWithFallback(scoped, 'labelPointStyle', this, context)); + labelTextColors.push(invokeCallbackWithFallback(scoped, 'labelTextColor', this, context)); + }); + this.labelColors = labelColors; + this.labelPointStyles = labelPointStyles; + this.labelTextColors = labelTextColors; + this.dataPoints = tooltipItems; + return tooltipItems; + } + update(changed, replay) { + const options = this.options.setContext(this.getContext()); + const active = this._active; + let properties; + let tooltipItems = []; + if (!active.length) { + if (this.opacity !== 0) { + properties = { + opacity: 0 + }; + } + } else { + const position = positioners[options.position].call(this, active, this._eventPosition); + tooltipItems = this._createItems(options); + this.title = this.getTitle(tooltipItems, options); + this.beforeBody = this.getBeforeBody(tooltipItems, options); + this.body = this.getBody(tooltipItems, options); + this.afterBody = this.getAfterBody(tooltipItems, options); + this.footer = this.getFooter(tooltipItems, options); + const size = this._size = getTooltipSize(this, options); + const positionAndSize = Object.assign({}, position, size); + const alignment = determineAlignment(this.chart, options, positionAndSize); + const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart); + this.xAlign = alignment.xAlign; + this.yAlign = alignment.yAlign; + properties = { + opacity: 1, + x: backgroundPoint.x, + y: backgroundPoint.y, + width: size.width, + height: size.height, + caretX: position.x, + caretY: position.y + }; + } + this._tooltipItems = tooltipItems; + this.$context = undefined; + if (properties) { + this._resolveAnimations().update(this, properties); + } + if (changed && options.external) { + options.external.call(this, { + chart: this.chart, + tooltip: this, + replay + }); + } + } + drawCaret(tooltipPoint, ctx, size, options) { + const caretPosition = this.getCaretPosition(tooltipPoint, size, options); + ctx.lineTo(caretPosition.x1, caretPosition.y1); + ctx.lineTo(caretPosition.x2, caretPosition.y2); + ctx.lineTo(caretPosition.x3, caretPosition.y3); + } + getCaretPosition(tooltipPoint, size, options) { + const { xAlign , yAlign } = this; + const { caretSize , cornerRadius } = options; + const { topLeft , topRight , bottomLeft , bottomRight } = toTRBLCorners(cornerRadius); + const { x: ptX , y: ptY } = tooltipPoint; + const { width , height } = size; + let x1, x2, x3, y1, y2, y3; + if (yAlign === 'center') { + y2 = ptY + height / 2; + if (xAlign === 'left') { + x1 = ptX; + x2 = x1 - caretSize; + y1 = y2 + caretSize; + y3 = y2 - caretSize; + } else { + x1 = ptX + width; + x2 = x1 + caretSize; + y1 = y2 - caretSize; + y3 = y2 + caretSize; + } + x3 = x1; + } else { + if (xAlign === 'left') { + x2 = ptX + Math.max(topLeft, bottomLeft) + caretSize; + } else if (xAlign === 'right') { + x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize; + } else { + x2 = this.caretX; + } + if (yAlign === 'top') { + y1 = ptY; + y2 = y1 - caretSize; + x1 = x2 - caretSize; + x3 = x2 + caretSize; + } else { + y1 = ptY + height; + y2 = y1 + caretSize; + x1 = x2 + caretSize; + x3 = x2 - caretSize; + } + y3 = y1; + } + return { + x1, + x2, + x3, + y1, + y2, + y3 + }; + } + drawTitle(pt, ctx, options) { + const title = this.title; + const length = title.length; + let titleFont, titleSpacing, i; + if (length) { + const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); + pt.x = getAlignedX(this, options.titleAlign, options); + ctx.textAlign = rtlHelper.textAlign(options.titleAlign); + ctx.textBaseline = 'middle'; + titleFont = toFont(options.titleFont); + titleSpacing = options.titleSpacing; + ctx.fillStyle = options.titleColor; + ctx.font = titleFont.string; + for(i = 0; i < length; ++i){ + ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2); + pt.y += titleFont.lineHeight + titleSpacing; + if (i + 1 === length) { + pt.y += options.titleMarginBottom - titleSpacing; + } + } + } + } + _drawColorBox(ctx, pt, i, rtlHelper, options) { + const labelColor = this.labelColors[i]; + const labelPointStyle = this.labelPointStyles[i]; + const { boxHeight , boxWidth } = options; + const bodyFont = toFont(options.bodyFont); + const colorX = getAlignedX(this, 'left', options); + const rtlColorX = rtlHelper.x(colorX); + const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0; + const colorY = pt.y + yOffSet; + if (options.usePointStyle) { + const drawOptions = { + radius: Math.min(boxWidth, boxHeight) / 2, + pointStyle: labelPointStyle.pointStyle, + rotation: labelPointStyle.rotation, + borderWidth: 1 + }; + const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2; + const centerY = colorY + boxHeight / 2; + ctx.strokeStyle = options.multiKeyBackground; + ctx.fillStyle = options.multiKeyBackground; + drawPoint(ctx, drawOptions, centerX, centerY); + ctx.strokeStyle = labelColor.borderColor; + ctx.fillStyle = labelColor.backgroundColor; + drawPoint(ctx, drawOptions, centerX, centerY); + } else { + ctx.lineWidth = isObject(labelColor.borderWidth) ? Math.max(...Object.values(labelColor.borderWidth)) : labelColor.borderWidth || 1; + ctx.strokeStyle = labelColor.borderColor; + ctx.setLineDash(labelColor.borderDash || []); + ctx.lineDashOffset = labelColor.borderDashOffset || 0; + const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth); + const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - 2); + const borderRadius = toTRBLCorners(labelColor.borderRadius); + if (Object.values(borderRadius).some((v)=>v !== 0)) { + ctx.beginPath(); + ctx.fillStyle = options.multiKeyBackground; + addRoundedRectPath(ctx, { + x: outerX, + y: colorY, + w: boxWidth, + h: boxHeight, + radius: borderRadius + }); + ctx.fill(); + ctx.stroke(); + ctx.fillStyle = labelColor.backgroundColor; + ctx.beginPath(); + addRoundedRectPath(ctx, { + x: innerX, + y: colorY + 1, + w: boxWidth - 2, + h: boxHeight - 2, + radius: borderRadius + }); + ctx.fill(); + } else { + ctx.fillStyle = options.multiKeyBackground; + ctx.fillRect(outerX, colorY, boxWidth, boxHeight); + ctx.strokeRect(outerX, colorY, boxWidth, boxHeight); + ctx.fillStyle = labelColor.backgroundColor; + ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2); + } + } + ctx.fillStyle = this.labelTextColors[i]; + } + drawBody(pt, ctx, options) { + const { body } = this; + const { bodySpacing , bodyAlign , displayColors , boxHeight , boxWidth , boxPadding } = options; + const bodyFont = toFont(options.bodyFont); + let bodyLineHeight = bodyFont.lineHeight; + let xLinePadding = 0; + const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); + const fillLineOfText = function(line) { + ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2); + pt.y += bodyLineHeight + bodySpacing; + }; + const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign); + let bodyItem, textColor, lines, i, j, ilen, jlen; + ctx.textAlign = bodyAlign; + ctx.textBaseline = 'middle'; + ctx.font = bodyFont.string; + pt.x = getAlignedX(this, bodyAlignForCalculation, options); + ctx.fillStyle = options.bodyColor; + each(this.beforeBody, fillLineOfText); + xLinePadding = displayColors && bodyAlignForCalculation !== 'right' ? bodyAlign === 'center' ? boxWidth / 2 + boxPadding : boxWidth + 2 + boxPadding : 0; + for(i = 0, ilen = body.length; i < ilen; ++i){ + bodyItem = body[i]; + textColor = this.labelTextColors[i]; + ctx.fillStyle = textColor; + each(bodyItem.before, fillLineOfText); + lines = bodyItem.lines; + if (displayColors && lines.length) { + this._drawColorBox(ctx, pt, i, rtlHelper, options); + bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight); + } + for(j = 0, jlen = lines.length; j < jlen; ++j){ + fillLineOfText(lines[j]); + bodyLineHeight = bodyFont.lineHeight; + } + each(bodyItem.after, fillLineOfText); + } + xLinePadding = 0; + bodyLineHeight = bodyFont.lineHeight; + each(this.afterBody, fillLineOfText); + pt.y -= bodySpacing; + } + drawFooter(pt, ctx, options) { + const footer = this.footer; + const length = footer.length; + let footerFont, i; + if (length) { + const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); + pt.x = getAlignedX(this, options.footerAlign, options); + pt.y += options.footerMarginTop; + ctx.textAlign = rtlHelper.textAlign(options.footerAlign); + ctx.textBaseline = 'middle'; + footerFont = toFont(options.footerFont); + ctx.fillStyle = options.footerColor; + ctx.font = footerFont.string; + for(i = 0; i < length; ++i){ + ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2); + pt.y += footerFont.lineHeight + options.footerSpacing; + } + } + } + drawBackground(pt, ctx, tooltipSize, options) { + const { xAlign , yAlign } = this; + const { x , y } = pt; + const { width , height } = tooltipSize; + const { topLeft , topRight , bottomLeft , bottomRight } = toTRBLCorners(options.cornerRadius); + ctx.fillStyle = options.backgroundColor; + ctx.strokeStyle = options.borderColor; + ctx.lineWidth = options.borderWidth; + ctx.beginPath(); + ctx.moveTo(x + topLeft, y); + if (yAlign === 'top') { + this.drawCaret(pt, ctx, tooltipSize, options); + } + ctx.lineTo(x + width - topRight, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + topRight); + if (yAlign === 'center' && xAlign === 'right') { + this.drawCaret(pt, ctx, tooltipSize, options); + } + ctx.lineTo(x + width, y + height - bottomRight); + ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height); + if (yAlign === 'bottom') { + this.drawCaret(pt, ctx, tooltipSize, options); + } + ctx.lineTo(x + bottomLeft, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft); + if (yAlign === 'center' && xAlign === 'left') { + this.drawCaret(pt, ctx, tooltipSize, options); + } + ctx.lineTo(x, y + topLeft); + ctx.quadraticCurveTo(x, y, x + topLeft, y); + ctx.closePath(); + ctx.fill(); + if (options.borderWidth > 0) { + ctx.stroke(); + } + } + _updateAnimationTarget(options) { + const chart = this.chart; + const anims = this.$animations; + const animX = anims && anims.x; + const animY = anims && anims.y; + if (animX || animY) { + const position = positioners[options.position].call(this, this._active, this._eventPosition); + if (!position) { + return; + } + const size = this._size = getTooltipSize(this, options); + const positionAndSize = Object.assign({}, position, this._size); + const alignment = determineAlignment(chart, options, positionAndSize); + const point = getBackgroundPoint(options, positionAndSize, alignment, chart); + if (animX._to !== point.x || animY._to !== point.y) { + this.xAlign = alignment.xAlign; + this.yAlign = alignment.yAlign; + this.width = size.width; + this.height = size.height; + this.caretX = position.x; + this.caretY = position.y; + this._resolveAnimations().update(this, point); + } + } + } + _willRender() { + return !!this.opacity; + } + draw(ctx) { + const options = this.options.setContext(this.getContext()); + let opacity = this.opacity; + if (!opacity) { + return; + } + this._updateAnimationTarget(options); + const tooltipSize = { + width: this.width, + height: this.height + }; + const pt = { + x: this.x, + y: this.y + }; + opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity; + const padding = toPadding(options.padding); + const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length; + if (options.enabled && hasTooltipContent) { + ctx.save(); + ctx.globalAlpha = opacity; + this.drawBackground(pt, ctx, tooltipSize, options); + overrideTextDirection(ctx, options.textDirection); + pt.y += padding.top; + this.drawTitle(pt, ctx, options); + this.drawBody(pt, ctx, options); + this.drawFooter(pt, ctx, options); + restoreTextDirection(ctx, options.textDirection); + ctx.restore(); + } + } + getActiveElements() { + return this._active || []; + } + setActiveElements(activeElements, eventPosition) { + const lastActive = this._active; + const active = activeElements.map(({ datasetIndex , index })=>{ + const meta = this.chart.getDatasetMeta(datasetIndex); + if (!meta) { + throw new Error('Cannot find a dataset at index ' + datasetIndex); + } + return { + datasetIndex, + element: meta.data[index], + index + }; + }); + const changed = !_elementsEqual(lastActive, active); + const positionChanged = this._positionChanged(active, eventPosition); + if (changed || positionChanged) { + this._active = active; + this._eventPosition = eventPosition; + this._ignoreReplayEvents = true; + this.update(true); + } + } + handleEvent(e, replay, inChartArea = true) { + if (replay && this._ignoreReplayEvents) { + return false; + } + this._ignoreReplayEvents = false; + const options = this.options; + const lastActive = this._active || []; + const active = this._getActiveElements(e, lastActive, replay, inChartArea); + const positionChanged = this._positionChanged(active, e); + const changed = replay || !_elementsEqual(active, lastActive) || positionChanged; + if (changed) { + this._active = active; + if (options.enabled || options.external) { + this._eventPosition = { + x: e.x, + y: e.y + }; + this.update(true, replay); + } + } + return changed; + } + _getActiveElements(e, lastActive, replay, inChartArea) { + const options = this.options; + if (e.type === 'mouseout') { + return []; + } + if (!inChartArea) { + return lastActive.filter((i)=>this.chart.data.datasets[i.datasetIndex] && this.chart.getDatasetMeta(i.datasetIndex).controller.getParsed(i.index) !== undefined); + } + const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay); + if (options.reverse) { + active.reverse(); + } + return active; + } + _positionChanged(active, e) { + const { caretX , caretY , options } = this; + const position = positioners[options.position].call(this, active, e); + return position !== false && (caretX !== position.x || caretY !== position.y); + } +} +var plugin_tooltip = { + id: 'tooltip', + _element: Tooltip, + positioners, + afterInit (chart, _args, options) { + if (options) { + chart.tooltip = new Tooltip({ + chart, + options + }); + } + }, + beforeUpdate (chart, _args, options) { + if (chart.tooltip) { + chart.tooltip.initialize(options); + } + }, + reset (chart, _args, options) { + if (chart.tooltip) { + chart.tooltip.initialize(options); + } + }, + afterDraw (chart) { + const tooltip = chart.tooltip; + if (tooltip && tooltip._willRender()) { + const args = { + tooltip + }; + if (chart.notifyPlugins('beforeTooltipDraw', { + ...args, + cancelable: true + }) === false) { + return; + } + tooltip.draw(chart.ctx); + chart.notifyPlugins('afterTooltipDraw', args); + } + }, + afterEvent (chart, args) { + if (chart.tooltip) { + const useFinalPosition = args.replay; + if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) { + args.changed = true; + } + } + }, + defaults: { + enabled: true, + external: null, + position: 'average', + backgroundColor: 'rgba(0,0,0,0.8)', + titleColor: '#fff', + titleFont: { + weight: 'bold' + }, + titleSpacing: 2, + titleMarginBottom: 6, + titleAlign: 'left', + bodyColor: '#fff', + bodySpacing: 2, + bodyFont: {}, + bodyAlign: 'left', + footerColor: '#fff', + footerSpacing: 2, + footerMarginTop: 6, + footerFont: { + weight: 'bold' + }, + footerAlign: 'left', + padding: 6, + caretPadding: 2, + caretSize: 5, + cornerRadius: 6, + boxHeight: (ctx, opts)=>opts.bodyFont.size, + boxWidth: (ctx, opts)=>opts.bodyFont.size, + multiKeyBackground: '#fff', + displayColors: true, + boxPadding: 0, + borderColor: 'rgba(0,0,0,0)', + borderWidth: 0, + animation: { + duration: 400, + easing: 'easeOutQuart' + }, + animations: { + numbers: { + type: 'number', + properties: [ + 'x', + 'y', + 'width', + 'height', + 'caretX', + 'caretY' + ] + }, + opacity: { + easing: 'linear', + duration: 200 + } + }, + callbacks: defaultCallbacks + }, + defaultRoutes: { + bodyFont: 'font', + footerFont: 'font', + titleFont: 'font' + }, + descriptors: { + _scriptable: (name)=>name !== 'filter' && name !== 'itemSort' && name !== 'external', + _indexable: false, + callbacks: { + _scriptable: false, + _indexable: false + }, + animation: { + _fallback: false + }, + animations: { + _fallback: 'animation' + } + }, + additionalOptionScopes: [ + 'interaction' + ] +}; + +const INTERVALS = { + millisecond: { + common: true, + size: 1, + steps: 1000 + }, + second: { + common: true, + size: 1000, + steps: 60 + }, + minute: { + common: true, + size: 60000, + steps: 60 + }, + hour: { + common: true, + size: 3600000, + steps: 24 + }, + day: { + common: true, + size: 86400000, + steps: 30 + }, + week: { + common: false, + size: 604800000, + steps: 4 + }, + month: { + common: true, + size: 2.628e9, + steps: 12 + }, + quarter: { + common: false, + size: 7.884e9, + steps: 4 + }, + year: { + common: true, + size: 3.154e10 + } +}; + const UNITS = /* #__PURE__ */ Object.keys(INTERVALS); + function sorter(a, b) { + return a - b; +} + function parse(scale, input) { + if (isNullOrUndef(input)) { + return null; + } + const adapter = scale._adapter; + const { parser , round , isoWeekday } = scale._parseOpts; + let value = input; + if (typeof parser === 'function') { + value = parser(value); + } + if (!isNumberFinite(value)) { + value = typeof parser === 'string' ? adapter.parse(value, parser) : adapter.parse(value); + } + if (value === null) { + return null; + } + if (round) { + value = round === 'week' && (isNumber(isoWeekday) || isoWeekday === true) ? adapter.startOf(value, 'isoWeek', isoWeekday) : adapter.startOf(value, round); + } + return +value; +} + function determineUnitForAutoTicks(minUnit, min, max, capacity) { + const ilen = UNITS.length; + for(let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i){ + const interval = INTERVALS[UNITS[i]]; + const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER; + if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) { + return UNITS[i]; + } + } + return UNITS[ilen - 1]; +} + function determineUnitForFormatting(scale, numTicks, minUnit, min, max) { + for(let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--){ + const unit = UNITS[i]; + if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) { + return unit; + } + } + return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0]; +} + function determineMajorUnit(unit) { + for(let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i){ + if (INTERVALS[UNITS[i]].common) { + return UNITS[i]; + } + } +} + function addTick(ticks, time, timestamps) { + if (!timestamps) { + ticks[time] = true; + } else if (timestamps.length) { + const { lo , hi } = _lookup(timestamps, time); + const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi]; + ticks[timestamp] = true; + } +} + function setMajorTicks(scale, ticks, map, majorUnit) { + const adapter = scale._adapter; + const first = +adapter.startOf(ticks[0].value, majorUnit); + const last = ticks[ticks.length - 1].value; + let major, index; + for(major = first; major <= last; major = +adapter.add(major, 1, majorUnit)){ + index = map[major]; + if (index >= 0) { + ticks[index].major = true; + } + } + return ticks; +} + function ticksFromTimestamps(scale, values, majorUnit) { + const ticks = []; + const map = {}; + const ilen = values.length; + let i, value; + for(i = 0; i < ilen; ++i){ + value = values[i]; + map[value] = i; + ticks.push({ + value, + major: false + }); + } + return ilen === 0 || !majorUnit ? ticks : setMajorTicks(scale, ticks, map, majorUnit); +} +class TimeScale extends Scale { + static id = 'time'; + static defaults = { + bounds: 'data', + adapters: {}, + time: { + parser: false, + unit: false, + round: false, + isoWeekday: false, + minUnit: 'millisecond', + displayFormats: {} + }, + ticks: { + source: 'auto', + callback: false, + major: { + enabled: false + } + } + }; + constructor(props){ + super(props); + this._cache = { + data: [], + labels: [], + all: [] + }; + this._unit = 'day'; + this._majorUnit = undefined; + this._offsets = {}; + this._normalized = false; + this._parseOpts = undefined; + } + init(scaleOpts, opts = {}) { + const time = scaleOpts.time || (scaleOpts.time = {}); + const adapter = this._adapter = new adapters._date(scaleOpts.adapters.date); + adapter.init(opts); + mergeIf(time.displayFormats, adapter.formats()); + this._parseOpts = { + parser: time.parser, + round: time.round, + isoWeekday: time.isoWeekday + }; + super.init(scaleOpts); + this._normalized = opts.normalized; + } + parse(raw, index) { + if (raw === undefined) { + return null; + } + return parse(this, raw); + } + beforeLayout() { + super.beforeLayout(); + this._cache = { + data: [], + labels: [], + all: [] + }; + } + determineDataLimits() { + const options = this.options; + const adapter = this._adapter; + const unit = options.time.unit || 'day'; + let { min , max , minDefined , maxDefined } = this.getUserBounds(); + function _applyBounds(bounds) { + if (!minDefined && !isNaN(bounds.min)) { + min = Math.min(min, bounds.min); + } + if (!maxDefined && !isNaN(bounds.max)) { + max = Math.max(max, bounds.max); + } + } + if (!minDefined || !maxDefined) { + _applyBounds(this._getLabelBounds()); + if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') { + _applyBounds(this.getMinMax(false)); + } + } + min = isNumberFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit); + max = isNumberFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1; + this.min = Math.min(min, max - 1); + this.max = Math.max(min + 1, max); + } + _getLabelBounds() { + const arr = this.getLabelTimestamps(); + let min = Number.POSITIVE_INFINITY; + let max = Number.NEGATIVE_INFINITY; + if (arr.length) { + min = arr[0]; + max = arr[arr.length - 1]; + } + return { + min, + max + }; + } + buildTicks() { + const options = this.options; + const timeOpts = options.time; + const tickOpts = options.ticks; + const timestamps = tickOpts.source === 'labels' ? this.getLabelTimestamps() : this._generate(); + if (options.bounds === 'ticks' && timestamps.length) { + this.min = this._userMin || timestamps[0]; + this.max = this._userMax || timestamps[timestamps.length - 1]; + } + const min = this.min; + const max = this.max; + const ticks = _filterBetween(timestamps, min, max); + this._unit = timeOpts.unit || (tickOpts.autoSkip ? determineUnitForAutoTicks(timeOpts.minUnit, this.min, this.max, this._getLabelCapacity(min)) : determineUnitForFormatting(this, ticks.length, timeOpts.minUnit, this.min, this.max)); + this._majorUnit = !tickOpts.major.enabled || this._unit === 'year' ? undefined : determineMajorUnit(this._unit); + this.initOffsets(timestamps); + if (options.reverse) { + ticks.reverse(); + } + return ticksFromTimestamps(this, ticks, this._majorUnit); + } + afterAutoSkip() { + if (this.options.offsetAfterAutoskip) { + this.initOffsets(this.ticks.map((tick)=>+tick.value)); + } + } + initOffsets(timestamps = []) { + let start = 0; + let end = 0; + let first, last; + if (this.options.offset && timestamps.length) { + first = this.getDecimalForValue(timestamps[0]); + if (timestamps.length === 1) { + start = 1 - first; + } else { + start = (this.getDecimalForValue(timestamps[1]) - first) / 2; + } + last = this.getDecimalForValue(timestamps[timestamps.length - 1]); + if (timestamps.length === 1) { + end = last; + } else { + end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2; + } + } + const limit = timestamps.length < 3 ? 0.5 : 0.25; + start = _limitValue(start, 0, limit); + end = _limitValue(end, 0, limit); + this._offsets = { + start, + end, + factor: 1 / (start + 1 + end) + }; + } + _generate() { + const adapter = this._adapter; + const min = this.min; + const max = this.max; + const options = this.options; + const timeOpts = options.time; + const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min)); + const stepSize = valueOrDefault(options.ticks.stepSize, 1); + const weekday = minor === 'week' ? timeOpts.isoWeekday : false; + const hasWeekday = isNumber(weekday) || weekday === true; + const ticks = {}; + let first = min; + let time, count; + if (hasWeekday) { + first = +adapter.startOf(first, 'isoWeek', weekday); + } + first = +adapter.startOf(first, hasWeekday ? 'day' : minor); + if (adapter.diff(max, min, minor) > 100000 * stepSize) { + throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor); + } + const timestamps = options.ticks.source === 'data' && this.getDataTimestamps(); + for(time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++){ + addTick(ticks, time, timestamps); + } + if (time === max || options.bounds === 'ticks' || count === 1) { + addTick(ticks, time, timestamps); + } + return Object.keys(ticks).sort(sorter).map((x)=>+x); + } + getLabelForValue(value) { + const adapter = this._adapter; + const timeOpts = this.options.time; + if (timeOpts.tooltipFormat) { + return adapter.format(value, timeOpts.tooltipFormat); + } + return adapter.format(value, timeOpts.displayFormats.datetime); + } + format(value, format) { + const options = this.options; + const formats = options.time.displayFormats; + const unit = this._unit; + const fmt = format || formats[unit]; + return this._adapter.format(value, fmt); + } + _tickFormatFunction(time, index, ticks, format) { + const options = this.options; + const formatter = options.ticks.callback; + if (formatter) { + return callback(formatter, [ + time, + index, + ticks + ], this); + } + const formats = options.time.displayFormats; + const unit = this._unit; + const majorUnit = this._majorUnit; + const minorFormat = unit && formats[unit]; + const majorFormat = majorUnit && formats[majorUnit]; + const tick = ticks[index]; + const major = majorUnit && majorFormat && tick && tick.major; + return this._adapter.format(time, format || (major ? majorFormat : minorFormat)); + } + generateTickLabels(ticks) { + let i, ilen, tick; + for(i = 0, ilen = ticks.length; i < ilen; ++i){ + tick = ticks[i]; + tick.label = this._tickFormatFunction(tick.value, i, ticks); + } + } + getDecimalForValue(value) { + return value === null ? NaN : (value - this.min) / (this.max - this.min); + } + getPixelForValue(value) { + const offsets = this._offsets; + const pos = this.getDecimalForValue(value); + return this.getPixelForDecimal((offsets.start + pos) * offsets.factor); + } + getValueForPixel(pixel) { + const offsets = this._offsets; + const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; + return this.min + pos * (this.max - this.min); + } + _getLabelSize(label) { + const ticksOpts = this.options.ticks; + const tickLabelWidth = this.ctx.measureText(label).width; + const angle = toRadians(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation); + const cosRotation = Math.cos(angle); + const sinRotation = Math.sin(angle); + const tickFontSize = this._resolveTickFontOptions(0).size; + return { + w: tickLabelWidth * cosRotation + tickFontSize * sinRotation, + h: tickLabelWidth * sinRotation + tickFontSize * cosRotation + }; + } + _getLabelCapacity(exampleTime) { + const timeOpts = this.options.time; + const displayFormats = timeOpts.displayFormats; + const format = displayFormats[timeOpts.unit] || displayFormats.millisecond; + const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [ + exampleTime + ], this._majorUnit), format); + const size = this._getLabelSize(exampleLabel); + const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1; + return capacity > 0 ? capacity : 1; + } + getDataTimestamps() { + let timestamps = this._cache.data || []; + let i, ilen; + if (timestamps.length) { + return timestamps; + } + const metas = this.getMatchingVisibleMetas(); + if (this._normalized && metas.length) { + return this._cache.data = metas[0].controller.getAllParsedValues(this); + } + for(i = 0, ilen = metas.length; i < ilen; ++i){ + timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(this)); + } + return this._cache.data = this.normalize(timestamps); + } + getLabelTimestamps() { + const timestamps = this._cache.labels || []; + let i, ilen; + if (timestamps.length) { + return timestamps; + } + const labels = this.getLabels(); + for(i = 0, ilen = labels.length; i < ilen; ++i){ + timestamps.push(parse(this, labels[i])); + } + return this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps); + } + normalize(values) { + return _arrayUnique(values.sort(sorter)); + } +} + +function interpolate(table, val, reverse) { + let lo = 0; + let hi = table.length - 1; + let prevSource, nextSource, prevTarget, nextTarget; + if (reverse) { + if (val >= table[lo].pos && val <= table[hi].pos) { + ({ lo , hi } = _lookupByKey(table, 'pos', val)); + } + ({ pos: prevSource , time: prevTarget } = table[lo]); + ({ pos: nextSource , time: nextTarget } = table[hi]); + } else { + if (val >= table[lo].time && val <= table[hi].time) { + ({ lo , hi } = _lookupByKey(table, 'time', val)); + } + ({ time: prevSource , pos: prevTarget } = table[lo]); + ({ time: nextSource , pos: nextTarget } = table[hi]); + } + const span = nextSource - prevSource; + return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget; +} +class TimeSeriesScale extends TimeScale { + static id = 'timeseries'; + static defaults = TimeScale.defaults; + constructor(props){ + super(props); + this._table = []; + this._minPos = undefined; + this._tableRange = undefined; + } + initOffsets() { + const timestamps = this._getTimestampsForTable(); + const table = this._table = this.buildLookupTable(timestamps); + this._minPos = interpolate(table, this.min); + this._tableRange = interpolate(table, this.max) - this._minPos; + super.initOffsets(timestamps); + } + buildLookupTable(timestamps) { + const { min , max } = this; + const items = []; + const table = []; + let i, ilen, prev, curr, next; + for(i = 0, ilen = timestamps.length; i < ilen; ++i){ + curr = timestamps[i]; + if (curr >= min && curr <= max) { + items.push(curr); + } + } + if (items.length < 2) { + return [ + { + time: min, + pos: 0 + }, + { + time: max, + pos: 1 + } + ]; + } + for(i = 0, ilen = items.length; i < ilen; ++i){ + next = items[i + 1]; + prev = items[i - 1]; + curr = items[i]; + if (Math.round((next + prev) / 2) !== curr) { + table.push({ + time: curr, + pos: i / (ilen - 1) + }); + } + } + return table; + } + _generate() { + const min = this.min; + const max = this.max; + let timestamps = super.getDataTimestamps(); + if (!timestamps.includes(min) || !timestamps.length) { + timestamps.splice(0, 0, min); + } + if (!timestamps.includes(max) || timestamps.length === 1) { + timestamps.push(max); + } + return timestamps.sort((a, b)=>a - b); + } + _getTimestampsForTable() { + let timestamps = this._cache.all || []; + if (timestamps.length) { + return timestamps; + } + const data = this.getDataTimestamps(); + const label = this.getLabelTimestamps(); + if (data.length && label.length) { + timestamps = this.normalize(data.concat(label)); + } else { + timestamps = data.length ? data : label; + } + timestamps = this._cache.all = timestamps; + return timestamps; + } + getDecimalForValue(value) { + return (interpolate(this._table, value) - this._minPos) / this._tableRange; + } + getValueForPixel(pixel) { + const offsets = this._offsets; + const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; + return interpolate(this._table, decimal * this._tableRange + this._minPos, true); + } +} + +/* src/view/FolderStatistics.svelte generated by Svelte v3.59.2 */ + +function create_catch_block(ctx) { + let p; + let t_value = /*error*/ ctx[7].message + ""; + let t; + + return { + c() { + p = element("p"); + t = text(t_value); + set_style(p, "color", "red"); + }, + m(target, anchor) { + insert(target, p, anchor); + append(p, t); + }, + p: noop$1, + d(detaching) { + if (detaching) detach(p); + } + }; +} + +// (59:4) {:then data} +function create_then_block(ctx) { + let p; + let t0; + let t1_value = /*data*/ ctx[6] + ""; + let t1; + let t2; + + return { + c() { + p = element("p"); + t0 = text("Total: "); + t1 = text(t1_value); + t2 = text(" words"); + }, + m(target, anchor) { + insert(target, p, anchor); + append(p, t0); + append(p, t1); + append(p, t2); + }, + p: noop$1, + d(detaching) { + if (detaching) detach(p); + } + }; +} + +// (57:26)

Counting

{:then data} +function create_pending_block(ctx) { + let p; + + return { + c() { + p = element("p"); + p.textContent = "Counting"; + }, + m(target, anchor) { + insert(target, p, anchor); + }, + p: noop$1, + d(detaching) { + if (detaching) detach(p); + } + }; +} + +function create_fragment(ctx) { + let div; + let h1; + let t0_value = /*file*/ ctx[0].name + ""; + let t0; + let t1; + let t2; + let canvas; + + let info = { + ctx, + current: null, + token: null, + hasCatch: true, + pending: create_pending_block, + then: create_then_block, + catch: create_catch_block, + value: 6, + error: 7 + }; + + handle_promise(/*renderChart*/ ctx[2](), info); + + return { + c() { + div = element("div"); + h1 = element("h1"); + t0 = text(t0_value); + t1 = space(); + info.block.c(); + t2 = space(); + canvas = element("canvas"); + attr(canvas, "class", "pieChart"); + }, + m(target, anchor) { + insert(target, div, anchor); + append(div, h1); + append(h1, t0); + append(div, t1); + info.block.m(div, info.anchor = null); + info.mount = () => div; + info.anchor = t2; + append(div, t2); + append(div, canvas); + /*canvas_binding*/ ctx[4](canvas); + }, + p(new_ctx, [dirty]) { + ctx = new_ctx; + if (dirty & /*file*/ 1 && t0_value !== (t0_value = /*file*/ ctx[0].name + "")) set_data(t0, t0_value); + update_await_block_branch(info, ctx, dirty); + }, + i: noop$1, + o: noop$1, + d(detaching) { + if (detaching) detach(div); + info.block.d(); + info.token = null; + info = null; + /*canvas_binding*/ ctx[4](null); + } + }; +} + +function instance($$self, $$props, $$invalidate) { + Chart.register(ArcElement, PieController); + Chart.register(plugin_tooltip); + let { file } = $$props; + let { plugin } = $$props; + let chartContainer; + + // Function to map the word count of each file to a chart js data object + const getFolderWordStats = async () => { + // Get all files in the folder + const allFiles = getAllFilesInFolder(plugin, file.path); + + // Get the content of all files in the folder + const content = await getAllFileContentInFolder(allFiles); + + // Get the word count of all files in the folder + const wordCounts = content.map(c => getWordCount(c)); + + return { + labels: allFiles.map(file => file.name), + datasets: [ + { + label: "Word Count", + data: wordCounts, + backgroundColor: "rgba(255, 99, 132, 0.2)", + borderColor: "rgba(255, 99, 132, 1)", + borderWidth: 1 + } + ] + }; + }; + + // Function to get all the data and render the chart + async function renderChart() { + const options = { + title: { + display: true, + text: "All Files and there Word Count", + position: "top" + }, + rotation: -0.7 * Math.PI, + legend: { display: false } + }; + + const data = await getFolderWordStats(); + new Chart(chartContainer, { type: "pie", data, options }); + return data.datasets[0].data.reduce((acc, current) => acc += current, 0); + } + + function canvas_binding($$value) { + binding_callbacks[$$value ? 'unshift' : 'push'](() => { + chartContainer = $$value; + $$invalidate(1, chartContainer); + }); + } + + $$self.$$set = $$props => { + if ('file' in $$props) $$invalidate(0, file = $$props.file); + if ('plugin' in $$props) $$invalidate(3, plugin = $$props.plugin); + }; + + return [file, chartContainer, renderChart, plugin, canvas_binding]; +} + +class FolderStatistics extends SvelteComponent { + constructor(options) { + super(); + init(this, options, instance, create_fragment, safe_not_equal, { file: 0, plugin: 3 }); + } +} + +// Modal to wrap the svelte component passing the required props +class FolderStatisticsModal extends obsidian.Modal { + constructor(plugin, file) { + super(plugin.app); + this.plugin = plugin; + this.file = file; + } + async onOpen() { + const { contentEl } = this; + new FolderStatistics({ + target: contentEl, + props: { + plugin: this.plugin, + file: this.file, + }, + }); + } + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +} + +function handleFileMenu(menu, file, source, plugin) { + if (source !== "file-explorer-context-menu") { + return; + } + if (!file) { + return; + } + // Make sure the menu only shows up for folders + if (file instanceof obsidian.TFile) { + return; + } + menu.addItem((item) => { + item.setTitle(`Count Words`) + .setIcon("info") + .setSection("action") + .onClick(async (_) => { + new FolderStatisticsModal(plugin, file).open(); + }); + }); +} + +class BetterWordCount extends obsidian.Plugin { + constructor() { + super(...arguments); + this.api = new BetterWordCountApi(this); + } + async onunload() { + this.statsManager = null; + this.statusBar = null; + } + async onload() { + // Settings Store + // this.register( + // settingsStore.subscribe((value) => { + // this.settings = value; + // }) + // ); + // Handle Settings + this.settings = Object.assign(DEFAULT_SETTINGS, await this.loadData()); + this.addSettingTab(new BetterWordCountSettingsTab(this.app, this)); + // Handle Statistics + if (this.settings.collectStats) { + this.statsManager = new StatsManager(this.app.vault, this.app.workspace, this); + } + // Handle Status Bar + let statusBarEl = this.addStatusBarItem(); + this.statusBar = new StatusBar(statusBarEl, this); + // Handle the Editor Plugins + this.registerEditorExtension([pluginField.init(() => this), statusBarEditorPlugin, sectionWordCountEditorPlugin]); + this.registerEvent(this.app.workspace.on("active-leaf-change", async (leaf) => { + if (leaf.view.getViewType() !== "markdown") { + this.statusBar.updateAltBar(); + } + if (!this.settings.collectStats) + return; + await this.statsManager.recalcTotals(); + })); + this.registerEvent(this.app.vault.on("delete", async () => { + if (!this.settings.collectStats) + return; + await this.statsManager.recalcTotals(); + })); + // Register a new action for right clicking on folders + this.registerEvent(this.app.workspace.on("file-menu", (menu, file, source) => { + handleFileMenu(menu, file, source, this); + })); + } + async saveSettings() { + await this.saveData(this.settings); + } + onDisplaySectionCountsChange() { + this.app.workspace.getLeavesOfType("markdown").forEach((leaf) => { + if ((leaf === null || leaf === void 0 ? void 0 : leaf.view) instanceof obsidian.MarkdownView) { + const cm = leaf.view.editor.cm; + if (cm.dispatch) { + cm.dispatch({ + effects: [settingsChanged.of()], + }); + } + } + }); + } +} + +module.exports = BetterWordCount; + + +/* nosourcemap */ \ No newline at end of file diff --git a/.obsidian/plugins/better-word-count/manifest.json b/.obsidian/plugins/better-word-count/manifest.json new file mode 100644 index 0000000..868ee8d --- /dev/null +++ b/.obsidian/plugins/better-word-count/manifest.json @@ -0,0 +1,9 @@ +{ + "id": "better-word-count", + "name": "Better Word Count", + "version": "0.10.1", + "description": "Counts the words of selected text in the editor.", + "author": "Luke Leppan", + "authorUrl": "https://lukeleppan.com", + "isDesktopOnly": false +} diff --git a/.obsidian/plugins/better-word-count/styles.css b/.obsidian/plugins/better-word-count/styles.css new file mode 100644 index 0000000..dc35030 --- /dev/null +++ b/.obsidian/plugins/better-word-count/styles.css @@ -0,0 +1,37 @@ +details.bwc-sb-item-setting { + border: 1px solid var(--background-modifier-border); + border-radius: 10px; + padding: 10px 5px 20px 10px; + margin-top: 5px; + margin-bottom: 10px; +} +.bwc-sb-item-setting summary::marker { + font-size: 10px; +} + +/* .bwc-sb-item-setting summary { */ +/* margin-bottom: 5px; */ +/* } */ +.bwc-sb-item-setting summary span.bwc-sb-buttons { + float: right; +} + +.bwc-status-bar-settings-title { + margin-bottom: 0px; +} + +.bwc-section-count { + background: var(--background-secondary); + border-radius: var(--tag-radius); + color: var(--text-muted); + content: var(--word-count); + display: inline-flex; + font-size: var(--font-ui-smaller); + font-weight: var(--font-normal); + line-height: 1; + margin: calc(-1 * var(--size-2-3)) 0 calc(-1 * var(--size-2-3)) var(--size-4-2); + padding: var(--size-2-3) var(--size-4-2); + pointer-events: none; + position: relative; + top: -3px; +} diff --git a/.obsidian/plugins/bmo-chatbot/data.json b/.obsidian/plugins/bmo-chatbot/data.json new file mode 100644 index 0000000..2d30767 --- /dev/null +++ b/.obsidian/plugins/bmo-chatbot/data.json @@ -0,0 +1,115 @@ +{ + "profiles": { + "profile": "BMO.md", + "profileFolderPath": "BMO/Profiles", + "lastLoadedChatHistoryPath": null, + "lastLoadedChatHistory": [ + null + ] + }, + "general": { + "model": "", + "system_role": "You are a helpful assistant.", + "max_tokens": null, + "temperature": "1.00", + "enableReferenceCurrentNote": false + }, + "appearance": { + "userName": "YOU", + "chatbotName": "BMO", + "chatbotContainerBackgroundColor": "#--background-secondary", + "messageContainerBackgroundColor": "#--background-secondary", + "userMessageFontColor": "#--text-normal", + "userMessageBackgroundColor": "#--background-primary", + "botMessageFontColor": "#--text-normal", + "botMessageBackgroundColor": "#--background-secondary", + "chatBoxFontColor": "#--text-normal", + "chatBoxBackgroundColor": "#--interactive-accent", + "enableHeader": true, + "enableScrollBar": false, + "bmoGenerateBackgroundColor": "#0c0a12", + "bmoGenerateFontColor": "#--text-normal" + }, + "prompts": { + "prompt": "", + "promptFolderPath": "BMO/Prompts" + }, + "editor": { + "systen_role": "You are a helpful assistant." + }, + "chatHistory": { + "chatHistoryPath": "BMO/History", + "templateFilePath": "", + "allowRenameNoteTitle": false + }, + "OllamaConnection": { + "RESTAPIURL": "http://localhost:11434", + "enableStream": true, + "ollamaParameters": { + "mirostat": "0", + "mirostat_eta": "0.10", + "mirostat_tau": "5.00", + "num_ctx": "2048", + "num_gqa": null, + "num_thread": null, + "repeat_last_n": "64", + "repeat_penalty": "1.10", + "seed": null, + "stop": [], + "tfs_z": "1.00", + "top_k": "40", + "top_p": "0.90", + "min_p": "0.00", + "keep_alive": "" + }, + "ollamaModels": [] + }, + "RESTAPIURLConnection": { + "APIKey": "", + "RESTAPIURL": "", + "enableStream": false, + "RESTAPIURLModels": [] + }, + "APIConnections": { + "anthropic": { + "APIKey": "", + "anthropicModels": [] + }, + "googleGemini": { + "APIKey": "", + "enableStream": false, + "geminiModels": [] + }, + "mistral": { + "APIKey": "", + "enableStream": false, + "mistralModels": [] + }, + "openAI": { + "APIKey": "", + "openAIBaseUrl": "https://api.openai.com/v1", + "enableStream": true, + "openAIBaseModels": [] + }, + "openRouter": { + "APIKey": "", + "enableStream": false, + "openRouterModels": [] + } + }, + "toggleGeneralSettings": true, + "toggleAppearanceSettings": false, + "togglePromptSettings": false, + "toggleEditorSettings": false, + "toggleChatHistorySettings": false, + "toggleProfileSettings": false, + "toggleAPIConnectionSettings": true, + "toggleOpenAISettings": false, + "toggleMistralSettings": false, + "toggleGoogleGeminiSettings": false, + "toggleAnthropicSettings": false, + "toggleRESTAPIURLSettings": true, + "toggleOpenRouterSettings": false, + "toggleOllamaSettings": true, + "toggleAdvancedSettings": false +} \ No newline at end of file diff --git a/.obsidian/plugins/bmo-chatbot/data/messageHistory_BMO.json b/.obsidian/plugins/bmo-chatbot/data/messageHistory_BMO.json new file mode 100644 index 0000000..e69de29 diff --git a/.obsidian/plugins/bmo-chatbot/main.js b/.obsidian/plugins/bmo-chatbot/main.js new file mode 100644 index 0000000..499e7f6 --- /dev/null +++ b/.obsidian/plugins/bmo-chatbot/main.js @@ -0,0 +1,10079 @@ +/* +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 __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// src/main.ts +var main_exports = {}; +__export(main_exports, { + DEFAULT_SETTINGS: () => DEFAULT_SETTINGS, + checkActiveFile: () => checkActiveFile, + default: () => BMOGPT15, + defaultFrontMatter: () => defaultFrontMatter, + updateFrontMatter: () => updateFrontMatter, + updateProfile: () => updateProfile, + updateSettingsFromFrontMatter: () => updateSettingsFromFrontMatter +}); +module.exports = __toCommonJS(main_exports); +var import_obsidian27 = require("obsidian"); + +// src/view.ts +var import_obsidian7 = require("obsidian"); + +// src/components/chat/Commands.ts +var import_obsidian6 = require("obsidian"); + +// src/utils/ColorConverter.ts +function colorToHex(colorValue) { + if (colorValue.startsWith("hsl")) { + const match = colorValue.match(/(\d+(\.\d+)?)%?/g); + if (match === null || match.length < 3) { + throw new Error("Invalid HSL value"); + } + const h = parseInt(match[0]) / 360; + const s = parseInt(match[1]) / 100; + const l = parseInt(match[2]) / 100; + const q = l < 0.5 ? l * (1 + s) : l + s - l * s; + const p = 2 * l - q; + const r = hue2rgb(p, q, h + 1 / 3); + const g2 = hue2rgb(p, q, h); + const b = hue2rgb(p, q, h - 1 / 3); + const toHex = function(c) { + const hex2 = Math.round(c * 255).toString(16); + return hex2.length === 1 ? "0" + hex2 : hex2; + }; + const hex = "#" + toHex(r) + toHex(g2) + toHex(b); + return hex; + } else if (colorValue.startsWith("rgb")) { + const sep = colorValue.indexOf(",") > -1 ? "," : " "; + const rgbArray = colorValue.substr(4).split(")")[0].split(sep); + let r = (+rgbArray[0]).toString(16), g2 = (+rgbArray[1]).toString(16), b = (+rgbArray[2]).toString(16); + if (r.length == 1) + r = "0" + r; + if (g2.length == 1) + g2 = "0" + g2; + if (b.length == 1) + b = "0" + b; + return "#" + r + g2 + b; + } else { + return colorValue; + } +} +function hue2rgb(p, q, t) { + if (t < 0) + t += 1; + if (t > 1) + t -= 1; + if (t < 1 / 6) + return p + (q - p) * 6 * t; + if (t < 1 / 2) + return q; + if (t < 2 / 3) + return p + (q - p) * (2 / 3 - t) * 6; + return p; +} +var isValidHexColor = (color) => { + const hexColorRegex = /^[0-9A-Fa-f]{6}$/; + return hexColorRegex.test(color); +}; + +// src/components/FetchModelResponse.ts +var import_obsidian4 = require("obsidian"); + +// src/components/chat/Buttons.ts +var import_obsidian = require("obsidian"); + +// src/components/editor/ReferenceCurrentNote.ts +var referenceCurrentNoteContent = ""; +async function getActiveFileContent(plugin, settings) { + const dotElement = document.querySelector(".dotIndicator"); + referenceCurrentNoteContent = ""; + if (settings.general.enableReferenceCurrentNote === true) { + if (dotElement) { + dotElement.style.backgroundColor = "#da2c2c"; + referenceCurrentNoteContent = ""; + } + const activeFile = plugin.app.workspace.getActiveFile(); + if ((activeFile == null ? void 0 : activeFile.extension) === "md") { + if (dotElement) { + dotElement.style.backgroundColor = "green"; + } + const content = await plugin.app.vault.read(activeFile); + const clearYamlContent = content.replace(/---[\s\S]+?---/, "").trim(); + referenceCurrentNoteContent = "\n\nAdditional Note:\n\n" + clearYamlContent + "\n\n"; + } + } + return referenceCurrentNoteContent; +} +function getCurrentNoteContent() { + return referenceCurrentNoteContent; +} + +// src/components/chat/Buttons.ts +function regenerateUserButton(plugin, settings) { + const regenerateButton = document.createElement("button"); + regenerateButton.textContent = "regenerate"; + (0, import_obsidian.setIcon)(regenerateButton, "refresh-ccw"); + regenerateButton.classList.add("regenerate-button"); + regenerateButton.title = "regenerate"; + let lastClickedElement = null; + regenerateButton.addEventListener("click", async function(event) { + event.stopPropagation(); + lastClickedElement = event.target; + while (lastClickedElement && !lastClickedElement.classList.contains("userMessage")) { + lastClickedElement = lastClickedElement.parentElement; + } + let index2 = -1; + if (lastClickedElement) { + const userMessages = Array.from(document.querySelectorAll("#messageContainer .userMessage")); + index2 = userMessages.indexOf(lastClickedElement) * 2; + } + if (index2 !== -1) { + deleteMessage(plugin, index2 + 1); + if (OPENAI_MODELS.includes(settings.general.model) || settings.APIConnections.openAI.openAIBaseModels.includes(settings.general.model)) { + try { + if (settings.APIConnections.openAI.enableStream) { + await fetchOpenAIAPIResponseStream(plugin, settings, index2); + } else { + await fetchOpenAIAPIResponse(plugin, settings, index2); + } + } catch (error) { + new import_obsidian.Notice("Error occurred while fetching completion: " + error.message); + console.log(error.message); + } + } else if (settings.OllamaConnection.RESTAPIURL && settings.OllamaConnection.ollamaModels.includes(settings.general.model)) { + if (settings.OllamaConnection.enableStream) { + await fetchOllamaResponseStream(plugin, settings, index2); + } else { + await fetchOllamaResponse(plugin, settings, index2); + } + } else if (settings.RESTAPIURLConnection.RESTAPIURLModels.includes(settings.general.model)) { + if (settings.RESTAPIURLConnection.enableStream) { + await fetchRESTAPIURLResponseStream(plugin, settings, index2); + } else { + await fetchRESTAPIURLResponse(plugin, settings, index2); + } + } else if (settings.APIConnections.openRouter.openRouterModels.includes(settings.general.model)) { + if (settings.APIConnections.openRouter.enableStream) { + await fetchOpenRouterResponseStream(plugin, settings, index2); + } else { + await fetchOpenRouterResponse(plugin, settings, index2); + } + } else if (settings.APIConnections.mistral.mistralModels.includes(settings.general.model)) { + try { + if (settings.APIConnections.mistral.enableStream) { + await fetchMistralResponseStream(plugin, settings, index2); + } else { + await fetchMistralResponse(plugin, settings, index2); + } + } catch (error) { + console.error("Mistral Error:", error); + } + } else if (settings.APIConnections.googleGemini.geminiModels.includes(settings.general.model)) { + try { + if (settings.APIConnections.googleGemini.enableStream) { + await fetchGoogleGeminiResponseStream(plugin, settings, index2); + } else { + await fetchGoogleGeminiResponse(plugin, settings, index2); + } + } catch (error) { + console.error("Google Gemini Error:", error); + } + } else if (ANTHROPIC_MODELS.includes(settings.general.model)) { + try { + await fetchAnthropicResponse(plugin, settings, index2); + } catch (error) { + console.error("Anthropic Error:", error); + } + } + } else { + new import_obsidian.Notice("No models detected."); + } + }); + return regenerateButton; +} +function displayUserEditButton(plugin, settings, userPre) { + const editButton = document.createElement("button"); + editButton.textContent = "edit"; + (0, import_obsidian.setIcon)(editButton, "edit"); + editButton.classList.add("edit-button"); + editButton.title = "edit"; + let lastClickedElement = null; + editButton.addEventListener("click", function(event) { + var _a2; + const editContainer = document.createElement("div"); + editContainer.classList.add("edit-container"); + const textArea = document.createElement("textarea"); + textArea.classList.add("edit-textarea"); + textArea.value = (_a2 = userPre.textContent) != null ? _a2 : ""; + editContainer.appendChild(textArea); + const textareaEditButton = document.createElement("button"); + textareaEditButton.textContent = "Edit"; + textareaEditButton.classList.add("textarea-edit-button"); + textareaEditButton.title = "edit"; + const cancelButton = document.createElement("button"); + cancelButton.textContent = "Cancel"; + cancelButton.classList.add("textarea-cancel-button"); + cancelButton.title = "cancel"; + event.stopPropagation(); + lastClickedElement = event.target; + while (lastClickedElement && !lastClickedElement.classList.contains("userMessage")) { + lastClickedElement = lastClickedElement.parentElement; + } + textareaEditButton.addEventListener("click", async function() { + userPre.textContent = textArea.value.trim(); + editContainer.replaceWith(userPre); + if (lastClickedElement) { + const userMessages = Array.from(document.querySelectorAll("#messageContainer .userMessage")); + const index2 = userMessages.indexOf(lastClickedElement) * 2; + if (index2 !== -1) { + messageHistory[index2].content = textArea.value.trim(); + deleteMessage(plugin, index2 + 1); + const regex = /(!?)\[\[(.*?)\]\]/g; + let matches; + let inputModified = messageHistory[index2].content; + const replacements = /* @__PURE__ */ new Map(); + while ((matches = regex.exec(messageHistory[index2].content)) !== null) { + const exclamation = matches[1]; + const linktext = matches[2]; + const [path, subpath] = linktext.split("#"); + const file = plugin.app.metadataCache.getFirstLinkpathDest(path, ""); + if (file && file instanceof import_obsidian.TFile) { + try { + const filePath = file.path; + const fileExtension = filePath.split(".").pop(); + if (fileExtension !== "md") { + const isImageFile = /\.(jpg|jpeg|png|gif|webp|bmp|tiff|tif|svg)$/i.test(filePath); + if (!plugin.settings.OllamaConnection.ollamaModels.includes(plugin.settings.general.model)) { + replacements.set(matches[0], `${exclamation}[[${matches[2]}]]ERROR: File cannot be read.`); + } else if (plugin.settings.OllamaConnection.ollamaModels.includes(plugin.settings.general.model)) { + if (!isImageFile) { + replacements.set(matches[0], `${exclamation}[[${matches[2]}]]ERROR: File cannot be read.`); + } + } + continue; + } + const content = await plugin.app.vault.read(file); + let contentToInsert = content; + if (subpath) { + const lines = content.split("\n"); + let inSubpath = false; + const subpathContent = []; + let subpathLevel = 0; + for (const line of lines) { + if (line.startsWith("#")) { + const match = line.match(/^#+/); + const headingLevel = match ? match[0].length : 0; + if (inSubpath) { + if (headingLevel <= subpathLevel) { + break; + } + } + if (!inSubpath && line.toLowerCase().includes(subpath.toLowerCase())) { + inSubpath = true; + subpathLevel = headingLevel; + } + } + if (inSubpath) { + subpathContent.push(line); + } + } + contentToInsert = subpathContent.join("\n"); + } + replacements.set(matches[0], `${exclamation}[[${matches[2]}]]${contentToInsert}`); + } catch (err) { + console.error(`Failed to read the content of "${path}": ${err}`); + } + } else { + replacements.set(matches[0], `${exclamation}[[${matches[2]}]]File cannot be read.`); + } + } + for (const [original, replacement] of replacements) { + inputModified = inputModified.split(original).join(replacement); + } + inputModified = inputModified.replace(/(File cannot be read.<\/note-rendered>)+/g, "File cannot be read."); + messageHistory[index2].content = inputModified; + if (settings.OllamaConnection.RESTAPIURL && settings.OllamaConnection.ollamaModels.includes(settings.general.model)) { + if (settings.OllamaConnection.enableStream) { + await fetchOllamaResponseStream(plugin, settings, index2); + } else { + await fetchOllamaResponse(plugin, settings, index2); + } + } else if (settings.RESTAPIURLConnection.RESTAPIURLModels.includes(settings.general.model)) { + if (settings.RESTAPIURLConnection.enableStream) { + await fetchRESTAPIURLResponseStream(plugin, settings, index2); + } else { + await fetchRESTAPIURLResponse(plugin, settings, index2); + } + } else if (ANTHROPIC_MODELS.includes(settings.general.model)) { + try { + await fetchAnthropicResponse(plugin, settings, index2); + } catch (error) { + console.error("Anthropic Error:", error); + } + } else if (settings.APIConnections.googleGemini.geminiModels.includes(settings.general.model)) { + try { + if (settings.APIConnections.googleGemini.enableStream) { + await fetchGoogleGeminiResponseStream(plugin, settings, index2); + } else { + await fetchGoogleGeminiResponse(plugin, settings, index2); + } + } catch (error) { + console.error("Google GeminiError:", error); + } + } else if (settings.APIConnections.mistral.mistralModels.includes(settings.general.model)) { + try { + if (settings.APIConnections.mistral.enableStream) { + await fetchMistralResponseStream(plugin, settings, index2); + } else { + await fetchMistralResponse(plugin, settings, index2); + } + } catch (error) { + console.error("Mistral Error:", error); + } + } else if (OPENAI_MODELS.includes(settings.general.model) || settings.APIConnections.openAI.openAIBaseModels.includes(settings.general.model)) { + try { + if (settings.APIConnections.openAI.enableStream) { + await fetchOpenAIAPIResponseStream(plugin, settings, index2); + } else { + await fetchOpenAIAPIResponse(plugin, settings, index2); + } + } catch (error) { + new import_obsidian.Notice("Error occurred while fetching completion: " + error.message); + console.log(error.message); + } + } else if (settings.APIConnections.openRouter.openRouterModels.includes(settings.general.model)) { + if (settings.APIConnections.openRouter.enableStream) { + await fetchOpenRouterResponseStream(plugin, settings, index2); + } else { + await fetchOpenRouterResponse(plugin, settings, index2); + } + } + } else { + new import_obsidian.Notice("No models detected."); + } + } + }); + cancelButton.addEventListener("click", function() { + editContainer.replaceWith(userPre); + }); + editContainer.appendChild(textareaEditButton); + editContainer.appendChild(cancelButton); + if (userPre.parentNode !== null) { + userPre.parentNode.replaceChild(editContainer, userPre); + } + }); + return editButton; +} +function displayBotEditButton(plugin, message) { + const editButton = document.createElement("button"); + editButton.textContent = "edit"; + (0, import_obsidian.setIcon)(editButton, "edit"); + editButton.classList.add("edit-button"); + editButton.title = "edit"; + let lastClickedElement = null; + editButton.addEventListener("click", function(event) { + const editContainer = document.createElement("div"); + editContainer.classList.add("edit-container"); + const textArea = document.createElement("textarea"); + textArea.classList.add("edit-textarea"); + textArea.value = message; + const textareaEditButton = document.createElement("button"); + textareaEditButton.textContent = "Edit"; + textareaEditButton.classList.add("textarea-edit-button"); + textareaEditButton.title = "edit"; + const cancelButton = document.createElement("button"); + cancelButton.textContent = "Cancel"; + cancelButton.classList.add("textarea-cancel-button"); + cancelButton.title = "cancel"; + editContainer.appendChild(textArea); + event.stopPropagation(); + lastClickedElement = event.target; + while (lastClickedElement && !lastClickedElement.classList.contains("botMessage")) { + lastClickedElement = lastClickedElement.parentElement; + } + let messageBlock = lastClickedElement == null ? void 0 : lastClickedElement.querySelector(".messageBlock"); + if (messageBlock) { + messageBlock.innerHTML = ""; + messageBlock.appendChild(editContainer); + } else { + console.log("messageBlock not found."); + } + textareaEditButton.addEventListener("click", async function() { + message = textArea.value; + editContainer.remove(); + messageBlock == null ? void 0 : messageBlock.remove(); + messageBlock = document.createElement("div"); + messageBlock.className = "messageBlock"; + lastClickedElement == null ? void 0 : lastClickedElement.appendChild(messageBlock); + await import_obsidian.MarkdownRenderer.render(plugin.app, message, messageBlock, "/", plugin); + addParagraphBreaks(messageBlock); + const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); + copyCodeBlocks.forEach((copyCodeBlock) => { + copyCodeBlock.textContent = "Copy"; + (0, import_obsidian.setIcon)(copyCodeBlock, "copy"); + }); + if (lastClickedElement) { + const allMessages = Array.from(document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage")); + const index2 = allMessages.indexOf(lastClickedElement); + if (index2 !== -1) { + const regex = /(!?)\[\[(.*?)\]\]/g; + let matches; + let inputModified = textArea.value; + const replacements = /* @__PURE__ */ new Map(); + while ((matches = regex.exec(textArea.value)) !== null) { + const exclamation = matches[1]; + const linktext = matches[2]; + const [path, subpath] = linktext.split("#"); + const file = plugin.app.metadataCache.getFirstLinkpathDest(path, ""); + if (file && file instanceof import_obsidian.TFile) { + try { + const filePath = file.path; + const fileExtension = filePath.split(".").pop(); + if (fileExtension !== "md") { + const isImageFile = /\.(jpg|jpeg|png|gif|webp|bmp|tiff|tif|svg)$/i.test(filePath); + if (!plugin.settings.OllamaConnection.ollamaModels.includes(plugin.settings.general.model)) { + replacements.set(matches[0], `${exclamation}[[${matches[2]}]]ERROR: File cannot be read.`); + } else if (plugin.settings.OllamaConnection.ollamaModels.includes(plugin.settings.general.model)) { + if (!isImageFile) { + replacements.set(matches[0], `${exclamation}[[${matches[2]}]]ERROR: File cannot be read.`); + } + } + continue; + } + const content = await plugin.app.vault.read(file); + let contentToInsert = content; + if (subpath) { + const lines = content.split("\n"); + let inSubpath = false; + const subpathContent = []; + let subpathLevel = 0; + for (const line of lines) { + if (line.startsWith("#")) { + const match = line.match(/^#+/); + const headingLevel = match ? match[0].length : 0; + if (inSubpath) { + if (headingLevel <= subpathLevel) { + break; + } + } + if (!inSubpath && line.toLowerCase().includes(subpath.toLowerCase())) { + inSubpath = true; + subpathLevel = headingLevel; + } + } + if (inSubpath) { + subpathContent.push(line); + } + } + contentToInsert = subpathContent.join("\n"); + } + replacements.set(matches[0], `${exclamation}[[${matches[2]}]]${contentToInsert}`); + } catch (err) { + console.error(`Failed to read the content of "${path}": ${err}`); + } + } else { + replacements.set(matches[0], `${exclamation}[[${matches[2]}]]File cannot be read.`); + } + } + for (const [original, replacement] of replacements) { + inputModified = inputModified.split(original).join(replacement); + } + inputModified = inputModified.replace(/(File cannot be read.<\/note-rendered>)+/g, "File cannot be read."); + messageHistory[index2].content = inputModified; + const jsonString = JSON.stringify(messageHistory, null, 4); + try { + await plugin.app.vault.adapter.write(fileNameMessageHistoryJson(plugin), jsonString); + } catch (error) { + console.error("Error writing to message history file:", error); + } + } else { + new import_obsidian.Notice("No models detected."); + } + } + }); + cancelButton.addEventListener("click", async function() { + editContainer.remove(); + messageBlock == null ? void 0 : messageBlock.remove(); + messageBlock = document.createElement("div"); + messageBlock.className = "messageBlock"; + lastClickedElement == null ? void 0 : lastClickedElement.appendChild(messageBlock); + const regexRenderedBlock = /[\s\S]*?<\/block-rendered>/g; + message = message.replace(regexRenderedBlock, "").trim(); + const regexRenderedNote = /[\s\S]*?<\/note-rendered>/g; + message = message.replace(regexRenderedNote, "").trim(); + await import_obsidian.MarkdownRenderer.render(plugin.app, message, messageBlock, "/", plugin); + addParagraphBreaks(messageBlock); + const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); + copyCodeBlocks.forEach((copyCodeBlock) => { + copyCodeBlock.textContent = "Copy"; + (0, import_obsidian.setIcon)(copyCodeBlock, "copy"); + }); + }); + editContainer.appendChild(textareaEditButton); + editContainer.appendChild(cancelButton); + }); + return editButton; +} +function displayUserCopyButton(userPre) { + const copyButton = document.createElement("button"); + copyButton.textContent = "copy"; + (0, import_obsidian.setIcon)(copyButton, "copy"); + copyButton.classList.add("copy-button"); + copyButton.title = "copy"; + copyButton.addEventListener("click", function() { + const messageText = userPre.textContent; + if (messageText !== null) { + copyMessageToClipboard(messageText); + new import_obsidian.Notice("Copied user message."); + } else { + console.error("Message content is null. Cannot copy."); + } + }); + return copyButton; +} +function displayBotCopyButton(settings, message) { + const copyButton = document.createElement("button"); + copyButton.textContent = "copy"; + (0, import_obsidian.setIcon)(copyButton, "copy"); + copyButton.classList.add("copy-button"); + copyButton.title = "copy"; + copyButton.addEventListener("click", function() { + if (message !== null) { + copyMessageToClipboard(message); + new import_obsidian.Notice("Copied bot message."); + } else { + console.error("Message content is null. Cannot copy."); + } + }); + return copyButton; +} +function copyMessageToClipboard(message) { + navigator.clipboard.writeText(message).then(function() { + }).catch(function(err) { + console.error("Unable to copy message: ", err); + }); +} +function displayAppendButton(plugin, settings, message) { + const appendButton = document.createElement("button"); + appendButton.textContent = "append"; + (0, import_obsidian.setIcon)(appendButton, "plus-square"); + appendButton.classList.add("append-button"); + appendButton.title = "append"; + const messageText = message; + appendButton.addEventListener("click", async function(event) { + var _a2, _b; + if (((_a2 = checkActiveFile) == null ? void 0 : _a2.extension) === "md") { + if (checkActiveFile !== lastCursorPositionFile) { + getActiveFileContent(plugin, settings); + const existingContent = await plugin.app.vault.read(checkActiveFile); + const updatedContent = existingContent + "\n" + messageText; + plugin.app.vault.modify(checkActiveFile, updatedContent); + } else { + (_b = activeEditor) == null ? void 0 : _b.replaceRange(messageText, lastCursorPosition); + } + event.stopPropagation(); + new import_obsidian.Notice("Appended response."); + } else { + new import_obsidian.Notice("No active Markdown file detected."); + } + }); + return appendButton; +} +function displayTrashButton(plugin) { + const trashButton = document.createElement("button"); + trashButton.textContent = "trash"; + (0, import_obsidian.setIcon)(trashButton, "trash"); + trashButton.classList.add("trash-button"); + trashButton.title = "trash"; + let lastClickedElement = null; + trashButton.addEventListener("click", function(event) { + event.stopPropagation(); + lastClickedElement = event.target; + while (lastClickedElement && !lastClickedElement.classList.contains("userMessage")) { + lastClickedElement = lastClickedElement.parentElement; + } + if (lastClickedElement) { + const userMessages = Array.from(document.querySelectorAll("#messageContainer .userMessage")); + const index2 = userMessages.indexOf(lastClickedElement) * 2; + if (index2 !== -1) { + const modal = new import_obsidian.Modal(plugin.app); + modal.contentEl.innerHTML = ` + + `; + const confirmDeleteButton = modal.contentEl.querySelector("#confirmDelete"); + confirmDeleteButton == null ? void 0 : confirmDeleteButton.addEventListener("click", async function() { + deleteMessage(plugin, index2); + new import_obsidian.Notice("Message deleted."); + modal.close(); + }); + modal.open(); + } + } + }); + return trashButton; +} +async function deleteMessage(plugin, index2) { + const messageContainer = document.querySelector("#messageContainer"); + const divElements = messageContainer == null ? void 0 : messageContainer.querySelectorAll("div.botMessage, div.userMessage"); + if (divElements && divElements.length > 0 && index2 >= 0 && index2 < divElements.length) { + messageContainer == null ? void 0 : messageContainer.removeChild(divElements[index2]); + if (index2 + 1 < divElements.length) { + const nextMessage = divElements[index2 + 1]; + if (nextMessage.classList.contains("botMessage")) { + messageContainer == null ? void 0 : messageContainer.removeChild(nextMessage); + } + } + } + if (messageHistory[index2 + 1] && messageHistory[index2 + 1].role === "assistant") { + messageHistory.splice(index2, 2); + } else { + messageHistory.splice(index2, 1); + } + const jsonString = JSON.stringify(messageHistory, null, 4); + try { + await plugin.app.vault.adapter.write(fileNameMessageHistoryJson(plugin), jsonString); + } catch (error) { + console.error("Error writing messageHistory.json", error); + } +} + +// src/components/chat/Message.ts +var import_obsidian2 = require("obsidian"); +async function addMessage(plugin, input, messageType, settings, index2) { + const messageObj = { + role: "", + content: "", + images: [] + }; + const referenceCurrentNoteContent2 = getCurrentNoteContent() || ""; + const fullInput = referenceCurrentNoteContent2 + input; + const imagesVaultPath = []; + if (plugin.settings.OllamaConnection.ollamaModels.includes(plugin.settings.general.model)) { + const imageMatch = fullInput.match(/!?\[\[(.*?)\]\]/g); + const imageLink = imageMatch ? imageMatch.map((item) => item.startsWith("!") ? item.slice(3, -2) : item.slice(2, -2)).filter((link) => /\.(jpg|jpeg|png|gif|webp|bmp|tiff|tif|svg)$/i.test(link)) : []; + if (imageLink.length > 0) { + imageLink.forEach((link) => { + const imageFile = this.app.metadataCache.getFirstLinkpathDest(link, ""); + const image = imageFile ? this.app.vault.adapter.getFullPath(imageFile.path) : null; + if (image) { + imagesVaultPath.push(image); + } + }); + } + } + if (messageType === "userMessage") { + messageObj.role = "user"; + messageObj.content = input; + messageObj.images = imagesVaultPath; + } else if (messageType === "botMessage") { + messageObj.role = "assistant"; + messageObj.content = input; + const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const botMessageToolBarDiv = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".botMessageToolBar"); + const buttonContainerDiv = document.createElement("div"); + buttonContainerDiv.className = "button-container"; + botMessageToolBarDiv == null ? void 0 : botMessageToolBarDiv.appendChild(buttonContainerDiv); + const submitButton = document.querySelector(".submit-button"); + submitButton.textContent = "send"; + (0, import_obsidian2.setIcon)(submitButton, "arrow-up"); + submitButton.title = "send"; + if (!messageObj.content.includes("commandBotMessage") && !messageObj.content.includes("errorBotMessage")) { + const editButton = displayBotEditButton(plugin, messageObj.content); + const copyBotButton = displayBotCopyButton(settings, messageObj.content); + const appendButton = displayAppendButton(plugin, settings, messageObj.content); + buttonContainerDiv.appendChild(editButton); + buttonContainerDiv.appendChild(copyBotButton); + buttonContainerDiv.appendChild(appendButton); + } + } + try { + messageHistory.splice(index2 + 1, 0, messageObj); + const jsonString = JSON.stringify(messageHistory, null, 4); + await plugin.app.vault.adapter.write(fileNameMessageHistoryJson(plugin), jsonString); + const messageContainerEl = document.getElementById("messageContainer"); + if (messageContainerEl) { + const lastBotMessage = messageContainerEl.querySelector(".botMessage:last-child"); + if (lastBotMessage) { + const getBlockLanguage = lastBotMessage.querySelectorAll('div[class^="block-language-"]'); + const replacedLangaugeBlocks = /* @__PURE__ */ new Set(); + getBlockLanguage.forEach(async (block) => { + if (!block.querySelector(".rendered-markdown-output") && messageType === "botMessage") { + const blockToMarkdown = (0, import_obsidian2.htmlToMarkdown)(block || ""); + const markdownNode = document.createElement("div"); + markdownNode.classList.add("rendered-markdown-output"); + markdownNode.textContent = ` + + +${blockToMarkdown} + + +`; + let renderedMarkdownOutput = markdownNode.textContent; + renderedMarkdownOutput = renderedMarkdownOutput.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, p1, p2) => { + const filename = p2.split("/").pop().replace(".md", ""); + return `[[${filename}]]`; + }); + const extractBlocks = (message) => { + const regex = /```(\w+)\n([\s\S]*?)```(\s*([\s\S]*?<\/block-rendered>\s*)?)/g; + let updatedMessage = message; + for (const match of [...message.matchAll(regex)]) { + const oldBlock = match[0]; + const blockContent = match[2].trim(); + if (replacedLangaugeBlocks.has(oldBlock)) { + continue; + } + const newBlock = `\`\`\`${match[1]} +${blockContent} +\`\`\`${renderedMarkdownOutput}`; + updatedMessage = updatedMessage.replace(oldBlock, newBlock); + replacedLangaugeBlocks.add(newBlock); + break; + } + return updatedMessage; + }; + const updatedMessageContent = extractBlocks(messageObj.content); + messageObj.content = updatedMessageContent; + const updatedJsonString = JSON.stringify(messageHistory, null, 4); + await plugin.app.vault.adapter.write(fileNameMessageHistoryJson(plugin), updatedJsonString); + } + }); + const getNoteContent = lastBotMessage.querySelectorAll(".internal-embed.markdown-embed.inline-embed.is-loaded"); + const replacedNoteBlocks = /* @__PURE__ */ new Set(); + getNoteContent.forEach(async (link) => { + if (!link.querySelector(".rendered-markdown-output")) { + const blockToMarkdown = (0, import_obsidian2.htmlToMarkdown)(link || ""); + const markdownNode = document.createElement("div"); + markdownNode.classList.add("rendered-markdown-output"); + markdownNode.textContent = ` + + +${blockToMarkdown} + + +`; + const renderedMarkdownOutput = markdownNode.textContent; + const extractLinks = (message) => { + const regex = /(!\[\[.*?\]\])(\s*([\s\S]*?<\/note-rendered>\s*)?)/g; + let updatedMessage = message; + for (const match of [...message.matchAll(regex)]) { + const oldLink = match[0]; + const noteLink = match[1]; + if (replacedNoteBlocks.has(oldLink)) { + continue; + } + const newLink = `${noteLink} +${renderedMarkdownOutput}`; + updatedMessage = updatedMessage.replace(oldLink, newLink); + replacedNoteBlocks.add(newLink); + break; + } + return updatedMessage; + }; + const updatedMessageContent = extractLinks(messageObj.content); + messageObj.content = updatedMessageContent; + const updatedJsonString = JSON.stringify(messageHistory, null, 4); + await plugin.app.vault.adapter.write(fileNameMessageHistoryJson(plugin), updatedJsonString); + } + }); + } + } + } catch (error) { + console.error("Error writing to message history file:", error); + } +} +function addParagraphBreaks(messageBlock) { + const paragraphs = messageBlock.querySelectorAll("p"); + for (let i = 0; i < paragraphs.length; i++) { + const p = paragraphs[i]; + const nextSibling = p.nextElementSibling; + if (nextSibling && nextSibling.nodeName === "P") { + const br = document.createElement("br"); + const parent = p.parentNode; + if (parent) { + parent.insertBefore(br, nextSibling); + } + } + } +} +function updateUnresolvedInternalLinks(plugin, divBlock) { + const internalLinks = divBlock.querySelectorAll("a"); + internalLinks.forEach((link) => { + let linkHref = link.getAttribute("href") || link.getAttribute("data-href"); + if (linkHref) { + if (linkHref.includes("#")) { + linkHref = linkHref.split("#")[0]; + } + const linkExists = plugin.app.metadataCache.getFirstLinkpathDest(linkHref, ""); + if (!linkExists) { + link.style.color = "grey"; + } + } + }); +} + +// src/components/chat/BotMessage.ts +var import_obsidian3 = require("obsidian"); +function displayBotMessage(plugin, settings, messageHistory2, message) { + const botMessageDiv = document.createElement("div"); + botMessageDiv.className = "botMessage"; + botMessageDiv.style.backgroundColor = colorToHex(settings.appearance.botMessageBackgroundColor || getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor).trim()); + botMessageDiv.style.color = settings.appearance.botMessageFontColor || DEFAULT_SETTINGS.appearance.botMessageFontColor; + const botMessageToolBarDiv = document.createElement("div"); + botMessageToolBarDiv.className = "botMessageToolBar"; + const buttonContainerDiv = document.createElement("div"); + buttonContainerDiv.className = "button-container"; + const botNameSpan = document.createElement("span"); + botNameSpan.textContent = settings.appearance.chatbotName || DEFAULT_SETTINGS.appearance.chatbotName; + botNameSpan.className = "chatbotName"; + botMessageToolBarDiv.appendChild(botNameSpan); + botMessageToolBarDiv.appendChild(buttonContainerDiv); + const messageBlockDiv = document.createElement("div"); + messageBlockDiv.className = "messageBlock"; + const regexRenderedBlock = /[\s\S]*?<\/block-rendered>/g; + message = message.replace(regexRenderedBlock, "").trim(); + const regexRenderedNote = /[\s\S]*?<\/note-rendered>/g; + message = message.replace(regexRenderedNote, "").trim(); + import_obsidian3.MarkdownRenderer.render(plugin.app, message, messageBlockDiv, "", plugin); + if (!message.includes("commandBotMessage") && !message.includes("errorBotMessage")) { + const editButton = displayBotEditButton(plugin, message); + const copyBotButton = displayBotCopyButton(settings, message); + const appendButton = displayAppendButton(plugin, settings, message); + buttonContainerDiv.appendChild(editButton); + buttonContainerDiv.appendChild(copyBotButton); + buttonContainerDiv.appendChild(appendButton); + addParagraphBreaks(messageBlockDiv); + } + const copyCodeBlocks = messageBlockDiv.querySelectorAll(".copy-code-button"); + copyCodeBlocks.forEach((copyCodeBlock) => { + copyCodeBlock.textContent = "Copy"; + (0, import_obsidian3.setIcon)(copyCodeBlock, "copy"); + }); + botMessageDiv.appendChild(botMessageToolBarDiv); + botMessageDiv.appendChild(messageBlockDiv); + return botMessageDiv; +} +function displayLoadingBotMessage(settings) { + const botMessageDiv = document.createElement("div"); + botMessageDiv.className = "botMessage"; + botMessageDiv.style.backgroundColor = colorToHex(settings.appearance.botMessageBackgroundColor || getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor).trim()); + botMessageDiv.style.color = settings.appearance.botMessageFontColor || DEFAULT_SETTINGS.appearance.botMessageFontColor; + const botMessageToolBarDiv = document.createElement("div"); + botMessageToolBarDiv.className = "botMessageToolBar"; + const botNameSpan = document.createElement("span"); + botNameSpan.textContent = settings.appearance.chatbotName || DEFAULT_SETTINGS.appearance.chatbotName; + botNameSpan.className = "chatbotName"; + const messageBlockDiv = document.createElement("div"); + messageBlockDiv.className = "messageBlock"; + const loadingEl = document.createElement("span"); + loadingEl.setAttribute("id", "loading"); + for (let i = 0; i < 3; i++) { + const dotSpan = document.createElement("span"); + dotSpan.textContent = "."; + loadingEl.appendChild(dotSpan); + } + botMessageToolBarDiv.appendChild(botNameSpan); + botMessageDiv.appendChild(botMessageToolBarDiv); + botMessageDiv.appendChild(messageBlockDiv); + botMessageDiv.appendChild(loadingEl); + return botMessageDiv; +} +function displayCommandBotMessage(plugin, settings, messageHistory2, message) { + const botMessageDiv = document.createElement("div"); + botMessageDiv.className = "botMessage"; + botMessageDiv.style.backgroundColor = colorToHex(settings.appearance.botMessageBackgroundColor || getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor).trim()); + const botMessageToolBarDiv = document.createElement("div"); + botMessageToolBarDiv.className = "botMessageToolBar"; + const botNameSpan = document.createElement("span"); + botNameSpan.textContent = settings.appearance.chatbotName || DEFAULT_SETTINGS.appearance.chatbotName; + botNameSpan.className = "chatbotName"; + const messageBlockDiv = document.createElement("div"); + messageBlockDiv.className = "messageBlock"; + const displayCommandBotMessageDiv = document.createElement("div"); + displayCommandBotMessageDiv.className = "commandBotMessage"; + displayCommandBotMessageDiv.innerHTML = message; + messageBlockDiv.appendChild(displayCommandBotMessageDiv); + botMessageToolBarDiv.appendChild(botNameSpan); + botMessageDiv.appendChild(botMessageToolBarDiv); + botMessageDiv.appendChild(messageBlockDiv); + const index2 = messageHistory2.length - 1; + addMessage(plugin, messageBlockDiv.innerHTML, "botMessage", settings, index2); + return botMessageDiv; +} +function displayErrorBotMessage(plugin, settings, messageHistory2, message) { + const botMessageDiv = document.createElement("div"); + botMessageDiv.className = "botMessage"; + botMessageDiv.style.backgroundColor = colorToHex(settings.appearance.botMessageBackgroundColor || getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor).trim()); + const botMessageToolBarDiv = document.createElement("div"); + botMessageToolBarDiv.className = "botMessageToolBar"; + const botNameSpan = document.createElement("span"); + botNameSpan.textContent = settings.appearance.chatbotName || DEFAULT_SETTINGS.appearance.chatbotName; + botNameSpan.className = "chatbotName"; + const messageBlockDiv = document.createElement("div"); + messageBlockDiv.className = "messageBlock"; + const displayErrorBotMessageDiv = document.createElement("div"); + displayErrorBotMessageDiv.className = "errorBotMessage"; + const BotP = document.createElement("p"); + BotP.textContent = message; + console.error(message); + messageBlockDiv.appendChild(displayErrorBotMessageDiv); + displayErrorBotMessageDiv.appendChild(BotP); + botMessageToolBarDiv.appendChild(botNameSpan); + botMessageDiv.appendChild(botMessageToolBarDiv); + botMessageDiv.appendChild(messageBlockDiv); + const index2 = messageHistory2.length - 1; + addMessage(plugin, messageBlockDiv.innerHTML, "botMessage", this.settings, index2); + return botMessageDiv; +} + +// src/components/chat/Prompt.ts +async function getPrompt(plugin, settings) { + if (settings.prompts.prompt.trim() === "") { + return ""; + } + const promptFilePath = settings.prompts.promptFolderPath + "/" + settings.prompts.prompt; + try { + const content = await plugin.app.vault.adapter.read(promptFilePath); + const clearYamlContent = content.replace(/---[\s\S]+?---/, "").trim(); + return "\n\n" + clearYamlContent + "\n\n"; + } catch (error) { + console.error(`Error reading file ${promptFilePath}:`, error); + return null; + } +} + +// src/components/FetchModelResponse.ts +var abortController = null; +async function fetchOllamaResponse(plugin, settings, index2) { + const ollamaRESTAPIURL = settings.OllamaConnection.RESTAPIURL; + if (!ollamaRESTAPIURL) { + return; + } + const prompt = await getPrompt(plugin, settings); + const filteredMessageHistory = filterMessageHistory(messageHistory); + const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); + const messageContainerEl = document.querySelector("#messageContainer"); + const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); + const botMessageDiv = displayLoadingBotMessage(settings); + messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); + botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); + await getActiveFileContent(plugin, settings); + const referenceCurrentNoteContent2 = getCurrentNoteContent(); + abortController = new AbortController(); + const submitButton = document.querySelector(".submit-button"); + (0, import_obsidian4.setIcon)(submitButton, "square"); + submitButton.title = "stop"; + submitButton.addEventListener("click", async () => { + if (submitButton.title === "stop") { + const controller = getAbortController(); + if (controller) { + controller.abort(); + } + } + }); + try { + const response = await fetch(ollamaRESTAPIURL + "/api/chat", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + model: settings.general.model, + messages: [ + { role: "system", content: referenceCurrentNoteContent2 + settings.general.system_role + prompt + referenceCurrentNoteContent2 }, + ...messageHistoryAtIndex + ], + stream: false, + options: ollamaParametersOptions(settings) + }), + signal: abortController.signal + }); + const responseData = await response.json(); + let message = responseData.message.content; + if (messageContainerEl) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock) { + if (loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + } + await import_obsidian4.MarkdownRenderer.render(plugin.app, message || "", messageBlock, "/", plugin); + addParagraphBreaks(messageBlock); + updateUnresolvedInternalLinks(plugin, messageBlock); + const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); + copyCodeBlocks.forEach((copyCodeBlock) => { + copyCodeBlock.textContent = "Copy"; + (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); + }); + targetBotMessage == null ? void 0 : targetBotMessage.appendChild(messageBlock); + } + targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); + } + const regexPatterns = [ + /[\s\S]*?<\/block-rendered>/g, + /[\s\S]*?<\/note-rendered>/g + ]; + regexPatterns.forEach((pattern) => { + message = message.replace(pattern, "").trim(); + }); + addMessage(plugin, message.trim(), "botMessage", settings, index2); + } catch (error) { + if (error.name === "AbortError") { + console.log("Request aborted"); + (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); + submitButton.title = "send"; + if (messageContainerEl) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock && loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + messageBlock.textContent = "SYSTEM: Response aborted."; + addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); + } + } + } else { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + targetBotMessage == null ? void 0 : targetBotMessage.remove(); + const messageContainer = document.querySelector("#messageContainer"); + const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); + messageContainer.appendChild(botMessageDiv2); + } + } finally { + abortController = null; + } +} +async function fetchOllamaResponseStream(plugin, settings, index2) { + const ollamaRESTAPIURL = settings.OllamaConnection.RESTAPIURL; + if (!ollamaRESTAPIURL) { + return; + } + const prompt = await getPrompt(plugin, settings); + const url = ollamaRESTAPIURL + "/api/chat"; + abortController = new AbortController(); + let message = ""; + let isScroll = false; + const filteredMessageHistory = filterMessageHistory(messageHistory); + const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); + const messageContainerEl = document.querySelector("#messageContainer"); + const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); + const botMessageDiv = displayLoadingBotMessage(settings); + messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); + botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); + await getActiveFileContent(plugin, settings); + const referenceCurrentNoteContent2 = getCurrentNoteContent(); + const submitButton = document.querySelector(".submit-button"); + (0, import_obsidian4.setIcon)(submitButton, "square"); + submitButton.title = "stop"; + submitButton.addEventListener("click", () => { + if (submitButton.title === "stop") { + const controller = getAbortController(); + if (controller) { + controller.abort(); + } + } + }); + try { + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + model: settings.general.model, + messages: [ + { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 }, + ...messageHistoryAtIndex + ], + stream: true, + keep_alive: parseInt(settings.OllamaConnection.ollamaParameters.keep_alive), + options: ollamaParametersOptions(settings) + }), + signal: abortController.signal + }); + if (!response.ok) { + new import_obsidian4.Notice(`HTTP error! Status: ${response.status}`); + throw new Error(`HTTP error! Status: ${response.status}`); + } + if (!response.body) { + new import_obsidian4.Notice("Response body is null or undefined."); + throw new Error("Response body is null or undefined."); + } + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + let reading = true; + while (reading) { + const { done, value } = await reader.read(); + if (done) { + reading = false; + break; + } + const chunk = decoder.decode(value, { stream: true }) || ""; + const parts = chunk.split("\n"); + for (const part of parts.filter(Boolean)) { + let parsedChunk; + try { + parsedChunk = JSON.parse(part); + if (parsedChunk.done !== true) { + const content = parsedChunk.message.content; + message += content; + } + } catch (err) { + console.error("Error parsing JSON:", err); + console.log("Part with error:", part); + parsedChunk = { response: "{_e_}" }; + } + } + const messageContainerEl2 = document.querySelector("#messageContainer"); + if (messageContainerEl2) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock) { + if (loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + } + messageBlock.innerHTML = ""; + const fragment = document.createDocumentFragment(); + const tempContainer = document.createElement("div"); + fragment.appendChild(tempContainer); + await import_obsidian4.MarkdownRenderer.render(plugin.app, message, tempContainer, "/", plugin); + while (tempContainer.firstChild) { + messageBlock.appendChild(tempContainer.firstChild); + } + addParagraphBreaks(messageBlock); + updateUnresolvedInternalLinks(plugin, messageBlock); + const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); + copyCodeBlocks.forEach((copyCodeBlock) => { + copyCodeBlock.textContent = "Copy"; + (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); + }); + } + messageContainerEl2.addEventListener("wheel", (event) => { + if (event.deltaY < 0 || event.deltaY > 0) { + isScroll = true; + } + }); + if (!isScroll) { + targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "auto", block: "start" }); + } + } + } + const regexPatterns = [ + /[\s\S]*?<\/block-rendered>/g, + /[\s\S]*?<\/note-rendered>/g + ]; + regexPatterns.forEach((pattern) => { + message = message.replace(pattern, "").trim(); + }); + addMessage(plugin, message.trim(), "botMessage", settings, index2); + } catch (error) { + if (error.name === "AbortError") { + if (messageContainerEl) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock && loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + messageBlock.textContent = "SYSTEM: Response aborted."; + } + } + } else { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + targetBotMessage == null ? void 0 : targetBotMessage.remove(); + const messageContainer = document.querySelector("#messageContainer"); + const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); + messageContainer.appendChild(botMessageDiv2); + } + if (message.trim() === "") { + addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); + } else { + addMessage(plugin, message.trim(), "botMessage", settings, index2); + } + new import_obsidian4.Notice("Stream stopped."); + console.error("Error fetching chat response from Ollama:", error); + } finally { + abortController = null; + } + submitButton.textContent = "send"; + (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); + submitButton.title = "send"; +} +async function fetchRESTAPIURLResponse(plugin, settings, index2) { + const prompt = await getPrompt(plugin, settings); + const noImageMessageHistory = messageHistory.map(({ role, content }) => ({ role, content })); + const filteredMessageHistory = filterMessageHistory(noImageMessageHistory); + const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); + const messageContainerEl = document.querySelector("#messageContainer"); + const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); + const botMessageDiv = displayLoadingBotMessage(settings); + messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); + botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); + await getActiveFileContent(plugin, settings); + const referenceCurrentNoteContent2 = getCurrentNoteContent(); + try { + const response = await (0, import_obsidian4.requestUrl)({ + url: settings.RESTAPIURLConnection.RESTAPIURL + "/chat/completions", + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${settings.RESTAPIURLConnection.APIKey}` + }, + body: JSON.stringify({ + model: settings.general.model, + messages: [ + { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 || "You are a helpful assistant." }, + ...messageHistoryAtIndex + ], + max_tokens: parseInt(settings.general.max_tokens) || -1, + temperature: parseInt(settings.general.temperature) + }) + }); + let message = response.json.choices[0].message.content; + const messageContainerEl2 = document.querySelector("#messageContainer"); + if (messageContainerEl2) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock) { + if (loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + } + await import_obsidian4.MarkdownRenderer.render(plugin.app, message || "", messageBlock, "/", plugin); + addParagraphBreaks(messageBlock); + updateUnresolvedInternalLinks(plugin, messageBlock); + const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); + copyCodeBlocks.forEach((copyCodeBlock) => { + copyCodeBlock.textContent = "Copy"; + (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); + }); + targetBotMessage == null ? void 0 : targetBotMessage.appendChild(messageBlock); + } + targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); + } + const regexPatterns = [ + /[\s\S]*?<\/block-rendered>/g, + /[\s\S]*?<\/note-rendered>/g + ]; + regexPatterns.forEach((pattern) => { + message = message.replace(pattern, "").trim(); + }); + addMessage(plugin, message.trim(), "botMessage", settings, index2); + return; + } catch (error) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + targetBotMessage == null ? void 0 : targetBotMessage.remove(); + const messageContainer = document.querySelector("#messageContainer"); + const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); + messageContainer.appendChild(botMessageDiv2); + } +} +async function fetchRESTAPIURLResponseStream(plugin, settings, index2) { + const RESTAPIURL = settings.RESTAPIURLConnection.RESTAPIURL; + if (!RESTAPIURL) { + return; + } + const prompt = await getPrompt(plugin, settings); + const url = RESTAPIURL + "/chat/completions"; + abortController = new AbortController(); + let message = ""; + let isScroll = false; + const noImageMessageHistory = messageHistory.map(({ role, content }) => ({ role, content })); + const filteredMessageHistory = filterMessageHistory(noImageMessageHistory); + const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); + const messageContainerEl = document.querySelector("#messageContainer"); + const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); + const botMessageDiv = displayLoadingBotMessage(settings); + messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); + botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); + await getActiveFileContent(plugin, settings); + const referenceCurrentNoteContent2 = getCurrentNoteContent(); + const submitButton = document.querySelector(".submit-button"); + (0, import_obsidian4.setIcon)(submitButton, "square"); + submitButton.title = "stop"; + submitButton.addEventListener("click", () => { + if (submitButton.title === "stop") { + const controller = getAbortController(); + if (controller) { + controller.abort(); + } + } + }); + try { + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${settings.RESTAPIURLConnection.APIKey}` + }, + body: JSON.stringify({ + model: settings.general.model, + messages: [ + { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 || "You are a helpful assistant." }, + ...messageHistoryAtIndex + ], + stream: true, + temperature: parseInt(settings.general.temperature), + max_tokens: parseInt(settings.general.max_tokens) || 4096 + }), + signal: abortController.signal + }); + if (!response.ok) { + new import_obsidian4.Notice(`HTTP error! Status: ${response.status}`); + throw new Error(`HTTP error! Status: ${response.status}`); + } + if (!response.body) { + new import_obsidian4.Notice("Response body is null or undefined."); + throw new Error("Response body is null or undefined."); + } + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + let reading = true; + while (reading) { + const { done, value } = await reader.read(); + if (done) { + reading = false; + break; + } + const chunk = decoder.decode(value, { stream: false }) || ""; + const parts = chunk.split("\n"); + for (const part of parts.filter(Boolean)) { + if (part.includes("data: [DONE]")) { + break; + } + let parsedChunk; + try { + parsedChunk = JSON.parse(part.replace(/^data: /, "")); + if (parsedChunk.choices[0].finish_reason !== "stop") { + const content = parsedChunk.choices[0].delta.content; + message += content; + } + } catch (err) { + console.error("Error parsing JSON:", err); + console.log("Part with error:", part); + parsedChunk = { response: "{_e_}" }; + } + } + const messageContainerEl2 = document.querySelector("#messageContainer"); + if (messageContainerEl2) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock) { + if (loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + } + messageBlock.innerHTML = ""; + const fragment = document.createDocumentFragment(); + const tempContainer = document.createElement("div"); + fragment.appendChild(tempContainer); + await import_obsidian4.MarkdownRenderer.render(plugin.app, message, tempContainer, "/", plugin); + while (tempContainer.firstChild) { + messageBlock.appendChild(tempContainer.firstChild); + } + addParagraphBreaks(messageBlock); + updateUnresolvedInternalLinks(plugin, messageBlock); + const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); + copyCodeBlocks.forEach((copyCodeBlock) => { + copyCodeBlock.textContent = "Copy"; + (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); + }); + } + messageContainerEl2.addEventListener("wheel", (event) => { + if (event.deltaY < 0 || event.deltaY > 0) { + isScroll = true; + } + }); + if (!isScroll) { + targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "auto", block: "start" }); + } + } + } + const regexPatterns = [ + /[\s\S]*?<\/block-rendered>/g, + /[\s\S]*?<\/note-rendered>/g + ]; + regexPatterns.forEach((pattern) => { + message = message.replace(pattern, "").trim(); + }); + addMessage(plugin, message.trim(), "botMessage", settings, index2); + } catch (error) { + if (error.name === "AbortError") { + if (messageContainerEl) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock && loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + messageBlock.textContent = "SYSTEM: Response aborted."; + } + } + } else { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + targetBotMessage == null ? void 0 : targetBotMessage.remove(); + const messageContainer = document.querySelector("#messageContainer"); + const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); + messageContainer.appendChild(botMessageDiv2); + } + if (message.trim() === "") { + addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); + } else { + addMessage(plugin, message.trim(), "botMessage", settings, index2); + } + new import_obsidian4.Notice("Stream stopped."); + console.error("Error fetching chat response from Ollama:", error); + } finally { + abortController = null; + } + submitButton.textContent = "send"; + (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); + submitButton.title = "send"; +} +async function fetchAnthropicResponse(plugin, settings, index2) { + const prompt = await getPrompt(plugin, settings); + const noImageMessageHistory = messageHistory.map(({ role, content }) => ({ role, content })); + const filteredMessageHistory = filterMessageHistory(noImageMessageHistory); + const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); + const messageContainerEl = document.querySelector("#messageContainer"); + const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); + const botMessageDiv = displayLoadingBotMessage(settings); + messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); + botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); + await getActiveFileContent(plugin, settings); + const referenceCurrentNoteContent2 = getCurrentNoteContent(); + abortController = new AbortController(); + const submitButton = document.querySelector(".submit-button"); + (0, import_obsidian4.setIcon)(submitButton, "square"); + submitButton.title = "stop"; + submitButton.addEventListener("click", async () => { + if (submitButton.title === "stop") { + const controller = getAbortController(); + if (controller) { + controller.abort(); + } + } + }); + try { + const response = await (0, import_obsidian4.requestUrl)({ + url: "https://api.anthropic.com/v1/messages", + method: "POST", + headers: { + "anthropic-version": "2023-06-01", + "content-type": "application/json", + "x-api-key": settings.APIConnections.anthropic.APIKey + }, + body: JSON.stringify({ + model: settings.general.model, + system: settings.general.system_role + prompt + referenceCurrentNoteContent2, + messages: [ + ...messageHistoryAtIndex + ], + max_tokens: parseInt(settings.general.max_tokens) || 4096, + temperature: parseInt(settings.general.temperature) + }) + }); + let message = response.json.content[0].text; + const messageContainerEl2 = document.querySelector("#messageContainer"); + if (messageContainerEl2) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock) { + if (loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + } + await import_obsidian4.MarkdownRenderer.render(plugin.app, message || "", messageBlock, "/", plugin); + addParagraphBreaks(messageBlock); + updateUnresolvedInternalLinks(plugin, messageBlock); + const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); + copyCodeBlocks.forEach((copyCodeBlock) => { + copyCodeBlock.textContent = "Copy"; + (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); + }); + targetBotMessage == null ? void 0 : targetBotMessage.appendChild(messageBlock); + } + targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); + } + const regexPatterns = [ + /[\s\S]*?<\/block-rendered>/g, + /[\s\S]*?<\/note-rendered>/g + ]; + regexPatterns.forEach((pattern) => { + message = message.replace(pattern, "").trim(); + }); + addMessage(plugin, message.trim(), "botMessage", settings, index2); + return; + } catch (error) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + targetBotMessage == null ? void 0 : targetBotMessage.remove(); + const messageContainer = document.querySelector("#messageContainer"); + const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); + messageContainer.appendChild(botMessageDiv2); + } +} +async function fetchGoogleGeminiResponse(plugin, settings, index2) { + const prompt = await getPrompt(plugin, settings); + const filteredMessageHistory = filterMessageHistory(messageHistory); + const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); + const messageContainerEl = document.querySelector("#messageContainer"); + const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); + const botMessageDiv = displayLoadingBotMessage(settings); + messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); + botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); + await getActiveFileContent(plugin, settings); + const referenceCurrentNoteContent2 = getCurrentNoteContent(); + const convertMessageHistory = (messageHistory2) => { + const modifiedMessageHistory = [...messageHistory2]; + const convertedMessageHistory2 = modifiedMessageHistory.map(({ role, content }) => ({ + role: role === "assistant" ? "model" : role, + parts: [{ text: content }] + })); + const contents = [ + ...convertedMessageHistory2 + ]; + return { contents }; + }; + const convertedMessageHistory = convertMessageHistory(messageHistoryAtIndex); + abortController = new AbortController(); + const submitButton = document.querySelector(".submit-button"); + (0, import_obsidian4.setIcon)(submitButton, "square"); + submitButton.title = "stop"; + submitButton.addEventListener("click", async () => { + if (submitButton.title === "stop") { + const controller = getAbortController(); + if (controller) { + controller.abort(); + } + } + }); + try { + const API_KEY = settings.APIConnections.googleGemini.APIKey; + const MODEL = settings.general.model; + const url = "https://generativelanguage.googleapis.com/v1beta/" + MODEL + ":generateContent?key=" + API_KEY; + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + contents: [ + { + role: "user", + parts: [{ text: `System prompt: + + ${plugin.settings.general.system_role} ${prompt} ${referenceCurrentNoteContent2} Respond understood if you got it.` }] + }, + { + role: "model", + parts: [{ text: "Understood." }] + }, + ...convertedMessageHistory.contents + ], + generationConfig: { + stopSequences: "", + temperature: parseInt(settings.general.temperature), + maxOutputTokens: settings.general.max_tokens || 4096, + topP: 0.8, + topK: 10 + } + }), + signal: abortController == null ? void 0 : abortController.signal + }); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const responseData = await response.json(); + let message = responseData.candidates[0].content.parts[0].text; + const messageContainerEl2 = document.querySelector("#messageContainer"); + if (messageContainerEl2) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock) { + if (loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + } + await import_obsidian4.MarkdownRenderer.render(plugin.app, message || "", messageBlock, "/", plugin); + addParagraphBreaks(messageBlock); + updateUnresolvedInternalLinks(plugin, messageBlock); + const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); + copyCodeBlocks.forEach((copyCodeBlock) => { + copyCodeBlock.textContent = "Copy"; + (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); + }); + targetBotMessage == null ? void 0 : targetBotMessage.appendChild(messageBlock); + } + targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); + } + const regexPatterns = [ + /[\s\S]*?<\/block-rendered>/g, + /[\s\S]*?<\/note-rendered>/g + ]; + regexPatterns.forEach((pattern) => { + message = message.replace(pattern, "").trim(); + }); + addMessage(plugin, message.trim(), "botMessage", settings, index2); + return; + } catch (error) { + if (error.name === "AbortError") { + console.log("Request aborted"); + (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); + submitButton.title = "send"; + if (messageContainerEl) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock && loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + messageBlock.textContent = "SYSTEM: Response aborted."; + addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); + } + } + } else { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + targetBotMessage == null ? void 0 : targetBotMessage.remove(); + const messageContainer = document.querySelector("#messageContainer"); + const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); + messageContainer.appendChild(botMessageDiv2); + } + } finally { + abortController = null; + } +} +async function fetchGoogleGeminiResponseStream(plugin, settings, index2) { + const prompt = await getPrompt(plugin, settings); + abortController = new AbortController(); + let message = ""; + let isScroll = false; + const filteredMessageHistory = filterMessageHistory(messageHistory); + const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); + const messageContainerEl = document.querySelector("#messageContainer"); + const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); + const botMessageDiv = displayLoadingBotMessage(settings); + messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); + botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); + await getActiveFileContent(plugin, settings); + const referenceCurrentNoteContent2 = getCurrentNoteContent(); + const convertMessageHistory = (messageHistory2) => { + const modifiedMessageHistory = [...messageHistory2]; + const convertedMessageHistory2 = modifiedMessageHistory.map(({ role, content }) => ({ + role: role === "assistant" ? "model" : role, + parts: [{ text: content }] + })); + const contents = [ + ...convertedMessageHistory2 + ]; + return { contents }; + }; + const convertedMessageHistory = convertMessageHistory(messageHistoryAtIndex); + abortController = new AbortController(); + const submitButton = document.querySelector(".submit-button"); + (0, import_obsidian4.setIcon)(submitButton, "square"); + submitButton.title = "stop"; + submitButton.addEventListener("click", async () => { + if (submitButton.title === "stop") { + const controller = getAbortController(); + if (controller) { + controller.abort(); + } + } + }); + try { + const API_KEY = settings.APIConnections.googleGemini.APIKey; + const MODEL = settings.general.model; + const url = "https://generativelanguage.googleapis.com/v1beta/" + MODEL + ":streamGenerateContent?alt=sse&key=" + API_KEY; + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + contents: [ + { + role: "user", + parts: [{ text: `System prompt: + + ${plugin.settings.general.system_role} ${prompt} ${referenceCurrentNoteContent2} Respond understood if you got it.` }] + }, + { + role: "model", + parts: [{ text: "Understood." }] + }, + ...convertedMessageHistory.contents + ], + generationConfig: { + stopSequences: "", + temperature: parseInt(settings.general.temperature), + maxOutputTokens: settings.general.max_tokens || 4096, + topP: 0.8, + topK: 10 + } + }), + signal: abortController == null ? void 0 : abortController.signal + }); + if (!response.ok) { + new import_obsidian4.Notice(`HTTP error! Status: ${response.status}`); + throw new Error(`HTTP error! Status: ${response.status}`); + } + if (!response.body) { + new import_obsidian4.Notice("Response body is null or undefined."); + throw new Error("Response body is null or undefined."); + } + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + let reading = true; + while (reading) { + const { done, value } = await reader.read(); + if (done) { + reading = false; + break; + } + const chunk = decoder.decode(value, { stream: true }) || ""; + const parts = chunk.split("\n"); + for (const part of parts.filter(Boolean)) { + if (part.startsWith("data: ")) { + const jsonData = part.slice(6); + let parsedChunk; + try { + parsedChunk = JSON.parse(jsonData); + if (parsedChunk.done !== true) { + const content = parsedChunk.candidates[0].content.parts[0].text; + message += content; + } + } catch (err) { + console.error("Error parsing JSON:", err); + console.log("Part with error:", jsonData); + parsedChunk = { response: "{_e_}" }; + } + } + } + const messageContainerEl2 = document.querySelector("#messageContainer"); + if (messageContainerEl2) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock) { + if (loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + } + messageBlock.innerHTML = ""; + const fragment = document.createDocumentFragment(); + const tempContainer = document.createElement("div"); + fragment.appendChild(tempContainer); + await import_obsidian4.MarkdownRenderer.render(plugin.app, message, tempContainer, "/", plugin); + while (tempContainer.firstChild) { + messageBlock.appendChild(tempContainer.firstChild); + } + addParagraphBreaks(messageBlock); + updateUnresolvedInternalLinks(plugin, messageBlock); + const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); + copyCodeBlocks.forEach((copyCodeBlock) => { + copyCodeBlock.textContent = "Copy"; + (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); + }); + } + messageContainerEl2.addEventListener("wheel", (event) => { + if (event.deltaY < 0 || event.deltaY > 0) { + isScroll = true; + } + }); + if (!isScroll) { + targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "auto", block: "start" }); + } + } + } + const regexPatterns = [ + /[\s\S]*?<\/block-rendered>/g, + /[\s\S]*?<\/note-rendered>/g + ]; + regexPatterns.forEach((pattern) => { + message = message.replace(pattern, "").trim(); + }); + addMessage(plugin, message.trim(), "botMessage", settings, index2); + } catch (error) { + if (error.name === "AbortError") { + if (messageContainerEl) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock && loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + messageBlock.textContent = "SYSTEM: Response aborted."; + } + } + } else { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + targetBotMessage == null ? void 0 : targetBotMessage.remove(); + const messageContainer = document.querySelector("#messageContainer"); + const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); + messageContainer.appendChild(botMessageDiv2); + } + if (message.trim() === "") { + addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); + } else { + addMessage(plugin, message.trim(), "botMessage", settings, index2); + } + new import_obsidian4.Notice("Stream stopped."); + console.error("Error fetching chat response from Google Gemini:", error); + } finally { + abortController = null; + } + submitButton.textContent = "send"; + (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); + submitButton.title = "send"; +} +async function fetchMistralResponse(plugin, settings, index2) { + const prompt = await getPrompt(plugin, settings); + const noImageMessageHistory = messageHistory.map(({ role, content }) => ({ role, content })); + const filteredMessageHistory = filterMessageHistory(noImageMessageHistory); + const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); + const messageContainerEl = document.querySelector("#messageContainer"); + const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); + const botMessageDiv = displayLoadingBotMessage(settings); + messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); + botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); + await getActiveFileContent(plugin, settings); + const referenceCurrentNoteContent2 = getCurrentNoteContent(); + abortController = new AbortController(); + const submitButton = document.querySelector(".submit-button"); + (0, import_obsidian4.setIcon)(submitButton, "square"); + submitButton.title = "stop"; + submitButton.addEventListener("click", async () => { + if (submitButton.title === "stop") { + const controller = getAbortController(); + if (controller) { + controller.abort(); + } + } + }); + try { + const response = await fetch("https://api.mistral.ai/v1/chat/completions", { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${settings.APIConnections.mistral.APIKey}` + }, + body: JSON.stringify({ + model: settings.general.model, + messages: [ + { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 }, + ...messageHistoryAtIndex + ], + max_tokens: parseInt(settings.general.max_tokens) || 4096, + temperature: parseInt(settings.general.temperature) + }), + signal: abortController == null ? void 0 : abortController.signal + }); + const data = await response.json(); + let message = data.choices[0].message.content; + const messageContainerEl2 = document.querySelector("#messageContainer"); + if (messageContainerEl2) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock) { + if (loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + } + await import_obsidian4.MarkdownRenderer.render(plugin.app, message || "", messageBlock, "/", plugin); + addParagraphBreaks(messageBlock); + updateUnresolvedInternalLinks(plugin, messageBlock); + const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); + copyCodeBlocks.forEach((copyCodeBlock) => { + copyCodeBlock.textContent = "Copy"; + (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); + }); + targetBotMessage == null ? void 0 : targetBotMessage.appendChild(messageBlock); + } + targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); + } + const regexPatterns = [ + /[\s\S]*?<\/block-rendered>/g, + /[\s\S]*?<\/note-rendered>/g + ]; + regexPatterns.forEach((pattern) => { + message = message.replace(pattern, "").trim(); + }); + addMessage(plugin, message.trim(), "botMessage", settings, index2); + return; + } catch (error) { + if (error.name === "AbortError") { + console.log("Request aborted"); + (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); + submitButton.title = "send"; + if (messageContainerEl) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock && loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + messageBlock.textContent = "SYSTEM: Response aborted."; + addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); + } + } + } else { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + targetBotMessage == null ? void 0 : targetBotMessage.remove(); + const messageContainer = document.querySelector("#messageContainer"); + const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); + messageContainer.appendChild(botMessageDiv2); + } + } finally { + abortController = null; + } +} +async function fetchMistralResponseStream(plugin, settings, index2) { + abortController = new AbortController(); + const prompt = await getPrompt(plugin, settings); + let message = ""; + let isScroll = false; + const noImageMessageHistory = messageHistory.map(({ role, content }) => ({ role, content })); + const filteredMessageHistory = filterMessageHistory(noImageMessageHistory); + const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); + const messageContainerEl = document.querySelector("#messageContainer"); + const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); + const botMessageDiv = displayLoadingBotMessage(settings); + messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); + botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); + await getActiveFileContent(plugin, settings); + const referenceCurrentNoteContent2 = getCurrentNoteContent(); + abortController = new AbortController(); + const submitButton = document.querySelector(".submit-button"); + (0, import_obsidian4.setIcon)(submitButton, "square"); + submitButton.title = "stop"; + submitButton.addEventListener("click", async () => { + if (submitButton.title === "stop") { + const controller = getAbortController(); + if (controller) { + controller.abort(); + } + } + }); + try { + const response = await fetch("https://api.mistral.ai/v1/chat/completions", { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${settings.APIConnections.mistral.APIKey}` + }, + body: JSON.stringify({ + model: settings.general.model, + messages: [ + { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 }, + ...messageHistoryAtIndex + ], + stream: true, + temperature: parseInt(settings.general.temperature), + max_tokens: parseInt(settings.general.max_tokens) || 4096 + }), + signal: abortController.signal + }); + (0, import_obsidian4.setIcon)(submitButton, "square"); + submitButton.title = "stop"; + if (!response.ok) { + new import_obsidian4.Notice(`HTTP error! Status: ${response.status}`); + throw new Error(`HTTP error! Status: ${response.status}`); + } + if (!response.body) { + new import_obsidian4.Notice("Response body is null or undefined."); + throw new Error("Response body is null or undefined."); + } + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + let reading = true; + while (reading) { + const { done, value } = await reader.read(); + if (done) { + reading = false; + break; + } + const chunk = decoder.decode(value, { stream: false }) || ""; + const parts = chunk.split("\n"); + for (const part of parts.filter(Boolean)) { + if (part.includes("data: [DONE]")) { + break; + } + let parsedChunk; + try { + parsedChunk = JSON.parse(part.replace(/^data: /, "")); + if (parsedChunk.choices[0].finish_reason !== "stop") { + const content = parsedChunk.choices[0].delta.content; + message += content; + } + } catch (err) { + console.error("Error parsing JSON:", err); + console.log("Part with error:", part); + parsedChunk = { response: "{_e_}" }; + } + } + const messageContainerEl2 = document.querySelector("#messageContainer"); + if (messageContainerEl2) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock) { + if (loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + } + messageBlock.innerHTML = ""; + const fragment = document.createDocumentFragment(); + const tempContainer = document.createElement("div"); + fragment.appendChild(tempContainer); + await import_obsidian4.MarkdownRenderer.render(plugin.app, message, tempContainer, "/", plugin); + while (tempContainer.firstChild) { + messageBlock.appendChild(tempContainer.firstChild); + } + addParagraphBreaks(messageBlock); + updateUnresolvedInternalLinks(plugin, messageBlock); + const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); + copyCodeBlocks.forEach((copyCodeBlock) => { + copyCodeBlock.textContent = "Copy"; + (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); + }); + } + messageContainerEl2.addEventListener("wheel", (event) => { + if (event.deltaY < 0 || event.deltaY > 0) { + isScroll = true; + } + }); + if (!isScroll) { + targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "auto", block: "start" }); + } + } + } + const regexPatterns = [ + /[\s\S]*?<\/block-rendered>/g, + /[\s\S]*?<\/note-rendered>/g + ]; + regexPatterns.forEach((pattern) => { + message = message.replace(pattern, "").trim(); + }); + addMessage(plugin, message.trim(), "botMessage", settings, index2); + } catch (error) { + if (error.name === "AbortError") { + if (messageContainerEl) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock && loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + messageBlock.textContent = "SYSTEM: Response aborted."; + } + } + } else { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + targetBotMessage == null ? void 0 : targetBotMessage.remove(); + const messageContainer = document.querySelector("#messageContainer"); + const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); + messageContainer.appendChild(botMessageDiv2); + } + if (message.trim() === "") { + addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); + } else { + addMessage(plugin, message.trim(), "botMessage", settings, index2); + } + new import_obsidian4.Notice("Stream stopped."); + console.error("Error fetching chat response from Mistral:", error); + } finally { + abortController = null; + } + submitButton.textContent = "send"; + (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); + submitButton.title = "send"; +} +async function fetchOpenAIAPIResponse(plugin, settings, index2) { + abortController = new AbortController(); + const prompt = await getPrompt(plugin, settings); + const filteredMessageHistory = filterMessageHistory(messageHistory); + const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); + const messageContainerEl = document.querySelector("#messageContainer"); + const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); + const botMessageDiv = displayLoadingBotMessage(settings); + messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); + botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); + await getActiveFileContent(plugin, settings); + const referenceCurrentNoteContent2 = getCurrentNoteContent(); + const submitButton = document.querySelector(".submit-button"); + (0, import_obsidian4.setIcon)(submitButton, "square"); + submitButton.title = "stop"; + submitButton.addEventListener("click", async () => { + if (submitButton.title === "stop") { + const controller = getAbortController(); + if (controller) { + controller.abort(); + } + } + }); + try { + const response = await fetch(`${plugin.settings.APIConnections.openAI.openAIBaseUrl}/chat/completions`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${plugin.settings.APIConnections.openAI.APIKey}` + }, + body: JSON.stringify({ + model: settings.general.model, + max_tokens: parseInt(settings.general.max_tokens), + stream: false, + messages: [ + { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 }, + ...messageHistoryAtIndex + ] + }), + signal: abortController.signal + }); + const data = await response.json(); + let message = data.choices[0].message.content || ""; + if (messageContainerEl) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock) { + if (loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + } + await import_obsidian4.MarkdownRenderer.render(plugin.app, message || "", messageBlock, "/", plugin); + addParagraphBreaks(messageBlock); + updateUnresolvedInternalLinks(plugin, messageBlock); + const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); + copyCodeBlocks.forEach((copyCodeBlock) => { + copyCodeBlock.textContent = "Copy"; + (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); + }); + targetBotMessage == null ? void 0 : targetBotMessage.appendChild(messageBlock); + } + targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); + } + if (message != null) { + const regexPatterns = [ + /[\s\S]*?<\/block-rendered>/g, + /[\s\S]*?<\/note-rendered>/g, + /[\s\S]*?<\/note-rendered>/g + ]; + regexPatterns.forEach((pattern) => { + message = message.replace(pattern, "").trim(); + }); + addMessage(plugin, message.trim(), "botMessage", settings, index2); + } + } catch (error) { + if (error.name === "AbortError") { + console.log("Request aborted"); + (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); + submitButton.title = "send"; + if (messageContainerEl) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock && loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + messageBlock.textContent = "SYSTEM: Response aborted."; + addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); + } + } + } else { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + targetBotMessage == null ? void 0 : targetBotMessage.remove(); + const messageContainer = document.querySelector("#messageContainer"); + const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); + messageContainer.appendChild(botMessageDiv2); + } + } finally { + abortController = null; + } +} +async function fetchOpenAIAPIResponseStream(plugin, settings, index2) { + abortController = new AbortController(); + const prompt = await getPrompt(plugin, settings); + let message = ""; + let isScroll = false; + const filteredMessageHistory = filterMessageHistory(messageHistory); + const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); + const messageContainerEl = document.querySelector("#messageContainer"); + const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); + const botMessageDiv = displayLoadingBotMessage(settings); + messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); + botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + await getActiveFileContent(plugin, settings); + const referenceCurrentNoteContent2 = getCurrentNoteContent(); + const submitButton = document.querySelector(".submit-button"); + (0, import_obsidian4.setIcon)(submitButton, "square"); + submitButton.title = "stop"; + submitButton.addEventListener("click", () => { + if (submitButton.title === "stop") { + const controller = getAbortController(); + if (controller) { + controller.abort(); + } + } + }); + try { + const response = await fetch(`${plugin.settings.APIConnections.openAI.openAIBaseUrl}/chat/completions`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${plugin.settings.APIConnections.openAI.APIKey}` + }, + body: JSON.stringify({ + model: settings.general.model, + max_tokens: parseInt(settings.general.max_tokens), + stream: true, + messages: [ + { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 }, + ...messageHistoryAtIndex + ] + }), + signal: abortController.signal + }); + if (!response.ok) { + new import_obsidian4.Notice(`HTTP error! Status: ${response.status}`); + throw new Error(`HTTP error! Status: ${response.status}`); + } + if (!response.body) { + new import_obsidian4.Notice("Response body is null or undefined."); + throw new Error("Response body is null or undefined."); + } + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + let reading = true; + while (reading) { + const { done, value } = await reader.read(); + if (done) { + reading = false; + break; + } + const chunk = decoder.decode(value, { stream: true }) || ""; + const parts = chunk.split("\n"); + for (const part of parts) { + if (part.includes("data: [DONE]")) { + reading = false; + break; + } + try { + const trimmedPart = part.replace(/^data: /, "").trim(); + if (trimmedPart) { + const data = JSON.parse(trimmedPart); + if (data.choices && data.choices[0].delta && data.choices[0].delta.content) { + const content = data.choices[0].delta.content; + message += content; + } + } + } catch (err) { + console.error("Error parsing JSON:", err); + console.log("Part with error:", part); + } + } + if (messageContainerEl) { + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock) { + if (loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + } + messageBlock.innerHTML = ""; + const fragment = document.createDocumentFragment(); + const tempContainer = document.createElement("div"); + fragment.appendChild(tempContainer); + await import_obsidian4.MarkdownRenderer.render(plugin.app, message, tempContainer, "/", plugin); + while (tempContainer.firstChild) { + messageBlock.appendChild(tempContainer.firstChild); + } + addParagraphBreaks(messageBlock); + updateUnresolvedInternalLinks(plugin, messageBlock); + const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); + copyCodeBlocks.forEach((copyCodeBlock) => { + copyCodeBlock.textContent = "Copy"; + (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); + }); + } + messageContainerEl.addEventListener("wheel", (event) => { + if (event.deltaY < 0 || event.deltaY > 0) { + isScroll = true; + } + }); + if (!isScroll) { + targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "auto", block: "start" }); + } + } + if (abortController.signal.aborted) { + new import_obsidian4.Notice("Stream stopped."); + break; + } + } + const regexPatterns = [ + /[\s\S]*?<\/block-rendered>/g, + /[\s\S]*?<\/note-rendered>/g + ]; + regexPatterns.forEach((pattern) => { + message = message.replace(pattern, "").trim(); + }); + addMessage(plugin, message.trim(), "botMessage", settings, index2); + } catch (error) { + if (error.name === "AbortError") { + if (messageContainerEl) { + const targetUserMessage2 = messageContainerElDivs[index2]; + const targetBotMessage2 = targetUserMessage2.nextElementSibling; + const messageBlock = targetBotMessage2 == null ? void 0 : targetBotMessage2.querySelector(".messageBlock"); + const loadingEl = targetBotMessage2 == null ? void 0 : targetBotMessage2.querySelector("#loading"); + if (messageBlock && loadingEl) { + targetBotMessage2 == null ? void 0 : targetBotMessage2.removeChild(loadingEl); + messageBlock.textContent = "SYSTEM: Response aborted."; + } + } + } else { + const targetUserMessage2 = messageContainerElDivs[index2]; + const targetBotMessage2 = targetUserMessage2.nextElementSibling; + targetBotMessage2 == null ? void 0 : targetBotMessage2.remove(); + const messageContainer = document.querySelector("#messageContainer"); + const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); + messageContainer.appendChild(botMessageDiv2); + } + if (message.trim() === "") { + addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); + } else { + addMessage(plugin, message.trim(), "botMessage", settings, index2); + } + new import_obsidian4.Notice("Stream stopped."); + console.error("Error fetching chat response from OpenAI-Based Models:", error); + } finally { + abortController = null; + } + submitButton.textContent = "send"; + (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); + submitButton.title = "send"; +} +async function fetchOpenRouterResponse(plugin, settings, index2) { + abortController = new AbortController(); + const prompt = await getPrompt(plugin, settings); + const filteredMessageHistory = filterMessageHistory(messageHistory); + const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); + const messageContainerEl = document.querySelector("#messageContainer"); + const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); + const botMessageDiv = displayLoadingBotMessage(settings); + messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); + botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); + await getActiveFileContent(plugin, settings); + const referenceCurrentNoteContent2 = getCurrentNoteContent(); + const submitButton = document.querySelector(".submit-button"); + (0, import_obsidian4.setIcon)(submitButton, "square"); + submitButton.title = "stop"; + submitButton.addEventListener("click", async () => { + if (submitButton.title === "stop") { + const controller = getAbortController(); + if (controller) { + controller.abort(); + } + } + }); + try { + const response = await fetch("https://openrouter.ai/api/v1/chat/completions", { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${settings.APIConnections.openRouter.APIKey}` + }, + body: JSON.stringify({ + model: settings.general.model, + messages: [ + { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 || "You are a helpful assistant." }, + ...messageHistoryAtIndex + ], + max_tokens: parseInt(settings.general.max_tokens) || 4096, + temperature: parseInt(settings.general.temperature) + }), + signal: abortController.signal + }); + const data = await response.json(); + let message = data.choices[0].message.content; + const messageContainerEl2 = document.querySelector("#messageContainer"); + if (messageContainerEl2) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock) { + if (loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + } + await import_obsidian4.MarkdownRenderer.render(plugin.app, message || "", messageBlock, "/", plugin); + addParagraphBreaks(messageBlock); + updateUnresolvedInternalLinks(plugin, messageBlock); + const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); + copyCodeBlocks.forEach((copyCodeBlock) => { + copyCodeBlock.textContent = "Copy"; + (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); + }); + targetBotMessage == null ? void 0 : targetBotMessage.appendChild(messageBlock); + } + targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); + } + const regexPatterns = [ + /[\s\S]*?<\/block-rendered>/g, + /[\s\S]*?<\/note-rendered>/g + ]; + regexPatterns.forEach((pattern) => { + message = message.replace(pattern, "").trim(); + }); + addMessage(plugin, message.trim(), "botMessage", settings, index2); + return; + } catch (error) { + if (error.name === "AbortError") { + console.log("Request aborted"); + (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); + submitButton.title = "send"; + if (messageContainerEl) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock && loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + messageBlock.textContent = "SYSTEM: Response aborted."; + addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); + } + } + } else { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + targetBotMessage == null ? void 0 : targetBotMessage.remove(); + const messageContainer = document.querySelector("#messageContainer"); + const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); + messageContainer.appendChild(botMessageDiv2); + } + } finally { + abortController = null; + } +} +async function fetchOpenRouterResponseStream(plugin, settings, index2) { + const url = "https://openrouter.ai/api/v1/chat/completions"; + abortController = new AbortController(); + const prompt = await getPrompt(plugin, settings); + let message = ""; + let isScroll = false; + const filteredMessageHistory = filterMessageHistory(messageHistory); + const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); + const messageContainerEl = document.querySelector("#messageContainer"); + const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); + const botMessageDiv = displayLoadingBotMessage(settings); + messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); + botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); + await getActiveFileContent(plugin, settings); + const referenceCurrentNoteContent2 = getCurrentNoteContent(); + const submitButton = document.querySelector(".submit-button"); + (0, import_obsidian4.setIcon)(submitButton, "square"); + submitButton.title = "stop"; + submitButton.addEventListener("click", () => { + if (submitButton.title === "stop") { + const controller = getAbortController(); + if (controller) { + controller.abort(); + } + } + }); + try { + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${settings.APIConnections.openRouter.APIKey}` + }, + body: JSON.stringify({ + model: settings.general.model, + messages: [ + { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 || "You are a helpful assistant." }, + ...messageHistoryAtIndex + ], + stream: true, + temperature: parseInt(settings.general.temperature), + max_tokens: parseInt(settings.general.max_tokens) || 4096 + }), + signal: abortController.signal + }); + if (!response.ok) { + new import_obsidian4.Notice(`HTTP error! Status: ${response.status}`); + throw new Error(`HTTP error! Status: ${response.status}`); + } + if (!response.body) { + new import_obsidian4.Notice("Response body is null or undefined."); + throw new Error("Response body is null or undefined."); + } + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + let reading = true; + while (reading) { + const { done, value } = await reader.read(); + if (done) { + reading = false; + break; + } + const chunk = decoder.decode(value, { stream: false }) || ""; + const parts = chunk.split("\n"); + for (const part of parts.filter(Boolean)) { + if (part.includes("data: [DONE]")) { + break; + } + let parsedChunk; + try { + parsedChunk = JSON.parse(part.replace(/^data: /, "")); + if (parsedChunk.choices[0].finish_reason !== "stop") { + const content = parsedChunk.choices[0].delta.content; + message += content; + } + } catch (err) { + console.error("Error parsing JSON:", err); + console.log("Part with error:", part); + parsedChunk = { response: "{_e_}" }; + } + } + const messageContainerEl2 = document.querySelector("#messageContainer"); + if (messageContainerEl2) { + const targetUserMessage = messageContainerElDivs[index2]; + const targetBotMessage = targetUserMessage.nextElementSibling; + const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); + const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); + if (messageBlock) { + if (loadingEl) { + targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); + } + messageBlock.innerHTML = ""; + const fragment = document.createDocumentFragment(); + const tempContainer = document.createElement("div"); + fragment.appendChild(tempContainer); + await import_obsidian4.MarkdownRenderer.render(plugin.app, message, tempContainer, "/", plugin); + while (tempContainer.firstChild) { + messageBlock.appendChild(tempContainer.firstChild); + } + addParagraphBreaks(messageBlock); + updateUnresolvedInternalLinks(plugin, messageBlock); + const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); + copyCodeBlocks.forEach((copyCodeBlock) => { + copyCodeBlock.textContent = "Copy"; + (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); + }); + } + messageContainerEl2.addEventListener("wheel", (event) => { + if (event.deltaY < 0 || event.deltaY > 0) { + isScroll = true; + } + }); + if (!isScroll) { + targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "auto", block: "start" }); + } + } + } + const regexPatterns = [ + /[\s\S]*?<\/block-rendered>/g, + /[\s\S]*?<\/note-rendered>/g + ]; + regexPatterns.forEach((pattern) => { + message = message.replace(pattern, "").trim(); + }); + addMessage(plugin, message.trim(), "botMessage", settings, index2); + } catch (error) { + addMessage(plugin, message.trim(), "botMessage", settings, index2); + new import_obsidian4.Notice("Stream stopped."); + console.error(error); + } + submitButton.textContent = "send"; + (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); + submitButton.title = "send"; +} +function getAbortController() { + return abortController; +} +function ollamaParametersOptions(settings) { + return { + mirostat: parseInt(settings.OllamaConnection.ollamaParameters.mirostat), + mirostat_eta: parseFloat(settings.OllamaConnection.ollamaParameters.mirostat_eta), + mirostat_tau: parseFloat(settings.OllamaConnection.ollamaParameters.mirostat_tau), + num_ctx: parseInt(settings.OllamaConnection.ollamaParameters.num_ctx), + num_gqa: parseInt(settings.OllamaConnection.ollamaParameters.num_gqa), + num_thread: parseInt(settings.OllamaConnection.ollamaParameters.num_thread), + repeat_last_n: parseInt(settings.OllamaConnection.ollamaParameters.repeat_last_n), + repeat_penalty: parseFloat(settings.OllamaConnection.ollamaParameters.repeat_penalty), + temperature: parseInt(settings.general.temperature), + seed: parseInt(settings.OllamaConnection.ollamaParameters.seed), + stop: settings.OllamaConnection.ollamaParameters.stop, + tfs_z: parseFloat(settings.OllamaConnection.ollamaParameters.tfs_z), + num_predict: parseInt(settings.general.max_tokens) || -1, + top_k: parseInt(settings.OllamaConnection.ollamaParameters.top_k), + top_p: parseFloat(settings.OllamaConnection.ollamaParameters.top_p), + min_p: parseFloat(settings.OllamaConnection.ollamaParameters.min_p) + }; +} +function filterMessageHistory(messageHistory2) { + const skipIndexes = /* @__PURE__ */ new Set(); + messageHistory2.forEach((message, index2, array) => { + if (message.role === "user" && message.content.startsWith("/")) { + skipIndexes.add(index2); + if (index2 + 1 < array.length && array[index2 + 1].role === "assistant") { + skipIndexes.add(index2 + 1); + } + } else if (message.role === "assistant" && message.content.includes("errorBotMessage")) { + skipIndexes.add(index2); + if (index2 > 0) { + skipIndexes.add(index2 - 1); + } + } + }); + const filteredMessageHistory = messageHistory2.filter((_, index2) => !skipIndexes.has(index2)); + return filteredMessageHistory; +} +function removeConsecutiveUserRoles(messageHistory2) { + const result = []; + let foundUserMessage = false; + for (let i = 0; i < messageHistory2.length; i++) { + if (messageHistory2[i].role === "user") { + if (!foundUserMessage) { + result.push(messageHistory2[i]); + foundUserMessage = true; + } else { + break; + } + } else { + result.push(messageHistory2[i]); + foundUserMessage = false; + } + } + return result; +} + +// src/components/editor/FetchRenameNoteTitle.ts +var import_obsidian5 = require("obsidian"); + +// node_modules/whatwg-fetch/fetch.js +var g = typeof globalThis !== "undefined" && globalThis || typeof self !== "undefined" && self || // eslint-disable-next-line no-undef +typeof global !== "undefined" && global || {}; +var support = { + searchParams: "URLSearchParams" in g, + iterable: "Symbol" in g && "iterator" in Symbol, + blob: "FileReader" in g && "Blob" in g && function() { + try { + new Blob(); + return true; + } catch (e) { + return false; + } + }(), + formData: "FormData" in g, + arrayBuffer: "ArrayBuffer" in g +}; +function isDataView(obj) { + return obj && DataView.prototype.isPrototypeOf(obj); +} +if (support.arrayBuffer) { + viewClasses = [ + "[object Int8Array]", + "[object Uint8Array]", + "[object Uint8ClampedArray]", + "[object Int16Array]", + "[object Uint16Array]", + "[object Int32Array]", + "[object Uint32Array]", + "[object Float32Array]", + "[object Float64Array]" + ]; + isArrayBufferView = ArrayBuffer.isView || function(obj) { + return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1; + }; +} +var viewClasses; +var isArrayBufferView; +function normalizeName(name) { + if (typeof name !== "string") { + name = String(name); + } + if (/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(name) || name === "") { + throw new TypeError('Invalid character in header field name: "' + name + '"'); + } + return name.toLowerCase(); +} +function normalizeValue(value) { + if (typeof value !== "string") { + value = String(value); + } + return value; +} +function iteratorFor(items) { + var iterator = { + next: function() { + var value = items.shift(); + return { done: value === void 0, value }; + } + }; + if (support.iterable) { + iterator[Symbol.iterator] = function() { + return iterator; + }; + } + return iterator; +} +function Headers2(headers) { + this.map = {}; + if (headers instanceof Headers2) { + headers.forEach(function(value, name) { + this.append(name, value); + }, this); + } else if (Array.isArray(headers)) { + headers.forEach(function(header) { + if (header.length != 2) { + throw new TypeError("Headers constructor: expected name/value pair to be length 2, found" + header.length); + } + this.append(header[0], header[1]); + }, this); + } else if (headers) { + Object.getOwnPropertyNames(headers).forEach(function(name) { + this.append(name, headers[name]); + }, this); + } +} +Headers2.prototype.append = function(name, value) { + name = normalizeName(name); + value = normalizeValue(value); + var oldValue = this.map[name]; + this.map[name] = oldValue ? oldValue + ", " + value : value; +}; +Headers2.prototype["delete"] = function(name) { + delete this.map[normalizeName(name)]; +}; +Headers2.prototype.get = function(name) { + name = normalizeName(name); + return this.has(name) ? this.map[name] : null; +}; +Headers2.prototype.has = function(name) { + return this.map.hasOwnProperty(normalizeName(name)); +}; +Headers2.prototype.set = function(name, value) { + this.map[normalizeName(name)] = normalizeValue(value); +}; +Headers2.prototype.forEach = function(callback, thisArg) { + for (var name in this.map) { + if (this.map.hasOwnProperty(name)) { + callback.call(thisArg, this.map[name], name, this); + } + } +}; +Headers2.prototype.keys = function() { + var items = []; + this.forEach(function(value, name) { + items.push(name); + }); + return iteratorFor(items); +}; +Headers2.prototype.values = function() { + var items = []; + this.forEach(function(value) { + items.push(value); + }); + return iteratorFor(items); +}; +Headers2.prototype.entries = function() { + var items = []; + this.forEach(function(value, name) { + items.push([name, value]); + }); + return iteratorFor(items); +}; +if (support.iterable) { + Headers2.prototype[Symbol.iterator] = Headers2.prototype.entries; +} +function consumed(body) { + if (body._noBody) + return; + if (body.bodyUsed) { + return Promise.reject(new TypeError("Already read")); + } + body.bodyUsed = true; +} +function fileReaderReady(reader) { + return new Promise(function(resolve2, reject) { + reader.onload = function() { + resolve2(reader.result); + }; + reader.onerror = function() { + reject(reader.error); + }; + }); +} +function readBlobAsArrayBuffer(blob) { + var reader = new FileReader(); + var promise = fileReaderReady(reader); + reader.readAsArrayBuffer(blob); + return promise; +} +function readBlobAsText(blob) { + var reader = new FileReader(); + var promise = fileReaderReady(reader); + var match = /charset=([A-Za-z0-9_-]+)/.exec(blob.type); + var encoding = match ? match[1] : "utf-8"; + reader.readAsText(blob, encoding); + return promise; +} +function readArrayBufferAsText(buf) { + var view = new Uint8Array(buf); + var chars = new Array(view.length); + for (var i = 0; i < view.length; i++) { + chars[i] = String.fromCharCode(view[i]); + } + return chars.join(""); +} +function bufferClone(buf) { + if (buf.slice) { + return buf.slice(0); + } else { + var view = new Uint8Array(buf.byteLength); + view.set(new Uint8Array(buf)); + return view.buffer; + } +} +function Body() { + this.bodyUsed = false; + this._initBody = function(body) { + this.bodyUsed = this.bodyUsed; + this._bodyInit = body; + if (!body) { + this._noBody = true; + this._bodyText = ""; + } else if (typeof body === "string") { + this._bodyText = body; + } else if (support.blob && Blob.prototype.isPrototypeOf(body)) { + this._bodyBlob = body; + } else if (support.formData && FormData.prototype.isPrototypeOf(body)) { + this._bodyFormData = body; + } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) { + this._bodyText = body.toString(); + } else if (support.arrayBuffer && support.blob && isDataView(body)) { + this._bodyArrayBuffer = bufferClone(body.buffer); + this._bodyInit = new Blob([this._bodyArrayBuffer]); + } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) { + this._bodyArrayBuffer = bufferClone(body); + } else { + this._bodyText = body = Object.prototype.toString.call(body); + } + if (!this.headers.get("content-type")) { + if (typeof body === "string") { + this.headers.set("content-type", "text/plain;charset=UTF-8"); + } else if (this._bodyBlob && this._bodyBlob.type) { + this.headers.set("content-type", this._bodyBlob.type); + } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) { + this.headers.set("content-type", "application/x-www-form-urlencoded;charset=UTF-8"); + } + } + }; + if (support.blob) { + this.blob = function() { + var rejected = consumed(this); + if (rejected) { + return rejected; + } + if (this._bodyBlob) { + return Promise.resolve(this._bodyBlob); + } else if (this._bodyArrayBuffer) { + return Promise.resolve(new Blob([this._bodyArrayBuffer])); + } else if (this._bodyFormData) { + throw new Error("could not read FormData body as blob"); + } else { + return Promise.resolve(new Blob([this._bodyText])); + } + }; + } + this.arrayBuffer = function() { + if (this._bodyArrayBuffer) { + var isConsumed = consumed(this); + if (isConsumed) { + return isConsumed; + } else if (ArrayBuffer.isView(this._bodyArrayBuffer)) { + return Promise.resolve( + this._bodyArrayBuffer.buffer.slice( + this._bodyArrayBuffer.byteOffset, + this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength + ) + ); + } else { + return Promise.resolve(this._bodyArrayBuffer); + } + } else if (support.blob) { + return this.blob().then(readBlobAsArrayBuffer); + } else { + throw new Error("could not read as ArrayBuffer"); + } + }; + this.text = function() { + var rejected = consumed(this); + if (rejected) { + return rejected; + } + if (this._bodyBlob) { + return readBlobAsText(this._bodyBlob); + } else if (this._bodyArrayBuffer) { + return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer)); + } else if (this._bodyFormData) { + throw new Error("could not read FormData body as text"); + } else { + return Promise.resolve(this._bodyText); + } + }; + if (support.formData) { + this.formData = function() { + return this.text().then(decode); + }; + } + this.json = function() { + return this.text().then(JSON.parse); + }; + return this; +} +var methods = ["CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"]; +function normalizeMethod(method) { + var upcased = method.toUpperCase(); + return methods.indexOf(upcased) > -1 ? upcased : method; +} +function Request2(input, options) { + if (!(this instanceof Request2)) { + throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.'); + } + options = options || {}; + var body = options.body; + if (input instanceof Request2) { + if (input.bodyUsed) { + throw new TypeError("Already read"); + } + this.url = input.url; + this.credentials = input.credentials; + if (!options.headers) { + this.headers = new Headers2(input.headers); + } + this.method = input.method; + this.mode = input.mode; + this.signal = input.signal; + if (!body && input._bodyInit != null) { + body = input._bodyInit; + input.bodyUsed = true; + } + } else { + this.url = String(input); + } + this.credentials = options.credentials || this.credentials || "same-origin"; + if (options.headers || !this.headers) { + this.headers = new Headers2(options.headers); + } + this.method = normalizeMethod(options.method || this.method || "GET"); + this.mode = options.mode || this.mode || null; + this.signal = options.signal || this.signal || function() { + if ("AbortController" in g) { + var ctrl = new AbortController(); + return ctrl.signal; + } + }(); + this.referrer = null; + if ((this.method === "GET" || this.method === "HEAD") && body) { + throw new TypeError("Body not allowed for GET or HEAD requests"); + } + this._initBody(body); + if (this.method === "GET" || this.method === "HEAD") { + if (options.cache === "no-store" || options.cache === "no-cache") { + var reParamSearch = /([?&])_=[^&]*/; + if (reParamSearch.test(this.url)) { + this.url = this.url.replace(reParamSearch, "$1_=" + new Date().getTime()); + } else { + var reQueryString = /\?/; + this.url += (reQueryString.test(this.url) ? "&" : "?") + "_=" + new Date().getTime(); + } + } + } +} +Request2.prototype.clone = function() { + return new Request2(this, { body: this._bodyInit }); +}; +function decode(body) { + var form = new FormData(); + body.trim().split("&").forEach(function(bytes) { + if (bytes) { + var split = bytes.split("="); + var name = split.shift().replace(/\+/g, " "); + var value = split.join("=").replace(/\+/g, " "); + form.append(decodeURIComponent(name), decodeURIComponent(value)); + } + }); + return form; +} +function parseHeaders(rawHeaders) { + var headers = new Headers2(); + var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, " "); + preProcessedHeaders.split("\r").map(function(header) { + return header.indexOf("\n") === 0 ? header.substr(1, header.length) : header; + }).forEach(function(line) { + var parts = line.split(":"); + var key = parts.shift().trim(); + if (key) { + var value = parts.join(":").trim(); + try { + headers.append(key, value); + } catch (error) { + console.warn("Response " + error.message); + } + } + }); + return headers; +} +Body.call(Request2.prototype); +function Response2(bodyInit, options) { + if (!(this instanceof Response2)) { + throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.'); + } + if (!options) { + options = {}; + } + this.type = "default"; + this.status = options.status === void 0 ? 200 : options.status; + if (this.status < 200 || this.status > 599) { + throw new RangeError("Failed to construct 'Response': The status provided (0) is outside the range [200, 599]."); + } + this.ok = this.status >= 200 && this.status < 300; + this.statusText = options.statusText === void 0 ? "" : "" + options.statusText; + this.headers = new Headers2(options.headers); + this.url = options.url || ""; + this._initBody(bodyInit); +} +Body.call(Response2.prototype); +Response2.prototype.clone = function() { + return new Response2(this._bodyInit, { + status: this.status, + statusText: this.statusText, + headers: new Headers2(this.headers), + url: this.url + }); +}; +Response2.error = function() { + var response = new Response2(null, { status: 200, statusText: "" }); + response.ok = false; + response.status = 0; + response.type = "error"; + return response; +}; +var redirectStatuses = [301, 302, 303, 307, 308]; +Response2.redirect = function(url, status) { + if (redirectStatuses.indexOf(status) === -1) { + throw new RangeError("Invalid status code"); + } + return new Response2(null, { status, headers: { location: url } }); +}; +var DOMException = g.DOMException; +try { + new DOMException(); +} catch (err) { + DOMException = function(message, name) { + this.message = message; + this.name = name; + var error = Error(message); + this.stack = error.stack; + }; + DOMException.prototype = Object.create(Error.prototype); + DOMException.prototype.constructor = DOMException; +} +function fetch2(input, init) { + return new Promise(function(resolve2, reject) { + var request = new Request2(input, init); + if (request.signal && request.signal.aborted) { + return reject(new DOMException("Aborted", "AbortError")); + } + var xhr = new XMLHttpRequest(); + function abortXhr() { + xhr.abort(); + } + xhr.onload = function() { + var options = { + statusText: xhr.statusText, + headers: parseHeaders(xhr.getAllResponseHeaders() || "") + }; + if (request.url.indexOf("file://") === 0 && (xhr.status < 200 || xhr.status > 599)) { + options.status = 200; + } else { + options.status = xhr.status; + } + options.url = "responseURL" in xhr ? xhr.responseURL : options.headers.get("X-Request-URL"); + var body = "response" in xhr ? xhr.response : xhr.responseText; + setTimeout(function() { + resolve2(new Response2(body, options)); + }, 0); + }; + xhr.onerror = function() { + setTimeout(function() { + reject(new TypeError("Network request failed")); + }, 0); + }; + xhr.ontimeout = function() { + setTimeout(function() { + reject(new TypeError("Network request timed out")); + }, 0); + }; + xhr.onabort = function() { + setTimeout(function() { + reject(new DOMException("Aborted", "AbortError")); + }, 0); + }; + function fixUrl(url) { + try { + return url === "" && g.location.href ? g.location.href : url; + } catch (e) { + return url; + } + } + xhr.open(request.method, fixUrl(request.url), true); + if (request.credentials === "include") { + xhr.withCredentials = true; + } else if (request.credentials === "omit") { + xhr.withCredentials = false; + } + if ("responseType" in xhr) { + if (support.blob) { + xhr.responseType = "blob"; + } else if (support.arrayBuffer) { + xhr.responseType = "arraybuffer"; + } + } + if (init && typeof init.headers === "object" && !(init.headers instanceof Headers2 || g.Headers && init.headers instanceof g.Headers)) { + var names = []; + Object.getOwnPropertyNames(init.headers).forEach(function(name) { + names.push(normalizeName(name)); + xhr.setRequestHeader(name, normalizeValue(init.headers[name])); + }); + request.headers.forEach(function(value, name) { + if (names.indexOf(name) === -1) { + xhr.setRequestHeader(name, value); + } + }); + } else { + request.headers.forEach(function(value, name) { + xhr.setRequestHeader(name, value); + }); + } + if (request.signal) { + request.signal.addEventListener("abort", abortXhr); + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + request.signal.removeEventListener("abort", abortXhr); + } + }; + } + xhr.send(typeof request._bodyInit === "undefined" ? null : request._bodyInit); + }); +} +fetch2.polyfill = true; +if (!g.fetch) { + g.fetch = fetch2; + g.Headers = Headers2; + g.Request = Request2; + g.Response = Response2; +} + +// node_modules/ollama/dist/shared/ollama.14e58652.mjs +var version = "0.5.1"; +var ResponseError = class extends Error { + constructor(error, status_code) { + super(error); + this.error = error; + this.status_code = status_code; + this.name = "ResponseError"; + if (Error.captureStackTrace) { + Error.captureStackTrace(this, ResponseError); + } + } +}; +var checkOk = async (response) => { + var _a2; + if (!response.ok) { + let message = `Error ${response.status}: ${response.statusText}`; + let errorData = null; + if ((_a2 = response.headers.get("content-type")) == null ? void 0 : _a2.includes("application/json")) { + try { + errorData = await response.json(); + message = errorData.error || message; + } catch (error) { + console.log("Failed to parse error response as JSON"); + } + } else { + try { + console.log("Getting text from response"); + const textResponse = await response.text(); + message = textResponse || message; + } catch (error) { + console.log("Failed to get text from error response"); + } + } + throw new ResponseError(message, response.status); + } +}; +function getPlatform() { + if (typeof window !== "undefined" && window.navigator) { + return `${window.navigator.platform.toLowerCase()} Browser/${navigator.userAgent};`; + } else if (typeof process !== "undefined") { + return `${process.arch} ${process.platform} Node.js/${process.version}`; + } + return ""; +} +var fetchWithHeaders = async (fetch3, url, options = {}) => { + const defaultHeaders = { + "Content-Type": "application/json", + Accept: "application/json", + "User-Agent": `ollama-js/${version} (${getPlatform()})` + }; + if (!options.headers) { + options.headers = {}; + } + options.headers = { + ...defaultHeaders, + ...options.headers + }; + return fetch3(url, options); +}; +var get = async (fetch3, host) => { + const response = await fetchWithHeaders(fetch3, host); + await checkOk(response); + return response; +}; +var head = async (fetch3, host) => { + const response = await fetchWithHeaders(fetch3, host, { + method: "HEAD" + }); + await checkOk(response); + return response; +}; +var post = async (fetch3, host, data, options) => { + const isRecord = (input) => { + return input !== null && typeof input === "object" && !Array.isArray(input); + }; + const formattedData = isRecord(data) ? JSON.stringify(data) : data; + const response = await fetchWithHeaders(fetch3, host, { + method: "POST", + body: formattedData, + signal: options == null ? void 0 : options.signal + }); + await checkOk(response); + return response; +}; +var del = async (fetch3, host, data) => { + const response = await fetchWithHeaders(fetch3, host, { + method: "DELETE", + body: JSON.stringify(data) + }); + await checkOk(response); + return response; +}; +var parseJSON = async function* (itr) { + var _a2; + const decoder = new TextDecoder("utf-8"); + let buffer = ""; + const reader = itr.getReader(); + while (true) { + const { done, value: chunk } = await reader.read(); + if (done) { + break; + } + buffer += decoder.decode(chunk); + const parts = buffer.split("\n"); + buffer = (_a2 = parts.pop()) != null ? _a2 : ""; + for (const part of parts) { + try { + yield JSON.parse(part); + } catch (error) { + console.warn("invalid json: ", part); + } + } + } + for (const part of buffer.split("\n").filter((p) => p !== "")) { + try { + yield JSON.parse(part); + } catch (error) { + console.warn("invalid json: ", part); + } + } +}; +var formatHost = (host) => { + if (!host) { + return "http://127.0.0.1:11434"; + } + let isExplicitProtocol = host.includes("://"); + if (host.startsWith(":")) { + host = `http://127.0.0.1${host}`; + isExplicitProtocol = false; + } + if (!isExplicitProtocol) { + host = `http://${host}`; + } + const url = new URL(host); + let port = url.port; + if (!port) { + if (!isExplicitProtocol) { + port = "11434"; + } else { + port = url.protocol === "https:" ? "443" : "80"; + } + } + let formattedHost = `${url.protocol}//${url.hostname}:${port}${url.pathname}`; + if (formattedHost.endsWith("/")) { + formattedHost = formattedHost.slice(0, -1); + } + return formattedHost; +}; +var __defProp2 = Object.defineProperty; +var __defNormalProp = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __publicField = (obj, key, value) => { + __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); + return value; +}; +var Ollama$1 = class Ollama { + constructor(config) { + var _a2; + __publicField(this, "config"); + __publicField(this, "fetch"); + __publicField(this, "abortController"); + this.config = { + host: "" + }; + if (!(config == null ? void 0 : config.proxy)) { + this.config.host = formatHost((_a2 = config == null ? void 0 : config.host) != null ? _a2 : "http://127.0.0.1:11434"); + } + this.fetch = fetch; + if ((config == null ? void 0 : config.fetch) != null) { + this.fetch = config.fetch; + } + this.abortController = new AbortController(); + } + // Abort any ongoing requests to Ollama + abort() { + this.abortController.abort(); + this.abortController = new AbortController(); + } + async processStreamableRequest(endpoint, request) { + var _a2; + request.stream = (_a2 = request.stream) != null ? _a2 : false; + const response = await post( + this.fetch, + `${this.config.host}/api/${endpoint}`, + { + ...request + }, + { signal: this.abortController.signal } + ); + if (!response.body) { + throw new Error("Missing body"); + } + const itr = parseJSON(response.body); + if (request.stream) { + return async function* () { + for await (const message of itr) { + if ("error" in message) { + throw new Error(message.error); + } + yield message; + if (message.done || message.status === "success") { + return; + } + } + throw new Error("Did not receive done or success response in stream."); + }(); + } else { + const message = await itr.next(); + if (!message.value.done && message.value.status !== "success") { + throw new Error("Expected a completed response."); + } + return message.value; + } + } + async encodeImage(image) { + if (typeof image !== "string") { + const uint8Array = new Uint8Array(image); + const numberArray = Array.from(uint8Array); + const base64String = btoa(String.fromCharCode.apply(null, numberArray)); + return base64String; + } + return image; + } + async generate(request) { + if (request.images) { + request.images = await Promise.all(request.images.map(this.encodeImage.bind(this))); + } + return this.processStreamableRequest("generate", request); + } + async chat(request) { + if (request.messages) { + for (const message of request.messages) { + if (message.images) { + message.images = await Promise.all( + message.images.map(this.encodeImage.bind(this)) + ); + } + } + } + return this.processStreamableRequest("chat", request); + } + async create(request) { + return this.processStreamableRequest("create", { + name: request.model, + stream: request.stream, + modelfile: request.modelfile, + quantize: request.quantize + }); + } + async pull(request) { + return this.processStreamableRequest("pull", { + name: request.model, + stream: request.stream, + insecure: request.insecure + }); + } + async push(request) { + return this.processStreamableRequest("push", { + name: request.model, + stream: request.stream, + insecure: request.insecure + }); + } + async delete(request) { + await del(this.fetch, `${this.config.host}/api/delete`, { + name: request.model + }); + return { status: "success" }; + } + async copy(request) { + await post(this.fetch, `${this.config.host}/api/copy`, { ...request }); + return { status: "success" }; + } + async list() { + const response = await get(this.fetch, `${this.config.host}/api/tags`); + const listResponse = await response.json(); + return listResponse; + } + async show(request) { + const response = await post(this.fetch, `${this.config.host}/api/show`, { + ...request + }); + const showResponse = await response.json(); + return showResponse; + } + async embeddings(request) { + const response = await post(this.fetch, `${this.config.host}/api/embeddings`, { + ...request + }); + const embeddingsResponse = await response.json(); + return embeddingsResponse; + } +}; +var browser = new Ollama$1(); + +// node_modules/ollama/dist/index.mjs +var import_fs = __toESM(require("fs"), 1); +var import_path = require("path"); +var import_crypto = require("crypto"); +var import_os = require("os"); +var Ollama2 = class extends Ollama$1 { + async encodeImage(image) { + if (typeof image !== "string") { + const result = Buffer.from(image).toString("base64"); + return result; + } + try { + if (import_fs.default.existsSync(image)) { + const fileBuffer = await import_fs.promises.readFile((0, import_path.resolve)(image)); + return Buffer.from(fileBuffer).toString("base64"); + } + } catch (e) { + } + return image; + } + async parseModelfile(modelfile, mfDir = process.cwd()) { + const out = []; + const lines = modelfile.split("\n"); + for (const line of lines) { + const [command, args] = line.split(" ", 2); + if (["FROM", "ADAPTER"].includes(command.toUpperCase())) { + const path = this.resolvePath(args.trim(), mfDir); + if (await this.fileExists(path)) { + out.push(`${command} @${await this.createBlob(path)}`); + } else { + out.push(`${command} ${args}`); + } + } else { + out.push(line); + } + } + return out.join("\n"); + } + resolvePath(inputPath, mfDir) { + if (inputPath.startsWith("~")) { + return (0, import_path.join)((0, import_os.homedir)(), inputPath.slice(1)); + } + return (0, import_path.resolve)(mfDir, inputPath); + } + async fileExists(path) { + try { + await import_fs.promises.access(path); + return true; + } catch (e) { + return false; + } + } + async createBlob(path) { + if (typeof ReadableStream === "undefined") { + throw new Error("Streaming uploads are not supported in this environment."); + } + const fileStream = (0, import_fs.createReadStream)(path); + const sha256sum = await new Promise((resolve2, reject) => { + const hash = (0, import_crypto.createHash)("sha256"); + fileStream.on("data", (data) => hash.update(data)); + fileStream.on("end", () => resolve2(hash.digest("hex"))); + fileStream.on("error", reject); + }); + const digest = `sha256:${sha256sum}`; + try { + await head(this.fetch, `${this.config.host}/api/blobs/${digest}`); + } catch (e) { + if (e instanceof Error && e.message.includes("404")) { + const readableStream = new ReadableStream({ + start(controller) { + fileStream.on("data", (chunk) => { + controller.enqueue(chunk); + }); + fileStream.on("end", () => { + controller.close(); + }); + fileStream.on("error", (err) => { + controller.error(err); + }); + } + }); + await post( + this.fetch, + `${this.config.host}/api/blobs/${digest}`, + readableStream + ); + } else { + throw e; + } + } + return digest; + } + async create(request) { + let modelfileContent = ""; + if (request.path) { + modelfileContent = await import_fs.promises.readFile(request.path, { encoding: "utf8" }); + modelfileContent = await this.parseModelfile( + modelfileContent, + (0, import_path.dirname)(request.path) + ); + } else if (request.modelfile) { + modelfileContent = await this.parseModelfile(request.modelfile); + } else { + throw new Error("Must provide either path or modelfile to create a model"); + } + request.modelfile = modelfileContent; + if (request.stream) { + return super.create(request); + } else { + return super.create(request); + } + } +}; +var index = new Ollama2(); + +// node_modules/openai/version.mjs +var VERSION = "4.6.0"; + +// node_modules/openai/streaming.mjs +var Stream = class { + constructor(response, controller) { + this.response = response; + this.controller = controller; + this.decoder = new SSEDecoder(); + } + async *iterMessages() { + if (!this.response.body) { + this.controller.abort(); + throw new Error(`Attempted to iterate over a response with no body`); + } + const lineDecoder = new LineDecoder(); + const iter = readableStreamAsyncIterable(this.response.body); + for await (const chunk of iter) { + for (const line of lineDecoder.decode(chunk)) { + const sse = this.decoder.decode(line); + if (sse) + yield sse; + } + } + for (const line of lineDecoder.flush()) { + const sse = this.decoder.decode(line); + if (sse) + yield sse; + } + } + async *[Symbol.asyncIterator]() { + let done = false; + try { + for await (const sse of this.iterMessages()) { + if (done) + continue; + if (sse.data.startsWith("[DONE]")) { + done = true; + continue; + } + if (sse.event === null) { + try { + yield JSON.parse(sse.data); + } catch (e) { + console.error(`Could not parse message into JSON:`, sse.data); + console.error(`From chunk:`, sse.raw); + throw e; + } + } + } + done = true; + } catch (e) { + if (e instanceof Error && e.name === "AbortError") + return; + throw e; + } finally { + if (!done) + this.controller.abort(); + } + } +}; +var SSEDecoder = class { + constructor() { + this.event = null; + this.data = []; + this.chunks = []; + } + decode(line) { + if (line.endsWith("\r")) { + line = line.substring(0, line.length - 1); + } + if (!line) { + if (!this.event && !this.data.length) + return null; + const sse = { + event: this.event, + data: this.data.join("\n"), + raw: this.chunks + }; + this.event = null; + this.data = []; + this.chunks = []; + return sse; + } + this.chunks.push(line); + if (line.startsWith(":")) { + return null; + } + let [fieldname, _, value] = partition(line, ":"); + if (value.startsWith(" ")) { + value = value.substring(1); + } + if (fieldname === "event") { + this.event = value; + } else if (fieldname === "data") { + this.data.push(value); + } + return null; + } +}; +var LineDecoder = class { + constructor() { + this.buffer = []; + this.trailingCR = false; + } + decode(chunk) { + let text = this.decodeText(chunk); + if (this.trailingCR) { + text = "\r" + text; + this.trailingCR = false; + } + if (text.endsWith("\r")) { + this.trailingCR = true; + text = text.slice(0, -1); + } + if (!text) { + return []; + } + const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || ""); + let lines = text.split(LineDecoder.NEWLINE_REGEXP); + if (lines.length === 1 && !trailingNewline) { + this.buffer.push(lines[0]); + return []; + } + if (this.buffer.length > 0) { + lines = [this.buffer.join("") + lines[0], ...lines.slice(1)]; + this.buffer = []; + } + if (!trailingNewline) { + this.buffer = [lines.pop() || ""]; + } + return lines; + } + decodeText(bytes) { + var _a2; + if (bytes == null) + return ""; + if (typeof bytes === "string") + return bytes; + if (typeof Buffer !== "undefined") { + if (bytes instanceof Buffer) { + return bytes.toString(); + } + if (bytes instanceof Uint8Array) { + return Buffer.from(bytes).toString(); + } + throw new Error( + `Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global "Buffer" defined, which this library assumes to be Node. Please report this error.` + ); + } + if (typeof TextDecoder !== "undefined") { + if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) { + (_a2 = this.textDecoder) !== null && _a2 !== void 0 ? _a2 : this.textDecoder = new TextDecoder("utf8"); + return this.textDecoder.decode(bytes); + } + throw new Error( + `Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.` + ); + } + throw new Error( + `Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.` + ); + } + flush() { + if (!this.buffer.length && !this.trailingCR) { + return []; + } + const lines = [this.buffer.join("")]; + this.buffer = []; + this.trailingCR = false; + return lines; + } +}; +LineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set(["\n", "\r", "\v", "\f", "", "", "", "\x85", "\u2028", "\u2029"]); +LineDecoder.NEWLINE_REGEXP = /\r\n|[\n\r\x0b\x0c\x1c\x1d\x1e\x85\u2028\u2029]/g; +function partition(str, delimiter) { + const index2 = str.indexOf(delimiter); + if (index2 !== -1) { + return [str.substring(0, index2), delimiter, str.substring(index2 + delimiter.length)]; + } + return [str, "", ""]; +} +function readableStreamAsyncIterable(stream) { + if (stream[Symbol.asyncIterator]) + return stream; + const reader = stream.getReader(); + return { + async next() { + try { + const result = await reader.read(); + if (result === null || result === void 0 ? void 0 : result.done) + reader.releaseLock(); + return result; + } catch (e) { + reader.releaseLock(); + throw e; + } + }, + async return() { + const cancelPromise = reader.cancel(); + reader.releaseLock(); + await cancelPromise; + return { done: true, value: void 0 }; + }, + [Symbol.asyncIterator]() { + return this; + } + }; +} + +// node_modules/openai/error.mjs +var error_exports = {}; +__export(error_exports, { + APIConnectionError: () => APIConnectionError, + APIConnectionTimeoutError: () => APIConnectionTimeoutError, + APIError: () => APIError, + APIUserAbortError: () => APIUserAbortError, + AuthenticationError: () => AuthenticationError, + BadRequestError: () => BadRequestError, + ConflictError: () => ConflictError, + InternalServerError: () => InternalServerError, + NotFoundError: () => NotFoundError, + PermissionDeniedError: () => PermissionDeniedError, + RateLimitError: () => RateLimitError, + UnprocessableEntityError: () => UnprocessableEntityError +}); +var APIError = class extends Error { + constructor(status, error, message, headers) { + super(APIError.makeMessage(error, message)); + this.status = status; + this.headers = headers; + const data = error; + this.error = data; + this.code = data === null || data === void 0 ? void 0 : data["code"]; + this.param = data === null || data === void 0 ? void 0 : data["param"]; + this.type = data === null || data === void 0 ? void 0 : data["type"]; + } + static makeMessage(error, message) { + return (error === null || error === void 0 ? void 0 : error.message) ? typeof error.message === "string" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message || "Unknown error occurred"; + } + static generate(status, errorResponse, message, headers) { + if (!status) { + return new APIConnectionError({ cause: castToError(errorResponse) }); + } + const error = errorResponse === null || errorResponse === void 0 ? void 0 : errorResponse["error"]; + if (status === 400) { + return new BadRequestError(status, error, message, headers); + } + if (status === 401) { + return new AuthenticationError(status, error, message, headers); + } + if (status === 403) { + return new PermissionDeniedError(status, error, message, headers); + } + if (status === 404) { + return new NotFoundError(status, error, message, headers); + } + if (status === 409) { + return new ConflictError(status, error, message, headers); + } + if (status === 422) { + return new UnprocessableEntityError(status, error, message, headers); + } + if (status === 429) { + return new RateLimitError(status, error, message, headers); + } + if (status >= 500) { + return new InternalServerError(status, error, message, headers); + } + return new APIError(status, error, message, headers); + } +}; +var APIUserAbortError = class extends APIError { + constructor({ message } = {}) { + super(void 0, void 0, message || "Request was aborted.", void 0); + this.status = void 0; + } +}; +var APIConnectionError = class extends APIError { + constructor({ message, cause }) { + super(void 0, void 0, message || "Connection error.", void 0); + this.status = void 0; + if (cause) + this.cause = cause; + } +}; +var APIConnectionTimeoutError = class extends APIConnectionError { + constructor({ message } = {}) { + super({ message: message !== null && message !== void 0 ? message : "Request timed out." }); + } +}; +var BadRequestError = class extends APIError { + constructor() { + super(...arguments); + this.status = 400; + } +}; +var AuthenticationError = class extends APIError { + constructor() { + super(...arguments); + this.status = 401; + } +}; +var PermissionDeniedError = class extends APIError { + constructor() { + super(...arguments); + this.status = 403; + } +}; +var NotFoundError = class extends APIError { + constructor() { + super(...arguments); + this.status = 404; + } +}; +var ConflictError = class extends APIError { + constructor() { + super(...arguments); + this.status = 409; + } +}; +var UnprocessableEntityError = class extends APIError { + constructor() { + super(...arguments); + this.status = 422; + } +}; +var RateLimitError = class extends APIError { + constructor() { + super(...arguments); + this.status = 429; + } +}; +var InternalServerError = class extends APIError { +}; + +// node_modules/openai/_shims/agent.mjs +var getDefaultAgent = (url) => { + return void 0; +}; + +// node_modules/openai/_shims/fetch.mjs +var _fetch = fetch.bind(void 0); +var isPolyfilled = false; + +// node_modules/openai/_shims/form-data.mjs +var _FormData = FormData; +var _File = typeof File !== "undefined" ? File : ( + // Bun doesn't implement File yet, so just make a shim that throws a helpful error message + class File2 extends Blob { + constructor() { + throw new Error(`file uploads aren't supported in this environment yet as 'File' is not defined`); + } + } +); + +// node_modules/openai/_shims/getMultipartRequestOptions.mjs +async function getMultipartRequestOptions(form, opts) { + return { ...opts, body: new MultipartBody(form) }; +} + +// node_modules/openai/_shims/fileFromPath.mjs +async function fileFromPath() { + throw new Error( + "The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/openai/openai-node#file-uploads" + ); +} + +// node_modules/openai/_shims/node-readable.mjs +function isFsReadStream(value) { + return false; +} + +// node_modules/openai/uploads.mjs +var isResponseLike = (value) => value != null && typeof value === "object" && typeof value.url === "string" && typeof value.blob === "function"; +var isFileLike = (value) => value != null && typeof value === "object" && typeof value.name === "string" && typeof value.lastModified === "number" && isBlobLike(value); +var isBlobLike = (value) => value != null && typeof value === "object" && typeof value.size === "number" && typeof value.type === "string" && typeof value.text === "function" && typeof value.slice === "function" && typeof value.arrayBuffer === "function"; +var isUploadable = (value) => { + return isFileLike(value) || isResponseLike(value) || isFsReadStream(value); +}; +async function toFile(value, name, options = {}) { + var _a2, _b, _c; + value = await value; + if (isResponseLike(value)) { + const blob = await value.blob(); + name || (name = (_a2 = new URL(value.url).pathname.split(/[\\/]/).pop()) !== null && _a2 !== void 0 ? _a2 : "unknown_file"); + return new _File([blob], name, options); + } + const bits = await getBytes(value); + name || (name = (_b = getName(value)) !== null && _b !== void 0 ? _b : "unknown_file"); + if (!options.type) { + const type = (_c = bits[0]) === null || _c === void 0 ? void 0 : _c.type; + if (typeof type === "string") { + options = { ...options, type }; + } + } + return new _File(bits, name, options); +} +async function getBytes(value) { + var _a2; + let parts = []; + if (typeof value === "string" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc. + value instanceof ArrayBuffer) { + parts.push(value); + } else if (isBlobLike(value)) { + parts.push(await value.arrayBuffer()); + } else if (isAsyncIterableIterator(value)) { + for await (const chunk of value) { + parts.push(chunk); + } + } else { + throw new Error( + `Unexpected data type: ${typeof value}; constructor: ${(_a2 = value === null || value === void 0 ? void 0 : value.constructor) === null || _a2 === void 0 ? void 0 : _a2.name}; props: ${propsForError(value)}` + ); + } + return parts; +} +function propsForError(value) { + const props = Object.getOwnPropertyNames(value); + return `[${props.map((p) => `"${p}"`).join(", ")}]`; +} +function getName(value) { + var _a2; + return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream + ((_a2 = getStringFromMaybeBuffer(value.path)) === null || _a2 === void 0 ? void 0 : _a2.split(/[\\/]/).pop()); +} +var getStringFromMaybeBuffer = (x) => { + if (typeof x === "string") + return x; + if (typeof Buffer !== "undefined" && x instanceof Buffer) + return String(x); + return void 0; +}; +var isAsyncIterableIterator = (value) => value != null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function"; +var MultipartBody = class { + constructor(body) { + this.body = body; + } + get [Symbol.toStringTag]() { + return "MultipartBody"; + } +}; +var isMultipartBody = (body) => body && typeof body === "object" && body.body && body[Symbol.toStringTag] === "MultipartBody"; +var multipartFormRequestOptions = async (opts) => { + const form = await createForm(opts.body); + return getMultipartRequestOptions(form, opts); +}; +var createForm = async (body) => { + const form = new _FormData(); + await Promise.all(Object.entries(body || {}).map(([key, value]) => addFormValue(form, key, value))); + return form; +}; +var addFormValue = async (form, key, value) => { + if (value === void 0) + return; + if (value == null) { + throw new TypeError( + `Received null for "${key}"; to pass null in FormData, you must use the string 'null'` + ); + } + if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { + form.append(key, String(value)); + } else if (isUploadable(value)) { + const file = await toFile(value); + form.append(key, file); + } else if (Array.isArray(value)) { + await Promise.all(value.map((entry) => addFormValue(form, key + "[]", entry))); + } else if (typeof value === "object") { + await Promise.all( + Object.entries(value).map(([name, prop]) => addFormValue(form, `${key}[${name}]`, prop)) + ); + } else { + throw new TypeError( + `Invalid value given to form, expected a string, number, boolean, object, Array, File or Blob but got ${value} instead` + ); + } +}; + +// node_modules/openai/core.mjs +var __classPrivateFieldSet = function(receiver, state, value, kind, f) { + if (kind === "m") + throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) + throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) + throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value; +}; +var __classPrivateFieldGet = function(receiver, state, kind, f) { + if (kind === "a" && !f) + throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) + throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var _AbstractPage_client; +var MAX_RETRIES = 2; +async function defaultParseResponse(props) { + const { response } = props; + if (props.options.stream) { + return new Stream(response, props.controller); + } + const contentType = response.headers.get("content-type"); + if (contentType === null || contentType === void 0 ? void 0 : contentType.includes("application/json")) { + const json = await response.json(); + debug("response", response.status, response.url, response.headers, json); + return json; + } + const text = await response.text(); + debug("response", response.status, response.url, response.headers, text); + return text; +} +var APIPromise = class extends Promise { + constructor(responsePromise, parseResponse = defaultParseResponse) { + super((resolve2) => { + resolve2(null); + }); + this.responsePromise = responsePromise; + this.parseResponse = parseResponse; + } + _thenUnwrap(transform) { + return new APIPromise(this.responsePromise, async (props) => transform(await this.parseResponse(props))); + } + /** + * Gets the raw `Response` instance instead of parsing the response + * data. + * + * If you want to parse the response body but still get the `Response` + * instance, you can use {@link withResponse()}. + */ + asResponse() { + return this.responsePromise.then((p) => p.response); + } + /** + * Gets the parsed response data and the raw `Response` instance. + * + * If you just want to get the raw `Response` instance without parsing it, + * you can use {@link asResponse()}. + */ + async withResponse() { + const [data, response] = await Promise.all([this.parse(), this.asResponse()]); + return { data, response }; + } + parse() { + if (!this.parsedPromise) { + this.parsedPromise = this.responsePromise.then(this.parseResponse); + } + return this.parsedPromise; + } + then(onfulfilled, onrejected) { + return this.parse().then(onfulfilled, onrejected); + } + catch(onrejected) { + return this.parse().catch(onrejected); + } + finally(onfinally) { + return this.parse().finally(onfinally); + } +}; +var APIClient = class { + constructor({ + baseURL, + maxRetries, + timeout = 6e5, + // 10 minutes + httpAgent, + fetch: overridenFetch + }) { + this.baseURL = baseURL; + this.maxRetries = validatePositiveInteger( + "maxRetries", + maxRetries !== null && maxRetries !== void 0 ? maxRetries : MAX_RETRIES + ); + this.timeout = validatePositiveInteger("timeout", timeout); + this.httpAgent = httpAgent; + this.fetch = overridenFetch !== null && overridenFetch !== void 0 ? overridenFetch : _fetch; + } + authHeaders(opts) { + return {}; + } + /** + * Override this to add your own default headers, for example: + * + * { + * ...super.defaultHeaders(), + * Authorization: 'Bearer 123', + * } + */ + defaultHeaders(opts) { + return { + Accept: "application/json", + "Content-Type": "application/json", + "User-Agent": this.getUserAgent(), + ...getPlatformHeaders(), + ...this.authHeaders(opts) + }; + } + /** + * Override this to add your own headers validation: + */ + validateHeaders(headers, customHeaders) { + } + defaultIdempotencyKey() { + return `stainless-node-retry-${uuid4()}`; + } + get(path, opts) { + return this.methodRequest("get", path, opts); + } + post(path, opts) { + return this.methodRequest("post", path, opts); + } + patch(path, opts) { + return this.methodRequest("patch", path, opts); + } + put(path, opts) { + return this.methodRequest("put", path, opts); + } + delete(path, opts) { + return this.methodRequest("delete", path, opts); + } + methodRequest(method, path, opts) { + return this.request(Promise.resolve(opts).then((opts2) => ({ method, path, ...opts2 }))); + } + getAPIList(path, Page2, opts) { + return this.requestAPIList(Page2, { method: "get", path, ...opts }); + } + calculateContentLength(body) { + if (typeof body === "string") { + if (typeof Buffer !== "undefined") { + return Buffer.byteLength(body, "utf8").toString(); + } + if (typeof TextEncoder !== "undefined") { + const encoder = new TextEncoder(); + const encoded = encoder.encode(body); + return encoded.length.toString(); + } + } + return null; + } + buildRequest(options) { + var _a2, _b, _c, _d, _e, _f; + const { method, path, query, headers = {} } = options; + const body = isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null; + const contentLength = this.calculateContentLength(body); + const url = this.buildURL(path, query); + if ("timeout" in options) + validatePositiveInteger("timeout", options.timeout); + const timeout = (_a2 = options.timeout) !== null && _a2 !== void 0 ? _a2 : this.timeout; + const httpAgent = (_c = (_b = options.httpAgent) !== null && _b !== void 0 ? _b : this.httpAgent) !== null && _c !== void 0 ? _c : getDefaultAgent(url); + const minAgentTimeout = timeout + 1e3; + if (typeof ((_d = httpAgent === null || httpAgent === void 0 ? void 0 : httpAgent.options) === null || _d === void 0 ? void 0 : _d.timeout) === "number" && minAgentTimeout > ((_e = httpAgent.options.timeout) !== null && _e !== void 0 ? _e : 0)) { + httpAgent.options.timeout = minAgentTimeout; + } + if (this.idempotencyHeader && method !== "get") { + if (!options.idempotencyKey) + options.idempotencyKey = this.defaultIdempotencyKey(); + headers[this.idempotencyHeader] = options.idempotencyKey; + } + const reqHeaders = { + ...contentLength && { "Content-Length": contentLength }, + ...this.defaultHeaders(options), + ...headers + }; + if (isMultipartBody(options.body) && !isPolyfilled) { + delete reqHeaders["Content-Type"]; + } + Object.keys(reqHeaders).forEach((key) => reqHeaders[key] === null && delete reqHeaders[key]); + const req = { + method, + ...body && { body }, + headers: reqHeaders, + ...httpAgent && { agent: httpAgent }, + // @ts-ignore node-fetch uses a custom AbortSignal type that is + // not compatible with standard web types + signal: (_f = options.signal) !== null && _f !== void 0 ? _f : null + }; + this.validateHeaders(reqHeaders, headers); + return { req, url, timeout }; + } + /** + * Used as a callback for mutating the given `RequestInit` object. + * + * This is useful for cases where you want to add certain headers based off of + * the request properties, e.g. `method` or `url`. + */ + async prepareRequest(request, { url, options }) { + } + parseHeaders(headers) { + return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers }; + } + makeStatusError(status, error, message, headers) { + return APIError.generate(status, error, message, headers); + } + request(options, remainingRetries = null) { + return new APIPromise(this.makeRequest(options, remainingRetries)); + } + async makeRequest(optionsInput, retriesRemaining) { + var _a2, _b, _c; + const options = await optionsInput; + if (retriesRemaining == null) { + retriesRemaining = (_a2 = options.maxRetries) !== null && _a2 !== void 0 ? _a2 : this.maxRetries; + } + const { req, url, timeout } = this.buildRequest(options); + await this.prepareRequest(req, { url, options }); + debug("request", url, options, req.headers); + if ((_b = options.signal) === null || _b === void 0 ? void 0 : _b.aborted) { + throw new APIUserAbortError(); + } + const controller = new AbortController(); + const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError); + if (response instanceof Error) { + if ((_c = options.signal) === null || _c === void 0 ? void 0 : _c.aborted) { + throw new APIUserAbortError(); + } + if (retriesRemaining) { + return this.retryRequest(options, retriesRemaining); + } + if (response.name === "AbortError") { + throw new APIConnectionTimeoutError(); + } + throw new APIConnectionError({ cause: response }); + } + const responseHeaders = createResponseHeaders(response.headers); + if (!response.ok) { + if (retriesRemaining && this.shouldRetry(response)) { + return this.retryRequest(options, retriesRemaining, responseHeaders); + } + const errText = await response.text().catch(() => "Unknown"); + const errJSON = safeJSON(errText); + const errMessage = errJSON ? void 0 : errText; + debug("response", response.status, url, responseHeaders, errMessage); + const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders); + throw err; + } + return { response, options, controller }; + } + requestAPIList(Page2, options) { + const request = this.makeRequest(options, null); + return new PagePromise(this, request, Page2); + } + buildURL(path, query) { + const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith("/") && path.startsWith("/") ? path.slice(1) : path)); + const defaultQuery = this.defaultQuery(); + if (!isEmptyObj(defaultQuery)) { + query = { ...defaultQuery, ...query }; + } + if (query) { + url.search = this.stringifyQuery(query); + } + return url.toString(); + } + stringifyQuery(query) { + return Object.entries(query).filter(([_, value]) => typeof value !== "undefined").map(([key, value]) => { + if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { + return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`; + } + if (value === null) { + return `${encodeURIComponent(key)}=`; + } + throw new Error( + `Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.` + ); + }).join("&"); + } + async fetchWithTimeout(url, init, ms, controller) { + const { signal, ...options } = init || {}; + if (signal) + signal.addEventListener("abort", () => controller.abort()); + const timeout = setTimeout(() => controller.abort(), ms); + return this.getRequestClient().fetch(url, { signal: controller.signal, ...options }).finally(() => { + clearTimeout(timeout); + }); + } + getRequestClient() { + return { fetch: this.fetch }; + } + shouldRetry(response) { + const shouldRetryHeader = response.headers.get("x-should-retry"); + if (shouldRetryHeader === "true") + return true; + if (shouldRetryHeader === "false") + return false; + if (response.status === 409) + return true; + if (response.status === 429) + return true; + if (response.status >= 500) + return true; + return false; + } + async retryRequest(options, retriesRemaining, responseHeaders) { + var _a2; + retriesRemaining -= 1; + const retryAfter = parseInt( + (responseHeaders === null || responseHeaders === void 0 ? void 0 : responseHeaders["retry-after"]) || "" + ); + const maxRetries = (_a2 = options.maxRetries) !== null && _a2 !== void 0 ? _a2 : this.maxRetries; + const timeout = this.calculateRetryTimeoutSeconds(retriesRemaining, retryAfter, maxRetries) * 1e3; + await sleep(timeout); + return this.makeRequest(options, retriesRemaining); + } + calculateRetryTimeoutSeconds(retriesRemaining, retryAfter, maxRetries) { + const initialRetryDelay = 0.5; + const maxRetryDelay = 2; + if (Number.isInteger(retryAfter) && retryAfter <= 60) { + return retryAfter; + } + const numRetries = maxRetries - retriesRemaining; + const sleepSeconds = Math.min(initialRetryDelay * Math.pow(numRetries - 1, 2), maxRetryDelay); + const jitter = Math.random() - 0.5; + return sleepSeconds + jitter; + } + getUserAgent() { + return `${this.constructor.name}/JS ${VERSION}`; + } +}; +var AbstractPage = class { + constructor(client, response, body, options) { + _AbstractPage_client.set(this, void 0); + __classPrivateFieldSet(this, _AbstractPage_client, client, "f"); + this.options = options; + this.response = response; + this.body = body; + } + hasNextPage() { + const items = this.getPaginatedItems(); + if (!items.length) + return false; + return this.nextPageInfo() != null; + } + async getNextPage() { + const nextInfo = this.nextPageInfo(); + if (!nextInfo) { + throw new Error( + "No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`." + ); + } + const nextOptions = { ...this.options }; + if ("params" in nextInfo) { + nextOptions.query = { ...nextOptions.query, ...nextInfo.params }; + } else if ("url" in nextInfo) { + const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()]; + for (const [key, value] of params) { + nextInfo.url.searchParams.set(key, value); + } + nextOptions.query = void 0; + nextOptions.path = nextInfo.url.toString(); + } + return await __classPrivateFieldGet(this, _AbstractPage_client, "f").requestAPIList( + this.constructor, + nextOptions + ); + } + async *iterPages() { + let page = this; + yield page; + while (page.hasNextPage()) { + page = await page.getNextPage(); + yield page; + } + } + async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() { + for await (const page of this.iterPages()) { + for (const item of page.getPaginatedItems()) { + yield item; + } + } + } +}; +var PagePromise = class extends APIPromise { + constructor(client, request, Page2) { + super( + request, + async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options) + ); + } + /** + * Allow auto-paginating iteration on an unawaited list call, eg: + * + * for await (const item of client.items.list()) { + * console.log(item) + * } + */ + async *[Symbol.asyncIterator]() { + const page = await this; + for await (const item of page) { + yield item; + } + } +}; +var createResponseHeaders = (headers) => { + return new Proxy( + Object.fromEntries( + // @ts-ignore + headers.entries() + ), + { + get(target, name) { + const key = name.toString(); + return target[key.toLowerCase()] || target[key]; + } + } + ); +}; +var requestOptionsKeys = { + method: true, + path: true, + query: true, + body: true, + headers: true, + maxRetries: true, + stream: true, + timeout: true, + httpAgent: true, + signal: true, + idempotencyKey: true +}; +var isRequestOptions = (obj) => { + return typeof obj === "object" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k)); +}; +var getPlatformProperties = () => { + if (typeof Deno !== "undefined" && Deno.build != null) { + return { + "X-Stainless-Lang": "js", + "X-Stainless-Package-Version": VERSION, + "X-Stainless-OS": normalizePlatform(Deno.build.os), + "X-Stainless-Arch": normalizeArch(Deno.build.arch), + "X-Stainless-Runtime": "deno", + "X-Stainless-Runtime-Version": Deno.version + }; + } + if (typeof EdgeRuntime !== "undefined") { + return { + "X-Stainless-Lang": "js", + "X-Stainless-Package-Version": VERSION, + "X-Stainless-OS": "Unknown", + "X-Stainless-Arch": `other:${EdgeRuntime}`, + "X-Stainless-Runtime": "edge", + "X-Stainless-Runtime-Version": process.version + }; + } + if (Object.prototype.toString.call(typeof process !== "undefined" ? process : 0) === "[object process]") { + return { + "X-Stainless-Lang": "js", + "X-Stainless-Package-Version": VERSION, + "X-Stainless-OS": normalizePlatform(process.platform), + "X-Stainless-Arch": normalizeArch(process.arch), + "X-Stainless-Runtime": "node", + "X-Stainless-Runtime-Version": process.version + }; + } + const browserInfo = getBrowserInfo(); + if (browserInfo) { + return { + "X-Stainless-Lang": "js", + "X-Stainless-Package-Version": VERSION, + "X-Stainless-OS": "Unknown", + "X-Stainless-Arch": "unknown", + "X-Stainless-Runtime": `browser:${browserInfo.browser}`, + "X-Stainless-Runtime-Version": browserInfo.version + }; + } + return { + "X-Stainless-Lang": "js", + "X-Stainless-Package-Version": VERSION, + "X-Stainless-OS": "Unknown", + "X-Stainless-Arch": "unknown", + "X-Stainless-Runtime": "unknown", + "X-Stainless-Runtime-Version": "unknown" + }; +}; +function getBrowserInfo() { + if (typeof navigator === "undefined" || !navigator) { + return null; + } + const browserPatterns = [ + { key: "edge", pattern: /Edge(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: "ie", pattern: /MSIE(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: "ie", pattern: /Trident(?:.*rv\:(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: "chrome", pattern: /Chrome(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: "firefox", pattern: /Firefox(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: "safari", pattern: /(?:Version\W+(\d+)\.(\d+)(?:\.(\d+))?)?(?:\W+Mobile\S*)?\W+Safari/ } + ]; + for (const { key, pattern } of browserPatterns) { + const match = pattern.exec(navigator.userAgent); + if (match) { + const major = match[1] || 0; + const minor = match[2] || 0; + const patch = match[3] || 0; + return { browser: key, version: `${major}.${minor}.${patch}` }; + } + } + return null; +} +var normalizeArch = (arch) => { + if (arch === "x32") + return "x32"; + if (arch === "x86_64" || arch === "x64") + return "x64"; + if (arch === "arm") + return "arm"; + if (arch === "aarch64" || arch === "arm64") + return "arm64"; + if (arch) + return `other:${arch}`; + return "unknown"; +}; +var normalizePlatform = (platform) => { + platform = platform.toLowerCase(); + if (platform.includes("ios")) + return "iOS"; + if (platform === "android") + return "Android"; + if (platform === "darwin") + return "MacOS"; + if (platform === "win32") + return "Windows"; + if (platform === "freebsd") + return "FreeBSD"; + if (platform === "openbsd") + return "OpenBSD"; + if (platform === "linux") + return "Linux"; + if (platform) + return `Other:${platform}`; + return "Unknown"; +}; +var _platformHeaders; +var getPlatformHeaders = () => { + return _platformHeaders !== null && _platformHeaders !== void 0 ? _platformHeaders : _platformHeaders = getPlatformProperties(); +}; +var safeJSON = (text) => { + try { + return JSON.parse(text); + } catch (err) { + return void 0; + } +}; +var startsWithSchemeRegexp = new RegExp("^(?:[a-z]+:)?//", "i"); +var isAbsoluteURL = (url) => { + return startsWithSchemeRegexp.test(url); +}; +var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms)); +var validatePositiveInteger = (name, n) => { + if (typeof n !== "number" || !Number.isInteger(n)) { + throw new Error(`${name} must be an integer`); + } + if (n < 0) { + throw new Error(`${name} must be a positive integer`); + } + return n; +}; +var castToError = (err) => { + if (err instanceof Error) + return err; + return new Error(err); +}; +var readEnv = (env) => { + var _a2, _b, _c, _d; + if (typeof process !== "undefined") { + return (_b = (_a2 = process.env) === null || _a2 === void 0 ? void 0 : _a2[env]) !== null && _b !== void 0 ? _b : void 0; + } + if (typeof Deno !== "undefined") { + return (_d = (_c = Deno.env) === null || _c === void 0 ? void 0 : _c.get) === null || _d === void 0 ? void 0 : _d.call(_c, env); + } + return void 0; +}; +function isEmptyObj(obj) { + if (!obj) + return true; + for (const _k in obj) + return false; + return true; +} +function hasOwn(obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key); +} +function debug(action, ...args) { + if (typeof process !== "undefined" && process.env["DEBUG"] === "true") { + console.log(`OpenAI:DEBUG:${action}`, ...args); + } +} +var uuid4 = () => { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + const r = Math.random() * 16 | 0; + const v = c === "x" ? r : r & 3 | 8; + return v.toString(16); + }); +}; +var isRunningInBrowser = () => { + return ( + // @ts-ignore + typeof window !== "undefined" && // @ts-ignore + typeof window.document !== "undefined" && // @ts-ignore + typeof navigator !== "undefined" + ); +}; + +// node_modules/openai/pagination.mjs +var Page = class extends AbstractPage { + constructor(client, response, body, options) { + super(client, response, body, options); + this.object = body.object; + this.data = body.data; + } + getPaginatedItems() { + return this.data; + } + // @deprecated Please use `nextPageInfo()` instead + /** + * This page represents a response that isn't actually paginated at the API level + * so there will never be any next page params. + */ + nextPageParams() { + return null; + } + nextPageInfo() { + return null; + } +}; +var CursorPage = class extends AbstractPage { + constructor(client, response, body, options) { + super(client, response, body, options); + this.data = body.data; + } + getPaginatedItems() { + return this.data; + } + // @deprecated Please use `nextPageInfo()` instead + nextPageParams() { + const info = this.nextPageInfo(); + if (!info) + return null; + if ("params" in info) + return info.params; + const params = Object.fromEntries(info.url.searchParams); + if (!Object.keys(params).length) + return null; + return params; + } + nextPageInfo() { + var _a2, _b; + if (!((_a2 = this.data) === null || _a2 === void 0 ? void 0 : _a2.length)) { + return null; + } + const next = (_b = this.data[this.data.length - 1]) === null || _b === void 0 ? void 0 : _b.id; + if (!next) + return null; + return { params: { after: next } }; + } +}; + +// node_modules/openai/resource.mjs +var APIResource = class { + constructor(client) { + this.client = client; + this.get = client.get.bind(client); + this.post = client.post.bind(client); + this.patch = client.patch.bind(client); + this.put = client.put.bind(client); + this.delete = client.delete.bind(client); + this.getAPIList = client.getAPIList.bind(client); + } +}; + +// node_modules/openai/resources/audio/transcriptions.mjs +var Transcriptions = class extends APIResource { + /** + * Transcribes audio into the input language. + */ + create(body, options) { + return this.post("/audio/transcriptions", multipartFormRequestOptions({ body, ...options })); + } +}; +(function(Transcriptions2) { +})(Transcriptions || (Transcriptions = {})); + +// node_modules/openai/resources/audio/translations.mjs +var Translations = class extends APIResource { + /** + * Translates audio into English. + */ + create(body, options) { + return this.post("/audio/translations", multipartFormRequestOptions({ body, ...options })); + } +}; +(function(Translations2) { +})(Translations || (Translations = {})); + +// node_modules/openai/resources/audio/audio.mjs +var Audio = class extends APIResource { + constructor() { + super(...arguments); + this.transcriptions = new Transcriptions(this.client); + this.translations = new Translations(this.client); + } +}; +(function(Audio2) { + Audio2.Transcriptions = Transcriptions; + Audio2.Translations = Translations; +})(Audio || (Audio = {})); + +// node_modules/openai/resources/chat/completions.mjs +var Completions = class extends APIResource { + create(body, options) { + var _a2; + return this.post("/chat/completions", { + body, + ...options, + stream: (_a2 = body.stream) !== null && _a2 !== void 0 ? _a2 : false + }); + } +}; +(function(Completions3) { +})(Completions || (Completions = {})); + +// node_modules/openai/resources/chat/chat.mjs +var Chat = class extends APIResource { + constructor() { + super(...arguments); + this.completions = new Completions(this.client); + } +}; +(function(Chat2) { + Chat2.Completions = Completions; +})(Chat || (Chat = {})); + +// node_modules/openai/resources/completions.mjs +var Completions2 = class extends APIResource { + create(body, options) { + var _a2; + return this.post("/completions", { + body, + ...options, + stream: (_a2 = body.stream) !== null && _a2 !== void 0 ? _a2 : false + }); + } +}; +(function(Completions3) { +})(Completions2 || (Completions2 = {})); + +// node_modules/openai/resources/embeddings.mjs +var Embeddings = class extends APIResource { + /** + * Creates an embedding vector representing the input text. + */ + create(body, options) { + return this.post("/embeddings", { body, ...options }); + } +}; +(function(Embeddings2) { +})(Embeddings || (Embeddings = {})); + +// node_modules/openai/resources/edits.mjs +var Edits = class extends APIResource { + /** + * Creates a new edit for the provided input, instruction, and parameters. + * + * @deprecated The Edits API is deprecated; please use Chat Completions instead. + * + * https://openai.com/blog/gpt-4-api-general-availability#deprecation-of-the-edits-api + */ + create(body, options) { + return this.post("/edits", { body, ...options }); + } +}; +(function(Edits2) { +})(Edits || (Edits = {})); + +// node_modules/openai/resources/files.mjs +var Files = class extends APIResource { + /** + * Upload a file that contains document(s) to be used across various + * endpoints/features. Currently, the size of all the files uploaded by one + * organization can be up to 1 GB. Please contact us if you need to increase the + * storage limit. + */ + create(body, options) { + return this.post("/files", multipartFormRequestOptions({ body, ...options })); + } + /** + * Returns information about a specific file. + */ + retrieve(fileId, options) { + return this.get(`/files/${fileId}`, options); + } + /** + * Returns a list of files that belong to the user's organization. + */ + list(options) { + return this.getAPIList("/files", FileObjectsPage, options); + } + /** + * Delete a file. + */ + del(fileId, options) { + return this.delete(`/files/${fileId}`, options); + } + /** + * Returns the contents of the specified file + */ + retrieveContent(fileId, options) { + return this.get(`/files/${fileId}/content`, { + ...options, + headers: { + Accept: "application/json", + ...options === null || options === void 0 ? void 0 : options.headers + } + }); + } + /** + * Waits for the given file to be processed, default timeout is 30 mins. + */ + async waitForProcessing(id, { pollInterval = 5e3, maxWait = 30 * 60 * 1e3 } = {}) { + const TERMINAL_STATES = /* @__PURE__ */ new Set(["processed", "error", "deleted"]); + const start = Date.now(); + let file = await this.retrieve(id); + while (!file.status || !TERMINAL_STATES.has(file.status)) { + await sleep(pollInterval); + file = await this.retrieve(id); + if (Date.now() - start > maxWait) { + throw new APIConnectionTimeoutError({ + message: `Giving up on waiting for file ${id} to finish processing after ${maxWait} milliseconds.` + }); + } + } + return file; + } +}; +var FileObjectsPage = class extends Page { +}; +(function(Files2) { +})(Files || (Files = {})); + +// node_modules/openai/resources/fine-tunes.mjs +var FineTunes = class extends APIResource { + /** + * Creates a job that fine-tunes a specified model from a given dataset. + * + * Response includes details of the enqueued job including job status and the name + * of the fine-tuned models once complete. + * + * [Learn more about fine-tuning](/docs/guides/legacy-fine-tuning) + */ + create(body, options) { + return this.post("/fine-tunes", { body, ...options }); + } + /** + * Gets info about the fine-tune job. + * + * [Learn more about fine-tuning](/docs/guides/legacy-fine-tuning) + */ + retrieve(fineTuneId, options) { + return this.get(`/fine-tunes/${fineTuneId}`, options); + } + /** + * List your organization's fine-tuning jobs + */ + list(options) { + return this.getAPIList("/fine-tunes", FineTunesPage, options); + } + /** + * Immediately cancel a fine-tune job. + */ + cancel(fineTuneId, options) { + return this.post(`/fine-tunes/${fineTuneId}/cancel`, options); + } + listEvents(fineTuneId, query, options) { + var _a2; + return this.get(`/fine-tunes/${fineTuneId}/events`, { + query, + timeout: 864e5, + ...options, + stream: (_a2 = query === null || query === void 0 ? void 0 : query.stream) !== null && _a2 !== void 0 ? _a2 : false + }); + } +}; +var FineTunesPage = class extends Page { +}; +(function(FineTunes2) { +})(FineTunes || (FineTunes = {})); + +// node_modules/openai/resources/fine-tuning/jobs.mjs +var Jobs = class extends APIResource { + /** + * Creates a job that fine-tunes a specified model from a given dataset. + * + * Response includes details of the enqueued job including job status and the name + * of the fine-tuned models once complete. + * + * [Learn more about fine-tuning](/docs/guides/fine-tuning) + */ + create(body, options) { + return this.post("/fine_tuning/jobs", { body, ...options }); + } + /** + * Get info about a fine-tuning job. + * + * [Learn more about fine-tuning](/docs/guides/fine-tuning) + */ + retrieve(fineTuningJobId, options) { + return this.get(`/fine_tuning/jobs/${fineTuningJobId}`, options); + } + list(query = {}, options) { + if (isRequestOptions(query)) { + return this.list({}, query); + } + return this.getAPIList("/fine_tuning/jobs", FineTuningJobsPage, { query, ...options }); + } + /** + * Immediately cancel a fine-tune job. + */ + cancel(fineTuningJobId, options) { + return this.post(`/fine_tuning/jobs/${fineTuningJobId}/cancel`, options); + } + listEvents(fineTuningJobId, query = {}, options) { + if (isRequestOptions(query)) { + return this.listEvents(fineTuningJobId, {}, query); + } + return this.getAPIList(`/fine_tuning/jobs/${fineTuningJobId}/events`, FineTuningJobEventsPage, { + query, + ...options + }); + } +}; +var FineTuningJobsPage = class extends CursorPage { +}; +var FineTuningJobEventsPage = class extends CursorPage { +}; +(function(Jobs2) { +})(Jobs || (Jobs = {})); + +// node_modules/openai/resources/fine-tuning/fine-tuning.mjs +var FineTuning = class extends APIResource { + constructor() { + super(...arguments); + this.jobs = new Jobs(this.client); + } +}; +(function(FineTuning2) { + FineTuning2.Jobs = Jobs; + FineTuning2.FineTuningJobsPage = FineTuningJobsPage; + FineTuning2.FineTuningJobEventsPage = FineTuningJobEventsPage; +})(FineTuning || (FineTuning = {})); + +// node_modules/openai/resources/images.mjs +var Images = class extends APIResource { + /** + * Creates a variation of a given image. + */ + createVariation(body, options) { + return this.post("/images/variations", multipartFormRequestOptions({ body, ...options })); + } + /** + * Creates an edited or extended image given an original image and a prompt. + */ + edit(body, options) { + return this.post("/images/edits", multipartFormRequestOptions({ body, ...options })); + } + /** + * Creates an image given a prompt. + */ + generate(body, options) { + return this.post("/images/generations", { body, ...options }); + } +}; +(function(Images2) { +})(Images || (Images = {})); + +// node_modules/openai/resources/models.mjs +var Models = class extends APIResource { + /** + * Retrieves a model instance, providing basic information about the model such as + * the owner and permissioning. + */ + retrieve(model, options) { + return this.get(`/models/${model}`, options); + } + /** + * Lists the currently available models, and provides basic information about each + * one such as the owner and availability. + */ + list(options) { + return this.getAPIList("/models", ModelsPage, options); + } + /** + * Delete a fine-tuned model. You must have the Owner role in your organization to + * delete a model. + */ + del(model, options) { + return this.delete(`/models/${model}`, options); + } +}; +var ModelsPage = class extends Page { +}; +(function(Models2) { +})(Models || (Models = {})); + +// node_modules/openai/resources/moderations.mjs +var Moderations = class extends APIResource { + /** + * Classifies if text violates OpenAI's Content Policy + */ + create(body, options) { + return this.post("/moderations", { body, ...options }); + } +}; +(function(Moderations2) { +})(Moderations || (Moderations = {})); + +// node_modules/openai/index.mjs +var _a; +var OpenAI = class extends APIClient { + /** + * API Client for interfacing with the OpenAI API. + * + * @param {string} [opts.apiKey=process.env['OPENAI_API_KEY']] - The API Key to send to the API. + * @param {string} [opts.baseURL] - Override the default base URL for the API. + * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out. + * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections. + * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation. + * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request. + * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API. + * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API. + * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers. + * @param {string | null} [opts.organization] + */ + constructor(_b) { + var _c, _d, _e; + var { + apiKey = readEnv("OPENAI_API_KEY"), + organization = (_c = readEnv("OPENAI_ORG_ID")) !== null && _c !== void 0 ? _c : null, + ...opts + } = _b === void 0 ? {} : _b; + if (apiKey === void 0) { + throw new Error( + "The OPENAI_API_KEY environment variable is missing or empty; either provide it, or instantiate the OpenAI client with an apiKey option, like new OpenAI({ apiKey: 'my apiKey' })." + ); + } + const options = { + apiKey, + organization, + ...opts, + baseURL: (_d = opts.baseURL) !== null && _d !== void 0 ? _d : `https://api.openai.com/v1` + }; + if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) { + throw new Error( + "It looks like you're running in a browser-like environment.\n\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\nIf you understand the risks and have appropriate mitigations in place,\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\n\nnew OpenAI({ apiKey, dangerouslyAllowBrowser: true });\n\nhttps://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety\n" + ); + } + super({ + baseURL: options.baseURL, + timeout: (_e = options.timeout) !== null && _e !== void 0 ? _e : 6e5, + httpAgent: options.httpAgent, + maxRetries: options.maxRetries, + fetch: options.fetch + }); + this.completions = new Completions2(this); + this.chat = new Chat(this); + this.edits = new Edits(this); + this.embeddings = new Embeddings(this); + this.files = new Files(this); + this.images = new Images(this); + this.audio = new Audio(this); + this.moderations = new Moderations(this); + this.models = new Models(this); + this.fineTuning = new FineTuning(this); + this.fineTunes = new FineTunes(this); + this._options = options; + this.apiKey = apiKey; + this.organization = organization; + } + defaultQuery() { + return this._options.defaultQuery; + } + defaultHeaders(opts) { + return { + ...super.defaultHeaders(opts), + "OpenAI-Organization": this.organization, + ...this._options.defaultHeaders + }; + } + authHeaders(opts) { + return { Authorization: `Bearer ${this.apiKey}` }; + } +}; +_a = OpenAI; +OpenAI.OpenAI = _a; +OpenAI.APIError = APIError; +OpenAI.APIConnectionError = APIConnectionError; +OpenAI.APIConnectionTimeoutError = APIConnectionTimeoutError; +OpenAI.APIUserAbortError = APIUserAbortError; +OpenAI.NotFoundError = NotFoundError; +OpenAI.ConflictError = ConflictError; +OpenAI.RateLimitError = RateLimitError; +OpenAI.BadRequestError = BadRequestError; +OpenAI.AuthenticationError = AuthenticationError; +OpenAI.InternalServerError = InternalServerError; +OpenAI.PermissionDeniedError = PermissionDeniedError; +OpenAI.UnprocessableEntityError = UnprocessableEntityError; +var { + APIError: APIError2, + APIConnectionError: APIConnectionError2, + APIConnectionTimeoutError: APIConnectionTimeoutError2, + APIUserAbortError: APIUserAbortError2, + NotFoundError: NotFoundError2, + ConflictError: ConflictError2, + RateLimitError: RateLimitError2, + BadRequestError: BadRequestError2, + AuthenticationError: AuthenticationError2, + InternalServerError: InternalServerError2, + PermissionDeniedError: PermissionDeniedError2, + UnprocessableEntityError: UnprocessableEntityError2 +} = error_exports; +(function(OpenAI2) { + OpenAI2.toFile = toFile; + OpenAI2.fileFromPath = fileFromPath; + OpenAI2.Page = Page; + OpenAI2.CursorPage = CursorPage; + OpenAI2.Completions = Completions2; + OpenAI2.Chat = Chat; + OpenAI2.Edits = Edits; + OpenAI2.Embeddings = Embeddings; + OpenAI2.Files = Files; + OpenAI2.FileObjectsPage = FileObjectsPage; + OpenAI2.Images = Images; + OpenAI2.Audio = Audio; + OpenAI2.Moderations = Moderations; + OpenAI2.Models = Models; + OpenAI2.ModelsPage = ModelsPage; + OpenAI2.FineTuning = FineTuning; + OpenAI2.FineTunes = FineTunes; + OpenAI2.FineTunesPage = FineTunesPage; +})(OpenAI || (OpenAI = {})); +var openai_default = OpenAI; + +// src/components/editor/FetchRenameNoteTitle.ts +async function fetchModelRenameTitle(settings, referenceCurrentNoteContent2) { + var _a2, _b; + const clearYamlContent = referenceCurrentNoteContent2.replace(/---[\s\S]+?---/, "").trim(); + const prompt = `You are a title generator. You will give succinct titles that does not contain backslashes, + forward slashes, or colons. Only generate a title as your response for: + +`; + try { + if (settings.OllamaConnection.RESTAPIURL && settings.OllamaConnection.ollamaModels.includes(settings.general.model)) { + try { + const ollama = new Ollama2({ host: settings.OllamaConnection.RESTAPIURL }); + const response = await ollama.generate({ + model: settings.general.model, + system: prompt, + prompt: clearYamlContent + "\n\n", + stream: false, + options: { + temperature: parseInt(settings.general.temperature), + num_predict: 40 + } + }); + let title = response.response; + if (title) { + title = title.replace(/[\\/:"]/g, ""); + } + return title; + } catch (error) { + new import_obsidian5.Notice("Error generating title:", error); + console.error("Error generating title:", error); + throw error; + } + } else if (settings.RESTAPIURLConnection.RESTAPIURLModels.includes(settings.general.model)) { + try { + const response = await (0, import_obsidian5.requestUrl)({ + url: settings.RESTAPIURLConnection.RESTAPIURL + "/chat/completions", + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${settings.RESTAPIURLConnection.APIKey}` + }, + body: JSON.stringify({ + model: settings.general.model, + messages: [ + { role: "system", content: prompt + clearYamlContent }, + { role: "user", content: "\n" } + ], + max_tokens: 40 + }) + }); + let title = response.json.choices[0].message.content; + if (title) { + title = title.replace(/[\\/:"]/g, ""); + } + return title; + } catch (error) { + console.error("Error making API request:", error); + throw error; + } + } else if (ANTHROPIC_MODELS.includes(settings.general.model)) { + try { + const response = await (0, import_obsidian5.requestUrl)({ + url: "https://api.anthropic.com/v1/messages", + method: "POST", + headers: { + "anthropic-version": "2023-06-01", + "content-type": "application/json", + "x-api-key": settings.APIConnections.anthropic.APIKey + }, + body: JSON.stringify({ + model: settings.general.model, + system: prompt, + messages: [ + { role: "user", content: `${clearYamlContent}` } + ], + max_tokens: 40, + temperature: parseInt(settings.general.temperature) + }) + }); + let title = response.json.content[0].text; + if (title) { + title = title.replace(/[\\/:"]/g, ""); + } + return title; + } catch (error) { + new import_obsidian5.Notice(error); + console.error(error); + throw error; + } + } else if (settings.APIConnections.googleGemini.geminiModels.includes(settings.general.model)) { + try { + const API_KEY = settings.APIConnections.googleGemini.APIKey; + const requestBody = { + contents: [{ + parts: [ + { text: prompt + clearYamlContent } + ] + }] + }; + const response = await (0, import_obsidian5.requestUrl)({ + url: `https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${API_KEY}`, + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(requestBody) + }); + let title = response.json.candidates[0].content.parts[0].text; + if (title) { + title = title.replace(/[\\/:"]/g, ""); + } + return title; + } catch (error) { + console.error(error); + } + } else if (settings.APIConnections.mistral.mistralModels.includes(settings.general.model)) { + try { + const response = await (0, import_obsidian5.requestUrl)({ + url: "https://api.mistral.ai/v1/chat/completions", + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${settings.APIConnections.mistral.APIKey}` + }, + body: JSON.stringify({ + model: settings.general.model, + messages: [ + { role: "system", content: prompt + clearYamlContent }, + { role: "user", content: "\n" } + ], + max_tokens: 40 + }) + }); + let title = response.json.choices[0].message.content; + if (title) { + title = title.replace(/[\\/:"]/g, ""); + } + return title; + } catch (error) { + console.error(error); + } + } else if (OPENAI_MODELS.includes(settings.general.model) || settings.APIConnections.openAI.openAIBaseModels.includes(settings.general.model)) { + const openai = new openai_default({ + apiKey: settings.APIConnections.openAI.APIKey, + baseURL: settings.APIConnections.openAI.openAIBaseUrl, + dangerouslyAllowBrowser: true + // apiKey is stored within data.json + }); + const chatCompletion = await openai.chat.completions.create({ + model: settings.general.model, + max_tokens: 40, + messages: [ + { role: "system", content: prompt + clearYamlContent }, + { role: "user", content: "" } + ] + }); + let title = chatCompletion.choices[0].message.content; + if (title) { + title = title.replace(/[\\/:"]/g, ""); + } + return title; + } else if (settings.APIConnections.openRouter.openRouterModels.includes(settings.general.model)) { + try { + const response = await (0, import_obsidian5.requestUrl)({ + url: "https://openrouter.ai/api/v1/chat/completions", + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${settings.APIConnections.openRouter.APIKey}` + }, + body: JSON.stringify({ + model: settings.general.model, + messages: [ + { role: "system", content: prompt + clearYamlContent }, + { role: "user", content: "\n" } + ], + max_tokens: 40 + }) + }); + let title = response.json.choices[0].message.content; + if (title) { + title = title.replace(/[\\/:"]/g, ""); + } + return title; + } catch (error) { + console.error("Error making API request:", error); + throw error; + } + } else { + throw new Error("Invalid model selected for renaming note title. Please check your settings."); + } + } catch (error) { + console.log("ERROR"); + throw new Error(((_b = (_a2 = error.response) == null ? void 0 : _a2.data) == null ? void 0 : _b.error) || error.message); + } +} + +// src/components/chat/Commands.ts +var lastLoadedChatHistoryFile = null; +var commandMap = { + "/help": (input, settings, plugin) => commandHelp(plugin, settings), + "/model": (input, settings, plugin) => commandModel(input, settings, plugin), + "/profile": (input, settings, plugin) => commandProfile(input, settings, plugin), + "/prompt": (input, settings, plugin) => commandPrompt(input, settings, plugin), + "/reference": (input, settings, plugin) => commandReference(input, settings, plugin), + "/temperature": (input, settings, plugin) => commandTemperature(input, settings, plugin), + "/maxtokens": (input, settings, plugin) => commandMaxTokens(input, settings, plugin), + "/append": (input, settings, plugin) => commandAppend(plugin, settings), + "/save": (input, settings, plugin) => commandSave(plugin, settings), + "/load": (input, settings, plugin) => commandLoad(input, plugin, settings), + "/clear": (input, settings, plugin) => removeMessageThread(plugin, 0), + "/stop": (input, settings, plugin) => commandStop() +}; +var aliases = { + "/help": ["/h", "/man", "/manual", "/commands"], + "/model": ["/m", "/models"], + "/profile": ["/p", "/prof", "/profiles"], + "/prompt": ["/prompts"], + "/reference": ["/ref"], + "/temperature": ["/temp", ""], + "/clear": ["/c"], + "/stop": ["/s"] +}; +Object.entries(aliases).forEach(([command, aliasList]) => { + aliasList.forEach((alias) => commandMap[alias] = commandMap[command]); +}); +function executeCommand(input, settings, plugin) { + const command = input.split(" ")[0]; + const handler = commandMap[command] || (() => commandFalse()); + return handler(input, settings, plugin); +} +async function commandFalse() { + new import_obsidian6.Notice("Command not recognized. Type `/help` for commands."); + const chatbox = document.querySelector(".chatbox textarea"); + chatbox.value = ""; +} +function commandHelp(plugin, settings) { + const messageContainer = document.querySelector("#messageContainer"); + const botMessageDiv = document.createElement("div"); + botMessageDiv.className = "botMessage"; + botMessageDiv.style.backgroundColor = colorToHex(settings.appearance.botMessageBackgroundColor || getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor).trim()); + const botMessageToolBarDiv = document.createElement("div"); + botMessageToolBarDiv.className = "botMessageToolBar"; + const botNameSpan = document.createElement("span"); + botNameSpan.textContent = settings.appearance.chatbotName || DEFAULT_SETTINGS.appearance.chatbotName; + botNameSpan.className = "chatbotName"; + const messageBlockDiv = document.createElement("div"); + messageBlockDiv.className = "messageBlock"; + const displayCommandBotMessageDiv = document.createElement("div"); + displayCommandBotMessageDiv.className = "commandBotMessage"; + const header = document.createElement("h3"); + header.textContent = "Manual"; + header.style.textAlign = "center"; + displayCommandBotMessageDiv.appendChild(header); + const generalCommandHeader = document.createElement("h4"); + generalCommandHeader.textContent = "General Commands"; + generalCommandHeader.style.textAlign = "left"; + displayCommandBotMessageDiv.appendChild(generalCommandHeader); + const commandClearP = document.createElement("p"); + commandClearP.innerHTML = "/clear or /c - Clear chat history."; + displayCommandBotMessageDiv.appendChild(commandClearP); + const commandRefOnP = document.createElement("p"); + commandRefOnP.innerHTML = '/ref on - Turn on "reference current note".'; + displayCommandBotMessageDiv.appendChild(commandRefOnP); + const commandRefOffP = document.createElement("p"); + commandRefOffP.innerHTML = '/ref off - Turn off "reference current note".'; + displayCommandBotMessageDiv.appendChild(commandRefOffP); + const commandMaxTokensP = document.createElement("p"); + commandMaxTokensP.innerHTML = "/maxtokens [VALUE] - Set max tokens."; + displayCommandBotMessageDiv.appendChild(commandMaxTokensP); + const commandTempP = document.createElement("p"); + commandTempP.innerHTML = "/temp [VALUE] - Change temperature range from 0 to 2."; + displayCommandBotMessageDiv.appendChild(commandTempP); + const profileCommandHeader = document.createElement("h4"); + profileCommandHeader.textContent = "Profile Commands"; + profileCommandHeader.style.textAlign = "left"; + displayCommandBotMessageDiv.appendChild(profileCommandHeader); + const commandProfileListP = document.createElement("p"); + commandProfileListP.innerHTML = "/profile - List profile."; + displayCommandBotMessageDiv.appendChild(commandProfileListP); + const commandProfileChangeP = document.createElement("p"); + commandProfileChangeP.innerHTML = "/profile [PROFILE-NAME] or [VALUE] - Change profile."; + displayCommandBotMessageDiv.appendChild(commandProfileChangeP); + const modelCommandHeader = document.createElement("h4"); + modelCommandHeader.textContent = "Model Commands"; + modelCommandHeader.style.textAlign = "left"; + displayCommandBotMessageDiv.appendChild(modelCommandHeader); + const commandModelListP = document.createElement("p"); + commandModelListP.innerHTML = "/model - List model."; + displayCommandBotMessageDiv.appendChild(commandModelListP); + const commandModelChangeP = document.createElement("p"); + commandModelChangeP.innerHTML = "/model [MODEL-NAME] or [VALUE] - Change model."; + displayCommandBotMessageDiv.appendChild(commandModelChangeP); + const promptCommandHeader = document.createElement("h4"); + promptCommandHeader.textContent = "Prompt Commands"; + promptCommandHeader.style.textAlign = "left"; + displayCommandBotMessageDiv.appendChild(promptCommandHeader); + const commandPromptListP = document.createElement("p"); + commandPromptListP.innerHTML = "/prompt - List prompts."; + displayCommandBotMessageDiv.appendChild(commandPromptListP); + const commandPromptChangeP = document.createElement("p"); + commandPromptChangeP.innerHTML = "/prompt [PROMPT-NAME] or [VALUE] - Change prompts."; + displayCommandBotMessageDiv.appendChild(commandPromptChangeP); + const commandPromptClearP = document.createElement("p"); + commandPromptClearP.innerHTML = "/prompt clear - Clear prompt."; + displayCommandBotMessageDiv.appendChild(commandPromptClearP); + const editorCommandHeader = document.createElement("h4"); + editorCommandHeader.textContent = "Editor Commands"; + editorCommandHeader.style.textAlign = "left"; + displayCommandBotMessageDiv.appendChild(editorCommandHeader); + const commandAppendP = document.createElement("p"); + commandAppendP.innerHTML = "/append - Append current chat history to current active note."; + displayCommandBotMessageDiv.appendChild(commandAppendP); + const commandSaveP = document.createElement("p"); + commandSaveP.innerHTML = "/save - Save current chat history to a note."; + displayCommandBotMessageDiv.appendChild(commandSaveP); + const commandLoadP = document.createElement("p"); + commandLoadP.innerHTML = "/load - List or load a chat history into view."; + displayCommandBotMessageDiv.appendChild(commandLoadP); + const streamCommandHeader = document.createElement("h4"); + streamCommandHeader.textContent = "Response Commands"; + streamCommandHeader.style.textAlign = "left"; + displayCommandBotMessageDiv.appendChild(streamCommandHeader); + const commandStopP = document.createElement("p"); + commandStopP.innerHTML = "/stop or /s - Stop fetching response. Warning: Anthropric models cannot be aborted. Please use with caution."; + displayCommandBotMessageDiv.appendChild(commandStopP); + messageBlockDiv.appendChild(displayCommandBotMessageDiv); + botMessageToolBarDiv.appendChild(botNameSpan); + botMessageDiv.appendChild(botMessageToolBarDiv); + botMessageDiv.appendChild(messageBlockDiv); + const index2 = messageHistory.length - 1; + addMessage(plugin, messageBlockDiv.innerHTML, "botMessage", settings, index2); + messageContainer.appendChild(botMessageDiv); +} +async function commandModel(input, settings, plugin) { + const messageContainer = document.querySelector("#messageContainer"); + const ollamaModels = settings.OllamaConnection.ollamaModels.map((model) => model); + const RESTAPIModels = settings.RESTAPIURLConnection.RESTAPIURLModels.map((model) => model); + const anthropicModels = settings.APIConnections.anthropic.anthropicModels.map((model) => model); + const googleGeminiModels = settings.APIConnections.googleGemini.geminiModels.map((model) => model); + const mistralModels = settings.APIConnections.mistral.mistralModels.map((model) => model); + const openAIBaseModels = settings.APIConnections.openAI.openAIBaseModels.map((model) => model); + const openRouterModels = settings.APIConnections.openRouter.openRouterModels.map((model) => model); + const allModels = [ + ...settings.OllamaConnection.ollamaModels, + ...settings.RESTAPIURLConnection.RESTAPIURLModels, + ...settings.APIConnections.anthropic.anthropicModels, + ...settings.APIConnections.googleGemini.geminiModels, + ...settings.APIConnections.mistral.mistralModels, + ...settings.APIConnections.openAI.openAIBaseModels, + ...settings.APIConnections.openRouter.openRouterModels + ]; + if (!input.split(" ")[1]) { + let currentModel = settings.general.model; + if (!currentModel) { + currentModel = "Empty"; + } + const botMessageDiv = document.createElement("div"); + botMessageDiv.className = "botMessage"; + botMessageDiv.style.backgroundColor = colorToHex(settings.appearance.botMessageBackgroundColor || getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor).trim()); + const botMessageToolBarDiv = document.createElement("div"); + botMessageToolBarDiv.className = "botMessageToolBar"; + const botNameSpan = document.createElement("span"); + botNameSpan.textContent = settings.appearance.chatbotName || DEFAULT_SETTINGS.appearance.chatbotName; + botNameSpan.className = "chatbotName"; + const messageBlockDiv = document.createElement("div"); + messageBlockDiv.className = "messageBlock"; + const displayCommandBotMessageDiv = document.createElement("div"); + displayCommandBotMessageDiv.className = "commandBotMessage"; + const header = document.createElement("h3"); + header.textContent = "Model List"; + header.style.textAlign = "center"; + displayCommandBotMessageDiv.appendChild(header); + const currentModelP = document.createElement("p"); + currentModelP.innerHTML = `Current Model: ${currentModel}`; + currentModelP.style.textAlign = "center"; + displayCommandBotMessageDiv.appendChild(currentModelP); + const apiLists = [ + { header: "Ollama Models", items: ollamaModels }, + { header: "REST API Models", items: RESTAPIModels }, + { header: "Anthropic Models", items: anthropicModels }, + { header: "Google Gemini Models", items: googleGeminiModels }, + { header: "Mistral Models", items: mistralModels }, + { header: "OpenAI-Based Models", items: openAIBaseModels }, + { header: "OpenRouter Models", items: openRouterModels } + ]; + let currentStartIndex = 1; + apiLists.forEach((api) => { + if (Array.isArray(api.items) && api.items.length) { + const header2 = document.createElement("h4"); + header2.textContent = api.header; + displayCommandBotMessageDiv.appendChild(header2); + const list = document.createElement("ol"); + list.setAttribute("start", String(currentStartIndex)); + api.items.forEach((item) => { + const listItem = document.createElement("li"); + listItem.textContent = item; + list.appendChild(listItem); + }); + displayCommandBotMessageDiv.appendChild(list); + currentStartIndex += api.items.length; + } + }); + messageBlockDiv.appendChild(displayCommandBotMessageDiv); + botMessageToolBarDiv.appendChild(botNameSpan); + botMessageDiv.appendChild(botMessageToolBarDiv); + botMessageDiv.appendChild(messageBlockDiv); + const index2 = messageHistory.length - 1; + addMessage(plugin, messageBlockDiv.innerHTML, "botMessage", settings, index2); + messageContainer.appendChild(botMessageDiv); + } + if (input.split(" ")[1] !== void 0) { + const inputModel = input.split(" ")[1].replace(/^"(.*)"$/, "$1"); + const modelAliases = {}; + for (let i = 1; i <= allModels.length; i++) { + const model = allModels[i - 1]; + modelAliases[i] = model; + } + if (Object.entries(modelAliases).find(([key, val]) => key === inputModel)) { + settings.general.model = modelAliases[inputModel]; + new import_obsidian6.Notice(`Updated model to ${settings.general.model}`); + } else if (Object.entries(modelAliases).find(([key, val]) => val === inputModel)) { + settings.general.model = modelAliases[Object.keys(modelAliases).find((key) => modelAliases[key] === inputModel) || ""]; + new import_obsidian6.Notice(`Updated model to ${settings.general.model}`); + } else { + new import_obsidian6.Notice("Invalid model."); + } + await plugin.saveSettings(); + } +} +async function commandProfile(input, settings, plugin) { + const messageContainer = document.querySelector("#messageContainer"); + if (!settings.profiles.profileFolderPath) { + new import_obsidian6.Notice("Profile folder path not set."); + const commandBotMessage = "

Profile folder path not set.

"; + const botMessageDiv = displayCommandBotMessage(plugin, settings, messageHistory, commandBotMessage); + messageContainer.appendChild(botMessageDiv); + return; + } + const files = plugin.app.vault.getFiles().filter((file) => file.path.startsWith(plugin.settings.profiles.profileFolderPath)); + files.sort((a, b) => a.name.localeCompare(b.name)); + let currentProfile = settings.profiles.profile.replace(/\.[^/.]+$/, ""); + if (!input.split(" ")[1]) { + const fileListItems = files.map((file) => { + const fileNameWithoutExtension = file.name.replace(/\.[^/.]+$/, ""); + return `
  • ${fileNameWithoutExtension}
  • `; + }).join(""); + if (!currentProfile) { + currentProfile = "Empty"; + } + const commandBotMessage = `

    Profiles

    +

    Current profile: ${currentProfile}

    +
      ${fileListItems}
    `; + const botMessageDiv = displayCommandBotMessage(plugin, settings, messageHistory, commandBotMessage); + messageContainer.appendChild(botMessageDiv); + return; + } + if (input.startsWith("/p") || input.startsWith("/prof") || input.startsWith("/profile") || input.startsWith("/profiles")) { + let inputValue = input.split(" ").slice(1).join(" ").trim(); + if (inputValue.startsWith('"') && inputValue.endsWith('"') || inputValue.startsWith("'") && inputValue.endsWith("'")) { + inputValue = inputValue.substring(1, inputValue.length - 1); + } + const profileAliases = {}; + for (let i = 1; i <= files.length; i++) { + const fileNameWithoutExtension = files[i - 1].name.replace(/\.[^/.]+$/, ""); + profileAliases[i.toString().toLowerCase()] = fileNameWithoutExtension; + } + if (profileAliases[inputValue]) { + plugin.settings.profiles.profile = profileAliases[inputValue] + ".md"; + const profileFilePath = plugin.settings.profiles.profileFolderPath + "/" + profileAliases[inputValue] + ".md"; + const currentProfile2 = plugin.app.vault.getAbstractFileByPath(profileFilePath); + const currentProfileName = settings.profiles.profile.replace(/\.[^/.]+$/, ""); + const profileIndex = files.findIndex((file) => file.basename === currentProfileName); + settings.profiles.lastLoadedChatHistoryPath = settings.profiles.lastLoadedChatHistory[profileIndex]; + plugin.activateView(); + await updateSettingsFromFrontMatter(plugin, currentProfile2); + await plugin.saveSettings(); + } else if (Object.values(profileAliases).map((v) => v.toLowerCase()).includes(inputValue.toLowerCase())) { + const matchedProfile = Object.entries(profileAliases).find(([key, value]) => value.toLowerCase() === inputValue.toLowerCase()); + if (matchedProfile) { + plugin.settings.profiles.profile = matchedProfile[1] + ".md"; + const profileFilePath = plugin.settings.profiles.profileFolderPath + "/" + matchedProfile[1] + ".md"; + const currentProfile2 = plugin.app.vault.getAbstractFileByPath(profileFilePath); + const currentProfileName = settings.profiles.profile.replace(/\.[^/.]+$/, ""); + const profileIndex = files.findIndex((file) => file.basename === currentProfileName); + settings.profiles.lastLoadedChatHistoryPath = settings.profiles.lastLoadedChatHistory[profileIndex]; + plugin.activateView(); + await updateSettingsFromFrontMatter(plugin, currentProfile2); + await plugin.saveSettings(); + } + } else { + new import_obsidian6.Notice("Invalid profile."); + } + await plugin.saveSettings(); + } +} +async function commandPrompt(input, settings, plugin) { + const messageContainer = document.querySelector("#messageContainer"); + if (!settings.prompts.promptFolderPath) { + new import_obsidian6.Notice("Prompt folder path not set."); + const commandBotMessage = "

    Prompt folder path not set.

    "; + const botMessageDiv = displayCommandBotMessage(plugin, settings, messageHistory, commandBotMessage); + messageContainer.appendChild(botMessageDiv); + return; + } + const files = plugin.app.vault.getFiles().filter((file) => file.path.startsWith(plugin.settings.prompts.promptFolderPath)); + files.sort((a, b) => a.name.localeCompare(b.name)); + if (!input.split(" ")[1]) { + const fileListItems = files.map((file) => { + const fileNameWithoutExtension = file.name.replace(/\.[^/.]+$/, ""); + return `
  • ${fileNameWithoutExtension}
  • `; + }).join(""); + let currentPrompt = settings.prompts.prompt; + if (!currentPrompt) { + currentPrompt = "Empty"; + } + const commandBotMessage = `

    Prompts

    +

    Current prompt: ${currentPrompt.replace(".md", "")}

    +
      ${fileListItems}
    `; + const botMessageDiv = displayCommandBotMessage(plugin, settings, messageHistory, commandBotMessage); + messageContainer.appendChild(botMessageDiv); + return; + } + if (input.startsWith("/prompt")) { + let inputValue = input.split(" ").slice(1).join(" ").trim(); + if (inputValue.startsWith('"') && inputValue.endsWith('"') || inputValue.startsWith("'") && inputValue.endsWith("'")) { + inputValue = inputValue.substring(1, inputValue.length - 1); + } + if (inputValue === "clear" || inputValue === "c") { + settings.prompts.prompt = ""; + new import_obsidian6.Notice("Prompt cleared."); + await plugin.saveSettings(); + } + const promptAliases = {}; + for (let i = 1; i <= files.length; i++) { + const fileNameWithoutExtension = files[i - 1].name.replace(/\.[^/.]+$/, ""); + promptAliases[i.toString()] = fileNameWithoutExtension; + } + let currentModel; + if (promptAliases[inputValue]) { + settings.prompts.prompt = promptAliases[inputValue] + ".md"; + currentModel = settings.prompts.prompt.replace(/\.[^/.]+$/, ""); + new import_obsidian6.Notice(`Prompt updated to '${currentModel}'`); + } else if (Object.values(promptAliases).map((v) => v.toLowerCase()).includes(inputValue.toLowerCase())) { + const matchedProfile = Object.entries(promptAliases).find(([key, value]) => value.toLowerCase() === inputValue.toLowerCase()); + if (matchedProfile) { + settings.prompts.prompt = matchedProfile[1] + ".md"; + currentModel = settings.prompts.prompt.replace(/\.[^/.]+$/, ""); + new import_obsidian6.Notice(`Prompt updated to '${currentModel}'`); + } + } else { + if (inputValue !== "clear" && inputValue !== "c") { + new import_obsidian6.Notice("Invalid prompt."); + } + } + await plugin.saveSettings(); + } +} +async function commandReference(input, settings, plugin) { + var _a2; + const referenceCurrentNoteElement = document.getElementById("referenceCurrentNote"); + const inputValue = (_a2 = input.split(" ")[1]) == null ? void 0 : _a2.toLowerCase(); + if (inputValue === "true" || inputValue === "on") { + settings.general.enableReferenceCurrentNote = true; + if (referenceCurrentNoteElement) { + referenceCurrentNoteElement.style.display = "block"; + } + new import_obsidian6.Notice("Reference current note: on."); + } else if (inputValue === "false" || inputValue === "off") { + settings.general.enableReferenceCurrentNote = false; + if (referenceCurrentNoteElement) { + referenceCurrentNoteElement.style.display = "none"; + } + new import_obsidian6.Notice("Reference current note: off."); + } else { + new import_obsidian6.Notice("Type `/ref on` or `/ref off` to turn on/off reference current note."); + } + await plugin.saveSettings(); +} +async function commandTemperature(input, settings, plugin) { + const inputValue = input.split(" ")[1]; + const floatValue = parseFloat(inputValue); + if (settings && !isNaN(floatValue)) { + if (floatValue < 0) { + settings.general.temperature = "0.00"; + } else if (floatValue > 2) { + settings.general.temperature = "2.00"; + } else { + settings.general.temperature = floatValue.toFixed(2); + } + new import_obsidian6.Notice(`Temperature updated: ${settings.general.temperature}`); + } else { + new import_obsidian6.Notice(`Current temperature: ${settings.general.temperature}`); + } + await plugin.saveSettings(); +} +async function commandMaxTokens(input, settings, plugin) { + const commandParts = input.split(" "); + const commandAction = commandParts[1] ? commandParts[1].toLowerCase() : ""; + if (commandAction === "c" || commandAction === "clear") { + settings.general.max_tokens = ""; + new import_obsidian6.Notice("Max tokens cleared."); + } else if (commandAction !== "") { + const inputValue = parseInt(commandAction); + if (!isNaN(inputValue) && inputValue >= 0) { + settings.general.max_tokens = inputValue.toString(); + new import_obsidian6.Notice(`Max tokens updated: ${inputValue}`); + } else { + new import_obsidian6.Notice("Max tokens update: invalid"); + } + } else { + if (settings.general.max_tokens === "") { + new import_obsidian6.Notice("Current max tokens: Empty"); + } else { + new import_obsidian6.Notice(`Current max tokens: ${settings.general.max_tokens}`); + } + } + await plugin.saveSettings(); +} +async function commandAppend(plugin, settings) { + let markdownContent = ""; + const activeFile = plugin.app.workspace.getActiveFile(); + if ((activeFile == null ? void 0 : activeFile.extension) === "md") { + const existingContent = await plugin.app.vault.read(activeFile); + const userNames = document.querySelectorAll(".userName"); + let userNameText = "USER"; + if (userNames.length > 0) { + const userNameNode = userNames[0]; + Array.from(userNameNode.childNodes).forEach((node) => { + if (node.nodeType === Node.TEXT_NODE && node.textContent) { + userNameText = node.textContent.trim().toUpperCase(); + } + }); + } + const chatbotNames = document.querySelectorAll(".chatbotName"); + const chatbotNameText = chatbotNames.length > 0 && chatbotNames[0].textContent ? chatbotNames[0].textContent.toUpperCase() : "ASSISTANT"; + if (await this.app.vault.adapter.exists(fileNameMessageHistoryJson(plugin))) { + try { + const jsonContent = await this.app.vault.adapter.read(fileNameMessageHistoryJson(plugin)); + const messages = JSON.parse(jsonContent); + let skipNext = false; + markdownContent += messages.filter((messageHistory2, index2, array) => { + if (skipNext && messageHistory2.role === "assistant") { + skipNext = false; + return false; + } + if (messageHistory2.content.startsWith("/") || messageHistory2.content.includes("errorBotMessage")) { + skipNext = index2 + 1 < array.length && array[index2 + 1].role === "assistant" || messageHistory2.role === "assistant"; + return false; + } + return true; + }).map((message) => { + let roleText = message.role.toUpperCase(); + roleText = roleText === "USER" ? userNameText : roleText; + roleText = roleText === "ASSISTANT" ? chatbotNameText : roleText; + return `###### ${roleText} +${message.content} +`; + }).join("\n"); + } catch (error) { + const messageContainer = document.querySelector("#messageContainer"); + const botMessageDiv = displayCommandBotMessage(plugin, settings, messageHistory, error); + messageContainer.appendChild(botMessageDiv); + console.error("Error processing message history:", error); + } + } + const updatedContent = existingContent + "\n" + markdownContent; + await plugin.app.vault.modify(activeFile, updatedContent); + new import_obsidian6.Notice("Appended conversation."); + } else { + new import_obsidian6.Notice("No active Markdown file detected."); + } +} +async function commandSave(plugin, settings) { + new import_obsidian6.Notice("Saving conversation..."); + let folderName = settings.chatHistory.chatHistoryPath; + if (!await plugin.app.vault.adapter.exists(folderName)) { + await plugin.app.vault.createFolder(folderName); + } + const baseFileName = "Chat History"; + const fileExtension = ".md"; + if (folderName && !folderName.endsWith("/")) { + folderName += "/"; + } + const now = new Date(); + const dateTimeStamp = now.getFullYear() + "-" + (now.getMonth() + 1).toString().padStart(2, "0") + "-" + now.getDate().toString().padStart(2, "0") + " " + now.getHours().toString().padStart(2, "0") + "-" + now.getMinutes().toString().padStart(2, "0") + "-" + now.getSeconds().toString().padStart(2, "0"); + try { + let markdownContent = ""; + const allFiles = plugin.app.vault.getFiles(); + const templateFile = allFiles.find((file) => file.path.toLowerCase() === settings.chatHistory.templateFilePath.toLowerCase()); + if (templateFile) { + let fileContent = await plugin.app.vault.read(templateFile); + if (/^---\s*[\s\S]*?---/.test(fileContent)) { + if (!/^model:\s/m.test(fileContent)) { + fileContent = fileContent.replace(/^---/, `--- +model: ${settings.general.model}`); + } + } else { + fileContent = `--- + model: ${settings.general.model} +--- +` + fileContent; + } + markdownContent += fileContent; + } else { + markdownContent += `--- + model: ${settings.general.model} +--- +`; + } + const userNames = document.querySelectorAll(".userName"); + let userNameText = "USER"; + if (userNames.length > 0) { + const userNameNode = userNames[0]; + Array.from(userNameNode.childNodes).forEach((node) => { + if (node.nodeType === Node.TEXT_NODE && node.textContent) { + userNameText = node.textContent.trim().toUpperCase(); + } + }); + } + const chatbotNames = document.querySelectorAll(".chatbotName"); + const chatbotNameText = chatbotNames.length > 0 && chatbotNames[0].textContent ? chatbotNames[0].textContent.toUpperCase() : "ASSISTANT"; + if (await plugin.app.vault.adapter.exists(fileNameMessageHistoryJson(plugin))) { + try { + const jsonContent = await plugin.app.vault.adapter.read(fileNameMessageHistoryJson(plugin)); + const messages = JSON.parse(jsonContent); + let skipNext = false; + markdownContent += messages.filter((messageHistory2, index2, array) => { + if (skipNext && messageHistory2.role === "assistant") { + skipNext = false; + return false; + } + if (messageHistory2.content.startsWith("/") || messageHistory2.content.includes("errorBotMessage")) { + skipNext = index2 + 1 < array.length && array[index2 + 1].role === "assistant" || messageHistory2.role === "assistant"; + return false; + } + return true; + }).map((message) => { + let roleText = message.role.toUpperCase(); + roleText = roleText === "USER" ? userNameText : roleText; + roleText = roleText === "ASSISTANT" ? chatbotNameText : roleText; + const regexRenderedBlock = /[\s\S]*?<\/block-rendered>/g; + message.content = message.content.replace(regexRenderedBlock, "").trim(); + const regexRenderedNote = /[\s\S]*?<\/note-rendered>/g; + message.content = message.content.replace(regexRenderedNote, "").trim(); + return `###### ${roleText} +${message.content} +`; + }).join("\n"); + } catch (error) { + console.error("Error processing message history:", error); + } + } + let fileName = ""; + if (settings.chatHistory.allowRenameNoteTitle) { + let uniqueNameFound = false; + let modelRenameTitle; + const fileNameExists = (name) => { + return allFiles.some((file) => file.path === folderName + name + fileExtension); + }; + while (!uniqueNameFound) { + modelRenameTitle = await fetchModelRenameTitle(settings, markdownContent); + if (!fileNameExists(modelRenameTitle)) { + uniqueNameFound = true; + } + } + fileName = folderName + modelRenameTitle + fileExtension; + } else { + fileName = folderName + baseFileName + " " + dateTimeStamp + fileExtension; + } + if (settings.profiles.lastLoadedChatHistoryPath !== null) { + lastLoadedChatHistoryFile = plugin.app.vault.getAbstractFileByPath(settings.profiles.lastLoadedChatHistoryPath); + } + if (lastLoadedChatHistoryFile === null) { + const file = await plugin.app.vault.create(fileName, markdownContent); + const profileFiles = plugin.app.vault.getFiles().filter((file2) => file2.path.startsWith(settings.profiles.profileFolderPath)); + profileFiles.sort((a, b) => a.name.localeCompare(b.name)); + const currentProfile = settings.profiles.profile.replace(/\.[^/.]+$/, ""); + const profileIndex = profileFiles.findIndex((file2) => file2.basename === currentProfile); + if (file) { + settings.profiles.lastLoadedChatHistoryPath = file.path; + settings.profiles.lastLoadedChatHistory[profileIndex] = file.path; + plugin.app.workspace.openLinkText(fileName, "", true, { active: true }); + } + } else { + await plugin.app.vault.modify(lastLoadedChatHistoryFile, markdownContent); + const activeFile = plugin.app.workspace.getActiveFile(); + if ((activeFile == null ? void 0 : activeFile.path) !== lastLoadedChatHistoryFile.path) { + plugin.app.workspace.openLinkText(lastLoadedChatHistoryFile.path, lastLoadedChatHistoryFile.path, true, { active: true }); + } + } + new import_obsidian6.Notice(`Saved to '${lastLoadedChatHistoryFile == null ? void 0 : lastLoadedChatHistoryFile.name}'`); + await plugin.saveSettings(); + } catch (error) { + console.error("Failed to create note:", error); + } +} +async function commandLoad(input, plugin, settings) { + const messageContainer = document.querySelector("#messageContainer"); + const folderPath = plugin.settings.chatHistory.chatHistoryPath.trim() || DEFAULT_SETTINGS.chatHistory.chatHistoryPath; + const files = plugin.app.vault.getFiles().filter((file) => file.path.startsWith(folderPath)); + files.sort((a, b) => a.name.localeCompare(b.name)); + const profileFiles = plugin.app.vault.getFiles().filter((file) => file.path.startsWith(plugin.settings.profiles.profileFolderPath)); + profileFiles.sort((a, b) => a.name.localeCompare(b.name)); + const currentProfile = settings.profiles.profile.replace(/\.[^/.]+$/, ""); + const profileIndex = profileFiles.findIndex((file) => file.basename === currentProfile); + if (!input.split(" ")[1]) { + const fileGroups = files.reduce((acc, file) => { + const fileNameWithoutExtension = file.name.replace(/\.[^/.]+$/, ""); + if (acc[fileNameWithoutExtension]) { + acc[fileNameWithoutExtension].count++; + } else { + acc[fileNameWithoutExtension] = { count: 1 }; + } + return acc; + }, {}); + const fileListItems = Object.entries(fileGroups).map(([fileName, { count }]) => { + return count > 1 ? `
  • ${fileName} [${count} files found]
  • ` : `
  • ${fileName}
  • `; + }).join(""); + const commandBotMessage = `

    Chat History

    +

    Current Chat History: ${settings.profiles.lastLoadedChatHistory[profileIndex] ? settings.profiles.lastLoadedChatHistory[profileIndex] : "Empty"}

    +
      ${fileListItems}
    `; + const botMessageDiv = displayCommandBotMessage(plugin, settings, messageHistory, commandBotMessage); + messageContainer.appendChild(botMessageDiv); + return; + } + if (input.startsWith("/load")) { + let inputValue = input.split(" ").slice(1).join(" ").trim(); + if (inputValue.startsWith('"') && inputValue.endsWith('"') || inputValue.startsWith("'") && inputValue.endsWith("'")) { + inputValue = inputValue.substring(1, inputValue.length - 1); + } + const loadAliases = {}; + let currentIndex = 1; + for (let i = 0; i < files.length; i++) { + const fileNameWithoutExtension = files[i].name.replace(/\.[^/.]+$/, ""); + const existingKey = Object.values(loadAliases).find( + (value) => value === fileNameWithoutExtension + ); + if (!existingKey) { + loadAliases[currentIndex.toString().toLowerCase()] = fileNameWithoutExtension; + currentIndex++; + } + } + const messageHistory2 = []; + const loadChatHistory = async (filePath) => { + const currentLoad = plugin.app.vault.getAbstractFileByPath(filePath); + const fileContent = await plugin.app.vault.cachedRead(currentLoad); + const contentWithoutFrontmatter = fileContent.replace(/^---\n[\s\S]*?\n---\n/, ""); + const lines = contentWithoutFrontmatter.split("\n"); + let currentRole = ""; + let currentContent = ""; + let headerCount = 0; + for (const line of lines) { + if (line.startsWith("###### ")) { + headerCount++; + if (currentContent) { + messageHistory2.push({ + role: currentRole, + content: currentContent.trim() + }); + } + currentRole = currentRole === "user" ? "assistant" : "user"; + currentContent = ""; + } else { + currentContent += line + "\n"; + } + } + if (currentContent) { + messageHistory2.push({ + role: currentRole, + content: currentContent.trim() + }); + } + if (headerCount % 2 !== 0) { + new import_obsidian6.Notice("Incorrect formatting."); + return false; + } + const updatedJsonString = JSON.stringify(messageHistory2, null, 4); + await plugin.app.vault.adapter.write(fileNameMessageHistoryJson(plugin), updatedJsonString); + plugin.activateView(); + return true; + }; + if (loadAliases[inputValue]) { + const matchingFiles = files.filter((file) => file.name.includes(loadAliases[inputValue])); + const modal = new import_obsidian6.Modal(plugin.app); + const modalContent = document.createElement("div"); + modalContent.classList.add("modal-content"); + const heading = document.createElement("h2"); + heading.textContent = "Load Chat History"; + modalContent.appendChild(heading); + if (matchingFiles.length === 1) { + const message = document.createElement("p"); + message.textContent = `Are you sure you want to override your current chat history with "${matchingFiles[0].name}"?`; + modalContent.appendChild(message); + const confirmLoadButton = document.createElement("button"); + confirmLoadButton.id = "confirmLoad"; + confirmLoadButton.textContent = "Confirm"; + modalContent.appendChild(confirmLoadButton); + confirmLoadButton == null ? void 0 : confirmLoadButton.addEventListener("click", async function() { + const selectedFile = matchingFiles[0]; + const chatHistoryFilePath = selectedFile.path; + const success = await loadChatHistory(chatHistoryFilePath); + if (success) { + new import_obsidian6.Notice(`Switched to '${selectedFile.path}' chat history.`); + lastLoadedChatHistoryFile = selectedFile; + settings.profiles.lastLoadedChatHistoryPath = selectedFile.path; + settings.profiles.lastLoadedChatHistory[profileIndex] = settings.profiles.lastLoadedChatHistoryPath; + await plugin.saveSettings(); + } + modal.close(); + }); + } else { + const message = document.createElement("p"); + message.textContent = "Select a chat history to override:"; + modalContent.appendChild(message); + const optionsContainer = document.createElement("div"); + optionsContainer.classList.add("file-options"); + optionsContainer.style.marginBottom = "16px"; + matchingFiles.forEach((file, index2) => { + const radioElement = document.createElement("input"); + radioElement.type = "radio"; + radioElement.name = "fileOption"; + radioElement.value = file.path; + radioElement.id = `file-${index2}`; + const labelElement = document.createElement("label"); + labelElement.htmlFor = `file-${index2}`; + labelElement.textContent = file.path; + optionsContainer.appendChild(radioElement); + optionsContainer.appendChild(labelElement); + optionsContainer.appendChild(document.createElement("br")); + }); + modalContent.appendChild(optionsContainer); + const confirmLoadButton = document.createElement("button"); + confirmLoadButton.id = "confirmLoad"; + confirmLoadButton.textContent = "Load"; + modalContent.appendChild(confirmLoadButton); + confirmLoadButton == null ? void 0 : confirmLoadButton.addEventListener("click", async function() { + const selectedRadio = optionsContainer.querySelector('input[type="radio"]:checked'); + if (selectedRadio) { + const selectedFilePath = selectedRadio.value; + const selectedFile = matchingFiles.find((file) => file.path === selectedFilePath); + if (selectedFile) { + const chatHistoryFilePath = selectedFile.path; + const success = await loadChatHistory(chatHistoryFilePath); + if (success) { + new import_obsidian6.Notice(`Switched to '${selectedFile.path}' chat history.`); + lastLoadedChatHistoryFile = selectedFile; + settings.profiles.lastLoadedChatHistoryPath = selectedFile.path; + settings.profiles.lastLoadedChatHistory[profileIndex] = settings.profiles.lastLoadedChatHistoryPath; + await plugin.saveSettings(); + } + modal.close(); + } + } + }); + } + modal.contentEl.appendChild(modalContent); + modal.open(); + } else if (Object.values(loadAliases).map((v) => v.toLowerCase()).includes(inputValue.toLowerCase())) { + const matchedFile = Object.entries(loadAliases).find(([key, value]) => value.toLowerCase() === inputValue.toLowerCase()); + if (matchedFile) { + const matchingFiles = files.filter((file) => file.name.includes(matchedFile[1])); + const modal = new import_obsidian6.Modal(plugin.app); + const modalContent = document.createElement("div"); + modalContent.classList.add("modal-content"); + const heading = document.createElement("h2"); + heading.textContent = "Load Chat History"; + modalContent.appendChild(heading); + if (matchingFiles.length === 1) { + const message = document.createElement("p"); + message.textContent = `Are you sure you want to override your current chat history with "${matchingFiles[0].name}"?`; + modalContent.appendChild(message); + const confirmLoadButton = document.createElement("button"); + confirmLoadButton.id = "confirmLoad"; + confirmLoadButton.textContent = "Confirm"; + modalContent.appendChild(confirmLoadButton); + confirmLoadButton == null ? void 0 : confirmLoadButton.addEventListener("click", async function() { + const selectedFile = matchingFiles[0]; + const chatHistoryFilePath = selectedFile.path; + const success = await loadChatHistory(chatHistoryFilePath); + if (success) { + new import_obsidian6.Notice(`Switched to '${selectedFile.path}' chat history.`); + lastLoadedChatHistoryFile = selectedFile; + settings.profiles.lastLoadedChatHistoryPath = selectedFile.path; + settings.profiles.lastLoadedChatHistory[profileIndex] = settings.profiles.lastLoadedChatHistoryPath; + await plugin.saveSettings(); + } + modal.close(); + }); + } else { + const message = document.createElement("p"); + message.textContent = "Select a chat history to override:"; + modalContent.appendChild(message); + const optionsContainer = document.createElement("div"); + optionsContainer.classList.add("file-options"); + optionsContainer.style.marginBottom = "16px"; + matchingFiles.forEach((file, index2) => { + const radioElement = document.createElement("input"); + radioElement.type = "radio"; + radioElement.name = "fileOption"; + radioElement.value = file.path; + radioElement.id = `file-${index2}`; + const labelElement = document.createElement("label"); + labelElement.htmlFor = `file-${index2}`; + labelElement.textContent = file.path; + optionsContainer.appendChild(radioElement); + optionsContainer.appendChild(labelElement); + optionsContainer.appendChild(document.createElement("br")); + }); + modalContent.appendChild(optionsContainer); + const confirmLoadButton = document.createElement("button"); + confirmLoadButton.id = "confirmLoad"; + confirmLoadButton.textContent = "Load"; + modalContent.appendChild(confirmLoadButton); + confirmLoadButton == null ? void 0 : confirmLoadButton.addEventListener("click", async function() { + const selectedRadio = optionsContainer.querySelector('input[type="radio"]:checked'); + if (selectedRadio) { + const selectedFilePath = selectedRadio.value; + const selectedFile = matchingFiles.find((file) => file.path === selectedFilePath); + if (selectedFile) { + const chatHistoryFilePath = selectedFile.path; + const success = await loadChatHistory(chatHistoryFilePath); + if (success) { + new import_obsidian6.Notice(`Switched to '${selectedFile.path}' chat history.`); + lastLoadedChatHistoryFile = selectedFile; + settings.profiles.lastLoadedChatHistoryPath = selectedFile.path; + settings.profiles.lastLoadedChatHistory[profileIndex] = settings.profiles.lastLoadedChatHistoryPath; + await plugin.saveSettings(); + } + modal.close(); + } + } + }); + } + modal.contentEl.appendChild(modalContent); + modal.open(); + } + } else { + new import_obsidian6.Notice("File does not exist."); + } + } +} +function commandStop() { + const controller = getAbortController(); + if (controller) { + controller.abort(); + } +} +async function removeMessageThread(plugin, index2) { + const messageContainer = document.querySelector("#messageContainer"); + const divElements = messageContainer == null ? void 0 : messageContainer.querySelectorAll("div.botMessage, div.userMessage"); + if (divElements && divElements.length > 0 && index2 >= 0 && index2 < divElements.length) { + for (let i = index2; i < divElements.length; i++) { + messageContainer == null ? void 0 : messageContainer.removeChild(divElements[i]); + } + } + messageHistory.splice(index2); + const jsonString = JSON.stringify(messageHistory, null, 4); + try { + await plugin.app.vault.adapter.write(fileNameMessageHistoryJson(plugin), jsonString); + const profileFiles = plugin.app.vault.getFiles().filter((file) => file.path.startsWith(plugin.settings.profiles.profileFolderPath)); + profileFiles.sort((a, b) => a.name.localeCompare(b.name)); + const currentProfile = plugin.settings.profiles.profile.replace(/\.[^/.]+$/, ""); + const profileIndex = profileFiles.findIndex((file) => file.basename === currentProfile); + lastLoadedChatHistoryFile = null; + plugin.settings.profiles.lastLoadedChatHistoryPath = null; + plugin.settings.profiles.lastLoadedChatHistory[profileIndex] = plugin.settings.profiles.lastLoadedChatHistoryPath; + await plugin.saveSettings(); + new import_obsidian6.Notice("Chat history cleared."); + } catch (error) { + console.error("Error writing messageHistory.json", error); + } +} + +// src/components/chat/UserMessage.ts +function displayUserMessage(plugin, settings, message) { + let trimmedMessage = message.trim(); + const userMessageDiv = document.createElement("div"); + userMessageDiv.className = "userMessage"; + userMessageDiv.style.backgroundColor = colorToHex(settings.appearance.userMessageBackgroundColor || getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.userMessageBackgroundColor).trim()); + userMessageDiv.style.color = settings.appearance.userMessageFontColor || DEFAULT_SETTINGS.appearance.userMessageFontColor; + const userMessageToolBarDiv = document.createElement("div"); + userMessageToolBarDiv.className = "userMessageToolBar"; + const buttonContainerDiv = document.createElement("div"); + buttonContainerDiv.className = "button-container"; + const userNameSpan = document.createElement("span"); + userNameSpan.className = "userName"; + userNameSpan.textContent = settings.appearance.userName || DEFAULT_SETTINGS.appearance.userName; + userMessageToolBarDiv.appendChild(userNameSpan); + userMessageToolBarDiv.appendChild(buttonContainerDiv); + const userPre = document.createElement("pre"); + const preUserMessage = document.createElement("span"); + preUserMessage.className = "preUserMessage"; + userPre.appendChild(preUserMessage); + const regexRenderedNote = /[\s\S]*?<\/note-rendered>/g; + trimmedMessage = trimmedMessage.replace(regexRenderedNote, "").trim(); + preUserMessage.innerHTML = trimmedMessage; + const regenerateButton = regenerateUserButton(plugin, settings); + const editButton = displayUserEditButton(plugin, settings, userPre); + const copyUserButton = displayUserCopyButton(userPre); + const trashButton = displayTrashButton(plugin); + if (!message.startsWith("/")) { + buttonContainerDiv.appendChild(regenerateButton); + buttonContainerDiv.appendChild(editButton); + } + buttonContainerDiv.appendChild(copyUserButton); + buttonContainerDiv.appendChild(trashButton); + userMessageDiv.appendChild(userMessageToolBarDiv); + userMessageDiv.appendChild(userPre); + return userMessageDiv; +} + +// src/view.ts +var VIEW_TYPE_CHATBOT = "chatbot-view"; +var ANTHROPIC_MODELS = ["claude-instant-1.2", "claude-2.0", "claude-2.1", "claude-3-haiku-20240307", "claude-3-sonnet-20240229", "claude-3-5-sonnet-20240620", "claude-3-opus-20240229"]; +var OPENAI_MODELS = ["gpt-3.5-turbo", "gpt-4", "gpt-4-turbo", "gpt-4o", "gpt-4o-mini"]; +function fileNameMessageHistoryJson(plugin) { + const filenameMessageHistoryPath = "./.obsidian/plugins/bmo-chatbot/data/"; + const currentProfileMessageHistory = "messageHistory_" + plugin.settings.profiles.profile.replace(".md", ".json"); + return filenameMessageHistoryPath + currentProfileMessageHistory; +} +var messageHistory = []; +var lastCursorPosition = { + line: 0, + ch: 0 +}; +var lastCursorPositionFile = null; +var activeEditor = null; +var BMOView = class extends import_obsidian7.ItemView { + constructor(leaf, settings, plugin) { + super(leaf); + this.preventEnter = false; + this.settings = settings; + this.plugin = plugin; + this.icon = "bot"; + this.addCursorLogging(); + } + getViewType() { + return VIEW_TYPE_CHATBOT; + } + getDisplayText() { + return "BMO Chatbot"; + } + async onOpen() { + const container = this.containerEl.children[1]; + container.empty(); + const chatbotContainer = container.createEl("div", { + attr: { + class: "chatbotContainer" + } + }); + const header = chatbotContainer.createEl("div", { + attr: { + id: "header" + } + }); + const chatbotNameHeading = chatbotContainer.createEl("h1", { + text: this.settings.appearance.chatbotName || DEFAULT_SETTINGS.appearance.chatbotName, + attr: { + id: "chatbotNameHeading" + } + }); + const modelOptions = populateModelDropdown(this.plugin, this.settings); + const dotIndicator = chatbotContainer.createEl("span", { + attr: { + class: "dotIndicator", + id: "markDownBoolean" + } + }); + const referenceCurrentNoteElement = chatbotContainer.createEl("p", { + text: "Reference Current Note", + attr: { + id: "referenceCurrentNote" + } + }); + header.appendChild(chatbotNameHeading); + header.appendChild(modelOptions); + referenceCurrentNoteElement.appendChild(dotIndicator); + referenceCurrentNoteElement.style.display = "none"; + if (referenceCurrentNoteElement) { + if (this.settings.general.enableReferenceCurrentNote) { + referenceCurrentNoteElement.style.display = "block"; + } else { + referenceCurrentNoteElement.style.display = "none"; + } + } + const messageContainer = chatbotContainer.createEl("div", { + attr: { + id: "messageContainer" + } + }); + if (this.settings.appearance.enableHeader) { + header.style.display = "block"; + } else { + header.style.display = "none"; + messageContainer.style.maxHeight = "calc(100% - 60px)"; + referenceCurrentNoteElement.style.margin = "0.5rem 0 0.5rem 0"; + } + await loadData(this.plugin); + messageContainer.id = "messageContainer"; + messageHistory.forEach(async (messageData) => { + if (messageData.role == "user") { + const userMessageDiv = displayUserMessage(this.plugin, this.settings, messageData.content); + messageContainer.appendChild(userMessageDiv); + } + if (messageData.role == "assistant") { + const botMessageDiv = displayBotMessage(this.plugin, this.settings, messageHistory, messageData.content); + updateUnresolvedInternalLinks(this.plugin, botMessageDiv); + messageContainer.appendChild(botMessageDiv); + } + }); + messageContainer.addEventListener("click", (event) => { + const target = event.target; + if (target.tagName === "A" && target.classList.contains("internal-link")) { + const link = target; + const linkName = link.getAttribute("data-href") || ""; + this.plugin.app.workspace.openLinkText(linkName, "", false); + link.style.color = "var(--link-color)"; + } + }); + const parentElement = document.getElementById("parentElementId"); + parentElement == null ? void 0 : parentElement.appendChild(messageContainer); + const chatbox = chatbotContainer.createEl("div", { + attr: { + class: "chatbox" + } + }); + const textarea = document.createElement("textarea"); + textarea.setAttribute("contenteditable", true.toString()); + textarea.setAttribute("placeholder", "Start typing..."); + if (textarea) { + textarea.style.color = this.settings.appearance.chatBoxFontColor; + const style = document.createElement("style"); + style.textContent = ` + .chatbox textarea::placeholder { + color: ${this.settings.appearance.chatBoxFontColor} !important; + } + `; + textarea.appendChild(style); + } + const submitButton = document.createElement("button"); + submitButton.textContent = "send"; + (0, import_obsidian7.setIcon)(submitButton, "arrow-up"); + submitButton.classList.add("submit-button"); + submitButton.title = "send"; + submitButton.addEventListener("click", () => { + this.handleKeyup(new KeyboardEvent("keyup", { key: "Enter" }), true); + }); + chatbotContainer.style.backgroundColor = this.settings.appearance.chatbotContainerBackgroundColor || DEFAULT_SETTINGS.appearance.chatbotContainerBackgroundColor; + messageContainer.style.backgroundColor = this.settings.appearance.messageContainerBackgroundColor || DEFAULT_SETTINGS.appearance.messageContainerBackgroundColor; + textarea.style.backgroundColor = this.settings.appearance.chatBoxBackgroundColor || DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor; + textarea.style.borderColor = this.settings.appearance.chatBoxBackgroundColor || DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor; + textarea.style.color = this.settings.appearance.chatBoxFontColor || DEFAULT_SETTINGS.appearance.chatBoxFontColor; + chatbox.style.backgroundColor = this.settings.appearance.chatBoxBackgroundColor || DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor; + submitButton.style.backgroundColor = this.settings.appearance.chatBoxBackgroundColor || DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor; + const userMessages = messageContainer.querySelectorAll(".userMessage"); + userMessages.forEach((userMessage) => { + userMessage.style.color = this.settings.appearance.userMessageFontColor || DEFAULT_SETTINGS.appearance.userMessageFontColor; + }); + const botMessages = messageContainer.querySelectorAll(".botMessage"); + botMessages.forEach((botMessage) => { + botMessage.style.color = this.settings.appearance.botMessageFontColor || DEFAULT_SETTINGS.appearance.botMessageFontColor; + }); + chatbox.appendChild(textarea); + chatbox.appendChild(submitButton); + this.textareaElement = textarea; + this.addEventListeners(); + messageContainer.scrollTop = messageContainer.scrollHeight; + } + addEventListeners() { + this.textareaElement.addEventListener("keyup", this.handleKeyup.bind(this)); + this.textareaElement.addEventListener("keydown", this.handleKeydown.bind(this)); + this.textareaElement.addEventListener("input", this.handleInput.bind(this)); + this.textareaElement.addEventListener("blur", this.handleBlur.bind(this)); + } + async handleKeyup(event, fromSubmitButton = false) { + if ((document.body.classList.contains("is-mobile") || document.body.classList.contains("is-tablet")) && event.key === "Enter" && !fromSubmitButton) { + event.preventDefault(); + this.textareaElement.value += "\n"; + this.handleInput(event); + return; + } + const input = this.textareaElement.value; + const index2 = messageHistory.length - 1; + if (this.settings.OllamaConnection.enableStream || this.settings.RESTAPIURLConnection.enableStream || this.settings.APIConnections.mistral.enableStream || this.settings.APIConnections.openAI.enableStream) { + if ((input === "/s" || input === "/stop") && event.key === "Enter") { + this.preventEnter = false; + await executeCommand(input, this.settings, this.plugin); + } + } + const regex = /(!?)\[\[(.*?)\]\]/g; + let matches; + let inputModified = input; + const replacements = /* @__PURE__ */ new Map(); + while ((matches = regex.exec(input)) !== null) { + const exclamation = matches[1]; + const linktext = matches[2]; + const [path, subpath] = linktext.split("#"); + const file = this.plugin.app.metadataCache.getFirstLinkpathDest(path, ""); + if (file && file instanceof import_obsidian7.TFile) { + try { + const filePath = file.path; + const fileExtension = filePath.split(".").pop(); + if (fileExtension !== "md") { + const isImageFile = /\.(jpg|jpeg|png|gif|webp|bmp|tiff|tif|svg)$/i.test(filePath); + if (!this.plugin.settings.OllamaConnection.ollamaModels.includes(this.plugin.settings.general.model)) { + replacements.set(matches[0], `${exclamation}[[${matches[2]}]]ERROR: File cannot be read.`); + } else if (this.plugin.settings.OllamaConnection.ollamaModels.includes(this.plugin.settings.general.model)) { + if (!isImageFile) { + replacements.set(matches[0], `${exclamation}[[${matches[2]}]]ERROR: File cannot be read.`); + } + } + continue; + } + const content = await this.app.vault.read(file); + let contentToInsert = content; + if (subpath) { + const lines = content.split("\n"); + let inSubpath = false; + const subpathContent = []; + let subpathLevel = 0; + for (const line of lines) { + if (line.startsWith("#")) { + const match = line.match(/^#+/); + const headingLevel = match ? match[0].length : 0; + if (inSubpath) { + if (headingLevel <= subpathLevel) { + break; + } + } + if (!inSubpath && line.toLowerCase().includes(subpath.toLowerCase())) { + inSubpath = true; + subpathLevel = headingLevel; + } + } + if (inSubpath) { + subpathContent.push(line); + } + } + contentToInsert = subpathContent.join("\n"); + } + replacements.set(matches[0], `${exclamation}[[${matches[2]}]]${contentToInsert}`); + } catch (err) { + console.error(`Failed to read the content of "${path}": ${err}`); + } + } else { + replacements.set(matches[0], `${exclamation}[[${matches[2]}]]File cannot be read.`); + } + } + for (const [original, replacement] of replacements) { + inputModified = inputModified.split(original).join(replacement); + } + inputModified = inputModified.replace(/(File cannot be read.<\/note-rendered>)+/g, "File cannot be read."); + if (this.preventEnter === false && !event.shiftKey && event.key === "Enter") { + loadData(this.plugin); + event.preventDefault(); + if (input.length === 0) { + return; + } + const messageContainer = document.querySelector("#messageContainer"); + if (messageContainer) { + const excludedCommands = [ + "/c", + "/clear", + "/s", + "/stop", + "/save", + "/load ", + "/m ", + "/model ", + "/models ", + "/p ", + "/profile ", + "/prof ", + "/profiles ", + "/prompt ", + "/prompts ", + "/append", + "/reference ", + "/ref ", + "/maxtokens", + "/maxtokens ", + "/temperature", + "/temperature ", + "/temp", + "/temp " + ]; + if (!excludedCommands.some((cmd) => input.startsWith(cmd))) { + const parts = input.split(" "); + const baseCommand = parts[0]; + if (baseCommand.startsWith("/") && commandMap.hasOwnProperty(baseCommand)) { + addMessage(this.plugin, input, "userMessage", this.settings, index2); + const userMessageDiv = displayUserMessage(this.plugin, this.settings, input); + messageContainer.appendChild(userMessageDiv); + } else if (!baseCommand.startsWith("/")) { + addMessage(this.plugin, inputModified, "userMessage", this.settings, index2); + const userMessageDiv = displayUserMessage(this.plugin, this.settings, input); + messageContainer.appendChild(userMessageDiv); + } else { + } + } + if (input.startsWith("/")) { + executeCommand(input, this.settings, this.plugin); + if (!excludedCommands.some((cmd) => input.startsWith(cmd))) { + const botMessages = messageContainer.querySelectorAll(".botMessage"); + const lastBotMessage = botMessages[botMessages.length - 1]; + lastBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); + } + } else { + this.preventEnter = true; + this.BMOchatbot().then(() => { + this.preventEnter = false; + }).catch(() => { + const messageContainer2 = document.querySelector("#messageContainer"); + const botMessageDiv = displayErrorBotMessage(this.plugin, this.settings, messageHistory, "Oops, something went wrong. Please try again."); + messageContainer2.appendChild(botMessageDiv); + }); + } + } + this.textareaElement.value = ""; + this.textareaElement.style.height = "29px"; + this.textareaElement.value = this.textareaElement.value.trim(); + this.textareaElement.setSelectionRange(0, 0); + } + } + handleKeydown(event) { + if (event.key === "Enter" && !event.shiftKey) { + event.preventDefault(); + } + } + handleInput(event) { + this.textareaElement.style.height = "29px"; + this.textareaElement.style.height = this.textareaElement.scrollHeight + "px"; + } + handleBlur(event) { + if (!this.textareaElement.value) { + this.textareaElement.style.height = "29px"; + } + } + exportSettings() { + return this.settings; + } + addCursorLogging() { + const updateCursorPosition = async () => { + await getActiveFileContent(this.plugin, this.settings); + const view = this.plugin.app.workspace.getActiveViewOfType(import_obsidian7.MarkdownView); + if (view) { + const cursor = view.editor.getCursor(); + lastCursorPositionFile = this.plugin.app.workspace.getActiveFile(); + if (cursor != null && this.plugin.app.workspace.activeEditor != null) { + lastCursorPosition = cursor; + activeEditor = view.editor; + } + } + }; + activeWindow.addEventListener("click", updateCursorPosition); + activeWindow.addEventListener("keyup", updateCursorPosition); + activeWindow.addEventListener("keydown", updateCursorPosition); + activeWindow.addEventListener("input", updateCursorPosition); + } + cleanup() { + this.textareaElement.removeEventListener("keyup", this.handleKeyup.bind(this)); + this.textareaElement.addEventListener("keydown", this.handleKeydown.bind(this)); + this.textareaElement.removeEventListener("input", this.handleInput.bind(this)); + this.textareaElement.removeEventListener("blur", this.handleBlur.bind(this)); + } + async BMOchatbot() { + await getActiveFileContent(this.plugin, this.settings); + const index2 = messageHistory.length - 1; + if (this.settings.general.model === "") { + const errorMessage = "Model not found."; + const messageContainer = document.querySelector("#messageContainer"); + const botMessageDiv = displayErrorBotMessage(this.plugin, this.settings, messageHistory, errorMessage); + messageContainer.appendChild(botMessageDiv); + const botMessages = messageContainer.querySelectorAll(".botMessage"); + const lastBotMessage = botMessages[botMessages.length - 1]; + lastBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); + } else { + if (this.settings.OllamaConnection.ollamaModels.includes(this.settings.general.model)) { + if (this.settings.OllamaConnection.enableStream) { + await fetchOllamaResponseStream(this.plugin, this.settings, index2); + } else { + await fetchOllamaResponse(this.plugin, this.settings, index2); + } + } else if (this.settings.RESTAPIURLConnection.RESTAPIURLModels.includes(this.settings.general.model)) { + if (this.settings.RESTAPIURLConnection.enableStream) { + await fetchRESTAPIURLResponseStream(this.plugin, this.settings, index2); + } else { + await fetchRESTAPIURLResponse(this.plugin, this.settings, index2); + } + } else if (ANTHROPIC_MODELS.includes(this.settings.general.model)) { + await fetchAnthropicResponse(this.plugin, this.settings, index2); + } else if (this.settings.APIConnections.mistral.mistralModels.includes(this.settings.general.model)) { + if (this.settings.APIConnections.mistral.enableStream) { + await fetchMistralResponseStream(this.plugin, this.settings, index2); + } else { + await fetchMistralResponse(this.plugin, this.settings, index2); + } + } else if (this.settings.APIConnections.googleGemini.geminiModels.includes(this.settings.general.model)) { + if (this.settings.APIConnections.googleGemini.enableStream) { + await fetchGoogleGeminiResponseStream(this.plugin, this.settings, index2); + } else { + await fetchGoogleGeminiResponse(this.plugin, this.settings, index2); + } + } else if (this.settings.APIConnections.openAI.openAIBaseModels.includes(this.settings.general.model)) { + if (this.settings.APIConnections.openAI.enableStream) { + await fetchOpenAIAPIResponseStream(this.plugin, this.settings, index2); + } else { + await fetchOpenAIAPIResponse(this.plugin, this.settings, index2); + } + } else if (this.settings.APIConnections.openRouter.openRouterModels.includes(this.settings.general.model)) { + if (this.settings.APIConnections.openRouter.enableStream) { + await fetchOpenRouterResponseStream(this.plugin, this.settings, index2); + } else { + await fetchOpenRouterResponse(this.plugin, this.settings, index2); + } + } else { + const errorMessage = "Connection not found."; + const messageContainer = document.querySelector("#messageContainer"); + const botMessageDiv = displayErrorBotMessage(this.plugin, this.settings, messageHistory, errorMessage); + messageContainer.appendChild(botMessageDiv); + const botMessages = messageContainer.querySelectorAll(".botMessage"); + const lastBotMessage = botMessages[botMessages.length - 1]; + lastBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); + } + } + } + async onClose() { + } +}; +async function loadData(plugin) { + if (!await plugin.app.vault.adapter.exists("./.obsidian/plugins/bmo-chatbot/data/")) { + plugin.app.vault.adapter.mkdir("./.obsidian/plugins/bmo-chatbot/data/"); + } + if (await plugin.app.vault.adapter.exists(fileNameMessageHistoryJson(plugin))) { + try { + const fileContent = await plugin.app.vault.adapter.read(fileNameMessageHistoryJson(plugin)); + if (fileContent.trim() === "") { + messageHistory = []; + } else { + messageHistory = JSON.parse(fileContent); + } + } catch (error) { + console.error("Error processing message history:", error); + } + } else { + messageHistory = []; + } +} +function populateModelDropdown(plugin, settings) { + const modelOptions = document.createElement("select"); + modelOptions.id = "modelOptions"; + if (modelOptions) { + modelOptions.innerHTML = ""; + } + const defaultModel = settings.general.model || DEFAULT_SETTINGS.general.model; + const modelGroups = [ + { name: "Ollama Models", models: settings.OllamaConnection.ollamaModels }, + { name: "REST API Models", models: settings.RESTAPIURLConnection.RESTAPIURLModels }, + { name: "Anthropic Models", models: settings.APIConnections.anthropic.anthropicModels }, + { name: "Google Gemini Models", models: settings.APIConnections.googleGemini.geminiModels }, + { name: "Mistral Models", models: settings.APIConnections.mistral.mistralModels }, + { name: "OpenAI-Based Models", models: settings.APIConnections.openAI.openAIBaseModels }, + { name: "OpenRouter Models", models: settings.APIConnections.openRouter.openRouterModels } + ]; + if (defaultModel === "") { + const optionEl = document.createElement("option"); + optionEl.textContent = "No Model"; + optionEl.value = ""; + optionEl.selected = true; + modelOptions.appendChild(optionEl); + } + modelGroups.forEach((group) => { + if (group.models.length > 0) { + const optgroup = document.createElement("optgroup"); + optgroup.label = group.name; + group.models.forEach((model) => { + const optionEl = document.createElement("option"); + optionEl.textContent = model; + optionEl.value = model; + if (model === defaultModel) { + optionEl.selected = true; + } + optgroup.appendChild(optionEl); + }); + modelOptions.appendChild(optgroup); + } + }); + modelOptions.addEventListener("change", async function() { + plugin.settings.general.model = this.value; + await plugin.saveSettings(); + }); + return modelOptions; +} + +// src/settings.ts +var import_obsidian23 = require("obsidian"); + +// src/components/settings/GeneralSettings.ts +var import_obsidian9 = require("obsidian"); + +// src/components/FetchModelList.ts +var import_obsidian8 = require("obsidian"); +async function fetchOllamaModels(plugin) { + const ollamaRESTAPIURL = plugin.settings.OllamaConnection.RESTAPIURL; + try { + const ollama = new Ollama2({ host: ollamaRESTAPIURL }); + const modelsList = await ollama.list(); + const models = modelsList.models.map((model) => model.name); + plugin.settings.OllamaConnection.ollamaModels = models; + return models; + } catch (error) { + console.error("Error fetching models from Ollama:", error); + return; + } +} +async function fetchRESTAPIURLModels(plugin) { + const RESTAPIURL = plugin.settings.RESTAPIURLConnection.RESTAPIURL; + try { + new URL(RESTAPIURL); + } catch (error) { + console.error("Invalid REST API URL:", RESTAPIURL); + return; + } + try { + const response = await (0, import_obsidian8.requestUrl)({ + url: RESTAPIURL + "/models", + method: "GET", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${plugin.settings.RESTAPIURLConnection.APIKey}` + } + }); + if (response.json && (response.json.data || Array.isArray(response.json))) { + let models; + if (Array.isArray(response.json)) { + models = response.json.map((model) => model.id); + } else { + models = response.json.data.map((model) => model.id); + } + plugin.settings.RESTAPIURLConnection.RESTAPIURLModels = models; + return models; + } + } catch (error) { + console.error("Error making API request:", error); + throw error; + } +} +async function fetchGoogleGeminiModels(plugin) { + try { + const API_KEY = plugin.settings.APIConnections.googleGemini.APIKey; + const response = await (0, import_obsidian8.requestUrl)({ + url: `https://generativelanguage.googleapis.com/v1beta/models?key=${API_KEY}`, + method: "GET", + headers: { + "Content-Type": "application/json" + } + }); + if (response.json && response.json.models) { + const models = response.json.models.map((model) => model.name).filter((model) => model.startsWith("models/gemini")); + plugin.settings.APIConnections.googleGemini.geminiModels = models; + return models; + } + } catch (error) { + console.error(error); + } +} +async function fetchMistralModels(plugin) { + try { + const response = await (0, import_obsidian8.requestUrl)({ + url: "https://api.mistral.ai/v1/models", + method: "GET", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${plugin.settings.APIConnections.mistral.APIKey}` + } + }); + if (response.json && response.json.data) { + const models = response.json.data.map((model) => model.id); + plugin.settings.APIConnections.mistral.mistralModels = models; + console.log(models); + return models; + } + } catch (error) { + console.error(error); + } +} +async function fetchOpenAIBaseModels(plugin) { + const openai = new openai_default({ + apiKey: plugin.settings.APIConnections.openAI.APIKey, + baseURL: plugin.settings.APIConnections.openAI.openAIBaseUrl, + dangerouslyAllowBrowser: true + // apiKey is stored within data.json + }); + const list = await openai.models.list(); + if (openai.baseURL == "https://api.openai.com/v1") { + plugin.settings.APIConnections.openAI.openAIBaseModels = OPENAI_MODELS; + return OPENAI_MODELS; + } else { + const models = list.data.map((model) => model.id); + plugin.settings.APIConnections.openAI.openAIBaseModels = models; + return models; + } +} +async function fetchOpenRouterModels(plugin) { + try { + const response = await (0, import_obsidian8.requestUrl)({ + url: "https://openrouter.ai/api/v1/models", + method: "GET", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${plugin.settings.APIConnections.openRouter.APIKey}` + } + }); + if (response.json && (response.json.data || Array.isArray(response.json))) { + let models; + if (Array.isArray(response.json)) { + models = response.json.map((model) => model.id); + } else { + models = response.json.data.map((model) => model.id); + } + plugin.settings.APIConnections.openRouter.openRouterModels = models; + return models; + } + } catch (error) { + console.error("Error making API request:", error); + throw error; + } +} + +// src/components/settings/GeneralSettings.ts +async function addGeneralSettings(containerEl, plugin, SettingTab15) { + const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); + toggleSettingContainer.createEl("h2", { text: "General" }); + const initialState = plugin.settings.toggleGeneralSettings; + const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); + (0, import_obsidian9.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); + const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); + settingsContainer.style.display = initialState ? "block" : "none"; + toggleSettingContainer.addEventListener("click", async () => { + const isOpen = settingsContainer.style.display !== "none"; + if (isOpen) { + (0, import_obsidian9.setIcon)(chevronIcon, "chevron-right"); + settingsContainer.style.display = "none"; + plugin.settings.toggleGeneralSettings = false; + } else { + (0, import_obsidian9.setIcon)(chevronIcon, "chevron-down"); + settingsContainer.style.display = "block"; + plugin.settings.toggleGeneralSettings = true; + } + await plugin.saveSettings(); + }); + const createModelDropdown = (dropdown) => { + const modelGroups = [ + { name: "Ollama Models", models: plugin.settings.OllamaConnection.ollamaModels }, + { name: "REST API Models", models: plugin.settings.RESTAPIURLConnection.RESTAPIURLModels }, + { name: "Anthropic Models", models: plugin.settings.APIConnections.anthropic.anthropicModels }, + { name: "Google Gemini Models", models: plugin.settings.APIConnections.googleGemini.geminiModels }, + { name: "Mistral Models", models: plugin.settings.APIConnections.mistral.mistralModels }, + { name: "OpenAI-Based Models", models: plugin.settings.APIConnections.openAI.openAIBaseModels }, + { name: "OpenRouter Models", models: plugin.settings.APIConnections.openRouter.openRouterModels } + ]; + const selectEl = dropdown.selectEl; + selectEl.innerHTML = ""; + const defaultOption = selectEl.createEl("option", { + value: "", + text: "No Model" + }); + if (plugin.settings.general.model === "No Model") { + defaultOption.selected = true; + } + modelGroups.forEach((group) => { + if (group.models.length > 0) { + const optgroup = selectEl.createEl("optgroup"); + optgroup.label = group.name; + group.models.forEach((model) => { + const option = optgroup.createEl("option", { + value: model, + text: model + }); + if (model === plugin.settings.general.model) { + option.selected = true; + } + }); + } + }); + dropdown.onChange(async (value) => { + plugin.settings.general.model = value; + await plugin.saveSettings(); + }); + }; + let modelDropdown; + new import_obsidian9.Setting(settingsContainer).setName("Model").setDesc("Choose a model.").addButton( + (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { + new import_obsidian9.Notice("Reloading..."); + if (plugin.settings.OllamaConnection.RESTAPIURL !== "") { + const models = await fetchOllamaModels(plugin); + plugin.settings.OllamaConnection.ollamaModels = models || []; + } + if (plugin.settings.RESTAPIURLConnection.RESTAPIURL !== "") { + const models = await fetchRESTAPIURLModels(plugin); + plugin.settings.RESTAPIURLConnection.RESTAPIURLModels = models || []; + } + if (plugin.settings.APIConnections.anthropic.APIKey !== "") { + const models = ANTHROPIC_MODELS; + plugin.settings.APIConnections.anthropic.anthropicModels = models || []; + } + if (plugin.settings.APIConnections.googleGemini.APIKey !== "") { + const models = await fetchGoogleGeminiModels(plugin); + plugin.settings.APIConnections.googleGemini.geminiModels = models || []; + } + if (plugin.settings.APIConnections.mistral.APIKey !== "") { + const models = await fetchMistralModels(plugin); + plugin.settings.APIConnections.mistral.mistralModels = models || []; + } + if (plugin.settings.APIConnections.openAI.APIKey !== "" || plugin.settings.APIConnections.openAI.openAIBaseUrl != DEFAULT_SETTINGS.APIConnections.openAI.openAIBaseUrl) { + const models = await fetchOpenAIBaseModels(plugin); + plugin.settings.APIConnections.openAI.openAIBaseModels = models || []; + } + if (plugin.settings.APIConnections.openRouter.APIKey !== "") { + const models = await fetchOpenRouterModels(plugin); + plugin.settings.APIConnections.openRouter.openRouterModels = models || []; + } + if (modelDropdown) { + createModelDropdown(modelDropdown); + } + new import_obsidian9.Notice("Models reloaded."); + }) + ).addDropdown((dropdown) => { + modelDropdown = dropdown; + createModelDropdown(dropdown); + }); + new import_obsidian9.Setting(settingsContainer).setName("Max Tokens").setDesc("The maximum number of tokens, or words, that the model is allowed to generate in its output. Some models require a minimum number of tokens to be set. The default value is empty.").addText( + (text) => text.setPlaceholder("4096").setValue(plugin.settings.general.max_tokens).onChange(async (value) => { + plugin.settings.general.max_tokens = value; + await plugin.saveSettings(); + }) + ); + new import_obsidian9.Setting(settingsContainer).setName("Temperature").setDesc("Temperature controls how random the generated output is. Lower values make the text more predictable, while higher values make it more creative and unpredictable.").addText( + (text) => text.setPlaceholder("1.00").setValue(plugin.settings.general.temperature).onChange(async (value) => { + const floatValue = parseFloat(value); + if (!isNaN(floatValue)) { + if (!isNaN(floatValue)) { + if (floatValue < 0) { + plugin.settings.general.temperature = "0.00"; + } else if (floatValue > 2) { + plugin.settings.general.temperature = "2.00"; + } else { + plugin.settings.general.temperature = floatValue.toFixed(2); + } + } else { + plugin.settings.general.temperature = DEFAULT_SETTINGS.general.temperature; + } + } else { + plugin.settings.general.temperature = DEFAULT_SETTINGS.general.temperature; + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian9.Setting(settingsContainer).setName("Enable Reference Current Note").setDesc("Enable chatbot to reference current active note during conversation.").addToggle( + (toggle) => toggle.setValue(plugin.settings.general.enableReferenceCurrentNote).onChange((value) => { + plugin.settings.general.enableReferenceCurrentNote = value; + plugin.saveSettings(); + const referenceCurrentNoteElement = document.getElementById("referenceCurrentNote"); + if (referenceCurrentNoteElement) { + if (value) { + referenceCurrentNoteElement.style.display = "block"; + } else { + referenceCurrentNoteElement.style.display = "none"; + } + } + }) + ); +} + +// src/components/settings/AppearanceSettings.ts +var import_obsidian10 = require("obsidian"); +function addAppearanceSettings(containerEl, plugin, SettingTab15) { + const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); + toggleSettingContainer.createEl("h2", { text: "Appearance" }); + const initialState = plugin.settings.toggleAppearanceSettings; + const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); + (0, import_obsidian10.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); + const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); + settingsContainer.style.display = initialState ? "block" : "none"; + toggleSettingContainer.addEventListener("click", async () => { + const isOpen = settingsContainer.style.display !== "none"; + if (isOpen) { + (0, import_obsidian10.setIcon)(chevronIcon, "chevron-right"); + settingsContainer.style.display = "none"; + plugin.settings.toggleAppearanceSettings = false; + } else { + (0, import_obsidian10.setIcon)(chevronIcon, "chevron-down"); + settingsContainer.style.display = "block"; + plugin.settings.toggleAppearanceSettings = true; + } + await plugin.saveSettings(); + }); + settingsContainer.createEl("h6", { text: "Chat View" }); + new import_obsidian10.Setting(settingsContainer).setName("Enable Header").setDesc("Display chatbot name and model name in header.").addToggle( + (toggle) => toggle.setValue(plugin.settings.appearance.enableHeader).onChange((value) => { + plugin.settings.appearance.enableHeader = value; + const referenceCurrentNoteElement = document.querySelector("#referenceCurrentNote"); + if (value === true) { + const header = document.querySelector("#header"); + if (header) { + header.style.display = "block"; + referenceCurrentNoteElement.style.margin = "-0.5rem 0 0.5rem 0"; + } + } else { + const header = document.querySelector("#header"); + const messageContainer = document.querySelector("#messageContainer"); + if (header) { + header.style.display = "none"; + messageContainer.style.maxHeight = "calc(100% - 60px)"; + referenceCurrentNoteElement.style.margin = "0.5rem 0 0.5rem 0"; + } + } + plugin.saveSettings(); + }) + ); + new import_obsidian10.Setting(settingsContainer).setName("User Name").setDesc("Create a username.").addText( + (text) => text.setPlaceholder("Enter user name").setValue(plugin.settings.appearance.userName || DEFAULT_SETTINGS.appearance.userName).onChange(async (value) => { + plugin.settings.appearance.userName = value ? value : DEFAULT_SETTINGS.appearance.userName; + text.inputEl.maxLength = 30; + await plugin.saveSettings(); + const userNames = document.querySelectorAll(".userName"); + userNames.forEach((userName) => { + userName.textContent = plugin.settings.appearance.userName; + }); + }) + ); + let colorPicker1; + const defaultChatbotContainerBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.chatbotContainerBackgroundColor).trim(); + let colorPicker2; + const defaultMessageContainerBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.messageContainerBackgroundColor).trim(); + let colorPicker3; + const defaultUserMessageFontColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.userMessageFontColor).trim(); + let colorPicker4; + const defaultUserMessageBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.userMessageBackgroundColor).trim(); + let colorPicker5; + const defaultBotMessageFontColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageFontColor).trim(); + let colorPicker6; + const defaultBotMessageBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor).trim(); + let colorPicker7; + const defaultChatBoxFontColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.chatBoxFontColor).trim(); + let colorPicker8; + const defaultChatBoxBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor).trim(); + new import_obsidian10.Setting(settingsContainer).setName("Chatbot Container Background Color").setDesc("Modify the background color of the chatbot container.").addButton( + (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { + const defaultValue = colorToHex(defaultChatbotContainerBackgroundColor); + colorPicker1.setValue(defaultValue); + const chatbotContainer = document.querySelector(".chatbotContainer"); + const messageContainer = document.querySelector("#messageContainer"); + if (chatbotContainer) { + chatbotContainer.style.backgroundColor = defaultValue; + messageContainer.style.backgroundColor = colorPicker2.getValue(); + await plugin.saveSettings(); + } + }) + ).addColorPicker((color) => { + colorPicker1 = color; + let defaultValue = plugin.settings.appearance.chatbotContainerBackgroundColor; + if (plugin.settings.appearance.chatbotContainerBackgroundColor == "--background-secondary") { + defaultValue = colorToHex(defaultChatbotContainerBackgroundColor); + } + color.setValue(defaultValue).onChange(async (value) => { + const hexValue = colorToHex(value); + plugin.settings.appearance.chatbotContainerBackgroundColor = hexValue; + const chatbotContainer = document.querySelector(".chatbotContainer"); + const messageContainer = document.querySelector("#messageContainer"); + if (chatbotContainer) { + chatbotContainer.style.backgroundColor = hexValue; + messageContainer.style.backgroundColor = colorPicker2.getValue(); + } + await plugin.saveSettings(); + }); + }); + new import_obsidian10.Setting(settingsContainer).setName("Message Container Background Color").setDesc("Modify the background color of the message container.").addButton( + (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { + const defaultValue = colorToHex(defaultMessageContainerBackgroundColor); + colorPicker2.setValue(defaultValue); + const messageContainer = document.querySelector("#messageContainer"); + if (messageContainer) { + messageContainer.style.backgroundColor = defaultValue; + await plugin.saveSettings(); + } + }) + ).addColorPicker((color) => { + colorPicker2 = color; + let defaultValue = plugin.settings.appearance.messageContainerBackgroundColor; + if (plugin.settings.appearance.messageContainerBackgroundColor == "--background-secondary") { + defaultValue = colorToHex(defaultMessageContainerBackgroundColor); + } + color.setValue(defaultValue).onChange(async (value) => { + const hexValue = colorToHex(value); + plugin.settings.appearance.messageContainerBackgroundColor = hexValue; + const messageContainer = document.querySelector("#messageContainer"); + if (messageContainer) { + messageContainer.style.backgroundColor = hexValue; + } + await plugin.saveSettings(); + }); + }); + new import_obsidian10.Setting(settingsContainer).setName("User Message Font Color").setDesc("Modify the font color of the user message.").addButton( + (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { + const defaultValue = colorToHex(defaultUserMessageFontColor); + colorPicker3.setValue(defaultValue); + const messageContainer = document.querySelector("#messageContainer"); + if (messageContainer) { + const userMessages = messageContainer.querySelectorAll(".userMessage"); + userMessages.forEach((userMessage) => { + const element = userMessage; + element.style.color = defaultValue; + }); + await plugin.saveSettings(); + } + }) + ).addColorPicker((color) => { + colorPicker3 = color; + let defaultValue = plugin.settings.appearance.userMessageFontColor; + if (plugin.settings.appearance.userMessageFontColor == "--text-normal") { + defaultValue = colorToHex(defaultUserMessageFontColor); + } + color.setValue(defaultValue).onChange(async (value) => { + const hexValue = colorToHex(value); + plugin.settings.appearance.userMessageFontColor = hexValue; + const messageContainer = document.querySelector("#messageContainer"); + if (messageContainer) { + const userMessages = messageContainer.querySelectorAll(".userMessage"); + userMessages.forEach((userMessage) => { + const element = userMessage; + element.style.color = hexValue; + }); + } + await plugin.saveSettings(); + }); + }); + new import_obsidian10.Setting(settingsContainer).setName("User Message Background Color").setDesc("Modify the background color of the user message.").addButton( + (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { + const defaultValue = colorToHex(defaultUserMessageBackgroundColor); + colorPicker4.setValue(defaultValue); + const messageContainer = document.querySelector("#messageContainer"); + if (messageContainer) { + const userMessages = messageContainer.querySelectorAll(".userMessage"); + userMessages.forEach((userMessage) => { + const element = userMessage; + element.style.backgroundColor = defaultValue; + }); + await plugin.saveSettings(); + } + }) + ).addColorPicker((color) => { + colorPicker4 = color; + let defaultValue = plugin.settings.appearance.userMessageBackgroundColor; + if (plugin.settings.appearance.userMessageBackgroundColor == "--background-primary") { + defaultValue = colorToHex(defaultUserMessageBackgroundColor); + } + color.setValue(defaultValue).onChange(async (value) => { + const hexValue = colorToHex(value); + plugin.settings.appearance.userMessageBackgroundColor = hexValue; + const messageContainer = document.querySelector("#messageContainer"); + if (messageContainer) { + const userMessages = messageContainer.querySelectorAll(".userMessage"); + userMessages.forEach((userMessage) => { + const element = userMessage; + element.style.backgroundColor = hexValue; + }); + } + await plugin.saveSettings(); + }); + }); + new import_obsidian10.Setting(settingsContainer).setName("Bot Message Font Color").setDesc("Modify the font color of the bot message.").addButton( + (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { + const defaultValue = colorToHex(defaultBotMessageFontColor); + colorPicker5.setValue(defaultValue); + const messageContainer = document.querySelector("#messageContainer"); + if (messageContainer) { + const botMessages = messageContainer.querySelectorAll(".botMessage"); + botMessages.forEach((botMessage) => { + const element = botMessage; + element.style.color = defaultValue; + }); + await plugin.saveSettings(); + } + }) + ).addColorPicker((color) => { + colorPicker5 = color; + let defaultValue = plugin.settings.appearance.botMessageFontColor; + if (plugin.settings.appearance.botMessageFontColor == "--text-normal") { + defaultValue = colorToHex(defaultBotMessageFontColor); + } + color.setValue(defaultValue).onChange(async (value) => { + const hexValue = colorToHex(value); + plugin.settings.appearance.botMessageFontColor = hexValue; + const messageContainer = document.querySelector("#messageContainer"); + if (messageContainer) { + const botMessages = messageContainer.querySelectorAll(".botMessage"); + botMessages.forEach((botMessage) => { + const element = botMessage; + element.style.color = hexValue; + }); + } + await plugin.saveSettings(); + }); + }); + new import_obsidian10.Setting(settingsContainer).setName("Bot Message Background Color").setDesc("Modify the background color of the bot message.").addButton( + (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { + const defaultValue = colorToHex(defaultBotMessageBackgroundColor); + colorPicker6.setValue(defaultValue); + const messageContainer = document.querySelector("#messageContainer"); + if (messageContainer) { + const botMessages = messageContainer.querySelectorAll(".botMessage"); + botMessages.forEach((botMessage) => { + const element = botMessage; + element.style.backgroundColor = defaultValue; + }); + await plugin.saveSettings(); + } + }) + ).addColorPicker((color) => { + colorPicker6 = color; + let defaultValue = plugin.settings.appearance.botMessageBackgroundColor; + if (plugin.settings.appearance.botMessageBackgroundColor == "--background-secondary") { + defaultValue = colorToHex(defaultBotMessageBackgroundColor); + } + color.setValue(defaultValue).onChange(async (value) => { + const hexValue = colorToHex(value); + plugin.settings.appearance.botMessageBackgroundColor = hexValue; + const messageContainer = document.querySelector("#messageContainer"); + if (messageContainer) { + const botMessages = messageContainer.querySelectorAll(".botMessage"); + botMessages.forEach((botMessage) => { + const element = botMessage; + element.style.backgroundColor = hexValue; + }); + } + await plugin.saveSettings(); + }); + }); + new import_obsidian10.Setting(settingsContainer).setName("Chatbox Font Color").setDesc("Modify the font color of the chatbox.").addButton( + (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { + const defaultValue = colorToHex(defaultChatBoxFontColor); + colorPicker7.setValue(defaultValue); + const textarea = document.querySelector(".chatbox textarea"); + if (textarea) { + textarea.style.color = defaultValue; + const style = document.createElement("style"); + style.textContent = ` + .chatbox textarea::placeholder { + color: ${defaultValue} !important; + } + `; + textarea.appendChild(style); + await plugin.saveSettings(); + } + }) + ).addColorPicker(async (color) => { + colorPicker7 = color; + let defaultValue = plugin.settings.appearance.chatBoxFontColor; + if (defaultValue == "--text-normal") { + defaultValue = colorToHex(defaultChatBoxFontColor); + } + color.setValue(defaultValue).onChange(async (value) => { + const hexValue = colorToHex(value); + plugin.settings.appearance.chatBoxFontColor = hexValue; + const textarea = document.querySelector(".chatbox textarea"); + if (textarea) { + textarea.style.color = hexValue; + const style = document.createElement("style"); + style.textContent = ` + .chatbox textarea::placeholder { + color: ${hexValue} !important; + } + `; + textarea.appendChild(style); + } + await plugin.saveSettings(); + }); + }); + new import_obsidian10.Setting(settingsContainer).setName("Chatbox Background Color").setDesc("Modify the background color of the chatbox.").addButton( + (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { + const defaultValue = colorToHex(defaultChatBoxBackgroundColor); + colorPicker8.setValue(defaultValue); + const chatbox = document.querySelector(".chatbox"); + if (chatbox) { + const element = chatbox; + element.style.backgroundColor = defaultValue; + element.style.borderColor = defaultValue; + await plugin.saveSettings(); + } + }) + ).addColorPicker(async (color) => { + colorPicker8 = color; + let defaultValue = plugin.settings.appearance.chatBoxBackgroundColor; + if (defaultValue == "--interactive-accent") { + defaultValue = colorToHex(defaultChatBoxBackgroundColor); + } + color.setValue(defaultValue).onChange(async (value) => { + const hexValue = colorToHex(value); + plugin.settings.appearance.chatBoxBackgroundColor = hexValue; + const chatbox = document.querySelector(".chatbox"); + if (chatbox) { + const element = chatbox; + element.style.backgroundColor = hexValue; + element.style.borderColor = hexValue; + } + const textarea = document.querySelector(".chatbox textarea"); + if (textarea) { + const element = textarea; + element.style.backgroundColor = hexValue; + element.style.borderColor = hexValue; + } + const submitButton = document.querySelector(".chatbox .submit-button"); + if (submitButton) { + const element = submitButton; + element.style.backgroundColor = hexValue; + element.style.borderColor = hexValue; + } + await plugin.saveSettings(); + }); + }); + new import_obsidian10.Setting(settingsContainer).setName("Enable Scrollbar").setDesc("Display scrollbar in chatbox.").addToggle( + (toggle) => toggle.setValue(plugin.settings.appearance.enableScrollBar).onChange((value) => { + plugin.settings.appearance.enableScrollBar = value; + if (value === true) { + const chatbox = document.querySelector(".chatbox textarea"); + if (chatbox) { + chatbox.style.overflowY = "auto"; + } + } else { + const chatbox = document.querySelector(".chatbox textarea"); + if (chatbox) { + chatbox.style.overflowY = "hidden"; + } + } + plugin.saveSettings(); + }) + ); + settingsContainer.createEl("h6", { text: "Generate View" }); + let colorPicker9; + let colorPicker10; + const defaultBMOGenerateFontColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.bmoGenerateFontColor).trim(); + new import_obsidian10.Setting(settingsContainer).setName("BMO Generate Background Color").setDesc("Modify the background color of BMO Generate.").addButton( + (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { + colorPicker9.setValue(DEFAULT_SETTINGS.appearance.bmoGenerateBackgroundColor); + const containers = document.querySelectorAll(".bmoCodeBlockContainer"); + containers.forEach((container) => { + const element = container; + element.style.backgroundColor = DEFAULT_SETTINGS.appearance.bmoGenerateBackgroundColor; + }); + await plugin.saveSettings(); + }) + ).addColorPicker(async (color) => { + colorPicker9 = color; + const defaultValue = plugin.settings.appearance.bmoGenerateBackgroundColor; + color.setValue(defaultValue).onChange(async (value) => { + const hexValue = colorToHex(value); + plugin.settings.appearance.bmoGenerateBackgroundColor = hexValue; + const containers = document.querySelectorAll(".bmoCodeBlockContainer"); + containers.forEach((container) => { + const element = container; + element.style.backgroundColor = hexValue; + }); + await plugin.saveSettings(); + }); + }); + new import_obsidian10.Setting(settingsContainer).setName("BMO Generate Font Color").setDesc("Modify the font color of BMO Generate.").addButton( + (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { + const defaultValue = colorToHex(defaultBMOGenerateFontColor); + colorPicker10.setValue(defaultValue); + const bmoCodeBlockContents = document.querySelectorAll(".bmoCodeBlockContent"); + bmoCodeBlockContents.forEach((content) => { + const element = content; + element.style.color = defaultValue; + }); + await plugin.saveSettings(); + }) + ).addColorPicker(async (color) => { + colorPicker10 = color; + let defaultValue = plugin.settings.appearance.bmoGenerateFontColor; + if (defaultValue == "--text-normal") { + defaultValue = colorToHex(defaultBMOGenerateFontColor); + } + color.setValue(defaultValue).onChange(async (value) => { + const hexValue = colorToHex(value); + plugin.settings.appearance.bmoGenerateFontColor = hexValue; + const bmoCodeBlockContents2 = document.querySelectorAll(".bmoCodeBlockContent"); + bmoCodeBlockContents2.forEach((content) => { + const element = content; + element.style.color = hexValue; + }); + await plugin.saveSettings(); + }); + const bmoCodeBlockContents = document.querySelectorAll(".bmoCodeBlockContent"); + bmoCodeBlockContents.forEach((content) => { + const element = content; + element.style.color = defaultValue; + }); + }); +} + +// src/components/settings/ChatHistorySettings.ts +var import_obsidian11 = require("obsidian"); +function addChatHistorySettings(containerEl, plugin, SettingTab15) { + const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); + toggleSettingContainer.createEl("h2", { text: "Chat History" }); + const initialState = plugin.settings.toggleChatHistorySettings; + const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); + (0, import_obsidian11.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); + const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); + settingsContainer.style.display = initialState ? "block" : "none"; + toggleSettingContainer.addEventListener("click", async () => { + const isOpen = settingsContainer.style.display !== "none"; + if (isOpen) { + (0, import_obsidian11.setIcon)(chevronIcon, "chevron-right"); + settingsContainer.style.display = "none"; + plugin.settings.toggleChatHistorySettings = false; + } else { + (0, import_obsidian11.setIcon)(chevronIcon, "chevron-down"); + settingsContainer.style.display = "block"; + plugin.settings.toggleChatHistorySettings = true; + } + await plugin.saveSettings(); + }); + new import_obsidian11.Setting(settingsContainer).setName("Chat History Folder Path").setDesc("Save your chat history in a specified folder.").addText( + (text) => text.setPlaceholder("BMO/History").setValue(plugin.settings.chatHistory.chatHistoryPath || DEFAULT_SETTINGS.chatHistory.chatHistoryPath).onChange(async (value) => { + plugin.settings.chatHistory.chatHistoryPath = value ? value : DEFAULT_SETTINGS.chatHistory.chatHistoryPath; + if (value) { + let folderPath = plugin.settings.chatHistory.chatHistoryPath.trim() || DEFAULT_SETTINGS.chatHistory.chatHistoryPath; + while (folderPath.endsWith("/")) { + folderPath = folderPath.substring(0, folderPath.length - 1); + plugin.settings.chatHistory.chatHistoryPath = folderPath; + } + const folder = plugin.app.vault.getAbstractFileByPath(folderPath); + if (folder && folder instanceof import_obsidian11.TFolder) { + text.inputEl.style.borderColor = ""; + } else { + text.inputEl.style.borderColor = "red"; + } + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian11.Setting(settingsContainer).setName("Template File Path").setDesc("Insert your template file path.").addText( + (text) => text.setPlaceholder("templates/bmo.md").setValue(plugin.settings.chatHistory.templateFilePath || DEFAULT_SETTINGS.chatHistory.templateFilePath).onChange(async (value) => { + plugin.settings.chatHistory.templateFilePath = value ? value : DEFAULT_SETTINGS.chatHistory.templateFilePath; + if (value) { + if (!plugin.settings.chatHistory.templateFilePath.endsWith(".md")) { + plugin.settings.chatHistory.templateFilePath += ".md"; + } + await plugin.saveSettings(); + const allFiles = plugin.app.vault.getFiles(); + const fileExists = allFiles.some((file) => file.path.toLowerCase() === plugin.settings.chatHistory.templateFilePath.toLowerCase()); + if (fileExists) { + text.inputEl.style.borderColor = ""; + } else { + text.inputEl.style.borderColor = "red"; + } + } else { + text.inputEl.style.borderColor = ""; + plugin.settings.chatHistory.templateFilePath = DEFAULT_SETTINGS.chatHistory.templateFilePath; + } + }) + ); + new import_obsidian11.Setting(settingsContainer).setName("Enable Rename Note Title").setDesc("Enable model to rename the note title when saving chat history.").addToggle( + (toggle) => toggle.setValue(plugin.settings.chatHistory.allowRenameNoteTitle).onChange((value) => { + plugin.settings.chatHistory.allowRenameNoteTitle = value; + plugin.saveSettings(); + }) + ); +} + +// src/components/settings/OllamaSettings.ts +var import_obsidian12 = require("obsidian"); + +// src/utils/DescriptionLink.ts +function addDescriptionLink(text, link, extraWords, innerText) { + const frag = new DocumentFragment(); + const desc = document.createElement("span"); + desc.innerText = text + " "; + frag.appendChild(desc); + const anchor = document.createElement("a"); + anchor.href = link; + anchor.target = "_blank"; + anchor.rel = "noopener noreferrer"; + anchor.innerText = innerText; + frag.appendChild(anchor); + const extra = document.createElement("span"); + extra.innerText = " " + extraWords; + frag.appendChild(extra); + return frag; +} + +// src/components/settings/OllamaSettings.ts +function addOllamaSettings(containerEl, plugin, SettingTab15) { + const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); + toggleSettingContainer.createEl("h2", { text: "Ollama Connection" }); + const initialState = plugin.settings.toggleOllamaSettings; + const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); + (0, import_obsidian12.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); + const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); + settingsContainer.style.display = initialState ? "block" : "none"; + toggleSettingContainer.addEventListener("click", async () => { + const isOpen = settingsContainer.style.display !== "none"; + if (isOpen) { + (0, import_obsidian12.setIcon)(chevronIcon, "chevron-right"); + settingsContainer.style.display = "none"; + plugin.settings.toggleOllamaSettings = false; + } else { + (0, import_obsidian12.setIcon)(chevronIcon, "chevron-down"); + settingsContainer.style.display = "block"; + plugin.settings.toggleOllamaSettings = true; + } + await plugin.saveSettings(); + }); + new import_obsidian12.Setting(settingsContainer).setName("OLLAMA REST API URL").setDesc(addDescriptionLink("Enter your REST API URL. Update ", "https://ollama.com/", "to version >=0.1.42 to avoid CORS restriction.", "Ollama")).addText( + (text) => text.setPlaceholder("http://localhost:11434").setValue(plugin.settings.OllamaConnection.RESTAPIURL || DEFAULT_SETTINGS.OllamaConnection.RESTAPIURL).onChange(async (value) => { + plugin.settings.OllamaConnection.ollamaModels = []; + plugin.settings.OllamaConnection.RESTAPIURL = value ? value : DEFAULT_SETTINGS.OllamaConnection.RESTAPIURL; + if (plugin.settings.OllamaConnection.RESTAPIURL === "") { + plugin.settings.OllamaConnection.ollamaModels = []; + } else { + const models = await fetchOllamaModels(plugin); + models == null ? void 0 : models.forEach((model) => { + if (!plugin.settings.OllamaConnection.ollamaModels.includes(model)) { + plugin.settings.OllamaConnection.ollamaModels.push(model); + } + }); + } + }).inputEl.addEventListener("focusout", async () => { + await plugin.saveSettings(); + SettingTab15.display(); + }) + ); + new import_obsidian12.Setting(settingsContainer).setName("Enable Stream").setDesc("Enable Ollama models to stream response.").addToggle( + (toggle) => toggle.setValue(plugin.settings.OllamaConnection.enableStream).onChange((value) => { + plugin.settings.OllamaConnection.enableStream = value; + plugin.saveSettings(); + }) + ); + const advancedToggleSettingContainer = settingsContainer.createDiv({ cls: "toggleSettingContainer" }); + advancedToggleSettingContainer.createEl("h2", { text: "Advanced Settings" }); + const advancedInitialState = plugin.settings.toggleAdvancedSettings; + const advancedChevronIcon = advancedToggleSettingContainer.createEl("span", { cls: "chevron-icon" }); + (0, import_obsidian12.setIcon)(advancedChevronIcon, advancedInitialState ? "chevron-down" : "chevron-right"); + const advancedSettingsContainer = settingsContainer.createDiv({ cls: "settingsContainer" }); + advancedSettingsContainer.style.display = advancedInitialState ? "block" : "none"; + advancedToggleSettingContainer.addEventListener("click", async () => { + const isOpen = advancedSettingsContainer.style.display !== "none"; + if (isOpen) { + (0, import_obsidian12.setIcon)(advancedChevronIcon, "chevron-right"); + advancedSettingsContainer.style.display = "none"; + plugin.settings.toggleAdvancedSettings = false; + } else { + (0, import_obsidian12.setIcon)(advancedChevronIcon, "chevron-down"); + advancedSettingsContainer.style.display = "block"; + plugin.settings.toggleAdvancedSettings = true; + } + await plugin.saveSettings(); + }); + new import_obsidian12.Setting(advancedSettingsContainer).setName("mirostat").setDesc("Enable Mirostat sampling for controlling perplexity. (default: 0, 0 = disabled, 1 = Mirostat, 2 = Mirostat 2.0)").addText( + (text) => text.setPlaceholder("0").setValue(plugin.settings.OllamaConnection.ollamaParameters.mirostat || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat).onChange(async (value) => { + const intValue = parseInt(value, 10); + if (isNaN(intValue)) { + plugin.settings.OllamaConnection.ollamaParameters.mirostat = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat; + } else { + plugin.settings.OllamaConnection.ollamaParameters.mirostat = intValue.toString(); + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian12.Setting(advancedSettingsContainer).setName("mirostat_eta").setDesc("Influences how quickly the algorithm responds to feedback from the generated text. A lower learning rate will result in slower adjustments, while a higher learning rate will make the algorithm more responsive. (Default: 0.1)").addText( + (text) => text.setPlaceholder("0.1").setValue(plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat_eta).onChange(async (value) => { + const floatValue = parseFloat(value); + if (!isNaN(floatValue)) { + plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta = floatValue.toFixed(2).toString(); + } else { + plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat_eta; + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian12.Setting(advancedSettingsContainer).setName("mirostat_tau").setDesc("Controls the balance between coherence and diversity of the output. A lower value will result in more focused and coherent text. (Default: 5.0)").addText( + (text) => text.setPlaceholder("5.00").setValue(plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat_tau).onChange(async (value) => { + const floatValue = parseFloat(value); + if (!isNaN(floatValue)) { + plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau = floatValue.toFixed(2).toString(); + } else { + plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat_tau; + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian12.Setting(advancedSettingsContainer).setName("num_ctx").setDesc("Sets the size of the context window used to generate the next token. (Default: 2048)").addText( + (text) => text.setPlaceholder("2048").setValue(plugin.settings.OllamaConnection.ollamaParameters.num_ctx || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_ctx).onChange(async (value) => { + const intValue = parseInt(value, 10); + if (isNaN(intValue)) { + plugin.settings.OllamaConnection.ollamaParameters.num_ctx = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_ctx; + } else { + plugin.settings.OllamaConnection.ollamaParameters.num_ctx = intValue.toString(); + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian12.Setting(advancedSettingsContainer).setName("num_gqa").setDesc("The number of GQA groups in the transformer layer. Required for some models, for example it is 8 for llama2:70b.").addText( + (text) => text.setPlaceholder("0").setValue(plugin.settings.OllamaConnection.ollamaParameters.num_gqa || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_gqa).onChange(async (value) => { + const intValue = parseInt(value, 10); + if (isNaN(intValue)) { + plugin.settings.OllamaConnection.ollamaParameters.num_gqa = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_gqa; + } else { + plugin.settings.OllamaConnection.ollamaParameters.num_gqa = intValue.toString(); + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian12.Setting(advancedSettingsContainer).setName("num_thread").setDesc("Sets the number of threads to use during computation. By default, Ollama will detect this for optimal performance. It is recommended to set this value to the number of physical CPU cores your system has (as opposed to the logical number of cores).").addText( + (text) => text.setPlaceholder("0").setValue(plugin.settings.OllamaConnection.ollamaParameters.num_thread || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_thread).onChange(async (value) => { + const intValue = parseInt(value, 10); + if (isNaN(intValue)) { + plugin.settings.OllamaConnection.ollamaParameters.num_thread = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_thread; + } else { + plugin.settings.OllamaConnection.ollamaParameters.num_thread = intValue.toString(); + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian12.Setting(advancedSettingsContainer).setName("repeat_last_n").setDesc("Sets how far back for the model to look back to prevent repetition. (Default: 64, 0 = disabled, -1 = num_ctx)").addText( + (text) => text.setPlaceholder("64").setValue(plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.repeat_last_n).onChange(async (value) => { + const intValue = parseInt(value, 10); + if (isNaN(intValue)) { + plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.repeat_last_n; + } else { + plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n = intValue.toString(); + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian12.Setting(advancedSettingsContainer).setName("repeat_penalty").setDesc("Sets how strongly to penalize repetitions. A higher value (e.g., 1.5) will penalize repetitions more strongly, while a lower value (e.g., 0.9) will be more lenient. (Default: 1.1)").addText( + (text) => text.setPlaceholder("1.1").setValue(plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.repeat_penalty).onChange(async (value) => { + const floatValue = parseFloat(value); + if (isNaN(floatValue)) { + plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.repeat_penalty; + } else { + plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty = floatValue.toString(); + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian12.Setting(advancedSettingsContainer).setName("seed").setDesc("Sets the random number seed to use for generation. Setting this to a specific number will make the model generate the same text for the same prompt.").addText( + (text) => text.setPlaceholder("0").setValue(plugin.settings.OllamaConnection.ollamaParameters.seed || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.seed).onChange(async (value) => { + const intValue = parseInt(value, 10); + if (isNaN(intValue)) { + plugin.settings.OllamaConnection.ollamaParameters.seed = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.seed; + } else { + plugin.settings.OllamaConnection.ollamaParameters.seed = intValue.toString(); + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian12.Setting(advancedSettingsContainer).setName("stop").setDesc("Sets the stop sequences to use. When this pattern is encountered, the LLM will stop generating text and return. Multiple stop patterns may be set by specifying them as a comma-separated list in the input field.").addText( + (text) => text.setPlaceholder("stop, \\n, user:").setValue(plugin.settings.OllamaConnection.ollamaParameters.stop && Array.isArray(plugin.settings.OllamaConnection.ollamaParameters.stop) ? plugin.settings.OllamaConnection.ollamaParameters.stop.join(", ") : DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.stop.join(", ")).onChange(async (value) => { + const stopsArray = value ? value.split(",").map((s) => s.trim()) : [...DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.stop]; + plugin.settings.OllamaConnection.ollamaParameters.stop = stopsArray; + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian12.Setting(advancedSettingsContainer).setName("tfs_z").setDesc("Tail free sampling is used to reduce the impact of less probable tokens from the output. A higher value (e.g., 2.0) will reduce the impact more, while a value of 1.0 disables this setting. (default: 1)").addText( + (text) => text.setPlaceholder("1.0").setValue(plugin.settings.OllamaConnection.ollamaParameters.tfs_z || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.tfs_z).onChange(async (value) => { + const floatValue = parseFloat(value); + if (isNaN(floatValue)) { + plugin.settings.OllamaConnection.ollamaParameters.tfs_z = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.tfs_z; + } else { + plugin.settings.OllamaConnection.ollamaParameters.tfs_z = floatValue.toFixed(2).toString(); + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian12.Setting(advancedSettingsContainer).setName("top_k").setDesc("Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)").addText( + (text) => text.setPlaceholder("40").setValue(plugin.settings.OllamaConnection.ollamaParameters.top_k || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.top_k).onChange(async (value) => { + const intValue = parseInt(value, 10); + if (isNaN(intValue)) { + plugin.settings.OllamaConnection.ollamaParameters.top_k = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.top_k; + } else { + plugin.settings.OllamaConnection.ollamaParameters.top_k = intValue.toString(); + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian12.Setting(advancedSettingsContainer).setName("top_p").setDesc("Works together with top-k. A higher value (e.g., 0.95) will lead to more diverse text, while a lower value (e.g., 0.5) will generate more focused and conservative text. (Default: 0.9)").addText( + (text) => text.setPlaceholder("1.0").setValue(plugin.settings.OllamaConnection.ollamaParameters.top_p || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.top_p).onChange(async (value) => { + const floatValue = parseFloat(value); + if (isNaN(floatValue)) { + plugin.settings.OllamaConnection.ollamaParameters.top_p = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.top_p; + } else { + plugin.settings.OllamaConnection.ollamaParameters.top_p = floatValue.toFixed(2).toString(); + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian12.Setting(advancedSettingsContainer).setName("min_p").setDesc("Alternative to the top_p, and aims to ensure a balance of quality and variety. The parameter p represents the minimum probability for a token to be considered, relative to the probability of the most likely token. (Default: 0.0)").addText( + (text) => text.setPlaceholder("0.0").setValue(plugin.settings.OllamaConnection.ollamaParameters.min_p || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.min_p).onChange(async (value) => { + const floatValue = parseFloat(value); + if (isNaN(floatValue)) { + plugin.settings.OllamaConnection.ollamaParameters.min_p = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.min_p; + } else { + plugin.settings.OllamaConnection.ollamaParameters.min_p = floatValue.toFixed(2).toString(); + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian12.Setting(advancedSettingsContainer).setName("keep_alive").setDesc("If set to a positive duration (e.g. 20m, 1hr or 30), the model will stay loaded for the provided duration in seconds. If set to a negative duration (e.g. -1), the model will stay loaded indefinitely. If set to 0, the model will be unloaded immediately once finished. If not set, the model will stay loaded for 5 minutes by default.").addText( + (text) => text.setPlaceholder("30s").setValue(plugin.settings.OllamaConnection.ollamaParameters.keep_alive || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.keep_alive).onChange(async (value) => { + const match = value.match(/^(-?\d+)(m|hr|h)?$/); + if (match) { + const num = parseInt(match[1]); + const unit = match[2]; + let seconds; + if (unit === "m") { + seconds = num * 60; + } else if (unit === "hr" || unit === "h") { + seconds = num * 3600; + } else { + seconds = num; + } + plugin.settings.OllamaConnection.ollamaParameters.keep_alive = seconds.toString(); + } else { + plugin.settings.OllamaConnection.ollamaParameters.keep_alive = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.keep_alive; + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); +} + +// src/components/settings/ConnectionSettings.ts +var import_obsidian18 = require("obsidian"); + +// src/components/settings/APIConnections/OpenAIConnections.ts +var import_obsidian13 = require("obsidian"); +function addOpenAIConnectionSettings(containerEl, plugin, SettingTab15) { + const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); + toggleSettingContainer.createEl("h2", { text: "OpenAI" }); + const initialState = plugin.settings.toggleOpenAISettings; + const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); + (0, import_obsidian13.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); + const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); + settingsContainer.style.display = initialState ? "block" : "none"; + toggleSettingContainer.addEventListener("click", async () => { + const isOpen = settingsContainer.style.display !== "none"; + if (isOpen) { + (0, import_obsidian13.setIcon)(chevronIcon, "chevron-right"); + settingsContainer.style.display = "none"; + plugin.settings.toggleOpenAISettings = false; + } else { + (0, import_obsidian13.setIcon)(chevronIcon, "chevron-down"); + settingsContainer.style.display = "block"; + plugin.settings.toggleOpenAISettings = true; + } + await plugin.saveSettings(); + }); + new import_obsidian13.Setting(settingsContainer).setName("OpenAI API Key").setDesc("Insert OpenAI API Key.").addText( + (text) => text.setPlaceholder("insert-api-key").setValue(plugin.settings.APIConnections.openAI.APIKey ? `${plugin.settings.APIConnections.openAI.APIKey.slice(0, 7)}-...${plugin.settings.APIConnections.openAI.APIKey.slice(-4)}` : "").onChange(async (value) => { + plugin.settings.APIConnections.openAI.openAIBaseModels = []; + plugin.settings.APIConnections.openAI.APIKey = value; + if (plugin.settings.APIConnections.openAI.APIKey === "") { + plugin.settings.APIConnections.openAI.openAIBaseModels = []; + } else { + const models = await fetchOpenAIBaseModels(plugin); + models.forEach((model) => { + if (!plugin.settings.APIConnections.openAI.openAIBaseModels.includes(model)) { + plugin.settings.APIConnections.openAI.openAIBaseModels.push(model); + } + }); + } + }).inputEl.addEventListener("focusout", async () => { + await plugin.saveSettings(); + SettingTab15.display(); + }) + ); + new import_obsidian13.Setting(settingsContainer).setName("OpenAI-Based URL").setDesc("Enter your custom OpenAI-Based URL.").addButton( + (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { + plugin.settings.APIConnections.openAI.openAIBaseModels = []; + plugin.settings.APIConnections.openAI.openAIBaseUrl = DEFAULT_SETTINGS.APIConnections.openAI.openAIBaseUrl; + await plugin.saveSettings(); + SettingTab15.display(); + }) + ).addText( + (text) => text.setPlaceholder("https://api.openai.com/v1").setValue(plugin.settings.APIConnections.openAI.openAIBaseUrl || DEFAULT_SETTINGS.APIConnections.openAI.openAIBaseUrl).onChange(async (value) => { + plugin.settings.APIConnections.openAI.openAIBaseUrl = value ? value : DEFAULT_SETTINGS.APIConnections.openAI.openAIBaseUrl; + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian13.Setting(settingsContainer).setName("Enable Stream").setDesc("Enable stream for OpenAI-Based models.").addToggle( + (toggle) => toggle.setValue(plugin.settings.APIConnections.openAI.enableStream).onChange(async (value) => { + plugin.settings.APIConnections.openAI.enableStream = value; + await plugin.saveSettings(); + }) + ); +} + +// src/components/settings/APIConnections/MistralConnections.ts +var import_obsidian14 = require("obsidian"); +function addMistralConnectionSettings(containerEl, plugin, SettingTab15) { + const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); + toggleSettingContainer.createEl("h2", { text: "Mistral AI" }); + const initialState = plugin.settings.toggleMistralSettings; + const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); + (0, import_obsidian14.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); + const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); + settingsContainer.style.display = initialState ? "block" : "none"; + toggleSettingContainer.addEventListener("click", async () => { + const isOpen = settingsContainer.style.display !== "none"; + if (isOpen) { + (0, import_obsidian14.setIcon)(chevronIcon, "chevron-right"); + settingsContainer.style.display = "none"; + plugin.settings.toggleMistralSettings = false; + } else { + (0, import_obsidian14.setIcon)(chevronIcon, "chevron-down"); + settingsContainer.style.display = "block"; + plugin.settings.toggleMistralSettings = true; + } + await plugin.saveSettings(); + }); + new import_obsidian14.Setting(settingsContainer).setName("Mistral API Key").setDesc("Insert Mistral API Key.").addText( + (text) => text.setPlaceholder("insert-api-key").setValue(plugin.settings.APIConnections.mistral.APIKey ? `${plugin.settings.APIConnections.mistral.APIKey.slice(0, 6)}-...${plugin.settings.APIConnections.mistral.APIKey.slice(-4)}` : "").onChange(async (value) => { + plugin.settings.APIConnections.mistral.mistralModels = []; + plugin.settings.APIConnections.mistral.APIKey = value; + if (plugin.settings.APIConnections.mistral.APIKey === "") { + plugin.settings.APIConnections.mistral.mistralModels = []; + } else { + const models = await fetchMistralModels(plugin); + models.forEach((model) => { + if (!plugin.settings.APIConnections.mistral.mistralModels.includes(model)) { + plugin.settings.APIConnections.mistral.mistralModels.push(model); + } + }); + } + }).inputEl.addEventListener("focusout", async () => { + await plugin.saveSettings(); + SettingTab15.display(); + }) + ); + new import_obsidian14.Setting(settingsContainer).setName("Enable Stream").setDesc("Enable stream for Mistral models.").addToggle( + (toggle) => toggle.setValue(plugin.settings.APIConnections.mistral.enableStream).onChange((value) => { + plugin.settings.APIConnections.mistral.enableStream = value; + plugin.saveSettings(); + }) + ); +} + +// src/components/settings/APIConnections/GoogleGeminiConnections.ts +var import_obsidian15 = require("obsidian"); +function addGoogleGeminiConnectionSettings(containerEl, plugin, SettingTab15) { + const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); + toggleSettingContainer.createEl("h2", { text: "Google Gemini" }); + const initialState = plugin.settings.toggleGoogleGeminiSettings; + const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); + (0, import_obsidian15.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); + const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); + settingsContainer.style.display = initialState ? "block" : "none"; + toggleSettingContainer.addEventListener("click", async () => { + const isOpen = settingsContainer.style.display !== "none"; + if (isOpen) { + (0, import_obsidian15.setIcon)(chevronIcon, "chevron-right"); + settingsContainer.style.display = "none"; + plugin.settings.toggleGoogleGeminiSettings = false; + } else { + (0, import_obsidian15.setIcon)(chevronIcon, "chevron-down"); + settingsContainer.style.display = "block"; + plugin.settings.toggleGoogleGeminiSettings = true; + } + await plugin.saveSettings(); + }); + new import_obsidian15.Setting(settingsContainer).setName("Google Gemini API Key").setDesc("Insert Google Gemini API Key.").addText( + (text) => text.setPlaceholder("insert-api-key").setValue(plugin.settings.APIConnections.googleGemini.APIKey ? `${plugin.settings.APIConnections.googleGemini.APIKey.slice(0, 6)}-...${plugin.settings.APIConnections.googleGemini.APIKey.slice(-4)}` : "").onChange(async (value) => { + plugin.settings.APIConnections.googleGemini.geminiModels = []; + plugin.settings.APIConnections.googleGemini.APIKey = value; + if (plugin.settings.APIConnections.googleGemini.APIKey === "") { + plugin.settings.APIConnections.googleGemini.geminiModels = []; + } else { + const models = await fetchGoogleGeminiModels(plugin); + models.forEach((model) => { + if (!plugin.settings.APIConnections.googleGemini.geminiModels.includes(model)) { + plugin.settings.APIConnections.googleGemini.geminiModels.push(model); + } + }); + } + }).inputEl.addEventListener("focusout", async () => { + await plugin.saveSettings(); + SettingTab15.display(); + }) + ); + new import_obsidian15.Setting(settingsContainer).setName("Enable Stream").setDesc("Enable Google Gemini models to stream response.").addToggle( + (toggle) => toggle.setValue(plugin.settings.APIConnections.googleGemini.enableStream).onChange((value) => { + plugin.settings.APIConnections.googleGemini.enableStream = value; + plugin.saveSettings(); + }) + ); +} + +// src/components/settings/APIConnections/AnthropicConnections.ts +var import_obsidian16 = require("obsidian"); +function addAnthropicConnectionSettings(containerEl, plugin, SettingTab15) { + const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); + toggleSettingContainer.createEl("h2", { text: "Anthropic" }); + const initialState = plugin.settings.toggleAnthropicSettings; + const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); + (0, import_obsidian16.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); + const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); + settingsContainer.style.display = initialState ? "block" : "none"; + toggleSettingContainer.addEventListener("click", async () => { + const isOpen = settingsContainer.style.display !== "none"; + if (isOpen) { + (0, import_obsidian16.setIcon)(chevronIcon, "chevron-right"); + settingsContainer.style.display = "none"; + plugin.settings.toggleAnthropicSettings = false; + } else { + (0, import_obsidian16.setIcon)(chevronIcon, "chevron-down"); + settingsContainer.style.display = "block"; + plugin.settings.toggleAnthropicSettings = true; + } + await plugin.saveSettings(); + }); + new import_obsidian16.Setting(settingsContainer).setName("Anthropic API Key").setDesc("Insert Anthropic API Key. Warning: Anthropic models cannot be aborted. Please use with caution.").addText( + (text) => text.setPlaceholder("insert-api-key").setValue(plugin.settings.APIConnections.anthropic.APIKey ? `${plugin.settings.APIConnections.anthropic.APIKey.slice(0, 6)}-...${plugin.settings.APIConnections.anthropic.APIKey.slice(-4)}` : "").onChange(async (value) => { + plugin.settings.APIConnections.anthropic.anthropicModels = []; + plugin.settings.APIConnections.anthropic.APIKey = value; + if (plugin.settings.APIConnections.anthropic.APIKey === "") { + plugin.settings.APIConnections.anthropic.anthropicModels = []; + } else { + const models = ANTHROPIC_MODELS; + models.forEach((model) => { + if (!plugin.settings.APIConnections.anthropic.anthropicModels.includes(model)) { + plugin.settings.APIConnections.anthropic.anthropicModels.push(model); + } + }); + } + }).inputEl.addEventListener("focusout", async () => { + await plugin.saveSettings(); + SettingTab15.display(); + }) + ); +} + +// src/components/settings/APIConnections/OpenRouterConnections.ts +var import_obsidian17 = require("obsidian"); +function addOpenRouterConnectionSettings(containerEl, plugin, SettingTab15) { + const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); + toggleSettingContainer.createEl("h2", { text: "OpenRouter" }); + const initialState = plugin.settings.toggleOpenRouterSettings; + const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); + (0, import_obsidian17.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); + const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); + settingsContainer.style.display = initialState ? "block" : "none"; + toggleSettingContainer.addEventListener("click", async () => { + const isOpen = settingsContainer.style.display !== "none"; + if (isOpen) { + (0, import_obsidian17.setIcon)(chevronIcon, "chevron-right"); + settingsContainer.style.display = "none"; + plugin.settings.toggleOpenRouterSettings = false; + } else { + (0, import_obsidian17.setIcon)(chevronIcon, "chevron-down"); + settingsContainer.style.display = "block"; + plugin.settings.toggleOpenRouterSettings = true; + } + await plugin.saveSettings(); + }); + new import_obsidian17.Setting(settingsContainer).setName("OpenRouter API Key").setDesc("Insert OpenRouter API Key.").addText( + (text) => text.setPlaceholder("insert-api-key").setValue(plugin.settings.APIConnections.openRouter.APIKey ? `${plugin.settings.APIConnections.openRouter.APIKey.slice(0, 6)}-...${plugin.settings.APIConnections.openRouter.APIKey.slice(-4)}` : "").onChange(async (value) => { + plugin.settings.APIConnections.openAI.openAIBaseModels = []; + plugin.settings.APIConnections.openRouter.APIKey = value; + if (plugin.settings.APIConnections.openRouter.APIKey === "") { + plugin.settings.APIConnections.openRouter.openRouterModels = []; + } else { + const models = await fetchOpenRouterModels(plugin); + models.forEach((model) => { + if (!plugin.settings.APIConnections.openRouter.openRouterModels.includes(model)) { + plugin.settings.APIConnections.openRouter.openRouterModels.push(model); + } + }); + } + }).inputEl.addEventListener("focusout", async () => { + await plugin.saveSettings(); + SettingTab15.display(); + }) + ); + new import_obsidian17.Setting(settingsContainer).setName("Enable Stream").setDesc("Enable stream for OpenRouter models.").addToggle( + (toggle) => toggle.setValue(plugin.settings.APIConnections.openRouter.enableStream).onChange((value) => { + plugin.settings.APIConnections.openRouter.enableStream = value; + plugin.saveSettings(); + }) + ); +} + +// src/components/settings/ConnectionSettings.ts +function addAPIConnectionSettings(containerEl, plugin, SettingTab15) { + const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); + toggleSettingContainer.createEl("h2", { text: "API Connections" }); + const initialState = plugin.settings.toggleAPIConnectionSettings; + const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); + (0, import_obsidian18.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); + const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); + settingsContainer.style.display = initialState ? "block" : "none"; + toggleSettingContainer.addEventListener("click", async () => { + const isOpen = settingsContainer.style.display !== "none"; + if (isOpen) { + (0, import_obsidian18.setIcon)(chevronIcon, "chevron-right"); + settingsContainer.style.display = "none"; + plugin.settings.toggleAPIConnectionSettings = false; + } else { + (0, import_obsidian18.setIcon)(chevronIcon, "chevron-down"); + settingsContainer.style.display = "block"; + plugin.settings.toggleAPIConnectionSettings = true; + } + await plugin.saveSettings(); + }); + addAnthropicConnectionSettings(settingsContainer, plugin, SettingTab15); + addGoogleGeminiConnectionSettings(settingsContainer, plugin, SettingTab15); + addMistralConnectionSettings(settingsContainer, plugin, SettingTab15); + addOpenAIConnectionSettings(settingsContainer, plugin, SettingTab15); + addOpenRouterConnectionSettings(settingsContainer, plugin, SettingTab15); +} + +// src/components/settings/ProfileSettings.ts +var import_obsidian19 = require("obsidian"); +function addProfileSettings(containerEl, plugin, SettingTab15) { + const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); + toggleSettingContainer.createEl("h2", { text: "Profiles" }); + const initialState = plugin.settings.toggleProfileSettings; + const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); + (0, import_obsidian19.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); + const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); + settingsContainer.style.display = initialState ? "block" : "none"; + toggleSettingContainer.addEventListener("click", async () => { + const isOpen = settingsContainer.style.display !== "none"; + if (isOpen) { + (0, import_obsidian19.setIcon)(chevronIcon, "chevron-right"); + settingsContainer.style.display = "none"; + plugin.settings.toggleProfileSettings = false; + } else { + (0, import_obsidian19.setIcon)(chevronIcon, "chevron-down"); + settingsContainer.style.display = "block"; + plugin.settings.toggleProfileSettings = true; + } + await plugin.saveSettings(); + }); + new import_obsidian19.Setting(settingsContainer).setName("Profile").setDesc("Select a profile.").addDropdown((dropdown) => { + if (plugin.settings.profiles.profileFolderPath !== "") { + const files = plugin.app.vault.getFiles().filter((file) => file.path.startsWith(plugin.settings.profiles.profileFolderPath)); + files.sort((a, b) => a.name.localeCompare(b.name)); + const dataFolderPath = "./.obsidian/plugins/bmo-chatbot/data/"; + if (!plugin.app.vault.getAbstractFileByPath(dataFolderPath)) { + plugin.app.vault.adapter.mkdir(dataFolderPath); + } + files.forEach((file) => { + if (file instanceof import_obsidian19.TFile) { + const fileName = file.basename; + const newFileName = `messageHistory_${fileName}.json`; + const newFilePath = `${dataFolderPath}${newFileName}`; + plugin.app.vault.create(newFilePath, "").catch((err) => { + if (err.message === "File already exists.") { + } else { + throw err; + } + }); + dropdown.addOption(file.name, fileName); + } + }); + } + dropdown.setValue(plugin.settings.profiles.profile || DEFAULT_SETTINGS.profiles.profile).onChange(async (value) => { + plugin.settings.profiles.profile = value ? value : DEFAULT_SETTINGS.profiles.profile; + const profileFilePath = plugin.settings.profiles.profileFolderPath + "/" + plugin.settings.profiles.profile; + const currentProfile = plugin.app.vault.getAbstractFileByPath(profileFilePath); + plugin.activateView(); + await updateSettingsFromFrontMatter(plugin, currentProfile); + await plugin.saveSettings(); + SettingTab15.display(); + }); + }); + new import_obsidian19.Setting(settingsContainer).setName("Profile Folder Path").setDesc("Select a profile from a specified folder.").addText( + (text) => text.setPlaceholder("BMO/Profiles").setValue(plugin.settings.profiles.profileFolderPath || DEFAULT_SETTINGS.profiles.profileFolderPath).onChange(async (value) => { + plugin.settings.profiles.profileFolderPath = value ? value : DEFAULT_SETTINGS.profiles.profileFolderPath; + if (value) { + let folderPath = plugin.settings.profiles.profileFolderPath.trim() || DEFAULT_SETTINGS.profiles.profileFolderPath; + while (folderPath.endsWith("/")) { + folderPath = folderPath.substring(0, folderPath.length - 1); + plugin.settings.profiles.profileFolderPath = folderPath; + } + const folder = plugin.app.vault.getAbstractFileByPath(folderPath); + if (folder && folder instanceof import_obsidian19.TFolder) { + text.inputEl.style.borderColor = ""; + } else { + text.inputEl.style.borderColor = "red"; + } + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); +} + +// src/components/settings/RESTAPIURLSettings.ts +var import_obsidian20 = require("obsidian"); +function addRESTAPIURLSettings(containerEl, plugin, SettingTab15) { + const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); + toggleSettingContainer.createEl("h2", { text: "REST API Connection" }); + const initialState = plugin.settings.toggleRESTAPIURLSettings; + const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); + (0, import_obsidian20.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); + const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); + settingsContainer.style.display = initialState ? "block" : "none"; + toggleSettingContainer.addEventListener("click", async () => { + const isOpen = settingsContainer.style.display !== "none"; + if (isOpen) { + (0, import_obsidian20.setIcon)(chevronIcon, "chevron-right"); + settingsContainer.style.display = "none"; + plugin.settings.toggleRESTAPIURLSettings = false; + } else { + (0, import_obsidian20.setIcon)(chevronIcon, "chevron-down"); + settingsContainer.style.display = "block"; + plugin.settings.toggleRESTAPIURLSettings = true; + } + await plugin.saveSettings(); + }); + new import_obsidian20.Setting(settingsContainer).setName("API Key").setDesc("Insert API Key (Optional).").addText( + (text) => text.setPlaceholder("insert-api-key").setValue(plugin.settings.RESTAPIURLConnection.APIKey ? `${plugin.settings.RESTAPIURLConnection.APIKey.slice(0, 6)}-...${plugin.settings.RESTAPIURLConnection.APIKey.slice(-4)}` : "").onChange(async (value) => { + plugin.settings.RESTAPIURLConnection.RESTAPIURLModels = []; + plugin.settings.RESTAPIURLConnection.APIKey = value; + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); + new import_obsidian20.Setting(settingsContainer).setName("REST API URL").setDesc(addDescriptionLink("ENTER YOUR REST API URL.", "https://github.com/longy2k/obsidian-bmo-chatbot/wiki/How-to-setup-with-LM-Studio", "", "[Instructions]")).addText( + (text) => text.setPlaceholder("http://localhost:1234/v1").setValue(plugin.settings.RESTAPIURLConnection.RESTAPIURL || DEFAULT_SETTINGS.RESTAPIURLConnection.RESTAPIURL).onChange(async (value) => { + plugin.settings.RESTAPIURLConnection.RESTAPIURLModels = []; + plugin.settings.RESTAPIURLConnection.RESTAPIURL = value ? value : DEFAULT_SETTINGS.RESTAPIURLConnection.RESTAPIURL; + if (plugin.settings.RESTAPIURLConnection.RESTAPIURL === "") { + plugin.settings.RESTAPIURLConnection.RESTAPIURLModels = []; + } else { + const models = await fetchRESTAPIURLModels(plugin); + models.forEach((model) => { + if (!plugin.settings.RESTAPIURLConnection.RESTAPIURLModels.includes(model)) { + plugin.settings.RESTAPIURLConnection.RESTAPIURLModels.push(model); + } + }); + } + }).inputEl.addEventListener("focusout", async () => { + await plugin.saveSettings(); + SettingTab15.display(); + }) + ); + new import_obsidian20.Setting(settingsContainer).setName("Enable Stream").setDesc(addDescriptionLink("Enable REST API models to stream response.", "", "", "")).addToggle( + (toggle) => toggle.setValue(plugin.settings.RESTAPIURLConnection.enableStream).onChange((value) => { + plugin.settings.RESTAPIURLConnection.enableStream = value; + plugin.saveSettings(); + }) + ); +} + +// src/components/settings/EditorSettings.ts +var import_obsidian21 = require("obsidian"); +async function addEditorSettings(containerEl, plugin, SettingTab15) { + const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); + toggleSettingContainer.createEl("h2", { text: "Editor" }); + const initialState = plugin.settings.toggleEditorSettings; + const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); + (0, import_obsidian21.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); + const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); + settingsContainer.style.display = initialState ? "block" : "none"; + toggleSettingContainer.addEventListener("click", async () => { + const isOpen = settingsContainer.style.display !== "none"; + if (isOpen) { + (0, import_obsidian21.setIcon)(chevronIcon, "chevron-right"); + settingsContainer.style.display = "none"; + plugin.settings.toggleEditorSettings = false; + } else { + (0, import_obsidian21.setIcon)(chevronIcon, "chevron-down"); + settingsContainer.style.display = "block"; + plugin.settings.toggleEditorSettings = true; + } + await plugin.saveSettings(); + }); + new import_obsidian21.Setting(settingsContainer).setName("Editor System Role").setDesc("System role for BMO Generate and 'Prompt Select Generate' command.").addTextArea( + (text) => text.setPlaceholder("You are a helpful assistant.").setValue(plugin.settings.editor.systen_role !== void 0 ? plugin.settings.editor.systen_role : DEFAULT_SETTINGS.editor.systen_role).onChange(async (value) => { + plugin.settings.editor.systen_role = value !== void 0 ? value : DEFAULT_SETTINGS.editor.systen_role; + await plugin.saveSettings(); + }) + ); +} + +// src/components/settings/PromptSettings.ts +var import_obsidian22 = require("obsidian"); +function addPromptSettings(containerEl, plugin, SettingTab15) { + const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); + toggleSettingContainer.createEl("h2", { text: "Prompts" }); + const initialState = plugin.settings.togglePromptSettings; + const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); + (0, import_obsidian22.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); + const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); + settingsContainer.style.display = initialState ? "block" : "none"; + toggleSettingContainer.addEventListener("click", async () => { + const isOpen = settingsContainer.style.display !== "none"; + if (isOpen) { + (0, import_obsidian22.setIcon)(chevronIcon, "chevron-right"); + settingsContainer.style.display = "none"; + plugin.settings.togglePromptSettings = false; + } else { + (0, import_obsidian22.setIcon)(chevronIcon, "chevron-down"); + settingsContainer.style.display = "block"; + plugin.settings.togglePromptSettings = true; + } + await plugin.saveSettings(); + }); + new import_obsidian22.Setting(settingsContainer).setName("Prompt").setDesc("Select a prompt to provide additional context to the system role.").addDropdown((dropdown) => { + dropdown.addOption("", "--EMPTY--"); + if (plugin.settings.prompts.promptFolderPath !== "") { + const files = plugin.app.vault.getFiles().filter((file) => file.path.startsWith(plugin.settings.prompts.promptFolderPath)); + files.sort((a, b) => a.name.localeCompare(b.name)); + files.forEach((file) => { + if (file instanceof import_obsidian22.TFile) { + const fileName = file.basename; + dropdown.addOption(file.name, fileName); + } + }); + } + dropdown.setValue(""); + dropdown.setValue(plugin.settings.prompts.prompt || DEFAULT_SETTINGS.prompts.prompt).onChange(async (value) => { + plugin.settings.prompts.prompt = value ? value : DEFAULT_SETTINGS.prompts.prompt; + await plugin.saveSettings(); + }); + }); + new import_obsidian22.Setting(settingsContainer).setName("Prompt Folder Path").setDesc("Select a prompt from a specified folder.").addText( + (text) => text.setPlaceholder("BMO/Prompts").setValue(plugin.settings.prompts.promptFolderPath || DEFAULT_SETTINGS.prompts.promptFolderPath).onChange(async (value) => { + plugin.settings.prompts.promptFolderPath = value ? value : DEFAULT_SETTINGS.prompts.promptFolderPath; + if (value) { + let folderPath = plugin.settings.prompts.promptFolderPath.trim() || DEFAULT_SETTINGS.prompts.promptFolderPath; + while (folderPath.endsWith("/")) { + folderPath = folderPath.substring(0, folderPath.length - 1); + plugin.settings.prompts.promptFolderPath = folderPath; + } + const folder = plugin.app.vault.getAbstractFileByPath(folderPath); + if (folder && folder instanceof import_obsidian22.TFolder) { + text.inputEl.style.borderColor = ""; + } else { + text.inputEl.style.borderColor = "red"; + } + } + await plugin.saveSettings(); + }).inputEl.addEventListener("focusout", async () => { + SettingTab15.display(); + }) + ); +} + +// src/settings.ts +var BMOSettingTab = class extends import_obsidian23.PluginSettingTab { + constructor(app, plugin) { + super(app, plugin); + this.plugin = plugin; + } + async display() { + const { containerEl } = this; + containerEl.empty(); + containerEl.createEl("h1", { text: "BMO Chatbot Settings" }); + const linkContainer = containerEl.createEl("div"); + const links = [ + { text: "Changelog", href: "https://github.com/longy2k/obsidian-bmo-chatbot/releases" }, + { text: "Wiki", href: "https://github.com/longy2k/obsidian-bmo-chatbot/wiki" }, + { text: "Report a Bug", href: "https://github.com/longy2k/obsidian-bmo-chatbot/issues" }, + { text: "Support Me", href: "https://ko-fi.com/longy2k" } + ]; + links.forEach((link, index2) => { + if (index2 > 0) { + linkContainer.createEl("span", { + text: " | ", + attr: { style: "font-size: 0.8rem; margin-right: 5px;" } + }); + } + const linkEl = linkContainer.createEl("a", { + text: link.text, + href: link.href, + attr: { style: "font-size: 0.8rem;" } + }); + if (index2 < links.length - 1) { + linkEl.style.marginRight = "5px"; + } + }); + containerEl.createEl("p", { text: "Type `/help` in chat for commands." }); + addHorizontalRule(this.containerEl); + addProfileSettings(this.containerEl, this.plugin, this); + addGeneralSettings(this.containerEl, this.plugin, this); + addPromptSettings(this.containerEl, this.plugin, this); + addAppearanceSettings(this.containerEl, this.plugin, this); + addChatHistorySettings(this.containerEl, this.plugin, this); + addEditorSettings(this.containerEl, this.plugin, this); + addHorizontalRule(this.containerEl); + addOllamaSettings(this.containerEl, this.plugin, this); + addRESTAPIURLSettings(this.containerEl, this.plugin, this); + addAPIConnectionSettings(this.containerEl, this.plugin, this); + addHorizontalRule(this.containerEl); + const resetButton = containerEl.createEl("a", { + text: "Reset Settings", + href: "#", + attr: { + style: "display: block; text-align: center; margin: 1rem 0; font-size: 0.7rem; color: #ff6666;" + } + }); + resetButton.addEventListener("click", async (event) => { + event.preventDefault(); + const confirmReset = confirm("Are you sure you want to reset all settings to default?"); + if (confirmReset) { + const profilePathFile = this.plugin.settings.profiles.profileFolderPath + "/" + this.plugin.settings.profiles.profile; + const profilePath = this.plugin.app.vault.getAbstractFileByPath(profilePathFile); + const defaultProfilePathFile = DEFAULT_SETTINGS.profiles.profileFolderPath + "/" + DEFAULT_SETTINGS.profiles.profile; + const defaultProfilePath = this.plugin.app.vault.getAbstractFileByPath(defaultProfilePathFile); + if (profilePath) { + if (profilePath.path === defaultProfilePath.path) { + this.plugin.settings = DEFAULT_SETTINGS; + await this.plugin.saveSettings(); + await this.plugin.app.plugins.disablePlugin(this.plugin.manifest.id); + await this.plugin.app.plugins.enablePlugin(this.plugin.manifest.id); + } else { + const filenameMessageHistory = "./.obsidian/plugins/bmo-chatbot/data/messageHistory_" + defaultProfilePath.name.replace(".md", ".json"); + this.app.vault.adapter.remove(filenameMessageHistory); + this.plugin.app.vault.delete(profilePath); + this.plugin.settings.profiles.profile = DEFAULT_SETTINGS.profiles.profile; + await updateSettingsFromFrontMatter(this.plugin, defaultProfilePath); + await this.plugin.saveSettings(); + } + } + requestAnimationFrame(() => { + const refreshTab = this.plugin.app.setting.openTabById("bmo-chatbot"); + if (refreshTab) { + refreshTab.display(); + } else { + new BMOSettingTab(this.app, this.plugin).display(); + } + }); + } + }); + } +}; +function addHorizontalRule(containerEl) { + const separator = document.createElement("hr"); + separator.style.margin = "1rem 0"; + containerEl.appendChild(separator); +} + +// src/components/editor/EditorCommands.ts +var import_obsidian25 = require("obsidian"); + +// src/components/FetchModelEditor.ts +var import_obsidian24 = require("obsidian"); +async function fetchOllamaResponseEditor(settings, prompt, model, temperature, maxTokens, signal) { + const ollamaRESTAPIURL = settings.OllamaConnection.RESTAPIURL; + if (!ollamaRESTAPIURL) { + return; + } + const imageMatch = prompt.match(/!?\[\[(.*?)\]\]/g); + const imageLink = imageMatch ? imageMatch.map((item) => item.startsWith("!") ? item.slice(3, -2) : item.slice(2, -2)).filter((link) => /\.(jpg|jpeg|png|gif|webp|bmp|tiff|tif|svg)$/i.test(link)) : []; + const imagesVaultPath = []; + if (imageLink.length > 0) { + imageLink.forEach((link) => { + const imageFile = this.app.metadataCache.getFirstLinkpathDest(link, ""); + const image = imageFile ? this.app.vault.adapter.getFullPath(imageFile.path) : null; + if (image) { + imagesVaultPath.push(image); + } + }); + } + try { + const response = await fetch(ollamaRESTAPIURL + "/api/generate", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + model: model || settings.general.model, + system: settings.editor.systen_role, + prompt, + images: imagesVaultPath, + stream: false, + keep_alive: parseInt(settings.OllamaConnection.ollamaParameters.keep_alive), + options: { + temperature: temperature ? parseFloat(temperature) : parseFloat(settings.general.temperature), + num_predict: maxTokens ? parseInt(maxTokens) : parseInt(settings.general.max_tokens) + } + }), + signal + }); + const data = await response.json(); + const message = data.response.trim(); + return message; + } catch (error) { + if (error.name === "AbortError") { + console.log("Request aborted"); + } else { + console.error("Ollama request:", error); + throw error; + } + } +} +async function fetchRESTAPIURLDataEditor(settings, prompt, model, temperature, maxTokens, signal) { + try { + const response = await fetch(settings.RESTAPIURLConnection.RESTAPIURL + "/chat/completions", { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${settings.RESTAPIURLConnection.APIKey}` + }, + body: JSON.stringify({ + model: model || settings.general.model, + messages: [ + { role: "system", content: settings.editor.systen_role || "You are a helpful assistant." }, + { role: "user", content: prompt } + ], + max_tokens: parseInt(maxTokens || settings.general.max_tokens || "-1"), + temperature: parseFloat(temperature || settings.general.temperature) + }), + signal + }); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + const message = data.choices[0].message.content.trim(); + return message; + } catch (error) { + console.error("Error making API request:", error); + throw error; + } +} +async function fetchAnthropicResponseEditor(settings, prompt, model, temperature, maxTokens, signal) { + try { + const response = await (0, import_obsidian24.requestUrl)({ + url: "https://api.anthropic.com/v1/messages", + method: "POST", + headers: { + "anthropic-version": "2023-06-01", + "content-type": "application/json", + "x-api-key": settings.APIConnections.anthropic.APIKey + }, + body: JSON.stringify({ + model: model || settings.general.model, + system: settings.editor.systen_role, + messages: [ + { role: "user", content: prompt } + ], + max_tokens: parseInt(maxTokens || settings.general.max_tokens) || 4096, + temperature: parseFloat(temperature || settings.general.temperature) + }) + }); + const message = response.json.content[0].text.trim(); + return message; + } catch (error) { + console.error(error); + } +} +async function fetchGoogleGeminiDataEditor(settings, prompt, model, temperature, maxTokens, signal) { + try { + const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${settings.APIConnections.googleGemini.APIKey}`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + contents: [ + { + parts: [ + { text: settings.editor.systen_role + prompt } + ] + } + ], + model: model || settings.general.model, + generationConfig: { + temperature: parseFloat(temperature || settings.general.temperature), + maxOutputTokens: parseInt(maxTokens || settings.general.max_tokens) || 4096 + } + }), + signal + }); + const data = await response.json(); + const message = data.candidates[0].content.parts[0].text.trim(); + return message; + } catch (error) { + console.error(error); + } +} +async function fetchMistralDataEditor(settings, prompt, model, temperature, maxTokens, signal) { + try { + const response = await fetch("https://api.mistral.ai/v1/chat/completions", { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${settings.APIConnections.mistral.APIKey}` + }, + body: JSON.stringify({ + model: model || settings.general.model, + messages: [ + { role: "system", content: settings.editor.systen_role }, + { role: "user", content: prompt } + ], + max_tokens: parseInt(maxTokens || settings.general.max_tokens), + temperature: parseFloat(temperature || settings.general.temperature) + }), + signal + }); + const data = await response.json(); + const message = data.choices[0].message.content.trim(); + return message; + } catch (error) { + console.error(error); + } +} +async function fetchOpenAIBaseAPIResponseEditor(settings, prompt, model, temperature, maxTokens, signal) { + const response = await fetch(`${settings.APIConnections.openAI.openAIBaseUrl}/chat/completions`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${settings.APIConnections.openAI.APIKey}` + }, + body: JSON.stringify({ + model: model || settings.general.model, + max_tokens: parseInt(maxTokens || settings.general.max_tokens), + temperature: parseFloat(temperature || settings.general.temperature), + stream: false, + messages: [ + { role: "system", content: settings.editor.systen_role }, + { role: "user", content: prompt } + ] + }), + signal + }); + const data = await response.json(); + const message = data.choices[0].message.content || ""; + return message; +} +async function fetchOpenRouterEditor(settings, prompt, model, temperature, maxTokens, signal) { + try { + const response = await fetch("https://openrouter.ai/api/v1/chat/completions", { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${settings.APIConnections.openRouter.APIKey}` + }, + body: JSON.stringify({ + model: model || settings.general.model, + messages: [ + { role: "system", content: settings.editor.systen_role }, + { role: "user", content: prompt } + ], + max_tokens: parseInt(maxTokens || settings.general.max_tokens), + temperature: parseFloat(temperature || settings.general.temperature) + }), + signal + }); + const data = await response.json(); + const message = data.choices[0].message.content.trim(); + return message; + } catch (error) { + console.error("Error making API request:", error); + throw error; + } +} + +// src/components/editor/EditorCommands.ts +async function renameTitleCommand(plugin, settings) { + var _a2, _b, _c; + let uniqueNameFound = false; + let modelRenameTitle; + let folderName = ((_c = (_b = plugin.app.vault.getAbstractFileByPath(((_a2 = plugin.app.workspace.getActiveFile()) == null ? void 0 : _a2.path) || "")) == null ? void 0 : _b.parent) == null ? void 0 : _c.path) || ""; + const fileExtension = ".md"; + const allFiles = plugin.app.vault.getFiles(); + const activeFile = plugin.app.workspace.getActiveFile(); + let fileContent = ""; + try { + new import_obsidian25.Notice("Generating title..."); + if (activeFile) { + fileContent = await plugin.app.vault.read(activeFile); + } + if (folderName && !folderName.endsWith("/")) { + folderName += "/"; + } + const fileNameExists = (name) => { + return allFiles.some((file) => file.path === folderName + name + fileExtension); + }; + while (!uniqueNameFound) { + modelRenameTitle = await fetchModelRenameTitle(settings, fileContent); + if (!fileNameExists(modelRenameTitle)) { + uniqueNameFound = true; + } + } + const fileName = folderName + modelRenameTitle + fileExtension; + if (activeFile) { + plugin.app.vault.rename(activeFile, fileName); + } + new import_obsidian25.Notice("Renamed note title."); + } catch (error) { + console.error(error); + } +} +async function promptSelectGenerateCommand(plugin, settings) { + var _a2, _b; + const view = plugin.app.workspace.getActiveViewOfType(import_obsidian25.MarkdownView); + const select = view == null ? void 0 : view.editor.getSelection(); + if (view && select && select.trim() !== "") { + const generatingNotice = new import_obsidian25.Notice("Generating...", 0); + if (settings.OllamaConnection.RESTAPIURL && settings.OllamaConnection.ollamaModels.includes(settings.general.model)) { + try { + const response = await fetchOllamaResponseEditor(settings, select); + const cursorStart = view.editor.getCursor("from"); + view.editor.replaceSelection(response != null ? response : "ERROR"); + const cursorEnd = { + line: cursorStart.line, + ch: cursorStart.ch + (response != null ? response : "ERROR").length + }; + view.editor.setSelection(cursorStart, cursorEnd); + } catch (error) { + new import_obsidian25.Notice("Error occurred while fetching completion: " + error.message); + console.log(error.message); + } + } else if (settings.RESTAPIURLConnection.RESTAPIURL && settings.RESTAPIURLConnection.RESTAPIURLModels.includes(settings.general.model)) { + try { + const response = await fetchRESTAPIURLDataEditor(settings, select); + const cursorStart = view.editor.getCursor("from"); + view.editor.replaceSelection(response); + const cursorEnd = { + line: cursorStart.line, + ch: cursorStart.ch + (response == null ? void 0 : response.length) + }; + view.editor.setSelection(cursorStart, cursorEnd); + } catch (error) { + new import_obsidian25.Notice("Error occurred while fetching completion: " + error.message); + console.log(error.message); + } + } else if (ANTHROPIC_MODELS.includes(settings.general.model)) { + try { + const response = await fetchAnthropicResponseEditor(settings, select); + view.editor.replaceSelection(response); + } catch (error) { + new import_obsidian25.Notice("Error occurred while fetching completion: " + error.message); + console.log(error.message); + } + } else if (settings.APIConnections.googleGemini.geminiModels.includes(settings.general.model)) { + try { + const response = await fetchGoogleGeminiDataEditor(settings, select); + const cursorStart = view.editor.getCursor("from"); + view.editor.replaceSelection(response); + const cursorEnd = { + line: cursorStart.line, + ch: cursorStart.ch + (response == null ? void 0 : response.length) + }; + view.editor.setSelection(cursorStart, cursorEnd); + } catch (error) { + new import_obsidian25.Notice("Error occurred while fetching completion: " + error.message); + console.log(error.message); + } + } else if (settings.APIConnections.mistral.mistralModels.includes(settings.general.model)) { + try { + const response = await fetchMistralDataEditor(settings, select); + const cursorStart = view.editor.getCursor("from"); + view.editor.replaceSelection(response); + const cursorEnd = { + line: cursorStart.line, + ch: cursorStart.ch + (response == null ? void 0 : response.length) + }; + view.editor.setSelection(cursorStart, cursorEnd); + } catch (error) { + new import_obsidian25.Notice("Error occurred while fetching completion: " + error.message); + console.log(error.message); + } + } else if (OPENAI_MODELS.includes(settings.general.model)) { + try { + const response = await fetchOpenAIBaseAPIResponseEditor(settings, select); + const cursorStart = view.editor.getCursor("from"); + view.editor.replaceSelection(response || ""); + const cursorEnd = { + line: cursorStart.line, + ch: cursorStart.ch + ((_a2 = response == null ? void 0 : response.length) != null ? _a2 : 0) + }; + view.editor.setSelection(cursorStart, cursorEnd); + } catch (error) { + new import_obsidian25.Notice("Error occurred while fetching completion: " + error.message); + console.log(error.message); + } + } else if (settings.APIConnections.openAI.openAIBaseUrl != DEFAULT_SETTINGS.APIConnections.openAI.openAIBaseUrl && settings.APIConnections.openAI.openAIBaseModels.includes(settings.general.model)) { + try { + const response = await fetchOpenAIBaseAPIResponseEditor(settings, select); + const cursorStart = view.editor.getCursor("from"); + view.editor.replaceSelection(response || ""); + const cursorEnd = { + line: cursorStart.line, + ch: cursorStart.ch + ((_b = response == null ? void 0 : response.length) != null ? _b : 0) + }; + view.editor.setSelection(cursorStart, cursorEnd); + } catch (error) { + new import_obsidian25.Notice("Error occurred while fetching completion: " + error.message); + console.log(error.message); + } + } else if (settings.APIConnections.openRouter.openRouterModels.includes(settings.general.model)) { + try { + const response = await fetchOpenRouterEditor(settings, select); + const cursorStart = view.editor.getCursor("from"); + view.editor.replaceSelection(response); + const cursorEnd = { + line: cursorStart.line, + ch: cursorStart.ch + (response == null ? void 0 : response.length) + }; + view.editor.setSelection(cursorStart, cursorEnd); + } catch (error) { + new import_obsidian25.Notice("Error occurred while fetching completion: " + error.message); + console.log(error.message); + } + } + generatingNotice.hide(); + new import_obsidian25.Notice("Generation complete."); + } else { + new import_obsidian25.Notice("No text selected."); + } +} + +// src/components/editor/BMOCodeBlockProcessor.ts +var import_obsidian26 = require("obsidian"); +function bmoCodeBlockProcessor(plugin, settings) { + let previousPrompt = ""; + let abortController2 = null; + return plugin.registerMarkdownCodeBlockProcessor("bmo", async (source, el, ctx) => { + if (abortController2) { + abortController2.abort(); + } + abortController2 = new AbortController(); + const file = plugin.app.workspace.getActiveFile(); + if (file && settings.general.model !== "") { + const fileContent = await plugin.app.vault.read(file); + const codeBlockRegex = /```bmo\n([\s\S]*?)```/g; + let match; + let updatedFileContent = fileContent; + while ((match = codeBlockRegex.exec(fileContent)) !== null) { + const originalCodeBlock = match[0]; + const codeBlockContent = match[1]; + if (!codeBlockContent.includes("MODEL ")) { + const updatedSource = "MODEL " + settings.general.model + "\n" + codeBlockContent; + updatedFileContent = updatedFileContent.replace(originalCodeBlock, "```bmo\n" + updatedSource + "```"); + } + } + if (updatedFileContent !== fileContent) { + await plugin.app.vault.modify(file, updatedFileContent); + } + } + let modelName = "No Model"; + let temperature = "1.0"; + let maxTokens = ""; + let contentToRender = ""; + const modelMatch = source.match(/MODEL\s+(.+)/); + if (modelMatch) { + modelName = modelMatch[1].trim(); + } + const temperatureMatch = source.match(/TEMPERATURE\s+(.+)/); + if (temperatureMatch) { + temperature = temperatureMatch[1].trim(); + } + const maxTokensMatch = source.match(/MAX_TOKENS\s+(.+)/); + if (maxTokensMatch) { + maxTokens = maxTokensMatch[1].trim(); + } + const promptMatch = source.match(/^(?:MODEL.*\n|TEMPERATURE.*\n|MAX_TOKENS.*\n)*([\s\S]*?)(?=\s*|$)/); + let prompt = ""; + if (promptMatch) { + prompt = promptMatch[1].trim(); + } + if (prompt !== previousPrompt) { + previousPrompt = prompt; + } + const responseMatch = source.match(/([\s\S]*?)<\/response>/); + if (responseMatch) { + contentToRender = responseMatch[1].trim(); + } + const container = el.createEl("div"); + container.style.position = "relative"; + const bmoCodeBlockContainer = container.createEl("div", { cls: "bmoCodeBlockContainer" }); + bmoCodeBlockContainer.dataset.callout = "chat"; + bmoCodeBlockContainer.style.backgroundColor = settings.appearance.bmoGenerateBackgroundColor; + bmoCodeBlockContainer.style.border = "1px solid #0a0f0a"; + bmoCodeBlockContainer.style.borderRadius = "5px"; + bmoCodeBlockContainer.style.padding = "10px"; + bmoCodeBlockContainer.style.marginBottom = "10px"; + const bmoCodeBlockContent = bmoCodeBlockContainer.createEl("div", { cls: "bmoCodeBlockContent" }); + bmoCodeBlockContent.style.color = settings.appearance.bmoGenerateFontColor; + bmoCodeBlockContent.style.whiteSpace = "normal"; + const bottomContainer = container.createEl("div"); + bottomContainer.style.display = "flex"; + bottomContainer.style.justifyContent = "space-between"; + bottomContainer.style.alignItems = "center"; + bottomContainer.style.marginTop = "10px"; + const modelText = bottomContainer.createEl("span"); + modelText.textContent = modelName; + modelText.style.fontSize = "0.9em"; + modelText.style.color = "#666"; + modelText.style.fontWeight = "bold"; + const loaderCircle = bottomContainer.createEl("div"); + loaderCircle.classList.add("loader-circle"); + loaderCircle.style.width = "20px"; + loaderCircle.style.height = "20px"; + loaderCircle.style.border = "2px solid #666"; + loaderCircle.style.borderTopColor = "transparent"; + loaderCircle.style.borderRadius = "50%"; + loaderCircle.style.animation = "spin 1s linear infinite"; + loaderCircle.style.display = "none"; + const bmoGenerationNotice = bottomContainer.createEl("span"); + bmoGenerationNotice.textContent = "Done!"; + bmoGenerationNotice.style.fontSize = "0.9em"; + bmoGenerationNotice.style.color = "#4caf50"; + bmoGenerationNotice.style.display = "none"; + const button = bottomContainer.createEl("button"); + button.textContent = "Generate"; + button.onclick = async () => { + if (button.textContent === "Cancel") { + if (abortController2) { + abortController2.abort(); + abortController2 = null; + } + button.textContent = "Generate"; + loaderCircle.style.display = "none"; + bmoGenerationNotice.textContent = "Aborted."; + bmoGenerationNotice.style.color = "#ff6666"; + bmoGenerationNotice.style.display = "inline"; + setTimeout(() => { + bmoGenerationNotice.style.display = "none"; + }, 2e3); + return; + } + button.textContent = "Cancel"; + if (!abortController2) { + abortController2 = new AbortController(); + } + const signal = abortController2.signal; + loaderCircle.style.display = "block"; + let modelResponse = ""; + try { + if (settings.OllamaConnection.ollamaModels.includes(modelName)) { + modelResponse = await fetchOllamaResponseEditor(settings, prompt, modelName, temperature, maxTokens, signal) || contentToRender; + } else if (settings.RESTAPIURLConnection.RESTAPIURLModels.includes(modelName)) { + modelResponse = await fetchRESTAPIURLDataEditor(settings, prompt, modelName, temperature, maxTokens, signal) || contentToRender; + } else if (settings.APIConnections.anthropic.anthropicModels.includes(modelName)) { + button.disabled = true; + modelResponse = await fetchAnthropicResponseEditor(settings, prompt, modelName, temperature, maxTokens, signal) || contentToRender; + } else if (settings.APIConnections.googleGemini.geminiModels.includes(modelName)) { + modelResponse = await fetchGoogleGeminiDataEditor(settings, prompt, modelName, temperature, maxTokens, signal) || contentToRender; + } else if (settings.APIConnections.mistral.mistralModels.includes(modelName)) { + modelResponse = await fetchMistralDataEditor(settings, prompt, modelName, temperature, maxTokens, signal) || contentToRender; + } else if (settings.APIConnections.openAI.openAIBaseModels.includes(modelName)) { + modelResponse = await fetchOpenAIBaseAPIResponseEditor(settings, prompt, modelName, temperature, maxTokens, signal) || contentToRender; + } else if (settings.APIConnections.openRouter.openRouterModels.includes(modelName)) { + modelResponse = await fetchOpenRouterEditor(settings, prompt, modelName, temperature, maxTokens, signal) || contentToRender; + } else { + bmoGenerationNotice.textContent = "Model not found."; + bmoGenerationNotice.style.color = "#ff6666"; + bmoGenerationNotice.style.display = "inline"; + setTimeout(() => { + bmoGenerationNotice.style.display = "none"; + button.textContent = "Generate"; + }, 2e3); + } + if (modelResponse !== "") { + if (!modelResponse.includes("\\`")) { + modelResponse = modelResponse.replace(/`/g, "\\`"); + } + const responseTagsExist = source.includes("") && source.includes(""); + let updatedSource = source; + if (responseTagsExist) { + updatedSource = source.replace( + /[\s\S]*?<\/response>/, + ` +${modelResponse} +` + ); + } else { + updatedSource = `${source} + + +${modelResponse} +`; + } + const newResponseMatch = updatedSource.match(/([\s\S]*?)<\/response>/); + if (newResponseMatch) { + contentToRender = newResponseMatch[1].trim(); + } + const file2 = plugin.app.workspace.getActiveFile(); + if (file2) { + const fileContent = await plugin.app.vault.read(file2); + const updatedFileContent = fileContent.replace(source, updatedSource); + await plugin.app.vault.modify(file2, updatedFileContent); + } + } + loaderCircle.style.display = "none"; + } catch (error) { + if (error.name === "AbortError") { + console.log("BMO Generate Aborted."); + button.textContent = "Generate"; + loaderCircle.style.display = "none"; + bmoGenerationNotice.textContent = "Aborted."; + bmoGenerationNotice.style.color = "#ff6666"; + bmoGenerationNotice.style.display = "inline"; + setTimeout(() => { + bmoGenerationNotice.style.display = "none"; + }, 2e3); + return; + } else { + console.error("Generation error:", error); + bmoGenerationNotice.textContent = "Error occurred."; + bmoGenerationNotice.style.color = "#ff6666"; + bmoGenerationNotice.style.display = "inline"; + setTimeout(() => { + bmoGenerationNotice.style.display = "none"; + }, 2e3); + } + } + }; + if (source.includes("") && source.includes("")) { + await import_obsidian26.MarkdownRenderer.render(plugin.app, contentToRender, bmoCodeBlockContent, "/", plugin); + } else { + await import_obsidian26.MarkdownRenderer.render(plugin.app, prompt, bmoCodeBlockContent, "/", plugin); + } + }); +} + +// src/main.ts +var DEFAULT_SETTINGS = { + profiles: { + profile: "BMO.md", + profileFolderPath: "BMO/Profiles", + lastLoadedChatHistoryPath: null, + lastLoadedChatHistory: [] + }, + general: { + model: "", + system_role: "You are a helpful assistant.", + max_tokens: "", + temperature: "1.00", + enableReferenceCurrentNote: false + }, + appearance: { + userName: "YOU", + chatbotName: "BMO", + chatbotContainerBackgroundColor: "--background-secondary", + messageContainerBackgroundColor: "--background-secondary", + userMessageFontColor: "--text-normal", + userMessageBackgroundColor: "--background-primary", + botMessageFontColor: "--text-normal", + botMessageBackgroundColor: "--background-secondary", + chatBoxFontColor: "--text-normal", + chatBoxBackgroundColor: "--interactive-accent", + enableHeader: true, + enableScrollBar: false, + bmoGenerateBackgroundColor: "#0c0a12", + bmoGenerateFontColor: "--text-normal" + }, + prompts: { + prompt: "", + promptFolderPath: "BMO/Prompts" + }, + editor: { + systen_role: "You are a helpful assistant." + }, + chatHistory: { + chatHistoryPath: "BMO/History", + templateFilePath: "", + allowRenameNoteTitle: false + }, + OllamaConnection: { + RESTAPIURL: "http://localhost:11434", + enableStream: true, + ollamaParameters: { + mirostat: "0", + mirostat_eta: "0.10", + mirostat_tau: "5.00", + num_ctx: "2048", + num_gqa: "", + num_thread: "", + repeat_last_n: "64", + repeat_penalty: "1.10", + seed: "", + stop: [], + tfs_z: "1.00", + top_k: "40", + top_p: "0.90", + min_p: "0.0", + keep_alive: "" + }, + ollamaModels: [] + }, + RESTAPIURLConnection: { + APIKey: "", + RESTAPIURL: "", + enableStream: false, + RESTAPIURLModels: [] + }, + APIConnections: { + anthropic: { + APIKey: "", + anthropicModels: [] + }, + googleGemini: { + APIKey: "", + enableStream: false, + geminiModels: [] + }, + mistral: { + APIKey: "", + enableStream: false, + mistralModels: [] + }, + openAI: { + APIKey: "", + openAIBaseUrl: "https://api.openai.com/v1", + enableStream: true, + openAIBaseModels: [] + }, + openRouter: { + APIKey: "", + enableStream: false, + openRouterModels: [] + } + }, + toggleGeneralSettings: true, + toggleAppearanceSettings: false, + togglePromptSettings: false, + toggleEditorSettings: false, + toggleChatHistorySettings: false, + toggleProfileSettings: false, + toggleAPIConnectionSettings: true, + toggleOpenAISettings: false, + toggleMistralSettings: false, + toggleGoogleGeminiSettings: false, + toggleAnthropicSettings: false, + toggleRESTAPIURLSettings: true, + toggleOpenRouterSettings: false, + toggleOllamaSettings: true, + toggleAdvancedSettings: false +}; +var checkActiveFile = null; +var BMOGPT15 = class extends import_obsidian27.Plugin { + async onload() { + await this.loadSettings(); + const folderPath = this.settings.profiles.profileFolderPath || DEFAULT_SETTINGS.profiles.profileFolderPath; + const defaultFilePath = `${folderPath}/${DEFAULT_SETTINGS.profiles.profile}`; + const defaultProfile = this.app.vault.getAbstractFileByPath(defaultFilePath); + if (!await this.app.vault.adapter.exists(folderPath)) { + await this.app.vault.createFolder(folderPath); + } + if (!await this.app.vault.adapter.exists(defaultFilePath)) { + this.app.vault.create(defaultFilePath, ""); + console.log("Default profile created."); + } + this.registerEvent( + this.app.vault.on("create", async (file) => { + if (file instanceof import_obsidian27.TFile && file.path.startsWith(folderPath)) { + const fileContent = await this.app.vault.read(file); + if (fileContent.trim() === "") { + defaultFrontMatter(this, file); + } + const profileFiles = this.app.vault.getFiles().filter((file2) => file2.path.startsWith(this.settings.profiles.profileFolderPath)); + profileFiles.sort((a, b) => a.name.localeCompare(b.name)); + if (this.settings.profiles.lastLoadedChatHistory.length === 0) { + profileFiles.forEach((profile, index2) => { + if (!this.settings.profiles.lastLoadedChatHistory[index2]) { + this.settings.profiles.lastLoadedChatHistory[index2] = null; + } + }); + } else { + if (this.settings.profiles.lastLoadedChatHistory.length !== profileFiles.length) { + const profileIndex = profileFiles.findIndex((profileFiles2) => profileFiles2.basename === file.basename); + this.settings.profiles.lastLoadedChatHistory.splice(profileIndex, 0, null); + } + } + await this.saveSettings(); + } + }) + ); + this.registerEvent( + this.app.vault.on( + "delete", + async (file) => { + const profileFiles = this.app.vault.getFiles().filter((file2) => file2.path.startsWith(this.settings.profiles.profileFolderPath)); + profileFiles.sort((a, b) => a.name.localeCompare(b.name)); + if (file instanceof import_obsidian27.TFile && file.path.startsWith(this.settings.chatHistory.chatHistoryPath)) { + const currentProfile = this.settings.profiles.profile.replace(/\.[^/.]+$/, ""); + const profileIndex = profileFiles.findIndex((file2) => file2.basename === currentProfile); + const currentIndex = this.settings.profiles.lastLoadedChatHistory.indexOf(file.path); + if (this.settings.profiles.lastLoadedChatHistory[currentIndex] === file.path) { + this.settings.profiles.lastLoadedChatHistory[currentIndex] = null; + } + if (profileIndex === currentIndex) { + this.settings.profiles.lastLoadedChatHistoryPath = null; + } + } + if (file instanceof import_obsidian27.TFile && file.path.startsWith(folderPath)) { + const filenameMessageHistory = "./.obsidian/plugins/bmo-chatbot/data/messageHistory_" + file.name.replace(".md", ".json"); + this.app.vault.adapter.remove(filenameMessageHistory); + const profileIndex = profileFiles.findIndex((profileFile) => profileFile.name > file.name); + this.settings.profiles.lastLoadedChatHistory.splice(profileIndex, 1); + if (file.path === defaultFilePath) { + this.settings = DEFAULT_SETTINGS; + this.app.vault.create(defaultFilePath, ""); + await updateSettingsFromFrontMatter(this, defaultProfile); + } else { + if (this.settings.profiles.profile === file.name) { + this.settings.profiles.profile = DEFAULT_SETTINGS.profiles.profile; + const profileFiles2 = this.app.vault.getFiles().filter((file2) => file2.path.startsWith(this.settings.profiles.profileFolderPath)); + profileFiles2.sort((a, b) => a.name.localeCompare(b.name)); + const currentProfile = this.settings.profiles.profile.replace(/\.[^/.]+$/, ""); + const profileIndex2 = profileFiles2.findIndex((file2) => file2.basename === currentProfile); + if (this.settings.profiles.lastLoadedChatHistoryPath !== null) { + this.settings.profiles.lastLoadedChatHistoryPath = this.settings.profiles.lastLoadedChatHistory[profileIndex2]; + } + const fileContent = (await this.app.vault.read(defaultProfile)).replace(/^---\s*[\s\S]*?---/, "").trim(); + this.settings.general.system_role = fileContent; + await updateSettingsFromFrontMatter(this, defaultProfile); + } + } + } + await this.saveSettings(); + } + ) + ); + this.registerEvent( + this.app.vault.on( + "modify", + async (file) => { + const currentProfilePath = `${folderPath}/${this.settings.profiles.profile}`; + if (file.path === currentProfilePath) { + await updateSettingsFromFrontMatter(this, file); + const fileContent = (await this.app.vault.read(file)).replace(/^---\s*[\s\S]*?---/, "").trim(); + this.settings.general.system_role = fileContent; + await this.saveSettings(); + } + } + ) + ); + this.registerEvent( + this.app.vault.on("rename", async (file, oldPath) => { + try { + const currentProfilePath = `${folderPath}/${this.settings.profiles.profile}`; + if (oldPath === currentProfilePath) { + this.settings.profiles.profile = file.name; + this.settings.appearance.chatbotName = file.basename; + await this.saveSettings(); + } + if (file instanceof import_obsidian27.TFile && file.path.startsWith(folderPath)) { + const filenameMessageHistoryPath = "./.obsidian/plugins/bmo-chatbot/data/"; + const oldProfileMessageHistory = "messageHistory_" + oldPath.replace(folderPath + "/", "").replace(".md", ".json"); + await this.app.vault.adapter.rename(filenameMessageHistoryPath + oldProfileMessageHistory, filenameMessageHistoryPath + "messageHistory_" + file.name.replace(".md", ".json")).catch((error) => { + console.error("Error handling rename event:", error); + }); + await this.app.vault.adapter.remove(filenameMessageHistoryPath + oldProfileMessageHistory); + } + } catch (error) { + if (error.message.includes("ENOENT: no such file or directory, unlink")) { + } else { + console.error("Error handling rename event:", error); + } + } + const profileFiles = this.app.vault.getFiles().filter((file2) => file2.path.startsWith(this.settings.profiles.profileFolderPath)); + profileFiles.sort((a, b) => a.name.localeCompare(b.name)); + const currentIndex = profileFiles.findIndex((profileFile) => profileFile.path === file.path); + const prevFileName = oldPath.replace(folderPath + "/", ""); + const updatedProfileFiles = [...profileFiles, { name: prevFileName }]; + updatedProfileFiles.sort((a, b) => a.name.localeCompare(b.name)); + const fileIndex = updatedProfileFiles.findIndex((profileFile) => profileFile.name === file.name); + if (fileIndex !== -1) { + updatedProfileFiles.splice(fileIndex, 1); + } + const prevIndex = updatedProfileFiles.findIndex((profileFile) => profileFile.name === prevFileName); + if (currentIndex !== -1) { + const [removed] = this.settings.profiles.lastLoadedChatHistory.splice(prevIndex, 1); + this.settings.profiles.lastLoadedChatHistory.splice(currentIndex, 0, removed); + } + const currentProfile = this.settings.profiles.profile.replace(/\.[^/.]+$/, ""); + const profileIndex = profileFiles.findIndex((file2) => file2.basename === currentProfile); + const index2 = this.settings.profiles.lastLoadedChatHistory.indexOf(oldPath); + if (this.settings.profiles.lastLoadedChatHistory[profileIndex] === oldPath) { + this.settings.profiles.lastLoadedChatHistory[index2] = file.path; + this.settings.profiles.lastLoadedChatHistoryPath = file.path; + } else if (this.settings.profiles.lastLoadedChatHistory[index2] === oldPath) { + this.settings.profiles.lastLoadedChatHistory[index2] = file.path; + } + await this.saveSettings(); + }) + ); + this.registerEvent( + this.app.workspace.on("active-leaf-change", () => { + this.handleFileSwitch(); + }) + ); + this.registerView( + VIEW_TYPE_CHATBOT, + (leaf) => new BMOView(leaf, this.settings, this) + ); + this.addRibbonIcon("bot", "BMO Chatbot", () => { + this.activateView(); + }); + this.addCommand({ + id: "open-bmo-chatbot", + name: "Open BMO Chatbot", + callback: () => { + this.activateView(); + }, + hotkeys: [ + { + modifiers: ["Mod"], + key: "0" + } + ] + }); + this.addCommand({ + id: "rename-note-title", + name: "Rename Note Title", + callback: () => { + renameTitleCommand(this, this.settings); + }, + hotkeys: [ + { + modifiers: ["Mod"], + key: "'" + } + ] + }); + this.registerEvent( + this.app.workspace.on("file-menu", (menu, file) => { + if (!(file instanceof import_obsidian27.TFile)) { + return; + } + menu.addItem((item) => { + item.setTitle("BMO Chatbot: Generate new title").onClick(() => renameTitleCommand(this, this.settings)); + }); + }) + ); + this.addCommand({ + id: "prompt-select-generate", + name: "Prompt Select Generate", + callback: () => { + promptSelectGenerateCommand(this, this.settings); + }, + hotkeys: [ + { + modifiers: ["Mod", "Shift"], + key: "=" + } + ] + }); + bmoCodeBlockProcessor(this, this.settings); + this.addSettingTab(new BMOSettingTab(this.app, this)); + } + handleFileSwitch() { + checkActiveFile = this.app.workspace.getActiveFile(); + } + async onunload() { + this.app.workspace.getLeavesOfType(VIEW_TYPE_CHATBOT).forEach((leaf) => { + const bmoView = leaf.view; + if (bmoView) { + this.saveSettings(); + } + }); + } + async activateView() { + this.app.workspace.detachLeavesOfType(VIEW_TYPE_CHATBOT); + const rightLeaf = this.app.workspace.getRightLeaf(false); + await (rightLeaf == null ? void 0 : rightLeaf.setViewState({ + type: VIEW_TYPE_CHATBOT, + active: true + })); + this.app.workspace.revealLeaf( + this.app.workspace.getLeavesOfType(VIEW_TYPE_CHATBOT)[0] + ); + const textarea = document.querySelector(".chatbox textarea"); + if (textarea) { + textarea.style.opacity = "0"; + textarea.style.transition = "opacity 1s ease-in-out"; + setTimeout(() => { + textarea.focus(); + textarea.style.opacity = "1"; + }, 50); + } + this.app.workspace.revealLeaf( + this.app.workspace.getLeavesOfType(VIEW_TYPE_CHATBOT)[0] + ); + const messageContainer = document.querySelector("#messageContainer"); + if (messageContainer) { + messageContainer.scroll({ + top: messageContainer.scrollHeight, + behavior: "smooth" + }); + } + } + async loadSettings() { + this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + } + async saveSettings() { + const currentProfileFile = `${this.settings.profiles.profileFolderPath}/${this.settings.profiles.profile}`; + const currentProfile = this.app.vault.getAbstractFileByPath(currentProfileFile); + updateFrontMatter(this, currentProfile); + const header = document.querySelector("#header"); + const modelOptions = header == null ? void 0 : header.querySelector("#modelOptions"); + if (modelOptions) { + modelOptions.remove(); + } + const populateModelOptions = populateModelDropdown(this, this.settings); + header == null ? void 0 : header.appendChild(populateModelOptions); + await this.saveData(this.settings); + } +}; +async function defaultFrontMatter(plugin, file) { + const setDefaultFrontMatter = async (frontmatter) => { + frontmatter.model = DEFAULT_SETTINGS.general.model; + frontmatter.max_tokens = parseInt(DEFAULT_SETTINGS.general.max_tokens); + frontmatter.temperature = parseFloat(DEFAULT_SETTINGS.general.temperature); + frontmatter.enable_reference_current_note = DEFAULT_SETTINGS.general.enableReferenceCurrentNote; + frontmatter.prompt = DEFAULT_SETTINGS.prompts.prompt; + frontmatter.user_name = DEFAULT_SETTINGS.appearance.userName; + frontmatter.enable_header = DEFAULT_SETTINGS.appearance.enableHeader; + frontmatter.chatbot_container_background_color = DEFAULT_SETTINGS.appearance.chatbotContainerBackgroundColor.replace(/^#/, ""); + frontmatter.message_container_background_color = DEFAULT_SETTINGS.appearance.messageContainerBackgroundColor.replace(/^#/, ""); + frontmatter.user_message_font_color = DEFAULT_SETTINGS.appearance.userMessageFontColor.replace(/^#/, ""); + frontmatter.user_message_background_color = DEFAULT_SETTINGS.appearance.userMessageBackgroundColor.replace(/^#/, ""); + frontmatter.bot_message_font_color = DEFAULT_SETTINGS.appearance.botMessageFontColor.replace(/^#/, ""); + frontmatter.chatbot_message_background_color = DEFAULT_SETTINGS.appearance.botMessageBackgroundColor.replace(/^#/, ""); + frontmatter.chatbox_font_color = DEFAULT_SETTINGS.appearance.chatBoxFontColor.replace(/^#/, ""); + frontmatter.chatbox_background_color = DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor.replace(/^#/, ""); + frontmatter.bmo_generate_background_color = DEFAULT_SETTINGS.appearance.bmoGenerateBackgroundColor.replace(/^#/, ""); + frontmatter.bmo_generate_font_color = DEFAULT_SETTINGS.appearance.bmoGenerateFontColor.replace(/^#/, ""); + frontmatter.systen_role = DEFAULT_SETTINGS.editor.systen_role; + frontmatter.ollama_mirostat = parseFloat(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat); + frontmatter.ollama_mirostat_eta = parseFloat(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat_eta); + frontmatter.ollama_mirostat_tau = parseFloat(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat_tau); + frontmatter.ollama_num_ctx = parseInt(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_ctx); + frontmatter.ollama_num_gqa = parseInt(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_gqa); + frontmatter.ollama_num_thread = parseInt(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_thread); + frontmatter.ollama_repeat_last_n = parseInt(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.repeat_last_n); + frontmatter.ollama_repeat_penalty = parseFloat(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.repeat_penalty); + frontmatter.ollama_seed = parseInt(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.seed); + frontmatter.ollama_stop = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.stop; + frontmatter.ollama_tfs_z = parseFloat(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.tfs_z); + frontmatter.ollama_top_k = parseInt(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.top_k); + frontmatter.ollama_top_p = parseFloat(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.top_p); + frontmatter.ollama_min_p = parseFloat(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.min_p); + frontmatter.ollama_keep_alive = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.keep_alive; + }; + const writeOptions = { + // Specify options if needed + }; + try { + await plugin.app.fileManager.processFrontMatter(file, setDefaultFrontMatter, writeOptions); + } catch (error) { + console.error("Error processing frontmatter:", error); + } + plugin.app.vault.append(file, DEFAULT_SETTINGS.general.system_role); +} +async function updateSettingsFromFrontMatter(plugin, file) { + const updateSettings = async (frontmatter) => { + plugin.settings.general.model = frontmatter.model; + plugin.settings.general.max_tokens = frontmatter.max_tokens; + plugin.settings.general.temperature = frontmatter.temperature; + plugin.settings.general.enableReferenceCurrentNote = frontmatter.enable_reference_current_note; + plugin.settings.prompts.prompt = frontmatter.prompt; + plugin.settings.appearance.userName = frontmatter.user_name; + plugin.settings.appearance.chatbotName = file.basename; + plugin.settings.appearance.enableHeader = frontmatter.enable_header; + plugin.settings.appearance.chatbotContainerBackgroundColor = "#" + frontmatter.chatbot_container_background_color; + plugin.settings.appearance.messageContainerBackgroundColor = "#" + frontmatter.message_container_background_color; + plugin.settings.appearance.userMessageFontColor = "#" + frontmatter.user_message_font_color; + plugin.settings.appearance.userMessageBackgroundColor = "#" + frontmatter.user_message_background_color; + plugin.settings.appearance.botMessageFontColor = "#" + frontmatter.bot_message_font_color; + plugin.settings.appearance.botMessageBackgroundColor = "#" + frontmatter.chatbot_message_background_color; + plugin.settings.appearance.chatBoxFontColor = "#" + frontmatter.chatbox_font_color; + plugin.settings.appearance.chatBoxBackgroundColor = "#" + frontmatter.chatbox_background_color; + plugin.settings.appearance.bmoGenerateBackgroundColor = "#" + frontmatter.bmo_generate_background_color; + plugin.settings.appearance.bmoGenerateFontColor = "#" + frontmatter.bmo_generate_font_color; + plugin.settings.editor.systen_role = frontmatter.systen_role; + plugin.settings.OllamaConnection.ollamaParameters.mirostat = frontmatter.ollama_mirostat; + plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta = frontmatter.ollama_mirostat_eta; + plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau = frontmatter.ollama_mirostat_tau; + plugin.settings.OllamaConnection.ollamaParameters.num_ctx = frontmatter.ollama_num_ctx; + plugin.settings.OllamaConnection.ollamaParameters.num_gqa = frontmatter.ollama_num_gqa; + plugin.settings.OllamaConnection.ollamaParameters.num_thread = frontmatter.ollama_num_thread; + plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n = frontmatter.ollama_repeat_last_n; + plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty = frontmatter.ollama_repeat_penalty; + plugin.settings.OllamaConnection.ollamaParameters.seed = frontmatter.ollama_seed; + plugin.settings.OllamaConnection.ollamaParameters.stop = frontmatter.ollama_stop; + plugin.settings.OllamaConnection.ollamaParameters.tfs_z = frontmatter.ollama_tfs_z; + plugin.settings.OllamaConnection.ollamaParameters.top_k = frontmatter.ollama_top_k; + plugin.settings.OllamaConnection.ollamaParameters.top_p = frontmatter.ollama_top_p; + plugin.settings.OllamaConnection.ollamaParameters.min_p = frontmatter.ollama_min_p; + plugin.settings.OllamaConnection.ollamaParameters.keep_alive = frontmatter.ollama_keep_alive; + }; + const writeOptions = { + // Specify options if needed + }; + try { + await plugin.app.fileManager.processFrontMatter(file, updateSettings, writeOptions); + const fileContent = (await plugin.app.vault.read(file)).replace(/^---\s*[\s\S]*?---/, "").trim(); + plugin.settings.general.system_role = fileContent; + updateProfile(plugin, file); + } catch (error) { + console.error("Error processing frontmatter:", error); + } +} +async function updateFrontMatter(plugin, file) { + const modifyFrontMatter = async (frontmatter) => { + frontmatter.model = plugin.settings.general.model; + frontmatter.max_tokens = parseInt(plugin.settings.general.max_tokens); + frontmatter.temperature = parseFloat(plugin.settings.general.temperature); + frontmatter.enable_reference_current_note = plugin.settings.general.enableReferenceCurrentNote; + frontmatter.prompt = plugin.settings.prompts.prompt.replace(".md", ""); + frontmatter.user_name = plugin.settings.appearance.userName; + frontmatter.enable_header = plugin.settings.appearance.enableHeader; + frontmatter.chatbot_container_background_color = plugin.settings.appearance.chatbotContainerBackgroundColor.replace(/^#/, ""); + frontmatter.message_container_background_color = plugin.settings.appearance.messageContainerBackgroundColor.replace(/^#/, ""); + frontmatter.user_message_font_color = plugin.settings.appearance.userMessageFontColor.replace(/^#/, ""); + frontmatter.user_message_background_color = plugin.settings.appearance.userMessageBackgroundColor.replace(/^#/, ""); + frontmatter.bot_message_font_color = plugin.settings.appearance.botMessageFontColor.replace(/^#/, ""); + frontmatter.chatbot_message_background_color = plugin.settings.appearance.botMessageBackgroundColor.replace(/^#/, ""); + frontmatter.chatbox_font_color = plugin.settings.appearance.chatBoxFontColor.replace(/^#/, ""); + frontmatter.chatbox_background_color = plugin.settings.appearance.chatBoxBackgroundColor.replace(/^#/, ""); + frontmatter.bmo_generate_background_color = plugin.settings.appearance.bmoGenerateBackgroundColor.replace(/^#/, ""); + frontmatter.bmo_generate_font_color = plugin.settings.appearance.bmoGenerateFontColor.replace(/^#/, ""); + frontmatter.systen_role = plugin.settings.editor.systen_role; + frontmatter.ollama_mirostat = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.mirostat); + frontmatter.ollama_mirostat_eta = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta); + frontmatter.ollama_mirostat_tau = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau); + frontmatter.ollama_num_ctx = parseInt(plugin.settings.OllamaConnection.ollamaParameters.num_ctx); + frontmatter.ollama_num_gqa = parseInt(plugin.settings.OllamaConnection.ollamaParameters.num_gqa); + frontmatter.ollama_num_thread = parseInt(plugin.settings.OllamaConnection.ollamaParameters.num_thread); + frontmatter.ollama_repeat_last_n = parseInt(plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n); + frontmatter.ollama_repeat_penalty = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty); + frontmatter.ollama_seed = parseInt(plugin.settings.OllamaConnection.ollamaParameters.seed); + frontmatter.ollama_stop = plugin.settings.OllamaConnection.ollamaParameters.stop; + frontmatter.ollama_tfs_z = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.tfs_z); + frontmatter.ollama_top_k = parseInt(plugin.settings.OllamaConnection.ollamaParameters.top_k); + frontmatter.ollama_top_p = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.top_p); + frontmatter.ollama_min_p = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.min_p); + frontmatter.ollama_keep_alive = plugin.settings.OllamaConnection.ollamaParameters.keep_alive; + }; + const writeOptions = { + // Specify options if needed + }; + try { + await plugin.app.fileManager.processFrontMatter(file, modifyFrontMatter, writeOptions); + updateProfile(plugin, file); + } catch (error) { + console.error("Error processing frontmatter:", error); + } +} +async function updateProfile(plugin, file) { + try { + await plugin.app.fileManager.processFrontMatter(file, (frontmatter) => { + plugin.settings.general.model = frontmatter.model || DEFAULT_SETTINGS.general.model; + if (frontmatter.max_tokens) { + plugin.settings.general.max_tokens = frontmatter.max_tokens.toString(); + frontmatter.max_tokens = parseInt(plugin.settings.general.max_tokens); + } else { + plugin.settings.general.max_tokens = DEFAULT_SETTINGS.general.max_tokens; + } + if (frontmatter.temperature) { + if (frontmatter.temperature < 0) { + frontmatter.temperature = "0.00"; + } else if (frontmatter.temperature > 2) { + frontmatter.temperature = "2.00"; + } else { + plugin.settings.general.temperature = parseFloat(frontmatter.temperature).toFixed(2).toString(); + frontmatter.temperature = parseFloat(plugin.settings.general.temperature); + } + } else { + plugin.settings.general.temperature = DEFAULT_SETTINGS.general.temperature; + frontmatter.temperature = DEFAULT_SETTINGS.general.temperature; + } + plugin.settings.general.enableReferenceCurrentNote = frontmatter.enable_reference_current_note; + const referenceCurrentNoteElement = document.getElementById("referenceCurrentNote"); + if (referenceCurrentNoteElement) { + if (frontmatter.enable_reference_current_note === true) { + referenceCurrentNoteElement.style.display = "block"; + } else { + referenceCurrentNoteElement.style.display = "none"; + } + } + if (frontmatter.prompt && frontmatter.prompt !== "") { + plugin.settings.prompts.prompt = frontmatter.prompt + ".md"; + } else { + plugin.settings.prompts.prompt = DEFAULT_SETTINGS.prompts.prompt; + } + if (frontmatter.user_name) { + plugin.settings.appearance.userName = frontmatter.user_name.substring(0, 30); + } else { + plugin.settings.appearance.userName = DEFAULT_SETTINGS.appearance.userName; + } + frontmatter.user_name = plugin.settings.appearance.userName; + const userNames = document.querySelectorAll(".userName"); + userNames.forEach((userName) => { + userName.textContent = plugin.settings.appearance.userName; + }); + const chatbotNameHeading = document.querySelector("#chatbotNameHeading"); + const chatbotNames = document.querySelectorAll(".chatbotName"); + if (chatbotNameHeading) { + chatbotNameHeading.textContent = plugin.settings.appearance.chatbotName; + } + chatbotNames.forEach((chatbotName) => { + chatbotName.textContent = plugin.settings.appearance.chatbotName; + }); + const chatbotContainer = document.querySelector(".chatbotContainer"); + const messageContainer = document.querySelector("#messageContainer"); + if (isValidHexColor(frontmatter.chatbot_container_background_color)) { + plugin.settings.appearance.chatbotContainerBackgroundColor = "#" + frontmatter.chatbot_container_background_color.substring(0, 6); + if (chatbotContainer) { + chatbotContainer.style.backgroundColor = plugin.settings.appearance.chatbotContainerBackgroundColor; + } + } else { + plugin.settings.appearance.chatbotContainerBackgroundColor = colorToHex(DEFAULT_SETTINGS.appearance.chatbotContainerBackgroundColor); + frontmatter.chatbot_container_background_color = plugin.settings.appearance.chatbotContainerBackgroundColor.replace(/^#/, ""); + if (chatbotContainer) { + const defaultChatbotContainerBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.chatbotContainerBackgroundColor).trim(); + chatbotContainer.style.backgroundColor = defaultChatbotContainerBackgroundColor; + } + } + if (isValidHexColor(frontmatter.message_container_background_color)) { + plugin.settings.appearance.messageContainerBackgroundColor = "#" + frontmatter.message_container_background_color.substring(0, 6); + if (messageContainer) { + messageContainer.style.backgroundColor = plugin.settings.appearance.messageContainerBackgroundColor; + } + } else { + plugin.settings.appearance.messageContainerBackgroundColor = colorToHex(DEFAULT_SETTINGS.appearance.messageContainerBackgroundColor); + frontmatter.message_container_background_color = plugin.settings.appearance.messageContainerBackgroundColor.replace(/^#/, ""); + if (messageContainer) { + const defaultMessageContainerBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.messageContainerBackgroundColor).trim(); + messageContainer.style.backgroundColor = defaultMessageContainerBackgroundColor; + } + } + if (isValidHexColor(frontmatter.user_message_font_color)) { + plugin.settings.appearance.userMessageFontColor = "#" + frontmatter.user_message_font_color.substring(0, 6); + if (messageContainer) { + const userMessages = messageContainer.querySelectorAll(".userMessage"); + userMessages.forEach((userMessage) => { + const element = userMessage; + element.style.color = plugin.settings.appearance.userMessageFontColor; + }); + } + } else { + plugin.settings.appearance.userMessageFontColor = colorToHex(DEFAULT_SETTINGS.appearance.userMessageFontColor); + frontmatter.user_message_font_color = plugin.settings.appearance.userMessageFontColor.replace(/^#/, ""); + if (messageContainer) { + const userMessages = messageContainer.querySelectorAll(".userMessage"); + userMessages.forEach((userMessage) => { + const element = userMessage; + const defaultUserMessageFontColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.userMessageFontColor).trim(); + element.style.color = defaultUserMessageFontColor; + }); + } + } + if (isValidHexColor(frontmatter.user_message_background_color)) { + plugin.settings.appearance.userMessageBackgroundColor = "#" + frontmatter.user_message_background_color.substring(0, 6); + if (messageContainer) { + const userMessages = messageContainer.querySelectorAll(".userMessage"); + userMessages.forEach((userMessage) => { + const element = userMessage; + element.style.backgroundColor = plugin.settings.appearance.userMessageBackgroundColor; + }); + } + } else { + plugin.settings.appearance.userMessageBackgroundColor = colorToHex(DEFAULT_SETTINGS.appearance.userMessageBackgroundColor); + frontmatter.user_message_background_color = plugin.settings.appearance.userMessageBackgroundColor.replace(/^#/, ""); + if (messageContainer) { + const userMessages = messageContainer.querySelectorAll(".userMessage"); + userMessages.forEach((userMessage) => { + const element = userMessage; + const defaultUserMessageBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.userMessageBackgroundColor).trim(); + element.style.backgroundColor = defaultUserMessageBackgroundColor; + }); + } + } + if (isValidHexColor(frontmatter.bot_message_font_color)) { + plugin.settings.appearance.botMessageFontColor = "#" + frontmatter.bot_message_font_color.substring(0, 6); + if (messageContainer) { + const botMessages = messageContainer.querySelectorAll(".botMessage"); + botMessages.forEach((botMessage) => { + const element = botMessage; + element.style.color = plugin.settings.appearance.botMessageFontColor; + }); + } + } else { + plugin.settings.appearance.botMessageFontColor = colorToHex(DEFAULT_SETTINGS.appearance.botMessageFontColor); + frontmatter.bot_message_font_color = plugin.settings.appearance.botMessageFontColor.replace(/^#/, ""); + if (messageContainer) { + const botMessages = messageContainer.querySelectorAll(".botMessage"); + botMessages.forEach((botMessage) => { + const element = botMessage; + const defaultBotMessageFontColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageFontColor).trim(); + element.style.color = defaultBotMessageFontColor; + }); + } + } + if (isValidHexColor(frontmatter.chatbot_message_background_color)) { + plugin.settings.appearance.botMessageBackgroundColor = "#" + frontmatter.chatbot_message_background_color.substring(0, 6); + if (messageContainer) { + const botMessages = messageContainer.querySelectorAll(".botMessage"); + botMessages.forEach((botMessage) => { + const element = botMessage; + element.style.backgroundColor = plugin.settings.appearance.botMessageBackgroundColor; + }); + } + } else { + plugin.settings.appearance.botMessageBackgroundColor = colorToHex(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor); + frontmatter.chatbot_message_background_color = plugin.settings.appearance.botMessageBackgroundColor.replace(/^#/, ""); + if (messageContainer) { + const botMessages = messageContainer.querySelectorAll(".botMessage"); + botMessages.forEach((botMessage) => { + const element = botMessage; + const defaultBotMessageBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor).trim(); + element.style.backgroundColor = defaultBotMessageBackgroundColor; + }); + } + } + if (isValidHexColor(frontmatter.chatbox_font_color)) { + plugin.settings.appearance.chatBoxFontColor = "#" + frontmatter.chatbox_font_color.substring(0, 6); + const textarea = document.querySelector(".chatbox textarea"); + if (textarea) { + textarea.style.color = plugin.settings.appearance.chatBoxFontColor; + const style = document.createElement("style"); + style.textContent = ` + .chatbox textarea::placeholder { + color: ${plugin.settings.appearance.chatBoxFontColor} !important; + } + `; + textarea.appendChild(style); + } + } else { + plugin.settings.appearance.chatBoxFontColor = colorToHex(DEFAULT_SETTINGS.appearance.chatBoxFontColor); + frontmatter.chatbox_font_color = plugin.settings.appearance.chatBoxFontColor.replace(/^#/, ""); + const textarea = document.querySelector(".chatbox textarea"); + const defaultChatBoxFontColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.chatBoxFontColor).trim(); + if (textarea) { + textarea.style.color = DEFAULT_SETTINGS.appearance.chatBoxFontColor; + const style = document.createElement("style"); + style.textContent = ` + .chatbox textarea::placeholder { + color: ${defaultChatBoxFontColor} !important; + } + `; + textarea.appendChild(style); + } + } + if (isValidHexColor(frontmatter.chatbox_background_color)) { + plugin.settings.appearance.chatBoxBackgroundColor = "#" + frontmatter.chatbox_background_color.substring(0, 6); + if (messageContainer) { + const chatbox = document.querySelector(".chatbox"); + if (chatbox) { + const element = chatbox; + element.style.backgroundColor = plugin.settings.appearance.chatBoxBackgroundColor; + element.style.borderColor = plugin.settings.appearance.chatBoxBackgroundColor; + } + const textarea = document.querySelector(".chatbox textarea"); + if (textarea) { + const element = textarea; + element.style.backgroundColor = plugin.settings.appearance.chatBoxBackgroundColor; + element.style.borderColor = plugin.settings.appearance.chatBoxBackgroundColor; + } + const submitButton = document.querySelector(".chatbox .submit-button"); + if (submitButton) { + const element = submitButton; + element.style.backgroundColor = plugin.settings.appearance.chatBoxBackgroundColor; + element.style.borderColor = plugin.settings.appearance.chatBoxBackgroundColor; + } + } + } else { + plugin.settings.appearance.chatBoxBackgroundColor = DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor; + frontmatter.chatbox_background_color = DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor.replace(/^#/, ""); + const defaultChatBoxBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor).trim(); + if (messageContainer) { + const chatbox = document.querySelector(".chatbox"); + if (chatbox) { + const element = chatbox; + element.style.backgroundColor = defaultChatBoxBackgroundColor; + element.style.borderColor = defaultChatBoxBackgroundColor; + } + const textarea = document.querySelector(".chatbox textarea"); + if (textarea) { + const element = textarea; + element.style.backgroundColor = defaultChatBoxBackgroundColor; + element.style.borderColor = defaultChatBoxBackgroundColor; + } + const submitButton = document.querySelector(".chatbox .submit-button"); + if (submitButton) { + const element = submitButton; + element.style.backgroundColor = defaultChatBoxBackgroundColor; + element.style.borderColor = defaultChatBoxBackgroundColor; + } + } + } + if (isValidHexColor(frontmatter.bmo_generate_background_color)) { + plugin.settings.appearance.bmoGenerateBackgroundColor = "#" + frontmatter.bmo_generate_background_color.substring(0, 6); + const containers = document.querySelectorAll(".bmoCodeBlockContainer"); + containers.forEach((container) => { + const element = container; + element.style.backgroundColor = plugin.settings.appearance.bmoGenerateBackgroundColor; + }); + } else { + plugin.settings.appearance.bmoGenerateBackgroundColor = colorToHex(DEFAULT_SETTINGS.appearance.bmoGenerateBackgroundColor); + frontmatter.bmo_generate_background_color = plugin.settings.appearance.bmoGenerateBackgroundColor.replace(/^#/, ""); + const containers = document.querySelectorAll(".bmoCodeBlockContainer"); + containers.forEach((container) => { + const element = container; + const defaultBMOGenerateBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.bmoGenerateBackgroundColor).trim(); + element.style.backgroundColor = defaultBMOGenerateBackgroundColor; + }); + } + if (isValidHexColor(frontmatter.bmo_generate_font_color)) { + plugin.settings.appearance.bmoGenerateFontColor = "#" + frontmatter.bmo_generate_font_color.substring(0, 6); + const containers = document.querySelectorAll(".bmoCodeBlockContent"); + containers.forEach((container) => { + const element = container; + element.style.color = plugin.settings.appearance.bmoGenerateFontColor; + }); + } else { + plugin.settings.appearance.bmoGenerateFontColor = colorToHex(DEFAULT_SETTINGS.appearance.bmoGenerateFontColor); + frontmatter.bmo_generate_font_color = plugin.settings.appearance.bmoGenerateFontColor.replace(/^#/, ""); + const containers = document.querySelectorAll(".bmoCodeBlockContent"); + containers.forEach((container) => { + const element = container; + const defaultBMOGenerateFontColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.bmoGenerateFontColor).trim(); + element.style.color = defaultBMOGenerateFontColor; + }); + } + plugin.settings.editor.systen_role = frontmatter.systen_role; + plugin.settings.appearance.enableHeader = frontmatter.enable_header; + if (frontmatter.enable_header === true) { + const header = document.querySelector("#header"); + if (header) { + header.style.display = "block"; + referenceCurrentNoteElement.style.margin = "-0.5rem 0 0.5rem 0"; + } + } else { + const header = document.querySelector("#header"); + const messageContainer2 = document.querySelector("#messageContainer"); + if (header) { + header.style.display = "none"; + messageContainer2.style.maxHeight = "calc(100% - 60px)"; + referenceCurrentNoteElement.style.margin = "0.5rem 0 0.5rem 0"; + } + } + const intValue = parseInt(frontmatter.ollama_mirostat, 10); + if (isNaN(intValue)) { + plugin.settings.OllamaConnection.ollamaParameters.mirostat = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat; + frontmatter.ollama_mirostat = plugin.settings.OllamaConnection.ollamaParameters.mirostat; + } else { + plugin.settings.OllamaConnection.ollamaParameters.mirostat = intValue.toString(); + frontmatter.ollama_mirostat = intValue; + } + if (isNaN(parseFloat(frontmatter.ollama_mirostat_eta))) { + plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat_eta; + frontmatter.ollama_mirostat_eta = plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta; + } else { + plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta = parseFloat(frontmatter.ollama_mirostat_eta).toFixed(2).toString(); + frontmatter.ollama_mirostat_eta = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta); + } + if (isNaN(parseFloat(frontmatter.ollama_mirostat_tau))) { + plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat_tau; + frontmatter.ollama_mirostat_tau = plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau; + } else { + plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau = parseFloat(frontmatter.ollama_mirostat_tau).toFixed(2).toString(); + frontmatter.ollama_mirostat_tau = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau); + } + if (isNaN(parseInt(frontmatter.ollama_num_ctx))) { + plugin.settings.OllamaConnection.ollamaParameters.num_ctx = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_ctx; + frontmatter.ollama_num_ctx = plugin.settings.OllamaConnection.ollamaParameters.num_ctx; + } else { + plugin.settings.OllamaConnection.ollamaParameters.num_ctx = parseInt(frontmatter.ollama_num_ctx).toString(); + frontmatter.ollama_num_ctx = parseInt(plugin.settings.OllamaConnection.ollamaParameters.num_ctx); + } + if (isNaN(parseInt(frontmatter.ollama_num_gqa))) { + plugin.settings.OllamaConnection.ollamaParameters.num_gqa = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_gqa; + } else { + plugin.settings.OllamaConnection.ollamaParameters.num_gqa = parseInt(frontmatter.ollama_num_gqa).toString(); + frontmatter.ollama_num_gqa = parseInt(plugin.settings.OllamaConnection.ollamaParameters.num_gqa); + } + if (isNaN(parseInt(frontmatter.ollama_num_thread))) { + plugin.settings.OllamaConnection.ollamaParameters.num_thread = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_thread; + } else { + plugin.settings.OllamaConnection.ollamaParameters.num_thread = parseInt(frontmatter.ollama_num_thread).toString(); + frontmatter.ollama_num_thread = parseInt(plugin.settings.OllamaConnection.ollamaParameters.num_thread); + } + if (isNaN(parseInt(frontmatter.ollama_repeat_last_n))) { + plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.repeat_last_n; + frontmatter.ollama_repeat_last_n = plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n; + } else { + plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n = parseInt(frontmatter.ollama_repeat_last_n).toString(); + frontmatter.ollama_repeat_last_n = parseInt(plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n); + } + if (isNaN(parseFloat(frontmatter.ollama_repeat_penalty))) { + plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.repeat_penalty; + frontmatter.ollama_repeat_penalty = plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty; + } else { + plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty = parseFloat(frontmatter.ollama_repeat_penalty).toFixed(2).toString(); + frontmatter.ollama_repeat_penalty = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty); + } + if (isNaN(parseInt(frontmatter.ollama_seed))) { + plugin.settings.OllamaConnection.ollamaParameters.seed = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.seed; + } else { + plugin.settings.OllamaConnection.ollamaParameters.seed = parseInt(frontmatter.ollama_seed).toString(); + frontmatter.ollama_seed = parseInt(plugin.settings.OllamaConnection.ollamaParameters.seed); + } + plugin.settings.OllamaConnection.ollamaParameters.stop = frontmatter.ollama_stop; + if (isNaN(parseFloat(frontmatter.ollama_tfs_z))) { + plugin.settings.OllamaConnection.ollamaParameters.tfs_z = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.tfs_z; + frontmatter.ollama_tfs_z = plugin.settings.OllamaConnection.ollamaParameters.tfs_z; + } else { + plugin.settings.OllamaConnection.ollamaParameters.tfs_z = parseFloat(frontmatter.ollama_tfs_z).toFixed(2).toString(); + frontmatter.ollama_tfs_z = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.tfs_z); + } + if (isNaN(parseInt(frontmatter.ollama_top_k))) { + plugin.settings.OllamaConnection.ollamaParameters.top_k = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.top_k; + frontmatter.ollama_top_k = plugin.settings.OllamaConnection.ollamaParameters.top_k; + } else { + plugin.settings.OllamaConnection.ollamaParameters.top_k = parseInt(frontmatter.ollama_top_k).toString(); + frontmatter.ollama_top_k = parseInt(plugin.settings.OllamaConnection.ollamaParameters.top_k); + } + if (isNaN(parseInt(frontmatter.ollama_top_p))) { + plugin.settings.OllamaConnection.ollamaParameters.top_p = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.top_p; + frontmatter.ollama_top_p = plugin.settings.OllamaConnection.ollamaParameters.top_p; + } else { + plugin.settings.OllamaConnection.ollamaParameters.top_p = parseFloat(frontmatter.ollama_top_p).toFixed(2).toString(); + frontmatter.ollama_top_p = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.top_p); + } + if (isNaN(parseInt(frontmatter.ollama_min_p))) { + plugin.settings.OllamaConnection.ollamaParameters.min_p = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.min_p; + frontmatter.ollama_min_p = plugin.settings.OllamaConnection.ollamaParameters.min_p; + } else { + plugin.settings.OllamaConnection.ollamaParameters.min_p = parseFloat(frontmatter.ollama_min_p).toFixed(2).toString(); + frontmatter.ollama_min_p = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.min_p); + } + const match = String(frontmatter.ollama_keep_alive).match(/^(-?\d+)(m|hr|h)?$/); + if (match) { + const num = parseInt(match[1]); + const unit = match[2]; + let seconds; + if (unit === "m") { + seconds = num * 60; + } else if (unit === "hr" || unit === "h") { + seconds = num * 3600; + } else { + seconds = num; + } + plugin.settings.OllamaConnection.ollamaParameters.keep_alive = seconds.toString(); + frontmatter.ollama_keep_alive = plugin.settings.OllamaConnection.ollamaParameters.keep_alive; + } else { + plugin.settings.OllamaConnection.ollamaParameters.keep_alive = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.keep_alive; + frontmatter.ollama_keep_alive = plugin.settings.OllamaConnection.ollamaParameters.keep_alive; + } + }); + } catch (error) { + console.error("Error processing frontmatter:", error); + } +} + + +/* nosourcemap */ \ No newline at end of file diff --git a/.obsidian/plugins/bmo-chatbot/manifest.json b/.obsidian/plugins/bmo-chatbot/manifest.json new file mode 100644 index 0000000..abde1dd --- /dev/null +++ b/.obsidian/plugins/bmo-chatbot/manifest.json @@ -0,0 +1,11 @@ +{ + "id": "bmo-chatbot", + "name": "BMO Chatbot", + "version": "2.3.3", + "minAppVersion": "1.0.0", + "description": "Generate and brainstorm ideas while creating your notes using Large Language Models (LLMs) from Ollama, LM Studio, Anthropic, Google Gemini, Mistral AI, OpenAI, and more for Obsidian.", + "author": "Longy2k", + "authorUrl": "https://github.com/longy2k", + "fundingUrl": "https://ko-fi.com/longy2k", + "isDesktopOnly": false +} \ No newline at end of file diff --git a/.obsidian/plugins/bmo-chatbot/styles.css b/.obsidian/plugins/bmo-chatbot/styles.css new file mode 100644 index 0000000..eab7619 --- /dev/null +++ b/.obsidian/plugins/bmo-chatbot/styles.css @@ -0,0 +1,548 @@ +/* + +This CSS file will be included with your plugin, and +available in the app when your plugin is enabled. + +If your plugin does not need CSS, delete this file. + +*/ +.userMessage pre, +.preElement { + font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", + Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", + sans-serif; + margin: 0; + white-space: pre-wrap; +} + +.chatbotContainer { + height: 100%; + max-height: 99.2%; + position: relative; + border-radius: 5px; + border: 1px solid var(--background-modifier-border); + word-break: break-word; + display: flex; + flex-direction: column; + max-width: 800px; + margin: auto; +} + +#header { + padding: 10px 0px; +} + +#chatbotNameHeading { + color: var(--interactive-accent); + text-align: center; + margin-top: 0; + margin-bottom: 0; + padding: 0px 0px 0px 0px; + font-size: 1.5rem; +} + +#modelName { + margin: 0rem 0; + text-align: center; + color: var(--interactive-accent); + font-size: 0.65rem; +} + +#referenceCurrentNote { + margin: -0.5rem 0 0.5rem 0; + padding: 0 0 0 0; + text-align: center; + color: var(--interactive-accent); + font-size: 0.65rem; +} + +/* messageContainer */ + +#messageContainer { + margin-top: 0px; + flex-grow: 1; + overflow-y: auto; + -webkit-touch-callout: default; + -webkit-user-select: text; + -khtml-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + -o-user-select: text; + user-select: text; + max-height: calc(100% - 120px); + word-wrap: break-word; +} + +/* User & Bot Messages */ + +.userName, +.chatbotName { + display: block; + font-size: 0.8rem; + font-weight: bold; + color: var(--interactive-accent); + margin: 0; +} + +.userMessage, +.botMessage { + margin: 0; + padding: 10px 3.5%; + width: 100%; + display: inline-block; +} + +.userMessage { + background-color: var(--background-primary); + position: relative; +} + +.userMessage p, +.botMessage p { + margin: 0; + line-height: 1.6; +} + +.messageBlock { + margin: 0; + overflow-wrap: break-word; + position: relative; +} + +/* messageBlock style */ + +.messageBlock pre:not(.preElement) { + position: relative; + white-space: pre-wrap; + overflow-wrap: break-word; + font-size: 14px; + background-color: #282c34; + padding: 5px; + border-radius: 5px; + border: 1px solid #ccc; + line-height: 1.5; +} + +.messageBlock pre code { + padding: 5px; + font-weight: bold; + color: #ced4df; +} + +.edit-textarea { + max-width: 100%; + min-width: 100%; + min-height: 2rem; + width: 100%; + margin-top: 0.3rem; +} + +.textarea-edit-button, +.textarea-cancel-button { + margin: 0.2rem 0.5rem 0 0; + font-size: 0.7rem; + padding: 0 0.6rem; +} + +.textarea-edit-button:hover { + background-color: var(--interactive-accent); +} + +button.copy-code-button, +.messageBlock pre button.copy-button, +.messageBlock pre button.edit-button { + padding: 0 4px; + background-color: transparent !important; + box-shadow: none !important; + border: none; + position: absolute; + top: 0px; + right: 0px; + color: var(--text-muted); + display: inline-block; + max-width: 30px; +} + +button.copy-code-button:hover, +.messageBlock .copy-button:hover, +.messageBlock .edit-button:hover { + color: white; +} + +.userMessageToolBar { + display: flex; + justify-content: space-between; + align-items: center; + height: 1.2rem; +} + +.button-container { + margin: 0; +} + +/* Styles for copy button */ +.userMessageToolBar button.regenerate-button, +.userMessageToolBar button.edit-button, +.userMessageToolBar button.copy-button, +.userMessageToolBar button.trash-button { + padding: 0 3px; + background-color: transparent !important; + box-shadow: none !important; + border: none; + color: var(--interactive-accent); + width: 1.2rem; +} + +.userMessageToolBar .regenerate-button:hover, +.userMessageToolBar .edit-button:hover, +.userMessageToolBar .copy-button:hover { + color: var(--text-muted); +} + +.userMessageToolBar .trash-button:hover { + color: rgb(188, 35, 35); +} + +.botMessageToolBar { + display: flex; + justify-content: space-between; + align-items: center; + height: 1.2rem; +} + +.botMessageToolBar button.edit-button, +.botMessageToolBar button.copy-button, +.botMessageToolBar button.append-button { + padding: 0 3px; + background-color: transparent !important; + box-shadow: none !important; + border: none; + color: var(--interactive-accent); + width: 1.2rem; +} + +.botMessageToolBar .edit-button:hover, +.botMessageToolBar .copy-button:hover, +.botMessageToolBar .append-button:hover { + color: var(--text-muted); +} + +/* Hide buttons */ +.userMessage .edit-button, +.userMessage .regenerate-button, +.userMessage .copy-button, +.userMessage .trash-button, +.botMessage .append-button, +.botMessage .copy-button, +.botMessage .edit-button { + visibility: hidden; + opacity: 0; +} + +/* Show buttons on hover */ +.userMessage:hover .edit-button, +.userMessage:hover .regenerate-button, +.userMessage:hover .copy-button, +.userMessage:hover .trash-button, +.botMessage:hover .append-button, +.botMessage:hover .copy-button, +.botMessage:hover .edit-button { + visibility: visible; + opacity: 1; +} + +.userMessageToolBar button, +.botMessageToolBar button { + width: 1.2rem; +} + +/* Tables */ + +.messageBlock table { + border: 1px solid gray; + border-collapse: collapse; + margin: 5px 0px; +} +.messageBlock th, +.messageBlock td { + border: 1px solid gray; +} + +/* chatbox - textarea */ + +.chatbox { + display: flex; + align-items: flex-end; + justify-content: center; + margin: 13px 3.5%; + padding: 3px; + background-color: var(--interactive-accent); + border-radius: 5px; +} + +.chatbox textarea { + color: var(--text-normal); + font-weight: 500; + background-color: var(--interactive-accent); + border-color: var(--interactive-accent); + width: 100%; + height: 29px; + max-height: 150px; + resize: none; + font-size: 16px; + overflow-y: auto; +} + +.chatbox textarea::placeholder { + color: var(--text-normal); + font-weight: 500; +} + +.chatbox textarea:focus { + outline: none; + box-shadow: none; +} + +.chatbox textarea::selection { + background: blue !important; +} + +/* Send Button */ + +.chatbox .submit-button { + background-color: var(--interactive-accent); + filter: brightness(90%); + box-shadow: none !important; + color: white; + border: none; + border-radius: 50%; + padding: 8px; + max-width: 30px; + cursor: pointer; + margin: 0 3px; +} + +.chatbox .submit-button:hover { + filter: brightness(80%); +} + +.is-mobile .chatbox .submit-button { + background-color: var(--interactive-accent); + filter: brightness(90%); + color: white; + border: none; + border-radius: 50%; + padding: 8px !important; + max-width: 30px; + max-height: 30px; + cursor: pointer; +} + +.is-mobile .chatbox .submit-button:hover { + filter: brightness(80%); +} + +/* Misc */ + +.errorMessage { + color: red; +} + +.disabled { + pointer-events: none; +} + +#spacer { + height: 8vh; +} + +#loading { + color: white; + background-color: #808080; + padding: 0px 5px 12px 5px; + border-radius: 5px; + display: none; + line-height: 10px; + font-size: 25px; + font-weight: bolder; + margin: 5px 0px; + display: inline-block; + overflow: hidden; + white-space: nowrap; +} + +.theme-light #loading { + color: white; + background-color: #b0b0b0; +} + +@keyframes blink { + 0%, + 100% { + opacity: 1; + } + 49.9% { + opacity: 1; + } + 50% { + opacity: 0; + } + 50.1% { + opacity: 0; + } +} + +#loading span { + animation: blink 1.3s infinite both; +} + +#loading span:nth-child(1) { + animation-delay: 0s; +} + +#loading span:nth-child(2) { + animation-delay: 0.2s; +} + +#loading span:nth-child(3) { + animation-delay: 0.4s; +} + +.dotIndicator { + display: inline-block; + width: 0.3rem; + height: 0.3rem; + background-color: #da2c2c; + border-radius: 50%; + margin-left: 0.25rem; + margin-bottom: 0.05rem; +} + +ul#dropdownOptions { + position: absolute; + top: 1rem; + right: 0; + display: none; + z-index: 1; + background-color: #282c34; + border: 1px solid #ccc; + border-radius: 0.2rem; + list-style: none; + padding: 0; +} + +#dropdownOptions li { + padding: 0.3rem 1rem; + font-size: 0.8rem; +} + +/* CSS for highlighting
  • elements on hover */ +ul#dropdownOptions li:hover { + background-color: var(--interactive-accent); + color: white; + cursor: pointer; +} + +.commandBotMessage { + border: 1px solid #ccc; + background-color: #282c34; + padding: 10px; + border-radius: 5px; + margin: 0.5rem; + font-size: 0.8rem; +} + +.commandBotMessage h2 { + margin: 8px 0 12px 0; +} + +.commandBotMessage p { + padding: 0.1rem 0; +} + +.commandBotMessage code { + background-color: #4d5158; + border-radius: 0.2rem; + padding: 0.16rem; +} + +/* Display Error Bot Message Style */ + +.errorBotMessage { + color: #f30000; + border: 1px solid #ccc; + background-color: #282c34; + padding: 10px; + border-radius: 5px; + margin: 0.5rem; + font-size: 0.8rem; +} + +/* Toggle Settings Container */ +.toggleSettingContainer { + display: flex; + align-items: center; + cursor: pointer; + justify-content: space-between; +} + +.settingsContainer { + margin: 0rem 1.4rem; +} + +.chevron-icon { + margin-left: 0.5rem; + --icon-size: 1.2rem; +} + +/* Light Theme */ + +.theme-light .commandBotMessage, +.theme-light .errorBotMessage { + border: 1px solid #ccc; + background-color: white; + padding: 10px; + border-radius: 5px; + margin: 0.5rem; + font-size: 0.8rem; +} + +.theme-light .commandBotMessage code { + background-color: #ccc; + border-radius: 0.2rem; + padding: 0.16rem; +} + +.theme-light .messageBlock pre { + position: relative; + white-space: pre-wrap; + overflow-wrap: break-word; + font-size: 14px; + background-color: white; + padding: 5px; + border-radius: 5px; + border: 1px solid #ccc; + line-height: 1.5; +} + +.theme-light .messageBlock pre code { + padding: 5px; + font-weight: bold; + color: #222222; +} + +.theme-light .chatbox textarea::selection { + background: var(--interactive-accent) !important; +} + +#modelOptions { + height: 24px; + font-size: 0.7em; + color: var(--interactive-accent); + margin: 5px auto; + padding: 0 8px; + display: flex; + justify-content: center; + align-items: center; + text-align: center; +} diff --git a/.obsidian/plugins/code-styler/main.js b/.obsidian/plugins/code-styler/main.js new file mode 100644 index 0000000..bfdf0a8 --- /dev/null +++ b/.obsidian/plugins/code-styler/main.js @@ -0,0 +1,20047 @@ +/* +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 __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __defNormalProp = (obj, key2, value) => key2 in obj ? __defProp(obj, key2, { enumerable: true, configurable: true, writable: true, value }) : obj[key2] = value; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __export = (target, all3) => { + for (var name in all3) + __defProp(target, name, { get: all3[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key2 of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key2) && key2 !== except) + __defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var __publicField = (obj, key2, value) => { + __defNormalProp(obj, typeof key2 !== "symbol" ? key2 + "" : key2, value); + return value; +}; + +// node_modules/@simonwep/pickr/dist/pickr.min.js +var require_pickr_min = __commonJS({ + "node_modules/@simonwep/pickr/dist/pickr.min.js"(exports, module2) { + !function(t2, e2) { + "object" == typeof exports && "object" == typeof module2 ? module2.exports = e2() : "function" == typeof define && define.amd ? define([], e2) : "object" == typeof exports ? exports.Pickr = e2() : t2.Pickr = e2(); + }(self, () => (() => { + "use strict"; + var t2 = { d: (e3, o3) => { + for (var n3 in o3) + t2.o(o3, n3) && !t2.o(e3, n3) && Object.defineProperty(e3, n3, { enumerable: true, get: o3[n3] }); + }, o: (t3, e3) => Object.prototype.hasOwnProperty.call(t3, e3), r: (t3) => { + "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(t3, Symbol.toStringTag, { value: "Module" }), Object.defineProperty(t3, "__esModule", { value: true }); + } }, e2 = {}; + t2.d(e2, { default: () => E2 }); + var o2 = {}; + function n2(t3, e3, o3, n3, i3 = {}) { + e3 instanceof HTMLCollection || e3 instanceof NodeList ? e3 = Array.from(e3) : Array.isArray(e3) || (e3 = [e3]), Array.isArray(o3) || (o3 = [o3]); + for (const s4 of e3) + for (const e4 of o3) + s4[t3](e4, n3, { capture: false, ...i3 }); + return Array.prototype.slice.call(arguments, 1); + } + t2.r(o2), t2.d(o2, { adjustableInputNumbers: () => p3, createElementFromString: () => r2, createFromTemplate: () => a2, eventPath: () => l2, off: () => s3, on: () => i2, resolveElement: () => c2 }); + const i2 = n2.bind(null, "addEventListener"), s3 = n2.bind(null, "removeEventListener"); + function r2(t3) { + const e3 = document.createElement("div"); + return e3.innerHTML = t3.trim(), e3.firstElementChild; + } + function a2(t3) { + const e3 = (t4, e4) => { + const o4 = t4.getAttribute(e4); + return t4.removeAttribute(e4), o4; + }, o3 = (t4, n3 = {}) => { + const i3 = e3(t4, ":obj"), s4 = e3(t4, ":ref"), r3 = i3 ? n3[i3] = {} : n3; + s4 && (n3[s4] = t4); + for (const n4 of Array.from(t4.children)) { + const t5 = e3(n4, ":arr"), i4 = o3(n4, t5 ? {} : r3); + t5 && (r3[t5] || (r3[t5] = [])).push(Object.keys(i4).length ? i4 : n4); + } + return n3; + }; + return o3(r2(t3)); + } + function l2(t3) { + let e3 = t3.path || t3.composedPath && t3.composedPath(); + if (e3) + return e3; + let o3 = t3.target.parentElement; + for (e3 = [t3.target, o3]; o3 = o3.parentElement; ) + e3.push(o3); + return e3.push(document, window), e3; + } + function c2(t3) { + return t3 instanceof Element ? t3 : "string" == typeof t3 ? t3.split(/>>/g).reduce((t4, e3, o3, n3) => (t4 = t4.querySelector(e3), o3 < n3.length - 1 ? t4.shadowRoot : t4), document) : null; + } + function p3(t3, e3 = (t4) => t4) { + function o3(o4) { + const n3 = [1e-3, 0.01, 0.1][Number(o4.shiftKey || 2 * o4.ctrlKey)] * (o4.deltaY < 0 ? 1 : -1); + let i3 = 0, s4 = t3.selectionStart; + t3.value = t3.value.replace(/[\d.]+/g, (t4, o5) => o5 <= s4 && o5 + t4.length >= s4 ? (s4 = o5, e3(Number(t4), n3, i3)) : (i3++, t4)), t3.focus(), t3.setSelectionRange(s4, s4), o4.preventDefault(), t3.dispatchEvent(new Event("input")); + } + i2(t3, "focus", () => i2(window, "wheel", o3, { passive: false })), i2(t3, "blur", () => s3(window, "wheel", o3)); + } + const { min: u2, max: h3, floor: d2, round: m2 } = Math; + function f2(t3, e3, o3) { + e3 /= 100, o3 /= 100; + const n3 = d2(t3 = t3 / 360 * 6), i3 = t3 - n3, s4 = o3 * (1 - e3), r3 = o3 * (1 - i3 * e3), a3 = o3 * (1 - (1 - i3) * e3), l3 = n3 % 6; + return [255 * [o3, r3, s4, s4, a3, o3][l3], 255 * [a3, o3, o3, r3, s4, s4][l3], 255 * [s4, s4, a3, o3, o3, r3][l3]]; + } + function v2(t3, e3, o3) { + const n3 = (2 - (e3 /= 100)) * (o3 /= 100) / 2; + return 0 !== n3 && (e3 = 1 === n3 ? 0 : n3 < 0.5 ? e3 * o3 / (2 * n3) : e3 * o3 / (2 - 2 * n3)), [t3, 100 * e3, 100 * n3]; + } + function b2(t3, e3, o3) { + const n3 = u2(t3 /= 255, e3 /= 255, o3 /= 255), i3 = h3(t3, e3, o3), s4 = i3 - n3; + let r3, a3; + if (0 === s4) + r3 = a3 = 0; + else { + a3 = s4 / i3; + const n4 = ((i3 - t3) / 6 + s4 / 2) / s4, l3 = ((i3 - e3) / 6 + s4 / 2) / s4, c3 = ((i3 - o3) / 6 + s4 / 2) / s4; + t3 === i3 ? r3 = c3 - l3 : e3 === i3 ? r3 = 1 / 3 + n4 - c3 : o3 === i3 && (r3 = 2 / 3 + l3 - n4), r3 < 0 ? r3 += 1 : r3 > 1 && (r3 -= 1); + } + return [360 * r3, 100 * a3, 100 * i3]; + } + function y2(t3, e3, o3, n3) { + e3 /= 100, o3 /= 100; + return [...b2(255 * (1 - u2(1, (t3 /= 100) * (1 - (n3 /= 100)) + n3)), 255 * (1 - u2(1, e3 * (1 - n3) + n3)), 255 * (1 - u2(1, o3 * (1 - n3) + n3)))]; + } + function g2(t3, e3, o3) { + e3 /= 100; + const n3 = 2 * (e3 *= (o3 /= 100) < 0.5 ? o3 : 1 - o3) / (o3 + e3) * 100, i3 = 100 * (o3 + e3); + return [t3, isNaN(n3) ? 0 : n3, i3]; + } + function _2(t3) { + return b2(...t3.match(/.{2}/g).map((t4) => parseInt(t4, 16))); + } + function w2(t3) { + t3 = t3.match(/^[a-zA-Z]+$/) ? function(t4) { + if ("black" === t4.toLowerCase()) + return "#000"; + const e4 = document.createElement("canvas").getContext("2d"); + return e4.fillStyle = t4, "#000" === e4.fillStyle ? null : e4.fillStyle; + }(t3) : t3; + const e3 = { cmyk: /^cmyk\D+([\d.]+)\D+([\d.]+)\D+([\d.]+)\D+([\d.]+)/i, rgba: /^rgba?\D+([\d.]+)(%?)\D+([\d.]+)(%?)\D+([\d.]+)(%?)\D*?(([\d.]+)(%?)|$)/i, hsla: /^hsla?\D+([\d.]+)\D+([\d.]+)\D+([\d.]+)\D*?(([\d.]+)(%?)|$)/i, hsva: /^hsva?\D+([\d.]+)\D+([\d.]+)\D+([\d.]+)\D*?(([\d.]+)(%?)|$)/i, hexa: /^#?(([\dA-Fa-f]{3,4})|([\dA-Fa-f]{6})|([\dA-Fa-f]{8}))$/i }, o3 = (t4) => t4.map((t5) => /^(|\d+)\.\d+|\d+$/.test(t5) ? Number(t5) : void 0); + let n3; + t: + for (const i3 in e3) + if (n3 = e3[i3].exec(t3)) + switch (i3) { + case "cmyk": { + const [, t4, e4, s4, r3] = o3(n3); + if (t4 > 100 || e4 > 100 || s4 > 100 || r3 > 100) + break t; + return { values: y2(t4, e4, s4, r3), type: i3 }; + } + case "rgba": { + let [, t4, , e4, , s4, , , r3] = o3(n3); + if (t4 = "%" === n3[2] ? t4 / 100 * 255 : t4, e4 = "%" === n3[4] ? e4 / 100 * 255 : e4, s4 = "%" === n3[6] ? s4 / 100 * 255 : s4, r3 = "%" === n3[9] ? r3 / 100 : r3, t4 > 255 || e4 > 255 || s4 > 255 || r3 < 0 || r3 > 1) + break t; + return { values: [...b2(t4, e4, s4), r3], a: r3, type: i3 }; + } + case "hexa": { + let [, t4] = n3; + 4 !== t4.length && 3 !== t4.length || (t4 = t4.split("").map((t5) => t5 + t5).join("")); + const e4 = t4.substring(0, 6); + let o4 = t4.substring(6); + return o4 = o4 ? parseInt(o4, 16) / 255 : void 0, { values: [..._2(e4), o4], a: o4, type: i3 }; + } + case "hsla": { + let [, t4, e4, s4, , r3] = o3(n3); + if (r3 = "%" === n3[6] ? r3 / 100 : r3, t4 > 360 || e4 > 100 || s4 > 100 || r3 < 0 || r3 > 1) + break t; + return { values: [...g2(t4, e4, s4), r3], a: r3, type: i3 }; + } + case "hsva": { + let [, t4, e4, s4, , r3] = o3(n3); + if (r3 = "%" === n3[6] ? r3 / 100 : r3, t4 > 360 || e4 > 100 || s4 > 100 || r3 < 0 || r3 > 1) + break t; + return { values: [t4, e4, s4, r3], a: r3, type: i3 }; + } + } + return { values: null, type: null }; + } + function A2(t3 = 0, e3 = 0, o3 = 0, n3 = 1) { + const i3 = (t4, e4) => (o4 = -1) => e4(~o4 ? t4.map((t5) => Number(t5.toFixed(o4))) : t4), s4 = { h: t3, s: e3, v: o3, a: n3, toHSVA() { + const t4 = [s4.h, s4.s, s4.v, s4.a]; + return t4.toString = i3(t4, (t5) => `hsva(${t5[0]}, ${t5[1]}%, ${t5[2]}%, ${s4.a})`), t4; + }, toHSLA() { + const t4 = [...v2(s4.h, s4.s, s4.v), s4.a]; + return t4.toString = i3(t4, (t5) => `hsla(${t5[0]}, ${t5[1]}%, ${t5[2]}%, ${s4.a})`), t4; + }, toRGBA() { + const t4 = [...f2(s4.h, s4.s, s4.v), s4.a]; + return t4.toString = i3(t4, (t5) => `rgba(${t5[0]}, ${t5[1]}, ${t5[2]}, ${s4.a})`), t4; + }, toCMYK() { + const t4 = function(t5, e4, o4) { + const n4 = f2(t5, e4, o4), i4 = n4[0] / 255, s5 = n4[1] / 255, r3 = n4[2] / 255, a3 = u2(1 - i4, 1 - s5, 1 - r3); + return [100 * (1 === a3 ? 0 : (1 - i4 - a3) / (1 - a3)), 100 * (1 === a3 ? 0 : (1 - s5 - a3) / (1 - a3)), 100 * (1 === a3 ? 0 : (1 - r3 - a3) / (1 - a3)), 100 * a3]; + }(s4.h, s4.s, s4.v); + return t4.toString = i3(t4, (t5) => `cmyk(${t5[0]}%, ${t5[1]}%, ${t5[2]}%, ${t5[3]}%)`), t4; + }, toHEXA() { + const t4 = function(t5, e5, o4) { + return f2(t5, e5, o4).map((t6) => m2(t6).toString(16).padStart(2, "0")); + }(s4.h, s4.s, s4.v), e4 = s4.a >= 1 ? "" : Number((255 * s4.a).toFixed(0)).toString(16).toUpperCase().padStart(2, "0"); + return e4 && t4.push(e4), t4.toString = () => `#${t4.join("").toUpperCase()}`, t4; + }, clone: () => A2(s4.h, s4.s, s4.v, s4.a) }; + return s4; + } + const $3 = (t3) => Math.max(Math.min(t3, 1), 0); + function C2(t3) { + const e3 = { options: Object.assign({ lock: null, onchange: () => 0, onstop: () => 0 }, t3), _keyboard(t4) { + const { options: o4 } = e3, { type: n4, key: i3 } = t4; + if (document.activeElement === o4.wrapper) { + const { lock: o5 } = e3.options, s4 = "ArrowUp" === i3, r4 = "ArrowRight" === i3, a3 = "ArrowDown" === i3, l3 = "ArrowLeft" === i3; + if ("keydown" === n4 && (s4 || r4 || a3 || l3)) { + let n5 = 0, i4 = 0; + "v" === o5 ? n5 = s4 || r4 ? 1 : -1 : "h" === o5 ? n5 = s4 || r4 ? -1 : 1 : (i4 = s4 ? -1 : a3 ? 1 : 0, n5 = l3 ? -1 : r4 ? 1 : 0), e3.update($3(e3.cache.x + 0.01 * n5), $3(e3.cache.y + 0.01 * i4)), t4.preventDefault(); + } else + i3.startsWith("Arrow") && (e3.options.onstop(), t4.preventDefault()); + } + }, _tapstart(t4) { + i2(document, ["mouseup", "touchend", "touchcancel"], e3._tapstop), i2(document, ["mousemove", "touchmove"], e3._tapmove), t4.cancelable && t4.preventDefault(), e3._tapmove(t4); + }, _tapmove(t4) { + const { options: o4, cache: n4 } = e3, { lock: i3, element: s4, wrapper: r4 } = o4, a3 = r4.getBoundingClientRect(); + let l3 = 0, c3 = 0; + if (t4) { + const e4 = t4 && t4.touches && t4.touches[0]; + l3 = t4 ? (e4 || t4).clientX : 0, c3 = t4 ? (e4 || t4).clientY : 0, l3 < a3.left ? l3 = a3.left : l3 > a3.left + a3.width && (l3 = a3.left + a3.width), c3 < a3.top ? c3 = a3.top : c3 > a3.top + a3.height && (c3 = a3.top + a3.height), l3 -= a3.left, c3 -= a3.top; + } else + n4 && (l3 = n4.x * a3.width, c3 = n4.y * a3.height); + "h" !== i3 && (s4.style.left = `calc(${l3 / a3.width * 100}% - ${s4.offsetWidth / 2}px)`), "v" !== i3 && (s4.style.top = `calc(${c3 / a3.height * 100}% - ${s4.offsetHeight / 2}px)`), e3.cache = { x: l3 / a3.width, y: c3 / a3.height }; + const p4 = $3(l3 / a3.width), u3 = $3(c3 / a3.height); + switch (i3) { + case "v": + return o4.onchange(p4); + case "h": + return o4.onchange(u3); + default: + return o4.onchange(p4, u3); + } + }, _tapstop() { + e3.options.onstop(), s3(document, ["mouseup", "touchend", "touchcancel"], e3._tapstop), s3(document, ["mousemove", "touchmove"], e3._tapmove); + }, trigger() { + e3._tapmove(); + }, update(t4 = 0, o4 = 0) { + const { left: n4, top: i3, width: s4, height: r4 } = e3.options.wrapper.getBoundingClientRect(); + "h" === e3.options.lock && (o4 = t4), e3._tapmove({ clientX: n4 + s4 * t4, clientY: i3 + r4 * o4 }); + }, destroy() { + const { options: t4, _tapstart: o4, _keyboard: n4 } = e3; + s3(document, ["keydown", "keyup"], n4), s3([t4.wrapper, t4.element], "mousedown", o4), s3([t4.wrapper, t4.element], "touchstart", o4, { passive: false }); + } }, { options: o3, _tapstart: n3, _keyboard: r3 } = e3; + return i2([o3.wrapper, o3.element], "mousedown", n3), i2([o3.wrapper, o3.element], "touchstart", n3, { passive: false }), i2(document, ["keydown", "keyup"], r3), e3; + } + function k2(t3 = {}) { + t3 = Object.assign({ onchange: () => 0, className: "", elements: [] }, t3); + const e3 = i2(t3.elements, "click", (e4) => { + t3.elements.forEach((o3) => o3.classList[e4.target === o3 ? "add" : "remove"](t3.className)), t3.onchange(e4), e4.stopPropagation(); + }); + return { destroy: () => s3(...e3) }; + } + const S2 = { variantFlipOrder: { start: "sme", middle: "mse", end: "ems" }, positionFlipOrder: { top: "tbrl", right: "rltb", bottom: "btrl", left: "lrbt" }, position: "bottom", margin: 8, padding: 0 }, O2 = (t3, e3, o3) => { + const n3 = "object" != typeof t3 || t3 instanceof HTMLElement ? { reference: t3, popper: e3, ...o3 } : t3; + return { update(t4 = n3) { + const { reference: e4, popper: o4 } = Object.assign(n3, t4); + if (!o4 || !e4) + throw new Error("Popper- or reference-element missing."); + return ((t5, e5, o5) => { + const { container: n4, arrow: i3, margin: s4, padding: r3, position: a3, variantFlipOrder: l3, positionFlipOrder: c3 } = { container: document.documentElement.getBoundingClientRect(), ...S2, ...o5 }, { left: p4, top: u3 } = e5.style; + e5.style.left = "0", e5.style.top = "0"; + const h4 = t5.getBoundingClientRect(), d3 = e5.getBoundingClientRect(), m3 = { t: h4.top - d3.height - s4, b: h4.bottom + s4, r: h4.right + s4, l: h4.left - d3.width - s4 }, f3 = { vs: h4.left, vm: h4.left + h4.width / 2 - d3.width / 2, ve: h4.left + h4.width - d3.width, hs: h4.top, hm: h4.bottom - h4.height / 2 - d3.height / 2, he: h4.bottom - d3.height }, [v3, b3 = "middle"] = a3.split("-"), y3 = c3[v3], g3 = l3[b3], { top: _3, left: w3, bottom: A3, right: $4 } = n4; + for (const t6 of y3) { + const o6 = "t" === t6 || "b" === t6; + let n5 = m3[t6]; + const [s5, a4] = o6 ? ["top", "left"] : ["left", "top"], [l4, c4] = o6 ? [d3.height, d3.width] : [d3.width, d3.height], [p5, u4] = o6 ? [A3, $4] : [$4, A3], [v4, b4] = o6 ? [_3, w3] : [w3, _3]; + if (!(n5 < v4 || n5 + l4 + r3 > p5)) + for (const p6 of g3) { + let m4 = f3[(o6 ? "v" : "h") + p6]; + if (!(m4 < b4 || m4 + c4 + r3 > u4)) { + if (m4 -= d3[a4], n5 -= d3[s5], e5.style[a4] = `${m4}px`, e5.style[s5] = `${n5}px`, i3) { + const t7 = o6 ? h4.width / 2 : h4.height / 2, e6 = 2 * t7 < c4 ? h4[a4] + t7 : m4 + c4 / 2; + n5 < h4[s5] && (n5 += l4), i3.style[a4] = `${e6}px`, i3.style[s5] = `${n5}px`; + } + return t6 + p6; + } + } + } + return e5.style.left = p4, e5.style.top = u3, null; + })(e4, o4, n3); + } }; + }; + const _E = class _E { + constructor(t3) { + __publicField(this, "_initializingActive", true); + __publicField(this, "_recalc", true); + __publicField(this, "_nanopop", null); + __publicField(this, "_root", null); + __publicField(this, "_color", A2()); + __publicField(this, "_lastColor", A2()); + __publicField(this, "_swatchColors", []); + __publicField(this, "_setupAnimationFrame", null); + __publicField(this, "_eventListener", { init: [], save: [], hide: [], show: [], clear: [], change: [], changestop: [], cancel: [], swatchselect: [] }); + this.options = t3 = Object.assign({ ..._E.DEFAULT_OPTIONS }, t3); + const { swatches: e3, components: o3, theme: n3, sliders: i3, lockOpacity: s4, padding: r3 } = t3; + ["nano", "monolith"].includes(n3) && !i3 && (t3.sliders = "h"), o3.interaction || (o3.interaction = {}); + const { preview: a3, opacity: l3, hue: c3, palette: p4 } = o3; + o3.opacity = !s4 && l3, o3.palette = p4 || a3 || l3 || c3, this._preBuild(), this._buildComponents(), this._bindEvents(), this._finalBuild(), e3 && e3.length && e3.forEach((t4) => this.addSwatch(t4)); + const { button: u3, app: h4 } = this._root; + this._nanopop = O2(u3, h4, { margin: r3 }), u3.setAttribute("role", "button"), u3.setAttribute("aria-label", this._t("btn:toggle")); + const d3 = this; + this._setupAnimationFrame = requestAnimationFrame(function e4() { + if (!h4.offsetWidth) + return requestAnimationFrame(e4); + d3.setColor(t3.default), d3._rePositioningPicker(), t3.defaultRepresentation && (d3._representation = t3.defaultRepresentation, d3.setColorRepresentation(d3._representation)), t3.showAlways && d3.show(), d3._initializingActive = false, d3._emit("init"); + }); + } + _preBuild() { + const { options: t3 } = this; + for (const e3 of ["el", "container"]) + t3[e3] = c2(t3[e3]); + this._root = ((t4) => { + const { components: e3, useAsButton: o3, inline: n3, appClass: i3, theme: s4, lockOpacity: r3 } = t4.options, l3 = (t5) => t5 ? "" : 'style="display:none" hidden', c3 = (e4) => t4._t(e4), p4 = a2(` +
    + + ${o3 ? "" : ''} + +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    + +
    + + + + + + + + + + + +
    +
    +
    + `), u3 = p4.interaction; + return u3.options.find((t5) => !t5.hidden && !t5.classList.add("active")), u3.type = () => u3.options.find((t5) => t5.classList.contains("active")), p4; + })(this), t3.useAsButton && (this._root.button = t3.el), t3.container.appendChild(this._root.root); + } + _finalBuild() { + const t3 = this.options, e3 = this._root; + if (t3.container.removeChild(e3.root), t3.inline) { + const o3 = t3.el.parentElement; + t3.el.nextSibling ? o3.insertBefore(e3.app, t3.el.nextSibling) : o3.appendChild(e3.app); + } else + t3.container.appendChild(e3.app); + t3.useAsButton ? t3.inline && t3.el.remove() : t3.el.parentNode.replaceChild(e3.root, t3.el), t3.disabled && this.disable(), t3.comparison || (e3.button.style.transition = "none", t3.useAsButton || (e3.preview.lastColor.style.transition = "none")), this.hide(); + } + _buildComponents() { + const t3 = this, e3 = this.options.components, o3 = (t3.options.sliders || "v").repeat(2), [n3, i3] = o3.match(/^[vh]+$/g) ? o3 : [], s4 = () => this._color || (this._color = this._lastColor.clone()), r3 = { palette: C2({ element: t3._root.palette.picker, wrapper: t3._root.palette.palette, onstop: () => t3._emit("changestop", "slider", t3), onchange(o4, n4) { + if (!e3.palette) + return; + const i4 = s4(), { _root: r4, options: a3 } = t3, { lastColor: l3, currentColor: c3 } = r4.preview; + t3._recalc && (i4.s = 100 * o4, i4.v = 100 - 100 * n4, i4.v < 0 && (i4.v = 0), t3._updateOutput("slider")); + const p4 = i4.toRGBA().toString(0); + this.element.style.background = p4, this.wrapper.style.background = ` + linear-gradient(to top, rgba(0, 0, 0, ${i4.a}), transparent), + linear-gradient(to left, hsla(${i4.h}, 100%, 50%, ${i4.a}), rgba(255, 255, 255, ${i4.a})) + `, a3.comparison ? a3.useAsButton || t3._lastColor || l3.style.setProperty("--pcr-color", p4) : (r4.button.style.setProperty("--pcr-color", p4), r4.button.classList.remove("clear")); + const u3 = i4.toHEXA().toString(); + for (const { el: e4, color: o5 } of t3._swatchColors) + e4.classList[u3 === o5.toHEXA().toString() ? "add" : "remove"]("pcr-active"); + c3.style.setProperty("--pcr-color", p4); + } }), hue: C2({ lock: "v" === i3 ? "h" : "v", element: t3._root.hue.picker, wrapper: t3._root.hue.slider, onstop: () => t3._emit("changestop", "slider", t3), onchange(o4) { + if (!e3.hue || !e3.palette) + return; + const n4 = s4(); + t3._recalc && (n4.h = 360 * o4), this.element.style.backgroundColor = `hsl(${n4.h}, 100%, 50%)`, r3.palette.trigger(); + } }), opacity: C2({ lock: "v" === n3 ? "h" : "v", element: t3._root.opacity.picker, wrapper: t3._root.opacity.slider, onstop: () => t3._emit("changestop", "slider", t3), onchange(o4) { + if (!e3.opacity || !e3.palette) + return; + const n4 = s4(); + t3._recalc && (n4.a = Math.round(100 * o4) / 100), this.element.style.background = `rgba(0, 0, 0, ${n4.a})`, r3.palette.trigger(); + } }), selectable: k2({ elements: t3._root.interaction.options, className: "active", onchange(e4) { + t3._representation = e4.target.getAttribute("data-type").toUpperCase(), t3._recalc && t3._updateOutput("swatch"); + } }) }; + this._components = r3; + } + _bindEvents() { + const { _root: t3, options: e3 } = this, o3 = [i2(t3.interaction.clear, "click", () => this._clearColor()), i2([t3.interaction.cancel, t3.preview.lastColor], "click", () => { + this.setHSVA(...(this._lastColor || this._color).toHSVA(), true), this._emit("cancel"); + }), i2(t3.interaction.save, "click", () => { + !this.applyColor() && !e3.showAlways && this.hide(); + }), i2(t3.interaction.result, ["keyup", "input"], (t4) => { + this.setColor(t4.target.value, true) && !this._initializingActive && (this._emit("change", this._color, "input", this), this._emit("changestop", "input", this)), t4.stopImmediatePropagation(); + }), i2(t3.interaction.result, ["focus", "blur"], (t4) => { + this._recalc = "blur" === t4.type, this._recalc && this._updateOutput(null); + }), i2([t3.palette.palette, t3.palette.picker, t3.hue.slider, t3.hue.picker, t3.opacity.slider, t3.opacity.picker], ["mousedown", "touchstart"], () => this._recalc = true, { passive: true })]; + if (!e3.showAlways) { + const n3 = e3.closeWithKey; + o3.push(i2(t3.button, "click", () => this.isOpen() ? this.hide() : this.show()), i2(document, "keyup", (t4) => this.isOpen() && (t4.key === n3 || t4.code === n3) && this.hide()), i2(document, ["touchstart", "mousedown"], (e4) => { + this.isOpen() && !l2(e4).some((e5) => e5 === t3.app || e5 === t3.button) && this.hide(); + }, { capture: true })); + } + if (e3.adjustableNumbers) { + const e4 = { rgba: [255, 255, 255, 1], hsva: [360, 100, 100, 1], hsla: [360, 100, 100, 1], cmyk: [100, 100, 100, 100] }; + p3(t3.interaction.result, (t4, o4, n3) => { + const i3 = e4[this.getColorRepresentation().toLowerCase()]; + if (i3) { + const e5 = i3[n3], s4 = t4 + (e5 >= 100 ? 1e3 * o4 : o4); + return s4 <= 0 ? 0 : Number((s4 < e5 ? s4 : e5).toPrecision(3)); + } + return t4; + }); + } + if (e3.autoReposition && !e3.inline) { + let t4 = null; + const n3 = this; + o3.push(i2(window, ["scroll", "resize"], () => { + n3.isOpen() && (e3.closeOnScroll && n3.hide(), null === t4 ? (t4 = setTimeout(() => t4 = null, 100), requestAnimationFrame(function e4() { + n3._rePositioningPicker(), null !== t4 && requestAnimationFrame(e4); + })) : (clearTimeout(t4), t4 = setTimeout(() => t4 = null, 100))); + }, { capture: true })); + } + this._eventBindings = o3; + } + _rePositioningPicker() { + const { options: t3 } = this; + if (!t3.inline) { + if (!this._nanopop.update({ container: document.body.getBoundingClientRect(), position: t3.position })) { + const t4 = this._root.app, e3 = t4.getBoundingClientRect(); + t4.style.top = (window.innerHeight - e3.height) / 2 + "px", t4.style.left = (window.innerWidth - e3.width) / 2 + "px"; + } + } + } + _updateOutput(t3) { + const { _root: e3, _color: o3, options: n3 } = this; + if (e3.interaction.type()) { + const t4 = `to${e3.interaction.type().getAttribute("data-type")}`; + e3.interaction.result.value = "function" == typeof o3[t4] ? o3[t4]().toString(n3.outputPrecision) : ""; + } + !this._initializingActive && this._recalc && this._emit("change", o3, t3, this); + } + _clearColor(t3 = false) { + const { _root: e3, options: o3 } = this; + o3.useAsButton || e3.button.style.setProperty("--pcr-color", "rgba(0, 0, 0, 0.15)"), e3.button.classList.add("clear"), o3.showAlways || this.hide(), this._lastColor = null, this._initializingActive || t3 || (this._emit("save", null), this._emit("clear")); + } + _parseLocalColor(t3) { + const { values: e3, type: o3, a: n3 } = w2(t3), { lockOpacity: i3 } = this.options, s4 = void 0 !== n3 && 1 !== n3; + return e3 && 3 === e3.length && (e3[3] = void 0), { values: !e3 || i3 && s4 ? null : e3, type: o3 }; + } + _t(t3) { + return this.options.i18n[t3] || _E.I18N_DEFAULTS[t3]; + } + _emit(t3, ...e3) { + this._eventListener[t3].forEach((t4) => t4(...e3, this)); + } + on(t3, e3) { + return this._eventListener[t3].push(e3), this; + } + off(t3, e3) { + const o3 = this._eventListener[t3] || [], n3 = o3.indexOf(e3); + return ~n3 && o3.splice(n3, 1), this; + } + addSwatch(t3) { + const { values: e3 } = this._parseLocalColor(t3); + if (e3) { + const { _swatchColors: t4, _root: o3 } = this, n3 = A2(...e3), s4 = r2(`