Ask me anything about agentregistry: publishing artifacts, deployments, the arctl CLI, or the registry API.
+Note: AI-generated content might contain errors; please verify and test all returned information.
+Tip: one topic per conversation gives the best results. Use the + button in the chat header to start a new conversation.
++ Your feedback helps us improve assistant answers and identify docs gaps we should fix. +
+ ++ Need more help? Join us on Discord: + https://discord.gg/Af8bX99dbX +
++ Want to use your own agent? Add the Solo MCP server to query our docs directly. Get started here: + https://search.solo.io/. +
+…` on one line, because
+ * MarkdownRenderer.flush() matches exactly that shape when it injects the
+ * per-block copy buttons (see ui.js).
+ */
+export function configureMarked() {
+ if (!markedConfigured) {
+ marked.setOptions({
+ breaks: true,
+ gfm: true,
+ });
+ marked.use({
+ renderer: {
+ code(code, infostring) {
+ // marked v11 hands the renderer an object in some call paths and
+ // positional arguments in others; accept both.
+ const isObj = typeof code === 'object' && code !== null;
+ const text = String(isObj ? code.text : code);
+ const lang = isObj ? code.lang : infostring;
+
+ const { html, language } = renderCode(text, lang);
+ const classes = ['hljs'];
+ if (language) classes.push(`language-${language}`);
+ return `${html}\n`;
+ },
+ },
+ });
+ markedConfigured = true;
+ }
+
+ return marked;
+}
+
+/**
+ * Parse markdown to HTML
+ * @param {string} content - Markdown content
+ * @returns {string} HTML string
+ */
+export function parseMarkdown(content) {
+ const md = configureMarked();
+
+ if (md && typeof md.parse === 'function') {
+ return sanitize(md.parse(content));
+ }
+
+ // Fallback to plain text with basic escaping
+ return escapeHtml(content).replace(/\n/g, ']*)>([\s\S]*?)<\/code><\/pre>/g, (match, attrs, escapedCode) => {
+ const rawCode = escapedCode
+ .replace(/<[^>]+>/g, '')
+ .replace(/&/g, '&')
+ .replace(/</g, '<')
+ .replace(/>/g, '>')
+ .replace(/'/g, "'")
+ .replace(/"/g, '"');
+ const encodedCode = encodeURIComponent(rawCode);
+ return `${escapedCode}
`;
+ });
+}
+
+/**
+ * MarkdownRenderer - Handles buffered markdown rendering with code block streaming
+ */
+export class MarkdownRenderer {
+ constructor(renderFn) {
+ this.renderFn = renderFn; // marked.parse or fallback
+ this.tokenBuffer = '';
+ this.renderTimeout = null;
+ this.content = '';
+ this.lastRenderedHTML = '';
+ this.lastRenderedCodeBlockCount = 0;
+ this.lastCodeBlockLineCount = 0;
+ }
+
+ /**
+ * Add tokens to the buffer
+ */
+ addToken(token) {
+ this.tokenBuffer += token;
+
+ // Render if buffer contains newline or is too large
+ const hasNewline = this.tokenBuffer.includes('\n');
+ const bufferTooLarge = this.tokenBuffer.length > 50;
+
+ if (hasNewline || bufferTooLarge) {
+ if (this.renderTimeout) {
+ clearTimeout(this.renderTimeout);
+ this.renderTimeout = null;
+ }
+ this.render();
+ } else {
+ // Set timeout to render if no newline comes soon
+ if (this.renderTimeout) {
+ clearTimeout(this.renderTimeout);
+ }
+ this.renderTimeout = setTimeout(() => {
+ this.render();
+ this.renderTimeout = null;
+ }, 100);
+ }
+ }
+
+ /**
+ * Render buffered content with line-by-line code block reveal
+ */
+ render() {
+ if (this.renderTimeout) {
+ clearTimeout(this.renderTimeout);
+ this.renderTimeout = null;
+ }
+
+ if (this.tokenBuffer.length === 0) {
+ // Return cached HTML if buffer is empty
+ return this.lastRenderedHTML;
+ }
+
+ this.content += this.tokenBuffer;
+ this.tokenBuffer = '';
+
+ // Check for incomplete code blocks
+ const codeBlockMatches = this.content.match(/```/g);
+ const codeBlockCount = codeBlockMatches ? codeBlockMatches.length : 0;
+ const hasIncompleteCodeBlock = codeBlockCount % 2 === 1;
+
+ let contentToRender = this.content;
+ let incompleteCodeBlockHTML = '';
+
+ if (hasIncompleteCodeBlock) {
+ const lastCodeBlockStart = this.content.lastIndexOf('```');
+ const beforeCodeBlock = this.content.substring(0, lastCodeBlockStart);
+ const codeBlockContent = this.content.substring(lastCodeBlockStart + 3);
+
+ // Extract language
+ const firstLineBreak = codeBlockContent.indexOf('\n');
+ const codeText = firstLineBreak >= 0
+ ? codeBlockContent.substring(firstLineBreak + 1)
+ : codeBlockContent;
+
+ const lines = codeText.split('\n');
+ const completeLines = lines.slice(0, -1);
+ const incompleteLine = lines[lines.length - 1];
+ const newLineCount = completeLines.length;
+
+ incompleteCodeBlockHTML = '';
+ completeLines.forEach((line, index) => {
+ const escapedLine = this._escapeHtml(line);
+ if (index >= this.lastCodeBlockLineCount) {
+ incompleteCodeBlockHTML += `${escapedLine}\n`;
+ } else {
+ incompleteCodeBlockHTML += escapedLine + '\n';
+ }
+ });
+
+ this.lastCodeBlockLineCount = newLineCount;
+
+ if (incompleteLine) {
+ incompleteCodeBlockHTML += this._escapeHtml(incompleteLine);
+ }
+ incompleteCodeBlockHTML += '
';
+
+ contentToRender = beforeCodeBlock;
+ }
+
+ // Render markdown for complete parts
+ let html = this.renderFn(contentToRender) || '';
+
+ // Append incomplete code block (no copy button while still streaming)
+ if (hasIncompleteCodeBlock) {
+ html += incompleteCodeBlockHTML;
+ }
+
+ // Track completed code blocks
+ if (!hasIncompleteCodeBlock && codeBlockCount > this.lastRenderedCodeBlockCount) {
+ this.lastRenderedCodeBlockCount = codeBlockCount;
+ this.lastCodeBlockLineCount = 0;
+ }
+
+ // Cache the rendered HTML
+ this.lastRenderedHTML = html;
+
+ return html;
+ }
+
+ /**
+ * Flush any remaining buffered content and inject code copy buttons.
+ * Called once when streaming completes.
+ */
+ flush() {
+ if (this.renderTimeout) {
+ clearTimeout(this.renderTimeout);
+ this.renderTimeout = null;
+ }
+ this.render();
+ this.lastRenderedHTML = injectCodeCopyButtons(this.lastRenderedHTML);
+ return this.lastRenderedHTML;
+ }
+
+ /**
+ * Reset the renderer state
+ */
+ reset() {
+ this.tokenBuffer = '';
+ this.content = '';
+ this.lastRenderedHTML = '';
+ this.lastRenderedCodeBlockCount = 0;
+ this.lastCodeBlockLineCount = 0;
+ if (this.renderTimeout) {
+ clearTimeout(this.renderTimeout);
+ this.renderTimeout = null;
+ }
+ }
+
+ /**
+ * Get the current rendered content
+ */
+ getContent() {
+ return this.content;
+ }
+
+ _escapeHtml(text) {
+ return text.replace(//g, '>');
+ }
+}
+
+/**
+ * Resize button SVG icons
+ */
+export const RESIZE_ICONS = {
+ expand: `
+
+ `,
+ collapse: `
+
+ `
+};
diff --git a/assets/js/vendor/README.md b/assets/js/vendor/README.md
new file mode 100644
index 0000000..d138cd1
--- /dev/null
+++ b/assets/js/vendor/README.md
@@ -0,0 +1,48 @@
+# Vendored JS libraries for the chatbot widget
+
+These files are vendored (committed to the repo) so the chatbot has **zero
+external CDN script dependencies**: no third-party origin is contacted when a
+docs page loads, a `script-src 'self'` needs no CDN entry, and the framework
+tests' console-error spec does not depend on network access. Every file here
+goes through Hugo's `js.Build` bundle, which also sidesteps a CSP that forbids `'unsafe-eval'`, and
+keeps the widget portable to other Hugo doc sites (copy this directory along
+with `assets/js/chatbot/` and `layouts/_partials/chatbot.html`).
+
+Upstream (`solo-io/docs`) vendors only the three markdown/sanitizer modules and
+loads the full 36-language highlight.js build from cdnjs. Here it is the core
+plus one grammar, bundled — ~22 KB against 120 KB and one fewer request.
+
+| File | Library | Version | Source |
+|------|---------|---------|--------|
+| `preact-htm.module.js` | htm/preact standalone (preact core + hooks + htm's `html` tagged template, bundled, no external imports) | htm 3.1.1 (bundles preact 10.x) | https://unpkg.com/htm@3.1.1/preact/standalone.module.js |
+| `marked.esm.js` | marked (markdown renderer), dependency-free ESM | 11.1.1 | https://unpkg.com/marked@11.1.1/lib/marked.esm.js |
+| `purify.es.mjs` | DOMPurify (HTML sanitizer), dependency-free ESM. Sanitizes `marked` output before it is injected via `dangerouslySetInnerHTML`, since model responses are untrusted and prod's CSP allows `script-src 'unsafe-inline'`. | 3.4.11 | https://unpkg.com/dompurify@3.4.11/dist/purify.es.mjs |
+| `hljs-core.min.js` | highlight.js core (ESM), no bundled grammars | 11.9.0 | https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/core.min.js |
+| `hljs-yaml.min.js` | highlight.js YAML grammar (ESM). The ONLY grammar registered — see the header of `assets/js/chatbot/markdown.js` for why, and for how to add another. | 11.9.0 | https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/languages/yaml.min.js |
+
+Exports of `preact-htm.module.js`: `html, h, render, Component, createContext,
+useState, useReducer, useEffect, useLayoutEffect, useRef, useImperativeHandle,
+useMemo, useCallback, useContext, useDebugValue, useErrorBoundary`.
+
+## Updating
+
+1. Re-download from unpkg with a new pinned version (same URLs, bump the version).
+2. Verify the file is still self-contained (no `import ... from "bare-specifier"`)
+ and valid ESM:
+
+ ```sh
+ node --input-type=module -e "console.log(Object.keys(await import('./assets/js/vendor/preact-htm.module.js')).join(','))"
+ node --input-type=module -e "console.log(typeof (await import('./assets/js/vendor/marked.esm.js')).marked.parse)"
+ node --input-type=module -e "console.log(typeof (await import('./assets/js/vendor/purify.es.mjs')).default)"
+ ```
+
+ (DOMPurify's `.sanitize` only materializes when a DOM/`window` is present, so
+ in Node the default export is the `createDOMPurify` factory — `function`. In
+ the browser it is a ready instance with `.sanitize`.)
+3. Rebuild the site and re-test the chatbot.
+
+Note: the highlight.js *script* is intentionally NOT vendored — it loads from
+cdnjs.cloudflare.com, which prod's CSP `script-src` allowlists, and the widget
+degrades gracefully if it's absent. Its theme *stylesheets* ARE vendored (in
+`assets/css/vendor/hljs-github{,-dark}.min.css`) because prod's `style-src`
+does not include cdnjs, so CDN-hosted CSS gets blocked.
diff --git a/assets/js/vendor/hljs-core.min.js b/assets/js/vendor/hljs-core.min.js
new file mode 100644
index 0000000..b85b097
--- /dev/null
+++ b/assets/js/vendor/hljs-core.min.js
@@ -0,0 +1,307 @@
+/*!
+ Highlight.js v11.9.0 (git: f47103d4f1)
+ (c) 2006-2023 undefined and other contributors
+ License: BSD-3-Clause
+ */
+function e(t){return t instanceof Map?t.clear=t.delete=t.set=()=>{
+throw Error("map is read-only")}:t instanceof Set&&(t.add=t.clear=t.delete=()=>{
+throw Error("set is read-only")
+}),Object.freeze(t),Object.getOwnPropertyNames(t).forEach((n=>{
+const i=t[n],s=typeof i;"object"!==s&&"function"!==s||Object.isFrozen(i)||e(i)
+})),t}class t{constructor(e){
+void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}
+ignoreMatch(){this.isMatchIgnored=!0}}function n(e){
+return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")
+}function i(e,...t){const n=Object.create(null);for(const t in e)n[t]=e[t]
+;return t.forEach((e=>{for(const t in e)n[t]=e[t]})),n}const s=e=>!!e.scope
+;class r{constructor(e,t){
+this.buffer="",this.classPrefix=t.classPrefix,e.walk(this)}addText(e){
+this.buffer+=n(e)}openNode(e){if(!s(e))return;const t=((e,{prefix:t})=>{
+if(e.startsWith("language:"))return e.replace("language:","language-")
+;if(e.includes(".")){const n=e.split(".")
+;return[`${t}${n.shift()}`,...n.map(((e,t)=>`${e}${"_".repeat(t+1)}`))].join(" ")
+}return`${t}${e}`})(e.scope,{prefix:this.classPrefix});this.span(t)}
+closeNode(e){s(e)&&(this.buffer+="")}value(){return this.buffer}span(e){
+this.buffer+=``}}const o=(e={})=>{const t={children:[]}
+;return Object.assign(t,e),t};class a{constructor(){
+this.rootNode=o(),this.stack=[this.rootNode]}get top(){
+return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){
+this.top.children.push(e)}openNode(e){const t=o({scope:e})
+;this.add(t),this.stack.push(t)}closeNode(){
+if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){
+for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}
+walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,t){
+return"string"==typeof t?e.addText(t):t.children&&(e.openNode(t),
+t.children.forEach((t=>this._walk(e,t))),e.closeNode(t)),e}static _collapse(e){
+"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{
+a._collapse(e)})))}}class c extends a{constructor(e){super(),this.options=e}
+addText(e){""!==e&&this.add(e)}startScope(e){this.openNode(e)}endScope(){
+this.closeNode()}__addSublanguage(e,t){const n=e.root
+;t&&(n.scope="language:"+t),this.add(n)}toHTML(){
+return new r(this,this.options).value()}finalize(){
+return this.closeAllNodes(),!0}}function l(e){
+return e?"string"==typeof e?e:e.source:null}function g(e){return h("(?=",e,")")}
+function u(e){return h("(?:",e,")*")}function d(e){return h("(?:",e,")?")}
+function h(...e){return e.map((e=>l(e))).join("")}function f(...e){const t=(e=>{
+const t=e[e.length-1]
+;return"object"==typeof t&&t.constructor===Object?(e.splice(e.length-1,1),t):{}
+})(e);return"("+(t.capture?"":"?:")+e.map((e=>l(e))).join("|")+")"}
+function p(e){return RegExp(e.toString()+"|").exec("").length-1}
+const b=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./
+;function m(e,{joinWith:t}){let n=0;return e.map((e=>{n+=1;const t=n
+;let i=l(e),s="";for(;i.length>0;){const e=b.exec(i);if(!e){s+=i;break}
+s+=i.substring(0,e.index),
+i=i.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?s+="\\"+(Number(e[1])+t):(s+=e[0],
+"("===e[0]&&n++)}return s})).map((e=>`(${e})`)).join(t)}
+const E="[a-zA-Z]\\w*",x="[a-zA-Z_]\\w*",w="\\b\\d+(\\.\\d+)?",y="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",_="\\b(0b[01]+)",O={
+begin:"\\\\[\\s\\S]",relevance:0},k={scope:"string",begin:"'",end:"'",
+illegal:"\\n",contains:[O]},v={scope:"string",begin:'"',end:'"',illegal:"\\n",
+contains:[O]},N=(e,t,n={})=>{const s=i({scope:"comment",begin:e,end:t,
+contains:[]},n);s.contains.push({scope:"doctag",
+begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",
+end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0})
+;const r=f("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/)
+;return s.contains.push({begin:h(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),s
+},S=N("//","$"),M=N("/\\*","\\*/"),R=N("#","$");var A=Object.freeze({
+__proto__:null,APOS_STRING_MODE:k,BACKSLASH_ESCAPE:O,BINARY_NUMBER_MODE:{
+scope:"number",begin:_,relevance:0},BINARY_NUMBER_RE:_,COMMENT:N,
+C_BLOCK_COMMENT_MODE:M,C_LINE_COMMENT_MODE:S,C_NUMBER_MODE:{scope:"number",
+begin:y,relevance:0},C_NUMBER_RE:y,END_SAME_AS_BEGIN:e=>Object.assign(e,{
+"on:begin":(e,t)=>{t.data._beginMatch=e[1]},"on:end":(e,t)=>{
+t.data._beginMatch!==e[1]&&t.ignoreMatch()}}),HASH_COMMENT_MODE:R,IDENT_RE:E,
+MATCH_NOTHING_RE:/\b\B/,METHOD_GUARD:{begin:"\\.\\s*"+x,relevance:0},
+NUMBER_MODE:{scope:"number",begin:w,relevance:0},NUMBER_RE:w,
+PHRASAL_WORDS_MODE:{
+begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
+},QUOTE_STRING_MODE:v,REGEXP_MODE:{scope:"regexp",begin:/\/(?=[^/\n]*\/)/,
+end:/\/[gimuy]*/,contains:[O,{begin:/\[/,end:/\]/,relevance:0,contains:[O]}]},
+RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",
+SHEBANG:(e={})=>{const t=/^#![ ]*\//
+;return e.binary&&(e.begin=h(t,/.*\b/,e.binary,/\b.*/)),i({scope:"meta",begin:t,
+end:/$/,relevance:0,"on:begin":(e,t)=>{0!==e.index&&t.ignoreMatch()}},e)},
+TITLE_MODE:{scope:"title",begin:E,relevance:0},UNDERSCORE_IDENT_RE:x,
+UNDERSCORE_TITLE_MODE:{scope:"title",begin:x,relevance:0}});function j(e,t){
+"."===e.input[e.index-1]&&t.ignoreMatch()}function I(e,t){
+void 0!==e.className&&(e.scope=e.className,delete e.className)}function T(e,t){
+t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",
+e.__beforeBegin=j,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,
+void 0===e.relevance&&(e.relevance=0))}function L(e,t){
+Array.isArray(e.illegal)&&(e.illegal=f(...e.illegal))}function B(e,t){
+if(e.match){
+if(e.begin||e.end)throw Error("begin & end are not supported with match")
+;e.begin=e.match,delete e.match}}function P(e,t){
+void 0===e.relevance&&(e.relevance=1)}const D=(e,t)=>{if(!e.beforeMatch)return
+;if(e.starts)throw Error("beforeMatch cannot be used with starts")
+;const n=Object.assign({},e);Object.keys(e).forEach((t=>{delete e[t]
+})),e.keywords=n.keywords,e.begin=h(n.beforeMatch,g(n.begin)),e.starts={
+relevance:0,contains:[Object.assign(n,{endsParent:!0})]
+},e.relevance=0,delete n.beforeMatch
+},H=["of","and","for","in","not","or","if","then","parent","list","value"],C="keyword"
+;function $(e,t,n=C){const i=Object.create(null)
+;return"string"==typeof e?s(n,e.split(" ")):Array.isArray(e)?s(n,e):Object.keys(e).forEach((n=>{
+Object.assign(i,$(e[n],t,n))})),i;function s(e,n){
+t&&(n=n.map((e=>e.toLowerCase()))),n.forEach((t=>{const n=t.split("|")
+;i[n[0]]=[e,U(n[0],n[1])]}))}}function U(e,t){
+return t?Number(t):(e=>H.includes(e.toLowerCase()))(e)?0:1}const z={},W=e=>{
+console.error(e)},X=(e,...t)=>{console.log("WARN: "+e,...t)},G=(e,t)=>{
+z[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),z[`${e}/${t}`]=!0)
+},K=Error();function F(e,t,{key:n}){let i=0;const s=e[n],r={},o={}
+;for(let e=1;e<=t.length;e++)o[e+i]=s[e],r[e+i]=!0,i+=p(t[e-1])
+;e[n]=o,e[n]._emit=r,e[n]._multi=!0}function Z(e){(e=>{
+e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope,
+delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={
+_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope
+}),(e=>{if(Array.isArray(e.begin)){
+if(e.skip||e.excludeBegin||e.returnBegin)throw W("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),
+K
+;if("object"!=typeof e.beginScope||null===e.beginScope)throw W("beginScope must be object"),
+K;F(e,e.begin,{key:"beginScope"}),e.begin=m(e.begin,{joinWith:""})}})(e),(e=>{
+if(Array.isArray(e.end)){
+if(e.skip||e.excludeEnd||e.returnEnd)throw W("skip, excludeEnd, returnEnd not compatible with endScope: {}"),
+K
+;if("object"!=typeof e.endScope||null===e.endScope)throw W("endScope must be object"),
+K;F(e,e.end,{key:"endScope"}),e.end=m(e.end,{joinWith:""})}})(e)}function V(e){
+function t(t,n){
+return RegExp(l(t),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(n?"g":""))
+}class n{constructor(){
+this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}
+addRule(e,t){
+t.position=this.position++,this.matchIndexes[this.matchAt]=t,this.regexes.push([t,e]),
+this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null)
+;const e=this.regexes.map((e=>e[1]));this.matcherRe=t(m(e,{joinWith:"|"
+}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex
+;const t=this.matcherRe.exec(e);if(!t)return null
+;const n=t.findIndex(((e,t)=>t>0&&void 0!==e)),i=this.matchIndexes[n]
+;return t.splice(0,n),Object.assign(t,i)}}class s{constructor(){
+this.rules=[],this.multiRegexes=[],
+this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){
+if(this.multiRegexes[e])return this.multiRegexes[e];const t=new n
+;return this.rules.slice(e).forEach((([e,n])=>t.addRule(e,n))),
+t.compile(),this.multiRegexes[e]=t,t}resumingScanAtSamePosition(){
+return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,t){
+this.rules.push([e,t]),"begin"===t.type&&this.count++}exec(e){
+const t=this.getMatcher(this.regexIndex);t.lastIndex=this.lastIndex
+;let n=t.exec(e)
+;if(this.resumingScanAtSamePosition())if(n&&n.index===this.lastIndex);else{
+const t=this.getMatcher(0);t.lastIndex=this.lastIndex+1,n=t.exec(e)}
+return n&&(this.regexIndex+=n.position+1,
+this.regexIndex===this.count&&this.considerAll()),n}}
+if(e.compilerExtensions||(e.compilerExtensions=[]),
+e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.")
+;return e.classNameAliases=i(e.classNameAliases||{}),function n(r,o){const a=r
+;if(r.isCompiled)return a
+;[I,B,Z,D].forEach((e=>e(r,o))),e.compilerExtensions.forEach((e=>e(r,o))),
+r.__beforeBegin=null,[T,L,P].forEach((e=>e(r,o))),r.isCompiled=!0;let c=null
+;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords),
+c=r.keywords.$pattern,
+delete r.keywords.$pattern),c=c||/\w+/,r.keywords&&(r.keywords=$(r.keywords,e.case_insensitive)),
+a.keywordPatternRe=t(c,!0),
+o&&(r.begin||(r.begin=/\B|\b/),a.beginRe=t(a.begin),r.end||r.endsWithParent||(r.end=/\B|\b/),
+r.end&&(a.endRe=t(a.end)),
+a.terminatorEnd=l(a.end)||"",r.endsWithParent&&o.terminatorEnd&&(a.terminatorEnd+=(r.end?"|":"")+o.terminatorEnd)),
+r.illegal&&(a.illegalRe=t(r.illegal)),
+r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((t=>i(e,{
+variants:null},t)))),e.cachedVariants?e.cachedVariants:q(e)?i(e,{
+starts:e.starts?i(e.starts):null
+}):Object.isFrozen(e)?i(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{n(e,a)
+})),r.starts&&n(r.starts,o),a.matcher=(e=>{const t=new s
+;return e.contains.forEach((e=>t.addRule(e.begin,{rule:e,type:"begin"
+}))),e.terminatorEnd&&t.addRule(e.terminatorEnd,{type:"end"
+}),e.illegal&&t.addRule(e.illegal,{type:"illegal"}),t})(a),a}(e)}function q(e){
+return!!e&&(e.endsWithParent||q(e.starts))}class J extends Error{
+constructor(e,t){super(e),this.name="HTMLInjectionError",this.html=t}}
+const Y=n,Q=i,ee=Symbol("nomatch"),te=n=>{
+const i=Object.create(null),s=Object.create(null),r=[];let o=!0
+;const a="Could not find the language '{}', did you forget to load/include a language module?",l={
+disableAutodetect:!0,name:"Plain text",contains:[]};let p={
+ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,
+languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",
+cssSelector:"pre code",languages:null,__emitter:c};function b(e){
+return p.noHighlightRe.test(e)}function m(e,t,n){let i="",s=""
+;"object"==typeof t?(i=e,
+n=t.ignoreIllegals,s=t.language):(G("10.7.0","highlight(lang, code, ...args) has been deprecated."),
+G("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),
+s=e,i=t),void 0===n&&(n=!0);const r={code:i,language:s};N("before:highlight",r)
+;const o=r.result?r.result:E(r.language,r.code,n)
+;return o.code=r.code,N("after:highlight",o),o}function E(e,n,s,r){
+const c=Object.create(null);function l(){if(!N.keywords)return void M.addText(R)
+;let e=0;N.keywordPatternRe.lastIndex=0;let t=N.keywordPatternRe.exec(R),n=""
+;for(;t;){n+=R.substring(e,t.index)
+;const s=_.case_insensitive?t[0].toLowerCase():t[0],r=(i=s,N.keywords[i]);if(r){
+const[e,i]=r
+;if(M.addText(n),n="",c[s]=(c[s]||0)+1,c[s]<=7&&(A+=i),e.startsWith("_"))n+=t[0];else{
+const n=_.classNameAliases[e]||e;u(t[0],n)}}else n+=t[0]
+;e=N.keywordPatternRe.lastIndex,t=N.keywordPatternRe.exec(R)}var i
+;n+=R.substring(e),M.addText(n)}function g(){null!=N.subLanguage?(()=>{
+if(""===R)return;let e=null;if("string"==typeof N.subLanguage){
+if(!i[N.subLanguage])return void M.addText(R)
+;e=E(N.subLanguage,R,!0,S[N.subLanguage]),S[N.subLanguage]=e._top
+}else e=x(R,N.subLanguage.length?N.subLanguage:null)
+;N.relevance>0&&(A+=e.relevance),M.__addSublanguage(e._emitter,e.language)
+})():l(),R=""}function u(e,t){
+""!==e&&(M.startScope(t),M.addText(e),M.endScope())}function d(e,t){let n=1
+;const i=t.length-1;for(;n<=i;){if(!e._emit[n]){n++;continue}
+const i=_.classNameAliases[e[n]]||e[n],s=t[n];i?u(s,i):(R=s,l(),R=""),n++}}
+function h(e,t){
+return e.scope&&"string"==typeof e.scope&&M.openNode(_.classNameAliases[e.scope]||e.scope),
+e.beginScope&&(e.beginScope._wrap?(u(R,_.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap),
+R=""):e.beginScope._multi&&(d(e.beginScope,t),R="")),N=Object.create(e,{parent:{
+value:N}}),N}function f(e,n,i){let s=((e,t)=>{const n=e&&e.exec(t)
+;return n&&0===n.index})(e.endRe,i);if(s){if(e["on:end"]){const i=new t(e)
+;e["on:end"](n,i),i.isMatchIgnored&&(s=!1)}if(s){
+for(;e.endsParent&&e.parent;)e=e.parent;return e}}
+if(e.endsWithParent)return f(e.parent,n,i)}function b(e){
+return 0===N.matcher.regexIndex?(R+=e[0],1):(T=!0,0)}function m(e){
+const t=e[0],i=n.substring(e.index),s=f(N,e,i);if(!s)return ee;const r=N
+;N.endScope&&N.endScope._wrap?(g(),
+u(t,N.endScope._wrap)):N.endScope&&N.endScope._multi?(g(),
+d(N.endScope,e)):r.skip?R+=t:(r.returnEnd||r.excludeEnd||(R+=t),
+g(),r.excludeEnd&&(R=t));do{
+N.scope&&M.closeNode(),N.skip||N.subLanguage||(A+=N.relevance),N=N.parent
+}while(N!==s.parent);return s.starts&&h(s.starts,e),r.returnEnd?0:t.length}
+let w={};function y(i,r){const a=r&&r[0];if(R+=i,null==a)return g(),0
+;if("begin"===w.type&&"end"===r.type&&w.index===r.index&&""===a){
+if(R+=n.slice(r.index,r.index+1),!o){const t=Error(`0 width match regex (${e})`)
+;throw t.languageName=e,t.badRule=w.rule,t}return 1}
+if(w=r,"begin"===r.type)return(e=>{
+const n=e[0],i=e.rule,s=new t(i),r=[i.__beforeBegin,i["on:begin"]]
+;for(const t of r)if(t&&(t(e,s),s.isMatchIgnored))return b(n)
+;return i.skip?R+=n:(i.excludeBegin&&(R+=n),
+g(),i.returnBegin||i.excludeBegin||(R=n)),h(i,e),i.returnBegin?0:n.length})(r)
+;if("illegal"===r.type&&!s){
+const e=Error('Illegal lexeme "'+a+'" for mode "'+(N.scope||"")+'"')
+;throw e.mode=N,e}if("end"===r.type){const e=m(r);if(e!==ee)return e}
+if("illegal"===r.type&&""===a)return 1
+;if(I>1e5&&I>3*r.index)throw Error("potential infinite loop, way more iterations than matches")
+;return R+=a,a.length}const _=O(e)
+;if(!_)throw W(a.replace("{}",e)),Error('Unknown language: "'+e+'"')
+;const k=V(_);let v="",N=r||k;const S={},M=new p.__emitter(p);(()=>{const e=[]
+;for(let t=N;t!==_;t=t.parent)t.scope&&e.unshift(t.scope)
+;e.forEach((e=>M.openNode(e)))})();let R="",A=0,j=0,I=0,T=!1;try{
+if(_.__emitTokens)_.__emitTokens(n,M);else{for(N.matcher.considerAll();;){
+I++,T?T=!1:N.matcher.considerAll(),N.matcher.lastIndex=j
+;const e=N.matcher.exec(n);if(!e)break;const t=y(n.substring(j,e.index),e)
+;j=e.index+t}y(n.substring(j))}return M.finalize(),v=M.toHTML(),{language:e,
+value:v,relevance:A,illegal:!1,_emitter:M,_top:N}}catch(t){
+if(t.message&&t.message.includes("Illegal"))return{language:e,value:Y(n),
+illegal:!0,relevance:0,_illegalBy:{message:t.message,index:j,
+context:n.slice(j-100,j+100),mode:t.mode,resultSoFar:v},_emitter:M};if(o)return{
+language:e,value:Y(n),illegal:!1,relevance:0,errorRaised:t,_emitter:M,_top:N}
+;throw t}}function x(e,t){t=t||p.languages||Object.keys(i);const n=(e=>{
+const t={value:Y(e),illegal:!1,relevance:0,_top:l,_emitter:new p.__emitter(p)}
+;return t._emitter.addText(e),t})(e),s=t.filter(O).filter(v).map((t=>E(t,e,!1)))
+;s.unshift(n);const r=s.sort(((e,t)=>{
+if(e.relevance!==t.relevance)return t.relevance-e.relevance
+;if(e.language&&t.language){if(O(e.language).supersetOf===t.language)return 1
+;if(O(t.language).supersetOf===e.language)return-1}return 0})),[o,a]=r,c=o
+;return c.secondBest=a,c}function w(e){let t=null;const n=(e=>{
+let t=e.className+" ";t+=e.parentNode?e.parentNode.className:""
+;const n=p.languageDetectRe.exec(t);if(n){const t=O(n[1])
+;return t||(X(a.replace("{}",n[1])),
+X("Falling back to no-highlight mode for this block.",e)),t?n[1]:"no-highlight"}
+return t.split(/\s+/).find((e=>b(e)||O(e)))})(e);if(b(n))return
+;if(N("before:highlightElement",{el:e,language:n
+}),e.dataset.highlighted)return void console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",e)
+;if(e.children.length>0&&(p.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),
+console.warn("https://github.com/highlightjs/highlight.js/wiki/security"),
+console.warn("The element with unescaped HTML:"),
+console.warn(e)),p.throwUnescapedHTML))throw new J("One of your code blocks includes unescaped HTML.",e.innerHTML)
+;t=e;const i=t.textContent,r=n?m(i,{language:n,ignoreIllegals:!0}):x(i)
+;e.innerHTML=r.value,e.dataset.highlighted="yes",((e,t,n)=>{const i=t&&s[t]||n
+;e.classList.add("hljs"),e.classList.add("language-"+i)
+})(e,n,r.language),e.result={language:r.language,re:r.relevance,
+relevance:r.relevance},r.secondBest&&(e.secondBest={
+language:r.secondBest.language,relevance:r.secondBest.relevance
+}),N("after:highlightElement",{el:e,result:r,text:i})}let y=!1;function _(){
+"loading"!==document.readyState?document.querySelectorAll(p.cssSelector).forEach(w):y=!0
+}function O(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}
+function k(e,{languageName:t}){"string"==typeof e&&(e=[e]),e.forEach((e=>{
+s[e.toLowerCase()]=t}))}function v(e){const t=O(e)
+;return t&&!t.disableAutodetect}function N(e,t){const n=e;r.forEach((e=>{
+e[n]&&e[n](t)}))}
+"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{
+y&&_()}),!1),Object.assign(n,{highlight:m,highlightAuto:x,highlightAll:_,
+highlightElement:w,
+highlightBlock:e=>(G("10.7.0","highlightBlock will be removed entirely in v12.0"),
+G("10.7.0","Please use highlightElement now."),w(e)),configure:e=>{p=Q(p,e)},
+initHighlighting:()=>{
+_(),G("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")},
+initHighlightingOnLoad:()=>{
+_(),G("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")
+},registerLanguage:(e,t)=>{let s=null;try{s=t(n)}catch(t){
+if(W("Language definition for '{}' could not be registered.".replace("{}",e)),
+!o)throw t;W(t),s=l}
+s.name||(s.name=e),i[e]=s,s.rawDefinition=t.bind(null,n),s.aliases&&k(s.aliases,{
+languageName:e})},unregisterLanguage:e=>{delete i[e]
+;for(const t of Object.keys(s))s[t]===e&&delete s[t]},
+listLanguages:()=>Object.keys(i),getLanguage:O,registerAliases:k,
+autoDetection:v,inherit:Q,addPlugin:e=>{(e=>{
+e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=t=>{
+e["before:highlightBlock"](Object.assign({block:t.el},t))
+}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=t=>{
+e["after:highlightBlock"](Object.assign({block:t.el},t))})})(e),r.push(e)},
+removePlugin:e=>{const t=r.indexOf(e);-1!==t&&r.splice(t,1)}}),n.debugMode=()=>{
+o=!1},n.safeMode=()=>{o=!0},n.versionString="11.9.0",n.regex={concat:h,
+lookahead:g,either:f,optional:d,anyNumberOfTimes:u}
+;for(const t in A)"object"==typeof A[t]&&e(A[t]);return Object.assign(n,A),n
+},ne=te({});ne.newInstance=()=>te({});export{ne as default};
\ No newline at end of file
diff --git a/assets/js/vendor/hljs-yaml.min.js b/assets/js/vendor/hljs-yaml.min.js
new file mode 100644
index 0000000..b9ed1ca
--- /dev/null
+++ b/assets/js/vendor/hljs-yaml.min.js
@@ -0,0 +1,25 @@
+/*! `yaml` grammar compiled for Highlight.js 11.9.0 */
+var hljsGrammar=(()=>{"use strict";return e=>{
+const n="true false yes no null",a="[\\w#;/?:@&=+$,.~*'()[\\]]+",s={
+className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/
+},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable",
+variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(s,{
+variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),l={
+end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},t={begin:/\{/,
+end:/\}/,contains:[l],illegal:"\\n",relevance:0},r={begin:"\\[",end:"\\]",
+contains:[l],illegal:"\\n",relevance:0},b=[{className:"attr",variants:[{
+begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{
+begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$",
+relevance:10},{className:"string",
+begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{
+begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,
+relevance:0},{className:"type",begin:"!\\w+!"+a},{className:"type",
+begin:"!<"+a+">"},{className:"type",begin:"!"+a},{className:"type",begin:"!!"+a
+},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta",
+begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)",
+relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{
+className:"number",
+begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b"
+},{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},t,r,s],c=[...b]
+;return c.pop(),c.push(i),l.contains=c,{name:"YAML",case_insensitive:!0,
+aliases:["yml"],contains:b}}})();export default hljsGrammar;
\ No newline at end of file
diff --git a/assets/js/vendor/marked.esm.js b/assets/js/vendor/marked.esm.js
new file mode 100644
index 0000000..603ff05
--- /dev/null
+++ b/assets/js/vendor/marked.esm.js
@@ -0,0 +1,2424 @@
+/**
+ * marked v11.1.1 - a markdown parser
+ * Copyright (c) 2011-2023, Christopher Jeffrey. (MIT Licensed)
+ * https://github.com/markedjs/marked
+ */
+
+/**
+ * DO NOT EDIT THIS FILE
+ * The code in this file is generated from files in ./src/
+ */
+
+/**
+ * Gets the original marked default options.
+ */
+function _getDefaults() {
+ return {
+ async: false,
+ breaks: false,
+ extensions: null,
+ gfm: true,
+ hooks: null,
+ pedantic: false,
+ renderer: null,
+ silent: false,
+ tokenizer: null,
+ walkTokens: null
+ };
+}
+let _defaults = _getDefaults();
+function changeDefaults(newDefaults) {
+ _defaults = newDefaults;
+}
+
+/**
+ * Helpers
+ */
+const escapeTest = /[&<>"']/;
+const escapeReplace = new RegExp(escapeTest.source, 'g');
+const escapeTestNoEncode = /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/;
+const escapeReplaceNoEncode = new RegExp(escapeTestNoEncode.source, 'g');
+const escapeReplacements = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": '''
+};
+const getEscapeReplacement = (ch) => escapeReplacements[ch];
+function escape$1(html, encode) {
+ if (encode) {
+ if (escapeTest.test(html)) {
+ return html.replace(escapeReplace, getEscapeReplacement);
+ }
+ }
+ else {
+ if (escapeTestNoEncode.test(html)) {
+ return html.replace(escapeReplaceNoEncode, getEscapeReplacement);
+ }
+ }
+ return html;
+}
+const unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;
+function unescape(html) {
+ // explicitly match decimal, hex, and named HTML entities
+ return html.replace(unescapeTest, (_, n) => {
+ n = n.toLowerCase();
+ if (n === 'colon')
+ return ':';
+ if (n.charAt(0) === '#') {
+ return n.charAt(1) === 'x'
+ ? String.fromCharCode(parseInt(n.substring(2), 16))
+ : String.fromCharCode(+n.substring(1));
+ }
+ return '';
+ });
+}
+const caret = /(^|[^\[])\^/g;
+function edit(regex, opt) {
+ let source = typeof regex === 'string' ? regex : regex.source;
+ opt = opt || '';
+ const obj = {
+ replace: (name, val) => {
+ let valSource = typeof val === 'string' ? val : val.source;
+ valSource = valSource.replace(caret, '$1');
+ source = source.replace(name, valSource);
+ return obj;
+ },
+ getRegex: () => {
+ return new RegExp(source, opt);
+ }
+ };
+ return obj;
+}
+function cleanUrl(href) {
+ try {
+ href = encodeURI(href).replace(/%25/g, '%');
+ }
+ catch (e) {
+ return null;
+ }
+ return href;
+}
+const noopTest = { exec: () => null };
+function splitCells(tableRow, count) {
+ // ensure that every cell-delimiting pipe has a space
+ // before it to distinguish it from an escaped pipe
+ const row = tableRow.replace(/\|/g, (match, offset, str) => {
+ let escaped = false;
+ let curr = offset;
+ while (--curr >= 0 && str[curr] === '\\')
+ escaped = !escaped;
+ if (escaped) {
+ // odd number of slashes means | is escaped
+ // so we leave it alone
+ return '|';
+ }
+ else {
+ // add space before unescaped |
+ return ' |';
+ }
+ }), cells = row.split(/ \|/);
+ let i = 0;
+ // First/last cell in a row cannot be empty if it has no leading/trailing pipe
+ if (!cells[0].trim()) {
+ cells.shift();
+ }
+ if (cells.length > 0 && !cells[cells.length - 1].trim()) {
+ cells.pop();
+ }
+ if (count) {
+ if (cells.length > count) {
+ cells.splice(count);
+ }
+ else {
+ while (cells.length < count)
+ cells.push('');
+ }
+ }
+ for (; i < cells.length; i++) {
+ // leading or trailing whitespace is ignored per the gfm spec
+ cells[i] = cells[i].trim().replace(/\\\|/g, '|');
+ }
+ return cells;
+}
+/**
+ * Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
+ * /c*$/ is vulnerable to REDOS.
+ *
+ * @param str
+ * @param c
+ * @param invert Remove suffix of non-c chars instead. Default falsey.
+ */
+function rtrim(str, c, invert) {
+ const l = str.length;
+ if (l === 0) {
+ return '';
+ }
+ // Length of suffix matching the invert condition.
+ let suffLen = 0;
+ // Step left until we fail to match the invert condition.
+ while (suffLen < l) {
+ const currChar = str.charAt(l - suffLen - 1);
+ if (currChar === c && !invert) {
+ suffLen++;
+ }
+ else if (currChar !== c && invert) {
+ suffLen++;
+ }
+ else {
+ break;
+ }
+ }
+ return str.slice(0, l - suffLen);
+}
+function findClosingBracket(str, b) {
+ if (str.indexOf(b[1]) === -1) {
+ return -1;
+ }
+ let level = 0;
+ for (let i = 0; i < str.length; i++) {
+ if (str[i] === '\\') {
+ i++;
+ }
+ else if (str[i] === b[0]) {
+ level++;
+ }
+ else if (str[i] === b[1]) {
+ level--;
+ if (level < 0) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+function outputLink(cap, link, raw, lexer) {
+ const href = link.href;
+ const title = link.title ? escape$1(link.title) : null;
+ const text = cap[1].replace(/\\([\[\]])/g, '$1');
+ if (cap[0].charAt(0) !== '!') {
+ lexer.state.inLink = true;
+ const token = {
+ type: 'link',
+ raw,
+ href,
+ title,
+ text,
+ tokens: lexer.inlineTokens(text)
+ };
+ lexer.state.inLink = false;
+ return token;
+ }
+ return {
+ type: 'image',
+ raw,
+ href,
+ title,
+ text: escape$1(text)
+ };
+}
+function indentCodeCompensation(raw, text) {
+ const matchIndentToCode = raw.match(/^(\s+)(?:```)/);
+ if (matchIndentToCode === null) {
+ return text;
+ }
+ const indentToCode = matchIndentToCode[1];
+ return text
+ .split('\n')
+ .map(node => {
+ const matchIndentInNode = node.match(/^\s+/);
+ if (matchIndentInNode === null) {
+ return node;
+ }
+ const [indentInNode] = matchIndentInNode;
+ if (indentInNode.length >= indentToCode.length) {
+ return node.slice(indentToCode.length);
+ }
+ return node;
+ })
+ .join('\n');
+}
+/**
+ * Tokenizer
+ */
+class _Tokenizer {
+ options;
+ rules; // set by the lexer
+ lexer; // set by the lexer
+ constructor(options) {
+ this.options = options || _defaults;
+ }
+ space(src) {
+ const cap = this.rules.block.newline.exec(src);
+ if (cap && cap[0].length > 0) {
+ return {
+ type: 'space',
+ raw: cap[0]
+ };
+ }
+ }
+ code(src) {
+ const cap = this.rules.block.code.exec(src);
+ if (cap) {
+ const text = cap[0].replace(/^ {1,4}/gm, '');
+ return {
+ type: 'code',
+ raw: cap[0],
+ codeBlockStyle: 'indented',
+ text: !this.options.pedantic
+ ? rtrim(text, '\n')
+ : text
+ };
+ }
+ }
+ fences(src) {
+ const cap = this.rules.block.fences.exec(src);
+ if (cap) {
+ const raw = cap[0];
+ const text = indentCodeCompensation(raw, cap[3] || '');
+ return {
+ type: 'code',
+ raw,
+ lang: cap[2] ? cap[2].trim().replace(this.rules.inline.anyPunctuation, '$1') : cap[2],
+ text
+ };
+ }
+ }
+ heading(src) {
+ const cap = this.rules.block.heading.exec(src);
+ if (cap) {
+ let text = cap[2].trim();
+ // remove trailing #s
+ if (/#$/.test(text)) {
+ const trimmed = rtrim(text, '#');
+ if (this.options.pedantic) {
+ text = trimmed.trim();
+ }
+ else if (!trimmed || / $/.test(trimmed)) {
+ // CommonMark requires space before trailing #s
+ text = trimmed.trim();
+ }
+ }
+ return {
+ type: 'heading',
+ raw: cap[0],
+ depth: cap[1].length,
+ text,
+ tokens: this.lexer.inline(text)
+ };
+ }
+ }
+ hr(src) {
+ const cap = this.rules.block.hr.exec(src);
+ if (cap) {
+ return {
+ type: 'hr',
+ raw: cap[0]
+ };
+ }
+ }
+ blockquote(src) {
+ const cap = this.rules.block.blockquote.exec(src);
+ if (cap) {
+ const text = rtrim(cap[0].replace(/^ *>[ \t]?/gm, ''), '\n');
+ const top = this.lexer.state.top;
+ this.lexer.state.top = true;
+ const tokens = this.lexer.blockTokens(text);
+ this.lexer.state.top = top;
+ return {
+ type: 'blockquote',
+ raw: cap[0],
+ tokens,
+ text
+ };
+ }
+ }
+ list(src) {
+ let cap = this.rules.block.list.exec(src);
+ if (cap) {
+ let bull = cap[1].trim();
+ const isordered = bull.length > 1;
+ const list = {
+ type: 'list',
+ raw: '',
+ ordered: isordered,
+ start: isordered ? +bull.slice(0, -1) : '',
+ loose: false,
+ items: []
+ };
+ bull = isordered ? `\\d{1,9}\\${bull.slice(-1)}` : `\\${bull}`;
+ if (this.options.pedantic) {
+ bull = isordered ? bull : '[*+-]';
+ }
+ // Get next list item
+ const itemRegex = new RegExp(`^( {0,3}${bull})((?:[\t ][^\\n]*)?(?:\\n|$))`);
+ let raw = '';
+ let itemContents = '';
+ let endsWithBlankLine = false;
+ // Check if current bullet point can start a new List Item
+ while (src) {
+ let endEarly = false;
+ if (!(cap = itemRegex.exec(src))) {
+ break;
+ }
+ if (this.rules.block.hr.test(src)) { // End list if bullet was actually HR (possibly move into itemRegex?)
+ break;
+ }
+ raw = cap[0];
+ src = src.substring(raw.length);
+ let line = cap[2].split('\n', 1)[0].replace(/^\t+/, (t) => ' '.repeat(3 * t.length));
+ let nextLine = src.split('\n', 1)[0];
+ let indent = 0;
+ if (this.options.pedantic) {
+ indent = 2;
+ itemContents = line.trimStart();
+ }
+ else {
+ indent = cap[2].search(/[^ ]/); // Find first non-space char
+ indent = indent > 4 ? 1 : indent; // Treat indented code blocks (> 4 spaces) as having only 1 indent
+ itemContents = line.slice(indent);
+ indent += cap[1].length;
+ }
+ let blankLine = false;
+ if (!line && /^ *$/.test(nextLine)) { // Items begin with at most one blank line
+ raw += nextLine + '\n';
+ src = src.substring(nextLine.length + 1);
+ endEarly = true;
+ }
+ if (!endEarly) {
+ const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`);
+ const hrRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`);
+ const fencesBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:\`\`\`|~~~)`);
+ const headingBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}#`);
+ // Check if following lines should be included in List Item
+ while (src) {
+ const rawLine = src.split('\n', 1)[0];
+ nextLine = rawLine;
+ // Re-align to follow commonmark nesting rules
+ if (this.options.pedantic) {
+ nextLine = nextLine.replace(/^ {1,4}(?=( {4})*[^ ])/g, ' ');
+ }
+ // End list item if found code fences
+ if (fencesBeginRegex.test(nextLine)) {
+ break;
+ }
+ // End list item if found start of new heading
+ if (headingBeginRegex.test(nextLine)) {
+ break;
+ }
+ // End list item if found start of new bullet
+ if (nextBulletRegex.test(nextLine)) {
+ break;
+ }
+ // Horizontal rule found
+ if (hrRegex.test(src)) {
+ break;
+ }
+ if (nextLine.search(/[^ ]/) >= indent || !nextLine.trim()) { // Dedent if possible
+ itemContents += '\n' + nextLine.slice(indent);
+ }
+ else {
+ // not enough indentation
+ if (blankLine) {
+ break;
+ }
+ // paragraph continuation unless last line was a different block level element
+ if (line.search(/[^ ]/) >= 4) { // indented code block
+ break;
+ }
+ if (fencesBeginRegex.test(line)) {
+ break;
+ }
+ if (headingBeginRegex.test(line)) {
+ break;
+ }
+ if (hrRegex.test(line)) {
+ break;
+ }
+ itemContents += '\n' + nextLine;
+ }
+ if (!blankLine && !nextLine.trim()) { // Check if current line is blank
+ blankLine = true;
+ }
+ raw += rawLine + '\n';
+ src = src.substring(rawLine.length + 1);
+ line = nextLine.slice(indent);
+ }
+ }
+ if (!list.loose) {
+ // If the previous item ended with a blank line, the list is loose
+ if (endsWithBlankLine) {
+ list.loose = true;
+ }
+ else if (/\n *\n *$/.test(raw)) {
+ endsWithBlankLine = true;
+ }
+ }
+ let istask = null;
+ let ischecked;
+ // Check for task list items
+ if (this.options.gfm) {
+ istask = /^\[[ xX]\] /.exec(itemContents);
+ if (istask) {
+ ischecked = istask[0] !== '[ ] ';
+ itemContents = itemContents.replace(/^\[[ xX]\] +/, '');
+ }
+ }
+ list.items.push({
+ type: 'list_item',
+ raw,
+ task: !!istask,
+ checked: ischecked,
+ loose: false,
+ text: itemContents,
+ tokens: []
+ });
+ list.raw += raw;
+ }
+ // Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic
+ list.items[list.items.length - 1].raw = raw.trimEnd();
+ (list.items[list.items.length - 1]).text = itemContents.trimEnd();
+ list.raw = list.raw.trimEnd();
+ // Item child tokens handled here at end because we needed to have the final item to trim it first
+ for (let i = 0; i < list.items.length; i++) {
+ this.lexer.state.top = false;
+ list.items[i].tokens = this.lexer.blockTokens(list.items[i].text, []);
+ if (!list.loose) {
+ // Check if list should be loose
+ const spacers = list.items[i].tokens.filter(t => t.type === 'space');
+ const hasMultipleLineBreaks = spacers.length > 0 && spacers.some(t => /\n.*\n/.test(t.raw));
+ list.loose = hasMultipleLineBreaks;
+ }
+ }
+ // Set all items to loose if list is loose
+ if (list.loose) {
+ for (let i = 0; i < list.items.length; i++) {
+ list.items[i].loose = true;
+ }
+ }
+ return list;
+ }
+ }
+ html(src) {
+ const cap = this.rules.block.html.exec(src);
+ if (cap) {
+ const token = {
+ type: 'html',
+ block: true,
+ raw: cap[0],
+ pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',
+ text: cap[0]
+ };
+ return token;
+ }
+ }
+ def(src) {
+ const cap = this.rules.block.def.exec(src);
+ if (cap) {
+ const tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
+ const href = cap[2] ? cap[2].replace(/^<(.*)>$/, '$1').replace(this.rules.inline.anyPunctuation, '$1') : '';
+ const title = cap[3] ? cap[3].substring(1, cap[3].length - 1).replace(this.rules.inline.anyPunctuation, '$1') : cap[3];
+ return {
+ type: 'def',
+ tag,
+ raw: cap[0],
+ href,
+ title
+ };
+ }
+ }
+ table(src) {
+ const cap = this.rules.block.table.exec(src);
+ if (!cap) {
+ return;
+ }
+ if (!/[:|]/.test(cap[2])) {
+ // delimiter row must have a pipe (|) or colon (:) otherwise it is a setext heading
+ return;
+ }
+ const headers = splitCells(cap[1]);
+ const aligns = cap[2].replace(/^\||\| *$/g, '').split('|');
+ const rows = cap[3] && cap[3].trim() ? cap[3].replace(/\n[ \t]*$/, '').split('\n') : [];
+ const item = {
+ type: 'table',
+ raw: cap[0],
+ header: [],
+ align: [],
+ rows: []
+ };
+ if (headers.length !== aligns.length) {
+ // header and align columns must be equal, rows can be different.
+ return;
+ }
+ for (const align of aligns) {
+ if (/^ *-+: *$/.test(align)) {
+ item.align.push('right');
+ }
+ else if (/^ *:-+: *$/.test(align)) {
+ item.align.push('center');
+ }
+ else if (/^ *:-+ *$/.test(align)) {
+ item.align.push('left');
+ }
+ else {
+ item.align.push(null);
+ }
+ }
+ for (const header of headers) {
+ item.header.push({
+ text: header,
+ tokens: this.lexer.inline(header)
+ });
+ }
+ for (const row of rows) {
+ item.rows.push(splitCells(row, item.header.length).map(cell => {
+ return {
+ text: cell,
+ tokens: this.lexer.inline(cell)
+ };
+ }));
+ }
+ return item;
+ }
+ lheading(src) {
+ const cap = this.rules.block.lheading.exec(src);
+ if (cap) {
+ return {
+ type: 'heading',
+ raw: cap[0],
+ depth: cap[2].charAt(0) === '=' ? 1 : 2,
+ text: cap[1],
+ tokens: this.lexer.inline(cap[1])
+ };
+ }
+ }
+ paragraph(src) {
+ const cap = this.rules.block.paragraph.exec(src);
+ if (cap) {
+ const text = cap[1].charAt(cap[1].length - 1) === '\n'
+ ? cap[1].slice(0, -1)
+ : cap[1];
+ return {
+ type: 'paragraph',
+ raw: cap[0],
+ text,
+ tokens: this.lexer.inline(text)
+ };
+ }
+ }
+ text(src) {
+ const cap = this.rules.block.text.exec(src);
+ if (cap) {
+ return {
+ type: 'text',
+ raw: cap[0],
+ text: cap[0],
+ tokens: this.lexer.inline(cap[0])
+ };
+ }
+ }
+ escape(src) {
+ const cap = this.rules.inline.escape.exec(src);
+ if (cap) {
+ return {
+ type: 'escape',
+ raw: cap[0],
+ text: escape$1(cap[1])
+ };
+ }
+ }
+ tag(src) {
+ const cap = this.rules.inline.tag.exec(src);
+ if (cap) {
+ if (!this.lexer.state.inLink && /^/i.test(cap[0])) {
+ this.lexer.state.inLink = false;
+ }
+ if (!this.lexer.state.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
+ this.lexer.state.inRawBlock = true;
+ }
+ else if (this.lexer.state.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
+ this.lexer.state.inRawBlock = false;
+ }
+ return {
+ type: 'html',
+ raw: cap[0],
+ inLink: this.lexer.state.inLink,
+ inRawBlock: this.lexer.state.inRawBlock,
+ block: false,
+ text: cap[0]
+ };
+ }
+ }
+ link(src) {
+ const cap = this.rules.inline.link.exec(src);
+ if (cap) {
+ const trimmedUrl = cap[2].trim();
+ if (!this.options.pedantic && /^$/.test(trimmedUrl))) {
+ return;
+ }
+ // ending angle bracket cannot be escaped
+ const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), '\\');
+ if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {
+ return;
+ }
+ }
+ else {
+ // find closing parenthesis
+ const lastParenIndex = findClosingBracket(cap[2], '()');
+ if (lastParenIndex > -1) {
+ const start = cap[0].indexOf('!') === 0 ? 5 : 4;
+ const linkLen = start + cap[1].length + lastParenIndex;
+ cap[2] = cap[2].substring(0, lastParenIndex);
+ cap[0] = cap[0].substring(0, linkLen).trim();
+ cap[3] = '';
+ }
+ }
+ let href = cap[2];
+ let title = '';
+ if (this.options.pedantic) {
+ // split pedantic href and title
+ const link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
+ if (link) {
+ href = link[1];
+ title = link[3];
+ }
+ }
+ else {
+ title = cap[3] ? cap[3].slice(1, -1) : '';
+ }
+ href = href.trim();
+ if (/^$/.test(trimmedUrl))) {
+ // pedantic allows starting angle bracket without ending angle bracket
+ href = href.slice(1);
+ }
+ else {
+ href = href.slice(1, -1);
+ }
+ }
+ return outputLink(cap, {
+ href: href ? href.replace(this.rules.inline.anyPunctuation, '$1') : href,
+ title: title ? title.replace(this.rules.inline.anyPunctuation, '$1') : title
+ }, cap[0], this.lexer);
+ }
+ }
+ reflink(src, links) {
+ let cap;
+ if ((cap = this.rules.inline.reflink.exec(src))
+ || (cap = this.rules.inline.nolink.exec(src))) {
+ const linkString = (cap[2] || cap[1]).replace(/\s+/g, ' ');
+ const link = links[linkString.toLowerCase()];
+ if (!link) {
+ const text = cap[0].charAt(0);
+ return {
+ type: 'text',
+ raw: text,
+ text
+ };
+ }
+ return outputLink(cap, link, cap[0], this.lexer);
+ }
+ }
+ emStrong(src, maskedSrc, prevChar = '') {
+ let match = this.rules.inline.emStrongLDelim.exec(src);
+ if (!match)
+ return;
+ // _ can't be between two alphanumerics. \p{L}\p{N} includes non-english alphabet/numbers as well
+ if (match[3] && prevChar.match(/[\p{L}\p{N}]/u))
+ return;
+ const nextChar = match[1] || match[2] || '';
+ if (!nextChar || !prevChar || this.rules.inline.punctuation.exec(prevChar)) {
+ // unicode Regex counts emoji as 1 char; spread into array for proper count (used multiple times below)
+ const lLength = [...match[0]].length - 1;
+ let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0;
+ const endReg = match[0][0] === '*' ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd;
+ endReg.lastIndex = 0;
+ // Clip maskedSrc to same section of string as src (move to lexer?)
+ maskedSrc = maskedSrc.slice(-1 * src.length + lLength);
+ while ((match = endReg.exec(maskedSrc)) != null) {
+ rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];
+ if (!rDelim)
+ continue; // skip single * in __abc*abc__
+ rLength = [...rDelim].length;
+ if (match[3] || match[4]) { // found another Left Delim
+ delimTotal += rLength;
+ continue;
+ }
+ else if (match[5] || match[6]) { // either Left or Right Delim
+ if (lLength % 3 && !((lLength + rLength) % 3)) {
+ midDelimTotal += rLength;
+ continue; // CommonMark Emphasis Rules 9-10
+ }
+ }
+ delimTotal -= rLength;
+ if (delimTotal > 0)
+ continue; // Haven't found enough closing delimiters
+ // Remove extra characters. *a*** -> *a*
+ rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal);
+ // char length can be >1 for unicode characters;
+ const lastCharLength = [...match[0]][0].length;
+ const raw = src.slice(0, lLength + match.index + lastCharLength + rLength);
+ // Create `em` if smallest delimiter has odd char count. *a***
+ if (Math.min(lLength, rLength) % 2) {
+ const text = raw.slice(1, -1);
+ return {
+ type: 'em',
+ raw,
+ text,
+ tokens: this.lexer.inlineTokens(text)
+ };
+ }
+ // Create 'strong' if smallest delimiter has even char count. **a***
+ const text = raw.slice(2, -2);
+ return {
+ type: 'strong',
+ raw,
+ text,
+ tokens: this.lexer.inlineTokens(text)
+ };
+ }
+ }
+ }
+ codespan(src) {
+ const cap = this.rules.inline.code.exec(src);
+ if (cap) {
+ let text = cap[2].replace(/\n/g, ' ');
+ const hasNonSpaceChars = /[^ ]/.test(text);
+ const hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text);
+ if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
+ text = text.substring(1, text.length - 1);
+ }
+ text = escape$1(text, true);
+ return {
+ type: 'codespan',
+ raw: cap[0],
+ text
+ };
+ }
+ }
+ br(src) {
+ const cap = this.rules.inline.br.exec(src);
+ if (cap) {
+ return {
+ type: 'br',
+ raw: cap[0]
+ };
+ }
+ }
+ del(src) {
+ const cap = this.rules.inline.del.exec(src);
+ if (cap) {
+ return {
+ type: 'del',
+ raw: cap[0],
+ text: cap[2],
+ tokens: this.lexer.inlineTokens(cap[2])
+ };
+ }
+ }
+ autolink(src) {
+ const cap = this.rules.inline.autolink.exec(src);
+ if (cap) {
+ let text, href;
+ if (cap[2] === '@') {
+ text = escape$1(cap[1]);
+ href = 'mailto:' + text;
+ }
+ else {
+ text = escape$1(cap[1]);
+ href = text;
+ }
+ return {
+ type: 'link',
+ raw: cap[0],
+ text,
+ href,
+ tokens: [
+ {
+ type: 'text',
+ raw: text,
+ text
+ }
+ ]
+ };
+ }
+ }
+ url(src) {
+ let cap;
+ if (cap = this.rules.inline.url.exec(src)) {
+ let text, href;
+ if (cap[2] === '@') {
+ text = escape$1(cap[0]);
+ href = 'mailto:' + text;
+ }
+ else {
+ // do extended autolink path validation
+ let prevCapZero;
+ do {
+ prevCapZero = cap[0];
+ cap[0] = this.rules.inline._backpedal.exec(cap[0])?.[0] ?? '';
+ } while (prevCapZero !== cap[0]);
+ text = escape$1(cap[0]);
+ if (cap[1] === 'www.') {
+ href = 'http://' + cap[0];
+ }
+ else {
+ href = cap[0];
+ }
+ }
+ return {
+ type: 'link',
+ raw: cap[0],
+ text,
+ href,
+ tokens: [
+ {
+ type: 'text',
+ raw: text,
+ text
+ }
+ ]
+ };
+ }
+ }
+ inlineText(src) {
+ const cap = this.rules.inline.text.exec(src);
+ if (cap) {
+ let text;
+ if (this.lexer.state.inRawBlock) {
+ text = cap[0];
+ }
+ else {
+ text = escape$1(cap[0]);
+ }
+ return {
+ type: 'text',
+ raw: cap[0],
+ text
+ };
+ }
+ }
+}
+
+/**
+ * Block-Level Grammar
+ */
+const newline = /^(?: *(?:\n|$))+/;
+const blockCode = /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/;
+const fences = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/;
+const hr = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/;
+const heading = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/;
+const bullet = /(?:[*+-]|\d{1,9}[.)])/;
+const lheading = edit(/^(?!bull )((?:.|\n(?!\s*?\n|bull ))+?)\n {0,3}(=+|-+) *(?:\n+|$)/)
+ .replace(/bull/g, bullet) // lists can interrupt
+ .getRegex();
+const _paragraph = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/;
+const blockText = /^[^\n]+/;
+const _blockLabel = /(?!\s*\])(?:\\.|[^\[\]\\])+/;
+const def = edit(/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/)
+ .replace('label', _blockLabel)
+ .replace('title', /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/)
+ .getRegex();
+const list = edit(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/)
+ .replace(/bull/g, bullet)
+ .getRegex();
+const _tag = 'address|article|aside|base|basefont|blockquote|body|caption'
+ + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'
+ + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'
+ + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'
+ + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr'
+ + '|track|ul';
+const _comment = /|$)/;
+const html = edit('^ {0,3}(?:' // optional indentation
+ + '<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:\\1>[^\\n]*\\n+|$)' // (1)
+ + '|comment[^\\n]*(\\n+|$)' // (2)
+ + '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3)
+ + '|\\n*|$)' // (4)
+ + '|\\n*|$)' // (5)
+ + '|?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (6)
+ + '|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) open tag
+ + '|(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) closing tag
+ + ')', 'i')
+ .replace('comment', _comment)
+ .replace('tag', _tag)
+ .replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/)
+ .getRegex();
+const paragraph = edit(_paragraph)
+ .replace('hr', hr)
+ .replace('heading', ' {0,3}#{1,6}(?:\\s|$)')
+ .replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
+ .replace('|table', '')
+ .replace('blockquote', ' {0,3}>')
+ .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
+ .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
+ .replace('html', '?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
+ .replace('tag', _tag) // pars can be interrupted by type (6) html blocks
+ .getRegex();
+const blockquote = edit(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/)
+ .replace('paragraph', paragraph)
+ .getRegex();
+/**
+ * Normal Block Grammar
+ */
+const blockNormal = {
+ blockquote,
+ code: blockCode,
+ def,
+ fences,
+ heading,
+ hr,
+ html,
+ lheading,
+ list,
+ newline,
+ paragraph,
+ table: noopTest,
+ text: blockText
+};
+/**
+ * GFM Block Grammar
+ */
+const gfmTable = edit('^ *([^\\n ].*)\\n' // Header
+ + ' {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)' // Align
+ + '(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)') // Cells
+ .replace('hr', hr)
+ .replace('heading', ' {0,3}#{1,6}(?:\\s|$)')
+ .replace('blockquote', ' {0,3}>')
+ .replace('code', ' {4}[^\\n]')
+ .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
+ .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
+ .replace('html', '?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
+ .replace('tag', _tag) // tables can be interrupted by type (6) html blocks
+ .getRegex();
+const blockGfm = {
+ ...blockNormal,
+ table: gfmTable,
+ paragraph: edit(_paragraph)
+ .replace('hr', hr)
+ .replace('heading', ' {0,3}#{1,6}(?:\\s|$)')
+ .replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
+ .replace('table', gfmTable) // interrupt paragraphs with table
+ .replace('blockquote', ' {0,3}>')
+ .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
+ .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
+ .replace('html', '?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
+ .replace('tag', _tag) // pars can be interrupted by type (6) html blocks
+ .getRegex()
+};
+/**
+ * Pedantic grammar (original John Gruber's loose markdown specification)
+ */
+const blockPedantic = {
+ ...blockNormal,
+ html: edit('^ *(?:comment *(?:\\n|\\s*$)'
+ + '|<(tag)[\\s\\S]+?\\1> *(?:\\n{2,}|\\s*$)' // closed tag
+ + '| \\s]*)*?/?> *(?:\\n{2,}|\\s*$))')
+ .replace('comment', _comment)
+ .replace(/tag/g, '(?!(?:'
+ + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'
+ + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'
+ + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b')
+ .getRegex(),
+ def: /^ *\[([^\]]+)\]: *([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
+ heading: /^(#{1,6})(.*)(?:\n+|$)/,
+ fences: noopTest, // fences not supported
+ lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,
+ paragraph: edit(_paragraph)
+ .replace('hr', hr)
+ .replace('heading', ' *#{1,6} *[^\n]')
+ .replace('lheading', lheading)
+ .replace('|table', '')
+ .replace('blockquote', ' {0,3}>')
+ .replace('|fences', '')
+ .replace('|list', '')
+ .replace('|html', '')
+ .replace('|tag', '')
+ .getRegex()
+};
+/**
+ * Inline-Level Grammar
+ */
+const escape = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/;
+const inlineCode = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/;
+const br = /^( {2,}|\\)\n(?!\s*$)/;
+const inlineText = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\`^|~';
+const punctuation = edit(/^((?![*_])[\spunctuation])/, 'u')
+ .replace(/punctuation/g, _punctuation).getRegex();
+// sequences em should skip over [title](link), `code`,
+const blockSkip = /\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g;
+const emStrongLDelim = edit(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/, 'u')
+ .replace(/punct/g, _punctuation)
+ .getRegex();
+const emStrongRDelimAst = edit('^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)' // Skip orphan inside strong
+ + '|[^*]+(?=[^*])' // Consume to delim
+ + '|(?!\\*)[punct](\\*+)(?=[\\s]|$)' // (1) #*** can only be a Right Delimiter
+ + '|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)' // (2) a***#, a*** can only be a Right Delimiter
+ + '|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])' // (3) #***a, ***a can only be Left Delimiter
+ + '|[\\s](\\*+)(?!\\*)(?=[punct])' // (4) ***# can only be Left Delimiter
+ + '|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])' // (5) #***# can be either Left or Right Delimiter
+ + '|[^punct\\s](\\*+)(?=[^punct\\s])', 'gu') // (6) a***a can be either Left or Right Delimiter
+ .replace(/punct/g, _punctuation)
+ .getRegex();
+// (6) Not allowed for _
+const emStrongRDelimUnd = edit('^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)' // Skip orphan inside strong
+ + '|[^_]+(?=[^_])' // Consume to delim
+ + '|(?!_)[punct](_+)(?=[\\s]|$)' // (1) #___ can only be a Right Delimiter
+ + '|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)' // (2) a___#, a___ can only be a Right Delimiter
+ + '|(?!_)[punct\\s](_+)(?=[^punct\\s])' // (3) #___a, ___a can only be Left Delimiter
+ + '|[\\s](_+)(?!_)(?=[punct])' // (4) ___# can only be Left Delimiter
+ + '|(?!_)[punct](_+)(?!_)(?=[punct])', 'gu') // (5) #___# can be either Left or Right Delimiter
+ .replace(/punct/g, _punctuation)
+ .getRegex();
+const anyPunctuation = edit(/\\([punct])/, 'gu')
+ .replace(/punct/g, _punctuation)
+ .getRegex();
+const autolink = edit(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/)
+ .replace('scheme', /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/)
+ .replace('email', /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/)
+ .getRegex();
+const _inlineComment = edit(_comment).replace('(?:-->|$)', '-->').getRegex();
+const tag = edit('^comment'
+ + '|^[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
+ + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
+ + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g.
+ + '|^' // declaration, e.g.
+ + '|^') // CDATA section
+ .replace('comment', _inlineComment)
+ .replace('attribute', /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/)
+ .getRegex();
+const _inlineLabel = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
+const link = edit(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/)
+ .replace('label', _inlineLabel)
+ .replace('href', /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/)
+ .replace('title', /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/)
+ .getRegex();
+const reflink = edit(/^!?\[(label)\]\[(ref)\]/)
+ .replace('label', _inlineLabel)
+ .replace('ref', _blockLabel)
+ .getRegex();
+const nolink = edit(/^!?\[(ref)\](?:\[\])?/)
+ .replace('ref', _blockLabel)
+ .getRegex();
+const reflinkSearch = edit('reflink|nolink(?!\\()', 'g')
+ .replace('reflink', reflink)
+ .replace('nolink', nolink)
+ .getRegex();
+/**
+ * Normal Inline Grammar
+ */
+const inlineNormal = {
+ _backpedal: noopTest, // only used for GFM url
+ anyPunctuation,
+ autolink,
+ blockSkip,
+ br,
+ code: inlineCode,
+ del: noopTest,
+ emStrongLDelim,
+ emStrongRDelimAst,
+ emStrongRDelimUnd,
+ escape,
+ link,
+ nolink,
+ punctuation,
+ reflink,
+ reflinkSearch,
+ tag,
+ text: inlineText,
+ url: noopTest
+};
+/**
+ * Pedantic Inline Grammar
+ */
+const inlinePedantic = {
+ ...inlineNormal,
+ link: edit(/^!?\[(label)\]\((.*?)\)/)
+ .replace('label', _inlineLabel)
+ .getRegex(),
+ reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/)
+ .replace('label', _inlineLabel)
+ .getRegex()
+};
+/**
+ * GFM Inline Grammar
+ */
+const inlineGfm = {
+ ...inlineNormal,
+ escape: edit(escape).replace('])', '~|])').getRegex(),
+ url: edit(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/, 'i')
+ .replace('email', /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/)
+ .getRegex(),
+ _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,
+ del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
+ text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\ {
+ return leading + ' '.repeat(tabs.length);
+ });
+ }
+ let token;
+ let lastToken;
+ let cutSrc;
+ let lastParagraphClipped;
+ while (src) {
+ if (this.options.extensions
+ && this.options.extensions.block
+ && this.options.extensions.block.some((extTokenizer) => {
+ if (token = extTokenizer.call({ lexer: this }, src, tokens)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ return true;
+ }
+ return false;
+ })) {
+ continue;
+ }
+ // newline
+ if (token = this.tokenizer.space(src)) {
+ src = src.substring(token.raw.length);
+ if (token.raw.length === 1 && tokens.length > 0) {
+ // if there's a single \n as a spacer, it's terminating the last line,
+ // so move it there so that we don't get unnecessary paragraph tags
+ tokens[tokens.length - 1].raw += '\n';
+ }
+ else {
+ tokens.push(token);
+ }
+ continue;
+ }
+ // code
+ if (token = this.tokenizer.code(src)) {
+ src = src.substring(token.raw.length);
+ lastToken = tokens[tokens.length - 1];
+ // An indented code block cannot interrupt a paragraph.
+ if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) {
+ lastToken.raw += '\n' + token.raw;
+ lastToken.text += '\n' + token.text;
+ this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
+ }
+ else {
+ tokens.push(token);
+ }
+ continue;
+ }
+ // fences
+ if (token = this.tokenizer.fences(src)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ continue;
+ }
+ // heading
+ if (token = this.tokenizer.heading(src)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ continue;
+ }
+ // hr
+ if (token = this.tokenizer.hr(src)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ continue;
+ }
+ // blockquote
+ if (token = this.tokenizer.blockquote(src)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ continue;
+ }
+ // list
+ if (token = this.tokenizer.list(src)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ continue;
+ }
+ // html
+ if (token = this.tokenizer.html(src)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ continue;
+ }
+ // def
+ if (token = this.tokenizer.def(src)) {
+ src = src.substring(token.raw.length);
+ lastToken = tokens[tokens.length - 1];
+ if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) {
+ lastToken.raw += '\n' + token.raw;
+ lastToken.text += '\n' + token.raw;
+ this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
+ }
+ else if (!this.tokens.links[token.tag]) {
+ this.tokens.links[token.tag] = {
+ href: token.href,
+ title: token.title
+ };
+ }
+ continue;
+ }
+ // table (gfm)
+ if (token = this.tokenizer.table(src)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ continue;
+ }
+ // lheading
+ if (token = this.tokenizer.lheading(src)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ continue;
+ }
+ // top-level paragraph
+ // prevent paragraph consuming extensions by clipping 'src' to extension start
+ cutSrc = src;
+ if (this.options.extensions && this.options.extensions.startBlock) {
+ let startIndex = Infinity;
+ const tempSrc = src.slice(1);
+ let tempStart;
+ this.options.extensions.startBlock.forEach((getStartIndex) => {
+ tempStart = getStartIndex.call({ lexer: this }, tempSrc);
+ if (typeof tempStart === 'number' && tempStart >= 0) {
+ startIndex = Math.min(startIndex, tempStart);
+ }
+ });
+ if (startIndex < Infinity && startIndex >= 0) {
+ cutSrc = src.substring(0, startIndex + 1);
+ }
+ }
+ if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {
+ lastToken = tokens[tokens.length - 1];
+ if (lastParagraphClipped && lastToken.type === 'paragraph') {
+ lastToken.raw += '\n' + token.raw;
+ lastToken.text += '\n' + token.text;
+ this.inlineQueue.pop();
+ this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
+ }
+ else {
+ tokens.push(token);
+ }
+ lastParagraphClipped = (cutSrc.length !== src.length);
+ src = src.substring(token.raw.length);
+ continue;
+ }
+ // text
+ if (token = this.tokenizer.text(src)) {
+ src = src.substring(token.raw.length);
+ lastToken = tokens[tokens.length - 1];
+ if (lastToken && lastToken.type === 'text') {
+ lastToken.raw += '\n' + token.raw;
+ lastToken.text += '\n' + token.text;
+ this.inlineQueue.pop();
+ this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
+ }
+ else {
+ tokens.push(token);
+ }
+ continue;
+ }
+ if (src) {
+ const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
+ if (this.options.silent) {
+ console.error(errMsg);
+ break;
+ }
+ else {
+ throw new Error(errMsg);
+ }
+ }
+ }
+ this.state.top = true;
+ return tokens;
+ }
+ inline(src, tokens = []) {
+ this.inlineQueue.push({ src, tokens });
+ return tokens;
+ }
+ /**
+ * Lexing/Compiling
+ */
+ inlineTokens(src, tokens = []) {
+ let token, lastToken, cutSrc;
+ // String with links masked to avoid interference with em and strong
+ let maskedSrc = src;
+ let match;
+ let keepPrevChar, prevChar;
+ // Mask out reflinks
+ if (this.tokens.links) {
+ const links = Object.keys(this.tokens.links);
+ if (links.length > 0) {
+ while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {
+ if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) {
+ maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);
+ }
+ }
+ }
+ }
+ // Mask out other blocks
+ while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {
+ maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
+ }
+ // Mask out escaped characters
+ while ((match = this.tokenizer.rules.inline.anyPunctuation.exec(maskedSrc)) != null) {
+ maskedSrc = maskedSrc.slice(0, match.index) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);
+ }
+ while (src) {
+ if (!keepPrevChar) {
+ prevChar = '';
+ }
+ keepPrevChar = false;
+ // extensions
+ if (this.options.extensions
+ && this.options.extensions.inline
+ && this.options.extensions.inline.some((extTokenizer) => {
+ if (token = extTokenizer.call({ lexer: this }, src, tokens)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ return true;
+ }
+ return false;
+ })) {
+ continue;
+ }
+ // escape
+ if (token = this.tokenizer.escape(src)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ continue;
+ }
+ // tag
+ if (token = this.tokenizer.tag(src)) {
+ src = src.substring(token.raw.length);
+ lastToken = tokens[tokens.length - 1];
+ if (lastToken && token.type === 'text' && lastToken.type === 'text') {
+ lastToken.raw += token.raw;
+ lastToken.text += token.text;
+ }
+ else {
+ tokens.push(token);
+ }
+ continue;
+ }
+ // link
+ if (token = this.tokenizer.link(src)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ continue;
+ }
+ // reflink, nolink
+ if (token = this.tokenizer.reflink(src, this.tokens.links)) {
+ src = src.substring(token.raw.length);
+ lastToken = tokens[tokens.length - 1];
+ if (lastToken && token.type === 'text' && lastToken.type === 'text') {
+ lastToken.raw += token.raw;
+ lastToken.text += token.text;
+ }
+ else {
+ tokens.push(token);
+ }
+ continue;
+ }
+ // em & strong
+ if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ continue;
+ }
+ // code
+ if (token = this.tokenizer.codespan(src)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ continue;
+ }
+ // br
+ if (token = this.tokenizer.br(src)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ continue;
+ }
+ // del (gfm)
+ if (token = this.tokenizer.del(src)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ continue;
+ }
+ // autolink
+ if (token = this.tokenizer.autolink(src)) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ continue;
+ }
+ // url (gfm)
+ if (!this.state.inLink && (token = this.tokenizer.url(src))) {
+ src = src.substring(token.raw.length);
+ tokens.push(token);
+ continue;
+ }
+ // text
+ // prevent inlineText consuming extensions by clipping 'src' to extension start
+ cutSrc = src;
+ if (this.options.extensions && this.options.extensions.startInline) {
+ let startIndex = Infinity;
+ const tempSrc = src.slice(1);
+ let tempStart;
+ this.options.extensions.startInline.forEach((getStartIndex) => {
+ tempStart = getStartIndex.call({ lexer: this }, tempSrc);
+ if (typeof tempStart === 'number' && tempStart >= 0) {
+ startIndex = Math.min(startIndex, tempStart);
+ }
+ });
+ if (startIndex < Infinity && startIndex >= 0) {
+ cutSrc = src.substring(0, startIndex + 1);
+ }
+ }
+ if (token = this.tokenizer.inlineText(cutSrc)) {
+ src = src.substring(token.raw.length);
+ if (token.raw.slice(-1) !== '_') { // Track prevChar before string of ____ started
+ prevChar = token.raw.slice(-1);
+ }
+ keepPrevChar = true;
+ lastToken = tokens[tokens.length - 1];
+ if (lastToken && lastToken.type === 'text') {
+ lastToken.raw += token.raw;
+ lastToken.text += token.text;
+ }
+ else {
+ tokens.push(token);
+ }
+ continue;
+ }
+ if (src) {
+ const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
+ if (this.options.silent) {
+ console.error(errMsg);
+ break;
+ }
+ else {
+ throw new Error(errMsg);
+ }
+ }
+ }
+ return tokens;
+ }
+}
+
+/**
+ * Renderer
+ */
+class _Renderer {
+ options;
+ constructor(options) {
+ this.options = options || _defaults;
+ }
+ code(code, infostring, escaped) {
+ const lang = (infostring || '').match(/^\S*/)?.[0];
+ code = code.replace(/\n$/, '') + '\n';
+ if (!lang) {
+ return ''
+ + (escaped ? code : escape$1(code, true))
+ + '
\n';
+ }
+ return ''
+ + (escaped ? code : escape$1(code, true))
+ + '
\n';
+ }
+ blockquote(quote) {
+ return `\n${quote}
\n`;
+ }
+ html(html, block) {
+ return html;
+ }
+ heading(text, level, raw) {
+ // ignore IDs
+ return `${text} \n`;
+ }
+ hr() {
+ return '
\n';
+ }
+ list(body, ordered, start) {
+ const type = ordered ? 'ol' : 'ul';
+ const startatt = (ordered && start !== 1) ? (' start="' + start + '"') : '';
+ return '<' + type + startatt + '>\n' + body + '' + type + '>\n';
+ }
+ listitem(text, task, checked) {
+ return `${text} \n`;
+ }
+ checkbox(checked) {
+ return '';
+ }
+ paragraph(text) {
+ return `${text}
\n`;
+ }
+ table(header, body) {
+ if (body)
+ body = `${body}`;
+ return '\n'
+ + '\n'
+ + header
+ + '\n'
+ + body
+ + '
\n';
+ }
+ tablerow(content) {
+ return `\n${content} \n`;
+ }
+ tablecell(content, flags) {
+ const type = flags.header ? 'th' : 'td';
+ const tag = flags.align
+ ? `<${type} align="${flags.align}">`
+ : `<${type}>`;
+ return tag + content + `${type}>\n`;
+ }
+ /**
+ * span level renderer
+ */
+ strong(text) {
+ return `${text}`;
+ }
+ em(text) {
+ return `${text}`;
+ }
+ codespan(text) {
+ return `${text}`;
+ }
+ br() {
+ return '
';
+ }
+ del(text) {
+ return `${text}`;
+ }
+ link(href, title, text) {
+ const cleanHref = cleanUrl(href);
+ if (cleanHref === null) {
+ return text;
+ }
+ href = cleanHref;
+ let out = '' + text + '';
+ return out;
+ }
+ image(href, title, text) {
+ const cleanHref = cleanUrl(href);
+ if (cleanHref === null) {
+ return text;
+ }
+ href = cleanHref;
+ let out = `
';
+ return out;
+ }
+ text(text) {
+ return text;
+ }
+}
+
+/**
+ * TextRenderer
+ * returns only the textual part of the token
+ */
+class _TextRenderer {
+ // no need for block level renderers
+ strong(text) {
+ return text;
+ }
+ em(text) {
+ return text;
+ }
+ codespan(text) {
+ return text;
+ }
+ del(text) {
+ return text;
+ }
+ html(text) {
+ return text;
+ }
+ text(text) {
+ return text;
+ }
+ link(href, title, text) {
+ return '' + text;
+ }
+ image(href, title, text) {
+ return '' + text;
+ }
+ br() {
+ return '';
+ }
+}
+
+/**
+ * Parsing & Compiling
+ */
+class _Parser {
+ options;
+ renderer;
+ textRenderer;
+ constructor(options) {
+ this.options = options || _defaults;
+ this.options.renderer = this.options.renderer || new _Renderer();
+ this.renderer = this.options.renderer;
+ this.renderer.options = this.options;
+ this.textRenderer = new _TextRenderer();
+ }
+ /**
+ * Static Parse Method
+ */
+ static parse(tokens, options) {
+ const parser = new _Parser(options);
+ return parser.parse(tokens);
+ }
+ /**
+ * Static Parse Inline Method
+ */
+ static parseInline(tokens, options) {
+ const parser = new _Parser(options);
+ return parser.parseInline(tokens);
+ }
+ /**
+ * Parse Loop
+ */
+ parse(tokens, top = true) {
+ let out = '';
+ for (let i = 0; i < tokens.length; i++) {
+ const token = tokens[i];
+ // Run any renderer extensions
+ if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
+ const genericToken = token;
+ const ret = this.options.extensions.renderers[genericToken.type].call({ parser: this }, genericToken);
+ if (ret !== false || !['space', 'hr', 'heading', 'code', 'table', 'blockquote', 'list', 'html', 'paragraph', 'text'].includes(genericToken.type)) {
+ out += ret || '';
+ continue;
+ }
+ }
+ switch (token.type) {
+ case 'space': {
+ continue;
+ }
+ case 'hr': {
+ out += this.renderer.hr();
+ continue;
+ }
+ case 'heading': {
+ const headingToken = token;
+ out += this.renderer.heading(this.parseInline(headingToken.tokens), headingToken.depth, unescape(this.parseInline(headingToken.tokens, this.textRenderer)));
+ continue;
+ }
+ case 'code': {
+ const codeToken = token;
+ out += this.renderer.code(codeToken.text, codeToken.lang, !!codeToken.escaped);
+ continue;
+ }
+ case 'table': {
+ const tableToken = token;
+ let header = '';
+ // header
+ let cell = '';
+ for (let j = 0; j < tableToken.header.length; j++) {
+ cell += this.renderer.tablecell(this.parseInline(tableToken.header[j].tokens), { header: true, align: tableToken.align[j] });
+ }
+ header += this.renderer.tablerow(cell);
+ let body = '';
+ for (let j = 0; j < tableToken.rows.length; j++) {
+ const row = tableToken.rows[j];
+ cell = '';
+ for (let k = 0; k < row.length; k++) {
+ cell += this.renderer.tablecell(this.parseInline(row[k].tokens), { header: false, align: tableToken.align[k] });
+ }
+ body += this.renderer.tablerow(cell);
+ }
+ out += this.renderer.table(header, body);
+ continue;
+ }
+ case 'blockquote': {
+ const blockquoteToken = token;
+ const body = this.parse(blockquoteToken.tokens);
+ out += this.renderer.blockquote(body);
+ continue;
+ }
+ case 'list': {
+ const listToken = token;
+ const ordered = listToken.ordered;
+ const start = listToken.start;
+ const loose = listToken.loose;
+ let body = '';
+ for (let j = 0; j < listToken.items.length; j++) {
+ const item = listToken.items[j];
+ const checked = item.checked;
+ const task = item.task;
+ let itemBody = '';
+ if (item.task) {
+ const checkbox = this.renderer.checkbox(!!checked);
+ if (loose) {
+ if (item.tokens.length > 0 && item.tokens[0].type === 'paragraph') {
+ item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;
+ if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {
+ item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;
+ }
+ }
+ else {
+ item.tokens.unshift({
+ type: 'text',
+ text: checkbox + ' '
+ });
+ }
+ }
+ else {
+ itemBody += checkbox + ' ';
+ }
+ }
+ itemBody += this.parse(item.tokens, loose);
+ body += this.renderer.listitem(itemBody, task, !!checked);
+ }
+ out += this.renderer.list(body, ordered, start);
+ continue;
+ }
+ case 'html': {
+ const htmlToken = token;
+ out += this.renderer.html(htmlToken.text, htmlToken.block);
+ continue;
+ }
+ case 'paragraph': {
+ const paragraphToken = token;
+ out += this.renderer.paragraph(this.parseInline(paragraphToken.tokens));
+ continue;
+ }
+ case 'text': {
+ let textToken = token;
+ let body = textToken.tokens ? this.parseInline(textToken.tokens) : textToken.text;
+ while (i + 1 < tokens.length && tokens[i + 1].type === 'text') {
+ textToken = tokens[++i];
+ body += '\n' + (textToken.tokens ? this.parseInline(textToken.tokens) : textToken.text);
+ }
+ out += top ? this.renderer.paragraph(body) : body;
+ continue;
+ }
+ default: {
+ const errMsg = 'Token with "' + token.type + '" type was not found.';
+ if (this.options.silent) {
+ console.error(errMsg);
+ return '';
+ }
+ else {
+ throw new Error(errMsg);
+ }
+ }
+ }
+ }
+ return out;
+ }
+ /**
+ * Parse Inline Tokens
+ */
+ parseInline(tokens, renderer) {
+ renderer = renderer || this.renderer;
+ let out = '';
+ for (let i = 0; i < tokens.length; i++) {
+ const token = tokens[i];
+ // Run any renderer extensions
+ if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
+ const ret = this.options.extensions.renderers[token.type].call({ parser: this }, token);
+ if (ret !== false || !['escape', 'html', 'link', 'image', 'strong', 'em', 'codespan', 'br', 'del', 'text'].includes(token.type)) {
+ out += ret || '';
+ continue;
+ }
+ }
+ switch (token.type) {
+ case 'escape': {
+ const escapeToken = token;
+ out += renderer.text(escapeToken.text);
+ break;
+ }
+ case 'html': {
+ const tagToken = token;
+ out += renderer.html(tagToken.text);
+ break;
+ }
+ case 'link': {
+ const linkToken = token;
+ out += renderer.link(linkToken.href, linkToken.title, this.parseInline(linkToken.tokens, renderer));
+ break;
+ }
+ case 'image': {
+ const imageToken = token;
+ out += renderer.image(imageToken.href, imageToken.title, imageToken.text);
+ break;
+ }
+ case 'strong': {
+ const strongToken = token;
+ out += renderer.strong(this.parseInline(strongToken.tokens, renderer));
+ break;
+ }
+ case 'em': {
+ const emToken = token;
+ out += renderer.em(this.parseInline(emToken.tokens, renderer));
+ break;
+ }
+ case 'codespan': {
+ const codespanToken = token;
+ out += renderer.codespan(codespanToken.text);
+ break;
+ }
+ case 'br': {
+ out += renderer.br();
+ break;
+ }
+ case 'del': {
+ const delToken = token;
+ out += renderer.del(this.parseInline(delToken.tokens, renderer));
+ break;
+ }
+ case 'text': {
+ const textToken = token;
+ out += renderer.text(textToken.text);
+ break;
+ }
+ default: {
+ const errMsg = 'Token with "' + token.type + '" type was not found.';
+ if (this.options.silent) {
+ console.error(errMsg);
+ return '';
+ }
+ else {
+ throw new Error(errMsg);
+ }
+ }
+ }
+ }
+ return out;
+ }
+}
+
+class _Hooks {
+ options;
+ constructor(options) {
+ this.options = options || _defaults;
+ }
+ static passThroughHooks = new Set([
+ 'preprocess',
+ 'postprocess',
+ 'processAllTokens'
+ ]);
+ /**
+ * Process markdown before marked
+ */
+ preprocess(markdown) {
+ return markdown;
+ }
+ /**
+ * Process HTML after marked is finished
+ */
+ postprocess(html) {
+ return html;
+ }
+ /**
+ * Process all tokens before walk tokens
+ */
+ processAllTokens(tokens) {
+ return tokens;
+ }
+}
+
+class Marked {
+ defaults = _getDefaults();
+ options = this.setOptions;
+ parse = this.#parseMarkdown(_Lexer.lex, _Parser.parse);
+ parseInline = this.#parseMarkdown(_Lexer.lexInline, _Parser.parseInline);
+ Parser = _Parser;
+ Renderer = _Renderer;
+ TextRenderer = _TextRenderer;
+ Lexer = _Lexer;
+ Tokenizer = _Tokenizer;
+ Hooks = _Hooks;
+ constructor(...args) {
+ this.use(...args);
+ }
+ /**
+ * Run callback for every token
+ */
+ walkTokens(tokens, callback) {
+ let values = [];
+ for (const token of tokens) {
+ values = values.concat(callback.call(this, token));
+ switch (token.type) {
+ case 'table': {
+ const tableToken = token;
+ for (const cell of tableToken.header) {
+ values = values.concat(this.walkTokens(cell.tokens, callback));
+ }
+ for (const row of tableToken.rows) {
+ for (const cell of row) {
+ values = values.concat(this.walkTokens(cell.tokens, callback));
+ }
+ }
+ break;
+ }
+ case 'list': {
+ const listToken = token;
+ values = values.concat(this.walkTokens(listToken.items, callback));
+ break;
+ }
+ default: {
+ const genericToken = token;
+ if (this.defaults.extensions?.childTokens?.[genericToken.type]) {
+ this.defaults.extensions.childTokens[genericToken.type].forEach((childTokens) => {
+ values = values.concat(this.walkTokens(genericToken[childTokens], callback));
+ });
+ }
+ else if (genericToken.tokens) {
+ values = values.concat(this.walkTokens(genericToken.tokens, callback));
+ }
+ }
+ }
+ }
+ return values;
+ }
+ use(...args) {
+ const extensions = this.defaults.extensions || { renderers: {}, childTokens: {} };
+ args.forEach((pack) => {
+ // copy options to new object
+ const opts = { ...pack };
+ // set async to true if it was set to true before
+ opts.async = this.defaults.async || opts.async || false;
+ // ==-- Parse "addon" extensions --== //
+ if (pack.extensions) {
+ pack.extensions.forEach((ext) => {
+ if (!ext.name) {
+ throw new Error('extension name required');
+ }
+ if ('renderer' in ext) { // Renderer extensions
+ const prevRenderer = extensions.renderers[ext.name];
+ if (prevRenderer) {
+ // Replace extension with func to run new extension but fall back if false
+ extensions.renderers[ext.name] = function (...args) {
+ let ret = ext.renderer.apply(this, args);
+ if (ret === false) {
+ ret = prevRenderer.apply(this, args);
+ }
+ return ret;
+ };
+ }
+ else {
+ extensions.renderers[ext.name] = ext.renderer;
+ }
+ }
+ if ('tokenizer' in ext) { // Tokenizer Extensions
+ if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) {
+ throw new Error("extension level must be 'block' or 'inline'");
+ }
+ const extLevel = extensions[ext.level];
+ if (extLevel) {
+ extLevel.unshift(ext.tokenizer);
+ }
+ else {
+ extensions[ext.level] = [ext.tokenizer];
+ }
+ if (ext.start) { // Function to check for start of token
+ if (ext.level === 'block') {
+ if (extensions.startBlock) {
+ extensions.startBlock.push(ext.start);
+ }
+ else {
+ extensions.startBlock = [ext.start];
+ }
+ }
+ else if (ext.level === 'inline') {
+ if (extensions.startInline) {
+ extensions.startInline.push(ext.start);
+ }
+ else {
+ extensions.startInline = [ext.start];
+ }
+ }
+ }
+ }
+ if ('childTokens' in ext && ext.childTokens) { // Child tokens to be visited by walkTokens
+ extensions.childTokens[ext.name] = ext.childTokens;
+ }
+ });
+ opts.extensions = extensions;
+ }
+ // ==-- Parse "overwrite" extensions --== //
+ if (pack.renderer) {
+ const renderer = this.defaults.renderer || new _Renderer(this.defaults);
+ for (const prop in pack.renderer) {
+ if (!(prop in renderer)) {
+ throw new Error(`renderer '${prop}' does not exist`);
+ }
+ if (prop === 'options') {
+ // ignore options property
+ continue;
+ }
+ const rendererProp = prop;
+ const rendererFunc = pack.renderer[rendererProp];
+ const prevRenderer = renderer[rendererProp];
+ // Replace renderer with func to run extension, but fall back if false
+ renderer[rendererProp] = (...args) => {
+ let ret = rendererFunc.apply(renderer, args);
+ if (ret === false) {
+ ret = prevRenderer.apply(renderer, args);
+ }
+ return ret || '';
+ };
+ }
+ opts.renderer = renderer;
+ }
+ if (pack.tokenizer) {
+ const tokenizer = this.defaults.tokenizer || new _Tokenizer(this.defaults);
+ for (const prop in pack.tokenizer) {
+ if (!(prop in tokenizer)) {
+ throw new Error(`tokenizer '${prop}' does not exist`);
+ }
+ if (['options', 'rules', 'lexer'].includes(prop)) {
+ // ignore options, rules, and lexer properties
+ continue;
+ }
+ const tokenizerProp = prop;
+ const tokenizerFunc = pack.tokenizer[tokenizerProp];
+ const prevTokenizer = tokenizer[tokenizerProp];
+ // Replace tokenizer with func to run extension, but fall back if false
+ // @ts-expect-error cannot type tokenizer function dynamically
+ tokenizer[tokenizerProp] = (...args) => {
+ let ret = tokenizerFunc.apply(tokenizer, args);
+ if (ret === false) {
+ ret = prevTokenizer.apply(tokenizer, args);
+ }
+ return ret;
+ };
+ }
+ opts.tokenizer = tokenizer;
+ }
+ // ==-- Parse Hooks extensions --== //
+ if (pack.hooks) {
+ const hooks = this.defaults.hooks || new _Hooks();
+ for (const prop in pack.hooks) {
+ if (!(prop in hooks)) {
+ throw new Error(`hook '${prop}' does not exist`);
+ }
+ if (prop === 'options') {
+ // ignore options property
+ continue;
+ }
+ const hooksProp = prop;
+ const hooksFunc = pack.hooks[hooksProp];
+ const prevHook = hooks[hooksProp];
+ if (_Hooks.passThroughHooks.has(prop)) {
+ // @ts-expect-error cannot type hook function dynamically
+ hooks[hooksProp] = (arg) => {
+ if (this.defaults.async) {
+ return Promise.resolve(hooksFunc.call(hooks, arg)).then(ret => {
+ return prevHook.call(hooks, ret);
+ });
+ }
+ const ret = hooksFunc.call(hooks, arg);
+ return prevHook.call(hooks, ret);
+ };
+ }
+ else {
+ // @ts-expect-error cannot type hook function dynamically
+ hooks[hooksProp] = (...args) => {
+ let ret = hooksFunc.apply(hooks, args);
+ if (ret === false) {
+ ret = prevHook.apply(hooks, args);
+ }
+ return ret;
+ };
+ }
+ }
+ opts.hooks = hooks;
+ }
+ // ==-- Parse WalkTokens extensions --== //
+ if (pack.walkTokens) {
+ const walkTokens = this.defaults.walkTokens;
+ const packWalktokens = pack.walkTokens;
+ opts.walkTokens = function (token) {
+ let values = [];
+ values.push(packWalktokens.call(this, token));
+ if (walkTokens) {
+ values = values.concat(walkTokens.call(this, token));
+ }
+ return values;
+ };
+ }
+ this.defaults = { ...this.defaults, ...opts };
+ });
+ return this;
+ }
+ setOptions(opt) {
+ this.defaults = { ...this.defaults, ...opt };
+ return this;
+ }
+ lexer(src, options) {
+ return _Lexer.lex(src, options ?? this.defaults);
+ }
+ parser(tokens, options) {
+ return _Parser.parse(tokens, options ?? this.defaults);
+ }
+ #parseMarkdown(lexer, parser) {
+ return (src, options) => {
+ const origOpt = { ...options };
+ const opt = { ...this.defaults, ...origOpt };
+ // Show warning if an extension set async to true but the parse was called with async: false
+ if (this.defaults.async === true && origOpt.async === false) {
+ if (!opt.silent) {
+ console.warn('marked(): The async option was set to true by an extension. The async: false option sent to parse will be ignored.');
+ }
+ opt.async = true;
+ }
+ const throwError = this.#onError(!!opt.silent, !!opt.async);
+ // throw error in case of non string input
+ if (typeof src === 'undefined' || src === null) {
+ return throwError(new Error('marked(): input parameter is undefined or null'));
+ }
+ if (typeof src !== 'string') {
+ return throwError(new Error('marked(): input parameter is of type '
+ + Object.prototype.toString.call(src) + ', string expected'));
+ }
+ if (opt.hooks) {
+ opt.hooks.options = opt;
+ }
+ if (opt.async) {
+ return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src)
+ .then(src => lexer(src, opt))
+ .then(tokens => opt.hooks ? opt.hooks.processAllTokens(tokens) : tokens)
+ .then(tokens => opt.walkTokens ? Promise.all(this.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens)
+ .then(tokens => parser(tokens, opt))
+ .then(html => opt.hooks ? opt.hooks.postprocess(html) : html)
+ .catch(throwError);
+ }
+ try {
+ if (opt.hooks) {
+ src = opt.hooks.preprocess(src);
+ }
+ let tokens = lexer(src, opt);
+ if (opt.hooks) {
+ tokens = opt.hooks.processAllTokens(tokens);
+ }
+ if (opt.walkTokens) {
+ this.walkTokens(tokens, opt.walkTokens);
+ }
+ let html = parser(tokens, opt);
+ if (opt.hooks) {
+ html = opt.hooks.postprocess(html);
+ }
+ return html;
+ }
+ catch (e) {
+ return throwError(e);
+ }
+ };
+ }
+ #onError(silent, async) {
+ return (e) => {
+ e.message += '\nPlease report this to https://github.com/markedjs/marked.';
+ if (silent) {
+ const msg = 'An error occurred:
'
+ + escape$1(e.message + '', true)
+ + '
';
+ if (async) {
+ return Promise.resolve(msg);
+ }
+ return msg;
+ }
+ if (async) {
+ return Promise.reject(e);
+ }
+ throw e;
+ };
+ }
+}
+
+const markedInstance = new Marked();
+function marked(src, opt) {
+ return markedInstance.parse(src, opt);
+}
+/**
+ * Sets the default options.
+ *
+ * @param options Hash of options
+ */
+marked.options =
+ marked.setOptions = function (options) {
+ markedInstance.setOptions(options);
+ marked.defaults = markedInstance.defaults;
+ changeDefaults(marked.defaults);
+ return marked;
+ };
+/**
+ * Gets the original marked default options.
+ */
+marked.getDefaults = _getDefaults;
+marked.defaults = _defaults;
+/**
+ * Use Extension
+ */
+marked.use = function (...args) {
+ markedInstance.use(...args);
+ marked.defaults = markedInstance.defaults;
+ changeDefaults(marked.defaults);
+ return marked;
+};
+/**
+ * Run callback for every token
+ */
+marked.walkTokens = function (tokens, callback) {
+ return markedInstance.walkTokens(tokens, callback);
+};
+/**
+ * Compiles markdown to HTML without enclosing `p` tag.
+ *
+ * @param src String of markdown source to be compiled
+ * @param options Hash of options
+ * @return String of compiled HTML
+ */
+marked.parseInline = markedInstance.parseInline;
+/**
+ * Expose
+ */
+marked.Parser = _Parser;
+marked.parser = _Parser.parse;
+marked.Renderer = _Renderer;
+marked.TextRenderer = _TextRenderer;
+marked.Lexer = _Lexer;
+marked.lexer = _Lexer.lex;
+marked.Tokenizer = _Tokenizer;
+marked.Hooks = _Hooks;
+marked.parse = marked;
+const options = marked.options;
+const setOptions = marked.setOptions;
+const use = marked.use;
+const walkTokens = marked.walkTokens;
+const parseInline = marked.parseInline;
+const parse = marked;
+const parser = _Parser.parse;
+const lexer = _Lexer.lex;
+
+export { _Hooks as Hooks, _Lexer as Lexer, Marked, _Parser as Parser, _Renderer as Renderer, _TextRenderer as TextRenderer, _Tokenizer as Tokenizer, _defaults as defaults, _getDefaults as getDefaults, lexer, marked, options, parse, parseInline, parser, setOptions, use, walkTokens };
+//# sourceMappingURL=marked.esm.js.map
diff --git a/assets/js/vendor/preact-htm.module.js b/assets/js/vendor/preact-htm.module.js
new file mode 100644
index 0000000..e24f87b
--- /dev/null
+++ b/assets/js/vendor/preact-htm.module.js
@@ -0,0 +1 @@
+var e,n,_,t,o,r,u,l={},i=[],c=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function s(e,n){for(var _ in n)e[_]=n[_];return e}function f(e){var n=e.parentNode;n&&n.removeChild(e)}function a(n,_,t){var o,r,u,l={};for(u in _)"key"==u?o=_[u]:"ref"==u?r=_[u]:l[u]=_[u];if(arguments.length>2&&(l.children=arguments.length>3?e.call(arguments,2):t),"function"==typeof n&&null!=n.defaultProps)for(u in n.defaultProps)void 0===l[u]&&(l[u]=n.defaultProps[u]);return p(n,l,o,r,null)}function p(e,t,o,r,u){var l={type:e,props:t,key:o,ref:r,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:null==u?++_:u};return null!=n.vnode&&n.vnode(l),l}function h(e){return e.children}function d(e,n){this.props=e,this.context=n}function v(e,n){if(null==n)return e.__?v(e.__,e.__.__k.indexOf(e)+1):null;for(var _;n0?p(m.type,m.props,m.key,null,m.__v):m)){if(m.__=_,m.__b=_.__b+1,null===(y=H[a])||y&&m.key==y.key&&m.type===y.type)H[a]=void 0;else for(d=0;d=t.__.length&&t.__.push({}),t.__[e]}function G(e){return R=1,z(ie,e)}function z(e,n,_){var t=j(L++,2);return t.t=e,t.__c||(t.__=[_?_(n):ie(void 0,n),function(e){var n=t.t(t.__[0],e);t.__[0]!==n&&(t.__=[n,t.__[1]],t.__c.setState({}))}],t.__c=N),t.__}function J(e,_){var t=j(L++,3);!n.__s&&le(t.__H,_)&&(t.__=e,t.__H=_,N.__H.__h.push(t))}function K(e,_){var t=j(L++,4);!n.__s&&le(t.__H,_)&&(t.__=e,t.__H=_,N.__h.push(t))}function Q(e){return R=5,Y(function(){return{current:e}},[])}function X(e,n,_){R=6,K(function(){"function"==typeof e?e(n()):e&&(e.current=n())},null==_?_:_.concat(e))}function Y(e,n){var _=j(L++,7);return le(_.__H,n)&&(_.__=e(),_.__H=n,_.__h=e),_.__}function Z(e,n){return R=8,Y(function(){return e},n)}function ee(e){var n=N.context[e.__c],_=j(L++,9);return _.c=e,n?(null==_.__&&(_.__=!0,n.sub(N)),n.props.value):e.__}function ne(e,_){n.useDebugValue&&n.useDebugValue(_?_(e):e)}function _e(e){var n=j(L++,10),_=G();return n.__=e,N.componentDidCatch||(N.componentDidCatch=function(e){n.__&&n.__(e),_[1](e)}),[_[0],function(){_[1](void 0)}]}function te(){I.forEach(function(e){if(e.__P)try{e.__H.__h.forEach(re),e.__H.__h.forEach(ue),e.__H.__h=[]}catch(_){e.__H.__h=[],n.__e(_,e.__v)}}),I=[]}n.__b=function(e){N=null,O&&O(e)},n.__r=function(e){V&&V(e),L=0;var n=(N=e.__c).__H;n&&(n.__h.forEach(re),n.__h.forEach(ue),n.__h=[])},n.diffed=function(e){q&&q(e);var _=e.__c;_&&_.__H&&_.__H.__h.length&&(1!==I.push(_)&&W===n.requestAnimationFrame||((W=n.requestAnimationFrame)||function(e){var n,_=function(){clearTimeout(t),oe&&cancelAnimationFrame(n),setTimeout(e)},t=setTimeout(_,100);oe&&(n=requestAnimationFrame(_))})(te)),N=void 0},n.__c=function(e,_){_.some(function(e){try{e.__h.forEach(re),e.__h=e.__h.filter(function(e){return!e.__||ue(e)})}catch(t){_.some(function(e){e.__h&&(e.__h=[])}),_=[],n.__e(t,e.__v)}}),B&&B(e,_)},n.unmount=function(e){$&&$(e);var _=e.__c;if(_&&_.__H)try{_.__H.__.forEach(re)}catch(e){n.__e(e,_.__v)}};var oe="function"==typeof requestAnimationFrame;function re(e){var n=N;"function"==typeof e.__c&&e.__c(),N=n}function ue(e){var n=N;e.__c=e.__(),N=n}function le(e,n){return!e||e.length!==n.length||n.some(function(n,_){return n!==e[_]})}function ie(e,n){return"function"==typeof n?n(e):n}var ce=function(e,n,_,t){var o;n[0]=0;for(var r=1;r=5&&((o||!e&&5===t)&&(u.push(t,0,o,_),t=6),e&&(u.push(t,e,0,_),t=6)),o=""},i=0;i"===n?(t=1,o=""):o=n+o[0]:r?n===r?r="":o+=n:'"'===n||"'"===n?r=n:">"===n?(l(),t=1):t&&("="===n?(t=5,_=o,o=""):"/"===n&&(t<5||">"===e[i][c+1])?(l(),3===t&&(u=u[0]),t=u,(u=u[0]).push(2,0,t),t=0):" "===n||"\t"===n||"\n"===n||"\r"===n?(l(),t=2):o+=n),3===t&&"!--"===o&&(t=4,u=u[0])}return l(),u}(e)),n),arguments,[])).length>1?n:n[0]}.bind(a);export{a as h,fe as html,M as render,d as Component,F as createContext,G as useState,z as useReducer,J as useEffect,K as useLayoutEffect,Q as useRef,X as useImperativeHandle,Y as useMemo,Z as useCallback,ee as useContext,ne as useDebugValue,_e as useErrorBoundary};
diff --git a/assets/js/vendor/purify.es.mjs b/assets/js/vendor/purify.es.mjs
new file mode 100644
index 0000000..5b12eee
--- /dev/null
+++ b/assets/js/vendor/purify.es.mjs
@@ -0,0 +1,2249 @@
+/*! @license DOMPurify 3.4.11 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.11/LICENSE */
+
+function _arrayLikeToArray(r, a) {
+ (null == a || a > r.length) && (a = r.length);
+ for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
+ return n;
+}
+function _arrayWithHoles(r) {
+ if (Array.isArray(r)) return r;
+}
+function _iterableToArrayLimit(r, l) {
+ var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
+ if (null != t) {
+ var e,
+ n,
+ i,
+ u,
+ a = [],
+ f = true,
+ o = false;
+ try {
+ if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
+ } catch (r) {
+ o = true, n = r;
+ } finally {
+ try {
+ if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
+ } finally {
+ if (o) throw n;
+ }
+ }
+ return a;
+ }
+}
+function _nonIterableRest() {
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
+}
+function _slicedToArray(r, e) {
+ return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
+}
+function _unsupportedIterableToArray(r, a) {
+ if (r) {
+ if ("string" == typeof r) return _arrayLikeToArray(r, a);
+ var t = {}.toString.call(r).slice(8, -1);
+ return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
+ }
+}
+
+const entries = Object.entries,
+ setPrototypeOf = Object.setPrototypeOf,
+ isFrozen = Object.isFrozen,
+ getPrototypeOf = Object.getPrototypeOf,
+ getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
+let freeze = Object.freeze,
+ seal = Object.seal,
+ create = Object.create; // eslint-disable-line import/no-mutable-exports
+let _ref = typeof Reflect !== 'undefined' && Reflect,
+ apply = _ref.apply,
+ construct = _ref.construct;
+if (!freeze) {
+ freeze = function freeze(x) {
+ return x;
+ };
+}
+if (!seal) {
+ seal = function seal(x) {
+ return x;
+ };
+}
+if (!apply) {
+ apply = function apply(func, thisArg) {
+ for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
+ args[_key - 2] = arguments[_key];
+ }
+ return func.apply(thisArg, args);
+ };
+}
+if (!construct) {
+ construct = function construct(Func) {
+ for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
+ args[_key2 - 1] = arguments[_key2];
+ }
+ return new Func(...args);
+ };
+}
+const arrayForEach = unapply(Array.prototype.forEach);
+const arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);
+const arrayPop = unapply(Array.prototype.pop);
+const arrayPush = unapply(Array.prototype.push);
+const arraySplice = unapply(Array.prototype.splice);
+const arrayIsArray = Array.isArray;
+const stringToLowerCase = unapply(String.prototype.toLowerCase);
+const stringToString = unapply(String.prototype.toString);
+const stringMatch = unapply(String.prototype.match);
+const stringReplace = unapply(String.prototype.replace);
+const stringIndexOf = unapply(String.prototype.indexOf);
+const stringTrim = unapply(String.prototype.trim);
+const numberToString = unapply(Number.prototype.toString);
+const booleanToString = unapply(Boolean.prototype.toString);
+const bigintToString = typeof BigInt === 'undefined' ? null : unapply(BigInt.prototype.toString);
+const symbolToString = typeof Symbol === 'undefined' ? null : unapply(Symbol.prototype.toString);
+const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
+const objectToString = unapply(Object.prototype.toString);
+const regExpTest = unapply(RegExp.prototype.test);
+const typeErrorCreate = unconstruct(TypeError);
+/**
+ * Creates a new function that calls the given function with a specified thisArg and arguments.
+ *
+ * @param func - The function to be wrapped and called.
+ * @returns A new function that calls the given function with a specified thisArg and arguments.
+ */
+function unapply(func) {
+ return function (thisArg) {
+ if (thisArg instanceof RegExp) {
+ thisArg.lastIndex = 0;
+ }
+ for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
+ args[_key3 - 1] = arguments[_key3];
+ }
+ return apply(func, thisArg, args);
+ };
+}
+/**
+ * Creates a new function that constructs an instance of the given constructor function with the provided arguments.
+ *
+ * @param func - The constructor function to be wrapped and called.
+ * @returns A new function that constructs an instance of the given constructor function with the provided arguments.
+ */
+function unconstruct(Func) {
+ return function () {
+ for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
+ args[_key4] = arguments[_key4];
+ }
+ return construct(Func, args);
+ };
+}
+/**
+ * Add properties to a lookup table
+ *
+ * @param set - The set to which elements will be added.
+ * @param array - The array containing elements to be added to the set.
+ * @param transformCaseFunc - An optional function to transform the case of each element before adding to the set.
+ * @returns The modified set with added elements.
+ */
+function addToSet(set, array) {
+ let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;
+ if (setPrototypeOf) {
+ // Make 'in' and truthy checks like Boolean(set.constructor)
+ // independent of any properties defined on Object.prototype.
+ // Prevent prototype setters from intercepting set as a this value.
+ setPrototypeOf(set, null);
+ }
+ if (!arrayIsArray(array)) {
+ return set;
+ }
+ let l = array.length;
+ while (l--) {
+ let element = array[l];
+ if (typeof element === 'string') {
+ const lcElement = transformCaseFunc(element);
+ if (lcElement !== element) {
+ // Config presets (e.g. tags.js, attrs.js) are immutable.
+ if (!isFrozen(array)) {
+ array[l] = lcElement;
+ }
+ element = lcElement;
+ }
+ }
+ set[element] = true;
+ }
+ return set;
+}
+/**
+ * Clean up an array to harden against CSPP
+ *
+ * @param array - The array to be cleaned.
+ * @returns The cleaned version of the array
+ */
+function cleanArray(array) {
+ for (let index = 0; index < array.length; index++) {
+ const isPropertyExist = objectHasOwnProperty(array, index);
+ if (!isPropertyExist) {
+ array[index] = null;
+ }
+ }
+ return array;
+}
+/**
+ * Shallow clone an object
+ *
+ * @param object - The object to be cloned.
+ * @returns A new object that copies the original.
+ */
+function clone(object) {
+ const newObject = create(null);
+ for (const _ref2 of entries(object)) {
+ var _ref3 = _slicedToArray(_ref2, 2);
+ const property = _ref3[0];
+ const value = _ref3[1];
+ const isPropertyExist = objectHasOwnProperty(object, property);
+ if (isPropertyExist) {
+ if (arrayIsArray(value)) {
+ newObject[property] = cleanArray(value);
+ } else if (value && typeof value === 'object' && value.constructor === Object) {
+ newObject[property] = clone(value);
+ } else {
+ newObject[property] = value;
+ }
+ }
+ }
+ return newObject;
+}
+/**
+ * Convert non-node values into strings without depending on direct property access.
+ *
+ * @param value - The value to stringify.
+ * @returns A string representation of the provided value.
+ */
+function stringifyValue(value) {
+ switch (typeof value) {
+ case 'string':
+ {
+ return value;
+ }
+ case 'number':
+ {
+ return numberToString(value);
+ }
+ case 'boolean':
+ {
+ return booleanToString(value);
+ }
+ case 'bigint':
+ {
+ return bigintToString ? bigintToString(value) : '0';
+ }
+ case 'symbol':
+ {
+ return symbolToString ? symbolToString(value) : 'Symbol()';
+ }
+ case 'undefined':
+ {
+ return objectToString(value);
+ }
+ case 'function':
+ case 'object':
+ {
+ if (value === null) {
+ return objectToString(value);
+ }
+ const valueAsRecord = value;
+ const valueToString = lookupGetter(valueAsRecord, 'toString');
+ if (typeof valueToString === 'function') {
+ const stringified = valueToString(valueAsRecord);
+ return typeof stringified === 'string' ? stringified : objectToString(stringified);
+ }
+ return objectToString(value);
+ }
+ default:
+ {
+ return objectToString(value);
+ }
+ }
+}
+/**
+ * This method automatically checks if the prop is function or getter and behaves accordingly.
+ *
+ * @param object - The object to look up the getter function in its prototype chain.
+ * @param prop - The property name for which to find the getter function.
+ * @returns The getter function found in the prototype chain or a fallback function.
+ */
+function lookupGetter(object, prop) {
+ while (object !== null) {
+ const desc = getOwnPropertyDescriptor(object, prop);
+ if (desc) {
+ if (desc.get) {
+ return unapply(desc.get);
+ }
+ if (typeof desc.value === 'function') {
+ return unapply(desc.value);
+ }
+ }
+ object = getPrototypeOf(object);
+ }
+ function fallbackValue() {
+ return null;
+ }
+ return fallbackValue;
+}
+function isRegex(value) {
+ try {
+ regExpTest(value, '');
+ return true;
+ } catch (_unused) {
+ return false;
+ }
+}
+
+const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'search', 'section', 'select', 'shadow', 'slot', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
+const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'enterkeyhint', 'exportparts', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'inputmode', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'part', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
+const svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
+// List of SVG elements that are disallowed by default.
+// We still need to know them so that we can do namespace
+// checks properly in case one wants to add them to
+// allow-list.
+const svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']);
+const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'mprescripts']);
+// Similarly to SVG, we want to know all MathML elements,
+// even those that we disallow by default.
+const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
+const text = freeze(['#text']);
+
+const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'command', 'commandfor', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns']);
+const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'mask-type', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
+const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnalign', 'columnlines', 'columnspacing', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lquote', 'lspace', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
+const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
+
+const MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g);
+const ERB_EXPR = seal(/<%[\w\W]*|^[\w\W]*%>/g);
+const TMPLIT_EXPR = seal(/\${[\w\W]*/g);
+const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
+const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
+const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
+);
+const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
+const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
+);
+const DOCTYPE_NAME = seal(/^html$/i);
+const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
+// Markup-significant character probes used by _sanitizeElements.
+// Shared module-level instances are safe despite the sticky /g flags:
+// unapply() resets lastIndex for RegExp receivers before every call.
+const ELEMENT_MARKUP_PROBE = seal(/<[/\w!]/g);
+const COMMENT_MARKUP_PROBE = seal(/<[/\w]/g);
+const FALLBACK_TAG_CLOSE = seal(/<\/no(script|embed|frames)/i);
+const SELF_CLOSING_TAG = seal(/\/>/i);
+
+// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
+const NODE_TYPE = {
+ element: 1,
+ attribute: 2,
+ text: 3,
+ cdataSection: 4,
+ entityReference: 5,
+ // Deprecated
+ entityNode: 6,
+ // Deprecated
+ processingInstruction: 7,
+ comment: 8,
+ document: 9,
+ documentType: 10,
+ documentFragment: 11,
+ notation: 12 // Deprecated
+};
+const getGlobal = function getGlobal() {
+ return typeof window === 'undefined' ? null : window;
+};
+/**
+ * Creates a no-op policy for internal use only.
+ * Don't export this function outside this module!
+ * @param trustedTypes The policy factory.
+ * @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
+ * @return The policy created (or null, if Trusted Types
+ * are not supported or creating the policy failed).
+ */
+const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
+ if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
+ return null;
+ }
+ // Allow the callers to control the unique policy name
+ // by adding a data-tt-policy-suffix to the script element with the DOMPurify.
+ // Policy creation with duplicate names throws in Trusted Types.
+ let suffix = null;
+ const ATTR_NAME = 'data-tt-policy-suffix';
+ if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
+ suffix = purifyHostElement.getAttribute(ATTR_NAME);
+ }
+ const policyName = 'dompurify' + (suffix ? '#' + suffix : '');
+ try {
+ return trustedTypes.createPolicy(policyName, {
+ createHTML(html) {
+ return html;
+ },
+ createScriptURL(scriptUrl) {
+ return scriptUrl;
+ }
+ });
+ } catch (_) {
+ // Policy creation failed (most likely another DOMPurify script has
+ // already run). Skip creating the policy, as this will only cause errors
+ // if TT are enforced.
+ console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
+ return null;
+ }
+};
+const _createHooksMap = function _createHooksMap() {
+ return {
+ afterSanitizeAttributes: [],
+ afterSanitizeElements: [],
+ afterSanitizeShadowDOM: [],
+ beforeSanitizeAttributes: [],
+ beforeSanitizeElements: [],
+ beforeSanitizeShadowDOM: [],
+ uponSanitizeAttribute: [],
+ uponSanitizeElement: [],
+ uponSanitizeShadowNode: []
+ };
+};
+/**
+ * Resolve a set-valued configuration option: a fresh set built from
+ * cfg[key] when it is an own array property (seeded with a clone of
+ * options.base when given, case-normalized via options.transform),
+ * the fallback set otherwise.
+ *
+ * @param cfg the cloned, prototype-free configuration object
+ * @param key the configuration property to read
+ * @param fallback the set to use when the option is absent or not an array
+ * @param options transform and optional base set to merge into
+ * @returns the resolved set
+ */
+const _resolveSetOption = function _resolveSetOption(cfg, key, fallback, options) {
+ return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key]) ? addToSet(options.base ? clone(options.base) : {}, cfg[key], options.transform) : fallback;
+};
+function createDOMPurify() {
+ let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
+ const DOMPurify = root => createDOMPurify(root);
+ DOMPurify.version = '3.4.11';
+ DOMPurify.removed = [];
+ if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
+ // Not running in a browser, provide a factory function
+ // so that you can pass your own Window
+ DOMPurify.isSupported = false;
+ return DOMPurify;
+ }
+ let document = window.document;
+ const originalDocument = document;
+ const currentScript = originalDocument.currentScript;
+ window.DocumentFragment;
+ const HTMLTemplateElement = window.HTMLTemplateElement,
+ Node = window.Node,
+ Element = window.Element,
+ NodeFilter = window.NodeFilter,
+ _window$NamedNodeMap = window.NamedNodeMap;
+ _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap;
+ window.HTMLFormElement;
+ const DOMParser = window.DOMParser,
+ trustedTypes = window.trustedTypes;
+ const ElementPrototype = Element.prototype;
+ const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
+ const remove = lookupGetter(ElementPrototype, 'remove');
+ const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
+ const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
+ const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
+ const getShadowRoot = lookupGetter(ElementPrototype, 'shadowRoot');
+ const getAttributes = lookupGetter(ElementPrototype, 'attributes');
+ const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null;
+ const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeName') : null;
+ // As per issue #47, the web-components registry is inherited by a
+ // new document created via createHTMLDocument. As per the spec
+ // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
+ // a new empty registry is used when creating a template contents owner
+ // document, so we use that as our parent document to ensure nothing
+ // is inherited.
+ if (typeof HTMLTemplateElement === 'function') {
+ const template = document.createElement('template');
+ if (template.content && template.content.ownerDocument) {
+ document = template.content.ownerDocument;
+ }
+ }
+ let trustedTypesPolicy;
+ let emptyHTML = '';
+ // The instance's own internal Trusted Types policy. Unlike a caller-supplied
+ // `TRUSTED_TYPES_POLICY`, this is created at most once — Trusted Types throws
+ // on duplicate policy names — and is the only policy allowed to persist
+ // across configurations and survive `clearConfig()`.
+ let defaultTrustedTypesPolicy;
+ let defaultTrustedTypesPolicyResolved = false;
+ // Tracks whether we are already inside a call to the configured Trusted Types
+ // policy (`createHTML` or `createScriptURL`). If a supplied policy callback
+ // itself calls `DOMPurify.sanitize` (the cause of #1422), `sanitize` would
+ // re-enter the policy and recurse until the stack overflows. We detect that
+ // re-entry and throw a clear, actionable error instead. The guard is shared
+ // across both callbacks, because either one re-entering `sanitize` triggers
+ // the same unbounded recursion.
+ let IN_TRUSTED_TYPES_POLICY = 0;
+ const _assertNotInTrustedTypesPolicy = function _assertNotInTrustedTypesPolicy() {
+ if (IN_TRUSTED_TYPES_POLICY > 0) {
+ throw typeErrorCreate('A configured TRUSTED_TYPES_POLICY callback (createHTML or ' + 'createScriptURL) must not call DOMPurify.sanitize, as that causes ' + 'infinite recursion. Do not pass a policy whose callbacks wrap ' + 'DOMPurify as TRUSTED_TYPES_POLICY; see the "DOMPurify and Trusted ' + 'Types" section of the README.');
+ }
+ };
+ const _createTrustedHTML = function _createTrustedHTML(html) {
+ _assertNotInTrustedTypesPolicy();
+ IN_TRUSTED_TYPES_POLICY++;
+ try {
+ return trustedTypesPolicy.createHTML(html);
+ } finally {
+ IN_TRUSTED_TYPES_POLICY--;
+ }
+ };
+ const _createTrustedScriptURL = function _createTrustedScriptURL(scriptUrl) {
+ _assertNotInTrustedTypesPolicy();
+ IN_TRUSTED_TYPES_POLICY++;
+ try {
+ return trustedTypesPolicy.createScriptURL(scriptUrl);
+ } finally {
+ IN_TRUSTED_TYPES_POLICY--;
+ }
+ };
+ // Lazily resolve (and cache) the instance's internal default policy.
+ // Resolution is attempted at most once: a successful `createPolicy` cannot be
+ // repeated (Trusted Types throws on duplicate names), and a failed or
+ // unsupported attempt must not be retried on every parse.
+ const _getDefaultTrustedTypesPolicy = function _getDefaultTrustedTypesPolicy() {
+ if (!defaultTrustedTypesPolicyResolved) {
+ defaultTrustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
+ defaultTrustedTypesPolicyResolved = true;
+ }
+ return defaultTrustedTypesPolicy;
+ };
+ const _document = document,
+ implementation = _document.implementation,
+ createNodeIterator = _document.createNodeIterator,
+ createDocumentFragment = _document.createDocumentFragment,
+ getElementsByTagName = _document.getElementsByTagName;
+ const importNode = originalDocument.importNode;
+ let hooks = _createHooksMap();
+ /**
+ * Expose whether this browser supports running the full DOMPurify.
+ */
+ DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
+ const MUSTACHE_EXPR$1 = MUSTACHE_EXPR,
+ ERB_EXPR$1 = ERB_EXPR,
+ TMPLIT_EXPR$1 = TMPLIT_EXPR,
+ DATA_ATTR$1 = DATA_ATTR,
+ ARIA_ATTR$1 = ARIA_ATTR,
+ IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA,
+ ATTR_WHITESPACE$1 = ATTR_WHITESPACE,
+ CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT;
+ let IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
+ /**
+ * We consider the elements and attributes below to be safe. Ideally
+ * don't add any new ones but feel free to remove unwanted ones.
+ */
+ /* allowed element names */
+ let ALLOWED_TAGS = null;
+ const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);
+ /* Allowed attribute names */
+ let ALLOWED_ATTR = null;
+ const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
+ /*
+ * Configure how DOMPurify should handle custom elements and their attributes as well as customized built-in elements.
+ * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
+ * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
+ * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
+ */
+ let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, {
+ tagNameCheck: {
+ writable: true,
+ configurable: false,
+ enumerable: true,
+ value: null
+ },
+ attributeNameCheck: {
+ writable: true,
+ configurable: false,
+ enumerable: true,
+ value: null
+ },
+ allowCustomizedBuiltInElements: {
+ writable: true,
+ configurable: false,
+ enumerable: true,
+ value: false
+ }
+ }));
+ /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
+ let FORBID_TAGS = null;
+ /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
+ let FORBID_ATTR = null;
+ /* Config object to store ADD_TAGS/ADD_ATTR functions (when used as functions) */
+ const EXTRA_ELEMENT_HANDLING = Object.seal(create(null, {
+ tagCheck: {
+ writable: true,
+ configurable: false,
+ enumerable: true,
+ value: null
+ },
+ attributeCheck: {
+ writable: true,
+ configurable: false,
+ enumerable: true,
+ value: null
+ }
+ }));
+ /* Decide if ARIA attributes are okay */
+ let ALLOW_ARIA_ATTR = true;
+ /* Decide if custom data attributes are okay */
+ let ALLOW_DATA_ATTR = true;
+ /* Decide if unknown protocols are okay */
+ let ALLOW_UNKNOWN_PROTOCOLS = false;
+ /* Decide if self-closing tags in attributes are allowed.
+ * Usually removed due to a mXSS issue in jQuery 3.0 */
+ let ALLOW_SELF_CLOSE_IN_ATTR = true;
+ /* Output should be safe for common template engines.
+ * This means, DOMPurify removes data attributes, mustaches and ERB
+ */
+ let SAFE_FOR_TEMPLATES = false;
+ /* Output should be safe even for XML used within HTML and alike.
+ * This means, DOMPurify removes comments when containing risky content.
+ */
+ let SAFE_FOR_XML = true;
+ /* Decide if document with ... should be returned */
+ let WHOLE_DOCUMENT = false;
+ /* Track whether config is already set on this instance of DOMPurify. */
+ let SET_CONFIG = false;
+ /* Pristine allowlist bindings captured at setConfig() time. On the
+ * persistent-config path sanitize() restores the sets from these before
+ * the per-walk hook clone-guard, so a hook's in-call widening cannot
+ * carry across calls. Null until setConfig() is called; reset by
+ * clearConfig(). */
+ let SET_CONFIG_ALLOWED_TAGS = null;
+ let SET_CONFIG_ALLOWED_ATTR = null;
+ /* Decide if all elements (e.g. style, script) must be children of
+ * document.body. By default, browsers might move them to document.head */
+ let FORCE_BODY = false;
+ /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
+ * string (or a TrustedHTML object if Trusted Types are supported).
+ * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
+ */
+ let RETURN_DOM = false;
+ /* Decide if a DOM `DocumentFragment` should be returned, instead of a html
+ * string (or a TrustedHTML object if Trusted Types are supported) */
+ let RETURN_DOM_FRAGMENT = false;
+ /* Try to return a Trusted Type object instead of a string, return a string in
+ * case Trusted Types are not supported */
+ let RETURN_TRUSTED_TYPE = false;
+ /* Output should be free from DOM clobbering attacks?
+ * This sanitizes markups named with colliding, clobberable built-in DOM APIs.
+ */
+ let SANITIZE_DOM = true;
+ /* Achieve full DOM Clobbering protection by isolating the namespace of named
+ * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
+ *
+ * HTML/DOM spec rules that enable DOM Clobbering:
+ * - Named Access on Window (§7.3.3)
+ * - DOM Tree Accessors (§3.1.5)
+ * - Form Element Parent-Child Relations (§4.10.3)
+ * - Iframe srcdoc / Nested WindowProxies (§4.8.5)
+ * - HTMLCollection (§4.2.10.2)
+ *
+ * Namespace isolation is implemented by prefixing `id` and `name` attributes
+ * with a constant string, i.e., `user-content-`
+ */
+ let SANITIZE_NAMED_PROPS = false;
+ const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
+ /* Keep element content when removing element? */
+ let KEEP_CONTENT = true;
+ /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
+ * of importing it into a new Document and returning a sanitized copy */
+ let IN_PLACE = false;
+ /* Allow usage of profiles like html, svg and mathMl */
+ let USE_PROFILES = {};
+ /* Tags to ignore content of when KEEP_CONTENT is true */
+ let FORBID_CONTENTS = null;
+ const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script',
+ // mirrors the selected