window.relearn = window.relearn || {}; var theme = true; var isPrint = document.querySelector('body').classList.contains('print'); var isPrintPreview = false; var isRtl = document.querySelector('html').getAttribute('dir') == 'rtl'; var lang = document.querySelector('html').getAttribute('lang'); var dir_padding_start = 'padding-left'; var dir_padding_end = 'padding-right'; var dir_key_start = 37; var dir_key_end = 39; var dir_scroll = 1; if (isRtl) { dir_padding_start = 'padding-right'; dir_padding_end = 'padding-left'; dir_key_start = 39; dir_key_end = 37; dir_scroll = -1; } var touchsupport = 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0; var formelements = 'button, datalist, fieldset, input, label, legend, meter, optgroup, option, output, progress, select, textarea'; // PerfectScrollbar var psc; var psm; var pst = new Map(); var elc = document.querySelector('#R-body-inner'); function regexEscape(s) { return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); } function documentFocus() { elc.focus(); psc && psc.scrollbarY.focus(); } function scrollbarWidth() { // https://davidwalsh.name/detect-scrollbar-width // Create the measurement node var scrollDiv = document.createElement('div'); scrollDiv.className = 'scrollbar-measure'; document.body.appendChild(scrollDiv); // Get the scrollbar width var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth; // Delete the DIV document.body.removeChild(scrollDiv); return scrollbarWidth; } var scrollbarSize = scrollbarWidth(); function adjustContentWidth() { var start = parseFloat(getComputedStyle(elc).getPropertyValue(dir_padding_start)); var end = start; if (elc.scrollHeight > elc.clientHeight) { // if we have a scrollbar reduce the end margin by the scrollbar width end = Math.max(0, start - scrollbarSize); } elc.style[dir_padding_end] = '' + end + 'px'; } function throttle(func, limit) { let inThrottle; return function (...args) { if (!inThrottle) { func.apply(this, args); inThrottle = true; setTimeout(() => (inThrottle = false), limit); } }; } function fixCodeTabs() { /* if only a single code block is contained in the tab and no style was selected, treat it like style=code */ var codeTabContents = Array.from(document.querySelectorAll('.tab-content.tab-panel-style')).filter(function (tabContent) { return tabContent.querySelector('*:scope > .tab-content-text > div.highlight:only-child, *:scope > .tab-content-text > pre:not(.mermaid).pre-code:only-child'); }); codeTabContents.forEach(function (tabContent) { var tabId = tabContent.dataset.tabItem; var tabPanel = tabContent.parentNode.parentNode; var tabButton = tabPanel.querySelector('.tab-nav-button.tab-panel-style[data-tab-item="' + tabId + '"]'); if (tabContent.classList.contains('initial')) { tabButton.classList.remove('initial'); tabButton.classList.add('code'); tabContent.classList.remove('initial'); tabContent.classList.add('code'); } // mark code blocks for FF without :has() tabContent.classList.add('codify'); }); } function switchTab(tabGroup, tabId) { var tabs = Array.from(document.querySelectorAll('.tab-panel[data-tab-group="' + tabGroup + '"]')).filter(function (e) { return !!e.querySelector('[data-tab-item="' + tabId + '"]'); }); var allTabItems = tabs && tabs.reduce(function (a, e) { return a.concat( Array.from(e.querySelectorAll('[data-tab-item]')).filter(function (es) { return es.parentNode.parentNode == e; }) ); }, []); var targetTabItems = tabs && tabs.reduce(function (a, e) { return a.concat( Array.from(e.querySelectorAll('[data-tab-item="' + tabId + '"]')).filter(function (es) { return es.parentNode.parentNode == e; }) ); }, []); // if event is undefined then switchTab was called from restoreTabSelection // so it's not a button event and we don't need to safe the selction or // prevent page jump var isButtonEvent = event && event.target && event.target.getBoundingClientRect; if (isButtonEvent) { // save button position relative to viewport var yposButton = event.target.getBoundingClientRect().top; } allTabItems && allTabItems.forEach(function (e) { e.classList.remove('active'); e.removeAttribute('tabindex'); }); targetTabItems && targetTabItems.forEach(function (e) { e.classList.add('active'); e.setAttribute('tabindex', '-1'); }); if (isButtonEvent) { initMermaid(true); // reset screen to the same position relative to clicked button to prevent page jump var yposButtonDiff = event.target.getBoundingClientRect().top - yposButton; window.scrollTo(window.scrollX, window.scrollY + yposButtonDiff); // Store the selection to make it persistent if (window.localStorage) { var selectionsJSON = window.localStorage.getItem(window.relearn.absBaseUri + '/tab-selections'); if (selectionsJSON) { var tabSelections = JSON.parse(selectionsJSON); } else { var tabSelections = {}; } tabSelections[tabGroup] = tabId; window.localStorage.setItem(window.relearn.absBaseUri + '/tab-selections', JSON.stringify(tabSelections)); } } } function restoreTabSelections() { if (window.localStorage) { var selectionsJSON = window.localStorage.getItem(window.relearn.absBaseUri + '/tab-selections'); if (selectionsJSON) { var tabSelections = JSON.parse(selectionsJSON); } else { var tabSelections = {}; } Object.keys(tabSelections).forEach(function (tabGroup) { var tabItem = tabSelections[tabGroup]; switchTab(tabGroup, tabItem); }); } } function initMermaid(update, attrs) { var doBeside = true; var isImageRtl = false; // we are either in update or initialization mode; // during initialization, we want to edit the DOM; // during update we only want to execute if something changed var decodeHTML = function (html) { var txt = document.createElement('textarea'); txt.innerHTML = html; return txt.value; }; var encodeHTML = function (text) { var html = document.createElement('textarea'); html.textContent = text; return html.innerHTML; }; var parseGraph = function (graph) { // See https://github.com/mermaid-js/mermaid/blob/9a080bb975b03b2b1d4ef6b7927d09e6b6b62760/packages/mermaid/src/diagram-api/frontmatter.ts#L10 // for reference on the regex originally taken from jekyll var YAML = 1; var INIT = 2; var GRAPH = 3; var d = /^(?:\s*[\n\r])*(?:-{3}(\s*[\n\r](?:.*?)[\n\r])-{3}(?:\s*[\n\r]+)+)?(?:\s*(?:%%\s*\{\s*\w+\s*:([^%]*?)%%\s*[\n\r]?))?(.*)$/s; var m = d.exec(graph); var yaml = {}; var dir = {}; var content = graph; if (m && m.length == 4) { yaml = m[YAML] ? jsyaml.load(m[YAML]) : yaml; dir = m[INIT] ? JSON.parse('{ "init": ' + m[INIT]).init : dir; content = m[GRAPH] ? m[GRAPH] : content; } var ret = { yaml: yaml, dir: dir, content: content.trim() }; return ret; }; var serializeGraph = function (graph) { var yamlPart = ''; if (Object.keys(graph.yaml).length) { yamlPart = '---\n' + jsyaml.dump(graph.yaml) + '---\n'; } var dirPart = ''; if (Object.keys(graph.dir).length) { dirPart = '%%{init: ' + JSON.stringify(graph.dir) + '}%%\n'; } return yamlPart + dirPart + graph.content; }; var init_func = function (attrs) { var is_initialized = false; var theme = attrs.theme; document.querySelectorAll('.mermaid').forEach(function (element) { var parse = parseGraph(decodeHTML(element.innerHTML)); if (parse.yaml.theme) { parse.yaml.relearn_user_theme = true; } if (parse.dir.theme) { parse.dir.relearn_user_theme = true; } if (!parse.yaml.relearn_user_theme && !parse.dir.relearn_user_theme) { parse.yaml.theme = theme; } is_initialized = true; var graph = encodeHTML(serializeGraph(parse)); var new_element = document.createElement('div'); Array.from(element.attributes).forEach(function (attr) { new_element.setAttribute(attr.name, attr.value); element.removeAttribute(attr.name); }); new_element.classList.add('mermaid-container'); new_element.classList.remove('mermaid'); element.classList.add('mermaid'); element.innerHTML = graph; if (element.offsetParent !== null) { element.classList.add('mermaid-render'); } new_element.innerHTML = '
' + graph + '
' + element.outerHTML; element.parentNode.replaceChild(new_element, element); }); return is_initialized; }; var update_func = function (attrs) { var is_initialized = false; var theme = attrs.theme; document.querySelectorAll('.mermaid-container').forEach(function (e) { var element = e.querySelector('.mermaid'); var code = e.querySelector('.mermaid-code'); var parse = parseGraph(decodeHTML(code.innerHTML)); if (element.classList.contains('mermaid-render')) { if (parse.yaml.relearn_user_theme || parse.dir.relearn_user_theme) { return; } if (parse.yaml.theme == theme || parse.dir.theme == theme) { return; } } if (element.offsetParent !== null) { element.classList.add('mermaid-render'); } else { element.classList.remove('mermaid-render'); return; } is_initialized = true; parse.yaml.theme = theme; var graph = encodeHTML(serializeGraph(parse)); element.removeAttribute('data-processed'); element.innerHTML = graph; code.innerHTML = graph; }); return is_initialized; }; var state = this; if (update && !state.is_initialized) { return; } if (typeof mermaid == 'undefined' || typeof mermaid.mermaidAPI == 'undefined') { return; } if (!state.is_initialized) { state.is_initialized = true; window.addEventListener( 'beforeprint', function () { isPrintPreview = true; initMermaid(true, { theme: getColorValue('PRINT-MERMAID-theme'), }); }.bind(this) ); window.addEventListener( 'afterprint', function () { isPrintPreview = false; initMermaid(true); }.bind(this) ); } attrs = attrs || { theme: getColorValue('MERMAID-theme'), }; var search; if (update) { search = sessionStorage.getItem(window.relearn.absBaseUri + '/search-value'); unmark(); } var is_initialized = update ? update_func(attrs) : init_func(attrs); if (is_initialized) { mermaid.initialize(Object.assign({ securityLevel: 'antiscript', startOnLoad: false }, window.relearn.mermaidConfig, { theme: attrs.theme })); mermaid.run({ postRenderCallback: function (id) { // zoom for Mermaid // https://github.com/mermaid-js/mermaid/issues/1860#issuecomment-1345440607 var svgs = d3.selectAll('body:not(.print) .mermaid-container.zoomable > .mermaid > #' + id); svgs.each(function () { var parent = this.parentElement; // we need to copy the maxWidth, otherwise our reset button will not align in the upper right parent.style.maxWidth = this.style.maxWidth || this.getAttribute('width'); // if no unit is given for the width parent.style.maxWidth = parent.style.maxWidth || 'calc( ' + this.getAttribute('width') + 'px + 1rem )'; var svg = d3.select(this); svg.html('' + svg.html() + ''); var inner = svg.select('*:scope > g'); parent.insertAdjacentHTML('beforeend', ''); var button = parent.querySelector('.svg-reset-button'); var zoom = d3.zoom().on('zoom', function (e) { inner.attr('transform', e.transform); if (e.transform.k == 1 && e.transform.x == 0 && e.transform.y == 0) { button.classList.remove('zoomed'); } else { button.classList.add('zoomed'); } }); button.addEventListener('click', function (event) { svg.transition().duration(350).call(zoom.transform, d3.zoomIdentity); this.setAttribute('aria-label', window.T_View_reset); this.classList.add('tooltipped', 'tooltipped-' + (doBeside ? 'w' : 's' + (isImageRtl ? 'e' : 'w'))); }); button.addEventListener('mouseleave', function () { if (this.classList.contains('tooltipped')) { this.classList.remove('tooltipped', 'tooltipped-w', 'tooltipped-se', 'tooltipped-sw'); this.removeAttribute('aria-label'); } }); svg.call(zoom); }); }, querySelector: '.mermaid.mermaid-render', suppressErrors: true, }); } if (update && search && search.length) { sessionStorage.setItem(window.relearn.absBaseUri + '/search-value', search); mark(); } } function initOpenapi(update, attrs) { var state = this; if (update && !state.is_initialized) { return; } if (!state.is_initialized) { state.is_initialized = true; window.addEventListener( 'beforeprint', function () { isPrintPreview = true; initOpenapi(true); }.bind(this) ); window.addEventListener( 'afterprint', function () { isPrintPreview = false; initOpenapi(true); }.bind(this) ); } attrs = attrs || {}; function addFunctionToResizeEvent() {} function getFirstAncestorByClass() {} function renderOpenAPI(oc) { var relBasePath = window.relearn.relBasePath; var assetBuster = window.themeUseOpenapi.assetsBuster; var print = isPrint || isPrintPreview ? 'PRINT-' : ''; var format = print ? `print` : `html`; var min = window.relearn.min; var theme = `${relBasePath}/css/format-${format}${min}.css${assetBuster}`; var variant = document.documentElement.dataset.rThemeVariant; var swagger_theme = getColorValue(print + 'OPENAPI-theme'); var swagger_code_theme = getColorValue(print + 'OPENAPI-CODE-theme'); const openapiId = 'relearn-swagger-ui'; const openapiIframeId = openapiId + '-iframe'; const openapiIframe = document.getElementById(openapiIframeId); if (openapiIframe) { openapiIframe.remove(); } const openapiErrorId = openapiId + '-error'; const openapiError = document.getElementById(openapiErrorId); if (openapiError) { openapiError.remove(); } const oi = document.createElement('iframe'); oi.id = openapiIframeId; oi.classList.toggle('sc-openapi-iframe', true); oi.srcdoc = '' + '' + '' + '' + '' + '' + '' + '' + '' + 'Collapse all' + 'Expand all' + '
' + '' + '' + ''; oi.height = '100%'; oi.width = '100%'; oi.onload = function () { const openapiWrapper = getFirstAncestorByClass(oc, 'sc-openapi-wrapper'); const openapiPromise = new Promise(function (resolve) { resolve(); }); openapiPromise .then(function () { var options = { defaultModelsExpandDepth: 2, defaultModelExpandDepth: 2, docExpansion: isPrint || isPrintPreview ? 'full' : 'list', domNode: oi.contentWindow.document.getElementById(openapiId), filter: !(isPrint || isPrintPreview), layout: 'BaseLayout', onComplete: function () { if (isPrint || isPrintPreview) { oi.contentWindow.document.querySelectorAll('.model-container > .model-box > button[aria-expanded=false]').forEach(function (btn) { btn.click(); }); setOpenAPIHeight(oi); } }, plugins: [SwaggerUIBundle.plugins.DownloadUrl], presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset], syntaxHighlight: { activated: true, theme: swagger_code_theme, }, validatorUrl: 'none', }; if (oc.dataset.openapiSpec) { try { Object.assign(options, { spec: JSON.parse(oc.dataset.openapiSpec) }); } catch (err) { try { Object.assign(options, { spec: jsyaml.load(oc.dataset.openapiSpec) }); } catch (err) { console.error('OpenAPI: file "' + oc.dataset.openapiUrl + '" could not be parsed as JSON or YAML'); } } } else { Object.assign(options, { url: oc.dataset.openapiUrl }); } SwaggerUIBundle(options); }) .then(function () { let observerCallback = function () { setOpenAPIHeight(oi); }; let observer = new MutationObserver(observerCallback); observer.observe(oi.contentWindow.document.documentElement, { childList: true, subtree: true, }); }) .then(function () { if (openapiWrapper) { openapiWrapper.classList.toggle('is-loading', false); } setOpenAPIHeight(oi); }) .catch(function (error) { const ed = document.createElement('div'); ed.classList.add('sc-alert', 'sc-alert-error'); ed.innerHTML = error; ed.id = openapiErrorId; while (oc.lastChild) { oc.removeChild(oc.lastChild); } if (openapiWrapper) { openapiWrapper.classList.toggle('is-loading', false); openapiWrapper.insertAdjacentElement('afterbegin', ed); } }); }; oc.appendChild(oi); } function setOpenAPIHeight(oi) { // add empirical offset if in print preview (GC 103) oi.style.height = oi.contentWindow.document.documentElement.getBoundingClientRect().height + (isPrintPreview ? 200 : 0) + 'px'; } function resizeOpenAPI() { let divi = document.getElementsByClassName('sc-openapi-iframe'); for (let i = 0; i < divi.length; i++) { setOpenAPIHeight(divi[i]); } } let divo = document.getElementsByClassName('sc-openapi-container'); for (let i = 0; i < divo.length; i++) { renderOpenAPI(divo[i]); } if (divo.length) { addFunctionToResizeEvent(resizeOpenAPI); } } function initAnchorClipboard() { if (window.relearn.disableAnchorCopy && window.relearn.disableAnchorScrolling) { return; } document.querySelectorAll(':has(h1) :is(h2[id], h3[id], h4[id] , h5[id], h6[id])').forEach(function (element) { var url = encodeURI((document.location.origin == 'null' ? document.location.protocol + '//' + document.location.host : document.location.origin) + document.location.pathname); var link = url + '#' + element.id; var new_element = document.createElement('button'); new_element.classList.add('anchor'); if (!window.relearn.disableAnchorCopy) { new_element.setAttribute('title', window.T_Copy_link_to_clipboard); } new_element.setAttribute('data-clipboard-text', link); new_element.innerHTML = ''; element.appendChild(new_element); }); var anchors = document.querySelectorAll('.anchor'); if (!window.relearn.disableAnchorCopy) { for (var i = 0; i < anchors.length; i++) { anchors[i].addEventListener('mouseleave', function (e) { this.removeAttribute('aria-label'); this.classList.remove('tooltipped', 'tooltipped-se', 'tooltipped-sw'); }); } var clip = new ClipboardJS('.anchor'); clip.on('success', function (e) { e.clearSelection(); e.trigger.setAttribute('aria-label', window.T_Link_copied_to_clipboard); e.trigger.classList.add('tooltipped', 'tooltipped-s' + (isRtl ? 'e' : 'w')); if (!window.relearn.disableAnchorScrolling) { e.trigger.parentElement.scrollIntoView({ behavior: 'smooth' }); var state = window.history.state || {}; state = Object.assign({}, typeof state === 'object' ? state : {}); history.replaceState({}, '', e.text); } }); } else if (!window.relearn.disableAnchorScrolling) { for (var i = 0; i < anchors.length; i++) { anchors[i].addEventListener('click', function (e) { e.target.parentElement.parentElement.scrollIntoView({ behavior: 'smooth' }); var state = window.history.state || {}; state = Object.assign({}, typeof state === 'object' ? state : {}); history.replaceState({}, '', e.text); }); } } } function initCodeClipboard() { function getCodeText(node) { // if highlight shortcode is used in inline lineno mode, remove lineno nodes before generating text, otherwise it doesn't hurt var code = node.cloneNode(true); Array.from(code.querySelectorAll('*:scope > span > span:first-child:not(:last-child)')).forEach(function (lineno) { lineno.remove(); }); var text = code.textContent; // remove a trailing line break, this may most likely // come from the browser / Hugo transformation text = text.replace(/\n$/, ''); return text; } function fallbackMessage(action) { var actionMsg = ''; var actionKey = action === 'cut' ? 'X' : 'C'; if (/iPhone|iPad/i.test(navigator.userAgent)) { actionMsg = 'No support :('; } else if (/Mac/i.test(navigator.userAgent)) { actionMsg = 'Press ⌘-' + actionKey + ' to ' + action; } else { actionMsg = 'Press Ctrl-' + actionKey + ' to ' + action; } return actionMsg; } document.addEventListener('copy', function (ev) { // shabby FF generates empty lines on cursor selection that we need to filter out; see #925 var selection = document.getSelection(); var node = selection.anchorNode; // in case of GC, it works without this handler; // instead GC fails if this handler is active, because it still contains // the line number nodes with class 'ln' in the selection, although // they are flagged with 'user-select: none;' see https://issues.chromium.org/issues/41393366; // so in case of GC we don't want to do anything and bail out early in below code function selectionContainsLnClass(selection) { for (var i = 0; i < selection.rangeCount; i++) { var range = selection.getRangeAt(i); var fragment = range.cloneContents(); if (fragment.querySelector('.ln') || fragment.querySelector('[id]')) { return true; } } return false; } if (!selectionContainsLnClass(selection)) { while (node) { // selection could start in a text node, so account for this as it // obviously does not support `classList` if (node.nodeType === Node.ELEMENT_NODE && node.classList.contains('highlight')) { // only do this if we are inside of a code highlight node; // now fix FFs selection by calculating the text ourself var text = selection.toString(); ev.clipboardData.setData('text/plain', text); ev.preventDefault(); break; } node = node.parentNode; } } }); var codeElements = document.querySelectorAll('code'); for (var i = 0; i < codeElements.length; i++) { var code = codeElements[i]; var text = getCodeText(code); var inPre = code.parentNode.tagName.toLowerCase() == 'pre'; var inTable = inPre && code.parentNode.parentNode.tagName.toLowerCase() == 'td' && code.parentNode.parentNode.classList.contains('lntd'); // avoid copy-to-clipboard for highlight shortcode in table lineno mode var isFirstLineCell = inTable && code.parentNode.parentNode.parentNode.querySelector('td:first-child > pre > code') == code; var isBlock = inTable || inPre; if (!isFirstLineCell && (inPre || text.length > 5)) { code.classList.add('copy-to-clipboard-code'); if (inPre) { code.classList.add('copy-to-clipboard'); code.parentNode.classList.add('pre-code'); } else { var clone = code.cloneNode(true); var span = document.createElement('span'); span.classList.add('copy-to-clipboard'); span.appendChild(clone); code.parentNode.replaceChild(span, code); code = clone; } var button = null; if (isBlock || !window.relearn.disableInlineCopyToClipboard) { button = document.createElement('button'); var buttonPrefix = isBlock ? 'block' : 'inline'; button.classList.add(buttonPrefix + '-copy-to-clipboard-button'); button.setAttribute('title', window.T_Copy_to_clipboard); button.innerHTML = ''; button.addEventListener('mouseleave', function () { this.removeAttribute('aria-label'); this.classList.remove('tooltipped', 'tooltipped-w', 'tooltipped-se', 'tooltipped-sw'); }); if (isBlock) { // we have to make sure, the button is visible while // Clipboard.js is doing its magic button.addEventListener('focus', function (ev) { setTimeout(function () { ev.target.classList.add('force-display'); }, 0); }); button.addEventListener('blur', function (ev) { this.removeAttribute('aria-label'); this.classList.remove('tooltipped', 'tooltipped-w', 'tooltipped-se', 'tooltipped-sw'); setTimeout(function () { ev.target.classList.remove('force-display'); }, 0); }); } } if (inTable) { var table = code.parentNode.parentNode.parentNode.parentNode.parentNode; table.dataset.code = text; table.parentNode.insertBefore(button, table.nextSibling); } else if (inPre) { var pre = code.parentNode; pre.dataset.code = text; var p = pre.parentNode; // html
 constructs and indented code blocks are missing the div
        while (p != document && (p.tagName.toLowerCase() != 'div' || !p.classList.contains('highlight'))) {
          p = p.parentNode;
        }
        if (p == document) {
          var clone = pre.cloneNode(true);
          var div = document.createElement('div');
          div.classList.add('highlight');
          if (window.relearn.enableBlockCodeWrap) {
            div.classList.add('wrap-code');
          }
          div.appendChild(clone);
          pre.parentNode.replaceChild(div, pre);
          pre = clone;
        }
        pre.parentNode.insertBefore(button, pre.nextSibling);
      } else {
        code.classList.add('highlight');
        code.dataset.code = text;
        if (button) {
          // #1022 fix for FF; see CSS for explanation
          if (isRtl) {
            code.parentNode.insertBefore(button, code.parentNode.firstChild);
          } else {
            code.parentNode.insertBefore(button, code.nextSibling);
          }
        }
      }
    }
  }

  var clip = new ClipboardJS('.block-copy-to-clipboard-button, .inline-copy-to-clipboard-button', {
    text: function (trigger) {
      if (!trigger.previousElementSibling) {
        return '';
      }
      return trigger.previousElementSibling.dataset.code || '';
    },
  });

  clip.on('success', function (e) {
    e.clearSelection();
    var inPre = e.trigger.previousElementSibling && e.trigger.previousElementSibling.tagName.toLowerCase() == 'pre';
    var isCodeRtl = !inPre ? isRtl : false;
    var doBeside = inPre || (e.trigger.previousElementSibling && e.trigger.previousElementSibling.tagName.toLowerCase() == 'table');
    e.trigger.setAttribute('aria-label', window.T_Copied_to_clipboard);
    e.trigger.classList.add('tooltipped', 'tooltipped-' + (doBeside ? 'w' : 's' + (isCodeRtl ? 'e' : 'w')));
  });

  clip.on('error', function (e) {
    var inPre = e.trigger.previousElementSibling && e.trigger.previousElementSibling.tagName.toLowerCase() == 'pre';
    var isCodeRtl = !inPre ? isRtl : false;
    var doBeside = inPre || (e.trigger.previousElementSibling && e.trigger.previousElementSibling.tagName.toLowerCase() == 'table');
    e.trigger.setAttribute('aria-label', fallbackMessage(e.action));
    e.trigger.classList.add('tooltipped', 'tooltipped-' + (doBeside ? 'w' : 's' + (isCodeRtl ? 'e' : 'w')));
    var f = function () {
      e.trigger.setAttribute('aria-label', window.T_Copied_to_clipboard);
      e.trigger.classList.add('tooltipped', 'tooltipped-' + (doBeside ? 'w' : 's' + (isCodeRtl ? 'e' : 'w')));
      document.removeEventListener('copy', f);
    };
    document.addEventListener('copy', f);
  });
}

function initArrowVerticalNav() {
  var topMain = 0;
  if (!isPrint) {
    topMain = document.querySelector('main').getClientRects()[0].top;
  }

  document.addEventListener('keydown', function (event) {
    var elems = Array.from(
      document.querySelectorAll(`main :not(.include.hide-first-heading) > :where(
                .article-subheading,
                :not(.article-subheading) + h1:not(.a11y-only),
                h1:not(.a11y-only):first-child,
                h2, h3, h4, h5, h6
            ),
            main .include.hide-first-heading > :where( h1, h2, h3, h4, h5, h6 ) ~ :where( h1, h2, h3, h4, h5, h6 )
        `)
    );
    if (!event.shiftKey && !event.ctrlKey && event.altKey && !event.metaKey) {
      if (event.which == 38) {
        // up
        var target = isPrint ? document.querySelector('#R-body') : document.querySelector('.flex-block-wrapper');
        elems.some(function (elem, i) {
          var top = elem.getBoundingClientRect().top;
          var topBoundary = top - topMain;
          if (topBoundary > -1) {
            target.scrollIntoView();
            return true;
          }
          target = elem;
        });
      } else if (event.which == 40) {
        // down
        elems.some(function (elem, i) {
          var top = elem.getBoundingClientRect().top;
          var topBoundary = top - topMain;
          if (topBoundary > -1 && topBoundary < 1) {
            if (i + 1 < elems.length) {
              var target = elems[i + 1];
              target.scrollIntoView();
            }
            return true;
          }
          if (topBoundary >= 1) {
            var target = elem;
            target.scrollIntoView();
            return true;
          }
        });
      }
    }
  });
}

function initArrowHorizontalNav() {
  if (isPrint) {
    return;
  }

  // button navigation
  var prev = document.querySelector('.topbar-button-prev a');
  prev && prev.addEventListener('click', navPrev);
  var next = document.querySelector('.topbar-button-next a');
  next && next.addEventListener('click', navNext);

  // keyboard navigation
  // avoid prev/next navigation if we are not at the start/end of the
  // horizontal area
  var el = document.querySelector('#R-body-inner');
  var scrollStart = 0;
  var scrollEnd = 0;
  document.addEventListener('keydown', function (event) {
    if (!event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey) {
      var f = event.target.matches(formelements);
      if (f) {
        return;
      }
      if (event.which == dir_key_start) {
        if (!scrollStart && +el.scrollLeft.toFixed() * dir_scroll <= 0) {
          prev && prev.click();
        } else if (scrollStart != -1) {
          clearTimeout(scrollStart);
        }
        scrollStart = -1;
      }
      if (event.which == dir_key_end) {
        if (!scrollEnd && +el.scrollLeft.toFixed() * dir_scroll + +el.clientWidth.toFixed() >= +el.scrollWidth.toFixed()) {
          next && next.click();
        } else if (scrollEnd != -1) {
          clearTimeout(scrollEnd);
        }
        scrollEnd = -1;
      }
    }
  });
  document.addEventListener('keyup', function (event) {
    if (!event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey) {
      var f = event.target.matches(formelements);
      if (f) {
        return;
      }
      if (event.which == dir_key_start) {
        // check for false indication if keyup is delayed after navigation
        if (scrollStart == -1) {
          scrollStart = setTimeout(function () {
            scrollStart = 0;
          }, 300);
        }
      }
      if (event.which == dir_key_end) {
        if (scrollEnd == -1) {
          scrollEnd = setTimeout(function () {
            scrollEnd = 0;
          }, 300);
        }
      }
    }
  });
}

function initMenuScrollbar() {
  if (isPrint) {
    return;
  }

  var elm = document.querySelector('#R-content-wrapper');
  var elt = document.querySelector('.topbar-button.topbar-flyout .topbar-content-wrapper');

  var autofocus = true;
  document.addEventListener('keydown', function (event) {
    // for initial keyboard scrolling support, no element
    // may be hovered, but we still want to react on
    // cursor/page up/down. because we can't hack
    // the scrollbars implementation, we try to trick
    // it and give focus to the scrollbar - only
    // to just remove the focus right after scrolling
    // happend
    autofocus = false;
    if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey || event.which < 32 || event.which > 40) {
      // if tab key was pressed, we are ended with our initial
      // focus job
      return;
    }

    var c = elc && elc.matches(':hover');
    var m = elm && elm.matches(':hover');
    var t = elt && elt.matches(':hover');
    var f = event.target.matches(formelements);
    if (!c && !m && !t && !f) {
      // only do this hack if none of our scrollbars
      // is hovered
      // if we are showing the sidebar as a flyout we
      // want to scroll the content-wrapper, otherwise we want
      // to scroll the body
      var nt = document.querySelector('body').matches('.topbar-flyout');
      var nm = document.querySelector('body').matches('.sidebar-flyout');
      if (nt) {
        var psb = pst.get(document.querySelector('.topbar-button.topbar-flyout'));
        psb && psb.scrollbarY.focus();
      } else if (nm) {
        psm && psm.scrollbarY.focus();
      } else {
        document.querySelector('#R-body-inner').focus();
        psc && psc.scrollbarY.focus();
      }
    }
  });
  // scrollbars will install their own keyboard handlers
  // that need to be executed inbetween our own handlers
  // PSC removed for #242 #243 #244
  // psc = elc && new PerfectScrollbar('#R-body-inner');
  psm = elm && new PerfectScrollbar('#R-content-wrapper', { scrollingThreshold: 2000, swipeEasing: false, wheelPropagation: false });
  document.querySelectorAll('.topbar-button .topbar-content-wrapper').forEach(function (e) {
    var button = getTopbarButtonParent(e);
    if (!button) {
      return;
    }
    pst.set(button, new PerfectScrollbar(e, { scrollingThreshold: 2000, swipeEasing: false, wheelPropagation: false }));
    e.addEventListener('click', toggleTopbarFlyoutEvent);
  });

  document.addEventListener('keydown', function () {
    // if we facked initial scrolling, we want to
    // remove the focus to not leave visual markers on
    // the scrollbar
    if (autofocus) {
      psc && psc.scrollbarY.blur();
      psm && psm.scrollbarY.blur();
      pst.forEach(function (psb) {
        psb.scrollbarY.blur();
      });
      autofocus = false;
    }
  });
  // on resize, we have to redraw the scrollbars to let new height
  // affect their size
  window.addEventListener('resize', function () {
    pst.forEach(function (psb) {
      setTimeout(function () {
        psb.update();
      }, 10);
    });
    psm &&
      setTimeout(function () {
        psm.update();
      }, 10);
    psc &&
      setTimeout(function () {
        psc.update();
      }, 10);
  });
  // now that we may have collapsible menus, we need to call a resize
  // for the menu scrollbar if sections are expanded/collapsed
  document.querySelectorAll('#R-sidebar .collapsible-menu input').forEach(function (e) {
    e.addEventListener('change', function () {
      psm &&
        setTimeout(function () {
          psm.update();
        }, 10);
    });
  });
  // bugfix for PS in RTL mode: the initial scrollbar position is off;
  // calling update() once, fixes this
  pst.forEach(function (psb) {
    setTimeout(function () {
      psb.update();
    }, 10);
  });
  psm &&
    setTimeout(function () {
      psm.update();
    }, 10);
  psc &&
    setTimeout(function () {
      psc.update();
    }, 10);

  // finally, we want to adjust the contents end padding if there is a scrollbar visible
  window.addEventListener('resize', adjustContentWidth);
  adjustContentWidth();
}

function imageEscapeHandler(event) {
  if (event.key == 'Escape') {
    var image = event.target;
    image.click();
  }
}

function navShortcutHandler(event) {
  if (!event.shiftKey && event.altKey && event.ctrlKey && !event.metaKey && event.which == 78 /* n */) {
    toggleNav();
  }
}

function searchShortcutHandler(event) {
  if (!event.shiftKey && event.altKey && event.ctrlKey && !event.metaKey && event.which == 70 /* f */) {
    showSearch();
  }
}

function tocShortcutHandler(event) {
  if (!event.shiftKey && event.altKey && event.ctrlKey && !event.metaKey && event.which == 84 /* t */) {
    toggleToc();
  }
}

function editShortcutHandler(event) {
  if (!event.shiftKey && event.altKey && event.ctrlKey && !event.metaKey && event.which == 87 /* w */) {
    showEdit();
  }
}

function printShortcutHandler(event) {
  if (!event.shiftKey && event.altKey && event.ctrlKey && !event.metaKey && event.which == 80 /* p */) {
    showPrint();
  }
}

function showSearch() {
  var s = document.querySelector('#R-search-by');
  if (!s) {
    return;
  }
  var b = document.querySelector('body');
  if (s == document.activeElement) {
    if (b.classList.contains('sidebar-flyout')) {
      closeNav();
    }
    documentFocus();
  } else {
    if (!b.classList.contains('sidebar-flyout')) {
      openNav();
    }
    s.focus();
  }
}

function openNav() {
  closeSomeTopbarButtonFlyout();
  var b = document.querySelector('body');
  b.classList.add('sidebar-flyout');
  psm &&
    setTimeout(function () {
      psm.update();
    }, 10);
  psm && psm.scrollbarY.focus();
  var a = document.querySelector('#R-sidebar a');
  if (a) {
    a.focus();
  }
}

function closeNav() {
  var b = document.querySelector('body');
  b.classList.remove('sidebar-flyout');
  documentFocus();
}

function toggleNav() {
  var b = document.querySelector('body');
  if (b.classList.contains('sidebar-flyout')) {
    closeNav();
  } else {
    openNav();
  }
}

function navEscapeHandler(event) {
  if (event.key == 'Escape') {
    closeNav();
  }
}

function getTopbarButtonParent(e) {
  var button = e;
  while (button && !button.classList.contains('topbar-button')) {
    button = button.parentElement;
  }
  return button;
}

function openTopbarButtonFlyout(button) {
  closeNav();
  var body = document.querySelector('body');
  button.classList.add('topbar-flyout');
  body.classList.add('topbar-flyout');
  var psb = pst.get(button);
  psb &&
    setTimeout(function () {
      psb.update();
    }, 10);
  psb && psb.scrollbarY.focus();
  var a = button.querySelector('.topbar-content-wrapper a');
  if (a) {
    a.focus();
  }
}

function closeTopbarButtonFlyout(button) {
  var body = document.querySelector('body');
  button.classList.remove('topbar-flyout');
  body.classList.remove('topbar-flyout');
  documentFocus();
}

function closeSomeTopbarButtonFlyout() {
  var someButton = document.querySelector('.topbar-button.topbar-flyout');
  if (someButton) {
    closeTopbarButtonFlyout(someButton);
  }
  return someButton;
}

function toggleTopbarButtonFlyout(button) {
  var someButton = closeSomeTopbarButtonFlyout();
  if (button && button != someButton) {
    openTopbarButtonFlyout(button);
  }
}

function toggleTopbarFlyout(e) {
  var button = getTopbarButtonParent(e);
  if (!button) {
    return;
  }
  toggleTopbarButtonFlyout(button);
}

function toggleTopbarFlyoutEvent(event) {
  if (event.target.classList.contains('topbar-content') || event.target.classList.contains('topbar-content-wrapper') || event.target.classList.contains('ps__rail-x') || event.target.classList.contains('ps__rail-y') || event.target.classList.contains('ps__thumb-x') || event.target.classList.contains('ps__thumb-y')) {
    // the scrollbar was used, don't close flyout
    return;
  }
  toggleTopbarFlyout(event.target);
}

function topbarFlyoutEscapeHandler(event) {
  if (event.key == 'Escape') {
    closeSomeTopbarButtonFlyout();
  }
}

function toggleToc() {
  toggleTopbarButtonFlyout(document.querySelector('.topbar-button-toc'));
}

function showEdit() {
  var l = document.querySelector('.topbar-button-edit a');
  if (l) {
    l.click();
  }
}

function showPrint() {
  var l = document.querySelector('.topbar-button-print a');
  if (l) {
    l.click();
  }
}

function navPrev() {
  var e = document.querySelector('.topbar-button-prev a');
  location.href = e && e.getAttribute('href');
}

function navNext() {
  var e = document.querySelector('.topbar-button-next a');
  location.href = e && e.getAttribute('href');
}

function initToc() {
  if (isPrint) {
    return;
  }

  document.addEventListener('keydown', editShortcutHandler);
  document.addEventListener('keydown', navShortcutHandler);
  document.addEventListener('keydown', printShortcutHandler);
  document.addEventListener('keydown', searchShortcutHandler);
  document.addEventListener('keydown', tocShortcutHandler);
  document.addEventListener('keydown', navEscapeHandler);
  document.addEventListener('keydown', topbarFlyoutEscapeHandler);

  var b = document.querySelector('#R-body-overlay');
  if (b) {
    b.addEventListener('click', closeNav);
  }
  var m = document.querySelector('#R-main-overlay');
  if (m) {
    m.addEventListener('click', closeSomeTopbarButtonFlyout);
  }

  // finally give initial focus to allow keyboard scrolling in FF
  documentFocus();
}

function initSwipeHandler() {
  if (!touchsupport) {
    return;
  }

  var startx = null;
  var starty = null;
  var handleStartX = function (evt) {
    startx = evt.touches[0].clientX;
    starty = evt.touches[0].clientY;
  };
  var handleMoveX = function (evt) {
    if (startx !== null) {
      var diffx = startx - evt.touches[0].clientX;
      var diffy = starty - evt.touches[0].clientY || 0.1;
      if (diffx / Math.abs(diffy) < 2) {
        // detect mostly vertical swipes and reset our starting pos
        // to not detect a horizontal move if vertical swipe is unprecise
        startx = evt.touches[0].clientX;
      } else if (diffx > 30) {
        startx = null;
        starty = null;
        closeNav();
      }
    }
  };
  var handleEndX = function (evt) {
    startx = null;
    starty = null;
  };

  var s = document.querySelector('#R-body-overlay');
  s && s.addEventListener('touchstart', handleStartX, { capture: false, passive: true });
  document.querySelector('#R-sidebar').addEventListener('touchstart', handleStartX, { capture: false, passive: true });
  document.querySelectorAll('#R-sidebar *').forEach(function (e) {
    e.addEventListener('touchstart', handleStartX, { capture: false, passive: true });
  });
  s && s.addEventListener('touchmove', handleMoveX, { capture: false, passive: true });
  document.querySelector('#R-sidebar').addEventListener('touchmove', handleMoveX, { capture: false, passive: true });
  document.querySelectorAll('#R-sidebar *').forEach(function (e) {
    e.addEventListener('touchmove', handleMoveX, { capture: false, passive: true });
  });
  s && s.addEventListener('touchend', handleEndX, { capture: false, passive: true });
  document.querySelector('#R-sidebar').addEventListener('touchend', handleEndX, { capture: false, passive: true });
  document.querySelectorAll('#R-sidebar *').forEach(function (e) {
    e.addEventListener('touchend', handleEndX, { capture: false, passive: true });
  });
}

function initImage() {
  document.querySelectorAll('.lightbox-back').forEach(function (e) {
    e.addEventListener('keydown', imageEscapeHandler);
  });
}

function initExpand() {
  document.querySelectorAll('.expand > input').forEach(function (e) {
    e.addEventListener('change', initMermaid.bind(null, true, null));
  });
}

function clearHistory() {
  var visitedItem = window.relearn.absBaseUri + '/visited-url/';
  for (var item in sessionStorage) {
    if (item.substring(0, visitedItem.length) === visitedItem) {
      sessionStorage.removeItem(item);
      var url = item.substring(visitedItem.length);
      // in case we have `relativeURLs=true` we have to strip the
      // relative path to root
      url = url.replace(/\.\.\//g, '/').replace(/^\/+\//, '/');
      document.querySelectorAll('[data-nav-id="' + url + '"]').forEach(function (e) {
        e.classList.remove('visited');
      });
    }
  }
}

function initHistory() {
  var visitedItem = window.relearn.absBaseUri + '/visited-url/';
  sessionStorage.setItem(visitedItem + document.querySelector('body').dataset.url, 1);

  // loop through the sessionStorage and see if something should be marked as visited
  for (var item in sessionStorage) {
    if (item.substring(0, visitedItem.length) === visitedItem && sessionStorage.getItem(item) == 1) {
      var url = item.substring(visitedItem.length);
      // in case we have `relativeURLs=true` we have to strip the
      // relative path to root
      url = url.replace(/\.\.\//g, '/').replace(/^\/+\//, '/');
      document.querySelectorAll('[data-nav-id="' + url + '"]').forEach(function (e) {
        e.classList.add('visited');
      });
    }
  }
}

function initScrollPositionSaver() {
  function savePosition(event) {
    // #959 if we fiddle around with the history during print preview
    // GC will close the preview immediatley
    if (isPrintPreview) {
      return;
    }
    var state = window.history.state || {};
    state = Object.assign({}, typeof state === 'object' ? state : {});
    state.contentScrollTop = +elc.scrollTop;
    window.history.replaceState(state, '', window.location);
  }

  var ticking = false;
  elc.addEventListener('scroll', function (event) {
    if (!ticking) {
      window.requestAnimationFrame(function () {
        // #996 GC is so damn slow that we need further throttling
        throttle(savePosition, 250);
        ticking = false;
      });
      ticking = true;
    }
  });

  document.addEventListener('click', savePosition);
}

function scrollToPositions() {
  // show active menu entry
  window.setTimeout(function () {
    var e = document.querySelector('#R-sidebar li.active a');
    if (e && e.scrollIntoView) {
      e.scrollIntoView({
        block: 'center',
      });
    }
  }, 10);

  // scroll the content to point of interest;
  // if we have a scroll position saved, the user was here
  // before in his history stack and we want to reposition
  // to the position he was when he left the page;
  // otherwise if he used page search before, we want to position
  // to its last outcome;
  // otherwise he may want to see a specific fragment

  var state = window.history.state || {};
  state = typeof state === 'object' ? state : {};
  if (state.hasOwnProperty('contentScrollTop')) {
    window.setTimeout(function () {
      elc.scrollTop = +state.contentScrollTop;
    }, 10);
    return;
  }

  var search = sessionStorage.getItem(window.relearn.absBaseUri + '/search-value');
  if (search && search.length) {
    search = regexEscape(search);
    var found = elementContains(search, elc);
    var searchedElem = found.length && found[0];
    if (searchedElem) {
      searchedElem.scrollIntoView();
      var scrolledY = window.scrollY;
      if (scrolledY) {
        window.scroll(0, scrolledY - 125);
      }
    }
    return;
  }

  if (window.location.hash && window.location.hash.length > 1) {
    window.setTimeout(function () {
      try {
        var e = document.querySelector(window.location.hash);
        if (e && e.scrollIntoView) {
          e.scrollIntoView();
        }
      } catch (e) {}
    }, 10);
    return;
  }
}

window.addEventListener('popstate', function (event) {
  scrollToPositions();
});

const observer = new PerformanceObserver(function () {
  scrollToPositions();
});
observer.observe({ type: 'navigation' });

function mark() {
  // mark some additional stuff as searchable
  var bodyInnerLinks = document.querySelectorAll('#R-body-inner a:not(.lightbox-link):not(.btn):not(.lightbox-back)');
  for (var i = 0; i < bodyInnerLinks.length; i++) {
    bodyInnerLinks[i].classList.add('highlight');
  }

  var value = sessionStorage.getItem(window.relearn.absBaseUri + '/search-value');
  var highlightableElements = document.querySelectorAll('.highlightable');
  highlight(highlightableElements, value, { element: 'mark', className: 'search' });

  var markedElements = document.querySelectorAll('mark.search');
  for (var i = 0; i < markedElements.length; i++) {
    var parent = markedElements[i].parentNode;
    while (parent && parent.classList) {
      if (parent.classList.contains('expand')) {
        var expandInputs = parent.querySelectorAll('input:not(.expand-marked)');
        if (expandInputs.length) {
          expandInputs[0].classList.add('expand-marked');
          expandInputs[0].dataset.checked = expandInputs[0].checked ? 'true' : 'false';
          expandInputs[0].checked = true;
        }
      }
      if (parent.tagName.toLowerCase() === 'li' && parent.parentNode && parent.parentNode.tagName.toLowerCase() === 'ul' && parent.parentNode.classList.contains('collapsible-menu')) {
        var toggleInputs = parent.querySelectorAll('input:not(.menu-marked)');
        if (toggleInputs.length) {
          toggleInputs[0].classList.add('menu-marked');
          toggleInputs[0].dataset.checked = toggleInputs[0].checked ? 'true' : 'false';
          toggleInputs[0].checked = true;
        }
      }
      parent = parent.parentNode;
    }
  }
  psm &&
    setTimeout(function () {
      psm.update();
    }, 10);
}
window.relearn.markSearch = mark;

function highlight(es, words, options) {
  var settings = {
    className: 'highlight',
    element: 'span',
    caseSensitive: false,
    wordsOnly: false,
  };
  Object.assign(settings, options);

  if (!words) {
    return;
  }
  if (words.constructor === String) {
    words = [words];
  }
  words = words.filter(function (word, i) {
    return word != '';
  });
  words = words.map(function (word, i) {
    return regexEscape(word);
  });
  if (words.length == 0) {
    return this;
  }

  var flag = settings.caseSensitive ? '' : 'i';
  var pattern = '(' + words.join('|') + ')';
  if (settings.wordsOnly) {
    pattern = '\\b' + pattern + '\\b';
  }
  var re = new RegExp(pattern, flag);

  for (var i = 0; i < es.length; i++) {
    highlightNode(es[i], re, settings.element, settings.className);
  }
}

function highlightNode(node, re, nodeName, className) {
  if (node.nodeType === 3 && node.parentElement && node.parentElement.namespaceURI == 'http://www.w3.org/1999/xhtml') {
    // text nodes
    var match = node.data.match(re);
    if (match) {
      var highlight = document.createElement(nodeName || 'span');
      highlight.className = className || 'highlight';
      var wordNode = node.splitText(match.index);
      wordNode.splitText(match[0].length);
      var wordClone = wordNode.cloneNode(true);
      highlight.appendChild(wordClone);
      wordNode.parentNode.replaceChild(highlight, wordNode);
      return 1; //skip added node in parent
    }
  } else if (
    node.nodeType === 1 &&
    node.childNodes && // only element nodes that have children
    !/(script|style)/i.test(node.tagName) && // ignore script and style nodes
    !(node.tagName === nodeName.toUpperCase() && node.className === className)
  ) {
    // skip if already highlighted
    for (var i = 0; i < node.childNodes.length; i++) {
      i += highlightNode(node.childNodes[i], re, nodeName, className);
    }
  }
  return 0;
}

function unmark() {
  sessionStorage.removeItem(window.relearn.absBaseUri + '/search-value');
  var markedElements = document.querySelectorAll('mark.search');
  for (var i = 0; i < markedElements.length; i++) {
    var parent = markedElements[i].parentNode;
    while (parent && parent.classList) {
      if (parent.tagName.toLowerCase() === 'li' && parent.parentNode && parent.parentNode.tagName.toLowerCase() === 'ul' && parent.parentNode.classList.contains('collapsible-menu')) {
        var toggleInputs = parent.querySelectorAll('input.menu-marked');
        if (toggleInputs.length) {
          toggleInputs[0].checked = toggleInputs[0].dataset.checked === 'true';
          toggleInputs[0].dataset.checked = null;
          toggleInputs[0].classList.remove('menu-marked');
        }
      }
      if (parent.classList.contains('expand')) {
        var expandInputs = parent.querySelectorAll('input.expand-marked');
        if (expandInputs.length) {
          expandInputs[0].checked = expandInputs[0].dataset.checked === 'true';
          expandInputs[0].dataset.checked = null;
          expandInputs[0].classList.remove('expand-marked');
        }
      }
      parent = parent.parentNode;
    }
  }

  var highlighted = document.querySelectorAll('.highlightable');
  unhighlight(highlighted, { element: 'mark', className: 'search' });
  psm &&
    setTimeout(function () {
      psm.update();
    }, 10);
}

function unhighlight(es, options) {
  var settings = {
    className: 'highlight',
    element: 'span',
  };
  Object.assign(settings, options);

  for (var i = 0; i < es.length; i++) {
    var highlightedElements = es[i].querySelectorAll(settings.element + '.' + settings.className);
    for (var j = 0; j < highlightedElements.length; j++) {
      var parent = highlightedElements[j].parentNode;
      parent.replaceChild(highlightedElements[j].firstChild, highlightedElements[j]);
      parent.normalize();
    }
  }
}

// replace jQuery.createPseudo with https://stackoverflow.com/a/66318392
function elementContains(txt, e) {
  var regex = RegExp(txt, 'i');
  var nodes = [];
  if (e) {
    var tree = document.createTreeWalker(
      e,
      4 /* NodeFilter.SHOW_TEXT */,
      function (node) {
        return regex.test(node.data);
      },
      false
    );
    var node = null;
    while ((node = tree.nextNode())) {
      nodes.push(node.parentElement);
    }
  }
  return nodes;
}

function searchInputHandler(value) {
  unmark();
  if (value.length) {
    sessionStorage.setItem(window.relearn.absBaseUri + '/search-value', value);
    mark();
  }
}

function initSearch() {
  // sync input/escape between searchbox and searchdetail
  var inputs = document.querySelectorAll('input.search-by');
  inputs.forEach(function (e) {
    e.addEventListener('keydown', function (event) {
      if (event.key == 'Escape') {
        var input = event.target;
        var search = sessionStorage.getItem(window.relearn.absBaseUri + '/search-value');
        if (!search || !search.length) {
          input.blur();
        }
        searchInputHandler('');
        inputs.forEach(function (e) {
          e.value = '';
        });
        if (!search || !search.length) {
          documentFocus();
        }
      }
    });
    e.addEventListener('input', function (event) {
      var input = event.target;
      var value = input.value;
      searchInputHandler(value);
      inputs.forEach(function (e) {
        if (e != input) {
          e.value = value;
        }
      });
    });
  });

  document.querySelectorAll('[data-search-clear]').forEach(function (e) {
    e.addEventListener('click', function () {
      inputs.forEach(function (e) {
        e.value = '';
        var event = document.createEvent('Event');
        event.initEvent('input', false, false);
        e.dispatchEvent(event);
      });
      unmark();
    });
  });

  var urlParams = new URLSearchParams(window.location.search);
  var value = urlParams.get('search-by');
  if (value) {
    sessionStorage.setItem(window.relearn.absBaseUri + '/search-value', value);
  }
  mark();

  // set initial search value for inputs on page load
  if (sessionStorage.getItem(window.relearn.absBaseUri + '/search-value')) {
    var search = sessionStorage.getItem(window.relearn.absBaseUri + '/search-value');
    inputs.forEach(function (e) {
      e.value = search;
      var event = document.createEvent('Event');
      event.initEvent('input', false, false);
      e.dispatchEvent(event);
    });
  }

  window.relearn.isSearchInit = true;
  window.relearn.runInitialSearch && window.relearn.runInitialSearch();
}

document.addEventListener('themeVariantLoaded', function (ev) {
  updateTheme(ev);
});

function updateTheme(ev) {
  if (window.relearn.lastVariant == ev.detail.variant) {
    return;
  }
  window.relearn.lastVariant = ev.detail.variant;

  initMermaid(true);
  initOpenapi(true);
}

(function () {
  window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (event) => {
    initMermaid(true);
    initOpenapi(true);
  });
})();

function useMermaid(config) {
  delete config.theme;
  window.relearn.mermaidConfig = config;
  if (typeof mermaid != 'undefined' && typeof mermaid.mermaidAPI != 'undefined') {
    mermaid.initialize(Object.assign({ securityLevel: 'antiscript', startOnLoad: false }, config));
  }
}
if (window.themeUseMermaid) {
  useMermaid(window.themeUseMermaid);
}

function useOpenapi(config) {
  if (config.css && config.cssInProject) {
    config.css = window.relearn.relBasePath + config.css;
  }
}
if (window.themeUseOpenapi) {
  useOpenapi(window.themeUseOpenapi);
}

function ready(fn) {
  if (document.readyState == 'complete') {
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
}

ready(function () {
  initArrowVerticalNav();
  initArrowHorizontalNav();
  initMermaid();
  initOpenapi();
  initMenuScrollbar();
  initToc();
  initAnchorClipboard();
  initCodeClipboard();
  fixCodeTabs();
  restoreTabSelections();
  initSwipeHandler();
  initHistory();
  initSearch();
  initImage();
  initExpand();
  initScrollPositionSaver();
});

(function () {
  var body = document.querySelector('body');
  var topbar = document.querySelector('#R-topbar');
  function addTopbarButtonInfos() {
    // initially add some management infos to buttons and areas
    var areas = body.querySelectorAll('.topbar-area');
    areas.forEach(function (area) {
      area.dataset.area = 'area-' + area.dataset.area;
      var buttons = area.querySelectorAll(':scope > .topbar-button');
      buttons.forEach(function (button) {
        button.dataset.origin = area.dataset.area;
        button.dataset.action = 'show';
        var placeholder = document.createElement('div');
        placeholder.classList.add('topbar-placeholder');
        placeholder.dataset.action = 'show';
        button.insertAdjacentElement('afterend', placeholder);
      });
      var placeholder = document.createElement('div');
      area.insertAdjacentElement('beforeend', placeholder);
      var hidden = document.createElement('div');
      hidden.classList.add('topbar-hidden');
      hidden.dataset.area = area.dataset.area;
      var hplaceholder = document.createElement('div');
      hidden.insertAdjacentElement('beforeend', hplaceholder);
      area.insertAdjacentElement('afterend', hidden);
    });
  }
  function moveAreaTopbarButtons(width) {
    topbar.querySelectorAll('.topbar-hidden .topbar-button').forEach(function (button) {
      // move hidden to origins area
      var placeholder = button.parentNode.parentNode.querySelector(':scope > .topbar-area .topbar-placeholder[data-action="hide"]');
      placeholder.dataset.action = 'show';
      button.dataset.action = 'show';
      placeholder.insertAdjacentElement('beforebegin', button);
    });
    topbar.querySelectorAll('.topbar-area .topbar-button').forEach(function (button) {
      var current_area = button.dataset.action;
      var origin_area = button.dataset.origin;
      if (current_area != 'show' && origin_area != current_area) {
        // move moved to origins area
        var placeholder = topbar.querySelector('.topbar-area[data-area="' + origin_area + '"] > .topbar-placeholder[data-action="' + current_area + '"]');
        placeholder.dataset.action = 'show';
        button.dataset.action = 'show';
        placeholder.insertAdjacentElement('beforebegin', button);
      }
    });
    Array.from(topbar.querySelectorAll('.topbar-area .topbar-button'))
      .reverse()
      .forEach(function (button) {
        var parent = button.parentElement;
        var current_area = parent.dataset.area;
        var action = button.dataset['width' + width.toUpperCase()];
        if (action == 'show') {
        } else if (action == 'hide') {
          // move to origins hidden
          var hidden = button.parentNode.parentNode.querySelector(':scope > .topbar-hidden > *');
          var placeholder = button.nextSibling;
          placeholder.dataset.action = action;
          button.dataset.action = action;
          hidden.insertAdjacentElement('beforebegin', button);
        } else if (action != current_area) {
          // move to action area
          var dest = button.parentNode.parentNode.querySelector('.topbar-area[data-area="' + action + '"] > *');
          if (dest) {
            var placeholder = button.nextSibling;
            placeholder.dataset.action = action;
            button.dataset.action = action;
            dest.insertAdjacentElement('beforebegin', button);
          }
        }
      });
  }
  function moveTopbarButtons() {
    var isS = body.classList.contains('menu-width-s');
    var isM = body.classList.contains('menu-width-m');
    var isL = body.classList.contains('menu-width-l');
    // move buttons once, width has a distinct value
    if (isS && !isM && !isL) {
      moveAreaTopbarButtons('s');
    } else if (!isS && isM && !isL) {
      moveAreaTopbarButtons('m');
    } else if (!isS && !isM && isL) {
      moveAreaTopbarButtons('l');
    }
  }
  function adjustEmptyTopbarContents() {
    var buttons = Array.from(document.querySelectorAll('.topbar-button > .topbar-content > .topbar-content-wrapper'));
    // we have to reverse order to make sure to handle innermost areas first
    buttons.reverse().forEach(function (wrapper) {
      var button = getTopbarButtonParent(wrapper);
      if (button) {
        var isEmpty = true;
        var area = wrapper.querySelector(':scope > .topbar-area');
        if (area) {
          // if it's an area, we have to check each contained button
          // manually for its display property
          var areabuttons = area.querySelectorAll(':scope > .topbar-button');
          isEmpty = true;
          areabuttons.forEach(function (ab) {
            if (ab.style.display != 'none') {
              isEmpty = false;
            }
          });
        } else {
          var clone = wrapper.cloneNode(true);
          var irrelevant = clone.querySelectorAll('div.ps__rail-x, div.ps__rail-y');
          irrelevant.forEach(function (e) {
            e.parentNode.removeChild(e);
          });
          isEmpty = !clone.innerHTML.trim();
        }
        button.querySelector('button').disabled = isEmpty;
        button.style.display = isEmpty && button.dataset.contentEmpty == 'hide' ? 'none' : 'inline-block';
      }
    });
  }
  function setWidthS(e) {
    body.classList[e.matches ? 'add' : 'remove']('menu-width-s');
  }
  function setWidthM(e) {
    body.classList[e.matches ? 'add' : 'remove']('menu-width-m');
  }
  function setWidthL(e) {
    body.classList[e.matches ? 'add' : 'remove']('menu-width-l');
  }
  function onWidthChange(setWidth, e) {
    setWidth(e);
    moveTopbarButtons();
    adjustEmptyTopbarContents();
  }
  var mqs = window.matchMedia('only screen and (max-width: 47.999rem)');
  mqs.addEventListener('change', onWidthChange.bind(null, setWidthS));
  var mqm = window.matchMedia('only screen and (min-width: 48rem) and (max-width: 59.999rem)');
  mqm.addEventListener('change', onWidthChange.bind(null, setWidthM));
  var mql = window.matchMedia('only screen and (min-width: 60rem)');
  mql.addEventListener('change', onWidthChange.bind(null, setWidthL));

  addTopbarButtonInfos();
  setWidthS(mqs);
  setWidthM(mqm);
  setWidthL(mql);
  moveTopbarButtons();
  adjustEmptyTopbarContents();
})();

(function () {
  var body = document.querySelector('body');
  function setWidth(e) {
    body.classList[e.matches ? 'add' : 'remove']('main-width-max');
  }
  function onWidthChange(setWidth, e) {
    setWidth(e);
  }
  var width = getColorValue('MAIN-WIDTH-MAX');
  var mqm = window.matchMedia('screen and ( min-width: ' + width + ')');
  mqm.addEventListener('change', onWidthChange.bind(null, setWidth));
  setWidth(mqm);
})();

function getColorValue(c) {
  return this.normalizeColor(getComputedStyle(document.documentElement).getPropertyValue('--INTERNAL-' + c));
}

function normalizeColor(c) {
  if (!c || !c.trim) {
    return c;
  }
  c = c.trim();
  c = c.replace(/\s*\(\s*/g, '( ');
  c = c.replace(/\s*\)\s*/g, ' )');
  c = c.replace(/\s*,\s*/g, ', ');
  c = c.replace(/0*\./g, '.');
  c = c.replace(/ +/g, ' ');
  return c;
}