{"version":3,"sources":["jsdelivr-header.js","/gh/atteggiani/animated-terminal@3.1/animated-terminal.js"],"names":[],"mappings":"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","file":"/gh/atteggiani/animated-terminal@3.1/animated-terminal.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /gh/atteggiani/animated-terminal@3.1/animated-terminal.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","/**\n * @author Davide Marchegiani <davide.marchegiani@gmail.com>\n * @version 3.1\n */\n\n'use strict';\n\nfunction replaceTagSymbols(str) {\n    /**\n    * Replace HTML tag symbols '<' and '>' with HTML enities '&lt;' and '&gt;'\n    * for correct usage in directories, PS1, input/promp characters etc.\n    */ \n    return str?.replaceAll('<','&lt;').replaceAll('>','&gt;')\n}\n\nfunction sleep(time, signal = null) {\n    /**\n    * Sleep for an amount of time with the possibility to be aborted\n    */\n    if (! signal?.aborted) {\n        return new Promise((resolve,reject) => {\n            const timeout = setTimeout(resolve, time);\n            if (signal) {\n                signal.addEventListener('abort', () => {\n                    clearTimeout(timeout);\n                    resolve();\n                },\n                {once: true})\n            }\n        });\n    }\n}\n\nfunction hide(element) {\n    /**\n    * Change element's style to 'hidden'\n    */\n    element.style.visibility = 'hidden';\n}\n\nfunction show(element, signal = null) {\n    /**\n    * Change element's style to 'visible'\n    */\n    if (! signal?.aborted) {\n        element.style.visibility = 'visible';\n    }\n}\n\nconst terminalTemplate = document.createElement('template');\nterminalTemplate.innerHTML = `\n    <style>\n        /* Colors injected by 'applyMode' method */\n\n        :host {\n            position: relative;\n        }\n\n        .terminal-window::-webkit-scrollbar {\n            width: 14px;\n        }\n        \n        .terminal-window::-webkit-scrollbar-thumb {\n            border-radius: 20px;\n            border: 4px solid rgba(0,0,0,0);\n            background-clip: padding-box;\n            background-color: var(--color-scrollbar);\n        }\n\n        .terminal-window {\n            word-break: break-all;\n            scroll-behavior: smooth;\n            scrollbar-gutter: stable;\n            max-width: 100%;\n            min-width: 150px;\n            max-height: 510px;\n            margin-top: 15px;\n            margin-bottom: 15px;\n            background-color: var(--color-bg);\n            color: var(--color-text);\n            display: block;\n            flex-direction: column;\n            justify-content: flex-start;\n            font-size: 13px;\n            font-family: 'Roboto Mono', 'Fira Mono', Consolas, Menlo, Monaco, 'Courier New', Courier, monospace;\n            font-weight: bold;\n            border-radius: 8px;\n            padding: 30px 25px 25px;\n            position: relative;\n            overflow-y: auto;\n            overflow-x: hidden;\n            box-sizing: border-box;\n        }\n\n        .terminal-window::before {\n            content: '';\n            position: absolute;\n            top: 12px;\n            left: 12px;\n            display: flex;\n            flex-direction: column;\n            width: 10px;\n            height: 10px;\n            border-radius: 50%;\n            /* A little hack to display the window buttons in one pseudo element. */\n            background-color: #d9515d;\n            -webkit-box-shadow: 0px 0 0 #d9515d, 20px 0 0 #f4c025, 40px 0 0 #3ec930;\n                    box-shadow: 0px 0 0 #d9515d, 20px 0 0 #f4c025, 40px 0 0 #3ec930;\n        }\n\n        .fast-button-wrapper {\n            position: sticky;\n            top: 0px;\n            z-index: 2;\n        }\n        \n        .fast-button-wrapper:hover {\n            cursor: pointer;\n        }\n        \n        .fast-button {\n            position: absolute;\n            color: var(--color-control-buttons);\n            width: max-content;\n            text-align: center;\n            top: var(--top);\n            right: var(--right);\n        }\n        \n        .fast-button:hover {\n            color: var(--color-control-buttons-hover);\n        }\n\n        .restart-button-wrapper {\n            position: sticky;\n            height: fit-content;\n            top: var(--top);\n            z-index: 2;\n        }\n        \n        .restart-button-wrapper:hover {\n            cursor: pointer;\n        }\n\n        .restart-button {\n            position: absolute;\n            color: var(--color-control-buttons);\n            width: max-content;\n            text-align: center;\n            top: 0px;\n            right: -15px;\n        }\n\n        .restart-button:hover {\n            color: var(--color-control-buttons-hover);\n        }\n        \n        .img-icon-wrapper {\n            position: absolute;\n            height: var(--height);\n            top: 0px;\n            margin-top: 0px;\n            right: var(--right);\n            z-index: 0;\n        }\n        \n        .img-icon {\n            position: sticky;\n            top: var(--top);\n            text-align: center;\n        }\n        \n        .img-icon:hover {\n            cursor: pointer;\n        }\n        \n        .img-icon > svg {\n            color: var(--color-control-buttons);\n        }\n        \n        .img-icon > svg:hover {\n            color: var(--color-control-buttons-hover);\n        }\n\n        .img-wrapper {\n            position: absolute;\n            width: fit-content;\n            height: var(--height);\n            top: 0px;\n            margin-top: 0px;\n        }\n        \n        .img-wrapper > img {\n            position: sticky;\n            max-height: calc(var(--max-height) - 20px);\n            margin-left: -15px;\n            top: -20px;\n            border-radius: 7px;\n            border: solid 2px transparent;\n            z-index: 1;\n        }\n        \n        .img-wrapper > img:hover {\n            border-color: var(--color-control-buttons);\n            cursor: pointer;\n        }\n        \n        .img-wrapper > img:active {\n            cursor: default;\n        }\n        \n    </style>\n    <body>\n        <div class='terminal-window' part=\"terminal-window\" tabindex=-1>\n            <slot></slot>\n        </div>\n    </body>\n`\n/* terminal-window component */\nclass TerminalWindow extends HTMLElement {\n    /**\n    * Custom attributes for the <terminal-window> component:\n    * \n    * @param {string} mode - 'light' for light mode; 'dark' for dark mode (default).\n    * @param {string} data - Type of prompt for each line of the entire terminal. Choices can be:\n    *   - 'output': Output of the terminal. Written all at once; (default)\n    *   - 'input': Input to the terminal. Written with typing animation after 'directory' and 'inputChar' attributes;\n    *   - 'prompt': Same as input, but with written with typing animation after 'promptChar' attribute;\n    *   - 'progress' Line with progress bar animation.\n    * @param {number || string} startDelay - Delay before the start of terminal animation, in ms.\n    * @param {number || string} lineDelay - Delay before the start of each terminal line animation, in ms.\n    * @param {number || string} typingDelay - Delay between each typed character in the terminal, in ms.\n    * @param {number || string} imageDelay - Delay before the content inside <img> gets shown, in ms \n    *   (similar to lineDelay, but for <img> tags).\n    * @param {number || string} imageTime - Amount of time for an image to stay opened before being minimised, in ms. \n    *   If not present, the image will stay open (You will still be able to click on it to minimise).  \n    * @param {string} progressChar – Character(s) to use for progress bar for the entire terminal, defaults to █.\n    * @param {number || string} progressPercent - Max percent of progress for the entire terminal, default 100%.\n    * @param {string} cursor – Character to use for cursor for the entire terminal, defaults to ▋.\n    * @param {string} inputChar – Character(s) to use before the 'input' prompt for the entire terminal, \n    *   defaults to '$'.\n    * @param {string} directory – Directory to write in the 'input' prompt before the input character for \n    *   the entire terminal.\n    * @param {string} promptChar – Character(s) to use before the 'prompt' prompt for the entire terminal,\n    *   defaults to '>>>'.\n    * @param {string} PS1 – String to write in the 'input' prompt before the actual line for the entire terminal. \n    *  If present, any 'directory' or 'input' attribute will be disregarded.\n    *  Accepts HTML format. E.g.: \"This is a <span style='color: green;'>valid</span> PS1 attribute\"\n    * @param {boolean} init - Initialise the terminal animation at page load.\n    * @param {boolean} static - Create a static terminal without animation.\n    */\n    constructor() {\n        super();\n        this.DATA_TYPES = ['input','prompt','progress','output'];\n        // Attach shadowDOM\n        this.attachShadow({ mode: \"open\" });\n        this.shadowRoot.appendChild(terminalTemplate.content.cloneNode(true));\n    }\n\n    connectedCallback() {\n        // Keep only proper lines\n        this.keepLines();\n        // Apply colormode\n        this.applyMode();\n        this.createAbortControllers();\n        // Wait for terminal-lines to load, then continue\n        this.linesReady().then(() => {\n            this.setTerminal();\n            this.applyStatic();\n            this.initialise();\n        })\n    }\n    \n    get window() {\n        const window = this.shadowRoot.querySelector(\".terminal-window\");\n        for (let attr of ['lineDelay','typingDelay','imageDelay','imageTime']) {\n            if (this.hasAttribute(attr)) {\n                window.setAttribute(attr,parseFloat(this.getAttribute(attr)))\n            }    \n        }\n        return window\n    }\n\n    get mode() {\n        /**\n        * Getter for the mode property\n        */\n        if (this.getAttribute('mode')?.toString().toLowerCase() == 'light') {\n            return 'light';\n        } else {\n            return 'dark';\n        }\n    }\n\n    get data() {\n        /**\n        * Getter for the data property\n        */\n        let attr = this.getAttribute('data');\n        if (this.DATA_TYPES.includes(attr)) {\n            return attr;\n        } else {\n            return 'output'\n        }\n    }\n\n    get startDelay() {\n        /**\n        * Resets startDelay property.\n        */\n       return parseFloat(this.getAttribute('startDelay')) || 300;\n    }\n    \n    get imageDelay() {\n        /**\n        * Resets lineDelay property.\n        */\n        if (this.img && this.img.img.hasAttribute('imageDelay')) {\n            return parseFloat(this.img.img.getAttribute('imageDelay'));\n        } else if (this.hasAttribute('imageDelay')) {\n            return parseFloat(this.getAttribute('imageDelay'));\n        } else {\n            return 1500;\n        }\n    }\n    \n    get imageTime() {\n        /**\n        * Resets lineDelay property.\n        */\n        if (this.img && this.img.img.hasAttribute('imageTime')) {\n            return parseFloat(this.img.img.getAttribute('imageTime')) ? parseFloat(this.img.img.getAttribute('imageTime')) : this.img.img.getAttribute('imageTime');\n        } else if (this.hasAttribute('imageTime')) {\n            return parseFloat(this.getAttribute('imageTime')) ? parseFloat(this.getAttribute('imageTime')) : this.img.img.getAttribute('imageTime');\n        } else {\n            return 3000;\n        }\n    }\n\n    get progressChar() {\n        /**\n        * Getter for the progressChar property\n        */\n        return replaceTagSymbols(this.getAttribute('progressChar')?.toString()) || '█';\n    }\n    \n    get progressPercent() {\n        /**\n        * Getter for the progressPercent property\n        */\n        return parseFloat(this.getAttribute('progressPercent')) || 100;\n    }\n    \n    get cursor() {\n        /**\n        * Getter for the cursor property\n        */\n        return replaceTagSymbols(this.getAttribute('cursor')?.toString()) || '▋';\n    }\n    \n    get inputChar() {\n        /**\n        * Getter for the inputChar property\n        */\n        if (this.hasAttribute('PS1')) {\n            return '';\n        } else {\n            return replaceTagSymbols(this.getAttribute('inputChar')?.toString()) || '$';\n        }\n    }\n    \n    get promptChar() {\n        /**\n        * Getter for the promptChar property\n        */\n        return replaceTagSymbols(this.getAttribute('promptChar')?.toString()) || '>>>';\n    }\n    \n    get directory() {\n        /**\n        * Getter for the directory property\n        */\n        if (this.hasAttribute('PS1')) {\n            return '';\n        } else {\n            return replaceTagSymbols(this.getAttribute('directory')?.toString()) || '';\n        }\n    }\n\n    get PS1() {\n        /**\n        * Getter for the PS1 property\n        */\n        if (this.hasAttribute('PS1')) {\n            return this.getAttribute('PS1');\n        } else {\n            return `<span class=\"directory\" part='directory'>${this.directory}</span><span class=\"inputChar\" part='input-character'>${this.inputChar}&nbsp;</span>`;\n        }\n    }\n\n    get static() {\n        /**\n        * Getter for the static property\n        */\n        let attr = this.getAttribute('static')\n        if (attr == 'false') {\n            return false\n        } else if (attr == \"\") {\n            return true\n        } else {\n            return !!attr\n        }\n    }\n    \n    get init() {\n        /**\n        * Getter for the init property\n        */\n        let attr = this.getAttribute('init')\n        if (attr == 'false') {\n            return false\n        } else if (attr == \"\") {\n            return true\n        } else {\n            return !!attr\n        }\n    }\n    \n    async resetTerminal() {\n        this.hideAll();\n        this.abortControllerFast.abort();\n        this.abortControllerReset.abort();\n        await sleep(1)\n        this.setTerminal();\n        this.applyStatic();\n        this.restartFunction();\n    }\n\n    createAbortControllers() {\n        this.abortControllerFast = new AbortController();\n        this.abortControllerReset = new AbortController();\n    }\n\n    linesReady() {\n        let lineReadyPromises = [];\n        this.lines.forEach(line => {\n            lineReadyPromises.push(new Promise(async resolve => {\n                while (!line.ready) {\n                    await sleep(1);\n                }\n                resolve();\n            }))\n        })\n        return Promise.all(lineReadyPromises)\n    }\n\n    applyMode() {\n        /**\n        * Sets the color scheme according to the mode selected.\n        */\n        const colors = document.createElement('style');\n        if (this.mode == 'dark') {\n            colors.innerHTML = `\n                    :host {\n                        --color-bg: #252a33;\n                        --color-text: #eee;\n                        --color-control-buttons: #FAA619;\n                        --color-control-buttons-hover: #115D97;\n                        --color-scrollbar: rgba(255, 255, 255, .6);\n            `\n        } else {\n            colors.innerHTML = `\n                :host {\n                    --color-text: #252a33;\n                    --color-bg: #eee;\n                    --color-control-buttons-hover: #FAA619;\n                    --color-control-buttons: #115D97;\n                    --color-scrollbar: rgba(0, 0, 0, .6);\n            `\n        }\n        this.shadowRoot.appendChild(colors);\n    }\n\n    keepLines() {\n        /*\n        * Delete all terminal lines without tags or whose tags are not <terminal-line> or <img> (only first one, others are deleted)\n        * Also create the 'img' property if <img> tag is present, remove img node from lines and append it to shadowDOM\n        * Create the 'lines' property with the kept lines.\n        */\n        for (let i=0; i<this.childNodes.length; i++) {\n            let node = this.childNodes[i];\n            if (node.tagName?.toLowerCase() == 'img' && ! this.img) {\n                this.img = {\n                    img: node,\n                    index: i,\n                }\n                this.generateImg(node);\n                i--;\n            } else if (node.tagName?.toLowerCase() != 'terminal-line') {\n                node.remove();\n                i--;\n            } else {\n                hide(node);\n            }\n        }\n        this.lines = this.childNodes;\n    }\n\n    generateImg(node) {\n        // Create img wrapper for sticky behaviour\n        hide(node);\n        let imgwrapper = document.createElement('div');\n        imgwrapper.classList.add('img-wrapper');\n        this.window.appendChild(imgwrapper);\n        imgwrapper.appendChild(node);\n        node.setAttribute('part','img');\n        node.setAttribute('title','Click to minimise image');\n        // Change window height\n        const windowStyle = getComputedStyle(this.window);\n        this.window.setAttribute('style',`--max-height: ${windowStyle.maxHeight};`);\n        this.window.style.height = windowStyle.maxHeight;\n    }\n\n    async generateAllProgress() {\n        this.lines.forEach(line => {\n            if (line.data == 'progress') {\n                line.generateProgress();\n            }\n        })\n    }\n\n    hideLines() {\n        /**\n        * Hide lines inside the terminal\n        * Hide PS1 and Prompt Char for terminal reset\n        */\n        this.lines.forEach(line => {\n            hide(line);\n            let elem = line.shadowRoot?.querySelector('.ps1, .promptChar');\n            if (elem) {\n                hide(elem);\n            }\n        })\n    }\n    \n    showLines() {\n        /**\n        * Show lines inside the terminal\n        * Show PS1 and Prompt Char for terminal reset\n        */\n        this.lines.forEach(line => {\n            show(line, this.abortControllerReset.signal);\n            let elem = line.shadowRoot?.querySelector('.ps1, .promptChar');\n            if (elem) {\n                show(elem, this.abortControllerReset.signal);\n            }\n        })\n    }\n\n    async restartFunction() {\n        this.createAbortControllers();\n        this.hideAll();\n        this.mutationObserverLineBeingTyped.disconnect();\n        await this.scrollToTop();\n        this.initialiseWhenVisible();\n    }\n\n    generateRestartButton() {\n        /**\n        * Generate restart button and adds it hidden to 'this.window'\n        */\n        const restart = document.createElement('div')\n        restart.setAttribute('part','restart-button')\n        restart.addEventListener('click', () => {\n            this.window.focus();\n            this.restartFunction();\n        },\n        {passive: true})\n        restart.classList.add('restart-button');\n        restart.innerHTML = \"restart ↻\";\n        this.restartButton = restart;\n        this.window.appendChild(restart);\n        let wrapper = document.createElement('div')\n        wrapper.classList.add('restart-button-wrapper');\n        wrapper.appendChild(restart);\n        this.window.prepend(wrapper);\n        hide(restart);\n    }\n\n    generateFastButton() {\n        /**\n        * Generate fast button and adds it hidden to 'this.window'\n        */\n        const nullifyDelays = () => {\n            this.lines.forEach(line => {\n                line._lineDelay = 0;\n                line._typingDelay = 0;\n            })\n            this._imageDelay = 0;\n            this._imageTime = 0;\n        }\n        const fast = document.createElement('div')\n        fast.setAttribute('part','fast-button')\n        const fastFunction = async (e) => {\n            hide(fast);\n            this.window.focus();\n            this.abortControllerFast.abort();\n        }\n        fast.addEventListener('click', fastFunction, {passive: true});\n        fast.classList.add('fast-button');\n        fast.innerHTML = \"fast ❯❯❯\";\n        this.fastButton = fast;\n        let wrapper = document.createElement('div')\n        wrapper.classList.add('fast-button-wrapper');\n        wrapper.appendChild(fast);\n        this.window.prepend(wrapper);\n        let top = -(parseFloat(getComputedStyle(fast).fontSize) + parseFloat(getComputedStyle(this.window).paddingTop))/2;\n        fast.setAttribute(\"style\",`--top: ${top}px; --right: -15px;`);\n        hide(fast);\n    }\n\n    setTerminal() {\n        /**\n        * Clear window and generate restart/fast buttons.\n        */\n        this.generateRestartButton();\n        this.generateFastButton();\n        this.generateScrollObservers();\n        this.setImg();\n        this.generateImgMinimiser();\n        this.setWindow();\n        this.generateSizeObserver();\n    }\n\n    setWindow() {\n       /**\n        * Sets terminal window height\n        */\n       this.window.style.height = getComputedStyle(this.window).height;\n    }\n\n    generateSizeObserver() {\n        let observer = new ResizeObserver(entries => {\n            entries.forEach(entry => {\n                if (entry.contentRect.height) {\n                    observer.disconnect();\n                    this.setSizes();\n                }\n            })\n        })\n        observer.observe(this.window);\n    }\n\n    setSizes() {\n        // Set restart wrapper\n        const windowStyle = getComputedStyle(this.window);\n        let top = parseFloat(windowStyle.height) - parseFloat(windowStyle.paddingTop) - parseFloat(windowStyle.paddingBottom);\n        this.restartButton.parentElement.setAttribute(\"style\",`--top: ${top}px;`);\n        if (this.img) {\n            // img-icon wrapper height and top\n            let el = this.imgIcon.parentElement;\n            let top = parseFloat(windowStyle.height) - parseFloat(windowStyle.paddingTop) - parseFloat(windowStyle.paddingBottom);\n            let height = this.window.scrollHeight;\n            let right = this.restartButton.offsetWidth + parseFloat(getComputedStyle(this.restartButton).right) + el.offsetWidth;\n            el.setAttribute('style', `--height: ${height}px; --top: ${top}px; --right: ${right}px;`);\n            // Set img wrapper\n            el = this.img.img.parentElement;\n            el.setAttribute('style', `max-height: unset; --height: ${this.window.scrollHeight}px`);\n        }\n    }\n\n    generateImgMinimiser() {\n        if (this.img) {\n            // Create div  and wrapper for image iconisation with sticky behaviour\n            let imgIcon = document.createElement('div');\n            hide(imgIcon);\n            this.imgIcon = imgIcon;\n            imgIcon.innerHTML=`\n            <svg version=\"1.2\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 524 299\" width=\"2.5em\" part=\"img-icon\">\n                <title>Click to maximise image</title>\n                <style>\n                    .s0 {\n                        fill: currentColor;\n                    } \n                </style>\n                <path id=\"Layer\" fill-rule=\"evenodd\" class=\"s0\" d=\"m53 0h385.6l15 15 55.4 55.4 15 15v183.6c0 16.6-13.4 30-30 30h-441c-16.6 0-30-13.4-30-30v-120h-8c-8.3 0-15-6.7-15-15v-64c0-8.3 6.7-15 15-15h8v-25c0-16.6 13.4-30 30-30zm0 284h441c8.3 0 15-6.7 15-15v-177h-58c-11 0-20-9-20-20v-57h-378c-8.3 0-15 6.7-15 15v25h148c8.3 0 15 6.7 15 15v64c0 8.3-6.7 15-15 15h-148v120c0 8.3 6.7 15 15 15zm59.3-159.7q-0.1-1.5-0.1-2.8 0-6.1-0.1-12.7v-12.7q0-5-0.1-10 0-5 0-10.1 0-0.6-0.1-1.1 0-0.5-0.1-1.2-0.1-0.8-0.5-2-0.3-0.8-1.1-1.5-1-0.9-2.1-1-0.5-0.1-1.1-0.1-0.5-0.1-1.2-0.1-1.5 0-3 1.1-1.3 1-2.6 2.4-1.3 1.5-2.3 3-1 1.6-1.6 2.7-1.6 2.4-2.8 4.3-1.1 1.9-2.2 3.6-1 1.5-1.9 3-0.9 1.3-1.8 2.8-0.2 0.3-0.5 0.9-0.3 0.5-0.8 1.2l-0.7 1q-0.4 0.5-0.6 0.8-1.7-2.3-3.6-5.5-1.8-3.2-4.2-7-0.5-0.9-1.3-2-0.7-1.2-1.5-2.5-0.8-1.3-1.7-2.4-0.8-1.2-1.5-2-1.2-1.3-2.6-3-1.2-1.9-3.1-2.2-0.5-0.1-1.1-0.1-0.6-0.1-1.2-0.1-1.6 0-2.9 0.8-1.2 0.7-2 2.2-0.3 0.8-0.6 1.7-0.2 0.8-0.2 1.8-0.5 7.7-0.5 15.6v12.1l-0.1 14-0.1 7.1v2.4q0.1 1.2 0.2 2.5 0.2 1.1 0.7 2.5 0.6 1.4 1.8 2.1 1.9 1 3.6 0.9 1.6-0.1 2.8-0.9 1.3-0.8 2-2.1 0.7-1.4 0.7-2.9 0.1 0 0.2-2.8 0.1-2.9 0.1-7.2 0.1-4.2 0.1-9.1 0.1-5 0.1-9.3v-7.3q0.1-2.9 0.1-3 2.9 5.5 5.6 9.3 2.8 3.8 5 6.5 0.3 0.6 0.9 1.2l1.3 1.1q0.7 0.5 1.4 0.9 0.7 0.4 1.5 0.3 1.3-0.1 2.4-0.7 1.2-0.8 2.8-2.7 1.6-2 3.9-5.5 2.4-3.6 5.9-9.5 0.2 3 0.1 3.7v3.4q0.1 0.8 0.1 1.6v3.7l0.1 13.9v9.6q0 1.4 0.3 2.6 0.2 1.3 0.8 2.5 0.6 1.1 1.9 1.9 1 0.4 2.2 0.6 1.2 0.2 2.5-0.3 1.3 0 2.3-1 0.8-0.5 1.2-1.6 0.5-1 0.6-2.2 0.2-1.1 0.3-2.2 0.1-1.5 0-2.9zm-83.3 1.1q0 0.9 0 1.6 0.1 0.4 0.1 0.9l0.2 0.9q0 0.5 0.1 1.1 0.1 0.4 0.3 0.9 0.1 0.2 0.2 0.3 0.1 0.1 0.1 0.2 0 0.3 0.3 0.6 0.5 1.1 1.6 1.8 2.2 1 4.6 0.5 1.7-0.3 2.4-1 0.4-0.4 0.7-0.8 0.4-0.4 0.7-0.9 0.1-0.5 0.2-1 0.2-0.5 0.4-1 0.1-0.5 0.1-0.9 0.1-0.4 0.1-0.7v-0.9l0.5-47.1v-2.6q0.1-0.5 0.1-1.1 0-0.6-0.1-1.1 0-0.6-0.1-1.2-0.1-0.5-0.2-1-0.1-0.5-0.3-1.1-0.5-1-1-1.4-0.9-0.9-2.1-1.1-0.6-0.1-1.2-0.1-0.5-0.1-1.3-0.1-1.3 0-2.8 0.7-1.3 0.9-1.9 2.2-0.9 1.9-1 3.5 0 1-0.1 2 0 0.9-0.1 1.8v0.4q-0.2 3.2-0.2 5.7v12.2q0 3.1-0.1 6l-0.1 13.3-0.1 7.2zm143.7-7.8q0.3-2.8 0.3-5.6v-3.7q0-0.4-0.1-1 0-0.6-0.1-1.2-0.1-1-0.4-2-0.2-0.4-0.5-0.8l-0.5-0.7q-0.8-0.6-2.1-0.9-1.3-0.4-2.3-0.3h-9.6q-0.6 0-1.2 0.1-0.7 0.1-1.3 0.3-0.5 0.1-1 0.3-1.2 0.2-1.8 0.7-0.9 1.1-1.2 1.8l-0.1 1.1v1q0 1.4 0.9 2.4 0.8 1.2 2.4 1.8 1.9 0.7 3.9 0.7 0.5 0 1.4 0.1h2.1v0.1q0 1.9-0.4 3.6-0.2 1.7-1.1 3.2-1 1.4-2.5 2.5-1.6 1-4 1.6-1.7 0.5-3.7 0.3-1.9-0.2-3.6-0.8-1.7-0.7-3.2-1.8-1.4-1.2-2.2-2.6-2.1-3.9-3.1-8.4-0.5-2.6-0.7-5.4-0.1-2.9 0.3-5.8 0.3-2.9 1.1-5.5 0.9-2.7 2.4-5 1.3-2 3.2-3.5 2-1.6 4.2-2.3 2.3-0.7 4.6-0.5 2.5 0.2 4.7 1.5 1.9 1.2 2.8 3 0.9 1.7 1.6 3.8 0.5 1.9 2.1 3.2 1.6 1.2 3.3 1.4 1.8 0.2 3.2-0.8 1.5-1.1 2-3.8 0.5-3.1-0.3-6.4-0.8-3.4-2.3-5.7-2.1-3.2-5.7-5.1-3.6-1.9-7.8-2.7-4.1-0.7-8.4-0.2-4.2 0.3-7.7 1.8-3.9 1.5-6.7 4.5-2.7 3-4.6 6.7-1.9 3.8-2.9 7.8-0.9 3.9-1.2 7.4-0.4 5.8 0.3 12.2 0.8 6.4 3.5 11.8 2.7 5.5 7.7 9.2 5.1 3.6 13.3 3.9 1.8 0.1 3.8-0.1 2-0.1 4-0.5 2.1-0.4 3.9-0.9 1.9-0.7 3.3-1.6 2.8-1.7 4.5-4 1.6-2.3 2.4-4.9 0.9-2.6 1.1-5.3zm77.3-10.1c0-13.5 10.8-24.3 24.2-24.3 13.5 0 24.3 10.8 24.3 24.3 0 13.4-10.8 24.2-24.3 24.2-13.4 0-24.2-10.8-24.2-24.2zm195.6 129.1c2 3.4-0.4 7.6-4.3 7.6h-215.6c-3.9 0-6.3-4.2-4.3-7.6l42.6-71.7c2-3.3 6.7-3.3 8.6 0l33.8 56.9 60.9-102.3c1.9-3.2 6.7-3.2 8.6 0z\"/>\n            </svg>\n            `\n            imgIcon.classList.add('img-icon');\n            let imgIconWrapper = document.createElement('div');\n            imgIconWrapper.classList.add('img-icon-wrapper');\n            this.window.appendChild(imgIconWrapper);\n            imgIconWrapper.appendChild(imgIcon);\n            this.img.img.addEventListener(\"click\", this.minimiseImg.bind(this), {passive: true})\n            imgIcon.addEventListener(\"click\", this.maximiseImg.bind(this), {passive: true})\n        }\n    }\n\n    minimiseImg(e) {\n        hide(this.img.img);\n        show(this.imgIcon, this.abortControllerReset.signal);\n    }\n    \n    maximiseImg(e) {\n        show(this.img.img, this.abortControllerReset.signal);\n        hide(this.imgIcon);\n    }\n\n    setImg() {\n        if (this.img) {\n            let minWidth = parseFloat(getComputedStyle(this.window).minWidth);\n            // Set img sises\n            let aspectRatio = this.img.img.width/this.img.img.height;\n            let maxHeight = parseFloat(getComputedStyle(this.window).maxHeight) - 25;\n            // height\n            if (this.img.img.height > maxHeight) {\n                this.img.img.width = maxHeight*aspectRatio;\n            }\n            let observer = new ResizeObserver(entries => {\n                entries.forEach(entry => {\n                    let width = entry.contentRect.width - 75;\n                    // width\n                    if (width/aspectRatio <= maxHeight && width >= minWidth) {\n                        this.img.img.width = width;\n                    }\n                    \n                })\n            })\n            observer.observe(this.window);\n        }\n    }\n\n    hideAll() {\n        hide(this.restartButton);\n        hide(this.fastButton);\n        if (this.img) {\n            hide(this.img.img);\n            hide(this.imgIcon);\n        }\n        this.hideLines();\n    }   \n\n    showAll() {\n        if (this.img) {\n            show(this.imgIcon, this.abortControllerReset.signal);\n        }\n        this.showLines();\n    }   \n\n    async initialiseAnimation() {\n         /**\n         * Start the animation and render the lines\n         */\n        this.autoScroll();\n        await sleep(this.startDelay, this.abortControllerFast.signal);\n        show(this.fastButton);\n        for (let i=0; i<this.lines.length; i++) {\n            let line = this.lines[i];\n            //Show image if present \n            if (this.img && this.img.index == i) {\n                await this.showImage();\n            }\n            // Type line\n            line.classList.add('isBeingTyped');\n            await line.type();\n            line.classList.remove('isBeingTyped');\n            //Show image if it's at the end\n            if (this.img && this.img.index == this.lines.length && i == this.lines.length - 1) {\n                await this.showImage();\n            }\n        }\n        hide(this.fastButton);\n        if (!this.static) show(this.restartButton, this.abortControllerReset.signal);\n    }\n\n    async showImage() {\n        if (this.imageTime != 0) {\n            await sleep(this.imageDelay, this.abortControllerFast.signal);\n            this.maximiseImg();\n        }\n        if (this.imageTime != 'inf') {\n            await sleep(this.imageTime, this.abortControllerFast.signal);\n            this.minimiseImg();\n        }\n    }\n\n    initialise() {\n        if (this.init || this.static) {\n            this.initialiseAnimation();\n        } else {\n            this.initialiseWhenVisible();\n        }\n    }\n\n    initialiseWhenVisible() {\n        /**\n        * Initialise the terminal only when it becomes visible\n        */\n        let intersectionObserver = new IntersectionObserver(entries => {\n            entries.forEach(entry => {\n                if (entry.isIntersecting) {\n                    intersectionObserver.disconnect();\n                    this.initialiseAnimation();\n                }\n            })\n        },\n        {\n            threshold: \"0.4\",\n        })\n        intersectionObserver.observe(this);\n    }\n\n    async scrollToTop() {\n    // Scroll to the top of the window.\n        this.window.scrollTop = 0;\n        return new Promise( async resolve => {\n            while (this.window.scrollTop != 0) {\n                await sleep(1); //Should find and better way to do this\n            }\n            resolve();\n        })\n    }\n    \n    async scrollToBottom() {\n    // Scroll to the bottom of the window.\n        let maxHeight = parseFloat(getComputedStyle(this.window).maxHeight);\n        await sleep(20); // CHANGE!!!\n        this.window.scrollTo(0,this.window.scrollHeight);\n        const check = () => this.window.scrollTop == this.window.scrollHeight - maxHeight;\n    \n        if (check()) {\n            return\n        } else {                  \n            return new Promise(resolve => {\n                const timer = setInterval(() => {\n                    if (check()) {\n                        clearInterval(timer);\n                        resolve();\n                    }\n                }, 10)\n            })\n        }\n    }\n    \n    scrollOneLine(line) {\n        const nPix = parseInt(getComputedStyle(line).height);\n        this.window.scrollBy(0,nPix);\n    }\n\n    generateScrollObservers() {\n        const intersectionFunction = async entry => {\n            if (entry.intersectionRatio == 1) {\n                intersectionObserver.unobserve(entry.target);\n            } else {\n                if (entry.target.nextSibling) {\n                    this.scrollOneLine(entry.target);\n                }\n                intersectionObserver.unobserve(entry.target);\n            }\n        }\n           \n        let margin = `${parseInt(getComputedStyle(this.window).marginBottom) - 5}px` // Margin of the intersectionObserver computed as bottom margin - 5px (5px padding)\n        let intersectionObserver = new IntersectionObserver(entries => {\n            entries.forEach(entry => {\n                intersectionFunction(entry)\n            })\n        },\n        {\n            root: this.window,\n            rootMargin: `0px 0px ${margin} 0px`,\n        })\n        \n        const mutationFunction = async entry => {\n            let nextSibling = entry.target.nextSibling;\n            if (nextSibling) {\n                intersectionObserver.observe(nextSibling)\n            } else {\n                await this.scrollToBottom();\n            }\n        }\n\n        this.mutationObserverLineBeingTyped = new MutationObserver(entries => {\n            entries.forEach(entry => {\n                if (entry.oldValue?.includes(\"isBeingTyped\")) {\n                    mutationFunction(entry)\n                }\n            })\n        })\n    }\n    \n    autoScroll() {\n        /**\n        * Auto scrolls 1 line if the terminal content exceeds the terminal max-height.\n        */\n        this.lines.forEach(line => {\n            this.mutationObserverLineBeingTyped.observe(line,{\n                attributes: true,\n                attributeOldValue: true,\n                attributeFilter: [\"class\"]\n            })\n        });\n\n        this.addEventListener('wheel', e => {\n            this.mutationObserverLineBeingTyped.disconnect();\n        }, {passive: true})\n\n        this.addEventListener('keydown', e => {\n            if (['ArrowDown','Space','ArrowUp'].includes(e.code)) {\n                this.mutationObserverLineBeingTyped.disconnect();\n            }\n        }, {passive: true})\n    }\n\n    applyStatic() {\n        let observer = new MutationObserver(entries => {\n            entries.forEach(entry => {\n                if (entry.target.hasAttribute('static')) {                    \n                    this.abortControllerFast.abort();\n                    hide(this.restartButton);\n                } else {\n                    this.restartFunction();\n                }\n            })\n        })\n        observer.observe(this, \n            {\n            attributes: true,\n            attributeFilter: [\"static\"]\n            }\n        )\n        if (this.static) {\n            this.abortControllerFast.abort();\n        }\n    }\n}\n\n/* =============================================================================================================\n ===============================================================================================================\n ===============================================================================================================\n ===============================================================================================================\n ===============================================================================================================\n ===============================================================================================================\n ===============================================================================================================\n ===============================================================================================================\n ===============================================================================================================\n ===============================================================================================================\n =============================================================================================================== */\n\n /* terminal-line component */\nconst lineTemplate = document.createElement('template');\nlineTemplate.innerHTML = `\n    <style>\n        :host {\n            --color-text-prompt: #a2a2a2;\n            --color-text-directory: #A6CE39;\n            --color-text-symlink: #06AEEF;\n            --color-text-inputchar: #FAA619;\n            display: grid;\n        }\n        \n        div.terminal-line {\n            line-height: 1.5em;\n            min-height: 1.5em;\n            display: inline;\n            align-self: center;\n        }\n        \n        span.directory {\n            color: var(--color-text-directory);\n        }\n        \n        span.inputChar {\n            color: var(--color-text-inputchar);\n        }\n        \n        [cursor]::after {\n            content: attr(cursor);\n            font-family: monospace;\n            -webkit-animation: blink 1s infinite;\n                    animation: blink 1s infinite;\n        }\n        \n        @-webkit-keyframes blink {\n            50% {\n                opacity: 0;\n            }\n        }\n\n        @keyframes blink {\n            50% {\n                opacity: 0;\n            }\n        }\n    </style>\n    \n    <body>\n        <div class='terminal-line' part=\"terminal-line\"><slot></slot></div>\n    </body>\n    \n`\n\nclass TerminalLine extends HTMLElement {\n    /**\n     * Defining custom attributes for <terminal-line> component\n    //  * @param {string} data - Type of prompt for the current line. Choices can be:\n    //  *   - 'output': Output of the terminal. Written all at once; (default)\n    //  *   - 'input': Input to the terminal. Written with typing animation after 'directory' and 'inputChar' attributes;\n    //  *   - 'prompt': Same as input, but with written with typing animation after 'promptChar' attribute;\n    //  *   - 'progress' Line with progress bar animation.\n    //  * @param {number} lineDelay - Delay before the start of the line animation, in ms.\n    //  * @param {number} typingDelay - Delay between each typed character in the line, in ms.\n    //  * @param {string} progressChar – Character to use for progress bar in the line, defaults to █.\n\t//  * @param {number} progressPercent - Max percent of progress in the line, default 100%.\n    //  * @param {string} cursor – Character to use for cursor in the line, defaults to ▋.\n    //  * @param {string} inputChar – Character(s) to use before the 'input' prompt in the line, defaults to '$'.\n    //  * @param {string} directory – Directory to write in the 'input' prompt before the input character in the line.\n    //  * @param {string} promptChar – Character(s) to use before the 'prompt' prompt in the line, defaults to '>>>'.\n    //  * @param {string} PS1 – String to write in the 'input' prompt before the actual line. \n            If present, any 'directory' or 'input' attribute will be disregarded.\n            Accepts HTML format. E.g.: \"This is a <span style='color: green;'>valid</span> PS1 attribute\"\n    //  */\n    constructor() {\n        super();\n        this.ALLOWED_NODES = [\"span\"];\n        this.attachShadow({ mode: \"open\" });\n        this.shadowRoot.appendChild(lineTemplate.content.cloneNode(true));\n    }\n\n    connectedCallback() {\n        this.line = this.shadowRoot.querySelector(\".terminal-line\");\n        this.keepNodes();\n        this.generatePS1AndPromptCharElements();\n        this.addEventListener('click', e => this.window.focus(), {passive: true})\n        this.ready = true;\n    }\n    \n    get window() {\n        if (this.parentElement.tagName.toLowerCase() != 'terminal-window') {\n            throw new Error(\"A 'terminal-line' tag can only be placed inside a 'terminal-window' tag.\");\n        }\n        return this.parentElement;\n    }\n\n    get data() {\n        /**\n        * Getter for the data property\n        */\n        if (this.hasAttribute('data')) {\n            let attr = this.getAttribute('data');\n            if (this.window.DATA_TYPES.includes(attr)) {\n                return attr;\n            } else {\n                return 'output';\n            }\n        } else {\n            return this.window.data;\n        }\n    }\n    \n    get lineDelay() {\n        /**\n        * Resets lineDelay property.\n        */\n        if (this.hasAttribute('lineDelay')) {\n            return parseFloat(this.getAttribute('lineDelay'));\n        } else if (this.window.hasAttribute('lineDelay')) {\n            return parseFloat(this.window.getAttribute('lineDelay'));\n        } else if ([\"input\",\"prompt\"].includes(this.data)) {\n            return 600;\n        } else {\n            return 100;\n        }\n    }\n    \n    get typingDelay() {\n        /**\n        * Resets typingDelay property.\n        */\n        if (this.hasAttribute('typingDelay')) {\n            return parseFloat(this.getAttribute('typingDelay'));\n        } else if (this.window.hasAttribute('typingDelay')) {\n            return parseFloat(this.window.getAttribute('typingDelay'));\n        } else if ([\"progress\"].includes(this.data)) {\n            return 30;\n        } else {\n            return 80;\n        }\n    }\n    \n    get progressChar() {\n        /**\n        * Getter for the progressChar property\n        */\n        return replaceTagSymbols(this.getAttribute('progressChar')?.toString()) || this.window.progressChar;\n    }\n    \n    get progressPercent() {\n        /**\n        * Getter for the progressPercent property\n        */\n        return parseFloat(this.getAttribute('progressPercent')) || this.window.progressPercent;\n    }\n    \n    get cursor() {\n        /**\n        * Getter for the cursor property\n        */\n        return replaceTagSymbols(this.getAttribute('cursor')?.toString()) || this.window.cursor;\n    }\n    \n    get inputChar() {\n        /**\n        * Getter for the inputChar property\n        */\n        if (this.hasAttribute('PS1')) {\n            return '';\n        } else {\n            return replaceTagSymbols(this.getAttribute('inputChar')?.toString()) || this.window.inputChar;\n        }\n    }\n    \n    get promptChar() {\n        /**\n        * Getter for the promptChar property\n        */\n        return replaceTagSymbols(this.getAttribute('promptChar')?.toString()) || this.window.promptChar;\n    }\n    \n    get directory() {\n        /**\n        * Getter for the directory property\n        */\n        if (this.hasAttribute('PS1')) {\n            return '';\n        } else {\n            return replaceTagSymbols(this.getAttribute('directory')?.toString()) || this.window.directory;\n        }\n    }\n\n    get PS1() {\n        /**\n        * Getter for the PS1 property\n        */\n        if (this.hasAttribute('PS1')) {\n            return this.getAttribute('PS1');\n        } else if (this.hasAttribute('directory') || this.hasAttribute('inputChar')) {\n            return `<span class=\"directory\" part='directory'>${this.directory}</span><span class=\"inputChar\" part=\"input-character\">${this.inputChar}&nbsp;</span>`;\n        } else {\n            return this.window.PS1;\n        }\n    }\n\n    keepNodes(elementList=this.ALLOWED_NODES) {\n        /*\n        * Delete all line nodes whose tags are not within the elementList, \n        * create <span> tags around textNodes,\n        * and create the nodes property with the kept ones.\n        */\n        for (let i=0; i<this.childNodes.length; i++) {\n            let node = this.childNodes[i];\n            if (node.nodeType == 3) {\n                let span = document.createElement('span');\n                this.insertBefore(span,node);\n                span.appendChild(node);\n            } else if (!elementList.includes(node.tagName.toLowerCase())) {\n                node.remove();\n                i--;\n            }\n        }\n        this.nodes = Array.from(this.childNodes);\n        this.nodesNotHidden = this.nodes.filter(node => getComputedStyle(node).display != 'none');\n    }\n\n    showPS1() {\n        show(this.shadowRoot.querySelector('.ps1'), this.window.abortControllerReset.signal);\n    }\n    \n    showPromptChar() {\n        show(this.shadowRoot.querySelector('.promptChar'), this.window.abortControllerReset.signal);\n    }\n\n    async type() {\n        /**\n        * Function that handles the animation of the current line based on its data property\n        */\n        if (this.data == 'input') {\n            this.showPS1();\n            await this.typeInput();\n        } else if (this.data == 'progress') {\n            await sleep(this.lineDelay, this.window.abortControllerFast.signal);\n            await this.typeProgress();\n            return;\n        } else if (this.data == 'prompt') {\n            this.showPromptChar();\n            await this.typeInput();\n        } else {\n            await sleep(this.lineDelay, this.window.abortControllerFast.signal);\n            show(this, this.window.abortControllerReset.signal)\n        }\n\n    }\n\n    measureChar(char=this.progressChar) {\n        const ruler = document.createElement('span');\n        ruler.innerHTML = char;\n        ruler.style.whiteSpace = 'pre';\n        this.appendChild(ruler);\n        const width = ruler.offsetWidth;\n        this.removeChild(ruler);\n        return width;\n    }\n\n    async typeProgress() {\n        /**\n        * Animate a progress bar.\n        */\n        const progressCharWidth = this.measureChar();\n        const progressSteps = Math.round((parseInt(getComputedStyle(this).width)*0.8*(this.progressPercent/100))/progressCharWidth);\n        let percent = 0;\n        this.textContent = '0%';\n        show(this, this.window.abortControllerReset.signal);\n        for (let i=1; i<=progressSteps; i++) {\n            await sleep(this.typingDelay, this.window.abortControllerFast.signal);\n            percent = Math.round(this.progressPercent/progressSteps*i)\n            this.textContent = `${this.progressChar.repeat(i)} ${percent}%`;\n        }\n    }\n\n    generateProgress() {\n        const progressCharWidth = this.measureChar();\n        const progressLength = Math.round((parseInt(getComputedStyle(this).width)*0.8*(this.progressPercent/100))/progressCharWidth);\n        this.textContent = `${this.progressChar.repeat(progressLength)} ${this.progressPercent}%`;\n    }\n\n    async typeInput() {\n         /**\n         * Animate an input line.\n         */\n        let textArray = this.getAndRemoveTextContent();\n        show(this, this.window.abortControllerReset.signal);\n        this.addCursor();\n        await sleep(this.lineDelay, this.window.abortControllerFast.signal);\n        for (let i=0; i<this.nodesNotHidden.length; i++) {\n            let node = this.nodesNotHidden[i];\n            let text = textArray[i];\n            for (let char of text) {\n                await sleep(this.typingDelay, this.window.abortControllerFast.signal);\n                node.textContent += char;\n            }\n        }\n        this.removeCursor();\n    }\n\n    getAndRemoveTextContent() {\n        let textArray = [];\n        for (let node of this.nodesNotHidden) {\n            textArray.push(node.textContent);\n            node.textContent = \"\";\n        }\n        return textArray;\n    }\n\n    addCursor() {\n        this.line.setAttribute(\"cursor\", `${this.cursor}`)\n    }\n    \n    removeCursor() {\n        this.line.removeAttribute('cursor');\n    }\n\n    generatePS1AndPromptCharElements() {\n        let elem = document.createElement('div');\n        elem.style.display=\"inline\";\n        if (this.data == 'input') {\n            elem.innerHTML = this.PS1;\n            elem.classList.add('ps1');\n            this.line.prepend(elem)\n        } else if (this.data == 'prompt') {\n            elem.innerHTML = `${this.promptChar} `;\n            elem.classList.add('promptChar');\n            elem.setAttribute('part','prompt-character');\n            this.promptCharElement = elem;\n            this.line.prepend(elem)\n        }\n        if (!this.parentElement.static) {\n            hide(elem);\n        }\n    }\n}\n\ncustomElements.define(\"terminal-window\", TerminalWindow)\ncustomElements.define(\"terminal-line\", TerminalLine)\n"]}