From b6be007d98ac7fcc71e026142f681b505c6182f6 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 8 Aug 2022 09:13:58 +0800 Subject: [PATCH 01/13] fix: don't replace _ for the page name if it's not a local asset --- src/main/frontend/extensions/pdf/assets.cljs | 14 +++++++++----- .../frontend/extensions/pdf/assets_test.cljs | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 src/test/frontend/extensions/pdf/assets_test.cljs diff --git a/src/main/frontend/extensions/pdf/assets.cljs b/src/main/frontend/extensions/pdf/assets.cljs index 9613e9e3a0..888cfc92d3 100644 --- a/src/main/frontend/extensions/pdf/assets.cljs +++ b/src/main/frontend/extensions/pdf/assets.cljs @@ -261,11 +261,15 @@ (defn fix-local-asset-filename [filename] (when-not (string/blank? filename) - (let [local-asset? (re-find #"[0-9]{13}_\d$" filename)] - (-> filename - (subs 0 (- (count filename) (if local-asset? 15 0))) - (string/replace #"^hls__" "") - (string/replace "_" " "))))) + (let [local-asset? (re-find #"[0-9]{13}_\d$" filename) + hls? (and local-asset? (re-find #"^hls__" filename))] + (if (or local-asset? hls?) + (-> filename + (subs 0 (- (count filename) 15)) + (string/replace #"^hls__" "") + (string/replace "_" " ") + (string/trimr)) + filename)))) (rum/defc human-hls-filename-display [title] diff --git a/src/test/frontend/extensions/pdf/assets_test.cljs b/src/test/frontend/extensions/pdf/assets_test.cljs new file mode 100644 index 0000000000..3c39e43875 --- /dev/null +++ b/src/test/frontend/extensions/pdf/assets_test.cljs @@ -0,0 +1,16 @@ +(ns frontend.extensions.pdf.assets-test + (:require [clojure.test :as test :refer [are deftest testing]] + [clojure.string :as str] + [frontend.extensions.pdf.assets :as assets])) + +(deftest fix-local-asset-filename + (testing "matched filenames" + (are [x y] (= y (assets/fix-local-asset-filename x)) + "2015_Book_Intertwingled_1659920114630_0" "2015 Book Intertwingled" + "hls__2015_Book_Intertwingled_1659920114630_0" "2015 Book Intertwingled")) + (testing "non matched filenames" + (are [x y] (= y (assets/fix-local-asset-filename x)) + "foo" "foo" + "foo_bar" "foo_bar" + "foo__bar" "foo__bar" + "foo_bar.pdf" "foo_bar.pdf"))) From 52b7a5e20383c80a0225ee27a6924e2fa4186389 Mon Sep 17 00:00:00 2001 From: Andelf Date: Mon, 8 Aug 2022 13:14:08 +0800 Subject: [PATCH 02/13] test(e2e): add test case page name fix: lint --- e2e-tests/sidebar.spec.ts | 11 ++++++++++- src/test/frontend/extensions/pdf/assets_test.cljs | 1 - 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/e2e-tests/sidebar.spec.ts b/e2e-tests/sidebar.spec.ts index 63113f493a..033b49d512 100644 --- a/e2e-tests/sidebar.spec.ts +++ b/e2e-tests/sidebar.spec.ts @@ -1,6 +1,6 @@ import { expect } from '@playwright/test' import { test } from './fixtures' -import { createRandomPage, openLeftSidebar, searchAndJumpToPage } from './utils' +import { createPage, createRandomPage, openLeftSidebar, randomString, searchAndJumpToPage } from './utils' /*** * Test side bar features @@ -52,3 +52,12 @@ test('recent is updated #4320', async ({ page }) => { expect(await firstRecent.textContent()).toContain(page1) expect(await secondRecent.textContent()).toContain(page2) }) + +test('recent file name is displayed correctly #6297', async ({ page }) => { + const pageName = randomString(5) + "_@#$%^&*()_" + randomString(5) + await createPage(page, pageName) + await page.fill('textarea >> nth=0', 'Random Content') + + const firstRecent = page.locator('.nav-content-item.recent li >> nth=0') + expect(await firstRecent.textContent()).toContain(pageName) +}) diff --git a/src/test/frontend/extensions/pdf/assets_test.cljs b/src/test/frontend/extensions/pdf/assets_test.cljs index 3c39e43875..414fbf661c 100644 --- a/src/test/frontend/extensions/pdf/assets_test.cljs +++ b/src/test/frontend/extensions/pdf/assets_test.cljs @@ -1,6 +1,5 @@ (ns frontend.extensions.pdf.assets-test (:require [clojure.test :as test :refer [are deftest testing]] - [clojure.string :as str] [frontend.extensions.pdf.assets :as assets])) (deftest fix-local-asset-filename From a14b397899174dcda894bba26f83b00b978efe5d Mon Sep 17 00:00:00 2001 From: charlie Date: Wed, 13 Jul 2022 16:27:29 +0800 Subject: [PATCH 03/13] improve(api): the last active block also represent for current block --- src/main/logseq/api.cljs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/logseq/api.cljs b/src/main/logseq/api.cljs index 7ec47ef1fc..15c5c68bbe 100644 --- a/src/main/logseq/api.cljs +++ b/src/main/logseq/api.cljs @@ -545,7 +545,9 @@ (def ^:export get_current_block (fn [^js opts] (let [block (state/get-edit-block) - block (or block (some-> (first (state/get-selection-blocks)) + block (or block + (some-> (or (first (state/get-selection-blocks)) + (gdom/getElement (state/get-editing-block-dom-id))) (.getAttribute "blockid") (db-model/get-block-by-uuid)))] (get_block (:db/id block) opts)))) From 3e7c20fd80fdc7edc989bcc4e52688ba76878f10 Mon Sep 17 00:00:00 2001 From: charlie Date: Fri, 29 Jul 2022 22:44:55 +0800 Subject: [PATCH 04/13] improve(plugin): support textarea for settings input item --- libs/src/LSPlugin.ts | 2 +- src/main/frontend/components/plugins.css | 7 ++++++- src/main/frontend/components/plugins_settings.cljs | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/libs/src/LSPlugin.ts b/libs/src/LSPlugin.ts index 1f0cadb3b3..9bf22980d9 100644 --- a/libs/src/LSPlugin.ts +++ b/libs/src/LSPlugin.ts @@ -232,7 +232,7 @@ export type SettingSchemaDesc = { default: string | number | boolean | Array | object | null title: string description: string // support markdown - inputAs?: 'color' | 'date' | 'datetime-local' | 'range' + inputAs?: 'color' | 'date' | 'datetime-local' | 'range' | 'textarea' enumChoices?: Array enumPicker?: 'select' | 'radio' | 'checkbox' // default: select } diff --git a/src/main/frontend/components/plugins.css b/src/main/frontend/components/plugins.css index 8d28cf3216..82cdca3dbf 100644 --- a/src/main/frontend/components/plugins.css +++ b/src/main/frontend/components/plugins.css @@ -545,7 +545,12 @@ .form-input { padding: 5px; - width: 50%; + width: 70%; + } + + textarea.form-input { + overflow-y: auto; + resize: vertical; } .form-select { diff --git a/src/main/frontend/components/plugins_settings.cljs b/src/main/frontend/components/plugins_settings.cljs index e87df473ae..b07da1ce7c 100644 --- a/src/main/frontend/components/plugins_settings.cljs +++ b/src/main/frontend/components/plugins_settings.cljs @@ -25,7 +25,7 @@ (let [input-as (util/safe-lower-case (or inputAs (name type))) input-as (if (= input-as "string") :text (keyword input-as))] - [:input + [(if (= input-as :textarea) :textarea :input) {:class (util/classnames [{:form-input (not (contains? #{:color :range} input-as))}]) :type (name input-as) :defaultValue (or val default) From 16650583869e593e6fe110b0bc58a183f0033d59 Mon Sep 17 00:00:00 2001 From: charlie Date: Sun, 31 Jul 2022 23:16:51 +0800 Subject: [PATCH 05/13] improve(plugin): perf console table --- libs/src/LSPlugin.core.ts | 72 ++++++++++++++++---------------- src/electron/electron/utils.cljs | 2 +- 2 files changed, 36 insertions(+), 38 deletions(-) diff --git a/libs/src/LSPlugin.core.ts b/libs/src/LSPlugin.core.ts index f20b8ad759..1cabf6918f 100644 --- a/libs/src/LSPlugin.core.ts +++ b/libs/src/LSPlugin.core.ts @@ -437,9 +437,11 @@ class ExistedImportedPluginPackageError extends Error { /** * Host plugin for local */ -class PluginLocal extends EventEmitter< - 'loaded' | 'unloaded' | 'beforeunload' | 'error' | string -> { +class PluginLocal extends EventEmitter<'loaded' + | 'unloaded' + | 'beforeunload' + | 'error' + | string> { private _sdk: Partial = {} private _disposes: Array<() => Promise> = [] private _id: PluginLocalIdentity @@ -573,7 +575,7 @@ class PluginLocal extends EventEmitter< const localRoot = (this._localRoot = safetyPathNormalize(url)) const logseq: Partial = pkg.logseq || {} - // Pick legal attrs + // Pick legal attrs ;[ 'name', 'author', @@ -681,10 +683,10 @@ class PluginLocal extends EventEmitter< logseq plugin entry ${ - IS_DEV - ? `` - : `` - } + IS_DEV + ? `` + : `` + } @@ -1119,8 +1121,7 @@ class PluginLocal extends EventEmitter< * Host plugin core */ class LSPluginCore - extends EventEmitter< - | 'beforeenable' + extends EventEmitter<'beforeenable' | 'enabled' | 'beforedisable' | 'disabled' @@ -1133,10 +1134,8 @@ class LSPluginCore | 'settings-changed' | 'unlink-plugin' | 'beforereload' - | 'reloaded' - > - implements ILSPluginThemeManager -{ + | 'reloaded'> + implements ILSPluginThemeManager { private _isRegistering = false private _readyIndicator?: DeferredActor private readonly _hostMountedActor: DeferredActor = deferred() @@ -1150,10 +1149,8 @@ class LSPluginCore externals: [], } private readonly _registeredThemes = new Map() - private readonly _registeredPlugins = new Map< - PluginLocalIdentity, - PluginLocal - >() + private readonly _registeredPlugins = new Map() private _currentTheme: { pid: PluginLocalIdentity opt: Theme | LegacyTheme @@ -1229,21 +1226,22 @@ class LSPluginCore return } - const perfTable = new Map< - string, - { o: PluginLocal; s: number; e: number } - >() + const perfTable = new Map() const debugPerfInfo = () => { - const data = Array.from(perfTable.values()).reduce((ac, it) => { - const { options, status, disabled } = it.o + const data: any = Array.from(perfTable.values()).reduce((ac, it) => { + const { id, options, status, disabled } = it.o - ac[it.o.id] = { - name: options.name, - entry: options.entry, - status: status, - enabled: - typeof disabled === 'boolean' ? (!disabled ? '🟢' : '⚫️') : '🔴', - perf: !it.e ? it.o.loadErr : `${(it.e - it.s).toFixed(2)}ms`, + if (disabled !== true && + (options.entry || (!options.name && !options.entry))) { + ac[id] = { + name: options.name, + entry: options.entry, + status: status, + enabled: + typeof disabled === 'boolean' ? (!disabled ? '🟢' : '⚫️') : '🔴', + perf: !it.e ? it.o.loadErr : `${(it.e - it.s).toFixed(2)}ms`, + } } return ac @@ -1554,12 +1552,12 @@ class LSPluginCore await this.saveUserPreferences( theme.mode ? { - themes: { - ...this._userPreferences.themes, - mode: theme.mode, - [theme.mode]: theme, - }, - } + themes: { + ...this._userPreferences.themes, + mode: theme.mode, + [theme.mode]: theme, + }, + } : { theme: theme } ) } diff --git a/src/electron/electron/utils.cljs b/src/electron/electron/utils.cljs index babf6be5c2..a311392834 100644 --- a/src/electron/electron/utils.cljs +++ b/src/electron/electron/utils.cljs @@ -46,7 +46,7 @@ dirs (js->clj (fs/readdirSync plugins-root #js{"withFileTypes" true})) dirs (->> dirs (filter #(.isDirectory %)) - (filter #(not (string/starts-with? (.-name %) "_"))) + (filter (fn [f] (not (some #(string/starts-with? (.-name f) %) ["_" "."])))) (map #(path/join plugins-root (.-name %))))] dirs)) From 7bd32fb911f1ce67204a1e20141873fec920818b Mon Sep 17 00:00:00 2001 From: charlie Date: Mon, 1 Aug 2022 11:35:39 +0800 Subject: [PATCH 06/13] improve(plugin): update types --- libs/src/LSPlugin.user.ts | 8 ++++++-- libs/src/callable.apis.ts | 3 +++ src/main/frontend/components/page.cljs | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/libs/src/LSPlugin.user.ts b/libs/src/LSPlugin.user.ts index cb86e22cb6..aa07994cc5 100644 --- a/libs/src/LSPlugin.user.ts +++ b/libs/src/LSPlugin.user.ts @@ -5,6 +5,7 @@ import { safetyPathJoin, } from './helpers' import { LSPluginCaller } from './LSPlugin.caller' +import * as callableAPIs from './callable.apis' import { IAppProxy, IDBProxy, @@ -48,6 +49,9 @@ declare global { } } +type callableMethods = + keyof typeof callableAPIs | string // host exported SDK apis & host platform related apis + const PROXY_CONTINUE = Symbol.for('proxy-continue') const debug = Debug('LSPlugin:user') @@ -623,14 +627,14 @@ export class LSPluginUser }) } - _execCallableAPIAsync(method, ...args) { + _execCallableAPIAsync(method: callableMethods, ...args) { return this._caller.callAsync(`api:call`, { method, args, }) } - _execCallableAPI(method, ...args) { + _execCallableAPI(method: callableMethods, ...args) { this._caller.call(`api:call`, { method, args, diff --git a/libs/src/callable.apis.ts b/libs/src/callable.apis.ts index 797940c6fd..85860acea4 100644 --- a/libs/src/callable.apis.ts +++ b/libs/src/callable.apis.ts @@ -1,5 +1,8 @@ import { PluginLocal } from './LSPlugin.core' +/** + * Run in host + */ export function setSDKMetadata(this: PluginLocal, data: any) { if (this?.sdk && data) { this.sdk = Object.assign({}, this.sdk, data) diff --git a/src/main/frontend/components/page.cljs b/src/main/frontend/components/page.cljs index cd80c234cb..8420c56569 100644 --- a/src/main/frontend/components/page.cljs +++ b/src/main/frontend/components/page.cljs @@ -91,7 +91,7 @@ [:div.flex.flex-row.items-center.mr-2.ml-1 {:style {:height 24}} [:span.bullet-container.cursor [:span.bullet]]] - [:div.flex.flex-1 {:tabindex 0 + [:div.flex.flex-1 {:tabIndex 0 :on-key-press (fn [e] (when (= "Enter" (util/ekey e)) (handler-fn))) From af49427ef1b970dc17a487f0e24e2f360f484465 Mon Sep 17 00:00:00 2001 From: charlie Date: Wed, 3 Aug 2022 16:19:34 +0800 Subject: [PATCH 07/13] improve(plugin): api of select single block --- libs/src/LSPlugin.ts | 1 + src/main/logseq/api.cljs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/libs/src/LSPlugin.ts b/libs/src/LSPlugin.ts index 9bf22980d9..8b1fdc44d3 100644 --- a/libs/src/LSPlugin.ts +++ b/libs/src/LSPlugin.ts @@ -650,6 +650,7 @@ export interface IEditorProxy extends Record { ) => Promise editBlock: (srcBlock: BlockIdentity, opts?: { pos: number }) => Promise + selectBlock: (srcBlock: BlockIdentity) => Promise upsertBlockProperty: ( block: BlockIdentity, diff --git a/src/main/logseq/api.cljs b/src/main/logseq/api.cljs index 15c5c68bbe..06bf447ec1 100644 --- a/src/main/logseq/api.cljs +++ b/src/main/logseq/api.cljs @@ -442,6 +442,11 @@ [block-uuid] (editor-handler/open-block-in-sidebar! (uuid block-uuid))) +(def ^:export select_block + (fn [block-uuid] + (when-let [block (db-model/get-block-by-uuid block-uuid)] + (editor-handler/select-block! (:block/uuid block)) nil))) + (def ^:export edit_block (fn [block-uuid ^js opts] (when-let [block-uuid (and block-uuid (uuid block-uuid))] From 040c8282be8bd76d2fceb5431c8e9d708074dddd Mon Sep 17 00:00:00 2001 From: charlie Date: Sun, 7 Aug 2022 14:37:04 +0800 Subject: [PATCH 08/13] chore: build libs core --- resources/js/lsplugin.core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/lsplugin.core.js b/resources/js/lsplugin.core.js index 3fa7718b09..de2a8fe314 100644 --- a/resources/js/lsplugin.core.js +++ b/resources/js/lsplugin.core.js @@ -1,2 +1,2 @@ /*! For license information please see lsplugin.core.js.LICENSE.txt */ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.LSPlugin=t():e.LSPlugin=t()}(self,(()=>(()=>{var e={227:(e,t,n)=>{var r=n(155);t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;t.splice(1,0,n,"color: inherit");let r=0,i=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(r++,"%c"===e&&(i=r))})),t.splice(i,0,n)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&void 0!==r&&"env"in r&&(e=r.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=n(447)(t);const{formatters:i}=e.exports;i.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},447:(e,t,n)=>{e.exports=function(e){function t(e){let n,i,o,s=null;function a(...e){if(!a.enabled)return;const r=a,i=Number(new Date),o=i-(n||i);r.diff=o,r.prev=n,r.curr=i,n=i,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let s=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((n,i)=>{if("%%"===n)return"%";s++;const o=t.formatters[i];if("function"==typeof o){const t=e[s];n=o.call(r,t),e.splice(s,1),s--}return n})),t.formatArgs.call(r,e),(r.log||t.log).apply(r,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=r,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==s?s:(i!==t.namespaces&&(i=t.namespaces,o=t.enabled(e)),o),set:e=>{s=e}}),"function"==typeof t.init&&t.init(a),a}function r(e,n){const r=t(this.namespace+(void 0===n?":":n)+e);return r.log=this.log,r}function i(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(i),...t.skips.map(i).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let n;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const r=("string"==typeof e?e:"").split(/[\s,]+/),i=r.length;for(n=0;n{t[n]=e[n]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let n=0;for(let t=0;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n1?n-1:0),i=1;i/gm),W=h(/^data-[\-\w.\u00B7-\uFFFF]/),G=h(/^aria-[\-\w]+$/),J=h(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Z=h(/^(?:\w+script|data):/i),K=h(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),V=h(/^html$/i),Y=function(){return"undefined"==typeof window?null:window},X=function(t,n){if("object"!==e(t)||"function"!=typeof t.createPolicy)return null;var r=null,i="data-tt-policy-suffix";n.currentScript&&n.currentScript.hasAttribute(i)&&(r=n.currentScript.getAttribute(i));var o="dompurify"+(r?"#"+r:"");try{return t.createPolicy(o,{createHTML:function(e){return e}})}catch(e){return console.warn("TrustedTypes policy "+o+" could not be created."),null}};return function t(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:Y(),r=function(e){return t(e)};if(r.version="2.3.8",r.removed=[],!n||!n.document||9!==n.document.nodeType)return r.isSupported=!1,r;var o=n.document,s=n.document,a=n.DocumentFragment,c=n.HTMLTemplateElement,l=n.Node,u=n.Element,h=n.NodeFilter,p=n.NamedNodeMap,f=void 0===p?n.NamedNodeMap||n.MozNamedAttrMap:p,g=n.HTMLFormElement,m=n.DOMParser,y=n.trustedTypes,k=u.prototype,Q=I(k,"cloneNode"),ee=I(k,"nextSibling"),te=I(k,"childNodes"),ne=I(k,"parentNode");if("function"==typeof c){var re=s.createElement("template");re.content&&re.content.ownerDocument&&(s=re.content.ownerDocument)}var ie=X(y,o),oe=ie?ie.createHTML(""):"",se=s,ae=se.implementation,ce=se.createNodeIterator,le=se.createDocumentFragment,ue=se.getElementsByTagName,de=o.importNode,he={};try{he=j(s).documentMode?s.documentMode:{}}catch(e){}var pe={};r.isSupported="function"==typeof ne&&ae&&void 0!==ae.createHTMLDocument&&9!==he;var fe,ge,me=q,ye=B,_e=W,be=G,ve=Z,we=K,xe=J,Ce=null,Se=T({},[].concat(i(L),i(N),i(M),i(F),i(D))),Ee=null,Oe=T({},[].concat(i(U),i($),i(z),i(H))),Ae=Object.seal(Object.create(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),ke=null,Te=null,je=!0,Ie=!0,Le=!1,Ne=!1,Me=!1,Re=!1,Fe=!1,Pe=!1,De=!1,Ue=!1,$e=!0,ze=!0,He=!1,qe={},Be=null,We=T({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]),Ge=null,Je=T({},["audio","video","img","source","image","track"]),Ze=null,Ke=T({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Ve="http://www.w3.org/1998/Math/MathML",Ye="http://www.w3.org/2000/svg",Xe="http://www.w3.org/1999/xhtml",Qe=Xe,et=!1,tt=["application/xhtml+xml","text/html"],nt="text/html",rt=null,it=s.createElement("form"),ot=function(e){return e instanceof RegExp||e instanceof Function},st=function(t){rt&&rt===t||(t&&"object"===e(t)||(t={}),t=j(t),Ce="ALLOWED_TAGS"in t?T({},t.ALLOWED_TAGS):Se,Ee="ALLOWED_ATTR"in t?T({},t.ALLOWED_ATTR):Oe,Ze="ADD_URI_SAFE_ATTR"in t?T(j(Ke),t.ADD_URI_SAFE_ATTR):Ke,Ge="ADD_DATA_URI_TAGS"in t?T(j(Je),t.ADD_DATA_URI_TAGS):Je,Be="FORBID_CONTENTS"in t?T({},t.FORBID_CONTENTS):We,ke="FORBID_TAGS"in t?T({},t.FORBID_TAGS):{},Te="FORBID_ATTR"in t?T({},t.FORBID_ATTR):{},qe="USE_PROFILES"in t&&t.USE_PROFILES,je=!1!==t.ALLOW_ARIA_ATTR,Ie=!1!==t.ALLOW_DATA_ATTR,Le=t.ALLOW_UNKNOWN_PROTOCOLS||!1,Ne=t.SAFE_FOR_TEMPLATES||!1,Me=t.WHOLE_DOCUMENT||!1,Pe=t.RETURN_DOM||!1,De=t.RETURN_DOM_FRAGMENT||!1,Ue=t.RETURN_TRUSTED_TYPE||!1,Fe=t.FORCE_BODY||!1,$e=!1!==t.SANITIZE_DOM,ze=!1!==t.KEEP_CONTENT,He=t.IN_PLACE||!1,xe=t.ALLOWED_URI_REGEXP||xe,Qe=t.NAMESPACE||Xe,t.CUSTOM_ELEMENT_HANDLING&&ot(t.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(Ae.tagNameCheck=t.CUSTOM_ELEMENT_HANDLING.tagNameCheck),t.CUSTOM_ELEMENT_HANDLING&&ot(t.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(Ae.attributeNameCheck=t.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),t.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof t.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(Ae.allowCustomizedBuiltInElements=t.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),fe=fe=-1===tt.indexOf(t.PARSER_MEDIA_TYPE)?nt:t.PARSER_MEDIA_TYPE,ge="application/xhtml+xml"===fe?function(e){return e}:w,Ne&&(Ie=!1),De&&(Pe=!0),qe&&(Ce=T({},i(D)),Ee=[],!0===qe.html&&(T(Ce,L),T(Ee,U)),!0===qe.svg&&(T(Ce,N),T(Ee,$),T(Ee,H)),!0===qe.svgFilters&&(T(Ce,M),T(Ee,$),T(Ee,H)),!0===qe.mathMl&&(T(Ce,F),T(Ee,z),T(Ee,H))),t.ADD_TAGS&&(Ce===Se&&(Ce=j(Ce)),T(Ce,t.ADD_TAGS)),t.ADD_ATTR&&(Ee===Oe&&(Ee=j(Ee)),T(Ee,t.ADD_ATTR)),t.ADD_URI_SAFE_ATTR&&T(Ze,t.ADD_URI_SAFE_ATTR),t.FORBID_CONTENTS&&(Be===We&&(Be=j(Be)),T(Be,t.FORBID_CONTENTS)),ze&&(Ce["#text"]=!0),Me&&T(Ce,["html","head","body"]),Ce.table&&(T(Ce,["tbody"]),delete ke.tbody),d&&d(t),rt=t)},at=T({},["mi","mo","mn","ms","mtext"]),ct=T({},["foreignobject","desc","title","annotation-xml"]),lt=T({},["title","style","font","a","script"]),ut=T({},N);T(ut,M),T(ut,R);var dt=T({},F);T(dt,P);var ht=function(e){var t=ne(e);t&&t.tagName||(t={namespaceURI:Xe,tagName:"template"});var n=w(e.tagName),r=w(t.tagName);return e.namespaceURI===Ye?t.namespaceURI===Xe?"svg"===n:t.namespaceURI===Ve?"svg"===n&&("annotation-xml"===r||at[r]):Boolean(ut[n]):e.namespaceURI===Ve?t.namespaceURI===Xe?"math"===n:t.namespaceURI===Ye?"math"===n&&ct[r]:Boolean(dt[n]):e.namespaceURI===Xe&&!(t.namespaceURI===Ye&&!ct[r])&&!(t.namespaceURI===Ve&&!at[r])&&!dt[n]&&(lt[n]||!ut[n])},pt=function(e){v(r.removed,{element:e});try{e.parentNode.removeChild(e)}catch(t){try{e.outerHTML=oe}catch(t){e.remove()}}},ft=function(e,t){try{v(r.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){v(r.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e&&!Ee[e])if(Pe||De)try{pt(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},gt=function(e){var t,n;if(Fe)e=""+e;else{var r=x(e,/^[\r\n\t ]+/);n=r&&r[0]}"application/xhtml+xml"===fe&&(e=''+e+"");var i=ie?ie.createHTML(e):e;if(Qe===Xe)try{t=(new m).parseFromString(i,fe)}catch(e){}if(!t||!t.documentElement){t=ae.createDocument(Qe,"template",null);try{t.documentElement.innerHTML=et?"":i}catch(e){}}var o=t.body||t.documentElement;return e&&n&&o.insertBefore(s.createTextNode(n),o.childNodes[0]||null),Qe===Xe?ue.call(t,Me?"html":"body")[0]:Me?t.documentElement:o},mt=function(e){return ce.call(e.ownerDocument||e,e,h.SHOW_ELEMENT|h.SHOW_COMMENT|h.SHOW_TEXT,null,!1)},yt=function(e){return e instanceof g&&("string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||!(e.attributes instanceof f)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore)},_t=function(t){return"object"===e(l)?t instanceof l:t&&"object"===e(t)&&"number"==typeof t.nodeType&&"string"==typeof t.nodeName},bt=function(e,t,n){pe[e]&&_(pe[e],(function(e){e.call(r,t,n,rt)}))},vt=function(e){var t;if(bt("beforeSanitizeElements",e,null),yt(e))return pt(e),!0;if(O(/[\u0080-\uFFFF]/,e.nodeName))return pt(e),!0;var n=ge(e.nodeName);if(bt("uponSanitizeElement",e,{tagName:n,allowedTags:Ce}),e.hasChildNodes()&&!_t(e.firstElementChild)&&(!_t(e.content)||!_t(e.content.firstElementChild))&&O(/<[/\w]/g,e.innerHTML)&&O(/<[/\w]/g,e.textContent))return pt(e),!0;if("select"===n&&O(/